160484Sobrien// SPDX-License-Identifier: GPL-2.0
2218822Sdim/*
3218822Sdim * Driver for the ADB controller in the Mac I/O (Hydra) chip.
460484Sobrien */
560484Sobrien#include <linux/types.h>
680016Sobrien#include <linux/errno.h>
760484Sobrien#include <linux/kernel.h>
860484Sobrien#include <linux/delay.h>
960484Sobrien#include <linux/spinlock.h>
1060484Sobrien#include <linux/interrupt.h>
1160484Sobrien#include <linux/pgtable.h>
1260484Sobrien#include <linux/of.h>
1360484Sobrien#include <linux/of_address.h>
1460484Sobrien#include <linux/of_irq.h>
1560484Sobrien#include <linux/adb.h>
1660484Sobrien
1760484Sobrien#include <asm/io.h>
1860484Sobrien#include <asm/hydra.h>
1960484Sobrien#include <asm/irq.h>
2060484Sobrien#include <linux/init.h>
2160484Sobrien#include <linux/ioport.h>
22218822Sdim
23218822Sdimstruct preg {
2460484Sobrien	unsigned char r;
25130561Sobrien	char pad[15];
2660484Sobrien};
27218822Sdim
28130561Sobrienstruct adb_regs {
29130561Sobrien	struct preg intr;
30130561Sobrien	struct preg data[9];
31130561Sobrien	struct preg intr_enb;
32130561Sobrien	struct preg dcount;
33130561Sobrien	struct preg error;
34130561Sobrien	struct preg ctrl;
35130561Sobrien	struct preg autopoll;
36130561Sobrien	struct preg active_hi;
37130561Sobrien	struct preg active_lo;
38130561Sobrien	struct preg test;
39130561Sobrien};
40130561Sobrien
41130561Sobrien/* Bits in intr and intr_enb registers */
42130561Sobrien#define DFB	1		/* data from bus */
43130561Sobrien#define TAG	2		/* transfer access grant */
44218822Sdim
4560484Sobrien/* Bits in dcount register */
4660484Sobrien#define HMB	0x0f		/* how many bytes */
4760484Sobrien#define APD	0x10		/* auto-poll data */
4860484Sobrien
49218822Sdim/* Bits in error register */
50218822Sdim#define NRE	1		/* no response error */
51218822Sdim#define DLE	2		/* data lost error */
52218822Sdim
53218822Sdim/* Bits in ctrl register */
54218822Sdim#define TAR	1		/* transfer access request */
55218822Sdim#define DTB	2		/* data to bus */
56218822Sdim#define CRE	4		/* command response expected */
57218822Sdim#define ADB_RST	8		/* ADB reset */
58218822Sdim
59218822Sdim/* Bits in autopoll register */
60218822Sdim#define APE	1		/* autopoll enable */
61218822Sdim
62218822Sdimstatic volatile struct adb_regs __iomem *adb;
63218822Sdimstatic struct adb_request *current_req, *last_req;
64218822Sdimstatic DEFINE_SPINLOCK(macio_lock);
65218822Sdim
66218822Sdimstatic int macio_probe(void);
67218822Sdimstatic int macio_init(void);
6860484Sobrienstatic irqreturn_t macio_adb_interrupt(int irq, void *arg);
6960484Sobrienstatic int macio_send_request(struct adb_request *req, int sync);
7060484Sobrienstatic int macio_adb_autopoll(int devs);
71130561Sobrienstatic void macio_adb_poll(void);
7260484Sobrienstatic int macio_adb_reset_bus(void);
7360484Sobrien
7460484Sobrienstruct adb_driver macio_adb_driver = {
7560484Sobrien	.name         = "MACIO",
7660484Sobrien	.probe        = macio_probe,
77218822Sdim	.init         = macio_init,
78218822Sdim	.send_request = macio_send_request,
7960484Sobrien	.autopoll     = macio_adb_autopoll,
8060484Sobrien	.poll         = macio_adb_poll,
8160484Sobrien	.reset_bus    = macio_adb_reset_bus,
8260484Sobrien};
8360484Sobrien
84218822Sdimint macio_probe(void)
85218822Sdim{
86218822Sdim	struct device_node *np;
87218822Sdim
88218822Sdim	np = of_find_compatible_node(NULL, "adb", "chrp,adb0");
89218822Sdim	if (np) {
90218822Sdim		of_node_put(np);
91218822Sdim		return 0;
92218822Sdim	}
93218822Sdim	return -ENODEV;
94218822Sdim}
95218822Sdim
96218822Sdimint macio_init(void)
97218822Sdim{
98218822Sdim	struct device_node *adbs;
99218822Sdim	struct resource r;
100218822Sdim	unsigned int irq;
101218822Sdim
10260484Sobrien	adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0");
10360484Sobrien	if (!adbs)
10460484Sobrien		return -ENXIO;
10560484Sobrien
10660484Sobrien	if (of_address_to_resource(adbs, 0, &r)) {
10760484Sobrien		of_node_put(adbs);
10860484Sobrien		return -ENXIO;
10991041Sobrien	}
11060484Sobrien	adb = ioremap(r.start, sizeof(struct adb_regs));
11191041Sobrien	if (!adb) {
112218822Sdim		of_node_put(adbs);
11391041Sobrien		return -ENOMEM;
114218822Sdim	}
11560484Sobrien
11660484Sobrien	out_8(&adb->ctrl.r, 0);
117104834Sobrien	out_8(&adb->intr.r, 0);
11891041Sobrien	out_8(&adb->error.r, 0);
119104834Sobrien	out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */
12091041Sobrien	out_8(&adb->active_lo.r, 0xff);
12160484Sobrien	out_8(&adb->autopoll.r, APE);
12291041Sobrien
123130561Sobrien	irq = irq_of_parse_and_map(adbs, 0);
12491041Sobrien	of_node_put(adbs);
12591041Sobrien	if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
12691041Sobrien		iounmap(adb);
127130561Sobrien		printk(KERN_ERR "ADB: can't get irq %d\n", irq);
128218822Sdim		return -EAGAIN;
129218822Sdim	}
13091041Sobrien	out_8(&adb->intr_enb.r, DFB | TAG);
13191041Sobrien
132104834Sobrien	printk("adb: mac-io driver 1.0 for unified ADB\n");
13360484Sobrien
134218822Sdim	return 0;
13591041Sobrien}
13689857Sobrien
13791041Sobrienstatic int macio_adb_autopoll(int devs)
13891041Sobrien{
139218822Sdim	unsigned long flags;
140130561Sobrien
14191041Sobrien	spin_lock_irqsave(&macio_lock, flags);
14260484Sobrien	out_8(&adb->active_hi.r, devs >> 8);
14391041Sobrien	out_8(&adb->active_lo.r, devs);
144130561Sobrien	out_8(&adb->autopoll.r, devs? APE: 0);
14591041Sobrien	spin_unlock_irqrestore(&macio_lock, flags);
146218822Sdim	return 0;
14791041Sobrien}
14891041Sobrien
149218822Sdimstatic int macio_adb_reset_bus(void)
15091041Sobrien{
151104834Sobrien	unsigned long flags;
15277298Sobrien	int timeout = 1000000;
15389857Sobrien
154130561Sobrien	/* Hrm... we may want to not lock interrupts for so
15560484Sobrien	 * long ... oh well, who uses that chip anyway ? :)
156130561Sobrien	 * That function will be seldom used during boot
157130561Sobrien	 * on rare machines, so...
15860484Sobrien	 */
159130561Sobrien	spin_lock_irqsave(&macio_lock, flags);
16060484Sobrien	out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST);
161130561Sobrien	while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) {
162218822Sdim		if (--timeout == 0) {
163218822Sdim			out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST);
164218822Sdim			spin_unlock_irqrestore(&macio_lock, flags);
165218822Sdim			return -1;
166218822Sdim		}
167218822Sdim	}
168218822Sdim	spin_unlock_irqrestore(&macio_lock, flags);
169218822Sdim	return 0;
170218822Sdim}
171218822Sdim
172218822Sdim/* Send an ADB command */
173218822Sdimstatic int macio_send_request(struct adb_request *req, int sync)
174218822Sdim{
175218822Sdim	unsigned long flags;
176218822Sdim	int i;
177218822Sdim
178218822Sdim	if (req->data[0] != ADB_PACKET)
179218822Sdim		return -EINVAL;
180218822Sdim
181218822Sdim	for (i = 0; i < req->nbytes - 1; ++i)
182218822Sdim		req->data[i] = req->data[i+1];
183218822Sdim	--req->nbytes;
184218822Sdim
185218822Sdim	req->next = NULL;
186218822Sdim	req->sent = 0;
187218822Sdim	req->complete = 0;
188218822Sdim	req->reply_len = 0;
189218822Sdim
190218822Sdim	spin_lock_irqsave(&macio_lock, flags);
191218822Sdim	if (current_req) {
192218822Sdim		last_req->next = req;
193218822Sdim		last_req = req;
194218822Sdim	} else {
195218822Sdim		current_req = last_req = req;
196218822Sdim		out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
197218822Sdim	}
198218822Sdim	spin_unlock_irqrestore(&macio_lock, flags);
199218822Sdim
200218822Sdim	if (sync) {
201218822Sdim		while (!req->complete)
202218822Sdim			macio_adb_poll();
203218822Sdim	}
20460484Sobrien
205218822Sdim	return 0;
206218822Sdim}
207218822Sdim
208218822Sdimstatic irqreturn_t macio_adb_interrupt(int irq, void *arg)
209218822Sdim{
210218822Sdim	int i, n, err;
211218822Sdim	struct adb_request *req = NULL;
212218822Sdim	unsigned char ibuf[16];
213218822Sdim	int ibuf_len = 0;
214218822Sdim	int complete = 0;
215218822Sdim	int autopoll = 0;
216218822Sdim	int handled = 0;
217218822Sdim
218218822Sdim	spin_lock(&macio_lock);
219218822Sdim	if (in_8(&adb->intr.r) & TAG) {
220218822Sdim		handled = 1;
221218822Sdim		req = current_req;
222218822Sdim		if (req) {
223218822Sdim			/* put the current request in */
224218822Sdim			for (i = 0; i < req->nbytes; ++i)
225218822Sdim				out_8(&adb->data[i].r, req->data[i]);
226218822Sdim			out_8(&adb->dcount.r, req->nbytes & HMB);
227218822Sdim			req->sent = 1;
228218822Sdim			if (req->reply_expected) {
229218822Sdim				out_8(&adb->ctrl.r, DTB + CRE);
230218822Sdim			} else {
231218822Sdim				out_8(&adb->ctrl.r, DTB);
232218822Sdim				current_req = req->next;
233218822Sdim				complete = 1;
234218822Sdim				if (current_req)
235218822Sdim					out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
236218822Sdim			}
237218822Sdim		}
238218822Sdim		out_8(&adb->intr.r, 0);
239218822Sdim	}
240218822Sdim
241218822Sdim	if (in_8(&adb->intr.r) & DFB) {
242130561Sobrien		handled = 1;
243130561Sobrien		err = in_8(&adb->error.r);
24460484Sobrien		if (current_req && current_req->sent) {
24560484Sobrien			/* this is the response to a command */
24660484Sobrien			req = current_req;
24760484Sobrien			if (err == 0) {
24860484Sobrien				req->reply_len = in_8(&adb->dcount.r) & HMB;
249218822Sdim				for (i = 0; i < req->reply_len; ++i)
25060484Sobrien					req->reply[i] = in_8(&adb->data[i].r);
25160484Sobrien			}
25260484Sobrien			current_req = req->next;
25360484Sobrien			complete = 1;
25460484Sobrien			if (current_req)
25560484Sobrien				out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
25660484Sobrien		} else if (err == 0) {
25760484Sobrien			/* autopoll data */
25860484Sobrien			n = in_8(&adb->dcount.r) & HMB;
25960484Sobrien			for (i = 0; i < n; ++i)
26060484Sobrien				ibuf[i] = in_8(&adb->data[i].r);
26160484Sobrien			ibuf_len = n;
262130561Sobrien			autopoll = (in_8(&adb->dcount.r) & APD) != 0;
26360484Sobrien		}
26460484Sobrien		out_8(&adb->error.r, 0);
26560484Sobrien		out_8(&adb->intr.r, 0);
266218822Sdim	}
267218822Sdim	spin_unlock(&macio_lock);
268218822Sdim	if (complete && req) {
269218822Sdim	    void (*done)(struct adb_request *) = req->done;
270218822Sdim	    mb();
27160484Sobrien	    req->complete = 1;
27289857Sobrien	    /* Here, we assume that if the request has a done member, the
27389857Sobrien    	     * struct request will survive to setting req->complete to 1
27489857Sobrien	     */
27589857Sobrien	    if (done)
27689857Sobrien		(*done)(req);
27789857Sobrien	}
27889857Sobrien	if (ibuf_len)
27989857Sobrien		adb_input(ibuf, ibuf_len, autopoll);
28089857Sobrien
28189857Sobrien	return IRQ_RETVAL(handled);
28289857Sobrien}
28389857Sobrien
28489857Sobrienstatic void macio_adb_poll(void)
28589857Sobrien{
28689857Sobrien	unsigned long flags;
28789857Sobrien
288130561Sobrien	local_irq_save(flags);
28960484Sobrien	if (in_8(&adb->intr.r) != 0)
29078828Sobrien		macio_adb_interrupt(0, NULL);
29160484Sobrien	local_irq_restore(flags);
29289857Sobrien}
29360484Sobrien