1164426Ssam/*-
2164426Ssam * Copyright (c) 2006 Sam Leffler, Errno Consulting
3164426Ssam * All rights reserved.
4164426Ssam *
5164426Ssam * Redistribution and use in source and binary forms, with or without
6164426Ssam * modification, are permitted provided that the following conditions
7164426Ssam * are met:
8164426Ssam * 1. Redistributions of source code must retain the above copyright
9164426Ssam *    notice, this list of conditions and the following disclaimer,
10164426Ssam *    without modification.
11164426Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12164426Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13164426Ssam *    redistribution must be conditioned upon including a substantially
14164426Ssam *    similar Disclaimer requirement for further binary redistribution.
15164426Ssam *
16164426Ssam * NO WARRANTY
17164426Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18164426Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19164426Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20164426Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21164426Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22164426Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23164426Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24164426Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25164426Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26164426Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27164426Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28164426Ssam */
29164426Ssam
30164426Ssam#include <sys/cdefs.h>
31164426Ssam__FBSDID("$FreeBSD$");
32164426Ssam
33164426Ssam/*
34164426Ssam * Compact Flash Support for the Avila Gateworks XScale boards.
35167565Sjhay * The CF slot is operated in "True IDE" mode. Registers are on
36167565Sjhay * the Expansion Bus connected to CS1 and CS2. Interrupts are
37167565Sjhay * tied to GPIO pin 12.  No DMA, just PIO.
38164426Ssam *
39167565Sjhay * The ADI Pronghorn Metro is very similar. It use CS3 and CS4 and
40167565Sjhay * GPIO pin 0 for interrupts.
41167565Sjhay *
42164426Ssam * See also http://www.intel.com/design/network/applnots/302456.htm.
43164426Ssam */
44164426Ssam#include <sys/param.h>
45164426Ssam#include <sys/systm.h>
46164426Ssam#include <sys/kernel.h>
47164426Ssam#include <sys/module.h>
48164426Ssam#include <sys/time.h>
49164426Ssam#include <sys/bus.h>
50164426Ssam#include <sys/resource.h>
51164426Ssam#include <sys/rman.h>
52164426Ssam#include <sys/sysctl.h>
53164426Ssam#include <sys/endian.h>
54164426Ssam
55164426Ssam#include <machine/bus.h>
56164426Ssam#include <machine/cpu.h>
57164426Ssam#include <machine/cpufunc.h>
58164426Ssam#include <machine/resource.h>
59164426Ssam#include <machine/intr.h>
60164426Ssam#include <arm/xscale/ixp425/ixp425reg.h>
61164426Ssam#include <arm/xscale/ixp425/ixp425var.h>
62164426Ssam
63164426Ssam#include <sys/ata.h>
64164426Ssam#include <sys/sema.h>
65164426Ssam#include <sys/taskqueue.h>
66164426Ssam#include <vm/uma.h>
67164426Ssam#include <dev/ata/ata-all.h>
68164426Ssam#include <ata_if.h>
69164426Ssam
70186352Ssam#define	AVILA_IDE_CTRL	0x06
71164426Ssam
72186352Ssamstruct ata_config {
73186352Ssam	const char	*desc;		/* description for probe */
74186352Ssam	uint8_t		gpin;		/* GPIO pin */
75186352Ssam	uint8_t		irq;		/* IRQ */
76186352Ssam	uint32_t	base16;		/* CS base addr for 16-bit */
77186352Ssam	uint32_t	size16;		/* CS size for 16-bit */
78186352Ssam	uint32_t	off16;		/* CS offset for 16-bit */
79186352Ssam	uint32_t	basealt;	/* CS base addr for alt */
80186352Ssam	uint32_t	sizealt;	/* CS size for alt */
81186352Ssam	uint32_t	offalt;		/* CS offset for alt */
82186352Ssam};
83167565Sjhay
84186352Ssamstatic const struct ata_config *
85186352Ssamata_getconfig(struct ixp425_softc *sa)
86186352Ssam{
87186352Ssam	static const struct ata_config configs[] = {
88186352Ssam		{ .desc		= "Gateworks Avila IDE/CF Controller",
89186352Ssam		  .gpin		= 12,
90186352Ssam		  .irq		= IXP425_INT_GPIO_12,
91186352Ssam		  .base16	= IXP425_EXP_BUS_CS1_HWBASE,
92186352Ssam		  .size16	= IXP425_EXP_BUS_CS1_SIZE,
93186352Ssam		  .off16	= EXP_TIMING_CS1_OFFSET,
94186352Ssam		  .basealt	= IXP425_EXP_BUS_CS2_HWBASE,
95186352Ssam		  .sizealt	= IXP425_EXP_BUS_CS2_SIZE,
96186352Ssam		  .offalt	= EXP_TIMING_CS2_OFFSET,
97186352Ssam		},
98186352Ssam		{ .desc		= "Gateworks Cambria IDE/CF Controller",
99186352Ssam		  .gpin		= 12,
100186352Ssam		  .irq		= IXP425_INT_GPIO_12,
101186352Ssam		  .base16	= CAMBRIA_CFSEL0_HWBASE,
102186352Ssam		  .size16	= CAMBRIA_CFSEL0_SIZE,
103186352Ssam		  .off16	= EXP_TIMING_CS3_OFFSET,
104186352Ssam		  .basealt	= CAMBRIA_CFSEL1_HWBASE,
105186352Ssam		  .sizealt	= CAMBRIA_CFSEL1_SIZE,
106186352Ssam		  .offalt	= EXP_TIMING_CS4_OFFSET,
107186352Ssam		},
108186352Ssam		{ .desc		= "ADI Pronghorn Metro IDE/CF Controller",
109186352Ssam		  .gpin		= 0,
110186352Ssam		  .irq		= IXP425_INT_GPIO_0,
111186352Ssam		  .base16	= IXP425_EXP_BUS_CS3_HWBASE,
112186352Ssam		  .size16	= IXP425_EXP_BUS_CS3_SIZE,
113186352Ssam		  .off16	= EXP_TIMING_CS3_OFFSET,
114186352Ssam		  .basealt	= IXP425_EXP_BUS_CS4_HWBASE,
115186352Ssam		  .sizealt	= IXP425_EXP_BUS_CS4_SIZE,
116186352Ssam		  .offalt	= EXP_TIMING_CS4_OFFSET,
117186352Ssam		},
118186352Ssam	};
119186352Ssam
120186352Ssam	/* XXX honor hint? (but then no multi-board support) */
121186352Ssam	/* XXX total hack */
122194753Ssam	if (cpu_is_ixp43x())
123186352Ssam		return &configs[1];		/* Cambria */
124186352Ssam	if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
125186352Ssam		return &configs[0];		/* Avila */
126186352Ssam	return &configs[2];			/* Pronghorn */
127186352Ssam}
128186352Ssam
129164426Ssamstruct ata_avila_softc {
130164426Ssam	device_t		sc_dev;
131164426Ssam	bus_space_tag_t		sc_iot;
132164426Ssam	bus_space_handle_t	sc_exp_ioh;	/* Exp Bus config registers */
133167565Sjhay	bus_space_handle_t	sc_ioh;		/* CS1/3 data registers */
134167565Sjhay	bus_space_handle_t	sc_alt_ioh;	/* CS2/4 data registers */
135164426Ssam	struct bus_space	sc_expbus_tag;
136164426Ssam	struct resource		sc_ata;		/* hand-crafted for ATA */
137167565Sjhay	struct resource		sc_alt_ata;	/* hand-crafted for ATA */
138167565Sjhay	u_int32_t		sc_16bit_off;	/* EXP_TIMING_CSx_OFFSET */
139164426Ssam	int			sc_rid;		/* rid for IRQ */
140164426Ssam	struct resource		*sc_irq;	/* IRQ resource */
141164426Ssam	void			*sc_ih;		/* interrupt handler */
142164426Ssam	struct {
143164426Ssam		void	(*cb)(void *);
144164426Ssam		void	*arg;
145164426Ssam	} sc_intr[1];			/* NB: 1/channel */
146164426Ssam};
147164426Ssam
148164426Ssamstatic void ata_avila_intr(void *);
149164426Ssambs_protos(ata);
150278727Sianstatic	void ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t,
151164426Ssam		u_int16_t *, bus_size_t);
152278727Sianstatic	void ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t,
153164426Ssam		const u_int16_t *, bus_size_t);
154164426Ssam
155164426Ssamstatic int
156164426Ssamata_avila_probe(device_t dev)
157164426Ssam{
158167565Sjhay	struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
159186352Ssam	const struct ata_config *config;
160167565Sjhay
161186352Ssam	config = ata_getconfig(sa);
162186352Ssam	if (config != NULL) {
163186352Ssam		device_set_desc_copy(dev, config->desc);
164186352Ssam		return 0;
165186352Ssam	}
166186352Ssam	return ENXIO;
167164426Ssam}
168164426Ssam
169164426Ssamstatic int
170164426Ssamata_avila_attach(device_t dev)
171164426Ssam{
172164426Ssam	struct ata_avila_softc *sc = device_get_softc(dev);
173164426Ssam	struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
174186352Ssam	const struct ata_config	*config;
175164426Ssam
176186352Ssam	config = ata_getconfig(sa);
177186352Ssam	KASSERT(config != NULL, ("no board config"));
178186352Ssam
179164426Ssam	sc->sc_dev = dev;
180164426Ssam	/* NB: borrow from parent */
181164426Ssam	sc->sc_iot = sa->sc_iot;
182164426Ssam	sc->sc_exp_ioh = sa->sc_exp_ioh;
183167565Sjhay
184186352Ssam	if (bus_space_map(sc->sc_iot, config->base16, config->size16,
185186352Ssam	    0, &sc->sc_ioh))
186186352Ssam		panic("%s: cannot map 16-bit window (0x%x/0x%x)",
187186352Ssam		    __func__, config->base16, config->size16);
188186352Ssam	if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt,
189186352Ssam	    0, &sc->sc_alt_ioh))
190186352Ssam		panic("%s: cannot map alt window (0x%x/0x%x)",
191186352Ssam		    __func__, config->basealt, config->sizealt);
192186352Ssam	sc->sc_16bit_off = config->off16;
193186352Ssam
194194753Ssam	if (config->base16 != CAMBRIA_CFSEL0_HWBASE) {
195194753Ssam		/*
196194753Ssam		 * Craft special resource for ATA bus space ops
197194753Ssam		 * that go through the expansion bus and require
198194753Ssam		 * special hackery to ena/dis 16-bit operations.
199194753Ssam		 *
200194753Ssam		 * XXX probably should just make this generic for
201194753Ssam		 * accessing the expansion bus.
202194753Ssam		 */
203278727Sian		sc->sc_expbus_tag.bs_privdata = sc;	/* NB: backpointer */
204194753Ssam		/* read single */
205305615Spfg		sc->sc_expbus_tag.bs_r_1	= ata_bs_r_1;
206305615Spfg		sc->sc_expbus_tag.bs_r_2	= ata_bs_r_2;
207194753Ssam		/* read multiple */
208305615Spfg		sc->sc_expbus_tag.bs_rm_2	= ata_bs_rm_2;
209305615Spfg		sc->sc_expbus_tag.bs_rm_2_s	= ata_bs_rm_2_s;
210194753Ssam		/* write (single) */
211305615Spfg		sc->sc_expbus_tag.bs_w_1	= ata_bs_w_1;
212305615Spfg		sc->sc_expbus_tag.bs_w_2	= ata_bs_w_2;
213194753Ssam		/* write multiple */
214305615Spfg		sc->sc_expbus_tag.bs_wm_2	= ata_bs_wm_2;
215305615Spfg		sc->sc_expbus_tag.bs_wm_2_s	= ata_bs_wm_2_s;
216164426Ssam
217194753Ssam		rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
218194753Ssam		rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag);
219194753Ssam	} else {
220194753Ssam		/*
221194753Ssam		 * On Cambria use the shared CS3 expansion bus tag
222194753Ssam		 * that handles interlock for sharing access with the
223194753Ssam		 * optional UART's.
224194753Ssam		 */
225194753Ssam		rman_set_bustag(&sc->sc_ata, &cambria_exp_bs_tag);
226194753Ssam		rman_set_bustag(&sc->sc_alt_ata, &cambria_exp_bs_tag);
227194753Ssam	}
228164426Ssam	rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
229167565Sjhay	rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
230164426Ssam
231194653Ssam	ixp425_set_gpio(sa, config->gpin, GPIO_TYPE_EDG_RISING);
232164426Ssam
233167565Sjhay	/* configure CS1/3 window, leaving timing unchanged */
234167565Sjhay	EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
235167565Sjhay	    EXP_BUS_READ_4(sc, sc->sc_16bit_off) |
236164426Ssam	        EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
237167565Sjhay	/* configure CS2/4 window, leaving timing unchanged */
238186352Ssam	EXP_BUS_WRITE_4(sc, config->offalt,
239186352Ssam	    EXP_BUS_READ_4(sc, config->offalt) |
240167565Sjhay	        EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
241164426Ssam
242164426Ssam	/* setup interrupt */
243164426Ssam	sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
244186352Ssam	    config->irq, config->irq, 1, RF_ACTIVE);
245164426Ssam	if (!sc->sc_irq)
246186352Ssam		panic("Unable to allocate irq %u.\n", config->irq);
247164426Ssam	bus_setup_intr(dev, sc->sc_irq,
248164426Ssam	    INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
249166996Scognet	    NULL, ata_avila_intr, sc, &sc->sc_ih);
250164426Ssam
251164426Ssam	/* attach channel on this controller */
252194044Simp	device_add_child(dev, "ata", -1);
253164426Ssam	bus_generic_attach(dev);
254164426Ssam
255164426Ssam	return 0;
256164426Ssam}
257164426Ssam
258164426Ssamstatic int
259164426Ssamata_avila_detach(device_t dev)
260164426Ssam{
261164426Ssam	struct ata_avila_softc *sc = device_get_softc(dev);
262164426Ssam
263164426Ssam	/* XXX quiesce gpio? */
264164426Ssam
265164426Ssam	/* detach & delete all children */
266227849Shselasky	device_delete_children(dev);
267164426Ssam
268164426Ssam	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
269164426Ssam	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
270164426Ssam
271164426Ssam	return 0;
272164426Ssam}
273164426Ssam
274164426Ssamstatic void
275164426Ssamata_avila_intr(void *xsc)
276164426Ssam{
277164426Ssam	struct ata_avila_softc *sc = xsc;
278164426Ssam
279164426Ssam	if (sc->sc_intr[0].cb != NULL)
280164426Ssam		sc->sc_intr[0].cb(sc->sc_intr[0].arg);
281164426Ssam}
282164426Ssam
283164426Ssamstatic struct resource *
284164426Ssamata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
285164426Ssam		       u_long start, u_long end, u_long count, u_int flags)
286164426Ssam{
287164426Ssam	struct ata_avila_softc *sc = device_get_softc(dev);
288164426Ssam
289164426Ssam	KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
290164426Ssam	    ("type %u rid %u start %lu end %lu count %lu flags %u",
291164426Ssam	     type, *rid, start, end, count, flags));
292164426Ssam
293164426Ssam	/* doesn't matter what we return so reuse the real thing */
294164426Ssam	return sc->sc_irq;
295164426Ssam}
296164426Ssam
297164426Ssamstatic int
298164426Ssamata_avila_release_resource(device_t dev, device_t child, int type, int rid,
299164426Ssam			 struct resource *r)
300164426Ssam{
301164426Ssam	KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
302164426Ssam	    ("type %u rid %u", type, rid));
303164426Ssam	return 0;
304164426Ssam}
305164426Ssam
306164426Ssamstatic int
307236987Simpata_avila_setup_intr(device_t dev, device_t child, struct resource *irq,
308166996Scognet		   int flags, driver_filter_t *filt,
309166996Scognet		   driver_intr_t *function, void *argument, void **cookiep)
310164426Ssam{
311164426Ssam	struct ata_avila_softc *sc = device_get_softc(dev);
312164426Ssam	int unit = ((struct ata_channel *)device_get_softc(child))->unit;
313164426Ssam
314164426Ssam	KASSERT(unit == 0, ("unit %d", unit));
315164426Ssam	sc->sc_intr[unit].cb = function;
316164426Ssam	sc->sc_intr[unit].arg = argument;
317164426Ssam	*cookiep = sc;
318164426Ssam	return 0;
319164426Ssam}
320164426Ssam
321164426Ssamstatic int
322164426Ssamata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
323164426Ssam		      void *cookie)
324164426Ssam{
325164426Ssam	struct ata_avila_softc *sc = device_get_softc(dev);
326164426Ssam	int unit = ((struct ata_channel *)device_get_softc(child))->unit;
327164426Ssam
328164426Ssam	KASSERT(unit == 0, ("unit %d", unit));
329164426Ssam	sc->sc_intr[unit].cb = NULL;
330164426Ssam	sc->sc_intr[unit].arg = NULL;
331164426Ssam	return 0;
332164426Ssam}
333164426Ssam
334164426Ssam/*
335164426Ssam * Bus space accessors for CF-IDE PIO operations.
336164426Ssam */
337164426Ssam
338164426Ssam/*
339164426Ssam * Enable/disable 16-bit ops on the expansion bus.
340164426Ssam */
341186352Ssamstatic __inline void
342164426Ssamenable_16(struct ata_avila_softc *sc)
343164426Ssam{
344167565Sjhay	EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
345167565Sjhay	    EXP_BUS_READ_4(sc, sc->sc_16bit_off) &~ EXP_BYTE_EN);
346164426Ssam	DELAY(100);		/* XXX? */
347164426Ssam}
348164426Ssam
349186352Ssamstatic __inline void
350164426Ssamdisable_16(struct ata_avila_softc *sc)
351164426Ssam{
352164426Ssam	DELAY(100);		/* XXX? */
353167565Sjhay	EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
354167565Sjhay	    EXP_BUS_READ_4(sc, sc->sc_16bit_off) | EXP_BYTE_EN);
355164426Ssam}
356164426Ssam
357164426Ssamuint8_t
358278727Sianata_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o)
359164426Ssam{
360278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
361164426Ssam
362164426Ssam	return bus_space_read_1(sc->sc_iot, h, o);
363164426Ssam}
364164426Ssam
365164426Ssamvoid
366278727Sianata_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v)
367164426Ssam{
368278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
369164426Ssam
370164426Ssam	bus_space_write_1(sc->sc_iot, h, o, v);
371164426Ssam}
372164426Ssam
373164426Ssamuint16_t
374278727Sianata_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o)
375164426Ssam{
376278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
377164426Ssam	uint16_t v;
378164426Ssam
379164426Ssam	enable_16(sc);
380164426Ssam	v = bus_space_read_2(sc->sc_iot, h, o);
381164426Ssam	disable_16(sc);
382164426Ssam	return v;
383164426Ssam}
384164426Ssam
385164426Ssamvoid
386278727Sianata_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v)
387164426Ssam{
388278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
389164426Ssam
390164426Ssam	enable_16(sc);
391164426Ssam	bus_space_write_2(sc->sc_iot, h, o, v);
392164426Ssam	disable_16(sc);
393164426Ssam}
394164426Ssam
395164426Ssamvoid
396278727Sianata_bs_rm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
397164426Ssam	u_int16_t *d, bus_size_t c)
398164426Ssam{
399278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
400164426Ssam
401164426Ssam	enable_16(sc);
402164426Ssam	bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
403164426Ssam	disable_16(sc);
404164426Ssam}
405164426Ssam
406164426Ssamvoid
407278727Sianata_bs_wm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
408164426Ssam	const u_int16_t *d, bus_size_t c)
409164426Ssam{
410278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
411164426Ssam
412164426Ssam	enable_16(sc);
413164426Ssam	bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
414164426Ssam	disable_16(sc);
415164426Ssam}
416164426Ssam
417164426Ssam/* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
418164426Ssam
419164426Ssamvoid
420278727Sianata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
421164426Ssam	u_int16_t *d, bus_size_t c)
422164426Ssam{
423278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
424164426Ssam	uint16_t v;
425164426Ssam	bus_size_t i;
426164426Ssam
427164426Ssam	enable_16(sc);
428164426Ssam#if 1
429164426Ssam	for (i = 0; i < c; i++) {
430164426Ssam		v = bus_space_read_2(sc->sc_iot, h, o);
431164426Ssam		d[i] = bswap16(v);
432164426Ssam	}
433164426Ssam#else
434164426Ssam	bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
435164426Ssam#endif
436164426Ssam	disable_16(sc);
437164426Ssam}
438164426Ssam
439164426Ssamvoid
440278727Sianata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
441164426Ssam	const u_int16_t *d, bus_size_t c)
442164426Ssam{
443278727Sian	struct ata_avila_softc *sc = tag->bs_privdata;
444164426Ssam	bus_size_t i;
445164426Ssam
446164426Ssam	enable_16(sc);
447164426Ssam#if 1
448164426Ssam	for (i = 0; i < c; i++)
449164426Ssam		bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
450164426Ssam#else
451164426Ssam	bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
452164426Ssam#endif
453164426Ssam	disable_16(sc);
454164426Ssam}
455164426Ssam
456164426Ssamstatic device_method_t ata_avila_methods[] = {
457164426Ssam	/* device interface */
458164426Ssam	DEVMETHOD(device_probe,             ata_avila_probe),
459164426Ssam	DEVMETHOD(device_attach,            ata_avila_attach),
460164426Ssam	DEVMETHOD(device_detach,            ata_avila_detach),
461164426Ssam	DEVMETHOD(device_shutdown,          bus_generic_shutdown),
462164426Ssam	DEVMETHOD(device_suspend,           bus_generic_suspend),
463164426Ssam	DEVMETHOD(device_resume,            bus_generic_resume),
464164426Ssam
465164426Ssam	/* bus methods */
466164426Ssam	DEVMETHOD(bus_alloc_resource,       ata_avila_alloc_resource),
467164426Ssam	DEVMETHOD(bus_release_resource,     ata_avila_release_resource),
468164426Ssam	DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
469164426Ssam	DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
470164426Ssam	DEVMETHOD(bus_setup_intr,           ata_avila_setup_intr),
471164426Ssam	DEVMETHOD(bus_teardown_intr,        ata_avila_teardown_intr),
472164426Ssam
473164426Ssam	{ 0, 0 }
474164426Ssam};
475164426Ssam
476164426Ssamdevclass_t ata_avila_devclass;
477164426Ssam
478164426Ssamstatic driver_t ata_avila_driver = {
479164426Ssam	"ata_avila",
480164426Ssam	ata_avila_methods,
481164426Ssam	sizeof(struct ata_avila_softc),
482164426Ssam};
483164426Ssam
484164426SsamDRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0);
485164426SsamMODULE_VERSION(ata_avila, 1);
486164426SsamMODULE_DEPEND(ata_avila, ata, 1, 1, 1);
487164426Ssam
488164426Ssamstatic int
489164426Ssamavila_channel_probe(device_t dev)
490164426Ssam{
491164426Ssam	struct ata_channel *ch = device_get_softc(dev);
492164426Ssam
493164426Ssam	ch->unit = 0;
494164426Ssam	ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
495164426Ssam	device_set_desc_copy(dev, "ATA channel 0");
496164426Ssam
497164426Ssam	return ata_probe(dev);
498164426Ssam}
499164426Ssam
500164426Ssamstatic int
501164426Ssamavila_channel_attach(device_t dev)
502164426Ssam{
503164426Ssam	struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
504164426Ssam	struct ata_channel *ch = device_get_softc(dev);
505164426Ssam	int i;
506164426Ssam
507164426Ssam	for (i = 0; i < ATA_MAX_RES; i++)
508164426Ssam		ch->r_io[i].res = &sc->sc_ata;
509164426Ssam
510164426Ssam	ch->r_io[ATA_DATA].offset = ATA_DATA;
511164426Ssam	ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
512164426Ssam	ch->r_io[ATA_COUNT].offset = ATA_COUNT;
513164426Ssam	ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
514164426Ssam	ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
515164426Ssam	ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
516164426Ssam	ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
517164426Ssam	ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
518164426Ssam	ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
519164426Ssam	/* NB: should be used only for ATAPI devices */
520164426Ssam	ch->r_io[ATA_IREASON].offset = ATA_COUNT;
521164426Ssam	ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
522164426Ssam
523167565Sjhay	/* NB: the control and alt status registers are special */
524167565Sjhay	ch->r_io[ATA_ALTSTAT].res = &sc->sc_alt_ata;
525167565Sjhay	ch->r_io[ATA_ALTSTAT].offset = AVILA_IDE_CTRL;
526167565Sjhay	ch->r_io[ATA_CONTROL].res = &sc->sc_alt_ata;
527164426Ssam	ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
528164426Ssam
529164426Ssam	/* NB: by convention this points at the base of registers */
530164426Ssam	ch->r_io[ATA_IDX_ADDR].offset = 0;
531164426Ssam
532164426Ssam	ata_generic_hw(dev);
533164426Ssam	return ata_attach(dev);
534164426Ssam}
535164426Ssam
536164426Ssamstatic device_method_t avila_channel_methods[] = {
537164426Ssam	/* device interface */
538164426Ssam	DEVMETHOD(device_probe,     avila_channel_probe),
539164426Ssam	DEVMETHOD(device_attach,    avila_channel_attach),
540164426Ssam	DEVMETHOD(device_detach,    ata_detach),
541164426Ssam	DEVMETHOD(device_shutdown,  bus_generic_shutdown),
542164426Ssam	DEVMETHOD(device_suspend,   ata_suspend),
543164426Ssam	DEVMETHOD(device_resume,    ata_resume),
544164426Ssam
545164426Ssam	{ 0, 0 }
546164426Ssam};
547164426Ssam
548164426Ssamdriver_t avila_channel_driver = {
549164426Ssam	"ata",
550164426Ssam	avila_channel_methods,
551164426Ssam	sizeof(struct ata_channel),
552164426Ssam};
553164426SsamDRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);
554