[U-Boot] [PATCH 0/5] Extend ARM_PL180_MMCI

From: Patrice Chotard patrice.chotard@st.com
Currently this driver is used by VEXPRESS platform which doesn't support Driver Model. ARM_PL180_MMCI IP is embedded on STM32F4 and F7 platforms. In order to add SD support on these 2 STM32 family SoCs, the following reworks are needed: _ update arm_pl180_mmci_init() prototype to make this driver working with DM and none DM platforms _ addapt driver to driver model _ add bus_width device tree support _ add clock support _ add .get_cd callback support
This series has been tested internally on both STM32F4 and STM32F7 SoCs family. Future SD support for these 2 platforms will be added soon.
Patrice Chotard (5): mmc: arm_pl180_mmci: update arm_pl180_mmci_init() prototype mmc: arm_pl180_mmci: adapt driver to DM usage mmc: arm_pl180_mmci: add bus_width DT property support mmc: arm_pl180_mmci: add clock support mmc: arm_pl180_mmci: add .getcd callback
board/armltd/vexpress/vexpress_common.c | 3 +- drivers/mmc/Kconfig | 9 ++ drivers/mmc/arm_pl180_mmci.c | 184 +++++++++++++++++++++++++++++--- drivers/mmc/arm_pl180_mmci.h | 9 +- 4 files changed, 186 insertions(+), 19 deletions(-)

From: Patrice Chotard patrice.chotard@st.com
Update arm_pl180_mmci_init() prototype by adding struct mmc** param. This is needed before converting this driver to driver model in order to use arm_pl180_mmci_init() in driver model and in none driver model implementation
Signed-off-by: Patrice Chotard patrice.chotard@st.com --- board/armltd/vexpress/vexpress_common.c | 3 ++- drivers/mmc/arm_pl180_mmci.c | 10 +++++----- drivers/mmc/arm_pl180_mmci.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/board/armltd/vexpress/vexpress_common.c b/board/armltd/vexpress/vexpress_common.c index 89ab8f7..37b8d7f 100644 --- a/board/armltd/vexpress/vexpress_common.c +++ b/board/armltd/vexpress/vexpress_common.c @@ -76,6 +76,7 @@ int cpu_mmc_init(bd_t *bis) (void) bis; #ifdef CONFIG_ARM_PL180_MMCI struct pl180_mmc_host *host; + struct mmc *mmc;
host = malloc(sizeof(struct pl180_mmc_host)); if (!host) @@ -91,7 +92,7 @@ int cpu_mmc_init(bd_t *bis) host->clock_in = ARM_MCLK; host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; - rc = arm_pl180_mmci_init(host); + rc = arm_pl180_mmci_init(host, &mmc); #endif return rc; } diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index ddf8383..7898b0d 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -348,9 +348,8 @@ static const struct mmc_ops arm_pl180_mmci_ops = { * Set initial clock and power for mmc slot. * Initialize mmc struct and register with mmc framework. */ -int arm_pl180_mmci_init(struct pl180_mmc_host *host) +int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc) { - struct mmc *mmc; u32 sdi_u32;
writel(host->pwr_init, &host->base->power); @@ -373,11 +372,12 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host) else host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
- mmc = mmc_create(&host->cfg, host); - if (mmc == NULL) + *mmc = mmc_create(&host->cfg, host); + if (!*mmc) return -1;
- debug("registered mmc interface number is:%d\n", mmc->block_dev.devnum); + debug("registered mmc interface number is:%d\n", + (*mmc)->block_dev.devnum);
return 0; } diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index f23bd39..6e232f7 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -190,6 +190,6 @@ struct pl180_mmc_host { struct mmc_config cfg; };
-int arm_pl180_mmci_init(struct pl180_mmc_host *); +int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc);
#endif

From: Patrice Chotard patrice.chotard@st.com
Convert this driver to driver model. This driver is also used by VEXPRESS platforms which doesn't use driver model.
Tested on STM32F746 and STM32F769 platforms.
Signed-off-by: Christophe Priouzeau christophe.priouzeau@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com --- drivers/mmc/Kconfig | 9 ++++ drivers/mmc/arm_pl180_mmci.c | 125 ++++++++++++++++++++++++++++++++++++++----- drivers/mmc/arm_pl180_mmci.h | 3 ++ 3 files changed, 125 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 94050836..62ce0af 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -33,6 +33,15 @@ config SPL_DM_MMC
if MMC
+config ARM_PL180_MMCI + bool "ARM AMBA Multimedia Card Interface and compatible support" + depends on DM_MMC && OF_CONTROL + help + This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card + Interface (PL180, PL181 and compatible) support. + If you have an ARM(R) platform with a Multimedia Card slot, + say Y or M here. + config SPL_MMC_TINY bool "Tiny MMC framework in SPL" help diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 7898b0d..61dbbfb 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -12,12 +12,24 @@
/* #define DEBUG */
-#include <asm/io.h> #include "common.h" #include <errno.h> +#include <malloc.h> #include <mmc.h> + #include "arm_pl180_mmci.h" -#include <malloc.h> + +#include <asm/io.h> + +#ifdef CONFIG_DM_MMC +#include <dm.h> +DECLARE_GLOBAL_DATA_PTR; + +struct arm_pl180_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; +#endif
static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) { @@ -265,16 +277,6 @@ static int host_request(struct mmc *dev, return result; }
-/* MMC uses open drain drivers in the enumeration phase */ -static int mmc_host_reset(struct mmc *dev) -{ - struct pl180_mmc_host *host = dev->priv; - - writel(host->pwr_init, &host->base->power); - - return 0; -} - static int host_set_ios(struct mmc *dev) { struct pl180_mmc_host *host = dev->priv; @@ -337,11 +339,23 @@ static int host_set_ios(struct mmc *dev) return 0; }
+#ifndef CONFIG_DM_MMC +/* MMC uses open drain drivers in the enumeration phase */ +static int mmc_host_reset(struct mmc *dev) +{ + struct pl180_mmc_host *host = dev->priv; + + writel(host->pwr_init, &host->base->power); + + return 0; +} + static const struct mmc_ops arm_pl180_mmci_ops = { .send_cmd = host_request, .set_ios = host_set_ios, .init = mmc_host_reset, }; +#endif
/* * mmc_host_init - initialize the mmc controller. @@ -361,7 +375,9 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc) writel(sdi_u32, &host->base->mask0);
host->cfg.name = host->name; +#ifndef CONFIG_DM_MMC host->cfg.ops = &arm_pl180_mmci_ops; +#endif /* TODO remove the duplicates */ host->cfg.host_caps = host->caps; host->cfg.voltages = host->voltages; @@ -381,3 +397,88 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc)
return 0; } + +#ifdef CONFIG_DM_MMC +static int arm_pl180_mmc_probe(struct udevice *dev) +{ + struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct mmc *mmc = &pdata->mmc; + struct pl180_mmc_host *host = mmc->priv; + int ret; + + strcpy(host->name, "MMC"); + host->pwr_init = INIT_PWR; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN | + SDI_CLKCR_HWFC_EN; + host->voltages = VOLTAGE_WINDOW_SD; + host->caps = 0; + host->clock_in = 48000000; + host->clock_min = 400000; + host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000); + host->version2 = dev_get_driver_data(dev); + ret = arm_pl180_mmci_init(host, &mmc); + if (ret) { + dev_err(dev, "arm_pl180_mmci init failed\n"); + return ret; + } + + mmc->dev = dev; + dev->priv = host; + upriv->mmc = mmc; + + return 0; +} + +static int dm_host_request(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + + return host_request(mmc, cmd, data); +} + +static int dm_host_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + + return host_set_ios(mmc); +} + +static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = { + .send_cmd = dm_host_request, + .set_ios = dm_host_set_ios, +}; + +static int arm_pl180_mmc_ofdata_to_platdata(struct udevice *dev) +{ + struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev); + struct mmc *mmc = &pdata->mmc; + struct pl180_mmc_host *host = mmc->priv; + fdt_addr_t addr; + + addr = devfdt_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + host->base = (void *)addr; + + return 0; +} + +static const struct udevice_id arm_pl180_mmc_match[] = { + { .compatible = "st,stm32f4xx-sdio", .data = VERSION1 }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(arm_pl180_mmc) = { + .name = "arm_pl180_mmc", + .id = UCLASS_MMC, + .of_match = arm_pl180_mmc_match, + .ops = &arm_pl180_dm_mmc_ops, + .probe = arm_pl180_mmc_probe, + .ofdata_to_platdata = arm_pl180_mmc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct pl180_mmc_host), + .platdata_auto_alloc_size = sizeof(struct arm_pl180_mmc_plat), +}; +#endif diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 6e232f7..b935288 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -142,6 +142,9 @@
#define SDI_FIFO_BURST_SIZE 8
+#define VERSION1 false +#define VERSION2 true + struct sdi_registers { u32 power; /* 0x00*/ u32 clock; /* 0x04*/

On 10/19/2017 11:45 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Convert this driver to driver model. This driver is also used by VEXPRESS platforms which doesn't use driver model.
Tested on STM32F746 and STM32F769 platforms.
Signed-off-by: Christophe Priouzeau christophe.priouzeau@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/mmc/Kconfig | 9 ++++ drivers/mmc/arm_pl180_mmci.c | 125 ++++++++++++++++++++++++++++++++++++++----- drivers/mmc/arm_pl180_mmci.h | 3 ++ 3 files changed, 125 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 94050836..62ce0af 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -33,6 +33,15 @@ config SPL_DM_MMC
if MMC
+config ARM_PL180_MMCI
- bool "ARM AMBA Multimedia Card Interface and compatible support"
- depends on DM_MMC && OF_CONTROL
- help
This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
Interface (PL180, PL181 and compatible) support.
If you have an ARM(R) platform with a Multimedia Card slot,
say Y or M here.
config SPL_MMC_TINY bool "Tiny MMC framework in SPL" help diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 7898b0d..61dbbfb 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -12,12 +12,24 @@
/* #define DEBUG */
-#include <asm/io.h> #include "common.h" #include <errno.h> +#include <malloc.h> #include <mmc.h>
#include "arm_pl180_mmci.h" -#include <malloc.h>
+#include <asm/io.h>
+#ifdef CONFIG_DM_MMC +#include <dm.h> +DECLARE_GLOBAL_DATA_PTR;
+struct arm_pl180_mmc_plat {
- struct mmc_config cfg;
- struct mmc mmc;
+}; +#endif
static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) { @@ -265,16 +277,6 @@ static int host_request(struct mmc *dev, return result; }
-/* MMC uses open drain drivers in the enumeration phase */ -static int mmc_host_reset(struct mmc *dev) -{
- struct pl180_mmc_host *host = dev->priv;
- writel(host->pwr_init, &host->base->power);
- return 0;
-}
static int host_set_ios(struct mmc *dev) { struct pl180_mmc_host *host = dev->priv; @@ -337,11 +339,23 @@ static int host_set_ios(struct mmc *dev) return 0; }
+#ifndef CONFIG_DM_MMC +/* MMC uses open drain drivers in the enumeration phase */ +static int mmc_host_reset(struct mmc *dev) +{
- struct pl180_mmc_host *host = dev->priv;
- writel(host->pwr_init, &host->base->power);
- return 0;
+}
static const struct mmc_ops arm_pl180_mmci_ops = { .send_cmd = host_request, .set_ios = host_set_ios, .init = mmc_host_reset, }; +#endif
/*
- mmc_host_init - initialize the mmc controller.
@@ -361,7 +375,9 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc) writel(sdi_u32, &host->base->mask0);
host->cfg.name = host->name; +#ifndef CONFIG_DM_MMC host->cfg.ops = &arm_pl180_mmci_ops; +#endif /* TODO remove the duplicates */ host->cfg.host_caps = host->caps; host->cfg.voltages = host->voltages; @@ -381,3 +397,88 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc)
return 0; }
+#ifdef CONFIG_DM_MMC +static int arm_pl180_mmc_probe(struct udevice *dev) +{
- struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct mmc *mmc = &pdata->mmc;
- struct pl180_mmc_host *host = mmc->priv;
- int ret;
- strcpy(host->name, "MMC");
- host->pwr_init = INIT_PWR;
- host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN |
SDI_CLKCR_HWFC_EN;
- host->voltages = VOLTAGE_WINDOW_SD;
- host->caps = 0;
- host->clock_in = 48000000;
Use the defined variable instead of 480000000.
- host->clock_min = 400000;
Ditto.
- host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000);
- host->version2 = dev_get_driver_data(dev);
- ret = arm_pl180_mmci_init(host, &mmc);
- if (ret) {
dev_err(dev, "arm_pl180_mmci init failed\n");
return ret;
- }
- mmc->dev = dev;
- dev->priv = host;
- upriv->mmc = mmc;
- return 0;
+}
+static int dm_host_request(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
+{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- return host_request(mmc, cmd, data);
+}
+static int dm_host_set_ios(struct udevice *dev) +{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- return host_set_ios(mmc);
+}
+static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = {
- .send_cmd = dm_host_request,
- .set_ios = dm_host_set_ios,
+};
+static int arm_pl180_mmc_ofdata_to_platdata(struct udevice *dev) +{
- struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev);
- struct mmc *mmc = &pdata->mmc;
- struct pl180_mmc_host *host = mmc->priv;
- fdt_addr_t addr;
- addr = devfdt_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- host->base = (void *)addr;
- return 0;
+}
+static const struct udevice_id arm_pl180_mmc_match[] = {
- { .compatible = "st,stm32f4xx-sdio", .data = VERSION1 },
- { /* sentinel */ }
+};
+U_BOOT_DRIVER(arm_pl180_mmc) = {
- .name = "arm_pl180_mmc",
- .id = UCLASS_MMC,
- .of_match = arm_pl180_mmc_match,
- .ops = &arm_pl180_dm_mmc_ops,
- .probe = arm_pl180_mmc_probe,
- .ofdata_to_platdata = arm_pl180_mmc_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct pl180_mmc_host),
- .platdata_auto_alloc_size = sizeof(struct arm_pl180_mmc_plat),
+}; +#endif diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 6e232f7..b935288 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -142,6 +142,9 @@
#define SDI_FIFO_BURST_SIZE 8
+#define VERSION1 false +#define VERSION2 true
Where do this use?
struct sdi_registers { u32 power; /* 0x00*/ u32 clock; /* 0x04*/

Hi Jaehoon
On 10/20/2017 03:44 PM, Jaehoon Chung wrote:
On 10/19/2017 11:45 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Convert this driver to driver model. This driver is also used by VEXPRESS platforms which doesn't use driver model.
Tested on STM32F746 and STM32F769 platforms.
Signed-off-by: Christophe Priouzeau christophe.priouzeau@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/mmc/Kconfig | 9 ++++ drivers/mmc/arm_pl180_mmci.c | 125 ++++++++++++++++++++++++++++++++++++++----- drivers/mmc/arm_pl180_mmci.h | 3 ++ 3 files changed, 125 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 94050836..62ce0af 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -33,6 +33,15 @@ config SPL_DM_MMC
if MMC
+config ARM_PL180_MMCI
- bool "ARM AMBA Multimedia Card Interface and compatible support"
- depends on DM_MMC && OF_CONTROL
- help
This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
Interface (PL180, PL181 and compatible) support.
If you have an ARM(R) platform with a Multimedia Card slot,
say Y or M here.
- config SPL_MMC_TINY bool "Tiny MMC framework in SPL" help
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 7898b0d..61dbbfb 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -12,12 +12,24 @@
/* #define DEBUG */
-#include <asm/io.h> #include "common.h" #include <errno.h> +#include <malloc.h> #include <mmc.h>
- #include "arm_pl180_mmci.h"
-#include <malloc.h>
+#include <asm/io.h>
+#ifdef CONFIG_DM_MMC +#include <dm.h> +DECLARE_GLOBAL_DATA_PTR;
+struct arm_pl180_mmc_plat {
- struct mmc_config cfg;
- struct mmc mmc;
+}; +#endif
static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) { @@ -265,16 +277,6 @@ static int host_request(struct mmc *dev, return result; }
-/* MMC uses open drain drivers in the enumeration phase */ -static int mmc_host_reset(struct mmc *dev) -{
- struct pl180_mmc_host *host = dev->priv;
- writel(host->pwr_init, &host->base->power);
- return 0;
-}
- static int host_set_ios(struct mmc *dev) { struct pl180_mmc_host *host = dev->priv;
@@ -337,11 +339,23 @@ static int host_set_ios(struct mmc *dev) return 0; }
+#ifndef CONFIG_DM_MMC +/* MMC uses open drain drivers in the enumeration phase */ +static int mmc_host_reset(struct mmc *dev) +{
- struct pl180_mmc_host *host = dev->priv;
- writel(host->pwr_init, &host->base->power);
- return 0;
+}
- static const struct mmc_ops arm_pl180_mmci_ops = { .send_cmd = host_request, .set_ios = host_set_ios, .init = mmc_host_reset, };
+#endif
/*
- mmc_host_init - initialize the mmc controller.
@@ -361,7 +375,9 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc) writel(sdi_u32, &host->base->mask0);
host->cfg.name = host->name; +#ifndef CONFIG_DM_MMC host->cfg.ops = &arm_pl180_mmci_ops; +#endif /* TODO remove the duplicates */ host->cfg.host_caps = host->caps; host->cfg.voltages = host->voltages; @@ -381,3 +397,88 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc)
return 0; }
+#ifdef CONFIG_DM_MMC +static int arm_pl180_mmc_probe(struct udevice *dev) +{
- struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct mmc *mmc = &pdata->mmc;
- struct pl180_mmc_host *host = mmc->priv;
- int ret;
- strcpy(host->name, "MMC");
- host->pwr_init = INIT_PWR;
- host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN |
SDI_CLKCR_HWFC_EN;
- host->voltages = VOLTAGE_WINDOW_SD;
- host->caps = 0;
- host->clock_in = 48000000;
Use the defined variable instead of 480000000.
OK
- host->clock_min = 400000;
Ditto.
OK
- host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000);
- host->version2 = dev_get_driver_data(dev);
- ret = arm_pl180_mmci_init(host, &mmc);
- if (ret) {
dev_err(dev, "arm_pl180_mmci init failed\n");
return ret;
- }
- mmc->dev = dev;
- dev->priv = host;
- upriv->mmc = mmc;
- return 0;
+}
+static int dm_host_request(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
+{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- return host_request(mmc, cmd, data);
+}
+static int dm_host_set_ios(struct udevice *dev) +{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- return host_set_ios(mmc);
+}
+static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = {
- .send_cmd = dm_host_request,
- .set_ios = dm_host_set_ios,
+};
+static int arm_pl180_mmc_ofdata_to_platdata(struct udevice *dev) +{
- struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev);
- struct mmc *mmc = &pdata->mmc;
- struct pl180_mmc_host *host = mmc->priv;
- fdt_addr_t addr;
- addr = devfdt_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- host->base = (void *)addr;
- return 0;
+}
+static const struct udevice_id arm_pl180_mmc_match[] = {
- { .compatible = "st,stm32f4xx-sdio", .data = VERSION1 },
- { /* sentinel */ }
+};
+U_BOOT_DRIVER(arm_pl180_mmc) = {
- .name = "arm_pl180_mmc",
- .id = UCLASS_MMC,
- .of_match = arm_pl180_mmc_match,
- .ops = &arm_pl180_dm_mmc_ops,
- .probe = arm_pl180_mmc_probe,
- .ofdata_to_platdata = arm_pl180_mmc_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct pl180_mmc_host),
- .platdata_auto_alloc_size = sizeof(struct arm_pl180_mmc_plat),
+}; +#endif diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 6e232f7..b935288 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -142,6 +142,9 @@
#define SDI_FIFO_BURST_SIZE 8
+#define VERSION1 false +#define VERSION2 true
Where do this use?
This defines are used to indicated which IP version is supported. In do_data_transfer(), depending on host->version2 value, blksz bits are not located at the same location inside data_ctrl registers.
Patrice
- struct sdi_registers { u32 power; /* 0x00*/ u32 clock; /* 0x04*/

From: Patrice Chotard patrice.chotard@st.com
Allow to get "bus-width" property from device tree
Signed-off-by: Patrice Chotard patrice.chotard@st.com --- drivers/mmc/arm_pl180_mmci.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 61dbbfb..6ee77b1 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -405,6 +405,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct mmc *mmc = &pdata->mmc; struct pl180_mmc_host *host = mmc->priv; + u32 bus_width; int ret;
strcpy(host->name, "MMC"); @@ -417,6 +418,22 @@ static int arm_pl180_mmc_probe(struct udevice *dev) host->clock_min = 400000; host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000); host->version2 = dev_get_driver_data(dev); + + bus_width = dev_read_u32_default(dev, "bus-width", 1); + switch (bus_width) { + case 8: + host->caps |= MMC_MODE_8BIT; + /* Hosts capable of 8-bit transfers can also do 4 bits */ + case 4: + host->caps |= MMC_MODE_4BIT; + break; + case 1: + break; + default: + dev_err(dev, "Invalid bus-width value %u\n", bus_width); + return -EINVAL; + } + ret = arm_pl180_mmci_init(host, &mmc); if (ret) { dev_err(dev, "arm_pl180_mmci init failed\n");

On 10/19/2017 11:46 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Allow to get "bus-width" property from device tree
Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/mmc/arm_pl180_mmci.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 61dbbfb..6ee77b1 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -405,6 +405,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct mmc *mmc = &pdata->mmc; struct pl180_mmc_host *host = mmc->priv;
u32 bus_width; int ret;
strcpy(host->name, "MMC");
@@ -417,6 +418,22 @@ static int arm_pl180_mmc_probe(struct udevice *dev) host->clock_min = 400000; host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000); host->version2 = dev_get_driver_data(dev);
- bus_width = dev_read_u32_default(dev, "bus-width", 1);
- switch (bus_width) {
- case 8:
host->caps |= MMC_MODE_8BIT;
/* Hosts capable of 8-bit transfers can also do 4 bits */
- case 4:
host->caps |= MMC_MODE_4BIT;
break;
- case 1:
break;
- default:
dev_err(dev, "Invalid bus-width value %u\n", bus_width);
Doesn't need to return -EINVAL..It can be run with 1bit BUSWIDTH. I think that it's enough to display the error message.
return -EINVAL;
- }
- ret = arm_pl180_mmci_init(host, &mmc); if (ret) { dev_err(dev, "arm_pl180_mmci init failed\n");

Hi Jaehoon
On 10/20/2017 03:44 PM, Jaehoon Chung wrote:
On 10/19/2017 11:46 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Allow to get "bus-width" property from device tree
Signed-off-by: Patrice Chotard patrice.chotard@st.com
drivers/mmc/arm_pl180_mmci.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 61dbbfb..6ee77b1 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -405,6 +405,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct mmc *mmc = &pdata->mmc; struct pl180_mmc_host *host = mmc->priv;
u32 bus_width; int ret;
strcpy(host->name, "MMC");
@@ -417,6 +418,22 @@ static int arm_pl180_mmc_probe(struct udevice *dev) host->clock_min = 400000; host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000); host->version2 = dev_get_driver_data(dev);
- bus_width = dev_read_u32_default(dev, "bus-width", 1);
- switch (bus_width) {
- case 8:
host->caps |= MMC_MODE_8BIT;
/* Hosts capable of 8-bit transfers can also do 4 bits */
- case 4:
host->caps |= MMC_MODE_4BIT;
break;
- case 1:
break;
- default:
dev_err(dev, "Invalid bus-width value %u\n", bus_width);
Doesn't need to return -EINVAL..It can be run with 1bit BUSWIDTH. I think that it's enough to display the error message.
Right, i will remove the return here.
Thanks Patrice
return -EINVAL;
- }
- ret = arm_pl180_mmci_init(host, &mmc); if (ret) { dev_err(dev, "arm_pl180_mmci init failed\n");

From: Patrice Chotard patrice.chotard@st.com
Allow to get and enable MMC related clock
Signed-off-by: Patrice Chotard patrice.chotard@st.com --- drivers/mmc/arm_pl180_mmci.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 6ee77b1..f060c64 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -13,6 +13,7 @@ /* #define DEBUG */
#include "common.h" +#include <clk.h> #include <errno.h> #include <malloc.h> #include <mmc.h> @@ -405,17 +406,28 @@ static int arm_pl180_mmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct mmc *mmc = &pdata->mmc; struct pl180_mmc_host *host = mmc->priv; + struct clk clk; u32 bus_width; int ret;
+ ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + strcpy(host->name, "MMC"); host->pwr_init = INIT_PWR; host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN; host->voltages = VOLTAGE_WINDOW_SD; host->caps = 0; - host->clock_in = 48000000; - host->clock_min = 400000; + host->clock_in = clk_get_rate(&clk); + host->clock_min = host->clock_in / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000); host->version2 = dev_get_driver_data(dev);

From: Patrice Chotard patrice.chotard@st.com
Add .getcd callback to check is MMC card is present
Signed-off-by: Patrice Chotard patrice.chotard@st.com --- drivers/mmc/arm_pl180_mmci.c | 24 ++++++++++++++++++++++-- drivers/mmc/arm_pl180_mmci.h | 4 ++++ 2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index f060c64..a827a1e 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -18,9 +18,10 @@ #include <malloc.h> #include <mmc.h>
-#include "arm_pl180_mmci.h" - #include <asm/io.h> +#include <asm-generic/gpio.h> + +#include "arm_pl180_mmci.h"
#ifdef CONFIG_DM_MMC #include <dm.h> @@ -431,6 +432,8 @@ static int arm_pl180_mmc_probe(struct udevice *dev) host->clock_max = dev_read_u32_default(dev, "max-frequency", 48000000); host->version2 = dev_get_driver_data(dev);
+ 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: @@ -474,9 +477,26 @@ static int dm_host_set_ios(struct udevice *dev) return host_set_ios(mmc); }
+static int dm_mmc_getcd(struct udevice *dev) +{ + struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev); + struct mmc *mmc = &pdata->mmc; + struct pl180_mmc_host *host = mmc->priv; + int value = 1; + + if (dm_gpio_is_valid(&host->cd_gpio)) { + value = dm_gpio_get_value(&host->cd_gpio); + if (host->cd_inverted) + return !value; + } + + return value; +} + static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = { .send_cmd = dm_host_request, .set_ios = dm_host_set_ios, + .get_cd = dm_mmc_getcd, };
static int arm_pl180_mmc_ofdata_to_platdata(struct udevice *dev) diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index b935288..9df4b75 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -191,6 +191,10 @@ struct pl180_mmc_host { unsigned int pwr_init; int version2; struct mmc_config cfg; +#ifdef CONFIG_DM_MMC + struct gpio_desc cd_gpio; + bool cd_inverted; +#endif };
int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc);
participants (3)
-
Jaehoon Chung
-
Patrice CHOTARD
-
patrice.chotard@st.com