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
59struct 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
76u_int8_t wdc_obio_read_reg(struct channel_softc *, enum wdc_regs);
77void wdc_obio_write_reg(struct channel_softc *, enum wdc_regs, u_int8_t);
78
79struct 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
89int	wdc_obio_probe(struct device *, void *, void *);
90void	wdc_obio_attach(struct device *, struct device *, void *);
91int	wdc_obio_detach(struct device *, int);
92
93const struct cfattach wdc_obio_ca = {
94	sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach,
95	wdc_obio_detach
96};
97
98int	wdc_obio_dma_init(void *, int, int, void *, size_t, int);
99void	wdc_obio_dma_start(void *, int, int);
100int	wdc_obio_dma_finish(void *, int, int, int);
101void	wdc_obio_adjust_timing(struct channel_softc *);
102void	wdc_obio_ata4_adjust_timing(struct channel_softc *);
103void	wdc_obio_ata6_adjust_timing(struct channel_softc *);
104
105int
106wdc_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
129void
130wdc_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
232int
233wdc_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 */
257struct ide_timings {
258	int cycle;	/* minimum cycle time [ns] */
259	int active;	/* minimum command active time [ns] */
260};
261
262static 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
270static const struct ide_timings dma_timing[] = {
271	{ 480, 215 },	/* Mode 0 */
272	{ 150,  80 },	/* Mode 1 */
273	{ 120,  70 },	/* Mode 2 */
274};
275
276static 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. */
285static 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};
293static u_int32_t kauai_dma_timing[] = {
294	/*480*/	0x00618000,	/* Mode 0 */
295	/*360*/	0x00492000,	/* Mode 1 */
296	/*240*/	0x00149000	/* Mode 2 */ /* fw value */
297};
298static 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
325void
326wdc_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
390void
391wdc_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
471void
472wdc_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
535int
536wdc_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
567void
568wdc_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
575int
576wdc_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
590u_int8_t
591wdc_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
608void
609wdc_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