Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * Driver for the ADB controller in the Mac I/O (Hydra) chip. | |
4 | */ | |
5 | #include <stdarg.h> | |
6 | #include <linux/types.h> | |
7 | #include <linux/errno.h> | |
8 | #include <linux/kernel.h> | |
9 | #include <linux/delay.h> | |
1da177e4 LT |
10 | #include <linux/spinlock.h> |
11 | #include <linux/interrupt.h> | |
12 | #include <asm/prom.h> | |
13 | #include <linux/adb.h> | |
14 | #include <asm/io.h> | |
15 | #include <asm/pgtable.h> | |
16 | #include <asm/hydra.h> | |
17 | #include <asm/irq.h> | |
1da177e4 | 18 | #include <linux/init.h> |
36874579 | 19 | #include <linux/ioport.h> |
1da177e4 LT |
20 | |
21 | struct preg { | |
22 | unsigned char r; | |
23 | char pad[15]; | |
24 | }; | |
25 | ||
26 | struct adb_regs { | |
27 | struct preg intr; | |
28 | struct preg data[9]; | |
29 | struct preg intr_enb; | |
30 | struct preg dcount; | |
31 | struct preg error; | |
32 | struct preg ctrl; | |
33 | struct preg autopoll; | |
34 | struct preg active_hi; | |
35 | struct preg active_lo; | |
36 | struct preg test; | |
37 | }; | |
38 | ||
39 | /* Bits in intr and intr_enb registers */ | |
40 | #define DFB 1 /* data from bus */ | |
41 | #define TAG 2 /* transfer access grant */ | |
42 | ||
43 | /* Bits in dcount register */ | |
44 | #define HMB 0x0f /* how many bytes */ | |
45 | #define APD 0x10 /* auto-poll data */ | |
46 | ||
47 | /* Bits in error register */ | |
48 | #define NRE 1 /* no response error */ | |
49 | #define DLE 2 /* data lost error */ | |
50 | ||
51 | /* Bits in ctrl register */ | |
52 | #define TAR 1 /* transfer access request */ | |
53 | #define DTB 2 /* data to bus */ | |
54 | #define CRE 4 /* command response expected */ | |
55 | #define ADB_RST 8 /* ADB reset */ | |
56 | ||
57 | /* Bits in autopoll register */ | |
58 | #define APE 1 /* autopoll enable */ | |
59 | ||
60 | static volatile struct adb_regs __iomem *adb; | |
61 | static struct adb_request *current_req, *last_req; | |
62 | static DEFINE_SPINLOCK(macio_lock); | |
63 | ||
64 | static int macio_probe(void); | |
65 | static int macio_init(void); | |
7d12e780 | 66 | static irqreturn_t macio_adb_interrupt(int irq, void *arg); |
1da177e4 LT |
67 | static int macio_send_request(struct adb_request *req, int sync); |
68 | static int macio_adb_autopoll(int devs); | |
69 | static void macio_adb_poll(void); | |
70 | static int macio_adb_reset_bus(void); | |
71 | ||
72 | struct adb_driver macio_adb_driver = { | |
73 | "MACIO", | |
74 | macio_probe, | |
75 | macio_init, | |
76 | macio_send_request, | |
77 | /*macio_write,*/ | |
78 | macio_adb_autopoll, | |
79 | macio_adb_poll, | |
80 | macio_adb_reset_bus | |
81 | }; | |
82 | ||
83 | int macio_probe(void) | |
84 | { | |
4bf56e17 SR |
85 | struct device_node *np; |
86 | ||
87 | np = of_find_compatible_node(NULL, "adb", "chrp,adb0"); | |
88 | if (np) { | |
89 | of_node_put(np); | |
90 | return 0; | |
91 | } | |
92 | return -ENODEV; | |
1da177e4 LT |
93 | } |
94 | ||
95 | int macio_init(void) | |
96 | { | |
97 | struct device_node *adbs; | |
36874579 | 98 | struct resource r; |
0ebfff14 | 99 | unsigned int irq; |
1da177e4 | 100 | |
4bf56e17 | 101 | adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0"); |
1da177e4 LT |
102 | if (adbs == 0) |
103 | return -ENXIO; | |
104 | ||
4bf56e17 SR |
105 | if (of_address_to_resource(adbs, 0, &r)) { |
106 | of_node_put(adbs); | |
36874579 | 107 | return -ENXIO; |
4bf56e17 | 108 | } |
36874579 | 109 | adb = ioremap(r.start, sizeof(struct adb_regs)); |
1da177e4 LT |
110 | |
111 | out_8(&adb->ctrl.r, 0); | |
112 | out_8(&adb->intr.r, 0); | |
113 | out_8(&adb->error.r, 0); | |
114 | out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */ | |
115 | out_8(&adb->active_lo.r, 0xff); | |
116 | out_8(&adb->autopoll.r, APE); | |
117 | ||
0ebfff14 | 118 | irq = irq_of_parse_and_map(adbs, 0); |
4bf56e17 | 119 | of_node_put(adbs); |
0ebfff14 BH |
120 | if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) { |
121 | printk(KERN_ERR "ADB: can't get irq %d\n", irq); | |
1da177e4 LT |
122 | return -EAGAIN; |
123 | } | |
124 | out_8(&adb->intr_enb.r, DFB | TAG); | |
125 | ||
126 | printk("adb: mac-io driver 1.0 for unified ADB\n"); | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | static int macio_adb_autopoll(int devs) | |
132 | { | |
133 | unsigned long flags; | |
134 | ||
135 | spin_lock_irqsave(&macio_lock, flags); | |
136 | out_8(&adb->active_hi.r, devs >> 8); | |
137 | out_8(&adb->active_lo.r, devs); | |
138 | out_8(&adb->autopoll.r, devs? APE: 0); | |
139 | spin_unlock_irqrestore(&macio_lock, flags); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | static int macio_adb_reset_bus(void) | |
144 | { | |
145 | unsigned long flags; | |
146 | int timeout = 1000000; | |
147 | ||
148 | /* Hrm... we may want to not lock interrupts for so | |
149 | * long ... oh well, who uses that chip anyway ? :) | |
25985edc | 150 | * That function will be seldom used during boot |
1da177e4 LT |
151 | * on rare machines, so... |
152 | */ | |
153 | spin_lock_irqsave(&macio_lock, flags); | |
154 | out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST); | |
155 | while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) { | |
156 | if (--timeout == 0) { | |
157 | out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST); | |
86e4754a | 158 | spin_unlock_irqrestore(&macio_lock, flags); |
1da177e4 LT |
159 | return -1; |
160 | } | |
161 | } | |
162 | spin_unlock_irqrestore(&macio_lock, flags); | |
163 | return 0; | |
164 | } | |
165 | ||
166 | /* Send an ADB command */ | |
167 | static int macio_send_request(struct adb_request *req, int sync) | |
168 | { | |
169 | unsigned long flags; | |
170 | int i; | |
171 | ||
172 | if (req->data[0] != ADB_PACKET) | |
173 | return -EINVAL; | |
174 | ||
175 | for (i = 0; i < req->nbytes - 1; ++i) | |
176 | req->data[i] = req->data[i+1]; | |
177 | --req->nbytes; | |
178 | ||
179 | req->next = NULL; | |
180 | req->sent = 0; | |
181 | req->complete = 0; | |
182 | req->reply_len = 0; | |
183 | ||
184 | spin_lock_irqsave(&macio_lock, flags); | |
185 | if (current_req != 0) { | |
186 | last_req->next = req; | |
187 | last_req = req; | |
188 | } else { | |
189 | current_req = last_req = req; | |
190 | out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR); | |
191 | } | |
192 | spin_unlock_irqrestore(&macio_lock, flags); | |
193 | ||
194 | if (sync) { | |
195 | while (!req->complete) | |
196 | macio_adb_poll(); | |
197 | } | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
7d12e780 | 202 | static irqreturn_t macio_adb_interrupt(int irq, void *arg) |
1da177e4 LT |
203 | { |
204 | int i, n, err; | |
205 | struct adb_request *req = NULL; | |
206 | unsigned char ibuf[16]; | |
207 | int ibuf_len = 0; | |
208 | int complete = 0; | |
209 | int autopoll = 0; | |
210 | int handled = 0; | |
211 | ||
212 | spin_lock(&macio_lock); | |
213 | if (in_8(&adb->intr.r) & TAG) { | |
214 | handled = 1; | |
215 | if ((req = current_req) != 0) { | |
216 | /* put the current request in */ | |
217 | for (i = 0; i < req->nbytes; ++i) | |
218 | out_8(&adb->data[i].r, req->data[i]); | |
219 | out_8(&adb->dcount.r, req->nbytes & HMB); | |
220 | req->sent = 1; | |
221 | if (req->reply_expected) { | |
222 | out_8(&adb->ctrl.r, DTB + CRE); | |
223 | } else { | |
224 | out_8(&adb->ctrl.r, DTB); | |
225 | current_req = req->next; | |
226 | complete = 1; | |
227 | if (current_req) | |
228 | out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR); | |
229 | } | |
230 | } | |
231 | out_8(&adb->intr.r, 0); | |
232 | } | |
233 | ||
234 | if (in_8(&adb->intr.r) & DFB) { | |
235 | handled = 1; | |
236 | err = in_8(&adb->error.r); | |
237 | if (current_req && current_req->sent) { | |
238 | /* this is the response to a command */ | |
239 | req = current_req; | |
240 | if (err == 0) { | |
241 | req->reply_len = in_8(&adb->dcount.r) & HMB; | |
242 | for (i = 0; i < req->reply_len; ++i) | |
243 | req->reply[i] = in_8(&adb->data[i].r); | |
244 | } | |
245 | current_req = req->next; | |
246 | complete = 1; | |
247 | if (current_req) | |
248 | out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR); | |
249 | } else if (err == 0) { | |
250 | /* autopoll data */ | |
251 | n = in_8(&adb->dcount.r) & HMB; | |
252 | for (i = 0; i < n; ++i) | |
253 | ibuf[i] = in_8(&adb->data[i].r); | |
254 | ibuf_len = n; | |
255 | autopoll = (in_8(&adb->dcount.r) & APD) != 0; | |
256 | } | |
257 | out_8(&adb->error.r, 0); | |
258 | out_8(&adb->intr.r, 0); | |
259 | } | |
260 | spin_unlock(&macio_lock); | |
261 | if (complete && req) { | |
262 | void (*done)(struct adb_request *) = req->done; | |
263 | mb(); | |
264 | req->complete = 1; | |
265 | /* Here, we assume that if the request has a done member, the | |
266 | * struct request will survive to setting req->complete to 1 | |
267 | */ | |
268 | if (done) | |
269 | (*done)(req); | |
270 | } | |
271 | if (ibuf_len) | |
7d12e780 | 272 | adb_input(ibuf, ibuf_len, autopoll); |
1da177e4 LT |
273 | |
274 | return IRQ_RETVAL(handled); | |
275 | } | |
276 | ||
277 | static void macio_adb_poll(void) | |
278 | { | |
279 | unsigned long flags; | |
280 | ||
281 | local_irq_save(flags); | |
282 | if (in_8(&adb->intr.r) != 0) | |
9da3b1ad | 283 | macio_adb_interrupt(0, NULL); |
1da177e4 LT |
284 | local_irq_restore(flags); |
285 | } |