avila_ata.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 Sam Leffler, Errno Consulting 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * without modification. 13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15 * redistribution must be conditioned upon including a substantially 16 * similar Disclaimer requirement for further binary redistribution. 17 * 18 * NO WARRANTY 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29 * THE POSSIBILITY OF SUCH DAMAGES. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/11/sys/arm/xscale/ixp425/avila_ata.c 330897 2018-03-14 03:19:51Z eadler $"); 34 35/* 36 * Compact Flash Support for the Avila Gateworks XScale boards. 37 * The CF slot is operated in "True IDE" mode. Registers are on 38 * the Expansion Bus connected to CS1 and CS2. Interrupts are 39 * tied to GPIO pin 12. No DMA, just PIO. 40 * 41 * The ADI Pronghorn Metro is very similar. It use CS3 and CS4 and 42 * GPIO pin 0 for interrupts. 43 * 44 * See also http://www.intel.com/design/network/applnots/302456.htm. 45 */ 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/module.h> 50#include <sys/time.h> 51#include <sys/bus.h> 52#include <sys/resource.h> 53#include <sys/rman.h> 54#include <sys/sysctl.h> 55#include <sys/endian.h> 56 57#include <machine/bus.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_CTRL 0x06 71 72struct ata_config { 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 */ 82}; 83 84static const struct ata_config * 85ata_getconfig(struct ixp425_softc *sa) 86{ 87 static const struct ata_config configs[] = { 88 { .desc = "Gateworks Avila IDE/CF Controller", 89 .gpin = 12, 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, 97 }, 98 { .desc = "Gateworks Cambria IDE/CF Controller", 99 .gpin = 12, 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, 107 }, 108 { .desc = "ADI Pronghorn Metro IDE/CF Controller", 109 .gpin = 0, 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, 117 }, 118 }; 119 120 /* XXX honor hint? (but then no multi-board support) */ 121 /* XXX total hack */ 122 if (cpu_is_ixp43x()) 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 */ 127} 128 129struct ata_avila_softc { 130 device_t sc_dev; 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 */ 142 struct { 143 void (*cb)(void *); 144 void *arg; 145 } sc_intr[1]; /* NB: 1/channel */ 146}; 147 148static void ata_avila_intr(void *); 149bs_protos(ata); 150static 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); 152static 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); 154 155static int 156ata_avila_probe(device_t dev) 157{ 158 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 159 const struct ata_config *config; 160 161 config = ata_getconfig(sa); 162 if (config != NULL) { 163 device_set_desc_copy(dev, config->desc); 164 return 0; 165 } 166 return ENXIO; 167} 168 169static int 170ata_avila_attach(device_t dev) 171{ 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; 175 176 config = ata_getconfig(sa); 177 KASSERT(config != NULL, ("no board config")); 178 179 sc->sc_dev = dev; 180 /* NB: borrow from parent */ 181 sc->sc_iot = sa->sc_iot; 182 sc->sc_exp_ioh = sa->sc_exp_ioh; 183 184 if (bus_space_map(sc->sc_iot, config->base16, config->size16, 185 0, &sc->sc_ioh)) 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, 189 0, &sc->sc_alt_ioh)) 190 panic("%s: cannot map alt window (0x%x/0x%x)", 191 __func__, config->basealt, config->sizealt); 192 sc->sc_16bit_off = config->off16; 193 194 if (config->base16 != CAMBRIA_CFSEL0_HWBASE) { 195 /* 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. 199 * 200 * XXX probably should just make this generic for 201 * accessing the expansion bus. 202 */ 203 sc->sc_expbus_tag.bs_privdata = sc; /* NB: backpointer */ 204 /* read single */ 205 sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1; 206 sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2; 207 /* read multiple */ 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; 210 /* write (single) */ 211 sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1; 212 sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2; 213 /* write multiple */ 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; 216 217 rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag); 218 rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag); 219 } else { 220 /* 221 * On Cambria use the shared CS3 expansion bus tag 222 * that handles interlock for sharing access with the 223 * optional UART's. 224 */ 225 rman_set_bustag(&sc->sc_ata, &cambria_exp_bs_tag); 226 rman_set_bustag(&sc->sc_alt_ata, &cambria_exp_bs_tag); 227 } 228 rman_set_bushandle(&sc->sc_ata, sc->sc_ioh); 229 rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh); 230 231 ixp425_set_gpio(sa, config->gpin, GPIO_TYPE_EDG_RISING); 232 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); 241 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); 245 if (!sc->sc_irq) 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); 250 251 /* attach channel on this controller */ 252 device_add_child(dev, "ata", -1); 253 bus_generic_attach(dev); 254 255 return 0; 256} 257 258static int 259ata_avila_detach(device_t dev) 260{ 261 struct ata_avila_softc *sc = device_get_softc(dev); 262 263 /* XXX quiesce gpio? */ 264 265 /* detach & delete all children */ 266 device_delete_children(dev); 267 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); 270 271 return 0; 272} 273 274static void 275ata_avila_intr(void *xsc) 276{ 277 struct ata_avila_softc *sc = xsc; 278 279 if (sc->sc_intr[0].cb != NULL) 280 sc->sc_intr[0].cb(sc->sc_intr[0].arg); 281} 282 283static struct resource * 284ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid, 285 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 286{ 287 struct ata_avila_softc *sc = device_get_softc(dev); 288 289 KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID, 290 ("type %u rid %u start %ju end %ju count %ju flags %u", 291 type, *rid, start, end, count, flags)); 292 293 /* doesn't matter what we return so reuse the real thing */ 294 return sc->sc_irq; 295} 296 297static int 298ata_avila_release_resource(device_t dev, device_t child, int type, int rid, 299 struct resource *r) 300{ 301 KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID, 302 ("type %u rid %u", type, rid)); 303 return 0; 304} 305 306static int 307ata_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) 310{ 311 struct ata_avila_softc *sc = device_get_softc(dev); 312 int unit = ((struct ata_channel *)device_get_softc(child))->unit; 313 314 KASSERT(unit == 0, ("unit %d", unit)); 315 sc->sc_intr[unit].cb = function; 316 sc->sc_intr[unit].arg = argument; 317 *cookiep = sc; 318 return 0; 319} 320 321static int 322ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq, 323 void *cookie) 324{ 325 struct ata_avila_softc *sc = device_get_softc(dev); 326 int unit = ((struct ata_channel *)device_get_softc(child))->unit; 327 328 KASSERT(unit == 0, ("unit %d", unit)); 329 sc->sc_intr[unit].cb = NULL; 330 sc->sc_intr[unit].arg = NULL; 331 return 0; 332} 333 334/* 335 * Bus space accessors for CF-IDE PIO operations. 336 */ 337 338/* 339 * Enable/disable 16-bit ops on the expansion bus. 340 */ 341static __inline void 342enable_16(struct ata_avila_softc *sc) 343{ 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? */ 347} 348 349static __inline void 350disable_16(struct ata_avila_softc *sc) 351{ 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); 355} 356 357uint8_t 358ata_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) 359{ 360 struct ata_avila_softc *sc = tag->bs_privdata; 361 362 return bus_space_read_1(sc->sc_iot, h, o); 363} 364 365void 366ata_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v) 367{ 368 struct ata_avila_softc *sc = tag->bs_privdata; 369 370 bus_space_write_1(sc->sc_iot, h, o, v); 371} 372 373uint16_t 374ata_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) 375{ 376 struct ata_avila_softc *sc = tag->bs_privdata; 377 uint16_t v; 378 379 enable_16(sc); 380 v = bus_space_read_2(sc->sc_iot, h, o); 381 disable_16(sc); 382 return v; 383} 384 385void 386ata_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v) 387{ 388 struct ata_avila_softc *sc = tag->bs_privdata; 389 390 enable_16(sc); 391 bus_space_write_2(sc->sc_iot, h, o, v); 392 disable_16(sc); 393} 394 395void 396ata_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) 398{ 399 struct ata_avila_softc *sc = tag->bs_privdata; 400 401 enable_16(sc); 402 bus_space_read_multi_2(sc->sc_iot, h, o, d, c); 403 disable_16(sc); 404} 405 406void 407ata_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) 409{ 410 struct ata_avila_softc *sc = tag->bs_privdata; 411 412 enable_16(sc); 413 bus_space_write_multi_2(sc->sc_iot, h, o, d, c); 414 disable_16(sc); 415} 416 417/* XXX workaround ata driver by (incorrectly) byte swapping stream cases */ 418 419void 420ata_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) 422{ 423 struct ata_avila_softc *sc = tag->bs_privdata; 424 uint16_t v; 425 bus_size_t i; 426 427 enable_16(sc); 428#if 1 429 for (i = 0; i < c; i++) { 430 v = bus_space_read_2(sc->sc_iot, h, o); 431 d[i] = bswap16(v); 432 } 433#else 434 bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c); 435#endif 436 disable_16(sc); 437} 438 439void 440ata_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) 442{ 443 struct ata_avila_softc *sc = tag->bs_privdata; 444 bus_size_t i; 445 446 enable_16(sc); 447#if 1 448 for (i = 0; i < c; i++) 449 bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i])); 450#else 451 bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c); 452#endif 453 disable_16(sc); 454} 455 456static 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), 464 465 /* bus methods */ 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), 472 473 { 0, 0 } 474}; 475 476devclass_t ata_avila_devclass; 477 478static driver_t ata_avila_driver = { 479 "ata_avila", 480 ata_avila_methods, 481 sizeof(struct ata_avila_softc), 482}; 483 484DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0); 485MODULE_VERSION(ata_avila, 1); 486MODULE_DEPEND(ata_avila, ata, 1, 1, 1); 487 488static int 489avila_channel_probe(device_t dev) 490{ 491 struct ata_channel *ch = device_get_softc(dev); 492 493 ch->unit = 0; 494 ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE; 495 device_set_desc_copy(dev, "ATA channel 0"); 496 497 return ata_probe(dev); 498} 499 500static int 501avila_channel_attach(device_t dev) 502{ 503 struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev)); 504 struct ata_channel *ch = device_get_softc(dev); 505 int i; 506 507 for (i = 0; i < ATA_MAX_RES; i++) 508 ch->r_io[i].res = &sc->sc_ata; 509 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; 522 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; 528 529 /* NB: by convention this points at the base of registers */ 530 ch->r_io[ATA_IDX_ADDR].offset = 0; 531 532 ata_generic_hw(dev); 533 return ata_attach(dev); 534} 535 536static 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), 544 545 { 0, 0 } 546}; 547 548driver_t avila_channel_driver = { 549 "ata", 550 avila_channel_methods, 551 sizeof(struct ata_channel), 552}; 553DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0); 554