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 * There are 1 or 2 optional CF slots operated in "True IDE" mode.
36 * Registers are on the Expansion Bus connected to CS1. Interrupts
37 * are tied to GPIO pin 12. No DMA, just PIO.
39 * See also http://www.intel.com/design/network/applnots/302456.htm.
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
47 #include <sys/resource.h>
49 #include <sys/sysctl.h>
50 #include <sys/endian.h>
52 #include <machine/bus.h>
53 #include <machine/cpu.h>
54 #include <machine/cpufunc.h>
55 #include <machine/resource.h>
56 #include <machine/intr.h>
57 #include <arm/xscale/ixp425/ixp425reg.h>
58 #include <arm/xscale/ixp425/ixp425var.h>
62 #include <sys/taskqueue.h>
64 #include <dev/ata/ata-all.h>
67 #define AVILA_IDE_GPIN 12 /* GPIO pin # */
68 #define AVILA_IDE_IRQ IXP425_INT_GPIO_12
69 #define AVILA_IDE_CTRL 0x1e /* control register */
71 struct ata_avila_softc {
73 bus_space_tag_t sc_iot;
74 bus_space_handle_t sc_exp_ioh; /* Exp Bus config registers */
75 bus_space_handle_t sc_ioh; /* CS1 data registers */
76 struct bus_space sc_expbus_tag;
77 struct resource sc_ata; /* hand-crafted for ATA */
78 int sc_rid; /* rid for IRQ */
79 struct resource *sc_irq; /* IRQ resource */
80 void *sc_ih; /* interrupt handler */
84 } sc_intr[1]; /* NB: 1/channel */
87 static void ata_avila_intr(void *);
89 static void ata_bs_rm_2_s(void *, bus_space_handle_t, bus_size_t,
90 u_int16_t *, bus_size_t);
91 static void ata_bs_wm_2_s(void *, bus_space_handle_t, bus_size_t,
92 const u_int16_t *, bus_size_t);
95 ata_avila_probe(device_t dev)
97 /* XXX any way to check? */
98 device_set_desc_copy(dev, "Gateworks Avila IDE/CF Controller");
103 ata_avila_attach(device_t dev)
105 struct ata_avila_softc *sc = device_get_softc(dev);
106 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
109 /* NB: borrow from parent */
110 sc->sc_iot = sa->sc_iot;
111 sc->sc_exp_ioh = sa->sc_exp_ioh;
112 if (bus_space_map(sc->sc_iot,
113 IXP425_EXP_BUS_CS1_HWBASE, IXP425_EXP_BUS_CS1_SIZE, 0, &sc->sc_ioh))
114 panic("%s: unable to map Expansion Bus CS1 window", __func__);
117 * Craft special resource for ATA bus space ops
118 * that go through the expansion bus and require
119 * special hackery to ena/dis 16-bit operations.
121 * XXX probably should just make this generic for
122 * accessing the expansion bus.
124 sc->sc_expbus_tag.bs_cookie = sc; /* NB: backpointer */
126 sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1,
127 sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2,
129 sc->sc_expbus_tag.bs_rm_2 = ata_bs_rm_2,
130 sc->sc_expbus_tag.bs_rm_2_s = ata_bs_rm_2_s,
132 sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1,
133 sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2,
135 sc->sc_expbus_tag.bs_wm_2 = ata_bs_wm_2,
136 sc->sc_expbus_tag.bs_wm_2_s = ata_bs_wm_2_s,
138 rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
139 rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
141 GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPOER,
142 GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<AVILA_IDE_GPIN));
143 /* interrupt is active low */
144 GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(AVILA_IDE_GPIN),
145 GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(AVILA_IDE_GPIN) |
146 GPIO_TYPE(AVILA_IDE_GPIN, GPIO_TYPE_ACT_LOW)));
149 GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<AVILA_IDE_GPIN));
151 /* configure CS1 window, leaving timing unchanged */
152 EXP_BUS_WRITE_4(sc, EXP_TIMING_CS1_OFFSET,
153 EXP_BUS_READ_4(sc, EXP_TIMING_CS1_OFFSET) |
154 EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
156 /* setup interrupt */
157 sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
158 AVILA_IDE_IRQ, AVILA_IDE_IRQ, 1, RF_ACTIVE);
160 panic("Unable to allocate irq %u.\n", AVILA_IDE_IRQ);
161 bus_setup_intr(dev, sc->sc_irq,
162 INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
163 NULL, ata_avila_intr, sc, &sc->sc_ih);
165 /* attach channel on this controller */
166 device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 0));
167 bus_generic_attach(dev);
173 ata_avila_detach(device_t dev)
175 struct ata_avila_softc *sc = device_get_softc(dev);
179 /* XXX quiesce gpio? */
181 /* detach & delete all children */
182 if (device_get_children(dev, &children, &nc) == 0) {
184 device_delete_child(dev, children[0]);
185 free(children, M_TEMP);
188 bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
189 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
195 ata_avila_intr(void *xsc)
197 struct ata_avila_softc *sc = xsc;
199 if (sc->sc_intr[0].cb != NULL)
200 sc->sc_intr[0].cb(sc->sc_intr[0].arg);
203 static struct resource *
204 ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
205 u_long start, u_long end, u_long count, u_int flags)
207 struct ata_avila_softc *sc = device_get_softc(dev);
209 KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
210 ("type %u rid %u start %lu end %lu count %lu flags %u",
211 type, *rid, start, end, count, flags));
213 /* doesn't matter what we return so reuse the real thing */
218 ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
221 KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
222 ("type %u rid %u", type, rid));
227 ata_avila_setup_intr(device_t dev, device_t child, struct resource *irq,
228 int flags, driver_filter_t *filt,
229 driver_intr_t *function, void *argument, void **cookiep)
231 struct ata_avila_softc *sc = device_get_softc(dev);
232 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
234 KASSERT(unit == 0, ("unit %d", unit));
235 sc->sc_intr[unit].cb = function;
236 sc->sc_intr[unit].arg = argument;
242 ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
245 struct ata_avila_softc *sc = device_get_softc(dev);
246 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
248 KASSERT(unit == 0, ("unit %d", unit));
249 sc->sc_intr[unit].cb = NULL;
250 sc->sc_intr[unit].arg = NULL;
255 * Bus space accessors for CF-IDE PIO operations.
259 * Enable/disable 16-bit ops on the expansion bus.
262 enable_16(struct ata_avila_softc *sc)
264 EXP_BUS_WRITE_4(sc, EXP_TIMING_CS1_OFFSET,
265 EXP_BUS_READ_4(sc, EXP_TIMING_CS1_OFFSET) &~ EXP_BYTE_EN);
266 DELAY(100); /* XXX? */
270 disable_16(struct ata_avila_softc *sc)
272 DELAY(100); /* XXX? */
273 EXP_BUS_WRITE_4(sc, EXP_TIMING_CS1_OFFSET,
274 EXP_BUS_READ_4(sc, EXP_TIMING_CS1_OFFSET) | EXP_BYTE_EN);
278 ata_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
280 struct ata_avila_softc *sc = t;
282 return bus_space_read_1(sc->sc_iot, h, o);
286 ata_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
288 struct ata_avila_softc *sc = t;
290 bus_space_write_1(sc->sc_iot, h, o, v);
294 ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
296 struct ata_avila_softc *sc = t;
300 v = bus_space_read_2(sc->sc_iot, h, o);
306 ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
308 struct ata_avila_softc *sc = t;
311 bus_space_write_2(sc->sc_iot, h, o, v);
316 ata_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o,
317 u_int16_t *d, bus_size_t c)
319 struct ata_avila_softc *sc = t;
322 bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
327 ata_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o,
328 const u_int16_t *d, bus_size_t c)
330 struct ata_avila_softc *sc = t;
333 bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
337 /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
340 ata_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
341 u_int16_t *d, bus_size_t c)
343 struct ata_avila_softc *sc = t;
349 for (i = 0; i < c; i++) {
350 v = bus_space_read_2(sc->sc_iot, h, o);
354 bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
360 ata_bs_wm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
361 const u_int16_t *d, bus_size_t c)
363 struct ata_avila_softc *sc = t;
368 for (i = 0; i < c; i++)
369 bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
371 bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
376 static device_method_t ata_avila_methods[] = {
377 /* device interface */
378 DEVMETHOD(device_probe, ata_avila_probe),
379 DEVMETHOD(device_attach, ata_avila_attach),
380 DEVMETHOD(device_detach, ata_avila_detach),
381 DEVMETHOD(device_shutdown, bus_generic_shutdown),
382 DEVMETHOD(device_suspend, bus_generic_suspend),
383 DEVMETHOD(device_resume, bus_generic_resume),
386 DEVMETHOD(bus_alloc_resource, ata_avila_alloc_resource),
387 DEVMETHOD(bus_release_resource, ata_avila_release_resource),
388 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
389 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
390 DEVMETHOD(bus_setup_intr, ata_avila_setup_intr),
391 DEVMETHOD(bus_teardown_intr, ata_avila_teardown_intr),
396 devclass_t ata_avila_devclass;
398 static driver_t ata_avila_driver = {
401 sizeof(struct ata_avila_softc),
404 DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0);
405 MODULE_VERSION(ata_avila, 1);
406 MODULE_DEPEND(ata_avila, ata, 1, 1, 1);
409 avila_channel_probe(device_t dev)
411 struct ata_channel *ch = device_get_softc(dev);
414 ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
415 device_set_desc_copy(dev, "ATA channel 0");
417 return ata_probe(dev);
421 avila_channel_attach(device_t dev)
423 struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
424 struct ata_channel *ch = device_get_softc(dev);
427 for (i = 0; i < ATA_MAX_RES; i++)
428 ch->r_io[i].res = &sc->sc_ata;
430 ch->r_io[ATA_DATA].offset = ATA_DATA;
431 ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
432 ch->r_io[ATA_COUNT].offset = ATA_COUNT;
433 ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
434 ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
435 ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
436 ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
437 ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
438 ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
439 /* NB: should be used only for ATAPI devices */
440 ch->r_io[ATA_IREASON].offset = ATA_COUNT;
441 ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
442 /* alias this; required by ata_generic_status */
443 ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_STATUS].offset;
445 /* NB: the control register is special */
446 ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
448 /* NB: by convention this points at the base of registers */
449 ch->r_io[ATA_IDX_ADDR].offset = 0;
452 return ata_attach(dev);
455 /* XXX override ata_generic_reset to handle non-standard status */
457 avila_channel_reset(device_t dev)
459 struct ata_channel *ch = device_get_softc(dev);
460 u_int8_t ostat0 = 0, stat0 = 0;
461 u_int8_t err = 0, lsb = 0, msb = 0;
462 int mask = 0, timeout;
464 /* do we have any signs of ATA/ATAPI HW being present ? */
465 ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
467 ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
468 if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
474 device_printf(dev, "%s: reset tp1 mask=%02x ostat0=%02x\n",
475 __func__, mask, ostat0);
477 /* if nothing showed up there is no need to get any further */
478 /* XXX SOS is that too strong?, we just might loose devices here */
483 /* reset (both) devices on this channel */
484 ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
486 ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
488 ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
490 ATA_IDX_INB(ch, ATA_ERROR);
492 /* wait for BUSY to go inactive */
493 for (timeout = 0; timeout < 310; timeout++) {
494 if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
495 ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
497 err = ATA_IDX_INB(ch, ATA_ERROR);
498 lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
499 msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
500 stat0 = ATA_IDX_INB(ch, ATA_STATUS);
503 "%s: stat0=0x%02x err=0x%02x lsb=0x%02x "
504 "msb=0x%02x\n", __func__,
505 stat0, err, lsb, msb);
506 if (stat0 == err && lsb == err && msb == err &&
507 timeout > (stat0 & ATA_S_BUSY ? 100 : 10))
509 if (!(stat0 & ATA_S_BUSY)) {
510 if ((err & 0x7f) == ATA_E_ILI || err == 0) {
511 if (lsb == ATAPI_MAGIC_LSB &&
512 msb == ATAPI_MAGIC_MSB) {
513 ch->devices |= ATA_ATAPI_MASTER;
514 } else if (stat0 & ATA_S_READY) {
515 ch->devices |= ATA_ATA_MASTER;
517 } else if ((stat0 & 0x0f) &&
518 err == lsb && err == msb) {
523 if (mask == 0x00) /* nothing to wait for */
525 /* wait for master */
526 if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10))
532 device_printf(dev, "%s: reset tp2 stat0=%02x devices=0x%b\n",
533 __func__, stat0, ch->devices,
534 "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
537 static device_method_t avila_channel_methods[] = {
538 /* device interface */
539 DEVMETHOD(device_probe, avila_channel_probe),
540 DEVMETHOD(device_attach, avila_channel_attach),
541 DEVMETHOD(device_detach, ata_detach),
542 DEVMETHOD(device_shutdown, bus_generic_shutdown),
543 DEVMETHOD(device_suspend, ata_suspend),
544 DEVMETHOD(device_resume, ata_resume),
546 DEVMETHOD(ata_reset, avila_channel_reset),
551 driver_t avila_channel_driver = {
553 avila_channel_methods,
554 sizeof(struct ata_channel),
556 DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);