mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-04-10 16:31:32 +00:00
mmc: sdhci: Add the programmable clock mode support
Add the programmable clock mode for the clock generator. Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
This commit is contained in:
parent
e492dbb41e
commit
6dffdbc3a5
2 changed files with 42 additions and 10 deletions
|
@ -294,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)
|
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||||
{
|
{
|
||||||
struct sdhci_host *host = mmc->priv;
|
struct sdhci_host *host = mmc->priv;
|
||||||
unsigned int div, clk, timeout, reg;
|
unsigned int div, clk = 0, timeout, reg;
|
||||||
|
|
||||||
/* Wait max 20 ms */
|
/* Wait max 20 ms */
|
||||||
timeout = 200;
|
timeout = 200;
|
||||||
|
@ -318,14 +318,36 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
|
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
|
||||||
/* Version 3.00 divisors must be a multiple of 2. */
|
/*
|
||||||
if (mmc->cfg->f_max <= clock)
|
* Check if the Host Controller supports Programmable Clock
|
||||||
div = 1;
|
* Mode.
|
||||||
else {
|
*/
|
||||||
for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
|
if (host->clk_mul) {
|
||||||
if ((mmc->cfg->f_max / div) <= clock)
|
for (div = 1; div <= 1024; div++) {
|
||||||
|
if ((mmc->cfg->f_max * host->clk_mul / div)
|
||||||
|
<= clock)
|
||||||
break;
|
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 {
|
} else {
|
||||||
/* Version 2.00 divisors must be a power of 2. */
|
/* Version 2.00 divisors must be a power of 2. */
|
||||||
|
@ -333,13 +355,13 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||||
if ((mmc->cfg->f_max / div) <= clock)
|
if ((mmc->cfg->f_max / div) <= clock)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
div >>= 1;
|
||||||
}
|
}
|
||||||
div >>= 1;
|
|
||||||
|
|
||||||
if (host->set_clock)
|
if (host->set_clock)
|
||||||
host->set_clock(host->index, div);
|
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)
|
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
|
||||||
<< SDHCI_DIVIDER_HI_SHIFT;
|
<< SDHCI_DIVIDER_HI_SHIFT;
|
||||||
clk |= SDHCI_CLOCK_INT_EN;
|
clk |= SDHCI_CLOCK_INT_EN;
|
||||||
|
@ -513,7 +535,7 @@ static const struct mmc_ops sdhci_ops = {
|
||||||
int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
||||||
u32 max_clk, u32 min_clk)
|
u32 max_clk, u32 min_clk)
|
||||||
{
|
{
|
||||||
u32 caps;
|
u32 caps, caps_1;
|
||||||
|
|
||||||
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||||
|
|
||||||
|
@ -577,6 +599,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
||||||
|
|
||||||
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
#define SDHCI_DIV_MASK 0xFF
|
#define SDHCI_DIV_MASK 0xFF
|
||||||
#define SDHCI_DIV_MASK_LEN 8
|
#define SDHCI_DIV_MASK_LEN 8
|
||||||
#define SDHCI_DIV_HI_MASK 0x300
|
#define SDHCI_DIV_HI_MASK 0x300
|
||||||
|
#define SDHCI_PROG_CLOCK_MODE 0x0020
|
||||||
#define SDHCI_CLOCK_CARD_EN 0x0004
|
#define SDHCI_CLOCK_CARD_EN 0x0004
|
||||||
#define SDHCI_CLOCK_INT_STABLE 0x0002
|
#define SDHCI_CLOCK_INT_STABLE 0x0002
|
||||||
#define SDHCI_CLOCK_INT_EN 0x0001
|
#define SDHCI_CLOCK_INT_EN 0x0001
|
||||||
|
@ -242,6 +243,7 @@ struct sdhci_host {
|
||||||
unsigned int quirks;
|
unsigned int quirks;
|
||||||
unsigned int host_caps;
|
unsigned int host_caps;
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
|
unsigned int clk_mul; /* Clock Multiplier value */
|
||||||
unsigned int clock;
|
unsigned int clock;
|
||||||
struct mmc *mmc;
|
struct mmc *mmc;
|
||||||
const struct sdhci_ops *ops;
|
const struct sdhci_ops *ops;
|
||||||
|
|
Loading…
Add table
Reference in a new issue