[U-Boot] [PATCH 0/8] dm: mmc: Tidy up handling of block devices

The current MMC block device support has a few deficiencies which show up when both CONFIG_BLK and CONFIG_DM_MMC_OPS are defined:
- Block device numbering does not always following MMC device numbering - Environment in MMC does not always work correctly
In addition some parts of the code can be implemented in a better way.
This series fixes the above problems, adds a few tests and converts Tegra over to use CONFIG_BLK and CONFIG_DM_MMC_OPS.
Simon Glass (8): dm: mmc: Don't re-init when accessing environment dm: blk: Allow finding block devices without probing dm: blk: Add a function to find the next block device number dm: blk: Improve block device claiming dm: mmc: Avoid probing block devices in find_mmc_device() dm: mmc: Check that drivers have operations dm: mmc: Rewrite mmc_blk_probe() tegra: Convert MMC to use driver model for operations
arch/sandbox/dts/test.dts | 12 +++++- board/toradex/common/tdx-cfg-block.c | 2 +- common/env_mmc.c | 3 +- configs/apalis-tk1_defconfig | 2 - configs/apalis_t30_defconfig | 2 - configs/beaver_defconfig | 2 - configs/cardhu_defconfig | 2 - configs/cei-tk1-som_defconfig | 2 - configs/colibri_t20_defconfig | 2 - configs/colibri_t30_defconfig | 2 - configs/dalmore_defconfig | 2 - configs/e2220-1170_defconfig | 2 - configs/harmony_defconfig | 2 - configs/jetson-tk1_defconfig | 2 - configs/medcom-wide_defconfig | 2 - configs/nyan-big_defconfig | 2 - configs/p2371-0000_defconfig | 2 - configs/p2371-2180_defconfig | 2 - configs/p2571_defconfig | 2 - configs/p2771-0000-000_defconfig | 2 - configs/p2771-0000-500_defconfig | 2 - configs/paz00_defconfig | 2 - configs/plutux_defconfig | 2 - configs/seaboard_defconfig | 2 - configs/tec-ng_defconfig | 2 - configs/tec_defconfig | 2 - configs/trimslice_defconfig | 2 - configs/venice2_defconfig | 2 - configs/ventana_defconfig | 2 - configs/whistler_defconfig | 2 - drivers/block/blk-uclass.c | 65 ++++++++++++++++++++++++++++---- drivers/mmc/mmc-uclass.c | 27 ++++++++++---- drivers/mmc/tegra_mmc.c | 72 ++++++++++++++++++++---------------- include/blk.h | 15 +++++++- test/dm/blk.c | 60 +++++++++++++++++++++++++++++- 35 files changed, 203 insertions(+), 107 deletions(-)

With driver model MMC is probed automatically when needed. We should not re-init MMC each time.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/env_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/env_mmc.c b/common/env_mmc.c index a5d14d448c..1611886e22 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -98,9 +98,10 @@ static const char *init_mmc_for_env(struct mmc *mmc) if (!mmc) return "!No MMC card found";
+#ifndef CONFIG_BLK if (mmc_init(mmc)) return "!MMC init failed"; - +#endif if (mmc_set_env_part(mmc)) return "!MMC partition switch failed";

Hi Simon,
On 24/04/2017 04:02, Simon Glass wrote:
With driver model MMC is probed automatically when needed. We should not re-init MMC each time.
Signed-off-by: Simon Glass sjg@chromium.org
common/env_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/env_mmc.c b/common/env_mmc.c index a5d14d448c..1611886e22 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -98,9 +98,10 @@ static const char *init_mmc_for_env(struct mmc *mmc) if (!mmc) return "!No MMC card found";
+#ifndef CONFIG_BLK if (mmc_init(mmc)) return "!MMC init failed";
+#endif
I'm not convinced by this. mmc_init() is the starting point of the MMC device initialization process and it must be called somehow before accessing the device and most probe() functions do not call mmc_init(). The sandbox driver does it, but I'm not sure it's the right way because the MMC device initialization process takes a long time. I'd rather have the device initialized only when it's accessed for the first time not when it's probed (especially in the SPL)
Jean-Jacques
if (mmc_set_env_part(mmc)) return "!MMC partition switch failed";

Hi Jean-Jacques,
On 24 April 2017 at 02:55, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
Hi Simon,
On 24/04/2017 04:02, Simon Glass wrote:
With driver model MMC is probed automatically when needed. We should not re-init MMC each time.
Signed-off-by: Simon Glass sjg@chromium.org
common/env_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/env_mmc.c b/common/env_mmc.c index a5d14d448c..1611886e22 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -98,9 +98,10 @@ static const char *init_mmc_for_env(struct mmc *mmc) if (!mmc) return "!No MMC card found"; +#ifndef CONFIG_BLK if (mmc_init(mmc)) return "!MMC init failed";
+#endif
I'm not convinced by this. mmc_init() is the starting point of the MMC device initialization process and it must be called somehow before accessing the device and most probe() functions do not call mmc_init(). The sandbox driver does it, but I'm not sure it's the right way because the MMC device initialization process takes a long time. I'd rather have the device initialized only when it's accessed for the first time not when it's probed (especially in the SPL)
Yes I would like that too.
One option is to add an init() method to mmc and call that when the block device is probed.
Jean-Jacques
if (mmc_set_env_part(mmc)) return "!MMC partition switch failed";
Regards, Simon

Hi,
On 28 April 2017 at 18:27, Simon Glass sjg@chromium.org wrote:
Hi Jean-Jacques,
On 24 April 2017 at 02:55, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
Hi Simon,
On 24/04/2017 04:02, Simon Glass wrote:
With driver model MMC is probed automatically when needed. We should not re-init MMC each time.
Signed-off-by: Simon Glass sjg@chromium.org
common/env_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/env_mmc.c b/common/env_mmc.c index a5d14d448c..1611886e22 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -98,9 +98,10 @@ static const char *init_mmc_for_env(struct mmc *mmc) if (!mmc) return "!No MMC card found"; +#ifndef CONFIG_BLK if (mmc_init(mmc)) return "!MMC init failed";
+#endif
I'm not convinced by this. mmc_init() is the starting point of the MMC device initialization process and it must be called somehow before accessing the device and most probe() functions do not call mmc_init(). The sandbox driver does it, but I'm not sure it's the right way because the MMC device initialization process takes a long time. I'd rather have the device initialized only when it's accessed for the first time not when it's probed (especially in the SPL)
Yes I would like that too.
One option is to add an init() method to mmc and call that when the block device is probed.
Do you think that would work? I can try it out in the next version perhaps.
Then we have:
mmc device probe - very fast, just sets up clocks, etc. blk device probe - slow, tries to read card, partition table, etc.
Jean-Jacques
if (mmc_set_env_part(mmc)) return "!MMC partition switch failed";
Regards, Simon

Hi Simon,
On 03/05/2017 04:35, Simon Glass wrote:
Hi,
On 28 April 2017 at 18:27, Simon Glass sjg@chromium.org wrote:
Hi Jean-Jacques,
On 24 April 2017 at 02:55, Jean-Jacques Hiblot jjhiblot@ti.com wrote:
Hi Simon,
On 24/04/2017 04:02, Simon Glass wrote:
With driver model MMC is probed automatically when needed. We should not re-init MMC each time.
Signed-off-by: Simon Glass sjg@chromium.org
common/env_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/env_mmc.c b/common/env_mmc.c index a5d14d448c..1611886e22 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -98,9 +98,10 @@ static const char *init_mmc_for_env(struct mmc *mmc) if (!mmc) return "!No MMC card found"; +#ifndef CONFIG_BLK if (mmc_init(mmc)) return "!MMC init failed";
+#endif
I'm not convinced by this. mmc_init() is the starting point of the MMC device initialization process and it must be called somehow before accessing the device and most probe() functions do not call mmc_init(). The sandbox driver does it, but I'm not sure it's the right way because the MMC device initialization process takes a long time. I'd rather have the device initialized only when it's accessed for the first time not when it's probed (especially in the SPL)
Yes I would like that too.
One option is to add an init() method to mmc and call that when the block device is probed.
I've just discovered that in mmc_init() is now called from the 'blk' probe of the mc device (it wasn't on the code base I had been looking at). So it should be fine to remove the call to mmc_init() from init_mmc_for_env(). I did the test on DRA7 and it's working. So you can ignore my previous comment.
However I tried to go further by removing it from spl_mmc.c as well because mmc_init() is called from there first and then I ran into problems with the detection of the partitions. I don't really have time to look at it right now. It may be related to the fact that my env is not located on the boot device.
Jean-Jacques
Do you think that would work? I can try it out in the next version perhaps.
Then we have:
mmc device probe - very fast, just sets up clocks, etc. blk device probe - slow, tries to read card, partition table, etc.
Jean-Jacques
if (mmc_set_env_part(mmc)) return "!MMC partition switch failed";
Regards, Simon

Sometimes it is useful to be able to find a block device without also probing it. Add a function for this as well as the associated test.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 15 +++++++++++++-- include/blk.h | 15 ++++++++++++++- test/dm/blk.c | 21 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index af3c35f6d0..8b6b28d890 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -363,7 +363,7 @@ int blk_next_device(struct udevice **devp) } while (1); }
-int blk_get_device(int if_type, int devnum, struct udevice **devp) +int blk_find_device(int if_type, int devnum, struct udevice **devp) { struct uclass *uc; struct udevice *dev; @@ -379,13 +379,24 @@ int blk_get_device(int if_type, int devnum, struct udevice **devp) if_type, devnum, dev->name, desc->if_type, desc->devnum); if (desc->if_type == if_type && desc->devnum == devnum) { *devp = dev; - return device_probe(dev); + return 0; } }
return -ENODEV; }
+int blk_get_device(int if_type, int devnum, struct udevice **devp) +{ + int ret; + + ret = blk_find_device(if_type, devnum, devp); + if (ret) + return ret; + + return device_probe(*devp); +} + unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, void *buffer) { diff --git a/include/blk.h b/include/blk.h index 66a1c55cc8..a128ee4841 100644 --- a/include/blk.h +++ b/include/blk.h @@ -253,12 +253,25 @@ unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt);
/** + * blk_find_device() - Find a block device + * + * This function does not activate the device. The device will be returned + * whether or not it is activated. + * + * @if_type: Interface type (enum if_type_t) + * @devnum: Device number (specific to each interface type) + * @devp: the device, if found + * @return 0 if found, -ENODEV if no device found, or other -ve error value + */ +int blk_find_device(int if_type, int devnum, struct udevice **devp); + +/** * blk_get_device() - Find and probe a block device ready for use * * @if_type: Interface type (enum if_type_t) * @devnum: Device number (specific to each interface type) * @devp: the device, if found - * @return - if found, -ENODEV if no device found, or other -ve error value + * @return 0 if found, -ENODEV if no device found, or other -ve error value */ int blk_get_device(int if_type, int devnum, struct udevice **devp);
diff --git a/test/dm/blk.c b/test/dm/blk.c index 012bf4cab5..3e34336fae 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -94,3 +94,24 @@ static int dm_test_blk_usb(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_blk_usb, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test that we can find block devices without probing them */ +static int dm_test_blk_find(struct unit_test_state *uts) +{ + struct udevice *blk, *dev; + + ut_assertok(blk_create_device(gd->dm_root, "sandbox_host_blk", "test", + IF_TYPE_HOST, 1, 512, 1024, &blk)); + ut_asserteq(-ENODEV, blk_find_device(IF_TYPE_HOST, 0, &dev)); + ut_assertok(blk_find_device(IF_TYPE_HOST, 1, &dev)); + ut_asserteq_ptr(blk, dev); + ut_asserteq(false, device_active(dev)); + + /* Now activate it */ + ut_assertok(blk_get_device(IF_TYPE_HOST, 1, &dev)); + ut_asserteq_ptr(blk, dev); + ut_asserteq(true, device_active(dev)); + + return 0; +} +DM_TEST(dm_test_blk_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Sometimes it is useful to be able to find a block device without also probing it. Add a function for this as well as the associated test.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 15 +++++++++++++-- include/blk.h | 15 ++++++++++++++- test/dm/blk.c | 21 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-)
Applied to u-boot-dm

At present this code is inline. Move it into a function to allow it to be used elsewhere.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 8b6b28d890..7947ca6f22 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -473,6 +473,19 @@ int blk_find_max_devnum(enum if_type if_type) return max_devnum; }
+static int blk_next_free_devnum(enum if_type if_type) +{ + int ret; + + ret = blk_find_max_devnum(if_type); + if (ret == -ENODEV) + return 0; + else if (ret < 0) + return ret; + else + return ret + 1; +} + int blk_create_device(struct udevice *parent, const char *drv_name, const char *name, int if_type, int devnum, int blksz, lbaint_t size, struct udevice **devp) @@ -482,13 +495,10 @@ int blk_create_device(struct udevice *parent, const char *drv_name, int ret;
if (devnum == -1) { - ret = blk_find_max_devnum(if_type); - if (ret == -ENODEV) - devnum = 0; - else if (ret < 0) + ret = blk_next_free_devnum(if_type); + if (ret < 0) return ret; - else - devnum = ret + 1; + devnum = ret; } ret = device_bind_driver(parent, drv_name, name, &dev); if (ret)

On Mon, Apr 24, 2017 at 5:02 AM, Simon Glass sjg@chromium.org wrote:
At present this code is inline. Move it into a function to allow it to be used elsewhere.
Signed-off-by: Simon Glass sjg@chromium.org
+static int blk_next_free_devnum(enum if_type if_type) +{
int ret;
ret = blk_find_max_devnum(if_type);
if (ret == -ENODEV)
return 0;
else if (ret < 0)
Useless 'else'.
return ret;
else
Ditto.
return ret + 1;
+}

Hi Andy,
On 24 April 2017 at 02:04, Andy Shevchenko andy.shevchenko@gmail.com wrote:
On Mon, Apr 24, 2017 at 5:02 AM, Simon Glass sjg@chromium.org wrote:
At present this code is inline. Move it into a function to allow it to be used elsewhere.
Signed-off-by: Simon Glass sjg@chromium.org
+static int blk_next_free_devnum(enum if_type if_type) +{
int ret;
ret = blk_find_max_devnum(if_type);
if (ret == -ENODEV)
return 0;
else if (ret < 0)
Useless 'else'.
return ret;
else
Ditto.
return ret + 1;
+}
I think it is clearer with these. At least, I would ask for them to be added if they were missing.
What do you think of this series as a whole?
Regards, Simon

On Wed, May 3, 2017 at 5:36 AM, Simon Glass sjg@chromium.org wrote:
Hi Andy,
On 24 April 2017 at 02:04, Andy Shevchenko andy.shevchenko@gmail.com wrote:
On Mon, Apr 24, 2017 at 5:02 AM, Simon Glass sjg@chromium.org wrote:
At present this code is inline. Move it into a function to allow it to be used elsewhere.
Signed-off-by: Simon Glass sjg@chromium.org
+static int blk_next_free_devnum(enum if_type if_type) +{
int ret;
ret = blk_find_max_devnum(if_type);
if (ret == -ENODEV)
return 0;
else if (ret < 0)
Useless 'else'.
return ret;
else
Ditto.
return ret + 1;
+}
I think it is clearer with these. At least, I would ask for them to be added if they were missing.
Really? It's just noise in the code which makes it harder to read. In Linux kernel we remove that. If U-Boot has the above style kinda mandatory I would be really surprised.
What do you think of this series as a whole?
It was a while ago. So, if there were no comments from me, that means I have nothing to argue of.

On Wed, May 3, 2017 at 5:36 AM, Simon Glass sjg@chromium.org wrote:
Hi Andy,
On 24 April 2017 at 02:04, Andy Shevchenko andy.shevchenko@gmail.com wrote:
On Mon, Apr 24, 2017 at 5:02 AM, Simon Glass sjg@chromium.org wrote:
At present this code is inline. Move it into a function to allow it to be used elsewhere.
Signed-off-by: Simon Glass sjg@chromium.org
+static int blk_next_free_devnum(enum if_type if_type) +{
int ret;
ret = blk_find_max_devnum(if_type);
if (ret == -ENODEV)
return 0;
else if (ret < 0)
Useless 'else'.
return ret;
else
Ditto.
return ret + 1;
+}
I think it is clearer with these. At least, I would ask for them to be added if they were missing.
Really? It's just noise in the code which makes it harder to read. In Linux kernel we remove that. If U-Boot has the above style kinda mandatory I would be really surprised.
What do you think of this series as a whole?
It was a while ago. So, if there were no comments from me, that means I have nothing to argue of.

Hi Andy,
On 18 May 2017 at 10:01, sjg@google.com wrote:
On Wed, May 3, 2017 at 5:36 AM, Simon Glass sjg@chromium.org wrote:
Hi Andy,
On 24 April 2017 at 02:04, Andy Shevchenko andy.shevchenko@gmail.com wrote:
On Mon, Apr 24, 2017 at 5:02 AM, Simon Glass sjg@chromium.org wrote:
At present this code is inline. Move it into a function to allow it to be used elsewhere.
Signed-off-by: Simon Glass sjg@chromium.org
+static int blk_next_free_devnum(enum if_type if_type) +{
int ret;
ret = blk_find_max_devnum(if_type);
if (ret == -ENODEV)
return 0;
else if (ret < 0)
Useless 'else'.
return ret;
else
Ditto.
I updated these when applying.
- Simon

The intention with block devices is that the device number (devnum field in its descriptor) matches the alias of its parent device. For example, with:
aliases { mmc0 = "/sdhci@700b0600"; mmc1 = "/sdhci@700b0400"; }
we expect that the block devices for mmc0 and mmc1 would have device numbers of 0 and 1 respectively.
Unfortunately this does not currently always happen. If there is another MMC device earlier in the driver model data structures its block device will be created first. It will therefore get device number 0 and mmc0 will therefore miss out. In this case the MMC device will have sequence number 0 but its block device will not.
To avoid this, allow a device to request a device number and bump any existing device number that is using it. This all happens during the binding phase so it is safe to change these numbers around. This allows device numbers to match the aliases in all circumstances.
Add a test to verify the behaviour.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 12 +++++++++++- drivers/block/blk-uclass.c | 34 +++++++++++++++++++++++++++++++--- test/dm/blk.c | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 6 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index fff175d1b7..2f6abdbdbc 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -12,6 +12,8 @@ eth3 = ð_3; eth5 = ð_5; i2c0 = "/i2c@0"; + mmc0 = "/mmc0"; + mmc1 = "/mmc1"; pci0 = &pci; remoteproc1 = &rproc_1; remoteproc2 = &rproc_2; @@ -242,7 +244,15 @@ mbox-names = "other", "test"; };
- mmc { + mmc2 { + compatible = "sandbox,mmc"; + }; + + mmc1 { + compatible = "sandbox,mmc"; + }; + + mmc0 { compatible = "sandbox,mmc"; };
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 7947ca6f22..4ee71a9852 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -486,6 +486,31 @@ static int blk_next_free_devnum(enum if_type if_type) return ret + 1; }
+static int blk_claim_devnum(enum if_type if_type, int devnum) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_BLK, &uc); + if (ret) + return ret; + uclass_foreach_dev(dev, uc) { + struct blk_desc *desc = dev_get_uclass_platdata(dev); + + if (desc->if_type == if_type && desc->devnum == devnum) { + int next = blk_next_free_devnum(if_type); + + if (next < 0) + return next; + desc->devnum = next; + return 0; + } + } + + return -ENOENT; +} + int blk_create_device(struct udevice *parent, const char *drv_name, const char *name, int if_type, int devnum, int blksz, lbaint_t size, struct udevice **devp) @@ -495,11 +520,14 @@ int blk_create_device(struct udevice *parent, const char *drv_name, int ret;
if (devnum == -1) { - ret = blk_next_free_devnum(if_type); - if (ret < 0) + devnum = blk_next_free_devnum(if_type); + } else { + ret = blk_claim_devnum(if_type, devnum); + if (ret < 0 && ret != -ENOENT) return ret; - devnum = ret; } + if (devnum < 0) + return devnum; ret = device_bind_driver(parent, drv_name, name, &dev); if (ret) return ret; diff --git a/test/dm/blk.c b/test/dm/blk.c index 3e34336fae..5c5eb829a0 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -83,12 +83,12 @@ static int dm_test_blk_usb(struct unit_test_state *uts) ut_asserteq_ptr(usb_dev, dev_get_parent(dev));
/* Check we have one block device for each mass storage device */ - ut_asserteq(4, count_blk_devices()); + ut_asserteq(6, count_blk_devices());
/* Now go around again, making sure the old devices were unbound */ ut_assertok(usb_stop()); ut_assertok(usb_init()); - ut_asserteq(4, count_blk_devices()); + ut_asserteq(6, count_blk_devices()); ut_assertok(usb_stop());
return 0; @@ -115,3 +115,38 @@ static int dm_test_blk_find(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_blk_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test that block device numbering works as expected */ +static int dm_test_blk_devnum(struct unit_test_state *uts) +{ + struct udevice *dev, *mmc_dev, *parent; + int i; + + /* + * Probe the devices, with the first one being probed last. This is the + * one with no alias / sequence numnber. + */ + ut_assertok(uclass_get_device(UCLASS_MMC, 1, &dev)); + ut_assertok(uclass_get_device(UCLASS_MMC, 2, &dev)); + ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev)); + for (i = 0; i < 3; i++) { + struct blk_desc *desc; + + /* Check that the bblock device is attached */ + ut_assertok(uclass_get_device_by_seq(UCLASS_MMC, i, &mmc_dev)); + ut_assertok(blk_find_device(IF_TYPE_MMC, i, &dev)); + parent = dev_get_parent(dev); + ut_asserteq_ptr(parent, mmc_dev); + ut_asserteq(trailing_strtol(mmc_dev->name), i); + + /* + * Check that the block device devnum matches its parent's + * sequence number + */ + desc = dev_get_uclass_platdata(dev); + ut_asserteq(desc->devnum, i); + } + + return 0; +} +DM_TEST(dm_test_blk_devnum, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

The intention with block devices is that the device number (devnum field in its descriptor) matches the alias of its parent device. For example, with:
aliases { mmc0 = "/sdhci@700b0600"; mmc1 = "/sdhci@700b0400"; }
we expect that the block devices for mmc0 and mmc1 would have device numbers of 0 and 1 respectively.
Unfortunately this does not currently always happen. If there is another MMC device earlier in the driver model data structures its block device will be created first. It will therefore get device number 0 and mmc0 will therefore miss out. In this case the MMC device will have sequence number 0 but its block device will not.
To avoid this, allow a device to request a device number and bump any existing device number that is using it. This all happens during the binding phase so it is safe to change these numbers around. This allows device numbers to match the aliases in all circumstances.
Add a test to verify the behaviour.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 12 +++++++++++- drivers/block/blk-uclass.c | 34 +++++++++++++++++++++++++++++++--- test/dm/blk.c | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 6 deletions(-)
Applied to u-boot-dm

We do not need to probe the block device here, so avoid doing so. The MMC device itself must be active, but the block device can come later.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc-uclass.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 9c07871d3a..1a84a033ae 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -97,7 +97,7 @@ struct mmc *find_mmc_device(int dev_num) struct udevice *dev, *mmc_dev; int ret;
- ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev); + ret = blk_find_device(IF_TYPE_MMC, dev_num, &dev);
if (ret) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) @@ -108,7 +108,9 @@ struct mmc *find_mmc_device(int dev_num)
mmc_dev = dev_get_parent(dev);
- return mmc_get_mmc_dev(mmc_dev); + struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); + + return mmc; }
int get_mmc_num(void)

We do not need to probe the block device here, so avoid doing so. The MMC device itself must be active, but the block device can come later.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc-uclass.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
Applied to u-boot-dm

When binding a new MMC device, make sure that it has the required operations. Since for now we still support *not* having the operations (with CONFIG_DM_MMC_OPS not enabled) it makes sense to add this check.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc-uclass.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 1a84a033ae..ae0e22dfeb 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -198,6 +198,10 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) struct udevice *bdev; int ret, devnum = -1;
+#ifdef CONFIG_DM_MMC_OPS + if (!mmc_get_ops(dev)) + return -ENOSYS; +#endif #ifndef CONFIG_SPL_BUILD /* Use the fixed index with aliase node's index */ fdtdec_get_alias_seq(gd->fdt_blob, "mmc", dev->of_offset, &devnum);

When binding a new MMC device, make sure that it has the required operations. Since for now we still support *not* having the operations (with CONFIG_DM_MMC_OPS not enabled) it makes sense to add this check.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc-uclass.c | 4 ++++ 1 file changed, 4 insertions(+)
Applied to u-boot-dm

This function is called when the MMC block device is being probed. There is a recursive call in this function since find_mmc_device() itself can cause the MMC device to be probed.
Admittedly the MMC device should already be probed, since we would not be probing its child otherwise, but the current code is unnecessarily convoluted.
Rewrite this to access the MMC structure directly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc-uclass.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index ae0e22dfeb..63248c3480 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -262,13 +262,18 @@ static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
static int mmc_blk_probe(struct udevice *dev) { - struct blk_desc *block_dev = dev_get_uclass_platdata(dev); - int dev_num = block_dev->devnum; - struct mmc *mmc = find_mmc_device(dev_num); + struct udevice *mmc_dev = dev_get_parent(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev); + struct mmc *mmc = upriv->mmc; + int ret; + + ret = mmc_init(mmc); + if (ret) { + debug("%s: mmc_init() failed (err=%d)\n", __func__, ret); + return ret; + }
- if (!mmc) - return -ENODEV; - return mmc_init(mmc); + return 0; }
static const struct blk_ops mmc_blk_ops = {

This function is called when the MMC block device is being probed. There is a recursive call in this function since find_mmc_device() itself can cause the MMC device to be probed.
Admittedly the MMC device should already be probed, since we would not be probing its child otherwise, but the current code is unnecessarily convoluted.
Rewrite this to access the MMC structure directly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc-uclass.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
Applied to u-boot-dm

Enable CONFIG_DM_MMC_OPS and CONFIG_BLK for all Tegra devices. This moves Tegra to use driver model fully for MMC.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/toradex/common/tdx-cfg-block.c | 2 +- configs/apalis-tk1_defconfig | 2 - configs/apalis_t30_defconfig | 2 - configs/beaver_defconfig | 2 - configs/cardhu_defconfig | 2 - configs/cei-tk1-som_defconfig | 2 - configs/colibri_t20_defconfig | 2 - configs/colibri_t30_defconfig | 2 - configs/dalmore_defconfig | 2 - configs/e2220-1170_defconfig | 2 - configs/harmony_defconfig | 2 - configs/jetson-tk1_defconfig | 2 - configs/medcom-wide_defconfig | 2 - configs/nyan-big_defconfig | 2 - configs/p2371-0000_defconfig | 2 - configs/p2371-2180_defconfig | 2 - configs/p2571_defconfig | 2 - configs/p2771-0000-000_defconfig | 2 - configs/p2771-0000-500_defconfig | 2 - configs/paz00_defconfig | 2 - configs/plutux_defconfig | 2 - configs/seaboard_defconfig | 2 - configs/tec-ng_defconfig | 2 - configs/tec_defconfig | 2 - configs/trimslice_defconfig | 2 - configs/venice2_defconfig | 2 - configs/ventana_defconfig | 2 - configs/whistler_defconfig | 2 - drivers/mmc/tegra_mmc.c | 72 ++++++++++++++++++++---------------- 29 files changed, 42 insertions(+), 86 deletions(-)
diff --git a/board/toradex/common/tdx-cfg-block.c b/board/toradex/common/tdx-cfg-block.c index 0014ce80a1..2a810c89aa 100644 --- a/board/toradex/common/tdx-cfg-block.c +++ b/board/toradex/common/tdx-cfg-block.c @@ -110,7 +110,7 @@ static int tdx_cfg_block_mmc_storage(u8 *config_block, int write) ret = -ENODEV; goto out; } - if (part != mmc->block_dev.hwpart) { + if (part != mmc_get_blk_desc(mmc)->hwpart) { if (blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part)) { puts("MMC partition switch failed\n"); ret = -ENODEV; diff --git a/configs/apalis-tk1_defconfig b/configs/apalis-tk1_defconfig index 10862e56e7..27ca42c6c3 100644 --- a/configs/apalis-tk1_defconfig +++ b/configs/apalis-tk1_defconfig @@ -24,10 +24,8 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y -# CONFIG_DM_MMC_OPS is not set CONFIG_TEGRA124_MMC_DISABLE_EXT_LOOPBACK=y CONFIG_E1000=y CONFIG_PCI=y diff --git a/configs/apalis_t30_defconfig b/configs/apalis_t30_defconfig index a31b912968..864f71059f 100644 --- a/configs/apalis_t30_defconfig +++ b/configs/apalis_t30_defconfig @@ -25,10 +25,8 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y -# CONFIG_DM_MMC_OPS is not set CONFIG_E1000=y CONFIG_PCI=y CONFIG_DM_PCI=y diff --git a/configs/beaver_defconfig b/configs/beaver_defconfig index 0365246ee5..cb1018ea16 100644 --- a/configs/beaver_defconfig +++ b/configs/beaver_defconfig @@ -26,11 +26,9 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_RTL8169=y diff --git a/configs/cardhu_defconfig b/configs/cardhu_defconfig index 77dac784e3..38814c98e7 100644 --- a/configs/cardhu_defconfig +++ b/configs/cardhu_defconfig @@ -24,8 +24,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_RTL8169=y diff --git a/configs/cei-tk1-som_defconfig b/configs/cei-tk1-som_defconfig index 88b93cb0ff..1ab1f1fa9f 100644 --- a/configs/cei-tk1-som_defconfig +++ b/configs/cei-tk1-som_defconfig @@ -26,11 +26,9 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_RTL8169=y diff --git a/configs/colibri_t20_defconfig b/configs/colibri_t20_defconfig index 85956c52ea..f357f7e581 100644 --- a/configs/colibri_t20_defconfig +++ b/configs/colibri_t20_defconfig @@ -28,10 +28,8 @@ CONFIG_CMD_UBI=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y -# CONFIG_DM_MMC_OPS is not set CONFIG_MTD_UBI_FASTMAP=y CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y diff --git a/configs/colibri_t30_defconfig b/configs/colibri_t30_defconfig index 0071a923e4..5581390a0c 100644 --- a/configs/colibri_t30_defconfig +++ b/configs/colibri_t30_defconfig @@ -25,10 +25,8 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SYS_NS16550=y CONFIG_USB=y CONFIG_DM_USB=y diff --git a/configs/dalmore_defconfig b/configs/dalmore_defconfig index 8aae0e15dc..b02cfa578c 100644 --- a/configs/dalmore_defconfig +++ b/configs/dalmore_defconfig @@ -26,11 +26,9 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SYS_NS16550=y diff --git a/configs/e2220-1170_defconfig b/configs/e2220-1170_defconfig index c5563a4461..89137409b7 100644 --- a/configs/e2220-1170_defconfig +++ b/configs/e2220-1170_defconfig @@ -21,11 +21,9 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SYS_NS16550=y diff --git a/configs/harmony_defconfig b/configs/harmony_defconfig index 6163353621..e42e2b4dc6 100644 --- a/configs/harmony_defconfig +++ b/configs/harmony_defconfig @@ -22,8 +22,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y diff --git a/configs/jetson-tk1_defconfig b/configs/jetson-tk1_defconfig index 58d4184600..1c1b4b199b 100644 --- a/configs/jetson-tk1_defconfig +++ b/configs/jetson-tk1_defconfig @@ -26,11 +26,9 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_RTL8169=y diff --git a/configs/medcom-wide_defconfig b/configs/medcom-wide_defconfig index a811506f29..47dc7c46e4 100644 --- a/configs/medcom-wide_defconfig +++ b/configs/medcom-wide_defconfig @@ -23,8 +23,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig index 63f1a6f03f..007702e012 100644 --- a/configs/nyan-big_defconfig +++ b/configs/nyan-big_defconfig @@ -31,14 +31,12 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y CONFIG_CROS_EC_KEYB=y CONFIG_CROS_EC=y CONFIG_CROS_EC_SPI=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_DM_PMIC=y diff --git a/configs/p2371-0000_defconfig b/configs/p2371-0000_defconfig index 0ff4c13aa0..cc87e4298b 100644 --- a/configs/p2371-0000_defconfig +++ b/configs/p2371-0000_defconfig @@ -22,11 +22,9 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SYS_NS16550=y diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig index 4dfb02db20..69bc9a1735 100644 --- a/configs/p2371-2180_defconfig +++ b/configs/p2371-2180_defconfig @@ -22,11 +22,9 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_RTL8169=y diff --git a/configs/p2571_defconfig b/configs/p2571_defconfig index e49a42f45b..b88d096728 100644 --- a/configs/p2571_defconfig +++ b/configs/p2571_defconfig @@ -22,11 +22,9 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SYS_NS16550=y diff --git a/configs/p2771-0000-000_defconfig b/configs/p2771-0000-000_defconfig index b4daa1256a..edf6ce4a93 100644 --- a/configs/p2771-0000-000_defconfig +++ b/configs/p2771-0000-000_defconfig @@ -19,9 +19,7 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y -# CONFIG_BLK is not set CONFIG_TEGRA186_BPMP_I2C=y -# CONFIG_DM_MMC_OPS is not set CONFIG_DWC_ETH_QOS=y CONFIG_E1000=y CONFIG_RTL8169=y diff --git a/configs/p2771-0000-500_defconfig b/configs/p2771-0000-500_defconfig index 02e974d0e9..c3870c38d6 100644 --- a/configs/p2771-0000-500_defconfig +++ b/configs/p2771-0000-500_defconfig @@ -19,9 +19,7 @@ CONFIG_CMD_GPIO=y # CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_NFS is not set CONFIG_CMD_EXT4_WRITE=y -# CONFIG_BLK is not set CONFIG_TEGRA186_BPMP_I2C=y -# CONFIG_DM_MMC_OPS is not set CONFIG_DWC_ETH_QOS=y CONFIG_E1000=y CONFIG_RTL8169=y diff --git a/configs/paz00_defconfig b/configs/paz00_defconfig index 0ad0974d34..0f1ee66b6d 100644 --- a/configs/paz00_defconfig +++ b/configs/paz00_defconfig @@ -22,8 +22,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y diff --git a/configs/plutux_defconfig b/configs/plutux_defconfig index 0c6c65e9d8..aa6b597f1f 100644 --- a/configs/plutux_defconfig +++ b/configs/plutux_defconfig @@ -22,8 +22,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_SYS_NS16550=y CONFIG_USB=y CONFIG_DM_USB=y diff --git a/configs/seaboard_defconfig b/configs/seaboard_defconfig index 3e5549c073..9a247d554b 100644 --- a/configs/seaboard_defconfig +++ b/configs/seaboard_defconfig @@ -22,8 +22,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y diff --git a/configs/tec-ng_defconfig b/configs/tec-ng_defconfig index cd9b507803..1c1d835c28 100644 --- a/configs/tec-ng_defconfig +++ b/configs/tec-ng_defconfig @@ -25,8 +25,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SYS_NS16550=y diff --git a/configs/tec_defconfig b/configs/tec_defconfig index 1dd8a1ec20..74e9b7401a 100644 --- a/configs/tec_defconfig +++ b/configs/tec_defconfig @@ -23,8 +23,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y diff --git a/configs/trimslice_defconfig b/configs/trimslice_defconfig index 455f4b2819..9ab15fa3c6 100644 --- a/configs/trimslice_defconfig +++ b/configs/trimslice_defconfig @@ -24,8 +24,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_RTL8169=y diff --git a/configs/venice2_defconfig b/configs/venice2_defconfig index 1b0e646474..7e70875345 100644 --- a/configs/venice2_defconfig +++ b/configs/venice2_defconfig @@ -26,11 +26,9 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y -# CONFIG_DM_MMC_OPS is not set CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SYS_NS16550=y diff --git a/configs/ventana_defconfig b/configs/ventana_defconfig index 486861b461..d4207a1b07 100644 --- a/configs/ventana_defconfig +++ b/configs/ventana_defconfig @@ -21,8 +21,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_DM_PMIC=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y diff --git a/configs/whistler_defconfig b/configs/whistler_defconfig index 6c27b36235..69d435f538 100644 --- a/configs/whistler_defconfig +++ b/configs/whistler_defconfig @@ -22,8 +22,6 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set CONFIG_SPL_DM=y -# CONFIG_BLK is not set -# CONFIG_DM_MMC_OPS is not set CONFIG_SYS_NS16550=y CONFIG_USB=y CONFIG_DM_USB=y diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 6c6affb925..80e71d8a3f 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -18,6 +18,11 @@
DECLARE_GLOBAL_DATA_PTR;
+struct tegra_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + struct tegra_mmc_priv { struct tegra_mmc *reg; struct reset_ctl reset_ctl; @@ -27,8 +32,6 @@ struct tegra_mmc_priv { struct gpio_desc wp_gpio; /* Write Protect GPIO */ unsigned int version; /* SDHCI spec. version */ unsigned int clock; /* Current clock (MHz) */ - struct mmc_config cfg; /* mmc configuration */ - struct mmc *mmc; };
static void tegra_mmc_set_power(struct tegra_mmc_priv *priv, @@ -151,11 +154,11 @@ static int tegra_mmc_wait_inhibit(struct tegra_mmc_priv *priv, return 0; }
-static int tegra_mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, +static int tegra_mmc_send_cmd_bounced(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data, struct bounce_buffer *bbstate) { - struct tegra_mmc_priv *priv = mmc->priv; + struct tegra_mmc_priv *priv = dev_get_priv(dev); int flags, i; int result; unsigned int mask = 0; @@ -324,7 +327,7 @@ static int tegra_mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, return 0; }
-static int tegra_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, +static int tegra_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { void *buf; @@ -346,7 +349,7 @@ static int tegra_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, bounce_buffer_start(&bbstate, buf, len, bbflags); }
- ret = tegra_mmc_send_cmd_bounced(mmc, cmd, data, &bbstate); + ret = tegra_mmc_send_cmd_bounced(dev, cmd, data, &bbstate);
if (data) bounce_buffer_stop(&bbstate); @@ -408,9 +411,10 @@ out: priv->clock = clock; }
-static int tegra_mmc_set_ios(struct mmc *mmc) +static int tegra_mmc_set_ios(struct udevice *dev) { - struct tegra_mmc_priv *priv = mmc->priv; + struct tegra_mmc_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); unsigned char ctrl; debug(" mmc_set_ios called\n");
@@ -505,9 +509,10 @@ static void tegra_mmc_reset(struct tegra_mmc_priv *priv, struct mmc *mmc) tegra_mmc_pad_init(priv); }
-static int tegra_mmc_init(struct mmc *mmc) +static int tegra_mmc_init(struct udevice *dev) { - struct tegra_mmc_priv *priv = mmc->priv; + struct tegra_mmc_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); unsigned int mask; debug(" tegra_mmc_init called\n");
@@ -566,9 +571,9 @@ static int tegra_mmc_init(struct mmc *mmc) return 0; }
-static int tegra_mmc_getcd(struct mmc *mmc) +static int tegra_mmc_getcd(struct udevice *dev) { - struct tegra_mmc_priv *priv = mmc->priv; + struct tegra_mmc_priv *priv = dev_get_priv(dev);
debug("tegra_mmc_getcd called\n");
@@ -578,32 +583,32 @@ static int tegra_mmc_getcd(struct mmc *mmc) return 1; }
-static const struct mmc_ops tegra_mmc_ops = { +static const struct dm_mmc_ops tegra_mmc_ops = { .send_cmd = tegra_mmc_send_cmd, .set_ios = tegra_mmc_set_ios, - .init = tegra_mmc_init, - .getcd = tegra_mmc_getcd, + .get_cd = tegra_mmc_getcd, };
static int tegra_mmc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct tegra_mmc_plat *plat = dev_get_platdata(dev); struct tegra_mmc_priv *priv = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; int bus_width, ret;
- priv->cfg.name = "Tegra SD/MMC"; - priv->cfg.ops = &tegra_mmc_ops; + cfg->name = dev->name;
bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 1);
- priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - priv->cfg.host_caps = 0; + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + cfg->host_caps = 0; if (bus_width == 8) - priv->cfg.host_caps |= MMC_MODE_8BIT; + cfg->host_caps |= MMC_MODE_8BIT; if (bus_width >= 4) - priv->cfg.host_caps |= MMC_MODE_4BIT; - priv->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + cfg->host_caps |= MMC_MODE_4BIT; + cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
/* * min freq is for card identification, and is the highest @@ -611,10 +616,10 @@ static int tegra_mmc_probe(struct udevice *dev) * max freq is highest HS eMMC clock as per the SD/MMC spec * (actually 52MHz) */ - priv->cfg.f_min = 375000; - priv->cfg.f_max = 48000000; + cfg->f_min = 375000; + cfg->f_max = 48000000;
- priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
priv->reg = (void *)dev_get_addr(dev);
@@ -652,14 +657,16 @@ static int tegra_mmc_probe(struct udevice *dev) if (dm_gpio_is_valid(&priv->pwr_gpio)) dm_gpio_set_value(&priv->pwr_gpio, 1);
- priv->mmc = mmc_create(&priv->cfg, priv); - if (priv->mmc == NULL) - return -1; + upriv->mmc = &plat->mmc;
- priv->mmc->dev = dev; - upriv->mmc = priv->mmc; + return tegra_mmc_init(dev); +}
- return 0; +static int tegra_mmc_bind(struct udevice *dev) +{ + struct tegra_mmc_plat *plat = dev_get_platdata(dev); + + return mmc_bind(dev, &plat->mmc, &plat->cfg); }
static const struct udevice_id tegra_mmc_ids[] = { @@ -676,6 +683,9 @@ U_BOOT_DRIVER(tegra_mmc_drv) = { .name = "tegra_mmc", .id = UCLASS_MMC, .of_match = tegra_mmc_ids, + .bind = tegra_mmc_bind, .probe = tegra_mmc_probe, + .ops = &tegra_mmc_ops, + .platdata_auto_alloc_size = sizeof(struct tegra_mmc_plat), .priv_auto_alloc_size = sizeof(struct tegra_mmc_priv), };

Enable CONFIG_DM_MMC_OPS and CONFIG_BLK for all Tegra devices. This moves Tegra to use driver model fully for MMC.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/toradex/common/tdx-cfg-block.c | 2 +- configs/apalis-tk1_defconfig | 2 - configs/apalis_t30_defconfig | 2 - configs/beaver_defconfig | 2 - configs/cardhu_defconfig | 2 - configs/cei-tk1-som_defconfig | 2 - configs/colibri_t20_defconfig | 2 - configs/colibri_t30_defconfig | 2 - configs/dalmore_defconfig | 2 - configs/e2220-1170_defconfig | 2 - configs/harmony_defconfig | 2 - configs/jetson-tk1_defconfig | 2 - configs/medcom-wide_defconfig | 2 - configs/nyan-big_defconfig | 2 - configs/p2371-0000_defconfig | 2 - configs/p2371-2180_defconfig | 2 - configs/p2571_defconfig | 2 - configs/p2771-0000-000_defconfig | 2 - configs/p2771-0000-500_defconfig | 2 - configs/paz00_defconfig | 2 - configs/plutux_defconfig | 2 - configs/seaboard_defconfig | 2 - configs/tec-ng_defconfig | 2 - configs/tec_defconfig | 2 - configs/trimslice_defconfig | 2 - configs/venice2_defconfig | 2 - configs/ventana_defconfig | 2 - configs/whistler_defconfig | 2 - drivers/mmc/tegra_mmc.c | 72 ++++++++++++++++++++---------------- 29 files changed, 42 insertions(+), 86 deletions(-)
Applied to u-boot-dm

Simon,
What testing did you do?
Tom -- nvpublic
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] Sent: Thursday, May 18, 2017 9:01 AM To: Simon Glass sjg@chromium.org Cc: Alban Bedel alban.bedel@avionic-design.de; Max Krummenacher max.krummenacher@toradex.com; Masahiro Yamada yamada.masahiro@socionext.com; Tom Warren TWarren@nvidia.com; Peter.Chubb@data61.csiro.au; Stephen Warren swarren@wwwdotorg.org; Stefan Agner stefan.agner@toradex.com; Lucas Stach dev@lynxeye.de; Allen Martin AMartin@nvidia.com; Marcel Ziswiler marcel.ziswiler@toradex.com; Jaehoon Chung jh80.chung@samsung.com; Stephen Warren swarren@nvidia.com; U-Boot Mailing List <u- boot@lists.denx.de> Subject: Re: [PATCH 8/8] tegra: Convert MMC to use driver model for operations
Enable CONFIG_DM_MMC_OPS and CONFIG_BLK for all Tegra devices. This moves Tegra to use driver model fully for MMC.
Signed-off-by: Simon Glass sjg@chromium.org
board/toradex/common/tdx-cfg-block.c | 2 +- configs/apalis-tk1_defconfig | 2 - configs/apalis_t30_defconfig | 2 - configs/beaver_defconfig | 2 - configs/cardhu_defconfig | 2 - configs/cei-tk1-som_defconfig | 2 - configs/colibri_t20_defconfig | 2 - configs/colibri_t30_defconfig | 2 - configs/dalmore_defconfig | 2 - configs/e2220-1170_defconfig | 2 - configs/harmony_defconfig | 2 - configs/jetson-tk1_defconfig | 2 - configs/medcom-wide_defconfig | 2 - configs/nyan-big_defconfig | 2 - configs/p2371-0000_defconfig | 2 - configs/p2371-2180_defconfig | 2 - configs/p2571_defconfig | 2 - configs/p2771-0000-000_defconfig | 2 - configs/p2771-0000-500_defconfig | 2 - configs/paz00_defconfig | 2 - configs/plutux_defconfig | 2 - configs/seaboard_defconfig | 2 - configs/tec-ng_defconfig | 2 - configs/tec_defconfig | 2 - configs/trimslice_defconfig | 2 - configs/venice2_defconfig | 2 - configs/ventana_defconfig | 2 - configs/whistler_defconfig | 2 - drivers/mmc/tegra_mmc.c | 72 ++++++++++++++++++++---------------- 29 files changed, 42 insertions(+), 86 deletions(-)
Applied to u-boot-dm

Hi Tom,
On 18 May 2017 at 10:33, Tom Warren TWarren@nvidia.com wrote:
Simon,
What testing did you do?
This was tested on Nyan. I'd be grateful for any Tegra review / testing that you can arrange. It seems mighty quiet around here :-)
Tom
nvpublic
Regards, Simon

Hi Simon
On Thu, 2017-05-18 at 10:35 -0600, Simon Glass wrote:
Hi Tom,
On 18 May 2017 at 10:33, Tom Warren TWarren@nvidia.com wrote:
Simon,
What testing did you do?
This was tested on Nyan. I'd be grateful for any Tegra review / testing that you can arrange. It seems mighty quiet around here :-)
Sorry about that, been mighty busy around here.
I just tested dm/master on all our Tegra hardware being Apalis T30, Apalis TK1, Colibri T20 and Colibri T30 and all works fine including e.g. the 3 SD/MMC controllers via driver model now:
Apalis TK1 # dm tree Class Probed Name ---------------------------------------- root [ + ] root_driver ... mmc [ + ] |-- sdhci@700b0000 blk [ + ] | `-- sdhci@700b0000.blk mmc [ + ] |-- sdhci@700b0400 blk [ + ] | `-- sdhci@700b0400.blk mmc [ + ] |-- sdhci@700b0600 blk [ + ] | `-- sdhci@700b0600.blk usb [ ] |-- usb@7d000000 usb [ ] |-- usb@7d004000 usb [ ] |-- usb@7d008000 simple_bus [ ] `-- clocks clk [ ] `-- clock@0
With the live tree stuff I had less success but will post on resp. message there.
Tom
Cheers
Marcel
-- nvpublic
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

Hi Marcel,
On 29 May 2017 at 08:49, Marcel Ziswiler marcel.ziswiler@toradex.com wrote:
Hi Simon
On Thu, 2017-05-18 at 10:35 -0600, Simon Glass wrote:
Hi Tom,
On 18 May 2017 at 10:33, Tom Warren TWarren@nvidia.com wrote:
Simon,
What testing did you do?
This was tested on Nyan. I'd be grateful for any Tegra review / testing that you can arrange. It seems mighty quiet around here :-)
Sorry about that, been mighty busy around here.
I just tested dm/master on all our Tegra hardware being Apalis T30, Apalis TK1, Colibri T20 and Colibri T30 and all works fine including e.g. the 3 SD/MMC controllers via driver model now:
OK good, thanks!
Regards, Simon

On Mon, Apr 24, 2017 at 5:02 AM, Simon Glass sjg@chromium.org wrote:
The current MMC block device support has a few deficiencies which show up when both CONFIG_BLK and CONFIG_DM_MMC_OPS are defined:
- Block device numbering does not always following MMC device numbering
- Environment in MMC does not always work correctly
In addition some parts of the code can be implemented in a better way.
This series fixes the above problems, adds a few tests and converts Tegra over to use CONFIG_BLK and CONFIG_DM_MMC_OPS.
As far as I can see this series doesn't change power flow for MMC anyhow. If it's true, take my Reviewed-by: Andy Shevchenko andy.shevchenko@gmail.com
Simon Glass (8): dm: mmc: Don't re-init when accessing environment dm: blk: Allow finding block devices without probing dm: blk: Add a function to find the next block device number dm: blk: Improve block device claiming dm: mmc: Avoid probing block devices in find_mmc_device() dm: mmc: Check that drivers have operations dm: mmc: Rewrite mmc_blk_probe() tegra: Convert MMC to use driver model for operations
arch/sandbox/dts/test.dts | 12 +++++- board/toradex/common/tdx-cfg-block.c | 2 +- common/env_mmc.c | 3 +- configs/apalis-tk1_defconfig | 2 - configs/apalis_t30_defconfig | 2 - configs/beaver_defconfig | 2 - configs/cardhu_defconfig | 2 - configs/cei-tk1-som_defconfig | 2 - configs/colibri_t20_defconfig | 2 - configs/colibri_t30_defconfig | 2 - configs/dalmore_defconfig | 2 - configs/e2220-1170_defconfig | 2 - configs/harmony_defconfig | 2 - configs/jetson-tk1_defconfig | 2 - configs/medcom-wide_defconfig | 2 - configs/nyan-big_defconfig | 2 - configs/p2371-0000_defconfig | 2 - configs/p2371-2180_defconfig | 2 - configs/p2571_defconfig | 2 - configs/p2771-0000-000_defconfig | 2 - configs/p2771-0000-500_defconfig | 2 - configs/paz00_defconfig | 2 - configs/plutux_defconfig | 2 - configs/seaboard_defconfig | 2 - configs/tec-ng_defconfig | 2 - configs/tec_defconfig | 2 - configs/trimslice_defconfig | 2 - configs/venice2_defconfig | 2 - configs/ventana_defconfig | 2 - configs/whistler_defconfig | 2 - drivers/block/blk-uclass.c | 65 ++++++++++++++++++++++++++++---- drivers/mmc/mmc-uclass.c | 27 ++++++++++---- drivers/mmc/tegra_mmc.c | 72 ++++++++++++++++++++---------------- include/blk.h | 15 +++++++- test/dm/blk.c | 60 +++++++++++++++++++++++++++++- 35 files changed, 203 insertions(+), 107 deletions(-)
-- 2.12.2.816.g2cccc81164-goog
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot
participants (7)
-
Andy Shevchenko
-
Jean-Jacques Hiblot
-
Marcel Ziswiler
-
Simon Glass
-
Simon Glass
-
sjg@google.com
-
Tom Warren