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/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_GPIN 12 /* GPIO pin # */
71 #define AVILA_IDE_IRQ IXP425_INT_GPIO_12
72 #define AVILA_IDE_CTRL 0x06 /* control register */
73
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 */
77
78 struct ata_avila_softc {
79 device_t sc_dev;
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 */
91 struct {
92 void (*cb)(void *);
93 void *arg;
94 } sc_intr[1]; /* NB: 1/channel */
95 };
96
97 static void ata_avila_intr(void *);
98 bs_protos(ata);
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);
103
104 static int
105 ata_avila_probe(device_t dev)
106 {
107 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
108
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");
112 else
113 device_set_desc_copy(dev,
114 "ADI Pronghorn Metro IDE/CF Controller");
115 return 0;
116 }
117
118 static int
119 ata_avila_attach(device_t dev)
120 {
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;
124
125 sc->sc_dev = dev;
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) {
130 /* Avila board */
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",
134 __func__);
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",
138 __func__);
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;
143 } else {
144 /* Pronghorn */
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",
148 __func__);
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",
152 __func__);
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;
157 }
158
159 /*
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.
163 *
164 * XXX probably should just make this generic for
165 * accessing the expansion bus.
166 */
167 sc->sc_expbus_tag.bs_cookie = sc; /* NB: backpointer */
168 /* read single */
169 sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1,
170 sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2,
171 /* read multiple */
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,
174 /* write (single) */
175 sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1,
176 sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2,
177 /* write multiple */
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,
180
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);
185
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));
193
194 /* clear ISR */
195 GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<ide_gpin));
196
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);
205
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);
209 if (!sc->sc_irq)
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);
214
215 /* attach channel on this controller */
216 device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 0));
217 bus_generic_attach(dev);
218
219 return 0;
220 }
221
222 static int
223 ata_avila_detach(device_t dev)
224 {
225 struct ata_avila_softc *sc = device_get_softc(dev);
226 device_t *children;
227 int nc;
228
229 /* XXX quiesce gpio? */
230
231 /* detach & delete all children */
232 if (device_get_children(dev, &children, &nc) == 0) {
233 if (nc > 0)
234 device_delete_child(dev, children[0]);
235 free(children, M_TEMP);
236 }
237
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);
240
241 return 0;
242 }
243
244 static void
245 ata_avila_intr(void *xsc)
246 {
247 struct ata_avila_softc *sc = xsc;
248
249 if (sc->sc_intr[0].cb != NULL)
250 sc->sc_intr[0].cb(sc->sc_intr[0].arg);
251 }
252
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)
256 {
257 struct ata_avila_softc *sc = device_get_softc(dev);
258
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));
262
263 /* doesn't matter what we return so reuse the real thing */
264 return sc->sc_irq;
265 }
266
267 static int
268 ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
269 struct resource *r)
270 {
271 KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
272 ("type %u rid %u", type, rid));
273 return 0;
274 }
275
276 static int
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)
280 {
281 struct ata_avila_softc *sc = device_get_softc(dev);
282 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
283
284 KASSERT(unit == 0, ("unit %d", unit));
285 sc->sc_intr[unit].cb = function;
286 sc->sc_intr[unit].arg = argument;
287 *cookiep = sc;
288 return 0;
289 }
290
291 static int
292 ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
293 void *cookie)
294 {
295 struct ata_avila_softc *sc = device_get_softc(dev);
296 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
297
298 KASSERT(unit == 0, ("unit %d", unit));
299 sc->sc_intr[unit].cb = NULL;
300 sc->sc_intr[unit].arg = NULL;
301 return 0;
302 }
303
304 /*
305 * Bus space accessors for CF-IDE PIO operations.
306 */
307
308 /*
309 * Enable/disable 16-bit ops on the expansion bus.
310 */
311 static void __inline
312 enable_16(struct ata_avila_softc *sc)
313 {
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? */
317 }
318
319 static void __inline
320 disable_16(struct ata_avila_softc *sc)
321 {
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);
325 }
326
327 uint8_t
328 ata_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
329 {
330 struct ata_avila_softc *sc = t;
331
332 return bus_space_read_1(sc->sc_iot, h, o);
333 }
334
335 void
336 ata_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
337 {
338 struct ata_avila_softc *sc = t;
339
340 bus_space_write_1(sc->sc_iot, h, o, v);
341 }
342
343 uint16_t
344 ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
345 {
346 struct ata_avila_softc *sc = t;
347 uint16_t v;
348
349 enable_16(sc);
350 v = bus_space_read_2(sc->sc_iot, h, o);
351 disable_16(sc);
352 return v;
353 }
354
355 void
356 ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
357 {
358 struct ata_avila_softc *sc = t;
359
360 enable_16(sc);
361 bus_space_write_2(sc->sc_iot, h, o, v);
362 disable_16(sc);
363 }
364
365 void
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)
368 {
369 struct ata_avila_softc *sc = t;
370
371 enable_16(sc);
372 bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
373 disable_16(sc);
374 }
375
376 void
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)
379 {
380 struct ata_avila_softc *sc = t;
381
382 enable_16(sc);
383 bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
384 disable_16(sc);
385 }
386
387 /* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
388
389 void
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)
392 {
393 struct ata_avila_softc *sc = t;
394 uint16_t v;
395 bus_size_t i;
396
397 enable_16(sc);
398 #if 1
399 for (i = 0; i < c; i++) {
400 v = bus_space_read_2(sc->sc_iot, h, o);
401 d[i] = bswap16(v);
402 }
403 #else
404 bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
405 #endif
406 disable_16(sc);
407 }
408
409 void
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)
412 {
413 struct ata_avila_softc *sc = t;
414 bus_size_t i;
415
416 enable_16(sc);
417 #if 1
418 for (i = 0; i < c; i++)
419 bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
420 #else
421 bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
422 #endif
423 disable_16(sc);
424 }
425
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),
434
435 /* bus methods */
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),
442
443 { 0, 0 }
444 };
445
446 devclass_t ata_avila_devclass;
447
448 static driver_t ata_avila_driver = {
449 "ata_avila",
450 ata_avila_methods,
451 sizeof(struct ata_avila_softc),
452 };
453
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);
457
458 static int
459 avila_channel_probe(device_t dev)
460 {
461 struct ata_channel *ch = device_get_softc(dev);
462
463 ch->unit = 0;
464 ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
465 device_set_desc_copy(dev, "ATA channel 0");
466
467 return ata_probe(dev);
468 }
469
470 static int
471 avila_channel_attach(device_t dev)
472 {
473 struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
474 struct ata_channel *ch = device_get_softc(dev);
475 int i;
476
477 for (i = 0; i < ATA_MAX_RES; i++)
478 ch->r_io[i].res = &sc->sc_ata;
479
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;
492
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;
498
499 /* NB: by convention this points at the base of registers */
500 ch->r_io[ATA_IDX_ADDR].offset = 0;
501
502 ata_generic_hw(dev);
503 return ata_attach(dev);
504 }
505
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),
514
515 { 0, 0 }
516 };
517
518 driver_t avila_channel_driver = {
519 "ata",
520 avila_channel_methods,
521 sizeof(struct ata_channel),
522 };
523 DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);
Cache object: 01c0069514da7da4a0c3b9eefaedc6e5
|