1 /*-
2  * Copyright (c) 2006 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: stable/9/sys/arm/xscale/ixp425/avila_ata.c 229118 2011-12-31 15:31:34Z hselasky $");
32 
33 /*
34  * Compact Flash Support for the Avila Gateworks XScale boards.
35  * The CF slot is operated in "True IDE" mode. Registers are on
36  * the Expansion Bus connected to CS1 and CS2. Interrupts are
37  * tied to GPIO pin 12.  No DMA, just PIO.
38  *
39  * The ADI Pronghorn Metro is very similar. It use CS3 and CS4 and
40  * GPIO pin 0 for interrupts.
41  *
42  * See also http://www.intel.com/design/network/applnots/302456.htm.
43  */
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/module.h>
48 #include <sys/time.h>
49 #include <sys/bus.h>
50 #include <sys/resource.h>
51 #include <sys/rman.h>
52 #include <sys/sysctl.h>
53 #include <sys/endian.h>
54 
55 #include <machine/bus.h>
56 #include <machine/cpu.h>
57 #include <machine/cpufunc.h>
58 #include <machine/resource.h>
59 #include <machine/intr.h>
60 #include <arm/xscale/ixp425/ixp425reg.h>
61 #include <arm/xscale/ixp425/ixp425var.h>
62 
63 #include <sys/ata.h>
64 #include <sys/sema.h>
65 #include <sys/taskqueue.h>
66 #include <vm/uma.h>
67 #include <dev/ata/ata-all.h>
68 #include <ata_if.h>
69 
70 #define	AVILA_IDE_CTRL	0x06
71 
72 struct ata_config {
73 	const char	*desc;		/* description for probe */
74 	uint8_t		gpin;		/* GPIO pin */
75 	uint8_t		irq;		/* IRQ */
76 	uint32_t	base16;		/* CS base addr for 16-bit */
77 	uint32_t	size16;		/* CS size for 16-bit */
78 	uint32_t	off16;		/* CS offset for 16-bit */
79 	uint32_t	basealt;	/* CS base addr for alt */
80 	uint32_t	sizealt;	/* CS size for alt */
81 	uint32_t	offalt;		/* CS offset for alt */
82 };
83 
84 static const struct ata_config *
ata_getconfig(struct ixp425_softc * sa)85 ata_getconfig(struct ixp425_softc *sa)
86 {
87 	static const struct ata_config configs[] = {
88 		{ .desc		= "Gateworks Avila IDE/CF Controller",
89 		  .gpin		= 12,
90 		  .irq		= IXP425_INT_GPIO_12,
91 		  .base16	= IXP425_EXP_BUS_CS1_HWBASE,
92 		  .size16	= IXP425_EXP_BUS_CS1_SIZE,
93 		  .off16	= EXP_TIMING_CS1_OFFSET,
94 		  .basealt	= IXP425_EXP_BUS_CS2_HWBASE,
95 		  .sizealt	= IXP425_EXP_BUS_CS2_SIZE,
96 		  .offalt	= EXP_TIMING_CS2_OFFSET,
97 		},
98 		{ .desc		= "Gateworks Cambria IDE/CF Controller",
99 		  .gpin		= 12,
100 		  .irq		= IXP425_INT_GPIO_12,
101 		  .base16	= CAMBRIA_CFSEL0_HWBASE,
102 		  .size16	= CAMBRIA_CFSEL0_SIZE,
103 		  .off16	= EXP_TIMING_CS3_OFFSET,
104 		  .basealt	= CAMBRIA_CFSEL1_HWBASE,
105 		  .sizealt	= CAMBRIA_CFSEL1_SIZE,
106 		  .offalt	= EXP_TIMING_CS4_OFFSET,
107 		},
108 		{ .desc		= "ADI Pronghorn Metro IDE/CF Controller",
109 		  .gpin		= 0,
110 		  .irq		= IXP425_INT_GPIO_0,
111 		  .base16	= IXP425_EXP_BUS_CS3_HWBASE,
112 		  .size16	= IXP425_EXP_BUS_CS3_SIZE,
113 		  .off16	= EXP_TIMING_CS3_OFFSET,
114 		  .basealt	= IXP425_EXP_BUS_CS4_HWBASE,
115 		  .sizealt	= IXP425_EXP_BUS_CS4_SIZE,
116 		  .offalt	= EXP_TIMING_CS4_OFFSET,
117 		},
118 	};
119 
120 	/* XXX honor hint? (but then no multi-board support) */
121 	/* XXX total hack */
122 	if (cpu_is_ixp43x())
123 		return &configs[1];		/* Cambria */
124 	if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
125 		return &configs[0];		/* Avila */
126 	return &configs[2];			/* Pronghorn */
127 }
128 
129 struct ata_avila_softc {
130 	device_t		sc_dev;
131 	bus_space_tag_t		sc_iot;
132 	bus_space_handle_t	sc_exp_ioh;	/* Exp Bus config registers */
133 	bus_space_handle_t	sc_ioh;		/* CS1/3 data registers */
134 	bus_space_handle_t	sc_alt_ioh;	/* CS2/4 data registers */
135 	struct bus_space	sc_expbus_tag;
136 	struct resource		sc_ata;		/* hand-crafted for ATA */
137 	struct resource		sc_alt_ata;	/* hand-crafted for ATA */
138 	u_int32_t		sc_16bit_off;	/* EXP_TIMING_CSx_OFFSET */
139 	int			sc_rid;		/* rid for IRQ */
140 	struct resource		*sc_irq;	/* IRQ resource */
141 	void			*sc_ih;		/* interrupt handler */
142 	struct {
143 		void	(*cb)(void *);
144 		void	*arg;
145 	} sc_intr[1];			/* NB: 1/channel */
146 };
147 
148 static void ata_avila_intr(void *);
149 bs_protos(ata);
150 static	void ata_bs_rm_2_s(void *, bus_space_handle_t, bus_size_t,
151 		u_int16_t *, bus_size_t);
152 static	void ata_bs_wm_2_s(void *, bus_space_handle_t, bus_size_t,
153 		const u_int16_t *, bus_size_t);
154 
155 static int
ata_avila_probe(device_t dev)156 ata_avila_probe(device_t dev)
157 {
158 	struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
159 	const struct ata_config *config;
160 
161 	config = ata_getconfig(sa);
162 	if (config != NULL) {
163 		device_set_desc_copy(dev, config->desc);
164 		return 0;
165 	}
166 	return ENXIO;
167 }
168 
169 static int
ata_avila_attach(device_t dev)170 ata_avila_attach(device_t dev)
171 {
172 	struct ata_avila_softc *sc = device_get_softc(dev);
173 	struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
174 	const struct ata_config	*config;
175 
176 	config = ata_getconfig(sa);
177 	KASSERT(config != NULL, ("no board config"));
178 
179 	sc->sc_dev = dev;
180 	/* NB: borrow from parent */
181 	sc->sc_iot = sa->sc_iot;
182 	sc->sc_exp_ioh = sa->sc_exp_ioh;
183 
184 	if (bus_space_map(sc->sc_iot, config->base16, config->size16,
185 	    0, &sc->sc_ioh))
186 		panic("%s: cannot map 16-bit window (0x%x/0x%x)",
187 		    __func__, config->base16, config->size16);
188 	if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt,
189 	    0, &sc->sc_alt_ioh))
190 		panic("%s: cannot map alt window (0x%x/0x%x)",
191 		    __func__, config->basealt, config->sizealt);
192 	sc->sc_16bit_off = config->off16;
193 
194 	if (config->base16 != CAMBRIA_CFSEL0_HWBASE) {
195 		/*
196 		 * Craft special resource for ATA bus space ops
197 		 * that go through the expansion bus and require
198 		 * special hackery to ena/dis 16-bit operations.
199 		 *
200 		 * XXX probably should just make this generic for
201 		 * accessing the expansion bus.
202 		 */
203 		sc->sc_expbus_tag.bs_cookie = sc;	/* NB: backpointer */
204 		/* read single */
205 		sc->sc_expbus_tag.bs_r_1	= ata_bs_r_1,
206 		sc->sc_expbus_tag.bs_r_2	= ata_bs_r_2,
207 		/* read multiple */
208 		sc->sc_expbus_tag.bs_rm_2	= ata_bs_rm_2,
209 		sc->sc_expbus_tag.bs_rm_2_s	= ata_bs_rm_2_s,
210 		/* write (single) */
211 		sc->sc_expbus_tag.bs_w_1	= ata_bs_w_1,
212 		sc->sc_expbus_tag.bs_w_2	= ata_bs_w_2,
213 		/* write multiple */
214 		sc->sc_expbus_tag.bs_wm_2	= ata_bs_wm_2,
215 		sc->sc_expbus_tag.bs_wm_2_s	= ata_bs_wm_2_s,
216 
217 		rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
218 		rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag);
219 	} else {
220 		/*
221 		 * On Cambria use the shared CS3 expansion bus tag
222 		 * that handles interlock for sharing access with the
223 		 * optional UART's.
224 		 */
225 		rman_set_bustag(&sc->sc_ata, &cambria_exp_bs_tag);
226 		rman_set_bustag(&sc->sc_alt_ata, &cambria_exp_bs_tag);
227 	}
228 	rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
229 	rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
230 
231 	ixp425_set_gpio(sa, config->gpin, GPIO_TYPE_EDG_RISING);
232 
233 	/* configure CS1/3 window, leaving timing unchanged */
234 	EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
235 	    EXP_BUS_READ_4(sc, sc->sc_16bit_off) |
236 	        EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
237 	/* configure CS2/4 window, leaving timing unchanged */
238 	EXP_BUS_WRITE_4(sc, config->offalt,
239 	    EXP_BUS_READ_4(sc, config->offalt) |
240 	        EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
241 
242 	/* setup interrupt */
243 	sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
244 	    config->irq, config->irq, 1, RF_ACTIVE);
245 	if (!sc->sc_irq)
246 		panic("Unable to allocate irq %u.\n", config->irq);
247 	bus_setup_intr(dev, sc->sc_irq,
248 	    INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
249 	    NULL, ata_avila_intr, sc, &sc->sc_ih);
250 
251 	/* attach channel on this controller */
252 	device_add_child(dev, "ata", -1);
253 	bus_generic_attach(dev);
254 
255 	return 0;
256 }
257 
258 static int
ata_avila_detach(device_t dev)259 ata_avila_detach(device_t dev)
260 {
261 	struct ata_avila_softc *sc = device_get_softc(dev);
262 
263 	/* XXX quiesce gpio? */
264 
265 	/* detach & delete all children */
266 	device_delete_children(dev);
267 
268 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
269 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
270 
271 	return 0;
272 }
273 
274 static void
ata_avila_intr(void * xsc)275 ata_avila_intr(void *xsc)
276 {
277 	struct ata_avila_softc *sc = xsc;
278 
279 	if (sc->sc_intr[0].cb != NULL)
280 		sc->sc_intr[0].cb(sc->sc_intr[0].arg);
281 }
282 
283 static struct resource *
ata_avila_alloc_resource(device_t dev,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags)284 ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
285 		       u_long start, u_long end, u_long count, u_int flags)
286 {
287 	struct ata_avila_softc *sc = device_get_softc(dev);
288 
289 	KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
290 	    ("type %u rid %u start %lu end %lu count %lu flags %u",
291 	     type, *rid, start, end, count, flags));
292 
293 	/* doesn't matter what we return so reuse the real thing */
294 	return sc->sc_irq;
295 }
296 
297 static int
ata_avila_release_resource(device_t dev,device_t child,int type,int rid,struct resource * r)298 ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
299 			 struct resource *r)
300 {
301 	KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
302 	    ("type %u rid %u", type, rid));
303 	return 0;
304 }
305 
306 static int
ata_avila_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_filter_t * filt,driver_intr_t * function,void * argument,void ** cookiep)307 ata_avila_setup_intr(device_t dev, device_t child, struct resource *irq,
308 		   int flags, driver_filter_t *filt,
309 		   driver_intr_t *function, void *argument, void **cookiep)
310 {
311 	struct ata_avila_softc *sc = device_get_softc(dev);
312 	int unit = ((struct ata_channel *)device_get_softc(child))->unit;
313 
314 	KASSERT(unit == 0, ("unit %d", unit));
315 	sc->sc_intr[unit].cb = function;
316 	sc->sc_intr[unit].arg = argument;
317 	*cookiep = sc;
318 	return 0;
319 }
320 
321 static int
ata_avila_teardown_intr(device_t dev,device_t child,struct resource * irq,void * cookie)322 ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
323 		      void *cookie)
324 {
325 	struct ata_avila_softc *sc = device_get_softc(dev);
326 	int unit = ((struct ata_channel *)device_get_softc(child))->unit;
327 
328 	KASSERT(unit == 0, ("unit %d", unit));
329 	sc->sc_intr[unit].cb = NULL;
330 	sc->sc_intr[unit].arg = NULL;
331 	return 0;
332 }
333 
334 /*
335  * Bus space accessors for CF-IDE PIO operations.
336  */
337 
338 /*
339  * Enable/disable 16-bit ops on the expansion bus.
340  */
341 static __inline void
enable_16(struct ata_avila_softc * sc)342 enable_16(struct ata_avila_softc *sc)
343 {
344 	EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
345 	    EXP_BUS_READ_4(sc, sc->sc_16bit_off) &~ EXP_BYTE_EN);
346 	DELAY(100);		/* XXX? */
347 }
348 
349 static __inline void
disable_16(struct ata_avila_softc * sc)350 disable_16(struct ata_avila_softc *sc)
351 {
352 	DELAY(100);		/* XXX? */
353 	EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
354 	    EXP_BUS_READ_4(sc, sc->sc_16bit_off) | EXP_BYTE_EN);
355 }
356 
357 uint8_t
ata_bs_r_1(void * t,bus_space_handle_t h,bus_size_t o)358 ata_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
359 {
360 	struct ata_avila_softc *sc = t;
361 
362 	return bus_space_read_1(sc->sc_iot, h, o);
363 }
364 
365 void
ata_bs_w_1(void * t,bus_space_handle_t h,bus_size_t o,u_int8_t v)366 ata_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
367 {
368 	struct ata_avila_softc *sc = t;
369 
370 	bus_space_write_1(sc->sc_iot, h, o, v);
371 }
372 
373 uint16_t
ata_bs_r_2(void * t,bus_space_handle_t h,bus_size_t o)374 ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
375 {
376 	struct ata_avila_softc *sc = t;
377 	uint16_t v;
378 
379 	enable_16(sc);
380 	v = bus_space_read_2(sc->sc_iot, h, o);
381 	disable_16(sc);
382 	return v;
383 }
384 
385 void
ata_bs_w_2(void * t,bus_space_handle_t h,bus_size_t o,uint16_t v)386 ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
387 {
388 	struct ata_avila_softc *sc = t;
389 
390 	enable_16(sc);
391 	bus_space_write_2(sc->sc_iot, h, o, v);
392 	disable_16(sc);
393 }
394 
395 void
ata_bs_rm_2(void * t,bus_space_handle_t h,bus_size_t o,u_int16_t * d,bus_size_t c)396 ata_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o,
397 	u_int16_t *d, bus_size_t c)
398 {
399 	struct ata_avila_softc *sc = t;
400 
401 	enable_16(sc);
402 	bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
403 	disable_16(sc);
404 }
405 
406 void
ata_bs_wm_2(void * t,bus_space_handle_t h,bus_size_t o,const u_int16_t * d,bus_size_t c)407 ata_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o,
408 	const u_int16_t *d, bus_size_t c)
409 {
410 	struct ata_avila_softc *sc = t;
411 
412 	enable_16(sc);
413 	bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
414 	disable_16(sc);
415 }
416 
417 /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
418 
419 void
ata_bs_rm_2_s(void * t,bus_space_handle_t h,bus_size_t o,u_int16_t * d,bus_size_t c)420 ata_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
421 	u_int16_t *d, bus_size_t c)
422 {
423 	struct ata_avila_softc *sc = t;
424 	uint16_t v;
425 	bus_size_t i;
426 
427 	enable_16(sc);
428 #if 1
429 	for (i = 0; i < c; i++) {
430 		v = bus_space_read_2(sc->sc_iot, h, o);
431 		d[i] = bswap16(v);
432 	}
433 #else
434 	bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
435 #endif
436 	disable_16(sc);
437 }
438 
439 void
ata_bs_wm_2_s(void * t,bus_space_handle_t h,bus_size_t o,const u_int16_t * d,bus_size_t c)440 ata_bs_wm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
441 	const u_int16_t *d, bus_size_t c)
442 {
443 	struct ata_avila_softc *sc = t;
444 	bus_size_t i;
445 
446 	enable_16(sc);
447 #if 1
448 	for (i = 0; i < c; i++)
449 		bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
450 #else
451 	bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
452 #endif
453 	disable_16(sc);
454 }
455 
456 static device_method_t ata_avila_methods[] = {
457 	/* device interface */
458 	DEVMETHOD(device_probe,             ata_avila_probe),
459 	DEVMETHOD(device_attach,            ata_avila_attach),
460 	DEVMETHOD(device_detach,            ata_avila_detach),
461 	DEVMETHOD(device_shutdown,          bus_generic_shutdown),
462 	DEVMETHOD(device_suspend,           bus_generic_suspend),
463 	DEVMETHOD(device_resume,            bus_generic_resume),
464 
465 	/* bus methods */
466 	DEVMETHOD(bus_alloc_resource,       ata_avila_alloc_resource),
467 	DEVMETHOD(bus_release_resource,     ata_avila_release_resource),
468 	DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
469 	DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
470 	DEVMETHOD(bus_setup_intr,           ata_avila_setup_intr),
471 	DEVMETHOD(bus_teardown_intr,        ata_avila_teardown_intr),
472 
473 	{ 0, 0 }
474 };
475 
476 devclass_t ata_avila_devclass;
477 
478 static driver_t ata_avila_driver = {
479 	"ata_avila",
480 	ata_avila_methods,
481 	sizeof(struct ata_avila_softc),
482 };
483 
484 DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0);
485 MODULE_VERSION(ata_avila, 1);
486 MODULE_DEPEND(ata_avila, ata, 1, 1, 1);
487 
488 static int
avila_channel_probe(device_t dev)489 avila_channel_probe(device_t dev)
490 {
491 	struct ata_channel *ch = device_get_softc(dev);
492 
493 	ch->unit = 0;
494 	ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
495 	device_set_desc_copy(dev, "ATA channel 0");
496 
497 	return ata_probe(dev);
498 }
499 
500 static int
avila_channel_attach(device_t dev)501 avila_channel_attach(device_t dev)
502 {
503 	struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
504 	struct ata_channel *ch = device_get_softc(dev);
505 	int i;
506 
507 	for (i = 0; i < ATA_MAX_RES; i++)
508 		ch->r_io[i].res = &sc->sc_ata;
509 
510 	ch->r_io[ATA_DATA].offset = ATA_DATA;
511 	ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
512 	ch->r_io[ATA_COUNT].offset = ATA_COUNT;
513 	ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
514 	ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
515 	ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
516 	ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
517 	ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
518 	ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
519 	/* NB: should be used only for ATAPI devices */
520 	ch->r_io[ATA_IREASON].offset = ATA_COUNT;
521 	ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
522 
523 	/* NB: the control and alt status registers are special */
524 	ch->r_io[ATA_ALTSTAT].res = &sc->sc_alt_ata;
525 	ch->r_io[ATA_ALTSTAT].offset = AVILA_IDE_CTRL;
526 	ch->r_io[ATA_CONTROL].res = &sc->sc_alt_ata;
527 	ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
528 
529 	/* NB: by convention this points at the base of registers */
530 	ch->r_io[ATA_IDX_ADDR].offset = 0;
531 
532 	ata_generic_hw(dev);
533 	return ata_attach(dev);
534 }
535 
536 static device_method_t avila_channel_methods[] = {
537 	/* device interface */
538 	DEVMETHOD(device_probe,     avila_channel_probe),
539 	DEVMETHOD(device_attach,    avila_channel_attach),
540 	DEVMETHOD(device_detach,    ata_detach),
541 	DEVMETHOD(device_shutdown,  bus_generic_shutdown),
542 	DEVMETHOD(device_suspend,   ata_suspend),
543 	DEVMETHOD(device_resume,    ata_resume),
544 
545 	{ 0, 0 }
546 };
547 
548 driver_t avila_channel_driver = {
549 	"ata",
550 	avila_channel_methods,
551 	sizeof(struct ata_channel),
552 };
553 DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);
554