1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Driver for the ADB controller in the Mac I/O (Hydra) chip.
41da177e4SLinus Torvalds */
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/spinlock.h>
101da177e4SLinus Torvalds #include <linux/interrupt.h>
1165fddcfcSMike Rapoport #include <linux/pgtable.h>
12a486e512SChristophe Leroy #include <linux/of.h>
13a486e512SChristophe Leroy #include <linux/of_address.h>
14a486e512SChristophe Leroy #include <linux/of_irq.h>
151da177e4SLinus Torvalds #include <linux/adb.h>
16a486e512SChristophe Leroy
171da177e4SLinus Torvalds #include <asm/io.h>
181da177e4SLinus Torvalds #include <asm/hydra.h>
191da177e4SLinus Torvalds #include <asm/irq.h>
201da177e4SLinus Torvalds #include <linux/init.h>
2136874579SDavid Woodhouse #include <linux/ioport.h>
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds struct preg {
241da177e4SLinus Torvalds unsigned char r;
251da177e4SLinus Torvalds char pad[15];
261da177e4SLinus Torvalds };
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds struct adb_regs {
291da177e4SLinus Torvalds struct preg intr;
301da177e4SLinus Torvalds struct preg data[9];
311da177e4SLinus Torvalds struct preg intr_enb;
321da177e4SLinus Torvalds struct preg dcount;
331da177e4SLinus Torvalds struct preg error;
341da177e4SLinus Torvalds struct preg ctrl;
351da177e4SLinus Torvalds struct preg autopoll;
361da177e4SLinus Torvalds struct preg active_hi;
371da177e4SLinus Torvalds struct preg active_lo;
381da177e4SLinus Torvalds struct preg test;
391da177e4SLinus Torvalds };
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds /* Bits in intr and intr_enb registers */
421da177e4SLinus Torvalds #define DFB 1 /* data from bus */
431da177e4SLinus Torvalds #define TAG 2 /* transfer access grant */
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds /* Bits in dcount register */
461da177e4SLinus Torvalds #define HMB 0x0f /* how many bytes */
471da177e4SLinus Torvalds #define APD 0x10 /* auto-poll data */
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds /* Bits in error register */
501da177e4SLinus Torvalds #define NRE 1 /* no response error */
511da177e4SLinus Torvalds #define DLE 2 /* data lost error */
521da177e4SLinus Torvalds
531da177e4SLinus Torvalds /* Bits in ctrl register */
541da177e4SLinus Torvalds #define TAR 1 /* transfer access request */
551da177e4SLinus Torvalds #define DTB 2 /* data to bus */
561da177e4SLinus Torvalds #define CRE 4 /* command response expected */
571da177e4SLinus Torvalds #define ADB_RST 8 /* ADB reset */
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds /* Bits in autopoll register */
601da177e4SLinus Torvalds #define APE 1 /* autopoll enable */
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds static volatile struct adb_regs __iomem *adb;
631da177e4SLinus Torvalds static struct adb_request *current_req, *last_req;
641da177e4SLinus Torvalds static DEFINE_SPINLOCK(macio_lock);
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds static int macio_probe(void);
671da177e4SLinus Torvalds static int macio_init(void);
687d12e780SDavid Howells static irqreturn_t macio_adb_interrupt(int irq, void *arg);
691da177e4SLinus Torvalds static int macio_send_request(struct adb_request *req, int sync);
701da177e4SLinus Torvalds static int macio_adb_autopoll(int devs);
711da177e4SLinus Torvalds static void macio_adb_poll(void);
721da177e4SLinus Torvalds static int macio_adb_reset_bus(void);
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds struct adb_driver macio_adb_driver = {
753a52f6f9SFinn Thain .name = "MACIO",
763a52f6f9SFinn Thain .probe = macio_probe,
773a52f6f9SFinn Thain .init = macio_init,
783a52f6f9SFinn Thain .send_request = macio_send_request,
793a52f6f9SFinn Thain .autopoll = macio_adb_autopoll,
803a52f6f9SFinn Thain .poll = macio_adb_poll,
813a52f6f9SFinn Thain .reset_bus = macio_adb_reset_bus,
821da177e4SLinus Torvalds };
831da177e4SLinus Torvalds
macio_probe(void)841da177e4SLinus Torvalds int macio_probe(void)
851da177e4SLinus Torvalds {
864bf56e17SStephen Rothwell struct device_node *np;
874bf56e17SStephen Rothwell
884bf56e17SStephen Rothwell np = of_find_compatible_node(NULL, "adb", "chrp,adb0");
894bf56e17SStephen Rothwell if (np) {
904bf56e17SStephen Rothwell of_node_put(np);
914bf56e17SStephen Rothwell return 0;
924bf56e17SStephen Rothwell }
934bf56e17SStephen Rothwell return -ENODEV;
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds
macio_init(void)961da177e4SLinus Torvalds int macio_init(void)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds struct device_node *adbs;
9936874579SDavid Woodhouse struct resource r;
1000ebfff14SBenjamin Herrenschmidt unsigned int irq;
1011da177e4SLinus Torvalds
1024bf56e17SStephen Rothwell adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0");
103fc21ed8fSHaowen Bai if (!adbs)
1041da177e4SLinus Torvalds return -ENXIO;
1051da177e4SLinus Torvalds
1064bf56e17SStephen Rothwell if (of_address_to_resource(adbs, 0, &r)) {
1074bf56e17SStephen Rothwell of_node_put(adbs);
10836874579SDavid Woodhouse return -ENXIO;
1094bf56e17SStephen Rothwell }
11036874579SDavid Woodhouse adb = ioremap(r.start, sizeof(struct adb_regs));
111*dbaa3105SXie Shaowen if (!adb) {
112*dbaa3105SXie Shaowen of_node_put(adbs);
113*dbaa3105SXie Shaowen return -ENOMEM;
114*dbaa3105SXie Shaowen }
1151da177e4SLinus Torvalds
1161da177e4SLinus Torvalds out_8(&adb->ctrl.r, 0);
1171da177e4SLinus Torvalds out_8(&adb->intr.r, 0);
1181da177e4SLinus Torvalds out_8(&adb->error.r, 0);
1191da177e4SLinus Torvalds out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */
1201da177e4SLinus Torvalds out_8(&adb->active_lo.r, 0xff);
1211da177e4SLinus Torvalds out_8(&adb->autopoll.r, APE);
1221da177e4SLinus Torvalds
1230ebfff14SBenjamin Herrenschmidt irq = irq_of_parse_and_map(adbs, 0);
1244bf56e17SStephen Rothwell of_node_put(adbs);
1250ebfff14SBenjamin Herrenschmidt if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
1260ebfff14SBenjamin Herrenschmidt printk(KERN_ERR "ADB: can't get irq %d\n", irq);
1271da177e4SLinus Torvalds return -EAGAIN;
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds out_8(&adb->intr_enb.r, DFB | TAG);
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds printk("adb: mac-io driver 1.0 for unified ADB\n");
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds return 0;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds
macio_adb_autopoll(int devs)1361da177e4SLinus Torvalds static int macio_adb_autopoll(int devs)
1371da177e4SLinus Torvalds {
1381da177e4SLinus Torvalds unsigned long flags;
1391da177e4SLinus Torvalds
1401da177e4SLinus Torvalds spin_lock_irqsave(&macio_lock, flags);
1411da177e4SLinus Torvalds out_8(&adb->active_hi.r, devs >> 8);
1421da177e4SLinus Torvalds out_8(&adb->active_lo.r, devs);
1431da177e4SLinus Torvalds out_8(&adb->autopoll.r, devs? APE: 0);
1441da177e4SLinus Torvalds spin_unlock_irqrestore(&macio_lock, flags);
1451da177e4SLinus Torvalds return 0;
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds
macio_adb_reset_bus(void)1481da177e4SLinus Torvalds static int macio_adb_reset_bus(void)
1491da177e4SLinus Torvalds {
1501da177e4SLinus Torvalds unsigned long flags;
1511da177e4SLinus Torvalds int timeout = 1000000;
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds /* Hrm... we may want to not lock interrupts for so
1541da177e4SLinus Torvalds * long ... oh well, who uses that chip anyway ? :)
15525985edcSLucas De Marchi * That function will be seldom used during boot
1561da177e4SLinus Torvalds * on rare machines, so...
1571da177e4SLinus Torvalds */
1581da177e4SLinus Torvalds spin_lock_irqsave(&macio_lock, flags);
1591da177e4SLinus Torvalds out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST);
1601da177e4SLinus Torvalds while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) {
1611da177e4SLinus Torvalds if (--timeout == 0) {
1621da177e4SLinus Torvalds out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST);
16386e4754aSJulia Lawall spin_unlock_irqrestore(&macio_lock, flags);
1641da177e4SLinus Torvalds return -1;
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds spin_unlock_irqrestore(&macio_lock, flags);
1681da177e4SLinus Torvalds return 0;
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds /* Send an ADB command */
macio_send_request(struct adb_request * req,int sync)1721da177e4SLinus Torvalds static int macio_send_request(struct adb_request *req, int sync)
1731da177e4SLinus Torvalds {
1741da177e4SLinus Torvalds unsigned long flags;
1751da177e4SLinus Torvalds int i;
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds if (req->data[0] != ADB_PACKET)
1781da177e4SLinus Torvalds return -EINVAL;
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds for (i = 0; i < req->nbytes - 1; ++i)
1811da177e4SLinus Torvalds req->data[i] = req->data[i+1];
1821da177e4SLinus Torvalds --req->nbytes;
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds req->next = NULL;
1851da177e4SLinus Torvalds req->sent = 0;
1861da177e4SLinus Torvalds req->complete = 0;
1871da177e4SLinus Torvalds req->reply_len = 0;
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds spin_lock_irqsave(&macio_lock, flags);
190fc21ed8fSHaowen Bai if (current_req) {
1911da177e4SLinus Torvalds last_req->next = req;
1921da177e4SLinus Torvalds last_req = req;
1931da177e4SLinus Torvalds } else {
1941da177e4SLinus Torvalds current_req = last_req = req;
1951da177e4SLinus Torvalds out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds spin_unlock_irqrestore(&macio_lock, flags);
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds if (sync) {
2001da177e4SLinus Torvalds while (!req->complete)
2011da177e4SLinus Torvalds macio_adb_poll();
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds return 0;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds
macio_adb_interrupt(int irq,void * arg)2077d12e780SDavid Howells static irqreturn_t macio_adb_interrupt(int irq, void *arg)
2081da177e4SLinus Torvalds {
2091da177e4SLinus Torvalds int i, n, err;
2101da177e4SLinus Torvalds struct adb_request *req = NULL;
2111da177e4SLinus Torvalds unsigned char ibuf[16];
2121da177e4SLinus Torvalds int ibuf_len = 0;
2131da177e4SLinus Torvalds int complete = 0;
2141da177e4SLinus Torvalds int autopoll = 0;
2151da177e4SLinus Torvalds int handled = 0;
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds spin_lock(&macio_lock);
2181da177e4SLinus Torvalds if (in_8(&adb->intr.r) & TAG) {
2191da177e4SLinus Torvalds handled = 1;
220fc21ed8fSHaowen Bai req = current_req;
221fc21ed8fSHaowen Bai if (req) {
2221da177e4SLinus Torvalds /* put the current request in */
2231da177e4SLinus Torvalds for (i = 0; i < req->nbytes; ++i)
2241da177e4SLinus Torvalds out_8(&adb->data[i].r, req->data[i]);
2251da177e4SLinus Torvalds out_8(&adb->dcount.r, req->nbytes & HMB);
2261da177e4SLinus Torvalds req->sent = 1;
2271da177e4SLinus Torvalds if (req->reply_expected) {
2281da177e4SLinus Torvalds out_8(&adb->ctrl.r, DTB + CRE);
2291da177e4SLinus Torvalds } else {
2301da177e4SLinus Torvalds out_8(&adb->ctrl.r, DTB);
2311da177e4SLinus Torvalds current_req = req->next;
2321da177e4SLinus Torvalds complete = 1;
2331da177e4SLinus Torvalds if (current_req)
2341da177e4SLinus Torvalds out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds out_8(&adb->intr.r, 0);
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds if (in_8(&adb->intr.r) & DFB) {
2411da177e4SLinus Torvalds handled = 1;
2421da177e4SLinus Torvalds err = in_8(&adb->error.r);
2431da177e4SLinus Torvalds if (current_req && current_req->sent) {
2441da177e4SLinus Torvalds /* this is the response to a command */
2451da177e4SLinus Torvalds req = current_req;
2461da177e4SLinus Torvalds if (err == 0) {
2471da177e4SLinus Torvalds req->reply_len = in_8(&adb->dcount.r) & HMB;
2481da177e4SLinus Torvalds for (i = 0; i < req->reply_len; ++i)
2491da177e4SLinus Torvalds req->reply[i] = in_8(&adb->data[i].r);
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds current_req = req->next;
2521da177e4SLinus Torvalds complete = 1;
2531da177e4SLinus Torvalds if (current_req)
2541da177e4SLinus Torvalds out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
2551da177e4SLinus Torvalds } else if (err == 0) {
2561da177e4SLinus Torvalds /* autopoll data */
2571da177e4SLinus Torvalds n = in_8(&adb->dcount.r) & HMB;
2581da177e4SLinus Torvalds for (i = 0; i < n; ++i)
2591da177e4SLinus Torvalds ibuf[i] = in_8(&adb->data[i].r);
2601da177e4SLinus Torvalds ibuf_len = n;
2611da177e4SLinus Torvalds autopoll = (in_8(&adb->dcount.r) & APD) != 0;
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds out_8(&adb->error.r, 0);
2641da177e4SLinus Torvalds out_8(&adb->intr.r, 0);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds spin_unlock(&macio_lock);
2671da177e4SLinus Torvalds if (complete && req) {
2681da177e4SLinus Torvalds void (*done)(struct adb_request *) = req->done;
2691da177e4SLinus Torvalds mb();
2701da177e4SLinus Torvalds req->complete = 1;
2711da177e4SLinus Torvalds /* Here, we assume that if the request has a done member, the
2721da177e4SLinus Torvalds * struct request will survive to setting req->complete to 1
2731da177e4SLinus Torvalds */
2741da177e4SLinus Torvalds if (done)
2751da177e4SLinus Torvalds (*done)(req);
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds if (ibuf_len)
2787d12e780SDavid Howells adb_input(ibuf, ibuf_len, autopoll);
2791da177e4SLinus Torvalds
2801da177e4SLinus Torvalds return IRQ_RETVAL(handled);
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds
macio_adb_poll(void)2831da177e4SLinus Torvalds static void macio_adb_poll(void)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds unsigned long flags;
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds local_irq_save(flags);
2881da177e4SLinus Torvalds if (in_8(&adb->intr.r) != 0)
2899da3b1adSAl Viro macio_adb_interrupt(0, NULL);
2901da177e4SLinus Torvalds local_irq_restore(flags);
2911da177e4SLinus Torvalds }
292