diff mbox series

[U-Boot,2/5] mmc: arm_pl180_mmci: adapt driver to DM usage

Message ID 1508424362-19649-3-git-send-email-patrice.chotard@st.com
State Superseded
Delegated to: Tom Rini
Headers show
Series Extend ARM_PL180_MMCI | expand

Commit Message

Patrice CHOTARD Oct. 19, 2017, 2:45 p.m. UTC
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(-)

Comments

Jaehoon Chung Oct. 20, 2017, 1:44 p.m. UTC | #1
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*/
>
Patrice CHOTARD Oct. 23, 2017, 8:08 a.m. UTC | #2
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*/

>>

>
diff mbox series

Patch

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*/