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