b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * I/O Processor (IOP) ADB Driver
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Based on via-cuda.c by Paul Mackerras.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * 1999-07-01 (jmt) - First implementation for new driver architecture.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * 1999-07-31 (jmt) - First working version.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) #include <linux/types.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) #include <linux/kernel.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) #include <linux/mm.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) #include <linux/delay.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) #include <linux/init.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 18) #include <asm/macintosh.h>
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 19) #include <asm/macints.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) #include <asm/mac_iop.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) #include <asm/adb_iop.h>
c396dd2ec5bbd (Finn Thain 2021-01-18 17:19:40 +1100 22) #include <asm/unaligned.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 24) #include <linux/adb.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) static struct adb_request *current_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) static struct adb_request *last_req;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 28) static unsigned int autopoll_devs;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 29) static u8 autopoll_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) static enum adb_iop_state {
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 32) idle,
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 33) sending,
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 34) awaiting_reply
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) } adb_iop_state;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 37) static void adb_iop_start(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 38) static int adb_iop_probe(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) static int adb_iop_init(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 40) static int adb_iop_send_request(struct adb_request *, int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) static int adb_iop_write(struct adb_request *);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42) static int adb_iop_autopoll(int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 43) static void adb_iop_poll(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) static int adb_iop_reset_bus(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45)
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 46) /* ADB command byte structure */
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 47) #define ADDR_MASK 0xF0
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 48) #define OP_MASK 0x0C
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 49) #define TALK 0x0C
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 50)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) struct adb_driver adb_iop_driver = {
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 52) .name = "ISM IOP",
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 53) .probe = adb_iop_probe,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 54) .init = adb_iop_init,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 55) .send_request = adb_iop_send_request,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 56) .autopoll = adb_iop_autopoll,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 57) .poll = adb_iop_poll,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 58) .reset_bus = adb_iop_reset_bus
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 61) static void adb_iop_done(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) {
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 63) struct adb_request *req = current_req;
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 64)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 65) adb_iop_state = idle;
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 66)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) current_req = req->next;
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 69) if (req->done)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 70) (*req->done)(req);
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 71)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 72) if (adb_iop_state == idle)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 73) adb_iop_start();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77) * Completion routine for ADB commands sent to the IOP.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 79) * This will be called when a packet has been successfully sent.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 80) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 82) static void adb_iop_complete(struct iop_msg *msg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 83) {
38b7a2ae0ad3e (Geert Uytterhoeven 2010-11-11 14:05:06 -0800 84) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) local_irq_save(flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87)
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 88) adb_iop_state = awaiting_reply;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) local_irq_restore(flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) * Listen for ADB messages from the IOP.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) *
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 96) * This will be called when unsolicited IOP messages are received.
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 97) * These IOP messages can carry ADB autopoll responses and also occur
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 98) * after explicit ADB commands.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 100)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 101) static void adb_iop_listen(struct iop_msg *msg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102) {
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 103) struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 104) u8 addr = (amsg->cmd & ADDR_MASK) >> 4;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 105) u8 op = amsg->cmd & OP_MASK;
38b7a2ae0ad3e (Geert Uytterhoeven 2010-11-11 14:05:06 -0800 106) unsigned long flags;
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 107) bool req_done = false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 109) local_irq_save(flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110)
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 111) /* Responses to Talk commands may be unsolicited as they are
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 112) * produced when the IOP polls devices. They are mostly timeouts.
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 113) */
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 114) if (op == TALK && ((1 << addr) & autopoll_devs))
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 115) autopoll_addr = addr;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 116)
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 117) switch (amsg->flags & (ADB_IOP_EXPLICIT |
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 118) ADB_IOP_AUTOPOLL |
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 119) ADB_IOP_TIMEOUT)) {
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 120) case ADB_IOP_EXPLICIT:
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 121) case ADB_IOP_EXPLICIT | ADB_IOP_TIMEOUT:
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 122) if (adb_iop_state == awaiting_reply) {
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 123) struct adb_request *req = current_req;
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 124)
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 125) if (req->reply_expected) {
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 126) req->reply_len = amsg->count + 1;
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 127) memcpy(req->reply, &amsg->cmd, req->reply_len);
2c9cfbadfa234 (Finn Thain 2020-11-20 15:39:56 +1100 128) }
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 129)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 130) req_done = true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) }
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 132) break;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 133) case ADB_IOP_AUTOPOLL:
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 134) if (((1 << addr) & autopoll_devs) &&
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 135) amsg->cmd == ADB_READREG(addr, 0))
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 136) adb_input(&amsg->cmd, amsg->count + 1, 1);
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 137) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) }
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 139) msg->reply[0] = autopoll_addr ? ADB_IOP_AUTOPOLL : 0;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 140) msg->reply[1] = 0;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 141) msg->reply[2] = autopoll_addr ? ADB_READREG(autopoll_addr, 0) : 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) iop_complete_message(msg);
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 143)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 144) if (req_done)
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 145) adb_iop_done();
32226e8170439 (Finn Thain 2020-05-31 09:17:03 +1000 146)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147) local_irq_restore(flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151) * Start sending an ADB packet, IOP style
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 153) * There isn't much to do other than hand the packet over to the IOP
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 154) * after encapsulating it in an adb_iopmsg.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 156)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 157) static void adb_iop_start(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159) struct adb_request *req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160) struct adb_iopmsg amsg;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) /* get the packet to send */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 163) req = current_req;
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 164) if (!req)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 165) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 166)
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 167) /* The IOP takes MacII-style packets, so strip the initial
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 168) * ADB_PACKET byte.
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 169) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170) amsg.flags = ADB_IOP_EXPLICIT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 171) amsg.count = req->nbytes - 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 172)
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 173) /* amsg.data immediately follows amsg.cmd, effectively making
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 174) * &amsg.cmd a pointer to the beginning of a full ADB packet.
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 175) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 176) memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 177)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) req->sent = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 179) adb_iop_state = sending;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 180)
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 181) /* Now send it. The IOP manager will call adb_iop_complete
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 182) * when the message has been sent.
ff785e179faf4 (Finn Thain 2020-05-31 09:17:03 +1000 183) */
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 184) iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg,
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 185) adb_iop_complete);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 186) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 187)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 188) static int adb_iop_probe(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 189) {
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 190) if (!iop_ism_present)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 191) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 192) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 193) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 194)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 195) static int adb_iop_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 196) {
351e5ad327d07 (Finn Thain 2018-09-11 20:18:44 -0400 197) pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 198) iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 199) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 200) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 201)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 202) static int adb_iop_send_request(struct adb_request *req, int sync)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 203) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 204) int err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 205)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 206) err = adb_iop_write(req);
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 207) if (err)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 208) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 209)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 210) if (sync) {
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 211) while (!req->complete)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 212) adb_iop_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 213) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 214) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 215) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 216)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 217) static int adb_iop_write(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 218) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 219) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 220)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 221) if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 222) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 223) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 224) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 225)
a5d361fc24b75 (Al Viro 2006-01-12 01:06:34 -0800 226) req->next = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 227) req->sent = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 228) req->complete = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 229) req->reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 230)
aac840eca8fec (Finn Thain 2020-05-31 09:17:03 +1000 231) local_irq_save(flags);
aac840eca8fec (Finn Thain 2020-05-31 09:17:03 +1000 232)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 233) if (current_req) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 234) last_req->next = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 235) last_req = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 236) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 237) current_req = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 238) last_req = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 239) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 240)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 241) if (adb_iop_state == idle)
47fd2060660e6 (Finn Thain 2018-09-11 20:18:44 -0400 242) adb_iop_start();
aac840eca8fec (Finn Thain 2020-05-31 09:17:03 +1000 243)
aac840eca8fec (Finn Thain 2020-05-31 09:17:03 +1000 244) local_irq_restore(flags);
aac840eca8fec (Finn Thain 2020-05-31 09:17:03 +1000 245)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 246) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 247) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 248)
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 249) static void adb_iop_set_ap_complete(struct iop_msg *msg)
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 250) {
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 251) struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 252)
c396dd2ec5bbd (Finn Thain 2021-01-18 17:19:40 +1100 253) autopoll_devs = get_unaligned_be16(amsg->data);
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 254) if (autopoll_devs & (1 << autopoll_addr))
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 255) return;
10199e90ee20e (Finn Thain 2020-11-20 15:39:56 +1100 256) autopoll_addr = autopoll_devs ? (ffs(autopoll_devs) - 1) : 0;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 257) }
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 258)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 259) static int adb_iop_autopoll(int devs)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 260) {
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 261) struct adb_iopmsg amsg;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 262) unsigned long flags;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 263) unsigned int mask = (unsigned int)devs & 0xFFFE;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 264)
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 265) local_irq_save(flags);
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 266)
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 267) amsg.flags = ADB_IOP_SET_AUTOPOLL | (mask ? ADB_IOP_AUTOPOLL : 0);
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 268) amsg.count = 2;
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 269) amsg.cmd = 0;
c396dd2ec5bbd (Finn Thain 2021-01-18 17:19:40 +1100 270) put_unaligned_be16(mask, amsg.data);
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 271)
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 272) iop_send_message(ADB_IOP, ADB_CHAN, NULL, sizeof(amsg), (__u8 *)&amsg,
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 273) adb_iop_set_ap_complete);
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 274)
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 275) local_irq_restore(flags);
c66da95a39ec2 (Finn Thain 2020-05-31 09:17:03 +1000 276)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 277) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 278) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 279)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 280) static void adb_iop_poll(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 281) {
92178fcabbcd3 (Finn Thain 2017-10-26 22:45:24 -0400 282) iop_ism_irq_poll(ADB_IOP);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 283) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 284)
56b732edda96b (Finn Thain 2020-05-31 09:17:03 +1000 285) static int adb_iop_reset_bus(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 286) {
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 287) struct adb_request req;
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 288)
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 289) /* Command = 0, Address = ignored */
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 290) adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 291) adb_iop_send_request(&req, 1);
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 292)
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 293) /* Don't want any more requests during the Global Reset low time. */
303511edb859b (Finn Thain 2020-05-31 09:17:03 +1000 294) mdelay(3);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 295)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 296) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 297) }