2 * Copyright (c) 2006 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
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.
39 * The ADI Pronghorn Metro is very similar. It use CS3 and CS4 and
40 * GPIO pin 0 for interrupts.
42 * See also http://www.intel.com/design/network/applnots/302456.htm.
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/module.h>
50 #include <sys/resource.h>
52 #include <sys/sysctl.h>
53 #include <sys/endian.h>
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>
65 #include <sys/taskqueue.h>
67 #include <dev/ata/ata-all.h>
70 #define AVILA_IDE_GPIN 12 /* GPIO pin # */
71 #define AVILA_IDE_IRQ IXP425_INT_GPIO_12
72 #define AVILA_IDE_CTRL 0x06 /* control register */
74 #define PRONGHORN_IDE_GPIN 0 /* GPIO pin # */
75 #define PRONGHORN_IDE_IRQ IXP425_INT_GPIO_0
76 #define PRONGHORN_IDE_CNTRL 0x06 /* control register */
78 struct ata_avila_softc {
80 bus_space_tag_t sc_iot;
81 bus_space_handle_t sc_exp_ioh; /* Exp Bus config registers */
82 bus_space_handle_t sc_ioh; /* CS1/3 data registers */
83 bus_space_handle_t sc_alt_ioh; /* CS2/4 data registers */
84 struct bus_space sc_expbus_tag;
85 struct resource sc_ata; /* hand-crafted for ATA */
86 struct resource sc_alt_ata; /* hand-crafted for ATA */
87 u_int32_t sc_16bit_off; /* EXP_TIMING_CSx_OFFSET */
88 int sc_rid; /* rid for IRQ */
89 struct resource *sc_irq; /* IRQ resource */
90 void *sc_ih; /* interrupt handler */
94 } sc_intr[1]; /* NB: 1/channel */
97 static void ata_avila_intr(void *);
99 static void ata_bs_rm_2_s(void *, bus_space_handle_t, bus_size_t,
100 u_int16_t *, bus_size_t);
101 static void ata_bs_wm_2_s(void *, bus_space_handle_t, bus_size_t,
102 const u_int16_t *, bus_size_t);
105 ata_avila_probe(device_t dev)
107 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
109 /* XXX any way to check? */
110 if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
111 device_set_desc_copy(dev, "Gateworks Avila IDE/CF Controller");
113 device_set_desc_copy(dev,
114 "ADI Pronghorn Metro IDE/CF Controller");
119 ata_avila_attach(device_t dev)
121 struct ata_avila_softc *sc = device_get_softc(dev);
122 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
123 u_int32_t alt_t_off, ide_gpin, ide_irq;
126 /* NB: borrow from parent */
127 sc->sc_iot = sa->sc_iot;
128 sc->sc_exp_ioh = sa->sc_exp_ioh;
129 if (EXP_BUS_READ_4(sc, EXP_TIMING_CS2_OFFSET) != 0) {
131 if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS1_HWBASE,
132 IXP425_EXP_BUS_CS1_SIZE, 0, &sc->sc_ioh))
133 panic("%s: unable to map Expansion Bus CS1 window",
135 if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS2_HWBASE,
136 IXP425_EXP_BUS_CS2_SIZE, 0, &sc->sc_alt_ioh))
137 panic("%s: unable to map Expansion Bus CS2 window",
139 ide_gpin = AVILA_IDE_GPIN;
140 ide_irq = AVILA_IDE_IRQ;
141 sc->sc_16bit_off = EXP_TIMING_CS1_OFFSET;
142 alt_t_off = EXP_TIMING_CS2_OFFSET;
145 if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS3_HWBASE,
146 IXP425_EXP_BUS_CS3_SIZE, 0, &sc->sc_ioh))
147 panic("%s: unable to map Expansion Bus CS3 window",
149 if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS4_HWBASE,
150 IXP425_EXP_BUS_CS4_SIZE, 0, &sc->sc_alt_ioh))
151 panic("%s: unable to map Expansion Bus CS4 window",
153 ide_gpin = PRONGHORN_IDE_GPIN;
154 ide_irq = PRONGHORN_IDE_IRQ;
155 sc->sc_16bit_off = EXP_TIMING_CS3_OFFSET;
156 alt_t_off = EXP_TIMING_CS4_OFFSET;
160 * Craft special resource for ATA bus space ops
161 * that go through the expansion bus and require
162 * special hackery to ena/dis 16-bit operations.
164 * XXX probably should just make this generic for
165 * accessing the expansion bus.
167 sc->sc_expbus_tag.bs_cookie = sc; /* NB: backpointer */
169 sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1,
170 sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2,
172 sc->sc_expbus_tag.bs_rm_2 = ata_bs_rm_2,
173 sc->sc_expbus_tag.bs_rm_2_s = ata_bs_rm_2_s,
175 sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1,
176 sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2,
178 sc->sc_expbus_tag.bs_wm_2 = ata_bs_wm_2,
179 sc->sc_expbus_tag.bs_wm_2_s = ata_bs_wm_2_s,
181 rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
182 rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
183 rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag);
184 rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
186 GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPOER,
187 GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<ide_gpin));
188 /* set interrupt type */
189 GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(ide_gpin),
190 (GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(ide_gpin)) &~
191 GPIO_TYPE(ide_gpin, GPIO_TYPE_MASK)) |
192 GPIO_TYPE(ide_gpin, GPIO_TYPE_EDG_RISING));
195 GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<ide_gpin));
197 /* configure CS1/3 window, leaving timing unchanged */
198 EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
199 EXP_BUS_READ_4(sc, sc->sc_16bit_off) |
200 EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
201 /* configure CS2/4 window, leaving timing unchanged */
202 EXP_BUS_WRITE_4(sc, alt_t_off,
203 EXP_BUS_READ_4(sc, alt_t_off) |
204 EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
206 /* setup interrupt */
207 sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
208 ide_irq, ide_irq, 1, RF_ACTIVE);
210 panic("Unable to allocate irq %u.\n", ide_irq);
211 bus_setup_intr(dev, sc->sc_irq,
212 INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
213 NULL, ata_avila_intr, sc, &sc->sc_ih);
215 /* attach channel on this controller */
216 device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 0));
217 bus_generic_attach(dev);
223 ata_avila_detach(device_t dev)
225 struct ata_avila_softc *sc = device_get_softc(dev);
229 /* XXX quiesce gpio? */
231 /* detach & delete all children */
232 if (device_get_children(dev, &children, &nc) == 0) {
234 device_delete_child(dev, children[0]);
235 free(children, M_TEMP);
238 bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
239 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
245 ata_avila_intr(void *xsc)
247 struct ata_avila_softc *sc = xsc;
249 if (sc->sc_intr[0].cb != NULL)
250 sc->sc_intr[0].cb(sc->sc_intr[0].arg);
253 static struct resource *
254 ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
255 u_long start, u_long end, u_long count, u_int flags)
257 struct ata_avila_softc *sc = device_get_softc(dev);
259 KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
260 ("type %u rid %u start %lu end %lu count %lu flags %u",
261 type, *rid, start, end, count, flags));
263 /* doesn't matter what we return so reuse the real thing */
268 ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
271 KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
272 ("type %u rid %u", type, rid));
277 ata_avila_setup_intr(device_t dev, device_t child, struct resource *irq,
278 int flags, driver_filter_t *filt,
279 driver_intr_t *function, void *argument, void **cookiep)
281 struct ata_avila_softc *sc = device_get_softc(dev);
282 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
284 KASSERT(unit == 0, ("unit %d", unit));
285 sc->sc_intr[unit].cb = function;
286 sc->sc_intr[unit].arg = argument;
292 ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
295 struct ata_avila_softc *sc = device_get_softc(dev);
296 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
298 KASSERT(unit == 0, ("unit %d", unit));
299 sc->sc_intr[unit].cb = NULL;
300 sc->sc_intr[unit].arg = NULL;
305 * Bus space accessors for CF-IDE PIO operations.
309 * Enable/disable 16-bit ops on the expansion bus.
312 enable_16(struct ata_avila_softc *sc)
314 EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
315 EXP_BUS_READ_4(sc, sc->sc_16bit_off) &~ EXP_BYTE_EN);
316 DELAY(100); /* XXX? */
320 disable_16(struct ata_avila_softc *sc)
322 DELAY(100); /* XXX? */
323 EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
324 EXP_BUS_READ_4(sc, sc->sc_16bit_off) | EXP_BYTE_EN);
328 ata_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
330 struct ata_avila_softc *sc = t;
332 return bus_space_read_1(sc->sc_iot, h, o);
336 ata_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
338 struct ata_avila_softc *sc = t;
340 bus_space_write_1(sc->sc_iot, h, o, v);
344 ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
346 struct ata_avila_softc *sc = t;
350 v = bus_space_read_2(sc->sc_iot, h, o);
356 ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
358 struct ata_avila_softc *sc = t;
361 bus_space_write_2(sc->sc_iot, h, o, v);
366 ata_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o,
367 u_int16_t *d, bus_size_t c)
369 struct ata_avila_softc *sc = t;
372 bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
377 ata_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o,
378 const u_int16_t *d, bus_size_t c)
380 struct ata_avila_softc *sc = t;
383 bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
387 /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
390 ata_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
391 u_int16_t *d, bus_size_t c)
393 struct ata_avila_softc *sc = t;
399 for (i = 0; i < c; i++) {
400 v = bus_space_read_2(sc->sc_iot, h, o);
404 bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
410 ata_bs_wm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
411 const u_int16_t *d, bus_size_t c)
413 struct ata_avila_softc *sc = t;
418 for (i = 0; i < c; i++)
419 bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
421 bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
426 static device_method_t ata_avila_methods[] = {
427 /* device interface */
428 DEVMETHOD(device_probe, ata_avila_probe),
429 DEVMETHOD(device_attach, ata_avila_attach),
430 DEVMETHOD(device_detach, ata_avila_detach),
431 DEVMETHOD(device_shutdown, bus_generic_shutdown),
432 DEVMETHOD(device_suspend, bus_generic_suspend),
433 DEVMETHOD(device_resume, bus_generic_resume),
436 DEVMETHOD(bus_alloc_resource, ata_avila_alloc_resource),
437 DEVMETHOD(bus_release_resource, ata_avila_release_resource),
438 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
439 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
440 DEVMETHOD(bus_setup_intr, ata_avila_setup_intr),
441 DEVMETHOD(bus_teardown_intr, ata_avila_teardown_intr),
446 devclass_t ata_avila_devclass;
448 static driver_t ata_avila_driver = {
451 sizeof(struct ata_avila_softc),
454 DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0);
455 MODULE_VERSION(ata_avila, 1);
456 MODULE_DEPEND(ata_avila, ata, 1, 1, 1);
459 avila_channel_probe(device_t dev)
461 struct ata_channel *ch = device_get_softc(dev);
464 ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
465 device_set_desc_copy(dev, "ATA channel 0");
467 return ata_probe(dev);
471 avila_channel_attach(device_t dev)
473 struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
474 struct ata_channel *ch = device_get_softc(dev);
477 for (i = 0; i < ATA_MAX_RES; i++)
478 ch->r_io[i].res = &sc->sc_ata;
480 ch->r_io[ATA_DATA].offset = ATA_DATA;
481 ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
482 ch->r_io[ATA_COUNT].offset = ATA_COUNT;
483 ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
484 ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
485 ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
486 ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
487 ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
488 ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
489 /* NB: should be used only for ATAPI devices */
490 ch->r_io[ATA_IREASON].offset = ATA_COUNT;
491 ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
493 /* NB: the control and alt status registers are special */
494 ch->r_io[ATA_ALTSTAT].res = &sc->sc_alt_ata;
495 ch->r_io[ATA_ALTSTAT].offset = AVILA_IDE_CTRL;
496 ch->r_io[ATA_CONTROL].res = &sc->sc_alt_ata;
497 ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
499 /* NB: by convention this points at the base of registers */
500 ch->r_io[ATA_IDX_ADDR].offset = 0;
503 return ata_attach(dev);
506 static device_method_t avila_channel_methods[] = {
507 /* device interface */
508 DEVMETHOD(device_probe, avila_channel_probe),
509 DEVMETHOD(device_attach, avila_channel_attach),
510 DEVMETHOD(device_detach, ata_detach),
511 DEVMETHOD(device_shutdown, bus_generic_shutdown),
512 DEVMETHOD(device_suspend, ata_suspend),
513 DEVMETHOD(device_resume, ata_resume),
518 driver_t avila_channel_driver = {
520 avila_channel_methods,
521 sizeof(struct ata_channel),
523 DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);