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_CTRL 0x06
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 */
84 static const struct ata_config *
85 ata_getconfig(struct ixp425_softc *sa)
87 static const struct ata_config configs[] = {
88 { .desc = "Gateworks Avila IDE/CF Controller",
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,
98 { .desc = "Gateworks Cambria IDE/CF Controller",
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,
108 { .desc = "ADI Pronghorn Metro IDE/CF Controller",
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,
120 /* XXX honor hint? (but then no multi-board support) */
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 */
129 struct ata_avila_softc {
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 */
145 } sc_intr[1]; /* NB: 1/channel */
148 static void ata_avila_intr(void *);
150 static void ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t,
151 u_int16_t *, bus_size_t);
152 static void ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t,
153 const u_int16_t *, bus_size_t);
156 ata_avila_probe(device_t dev)
158 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
159 const struct ata_config *config;
161 config = ata_getconfig(sa);
162 if (config != NULL) {
163 device_set_desc_copy(dev, config->desc);
170 ata_avila_attach(device_t dev)
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;
176 config = ata_getconfig(sa);
177 KASSERT(config != NULL, ("no board config"));
180 /* NB: borrow from parent */
181 sc->sc_iot = sa->sc_iot;
182 sc->sc_exp_ioh = sa->sc_exp_ioh;
184 if (bus_space_map(sc->sc_iot, config->base16, config->size16,
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,
190 panic("%s: cannot map alt window (0x%x/0x%x)",
191 __func__, config->basealt, config->sizealt);
192 sc->sc_16bit_off = config->off16;
194 if (config->base16 != CAMBRIA_CFSEL0_HWBASE) {
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.
200 * XXX probably should just make this generic for
201 * accessing the expansion bus.
203 sc->sc_expbus_tag.bs_privdata = sc; /* NB: backpointer */
205 sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1,
206 sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2,
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,
211 sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1,
212 sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2,
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,
217 rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
218 rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag);
221 * On Cambria use the shared CS3 expansion bus tag
222 * that handles interlock for sharing access with the
225 rman_set_bustag(&sc->sc_ata, &cambria_exp_bs_tag);
226 rman_set_bustag(&sc->sc_alt_ata, &cambria_exp_bs_tag);
228 rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
229 rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
231 ixp425_set_gpio(sa, config->gpin, GPIO_TYPE_EDG_RISING);
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);
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);
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);
251 /* attach channel on this controller */
252 device_add_child(dev, "ata", -1);
253 bus_generic_attach(dev);
259 ata_avila_detach(device_t dev)
261 struct ata_avila_softc *sc = device_get_softc(dev);
263 /* XXX quiesce gpio? */
265 /* detach & delete all children */
266 device_delete_children(dev);
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);
275 ata_avila_intr(void *xsc)
277 struct ata_avila_softc *sc = xsc;
279 if (sc->sc_intr[0].cb != NULL)
280 sc->sc_intr[0].cb(sc->sc_intr[0].arg);
283 static struct resource *
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)
287 struct ata_avila_softc *sc = device_get_softc(dev);
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));
293 /* doesn't matter what we return so reuse the real thing */
298 ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
301 KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
302 ("type %u rid %u", type, rid));
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)
311 struct ata_avila_softc *sc = device_get_softc(dev);
312 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
314 KASSERT(unit == 0, ("unit %d", unit));
315 sc->sc_intr[unit].cb = function;
316 sc->sc_intr[unit].arg = argument;
322 ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
325 struct ata_avila_softc *sc = device_get_softc(dev);
326 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
328 KASSERT(unit == 0, ("unit %d", unit));
329 sc->sc_intr[unit].cb = NULL;
330 sc->sc_intr[unit].arg = NULL;
335 * Bus space accessors for CF-IDE PIO operations.
339 * Enable/disable 16-bit ops on the expansion bus.
342 enable_16(struct ata_avila_softc *sc)
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? */
350 disable_16(struct ata_avila_softc *sc)
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);
358 ata_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o)
360 struct ata_avila_softc *sc = tag->bs_privdata;
362 return bus_space_read_1(sc->sc_iot, h, o);
366 ata_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v)
368 struct ata_avila_softc *sc = tag->bs_privdata;
370 bus_space_write_1(sc->sc_iot, h, o, v);
374 ata_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o)
376 struct ata_avila_softc *sc = tag->bs_privdata;
380 v = bus_space_read_2(sc->sc_iot, h, o);
386 ata_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v)
388 struct ata_avila_softc *sc = tag->bs_privdata;
391 bus_space_write_2(sc->sc_iot, h, o, v);
396 ata_bs_rm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
397 u_int16_t *d, bus_size_t c)
399 struct ata_avila_softc *sc = tag->bs_privdata;
402 bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
407 ata_bs_wm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
408 const u_int16_t *d, bus_size_t c)
410 struct ata_avila_softc *sc = tag->bs_privdata;
413 bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
417 /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
420 ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
421 u_int16_t *d, bus_size_t c)
423 struct ata_avila_softc *sc = tag->bs_privdata;
429 for (i = 0; i < c; i++) {
430 v = bus_space_read_2(sc->sc_iot, h, o);
434 bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
440 ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
441 const u_int16_t *d, bus_size_t c)
443 struct ata_avila_softc *sc = tag->bs_privdata;
448 for (i = 0; i < c; i++)
449 bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
451 bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
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),
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),
476 devclass_t ata_avila_devclass;
478 static driver_t ata_avila_driver = {
481 sizeof(struct ata_avila_softc),
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);
489 avila_channel_probe(device_t dev)
491 struct ata_channel *ch = device_get_softc(dev);
494 ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
495 device_set_desc_copy(dev, "ATA channel 0");
497 return ata_probe(dev);
501 avila_channel_attach(device_t dev)
503 struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
504 struct ata_channel *ch = device_get_softc(dev);
507 for (i = 0; i < ATA_MAX_RES; i++)
508 ch->r_io[i].res = &sc->sc_ata;
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;
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;
529 /* NB: by convention this points at the base of registers */
530 ch->r_io[ATA_IDX_ADDR].offset = 0;
533 return ata_attach(dev);
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),
548 driver_t avila_channel_driver = {
550 avila_channel_methods,
551 sizeof(struct ata_channel),
553 DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);