The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/powermac/ata_kauai.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright 2004 by Peter Grehan. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  * 3. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  */
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 /*
   32  * Mac 'Kauai' PCI ATA controller
   33  */
   34 #include "opt_ata.h"
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/bus.h>
   40 #include <sys/malloc.h>
   41 #include <sys/sema.h>
   42 #include <sys/taskqueue.h>
   43 #include <vm/uma.h>
   44 #include <machine/stdarg.h>
   45 #include <machine/resource.h>
   46 #include <machine/bus.h>
   47 #include <sys/rman.h>
   48 #include <sys/ata.h>
   49 #include <dev/ata/ata-all.h>
   50 #include <ata_if.h>
   51 
   52 #include <dev/ofw/openfirm.h>
   53 #include <dev/ofw/ofw_bus.h>
   54 #include <machine/intr_machdep.h>
   55 
   56 #include <dev/pci/pcivar.h>
   57 #include <dev/pci/pcireg.h>
   58 
   59 #include "ata_dbdma.h"
   60 
   61 #define  ATA_KAUAI_REGOFFSET    0x2000
   62 #define  ATA_KAUAI_DBDMAOFFSET  0x1000
   63 
   64 /*
   65  * Offset to alt-control register from base
   66  */
   67 #define  ATA_KAUAI_ALTOFFSET    (ATA_KAUAI_REGOFFSET + 0x160)
   68 
   69 /*
   70  * Define the gap between registers
   71  */
   72 #define ATA_KAUAI_REGGAP        16
   73 
   74 /*
   75  * PIO and DMA access registers
   76  */
   77 #define PIO_CONFIG_REG  (ATA_KAUAI_REGOFFSET + 0x200)
   78 #define UDMA_CONFIG_REG (ATA_KAUAI_REGOFFSET + 0x210)
   79 #define DMA_IRQ_REG     (ATA_KAUAI_REGOFFSET + 0x300)
   80 
   81 #define USE_DBDMA_IRQ   0
   82 
   83 /*
   84  * Define the kauai pci bus attachment.
   85  */
   86 static  int  ata_kauai_probe(device_t dev);
   87 static  int  ata_kauai_attach(device_t dev);
   88 static  int  ata_kauai_setmode(device_t dev, int target, int mode);
   89 static  int  ata_kauai_begin_transaction(struct ata_request *request);
   90 
   91 static device_method_t ata_kauai_methods[] = {
   92         /* Device interface */
   93         DEVMETHOD(device_probe,         ata_kauai_probe),
   94         DEVMETHOD(device_attach,        ata_kauai_attach),
   95         DEVMETHOD(device_detach,        bus_generic_detach),
   96         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
   97         DEVMETHOD(device_suspend,       bus_generic_suspend),
   98         DEVMETHOD(device_resume,        bus_generic_resume),
   99 
  100         /* ATA interface */
  101         DEVMETHOD(ata_setmode,          ata_kauai_setmode),
  102         DEVMETHOD_END
  103 };
  104 
  105 struct ata_kauai_softc {
  106         struct ata_dbdma_channel sc_ch;
  107 
  108         struct resource *sc_memr;
  109 
  110         int shasta;
  111 
  112         uint32_t udmaconf[2];
  113         uint32_t wdmaconf[2];
  114         uint32_t pioconf[2];
  115 };
  116 
  117 static driver_t ata_kauai_driver = {
  118         "ata",
  119         ata_kauai_methods,
  120         sizeof(struct ata_kauai_softc),
  121 };
  122 
  123 DRIVER_MODULE(ata, pci, ata_kauai_driver, ata_devclass, NULL, NULL);
  124 MODULE_DEPEND(ata, ata, 1, 1, 1);
  125 
  126 /*
  127  * PCI ID search table
  128  */
  129 static const struct kauai_pci_dev {
  130         u_int32_t       kpd_devid;
  131         const char      *kpd_desc;
  132 } kauai_pci_devlist[] = {
  133         { 0x0033106b, "Uninorth2 Kauai ATA Controller" },
  134         { 0x003b106b, "Intrepid Kauai ATA Controller" },
  135         { 0x0043106b, "K2 Kauai ATA Controller" },
  136         { 0x0050106b, "Shasta Kauai ATA Controller" },
  137         { 0x0069106b, "Intrepid-2 Kauai ATA Controller" },
  138         { 0, NULL }
  139 };
  140 
  141 /*
  142  * IDE transfer timings
  143  */
  144 #define KAUAI_PIO_MASK  0xff000fff
  145 #define KAUAI_DMA_MASK  0x00fff000
  146 #define KAUAI_UDMA_MASK 0x0000ffff
  147 
  148 static const u_int pio_timing_kauai[] = {
  149         0x08000a92,     /* PIO0 */
  150         0x0800060f,     /* PIO1 */
  151         0x0800038b,     /* PIO2 */
  152         0x05000249,     /* PIO3 */
  153         0x04000148      /* PIO4 */
  154 };
  155 
  156 static const u_int pio_timing_shasta[] = {
  157         0x0a000c97,     /* PIO0 */
  158         0x07000712,     /* PIO1 */
  159         0x040003cd,     /* PIO2 */
  160         0x0400028b,     /* PIO3 */
  161         0x0400010a      /* PIO4 */
  162 };
  163 
  164 static const u_int dma_timing_kauai[] = {
  165         0x00618000,     /* WDMA0 */
  166         0x00209000,     /* WDMA1 */
  167         0x00148000      /* WDMA2 */
  168 };
  169 
  170 static const u_int dma_timing_shasta[] = {
  171         0x00820800,     /* WDMA0 */
  172         0x0028b000,     /* WDMA1 */
  173         0x001ca000      /* WDMA2 */
  174 };
  175 
  176 static const u_int udma_timing_kauai[] = {
  177         0x000070c1,     /* UDMA0 */
  178         0x00005d81,     /* UDMA1 */
  179         0x00004a61,     /* UDMA2 */
  180         0x00003a51,     /* UDMA3 */
  181         0x00002a31,     /* UDMA4 */
  182         0x00002921      /* UDMA5 */
  183 };
  184 
  185 static const u_int udma_timing_shasta[] = {
  186         0x00035901,     /* UDMA0 */
  187         0x000348b1,     /* UDMA1 */
  188         0x00033881,     /* UDMA2 */
  189         0x00033861,     /* UDMA3 */
  190         0x00033841,     /* UDMA4 */
  191         0x00033031,     /* UDMA5 */
  192         0x00033021      /* UDMA6 */
  193 };
  194 
  195 static int
  196 ata_kauai_probe(device_t dev)
  197 {
  198         struct ata_channel *ch;
  199         struct ata_kauai_softc *sc;
  200         u_int32_t devid;
  201         phandle_t node;
  202         const char *compatstring = NULL;
  203         int i, found, rid;
  204 
  205         found = 0;
  206         devid = pci_get_devid(dev);
  207         for (i = 0; kauai_pci_devlist[i].kpd_desc != NULL; i++) {
  208                 if (devid == kauai_pci_devlist[i].kpd_devid) {
  209                         found = 1;
  210                         device_set_desc(dev, kauai_pci_devlist[i].kpd_desc);
  211                 }
  212         }
  213 
  214         if (!found)
  215                 return (ENXIO);
  216 
  217         node = ofw_bus_get_node(dev);
  218         sc = device_get_softc(dev);
  219         bzero(sc, sizeof(struct ata_kauai_softc));
  220         ch = &sc->sc_ch.sc_ch;
  221 
  222         compatstring = ofw_bus_get_compat(dev);
  223         if (compatstring != NULL && strcmp(compatstring,"shasta-ata") == 0)
  224                 sc->shasta = 1;
  225 
  226         /* Pre-K2 controllers apparently need this hack */
  227         if (!sc->shasta &&
  228             (compatstring == NULL || strcmp(compatstring, "K2-UATA") != 0))
  229                 bus_set_resource(dev, SYS_RES_IRQ, 0, 39, 1);
  230 
  231         rid = PCIR_BARS;
  232         sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
  233             RF_ACTIVE);
  234         if (sc->sc_memr == NULL) {
  235                 device_printf(dev, "could not allocate memory\n");
  236                 return (ENXIO);
  237         }
  238 
  239         /*
  240          * Set up the resource vectors
  241          */
  242         for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
  243                 ch->r_io[i].res = sc->sc_memr;
  244                 ch->r_io[i].offset = i*ATA_KAUAI_REGGAP + ATA_KAUAI_REGOFFSET;
  245         }
  246         ch->r_io[ATA_CONTROL].res = sc->sc_memr;
  247         ch->r_io[ATA_CONTROL].offset = ATA_KAUAI_ALTOFFSET;
  248         ata_default_registers(dev);
  249 
  250         ch->unit = 0;
  251         ch->flags |= ATA_USE_16BIT;
  252         
  253         /* XXX: ATAPI DMA is unreliable. We should find out why. */
  254         ch->flags |= ATA_NO_ATAPI_DMA;
  255         ata_generic_hw(dev);
  256 
  257         return (ata_probe(dev));
  258 }
  259 
  260 #if USE_DBDMA_IRQ
  261 static int
  262 ata_kauai_dma_interrupt(struct ata_kauai_softc *sc)
  263 {
  264         /* Clear the DMA interrupt bits */
  265 
  266         bus_write_4(sc->sc_memr, DMA_IRQ_REG, 0x80000000);
  267 
  268         return ata_interrupt(sc);
  269 }
  270 #endif
  271 
  272 static int
  273 ata_kauai_attach(device_t dev)
  274 {
  275         struct ata_kauai_softc *sc = device_get_softc(dev);
  276 #if USE_DBDMA_IRQ
  277         int dbdma_irq_rid = 1;
  278         struct resource *dbdma_irq;
  279         void *cookie;
  280 #endif
  281 
  282         pci_enable_busmaster(dev);
  283 
  284         /* Init DMA engine */
  285 
  286         sc->sc_ch.dbdma_rid = 1;
  287         sc->sc_ch.dbdma_regs = sc->sc_memr;
  288         sc->sc_ch.dbdma_offset = ATA_KAUAI_DBDMAOFFSET;
  289 
  290         ata_dbdma_dmainit(dev);
  291 
  292 #if USE_DBDMA_IRQ
  293         /* Bind to DBDMA interrupt as well */
  294         if ((dbdma_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  295             &dbdma_irq_rid, RF_SHAREABLE | RF_ACTIVE)) != NULL) {
  296                 bus_setup_intr(dev, dbdma_irq, ATA_INTR_FLAGS, NULL,
  297                     (driver_intr_t *)ata_kauai_dma_interrupt, sc,&cookie);
  298         }
  299 #endif
  300 
  301         /* Set up initial mode */
  302         sc->pioconf[0] = sc->pioconf[1] = 
  303             bus_read_4(sc->sc_memr, PIO_CONFIG_REG) & 0x0f000fff;
  304 
  305         sc->udmaconf[0] = sc->udmaconf[1] = 0;
  306         sc->wdmaconf[0] = sc->wdmaconf[1] = 0;
  307 
  308         /* Magic FCR value from Apple */
  309         bus_write_4(sc->sc_memr, 0, 0x00000007);
  310 
  311         /* Set begin_transaction */
  312         sc->sc_ch.sc_ch.hw.begin_transaction = ata_kauai_begin_transaction;
  313 
  314         return ata_attach(dev);
  315 }
  316 
  317 static int
  318 ata_kauai_setmode(device_t dev, int target, int mode)
  319 {
  320         struct ata_kauai_softc *sc = device_get_softc(dev);
  321 
  322         mode = min(mode,sc->shasta ? ATA_UDMA6 : ATA_UDMA5);
  323 
  324         if (sc->shasta) {
  325                 switch (mode & ATA_DMA_MASK) {
  326                     case ATA_UDMA0:
  327                         sc->udmaconf[target] 
  328                             = udma_timing_shasta[mode & ATA_MODE_MASK];
  329                         break;
  330                     case ATA_WDMA0:
  331                         sc->udmaconf[target] = 0;
  332                         sc->wdmaconf[target] 
  333                             = dma_timing_shasta[mode & ATA_MODE_MASK];
  334                         break;
  335                     default:
  336                         sc->pioconf[target] 
  337                             = pio_timing_shasta[(mode & ATA_MODE_MASK) - 
  338                             ATA_PIO0];
  339                         break;
  340                 }
  341         } else {
  342                 switch (mode & ATA_DMA_MASK) {
  343                     case ATA_UDMA0:
  344                         sc->udmaconf[target] 
  345                             = udma_timing_kauai[mode & ATA_MODE_MASK];
  346                         break;
  347                     case ATA_WDMA0:
  348                         sc->udmaconf[target] = 0;
  349                         sc->wdmaconf[target]
  350                             = dma_timing_kauai[mode & ATA_MODE_MASK];
  351                         break;
  352                     default:
  353                         sc->pioconf[target] 
  354                             = pio_timing_kauai[(mode & ATA_MODE_MASK)
  355                             - ATA_PIO0];
  356                         break;
  357                 }
  358         }
  359 
  360         return (mode);
  361 }
  362 
  363 static int
  364 ata_kauai_begin_transaction(struct ata_request *request)
  365 {
  366         struct ata_kauai_softc *sc = device_get_softc(request->parent);
  367 
  368         bus_write_4(sc->sc_memr, UDMA_CONFIG_REG, sc->udmaconf[request->unit]);
  369         bus_write_4(sc->sc_memr, PIO_CONFIG_REG, 
  370             sc->wdmaconf[request->unit] | sc->pioconf[request->unit]);
  371 
  372         return ata_begin_transaction(request);
  373 }

Cache object: bd9b79e4d7ff12806ce2db55b1a1386c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.