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