|
|
|
@ -121,13 +121,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, |
|
|
|
|
* 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. |
|
|
|
|
* Each function call will use last timeout value. |
|
|
|
|
*/ |
|
|
|
|
#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT |
|
|
|
|
#define CONFIG_SDHCI_CMD_MAX_TIMEOUT 3200 |
|
|
|
|
#endif |
|
|
|
|
#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100 |
|
|
|
|
#define SDHCI_CMD_MAX_TIMEOUT 3200 |
|
|
|
|
#define SDHCI_CMD_DEFAULT_TIMEOUT 100 |
|
|
|
|
#define SDHCI_READ_STATUS_TIMEOUT 1000 |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_DM_MMC_OPS |
|
|
|
@ -151,7 +148,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, |
|
|
|
|
unsigned start = get_timer(0); |
|
|
|
|
|
|
|
|
|
/* Timeout unit - ms */ |
|
|
|
|
static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT; |
|
|
|
|
static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; |
|
|
|
|
|
|
|
|
|
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); |
|
|
|
|
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; |
|
|
|
@ -164,7 +161,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, |
|
|
|
|
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) { |
|
|
|
|
if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) { |
|
|
|
|
cmd_timeout += cmd_timeout; |
|
|
|
|
printf("timeout increasing to: %u ms.\n", |
|
|
|
|
cmd_timeout); |
|
|
|
@ -297,7 +294,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, |
|
|
|
|
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) |
|
|
|
|
{ |
|
|
|
|
struct sdhci_host *host = mmc->priv; |
|
|
|
|
unsigned int div, clk, timeout, reg; |
|
|
|
|
unsigned int div, clk = 0, timeout, reg; |
|
|
|
|
|
|
|
|
|
/* Wait max 20 ms */ |
|
|
|
|
timeout = 200; |
|
|
|
@ -321,14 +318,36 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) |
|
|
|
|
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) |
|
|
|
|
/*
|
|
|
|
|
* Check if the Host Controller supports Programmable Clock |
|
|
|
|
* Mode. |
|
|
|
|
*/ |
|
|
|
|
if (host->clk_mul) { |
|
|
|
|
for (div = 1; div <= 1024; div++) { |
|
|
|
|
if ((mmc->cfg->f_max * host->clk_mul / div) |
|
|
|
|
<= clock) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set Programmable Clock Mode in the Clock |
|
|
|
|
* Control register. |
|
|
|
|
*/ |
|
|
|
|
clk = SDHCI_PROG_CLOCK_MODE; |
|
|
|
|
div--; |
|
|
|
|
} else { |
|
|
|
|
/* 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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
div >>= 1; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* Version 2.00 divisors must be a power of 2. */ |
|
|
|
@ -336,13 +355,13 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) |
|
|
|
|
if ((mmc->cfg->f_max / div) <= clock) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
div >>= 1; |
|
|
|
|
} |
|
|
|
|
div >>= 1; |
|
|
|
|
|
|
|
|
|
if (host->set_clock) |
|
|
|
|
host->set_clock(host->index, div); |
|
|
|
|
|
|
|
|
|
clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; |
|
|
|
|
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; |
|
|
|
@ -451,6 +470,8 @@ static int sdhci_init(struct mmc *mmc) |
|
|
|
|
{ |
|
|
|
|
struct sdhci_host *host = mmc->priv; |
|
|
|
|
|
|
|
|
|
sdhci_reset(host, SDHCI_RESET_ALL); |
|
|
|
|
|
|
|
|
|
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { |
|
|
|
|
aligned_buffer = memalign(8, 512*1024); |
|
|
|
|
if (!aligned_buffer) { |
|
|
|
@ -514,9 +535,17 @@ static const struct mmc_ops sdhci_ops = { |
|
|
|
|
int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, |
|
|
|
|
u32 max_clk, u32 min_clk) |
|
|
|
|
{ |
|
|
|
|
u32 caps; |
|
|
|
|
u32 caps, caps_1; |
|
|
|
|
|
|
|
|
|
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 -EINVAL; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
host->version = sdhci_readw(host, SDHCI_HOST_VERSION); |
|
|
|
|
|
|
|
|
|
cfg->name = host->name; |
|
|
|
@ -534,8 +563,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, |
|
|
|
|
SDHCI_CLOCK_BASE_SHIFT; |
|
|
|
|
cfg->f_max *= 1000000; |
|
|
|
|
} |
|
|
|
|
if (cfg->f_max == 0) |
|
|
|
|
if (cfg->f_max == 0) { |
|
|
|
|
printf("%s: Hardware doesn't specify base clock frequency\n", |
|
|
|
|
__func__); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
if (min_clk) |
|
|
|
|
cfg->f_min = min_clk; |
|
|
|
|
else { |
|
|
|
@ -552,6 +584,9 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, |
|
|
|
|
if (caps & SDHCI_CAN_VDD_180) |
|
|
|
|
cfg->voltages |= MMC_VDD_165_195; |
|
|
|
|
|
|
|
|
|
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) |
|
|
|
|
cfg->voltages |= host->voltages; |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
@ -564,6 +599,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, |
|
|
|
|
|
|
|
|
|
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In case of Host Controller v3.00, find out whether clock |
|
|
|
|
* multiplier is supported. |
|
|
|
|
*/ |
|
|
|
|
caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); |
|
|
|
|
host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> |
|
|
|
|
SDHCI_CLOCK_MUL_SHIFT; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -575,27 +618,11 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg) |
|
|
|
|
#else |
|
|
|
|
int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) |
|
|
|
|
{ |
|
|
|
|
#ifdef CONFIG_MMC_SDMA |
|
|
|
|
unsigned int caps; |
|
|
|
|
|
|
|
|
|
caps = sdhci_readl(host, SDHCI_CAPABILITIES); |
|
|
|
|
if (!(caps & SDHCI_CAN_DO_SDMA)) { |
|
|
|
|
printf("%s: Your controller doesn't support SDMA!!\n", |
|
|
|
|
__func__); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
if (sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk)) { |
|
|
|
|
printf("%s: Hardware doesn't specify base clock frequency\n", |
|
|
|
|
__func__); |
|
|
|
|
return -EINVAL; |
|
|
|
|
} |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) |
|
|
|
|
host->cfg.voltages |= host->voltages; |
|
|
|
|
|
|
|
|
|
sdhci_reset(host, SDHCI_RESET_ALL); |
|
|
|
|
ret = sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk); |
|
|
|
|
if (ret) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
host->mmc = mmc_create(&host->cfg, host); |
|
|
|
|
if (host->mmc == NULL) { |
|
|
|
|