diff options
author | William Qiu <william.qiu@starfivetech.com> | 2023-07-17 09:36:43 +0300 |
---|---|---|
committer | William Qiu <william.qiu@starfivetech.com> | 2023-07-26 11:03:40 +0300 |
commit | 8bc74ce3e17fc569c612f4f1c70d1be4c94475f5 (patch) | |
tree | 8940519570e0914e33e17bb84e3424cc84dadd3a | |
parent | 1ed1ed24eb0792ffa206b20db00bf9c9dbbc37ff (diff) | |
download | u-boot-8bc74ce3e17fc569c612f4f1c70d1be4c94475f5.tar.xz |
mmc: starfive: add HS200 support
Add tuning and other related code to the driver to support HS200 mode.
Signed-off-by: William Qiu <william.qiu@starfivetech.com>
-rw-r--r-- | drivers/mmc/dw_mmc.c | 61 | ||||
-rw-r--r-- | include/dwmmc.h | 1 |
2 files changed, 61 insertions, 1 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index a949dad574..a6e50366dc 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -522,6 +522,64 @@ static int dwmci_set_ios(struct mmc *mmc) return 0; } +static void dw_mci_hs_set_bits(struct dwmci_host *host, u32 smpl_phase) +{ + /* change driver phase and sample phase */ + u32 mask = 0x1f; + u32 reg_value; + + reg_value = dwmci_readl(host, DWMCI_UHS_REG_EXT); + + /* In UHS_REG_EXT, only 5 bits valid in DRV_PHASE and SMPL_PHASE */ + reg_value &= ~(mask << 16); + reg_value |= (smpl_phase << 16); + dwmci_writel(host, DWMCI_UHS_REG_EXT, reg_value); + + /* We should delay 1ms wait for timing setting finished. */ + udelay(1000); +} + +static int dwmci_execute_tuning(struct udevice *dev, uint opcode) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct dwmci_host *host = mmc->priv; + int err = -1; + int smpl_phase, smpl_raise = -1, smpl_fall = -1; + int i; + + for (i = 0; i < 32; ++i) { + smpl_phase = i; + dw_mci_hs_set_bits(host, smpl_phase); + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); + + err = mmc_send_tuning(mmc, opcode, NULL); + + if (!err && smpl_raise < 0) { + smpl_raise = i; + } else if (err && smpl_raise >= 0) { + smpl_fall = i - 1; + break; + } + } + + if (i >= 32 && smpl_raise >= 0) + smpl_fall = 31; + + if (smpl_raise < 0) { + pr_err("No valid delay chain! use default\n"); + dw_mci_hs_set_bits(host, 0); + err = -EINVAL; + } else { + smpl_phase = (smpl_raise + smpl_fall) / 2; + dw_mci_hs_set_bits(host, smpl_phase); + pr_debug("Found valid delay chain! use it [delay=%d]\n", smpl_phase); + err = 0; + } + + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); + return err; +} + static int dwmci_init(struct mmc *mmc) { struct dwmci_host *host = mmc->priv; @@ -577,6 +635,7 @@ int dwmci_probe(struct udevice *dev) const struct dm_mmc_ops dm_dwmci_ops = { .send_cmd = dwmci_send_cmd, .set_ios = dwmci_set_ios, + .execute_tuning = dwmci_execute_tuning, }; #else @@ -608,7 +667,7 @@ void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host, cfg->host_caps |= MMC_MODE_4BIT; cfg->host_caps &= ~MMC_MODE_8BIT; } - cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; + cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS200; cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; } diff --git a/include/dwmmc.h b/include/dwmmc.h index 5fc8ed8395..a2f8ce2bf3 100644 --- a/include/dwmmc.h +++ b/include/dwmmc.h @@ -49,6 +49,7 @@ #define DWMCI_IDINTEN 0x090 #define DWMCI_DSCADDR 0x094 #define DWMCI_BUFADDR 0x098 +#define DWMCI_UHS_REG_EXT 0x108 #define DWMCI_DATA 0x200 /* Interrupt Mask register */ |