1 1.24 jdolecek /* $NetBSD: svwsata.c,v 1.24 2018/12/09 11:14:02 jdolecek Exp $ */ 2 1.1 bouyer 3 1.1 bouyer /* 4 1.1 bouyer * Copyright (c) 2005 Mark Kettenis 5 1.1 bouyer * 6 1.1 bouyer * Permission to use, copy, modify, and distribute this software for any 7 1.1 bouyer * purpose with or without fee is hereby granted, provided that the above 8 1.1 bouyer * copyright notice and this permission notice appear in all copies. 9 1.1 bouyer * 10 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 1.1 bouyer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 1.1 bouyer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 1.1 bouyer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 1.1 bouyer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 1.1 bouyer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 1.1 bouyer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 1.1 bouyer */ 18 1.1 bouyer 19 1.1 bouyer #include <sys/cdefs.h> 20 1.24 jdolecek __KERNEL_RCSID(0, "$NetBSD: svwsata.c,v 1.24 2018/12/09 11:14:02 jdolecek Exp $"); 21 1.1 bouyer 22 1.1 bouyer #include <sys/param.h> 23 1.1 bouyer #include <sys/systm.h> 24 1.1 bouyer 25 1.1 bouyer #include <dev/ata/atareg.h> 26 1.1 bouyer #include <dev/ata/satareg.h> 27 1.1 bouyer #include <dev/ata/satavar.h> 28 1.1 bouyer #include <dev/pci/pcivar.h> 29 1.1 bouyer #include <dev/pci/pcidevs.h> 30 1.1 bouyer #include <dev/pci/pciidereg.h> 31 1.1 bouyer #include <dev/pci/pciidevar.h> 32 1.1 bouyer #include <dev/pci/pciide_svwsata_reg.h> 33 1.1 bouyer 34 1.10 cube static int svwsata_match(device_t, cfdata_t, void *); 35 1.10 cube static void svwsata_attach(device_t, device_t, void *); 36 1.1 bouyer 37 1.13 dyoung static void svwsata_chip_map(struct pciide_softc *, 38 1.13 dyoung const struct pci_attach_args *); 39 1.13 dyoung static void svwsata_mapreg_dma(struct pciide_softc *, 40 1.13 dyoung const struct pci_attach_args *); 41 1.1 bouyer static void svwsata_mapchan(struct pciide_channel *); 42 1.21 macallan int svwsata_intr(void *); 43 1.1 bouyer 44 1.10 cube CFATTACH_DECL_NEW(svwsata, sizeof(struct pciide_softc), 45 1.18 jakllsch svwsata_match, svwsata_attach, pciide_detach, NULL); 46 1.1 bouyer 47 1.1 bouyer static const struct pciide_product_desc pciide_svwsata_products[] = { 48 1.1 bouyer { PCI_PRODUCT_SERVERWORKS_K2_SATA, 49 1.1 bouyer 0, 50 1.1 bouyer "ServerWorks K2 SATA Controller", 51 1.1 bouyer svwsata_chip_map 52 1.1 bouyer }, 53 1.2 bouyer { PCI_PRODUCT_SERVERWORKS_FRODO4_SATA, 54 1.2 bouyer 0, 55 1.2 bouyer "ServerWorks Frodo4 SATA Controller", 56 1.2 bouyer svwsata_chip_map 57 1.2 bouyer }, 58 1.2 bouyer { PCI_PRODUCT_SERVERWORKS_FRODO8_SATA, 59 1.2 bouyer 0, 60 1.2 bouyer "ServerWorks Frodo8 SATA Controller", 61 1.2 bouyer svwsata_chip_map 62 1.2 bouyer }, 63 1.8 xtraeme { PCI_PRODUCT_SERVERWORKS_HT1000_SATA_1, 64 1.8 xtraeme 0, 65 1.8 xtraeme "ServerWorks HT-1000 SATA Controller", 66 1.8 xtraeme svwsata_chip_map 67 1.8 xtraeme }, 68 1.8 xtraeme { PCI_PRODUCT_SERVERWORKS_HT1000_SATA_2, 69 1.2 bouyer 0, 70 1.2 bouyer "ServerWorks HT-1000 SATA Controller", 71 1.2 bouyer svwsata_chip_map 72 1.2 bouyer }, 73 1.1 bouyer { 0, 74 1.1 bouyer 0, 75 1.1 bouyer NULL, 76 1.1 bouyer NULL, 77 1.1 bouyer } 78 1.1 bouyer }; 79 1.1 bouyer 80 1.1 bouyer static int 81 1.10 cube svwsata_match(device_t parent, cfdata_t match, void *aux) 82 1.1 bouyer { 83 1.1 bouyer struct pci_attach_args *pa = aux; 84 1.1 bouyer 85 1.1 bouyer if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SERVERWORKS) { 86 1.1 bouyer if (pciide_lookup_product(pa->pa_id, 87 1.1 bouyer pciide_svwsata_products)) 88 1.1 bouyer return (2); 89 1.1 bouyer } 90 1.1 bouyer return (0); 91 1.1 bouyer } 92 1.1 bouyer 93 1.1 bouyer static void 94 1.10 cube svwsata_attach(device_t parent, device_t self, void *aux) 95 1.1 bouyer { 96 1.1 bouyer struct pci_attach_args *pa = aux; 97 1.10 cube struct pciide_softc *sc = device_private(self); 98 1.10 cube 99 1.10 cube sc->sc_wdcdev.sc_atac.atac_dev = self; 100 1.1 bouyer 101 1.1 bouyer pciide_common_attach(sc, pa, 102 1.1 bouyer pciide_lookup_product(pa->pa_id, pciide_svwsata_products)); 103 1.1 bouyer } 104 1.1 bouyer 105 1.1 bouyer static void 106 1.13 dyoung svwsata_chip_map(struct pciide_softc *sc, const struct pci_attach_args *pa) 107 1.1 bouyer { 108 1.1 bouyer struct pciide_channel *cp; 109 1.1 bouyer pci_intr_handle_t intrhandle; 110 1.1 bouyer pcireg_t interface; 111 1.1 bouyer const char *intrstr; 112 1.1 bouyer int channel; 113 1.19 christos char intrbuf[PCI_INTRSTR_LEN]; 114 1.1 bouyer 115 1.2 bouyer /* The 4-port version has a dummy second function. */ 116 1.2 bouyer if (pci_conf_read(sc->sc_pc, sc->sc_tag, 117 1.2 bouyer PCI_MAPREG_START + 0x14) == 0) { 118 1.2 bouyer aprint_normal("\n"); 119 1.2 bouyer return; 120 1.2 bouyer } 121 1.2 bouyer 122 1.1 bouyer if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x14, 123 1.1 bouyer PCI_MAPREG_TYPE_MEM | 124 1.1 bouyer PCI_MAPREG_MEM_TYPE_32BIT, 0, 125 1.1 bouyer &sc->sc_ba5_st, &sc->sc_ba5_sh, 126 1.12 jakllsch NULL, &sc->sc_ba5_ss) != 0) { 127 1.1 bouyer aprint_error(": unable to map BA5 register space\n"); 128 1.1 bouyer return; 129 1.1 bouyer } 130 1.1 bouyer 131 1.10 cube aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev, 132 1.10 cube "bus-master DMA support present"); 133 1.1 bouyer svwsata_mapreg_dma(sc, pa); 134 1.9 simonb aprint_verbose("\n"); 135 1.1 bouyer 136 1.7 hannken sc->sc_wdcdev.cap = WDC_CAPABILITY_WIDEREGS; 137 1.7 hannken 138 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32; 139 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_pio_cap = 4; 140 1.1 bouyer if (sc->sc_dma_ok) { 141 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA; 142 1.1 bouyer sc->sc_wdcdev.irqack = pciide_irqack; 143 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_dma_cap = 2; 144 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_udma_cap = 6; 145 1.1 bouyer } 146 1.1 bouyer 147 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray; 148 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_nchannels = 4; 149 1.1 bouyer sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel; 150 1.1 bouyer 151 1.1 bouyer /* We can use SControl and SStatus to probe for drives. */ 152 1.5 bouyer sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe; 153 1.16 bouyer sc->sc_wdcdev.wdc_maxdrives = 1; 154 1.1 bouyer 155 1.1 bouyer wdc_allocate_regs(&sc->sc_wdcdev); 156 1.1 bouyer 157 1.1 bouyer /* Map and establish the interrupt handler. */ 158 1.1 bouyer if(pci_intr_map(pa, &intrhandle) != 0) { 159 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 160 1.10 cube "couldn't map native-PCI interrupt\n"); 161 1.1 bouyer return; 162 1.1 bouyer } 163 1.19 christos intrstr = pci_intr_string(pa->pa_pc, intrhandle, intrbuf, sizeof(intrbuf)); 164 1.24 jdolecek sc->sc_pci_ih = pci_intr_establish_xname(pa->pa_pc, intrhandle, IPL_BIO, 165 1.24 jdolecek svwsata_intr, sc, device_xname(sc->sc_wdcdev.sc_atac.atac_dev)); 166 1.1 bouyer if (sc->sc_pci_ih != NULL) { 167 1.10 cube aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev, 168 1.10 cube "using %s for native-PCI interrupt\n", 169 1.1 bouyer intrstr ? intrstr : "unknown interrupt"); 170 1.1 bouyer } else { 171 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 172 1.10 cube "couldn't establish native-PCI interrupt"); 173 1.1 bouyer if (intrstr != NULL) 174 1.11 njoly aprint_error(" at %s", intrstr); 175 1.11 njoly aprint_error("\n"); 176 1.1 bouyer return; 177 1.1 bouyer } 178 1.1 bouyer 179 1.1 bouyer interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | 180 1.1 bouyer PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); 181 1.1 bouyer 182 1.1 bouyer for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels; 183 1.1 bouyer channel++) { 184 1.1 bouyer cp = &sc->pciide_channels[channel]; 185 1.1 bouyer 186 1.1 bouyer if (pciide_chansetup(sc, channel, interface) == 0) 187 1.1 bouyer continue; 188 1.1 bouyer svwsata_mapchan(cp); 189 1.1 bouyer } 190 1.1 bouyer } 191 1.1 bouyer 192 1.1 bouyer static void 193 1.13 dyoung svwsata_mapreg_dma(struct pciide_softc *sc, const struct pci_attach_args *pa) 194 1.1 bouyer { 195 1.1 bouyer struct pciide_channel *pc; 196 1.1 bouyer int chan, reg; 197 1.1 bouyer bus_size_t size; 198 1.1 bouyer 199 1.1 bouyer sc->sc_wdcdev.dma_arg = sc; 200 1.1 bouyer sc->sc_wdcdev.dma_init = pciide_dma_init; 201 1.1 bouyer sc->sc_wdcdev.dma_start = pciide_dma_start; 202 1.1 bouyer sc->sc_wdcdev.dma_finish = pciide_dma_finish; 203 1.1 bouyer 204 1.10 cube if (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags & 205 1.1 bouyer PCIIDE_OPTIONS_NODMA) { 206 1.1 bouyer aprint_normal( 207 1.1 bouyer ", but unused (forced off by config file)"); 208 1.1 bouyer sc->sc_dma_ok = 0; 209 1.1 bouyer return; 210 1.1 bouyer } 211 1.1 bouyer 212 1.1 bouyer /* 213 1.1 bouyer * Slice off a subregion of BA5 for each of the channel's DMA 214 1.1 bouyer * registers. 215 1.1 bouyer */ 216 1.1 bouyer 217 1.1 bouyer sc->sc_dma_iot = sc->sc_ba5_st; 218 1.1 bouyer for (chan = 0; chan < 4; chan++) { 219 1.1 bouyer pc = &sc->pciide_channels[chan]; 220 1.1 bouyer for (reg = 0; reg < IDEDMA_NREGS; reg++) { 221 1.1 bouyer size = 4; 222 1.1 bouyer if (size > (IDEDMA_SCH_OFFSET - reg)) 223 1.1 bouyer size = IDEDMA_SCH_OFFSET - reg; 224 1.1 bouyer if (bus_space_subregion(sc->sc_ba5_st, 225 1.1 bouyer sc->sc_ba5_sh, 226 1.1 bouyer (chan << 8) + SVWSATA_DMA + reg, 227 1.1 bouyer size, &pc->dma_iohs[reg]) != 0) { 228 1.1 bouyer sc->sc_dma_ok = 0; 229 1.1 bouyer aprint_normal(", but can't subregion offset " 230 1.1 bouyer "%lu size %lu", 231 1.1 bouyer (u_long) (chan << 8) + SVWSATA_DMA + reg, 232 1.1 bouyer (u_long) size); 233 1.1 bouyer return; 234 1.1 bouyer } 235 1.1 bouyer } 236 1.1 bouyer } 237 1.1 bouyer 238 1.1 bouyer /* DMA registers all set up! */ 239 1.1 bouyer sc->sc_dmat = pa->pa_dmat; 240 1.1 bouyer sc->sc_dma_ok = 1; 241 1.1 bouyer } 242 1.1 bouyer 243 1.1 bouyer static void 244 1.1 bouyer svwsata_mapchan(struct pciide_channel *cp) 245 1.1 bouyer { 246 1.1 bouyer struct ata_channel *wdc_cp = &cp->ata_channel; 247 1.1 bouyer struct pciide_softc *sc = CHAN_TO_PCIIDE(wdc_cp); 248 1.1 bouyer struct wdc_regs *wdr = CHAN_TO_WDC_REGS(wdc_cp); 249 1.1 bouyer int i; 250 1.1 bouyer 251 1.1 bouyer cp->compat = 0; 252 1.1 bouyer cp->ih = sc->sc_pci_ih; 253 1.1 bouyer 254 1.1 bouyer wdr->cmd_iot = sc->sc_ba5_st; 255 1.1 bouyer if (bus_space_subregion(sc->sc_ba5_st, sc->sc_ba5_sh, 256 1.1 bouyer (wdc_cp->ch_channel << 8) + SVWSATA_TF0, 257 1.1 bouyer SVWSATA_TF8 - SVWSATA_TF0, &wdr->cmd_baseioh) != 0) { 258 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 259 1.10 cube "couldn't map %s cmd regs\n", cp->name); 260 1.1 bouyer goto bad; 261 1.1 bouyer } 262 1.1 bouyer 263 1.1 bouyer wdr->ctl_iot = sc->sc_ba5_st; 264 1.1 bouyer if (bus_space_subregion(sc->sc_ba5_st, sc->sc_ba5_sh, 265 1.1 bouyer (wdc_cp->ch_channel << 8) + SVWSATA_TF8, 4, 266 1.1 bouyer &cp->ctl_baseioh) != 0) { 267 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 268 1.10 cube "couldn't map %s ctl regs\n", cp->name); 269 1.1 bouyer goto bad; 270 1.1 bouyer } 271 1.1 bouyer wdr->ctl_ioh = cp->ctl_baseioh; 272 1.1 bouyer 273 1.1 bouyer for (i = 0; i < WDC_NREG; i++) { 274 1.1 bouyer if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, 275 1.1 bouyer i << 2, i == 0 ? 4 : 1, 276 1.1 bouyer &wdr->cmd_iohs[i]) != 0) { 277 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 278 1.10 cube "couldn't subregion %s channel cmd regs\n", 279 1.10 cube cp->name); 280 1.1 bouyer goto bad; 281 1.1 bouyer } 282 1.1 bouyer } 283 1.20 jdolecek wdc_init_shadow_regs(wdr); 284 1.1 bouyer wdr->data32iot = wdr->cmd_iot; 285 1.1 bouyer wdr->data32ioh = wdr->cmd_iohs[0]; 286 1.1 bouyer 287 1.5 bouyer 288 1.5 bouyer wdr->sata_iot = sc->sc_ba5_st; 289 1.5 bouyer wdr->sata_baseioh = sc->sc_ba5_sh; 290 1.5 bouyer if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, 291 1.5 bouyer (wdc_cp->ch_channel << 8) + SVWSATA_SSTATUS, 1, 292 1.5 bouyer &wdr->sata_status) != 0) { 293 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 294 1.10 cube "couldn't map channel %d sata_status regs\n", 295 1.5 bouyer wdc_cp->ch_channel); 296 1.5 bouyer goto bad; 297 1.5 bouyer } 298 1.5 bouyer if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, 299 1.5 bouyer (wdc_cp->ch_channel << 8) + SVWSATA_SERROR, 1, 300 1.5 bouyer &wdr->sata_error) != 0) { 301 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 302 1.10 cube "couldn't map channel %d sata_error regs\n", 303 1.5 bouyer wdc_cp->ch_channel); 304 1.5 bouyer goto bad; 305 1.5 bouyer } 306 1.5 bouyer if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, 307 1.5 bouyer (wdc_cp->ch_channel << 8) + SVWSATA_SCONTROL, 1, 308 1.5 bouyer &wdr->sata_control) != 0) { 309 1.10 cube aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, 310 1.10 cube "couldn't map channel %d sata_control regs\n", 311 1.5 bouyer wdc_cp->ch_channel); 312 1.5 bouyer goto bad; 313 1.5 bouyer } 314 1.5 bouyer 315 1.17 macallan bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, 316 1.17 macallan (wdc_cp->ch_channel << 8) + SVWSATA_SICR1, 317 1.17 macallan bus_space_read_4(sc->sc_ba5_st, sc->sc_ba5_sh, 318 1.17 macallan (wdc_cp->ch_channel << 8) + SVWSATA_SICR1) 319 1.17 macallan & ~0x00040000); 320 1.17 macallan bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, 321 1.17 macallan (wdc_cp->ch_channel << 8) + SVWSATA_SERROR, 0xffffffff); 322 1.17 macallan bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, 323 1.17 macallan (wdc_cp->ch_channel << 8) + SVWSATA_SIM, 0); 324 1.17 macallan 325 1.21 macallan cp->ata_channel.ch_flags |= ATACH_DMA_BEFORE_CMD; 326 1.22 macallan 327 1.1 bouyer wdcattach(wdc_cp); 328 1.1 bouyer return; 329 1.1 bouyer 330 1.1 bouyer bad: 331 1.1 bouyer cp->ata_channel.ch_flags |= ATACH_DISABLED; 332 1.1 bouyer } 333 1.21 macallan 334 1.21 macallan int 335 1.21 macallan svwsata_intr(void *arg) 336 1.21 macallan { 337 1.21 macallan struct pciide_softc *sc = arg; 338 1.21 macallan struct pciide_channel *cp; 339 1.21 macallan struct ata_channel *wdc_cp; 340 1.21 macallan struct wdc_regs *wdr; 341 1.21 macallan int i, rv, crv; 342 1.21 macallan uint8_t dmastat; 343 1.21 macallan 344 1.21 macallan rv = 0; 345 1.21 macallan for (i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) { 346 1.21 macallan volatile uint32_t status; 347 1.21 macallan cp = &sc->pciide_channels[i]; 348 1.21 macallan wdc_cp = &cp->ata_channel; 349 1.21 macallan wdr = CHAN_TO_WDC_REGS(wdc_cp); 350 1.21 macallan 351 1.21 macallan /* 352 1.21 macallan * from FreeBSD's ata-serverworks.c: 353 1.21 macallan * We need to do a 4-byte read on the status reg before the 354 1.21 macallan * values will report correctly 355 1.21 macallan */ 356 1.21 macallan bus_space_read_4(wdr->cmd_iot, 357 1.21 macallan wdr->cmd_iohs[wd_status], 0); 358 1.21 macallan __USE(status); 359 1.21 macallan 360 1.21 macallan dmastat = bus_space_read_1(sc->sc_dma_iot, 361 1.21 macallan cp->dma_iohs[IDEDMA_CTL], 0); 362 1.21 macallan 363 1.21 macallan /* If a compat channel skip. */ 364 1.21 macallan if (cp->compat) 365 1.21 macallan continue; 366 1.21 macallan 367 1.21 macallan /* if this channel not waiting for intr, skip */ 368 1.21 macallan if ((wdc_cp->ch_flags & ATACH_IRQ_WAIT) == 0) { 369 1.21 macallan continue; 370 1.21 macallan } 371 1.21 macallan crv = wdcintr(wdc_cp); 372 1.23 kamil if (crv == 0) { 373 1.21 macallan bus_space_write_1(sc->sc_dma_iot, 374 1.21 macallan cp->dma_iohs[IDEDMA_CTL], 0, dmastat); 375 1.21 macallan } 376 1.21 macallan else if (crv == 1) 377 1.21 macallan rv = 1; /* claim the intr */ 378 1.21 macallan else if (rv == 0) /* crv should be -1 in this case */ 379 1.21 macallan rv = crv; /* if we've done no better, take it */ 380 1.21 macallan } 381 1.21 macallan return (rv); 382 1.21 macallan } 383