summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-02-05 17:39:31 +0300
committerTom Rini <trini@konsulko.com>2021-02-05 17:39:31 +0300
commit8308a28af821d6498186b3dd7463db9874cd2daf (patch)
tree660426244992e77c43b3d1ce5be3e19f061a589b /drivers
parent55ffabec7f9108060350fae29b932fbd832f8296 (diff)
parent6239cc8c4e8484d908afc555eb59441a16a58b53 (diff)
downloadu-boot-8308a28af821d6498186b3dd7463db9874cd2daf.tar.xz
Merge tag 'ti-v2021.04-rc2' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
- Sync DTS from Linux kernel for all K3 platforms - Add MMC higher speed nodes for AM65x, J721e, J7200 - Convert Nokia RX-51 to use CONFIG_DM_MMC - Minor fixes for LEGO MINDSTORMS
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/Kconfig1
-rw-r--r--drivers/mmc/am654_sdhci.c384
-rw-r--r--drivers/mmc/sdhci.c95
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c8
4 files changed, 376 insertions, 112 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 14d7913986..f8ea92172e 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 baa935e0d5..11dcde134c 100644
--- a/drivers/mmc/am654_sdhci.c
+++ b/drivers/mmc/am654_sdhci.c
@@ -9,9 +9,11 @@
#include <common.h>
#include <dm.h>
#include <malloc.h>
+#include <mmc.h>
#include <power-domain.h>
#include <regmap.h>
#include <sdhci.h>
+#include <soc.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/err.h>
@@ -47,6 +49,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
@@ -61,6 +65,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
@@ -69,6 +83,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;
@@ -76,34 +91,59 @@ 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;
+ u32 clkbuf_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)
- bool dll_on;
+#define DLL_PRESENT BIT(0)
+#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 {
- 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 {
@@ -111,19 +151,91 @@ struct am654_driver_data {
u32 flags;
};
-static void am654_sdhci_set_control_reg(struct sdhci_host *host)
+static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat,
+ unsigned int speed)
{
- 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);
+ 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);
}
- sdhci_set_uhs_timing(host);
+ /* 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)
@@ -131,7 +243,7 @@ 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;
@@ -141,81 +253,40 @@ 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);
/* 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;
- /* 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;
-
- plat->dll_on = true;
+ } else {
+ am654_sdhci_setup_delay_chain(plat, mode);
}
+ regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
+ plat->clkbuf_sel);
+
return 0;
}
@@ -229,7 +300,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 */
@@ -241,15 +312,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,20 +354,88 @@ 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)
+{
+ 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,
+ .set_control_reg = sdhci_set_control_reg,
+ .write_b = am654_sdhci_write_b,
};
const struct am654_driver_data am654_drv_data = {
.ops = &am654_sdhci_ops,
- .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | STRBSEL_4_BIT,
+ .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,
};
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)
@@ -319,12 +449,20 @@ 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;
}
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,
+ .set_control_reg = sdhci_set_control_reg,
+ .write_b = am654_sdhci_write_b,
};
const struct am654_driver_data j721e_4bit_drv_data = {
@@ -332,6 +470,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)
{
@@ -349,15 +492,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;
@@ -371,6 +519,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;
@@ -390,6 +540,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)
@@ -399,7 +550,13 @@ 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) {
+ soc_drv_data = soc->data;
+ host->ops = soc_drv_data->ops;
+ }
+
host->mmc->priv = host;
upriv->mmc = host->mmc;
@@ -452,6 +609,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;
@@ -464,9 +623,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);
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 0628934312..ed0dc17325 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <phys2bus.h>
+#include <power/regulator.h>
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)
{
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index 10bc4e99f0..3c569a3b7b 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) {