From 468ec2f3ef8fb4e08c01e6d92a530d3632ca6df5 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 26 Jan 2021 18:20:56 -0600 Subject: remoteproc: k3_r5: Sync to upstreamed kernel DT property names The K3 R5F remoteproc driver in U-Boot was upstreamed prior to the equivalent remoteproc driver in the Linux kernel. Some of the DT properties used in U-Boot got upstreamed using different names in Linux kernel. The modified property names include the R5F cluster mode configuration property "lockstep-mode"; and three different individual R5F core config properties - "atcm-enable", "btcm-enable" and "loczrama". The property names were updated as follows: lockstep-mode => ti,cluster-mode atcm-enable => ti,atcm-enable btcm-enable => ti,btcm-enable loczrama => ti,loczrama Update the K3 R5F remoteproc driver, the corresponding binding, and all the existing usage in AM65x, J721E and J7200 dts files all at once to use the new properties and to not break any bisectability. Signed-off-by: Suman Anna --- drivers/remoteproc/ti_k3_r5f_rproc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index 10bc4e99f0c..3c569a3b7b6 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -678,9 +678,9 @@ static int k3_r5f_of_to_priv(struct k3_r5f_core *core) dev_dbg(core->dev, "%s\n", __func__); - core->atcm_enable = dev_read_u32_default(core->dev, "atcm-enable", 0); - core->btcm_enable = dev_read_u32_default(core->dev, "btcm-enable", 1); - core->loczrama = dev_read_u32_default(core->dev, "loczrama", 1); + core->atcm_enable = dev_read_u32_default(core->dev, "ti,atcm-enable", 0); + core->btcm_enable = dev_read_u32_default(core->dev, "ti,btcm-enable", 1); + core->loczrama = dev_read_u32_default(core->dev, "ti,loczrama", 1); ret = ti_sci_proc_of_to_priv(core->dev, &core->tsp); if (ret) @@ -875,7 +875,7 @@ static int k3_r5f_cluster_probe(struct udevice *dev) dev_dbg(dev, "%s\n", __func__); - cluster->mode = dev_read_u32_default(dev, "lockstep-mode", + cluster->mode = dev_read_u32_default(dev, "ti,cluster-mode", CLUSTER_MODE_LOCKSTEP); if (device_get_child_count(dev) != 2) { -- cgit v1.2.3 From 43392b550e56b52274398763329f35d54109d291 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:46 +0530 Subject: mmc: sdhci: Add helper functions for UHS modes Add a set_voltage() function which handles the switch from 3.3V to 1.8V for SD card UHS modes. Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 06289343124..ed0dc173253 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -20,6 +20,7 @@ #include #include #include +#include static void sdhci_reset(struct sdhci_host *host, u8 mask) { @@ -509,6 +510,100 @@ void sdhci_set_uhs_timing(struct sdhci_host *host) sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); } +static void sdhci_set_voltage(struct sdhci_host *host) +{ + if (IS_ENABLED(CONFIG_MMC_IO_VOLTAGE)) { + struct mmc *mmc = (struct mmc *)host->mmc; + u32 ctrl; + + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + + switch (mmc->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: +#if CONFIG_IS_ENABLED(DM_REGULATOR) + if (mmc->vqmmc_supply) { + if (regulator_set_enable_if_allowed(mmc->vqmmc_supply, false)) { + pr_err("failed to disable vqmmc-supply\n"); + return; + } + + if (regulator_set_value(mmc->vqmmc_supply, 3300000)) { + pr_err("failed to set vqmmc-voltage to 3.3V\n"); + return; + } + + if (regulator_set_enable_if_allowed(mmc->vqmmc_supply, true)) { + pr_err("failed to enable vqmmc-supply\n"); + return; + } + } +#endif + if (IS_SD(mmc)) { + ctrl &= ~SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + } + + /* Wait for 5ms */ + mdelay(5); + + /* 3.3V regulator output should be stable within 5 ms */ + if (IS_SD(mmc)) { + if (ctrl & SDHCI_CTRL_VDD_180) { + pr_err("3.3V regulator output did not become stable\n"); + return; + } + } + + break; + case MMC_SIGNAL_VOLTAGE_180: +#if CONFIG_IS_ENABLED(DM_REGULATOR) + if (mmc->vqmmc_supply) { + if (regulator_set_enable_if_allowed(mmc->vqmmc_supply, false)) { + pr_err("failed to disable vqmmc-supply\n"); + return; + } + + if (regulator_set_value(mmc->vqmmc_supply, 1800000)) { + pr_err("failed to set vqmmc-voltage to 1.8V\n"); + return; + } + + if (regulator_set_enable_if_allowed(mmc->vqmmc_supply, true)) { + pr_err("failed to enable vqmmc-supply\n"); + return; + } + } +#endif + if (IS_SD(mmc)) { + ctrl |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + } + + /* Wait for 5 ms */ + mdelay(5); + + /* 1.8V regulator output has to be stable within 5 ms */ + if (IS_SD(mmc)) { + if (!(ctrl & SDHCI_CTRL_VDD_180)) { + pr_err("1.8V regulator output did not become stable\n"); + return; + } + } + + break; + default: + /* No signal voltage switch required */ + return; + } + } +} + +void sdhci_set_control_reg(struct sdhci_host *host) +{ + sdhci_set_voltage(host); + sdhci_set_uhs_timing(host); +} + #ifdef CONFIG_DM_MMC static int sdhci_set_ios(struct udevice *dev) { -- cgit v1.2.3 From c604e204eff2a465fe284d41e195e49f58bff72f Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:47 +0530 Subject: mmc: am654_sdhci: Unconditionally switch off DLL in the beginning of ios_post() There are some speed modes that work without switching the dll on. Unconditionally switch off the DLL before setting clock frequency to support this case. The software will automatically enable DLL for speed modes that require it. This also means the dll_on priv data member is no longer required. Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index baa935e0d5b..33f658fba71 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -84,7 +84,6 @@ struct am654_sdhci_plat { #define IOMUX_PRESENT (1 << 1) #define FREQSEL_2_BIT (1 << 2) #define STRBSEL_4_BIT (1 << 3) - bool dll_on; }; struct timing_data { @@ -141,12 +140,7 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) val &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, val, SDHCI_CLOCK_CONTROL); - /* power off phy */ - if (plat->dll_on) { - regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0); - - plat->dll_on = false; - } + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0); /* restart clock */ sdhci_set_clock(host->mmc, speed); @@ -212,8 +206,6 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) val & DLLRDY_MASK, 1000, 1000000); if (ret) return ret; - - plat->dll_on = true; } return 0; -- cgit v1.2.3 From 144e131d47fcc027ae6e9869273f7c8756eb8846 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:48 +0530 Subject: mmc: am654_sdhci: Convert flag fields to BIT macro Convert the flags field defines to use the BIT() macro. Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 33f658fba71..e0136dff971 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -80,10 +80,10 @@ struct am654_sdhci_plat { u32 drv_strength; u32 strb_sel; u32 flags; -#define DLL_PRESENT (1 << 0) -#define IOMUX_PRESENT (1 << 1) -#define FREQSEL_2_BIT (1 << 2) -#define STRBSEL_4_BIT (1 << 3) +#define DLL_PRESENT BIT(0) +#define IOMUX_PRESENT BIT(1) +#define FREQSEL_2_BIT BIT(2) +#define STRBSEL_4_BIT BIT(3) }; struct timing_data { -- cgit v1.2.3 From 5b29fd4a8db22a63f0e7b3ce773e81bf1d855428 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:49 +0530 Subject: mmc: am654_sdhci: Add flag for PHY calibration Not all controllers need calibration for the PHY DLL. Add a DLL_CALIB flag to indicate the same. Also move the write of trm_icp and driver strength to the set_clock() function to match the kernel configuration flow. Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index e0136dff971..1e065418381 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -84,6 +84,7 @@ struct am654_sdhci_plat { #define IOMUX_PRESENT BIT(1) #define FREQSEL_2_BIT BIT(2) #define STRBSEL_4_BIT BIT(3) +#define DLL_CALIB BIT(4) }; struct timing_data { @@ -195,6 +196,15 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) freqsel << FREQSEL_SHIFT); } + /* Configure DLL TRIM */ + mask = DLL_TRIM_ICP_MASK; + val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; + + /* Configure DLL driver strength */ + mask |= DR_TY_MASK; + val |= plat->drv_strength << DR_TY_SHIFT; + regmap_update_bits(plat->base, PHY_CTRL1, mask, val); + /* Enable DLL */ regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0x1 << ENDLL_SHIFT); @@ -221,7 +231,7 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat) mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0); - if (plat->flags & DLL_PRESENT) { + if (plat->flags & DLL_CALIB) { regmap_read(plat->base, PHY_STAT1, &val); if (~val & CALDONE_MASK) { /* Calibrate IO lines */ @@ -233,15 +243,6 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat) if (ret) return ret; } - - /* Configure DLL TRIM */ - mask = DLL_TRIM_ICP_MASK; - val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; - - /* Configure DLL driver strength */ - mask |= DR_TY_MASK; - val |= plat->drv_strength << DR_TY_SHIFT; - regmap_update_bits(plat->base, PHY_CTRL1, mask, val); } /* Enable pins by setting IO mux to 0 */ @@ -292,12 +293,13 @@ const struct sdhci_ops am654_sdhci_ops = { const struct am654_driver_data am654_drv_data = { .ops = &am654_sdhci_ops, - .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | STRBSEL_4_BIT, + .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | DLL_CALIB | + STRBSEL_4_BIT, }; const struct am654_driver_data j721e_8bit_drv_data = { .ops = &am654_sdhci_ops, - .flags = DLL_PRESENT, + .flags = DLL_PRESENT | DLL_CALIB, }; static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) -- cgit v1.2.3 From 8c32b5f3707fedeebe2d34ebd6aa4a77c4bacbd3 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:50 +0530 Subject: mmc: am654_sdhci: Add support for AM65x SR2.0 Add Support for AM65x PG2.0. Use the SoC bus framework to fixup the platform data and do DLL calibration if the revision is 1.0 Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 1e065418381..5790fa3d0db 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -292,6 +293,11 @@ const struct sdhci_ops am654_sdhci_ops = { }; const struct am654_driver_data am654_drv_data = { + .ops = &am654_sdhci_ops, + .flags = DLL_PRESENT | IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT, +}; + +const struct am654_driver_data am654_sr1_drv_data = { .ops = &am654_sdhci_ops, .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | DLL_CALIB | STRBSEL_4_BIT, @@ -326,6 +332,11 @@ const struct am654_driver_data j721e_4bit_drv_data = { .flags = IOMUX_PRESENT, }; +const struct soc_attr am654_sdhci_soc_attr[] = { + { .family = "AM65X", .revision = "SR1.0", .data = &am654_sr1_drv_data}, + {/* sentinel */} +}; + static int sdhci_am654_get_otap_delay(struct udevice *dev, struct mmc_config *cfg) { @@ -365,6 +376,8 @@ static int am654_sdhci_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_host *host = dev_get_priv(dev); struct mmc_config *cfg = &plat->cfg; + const struct soc_attr *soc; + const struct am654_driver_data *soc_drv_data; struct clk clk; unsigned long clock; int ret; @@ -394,6 +407,14 @@ static int am654_sdhci_probe(struct udevice *dev) return ret; host->ops = drv_data->ops; + + /* Update ops based on SoC revision */ + soc = soc_device_match(am654_sdhci_soc_attr); + if (soc && soc->data) { + soc_drv_data = soc->data; + host->ops = soc_drv_data->ops; + } + host->mmc->priv = host; upriv->mmc = host->mmc; @@ -458,9 +479,18 @@ static int am654_sdhci_bind(struct udevice *dev) struct am654_driver_data *drv_data = (struct am654_driver_data *)dev_get_driver_data(dev); struct am654_sdhci_plat *plat = dev_get_plat(dev); + const struct soc_attr *soc; + const struct am654_driver_data *soc_drv_data; plat->flags = drv_data->flags; + /* Update flags based on SoC revision */ + soc = soc_device_match(am654_sdhci_soc_attr); + if (soc && soc->data) { + soc_drv_data = soc->data; + plat->flags = soc_drv_data->flags; + } + return sdhci_bind(dev, &plat->mmc, &plat->cfg); } -- cgit v1.2.3 From c964447ea3d6af0f9bfd78ceda8a3cd7c27fd584 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:51 +0530 Subject: mmc: am654_sdhci: Add support for input tap delay DLL need only be enabled for speed modes and clock frequencies at or above 50 MHz. For speed modes that don't enable the DLL, we need to configure a static input delay value. This involves reading an optional itap-del-sel-* value from the device tree and configuring it for the appropriate speed mode. Therefore, move all dll configurations to their own functions and gate it with 50 MHz speed and a minimum mode. If both these conditions are not satisfied then configure delay chain modes. Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 241 +++++++++++++++++++++++++++++++--------------- 1 file changed, 161 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 5790fa3d0db..b82558254eb 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -62,6 +62,16 @@ #define CALDONE_MASK BIT(CALDONE_SHIFT) #define RETRIM_SHIFT 17 #define RETRIM_MASK BIT(RETRIM_SHIFT) +#define SELDLYTXCLK_SHIFT 17 +#define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT) +#define SELDLYRXCLK_SHIFT 16 +#define SELDLYRXCLK_MASK BIT(SELDLYRXCLK_SHIFT) +#define ITAPDLYSEL_SHIFT 0 +#define ITAPDLYSEL_MASK GENMASK(4, 0) +#define ITAPDLYENA_SHIFT 8 +#define ITAPDLYENA_MASK BIT(ITAPDLYENA_SHIFT) +#define ITAPCHGWIN_SHIFT 9 +#define ITAPCHGWIN_MASK BIT(ITAPCHGWIN_SHIFT) #define DRIVER_STRENGTH_50_OHM 0x0 #define DRIVER_STRENGTH_33_OHM 0x1 @@ -70,6 +80,7 @@ #define DRIVER_STRENGTH_40_OHM 0x4 #define AM654_SDHCI_MIN_FREQ 400000 +#define CLOCK_TOO_SLOW_HZ 50000000 struct am654_sdhci_plat { struct mmc_config cfg; @@ -77,6 +88,7 @@ struct am654_sdhci_plat { struct regmap *base; bool non_removable; u32 otap_del_sel[MMC_MODES_END]; + u32 itap_del_sel[MMC_MODES_END]; u32 trm_icp; u32 drv_strength; u32 strb_sel; @@ -89,22 +101,45 @@ struct am654_sdhci_plat { }; struct timing_data { - const char *binding; + const char *otap_binding; + const char *itap_binding; u32 capability; }; static const struct timing_data td[] = { - [MMC_LEGACY] = {"ti,otap-del-sel-legacy", 0}, - [MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP(MMC_HS)}, - [SD_HS] = {"ti,otap-del-sel-sd-hs", MMC_CAP(SD_HS)}, - [UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP(UHS_SDR12)}, - [UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP(UHS_SDR25)}, - [UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP(UHS_SDR50)}, - [UHS_SDR104] = {"ti,otap-del-sel-sdr104", MMC_CAP(UHS_SDR104)}, - [UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP(UHS_DDR50)}, - [MMC_DDR_52] = {"ti,otap-del-sel-ddr52", MMC_CAP(MMC_DDR_52)}, - [MMC_HS_200] = {"ti,otap-del-sel-hs200", MMC_CAP(MMC_HS_200)}, - [MMC_HS_400] = {"ti,otap-del-sel-hs400", MMC_CAP(MMC_HS_400)}, + [MMC_LEGACY] = {"ti,otap-del-sel-legacy", + "ti,itap-del-sel-legacy", + 0}, + [MMC_HS] = {"ti,otap-del-sel-mmc-hs", + "ti,itap-del-sel-mms-hs", + MMC_CAP(MMC_HS)}, + [SD_HS] = {"ti,otap-del-sel-sd-hs", + "ti,itap-del-sel-sd-hs", + MMC_CAP(SD_HS)}, + [UHS_SDR12] = {"ti,otap-del-sel-sdr12", + "ti,itap-del-sel-sdr12", + MMC_CAP(UHS_SDR12)}, + [UHS_SDR25] = {"ti,otap-del-sel-sdr25", + "ti,itap-del-sel-sdr25", + MMC_CAP(UHS_SDR25)}, + [UHS_SDR50] = {"ti,otap-del-sel-sdr50", + NULL, + MMC_CAP(UHS_SDR50)}, + [UHS_SDR104] = {"ti,otap-del-sel-sdr104", + NULL, + MMC_CAP(UHS_SDR104)}, + [UHS_DDR50] = {"ti,otap-del-sel-ddr50", + NULL, + MMC_CAP(UHS_DDR50)}, + [MMC_DDR_52] = {"ti,otap-del-sel-ddr52", + "ti,itap-del-sel-ddr52", + MMC_CAP(MMC_DDR_52)}, + [MMC_HS_200] = {"ti,otap-del-sel-hs200", + NULL, + MMC_CAP(MMC_HS_200)}, + [MMC_HS_400] = {"ti,otap-del-sel-hs400", + NULL, + MMC_CAP(MMC_HS_400)}, }; struct am654_driver_data { @@ -127,12 +162,99 @@ static void am654_sdhci_set_control_reg(struct sdhci_host *host) sdhci_set_uhs_timing(host); } +static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat, + unsigned int speed) +{ + int sel50, sel100, freqsel; + u32 mask, val; + int ret; + + /* Disable delay chain mode */ + regmap_update_bits(plat->base, PHY_CTRL5, + SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0); + + if (plat->flags & FREQSEL_2_BIT) { + switch (speed) { + case 200000000: + sel50 = 0; + sel100 = 0; + break; + case 100000000: + sel50 = 0; + sel100 = 1; + break; + default: + sel50 = 1; + sel100 = 0; + } + + /* Configure PHY DLL frequency */ + mask = SEL50_MASK | SEL100_MASK; + val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL5, mask, val); + } else { + switch (speed) { + case 200000000: + freqsel = 0x0; + break; + default: + freqsel = 0x4; + } + regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK, + freqsel << FREQSEL_SHIFT); + } + + /* Configure DLL TRIM */ + mask = DLL_TRIM_ICP_MASK; + val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; + + /* Configure DLL driver strength */ + mask |= DR_TY_MASK; + val |= plat->drv_strength << DR_TY_SHIFT; + regmap_update_bits(plat->base, PHY_CTRL1, mask, val); + + /* Enable DLL */ + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, + 0x1 << ENDLL_SHIFT); + /* + * Poll for DLL ready. Use a one second timeout. + * Works in all experiments done so far + */ + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, + val & DLLRDY_MASK, 1000, 1000000); + + return ret; +} + +static void am654_sdhci_write_itapdly(struct am654_sdhci_plat *plat, + u32 itapdly) +{ + /* Set ITAPCHGWIN before writing to ITAPDLY */ + regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYSEL_MASK, + itapdly << ITAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); +} + +static void am654_sdhci_setup_delay_chain(struct am654_sdhci_plat *plat, + int mode) +{ + u32 mask, val; + + val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT; + mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; + regmap_update_bits(plat->base, PHY_CTRL5, mask, val); + + am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode]); +} + static int am654_sdhci_set_ios_post(struct sdhci_host *host) { struct udevice *dev = host->mmc->dev; struct am654_sdhci_plat *plat = dev_get_plat(dev); unsigned int speed = host->mmc->clock; - int sel50, sel100, freqsel; + int mode = host->mmc->selected_mode; u32 otap_del_sel; u32 mask, val; int ret; @@ -148,75 +270,29 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) sdhci_set_clock(host->mmc, speed); /* switch phy back on */ - if (speed > AM654_SDHCI_MIN_FREQ) { - otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode]; - mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; - val = (1 << OTAPDLYENA_SHIFT) | - (otap_del_sel << OTAPDLYSEL_SHIFT); - - /* Write to STRBSEL for HS400 speed mode */ - if (host->mmc->selected_mode == MMC_HS_400) { - if (plat->flags & STRBSEL_4_BIT) - mask |= STRBSEL_4BIT_MASK; - else - mask |= STRBSEL_8BIT_MASK; - - val |= plat->strb_sel << STRBSEL_SHIFT; - } + otap_del_sel = plat->otap_del_sel[mode]; + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | + (otap_del_sel << OTAPDLYSEL_SHIFT); - regmap_update_bits(plat->base, PHY_CTRL4, mask, val); - - if (plat->flags & FREQSEL_2_BIT) { - switch (speed) { - case 200000000: - sel50 = 0; - sel100 = 0; - break; - case 100000000: - sel50 = 0; - sel100 = 1; - break; - default: - sel50 = 1; - sel100 = 0; - } - - /* Configure PHY DLL frequency */ - mask = SEL50_MASK | SEL100_MASK; - val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); - regmap_update_bits(plat->base, PHY_CTRL5, mask, val); - } else { - switch (speed) { - case 200000000: - freqsel = 0x0; - break; - default: - freqsel = 0x4; - } - regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK, - freqsel << FREQSEL_SHIFT); - } + /* Write to STRBSEL for HS400 speed mode */ + if (host->mmc->selected_mode == MMC_HS_400) { + if (plat->flags & STRBSEL_4_BIT) + mask |= STRBSEL_4BIT_MASK; + else + mask |= STRBSEL_8BIT_MASK; - /* Configure DLL TRIM */ - mask = DLL_TRIM_ICP_MASK; - val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; - - /* Configure DLL driver strength */ - mask |= DR_TY_MASK; - val |= plat->drv_strength << DR_TY_SHIFT; - regmap_update_bits(plat->base, PHY_CTRL1, mask, val); - - /* Enable DLL */ - regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, - 0x1 << ENDLL_SHIFT); - /* - * Poll for DLL ready. Use a one second timeout. - * Works in all experiments done so far - */ - ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, - val & DLLRDY_MASK, 1000, 1000000); + val |= plat->strb_sel << STRBSEL_SHIFT; + } + + regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + + if (mode > UHS_SDR25 && speed >= CLOCK_TOO_SLOW_HZ) { + ret = am654_sdhci_setup_dll(plat, speed); if (ret) return ret; + } else { + am654_sdhci_setup_delay_chain(plat, mode); } return 0; @@ -354,15 +430,20 @@ static int sdhci_am654_get_otap_delay(struct udevice *dev, * value is not found */ for (i = MMC_HS; i <= MMC_HS_400; i++) { - ret = dev_read_u32(dev, td[i].binding, &plat->otap_del_sel[i]); + ret = dev_read_u32(dev, td[i].otap_binding, + &plat->otap_del_sel[i]); if (ret) { - dev_dbg(dev, "Couldn't find %s\n", td[i].binding); + dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding); /* * Remove the corresponding capability * if an otap-del-sel value is not found */ cfg->host_caps &= ~td[i].capability; } + + if (td[i].itap_binding) + dev_read_u32(dev, td[i].itap_binding, + &plat->itap_del_sel[i]); } return 0; -- cgit v1.2.3 From 194c3756c89f3c460b5005b34d584eb50d8310c6 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:52 +0530 Subject: mmc: am654_sdhci: Add support for writing to clkbuf_sel Add support for writing new clock buffer select property for both the am654x and j721e 4 bit IPs Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index b82558254eb..e86ef1a8b21 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -48,6 +48,8 @@ #define SEL100_MASK BIT(SEL100_SHIFT) #define FREQSEL_SHIFT 8 #define FREQSEL_MASK GENMASK(10, 8) +#define CLKBUFSEL_SHIFT 0 +#define CLKBUFSEL_MASK GENMASK(2, 0) #define DLL_TRIM_ICP_SHIFT 4 #define DLL_TRIM_ICP_MASK GENMASK(7, 4) #define DR_TY_SHIFT 20 @@ -92,6 +94,7 @@ struct am654_sdhci_plat { u32 trm_icp; u32 drv_strength; u32 strb_sel; + u32 clkbuf_sel; u32 flags; #define DLL_PRESENT BIT(0) #define IOMUX_PRESENT BIT(1) @@ -295,6 +298,9 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) am654_sdhci_setup_delay_chain(plat, mode); } + regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK, + plat->clkbuf_sel); + return 0; } @@ -395,6 +401,9 @@ static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) val = (1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK, + plat->clkbuf_sel); + return 0; } @@ -548,6 +557,8 @@ static int am654_sdhci_of_to_plat(struct udevice *dev) } } + dev_read_u32(dev, "ti,clkbuf-sel", &plat->clkbuf_sel); + ret = mmc_of_parse(dev, cfg); if (ret) return ret; -- cgit v1.2.3 From a759abf569d4f2a238712485379d23f7a5261992 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:53 +0530 Subject: mmc: am654_sdhci: Add support for software tuning With the new SW tuning App note[1], a custom tuning algorithm is required for eMMC HS200, HS400 and SD card UHS modes. The algorithm involves running through the 32 possible input tap delay values and sending the appropriate tuning command (CMD19/21) for each of them to get a fail or pass result for each of the values. Typically, the range will have a small contiguous failing window. Considering the tuning range as a circular buffer, the algorithm then sets a final tuned value directly opposite to the failing window. [1] https://www.ti.com/lit/pdf/spract9 Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index e86ef1a8b21..9549420c658 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -368,7 +369,48 @@ static int am654_sdhci_deferred_probe(struct sdhci_host *host) return sdhci_probe(dev); } +#ifdef MMC_SUPPORTS_TUNING +#define ITAP_MAX 32 +static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) +{ + struct udevice *dev = mmc->dev; + struct am654_sdhci_plat *plat = dev_get_plat(dev); + int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; + u32 itap; + + /* Enable ITAPDLY */ + regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYENA_MASK, + 1 << ITAPDLYENA_SHIFT); + + for (itap = 0; itap < ITAP_MAX; itap++) { + am654_sdhci_write_itapdly(plat, itap); + + cur_val = !mmc_send_tuning(mmc, opcode, NULL); + if (cur_val && !prev_val) + pass_window = itap; + + if (!cur_val) + fail_len++; + + prev_val = cur_val; + } + /* + * Having determined the length of the failing window and start of + * the passing window calculate the length of the passing window and + * set the final value halfway through it considering the range as a + * circular buffer + */ + pass_len = ITAP_MAX - fail_len; + itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; + am654_sdhci_write_itapdly(plat, itap); + + return 0; +} +#endif const struct sdhci_ops am654_sdhci_ops = { +#ifdef MMC_SUPPORTS_TUNING + .platform_execute_tuning = am654_sdhci_execute_tuning, +#endif .deferred_probe = am654_sdhci_deferred_probe, .set_ios_post = &am654_sdhci_set_ios_post, .set_control_reg = &am654_sdhci_set_control_reg, @@ -408,6 +450,9 @@ static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) } const struct sdhci_ops j721e_4bit_sdhci_ops = { +#ifdef MMC_SUPPORTS_TUNING + .platform_execute_tuning = am654_sdhci_execute_tuning, +#endif .deferred_probe = am654_sdhci_deferred_probe, .set_ios_post = &j721e_4bit_sdhci_set_ios_post, }; -- cgit v1.2.3 From 27a87c834fde4442088fb55322162df9d96db228 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:54 +0530 Subject: mmc: am654_sdhci: Fix HISPD bit configuration in some lower speed modes According to the AM654x Data Manual[1], the setup timing in lower speed modes can only be met if the controller uses a falling edge data launch. To ensure this, the HIGH_SPEED_ENA (HOST_CONTROL[2]) bit should be cleared in default speed, SD high speed, MMC high speed, SDR12 and SDR25 speed modes. Use the sdhci writeb callback to implement this condition. [1] http://www.ti.com/lit/gpn/am6546 Section 5.10.5.16.1 Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/Kconfig | 1 + drivers/mmc/am654_sdhci.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 14d79139864..f8ea92172e4 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -526,6 +526,7 @@ config MMC_SDHCI_AM654 depends on MMC_SDHCI depends on DM_MMC && OF_CONTROL && BLK depends on REGMAP + select MMC_SDHCI_IO_ACCESSORS help Support for Secure Digital Host Controller Interface (SDHCI) controllers present on TI's AM654 SOCs. diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 9549420c658..5dea3eb1be4 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -369,6 +369,26 @@ static int am654_sdhci_deferred_probe(struct sdhci_host *host) return sdhci_probe(dev); } +static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg) +{ + if (reg == SDHCI_HOST_CONTROL) { + switch (host->mmc->selected_mode) { + /* + * According to the data manual, HISPD bit + * should not be set in these speed modes. + */ + case SD_HS: + case MMC_HS: + case UHS_SDR12: + case UHS_SDR25: + val &= ~SDHCI_CTRL_HISPD; + default: + break; + } + } + + writeb(val, host->ioaddr + reg); +} #ifdef MMC_SUPPORTS_TUNING #define ITAP_MAX 32 static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) @@ -414,6 +434,7 @@ const struct sdhci_ops am654_sdhci_ops = { .deferred_probe = am654_sdhci_deferred_probe, .set_ios_post = &am654_sdhci_set_ios_post, .set_control_reg = &am654_sdhci_set_control_reg, + .write_b = am654_sdhci_write_b, }; const struct am654_driver_data am654_drv_data = { @@ -455,6 +476,7 @@ const struct sdhci_ops j721e_4bit_sdhci_ops = { #endif .deferred_probe = am654_sdhci_deferred_probe, .set_ios_post = &j721e_4bit_sdhci_set_ios_post, + .write_b = am654_sdhci_write_b, }; const struct am654_driver_data j721e_4bit_drv_data = { @@ -532,6 +554,7 @@ static int am654_sdhci_probe(struct udevice *dev) host->max_clk = clock; host->mmc = &plat->mmc; host->mmc->dev = dev; + host->ops = drv_data->ops; ret = sdhci_setup_cfg(cfg, host, cfg->f_max, AM654_SDHCI_MIN_FREQ); if (ret) @@ -541,8 +564,6 @@ static int am654_sdhci_probe(struct udevice *dev) if (ret) return ret; - host->ops = drv_data->ops; - /* Update ops based on SoC revision */ soc = soc_device_match(am654_sdhci_soc_attr); if (soc && soc->data) { -- cgit v1.2.3 From e9fbbba4e3f1ec984c4b0b34aa5c6e19e3bcfa2c Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Thu, 4 Feb 2021 15:10:55 +0530 Subject: mmc: am654_sdhci: Use sdhci_set_control_reg() Use the generic sdhci_set_control_reg() instead of duplicating in platform driver. Signed-off-by: Faiz Abbas Signed-off-by: Aswath Govindraju Reviewed-by: Jaehoon Chung --- drivers/mmc/am654_sdhci.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 5dea3eb1be4..11dcde134c5 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -151,21 +151,6 @@ struct am654_driver_data { u32 flags; }; -static void am654_sdhci_set_control_reg(struct sdhci_host *host) -{ - struct mmc *mmc = (struct mmc *)host->mmc; - u32 reg; - - if (IS_SD(host->mmc) && - mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); - reg |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); - } - - sdhci_set_uhs_timing(host); -} - static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat, unsigned int speed) { @@ -433,7 +418,7 @@ const struct sdhci_ops am654_sdhci_ops = { #endif .deferred_probe = am654_sdhci_deferred_probe, .set_ios_post = &am654_sdhci_set_ios_post, - .set_control_reg = &am654_sdhci_set_control_reg, + .set_control_reg = sdhci_set_control_reg, .write_b = am654_sdhci_write_b, }; @@ -476,6 +461,7 @@ const struct sdhci_ops j721e_4bit_sdhci_ops = { #endif .deferred_probe = am654_sdhci_deferred_probe, .set_ios_post = &j721e_4bit_sdhci_set_ios_post, + .set_control_reg = sdhci_set_control_reg, .write_b = am654_sdhci_write_b, }; -- cgit v1.2.3