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