1164426Ssam/*- 2164426Ssam * Copyright (c) 2006 Sam Leffler, Errno Consulting 3164426Ssam * All rights reserved. 4164426Ssam * 5164426Ssam * Redistribution and use in source and binary forms, with or without 6164426Ssam * modification, are permitted provided that the following conditions 7164426Ssam * are met: 8164426Ssam * 1. Redistributions of source code must retain the above copyright 9164426Ssam * notice, this list of conditions and the following disclaimer, 10164426Ssam * without modification. 11164426Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12164426Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13164426Ssam * redistribution must be conditioned upon including a substantially 14164426Ssam * similar Disclaimer requirement for further binary redistribution. 15164426Ssam * 16164426Ssam * NO WARRANTY 17164426Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18164426Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19164426Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20164426Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21164426Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22164426Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23164426Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24164426Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25164426Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26164426Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27164426Ssam * THE POSSIBILITY OF SUCH DAMAGES. 28164426Ssam */ 29164426Ssam 30164426Ssam#include <sys/cdefs.h> 31164426Ssam__FBSDID("$FreeBSD$"); 32164426Ssam 33164426Ssam/* 34164426Ssam * Compact Flash Support for the Avila Gateworks XScale boards. 35167565Sjhay * The CF slot is operated in "True IDE" mode. Registers are on 36167565Sjhay * the Expansion Bus connected to CS1 and CS2. Interrupts are 37167565Sjhay * tied to GPIO pin 12. No DMA, just PIO. 38164426Ssam * 39167565Sjhay * The ADI Pronghorn Metro is very similar. It use CS3 and CS4 and 40167565Sjhay * GPIO pin 0 for interrupts. 41167565Sjhay * 42164426Ssam * See also http://www.intel.com/design/network/applnots/302456.htm. 43164426Ssam */ 44164426Ssam#include <sys/param.h> 45164426Ssam#include <sys/systm.h> 46164426Ssam#include <sys/kernel.h> 47164426Ssam#include <sys/module.h> 48164426Ssam#include <sys/time.h> 49164426Ssam#include <sys/bus.h> 50164426Ssam#include <sys/resource.h> 51164426Ssam#include <sys/rman.h> 52164426Ssam#include <sys/sysctl.h> 53164426Ssam#include <sys/endian.h> 54164426Ssam 55164426Ssam#include <machine/bus.h> 56164426Ssam#include <machine/cpu.h> 57164426Ssam#include <machine/cpufunc.h> 58164426Ssam#include <machine/resource.h> 59164426Ssam#include <machine/intr.h> 60164426Ssam#include <arm/xscale/ixp425/ixp425reg.h> 61164426Ssam#include <arm/xscale/ixp425/ixp425var.h> 62164426Ssam 63164426Ssam#include <sys/ata.h> 64164426Ssam#include <sys/sema.h> 65164426Ssam#include <sys/taskqueue.h> 66164426Ssam#include <vm/uma.h> 67164426Ssam#include <dev/ata/ata-all.h> 68164426Ssam#include <ata_if.h> 69164426Ssam 70186352Ssam#define AVILA_IDE_CTRL 0x06 71164426Ssam 72186352Ssamstruct ata_config { 73186352Ssam const char *desc; /* description for probe */ 74186352Ssam uint8_t gpin; /* GPIO pin */ 75186352Ssam uint8_t irq; /* IRQ */ 76186352Ssam uint32_t base16; /* CS base addr for 16-bit */ 77186352Ssam uint32_t size16; /* CS size for 16-bit */ 78186352Ssam uint32_t off16; /* CS offset for 16-bit */ 79186352Ssam uint32_t basealt; /* CS base addr for alt */ 80186352Ssam uint32_t sizealt; /* CS size for alt */ 81186352Ssam uint32_t offalt; /* CS offset for alt */ 82186352Ssam}; 83167565Sjhay 84186352Ssamstatic const struct ata_config * 85186352Ssamata_getconfig(struct ixp425_softc *sa) 86186352Ssam{ 87186352Ssam static const struct ata_config configs[] = { 88186352Ssam { .desc = "Gateworks Avila IDE/CF Controller", 89186352Ssam .gpin = 12, 90186352Ssam .irq = IXP425_INT_GPIO_12, 91186352Ssam .base16 = IXP425_EXP_BUS_CS1_HWBASE, 92186352Ssam .size16 = IXP425_EXP_BUS_CS1_SIZE, 93186352Ssam .off16 = EXP_TIMING_CS1_OFFSET, 94186352Ssam .basealt = IXP425_EXP_BUS_CS2_HWBASE, 95186352Ssam .sizealt = IXP425_EXP_BUS_CS2_SIZE, 96186352Ssam .offalt = EXP_TIMING_CS2_OFFSET, 97186352Ssam }, 98186352Ssam { .desc = "Gateworks Cambria IDE/CF Controller", 99186352Ssam .gpin = 12, 100186352Ssam .irq = IXP425_INT_GPIO_12, 101186352Ssam .base16 = CAMBRIA_CFSEL0_HWBASE, 102186352Ssam .size16 = CAMBRIA_CFSEL0_SIZE, 103186352Ssam .off16 = EXP_TIMING_CS3_OFFSET, 104186352Ssam .basealt = CAMBRIA_CFSEL1_HWBASE, 105186352Ssam .sizealt = CAMBRIA_CFSEL1_SIZE, 106186352Ssam .offalt = EXP_TIMING_CS4_OFFSET, 107186352Ssam }, 108186352Ssam { .desc = "ADI Pronghorn Metro IDE/CF Controller", 109186352Ssam .gpin = 0, 110186352Ssam .irq = IXP425_INT_GPIO_0, 111186352Ssam .base16 = IXP425_EXP_BUS_CS3_HWBASE, 112186352Ssam .size16 = IXP425_EXP_BUS_CS3_SIZE, 113186352Ssam .off16 = EXP_TIMING_CS3_OFFSET, 114186352Ssam .basealt = IXP425_EXP_BUS_CS4_HWBASE, 115186352Ssam .sizealt = IXP425_EXP_BUS_CS4_SIZE, 116186352Ssam .offalt = EXP_TIMING_CS4_OFFSET, 117186352Ssam }, 118186352Ssam }; 119186352Ssam 120186352Ssam /* XXX honor hint? (but then no multi-board support) */ 121186352Ssam /* XXX total hack */ 122194753Ssam if (cpu_is_ixp43x()) 123186352Ssam return &configs[1]; /* Cambria */ 124186352Ssam if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0) 125186352Ssam return &configs[0]; /* Avila */ 126186352Ssam return &configs[2]; /* Pronghorn */ 127186352Ssam} 128186352Ssam 129164426Ssamstruct ata_avila_softc { 130164426Ssam device_t sc_dev; 131164426Ssam bus_space_tag_t sc_iot; 132164426Ssam bus_space_handle_t sc_exp_ioh; /* Exp Bus config registers */ 133167565Sjhay bus_space_handle_t sc_ioh; /* CS1/3 data registers */ 134167565Sjhay bus_space_handle_t sc_alt_ioh; /* CS2/4 data registers */ 135164426Ssam struct bus_space sc_expbus_tag; 136164426Ssam struct resource sc_ata; /* hand-crafted for ATA */ 137167565Sjhay struct resource sc_alt_ata; /* hand-crafted for ATA */ 138167565Sjhay u_int32_t sc_16bit_off; /* EXP_TIMING_CSx_OFFSET */ 139164426Ssam int sc_rid; /* rid for IRQ */ 140164426Ssam struct resource *sc_irq; /* IRQ resource */ 141164426Ssam void *sc_ih; /* interrupt handler */ 142164426Ssam struct { 143164426Ssam void (*cb)(void *); 144164426Ssam void *arg; 145164426Ssam } sc_intr[1]; /* NB: 1/channel */ 146164426Ssam}; 147164426Ssam 148164426Ssamstatic void ata_avila_intr(void *); 149164426Ssambs_protos(ata); 150278727Sianstatic void ata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, 151164426Ssam u_int16_t *, bus_size_t); 152278727Sianstatic void ata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, 153164426Ssam const u_int16_t *, bus_size_t); 154164426Ssam 155164426Ssamstatic int 156164426Ssamata_avila_probe(device_t dev) 157164426Ssam{ 158167565Sjhay struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 159186352Ssam const struct ata_config *config; 160167565Sjhay 161186352Ssam config = ata_getconfig(sa); 162186352Ssam if (config != NULL) { 163186352Ssam device_set_desc_copy(dev, config->desc); 164186352Ssam return 0; 165186352Ssam } 166186352Ssam return ENXIO; 167164426Ssam} 168164426Ssam 169164426Ssamstatic int 170164426Ssamata_avila_attach(device_t dev) 171164426Ssam{ 172164426Ssam struct ata_avila_softc *sc = device_get_softc(dev); 173164426Ssam struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 174186352Ssam const struct ata_config *config; 175164426Ssam 176186352Ssam config = ata_getconfig(sa); 177186352Ssam KASSERT(config != NULL, ("no board config")); 178186352Ssam 179164426Ssam sc->sc_dev = dev; 180164426Ssam /* NB: borrow from parent */ 181164426Ssam sc->sc_iot = sa->sc_iot; 182164426Ssam sc->sc_exp_ioh = sa->sc_exp_ioh; 183167565Sjhay 184186352Ssam if (bus_space_map(sc->sc_iot, config->base16, config->size16, 185186352Ssam 0, &sc->sc_ioh)) 186186352Ssam panic("%s: cannot map 16-bit window (0x%x/0x%x)", 187186352Ssam __func__, config->base16, config->size16); 188186352Ssam if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt, 189186352Ssam 0, &sc->sc_alt_ioh)) 190186352Ssam panic("%s: cannot map alt window (0x%x/0x%x)", 191186352Ssam __func__, config->basealt, config->sizealt); 192186352Ssam sc->sc_16bit_off = config->off16; 193186352Ssam 194194753Ssam if (config->base16 != CAMBRIA_CFSEL0_HWBASE) { 195194753Ssam /* 196194753Ssam * Craft special resource for ATA bus space ops 197194753Ssam * that go through the expansion bus and require 198194753Ssam * special hackery to ena/dis 16-bit operations. 199194753Ssam * 200194753Ssam * XXX probably should just make this generic for 201194753Ssam * accessing the expansion bus. 202194753Ssam */ 203278727Sian sc->sc_expbus_tag.bs_privdata = sc; /* NB: backpointer */ 204194753Ssam /* read single */ 205305615Spfg sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1; 206305615Spfg sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2; 207194753Ssam /* read multiple */ 208305615Spfg sc->sc_expbus_tag.bs_rm_2 = ata_bs_rm_2; 209305615Spfg sc->sc_expbus_tag.bs_rm_2_s = ata_bs_rm_2_s; 210194753Ssam /* write (single) */ 211305615Spfg sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1; 212305615Spfg sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2; 213194753Ssam /* write multiple */ 214305615Spfg sc->sc_expbus_tag.bs_wm_2 = ata_bs_wm_2; 215305615Spfg sc->sc_expbus_tag.bs_wm_2_s = ata_bs_wm_2_s; 216164426Ssam 217194753Ssam rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag); 218194753Ssam rman_set_bustag(&sc->sc_alt_ata, &sc->sc_expbus_tag); 219194753Ssam } else { 220194753Ssam /* 221194753Ssam * On Cambria use the shared CS3 expansion bus tag 222194753Ssam * that handles interlock for sharing access with the 223194753Ssam * optional UART's. 224194753Ssam */ 225194753Ssam rman_set_bustag(&sc->sc_ata, &cambria_exp_bs_tag); 226194753Ssam rman_set_bustag(&sc->sc_alt_ata, &cambria_exp_bs_tag); 227194753Ssam } 228164426Ssam rman_set_bushandle(&sc->sc_ata, sc->sc_ioh); 229167565Sjhay rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh); 230164426Ssam 231194653Ssam ixp425_set_gpio(sa, config->gpin, GPIO_TYPE_EDG_RISING); 232164426Ssam 233167565Sjhay /* configure CS1/3 window, leaving timing unchanged */ 234167565Sjhay EXP_BUS_WRITE_4(sc, sc->sc_16bit_off, 235167565Sjhay EXP_BUS_READ_4(sc, sc->sc_16bit_off) | 236164426Ssam EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); 237167565Sjhay /* configure CS2/4 window, leaving timing unchanged */ 238186352Ssam EXP_BUS_WRITE_4(sc, config->offalt, 239186352Ssam EXP_BUS_READ_4(sc, config->offalt) | 240167565Sjhay EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); 241164426Ssam 242164426Ssam /* setup interrupt */ 243164426Ssam sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid, 244186352Ssam config->irq, config->irq, 1, RF_ACTIVE); 245164426Ssam if (!sc->sc_irq) 246186352Ssam panic("Unable to allocate irq %u.\n", config->irq); 247164426Ssam bus_setup_intr(dev, sc->sc_irq, 248164426Ssam INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, 249166996Scognet NULL, ata_avila_intr, sc, &sc->sc_ih); 250164426Ssam 251164426Ssam /* attach channel on this controller */ 252194044Simp device_add_child(dev, "ata", -1); 253164426Ssam bus_generic_attach(dev); 254164426Ssam 255164426Ssam return 0; 256164426Ssam} 257164426Ssam 258164426Ssamstatic int 259164426Ssamata_avila_detach(device_t dev) 260164426Ssam{ 261164426Ssam struct ata_avila_softc *sc = device_get_softc(dev); 262164426Ssam 263164426Ssam /* XXX quiesce gpio? */ 264164426Ssam 265164426Ssam /* detach & delete all children */ 266227849Shselasky device_delete_children(dev); 267164426Ssam 268164426Ssam bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); 269164426Ssam bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq); 270164426Ssam 271164426Ssam return 0; 272164426Ssam} 273164426Ssam 274164426Ssamstatic void 275164426Ssamata_avila_intr(void *xsc) 276164426Ssam{ 277164426Ssam struct ata_avila_softc *sc = xsc; 278164426Ssam 279164426Ssam if (sc->sc_intr[0].cb != NULL) 280164426Ssam sc->sc_intr[0].cb(sc->sc_intr[0].arg); 281164426Ssam} 282164426Ssam 283164426Ssamstatic struct resource * 284164426Ssamata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid, 285164426Ssam u_long start, u_long end, u_long count, u_int flags) 286164426Ssam{ 287164426Ssam struct ata_avila_softc *sc = device_get_softc(dev); 288164426Ssam 289164426Ssam KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID, 290164426Ssam ("type %u rid %u start %lu end %lu count %lu flags %u", 291164426Ssam type, *rid, start, end, count, flags)); 292164426Ssam 293164426Ssam /* doesn't matter what we return so reuse the real thing */ 294164426Ssam return sc->sc_irq; 295164426Ssam} 296164426Ssam 297164426Ssamstatic int 298164426Ssamata_avila_release_resource(device_t dev, device_t child, int type, int rid, 299164426Ssam struct resource *r) 300164426Ssam{ 301164426Ssam KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID, 302164426Ssam ("type %u rid %u", type, rid)); 303164426Ssam return 0; 304164426Ssam} 305164426Ssam 306164426Ssamstatic int 307236987Simpata_avila_setup_intr(device_t dev, device_t child, struct resource *irq, 308166996Scognet int flags, driver_filter_t *filt, 309166996Scognet driver_intr_t *function, void *argument, void **cookiep) 310164426Ssam{ 311164426Ssam struct ata_avila_softc *sc = device_get_softc(dev); 312164426Ssam int unit = ((struct ata_channel *)device_get_softc(child))->unit; 313164426Ssam 314164426Ssam KASSERT(unit == 0, ("unit %d", unit)); 315164426Ssam sc->sc_intr[unit].cb = function; 316164426Ssam sc->sc_intr[unit].arg = argument; 317164426Ssam *cookiep = sc; 318164426Ssam return 0; 319164426Ssam} 320164426Ssam 321164426Ssamstatic int 322164426Ssamata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq, 323164426Ssam void *cookie) 324164426Ssam{ 325164426Ssam struct ata_avila_softc *sc = device_get_softc(dev); 326164426Ssam int unit = ((struct ata_channel *)device_get_softc(child))->unit; 327164426Ssam 328164426Ssam KASSERT(unit == 0, ("unit %d", unit)); 329164426Ssam sc->sc_intr[unit].cb = NULL; 330164426Ssam sc->sc_intr[unit].arg = NULL; 331164426Ssam return 0; 332164426Ssam} 333164426Ssam 334164426Ssam/* 335164426Ssam * Bus space accessors for CF-IDE PIO operations. 336164426Ssam */ 337164426Ssam 338164426Ssam/* 339164426Ssam * Enable/disable 16-bit ops on the expansion bus. 340164426Ssam */ 341186352Ssamstatic __inline void 342164426Ssamenable_16(struct ata_avila_softc *sc) 343164426Ssam{ 344167565Sjhay EXP_BUS_WRITE_4(sc, sc->sc_16bit_off, 345167565Sjhay EXP_BUS_READ_4(sc, sc->sc_16bit_off) &~ EXP_BYTE_EN); 346164426Ssam DELAY(100); /* XXX? */ 347164426Ssam} 348164426Ssam 349186352Ssamstatic __inline void 350164426Ssamdisable_16(struct ata_avila_softc *sc) 351164426Ssam{ 352164426Ssam DELAY(100); /* XXX? */ 353167565Sjhay EXP_BUS_WRITE_4(sc, sc->sc_16bit_off, 354167565Sjhay EXP_BUS_READ_4(sc, sc->sc_16bit_off) | EXP_BYTE_EN); 355164426Ssam} 356164426Ssam 357164426Ssamuint8_t 358278727Sianata_bs_r_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) 359164426Ssam{ 360278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 361164426Ssam 362164426Ssam return bus_space_read_1(sc->sc_iot, h, o); 363164426Ssam} 364164426Ssam 365164426Ssamvoid 366278727Sianata_bs_w_1(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, u_int8_t v) 367164426Ssam{ 368278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 369164426Ssam 370164426Ssam bus_space_write_1(sc->sc_iot, h, o, v); 371164426Ssam} 372164426Ssam 373164426Ssamuint16_t 374278727Sianata_bs_r_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o) 375164426Ssam{ 376278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 377164426Ssam uint16_t v; 378164426Ssam 379164426Ssam enable_16(sc); 380164426Ssam v = bus_space_read_2(sc->sc_iot, h, o); 381164426Ssam disable_16(sc); 382164426Ssam return v; 383164426Ssam} 384164426Ssam 385164426Ssamvoid 386278727Sianata_bs_w_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, uint16_t v) 387164426Ssam{ 388278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 389164426Ssam 390164426Ssam enable_16(sc); 391164426Ssam bus_space_write_2(sc->sc_iot, h, o, v); 392164426Ssam disable_16(sc); 393164426Ssam} 394164426Ssam 395164426Ssamvoid 396278727Sianata_bs_rm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, 397164426Ssam u_int16_t *d, bus_size_t c) 398164426Ssam{ 399278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 400164426Ssam 401164426Ssam enable_16(sc); 402164426Ssam bus_space_read_multi_2(sc->sc_iot, h, o, d, c); 403164426Ssam disable_16(sc); 404164426Ssam} 405164426Ssam 406164426Ssamvoid 407278727Sianata_bs_wm_2(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, 408164426Ssam const u_int16_t *d, bus_size_t c) 409164426Ssam{ 410278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 411164426Ssam 412164426Ssam enable_16(sc); 413164426Ssam bus_space_write_multi_2(sc->sc_iot, h, o, d, c); 414164426Ssam disable_16(sc); 415164426Ssam} 416164426Ssam 417164426Ssam/* XXX workaround ata driver by (incorrectly) byte swapping stream cases */ 418164426Ssam 419164426Ssamvoid 420278727Sianata_bs_rm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, 421164426Ssam u_int16_t *d, bus_size_t c) 422164426Ssam{ 423278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 424164426Ssam uint16_t v; 425164426Ssam bus_size_t i; 426164426Ssam 427164426Ssam enable_16(sc); 428164426Ssam#if 1 429164426Ssam for (i = 0; i < c; i++) { 430164426Ssam v = bus_space_read_2(sc->sc_iot, h, o); 431164426Ssam d[i] = bswap16(v); 432164426Ssam } 433164426Ssam#else 434164426Ssam bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c); 435164426Ssam#endif 436164426Ssam disable_16(sc); 437164426Ssam} 438164426Ssam 439164426Ssamvoid 440278727Sianata_bs_wm_2_s(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t o, 441164426Ssam const u_int16_t *d, bus_size_t c) 442164426Ssam{ 443278727Sian struct ata_avila_softc *sc = tag->bs_privdata; 444164426Ssam bus_size_t i; 445164426Ssam 446164426Ssam enable_16(sc); 447164426Ssam#if 1 448164426Ssam for (i = 0; i < c; i++) 449164426Ssam bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i])); 450164426Ssam#else 451164426Ssam bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c); 452164426Ssam#endif 453164426Ssam disable_16(sc); 454164426Ssam} 455164426Ssam 456164426Ssamstatic device_method_t ata_avila_methods[] = { 457164426Ssam /* device interface */ 458164426Ssam DEVMETHOD(device_probe, ata_avila_probe), 459164426Ssam DEVMETHOD(device_attach, ata_avila_attach), 460164426Ssam DEVMETHOD(device_detach, ata_avila_detach), 461164426Ssam DEVMETHOD(device_shutdown, bus_generic_shutdown), 462164426Ssam DEVMETHOD(device_suspend, bus_generic_suspend), 463164426Ssam DEVMETHOD(device_resume, bus_generic_resume), 464164426Ssam 465164426Ssam /* bus methods */ 466164426Ssam DEVMETHOD(bus_alloc_resource, ata_avila_alloc_resource), 467164426Ssam DEVMETHOD(bus_release_resource, ata_avila_release_resource), 468164426Ssam DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 469164426Ssam DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 470164426Ssam DEVMETHOD(bus_setup_intr, ata_avila_setup_intr), 471164426Ssam DEVMETHOD(bus_teardown_intr, ata_avila_teardown_intr), 472164426Ssam 473164426Ssam { 0, 0 } 474164426Ssam}; 475164426Ssam 476164426Ssamdevclass_t ata_avila_devclass; 477164426Ssam 478164426Ssamstatic driver_t ata_avila_driver = { 479164426Ssam "ata_avila", 480164426Ssam ata_avila_methods, 481164426Ssam sizeof(struct ata_avila_softc), 482164426Ssam}; 483164426Ssam 484164426SsamDRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0); 485164426SsamMODULE_VERSION(ata_avila, 1); 486164426SsamMODULE_DEPEND(ata_avila, ata, 1, 1, 1); 487164426Ssam 488164426Ssamstatic int 489164426Ssamavila_channel_probe(device_t dev) 490164426Ssam{ 491164426Ssam struct ata_channel *ch = device_get_softc(dev); 492164426Ssam 493164426Ssam ch->unit = 0; 494164426Ssam ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE; 495164426Ssam device_set_desc_copy(dev, "ATA channel 0"); 496164426Ssam 497164426Ssam return ata_probe(dev); 498164426Ssam} 499164426Ssam 500164426Ssamstatic int 501164426Ssamavila_channel_attach(device_t dev) 502164426Ssam{ 503164426Ssam struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev)); 504164426Ssam struct ata_channel *ch = device_get_softc(dev); 505164426Ssam int i; 506164426Ssam 507164426Ssam for (i = 0; i < ATA_MAX_RES; i++) 508164426Ssam ch->r_io[i].res = &sc->sc_ata; 509164426Ssam 510164426Ssam ch->r_io[ATA_DATA].offset = ATA_DATA; 511164426Ssam ch->r_io[ATA_FEATURE].offset = ATA_FEATURE; 512164426Ssam ch->r_io[ATA_COUNT].offset = ATA_COUNT; 513164426Ssam ch->r_io[ATA_SECTOR].offset = ATA_SECTOR; 514164426Ssam ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB; 515164426Ssam ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB; 516164426Ssam ch->r_io[ATA_DRIVE].offset = ATA_DRIVE; 517164426Ssam ch->r_io[ATA_COMMAND].offset = ATA_COMMAND; 518164426Ssam ch->r_io[ATA_ERROR].offset = ATA_FEATURE; 519164426Ssam /* NB: should be used only for ATAPI devices */ 520164426Ssam ch->r_io[ATA_IREASON].offset = ATA_COUNT; 521164426Ssam ch->r_io[ATA_STATUS].offset = ATA_COMMAND; 522164426Ssam 523167565Sjhay /* NB: the control and alt status registers are special */ 524167565Sjhay ch->r_io[ATA_ALTSTAT].res = &sc->sc_alt_ata; 525167565Sjhay ch->r_io[ATA_ALTSTAT].offset = AVILA_IDE_CTRL; 526167565Sjhay ch->r_io[ATA_CONTROL].res = &sc->sc_alt_ata; 527164426Ssam ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL; 528164426Ssam 529164426Ssam /* NB: by convention this points at the base of registers */ 530164426Ssam ch->r_io[ATA_IDX_ADDR].offset = 0; 531164426Ssam 532164426Ssam ata_generic_hw(dev); 533164426Ssam return ata_attach(dev); 534164426Ssam} 535164426Ssam 536164426Ssamstatic device_method_t avila_channel_methods[] = { 537164426Ssam /* device interface */ 538164426Ssam DEVMETHOD(device_probe, avila_channel_probe), 539164426Ssam DEVMETHOD(device_attach, avila_channel_attach), 540164426Ssam DEVMETHOD(device_detach, ata_detach), 541164426Ssam DEVMETHOD(device_shutdown, bus_generic_shutdown), 542164426Ssam DEVMETHOD(device_suspend, ata_suspend), 543164426Ssam DEVMETHOD(device_resume, ata_resume), 544164426Ssam 545164426Ssam { 0, 0 } 546164426Ssam}; 547164426Ssam 548164426Ssamdriver_t avila_channel_driver = { 549164426Ssam "ata", 550164426Ssam avila_channel_methods, 551164426Ssam sizeof(struct ata_channel), 552164426Ssam}; 553164426SsamDRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0); 554