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$");
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/resource.h>
57 #include <machine/intr.h>
58 #include <arm/xscale/ixp425/ixp425reg.h>
59 #include <arm/xscale/ixp425/ixp425var.h>
60
61 #include <sys/ata.h>
62 #include <sys/sema.h>
63 #include <sys/taskqueue.h>
64 #include <vm/uma.h>
65 #include <dev/ata/ata-all.h>
66 #include <ata_if.h>
67
68 #define AVILA_IDE_CTRL 0x06
69
70 struct ata_config {
71 const char *desc; /* description for probe */
72 uint8_t gpin; /* GPIO pin */
73 uint8_t irq; /* IRQ */
74 uint32_t base16; /* CS base addr for 16-bit */
75 uint32_t size16; /* CS size for 16-bit */
76 uint32_t off16; /* CS offset for 16-bit */
77 uint32_t basealt; /* CS base addr for alt */
78 uint32_t sizealt; /* CS size for alt */
79 uint32_t offalt; /* CS offset for alt */
80 };
81
82 static const struct ata_config *
83 ata_getconfig(struct ixp425_softc *sa)
84 {
85 static const struct ata_config configs[] = {
86 { .desc = "Gateworks Avila IDE/CF Controller",
87 .gpin = 12,
88 .irq = IXP425_INT_GPIO_12,
89 .base16 = IXP425_EXP_BUS_CS1_HWBASE,
90 .size16 = IXP425_EXP_BUS_CS1_SIZE,
91 .off16 = EXP_TIMING_CS1_OFFSET,
92 .basealt = IXP425_EXP_BUS_CS2_HWBASE,
93 .sizealt = IXP425_EXP_BUS_CS2_SIZE,
94 .offalt = EXP_TIMING_CS2_OFFSET,
95 },
96 { .desc = "Gateworks Cambria IDE/CF Controller",
97 .gpin = 12,
98 .irq = IXP425_INT_GPIO_12,
99 .base16 = CAMBRIA_CFSEL0_HWBASE,
100 .size16 = CAMBRIA_CFSEL0_SIZE,
101 .off16 = EXP_TIMING_CS3_OFFSET,
102 .basealt = CAMBRIA_CFSEL1_HWBASE,
103 .sizealt = CAMBRIA_CFSEL1_SIZE,
104 .offalt = EXP_TIMING_CS4_OFFSET,
105 },
106 { .desc = "ADI Pronghorn Metro IDE/CF Controller",
107 .gpin = 0,
108 .irq = IXP425_INT_GPIO_0,
109 .base16 = IXP425_EXP_BUS_CS3_HWBASE,
110 .size16 = IXP425_EXP_BUS_CS3_SIZE,
111 .off16 = EXP_TIMING_CS3_OFFSET,
112 .basealt = IXP425_EXP_BUS_CS4_HWBASE,
113 .sizealt = IXP425_EXP_BUS_CS4_SIZE,
114 .offalt = EXP_TIMING_CS4_OFFSET,
115 },
116 };
117
118 /* XXX honor hint? (but then no multi-board support) */
119 /* XXX total hack */
120 if (cpu_is_ixp43x())
121 return &configs[1]; /* Cambria */
122 if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
123 return &configs[0]; /* Avila */
124 return &configs[2]; /* Pronghorn */
125 }
126
127 struct ata_avila_softc {
128 device_t sc_dev;
129 bus_space_tag_t sc_iot;
130 bus_space_handle_t sc_exp_ioh; /* Exp Bus config registers */
131 bus_space_handle_t sc_ioh; /* CS1/3 data registers */
132 bus_space_handle_t sc_alt_ioh; /* CS2/4 data registers */
133 struct bus_space sc_expbus_tag;
134 struct resource sc_ata; /* hand-crafted for ATA */
135 struct resource sc_alt_ata; /* hand-crafted for ATA */
136 u_int32_t sc_16bit_off; /* EXP_TIMING_CSx_OFFSET */
137 int sc_rid; /* rid for IRQ */
138 struct resource *sc_irq; /* IRQ resource */
139 void *sc_ih; /* interrupt handler */
140 struct {
141 void (*cb)(void *);
142 void *arg;
143 } sc_intr[1]; /* NB: 1/channel */
144 };
145
146 static void ata_avila_intr(void *);
147 bs_protos(ata);
148 static void ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t,
149 u_int16_t *, bus_size_t);
150 static void ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t,
151 const u_int16_t *, bus_size_t);
152
153 static int
154 ata_avila_probe(device_t dev)
155 {
156 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
157 const struct ata_config *config;
158
159 config = ata_getconfig(sa);
160 if (config != NULL) {
161 device_set_desc_copy(dev, config->desc);
162 return 0;
163 }
164 return ENXIO;
165 }
166
167 static int
168 ata_avila_attach(device_t dev)
169 {
170 struct ata_avila_softc *sc = device_get_softc(dev);
171 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
172 const struct ata_config *config;
173
174 config = ata_getconfig(sa);
175 KASSERT(config != NULL, ("no board config"));
176
177 sc->sc_dev = dev;
178 /* NB: borrow from parent */
179 sc->sc_iot = sa->sc_iot;
180 sc->sc_exp_ioh = sa->sc_exp_ioh;
181
182 if (bus_space_map(sc->sc_iot, config->base16, config->size16,
183 0, &sc->sc_ioh))
184 panic("%s: cannot map 16-bit window (0x%x/0x%x)",
185 __func__, config->base16, config->size16);
186 if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt,
187 0, &sc->sc_alt_ioh))
188 panic("%s: cannot map alt window (0x%x/0x%x)",
189 __func__, config->basealt, config->sizealt);
190 sc->sc_16bit_off = config->off16;
191
192 if (config->base16 != CAMBRIA_CFSEL0_HWBASE) {
193 /*
194 * Craft special resource for ATA bus space ops
195 * that go through the expansion bus and require
196 * special hackery to ena/dis 16-bit operations.
197 *
198 * XXX probably should just make this generic for
199 * accessing the expansion bus.
200 */
201 sc->sc_expbus_tag.bs_privdata = sc; /* NB: backpointer */
202 /* read single */
203 sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1;
204 sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2;
205 /* read multiple */
206 sc->sc_expbus_tag.bs_rm_2 = ata_bs_rm_2;
207 sc->sc_expbus_tag.bs_rm_2_s = ata_bs_rm_2_s;
208 /* write (single) */
209 sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1;
210 sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2;
211 /* write multiple */
212 sc->sc_expbus_tag.bs_wm_2 = ata_bs_wm_2;
213 sc->sc_expbus_tag.bs_wm_2_s = ata_bs_wm_2_s;
214
215 rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
216 rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag);
217 } else {
218 /*
219 * On Cambria use the shared CS3 expansion bus tag
220 * that handles interlock for sharing access with the
221 * optional UART's.
222 */
223 rman_set_bustag(&sc->sc_ata, &cambria_exp_bs_tag);
224 rman_set_bustag(&sc->sc_alt_ata, &cambria_exp_bs_tag);
225 }
226 rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
227 rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
228
229 ixp425_set_gpio(sa, config->gpin, GPIO_TYPE_EDG_RISING);
230
231 /* configure CS1/3 window, leaving timing unchanged */
232 EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
233 EXP_BUS_READ_4(sc, sc->sc_16bit_off) |
234 EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
235 /* configure CS2/4 window, leaving timing unchanged */
236 EXP_BUS_WRITE_4(sc, config->offalt,
237 EXP_BUS_READ_4(sc, config->offalt) |
238 EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
239
240 /* setup interrupt */
241 sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
242 config->irq, config->irq, 1, RF_ACTIVE);
243 if (!sc->sc_irq)
244 panic("Unable to allocate irq %u.\n", config->irq);
245 bus_setup_intr(dev, sc->sc_irq,
246 INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
247 NULL, ata_avila_intr, sc, &sc->sc_ih);
248
249 /* attach channel on this controller */
250 device_add_child(dev, "ata", -1);
251 bus_generic_attach(dev);
252
253 return 0;
254 }
255
256 static int
257 ata_avila_detach(device_t dev)
258 {
259 struct ata_avila_softc *sc = device_get_softc(dev);
260
261 /* XXX quiesce gpio? */
262
263 /* detach & delete all children */
264 device_delete_children(dev);
265
266 bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
267 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
268
269 return 0;
270 }
271
272 static void
273 ata_avila_intr(void *xsc)
274 {
275 struct ata_avila_softc *sc = xsc;
276
277 if (sc->sc_intr[0].cb != NULL)
278 sc->sc_intr[0].cb(sc->sc_intr[0].arg);
279 }
280
281 static struct resource *
282 ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
283 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
284 {
285 struct ata_avila_softc *sc = device_get_softc(dev);
286
287 KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
288 ("type %u rid %u start %ju end %ju count %ju flags %u",
289 type, *rid, start, end, count, flags));
290
291 /* doesn't matter what we return so reuse the real thing */
292 return sc->sc_irq;
293 }
294
295 static int
296 ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
297 struct resource *r)
298 {
299 KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
300 ("type %u rid %u", type, rid));
301 return 0;
302 }
303
304 static int
305 ata_avila_setup_intr(device_t dev, device_t child, struct resource *irq,
306 int flags, driver_filter_t *filt,
307 driver_intr_t *function, void *argument, void **cookiep)
308 {
309 struct ata_avila_softc *sc = device_get_softc(dev);
310 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
311
312 KASSERT(unit == 0, ("unit %d", unit));
313 sc->sc_intr[unit].cb = function;
314 sc->sc_intr[unit].arg = argument;
315 *cookiep = sc;
316 return 0;
317 }
318
319 static int
320 ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
321 void *cookie)
322 {
323 struct ata_avila_softc *sc = device_get_softc(dev);
324 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
325
326 KASSERT(unit == 0, ("unit %d", unit));
327 sc->sc_intr[unit].cb = NULL;
328 sc->sc_intr[unit].arg = NULL;
329 return 0;
330 }
331
332 /*
333 * Bus space accessors for CF-IDE PIO operations.
334 */
335
336 /*
337 * Enable/disable 16-bit ops on the expansion bus.
338 */
339 static __inline void
340 enable_16(struct ata_avila_softc *sc)
341 {
342 EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
343 EXP_BUS_READ_4(sc, sc->sc_16bit_off) &~ EXP_BYTE_EN);
344 DELAY(100); /* XXX? */
345 }
346
347 static __inline void
348 disable_16(struct ata_avila_softc *sc)
349 {
350 DELAY(100); /* XXX? */
351 EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
352 EXP_BUS_READ_4(sc, sc->sc_16bit_off) | EXP_BYTE_EN);
353 }
354
355 uint8_t
356 ata_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o)
357 {
358 struct ata_avila_softc *sc = tag->bs_privdata;
359
360 return bus_space_read_1(sc->sc_iot, h, o);
361 }
362
363 void
364 ata_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v)
365 {
366 struct ata_avila_softc *sc = tag->bs_privdata;
367
368 bus_space_write_1(sc->sc_iot, h, o, v);
369 }
370
371 uint16_t
372 ata_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o)
373 {
374 struct ata_avila_softc *sc = tag->bs_privdata;
375 uint16_t v;
376
377 enable_16(sc);
378 v = bus_space_read_2(sc->sc_iot, h, o);
379 disable_16(sc);
380 return v;
381 }
382
383 void
384 ata_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v)
385 {
386 struct ata_avila_softc *sc = tag->bs_privdata;
387
388 enable_16(sc);
389 bus_space_write_2(sc->sc_iot, h, o, v);
390 disable_16(sc);
391 }
392
393 void
394 ata_bs_rm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
395 u_int16_t *d, bus_size_t c)
396 {
397 struct ata_avila_softc *sc = tag->bs_privdata;
398
399 enable_16(sc);
400 bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
401 disable_16(sc);
402 }
403
404 void
405 ata_bs_wm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
406 const u_int16_t *d, bus_size_t c)
407 {
408 struct ata_avila_softc *sc = tag->bs_privdata;
409
410 enable_16(sc);
411 bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
412 disable_16(sc);
413 }
414
415 /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
416
417 void
418 ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
419 u_int16_t *d, bus_size_t c)
420 {
421 struct ata_avila_softc *sc = tag->bs_privdata;
422 uint16_t v;
423 bus_size_t i;
424
425 enable_16(sc);
426 #if 1
427 for (i = 0; i < c; i++) {
428 v = bus_space_read_2(sc->sc_iot, h, o);
429 d[i] = bswap16(v);
430 }
431 #else
432 bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
433 #endif
434 disable_16(sc);
435 }
436
437 void
438 ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o,
439 const u_int16_t *d, bus_size_t c)
440 {
441 struct ata_avila_softc *sc = tag->bs_privdata;
442 bus_size_t i;
443
444 enable_16(sc);
445 #if 1
446 for (i = 0; i < c; i++)
447 bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
448 #else
449 bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
450 #endif
451 disable_16(sc);
452 }
453
454 static device_method_t ata_avila_methods[] = {
455 /* device interface */
456 DEVMETHOD(device_probe, ata_avila_probe),
457 DEVMETHOD(device_attach, ata_avila_attach),
458 DEVMETHOD(device_detach, ata_avila_detach),
459 DEVMETHOD(device_shutdown, bus_generic_shutdown),
460 DEVMETHOD(device_suspend, bus_generic_suspend),
461 DEVMETHOD(device_resume, bus_generic_resume),
462
463 /* bus methods */
464 DEVMETHOD(bus_alloc_resource, ata_avila_alloc_resource),
465 DEVMETHOD(bus_release_resource, ata_avila_release_resource),
466 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
467 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
468 DEVMETHOD(bus_setup_intr, ata_avila_setup_intr),
469 DEVMETHOD(bus_teardown_intr, ata_avila_teardown_intr),
470
471 { 0, 0 }
472 };
473
474 devclass_t ata_avila_devclass;
475
476 static driver_t ata_avila_driver = {
477 "ata_avila",
478 ata_avila_methods,
479 sizeof(struct ata_avila_softc),
480 };
481
482 DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0);
483 MODULE_VERSION(ata_avila, 1);
484 MODULE_DEPEND(ata_avila, ata, 1, 1, 1);
485
486 static int
487 avila_channel_probe(device_t dev)
488 {
489 struct ata_channel *ch = device_get_softc(dev);
490
491 ch->unit = 0;
492 ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
493 device_set_desc_copy(dev, "ATA channel 0");
494
495 return ata_probe(dev);
496 }
497
498 static int
499 avila_channel_attach(device_t dev)
500 {
501 struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
502 struct ata_channel *ch = device_get_softc(dev);
503 int i;
504
505 for (i = 0; i < ATA_MAX_RES; i++)
506 ch->r_io[i].res = &sc->sc_ata;
507
508 ch->r_io[ATA_DATA].offset = ATA_DATA;
509 ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
510 ch->r_io[ATA_COUNT].offset = ATA_COUNT;
511 ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
512 ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
513 ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
514 ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
515 ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
516 ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
517 /* NB: should be used only for ATAPI devices */
518 ch->r_io[ATA_IREASON].offset = ATA_COUNT;
519 ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
520
521 /* NB: the control and alt status registers are special */
522 ch->r_io[ATA_ALTSTAT].res = &sc->sc_alt_ata;
523 ch->r_io[ATA_ALTSTAT].offset = AVILA_IDE_CTRL;
524 ch->r_io[ATA_CONTROL].res = &sc->sc_alt_ata;
525 ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
526
527 /* NB: by convention this points at the base of registers */
528 ch->r_io[ATA_IDX_ADDR].offset = 0;
529
530 ata_generic_hw(dev);
531 return ata_attach(dev);
532 }
533
534 static device_method_t avila_channel_methods[] = {
535 /* device interface */
536 DEVMETHOD(device_probe, avila_channel_probe),
537 DEVMETHOD(device_attach, avila_channel_attach),
538 DEVMETHOD(device_detach, ata_detach),
539 DEVMETHOD(device_shutdown, bus_generic_shutdown),
540 DEVMETHOD(device_suspend, ata_suspend),
541 DEVMETHOD(device_resume, ata_resume),
542
543 { 0, 0 }
544 };
545
546 driver_t avila_channel_driver = {
547 "ata",
548 avila_channel_methods,
549 sizeof(struct ata_channel),
550 };
551 DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);
Cache object: 09220053114e571698ff64f82a2634ef
|