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