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