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