ata_kauai.c revision 249213
1139825Simp/*- 2125735Sgrehan * Copyright 2004 by Peter Grehan. All rights reserved. 3125735Sgrehan * 4125735Sgrehan * Redistribution and use in source and binary forms, with or without 5125735Sgrehan * modification, are permitted provided that the following conditions 6125735Sgrehan * are met: 7125735Sgrehan * 1. Redistributions of source code must retain the above copyright 8125735Sgrehan * notice, this list of conditions and the following disclaimer. 9125735Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 10125735Sgrehan * notice, this list of conditions and the following disclaimer in the 11125735Sgrehan * documentation and/or other materials provided with the distribution. 12125735Sgrehan * 3. The name of the author may not be used to endorse or promote products 13125735Sgrehan * derived from this software without specific prior written permission. 14125735Sgrehan * 15125735Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16125735Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17125735Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18125735Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19125735Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20125735Sgrehan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21125735Sgrehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22125735Sgrehan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23125735Sgrehan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24125735Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25125735Sgrehan * SUCH DAMAGE. 26125735Sgrehan * 27125735Sgrehan */ 28125735Sgrehan#include <sys/cdefs.h> 29125735Sgrehan__FBSDID("$FreeBSD: head/sys/powerpc/powermac/ata_kauai.c 249213 2013-04-06 19:12:49Z marius $"); 30125735Sgrehan 31125735Sgrehan/* 32125735Sgrehan * Mac 'Kauai' PCI ATA controller 33125735Sgrehan */ 34125735Sgrehan#include <sys/param.h> 35125735Sgrehan#include <sys/systm.h> 36125735Sgrehan#include <sys/kernel.h> 37125735Sgrehan#include <sys/module.h> 38125735Sgrehan#include <sys/bus.h> 39125735Sgrehan#include <sys/malloc.h> 40125735Sgrehan#include <sys/sema.h> 41125735Sgrehan#include <sys/taskqueue.h> 42125735Sgrehan#include <vm/uma.h> 43125735Sgrehan#include <machine/stdarg.h> 44125735Sgrehan#include <machine/resource.h> 45125735Sgrehan#include <machine/bus.h> 46125735Sgrehan#include <sys/rman.h> 47125735Sgrehan#include <sys/ata.h> 48125735Sgrehan#include <dev/ata/ata-all.h> 49144457Sgrehan#include <ata_if.h> 50125735Sgrehan 51125735Sgrehan#include <dev/ofw/openfirm.h> 52183882Snwhitehorn#include <dev/ofw/ofw_bus.h> 53183409Snwhitehorn#include <machine/intr_machdep.h> 54125735Sgrehan 55125735Sgrehan#include <dev/pci/pcivar.h> 56125735Sgrehan#include <dev/pci/pcireg.h> 57125735Sgrehan 58183409Snwhitehorn#include "ata_dbdma.h" 59183409Snwhitehorn 60125735Sgrehan#define ATA_KAUAI_REGOFFSET 0x2000 61183409Snwhitehorn#define ATA_KAUAI_DBDMAOFFSET 0x1000 62125735Sgrehan 63125735Sgrehan/* 64126394Sgrehan * Offset to alt-control register from base 65126394Sgrehan */ 66126394Sgrehan#define ATA_KAUAI_ALTOFFSET (ATA_KAUAI_REGOFFSET + 0x160) 67126394Sgrehan 68126394Sgrehan/* 69126394Sgrehan * Define the gap between registers 70126394Sgrehan */ 71126394Sgrehan#define ATA_KAUAI_REGGAP 16 72126394Sgrehan 73126394Sgrehan/* 74183409Snwhitehorn * PIO and DMA access registers 75183409Snwhitehorn */ 76183409Snwhitehorn#define PIO_CONFIG_REG (ATA_KAUAI_REGOFFSET + 0x200) 77183409Snwhitehorn#define UDMA_CONFIG_REG (ATA_KAUAI_REGOFFSET + 0x210) 78183409Snwhitehorn#define DMA_IRQ_REG (ATA_KAUAI_REGOFFSET + 0x300) 79183409Snwhitehorn 80183409Snwhitehorn#define USE_DBDMA_IRQ 0 81183409Snwhitehorn 82183409Snwhitehorn/* 83125735Sgrehan * Define the kauai pci bus attachment. 84125735Sgrehan */ 85125735Sgrehanstatic int ata_kauai_probe(device_t dev); 86183409Snwhitehornstatic int ata_kauai_attach(device_t dev); 87200171Smavstatic int ata_kauai_setmode(device_t dev, int target, int mode); 88183409Snwhitehornstatic int ata_kauai_begin_transaction(struct ata_request *request); 89125735Sgrehan 90125735Sgrehanstatic device_method_t ata_kauai_methods[] = { 91125735Sgrehan /* Device interface */ 92125735Sgrehan DEVMETHOD(device_probe, ata_kauai_probe), 93183409Snwhitehorn DEVMETHOD(device_attach, ata_kauai_attach), 94125735Sgrehan DEVMETHOD(device_detach, bus_generic_detach), 95125735Sgrehan DEVMETHOD(device_shutdown, bus_generic_shutdown), 96125735Sgrehan DEVMETHOD(device_suspend, bus_generic_suspend), 97125735Sgrehan DEVMETHOD(device_resume, bus_generic_resume), 98125735Sgrehan 99144457Sgrehan /* ATA interface */ 100144457Sgrehan DEVMETHOD(ata_setmode, ata_kauai_setmode), 101249213Smarius DEVMETHOD_END 102125735Sgrehan}; 103125735Sgrehan 104183409Snwhitehornstruct ata_kauai_softc { 105183409Snwhitehorn struct ata_dbdma_channel sc_ch; 106183409Snwhitehorn 107183409Snwhitehorn struct resource *sc_memr; 108183409Snwhitehorn 109183409Snwhitehorn int shasta; 110183409Snwhitehorn 111183409Snwhitehorn uint32_t udmaconf[2]; 112183409Snwhitehorn uint32_t wdmaconf[2]; 113183409Snwhitehorn uint32_t pioconf[2]; 114183409Snwhitehorn}; 115183409Snwhitehorn 116125735Sgrehanstatic driver_t ata_kauai_driver = { 117125735Sgrehan "ata", 118125735Sgrehan ata_kauai_methods, 119183409Snwhitehorn sizeof(struct ata_kauai_softc), 120125735Sgrehan}; 121125735Sgrehan 122249213SmariusDRIVER_MODULE(ata, pci, ata_kauai_driver, ata_devclass, NULL, NULL); 123144359SgrehanMODULE_DEPEND(ata, ata, 1, 1, 1); 124125735Sgrehan 125125735Sgrehan/* 126125735Sgrehan * PCI ID search table 127125735Sgrehan */ 128249213Smariusstatic const struct kauai_pci_dev { 129249213Smarius u_int32_t kpd_devid; 130249213Smarius const char *kpd_desc; 131125735Sgrehan} kauai_pci_devlist[] = { 132125735Sgrehan { 0x0033106b, "Uninorth2 Kauai ATA Controller" }, 133125735Sgrehan { 0x003b106b, "Intrepid Kauai ATA Controller" }, 134125735Sgrehan { 0x0043106b, "K2 Kauai ATA Controller" }, 135183409Snwhitehorn { 0x0050106b, "Shasta Kauai ATA Controller" }, 136175668Sjulian { 0x0069106b, "Intrepid-2 Kauai ATA Controller" }, 137125735Sgrehan { 0, NULL } 138125735Sgrehan}; 139125735Sgrehan 140183409Snwhitehorn/* 141183409Snwhitehorn * IDE transfer timings 142183409Snwhitehorn */ 143183409Snwhitehorn#define KAUAI_PIO_MASK 0xff000fff 144183409Snwhitehorn#define KAUAI_DMA_MASK 0x00fff000 145183409Snwhitehorn#define KAUAI_UDMA_MASK 0x0000ffff 146183409Snwhitehorn 147183409Snwhitehornstatic const u_int pio_timing_kauai[] = { 148183409Snwhitehorn 0x08000a92, /* PIO0 */ 149183409Snwhitehorn 0x0800060f, /* PIO1 */ 150183409Snwhitehorn 0x0800038b, /* PIO2 */ 151183409Snwhitehorn 0x05000249, /* PIO3 */ 152183409Snwhitehorn 0x04000148 /* PIO4 */ 153183409Snwhitehorn}; 154249213Smarius 155183409Snwhitehornstatic const u_int pio_timing_shasta[] = { 156183409Snwhitehorn 0x0a000c97, /* PIO0 */ 157183409Snwhitehorn 0x07000712, /* PIO1 */ 158183409Snwhitehorn 0x040003cd, /* PIO2 */ 159183409Snwhitehorn 0x0400028b, /* PIO3 */ 160183409Snwhitehorn 0x0400010a /* PIO4 */ 161183409Snwhitehorn}; 162183409Snwhitehorn 163183409Snwhitehornstatic const u_int dma_timing_kauai[] = { 164183409Snwhitehorn 0x00618000, /* WDMA0 */ 165183409Snwhitehorn 0x00209000, /* WDMA1 */ 166183409Snwhitehorn 0x00148000 /* WDMA2 */ 167183409Snwhitehorn}; 168249213Smarius 169183409Snwhitehornstatic const u_int dma_timing_shasta[] = { 170183409Snwhitehorn 0x00820800, /* WDMA0 */ 171183409Snwhitehorn 0x0028b000, /* WDMA1 */ 172183409Snwhitehorn 0x001ca000 /* WDMA2 */ 173183409Snwhitehorn}; 174183409Snwhitehorn 175183409Snwhitehornstatic const u_int udma_timing_kauai[] = { 176183409Snwhitehorn 0x000070c1, /* UDMA0 */ 177183409Snwhitehorn 0x00005d81, /* UDMA1 */ 178183409Snwhitehorn 0x00004a61, /* UDMA2 */ 179183409Snwhitehorn 0x00003a51, /* UDMA3 */ 180183409Snwhitehorn 0x00002a31, /* UDMA4 */ 181183409Snwhitehorn 0x00002921 /* UDMA5 */ 182183409Snwhitehorn}; 183249213Smarius 184183409Snwhitehornstatic const u_int udma_timing_shasta[] = { 185183409Snwhitehorn 0x00035901, /* UDMA0 */ 186183409Snwhitehorn 0x000348b1, /* UDMA1 */ 187183409Snwhitehorn 0x00033881, /* UDMA2 */ 188183409Snwhitehorn 0x00033861, /* UDMA3 */ 189183409Snwhitehorn 0x00033841, /* UDMA4 */ 190183409Snwhitehorn 0x00033031, /* UDMA5 */ 191183409Snwhitehorn 0x00033021 /* UDMA6 */ 192183409Snwhitehorn}; 193183409Snwhitehorn 194125735Sgrehanstatic int 195125735Sgrehanata_kauai_probe(device_t dev) 196125735Sgrehan{ 197125735Sgrehan struct ata_channel *ch; 198183409Snwhitehorn struct ata_kauai_softc *sc; 199125735Sgrehan u_int32_t devid; 200183409Snwhitehorn phandle_t node; 201183882Snwhitehorn const char *compatstring = NULL; 202183882Snwhitehorn int i, found, rid; 203125735Sgrehan 204125735Sgrehan found = 0; 205125735Sgrehan devid = pci_get_devid(dev); 206125735Sgrehan for (i = 0; kauai_pci_devlist[i].kpd_desc != NULL; i++) { 207125735Sgrehan if (devid == kauai_pci_devlist[i].kpd_devid) { 208125735Sgrehan found = 1; 209125735Sgrehan device_set_desc(dev, kauai_pci_devlist[i].kpd_desc); 210125735Sgrehan } 211125735Sgrehan } 212125735Sgrehan 213125735Sgrehan if (!found) 214125735Sgrehan return (ENXIO); 215125735Sgrehan 216183882Snwhitehorn node = ofw_bus_get_node(dev); 217183409Snwhitehorn sc = device_get_softc(dev); 218183409Snwhitehorn bzero(sc, sizeof(struct ata_kauai_softc)); 219183409Snwhitehorn ch = &sc->sc_ch.sc_ch; 220183409Snwhitehorn 221183882Snwhitehorn compatstring = ofw_bus_get_compat(dev); 222217756Snwhitehorn if (compatstring != NULL && strcmp(compatstring,"shasta-ata") == 0) 223183409Snwhitehorn sc->shasta = 1; 224183409Snwhitehorn 225208168Snwhitehorn /* Pre-K2 controllers apparently need this hack */ 226208168Snwhitehorn if (!sc->shasta && 227208168Snwhitehorn (compatstring == NULL || strcmp(compatstring, "K2-UATA") != 0)) 228183882Snwhitehorn bus_set_resource(dev, SYS_RES_IRQ, 0, 39, 1); 229183409Snwhitehorn 230126394Sgrehan rid = PCIR_BARS; 231183409Snwhitehorn sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 232183409Snwhitehorn RF_ACTIVE); 233183409Snwhitehorn if (sc->sc_memr == NULL) { 234125735Sgrehan device_printf(dev, "could not allocate memory\n"); 235125735Sgrehan return (ENXIO); 236125735Sgrehan } 237125735Sgrehan 238125735Sgrehan /* 239125735Sgrehan * Set up the resource vectors 240125735Sgrehan */ 241145221Sgrehan for (i = ATA_DATA; i <= ATA_COMMAND; i++) { 242183409Snwhitehorn ch->r_io[i].res = sc->sc_memr; 243126394Sgrehan ch->r_io[i].offset = i*ATA_KAUAI_REGGAP + ATA_KAUAI_REGOFFSET; 244125735Sgrehan } 245183409Snwhitehorn ch->r_io[ATA_CONTROL].res = sc->sc_memr; 246145311Sgrehan ch->r_io[ATA_CONTROL].offset = ATA_KAUAI_ALTOFFSET; 247145772Sgrehan ata_default_registers(dev); 248125735Sgrehan 249217756Snwhitehorn ch->unit = 0; 250217756Snwhitehorn ch->flags |= ATA_USE_16BIT; 251217756Snwhitehorn 252217756Snwhitehorn /* XXX: ATAPI DMA is unreliable. We should find out why. */ 253217756Snwhitehorn ch->flags |= ATA_NO_ATAPI_DMA; 254145772Sgrehan ata_generic_hw(dev); 255125735Sgrehan 256125735Sgrehan return (ata_probe(dev)); 257125735Sgrehan} 258125735Sgrehan 259183409Snwhitehorn#if USE_DBDMA_IRQ 260183409Snwhitehornstatic int 261183409Snwhitehornata_kauai_dma_interrupt(struct ata_kauai_softc *sc) 262183409Snwhitehorn{ 263183409Snwhitehorn /* Clear the DMA interrupt bits */ 264183409Snwhitehorn 265183409Snwhitehorn bus_write_4(sc->sc_memr, DMA_IRQ_REG, 0x80000000); 266183409Snwhitehorn 267183409Snwhitehorn return ata_interrupt(sc); 268183409Snwhitehorn} 269183409Snwhitehorn#endif 270183409Snwhitehorn 271183409Snwhitehornstatic int 272183409Snwhitehornata_kauai_attach(device_t dev) 273183409Snwhitehorn{ 274183409Snwhitehorn struct ata_kauai_softc *sc = device_get_softc(dev); 275183409Snwhitehorn#if USE_DBDMA_IRQ 276183409Snwhitehorn int dbdma_irq_rid = 1; 277183409Snwhitehorn struct resource *dbdma_irq; 278183409Snwhitehorn void *cookie; 279183409Snwhitehorn#endif 280183409Snwhitehorn 281183409Snwhitehorn pci_enable_busmaster(dev); 282183409Snwhitehorn 283183409Snwhitehorn /* Init DMA engine */ 284183409Snwhitehorn 285183409Snwhitehorn sc->sc_ch.dbdma_rid = 1; 286183409Snwhitehorn sc->sc_ch.dbdma_regs = sc->sc_memr; 287183409Snwhitehorn sc->sc_ch.dbdma_offset = ATA_KAUAI_DBDMAOFFSET; 288183409Snwhitehorn 289183409Snwhitehorn ata_dbdma_dmainit(dev); 290183409Snwhitehorn 291183409Snwhitehorn#if USE_DBDMA_IRQ 292183409Snwhitehorn /* Bind to DBDMA interrupt as well */ 293183409Snwhitehorn if ((dbdma_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 294183409Snwhitehorn &dbdma_irq_rid, RF_SHAREABLE | RF_ACTIVE)) != NULL) { 295183409Snwhitehorn bus_setup_intr(dev, dbdma_irq, ATA_INTR_FLAGS, NULL, 296183409Snwhitehorn (driver_intr_t *)ata_kauai_dma_interrupt, sc,&cookie); 297183409Snwhitehorn } 298183409Snwhitehorn#endif 299183409Snwhitehorn 300183409Snwhitehorn /* Set up initial mode */ 301184314Snwhitehorn sc->pioconf[0] = sc->pioconf[1] = 302184314Snwhitehorn bus_read_4(sc->sc_memr, PIO_CONFIG_REG) & 0x0f000fff; 303183409Snwhitehorn 304183409Snwhitehorn sc->udmaconf[0] = sc->udmaconf[1] = 0; 305183409Snwhitehorn sc->wdmaconf[0] = sc->wdmaconf[1] = 0; 306183409Snwhitehorn 307183409Snwhitehorn /* Magic FCR value from Apple */ 308183409Snwhitehorn bus_write_4(sc->sc_memr, 0, 0x00000007); 309183409Snwhitehorn 310183409Snwhitehorn /* Set begin_transaction */ 311183409Snwhitehorn sc->sc_ch.sc_ch.hw.begin_transaction = ata_kauai_begin_transaction; 312183409Snwhitehorn 313183409Snwhitehorn return ata_attach(dev); 314183409Snwhitehorn} 315183409Snwhitehorn 316200171Smavstatic int 317200171Smavata_kauai_setmode(device_t dev, int target, int mode) 318144457Sgrehan{ 319200171Smav struct ata_kauai_softc *sc = device_get_softc(dev); 320144457Sgrehan 321200171Smav mode = min(mode,sc->shasta ? ATA_UDMA6 : ATA_UDMA5); 322183409Snwhitehorn 323183409Snwhitehorn if (sc->shasta) { 324183409Snwhitehorn switch (mode & ATA_DMA_MASK) { 325183409Snwhitehorn case ATA_UDMA0: 326200171Smav sc->udmaconf[target] 327183409Snwhitehorn = udma_timing_shasta[mode & ATA_MODE_MASK]; 328183409Snwhitehorn break; 329183409Snwhitehorn case ATA_WDMA0: 330200171Smav sc->udmaconf[target] = 0; 331200171Smav sc->wdmaconf[target] 332183409Snwhitehorn = dma_timing_shasta[mode & ATA_MODE_MASK]; 333183409Snwhitehorn break; 334183409Snwhitehorn default: 335200171Smav sc->pioconf[target] 336183409Snwhitehorn = pio_timing_shasta[(mode & ATA_MODE_MASK) - 337183409Snwhitehorn ATA_PIO0]; 338183409Snwhitehorn break; 339183409Snwhitehorn } 340183409Snwhitehorn } else { 341183409Snwhitehorn switch (mode & ATA_DMA_MASK) { 342183409Snwhitehorn case ATA_UDMA0: 343200171Smav sc->udmaconf[target] 344183409Snwhitehorn = udma_timing_kauai[mode & ATA_MODE_MASK]; 345183409Snwhitehorn break; 346183409Snwhitehorn case ATA_WDMA0: 347200171Smav sc->udmaconf[target] = 0; 348200171Smav sc->wdmaconf[target] 349183409Snwhitehorn = dma_timing_kauai[mode & ATA_MODE_MASK]; 350183409Snwhitehorn break; 351183409Snwhitehorn default: 352200171Smav sc->pioconf[target] 353183409Snwhitehorn = pio_timing_kauai[(mode & ATA_MODE_MASK) 354183409Snwhitehorn - ATA_PIO0]; 355183409Snwhitehorn break; 356183409Snwhitehorn } 357183409Snwhitehorn } 358200171Smav 359200171Smav return (mode); 360144457Sgrehan} 361183409Snwhitehorn 362183409Snwhitehornstatic int 363183409Snwhitehornata_kauai_begin_transaction(struct ata_request *request) 364183409Snwhitehorn{ 365183409Snwhitehorn struct ata_kauai_softc *sc = device_get_softc(request->parent); 366183409Snwhitehorn 367200171Smav bus_write_4(sc->sc_memr, UDMA_CONFIG_REG, sc->udmaconf[request->unit]); 368183409Snwhitehorn bus_write_4(sc->sc_memr, PIO_CONFIG_REG, 369200171Smav sc->wdmaconf[request->unit] | sc->pioconf[request->unit]); 370183409Snwhitehorn 371183409Snwhitehorn return ata_begin_transaction(request); 372183409Snwhitehorn} 373