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