160727d8bSWarner Losh /*- 2321fd460SPeter Grehan * Copyright 2004 by Peter Grehan. All rights reserved. 3321fd460SPeter Grehan * 4321fd460SPeter Grehan * Redistribution and use in source and binary forms, with or without 5321fd460SPeter Grehan * modification, are permitted provided that the following conditions 6321fd460SPeter Grehan * are met: 7321fd460SPeter Grehan * 1. Redistributions of source code must retain the above copyright 8321fd460SPeter Grehan * notice, this list of conditions and the following disclaimer. 9321fd460SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 10321fd460SPeter Grehan * notice, this list of conditions and the following disclaimer in the 11321fd460SPeter Grehan * documentation and/or other materials provided with the distribution. 12321fd460SPeter Grehan * 3. The name of the author may not be used to endorse or promote products 13321fd460SPeter Grehan * derived from this software without specific prior written permission. 14321fd460SPeter Grehan * 15321fd460SPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16321fd460SPeter Grehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17321fd460SPeter Grehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18321fd460SPeter Grehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19321fd460SPeter Grehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20321fd460SPeter Grehan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21321fd460SPeter Grehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22321fd460SPeter Grehan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23321fd460SPeter Grehan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24321fd460SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25321fd460SPeter Grehan * SUCH DAMAGE. 26321fd460SPeter Grehan * 27321fd460SPeter Grehan */ 28321fd460SPeter Grehan #include <sys/cdefs.h> 29321fd460SPeter Grehan __FBSDID("$FreeBSD$"); 30321fd460SPeter Grehan 31321fd460SPeter Grehan /* 32321fd460SPeter Grehan * Mac 'Kauai' PCI ATA controller 33321fd460SPeter Grehan */ 34321fd460SPeter Grehan #include "opt_ata.h" 35321fd460SPeter Grehan #include <sys/param.h> 36321fd460SPeter Grehan #include <sys/systm.h> 37321fd460SPeter Grehan #include <sys/kernel.h> 38321fd460SPeter Grehan #include <sys/module.h> 39321fd460SPeter Grehan #include <sys/bus.h> 40321fd460SPeter Grehan #include <sys/malloc.h> 41321fd460SPeter Grehan #include <sys/sema.h> 42321fd460SPeter Grehan #include <sys/taskqueue.h> 43321fd460SPeter Grehan #include <vm/uma.h> 44321fd460SPeter Grehan #include <machine/stdarg.h> 45321fd460SPeter Grehan #include <machine/resource.h> 46321fd460SPeter Grehan #include <machine/bus.h> 47321fd460SPeter Grehan #include <sys/rman.h> 48321fd460SPeter Grehan #include <sys/ata.h> 49321fd460SPeter Grehan #include <dev/ata/ata-all.h> 5098cbfce5SPeter Grehan #include <ata_if.h> 51321fd460SPeter Grehan 52321fd460SPeter Grehan #include <dev/ofw/openfirm.h> 53321fd460SPeter Grehan 54321fd460SPeter Grehan #include <dev/pci/pcivar.h> 55321fd460SPeter Grehan #include <dev/pci/pcireg.h> 56321fd460SPeter Grehan 57321fd460SPeter Grehan #define ATA_KAUAI_REGOFFSET 0x2000 5880bd99beSPeter Grehan 5980bd99beSPeter Grehan /* 6080bd99beSPeter Grehan * Offset to alt-control register from base 6180bd99beSPeter Grehan */ 6280bd99beSPeter Grehan #define ATA_KAUAI_ALTOFFSET (ATA_KAUAI_REGOFFSET + 0x160) 6380bd99beSPeter Grehan 6480bd99beSPeter Grehan /* 6580bd99beSPeter Grehan * Define the gap between registers 6680bd99beSPeter Grehan */ 6780bd99beSPeter Grehan #define ATA_KAUAI_REGGAP 16 68321fd460SPeter Grehan 69321fd460SPeter Grehan /* 70321fd460SPeter Grehan * Define the kauai pci bus attachment. 71321fd460SPeter Grehan */ 72321fd460SPeter Grehan static int ata_kauai_probe(device_t dev); 7398cbfce5SPeter Grehan static void ata_kauai_setmode(device_t parent, device_t dev); 74321fd460SPeter Grehan 75321fd460SPeter Grehan static device_method_t ata_kauai_methods[] = { 76321fd460SPeter Grehan /* Device interface */ 77321fd460SPeter Grehan DEVMETHOD(device_probe, ata_kauai_probe), 78321fd460SPeter Grehan DEVMETHOD(device_attach, ata_attach), 79321fd460SPeter Grehan DEVMETHOD(device_detach, bus_generic_detach), 80321fd460SPeter Grehan DEVMETHOD(device_shutdown, bus_generic_shutdown), 81321fd460SPeter Grehan DEVMETHOD(device_suspend, bus_generic_suspend), 82321fd460SPeter Grehan DEVMETHOD(device_resume, bus_generic_resume), 83321fd460SPeter Grehan 8498cbfce5SPeter Grehan /* ATA interface */ 8598cbfce5SPeter Grehan DEVMETHOD(ata_setmode, ata_kauai_setmode), 86321fd460SPeter Grehan { 0, 0 } 87321fd460SPeter Grehan }; 88321fd460SPeter Grehan 89321fd460SPeter Grehan static driver_t ata_kauai_driver = { 90321fd460SPeter Grehan "ata", 91321fd460SPeter Grehan ata_kauai_methods, 92321fd460SPeter Grehan sizeof(struct ata_channel), 93321fd460SPeter Grehan }; 94321fd460SPeter Grehan 95321fd460SPeter Grehan DRIVER_MODULE(ata, pci, ata_kauai_driver, ata_devclass, 0, 0); 9605a016a3SPeter Grehan MODULE_DEPEND(ata, ata, 1, 1, 1); 97321fd460SPeter Grehan 98321fd460SPeter Grehan /* 99321fd460SPeter Grehan * PCI ID search table 100321fd460SPeter Grehan */ 101321fd460SPeter Grehan static struct kauai_pci_dev { 102321fd460SPeter Grehan u_int32_t kpd_devid; 103321fd460SPeter Grehan char *kpd_desc; 104321fd460SPeter Grehan } kauai_pci_devlist[] = { 105321fd460SPeter Grehan { 0x0033106b, "Uninorth2 Kauai ATA Controller" }, 106321fd460SPeter Grehan { 0x003b106b, "Intrepid Kauai ATA Controller" }, 107321fd460SPeter Grehan { 0x0043106b, "K2 Kauai ATA Controller" }, 108321fd460SPeter Grehan { 0, NULL } 109321fd460SPeter Grehan }; 110321fd460SPeter Grehan 111321fd460SPeter Grehan static int 112321fd460SPeter Grehan ata_kauai_probe(device_t dev) 113321fd460SPeter Grehan { 114321fd460SPeter Grehan struct ata_channel *ch; 115321fd460SPeter Grehan struct resource *mem; 116321fd460SPeter Grehan u_long startp, countp; 117321fd460SPeter Grehan u_int32_t devid; 118321fd460SPeter Grehan int i, found, rid, status; 119321fd460SPeter Grehan 120321fd460SPeter Grehan found = 0; 121321fd460SPeter Grehan devid = pci_get_devid(dev); 122321fd460SPeter Grehan for (i = 0; kauai_pci_devlist[i].kpd_desc != NULL; i++) { 123321fd460SPeter Grehan if (devid == kauai_pci_devlist[i].kpd_devid) { 124321fd460SPeter Grehan found = 1; 125321fd460SPeter Grehan device_set_desc(dev, kauai_pci_devlist[i].kpd_desc); 126321fd460SPeter Grehan } 127321fd460SPeter Grehan } 128321fd460SPeter Grehan 129321fd460SPeter Grehan if (!found) 130321fd460SPeter Grehan return (ENXIO); 131321fd460SPeter Grehan 132321fd460SPeter Grehan /* 133321fd460SPeter Grehan * This device seems to ignore writes to the interrupt 134321fd460SPeter Grehan * config register, resulting in interrupt resources 135321fd460SPeter Grehan * not being attached. If this is the case, use 136321fd460SPeter Grehan * Open Firmware to determine the irq, and then attach 137321fd460SPeter Grehan * the resource. This allows the ATA common code to 138321fd460SPeter Grehan * allocate the irq. 139321fd460SPeter Grehan */ 140321fd460SPeter Grehan status = bus_get_resource(dev, SYS_RES_IRQ, 0, &startp, &countp); 141321fd460SPeter Grehan if (status == ENOENT) { 142321fd460SPeter Grehan int irq; 143321fd460SPeter Grehan 144321fd460SPeter Grehan /* 145321fd460SPeter Grehan * Aargh, hideous hack until ofw pci intr routine is 146321fd460SPeter Grehan * exported 147321fd460SPeter Grehan */ 148321fd460SPeter Grehan irq = 39; /* XXX */ 149321fd460SPeter Grehan bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 150321fd460SPeter Grehan 151321fd460SPeter Grehan /* 152321fd460SPeter Grehan * Sanity check... 153321fd460SPeter Grehan */ 154321fd460SPeter Grehan status = bus_get_resource(dev, SYS_RES_IRQ, 0, &startp, 155321fd460SPeter Grehan &countp); 156321fd460SPeter Grehan if (status == ENOENT || 157321fd460SPeter Grehan startp != 39) { 158321fd460SPeter Grehan printf("kauai irq not set!\n"); 159321fd460SPeter Grehan return (ENXIO); 160321fd460SPeter Grehan } 161321fd460SPeter Grehan } 162321fd460SPeter Grehan 163321fd460SPeter Grehan ch = device_get_softc(dev); 16450069af1SPeter Grehan bzero(ch, sizeof(struct ata_channel)); 165321fd460SPeter Grehan 16680bd99beSPeter Grehan rid = PCIR_BARS; 1672e428c54SPeter Grehan mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 168321fd460SPeter Grehan if (mem == NULL) { 169321fd460SPeter Grehan device_printf(dev, "could not allocate memory\n"); 170321fd460SPeter Grehan return (ENXIO); 171321fd460SPeter Grehan } 172321fd460SPeter Grehan 173321fd460SPeter Grehan /* 174321fd460SPeter Grehan * Set up the resource vectors 175321fd460SPeter Grehan */ 1765a276744SPeter Grehan for (i = ATA_DATA; i <= ATA_COMMAND; i++) { 177321fd460SPeter Grehan ch->r_io[i].res = mem; 17880bd99beSPeter Grehan ch->r_io[i].offset = i*ATA_KAUAI_REGGAP + ATA_KAUAI_REGOFFSET; 179321fd460SPeter Grehan } 180a378bbabSPeter Grehan ch->r_io[ATA_CONTROL].res = mem; 181a378bbabSPeter Grehan ch->r_io[ATA_CONTROL].offset = ATA_KAUAI_ALTOFFSET; 1826ac8f17eSPeter Grehan ata_default_registers(dev); 183321fd460SPeter Grehan 184321fd460SPeter Grehan ch->unit = 0; 185321fd460SPeter Grehan ch->flags |= ATA_USE_16BIT|ATA_NO_SLAVE; 1866ac8f17eSPeter Grehan ata_generic_hw(dev); 187321fd460SPeter Grehan 188321fd460SPeter Grehan return (ata_probe(dev)); 189321fd460SPeter Grehan } 190321fd460SPeter Grehan 19198cbfce5SPeter Grehan static void 19298cbfce5SPeter Grehan ata_kauai_setmode(device_t parent, device_t dev) 19398cbfce5SPeter Grehan { 19498cbfce5SPeter Grehan struct ata_device *atadev = device_get_softc(dev); 19598cbfce5SPeter Grehan 19698cbfce5SPeter Grehan /* TODO bang kauai speed register */ 19798cbfce5SPeter Grehan atadev->mode = ATA_PIO; 19898cbfce5SPeter Grehan } 199