1184138Smav/*- 2184138Smav * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org> 3184138Smav * All rights reserved. 4184138Smav * 5184138Smav * Redistribution and use in source and binary forms, with or without 6184138Smav * modification, are permitted provided that the following conditions 7184138Smav * are met: 8184138Smav * 1. Redistributions of source code must retain the above copyright 9184138Smav * notice, this list of conditions and the following disclaimer. 10184138Smav * 2. Redistributions in binary form must reproduce the above copyright 11184138Smav * notice, this list of conditions and the following disclaimer in the 12184138Smav * documentation and/or other materials provided with the distribution. 13184138Smav * 14184138Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15184138Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16184138Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17184138Smav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18184138Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19184138Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20184138Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21184138Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22184138Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23184138Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24184138Smav */ 25184138Smav 26184138Smav#include <sys/cdefs.h> 27184138Smav__FBSDID("$FreeBSD: releng/10.3/sys/dev/sdhci/sdhci.c 283318 2015-05-23 17:43:02Z ian $"); 28184138Smav 29184138Smav#include <sys/param.h> 30184138Smav#include <sys/systm.h> 31184138Smav#include <sys/bus.h> 32266200Sian#include <sys/callout.h> 33184138Smav#include <sys/conf.h> 34184138Smav#include <sys/kernel.h> 35184138Smav#include <sys/lock.h> 36184138Smav#include <sys/module.h> 37184138Smav#include <sys/mutex.h> 38184138Smav#include <sys/resource.h> 39184138Smav#include <sys/rman.h> 40187876Smav#include <sys/sysctl.h> 41184138Smav#include <sys/taskqueue.h> 42184138Smav 43184138Smav#include <machine/bus.h> 44184138Smav#include <machine/resource.h> 45184138Smav#include <machine/stdarg.h> 46184138Smav 47184138Smav#include <dev/mmc/bridge.h> 48184138Smav#include <dev/mmc/mmcreg.h> 49184138Smav#include <dev/mmc/mmcbrvar.h> 50184138Smav 51184138Smav#include "mmcbr_if.h" 52184138Smav#include "sdhci.h" 53241600Sgonzo#include "sdhci_if.h" 54184138Smav 55271051SmariusSYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); 56184138Smav 57271051Smariusstatic int sdhci_debug; 58187876SmavTUNABLE_INT("hw.sdhci.debug", &sdhci_debug); 59271051SmariusSYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level"); 60187876Smav 61241600Sgonzo#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) 62241600Sgonzo#define RD2(slot, off) SDHCI_READ_2((slot)->bus, (slot), (off)) 63241600Sgonzo#define RD4(slot, off) SDHCI_READ_4((slot)->bus, (slot), (off)) 64241600Sgonzo#define RD_MULTI_4(slot, off, ptr, count) \ 65241600Sgonzo SDHCI_READ_MULTI_4((slot)->bus, (slot), (off), (ptr), (count)) 66184138Smav 67241600Sgonzo#define WR1(slot, off, val) SDHCI_WRITE_1((slot)->bus, (slot), (off), (val)) 68241600Sgonzo#define WR2(slot, off, val) SDHCI_WRITE_2((slot)->bus, (slot), (off), (val)) 69241600Sgonzo#define WR4(slot, off, val) SDHCI_WRITE_4((slot)->bus, (slot), (off), (val)) 70241600Sgonzo#define WR_MULTI_4(slot, off, ptr, count) \ 71241600Sgonzo SDHCI_WRITE_MULTI_4((slot)->bus, (slot), (off), (ptr), (count)) 72184138Smav 73184138Smavstatic void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock); 74184138Smavstatic void sdhci_start(struct sdhci_slot *slot); 75184138Smavstatic void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data); 76184138Smav 77184138Smavstatic void sdhci_card_task(void *, int); 78184138Smav 79184138Smav/* helper routines */ 80184138Smav#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx) 81184138Smav#define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx) 82184138Smav#define SDHCI_LOCK_INIT(_slot) \ 83184138Smav mtx_init(&_slot->mtx, "SD slot mtx", "sdhci", MTX_DEF) 84184138Smav#define SDHCI_LOCK_DESTROY(_slot) mtx_destroy(&_slot->mtx); 85184138Smav#define SDHCI_ASSERT_LOCKED(_slot) mtx_assert(&_slot->mtx, MA_OWNED); 86184138Smav#define SDHCI_ASSERT_UNLOCKED(_slot) mtx_assert(&_slot->mtx, MA_NOTOWNED); 87184138Smav 88243689Sgonzo#define SDHCI_DEFAULT_MAX_FREQ 50 89243689Sgonzo 90246886Sgonzo#define SDHCI_200_MAX_DIVIDER 256 91246886Sgonzo#define SDHCI_300_MAX_DIVIDER 2046 92246886Sgonzo 93241600Sgonzostatic void 94241600Sgonzosdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 95241600Sgonzo{ 96241600Sgonzo if (error != 0) { 97241600Sgonzo printf("getaddr: error %d\n", error); 98241600Sgonzo return; 99241600Sgonzo } 100241600Sgonzo *(bus_addr_t *)arg = segs[0].ds_addr; 101241600Sgonzo} 102241600Sgonzo 103184138Smavstatic int 104184138Smavslot_printf(struct sdhci_slot *slot, const char * fmt, ...) 105184138Smav{ 106184138Smav va_list ap; 107184138Smav int retval; 108184138Smav 109184138Smav retval = printf("%s-slot%d: ", 110241600Sgonzo device_get_nameunit(slot->bus), slot->num); 111184138Smav 112184138Smav va_start(ap, fmt); 113184138Smav retval += vprintf(fmt, ap); 114184138Smav va_end(ap); 115184138Smav return (retval); 116184138Smav} 117184138Smav 118184138Smavstatic void 119184138Smavsdhci_dumpregs(struct sdhci_slot *slot) 120184138Smav{ 121184138Smav slot_printf(slot, 122184138Smav "============== REGISTER DUMP ==============\n"); 123184138Smav 124184138Smav slot_printf(slot, "Sys addr: 0x%08x | Version: 0x%08x\n", 125184138Smav RD4(slot, SDHCI_DMA_ADDRESS), RD2(slot, SDHCI_HOST_VERSION)); 126184138Smav slot_printf(slot, "Blk size: 0x%08x | Blk cnt: 0x%08x\n", 127184138Smav RD2(slot, SDHCI_BLOCK_SIZE), RD2(slot, SDHCI_BLOCK_COUNT)); 128184138Smav slot_printf(slot, "Argument: 0x%08x | Trn mode: 0x%08x\n", 129184138Smav RD4(slot, SDHCI_ARGUMENT), RD2(slot, SDHCI_TRANSFER_MODE)); 130184138Smav slot_printf(slot, "Present: 0x%08x | Host ctl: 0x%08x\n", 131184138Smav RD4(slot, SDHCI_PRESENT_STATE), RD1(slot, SDHCI_HOST_CONTROL)); 132184138Smav slot_printf(slot, "Power: 0x%08x | Blk gap: 0x%08x\n", 133184138Smav RD1(slot, SDHCI_POWER_CONTROL), RD1(slot, SDHCI_BLOCK_GAP_CONTROL)); 134184138Smav slot_printf(slot, "Wake-up: 0x%08x | Clock: 0x%08x\n", 135184138Smav RD1(slot, SDHCI_WAKE_UP_CONTROL), RD2(slot, SDHCI_CLOCK_CONTROL)); 136184138Smav slot_printf(slot, "Timeout: 0x%08x | Int stat: 0x%08x\n", 137184138Smav RD1(slot, SDHCI_TIMEOUT_CONTROL), RD4(slot, SDHCI_INT_STATUS)); 138184138Smav slot_printf(slot, "Int enab: 0x%08x | Sig enab: 0x%08x\n", 139184138Smav RD4(slot, SDHCI_INT_ENABLE), RD4(slot, SDHCI_SIGNAL_ENABLE)); 140184138Smav slot_printf(slot, "AC12 err: 0x%08x | Slot int: 0x%08x\n", 141184138Smav RD2(slot, SDHCI_ACMD12_ERR), RD2(slot, SDHCI_SLOT_INT_STATUS)); 142184138Smav slot_printf(slot, "Caps: 0x%08x | Max curr: 0x%08x\n", 143184138Smav RD4(slot, SDHCI_CAPABILITIES), RD4(slot, SDHCI_MAX_CURRENT)); 144184138Smav 145184138Smav slot_printf(slot, 146184138Smav "===========================================\n"); 147184138Smav} 148184138Smav 149184138Smavstatic void 150184138Smavsdhci_reset(struct sdhci_slot *slot, uint8_t mask) 151184138Smav{ 152184138Smav int timeout; 153184138Smav 154241600Sgonzo if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { 155184138Smav if (!(RD4(slot, SDHCI_PRESENT_STATE) & 156184138Smav SDHCI_CARD_PRESENT)) 157184138Smav return; 158184138Smav } 159184138Smav 160184138Smav /* Some controllers need this kick or reset won't work. */ 161184138Smav if ((mask & SDHCI_RESET_ALL) == 0 && 162241600Sgonzo (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) { 163184138Smav uint32_t clock; 164184138Smav 165184138Smav /* This is to force an update */ 166184138Smav clock = slot->clock; 167184138Smav slot->clock = 0; 168184138Smav sdhci_set_clock(slot, clock); 169184138Smav } 170184138Smav 171185661Smav if (mask & SDHCI_RESET_ALL) { 172184138Smav slot->clock = 0; 173185661Smav slot->power = 0; 174185661Smav } 175184138Smav 176276287Sian WR1(slot, SDHCI_SOFTWARE_RESET, mask); 177276287Sian 178276287Sian if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) { 179276287Sian /* 180276287Sian * Resets on TI OMAPs and AM335x are incompatible with SDHCI 181276287Sian * specification. The reset bit has internal propagation delay, 182276287Sian * so a fast read after write returns 0 even if reset process is 183276287Sian * in progress. The workaround is to poll for 1 before polling 184276287Sian * for 0. In the worst case, if we miss seeing it asserted the 185276287Sian * time we spent waiting is enough to ensure the reset finishes. 186276287Sian */ 187276287Sian timeout = 10000; 188276287Sian while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) { 189276287Sian if (timeout <= 0) 190276287Sian break; 191276287Sian timeout--; 192276287Sian DELAY(1); 193276287Sian } 194276287Sian } 195276287Sian 196184138Smav /* Wait max 100 ms */ 197276287Sian timeout = 10000; 198184138Smav /* Controller clears the bits when it's done */ 199276287Sian while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) { 200276287Sian if (timeout <= 0) { 201276287Sian slot_printf(slot, "Reset 0x%x never completed.\n", 202276287Sian mask); 203184138Smav sdhci_dumpregs(slot); 204184138Smav return; 205184138Smav } 206184138Smav timeout--; 207276287Sian DELAY(10); 208184138Smav } 209184138Smav} 210184138Smav 211184138Smavstatic void 212184138Smavsdhci_init(struct sdhci_slot *slot) 213184138Smav{ 214184138Smav 215184138Smav sdhci_reset(slot, SDHCI_RESET_ALL); 216184138Smav 217184138Smav /* Enable interrupts. */ 218184138Smav slot->intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | 219184138Smav SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | 220184138Smav SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | 221184138Smav SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | 222184138Smav SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | 223184138Smav SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | 224184138Smav SDHCI_INT_ACMD12ERR; 225184138Smav WR4(slot, SDHCI_INT_ENABLE, slot->intmask); 226184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); 227184138Smav} 228184138Smav 229184138Smavstatic void 230184138Smavsdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) 231184138Smav{ 232184138Smav uint32_t res; 233184138Smav uint16_t clk; 234242320Sgonzo uint16_t div; 235184138Smav int timeout; 236184138Smav 237184138Smav if (clock == slot->clock) 238184138Smav return; 239184138Smav slot->clock = clock; 240184138Smav 241184138Smav /* Turn off the clock. */ 242266751Sian clk = RD2(slot, SDHCI_CLOCK_CONTROL); 243266751Sian WR2(slot, SDHCI_CLOCK_CONTROL, clk & ~SDHCI_CLOCK_CARD_EN); 244184138Smav /* If no clock requested - left it so. */ 245184138Smav if (clock == 0) 246184138Smav return; 247254423Sian 248254423Sian /* Recalculate timeout clock frequency based on the new sd clock. */ 249254423Sian if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) 250254423Sian slot->timeout_clk = slot->clock / 1000; 251254423Sian 252242320Sgonzo if (slot->version < SDHCI_SPEC_300) { 253242320Sgonzo /* Looking for highest freq <= clock. */ 254242320Sgonzo res = slot->max_clk; 255246886Sgonzo for (div = 1; div < SDHCI_200_MAX_DIVIDER; div <<= 1) { 256242320Sgonzo if (res <= clock) 257242320Sgonzo break; 258242320Sgonzo res >>= 1; 259242320Sgonzo } 260242320Sgonzo /* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */ 261242320Sgonzo div >>= 1; 262184138Smav } 263242320Sgonzo else { 264242320Sgonzo /* Version 3.0 divisors are multiples of two up to 1023*2 */ 265246886Sgonzo if (clock >= slot->max_clk) 266246886Sgonzo div = 0; 267242320Sgonzo else { 268246886Sgonzo for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { 269242320Sgonzo if ((slot->max_clk / div) <= clock) 270242320Sgonzo break; 271242320Sgonzo } 272242320Sgonzo } 273242320Sgonzo div >>= 1; 274242320Sgonzo } 275242320Sgonzo 276242320Sgonzo if (bootverbose || sdhci_debug) 277242320Sgonzo slot_printf(slot, "Divider %d for freq %d (max %d)\n", 278242320Sgonzo div, clock, slot->max_clk); 279242320Sgonzo 280184138Smav /* Now we have got divider, set it. */ 281242320Sgonzo clk = (div & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT; 282242320Sgonzo clk |= ((div >> SDHCI_DIVIDER_MASK_LEN) & SDHCI_DIVIDER_HI_MASK) 283242320Sgonzo << SDHCI_DIVIDER_HI_SHIFT; 284242320Sgonzo 285184138Smav WR2(slot, SDHCI_CLOCK_CONTROL, clk); 286184138Smav /* Enable clock. */ 287184138Smav clk |= SDHCI_CLOCK_INT_EN; 288184138Smav WR2(slot, SDHCI_CLOCK_CONTROL, clk); 289184138Smav /* Wait up to 10 ms until it stabilize. */ 290184138Smav timeout = 10; 291184138Smav while (!((clk = RD2(slot, SDHCI_CLOCK_CONTROL)) 292184138Smav & SDHCI_CLOCK_INT_STABLE)) { 293184138Smav if (timeout == 0) { 294184138Smav slot_printf(slot, 295184138Smav "Internal clock never stabilised.\n"); 296184138Smav sdhci_dumpregs(slot); 297184138Smav return; 298184138Smav } 299184138Smav timeout--; 300184138Smav DELAY(1000); 301184138Smav } 302184138Smav /* Pass clock signal to the bus. */ 303184138Smav clk |= SDHCI_CLOCK_CARD_EN; 304184138Smav WR2(slot, SDHCI_CLOCK_CONTROL, clk); 305184138Smav} 306184138Smav 307184138Smavstatic void 308184138Smavsdhci_set_power(struct sdhci_slot *slot, u_char power) 309184138Smav{ 310184138Smav uint8_t pwr; 311184138Smav 312184138Smav if (slot->power == power) 313184138Smav return; 314241600Sgonzo 315184138Smav slot->power = power; 316184138Smav 317184138Smav /* Turn off the power. */ 318184138Smav pwr = 0; 319184138Smav WR1(slot, SDHCI_POWER_CONTROL, pwr); 320184138Smav /* If power down requested - left it so. */ 321184138Smav if (power == 0) 322184138Smav return; 323184138Smav /* Set voltage. */ 324184138Smav switch (1 << power) { 325184138Smav case MMC_OCR_LOW_VOLTAGE: 326184138Smav pwr |= SDHCI_POWER_180; 327184138Smav break; 328184138Smav case MMC_OCR_290_300: 329184138Smav case MMC_OCR_300_310: 330184138Smav pwr |= SDHCI_POWER_300; 331184138Smav break; 332184138Smav case MMC_OCR_320_330: 333184138Smav case MMC_OCR_330_340: 334184138Smav pwr |= SDHCI_POWER_330; 335184138Smav break; 336184138Smav } 337184138Smav WR1(slot, SDHCI_POWER_CONTROL, pwr); 338184138Smav /* Turn on the power. */ 339184138Smav pwr |= SDHCI_POWER_ON; 340184138Smav WR1(slot, SDHCI_POWER_CONTROL, pwr); 341184138Smav} 342184138Smav 343184138Smavstatic void 344184138Smavsdhci_read_block_pio(struct sdhci_slot *slot) 345184138Smav{ 346184138Smav uint32_t data; 347184138Smav char *buffer; 348184138Smav size_t left; 349184138Smav 350184138Smav buffer = slot->curcmd->data->data; 351184138Smav buffer += slot->offset; 352184138Smav /* Transfer one block at a time. */ 353184138Smav left = min(512, slot->curcmd->data->len - slot->offset); 354184138Smav slot->offset += left; 355184138Smav 356184138Smav /* If we are too fast, broken controllers return zeroes. */ 357241600Sgonzo if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) 358184138Smav DELAY(10); 359254512Srpaulo /* Handle unaligned and aligned buffer cases. */ 360184138Smav if ((intptr_t)buffer & 3) { 361184138Smav while (left > 3) { 362184138Smav data = RD4(slot, SDHCI_BUFFER); 363184138Smav buffer[0] = data; 364184138Smav buffer[1] = (data >> 8); 365184138Smav buffer[2] = (data >> 16); 366184138Smav buffer[3] = (data >> 24); 367184138Smav buffer += 4; 368184138Smav left -= 4; 369184138Smav } 370184138Smav } else { 371241600Sgonzo RD_MULTI_4(slot, SDHCI_BUFFER, 372184138Smav (uint32_t *)buffer, left >> 2); 373184138Smav left &= 3; 374184138Smav } 375184138Smav /* Handle uneven size case. */ 376184138Smav if (left > 0) { 377184138Smav data = RD4(slot, SDHCI_BUFFER); 378184138Smav while (left > 0) { 379184138Smav *(buffer++) = data; 380184138Smav data >>= 8; 381184138Smav left--; 382184138Smav } 383184138Smav } 384184138Smav} 385184138Smav 386184138Smavstatic void 387184138Smavsdhci_write_block_pio(struct sdhci_slot *slot) 388184138Smav{ 389184138Smav uint32_t data = 0; 390184138Smav char *buffer; 391184138Smav size_t left; 392184138Smav 393184138Smav buffer = slot->curcmd->data->data; 394184138Smav buffer += slot->offset; 395184138Smav /* Transfer one block at a time. */ 396184138Smav left = min(512, slot->curcmd->data->len - slot->offset); 397184138Smav slot->offset += left; 398184138Smav 399254512Srpaulo /* Handle unaligned and aligned buffer cases. */ 400184138Smav if ((intptr_t)buffer & 3) { 401184138Smav while (left > 3) { 402184138Smav data = buffer[0] + 403184138Smav (buffer[1] << 8) + 404184138Smav (buffer[2] << 16) + 405184138Smav (buffer[3] << 24); 406184138Smav left -= 4; 407184138Smav buffer += 4; 408184138Smav WR4(slot, SDHCI_BUFFER, data); 409184138Smav } 410184138Smav } else { 411241600Sgonzo WR_MULTI_4(slot, SDHCI_BUFFER, 412184138Smav (uint32_t *)buffer, left >> 2); 413184138Smav left &= 3; 414184138Smav } 415184138Smav /* Handle uneven size case. */ 416184138Smav if (left > 0) { 417184138Smav while (left > 0) { 418184138Smav data <<= 8; 419184138Smav data += *(buffer++); 420184138Smav left--; 421184138Smav } 422184138Smav WR4(slot, SDHCI_BUFFER, data); 423184138Smav } 424184138Smav} 425184138Smav 426184138Smavstatic void 427184138Smavsdhci_transfer_pio(struct sdhci_slot *slot) 428184138Smav{ 429184138Smav 430184138Smav /* Read as many blocks as possible. */ 431184138Smav if (slot->curcmd->data->flags & MMC_DATA_READ) { 432184138Smav while (RD4(slot, SDHCI_PRESENT_STATE) & 433184138Smav SDHCI_DATA_AVAILABLE) { 434184138Smav sdhci_read_block_pio(slot); 435184138Smav if (slot->offset >= slot->curcmd->data->len) 436184138Smav break; 437184138Smav } 438184138Smav } else { 439184138Smav while (RD4(slot, SDHCI_PRESENT_STATE) & 440184138Smav SDHCI_SPACE_AVAILABLE) { 441184138Smav sdhci_write_block_pio(slot); 442184138Smav if (slot->offset >= slot->curcmd->data->len) 443184138Smav break; 444184138Smav } 445184138Smav } 446184138Smav} 447184138Smav 448184138Smavstatic void 449184138Smavsdhci_card_delay(void *arg) 450184138Smav{ 451184138Smav struct sdhci_slot *slot = arg; 452184138Smav 453184138Smav taskqueue_enqueue(taskqueue_swi_giant, &slot->card_task); 454184138Smav} 455184138Smav 456184138Smavstatic void 457184138Smavsdhci_card_task(void *arg, int pending) 458184138Smav{ 459184138Smav struct sdhci_slot *slot = arg; 460184138Smav 461184138Smav SDHCI_LOCK(slot); 462184138Smav if (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) { 463184138Smav if (slot->dev == NULL) { 464184138Smav /* If card is present - attach mmc bus. */ 465241600Sgonzo slot->dev = device_add_child(slot->bus, "mmc", -1); 466184138Smav device_set_ivars(slot->dev, slot); 467184138Smav SDHCI_UNLOCK(slot); 468184138Smav device_probe_and_attach(slot->dev); 469184138Smav } else 470184138Smav SDHCI_UNLOCK(slot); 471184138Smav } else { 472184138Smav if (slot->dev != NULL) { 473184138Smav /* If no card present - detach mmc bus. */ 474184138Smav device_t d = slot->dev; 475184138Smav slot->dev = NULL; 476184138Smav SDHCI_UNLOCK(slot); 477241600Sgonzo device_delete_child(slot->bus, d); 478184138Smav } else 479184138Smav SDHCI_UNLOCK(slot); 480184138Smav } 481184138Smav} 482184138Smav 483241600Sgonzoint 484241600Sgonzosdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num) 485184138Smav{ 486254507Sian uint32_t caps, freq; 487241600Sgonzo int err; 488184138Smav 489241600Sgonzo SDHCI_LOCK_INIT(slot); 490241600Sgonzo slot->num = num; 491241600Sgonzo slot->bus = dev; 492184138Smav 493241600Sgonzo /* Allocate DMA tag. */ 494241600Sgonzo err = bus_dma_tag_create(bus_get_dma_tag(dev), 495241600Sgonzo DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, 496241600Sgonzo BUS_SPACE_MAXADDR, NULL, NULL, 497241600Sgonzo DMA_BLOCK_SIZE, 1, DMA_BLOCK_SIZE, 498241600Sgonzo BUS_DMA_ALLOCNOW, NULL, NULL, 499241600Sgonzo &slot->dmatag); 500241600Sgonzo if (err != 0) { 501241600Sgonzo device_printf(dev, "Can't create DMA tag\n"); 502241600Sgonzo SDHCI_LOCK_DESTROY(slot); 503241600Sgonzo return (err); 504184138Smav } 505241600Sgonzo /* Allocate DMA memory. */ 506241600Sgonzo err = bus_dmamem_alloc(slot->dmatag, (void **)&slot->dmamem, 507241600Sgonzo BUS_DMA_NOWAIT, &slot->dmamap); 508241600Sgonzo if (err != 0) { 509241600Sgonzo device_printf(dev, "Can't alloc DMA memory\n"); 510241600Sgonzo SDHCI_LOCK_DESTROY(slot); 511241600Sgonzo return (err); 512184138Smav } 513241600Sgonzo /* Map the memory. */ 514241600Sgonzo err = bus_dmamap_load(slot->dmatag, slot->dmamap, 515241600Sgonzo (void *)slot->dmamem, DMA_BLOCK_SIZE, 516241600Sgonzo sdhci_getaddr, &slot->paddr, 0); 517241600Sgonzo if (err != 0 || slot->paddr == 0) { 518241600Sgonzo device_printf(dev, "Can't load DMA memory\n"); 519241600Sgonzo SDHCI_LOCK_DESTROY(slot); 520241600Sgonzo if(err) 521241600Sgonzo return (err); 522241600Sgonzo else 523241600Sgonzo return (EFAULT); 524184138Smav } 525184138Smav 526241600Sgonzo /* Initialize slot. */ 527241600Sgonzo sdhci_init(slot); 528241600Sgonzo slot->version = (RD2(slot, SDHCI_HOST_VERSION) 529241600Sgonzo >> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK; 530242320Sgonzo if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) 531242320Sgonzo caps = slot->caps; 532242320Sgonzo else 533242320Sgonzo caps = RD4(slot, SDHCI_CAPABILITIES); 534241600Sgonzo /* Calculate base clock frequency. */ 535243689Sgonzo if (slot->version >= SDHCI_SPEC_300) 536254507Sian freq = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> 537254507Sian SDHCI_CLOCK_BASE_SHIFT; 538243689Sgonzo else 539254507Sian freq = (caps & SDHCI_CLOCK_BASE_MASK) >> 540254507Sian SDHCI_CLOCK_BASE_SHIFT; 541254507Sian if (freq != 0) 542254507Sian slot->max_clk = freq * 1000000; 543254507Sian /* 544254507Sian * If the frequency wasn't in the capabilities and the hardware driver 545254507Sian * hasn't already set max_clk we're probably not going to work right 546254507Sian * with an assumption, so complain about it. 547254507Sian */ 548241600Sgonzo if (slot->max_clk == 0) { 549254507Sian slot->max_clk = SDHCI_DEFAULT_MAX_FREQ * 1000000; 550241600Sgonzo device_printf(dev, "Hardware doesn't specify base clock " 551243689Sgonzo "frequency, using %dMHz as default.\n", SDHCI_DEFAULT_MAX_FREQ); 552241600Sgonzo } 553241600Sgonzo /* Calculate timeout clock frequency. */ 554242320Sgonzo if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) { 555242320Sgonzo slot->timeout_clk = slot->max_clk / 1000; 556242320Sgonzo } else { 557242320Sgonzo slot->timeout_clk = 558242320Sgonzo (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; 559242320Sgonzo if (caps & SDHCI_TIMEOUT_CLK_UNIT) 560242320Sgonzo slot->timeout_clk *= 1000; 561242320Sgonzo } 562254507Sian /* 563254507Sian * If the frequency wasn't in the capabilities and the hardware driver 564254507Sian * hasn't already set timeout_clk we'll probably work okay using the 565254507Sian * max timeout, but still mention it. 566254507Sian */ 567241600Sgonzo if (slot->timeout_clk == 0) { 568241600Sgonzo device_printf(dev, "Hardware doesn't specify timeout clock " 569254423Sian "frequency, setting BROKEN_TIMEOUT quirk.\n"); 570254423Sian slot->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 571241600Sgonzo } 572184138Smav 573246886Sgonzo slot->host.f_min = SDHCI_MIN_FREQ(slot->bus, slot); 574241600Sgonzo slot->host.f_max = slot->max_clk; 575241600Sgonzo slot->host.host_ocr = 0; 576241600Sgonzo if (caps & SDHCI_CAN_VDD_330) 577241600Sgonzo slot->host.host_ocr |= MMC_OCR_320_330 | MMC_OCR_330_340; 578241600Sgonzo if (caps & SDHCI_CAN_VDD_300) 579241600Sgonzo slot->host.host_ocr |= MMC_OCR_290_300 | MMC_OCR_300_310; 580241600Sgonzo if (caps & SDHCI_CAN_VDD_180) 581241600Sgonzo slot->host.host_ocr |= MMC_OCR_LOW_VOLTAGE; 582241600Sgonzo if (slot->host.host_ocr == 0) { 583241600Sgonzo device_printf(dev, "Hardware doesn't report any " 584241600Sgonzo "support voltages.\n"); 585184138Smav } 586241600Sgonzo slot->host.caps = MMC_CAP_4_BIT_DATA; 587283318Sian if (caps & SDHCI_CAN_DO_8BITBUS) 588283318Sian slot->host.caps |= MMC_CAP_8_BIT_DATA; 589241600Sgonzo if (caps & SDHCI_CAN_DO_HISPD) 590241600Sgonzo slot->host.caps |= MMC_CAP_HSPEED; 591241600Sgonzo /* Decide if we have usable DMA. */ 592241600Sgonzo if (caps & SDHCI_CAN_DO_DMA) 593241600Sgonzo slot->opt |= SDHCI_HAVE_DMA; 594184138Smav 595241600Sgonzo if (slot->quirks & SDHCI_QUIRK_BROKEN_DMA) 596241600Sgonzo slot->opt &= ~SDHCI_HAVE_DMA; 597241600Sgonzo if (slot->quirks & SDHCI_QUIRK_FORCE_DMA) 598241600Sgonzo slot->opt |= SDHCI_HAVE_DMA; 599241600Sgonzo 600247495Sgonzo /* 601247495Sgonzo * Use platform-provided transfer backend 602247495Sgonzo * with PIO as a fallback mechanism 603247495Sgonzo */ 604247495Sgonzo if (slot->opt & SDHCI_PLATFORM_TRANSFER) 605247495Sgonzo slot->opt &= ~SDHCI_HAVE_DMA; 606247495Sgonzo 607241600Sgonzo if (bootverbose || sdhci_debug) { 608283318Sian slot_printf(slot, "%uMHz%s %s%s%s%s %s\n", 609241600Sgonzo slot->max_clk / 1000000, 610241600Sgonzo (caps & SDHCI_CAN_DO_HISPD) ? " HS" : "", 611283318Sian (caps & MMC_CAP_8_BIT_DATA) ? "8bits" : 612283318Sian ((caps & MMC_CAP_4_BIT_DATA) ? "4bits" : "1bit"), 613241600Sgonzo (caps & SDHCI_CAN_VDD_330) ? " 3.3V" : "", 614241600Sgonzo (caps & SDHCI_CAN_VDD_300) ? " 3.0V" : "", 615241600Sgonzo (caps & SDHCI_CAN_VDD_180) ? " 1.8V" : "", 616241600Sgonzo (slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO"); 617241600Sgonzo sdhci_dumpregs(slot); 618184138Smav } 619241600Sgonzo 620241600Sgonzo TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot); 621241600Sgonzo callout_init(&slot->card_callout, 1); 622266200Sian callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0); 623184138Smav return (0); 624184138Smav} 625184138Smav 626241600Sgonzovoid 627241600Sgonzosdhci_start_slot(struct sdhci_slot *slot) 628184138Smav{ 629241600Sgonzo sdhci_card_task(slot, 0); 630241600Sgonzo} 631184138Smav 632241600Sgonzoint 633241600Sgonzosdhci_cleanup_slot(struct sdhci_slot *slot) 634241600Sgonzo{ 635241600Sgonzo device_t d; 636184138Smav 637266200Sian callout_drain(&slot->timeout_callout); 638241600Sgonzo callout_drain(&slot->card_callout); 639241600Sgonzo taskqueue_drain(taskqueue_swi_giant, &slot->card_task); 640184138Smav 641241600Sgonzo SDHCI_LOCK(slot); 642241600Sgonzo d = slot->dev; 643241600Sgonzo slot->dev = NULL; 644241600Sgonzo SDHCI_UNLOCK(slot); 645241600Sgonzo if (d != NULL) 646241600Sgonzo device_delete_child(slot->bus, d); 647184138Smav 648241600Sgonzo SDHCI_LOCK(slot); 649241600Sgonzo sdhci_reset(slot, SDHCI_RESET_ALL); 650241600Sgonzo SDHCI_UNLOCK(slot); 651241600Sgonzo bus_dmamap_unload(slot->dmatag, slot->dmamap); 652241600Sgonzo bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap); 653241600Sgonzo bus_dma_tag_destroy(slot->dmatag); 654184138Smav 655241600Sgonzo SDHCI_LOCK_DESTROY(slot); 656241600Sgonzo 657184138Smav return (0); 658184138Smav} 659184138Smav 660241600Sgonzoint 661241600Sgonzosdhci_generic_suspend(struct sdhci_slot *slot) 662185527Smav{ 663241600Sgonzo sdhci_reset(slot, SDHCI_RESET_ALL); 664185527Smav 665185527Smav return (0); 666185527Smav} 667185527Smav 668241600Sgonzoint 669241600Sgonzosdhci_generic_resume(struct sdhci_slot *slot) 670185527Smav{ 671241600Sgonzo sdhci_init(slot); 672185527Smav 673241600Sgonzo return (0); 674185527Smav} 675185527Smav 676246886Sgonzouint32_t 677246886Sgonzosdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot) 678246886Sgonzo{ 679246886Sgonzo if (slot->version >= SDHCI_SPEC_300) 680246886Sgonzo return (slot->max_clk / SDHCI_300_MAX_DIVIDER); 681246886Sgonzo else 682246886Sgonzo return (slot->max_clk / SDHCI_200_MAX_DIVIDER); 683246886Sgonzo} 684246886Sgonzo 685241600Sgonzoint 686241600Sgonzosdhci_generic_update_ios(device_t brdev, device_t reqdev) 687184138Smav{ 688184138Smav struct sdhci_slot *slot = device_get_ivars(reqdev); 689184138Smav struct mmc_ios *ios = &slot->host.ios; 690184138Smav 691184138Smav SDHCI_LOCK(slot); 692184138Smav /* Do full reset on bus power down to clear from any state. */ 693184138Smav if (ios->power_mode == power_off) { 694184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, 0); 695184138Smav sdhci_init(slot); 696184138Smav } 697184138Smav /* Configure the bus. */ 698184138Smav sdhci_set_clock(slot, ios->clock); 699283318Sian sdhci_set_power(slot, (ios->power_mode == power_off) ? 0 : ios->vdd); 700283318Sian if (ios->bus_width == bus_width_8) { 701283318Sian slot->hostctrl |= SDHCI_CTRL_8BITBUS; 702283318Sian slot->hostctrl &= ~SDHCI_CTRL_4BITBUS; 703283318Sian } else if (ios->bus_width == bus_width_4) { 704283318Sian slot->hostctrl &= ~SDHCI_CTRL_8BITBUS; 705184138Smav slot->hostctrl |= SDHCI_CTRL_4BITBUS; 706283318Sian } else if (ios->bus_width == bus_width_1) { 707283318Sian slot->hostctrl &= ~SDHCI_CTRL_8BITBUS; 708184138Smav slot->hostctrl &= ~SDHCI_CTRL_4BITBUS; 709283318Sian } else { 710283318Sian panic("Invalid bus width: %d", ios->bus_width); 711283318Sian } 712278703Sian if (ios->timing == bus_timing_hs && 713278703Sian !(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT)) 714184138Smav slot->hostctrl |= SDHCI_CTRL_HISPD; 715184138Smav else 716184138Smav slot->hostctrl &= ~SDHCI_CTRL_HISPD; 717184138Smav WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl); 718184138Smav /* Some controllers like reset after bus changes. */ 719241600Sgonzo if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS) 720184138Smav sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); 721184138Smav 722184138Smav SDHCI_UNLOCK(slot); 723184138Smav return (0); 724184138Smav} 725184138Smav 726266200Sianstatic void 727266200Siansdhci_req_done(struct sdhci_slot *slot) 728266200Sian{ 729266200Sian struct mmc_request *req; 730266200Sian 731266200Sian if (slot->req != NULL && slot->curcmd != NULL) { 732266200Sian callout_stop(&slot->timeout_callout); 733266200Sian req = slot->req; 734266200Sian slot->req = NULL; 735266200Sian slot->curcmd = NULL; 736266200Sian req->done(req); 737266200Sian } 738266200Sian} 739266200Sian 740266200Sianstatic void 741266200Siansdhci_timeout(void *arg) 742266200Sian{ 743266200Sian struct sdhci_slot *slot = arg; 744266200Sian 745266200Sian if (slot->curcmd != NULL) { 746276287Sian slot_printf(slot, " Controller timeout\n"); 747276287Sian sdhci_dumpregs(slot); 748266200Sian sdhci_reset(slot, SDHCI_RESET_CMD|SDHCI_RESET_DATA); 749266200Sian slot->curcmd->error = MMC_ERR_TIMEOUT; 750266200Sian sdhci_req_done(slot); 751276287Sian } else { 752276287Sian slot_printf(slot, " Spurious timeout - no active command\n"); 753266200Sian } 754266200Sian} 755266200Sian 756184138Smavstatic void 757184138Smavsdhci_set_transfer_mode(struct sdhci_slot *slot, 758184138Smav struct mmc_data *data) 759184138Smav{ 760184138Smav uint16_t mode; 761184138Smav 762184138Smav if (data == NULL) 763184138Smav return; 764184138Smav 765184138Smav mode = SDHCI_TRNS_BLK_CNT_EN; 766184138Smav if (data->len > 512) 767184138Smav mode |= SDHCI_TRNS_MULTI; 768184138Smav if (data->flags & MMC_DATA_READ) 769184138Smav mode |= SDHCI_TRNS_READ; 770184138Smav if (slot->req->stop) 771184138Smav mode |= SDHCI_TRNS_ACMD12; 772184138Smav if (slot->flags & SDHCI_USE_DMA) 773184138Smav mode |= SDHCI_TRNS_DMA; 774184138Smav 775184138Smav WR2(slot, SDHCI_TRANSFER_MODE, mode); 776184138Smav} 777184138Smav 778184138Smavstatic void 779184138Smavsdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd) 780184138Smav{ 781184138Smav int flags, timeout; 782184138Smav uint32_t mask, state; 783184138Smav 784184138Smav slot->curcmd = cmd; 785184138Smav slot->cmd_done = 0; 786184138Smav 787184138Smav cmd->error = MMC_ERR_NONE; 788184138Smav 789184138Smav /* This flags combination is not supported by controller. */ 790184138Smav if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { 791184138Smav slot_printf(slot, "Unsupported response type!\n"); 792184138Smav cmd->error = MMC_ERR_FAILED; 793266200Sian sdhci_req_done(slot); 794184138Smav return; 795184138Smav } 796184138Smav 797184138Smav /* Read controller present state. */ 798184138Smav state = RD4(slot, SDHCI_PRESENT_STATE); 799185661Smav /* Do not issue command if there is no card, clock or power. 800185661Smav * Controller will not detect timeout without clock active. */ 801185661Smav if ((state & SDHCI_CARD_PRESENT) == 0 || 802185661Smav slot->power == 0 || 803185661Smav slot->clock == 0) { 804184138Smav cmd->error = MMC_ERR_FAILED; 805266200Sian sdhci_req_done(slot); 806184138Smav return; 807184138Smav } 808184138Smav /* Always wait for free CMD bus. */ 809184138Smav mask = SDHCI_CMD_INHIBIT; 810184138Smav /* Wait for free DAT if we have data or busy signal. */ 811184138Smav if (cmd->data || (cmd->flags & MMC_RSP_BUSY)) 812184138Smav mask |= SDHCI_DAT_INHIBIT; 813184138Smav /* We shouldn't wait for DAT for stop commands. */ 814184138Smav if (cmd == slot->req->stop) 815184138Smav mask &= ~SDHCI_DAT_INHIBIT; 816266200Sian /* 817266200Sian * Wait for bus no more then 250 ms. Typically there will be no wait 818266200Sian * here at all, but when writing a crash dump we may be bypassing the 819266200Sian * host platform's interrupt handler, and in some cases that handler 820266200Sian * may be working around hardware quirks such as not respecting r1b 821266200Sian * busy indications. In those cases, this wait-loop serves the purpose 822266200Sian * of waiting for the prior command and data transfers to be done, and 823266200Sian * SD cards are allowed to take up to 250ms for write and erase ops. 824266200Sian * (It's usually more like 20-30ms in the real world.) 825266200Sian */ 826266200Sian timeout = 250; 827184138Smav while (state & mask) { 828184138Smav if (timeout == 0) { 829184138Smav slot_printf(slot, "Controller never released " 830184138Smav "inhibit bit(s).\n"); 831184138Smav sdhci_dumpregs(slot); 832184138Smav cmd->error = MMC_ERR_FAILED; 833266200Sian sdhci_req_done(slot); 834184138Smav return; 835184138Smav } 836184138Smav timeout--; 837184138Smav DELAY(1000); 838184138Smav state = RD4(slot, SDHCI_PRESENT_STATE); 839184138Smav } 840184138Smav 841184138Smav /* Prepare command flags. */ 842184138Smav if (!(cmd->flags & MMC_RSP_PRESENT)) 843184138Smav flags = SDHCI_CMD_RESP_NONE; 844184138Smav else if (cmd->flags & MMC_RSP_136) 845184138Smav flags = SDHCI_CMD_RESP_LONG; 846184138Smav else if (cmd->flags & MMC_RSP_BUSY) 847184138Smav flags = SDHCI_CMD_RESP_SHORT_BUSY; 848184138Smav else 849184138Smav flags = SDHCI_CMD_RESP_SHORT; 850184138Smav if (cmd->flags & MMC_RSP_CRC) 851184138Smav flags |= SDHCI_CMD_CRC; 852184138Smav if (cmd->flags & MMC_RSP_OPCODE) 853184138Smav flags |= SDHCI_CMD_INDEX; 854184138Smav if (cmd->data) 855184138Smav flags |= SDHCI_CMD_DATA; 856184138Smav if (cmd->opcode == MMC_STOP_TRANSMISSION) 857184138Smav flags |= SDHCI_CMD_TYPE_ABORT; 858184138Smav /* Prepare data. */ 859184138Smav sdhci_start_data(slot, cmd->data); 860184138Smav /* 861184138Smav * Interrupt aggregation: To reduce total number of interrupts 862184138Smav * group response interrupt with data interrupt when possible. 863184138Smav * If there going to be data interrupt, mask response one. 864184138Smav */ 865184138Smav if (slot->data_done == 0) { 866184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, 867184138Smav slot->intmask &= ~SDHCI_INT_RESPONSE); 868184138Smav } 869184138Smav /* Set command argument. */ 870184138Smav WR4(slot, SDHCI_ARGUMENT, cmd->arg); 871184138Smav /* Set data transfer mode. */ 872184138Smav sdhci_set_transfer_mode(slot, cmd->data); 873184138Smav /* Start command. */ 874241600Sgonzo WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff)); 875266200Sian /* Start timeout callout. */ 876266200Sian callout_reset(&slot->timeout_callout, 2*hz, sdhci_timeout, slot); 877184138Smav} 878184138Smav 879184138Smavstatic void 880184138Smavsdhci_finish_command(struct sdhci_slot *slot) 881184138Smav{ 882184138Smav int i; 883184138Smav 884184138Smav slot->cmd_done = 1; 885184138Smav /* Interrupt aggregation: Restore command interrupt. 886184138Smav * Main restore point for the case when command interrupt 887184138Smav * happened first. */ 888184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE); 889184138Smav /* In case of error - reset host and return. */ 890184138Smav if (slot->curcmd->error) { 891184138Smav sdhci_reset(slot, SDHCI_RESET_CMD); 892184138Smav sdhci_reset(slot, SDHCI_RESET_DATA); 893184138Smav sdhci_start(slot); 894184138Smav return; 895184138Smav } 896184138Smav /* If command has response - fetch it. */ 897184138Smav if (slot->curcmd->flags & MMC_RSP_PRESENT) { 898184138Smav if (slot->curcmd->flags & MMC_RSP_136) { 899184138Smav /* CRC is stripped so we need one byte shift. */ 900184138Smav uint8_t extra = 0; 901184138Smav for (i = 0; i < 4; i++) { 902184138Smav uint32_t val = RD4(slot, SDHCI_RESPONSE + i * 4); 903254496Sian if (slot->quirks & SDHCI_QUIRK_DONT_SHIFT_RESPONSE) 904254496Sian slot->curcmd->resp[3 - i] = val; 905254496Sian else { 906254496Sian slot->curcmd->resp[3 - i] = 907254496Sian (val << 8) | extra; 908254496Sian extra = val >> 24; 909254496Sian } 910184138Smav } 911184138Smav } else 912184138Smav slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE); 913184138Smav } 914184138Smav /* If data ready - finish. */ 915184138Smav if (slot->data_done) 916184138Smav sdhci_start(slot); 917184138Smav} 918184138Smav 919184138Smavstatic void 920184138Smavsdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) 921184138Smav{ 922184138Smav uint32_t target_timeout, current_timeout; 923184138Smav uint8_t div; 924184138Smav 925184138Smav if (data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) { 926184138Smav slot->data_done = 1; 927184138Smav return; 928184138Smav } 929184138Smav 930184138Smav slot->data_done = 0; 931184138Smav 932184138Smav /* Calculate and set data timeout.*/ 933184138Smav /* XXX: We should have this from mmc layer, now assume 1 sec. */ 934254423Sian if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) { 935184138Smav div = 0xE; 936254423Sian } else { 937254423Sian target_timeout = 1000000; 938254423Sian div = 0; 939254423Sian current_timeout = (1 << 13) * 1000 / slot->timeout_clk; 940254423Sian while (current_timeout < target_timeout && div < 0xE) { 941254423Sian ++div; 942254423Sian current_timeout <<= 1; 943254423Sian } 944254423Sian /* Compensate for an off-by-one error in the CaFe chip.*/ 945254423Sian if (div < 0xE && 946254423Sian (slot->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL)) { 947254423Sian ++div; 948254423Sian } 949184138Smav } 950184138Smav WR1(slot, SDHCI_TIMEOUT_CONTROL, div); 951184138Smav 952184138Smav if (data == NULL) 953184138Smav return; 954184138Smav 955184138Smav /* Use DMA if possible. */ 956184138Smav if ((slot->opt & SDHCI_HAVE_DMA)) 957184138Smav slot->flags |= SDHCI_USE_DMA; 958184138Smav /* If data is small, broken DMA may return zeroes instead of data, */ 959241600Sgonzo if ((slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) && 960184138Smav (data->len <= 512)) 961184138Smav slot->flags &= ~SDHCI_USE_DMA; 962184138Smav /* Some controllers require even block sizes. */ 963241600Sgonzo if ((slot->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && 964184138Smav ((data->len) & 0x3)) 965184138Smav slot->flags &= ~SDHCI_USE_DMA; 966184138Smav /* Load DMA buffer. */ 967184138Smav if (slot->flags & SDHCI_USE_DMA) { 968184138Smav if (data->flags & MMC_DATA_READ) 969254512Srpaulo bus_dmamap_sync(slot->dmatag, slot->dmamap, 970254512Srpaulo BUS_DMASYNC_PREREAD); 971184138Smav else { 972184138Smav memcpy(slot->dmamem, data->data, 973254512Srpaulo (data->len < DMA_BLOCK_SIZE) ? 974254512Srpaulo data->len : DMA_BLOCK_SIZE); 975254512Srpaulo bus_dmamap_sync(slot->dmatag, slot->dmamap, 976254512Srpaulo BUS_DMASYNC_PREWRITE); 977184138Smav } 978184138Smav WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); 979184138Smav /* Interrupt aggregation: Mask border interrupt 980184138Smav * for the last page and unmask else. */ 981184138Smav if (data->len == DMA_BLOCK_SIZE) 982184138Smav slot->intmask &= ~SDHCI_INT_DMA_END; 983184138Smav else 984184138Smav slot->intmask |= SDHCI_INT_DMA_END; 985184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); 986184138Smav } 987184138Smav /* Current data offset for both PIO and DMA. */ 988184138Smav slot->offset = 0; 989184138Smav /* Set block size and request IRQ on 4K border. */ 990184138Smav WR2(slot, SDHCI_BLOCK_SIZE, 991184138Smav SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512)?data->len:512)); 992184138Smav /* Set block count. */ 993184138Smav WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512); 994184138Smav} 995184138Smav 996247495Sgonzovoid 997184138Smavsdhci_finish_data(struct sdhci_slot *slot) 998184138Smav{ 999184138Smav struct mmc_data *data = slot->curcmd->data; 1000184138Smav 1001184138Smav /* Interrupt aggregation: Restore command interrupt. 1002254512Srpaulo * Auxiliary restore point for the case when data interrupt 1003184138Smav * happened first. */ 1004184138Smav if (!slot->cmd_done) { 1005184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, 1006184138Smav slot->intmask |= SDHCI_INT_RESPONSE); 1007184138Smav } 1008184138Smav /* Unload rest of data from DMA buffer. */ 1009278688Sian if (!slot->data_done && (slot->flags & SDHCI_USE_DMA)) { 1010184138Smav if (data->flags & MMC_DATA_READ) { 1011184138Smav size_t left = data->len - slot->offset; 1012254512Srpaulo bus_dmamap_sync(slot->dmatag, slot->dmamap, 1013254512Srpaulo BUS_DMASYNC_POSTREAD); 1014184138Smav memcpy((u_char*)data->data + slot->offset, slot->dmamem, 1015184138Smav (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); 1016184138Smav } else 1017254512Srpaulo bus_dmamap_sync(slot->dmatag, slot->dmamap, 1018254512Srpaulo BUS_DMASYNC_POSTWRITE); 1019184138Smav } 1020278688Sian slot->data_done = 1; 1021184138Smav /* If there was error - reset the host. */ 1022184138Smav if (slot->curcmd->error) { 1023184138Smav sdhci_reset(slot, SDHCI_RESET_CMD); 1024184138Smav sdhci_reset(slot, SDHCI_RESET_DATA); 1025184138Smav sdhci_start(slot); 1026184138Smav return; 1027184138Smav } 1028184138Smav /* If we already have command response - finish. */ 1029184138Smav if (slot->cmd_done) 1030184138Smav sdhci_start(slot); 1031184138Smav} 1032184138Smav 1033184138Smavstatic void 1034184138Smavsdhci_start(struct sdhci_slot *slot) 1035184138Smav{ 1036184138Smav struct mmc_request *req; 1037184138Smav 1038184138Smav req = slot->req; 1039184138Smav if (req == NULL) 1040184138Smav return; 1041184138Smav 1042184138Smav if (!(slot->flags & CMD_STARTED)) { 1043184138Smav slot->flags |= CMD_STARTED; 1044184138Smav sdhci_start_command(slot, req->cmd); 1045184138Smav return; 1046184138Smav } 1047184138Smav/* We don't need this until using Auto-CMD12 feature 1048184138Smav if (!(slot->flags & STOP_STARTED) && req->stop) { 1049184138Smav slot->flags |= STOP_STARTED; 1050184138Smav sdhci_start_command(slot, req->stop); 1051184138Smav return; 1052184138Smav } 1053184138Smav*/ 1054187876Smav if (sdhci_debug > 1) 1055187876Smav slot_printf(slot, "result: %d\n", req->cmd->error); 1056187876Smav if (!req->cmd->error && 1057241600Sgonzo (slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) { 1058184138Smav sdhci_reset(slot, SDHCI_RESET_CMD); 1059184138Smav sdhci_reset(slot, SDHCI_RESET_DATA); 1060184138Smav } 1061184138Smav 1062266200Sian sdhci_req_done(slot); 1063184138Smav} 1064184138Smav 1065241600Sgonzoint 1066241600Sgonzosdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req) 1067184138Smav{ 1068184138Smav struct sdhci_slot *slot = device_get_ivars(reqdev); 1069184138Smav 1070184138Smav SDHCI_LOCK(slot); 1071184138Smav if (slot->req != NULL) { 1072184138Smav SDHCI_UNLOCK(slot); 1073184138Smav return (EBUSY); 1074184138Smav } 1075187876Smav if (sdhci_debug > 1) { 1076187876Smav slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", 1077187876Smav req->cmd->opcode, req->cmd->arg, req->cmd->flags, 1078187876Smav (req->cmd->data)?(u_int)req->cmd->data->len:0, 1079187876Smav (req->cmd->data)?req->cmd->data->flags:0); 1080187876Smav } 1081184138Smav slot->req = req; 1082184138Smav slot->flags = 0; 1083184138Smav sdhci_start(slot); 1084184138Smav SDHCI_UNLOCK(slot); 1085188724Smav if (dumping) { 1086188724Smav while (slot->req != NULL) { 1087241600Sgonzo sdhci_generic_intr(slot); 1088188724Smav DELAY(10); 1089188724Smav } 1090188724Smav } 1091184138Smav return (0); 1092184138Smav} 1093184138Smav 1094241600Sgonzoint 1095241600Sgonzosdhci_generic_get_ro(device_t brdev, device_t reqdev) 1096184138Smav{ 1097184138Smav struct sdhci_slot *slot = device_get_ivars(reqdev); 1098184138Smav uint32_t val; 1099184138Smav 1100184138Smav SDHCI_LOCK(slot); 1101184138Smav val = RD4(slot, SDHCI_PRESENT_STATE); 1102184138Smav SDHCI_UNLOCK(slot); 1103184138Smav return (!(val & SDHCI_WRITE_PROTECT)); 1104184138Smav} 1105184138Smav 1106241600Sgonzoint 1107241600Sgonzosdhci_generic_acquire_host(device_t brdev, device_t reqdev) 1108184138Smav{ 1109184138Smav struct sdhci_slot *slot = device_get_ivars(reqdev); 1110184138Smav int err = 0; 1111184138Smav 1112184138Smav SDHCI_LOCK(slot); 1113184138Smav while (slot->bus_busy) 1114185722Smav msleep(slot, &slot->mtx, 0, "sdhciah", 0); 1115184138Smav slot->bus_busy++; 1116184138Smav /* Activate led. */ 1117184138Smav WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl |= SDHCI_CTRL_LED); 1118184138Smav SDHCI_UNLOCK(slot); 1119184138Smav return (err); 1120184138Smav} 1121184138Smav 1122241600Sgonzoint 1123241600Sgonzosdhci_generic_release_host(device_t brdev, device_t reqdev) 1124184138Smav{ 1125184138Smav struct sdhci_slot *slot = device_get_ivars(reqdev); 1126184138Smav 1127184138Smav SDHCI_LOCK(slot); 1128184138Smav /* Deactivate led. */ 1129184138Smav WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl &= ~SDHCI_CTRL_LED); 1130184138Smav slot->bus_busy--; 1131185722Smav SDHCI_UNLOCK(slot); 1132184138Smav wakeup(slot); 1133184138Smav return (0); 1134184138Smav} 1135184138Smav 1136184138Smavstatic void 1137184138Smavsdhci_cmd_irq(struct sdhci_slot *slot, uint32_t intmask) 1138184138Smav{ 1139184138Smav 1140184138Smav if (!slot->curcmd) { 1141184138Smav slot_printf(slot, "Got command interrupt 0x%08x, but " 1142184138Smav "there is no active command.\n", intmask); 1143184138Smav sdhci_dumpregs(slot); 1144184138Smav return; 1145184138Smav } 1146184138Smav if (intmask & SDHCI_INT_TIMEOUT) 1147184138Smav slot->curcmd->error = MMC_ERR_TIMEOUT; 1148184138Smav else if (intmask & SDHCI_INT_CRC) 1149184138Smav slot->curcmd->error = MMC_ERR_BADCRC; 1150184138Smav else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) 1151184138Smav slot->curcmd->error = MMC_ERR_FIFO; 1152184138Smav 1153184138Smav sdhci_finish_command(slot); 1154184138Smav} 1155184138Smav 1156184138Smavstatic void 1157184138Smavsdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) 1158184138Smav{ 1159184138Smav 1160184138Smav if (!slot->curcmd) { 1161184138Smav slot_printf(slot, "Got data interrupt 0x%08x, but " 1162184138Smav "there is no active command.\n", intmask); 1163184138Smav sdhci_dumpregs(slot); 1164184138Smav return; 1165184138Smav } 1166184138Smav if (slot->curcmd->data == NULL && 1167184138Smav (slot->curcmd->flags & MMC_RSP_BUSY) == 0) { 1168184138Smav slot_printf(slot, "Got data interrupt 0x%08x, but " 1169184138Smav "there is no active data operation.\n", 1170184138Smav intmask); 1171184138Smav sdhci_dumpregs(slot); 1172184138Smav return; 1173184138Smav } 1174184138Smav if (intmask & SDHCI_INT_DATA_TIMEOUT) 1175184138Smav slot->curcmd->error = MMC_ERR_TIMEOUT; 1176246891Sgonzo else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) 1177184138Smav slot->curcmd->error = MMC_ERR_BADCRC; 1178184138Smav if (slot->curcmd->data == NULL && 1179184138Smav (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | 1180184138Smav SDHCI_INT_DMA_END))) { 1181184138Smav slot_printf(slot, "Got data interrupt 0x%08x, but " 1182184138Smav "there is busy-only command.\n", intmask); 1183184138Smav sdhci_dumpregs(slot); 1184184138Smav slot->curcmd->error = MMC_ERR_INVALID; 1185184138Smav } 1186184138Smav if (slot->curcmd->error) { 1187184138Smav /* No need to continue after any error. */ 1188278688Sian goto done; 1189184138Smav } 1190184138Smav 1191184138Smav /* Handle PIO interrupt. */ 1192247495Sgonzo if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) { 1193247495Sgonzo if ((slot->opt & SDHCI_PLATFORM_TRANSFER) && 1194247495Sgonzo SDHCI_PLATFORM_WILL_HANDLE(slot->bus, slot)) { 1195247495Sgonzo SDHCI_PLATFORM_START_TRANSFER(slot->bus, slot, &intmask); 1196247495Sgonzo slot->flags |= PLATFORM_DATA_STARTED; 1197247495Sgonzo } else 1198247495Sgonzo sdhci_transfer_pio(slot); 1199247495Sgonzo } 1200184138Smav /* Handle DMA border. */ 1201184138Smav if (intmask & SDHCI_INT_DMA_END) { 1202184138Smav struct mmc_data *data = slot->curcmd->data; 1203184138Smav size_t left; 1204184138Smav 1205184138Smav /* Unload DMA buffer... */ 1206184138Smav left = data->len - slot->offset; 1207184138Smav if (data->flags & MMC_DATA_READ) { 1208184138Smav bus_dmamap_sync(slot->dmatag, slot->dmamap, 1209184138Smav BUS_DMASYNC_POSTREAD); 1210184138Smav memcpy((u_char*)data->data + slot->offset, slot->dmamem, 1211184138Smav (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); 1212184138Smav } else { 1213184138Smav bus_dmamap_sync(slot->dmatag, slot->dmamap, 1214184138Smav BUS_DMASYNC_POSTWRITE); 1215184138Smav } 1216184138Smav /* ... and reload it again. */ 1217184138Smav slot->offset += DMA_BLOCK_SIZE; 1218184138Smav left = data->len - slot->offset; 1219184138Smav if (data->flags & MMC_DATA_READ) { 1220184138Smav bus_dmamap_sync(slot->dmatag, slot->dmamap, 1221184138Smav BUS_DMASYNC_PREREAD); 1222184138Smav } else { 1223184138Smav memcpy(slot->dmamem, (u_char*)data->data + slot->offset, 1224184138Smav (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); 1225184138Smav bus_dmamap_sync(slot->dmatag, slot->dmamap, 1226184138Smav BUS_DMASYNC_PREWRITE); 1227184138Smav } 1228184138Smav /* Interrupt aggregation: Mask border interrupt 1229184138Smav * for the last page. */ 1230184138Smav if (left == DMA_BLOCK_SIZE) { 1231184138Smav slot->intmask &= ~SDHCI_INT_DMA_END; 1232184138Smav WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); 1233184138Smav } 1234184138Smav /* Restart DMA. */ 1235184138Smav WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); 1236184138Smav } 1237184138Smav /* We have got all data. */ 1238247495Sgonzo if (intmask & SDHCI_INT_DATA_END) { 1239247495Sgonzo if (slot->flags & PLATFORM_DATA_STARTED) { 1240247495Sgonzo slot->flags &= ~PLATFORM_DATA_STARTED; 1241247495Sgonzo SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); 1242247495Sgonzo } else 1243247495Sgonzo sdhci_finish_data(slot); 1244247495Sgonzo } 1245278688Siandone: 1246278688Sian if (slot->curcmd != NULL && slot->curcmd->error != 0) { 1247278688Sian if (slot->flags & PLATFORM_DATA_STARTED) { 1248278688Sian slot->flags &= ~PLATFORM_DATA_STARTED; 1249278688Sian SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot); 1250278688Sian } else 1251278688Sian sdhci_finish_data(slot); 1252278688Sian return; 1253278688Sian } 1254184138Smav} 1255184138Smav 1256184138Smavstatic void 1257184138Smavsdhci_acmd_irq(struct sdhci_slot *slot) 1258184138Smav{ 1259184138Smav uint16_t err; 1260184138Smav 1261184138Smav err = RD4(slot, SDHCI_ACMD12_ERR); 1262184138Smav if (!slot->curcmd) { 1263184138Smav slot_printf(slot, "Got AutoCMD12 error 0x%04x, but " 1264184138Smav "there is no active command.\n", err); 1265184138Smav sdhci_dumpregs(slot); 1266184138Smav return; 1267184138Smav } 1268184138Smav slot_printf(slot, "Got AutoCMD12 error 0x%04x\n", err); 1269184138Smav sdhci_reset(slot, SDHCI_RESET_CMD); 1270184138Smav} 1271184138Smav 1272241600Sgonzovoid 1273241600Sgonzosdhci_generic_intr(struct sdhci_slot *slot) 1274184138Smav{ 1275241600Sgonzo uint32_t intmask; 1276241600Sgonzo 1277241600Sgonzo SDHCI_LOCK(slot); 1278241600Sgonzo /* Read slot interrupt status. */ 1279241600Sgonzo intmask = RD4(slot, SDHCI_INT_STATUS); 1280241600Sgonzo if (intmask == 0 || intmask == 0xffffffff) { 1281241600Sgonzo SDHCI_UNLOCK(slot); 1282241600Sgonzo return; 1283241600Sgonzo } 1284241600Sgonzo if (sdhci_debug > 2) 1285241600Sgonzo slot_printf(slot, "Interrupt %#x\n", intmask); 1286184138Smav 1287241600Sgonzo /* Handle card presence interrupts. */ 1288241600Sgonzo if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { 1289241600Sgonzo WR4(slot, SDHCI_INT_STATUS, intmask & 1290241600Sgonzo (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)); 1291187876Smav 1292241600Sgonzo if (intmask & SDHCI_INT_CARD_REMOVE) { 1293241600Sgonzo if (bootverbose || sdhci_debug) 1294241600Sgonzo slot_printf(slot, "Card removed\n"); 1295241600Sgonzo callout_stop(&slot->card_callout); 1296241600Sgonzo taskqueue_enqueue(taskqueue_swi_giant, 1297241600Sgonzo &slot->card_task); 1298184138Smav } 1299241600Sgonzo if (intmask & SDHCI_INT_CARD_INSERT) { 1300241600Sgonzo if (bootverbose || sdhci_debug) 1301241600Sgonzo slot_printf(slot, "Card inserted\n"); 1302241600Sgonzo callout_reset(&slot->card_callout, hz / 2, 1303241600Sgonzo sdhci_card_delay, slot); 1304184138Smav } 1305241600Sgonzo intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); 1306184138Smav } 1307241600Sgonzo /* Handle command interrupts. */ 1308241600Sgonzo if (intmask & SDHCI_INT_CMD_MASK) { 1309241600Sgonzo WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_CMD_MASK); 1310241600Sgonzo sdhci_cmd_irq(slot, intmask & SDHCI_INT_CMD_MASK); 1311241600Sgonzo } 1312241600Sgonzo /* Handle data interrupts. */ 1313241600Sgonzo if (intmask & SDHCI_INT_DATA_MASK) { 1314241600Sgonzo WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_DATA_MASK); 1315276287Sian /* Dont call data_irq in case of errored command */ 1316276287Sian if ((intmask & SDHCI_INT_CMD_ERROR_MASK) == 0) 1317276287Sian sdhci_data_irq(slot, intmask & SDHCI_INT_DATA_MASK); 1318241600Sgonzo } 1319241600Sgonzo /* Handle AutoCMD12 error interrupt. */ 1320241600Sgonzo if (intmask & SDHCI_INT_ACMD12ERR) { 1321241600Sgonzo WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ACMD12ERR); 1322241600Sgonzo sdhci_acmd_irq(slot); 1323241600Sgonzo } 1324241600Sgonzo intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); 1325241600Sgonzo intmask &= ~SDHCI_INT_ACMD12ERR; 1326241600Sgonzo intmask &= ~SDHCI_INT_ERROR; 1327241600Sgonzo /* Handle bus power interrupt. */ 1328241600Sgonzo if (intmask & SDHCI_INT_BUS_POWER) { 1329241600Sgonzo WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_BUS_POWER); 1330241600Sgonzo slot_printf(slot, 1331241600Sgonzo "Card is consuming too much power!\n"); 1332241600Sgonzo intmask &= ~SDHCI_INT_BUS_POWER; 1333241600Sgonzo } 1334241600Sgonzo /* The rest is unknown. */ 1335241600Sgonzo if (intmask) { 1336241600Sgonzo WR4(slot, SDHCI_INT_STATUS, intmask); 1337241600Sgonzo slot_printf(slot, "Unexpected interrupt 0x%08x.\n", 1338241600Sgonzo intmask); 1339241600Sgonzo sdhci_dumpregs(slot); 1340241600Sgonzo } 1341241600Sgonzo 1342241600Sgonzo SDHCI_UNLOCK(slot); 1343184138Smav} 1344184138Smav 1345241600Sgonzoint 1346241600Sgonzosdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 1347184138Smav{ 1348184138Smav struct sdhci_slot *slot = device_get_ivars(child); 1349184138Smav 1350184138Smav switch (which) { 1351184138Smav default: 1352184138Smav return (EINVAL); 1353184138Smav case MMCBR_IVAR_BUS_MODE: 1354222475Sjchandra *result = slot->host.ios.bus_mode; 1355184138Smav break; 1356184138Smav case MMCBR_IVAR_BUS_WIDTH: 1357222475Sjchandra *result = slot->host.ios.bus_width; 1358184138Smav break; 1359184138Smav case MMCBR_IVAR_CHIP_SELECT: 1360222475Sjchandra *result = slot->host.ios.chip_select; 1361184138Smav break; 1362184138Smav case MMCBR_IVAR_CLOCK: 1363222475Sjchandra *result = slot->host.ios.clock; 1364184138Smav break; 1365184138Smav case MMCBR_IVAR_F_MIN: 1366222475Sjchandra *result = slot->host.f_min; 1367184138Smav break; 1368184138Smav case MMCBR_IVAR_F_MAX: 1369222475Sjchandra *result = slot->host.f_max; 1370184138Smav break; 1371184138Smav case MMCBR_IVAR_HOST_OCR: 1372222475Sjchandra *result = slot->host.host_ocr; 1373184138Smav break; 1374184138Smav case MMCBR_IVAR_MODE: 1375222475Sjchandra *result = slot->host.mode; 1376184138Smav break; 1377184138Smav case MMCBR_IVAR_OCR: 1378222475Sjchandra *result = slot->host.ocr; 1379184138Smav break; 1380184138Smav case MMCBR_IVAR_POWER_MODE: 1381222475Sjchandra *result = slot->host.ios.power_mode; 1382184138Smav break; 1383184138Smav case MMCBR_IVAR_VDD: 1384222475Sjchandra *result = slot->host.ios.vdd; 1385184138Smav break; 1386184138Smav case MMCBR_IVAR_CAPS: 1387222475Sjchandra *result = slot->host.caps; 1388184138Smav break; 1389184138Smav case MMCBR_IVAR_TIMING: 1390222475Sjchandra *result = slot->host.ios.timing; 1391184138Smav break; 1392184452Smav case MMCBR_IVAR_MAX_DATA: 1393222475Sjchandra *result = 65535; 1394184452Smav break; 1395184138Smav } 1396184138Smav return (0); 1397184138Smav} 1398184138Smav 1399241600Sgonzoint 1400241600Sgonzosdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value) 1401184138Smav{ 1402184138Smav struct sdhci_slot *slot = device_get_ivars(child); 1403184138Smav 1404184138Smav switch (which) { 1405184138Smav default: 1406184138Smav return (EINVAL); 1407184138Smav case MMCBR_IVAR_BUS_MODE: 1408184138Smav slot->host.ios.bus_mode = value; 1409184138Smav break; 1410184138Smav case MMCBR_IVAR_BUS_WIDTH: 1411184138Smav slot->host.ios.bus_width = value; 1412184138Smav break; 1413184138Smav case MMCBR_IVAR_CHIP_SELECT: 1414184138Smav slot->host.ios.chip_select = value; 1415184138Smav break; 1416184138Smav case MMCBR_IVAR_CLOCK: 1417184138Smav if (value > 0) { 1418246886Sgonzo uint32_t max_clock; 1419246886Sgonzo uint32_t clock; 1420184138Smav int i; 1421184138Smav 1422246886Sgonzo max_clock = slot->max_clk; 1423246886Sgonzo clock = max_clock; 1424246886Sgonzo 1425246886Sgonzo if (slot->version < SDHCI_SPEC_300) { 1426246886Sgonzo for (i = 0; i < SDHCI_200_MAX_DIVIDER; 1427246886Sgonzo i <<= 1) { 1428246886Sgonzo if (clock <= value) 1429246886Sgonzo break; 1430246886Sgonzo clock >>= 1; 1431246886Sgonzo } 1432184138Smav } 1433246886Sgonzo else { 1434246886Sgonzo for (i = 0; i < SDHCI_300_MAX_DIVIDER; 1435246886Sgonzo i += 2) { 1436246886Sgonzo if (clock <= value) 1437246886Sgonzo break; 1438246886Sgonzo clock = max_clock / (i + 2); 1439246886Sgonzo } 1440246886Sgonzo } 1441246886Sgonzo 1442184138Smav slot->host.ios.clock = clock; 1443184138Smav } else 1444184138Smav slot->host.ios.clock = 0; 1445184138Smav break; 1446184138Smav case MMCBR_IVAR_MODE: 1447184138Smav slot->host.mode = value; 1448184138Smav break; 1449184138Smav case MMCBR_IVAR_OCR: 1450184138Smav slot->host.ocr = value; 1451184138Smav break; 1452184138Smav case MMCBR_IVAR_POWER_MODE: 1453184138Smav slot->host.ios.power_mode = value; 1454184138Smav break; 1455184138Smav case MMCBR_IVAR_VDD: 1456184138Smav slot->host.ios.vdd = value; 1457184138Smav break; 1458184138Smav case MMCBR_IVAR_TIMING: 1459184138Smav slot->host.ios.timing = value; 1460184138Smav break; 1461184138Smav case MMCBR_IVAR_CAPS: 1462184138Smav case MMCBR_IVAR_HOST_OCR: 1463184138Smav case MMCBR_IVAR_F_MIN: 1464184138Smav case MMCBR_IVAR_F_MAX: 1465184452Smav case MMCBR_IVAR_MAX_DATA: 1466184138Smav return (EINVAL); 1467184138Smav } 1468184138Smav return (0); 1469184138Smav} 1470184138Smav 1471241600SgonzoMODULE_VERSION(sdhci, 1); 1472