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: stable/11/sys/arm/xscale/ixp425/avila_ata.c 308325 2016-11-05 04:30:44Z mmel $"); 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 70struct 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 82static const struct ata_config * 83ata_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 127struct 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 146static void ata_avila_intr(void *); 147bs_protos(ata); 148static 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); 150static 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 153static int 154ata_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 167static int 168ata_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 256static int 257ata_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 272static void 273ata_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 281static struct resource * 282ata_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 295static int 296ata_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 304static int 305ata_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 319static int 320ata_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 */ 339static __inline void 340enable_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 347static __inline void 348disable_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 355uint8_t 356ata_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 363void 364ata_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 371uint16_t 372ata_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 383void 384ata_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 393void 394ata_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 404void 405ata_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 417void 418ata_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 437void 438ata_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 454static 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 474devclass_t ata_avila_devclass; 475 476static driver_t ata_avila_driver = { 477 "ata_avila", 478 ata_avila_methods, 479 sizeof(struct ata_avila_softc), 480}; 481 482DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0); 483MODULE_VERSION(ata_avila, 1); 484MODULE_DEPEND(ata_avila, ata, 1, 1, 1); 485 486static int 487avila_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 498static int 499avila_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 534static 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 546driver_t avila_channel_driver = { 547 "ata", 548 avila_channel_methods, 549 sizeof(struct ata_channel), 550}; 551DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0); 552