diff options
Diffstat (limited to 'qemu/roms/u-boot/drivers/mmc/sdhci.c')
-rw-r--r-- | qemu/roms/u-boot/drivers/mmc/sdhci.c | 513 |
1 files changed, 0 insertions, 513 deletions
diff --git a/qemu/roms/u-boot/drivers/mmc/sdhci.c b/qemu/roms/u-boot/drivers/mmc/sdhci.c deleted file mode 100644 index 3125d13ba..000000000 --- a/qemu/roms/u-boot/drivers/mmc/sdhci.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright 2011, Marvell Semiconductor Inc. - * Lei Wen <leiwen@marvell.com> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * Back ported to the 8xx platform (from the 8260 platform) by - * Murray.Jensen@cmst.csiro.au, 27-Jan-01. - */ - -#include <common.h> -#include <malloc.h> -#include <mmc.h> -#include <sdhci.h> - -void *aligned_buffer; - -static void sdhci_reset(struct sdhci_host *host, u8 mask) -{ - unsigned long timeout; - - /* Wait max 100 ms */ - timeout = 100; - sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); - while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { - if (timeout == 0) { - printf("%s: Reset 0x%x never completed.\n", - __func__, (int)mask); - return; - } - timeout--; - udelay(1000); - } -} - -static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd) -{ - int i; - if (cmd->resp_type & MMC_RSP_136) { - /* CRC is stripped so we need to do some shifting. */ - for (i = 0; i < 4; i++) { - cmd->response[i] = sdhci_readl(host, - SDHCI_RESPONSE + (3-i)*4) << 8; - if (i != 3) - cmd->response[i] |= sdhci_readb(host, - SDHCI_RESPONSE + (3-i)*4-1); - } - } else { - cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE); - } -} - -static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data) -{ - int i; - char *offs; - for (i = 0; i < data->blocksize; i += 4) { - offs = data->dest + i; - if (data->flags == MMC_DATA_READ) - *(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER); - else - sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER); - } -} - -static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, - unsigned int start_addr) -{ - unsigned int stat, rdy, mask, timeout, block = 0; -#ifdef CONFIG_MMC_SDMA - unsigned char ctrl; - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - ctrl &= ~SDHCI_CTRL_DMA_MASK; - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -#endif - - timeout = 1000000; - rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; - mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE; - do { - stat = sdhci_readl(host, SDHCI_INT_STATUS); - if (stat & SDHCI_INT_ERROR) { - printf("%s: Error detected in status(0x%X)!\n", - __func__, stat); - return -1; - } - if (stat & rdy) { - if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)) - continue; - sdhci_writel(host, rdy, SDHCI_INT_STATUS); - sdhci_transfer_pio(host, data); - data->dest += data->blocksize; - if (++block >= data->blocks) - break; - } -#ifdef CONFIG_MMC_SDMA - if (stat & SDHCI_INT_DMA_END) { - sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS); - start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1); - start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE; - sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); - } -#endif - if (timeout-- > 0) - udelay(10); - else { - printf("%s: Transfer data timeout\n", __func__); - return -1; - } - } while (!(stat & SDHCI_INT_DATA_END)); - return 0; -} - -/* - * No command will be sent by driver if card is busy, so driver must wait - * for card ready state. - * Every time when card is busy after timeout then (last) timeout value will be - * increased twice but only if it doesn't exceed global defined maximum. - * Each function call will use last timeout value. Max timeout can be redefined - * in board config file. - */ -#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT -#define CONFIG_SDHCI_CMD_MAX_TIMEOUT 3200 -#endif -#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100 - -int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct sdhci_host *host = mmc->priv; - unsigned int stat = 0; - int ret = 0; - int trans_bytes = 0, is_aligned = 1; - u32 mask, flags, mode; - unsigned int time = 0, start_addr = 0; - unsigned int retry = 10000; - int mmc_dev = mmc->block_dev.dev; - - /* Timeout unit - ms */ - static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT; - - sdhci_writel(host, 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->cmdidx == MMC_CMD_STOP_TRANSMISSION) - mask &= ~SDHCI_DATA_INHIBIT; - - while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { - if (time >= cmd_timeout) { - printf("%s: MMC: %d busy ", __func__, mmc_dev); - if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) { - cmd_timeout += cmd_timeout; - printf("timeout increasing to: %u ms.\n", - cmd_timeout); - } else { - puts("timeout.\n"); - return COMM_ERR; - } - } - time++; - udelay(1000); - } - - mask = SDHCI_INT_RESPONSE; - if (!(cmd->resp_type & MMC_RSP_PRESENT)) - flags = SDHCI_CMD_RESP_NONE; - else if (cmd->resp_type & MMC_RSP_136) - flags = SDHCI_CMD_RESP_LONG; - else if (cmd->resp_type & MMC_RSP_BUSY) { - flags = SDHCI_CMD_RESP_SHORT_BUSY; - mask |= SDHCI_INT_DATA_END; - } else - flags = SDHCI_CMD_RESP_SHORT; - - if (cmd->resp_type & MMC_RSP_CRC) - flags |= SDHCI_CMD_CRC; - if (cmd->resp_type & MMC_RSP_OPCODE) - flags |= SDHCI_CMD_INDEX; - if (data) - flags |= SDHCI_CMD_DATA; - - /* Set Transfer mode regarding to data flag */ - if (data != 0) { - sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); - mode = SDHCI_TRNS_BLK_CNT_EN; - trans_bytes = data->blocks * data->blocksize; - if (data->blocks > 1) - mode |= SDHCI_TRNS_MULTI; - - if (data->flags == MMC_DATA_READ) - mode |= SDHCI_TRNS_READ; - -#ifdef CONFIG_MMC_SDMA - if (data->flags == MMC_DATA_READ) - start_addr = (unsigned int)data->dest; - else - start_addr = (unsigned int)data->src; - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && - (start_addr & 0x7) != 0x0) { - is_aligned = 0; - start_addr = (unsigned int)aligned_buffer; - if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); - } - - sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); - mode |= SDHCI_TRNS_DMA; -#endif - sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, - data->blocksize), - SDHCI_BLOCK_SIZE); - sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); - sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); - } - - sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); -#ifdef CONFIG_MMC_SDMA - flush_cache(start_addr, trans_bytes); -#endif - sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); - do { - stat = sdhci_readl(host, SDHCI_INT_STATUS); - if (stat & SDHCI_INT_ERROR) - break; - if (--retry == 0) - break; - } while ((stat & mask) != mask); - - if (retry == 0) { - if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) - return 0; - else { - printf("%s: Timeout for status update!\n", __func__); - return TIMEOUT; - } - } - - if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { - sdhci_cmd_done(host, cmd); - sdhci_writel(host, mask, SDHCI_INT_STATUS); - } else - ret = -1; - - if (!ret && data) - ret = sdhci_transfer_data(host, data, start_addr); - - if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) - udelay(1000); - - stat = sdhci_readl(host, SDHCI_INT_STATUS); - sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); - if (!ret) { - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && - !is_aligned && (data->flags == MMC_DATA_READ)) - memcpy(data->dest, aligned_buffer, trans_bytes); - return 0; - } - - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); - if (stat & SDHCI_INT_TIMEOUT) - return TIMEOUT; - else - return COMM_ERR; -} - -static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) -{ - struct sdhci_host *host = mmc->priv; - unsigned int div, clk, timeout; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) - return 0; - - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { - /* Version 3.00 divisors must be a multiple of 2. */ - if (mmc->cfg->f_max <= clock) - div = 1; - else { - for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { - if ((mmc->cfg->f_max / div) <= clock) - break; - } - } - } else { - /* Version 2.00 divisors must be a power of 2. */ - for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { - if ((mmc->cfg->f_max / div) <= clock) - break; - } - } - div >>= 1; - - if (host->set_clock) - host->set_clock(host->index, div); - - 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(host, clk, SDHCI_CLOCK_CONTROL); - - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - printf("%s: Internal clock never stabilised.\n", - __func__); - return -1; - } - timeout--; - udelay(1000); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - return 0; -} - -static void sdhci_set_power(struct sdhci_host *host, unsigned short power) -{ - u8 pwr = 0; - - if (power != (unsigned short)-1) { - switch (1 << power) { - case MMC_VDD_165_195: - pwr = SDHCI_POWER_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - pwr = SDHCI_POWER_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - pwr = SDHCI_POWER_330; - break; - } - } - - if (pwr == 0) { - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - return; - } - - if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - pwr |= SDHCI_POWER_ON; - - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); -} - -void sdhci_set_ios(struct mmc *mmc) -{ - u32 ctrl; - struct sdhci_host *host = mmc->priv; - - if (host->set_control_reg) - host->set_control_reg(host); - - if (mmc->clock != host->clock) - sdhci_set_clock(mmc, mmc->clock); - - /* Set bus width */ - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - if (mmc->bus_width == 8) { - ctrl &= ~SDHCI_CTRL_4BITBUS; - if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) || - (host->quirks & SDHCI_QUIRK_USE_WIDE8)) - ctrl |= SDHCI_CTRL_8BITBUS; - } else { - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - ctrl &= ~SDHCI_CTRL_8BITBUS; - if (mmc->bus_width == 4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; - } - - if (mmc->clock > 26000000) - ctrl |= SDHCI_CTRL_HISPD; - else - ctrl &= ~SDHCI_CTRL_HISPD; - - if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) - ctrl &= ~SDHCI_CTRL_HISPD; - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} - -int sdhci_init(struct mmc *mmc) -{ - struct sdhci_host *host = mmc->priv; - - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { - aligned_buffer = memalign(8, 512*1024); - if (!aligned_buffer) { - printf("%s: Aligned buffer alloc failed!!!\n", - __func__); - return -1; - } - } - - sdhci_set_power(host, fls(mmc->cfg->voltages) - 1); - - if (host->quirks & SDHCI_QUIRK_NO_CD) { - unsigned int status; - - sdhci_writel(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST, - SDHCI_HOST_CONTROL); - - status = sdhci_readl(host, SDHCI_PRESENT_STATE); - while ((!(status & SDHCI_CARD_PRESENT)) || - (!(status & SDHCI_CARD_STATE_STABLE)) || - (!(status & SDHCI_CARD_DETECT_PIN_LEVEL))) - status = sdhci_readl(host, SDHCI_PRESENT_STATE); - } - - /* Enable only interrupts served by the SD controller */ - sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, - SDHCI_INT_ENABLE); - /* Mask all sdhci interrupt sources */ - sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE); - - return 0; -} - - -static const struct mmc_ops sdhci_ops = { - .send_cmd = sdhci_send_command, - .set_ios = sdhci_set_ios, - .init = sdhci_init, -}; - -int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) -{ - unsigned int caps; - - host->cfg.name = host->name; - host->cfg.ops = &sdhci_ops; - - caps = sdhci_readl(host, SDHCI_CAPABILITIES); -#ifdef CONFIG_MMC_SDMA - if (!(caps & SDHCI_CAN_DO_SDMA)) { - printf("%s: Your controller doesn't support SDMA!!\n", - __func__); - return -1; - } -#endif - - if (max_clk) - host->cfg.f_max = max_clk; - else { - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - else - host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - host->cfg.f_max *= 1000000; - } - if (host->cfg.f_max == 0) { - printf("%s: Hardware doesn't specify base clock frequency\n", - __func__); - return -1; - } - if (min_clk) - host->cfg.f_min = min_clk; - else { - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - host->cfg.f_min = host->cfg.f_max / - SDHCI_MAX_DIV_SPEC_300; - else - host->cfg.f_min = host->cfg.f_max / - SDHCI_MAX_DIV_SPEC_200; - } - - host->cfg.voltages = 0; - if (caps & SDHCI_CAN_VDD_330) - host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; - if (caps & SDHCI_CAN_VDD_300) - host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; - if (caps & SDHCI_CAN_VDD_180) - host->cfg.voltages |= MMC_VDD_165_195; - - if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) - host->cfg.voltages |= host->voltages; - - host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { - if (caps & SDHCI_CAN_DO_8BIT) - host->cfg.host_caps |= MMC_MODE_8BIT; - } - if (host->host_caps) - host->cfg.host_caps |= host->host_caps; - - host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - - sdhci_reset(host, SDHCI_RESET_ALL); - - host->mmc = mmc_create(&host->cfg, host); - if (host->mmc == NULL) { - printf("%s: mmc create fail!\n", __func__); - return -1; - } - - return 0; -} |