1*ec43f8fcSlukem /* $NetBSD: iteide.c,v 1.3 2005/05/24 05:25:15 lukem Exp $ */ 29204390fSgrant 39204390fSgrant /* 49204390fSgrant * Copyright (c) 2004 The NetBSD Foundation, Inc. 59204390fSgrant * 69204390fSgrant * This code is derived from software contributed to The NetBSD Foundation 79204390fSgrant * by Grant Beattie. 89204390fSgrant * 99204390fSgrant * Redistribution and use in source and binary forms, with or without 109204390fSgrant * modification, are permitted provided that the following conditions 119204390fSgrant * are met: 129204390fSgrant * 1. Redistributions of source code must retain the above copyright 139204390fSgrant * notice, this list of conditions and the following disclaimer. 149204390fSgrant * 2. Redistributions in binary form must reproduce the above copyright 159204390fSgrant * notice, this list of conditions and the following disclaimer in the 169204390fSgrant * documentation and/or other materials provided with the distribution. 179204390fSgrant * 3. The name of the author may not be used to endorse or promote products 189204390fSgrant * derived from this software without specific prior written permission. 199204390fSgrant * 209204390fSgrant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 219204390fSgrant * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 229204390fSgrant * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 239204390fSgrant * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 249204390fSgrant * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 259204390fSgrant * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 269204390fSgrant * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 279204390fSgrant * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 289204390fSgrant * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 299204390fSgrant * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 309204390fSgrant * 319204390fSgrant */ 329204390fSgrant 33*ec43f8fcSlukem #include <sys/cdefs.h> 34*ec43f8fcSlukem __KERNEL_RCSID(0, "$NetBSD: iteide.c,v 1.3 2005/05/24 05:25:15 lukem Exp $"); 35*ec43f8fcSlukem 369204390fSgrant #include <sys/param.h> 379204390fSgrant #include <sys/systm.h> 389204390fSgrant 399204390fSgrant #include <dev/pci/pcivar.h> 409204390fSgrant #include <dev/pci/pcidevs.h> 419204390fSgrant #include <dev/pci/pciidereg.h> 429204390fSgrant #include <dev/pci/pciidevar.h> 439204390fSgrant #include <dev/pci/pciide_ite_reg.h> 449204390fSgrant 459204390fSgrant static void ite_chip_map(struct pciide_softc*, struct pci_attach_args*); 469204390fSgrant static void ite_setup_channel(struct ata_channel*); 479204390fSgrant 489204390fSgrant static int iteide_match(struct device *, struct cfdata *, void *); 499204390fSgrant static void iteide_attach(struct device *, struct device *, void *); 509204390fSgrant 519204390fSgrant CFATTACH_DECL(iteide, sizeof(struct pciide_softc), 529204390fSgrant iteide_match, iteide_attach, NULL, NULL); 539204390fSgrant 549204390fSgrant static const struct pciide_product_desc pciide_ite_products[] = { 559204390fSgrant { PCI_PRODUCT_ITE_IT8212, 569204390fSgrant 0, 579204390fSgrant "Integrated Technology Express IDE controller", 589204390fSgrant ite_chip_map, 599204390fSgrant }, 609204390fSgrant { 0, 619204390fSgrant 0, 629204390fSgrant NULL, 639204390fSgrant NULL 649204390fSgrant } 659204390fSgrant }; 669204390fSgrant 679204390fSgrant static int 689204390fSgrant iteide_match(struct device *parent, struct cfdata *match, void *aux) 699204390fSgrant { 709204390fSgrant struct pci_attach_args *pa = aux; 719204390fSgrant if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ITE && 729204390fSgrant PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE) { 739204390fSgrant if (pciide_lookup_product(pa->pa_id, pciide_ite_products)) 749204390fSgrant return (2); 759204390fSgrant } 769204390fSgrant return (0); 779204390fSgrant } 789204390fSgrant 799204390fSgrant static void 809204390fSgrant iteide_attach(struct device *parent, struct device *self, void *aux) 819204390fSgrant { 829204390fSgrant struct pci_attach_args *pa = aux; 839204390fSgrant struct pciide_softc *sc = (struct pciide_softc *)self; 849204390fSgrant 859204390fSgrant pciide_common_attach(sc, pa, 869204390fSgrant pciide_lookup_product(pa->pa_id, pciide_ite_products)); 879204390fSgrant } 889204390fSgrant 899204390fSgrant static void 909204390fSgrant ite_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa) 919204390fSgrant { 929204390fSgrant struct pciide_channel *cp; 939204390fSgrant int channel; 949204390fSgrant pcireg_t interface; 959204390fSgrant bus_size_t cmdsize, ctlsize; 969204390fSgrant pcireg_t cfg, modectl; 979204390fSgrant 989204390fSgrant /* fake interface since IT8212 claims to be a RAID device */ 999204390fSgrant interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | 1009204390fSgrant PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); 1019204390fSgrant 1029204390fSgrant cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG); 1039204390fSgrant modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE); 1049204390fSgrant ATADEBUG_PRINT(("%s: cfg=0x%x, modectl=0x%x\n", 1059204390fSgrant sc->sc_wdcdev.sc_atac.atac_dev.dv_xname, cfg & IT_CFG_MASK, 1069204390fSgrant modectl & IT_MODE_MASK), DEBUG_PROBE); 1079204390fSgrant 1089204390fSgrant if (pciide_chipen(sc, pa) == 0) 1099204390fSgrant return; 1109204390fSgrant 1119204390fSgrant aprint_normal("%s: bus-master DMA support present", 1129204390fSgrant sc->sc_wdcdev.sc_atac.atac_dev.dv_xname); 1139204390fSgrant pciide_mapreg_dma(sc, pa); 1149204390fSgrant aprint_normal("\n"); 1159204390fSgrant 1169204390fSgrant sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16 | ATAC_CAP_DATA32; 1179204390fSgrant 1189204390fSgrant if (sc->sc_dma_ok) { 1199204390fSgrant sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA; 1209204390fSgrant sc->sc_wdcdev.irqack = pciide_irqack; 1219204390fSgrant } 1229204390fSgrant sc->sc_wdcdev.sc_atac.atac_pio_cap = 4; 1239204390fSgrant sc->sc_wdcdev.sc_atac.atac_dma_cap = 2; 1249204390fSgrant sc->sc_wdcdev.sc_atac.atac_udma_cap = 6; 1259204390fSgrant 1269204390fSgrant sc->sc_wdcdev.sc_atac.atac_set_modes = ite_setup_channel; 1279204390fSgrant sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray; 1289204390fSgrant sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS; 1299204390fSgrant 1309204390fSgrant wdc_allocate_regs(&sc->sc_wdcdev); 1319204390fSgrant 1329204390fSgrant /* Disable RAID */ 1339204390fSgrant modectl &= ~IT_MODE_RAID1; 1349204390fSgrant /* Disable CPU firmware mode */ 1359204390fSgrant modectl &= ~IT_MODE_CPU; 1369204390fSgrant 1379204390fSgrant pci_conf_write(sc->sc_pc, sc->sc_tag, IT_MODE, modectl); 1389204390fSgrant 1399204390fSgrant for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels; channel++) { 1409204390fSgrant cp = &sc->pciide_channels[channel]; 1419204390fSgrant 1429204390fSgrant if (pciide_chansetup(sc, channel, interface) == 0) 1439204390fSgrant continue; 1449204390fSgrant 1459204390fSgrant pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, 1469204390fSgrant pciide_pci_intr); 1479204390fSgrant } 1489204390fSgrant /* Re-read configuration registers after channels setup */ 1499204390fSgrant cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG); 1509204390fSgrant modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE); 1519204390fSgrant ATADEBUG_PRINT(("%s: cfg=0x%x, modectl=0x%x\n", 1529204390fSgrant sc->sc_wdcdev.sc_atac.atac_dev.dv_xname, cfg & IT_CFG_MASK, 1539204390fSgrant modectl & IT_MODE_MASK), DEBUG_PROBE); 1549204390fSgrant } 1559204390fSgrant 1569204390fSgrant static void 1579204390fSgrant ite_setup_channel(struct ata_channel *chp) 1589204390fSgrant { 1599204390fSgrant struct ata_drive_datas *drvp; 1609204390fSgrant int drive, mode = 0; 1619204390fSgrant u_int32_t idedma_ctl; 1629204390fSgrant struct pciide_channel *cp = CHAN_TO_PCHAN(chp); 1639204390fSgrant struct pciide_softc *sc = CHAN_TO_PCIIDE(chp); 1649204390fSgrant int channel = chp->ch_channel; 1659204390fSgrant pcireg_t cfg, modectl; 1669204390fSgrant pcireg_t tim; 1679204390fSgrant 1689204390fSgrant cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG); 1699204390fSgrant modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE); 1709204390fSgrant tim = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_TIM(channel)); 1719204390fSgrant ATADEBUG_PRINT(("%s:%d: tim=0x%x\n", 1729204390fSgrant sc->sc_wdcdev.sc_atac.atac_dev.dv_xname, 1739204390fSgrant channel, tim), DEBUG_PROBE); 1749204390fSgrant 1759204390fSgrant /* Setup DMA if needed */ 1769204390fSgrant pciide_channel_dma_setup(cp); 1779204390fSgrant 1789204390fSgrant /* Clear all bits for this channel */ 1799204390fSgrant idedma_ctl = 0; 1809204390fSgrant 1819204390fSgrant /* Per channel settings */ 1829204390fSgrant for (drive = 0; drive < 2; drive++) { 1839204390fSgrant drvp = &chp->ch_drive[drive]; 1849204390fSgrant 1859204390fSgrant /* If no drive, skip */ 1869204390fSgrant if ((drvp->drive_flags & DRIVE) == 0) 1879204390fSgrant continue; 1889204390fSgrant 1899204390fSgrant if ((chp->ch_atac->atac_cap & ATAC_CAP_UDMA) != 0 && 1909204390fSgrant (drvp->drive_flags & DRIVE_UDMA) != 0) { 1919204390fSgrant /* Setup UltraDMA mode */ 1929204390fSgrant drvp->drive_flags &= ~DRIVE_DMA; 1939204390fSgrant modectl &= ~IT_MODE_DMA(channel, drive); 1949204390fSgrant 1959204390fSgrant #if 0 1969204390fSgrant /* Check cable, only works in CPU firmware mode */ 1979204390fSgrant if (drvp->UDMA_mode > 2 && 1989204390fSgrant (cfg & IT_CFG_CABLE(channel, drive)) == 0) { 1999204390fSgrant ATADEBUG_PRINT(("(%s:%d:%d): " 2009204390fSgrant "80-wire cable not detected\n", 2019204390fSgrant sc->sc_wdcdev.sc_atac.atac_dev.dv_xname, 2029204390fSgrant channel, drive), DEBUG_PROBE); 2039204390fSgrant drvp->UDMA_mode = 2; 2049204390fSgrant } 2059204390fSgrant #endif 2069204390fSgrant 2079204390fSgrant if (drvp->UDMA_mode >= 5) 2089204390fSgrant tim |= IT_TIM_UDMA5(drive); 2099204390fSgrant else 2109204390fSgrant tim &= ~IT_TIM_UDMA5(drive); 2119204390fSgrant 2129204390fSgrant mode = drvp->PIO_mode; 2139204390fSgrant } else if ((chp->ch_atac->atac_cap & ATAC_CAP_DMA) != 0 && 2149204390fSgrant (drvp->drive_flags & DRIVE_DMA) != 0) { 2159204390fSgrant /* Setup multiword DMA mode */ 2169204390fSgrant drvp->drive_flags &= ~DRIVE_UDMA; 2179204390fSgrant modectl |= IT_MODE_DMA(channel, drive); 2189204390fSgrant 2199204390fSgrant /* mode = min(pio, dma + 2) */ 2209204390fSgrant if (drvp->PIO_mode <= (drvp->DMA_mode + 2)) 2219204390fSgrant mode = drvp->PIO_mode; 2229204390fSgrant else 2239204390fSgrant mode = drvp->DMA_mode + 2; 2249204390fSgrant } else { 2259204390fSgrant goto pio; 2269204390fSgrant } 2279204390fSgrant idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); 2289204390fSgrant 2299204390fSgrant pio: 2309204390fSgrant /* Setup PIO mode */ 2319204390fSgrant if (mode <= 2) { 2329204390fSgrant drvp->DMA_mode = 0; 2339204390fSgrant drvp->PIO_mode = 0; 2349204390fSgrant mode = 0; 2359204390fSgrant } else { 2369204390fSgrant drvp->PIO_mode = mode; 2379204390fSgrant drvp->DMA_mode = mode - 2; 2389204390fSgrant } 2399204390fSgrant 2409204390fSgrant /* Enable IORDY if PIO mode >= 3 */ 2419204390fSgrant if (drvp->PIO_mode >= 3) 2429204390fSgrant cfg |= IT_CFG_IORDY(channel); 2439204390fSgrant } 2449204390fSgrant 2459204390fSgrant ATADEBUG_PRINT(("%s: tim=0x%x\n", 2469204390fSgrant sc->sc_wdcdev.sc_atac.atac_dev.dv_xname, tim), DEBUG_PROBE); 2479204390fSgrant 2489204390fSgrant pci_conf_write(sc->sc_pc, sc->sc_tag, IT_CFG, cfg); 2499204390fSgrant pci_conf_write(sc->sc_pc, sc->sc_tag, IT_MODE, modectl); 2509204390fSgrant pci_conf_write(sc->sc_pc, sc->sc_tag, IT_TIM(channel), tim); 2519204390fSgrant 2529204390fSgrant if (idedma_ctl != 0) { 2539204390fSgrant /* Add software bits in status register */ 2549204390fSgrant bus_space_write_1(sc->sc_dma_iot, 2559204390fSgrant cp->dma_iohs[IDEDMA_CTL], 0, idedma_ctl); 2569204390fSgrant } 2579204390fSgrant } 258