From a9f7be509af90fa5f2c308867ad3b0bd48532c6e Mon Sep 17 00:00:00 2001 From: litchipi Date: Tue, 15 Jun 2021 08:53:06 +0000 Subject: mmc: rpmb: Fix driver routing memory alignment with tmp buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix mmc_rpmb_route_frames() implementation to comply with most MMC drivers that expect some alignment of MMC data frames in memory. When called from drivers/tee/optee/rpmb.c, the address passed is not aligned properly. OP-TEE OS inserts a 6-byte header before a raw RPMB frame which makes RPMB data buffer not 32bit aligned. To prevent breaking ABI with OPTEE-OS RPC memrefs, allocate a temporary buffer to copy the data into an aligned memory. Many RPMB drivers implicitly expect 32bit alignment of the eMMC frame including arm_pl180_mmci.c, sandbox_mmc.c and stm32_sdmmc2.c Signed-off-by: Timothée Cercueil Signed-off-by: Timothée Cercueil Reviewed-by: Jaehoon Chung --- drivers/mmc/rpmb.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index ea7e506666b..b68d98573c9 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -480,10 +480,24 @@ int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen, * and possibly just delay an eventual error which will be harder * to track down. */ + void *rpmb_data = NULL; + int ret; if (reqlen % sizeof(struct s_rpmb) || rsplen % sizeof(struct s_rpmb)) return -EINVAL; - return rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb), - rsp, rsplen / sizeof(struct s_rpmb)); + if (!IS_ALIGNED((uintptr_t)req, ARCH_DMA_MINALIGN)) { + /* Memory alignment is required by MMC driver */ + rpmb_data = malloc(reqlen); + if (!rpmb_data) + return -ENOMEM; + + memcpy(rpmb_data, req, reqlen); + req = rpmb_data; + } + + ret = rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb), + rsp, rsplen / sizeof(struct s_rpmb)); + free(rpmb_data); + return ret; } -- cgit From 936e9cd39260559b6c3f931038fe3f2173e43605 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 6 Jul 2021 16:54:33 +0200 Subject: mmc: arm_pl180_mmci: Don't bind to all arm, primecell devices The arm,primecell compatible is used for lots of different types of devices, e.g. I2C, SPI, coresight, ... We really should not bind the MMC driver to all of them. Looking through the device trees in U-Boot there seems to be always a second compatible string for the pl180 device, either arm,pl180 (already listed) or arm,pl18x. Add the "arm,pl18x" compatible to the list but remove the generic "arm,primecell". Note that on Linux these compatibles cannot be found in drivers because AMBA/primecell devices are matched based on their peripheral ID instead of the compatible. This fixes the following error messages when booting the ST-Ericsson U8500 "stemmy" board with the arm_pl180_mmci driver enabled: MMC: ptm@801ae000 - probe failed: -38 ptm@801af000 - probe failed: -38 funnel@801a6000 - probe failed: -38 tpiu@80190000 - probe failed: -38 etb@801a4000 - probe failed: -38 Cc: Patrice Chotard Fixes: 6f41d1a17e20 ("mmc: arm_pl180_mmci: Sync compatible with kernel") Signed-off-by: Stephan Gerhold Reviewed-by: Patrice Chotard Tested-by: Patrice Chotard on stm32f769-disco Reviewed-by: Jaehoon Chung --- drivers/mmc/arm_pl180_mmci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index b2d1b4f9aa9..5d1ee64356e 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -539,7 +539,7 @@ static int arm_pl180_mmc_of_to_plat(struct udevice *dev) static const struct udevice_id arm_pl180_mmc_match[] = { { .compatible = "arm,pl180" }, - { .compatible = "arm,primecell" }, + { .compatible = "arm,pl18x" }, { /* sentinel */ } }; -- cgit From 19e1da0c66454bd6206a4badfdc0077d7fd76aed Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 6 Jul 2021 16:54:34 +0200 Subject: mmc: arm_pl180_mmci: Simplify code using dev_read_addr_ptr() Simplify the code a bit by using dev_read_addr_ptr() instead of dev_read_addr(). This avoids having to cast explicitly to void*. Signed-off-by: Stephan Gerhold Reviewed-by: Patrice Chotard Tested-by: Patrice Chotard on stm32f769-disco Reviewed-by: Jaehoon Chung --- drivers/mmc/arm_pl180_mmci.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 5d1ee64356e..e632eed03fa 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -526,14 +526,11 @@ static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = { static int arm_pl180_mmc_of_to_plat(struct udevice *dev) { struct pl180_mmc_host *host = dev_get_priv(dev); - fdt_addr_t addr; - addr = dev_read_addr(dev); - if (addr == FDT_ADDR_T_NONE) + host->base = dev_read_addr_ptr(dev); + if (!host->base) return -EINVAL; - host->base = (void *)addr; - return 0; } -- cgit From 4daf2ec357c1c22ec0dc8db206add877f6632bc8 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 6 Jul 2021 16:54:35 +0200 Subject: mmc: arm_pl180_mmci: Simplify code using mmc_of_parse() Simplify the code a bit by using the common mmc_of_parse() function instead of duplicating the device tree parsing code. We can still get a default value for cfg->f_max by assigning it before calling mmc_of_parse(). Another advantage of this refactoring is that we parse more properties now, e.g. "non-removable" can be used to disable CD entirely. Signed-off-by: Stephan Gerhold Reviewed-by: Patrice Chotard Tested-by: Patrice Chotard on stm32f769-disco Reviewed-by: Jaehoon Chung --- drivers/mmc/arm_pl180_mmci.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index e632eed03fa..809b86570af 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -424,7 +424,6 @@ static int arm_pl180_mmc_probe(struct udevice *dev) struct pl180_mmc_host *host = dev_get_priv(dev); struct mmc_config *cfg = &pdata->cfg; struct clk clk; - u32 bus_width; u32 periphid; int ret; @@ -457,24 +456,14 @@ static int arm_pl180_mmc_probe(struct udevice *dev) cfg->voltages = VOLTAGE_WINDOW_SD; cfg->host_caps = 0; cfg->f_min = host->clock_in / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); - cfg->f_max = dev_read_u32_default(dev, "max-frequency", MMC_CLOCK_MAX); + cfg->f_max = MMC_CLOCK_MAX; cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN); - bus_width = dev_read_u32_default(dev, "bus-width", 1); - switch (bus_width) { - case 8: - cfg->host_caps |= MMC_MODE_8BIT; - /* Hosts capable of 8-bit transfers can also do 4 bits */ - case 4: - cfg->host_caps |= MMC_MODE_4BIT; - break; - case 1: - break; - default: - dev_err(dev, "Invalid bus-width value %u\n", bus_width); - } + ret = mmc_of_parse(dev, cfg); + if (ret) + return ret; arm_pl180_mmc_init(host); mmc->priv = host; -- cgit From d890f23406c00e3af5c63d76a9991e2e79d84096 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 6 Jul 2021 16:54:36 +0200 Subject: mmc: arm_pl180_mmci: Add configuration for ST-Ericsson Ux500v2 For the eMMC on ST-Ericsson Ux500v2 we need slightly different configuration values. Use the existing switch statement to match the peripheral ID of Ux500v2 (0x10480180) and override the necessary values to make the eMMC work on devices with ST-Ericsson Ux500. Cc: Linus Walleij Signed-off-by: Stephan Gerhold Reviewed-by: Patrice Chotard Tested-by: Patrice Chotard on stm32f769-disco Reviewed-by: Jaehoon Chung --- drivers/mmc/arm_pl180_mmci.c | 22 +++++++++++++++------- drivers/mmc/arm_pl180_mmci.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 809b86570af..f99b5f997e2 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -443,22 +443,30 @@ static int arm_pl180_mmc_probe(struct udevice *dev) SDI_CLKCR_HWFC_EN; host->clock_in = clk_get_rate(&clk); + cfg->name = dev->name; + cfg->voltages = VOLTAGE_WINDOW_SD; + cfg->host_caps = 0; + cfg->f_min = host->clock_in / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); + cfg->f_max = MMC_CLOCK_MAX; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + periphid = dev_read_u32_default(dev, "arm,primecell-periphid", 0); switch (periphid) { case STM32_MMCI_ID: /* stm32 variant */ host->version2 = false; break; + case UX500V2_MMCI_ID: + host->pwr_init = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | SDI_CLKCR_CLKEN | + SDI_CLKCR_HWFC_EN; + cfg->voltages = VOLTAGE_WINDOW_MMC; + cfg->f_min = host->clock_in / (2 + SDI_CLKCR_CLKDIV_INIT_V2); + host->version2 = true; + break; default: host->version2 = true; } - cfg->name = dev->name; - cfg->voltages = VOLTAGE_WINDOW_SD; - cfg->host_caps = 0; - cfg->f_min = host->clock_in / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); - cfg->f_max = MMC_CLOCK_MAX; - cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN); ret = mmc_of_parse(dev, cfg); diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 61ee96a112d..15c29beadbc 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -142,6 +142,7 @@ #define SDI_FIFO_BURST_SIZE 8 #define STM32_MMCI_ID 0x00880180 +#define UX500V2_MMCI_ID 0x10480180 struct sdi_registers { u32 power; /* 0x00*/ -- cgit