mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-22 12:54:37 +00:00
mmc: sdhci: Add support for HOST_CONTROL2 and setting UHS timings
The HOST_CONTROL2 register is a part of SDHC v3.00 and not just specific to arasan/zynq controllers. Add the same to sdhci.h. Also create a common API to set UHS timings in HOST_CONTROL2. Signed-off-by: Faiz Abbas <faiz_abbas@ti.com> Reviewed-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
parent
5a6098fff0
commit
d1c0a2200a
3 changed files with 55 additions and 37 deletions
|
@ -534,6 +534,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
|
||||||
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
|
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sdhci_set_uhs_timing(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
struct mmc *mmc = (struct mmc *)host->mmc;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||||
|
reg &= ~SDHCI_CTRL_UHS_MASK;
|
||||||
|
|
||||||
|
switch (mmc->selected_mode) {
|
||||||
|
case UHS_SDR50:
|
||||||
|
case MMC_HS_52:
|
||||||
|
reg |= SDHCI_CTRL_UHS_SDR50;
|
||||||
|
break;
|
||||||
|
case UHS_DDR50:
|
||||||
|
case MMC_DDR_52:
|
||||||
|
reg |= SDHCI_CTRL_UHS_DDR50;
|
||||||
|
break;
|
||||||
|
case UHS_SDR104:
|
||||||
|
case MMC_HS_200:
|
||||||
|
reg |= SDHCI_CTRL_UHS_SDR104;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reg |= SDHCI_CTRL_UHS_SDR12;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DM_MMC
|
#ifdef CONFIG_DM_MMC
|
||||||
static int sdhci_set_ios(struct udevice *dev)
|
static int sdhci_set_ios(struct udevice *dev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,11 +48,6 @@ static const u8 mode2timing[] = {
|
||||||
[MMC_HS_200] = MMC_HS200_BUS_SPEED,
|
[MMC_HS_200] = MMC_HS200_BUS_SPEED,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SDHCI_HOST_CTRL2 0x3E
|
|
||||||
#define SDHCI_CTRL2_MODE_MASK 0x7
|
|
||||||
#define SDHCI_18V_SIGNAL 0x8
|
|
||||||
#define SDHCI_CTRL_EXEC_TUNING 0x0040
|
|
||||||
#define SDHCI_CTRL_TUNED_CLK 0x80
|
|
||||||
#define SDHCI_TUNING_LOOP_COUNT 40
|
#define SDHCI_TUNING_LOOP_COUNT 40
|
||||||
|
|
||||||
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
|
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
|
||||||
|
@ -99,9 +94,9 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
|
||||||
host = priv->host;
|
host = priv->host;
|
||||||
deviceid = priv->deviceid;
|
deviceid = priv->deviceid;
|
||||||
|
|
||||||
ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
|
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||||
ctrl |= SDHCI_CTRL_EXEC_TUNING;
|
ctrl |= SDHCI_CTRL_EXEC_TUNING;
|
||||||
sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2);
|
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
|
||||||
|
|
||||||
mdelay(1);
|
mdelay(1);
|
||||||
|
|
||||||
|
@ -133,7 +128,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
|
||||||
sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
|
sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
|
||||||
|
|
||||||
mmc_send_cmd(mmc, &cmd, NULL);
|
mmc_send_cmd(mmc, &cmd, NULL);
|
||||||
ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
|
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||||
|
|
||||||
if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
|
if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
@ -142,7 +137,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
|
||||||
|
|
||||||
if (tuning_loop_counter < 0) {
|
if (tuning_loop_counter < 0) {
|
||||||
ctrl &= ~SDHCI_CTRL_TUNED_CLK;
|
ctrl &= ~SDHCI_CTRL_TUNED_CLK;
|
||||||
sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2);
|
sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
|
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
|
||||||
|
@ -184,36 +179,14 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
|
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
|
||||||
reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
|
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||||
reg |= SDHCI_18V_SIGNAL;
|
reg |= SDHCI_CTRL_VDD_180;
|
||||||
sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
|
sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mmc->selected_mode > SD_HS &&
|
if (mmc->selected_mode > SD_HS &&
|
||||||
mmc->selected_mode <= UHS_DDR50) {
|
mmc->selected_mode <= UHS_DDR50)
|
||||||
reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
|
sdhci_set_uhs_timing(host);
|
||||||
reg &= ~SDHCI_CTRL2_MODE_MASK;
|
|
||||||
switch (mmc->selected_mode) {
|
|
||||||
case UHS_SDR12:
|
|
||||||
reg |= UHS_SDR12_BUS_SPEED;
|
|
||||||
break;
|
|
||||||
case UHS_SDR25:
|
|
||||||
reg |= UHS_SDR25_BUS_SPEED;
|
|
||||||
break;
|
|
||||||
case UHS_SDR50:
|
|
||||||
reg |= UHS_SDR50_BUS_SPEED;
|
|
||||||
break;
|
|
||||||
case UHS_SDR104:
|
|
||||||
reg |= UHS_SDR104_BUS_SPEED;
|
|
||||||
break;
|
|
||||||
case UHS_DDR50:
|
|
||||||
reg |= UHS_DDR50_BUS_SPEED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,23 @@
|
||||||
|
|
||||||
#define SDHCI_ACMD12_ERR 0x3C
|
#define SDHCI_ACMD12_ERR 0x3C
|
||||||
|
|
||||||
/* 3E-3F reserved */
|
#define SDHCI_HOST_CONTROL2 0x3E
|
||||||
|
#define SDHCI_CTRL_UHS_MASK 0x0007
|
||||||
|
#define SDHCI_CTRL_UHS_SDR12 0x0000
|
||||||
|
#define SDHCI_CTRL_UHS_SDR25 0x0001
|
||||||
|
#define SDHCI_CTRL_UHS_SDR50 0x0002
|
||||||
|
#define SDHCI_CTRL_UHS_SDR104 0x0003
|
||||||
|
#define SDHCI_CTRL_UHS_DDR50 0x0004
|
||||||
|
#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
|
||||||
|
#define SDHCI_CTRL_VDD_180 0x0008
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_A 0x0010
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_C 0x0020
|
||||||
|
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
|
||||||
|
#define SDHCI_CTRL_EXEC_TUNING 0x0040
|
||||||
|
#define SDHCI_CTRL_TUNED_CLK 0x0080
|
||||||
|
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
|
||||||
|
|
||||||
#define SDHCI_CAPABILITIES 0x40
|
#define SDHCI_CAPABILITIES 0x40
|
||||||
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
|
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
|
||||||
|
@ -467,6 +483,7 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
|
||||||
int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min);
|
int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min);
|
||||||
#endif /* !CONFIG_BLK */
|
#endif /* !CONFIG_BLK */
|
||||||
|
|
||||||
|
void sdhci_set_uhs_timing(struct sdhci_host *host);
|
||||||
#ifdef CONFIG_DM_MMC
|
#ifdef CONFIG_DM_MMC
|
||||||
/* Export the operations to drivers */
|
/* Export the operations to drivers */
|
||||||
int sdhci_probe(struct udevice *dev);
|
int sdhci_probe(struct udevice *dev);
|
||||||
|
|
Loading…
Add table
Reference in a new issue