xref: /openbmc/linux/drivers/macintosh/macio-adb.c (revision 36874579dbf4cafa31486d4207c6807efbbf1378)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Driver for the ADB controller in the Mac I/O (Hydra) chip.
31da177e4SLinus Torvalds  */
41da177e4SLinus Torvalds #include <stdarg.h>
51da177e4SLinus Torvalds #include <linux/types.h>
61da177e4SLinus Torvalds #include <linux/errno.h>
71da177e4SLinus Torvalds #include <linux/kernel.h>
81da177e4SLinus Torvalds #include <linux/delay.h>
91da177e4SLinus Torvalds #include <linux/sched.h>
101da177e4SLinus Torvalds #include <linux/spinlock.h>
111da177e4SLinus Torvalds #include <linux/interrupt.h>
121da177e4SLinus Torvalds #include <asm/prom.h>
131da177e4SLinus Torvalds #include <linux/adb.h>
141da177e4SLinus Torvalds #include <asm/io.h>
151da177e4SLinus Torvalds #include <asm/pgtable.h>
161da177e4SLinus Torvalds #include <asm/hydra.h>
171da177e4SLinus Torvalds #include <asm/irq.h>
181da177e4SLinus Torvalds #include <asm/system.h>
191da177e4SLinus Torvalds #include <linux/init.h>
20*36874579SDavid Woodhouse #include <linux/ioport.h>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds struct preg {
231da177e4SLinus Torvalds 	unsigned char r;
241da177e4SLinus Torvalds 	char pad[15];
251da177e4SLinus Torvalds };
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds struct adb_regs {
281da177e4SLinus Torvalds 	struct preg intr;
291da177e4SLinus Torvalds 	struct preg data[9];
301da177e4SLinus Torvalds 	struct preg intr_enb;
311da177e4SLinus Torvalds 	struct preg dcount;
321da177e4SLinus Torvalds 	struct preg error;
331da177e4SLinus Torvalds 	struct preg ctrl;
341da177e4SLinus Torvalds 	struct preg autopoll;
351da177e4SLinus Torvalds 	struct preg active_hi;
361da177e4SLinus Torvalds 	struct preg active_lo;
371da177e4SLinus Torvalds 	struct preg test;
381da177e4SLinus Torvalds };
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds /* Bits in intr and intr_enb registers */
411da177e4SLinus Torvalds #define DFB	1		/* data from bus */
421da177e4SLinus Torvalds #define TAG	2		/* transfer access grant */
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds /* Bits in dcount register */
451da177e4SLinus Torvalds #define HMB	0x0f		/* how many bytes */
461da177e4SLinus Torvalds #define APD	0x10		/* auto-poll data */
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds /* Bits in error register */
491da177e4SLinus Torvalds #define NRE	1		/* no response error */
501da177e4SLinus Torvalds #define DLE	2		/* data lost error */
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds /* Bits in ctrl register */
531da177e4SLinus Torvalds #define TAR	1		/* transfer access request */
541da177e4SLinus Torvalds #define DTB	2		/* data to bus */
551da177e4SLinus Torvalds #define CRE	4		/* command response expected */
561da177e4SLinus Torvalds #define ADB_RST	8		/* ADB reset */
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds /* Bits in autopoll register */
591da177e4SLinus Torvalds #define APE	1		/* autopoll enable */
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds static volatile struct adb_regs __iomem *adb;
621da177e4SLinus Torvalds static struct adb_request *current_req, *last_req;
631da177e4SLinus Torvalds static DEFINE_SPINLOCK(macio_lock);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds static int macio_probe(void);
661da177e4SLinus Torvalds static int macio_init(void);
671da177e4SLinus Torvalds static irqreturn_t macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs);
681da177e4SLinus Torvalds static int macio_send_request(struct adb_request *req, int sync);
691da177e4SLinus Torvalds static int macio_adb_autopoll(int devs);
701da177e4SLinus Torvalds static void macio_adb_poll(void);
711da177e4SLinus Torvalds static int macio_adb_reset_bus(void);
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds struct adb_driver macio_adb_driver = {
741da177e4SLinus Torvalds 	"MACIO",
751da177e4SLinus Torvalds 	macio_probe,
761da177e4SLinus Torvalds 	macio_init,
771da177e4SLinus Torvalds 	macio_send_request,
781da177e4SLinus Torvalds 	/*macio_write,*/
791da177e4SLinus Torvalds 	macio_adb_autopoll,
801da177e4SLinus Torvalds 	macio_adb_poll,
811da177e4SLinus Torvalds 	macio_adb_reset_bus
821da177e4SLinus Torvalds };
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds int macio_probe(void)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds int macio_init(void)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	struct device_node *adbs;
92*36874579SDavid Woodhouse 	struct resource r;
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	adbs = find_compatible_devices("adb", "chrp,adb0");
951da177e4SLinus Torvalds 	if (adbs == 0)
961da177e4SLinus Torvalds 		return -ENXIO;
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds #if 0
99*36874579SDavid Woodhouse 	{ int i = 0;
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	printk("macio_adb_init: node = %p, addrs =", adbs->node);
102*36874579SDavid Woodhouse 	while(!of_address_to_resource(adbs, i, &r))
103*36874579SDavid Woodhouse 		printk(" %x(%x)", r.start, r.end - r.start);
1041da177e4SLinus Torvalds 	printk(", intrs =");
1051da177e4SLinus Torvalds 	for (i = 0; i < adbs->n_intrs; ++i)
1061da177e4SLinus Torvalds 		printk(" %x", adbs->intrs[i].line);
1071da177e4SLinus Torvalds 	printk("\n"); }
1081da177e4SLinus Torvalds #endif
109*36874579SDavid Woodhouse 	if (of_address_to_resource(adbs, 0, &r))
110*36874579SDavid Woodhouse 		return -ENXIO;
111*36874579SDavid Woodhouse 	adb = ioremap(r.start, sizeof(struct adb_regs));
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	out_8(&adb->ctrl.r, 0);
1141da177e4SLinus Torvalds 	out_8(&adb->intr.r, 0);
1151da177e4SLinus Torvalds 	out_8(&adb->error.r, 0);
1161da177e4SLinus Torvalds 	out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */
1171da177e4SLinus Torvalds 	out_8(&adb->active_lo.r, 0xff);
1181da177e4SLinus Torvalds 	out_8(&adb->autopoll.r, APE);
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
1211da177e4SLinus Torvalds 			0, "ADB", (void *)0)) {
1221da177e4SLinus Torvalds 		printk(KERN_ERR "ADB: can't get irq %d\n",
1231da177e4SLinus Torvalds 		       adbs->intrs[0].line);
1241da177e4SLinus Torvalds 		return -EAGAIN;
1251da177e4SLinus Torvalds 	}
1261da177e4SLinus Torvalds 	out_8(&adb->intr_enb.r, DFB | TAG);
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	printk("adb: mac-io driver 1.0 for unified ADB\n");
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	return 0;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds static int macio_adb_autopoll(int devs)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	unsigned long flags;
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	spin_lock_irqsave(&macio_lock, flags);
1381da177e4SLinus Torvalds 	out_8(&adb->active_hi.r, devs >> 8);
1391da177e4SLinus Torvalds 	out_8(&adb->active_lo.r, devs);
1401da177e4SLinus Torvalds 	out_8(&adb->autopoll.r, devs? APE: 0);
1411da177e4SLinus Torvalds 	spin_unlock_irqrestore(&macio_lock, flags);
1421da177e4SLinus Torvalds 	return 0;
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds static int macio_adb_reset_bus(void)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds 	unsigned long flags;
1481da177e4SLinus Torvalds 	int timeout = 1000000;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	/* Hrm... we may want to not lock interrupts for so
1511da177e4SLinus Torvalds 	 * long ... oh well, who uses that chip anyway ? :)
1521da177e4SLinus Torvalds 	 * That function will be seldomly used during boot
1531da177e4SLinus Torvalds 	 * on rare machines, so...
1541da177e4SLinus Torvalds 	 */
1551da177e4SLinus Torvalds 	spin_lock_irqsave(&macio_lock, flags);
1561da177e4SLinus Torvalds 	out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST);
1571da177e4SLinus Torvalds 	while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) {
1581da177e4SLinus Torvalds 		if (--timeout == 0) {
1591da177e4SLinus Torvalds 			out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST);
1601da177e4SLinus Torvalds 			return -1;
1611da177e4SLinus Torvalds 		}
1621da177e4SLinus Torvalds 	}
1631da177e4SLinus Torvalds 	spin_unlock_irqrestore(&macio_lock, flags);
1641da177e4SLinus Torvalds 	return 0;
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds /* Send an ADB command */
1681da177e4SLinus Torvalds static int macio_send_request(struct adb_request *req, int sync)
1691da177e4SLinus Torvalds {
1701da177e4SLinus Torvalds 	unsigned long flags;
1711da177e4SLinus Torvalds 	int i;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	if (req->data[0] != ADB_PACKET)
1741da177e4SLinus Torvalds 		return -EINVAL;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	for (i = 0; i < req->nbytes - 1; ++i)
1771da177e4SLinus Torvalds 		req->data[i] = req->data[i+1];
1781da177e4SLinus Torvalds 	--req->nbytes;
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	req->next = NULL;
1811da177e4SLinus Torvalds 	req->sent = 0;
1821da177e4SLinus Torvalds 	req->complete = 0;
1831da177e4SLinus Torvalds 	req->reply_len = 0;
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	spin_lock_irqsave(&macio_lock, flags);
1861da177e4SLinus Torvalds 	if (current_req != 0) {
1871da177e4SLinus Torvalds 		last_req->next = req;
1881da177e4SLinus Torvalds 		last_req = req;
1891da177e4SLinus Torvalds 	} else {
1901da177e4SLinus Torvalds 		current_req = last_req = req;
1911da177e4SLinus Torvalds 		out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
1921da177e4SLinus Torvalds 	}
1931da177e4SLinus Torvalds 	spin_unlock_irqrestore(&macio_lock, flags);
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	if (sync) {
1961da177e4SLinus Torvalds 		while (!req->complete)
1971da177e4SLinus Torvalds 			macio_adb_poll();
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	return 0;
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds static irqreturn_t macio_adb_interrupt(int irq, void *arg,
2041da177e4SLinus Torvalds 				       struct pt_regs *regs)
2051da177e4SLinus Torvalds {
2061da177e4SLinus Torvalds 	int i, n, err;
2071da177e4SLinus Torvalds 	struct adb_request *req = NULL;
2081da177e4SLinus Torvalds 	unsigned char ibuf[16];
2091da177e4SLinus Torvalds 	int ibuf_len = 0;
2101da177e4SLinus Torvalds 	int complete = 0;
2111da177e4SLinus Torvalds 	int autopoll = 0;
2121da177e4SLinus Torvalds 	int handled = 0;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	spin_lock(&macio_lock);
2151da177e4SLinus Torvalds 	if (in_8(&adb->intr.r) & TAG) {
2161da177e4SLinus Torvalds 		handled = 1;
2171da177e4SLinus Torvalds 		if ((req = current_req) != 0) {
2181da177e4SLinus Torvalds 			/* put the current request in */
2191da177e4SLinus Torvalds 			for (i = 0; i < req->nbytes; ++i)
2201da177e4SLinus Torvalds 				out_8(&adb->data[i].r, req->data[i]);
2211da177e4SLinus Torvalds 			out_8(&adb->dcount.r, req->nbytes & HMB);
2221da177e4SLinus Torvalds 			req->sent = 1;
2231da177e4SLinus Torvalds 			if (req->reply_expected) {
2241da177e4SLinus Torvalds 				out_8(&adb->ctrl.r, DTB + CRE);
2251da177e4SLinus Torvalds 			} else {
2261da177e4SLinus Torvalds 				out_8(&adb->ctrl.r, DTB);
2271da177e4SLinus Torvalds 				current_req = req->next;
2281da177e4SLinus Torvalds 				complete = 1;
2291da177e4SLinus Torvalds 				if (current_req)
2301da177e4SLinus Torvalds 					out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
2311da177e4SLinus Torvalds 			}
2321da177e4SLinus Torvalds 		}
2331da177e4SLinus Torvalds 		out_8(&adb->intr.r, 0);
2341da177e4SLinus Torvalds 	}
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	if (in_8(&adb->intr.r) & DFB) {
2371da177e4SLinus Torvalds 		handled = 1;
2381da177e4SLinus Torvalds 		err = in_8(&adb->error.r);
2391da177e4SLinus Torvalds 		if (current_req && current_req->sent) {
2401da177e4SLinus Torvalds 			/* this is the response to a command */
2411da177e4SLinus Torvalds 			req = current_req;
2421da177e4SLinus Torvalds 			if (err == 0) {
2431da177e4SLinus Torvalds 				req->reply_len = in_8(&adb->dcount.r) & HMB;
2441da177e4SLinus Torvalds 				for (i = 0; i < req->reply_len; ++i)
2451da177e4SLinus Torvalds 					req->reply[i] = in_8(&adb->data[i].r);
2461da177e4SLinus Torvalds 			}
2471da177e4SLinus Torvalds 			current_req = req->next;
2481da177e4SLinus Torvalds 			complete = 1;
2491da177e4SLinus Torvalds 			if (current_req)
2501da177e4SLinus Torvalds 				out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
2511da177e4SLinus Torvalds 		} else if (err == 0) {
2521da177e4SLinus Torvalds 			/* autopoll data */
2531da177e4SLinus Torvalds 			n = in_8(&adb->dcount.r) & HMB;
2541da177e4SLinus Torvalds 			for (i = 0; i < n; ++i)
2551da177e4SLinus Torvalds 				ibuf[i] = in_8(&adb->data[i].r);
2561da177e4SLinus Torvalds 			ibuf_len = n;
2571da177e4SLinus Torvalds 			autopoll = (in_8(&adb->dcount.r) & APD) != 0;
2581da177e4SLinus Torvalds 		}
2591da177e4SLinus Torvalds 		out_8(&adb->error.r, 0);
2601da177e4SLinus Torvalds 		out_8(&adb->intr.r, 0);
2611da177e4SLinus Torvalds 	}
2621da177e4SLinus Torvalds 	spin_unlock(&macio_lock);
2631da177e4SLinus Torvalds 	if (complete && req) {
2641da177e4SLinus Torvalds 	    void (*done)(struct adb_request *) = req->done;
2651da177e4SLinus Torvalds 	    mb();
2661da177e4SLinus Torvalds 	    req->complete = 1;
2671da177e4SLinus Torvalds 	    /* Here, we assume that if the request has a done member, the
2681da177e4SLinus Torvalds     	     * struct request will survive to setting req->complete to 1
2691da177e4SLinus Torvalds 	     */
2701da177e4SLinus Torvalds 	    if (done)
2711da177e4SLinus Torvalds 		(*done)(req);
2721da177e4SLinus Torvalds 	}
2731da177e4SLinus Torvalds 	if (ibuf_len)
2741da177e4SLinus Torvalds 		adb_input(ibuf, ibuf_len, regs, autopoll);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds static void macio_adb_poll(void)
2801da177e4SLinus Torvalds {
2811da177e4SLinus Torvalds 	unsigned long flags;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	local_irq_save(flags);
2841da177e4SLinus Torvalds 	if (in_8(&adb->intr.r) != 0)
2851da177e4SLinus Torvalds 		macio_adb_interrupt(0, NULL, NULL);
2861da177e4SLinus Torvalds 	local_irq_restore(flags);
2871da177e4SLinus Torvalds }
288