summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-11-07 08:26:10 -0600
committerTom Rini <[email protected]>2025-11-07 08:26:10 -0600
commitb660df558545b42f7257899807b83cfc620b2983 (patch)
treebca942b3912681010f038bf154d154482d6be4e5
parentfdf36c2e9ad4f770ee951398a86bd55404d9b7ec (diff)
parent0408ae531fe8ad01b9b788181fc5b91e0a527b42 (diff)
Merge tag 'mmc-master-2025-11-07' of https://source.denx.de/u-boot/custodians/u-boot-mmc
CI: https://source.denx.de/u-boot/custodians/u-boot-mmc/-/pipelines/28218 - Disabling FMP on Exynos850 to make eMMC functional when U-Boot is executed during USB boot - Drop extra included errno.h
-rw-r--r--arch/arm/mach-exynos/include/mach/dwmmc.h6
-rw-r--r--common/spl/spl_mmc.c1
-rw-r--r--drivers/mmc/dw_mmc.c6
-rw-r--r--drivers/mmc/exynos_dw_mmc.c78
-rw-r--r--include/dwmmc.h3
5 files changed, 65 insertions, 29 deletions
diff --git a/arch/arm/mach-exynos/include/mach/dwmmc.h b/arch/arm/mach-exynos/include/mach/dwmmc.h
index 75d84988b7d..4432deedef7 100644
--- a/arch/arm/mach-exynos/include/mach/dwmmc.h
+++ b/arch/arm/mach-exynos/include/mach/dwmmc.h
@@ -17,10 +17,16 @@
/* Protector Register */
#define DWMCI_EMMCP_BASE 0x1000
+#define EMMCP_MPSECURITY (DWMCI_EMMCP_BASE + 0x0010)
#define EMMCP_MPSBEGIN0 (DWMCI_EMMCP_BASE + 0x0200)
#define EMMCP_SEND0 (DWMCI_EMMCP_BASE + 0x0204)
#define EMMCP_CTRL0 (DWMCI_EMMCP_BASE + 0x020c)
+/* EMMCP_MPSECURITY bits */
+#define MPSECURITY_FMP_ON BIT(29)
+#define MPSECURITY_MMC_SFR_PROT_ON BIT(28)
+
+/* EMMCP_CTRL0 bits */
#define MPSCTRL_SECURE_READ_BIT BIT(7)
#define MPSCTRL_SECURE_WRITE_BIT BIT(6)
#define MPSCTRL_NON_SECURE_READ_BIT BIT(5)
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 0a00d295575..d8ce3a84614 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -12,7 +12,6 @@
#include <spl_load.h>
#include <linux/compiler.h>
#include <errno.h>
-#include <errno.h>
#include <mmc.h>
#include <image.h>
#include <imx_container.h>
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index f3c0cc5cd8e..d9c05b223d5 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -490,8 +490,8 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd,
}
#ifdef CONFIG_DM_MMC
-int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data)
+static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
#else
@@ -597,7 +597,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
}
#ifdef CONFIG_DM_MMC
-int dwmci_set_ios(struct udevice *dev)
+static int dwmci_set_ios(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
#else
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index b230e9dbbf8..7ccd113bd79 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -26,12 +26,25 @@
#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
/* CLKSEL register defines */
-#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
-#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) |\
+#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
+#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) | \
CLKSEL_CCLK_SAMPLE(y))
-/* Quirks */
+/**
+ * DOC: Quirk flags for different Exynos DW MMC blocks
+ *
+ * %DWMCI_QUIRK_DISABLE_SMU: DW MMC block has Security Management Unit (SMU)
+ * which has to be configured in non-encryption mode during driver's init.
+ *
+ * %DWMCI_QUIRK_DISABLE_FMP: DW MMC block has Flash Memory Protector (FMP) which
+ * has to be disabled during driver's init. This flag disables FMP encryption
+ * and lets external non-secure main CPUs access the SFR (peripheral memory
+ * region, i.e. registers) in MMC core. Although it's usually done by early
+ * bootloaders (before U-Boot), in some cases like during USB boot the FMP might
+ * be left unconfigured.
+ */
#define DWMCI_QUIRK_DISABLE_SMU BIT(0)
+#define DWMCI_QUIRK_DISABLE_FMP BIT(1)
#ifdef CONFIG_DM_MMC
#include <dm.h>
@@ -183,9 +196,11 @@ static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
int err;
/* Should be double rate for DDR or HS mode */
- if ((host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8) ||
- host->mmc->selected_mode == MMC_HS_400)
+ if ((host->mmc->selected_mode == MMC_DDR_52 &&
+ host->mmc->bus_width == 8) ||
+ host->mmc->selected_mode == MMC_HS_400) {
freq *= 2;
+ }
clk_div = exynos_dwmmc_get_ciu_div(host);
err = exynos_dwmmc_set_sclk(host, freq * clk_div);
@@ -218,6 +233,18 @@ static void exynos_dwmci_board_init(struct dwmci_host *host)
MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID);
}
+ if (priv->chip->quirks & DWMCI_QUIRK_DISABLE_FMP) {
+ u32 reg;
+
+ reg = dwmci_readl(host, EMMCP_MPSECURITY);
+ if (reg & MPSECURITY_FMP_ON ||
+ reg & MPSECURITY_MMC_SFR_PROT_ON) {
+ reg &= ~MPSECURITY_FMP_ON;
+ reg &= ~MPSECURITY_MMC_SFR_PROT_ON;
+ dwmci_writel(host, EMMCP_MPSECURITY, reg);
+ }
+ }
+
if (priv->sdr_timing)
exynos_dwmci_clksel(host);
}
@@ -302,7 +329,7 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev)
#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
static int exynos_dwmmc_get_best_clksmpl(u8 candidates)
{
- u8 i;
+ int i;
for (i = 0; i < 8; i++) {
candidates = (candidates >> 1) | (candidates << 7); /* ror */
@@ -317,8 +344,8 @@ static int exynos_dwmmc_get_best_clksmpl(u8 candidates)
}
/*
- * If no valid clock sample values are found, use the first
- * canditate bit for clock sample value.
+ * If no valid clock sample values are found, use the first candidate
+ * bit for clock sample value.
*/
for (i = 0; i < 8; i++) {
candidates = (candidates >> 1) | (candidates << 7); /* ror */
@@ -344,7 +371,7 @@ static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode)
do {
dwmci_writel(host, DWMCI_TMOUT, ~0);
- /* move to the next clksmpl */
+ /* Move to the next clksmpl */
smpl = (clksel + 1) & 0x7;
clksel = CLKSEL_UP_SAMPLE(clksel, smpl);
dwmci_writel(host, priv->chip->clksel, clksel);
@@ -360,12 +387,13 @@ static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode)
return ret;
}
- dwmci_writel(host, priv->chip->clksel,
- CLKSEL_UP_SAMPLE(clksel, ret));
+ dwmci_writel(host, priv->chip->clksel, CLKSEL_UP_SAMPLE(clksel, ret));
return 0;
}
-#endif
+#endif /* CONFIG_MMC_SUPPORTS_TUNING */
+
+struct dm_mmc_ops exynos_dwmmc_ops;
static int exynos_dwmmc_probe(struct udevice *dev)
{
@@ -376,6 +404,12 @@ static int exynos_dwmmc_probe(struct udevice *dev)
unsigned long freq;
int err;
+ /* Extend generic 'dm_dwmci_ops' with .execute_tuning implementation */
+ memcpy(&exynos_dwmmc_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops));
+#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
+ exynos_dwmmc_ops.execute_tuning = exynos_dwmmc_execute_tuning;
+#endif
+
#ifndef CONFIG_CPU_V7A
err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */
if (err)
@@ -388,7 +422,7 @@ static int exynos_dwmmc_probe(struct udevice *dev)
flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
err = exynos_pinmux_config(host->dev_id, flag);
if (err) {
- printf("DWMMC%d not configure\n", host->dev_index);
+ printf("DWMMC%d not configured\n", host->dev_index);
return err;
}
#endif
@@ -454,6 +488,11 @@ static const struct exynos_dwmmc_variant exynos7_smu_drv_data = {
.quirks = DWMCI_QUIRK_DISABLE_SMU,
};
+static const struct exynos_dwmmc_variant exynos850_drv_data = {
+ .clksel = DWMCI_CLKSEL64,
+ .quirks = DWMCI_QUIRK_DISABLE_SMU | DWMCI_QUIRK_DISABLE_FMP,
+};
+
static const struct udevice_id exynos_dwmmc_ids[] = {
{
.compatible = "samsung,exynos4412-dw-mshc",
@@ -476,18 +515,13 @@ static const struct udevice_id exynos_dwmmc_ids[] = {
}, {
.compatible = "samsung,exynos7870-dw-mshc-smu",
.data = (ulong)&exynos7_smu_drv_data,
+ }, {
+ .compatible = "samsung,exynos850-dw-mshc-smu",
+ .data = (ulong)&exynos850_drv_data,
},
{ }
};
-struct dm_mmc_ops exynos_dwmmc_ops = {
- .send_cmd = dwmci_send_cmd,
- .set_ios = dwmci_set_ios,
-#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
- .execute_tuning = exynos_dwmmc_execute_tuning,
-#endif
-};
-
U_BOOT_DRIVER(exynos_dwmmc_drv) = {
.name = "exynos_dwmmc",
.id = UCLASS_MMC,
@@ -499,4 +533,4 @@ U_BOOT_DRIVER(exynos_dwmmc_drv) = {
.priv_auto = sizeof(struct dwmci_exynos_priv_data),
.plat_auto = sizeof(struct exynos_mmc_plat),
};
-#endif
+#endif /* CONFIG_DM_MMC */
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 47e3220985e..7e1a6646518 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -338,9 +338,6 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk);
#ifdef CONFIG_DM_MMC
/* Export the operations to drivers */
int dwmci_probe(struct udevice *dev);
-int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data);
-int dwmci_set_ios(struct udevice *dev);
extern const struct dm_mmc_ops dm_dwmci_ops;
#endif