diff options
Diffstat (limited to 'src/drivers/storage/sdhci.c')
-rw-r--r-- | src/drivers/storage/sdhci.c | 813 |
1 files changed, 0 insertions, 813 deletions
diff --git a/src/drivers/storage/sdhci.c b/src/drivers/storage/sdhci.c deleted file mode 100644 index c17aa27b9f..0000000000 --- a/src/drivers/storage/sdhci.c +++ /dev/null @@ -1,813 +0,0 @@ -/* - * Copyright 2011, Marvell Semiconductor Inc. - * Lei Wen <leiwen@marvell.com> - * - * Copyright 2017 Intel Corporation - * - * Secure Digital (SD) Host Controller interface specific code - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <assert.h> -#include "bouncebuf.h" -#include <console/console.h> -#include <delay.h> -#include <device/sd_mmc_ctrlr.h> -#include <device/sdhci.h> -#include <device/storage.h> -#include <endian.h> -#include <halt.h> -#include "sdhci.h" -#include "sd_mmc.h" -#include "storage.h" -#include <string.h> -#include <timer.h> -#include <commonlib/stdlib.h> - -#define DMA_AVAILABLE ((CONFIG_SDHCI_ADMA_IN_BOOTBLOCK && ENV_BOOTBLOCK) \ - || (CONFIG_SDHCI_ADMA_IN_VERSTAGE && ENV_VERSTAGE) \ - || (CONFIG_SDHCI_ADMA_IN_ROMSTAGE && ENV_ROMSTAGE) \ - || ENV_POSTCAR || ENV_RAMSTAGE) - -__attribute__((weak)) void *dma_malloc(size_t length_in_bytes) -{ - return malloc(length_in_bytes); -} - -void sdhci_reset(struct sdhci_ctrlr *sdhci_ctrlr, u8 mask) -{ - struct stopwatch sw; - - /* Wait max 100 ms */ - stopwatch_init_msecs_expire(&sw, 100); - - sdhci_writeb(sdhci_ctrlr, mask, SDHCI_SOFTWARE_RESET); - while (sdhci_readb(sdhci_ctrlr, SDHCI_SOFTWARE_RESET) & mask) { - if (stopwatch_expired(&sw)) { - sdhc_error("Reset 0x%x never completed.\n", (int)mask); - return; - } - udelay(1000); - } -} - -void sdhci_cmd_done(struct sdhci_ctrlr *sdhci_ctrlr, struct mmc_command *cmd) -{ - int i; - if (cmd->resp_type & CARD_RSP_136) { - /* CRC is stripped so we need to do some shifting. */ - for (i = 0; i < 4; i++) { - cmd->response[i] = sdhci_readl(sdhci_ctrlr, - SDHCI_RESPONSE + (3-i)*4) << 8; - if (i != 3) - cmd->response[i] |= sdhci_readb(sdhci_ctrlr, - SDHCI_RESPONSE + (3-i)*4-1); - } - sdhc_log_response(4, &cmd->response[0]); - sdhc_trace("Response: 0x%08x.%08x.%08x.%08x\n", - cmd->response[3], cmd->response[2], cmd->response[1], - cmd->response[0]); - } else { - cmd->response[0] = sdhci_readl(sdhci_ctrlr, SDHCI_RESPONSE); - sdhc_log_response(1, &cmd->response[0]); - sdhc_trace("Response: 0x%08x\n", cmd->response[0]); - } -} - -static int sdhci_transfer_data(struct sdhci_ctrlr *sdhci_ctrlr, - struct mmc_data *data, unsigned int start_addr) -{ - uint32_t block_count; - uint32_t *buffer; - uint32_t *buffer_end; - uint32_t ps; - uint32_t ps_mask; - uint32_t stat; - struct stopwatch sw; - - block_count = 0; - buffer = (uint32_t *)data->dest; - ps_mask = (data->flags & DATA_FLAG_READ) - ? SDHCI_DATA_AVAILABLE : SDHCI_SPACE_AVAILABLE; - stopwatch_init_msecs_expire(&sw, 100); - do { - /* Stop transfers if there is an error */ - stat = sdhci_readl(sdhci_ctrlr, SDHCI_INT_STATUS); - sdhci_writel(sdhci_ctrlr, stat, SDHCI_INT_STATUS); - if (stat & SDHCI_INT_ERROR) { - sdhc_error("Error detected in status(0x%X)!\n", stat); - return -1; - } - - /* Determine if the buffer is ready to move data */ - ps = sdhci_readl(sdhci_ctrlr, SDHCI_PRESENT_STATE); - if (!(ps & ps_mask)) { - if (stopwatch_expired(&sw)) { - sdhc_error("Transfer data timeout\n"); - return -1; - } - udelay(1); - continue; - } - - /* Transfer a block of data */ - buffer_end = &buffer[data->blocksize >> 2]; - if (data->flags == DATA_FLAG_READ) - while (buffer_end > buffer) - *buffer++ = sdhci_readl(sdhci_ctrlr, - SDHCI_BUFFER); - else - while (buffer_end > buffer) - sdhci_writel(sdhci_ctrlr, *buffer++, - SDHCI_BUFFER); - if (++block_count >= data->blocks) - break; - } while (!(stat & SDHCI_INT_DATA_END)); - return 0; -} - -static int sdhci_send_command_bounced(struct sd_mmc_ctrlr *ctrlr, - struct mmc_command *cmd, struct mmc_data *data, - struct bounce_buffer *bbstate) -{ - struct sdhci_ctrlr *sdhci_ctrlr = (struct sdhci_ctrlr *)ctrlr; - u16 mode = 0; - unsigned int stat = 0; - int ret = 0; - u32 mask, flags; - unsigned int timeout, start_addr = 0; - struct stopwatch sw; - - /* Wait max 1 s */ - timeout = 1000; - - sdhci_writel(sdhci_ctrlr, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); - mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; - - /* We shouldn't wait for data inihibit for stop commands, even - though they might use busy signaling */ - if (cmd->flags & CMD_FLAG_IGNORE_INHIBIT) - mask &= ~SDHCI_DATA_INHIBIT; - - while (sdhci_readl(sdhci_ctrlr, SDHCI_PRESENT_STATE) & mask) { - if (timeout == 0) { - sdhc_trace("Cmd: %2d, Arg: 0x%08x, not sent\n", - cmd->cmdidx, cmd->cmdarg); - sdhc_error("Controller never released inhibit bit(s), " - "present state %#8.8x.\n", - sdhci_readl(sdhci_ctrlr, SDHCI_PRESENT_STATE)); - return CARD_COMM_ERR; - } - timeout--; - udelay(1000); - } - - mask = SDHCI_INT_RESPONSE; - if (!(cmd->resp_type & CARD_RSP_PRESENT)) - flags = SDHCI_CMD_RESP_NONE; - else if (cmd->resp_type & CARD_RSP_136) - flags = SDHCI_CMD_RESP_LONG; - else if (cmd->resp_type & CARD_RSP_BUSY) { - flags = SDHCI_CMD_RESP_SHORT_BUSY; - mask |= SDHCI_INT_DATA_END; - } else - flags = SDHCI_CMD_RESP_SHORT; - - if (cmd->resp_type & CARD_RSP_CRC) - flags |= SDHCI_CMD_CRC; - if (cmd->resp_type & CARD_RSP_OPCODE) - flags |= SDHCI_CMD_INDEX; - if (data) - flags |= SDHCI_CMD_DATA; - - /* Set Transfer mode regarding to data flag */ - if (data) { - sdhci_writew(sdhci_ctrlr, - SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, - data->blocksize), SDHCI_BLOCK_SIZE); - - if (data->flags == DATA_FLAG_READ) - mode |= SDHCI_TRNS_READ; - - if (data->blocks > 1) - mode |= SDHCI_TRNS_BLK_CNT_EN | - SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12; - - sdhci_writew(sdhci_ctrlr, data->blocks, SDHCI_BLOCK_COUNT); - - if (DMA_AVAILABLE && (ctrlr->caps & DRVR_CAP_AUTO_CMD12) - && (cmd->cmdidx != MMC_CMD_AUTO_TUNING_SEQUENCE)) { - if (sdhci_setup_adma(sdhci_ctrlr, data)) - return -1; - mode |= SDHCI_TRNS_DMA; - } - sdhci_writew(sdhci_ctrlr, mode, SDHCI_TRANSFER_MODE); - } - - sdhc_trace("Cmd: %2d, Arg: 0x%08x\n", cmd->cmdidx, cmd->cmdarg); - sdhci_writel(sdhci_ctrlr, cmd->cmdarg, SDHCI_ARGUMENT); - sdhci_writew(sdhci_ctrlr, SDHCI_MAKE_CMD(cmd->cmdidx, flags), - SDHCI_COMMAND); - sdhc_log_command_issued(); - - if (DMA_AVAILABLE && (mode & SDHCI_TRNS_DMA)) - return sdhci_complete_adma(sdhci_ctrlr, cmd); - - stopwatch_init_msecs_expire(&sw, 2550); - do { - stat = sdhci_readl(sdhci_ctrlr, SDHCI_INT_STATUS); - if (stat & SDHCI_INT_ERROR) { - sdhc_trace("Error - IntStatus: 0x%08x\n", stat); - break; - } - - if (stat & SDHCI_INT_DATA_AVAIL) { - sdhci_writel(sdhci_ctrlr, stat, SDHCI_INT_STATUS); - return 0; - } - - /* Apply max timeout for R1b-type CMD defined in eMMC ext_csd - except for erase ones */ - if (stopwatch_expired(&sw)) { - if (ctrlr->caps & DRVR_CAP_BROKEN_R1B) - return 0; - sdhc_error( - "Timeout for status update! IntStatus: 0x%08x\n", - stat); - return CARD_TIMEOUT; - } - } while ((stat & mask) != mask); - - if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { - if (cmd->cmdidx) - sdhci_cmd_done(sdhci_ctrlr, cmd); - sdhci_writel(sdhci_ctrlr, mask, SDHCI_INT_STATUS); - } else - ret = -1; - - if (!ret && data) - ret = sdhci_transfer_data(sdhci_ctrlr, data, start_addr); - - if (ctrlr->udelay_wait_after_cmd) - udelay(ctrlr->udelay_wait_after_cmd); - - stat = sdhci_readl(sdhci_ctrlr, SDHCI_INT_STATUS); - sdhci_writel(sdhci_ctrlr, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); - - if (!ret) - return 0; - - sdhci_reset(sdhci_ctrlr, SDHCI_RESET_CMD); - sdhci_reset(sdhci_ctrlr, SDHCI_RESET_DATA); - if (stat & SDHCI_INT_TIMEOUT) { - sdhc_error("CMD%d timeout, IntStatus: 0x%08x\n", cmd->cmdidx, - stat); - return CARD_TIMEOUT; - } - - sdhc_error("CMD%d failed, IntStatus: 0x%08x\n", cmd->cmdidx, stat); - return CARD_COMM_ERR; -} - -__attribute__((weak)) void sdhc_log_command(struct mmc_command *cmd) -{ -} - -__attribute__((weak)) void sdhc_log_command_issued(void) -{ -} - -__attribute__((weak)) void sdhc_log_response(uint32_t entries, - uint32_t *response) -{ -} - -__attribute__((weak)) void sdhc_log_ret(int ret) -{ -} - -static void sdhci_led_control(struct sd_mmc_ctrlr *ctrlr, int on) -{ - uint8_t host_ctrl; - struct sdhci_ctrlr *sdhci_ctrlr = (struct sdhci_ctrlr *)ctrlr; - - host_ctrl = sdhci_readb(sdhci_ctrlr, SDHCI_HOST_CONTROL); - host_ctrl &= ~SDHCI_CTRL_LED; - if (on) - host_ctrl |= SDHCI_CTRL_LED; - sdhci_writeb(sdhci_ctrlr, host_ctrl, SDHCI_HOST_CONTROL); -} - -static int sdhci_send_command(struct sd_mmc_ctrlr *ctrlr, - struct mmc_command *cmd, struct mmc_data *data) -{ - void *buf; - unsigned int bbflags; - size_t len; - struct bounce_buffer *bbstate = NULL; - struct bounce_buffer bbstate_val; - int ret; - - sdhc_log_command(cmd); - - if (IS_ENABLED(CONFIG_SDHCI_BOUNCE_BUFFER) && data) { - if (data->flags & DATA_FLAG_READ) { - buf = data->dest; - bbflags = GEN_BB_WRITE; - } else { - buf = (void *)data->src; - bbflags = GEN_BB_READ; - } - len = data->blocks * data->blocksize; - - /* - * on some platform(like rk3399 etc) need to worry about - * cache coherency, so check the buffer, if not dma - * coherent, use bounce_buffer to do DMA management. - */ - if (!dma_coherent(buf)) { - bbstate = &bbstate_val; - if (bounce_buffer_start(bbstate, buf, len, bbflags)) { - sdhc_error( - "ERROR: Failed to get bounce buffer.\n"); - return -1; - } - } - } - - sdhci_led_control(ctrlr, 1); - ret = sdhci_send_command_bounced(ctrlr, cmd, data, bbstate); - sdhci_led_control(ctrlr, 0); - sdhc_log_ret(ret); - - if (IS_ENABLED(CONFIG_SDHCI_BOUNCE_BUFFER) && bbstate) - bounce_buffer_stop(bbstate); - - return ret; -} - -static int sdhci_set_clock(struct sdhci_ctrlr *sdhci_ctrlr, unsigned int clock) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - unsigned int actual, div, clk, timeout; - - /* Turn off the clock if requested */ - actual = clock; - if (actual == 0) { - sdhci_writew(sdhci_ctrlr, 0, SDHCI_CLOCK_CONTROL); - sdhc_debug("SDHCI bus clock: Off\n"); - return 0; - } - - /* Compute the divisor for the new clock frequency */ - actual = MIN(actual, ctrlr->f_max); - actual = MAX(actual, ctrlr->f_min); - if (ctrlr->clock_base <= actual) - div = 0; - else { - /* Version 3.00 divisors must be a multiple of 2. */ - if ((ctrlr->version & SDHCI_SPEC_VER_MASK) - >= SDHCI_SPEC_300) { - div = MIN(((ctrlr->clock_base + actual - 1) - / actual), SDHCI_MAX_DIV_SPEC_300); - actual = ctrlr->clock_base / div; - div += 1; - } else { - /* Version 2.00 divisors must be a power of 2. */ - for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { - if ((ctrlr->clock_base / div) <= actual) - break; - } - actual = ctrlr->clock_base / div; - } - div >>= 1; - } - - /* Set the new clock frequency */ - if (actual != ctrlr->bus_hz) { - /* Turn off the clock */ - sdhci_writew(sdhci_ctrlr, 0, SDHCI_CLOCK_CONTROL); - - /* Set the new clock frequency */ - clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; - clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) - << SDHCI_DIVIDER_HI_SHIFT; - clk |= SDHCI_CLOCK_INT_EN; - sdhci_writew(sdhci_ctrlr, clk, SDHCI_CLOCK_CONTROL); - - /* Display the requested clock frequency */ - sdhc_debug("SDHCI bus clock: %d.%03d MHz\n", - actual / 1000000, - (actual / 1000) % 1000); - - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(sdhci_ctrlr, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - sdhc_error( - "Internal clock never stabilised.\n"); - return -1; - } - timeout--; - udelay(1000); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(sdhci_ctrlr, clk, SDHCI_CLOCK_CONTROL); - ctrlr->bus_hz = actual; - } - return 0; -} - -/* Find leftmost set bit in a 32 bit integer */ -static int fls(u32 x) -{ - int r = 32; - - if (!x) - return 0; - if (!(x & 0xffff0000u)) { - x <<= 16; - r -= 16; - } - if (!(x & 0xff000000u)) { - x <<= 8; - r -= 8; - } - if (!(x & 0xf0000000u)) { - x <<= 4; - r -= 4; - } - if (!(x & 0xc0000000u)) { - x <<= 2; - r -= 2; - } - if (!(x & 0x80000000u)) { - x <<= 1; - r -= 1; - } - return r; -} - -static void sdhci_set_power(struct sdhci_ctrlr *sdhci_ctrlr, - unsigned short power) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - u8 pwr = 0; - u8 pwr_ctrl; - const char *voltage; - - if (power != (unsigned short)-1) { - switch (1 << power) { - case MMC_VDD_165_195: - voltage = "1.8"; - pwr = SDHCI_POWER_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - voltage = "3.0"; - pwr = SDHCI_POWER_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - voltage = "3.3"; - pwr = SDHCI_POWER_330; - break; - } - } - - /* Determine the power state */ - pwr_ctrl = sdhci_readb(sdhci_ctrlr, SDHCI_POWER_CONTROL); - if (pwr == 0) { - if (pwr_ctrl & SDHCI_POWER_ON) - sdhc_debug("SDHCI voltage: Off\n"); - sdhci_writeb(sdhci_ctrlr, 0, SDHCI_POWER_CONTROL); - return; - } - - /* Determine if the power has changed */ - if (pwr_ctrl != (pwr | SDHCI_POWER_ON)) { - sdhc_debug("SDHCI voltage: %s Volts\n", voltage); - - /* Select the voltage */ - if (ctrlr->caps & DRVR_CAP_NO_SIMULT_VDD_AND_POWER) - sdhci_writeb(sdhci_ctrlr, pwr, SDHCI_POWER_CONTROL); - - /* Apply power to the SD/MMC device */ - pwr |= SDHCI_POWER_ON; - sdhci_writeb(sdhci_ctrlr, pwr, SDHCI_POWER_CONTROL); - } -} - -const u16 speed_driver_voltage[] = { - 0, /* 0: BUS_TIMING_LEGACY */ - 0, /* 1: BUS_TIMING_MMC_HS */ - 0, /* 2: BUS_TIMING_SD_HS */ - SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180, /* 3: BUS_TIMING_UHS_SDR12 */ - SDHCI_CTRL_UHS_SDR25 | SDHCI_CTRL_VDD_180, /* 4: BUS_TIMING_UHS_SDR25 */ - SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180, /* 5: BUS_TIMING_UHS_SDR50 */ - /* 6: BUS_TIMING_UHS_SDR104 */ - SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_DRV_TYPE_A | SDHCI_CTRL_VDD_180, - SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180, /* 7: BUS_TIMING_UHS_DDR50 */ - SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180, /* 8: BUS_TIMING_MMC_DDR52 */ - /* 9: BUS_TIMING_MMC_HS200 */ - SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_DRV_TYPE_A | SDHCI_CTRL_VDD_180, - /* 10: BUS_TIMING_MMC_HS400 */ - SDHCI_CTRL_HS400 | SDHCI_CTRL_DRV_TYPE_A | SDHCI_CTRL_VDD_180, - /* 11: BUS_TIMING_MMC_HS400ES */ - SDHCI_CTRL_HS400 | SDHCI_CTRL_DRV_TYPE_A | SDHCI_CTRL_VDD_180 -}; - -static void sdhci_set_uhs_signaling(struct sdhci_ctrlr *sdhci_ctrlr, - uint32_t timing) -{ - u16 ctrl_2; - - /* Select bus speed mode, driver and VDD 1.8 volt support */ - ctrl_2 = sdhci_readw(sdhci_ctrlr, SDHCI_HOST_CONTROL2); - ctrl_2 &= ~(SDHCI_CTRL_UHS_MASK | SDHCI_CTRL_DRV_TYPE_MASK - | SDHCI_CTRL_VDD_180); - if (timing < ARRAY_SIZE(speed_driver_voltage)) - ctrl_2 |= speed_driver_voltage[timing]; - sdhci_writew(sdhci_ctrlr, ctrl_2, SDHCI_HOST_CONTROL2); -} - -static void sdhci_set_ios(struct sd_mmc_ctrlr *ctrlr) -{ - struct sdhci_ctrlr *sdhci_ctrlr = (struct sdhci_ctrlr *)ctrlr; - u32 ctrl; - u32 previous_ctrl; - u32 bus_width; - int version; - - /* Set the clock frequency */ - if (ctrlr->bus_hz != ctrlr->request_hz) - sdhci_set_clock(sdhci_ctrlr, ctrlr->request_hz); - - /* Switch to 1.8 volt for HS200 */ - if (ctrlr->caps & DRVR_CAP_1V8_VDD) - if (ctrlr->bus_hz == CLOCK_200MHZ) - sdhci_set_power(sdhci_ctrlr, MMC_VDD_165_195_SHIFT); - - /* Determine the new bus width */ - bus_width = 1; - ctrl = sdhci_readb(sdhci_ctrlr, SDHCI_HOST_CONTROL); - previous_ctrl = ctrl; - ctrl &= ~SDHCI_CTRL_4BITBUS; - version = ctrlr->version & SDHCI_SPEC_VER_MASK; - if (version >= SDHCI_SPEC_300) - ctrl &= ~SDHCI_CTRL_8BITBUS; - - if ((ctrlr->bus_width == 8) && (version >= SDHCI_SPEC_300)) { - ctrl |= SDHCI_CTRL_8BITBUS; - bus_width = 8; - } else if (ctrlr->bus_width == 4) { - ctrl |= SDHCI_CTRL_4BITBUS; - bus_width = 4; - } - - if (!(ctrlr->timing == BUS_TIMING_LEGACY) && - !(ctrlr->caps & DRVR_CAP_NO_HISPD_BIT)) - ctrl |= SDHCI_CTRL_HISPD; - else - ctrl &= ~SDHCI_CTRL_HISPD; - - sdhci_set_uhs_signaling(sdhci_ctrlr, ctrlr->timing); - - if (DMA_AVAILABLE) { - if (ctrlr->caps & DRVR_CAP_AUTO_CMD12) { - ctrl &= ~SDHCI_CTRL_DMA_MASK; - if (ctrlr->caps & DRVR_CAP_DMA_64BIT) - ctrl |= SDHCI_CTRL_ADMA64; - else - ctrl |= SDHCI_CTRL_ADMA32; - } - } - - /* Set the new bus width */ - if (IS_ENABLED(CONFIG_SDHC_DEBUG) - && ((ctrl ^ previous_ctrl) & (SDHCI_CTRL_4BITBUS - | ((version >= SDHCI_SPEC_300) ? SDHCI_CTRL_8BITBUS : 0)))) - sdhc_debug("SDHCI bus width: %d bit%s\n", bus_width, - (bus_width != 1) ? "s" : ""); - sdhci_writeb(sdhci_ctrlr, ctrl, SDHCI_HOST_CONTROL); -} - -static void sdhci_tuning_start(struct sd_mmc_ctrlr *ctrlr, int retune) -{ - uint16_t host_ctrl2; - struct sdhci_ctrlr *sdhci_ctrlr = (struct sdhci_ctrlr *)ctrlr; - - /* Start the bus tuning */ - host_ctrl2 = sdhci_readw(sdhci_ctrlr, SDHCI_HOST_CONTROL2); - host_ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; - host_ctrl2 |= (retune ? SDHCI_CTRL_TUNED_CLK : 0) - | SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(sdhci_ctrlr, host_ctrl2, SDHCI_HOST_CONTROL2); -} - -static int sdhci_is_tuning_complete(struct sd_mmc_ctrlr *ctrlr, int *successful) -{ - uint16_t host_ctrl2; - struct sdhci_ctrlr *sdhci_ctrlr = (struct sdhci_ctrlr *)ctrlr; - - /* Determine if the bus tuning has completed */ - host_ctrl2 = sdhci_readw(sdhci_ctrlr, SDHCI_HOST_CONTROL2); - *successful = ((host_ctrl2 & SDHCI_CTRL_TUNED_CLK) != 0); - return ((host_ctrl2 & SDHCI_CTRL_EXEC_TUNING) == 0); -} - -/* Prepare SDHCI controller to be initialized */ -static int sdhci_pre_init(struct sdhci_ctrlr *sdhci_ctrlr) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - unsigned int caps, caps_1; - - /* Get controller version and capabilities */ - ctrlr->version = sdhci_readw(sdhci_ctrlr, SDHCI_HOST_VERSION) & 0xff; - caps = sdhci_readl(sdhci_ctrlr, SDHCI_CAPABILITIES); - caps_1 = sdhci_readl(sdhci_ctrlr, SDHCI_CAPABILITIES_1); - - /* Determine the supported voltages */ - if (caps & SDHCI_CAN_VDD_330) - ctrlr->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; - if (caps & SDHCI_CAN_VDD_300) - ctrlr->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; - if (caps & SDHCI_CAN_VDD_180) - ctrlr->voltages |= MMC_VDD_165_195; - - /* Get the controller's base clock frequency */ - if ((ctrlr->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) - ctrlr->clock_base = (caps & SDHCI_CLOCK_V3_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - else - ctrlr->clock_base = (caps & SDHCI_CLOCK_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - ctrlr->clock_base *= 1000000; - ctrlr->f_max = ctrlr->clock_base; - - /* Determine the controller's clock frequency range */ - ctrlr->f_min = 0; - if ((ctrlr->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) - ctrlr->f_min = - ctrlr->clock_base / SDHCI_MAX_DIV_SPEC_300; - else - ctrlr->f_min = - ctrlr->clock_base / SDHCI_MAX_DIV_SPEC_200; - - /* Determine the controller's modes of operation */ - ctrlr->caps |= DRVR_CAP_HS52 | DRVR_CAP_HS; - if (ctrlr->clock_base >= CLOCK_200MHZ) { - ctrlr->caps |= DRVR_CAP_HS200 | DRVR_CAP_HS200_TUNING; - if (caps_1 & SDHCI_SUPPORT_HS400) - ctrlr->caps |= DRVR_CAP_HS400 - | DRVR_CAP_ENHANCED_STROBE; - } - - /* Determine the bus widths the controller supports */ - ctrlr->caps |= DRVR_CAP_4BIT; - if (caps & SDHCI_CAN_DO_8BIT) - ctrlr->caps |= DRVR_CAP_8BIT; - - /* Determine the controller's DMA support */ - if (caps & SDHCI_CAN_DO_ADMA2) - ctrlr->caps |= DRVR_CAP_AUTO_CMD12; - if (DMA_AVAILABLE && (caps & SDHCI_CAN_64BIT)) - ctrlr->caps |= DRVR_CAP_DMA_64BIT; - - /* Specify the modes that the driver stack supports */ - ctrlr->caps |= DRVR_CAP_HC; - - /* Let the SOC adjust the configuration to handle controller quirks */ - soc_sd_mmc_controller_quirks(&sdhci_ctrlr->sd_mmc_ctrlr); - if (ctrlr->clock_base == 0) { - sdhc_error("Hardware doesn't specify base clock frequency\n"); - return -1; - } - if (!ctrlr->f_max) - ctrlr->f_max = ctrlr->clock_base; - - /* Display the results */ - sdhc_trace("0x%08x: ctrlr->caps\n", ctrlr->caps); - sdhc_trace("%d.%03d MHz: ctrlr->clock_base\n", - ctrlr->clock_base / 1000000, - (ctrlr->clock_base / 1000) % 1000); - sdhc_trace("%d.%03d MHz: ctrlr->f_max\n", - ctrlr->f_max / 1000000, - (ctrlr->f_max / 1000) % 1000); - sdhc_trace("%d.%03d MHz: ctrlr->f_min\n", - ctrlr->f_min / 1000000, - (ctrlr->f_min / 1000) % 1000); - sdhc_trace("0x%08x: ctrlr->voltages\n", ctrlr->voltages); - - sdhci_reset(sdhci_ctrlr, SDHCI_RESET_ALL); - - return 0; -} - -__attribute__((weak)) void soc_sd_mmc_controller_quirks(struct sd_mmc_ctrlr - *ctrlr) -{ -} - -static int sdhci_init(struct sdhci_ctrlr *sdhci_ctrlr) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - int rv; - - /* Only initialize the controller upon reset or card insertion */ - if (ctrlr->initialized) - return 0; - - sdhc_debug("SDHCI Controller Base Address: 0x%p\n", - sdhci_ctrlr->ioaddr); - - rv = sdhci_pre_init(sdhci_ctrlr); - if (rv) - return rv; /* The error has been already reported */ - - sdhci_set_power(sdhci_ctrlr, fls(ctrlr->voltages) - 1); - - if (ctrlr->caps & DRVR_CAP_NO_CD) { - unsigned int status; - - sdhci_writel(sdhci_ctrlr, SDHCI_CTRL_CD_TEST_INS - | SDHCI_CTRL_CD_TEST, SDHCI_HOST_CONTROL); - - status = sdhci_readl(sdhci_ctrlr, SDHCI_PRESENT_STATE); - while ((!(status & SDHCI_CARD_PRESENT)) || - (!(status & SDHCI_CARD_STATE_STABLE)) || - (!(status & SDHCI_CARD_DETECT_PIN_LEVEL))) - status = sdhci_readl(sdhci_ctrlr, SDHCI_PRESENT_STATE); - } - - /* Enable only interrupts served by the SD controller */ - sdhci_writel(sdhci_ctrlr, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, - SDHCI_INT_ENABLE); - /* Mask all sdhci interrupt sources */ - sdhci_writel(sdhci_ctrlr, 0x0, SDHCI_SIGNAL_ENABLE); - - /* Set timeout to maximum, shouldn't happen if everything's right. */ - sdhci_writeb(sdhci_ctrlr, 0xe, SDHCI_TIMEOUT_CONTROL); - - mdelay(10); - ctrlr->initialized = 1; - return 0; -} - -static int sdhci_update(struct sdhci_ctrlr *sdhci_ctrlr) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - - if (ctrlr->caps & DRVR_CAP_REMOVABLE) { - int present = (sdhci_readl(sdhci_ctrlr, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT) != 0; - - if (!present) { - /* A card was present indicate the controller needs - * initialization on the next call. - */ - ctrlr->initialized = 0; - return 0; - } - } - - /* A card is present, get it ready. */ - if (sdhci_init(sdhci_ctrlr)) - return -1; - return 0; -} - -void sdhci_update_pointers(struct sdhci_ctrlr *sdhci_ctrlr) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - - /* Update the routine pointers */ - ctrlr->send_cmd = &sdhci_send_command; - ctrlr->set_ios = &sdhci_set_ios; - ctrlr->tuning_start = &sdhci_tuning_start; - ctrlr->is_tuning_complete = &sdhci_is_tuning_complete; -} - -int add_sdhci(struct sdhci_ctrlr *sdhci_ctrlr) -{ - struct sd_mmc_ctrlr *ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; - - sdhci_update_pointers(sdhci_ctrlr); - - /* TODO(vbendeb): check if SDHCI spec allows to retrieve this value. */ - ctrlr->b_max = 65535; - - /* Initialize the SDHC controller */ - return sdhci_update(sdhci_ctrlr); -} |