1 /* $OpenBSD: wdc_obio.c,v 1.31 2022/03/13 12:33:01 mpi Exp $ */
2 /* $NetBSD: wdc_obio.c,v 1.15 2001/07/25 20:26:33 bouyer Exp $ */
3
4 /*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Charles M. Hannum and by Onno van der Linden.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/malloc.h>
37
38 #include <uvm/uvm_extern.h>
39
40 #include <machine/bus.h>
41 #include <machine/autoconf.h>
42
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ata/atavar.h>
45 #include <dev/ata/atareg.h>
46 #include <dev/ic/wdcvar.h>
47
48 #include <macppc/dev/dbdma.h>
49
50 #define WDC_REG_NPORTS 8
51 #define WDC_AUXREG_OFFSET 0x16
52 #define WDC_DEFAULT_PIO_IRQ 13 /* XXX */
53 #define WDC_DEFAULT_DMA_IRQ 2 /* XXX */
54
55 #define WDC_OPTIONS_DMA 0x01
56
57 #define WDC_DMALIST_MAX 32
58
59 struct wdc_obio_softc {
60 struct wdc_softc sc_wdcdev;
61 struct channel_softc *wdc_chanptr;
62 struct channel_softc wdc_channel;
63
64 bus_dma_tag_t sc_dmat;
65 bus_dmamap_t sc_dmamap;
66 dbdma_regmap_t *sc_dmareg;
67 dbdma_command_t *sc_dmacmd;
68 dbdma_t sc_dbdma;
69
70 void *sc_ih;
71 int sc_use_dma;
72 bus_size_t sc_cmdsize;
73 size_t sc_dmasize;
74 };
75
76 u_int8_t wdc_obio_read_reg(struct channel_softc *, enum wdc_regs);
77 void wdc_obio_write_reg(struct channel_softc *, enum wdc_regs, u_int8_t);
78
79 struct channel_softc_vtbl wdc_obio_vtbl = {
80 wdc_obio_read_reg,
81 wdc_obio_write_reg,
82 wdc_default_lba48_write_reg,
83 wdc_default_read_raw_multi_2,
84 wdc_default_write_raw_multi_2,
85 wdc_default_read_raw_multi_4,
86 wdc_default_write_raw_multi_4
87 };
88
89 int wdc_obio_probe(struct device *, void *, void *);
90 void wdc_obio_attach(struct device *, struct device *, void *);
91 int wdc_obio_detach(struct device *, int);
92
93 const struct cfattach wdc_obio_ca = {
94 sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach,
95 wdc_obio_detach
96 };
97
98 int wdc_obio_dma_init(void *, int, int, void *, size_t, int);
99 void wdc_obio_dma_start(void *, int, int);
100 int wdc_obio_dma_finish(void *, int, int, int);
101 void wdc_obio_adjust_timing(struct channel_softc *);
102 void wdc_obio_ata4_adjust_timing(struct channel_softc *);
103 void wdc_obio_ata6_adjust_timing(struct channel_softc *);
104
105 int
wdc_obio_probe(struct device * parent,void * match,void * aux)106 wdc_obio_probe(struct device *parent, void *match, void *aux)
107 {
108 struct confargs *ca = aux;
109 char compat[32];
110
111 if (ca->ca_nreg < 8)
112 return 0;
113
114 /* XXX should not use name */
115 if (strcmp(ca->ca_name, "ATA") == 0 ||
116 strncmp(ca->ca_name, "ata", 3) == 0 ||
117 strcmp(ca->ca_name, "ide") == 0)
118 return 1;
119
120 bzero(compat, sizeof(compat));
121 OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
122 if (strcmp(compat, "heathrow-ata") == 0 ||
123 strcmp(compat, "keylargo-ata") == 0)
124 return 1;
125
126 return 0;
127 }
128
129 void
wdc_obio_attach(struct device * parent,struct device * self,void * aux)130 wdc_obio_attach(struct device *parent, struct device *self, void *aux)
131 {
132 struct wdc_obio_softc *sc = (void *)self;
133 struct confargs *ca = aux;
134 struct channel_softc *chp = &sc->wdc_channel;
135 int intr, error;
136 bus_addr_t cmdbase;
137
138 sc->sc_use_dma = 0;
139 if (ca->ca_nreg >= 16)
140 sc->sc_use_dma = 1; /* Enable dma */
141
142 sc->sc_dmat = ca->ca_dmat;
143 if ((error = bus_dmamap_create(sc->sc_dmat,
144 WDC_DMALIST_MAX * DBDMA_COUNT_MAX, WDC_DMALIST_MAX,
145 DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
146 printf(": cannot create dma map, error = %d\n", error);
147 return;
148 }
149
150 if (ca->ca_nintr >= 4 && ca->ca_nreg >= 8) {
151 intr = ca->ca_intr[0];
152 printf(" irq %d", intr);
153 } else if (ca->ca_nintr == -1) {
154 intr = WDC_DEFAULT_PIO_IRQ;
155 printf(" irq property not found; using %d", intr);
156 } else {
157 printf(": couldn't get irq property\n");
158 return;
159 }
160
161 if (sc->sc_use_dma)
162 printf(": DMA");
163
164 printf("\n");
165
166 chp->cmd_iot = chp->ctl_iot = ca->ca_iot;
167 chp->_vtbl = &wdc_obio_vtbl;
168
169 cmdbase = ca->ca_reg[0];
170 sc->sc_cmdsize = ca->ca_reg[1];
171
172 if (bus_space_map(chp->cmd_iot, cmdbase, sc->sc_cmdsize, 0,
173 &chp->cmd_ioh) || bus_space_subregion(chp->cmd_iot, chp->cmd_ioh,
174 /* WDC_AUXREG_OFFSET<<4 */ 0x160, 1, &chp->ctl_ioh)) {
175 printf("%s: couldn't map registers\n",
176 sc->sc_wdcdev.sc_dev.dv_xname);
177 return;
178 }
179 chp->data32iot = chp->cmd_iot;
180 chp->data32ioh = chp->cmd_ioh;
181
182 sc->sc_ih = mac_intr_establish(parent, intr, IST_LEVEL, IPL_BIO,
183 wdcintr, chp, sc->sc_wdcdev.sc_dev.dv_xname);
184
185 sc->sc_wdcdev.set_modes = wdc_obio_adjust_timing;
186 if (sc->sc_use_dma) {
187 sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, WDC_DMALIST_MAX + 1);
188 sc->sc_dmacmd = sc->sc_dbdma->d_addr;
189
190 sc->sc_dmareg = mapiodev(ca->ca_baseaddr + ca->ca_reg[2],
191 sc->sc_dmasize = ca->ca_reg[3]);
192
193 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
194 sc->sc_wdcdev.DMA_cap = 2;
195 if (strcmp(ca->ca_name, "ata-4") == 0) {
196 sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
197 WDC_CAPABILITY_MODE;
198 sc->sc_wdcdev.UDMA_cap = 4;
199 sc->sc_wdcdev.set_modes = wdc_obio_ata4_adjust_timing;
200 }
201 if (strcmp(ca->ca_name, "ata-6") == 0) {
202 sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
203 WDC_CAPABILITY_MODE;
204 sc->sc_wdcdev.UDMA_cap = 5;
205 sc->sc_wdcdev.set_modes = wdc_obio_ata6_adjust_timing;
206 }
207 }
208 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
209 sc->sc_wdcdev.PIO_cap = 4;
210 sc->wdc_chanptr = chp;
211 sc->sc_wdcdev.channels = &sc->wdc_chanptr;
212 sc->sc_wdcdev.nchannels = 1;
213 sc->sc_wdcdev.dma_arg = sc;
214 sc->sc_wdcdev.dma_init = wdc_obio_dma_init;
215 sc->sc_wdcdev.dma_start = wdc_obio_dma_start;
216 sc->sc_wdcdev.dma_finish = wdc_obio_dma_finish;
217 chp->channel = 0;
218 chp->wdc = &sc->sc_wdcdev;
219
220 chp->ch_queue = wdc_alloc_queue();
221 if (chp->ch_queue == NULL) {
222 printf("%s: cannot allocate channel queue",
223 sc->sc_wdcdev.sc_dev.dv_xname);
224 return;
225 }
226
227 wdcattach(chp);
228 sc->sc_wdcdev.set_modes(chp);
229 wdc_print_current_modes(chp);
230 }
231
232 int
wdc_obio_detach(struct device * self,int flags)233 wdc_obio_detach(struct device *self, int flags)
234 {
235 struct wdc_obio_softc *sc = (struct wdc_obio_softc *)self;
236 struct channel_softc *chp = &sc->wdc_channel;
237 int error;
238
239 if ((error = wdcdetach(chp, flags)) != 0)
240 return (error);
241
242 wdc_free_queue(chp->ch_queue);
243
244 if (sc->sc_use_dma) {
245 unmapiodev((void *)sc->sc_dmareg, sc->sc_dmasize);
246 dbdma_free(sc->sc_dbdma);
247 }
248 mac_intr_disestablish(NULL, sc->sc_ih);
249
250 bus_space_unmap(chp->cmd_iot, chp->cmd_ioh, sc->sc_cmdsize);
251 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
252
253 return (0);
254 }
255
256 /* Multiword DMA transfer timings */
257 struct ide_timings {
258 int cycle; /* minimum cycle time [ns] */
259 int active; /* minimum command active time [ns] */
260 };
261
262 static const struct ide_timings pio_timing[] = {
263 { 600, 165 }, /* Mode 0 */
264 { 383, 125 }, /* 1 */
265 { 240, 100 }, /* 2 */
266 { 180, 80 }, /* 3 */
267 { 120, 70 } /* 4 */
268 };
269
270 static const struct ide_timings dma_timing[] = {
271 { 480, 215 }, /* Mode 0 */
272 { 150, 80 }, /* Mode 1 */
273 { 120, 70 }, /* Mode 2 */
274 };
275
276 static const struct ide_timings udma_timing[] = {
277 {114, 0}, /* Mode 0 */
278 { 75, 0}, /* Mode 1 */
279 { 55, 0}, /* Mode 2 */
280 { 45, 100}, /* Mode 3 */
281 { 25, 100} /* Mode 4 */
282 };
283
284 /* these number _guessed_ from linux driver. */
285 static u_int32_t kauai_pio_timing[] = {
286 /*600*/ 0x08000a92, /* Mode 0 */
287 /*360*/ 0x08000492, /* Mode 1 */
288 /*240*/ 0x0800038b, /* Mode 2 */
289 /*180*/ 0x05000249, /* Mode 3 */
290 /*120*/ 0x04000148 /* Mode 4 */
291
292 };
293 static u_int32_t kauai_dma_timing[] = {
294 /*480*/ 0x00618000, /* Mode 0 */
295 /*360*/ 0x00492000, /* Mode 1 */
296 /*240*/ 0x00149000 /* Mode 2 */ /* fw value */
297 };
298 static u_int32_t kauai_udma_timing[] = {
299 /*120*/ 0x000070c0, /* Mode 0 */
300 /* 90*/ 0x00005d80, /* Mode 1 */
301 /* 60*/ 0x00004a60, /* Mode 2 */
302 /* 45*/ 0x00003a50, /* Mode 3 */
303 /* 30*/ 0x00002a30, /* Mode 4 */
304 /* 20*/ 0x00002921 /* Mode 5 */
305 };
306
307 #define TIME_TO_TICK(time) howmany((time), 30)
308 #define PIO_REC_OFFSET 4
309 #define PIO_REC_MIN 1
310 #define PIO_ACT_MIN 1
311 #define DMA_REC_OFFSET 1
312 #define DMA_REC_MIN 1
313 #define DMA_ACT_MIN 1
314
315 #define ATA4_TIME_TO_TICK(time) howmany((time) * 1000, 7500)
316
317 #define CONFIG_REG (0x200) /* IDE access timing register */
318 #define KAUAI_ULTRA_CONFIG (0x210) /* secondary config register (kauai)*/
319
320 #define KAUAI_PIO_MASK 0xff000fff
321 #define KAUAI_DMA_MASK 0x00fff000
322 #define KAUAI_UDMA_MASK 0x0000ffff
323 #define KAUAI_UDMA_EN 0x00000001
324
325 void
wdc_obio_adjust_timing(struct channel_softc * chp)326 wdc_obio_adjust_timing(struct channel_softc *chp)
327 {
328 struct ata_drive_datas *drvp;
329 u_int conf;
330 int drive;
331 int piomode = -1, dmamode = -1;
332 int min_cycle, min_active;
333 int cycle_tick, act_tick, inact_tick, half_tick;
334
335 for (drive = 0; drive < 2; drive++) {
336 drvp = &chp->ch_drive[drive];
337 if ((drvp->drive_flags & DRIVE) == 0)
338 continue;
339 if (piomode == -1 || piomode > drvp->PIO_mode)
340 piomode = drvp->PIO_mode;
341 if (drvp->drive_flags & DRIVE_DMA)
342 if (dmamode == -1 || dmamode > drvp->DMA_mode)
343 dmamode = drvp->DMA_mode;
344 }
345 if (piomode == -1)
346 return; /* No drive */
347 for (drive = 0; drive < 2; drive++) {
348 drvp = &chp->ch_drive[drive];
349 if (drvp->drive_flags & DRIVE) {
350 drvp->PIO_mode = piomode;
351 if (drvp->drive_flags & DRIVE_DMA)
352 drvp->DMA_mode = dmamode;
353 }
354 }
355 min_cycle = pio_timing[piomode].cycle;
356 min_active = pio_timing[piomode].active;
357
358 cycle_tick = TIME_TO_TICK(min_cycle);
359 act_tick = TIME_TO_TICK(min_active);
360 if (act_tick < PIO_ACT_MIN)
361 act_tick = PIO_ACT_MIN;
362 inact_tick = cycle_tick - act_tick - PIO_REC_OFFSET;
363 if (inact_tick < PIO_REC_MIN)
364 inact_tick = PIO_REC_MIN;
365 /* mask: 0x000007ff */
366 conf = (inact_tick << 5) | act_tick;
367 if (dmamode != -1) {
368 /* there are active DMA mode */
369
370 min_cycle = dma_timing[dmamode].cycle;
371 min_active = dma_timing[dmamode].active;
372 cycle_tick = TIME_TO_TICK(min_cycle);
373 act_tick = TIME_TO_TICK(min_active);
374 inact_tick = cycle_tick - act_tick - DMA_REC_OFFSET;
375 if (inact_tick < DMA_REC_MIN)
376 inact_tick = DMA_REC_MIN;
377 half_tick = 0; /* XXX */
378 /* mask: 0xfffff800 */
379 conf |=
380 (half_tick << 21) |
381 (inact_tick << 16) | (act_tick << 11);
382 }
383 bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
384 #if 0
385 printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n",
386 conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick);
387 #endif
388 }
389
390 void
wdc_obio_ata4_adjust_timing(struct channel_softc * chp)391 wdc_obio_ata4_adjust_timing(struct channel_softc *chp)
392 {
393 struct ata_drive_datas *drvp;
394 u_int conf;
395 int drive;
396 int piomode = -1, dmamode = -1;
397 int min_cycle, min_active;
398 int cycle_tick, act_tick, inact_tick;
399 int udmamode = -1;
400
401 for (drive = 0; drive < 2; drive++) {
402 drvp = &chp->ch_drive[drive];
403 if ((drvp->drive_flags & DRIVE) == 0)
404 continue;
405 if (piomode == -1 || piomode > drvp->PIO_mode)
406 piomode = drvp->PIO_mode;
407 if (drvp->drive_flags & DRIVE_DMA)
408 if (dmamode == -1 || dmamode > drvp->DMA_mode)
409 dmamode = drvp->DMA_mode;
410 if (drvp->drive_flags & DRIVE_UDMA) {
411 if (udmamode == -1 || udmamode > drvp->UDMA_mode)
412 udmamode = drvp->UDMA_mode;
413 } else
414 udmamode = -2;
415 }
416 if (piomode == -1)
417 return; /* No drive */
418 for (drive = 0; drive < 2; drive++) {
419 drvp = &chp->ch_drive[drive];
420 if (drvp->drive_flags & DRIVE) {
421 drvp->PIO_mode = piomode;
422 if (drvp->drive_flags & DRIVE_DMA)
423 drvp->DMA_mode = dmamode;
424 if (drvp->drive_flags & DRIVE_UDMA) {
425 if (udmamode == -2)
426 drvp->drive_flags &= ~DRIVE_UDMA;
427 else
428 drvp->UDMA_mode = udmamode;
429 }
430 }
431 }
432
433 if (udmamode == -2)
434 udmamode = -1;
435
436 min_cycle = pio_timing[piomode].cycle;
437 min_active = pio_timing[piomode].active;
438
439 cycle_tick = ATA4_TIME_TO_TICK(min_cycle);
440 act_tick = ATA4_TIME_TO_TICK(min_active);
441 inact_tick = cycle_tick - act_tick;
442 /* mask: 0x000003ff */
443 conf = (inact_tick << 5) | act_tick;
444 if (dmamode != -1) {
445 /* there are active DMA mode */
446
447 min_cycle = dma_timing[dmamode].cycle;
448 min_active = dma_timing[dmamode].active;
449 cycle_tick = ATA4_TIME_TO_TICK(min_cycle);
450 act_tick = ATA4_TIME_TO_TICK(min_active);
451 inact_tick = cycle_tick - act_tick;
452 /* mask: 0x001ffc00 */
453 conf |= (act_tick << 10) | (inact_tick << 15);
454 }
455 if (udmamode != -1) {
456 min_cycle = udma_timing[udmamode].cycle;
457 min_active = udma_timing[udmamode].active;
458 act_tick = ATA4_TIME_TO_TICK(min_active);
459 cycle_tick = ATA4_TIME_TO_TICK(min_cycle);
460 /* mask: 0x1ff00000 */
461 conf |= (cycle_tick << 21) | (act_tick << 25) | 0x100000;
462 }
463
464 bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
465 #if 0
466 printf("ata4 conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n",
467 conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick);
468 #endif
469 }
470
471 void
wdc_obio_ata6_adjust_timing(struct channel_softc * chp)472 wdc_obio_ata6_adjust_timing(struct channel_softc *chp)
473 {
474 struct ata_drive_datas *drvp;
475 u_int conf, conf1;
476 int drive;
477 int piomode = -1, dmamode = -1;
478 int udmamode = -1;
479
480 for (drive = 0; drive < 2; drive++) {
481 drvp = &chp->ch_drive[drive];
482 if ((drvp->drive_flags & DRIVE) == 0)
483 continue;
484 if (piomode == -1 || piomode > drvp->PIO_mode)
485 piomode = drvp->PIO_mode;
486 if (drvp->drive_flags & DRIVE_DMA) {
487 if (dmamode == -1 || dmamode > drvp->DMA_mode)
488 dmamode = drvp->DMA_mode;
489 }
490 if (drvp->drive_flags & DRIVE_UDMA) {
491 if (udmamode == -1 || udmamode > drvp->UDMA_mode)
492 udmamode = drvp->UDMA_mode;
493 } else
494 udmamode = -2;
495 }
496 if (piomode == -1)
497 return; /* No drive */
498 for (drive = 0; drive < 2; drive++) {
499 drvp = &chp->ch_drive[drive];
500 if (drvp->drive_flags & DRIVE) {
501 drvp->PIO_mode = piomode;
502 if (drvp->drive_flags & DRIVE_DMA)
503 drvp->DMA_mode = dmamode;
504 if (drvp->drive_flags & DRIVE_UDMA) {
505 if (udmamode == -2)
506 drvp->drive_flags &= ~DRIVE_UDMA;
507 else
508 drvp->UDMA_mode = udmamode;
509 }
510 }
511 }
512
513 if (udmamode == -2)
514 udmamode = -1;
515
516 conf = bus_space_read_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG);
517 conf1 = bus_space_read_4(chp->cmd_iot, chp->cmd_ioh,
518 KAUAI_ULTRA_CONFIG);
519
520 conf = (conf & ~KAUAI_PIO_MASK) | kauai_pio_timing[piomode];
521
522 if (dmamode != -1)
523 conf = (conf & ~KAUAI_DMA_MASK) | kauai_dma_timing[dmamode];
524 if (udmamode != -1)
525 conf1 = (conf1 & ~KAUAI_UDMA_MASK) |
526 kauai_udma_timing[udmamode] | KAUAI_UDMA_EN;
527 else
528 conf1 = conf1 & ~KAUAI_UDMA_EN;
529
530 bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
531 bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, KAUAI_ULTRA_CONFIG,
532 conf1);
533 }
534
535 int
wdc_obio_dma_init(void * v,int channel,int drive,void * databuf,size_t datalen,int flags)536 wdc_obio_dma_init(void *v, int channel, int drive, void *databuf,
537 size_t datalen, int flags)
538 {
539 struct wdc_obio_softc *sc = v;
540 dbdma_command_t *cmdp;
541 u_int cmd;
542 int i, error;
543
544 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, databuf,
545 datalen, NULL, BUS_DMA_NOWAIT)) != 0)
546 return (error);
547
548 cmdp = sc->sc_dmacmd;
549 cmd = (flags & WDC_DMA_READ) ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
550
551 for (i = 0; i < sc->sc_dmamap->dm_nsegs; i++, cmdp++) {
552 if (i + 1 == sc->sc_dmamap->dm_nsegs)
553 cmd = (flags & WDC_DMA_READ) ? DBDMA_CMD_IN_LAST :
554 DBDMA_CMD_OUT_LAST;
555
556 DBDMA_BUILD(cmdp, cmd, 0, sc->sc_dmamap->dm_segs[i].ds_len,
557 sc->sc_dmamap->dm_segs[i].ds_addr,
558 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
559 }
560
561 DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
562 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
563
564 return 0;
565 }
566
567 void
wdc_obio_dma_start(void * v,int channel,int drive)568 wdc_obio_dma_start(void *v, int channel, int drive)
569 {
570 struct wdc_obio_softc *sc = v;
571
572 dbdma_start(sc->sc_dmareg, sc->sc_dbdma);
573 }
574
575 int
wdc_obio_dma_finish(void * v,int channel,int drive,int force)576 wdc_obio_dma_finish(void *v, int channel, int drive, int force)
577 {
578 struct wdc_obio_softc *sc = v;
579
580 dbdma_stop(sc->sc_dmareg);
581 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
582 return 0;
583 }
584
585 /* read register code
586 * this allows the registers to be spaced by 0x10, instead of 0x1.
587 * mac hardware (obio) requires this.
588 */
589
590 u_int8_t
wdc_obio_read_reg(struct channel_softc * chp,enum wdc_regs reg)591 wdc_obio_read_reg(struct channel_softc *chp, enum wdc_regs reg)
592 {
593 #ifdef DIAGNOSTIC
594 if (reg & _WDC_WRONLY) {
595 printf ("wdc_obio_read_reg: reading from a write-only register %d\n", reg);
596 }
597 #endif
598
599 if (reg & _WDC_AUX)
600 return (bus_space_read_1(chp->ctl_iot, chp->ctl_ioh,
601 (reg & _WDC_REGMASK) << 4));
602 else
603 return (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
604 (reg & _WDC_REGMASK) << 4));
605 }
606
607
608 void
wdc_obio_write_reg(struct channel_softc * chp,enum wdc_regs reg,u_int8_t val)609 wdc_obio_write_reg(struct channel_softc *chp, enum wdc_regs reg, u_int8_t val)
610 {
611 #ifdef DIAGNOSTIC
612 if (reg & _WDC_RDONLY) {
613 printf ("wdc_obio_write_reg: writing to a read-only register %d\n", reg);
614 }
615 #endif
616
617 if (reg & _WDC_AUX)
618 bus_space_write_1(chp->ctl_iot, chp->ctl_ioh,
619 (reg & _WDC_REGMASK) << 4, val);
620 else
621 bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
622 (reg & _WDC_REGMASK) << 4, val);
623 }
624