1 /* $NetBSD: geodeide.c,v 1.25 2013/10/07 19:51:55 jakllsch Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 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, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 /* 29 * Driver for the IDE part of the AMD Geode CS5530A companion chip 30 * and AMD Geode SC1100. 31 * Docs available from AMD's web site 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: geodeide.c,v 1.25 2013/10/07 19:51:55 jakllsch Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 40 #include <dev/pci/pcivar.h> 41 #include <dev/pci/pcidevs.h> 42 #include <dev/pci/pciidereg.h> 43 #include <dev/pci/pciidevar.h> 44 45 #include <dev/pci/pciide_geode_reg.h> 46 47 static void geodeide_chip_map(struct pciide_softc *, 48 const struct pci_attach_args *); 49 static void geodeide_setup_channel(struct ata_channel *); 50 static int geodeide_dma_init(void *, int, int, void *, size_t, int); 51 52 static int geodeide_match(device_t, cfdata_t, void *); 53 static void geodeide_attach(device_t, device_t, void *); 54 55 CFATTACH_DECL_NEW(geodeide, sizeof(struct pciide_softc), 56 geodeide_match, geodeide_attach, pciide_detach, NULL); 57 58 static const struct pciide_product_desc pciide_geode_products[] = { 59 { PCI_PRODUCT_CYRIX_CX5530_IDE, 60 0, 61 "AMD Geode CX5530 IDE controller", 62 geodeide_chip_map, 63 }, 64 { PCI_PRODUCT_NS_SC1100_IDE, 65 0, 66 "AMD Geode SC1100 IDE controller", 67 geodeide_chip_map, 68 }, 69 { 0, 70 0, 71 NULL, 72 NULL, 73 }, 74 }; 75 76 static int 77 geodeide_match(device_t parent, cfdata_t match, void *aux) 78 { 79 struct pci_attach_args *pa = aux; 80 81 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CYRIX || 82 PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS) && 83 PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE && 84 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE && 85 pciide_lookup_product(pa->pa_id, pciide_geode_products)) 86 return(2); 87 return (0); 88 } 89 90 static void 91 geodeide_attach(device_t parent, device_t self, void *aux) 92 { 93 struct pci_attach_args *pa = aux; 94 struct pciide_softc *sc = device_private(self); 95 96 sc->sc_wdcdev.sc_atac.atac_dev = self; 97 98 pciide_common_attach(sc, pa, 99 pciide_lookup_product(pa->pa_id, pciide_geode_products)); 100 } 101 102 static void 103 geodeide_chip_map(struct pciide_softc *sc, const struct pci_attach_args *pa) 104 { 105 struct pciide_channel *cp; 106 int channel; 107 108 if (pciide_chipen(sc, pa) == 0) 109 return; 110 111 aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev, 112 "bus-master DMA support present"); 113 pciide_mapreg_dma(sc, pa); 114 aprint_verbose("\n"); 115 if (sc->sc_dma_ok) { 116 sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DMA | ATAC_CAP_UDMA; 117 sc->sc_wdcdev.irqack = pciide_irqack; 118 /* 119 * XXXJRT What chip revisions actually need the DMA 120 * alignment work-around? 121 */ 122 sc->sc_wdcdev.dma_init = geodeide_dma_init; 123 } 124 sc->sc_wdcdev.sc_atac.atac_pio_cap = 4; 125 sc->sc_wdcdev.sc_atac.atac_dma_cap = 2; 126 sc->sc_wdcdev.sc_atac.atac_udma_cap = 2; 127 /* 128 * The 5530 is utterly swamped by UDMA mode 2, so limit to mode 1 129 * so that the chip is able to perform the other functions it has 130 * while IDE UDMA is going on. 131 */ 132 if (sc->sc_pp->ide_product == PCI_PRODUCT_CYRIX_CX5530_IDE) { 133 sc->sc_wdcdev.sc_atac.atac_udma_cap = 1; 134 } 135 sc->sc_wdcdev.sc_atac.atac_set_modes = geodeide_setup_channel; 136 sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray; 137 sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS; 138 sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32; 139 sc->sc_wdcdev.wdc_maxdrives = 2; 140 141 /* 142 * Soekris Engineering Issue #0003: 143 * "The SC1100 built in busmaster IDE controller is pretty 144 * standard, but have two bugs: data transfers need to be 145 * dword aligned and it cannot do an exact 64Kbyte data 146 * transfer." 147 */ 148 if (sc->sc_pp->ide_product == PCI_PRODUCT_NS_SC1100_IDE) { 149 if (sc->sc_dma_boundary == 0x10000) 150 sc->sc_dma_boundary -= PAGE_SIZE; 151 152 if (sc->sc_dma_maxsegsz == 0x10000) 153 sc->sc_dma_maxsegsz -= PAGE_SIZE; 154 } 155 156 wdc_allocate_regs(&sc->sc_wdcdev); 157 158 for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels; 159 channel++) { 160 cp = &sc->pciide_channels[channel]; 161 /* controller is compat-only */ 162 if (pciide_chansetup(sc, channel, 0) == 0) 163 continue; 164 pciide_mapchan(pa, cp, 0, pciide_pci_intr); 165 } 166 } 167 168 static void 169 geodeide_setup_channel(struct ata_channel *chp) 170 { 171 struct ata_drive_datas *drvp; 172 struct pciide_channel *cp = CHAN_TO_PCHAN(chp); 173 struct pciide_softc *sc = CHAN_TO_PCIIDE(chp); 174 int channel = chp->ch_channel; 175 int drive, s; 176 u_int32_t dma_timing; 177 u_int8_t idedma_ctl; 178 const int32_t *geode_pio; 179 const int32_t *geode_dma; 180 const int32_t *geode_udma; 181 bus_size_t dmaoff, piooff; 182 183 switch (sc->sc_pp->ide_product) { 184 case PCI_PRODUCT_CYRIX_CX5530_IDE: 185 geode_pio = geode_cs5530_pio; 186 geode_dma = geode_cs5530_dma; 187 geode_udma = geode_cs5530_udma; 188 break; 189 190 case PCI_PRODUCT_NS_SC1100_IDE: 191 default: /* XXX gcc */ 192 geode_pio = geode_sc1100_pio; 193 geode_dma = geode_sc1100_dma; 194 geode_udma = geode_sc1100_udma; 195 break; 196 } 197 198 /* setup DMA if needed */ 199 pciide_channel_dma_setup(cp); 200 201 idedma_ctl = 0; 202 203 /* Per drive settings */ 204 for (drive = 0; drive < 2; drive++) { 205 drvp = &chp->ch_drive[drive]; 206 /* If no drive, skip */ 207 if (drvp->drive_type == ATA_DRIVET_NONE) 208 continue; 209 210 switch (sc->sc_pp->ide_product) { 211 case PCI_PRODUCT_CYRIX_CX5530_IDE: 212 dmaoff = CS5530_DMA_REG(channel, drive); 213 piooff = CS5530_PIO_REG(channel, drive); 214 dma_timing = CS5530_DMA_REG_PIO_FORMAT; 215 break; 216 217 case PCI_PRODUCT_NS_SC1100_IDE: 218 default: /* XXX gcc */ 219 dmaoff = SC1100_DMA_REG(channel, drive); 220 piooff = SC1100_PIO_REG(channel, drive); 221 dma_timing = 0; 222 break; 223 } 224 225 /* add timing values, setup DMA if needed */ 226 if (drvp->drive_flags & ATA_DRIVE_UDMA) { 227 /* Use Ultra-DMA */ 228 dma_timing |= geode_udma[drvp->UDMA_mode]; 229 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); 230 } else if (drvp->drive_flags & ATA_DRIVE_DMA) { 231 /* use Multiword DMA */ 232 dma_timing |= geode_dma[drvp->DMA_mode]; 233 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); 234 } else { 235 /* PIO only */ 236 s = splbio(); 237 drvp->drive_flags &= ~(ATA_DRIVE_UDMA | ATA_DRIVE_DMA); 238 splx(s); 239 } 240 241 switch (sc->sc_pp->ide_product) { 242 case PCI_PRODUCT_CYRIX_CX5530_IDE: 243 bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh, 244 dmaoff, dma_timing); 245 bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh, 246 piooff, geode_pio[drvp->PIO_mode]); 247 break; 248 249 case PCI_PRODUCT_NS_SC1100_IDE: 250 pci_conf_write(sc->sc_pc, sc->sc_tag, dmaoff, 251 dma_timing); 252 pci_conf_write(sc->sc_pc, sc->sc_tag, piooff, 253 geode_pio[drvp->PIO_mode]); 254 break; 255 } 256 } 257 258 if (idedma_ctl != 0) { 259 /* Add software bits in status register */ 260 bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0, 261 idedma_ctl); 262 } 263 } 264 265 static int 266 geodeide_dma_init(void *v, int channel, int drive, void *databuf, 267 size_t datalen, int flags) 268 { 269 270 /* 271 * If the buffer is not properly aligned, we can't allow DMA 272 * and need to fall back to PIO. 273 */ 274 if (((uintptr_t)databuf) & 0xf) 275 return (EINVAL); 276 277 return (pciide_dma_init(v, channel, drive, databuf, datalen, flags)); 278 } 279