1 /* $NetBSD: wdc_obio.c,v 1.11 2000/11/08 17:50:44 wrstuden Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum and by Onno van der Linden. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 #include <sys/malloc.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <machine/bus.h> 47 #include <machine/autoconf.h> 48 49 #include <dev/ata/atareg.h> 50 #include <dev/ata/atavar.h> 51 #include <dev/ic/wdcvar.h> 52 53 #include <macppc/dev/dbdma.h> 54 55 #define WDC_REG_NPORTS 8 56 #define WDC_AUXREG_OFFSET 0x16 57 #define WDC_DEFAULT_PIO_IRQ 13 /* XXX */ 58 #define WDC_DEFAULT_DMA_IRQ 2 /* XXX */ 59 60 #define WDC_OPTIONS_DMA 0x01 61 62 /* 63 * XXX This code currently doesn't even try to allow 32-bit data port use. 64 */ 65 66 struct wdc_obio_softc { 67 struct wdc_softc sc_wdcdev; 68 struct channel_softc *wdc_chanptr; 69 struct channel_softc wdc_channel; 70 dbdma_regmap_t *sc_dmareg; 71 dbdma_command_t *sc_dmacmd; 72 void *sc_ih; 73 }; 74 75 int wdc_obio_probe __P((struct device *, struct cfdata *, void *)); 76 void wdc_obio_attach __P((struct device *, struct device *, void *)); 77 int wdc_obio_detach __P((struct device *, int)); 78 int wdc_obio_dma_init __P((void *, int, int, void *, size_t, int)); 79 void wdc_obio_dma_start __P((void *, int, int)); 80 int wdc_obio_dma_finish __P((void *, int, int, int)); 81 static void adjust_timing __P((struct channel_softc *)); 82 83 struct cfattach wdc_obio_ca = { 84 sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach, 85 wdc_obio_detach, wdcactivate 86 }; 87 88 89 int 90 wdc_obio_probe(parent, match, aux) 91 struct device *parent; 92 struct cfdata *match; 93 void *aux; 94 { 95 struct confargs *ca = aux; 96 char compat[32]; 97 98 /* XXX should not use name */ 99 if (strcmp(ca->ca_name, "ATA") == 0 || 100 strcmp(ca->ca_name, "ata") == 0 || 101 strcmp(ca->ca_name, "ata0") == 0 || 102 strcmp(ca->ca_name, "ide") == 0) 103 return 1; 104 105 bzero(compat, sizeof(compat)); 106 OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat)); 107 if (strcmp(compat, "heathrow-ata") == 0 || 108 strcmp(compat, "keylargo-ata") == 0) 109 return 1; 110 111 return 0; 112 } 113 114 void 115 wdc_obio_attach(parent, self, aux) 116 struct device *parent, *self; 117 void *aux; 118 { 119 struct wdc_obio_softc *sc = (void *)self; 120 struct confargs *ca = aux; 121 struct channel_softc *chp = &sc->wdc_channel; 122 int intr; 123 int use_dma = 0; 124 char path[80]; 125 126 if (sc->sc_wdcdev.sc_dev.dv_cfdata->cf_flags & WDC_OPTIONS_DMA) { 127 if (ca->ca_nreg >= 16 || ca->ca_nintr == -1) 128 use_dma = 1; /* XXX Don't work yet. */ 129 } 130 131 if (ca->ca_nintr >= 4 && ca->ca_nreg >= 8) { 132 intr = ca->ca_intr[0]; 133 printf(" irq %d", intr); 134 } else if (ca->ca_nintr == -1) { 135 intr = WDC_DEFAULT_PIO_IRQ; 136 printf(" irq property not found; using %d", intr); 137 } else { 138 printf(": couldn't get irq property\n"); 139 return; 140 } 141 142 if (use_dma) 143 printf(": DMA transfer"); 144 145 printf("\n"); 146 147 chp->cmd_iot = chp->ctl_iot = 148 macppc_make_bus_space_tag(ca->ca_baseaddr + ca->ca_reg[0], 4); 149 150 if (bus_space_map(chp->cmd_iot, 0, WDC_REG_NPORTS, 0, &chp->cmd_ioh) || 151 bus_space_subregion(chp->cmd_iot, chp->cmd_ioh, 152 WDC_AUXREG_OFFSET, 1, &chp->ctl_ioh)) { 153 printf("%s: couldn't map registers\n", 154 sc->sc_wdcdev.sc_dev.dv_xname); 155 return; 156 } 157 #if 0 158 chp->data32iot = chp->cmd_iot; 159 chp->data32ioh = chp->cmd_ioh; 160 #endif 161 162 sc->sc_ih = intr_establish(intr, IST_LEVEL, IPL_BIO, wdcintr, chp); 163 164 if (use_dma) { 165 sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20); 166 sc->sc_dmareg = mapiodev(ca->ca_baseaddr + ca->ca_reg[2], 167 ca->ca_reg[3]); 168 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; 169 } 170 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; 171 sc->sc_wdcdev.PIO_cap = 0; 172 sc->wdc_chanptr = chp; 173 sc->sc_wdcdev.channels = &sc->wdc_chanptr; 174 sc->sc_wdcdev.nchannels = 1; 175 sc->sc_wdcdev.dma_arg = sc; 176 sc->sc_wdcdev.dma_init = wdc_obio_dma_init; 177 sc->sc_wdcdev.dma_start = wdc_obio_dma_start; 178 sc->sc_wdcdev.dma_finish = wdc_obio_dma_finish; 179 chp->channel = 0; 180 chp->wdc = &sc->sc_wdcdev; 181 chp->ch_queue = malloc(sizeof(struct channel_queue), 182 M_DEVBUF, M_NOWAIT); 183 if (chp->ch_queue == NULL) { 184 printf("%s: can't allocate memory for command queue", 185 sc->sc_wdcdev.sc_dev.dv_xname); 186 return; 187 } 188 189 #define OHARE_FEATURE_REG 0xf3000038 190 191 /* XXX Enable wdc1 by feature reg. */ 192 bzero(path, sizeof(path)); 193 OF_package_to_path(ca->ca_node, path, sizeof(path)); 194 if (strcmp(path, "/bandit@F2000000/ohare@10/ata@21000") == 0) { 195 u_int x; 196 197 x = in32rb(OHARE_FEATURE_REG); 198 x |= 8; 199 out32rb(OHARE_FEATURE_REG, x); 200 } 201 202 wdcattach(chp); 203 204 /* modify DMA access timings */ 205 if (use_dma) 206 adjust_timing(chp); 207 208 wdc_print_modes(chp); 209 } 210 211 /* Multiword DMA transfer timings */ 212 static struct { 213 int cycle; /* minimum cycle time [ns] */ 214 int active; /* minimum command active time [ns] */ 215 } dma_timing[3] = { 216 480, 215, /* Mode 0 */ 217 150, 80, /* Mode 1 */ 218 120, 70, /* Mode 2 */ 219 }; 220 221 #define TIME_TO_TICK(time) howmany((time), 30) 222 223 #define CONFIG_REG (0x200 >> 4) /* IDE access timing register */ 224 225 void 226 adjust_timing(chp) 227 struct channel_softc *chp; 228 { 229 struct ataparams params; 230 struct ata_drive_datas *drvp = &chp->ch_drive[0]; /* XXX */ 231 u_int conf; 232 int mode; 233 int cycle, active, min_cycle, min_active; 234 int cycle_tick, act_tick, inact_tick, half_tick; 235 236 if (ata_get_params(drvp, AT_POLL, ¶ms) != CMD_OK) 237 return; 238 239 for (mode = 2; mode >= 0; mode--) 240 if (params.atap_dmamode_act & (1 << mode)) 241 goto found; 242 243 /* No active DMA mode is found... Do nothing. */ 244 return; 245 246 found: 247 min_cycle = dma_timing[mode].cycle; 248 min_active = dma_timing[mode].active; 249 250 #ifdef notyet 251 /* Minimum cycle time is 150ns on ohare. */ 252 if (ohare && params.atap_dmatiming_recom < 150) 253 params.atap_dmatiming_recom = 150; 254 #endif 255 cycle = max(min_cycle, params.atap_dmatiming_recom); 256 active = min_active + (cycle - min_cycle); /* XXX */ 257 258 cycle_tick = TIME_TO_TICK(cycle); 259 act_tick = TIME_TO_TICK(active); 260 inact_tick = cycle_tick - act_tick - 1; 261 if (inact_tick < 1) 262 inact_tick = 1; 263 half_tick = 0; /* XXX */ 264 conf = (half_tick << 21) | (inact_tick << 16) | (act_tick << 11); 265 bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf); 266 #if 0 267 printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n", 268 conf, cycle_tick, cycle, act_tick, active, inact_tick); 269 #endif 270 } 271 272 int 273 wdc_obio_detach(self, flags) 274 struct device *self; 275 int flags; 276 { 277 struct wdc_obio_softc *sc = (void *)self; 278 struct channel_softc *chp = &sc->wdc_channel; 279 int error; 280 281 if ((error = wdcdetach(self, flags)) != 0) 282 return error; 283 284 intr_disestablish(sc->sc_ih); 285 286 free(sc->wdc_channel.ch_queue, M_DEVBUF); 287 288 /* Unmap our i/o space. */ 289 bus_space_unmap(chp->cmd_iot, chp->cmd_ioh, WDC_REG_NPORTS); 290 291 /* Unmap DMA registers. */ 292 /* XXX unmapiodev(sc->sc_dmareg); */ 293 /* XXX free(sc->sc_dmacmd); */ 294 295 return 0; 296 } 297 298 int 299 wdc_obio_dma_init(v, channel, drive, databuf, datalen, read) 300 void *v; 301 void *databuf; 302 size_t datalen; 303 int read; 304 { 305 struct wdc_obio_softc *sc = v; 306 vaddr_t va = (vaddr_t)databuf; 307 dbdma_command_t *cmdp; 308 u_int cmd, offset; 309 310 cmdp = sc->sc_dmacmd; 311 cmd = read ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE; 312 313 offset = va & PGOFSET; 314 315 /* if va is not page-aligned, setup the first page */ 316 if (offset != 0) { 317 int rest = NBPG - offset; /* the rest of the page */ 318 319 if (datalen > rest) { /* if continues to next page */ 320 DBDMA_BUILD(cmdp, cmd, 0, rest, vtophys(va), 321 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, 322 DBDMA_BRANCH_NEVER); 323 datalen -= rest; 324 va += rest; 325 cmdp++; 326 } 327 } 328 329 /* now va is page-aligned */ 330 while (datalen > NBPG) { 331 DBDMA_BUILD(cmdp, cmd, 0, NBPG, vtophys(va), 332 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 333 datalen -= NBPG; 334 va += NBPG; 335 cmdp++; 336 } 337 338 /* the last page (datalen <= NBPG here) */ 339 cmd = read ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST; 340 DBDMA_BUILD(cmdp, cmd, 0, datalen, vtophys(va), 341 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 342 cmdp++; 343 344 DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, 345 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 346 347 return 0; 348 } 349 350 void 351 wdc_obio_dma_start(v, channel, drive) 352 void *v; 353 int channel, drive; 354 { 355 struct wdc_obio_softc *sc = v; 356 357 dbdma_start(sc->sc_dmareg, sc->sc_dmacmd); 358 } 359 360 int 361 wdc_obio_dma_finish(v, channel, drive, read) 362 void *v; 363 int channel, drive; 364 int read; 365 { 366 struct wdc_obio_softc *sc = v; 367 368 dbdma_stop(sc->sc_dmareg); 369 return 0; 370 } 371