Skip to contentSkip to conversation

Support for eMMC partitioning and related fixes

PATCH New Diego Santa Cruz 3 participants 28 messages Dec 23, 2014 – Jan 23, 2015 MMC, SD and SDIO

lore
Share & tools
lore
#0 lore raw

v4 cover Support for eMMC partitioning and related fixes

I have the need to hardware partition eMMC devices from U-Boot along with setting enhanced and reliable write attributes.

This series of patches adds this support to U-Boot via a new mmc API, a few new members of struct mmc and a new mmc sub-command. It also features several fixes to the eMMC hardware partition support. I have tested this with Micron eMMC 4.41 parts and it is working as expected.

This version resyncs to u-boot.git master d8bec60c1b0de7770f9b56ad092ab9be801d99af as some recent mmc changes conflicted with these patches, in particular the DDR mode support.

Diego Santa Cruz (18):
mmc: show hardware partition sizes in mmcinfo output
mmc: extend mmcinfo to show enhanced partition attribute
mmc: make eMMC general purpose partition numbering match spec
mmc: skip mmcinfo partition info processing for eMMC < 4.41
mmc: incomplete test to switch to high-capacity group size definitions
mmc: computation of eMMC GP partition size was missing 512 KiB factor
mmc: read the size of eMMC enhanced user data area
mmc: display size and start of eMMC enhanced user data area in mmcinfo
mmc: fix erase_grp_size computation with high-capacity size definition
mmc: read the high capacity WP group size for eMMC
mmc: show the erase group size and HC WP group size in mmcinfo output
mmc: eMMC partitioning data is not effective till partitioning
completed
mmc: the ext_csd data may be used during init even if reading failed
mmc: add API to do eMMC hardware partitioning
mmc: add mmc hwpartition sub-command to do eMMC hardware partitioning
mmc: extend the mmc hardware partitioning API with write reliability
mmc: extend the mmc hwpartition sub-command to change write
reliability
mmc: extend mmcinfo output to show partition write reliability
settings

 common/cmd_mmc.c  | 207 ++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/mmc.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 include/mmc.h     |  45 ++++++++-
 3 files changed, 515 insertions(+), 25 deletions(-)
Signature · 1 line
2.2.1
#1 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

There is currently no command that will provide an overview of the hardware partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

---
 common/cmd_mmc.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
common/cmd_mmc.c +17 -0
index 96478e4..fa765d7 100644
@@ -73,6 +73,8 @@ U_BOOT_CMD(
 
 static void print_mmcinfo(struct mmc *mmc)
 {
+	int i;
+
 	printf("Device: %s\n", mmc->cfg->name);
 	printf("Manufacturer ID: %x\n", mmc->cid[0] >> 24);
 	printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff);
@@ -92,6 +94,21 @@ static void print_mmcinfo(struct mmc *mmc)
 
 	printf("Bus Width: %d-bit%s\n", mmc->bus_width,
 			mmc->ddr_mode ? " DDR" : "");
+
+	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
+		puts("User Capacity: ");
+		print_size(mmc->capacity_user, "\n");
+		puts("Boot Capacity: ");
+		print_size(mmc->capacity_boot, "\n");
+		puts("RPMB Capacity: ");
+		print_size(mmc->capacity_rpmb, "\n");
+		for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) {
+			if (mmc->capacity_gp[i]) {
+				printf("GP%i Capacity: ", i);
+				print_size(mmc->capacity_gp[i], "\n");
+			}
+		}
+	}
 }
 static struct mmc *init_mmc_device(int dev, bool force_init)
 {
Signature · 1 line
2.2.1
#2 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

Hi Diego,

Quoted 67 lines · Diego Santa Cruz

There is currently no command that will provide an overview of the hardware partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

---
common/cmd_mmc.c | 17 +++++++++++++++++

1 file changed, 17 insertions(+)
common/cmd_mmc.c +17 -0
index 96478e4..fa765d7 100644
@@ -73,6 +73,8 @@ U_BOOT_CMD(
 
 static void print_mmcinfo(struct mmc *mmc)
 {
+	int i;
+
 	printf("Device: %s\n", mmc->cfg->name);
 	printf("Manufacturer ID: %x\n", mmc->cid[0] >> 24);
 	printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff);
@@ -92,6 +94,21 @@ static void print_mmcinfo(struct mmc *mmc)
 
 	printf("Bus Width: %d-bit%s\n", mmc->bus_width,
 			mmc->ddr_mode ? " DDR" : "");
+
+	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
+		puts("User Capacity: ");
+		print_size(mmc->capacity_user, "\n");
+		puts("Boot Capacity: ");
+		print_size(mmc->capacity_boot, "\n");
+		puts("RPMB Capacity: ");
+		print_size(mmc->capacity_rpmb, "\n");
+		for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) {
+			if (mmc->capacity_gp[i]) {
+				printf("GP%i Capacity: ", i);
+				print_size(mmc->capacity_gp[i], "\n");
+			}
+		}
+	}
 }
 static struct mmc *init_mmc_device(int dev, bool force_init)
 {
Signature · 1 line
2.2.1

Applied with a minor edit removing the superfluous parentheses.

? Pantelis

#3 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

In reply to Diego Santa Cruz
Quoted 6 lines · Diego Santa Cruz

There is currently no command that will provide an overview of the hardware partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Quoted 15 lines

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

I have an MMC device which has at least boot HW partitions, yet with the very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

#4 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

Hi Stephen,

Quoted 46 lines · Stephen Warren
Quoted 6 lines · Diego Santa Cruz

There is currently no command that will provide an overview of the hardware partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Quoted 15 lines

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

I have an MMC device which has at least boot HW partitions, yet with the very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Quoted 15 lines

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

That is really weird; are you sure you got the latest version of u-boot containing those patches?

Quoted 2 lines
      if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {

The test for printing out the capacities is as above, you should get the printouts.

Interesting; for reference on beaglebone black I get for the onboard eMMC:

Quoted 9 lines

mmc1(part 0) is current device U-Boot# mmc info
Device: OMAP SD/MMC Manufacturer ID: fe
OEM: 14e
Name: MMC02
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41

Quoted 8 lines

High Capacity: No
Capacity: 1.8 GiB
Bus Width: 4-bit
Erase Group Size: 512 KiB
HC WP Group Size: 0 Bytes User Capacity: 1.8 GiB
Boot Capacity: 1 MiB ENH RPMB Capacity: 128 KiB ENH

Regards

? Pantelis

#5 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

Quoted 64 lines · Pantelis Antoniou

Hi Stephen,

Quoted 46 lines · Stephen Warren
Quoted 6 lines · Diego Santa Cruz

There is currently no command that will provide an overview of the hardware partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Quoted 15 lines

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

I have an MMC device which has at least boot HW partitions, yet with the very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Quoted 15 lines

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

Quoted 4 lines

That is really weird; are you sure you got the latest version of u-boot containing those patches?

Quoted 1 line
       if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {

Ah, my device is MMC 4.5, and the version numbers aren't monotonic:

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)

Should that be 0x450, or do we need some more complex version comparison logic?

FWIW, if I hack the test you quoted to always pass, then the data that's printed looks plausible. At the very least, the boot capacity agrees with Linux.

#6 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

Hi Stephen,

Quoted 70 lines · Stephen Warren
Quoted 67 lines · Pantelis Antoniou

Hi Stephen,

Quoted 46 lines · Stephen Warren
Quoted 6 lines · Diego Santa Cruz

There is currently no command that will provide an overview of the hardware partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Quoted 15 lines

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

I have an MMC device which has at least boot HW partitions, yet with the very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Quoted 15 lines

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

That is really weird; are you sure you got the latest version of u-boot containing those patches?

Quoted 7 lines
Quoted 1 line
Quoted 1 line
      if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {

Ah, my device is MMC 4.5, and the version numbers aren't monotonic:

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)

Gah. That?s bad. I believe that?s a bug.

Quoted 2 lines

Should that be 0x450, or do we need some more complex version comparison logic?

Frankly I hope not. 0x450 should be used. But that would require changing all the others version definitions cause for instance MMC_VERSION_4_1 = 0x401.

Quoted 1 line

FWIW, if I hack the test you quoted to always pass, then the data that's printed looks plausible. At the very least, the boot capacity agrees with Linux.

Thanks for the report; I?ll get it fixed.

Regards

? Pantelis

#7 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

In reply to Stephen Warren
Quoted 87 lines

-----Original Message-----
From: Stephen Warren [mailto:swarren at wwwdotorg.org]
Sent: Thursday, January 22, 2015 8:59 PM
To: Pantelis Antoniou
Cc: Diego Santa Cruz; u-boot at lists.denx.de
Subject: Re: [U-Boot] [PATCH v4 01/18] mmc: show hardware partition sizes in mmcinfo output

Quoted 6 lines · Pantelis Antoniou

Hi Stephen,

Quoted 4 lines · Stephen Warren
Quoted 1 line · Diego Santa Cruz

There is currently no command that will provide an overview of the

hardware

Quoted 21 lines
Quoted 21 lines
Quoted 20 lines

partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

Quoted 1 line
Quoted 1 line

I have an MMC device which has at least boot HW partitions, yet with the

very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Quoted 36 lines
Quoted 20 lines

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Quoted 15 lines

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

Quoted 4 lines

That is really weird; are you sure you got the latest version of u-boot containing those patches?

Quoted 1 line
       if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {

Ah, my device is MMC 4.5, and the version numbers aren't monotonic:

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)

Quoted 6 lines

Should that be 0x450, or do we need some more complex version comparison logic?

FWIW, if I hack the test you quoted to always pass, then the data that's printed looks plausible. At the very least, the boot capacity agrees with Linux.

Thanks for spotting this, looking at all the defines in mmc.h they are

#define MMC_VERSION_UNKNOWN (MMC_VERSION_MMC)

#define MMC_VERSION_1_2		(MMC_VERSION_MMC | 0x102)
#define MMC_VERSION_1_4		(MMC_VERSION_MMC | 0x104)
#define MMC_VERSION_2_2		(MMC_VERSION_MMC | 0x202)
#define MMC_VERSION_3		(MMC_VERSION_MMC | 0x300)
#define MMC_VERSION_4		(MMC_VERSION_MMC | 0x400)
#define MMC_VERSION_4_1		(MMC_VERSION_MMC | 0x401)
#define MMC_VERSION_4_2		(MMC_VERSION_MMC | 0x402)
#define MMC_VERSION_4_3		(MMC_VERSION_MMC | 0x403)

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)
#define MMC_VERSION_5_0 (MMC_VERSION_MMC | 0x500)

I do not get it why MMC_VERSION_4_41 is 0x429, it should be 0x404 to follow the sequence.

Wouldn't it be sane to change it to be

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x404)

I checked mmc_startup() and these defines are not matching bitfields in CSD nor EXT_CSD, so I think it should be safe to change them.

Best,

Diego

--
Diego Santa Cruz, PhD
Technology Architect
T +41 21 341 15 50
diego.santacruz at spinetix.com
spinetix.com

#8 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

Hi Diego,

Quoted 111 lines · Diego Santa Cruz
Quoted 88 lines

-----Original Message-----
From: Stephen Warren [mailto:swarren at wwwdotorg.org]
Sent: Thursday, January 22, 2015 8:59 PM
To: Pantelis Antoniou
Cc: Diego Santa Cruz; u-boot at lists.denx.de
Subject: Re: [U-Boot] [PATCH v4 01/18] mmc: show hardware partition sizes in mmcinfo output

Quoted 6 lines · Pantelis Antoniou

Hi Stephen,

Quoted 4 lines · Stephen Warren
Quoted 1 line · Diego Santa Cruz

There is currently no command that will provide an overview of the

hardware

Quoted 21 lines
Quoted 21 lines
Quoted 20 lines

partitions present on an eMMC device, one has to switch to every partition via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

Quoted 1 line
Quoted 1 line

I have an MMC device which has at least boot HW partitions, yet with the

very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Quoted 36 lines
Quoted 20 lines

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Quoted 15 lines

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

Quoted 4 lines

That is really weird; are you sure you got the latest version of u-boot containing those patches?

Quoted 1 line
      if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {

Ah, my device is MMC 4.5, and the version numbers aren't monotonic:

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)

Quoted 6 lines

Should that be 0x450, or do we need some more complex version comparison logic?

FWIW, if I hack the test you quoted to always pass, then the data that's printed looks plausible. At the very least, the boot capacity agrees with Linux.

Thanks for spotting this, looking at all the defines in mmc.h they are

#define MMC_VERSION_UNKNOWN (MMC_VERSION_MMC)

#define MMC_VERSION_1_2		(MMC_VERSION_MMC | 0x102)
#define MMC_VERSION_1_4		(MMC_VERSION_MMC | 0x104)
#define MMC_VERSION_2_2		(MMC_VERSION_MMC | 0x202)
#define MMC_VERSION_3		(MMC_VERSION_MMC | 0x300)
#define MMC_VERSION_4		(MMC_VERSION_MMC | 0x400)
#define MMC_VERSION_4_1		(MMC_VERSION_MMC | 0x401)
#define MMC_VERSION_4_2		(MMC_VERSION_MMC | 0x402)
#define MMC_VERSION_4_3		(MMC_VERSION_MMC | 0x403)

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)
#define MMC_VERSION_5_0 (MMC_VERSION_MMC | 0x500)

Quoted 8 lines

I do not get it why MMC_VERSION_4_41 is 0x429, it should be 0x404 to follow the sequence.

Wouldn't it be sane to change it to be

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x404)

I checked mmc_startup() and these defines are not matching bitfields in CSD nor EXT_CSD, so I think it should be safe to change them.

Changing them is one thing; we have to change the version printout too.

Quoted 4 lines

Best,

Diego

Regards

? Pantelis

Quoted 7 lines

--
Diego Santa Cruz, PhD
Technology Architect
T +41 21 341 15 50
diego.santacruz at spinetix.com
spinetix.com

#9 lore raw

PATCH v4 1/18 mmc: show hardware partition sizes in mmcinfo output

Quoted 130 lines

-----Original Message-----
From: Pantelis Antoniou [mailto:panto at antoniou-consulting.com]
Sent: Friday, January 23, 2015 9:35 AM
To: Diego Santa Cruz
Cc: Stephen Warren; u-boot at lists.denx.de
Subject: Re: [U-Boot] [PATCH v4 01/18] mmc: show hardware partition sizes in mmcinfo output

Hi Diego,

Quoted 1 line

On Jan 23, 2015, at 10:30 , Diego Santa Cruz <[email protected]>

Quoted 7 lines · wrote:
Quoted 7 lines

-----Original Message-----
From: Stephen Warren [mailto:swarren at wwwdotorg.org]
Sent: Thursday, January 22, 2015 8:59 PM
To: Pantelis Antoniou
Cc: Diego Santa Cruz; u-boot at lists.denx.de
Subject: Re: [U-Boot] [PATCH v4 01/18] mmc: show hardware partition sizes

in

Quoted 11 lines
Quoted 11 lines

mmcinfo output

Quoted 6 lines · Pantelis Antoniou

Hi Stephen,

Quoted 4 lines · Stephen Warren
Quoted 1 line · Diego Santa Cruz

There is currently no command that will provide an overview of the

hardware

Quoted 1 line
Quoted 1 line
Quoted 1 line

partitions present on an eMMC device, one has to switch to every

partition

Quoted 88 lines
Quoted 70 lines
Quoted 20 lines
Quoted 20 lines
Quoted 19 lines

via "mmc dev" and run mmcinfo for each to get the partition's capacity. This commit adds a few lines of output to mmcinfo with the sizes of the present partitions, like this:

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB
Boot Capacity: 16 MiB
RPMB Capacity: 128 KiB
GP1 Capacity: 64 MiB
GP2 Capacity: 64 MiB

Quoted 1 line
Quoted 1 line

I have an MMC device which has at least boot HW partitions, yet with the

very latest code in u-boot.git, I don't see the additional lines mentioned above. My HW partitions are still working fine, since I can select a boot partition and mmcinfo shows the correct "Capacity" for it:

Quoted 36 lines
Quoted 20 lines

Any ideas why?

Tegra124 (Jetson TK1) # mmc dev 0
switch to partitions #0, OK
mmc0(part 0) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 14.7 GiB <<<< Sounds right for a 16GB device with partitions Bus Width: 8-bit
Erase Group Size: 512 KiB
<<<< No HW partition information is printed here

Quoted 15 lines

Tegra124 (Jetson TK1) # mmc dev 0 1 <<<< select "boot0" HW partition switch to partitions #1, OK
mmc0(part 1) is current device
Tegra124 (Jetson TK1) # mmcinfo
Device: Tegra SD/MMC
Manufacturer ID: 45
OEM: 100
Name: SEM16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.5
High Capacity: Yes
Capacity: 4 MiB <<<< "boot0" partition size correctly reported Bus Width: 8-bit
Erase Group Size: 512 KiB

Quoted 4 lines

That is really weird; are you sure you got the latest version of u-boot containing those patches?

Quoted 1 line
      if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {

Ah, my device is MMC 4.5, and the version numbers aren't monotonic:

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)

Quoted 6 lines

Should that be 0x450, or do we need some more complex version comparison logic?

FWIW, if I hack the test you quoted to always pass, then the data that's printed looks plausible. At the very least, the boot capacity agrees with Linux.

Thanks for spotting this, looking at all the defines in mmc.h they are

#define MMC_VERSION_UNKNOWN (MMC_VERSION_MMC)

#define MMC_VERSION_1_2		(MMC_VERSION_MMC | 0x102)
#define MMC_VERSION_1_4		(MMC_VERSION_MMC | 0x104)
#define MMC_VERSION_2_2		(MMC_VERSION_MMC | 0x202)
#define MMC_VERSION_3		(MMC_VERSION_MMC | 0x300)
#define MMC_VERSION_4		(MMC_VERSION_MMC | 0x400)
#define MMC_VERSION_4_1		(MMC_VERSION_MMC | 0x401)
#define MMC_VERSION_4_2		(MMC_VERSION_MMC | 0x402)
#define MMC_VERSION_4_3		(MMC_VERSION_MMC | 0x403)
Quoted 5 lines

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x429)
#define MMC_VERSION_4_5 (MMC_VERSION_MMC | 0x405)
#define MMC_VERSION_5_0 (MMC_VERSION_MMC | 0x500)

I do not get it why MMC_VERSION_4_41 is 0x429, it should be 0x404 to follow

the sequence.

Quoted 3 lines

Wouldn't it be sane to change it to be

Quoted 8 lines
Quoted 3 lines

#define MMC_VERSION_4_41 (MMC_VERSION_MMC | 0x404)

I checked mmc_startup() and these defines are not matching bitfields in CSD

nor EXT_CSD, so I think it should be safe to change them.

Quoted 1 line

Changing them is one thing; we have to change the version printout too.

Of course, dumb me..., forget my idea. So changing the others to 0x410, 0x420, ... 0x450, etc., as you propose, would keep version comparisons as they are and the version printout would be easier to handle.

Thanks for volunteering to fix it.

Regards,

Diego

Signature · 3 lines
Diego Santa Cruz, PhD
Technology Architect
spinetix.com
#10 lore raw

PATCH v4 2/18 mmc: extend mmcinfo to show enhanced partition attribute

In reply to Diego Santa Cruz

This extends the mmcinfo command's output to show which eMMC partitions have the enhanced attribute set. Note that the eMMC spec says that if the enhanced attribute is supported then the boot and RPMB partitions are of the enhanced type.

The output of mmcinfo becomes:
Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
User Capacity: 13.8 GiB ENH
Boot Capacity: 16 MiB ENH
RPMB Capacity: 128 KiB ENH
GP1 Capacity: 64 MiB ENH
GP2 Capacity: 64 MiB ENH

---
 common/cmd_mmc.c  | 14 ++++++++++----
 drivers/mmc/mmc.c |  3 +++
 include/mmc.h     |  6 ++++++
 3 files changed, 19 insertions(+), 4 deletions(-)
common/cmd_mmc.c +10 -4
index fa765d7..18cfe09 100644
@@ -96,16 +96,22 @@ static void print_mmcinfo(struct mmc *mmc)
 			mmc->ddr_mode ? " DDR" : "");
 
 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
+		bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
 		puts("User Capacity: ");
-		print_size(mmc->capacity_user, "\n");
+		print_size(mmc->capacity_user,
+			   has_enh && (mmc->part_attr & EXT_CSD_ENH_USR) ?
+			   " ENH\n" : "\n");
 		puts("Boot Capacity: ");
-		print_size(mmc->capacity_boot, "\n");
+		print_size(mmc->capacity_boot, has_enh ? " ENH\n" : "\n");
 		puts("RPMB Capacity: ");
-		print_size(mmc->capacity_rpmb, "\n");
+		print_size(mmc->capacity_rpmb, has_enh ? " ENH\n" : "\n");
 		for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) {
+			bool is_enh = has_enh &&
+				(mmc->part_attr & EXT_CSD_ENH_GP(i));
 			if (mmc->capacity_gp[i]) {
 				printf("GP%i Capacity: ", i);
-				print_size(mmc->capacity_gp[i], "\n");
+				print_size(mmc->capacity_gp[i],
+					   is_enh ? " ENH\n" : "\n");
 			}
 		}
 	}
drivers/mmc/mmc.c +3 -0
index 1eb9c27..9ce15d0 100644
@@ -1050,9 +1050,12 @@ static int mmc_startup(struct mmc *mmc)
 		}
 
 		/* store the partition info of emmc */
+		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
 		    ext_csd[EXT_CSD_BOOT_MULT])
 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+		if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)
+			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
 
 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
 
include/mmc.h +6 -0
index 7ec255d..69c6070 100644
@@ -201,6 +201,9 @@
 
 #define EXT_CSD_PARTITION_SETTING_COMPLETED	(1 << 0)
 
+#define EXT_CSD_ENH_USR		(1 << 0)	/* user data area is enhanced */
+#define EXT_CSD_ENH_GP(x)	(1 << ((x)+1))	/* GP part (x+1) is enhanced */
+
 #define R1_ILLEGAL_COMMAND		(1 << 22)
 #define R1_APP_CMD			(1 << 5)
 
@@ -224,6 +227,7 @@
 #define MMCPART_NOAVAILABLE	(0xff)
 #define PART_ACCESS_MASK	(0x7)
 #define PART_SUPPORT		(0x1)
+#define ENHNCD_SUPPORT		(0x2)
 #define PART_ENH_ATTRIB		(0x1f)
 
 /* Maximum block size for MMC */
@@ -302,6 +306,8 @@ struct mmc {
 	uint csd[4];
 	uint cid[4];
 	ushort rca;
+	u8 part_support;
+	u8 part_attr;
 	char part_config;
 	char part_num;
 	uint tran_speed;
Signature · 1 line
2.2.1
#11 lore raw

PATCH v4 3/18 mmc: make eMMC general purpose partition numbering match spec

In reply to Diego Santa Cruz

The eMMC spec numbers general purpose partitions starting at 1, but the mmcinfo output follows the internal numbering which starts at 0. Make the mmcinfo command output number partitions as in the eMMC spec to avoid confusion.

---
 common/cmd_mmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
common/cmd_mmc.c +1 -1
index 18cfe09..10315b8 100644
@@ -109,7 +109,7 @@ static void print_mmcinfo(struct mmc *mmc)
 			bool is_enh = has_enh &&
 				(mmc->part_attr & EXT_CSD_ENH_GP(i));
 			if (mmc->capacity_gp[i]) {
-				printf("GP%i Capacity: ", i);
+				printf("GP%i Capacity: ", i+1);
 				print_size(mmc->capacity_gp[i],
 					   is_enh ? " ENH\n" : "\n");
 			}
Signature · 1 line
2.2.1
#12 lore raw

PATCH v4 4/18 mmc: skip mmcinfo partition info processing for eMMC < 4.41

In reply to Diego Santa Cruz

eMMC partitions are defined as of eMMC 4.41, but mmcinfo process partition info for eMMC >= 4.0, change it to do it for >= 4.41

---
 common/cmd_mmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
common/cmd_mmc.c +1 -1
index 10315b8..3f8dbdb 100644
@@ -95,7 +95,7 @@ static void print_mmcinfo(struct mmc *mmc)
 	printf("Bus Width: %d-bit%s\n", mmc->bus_width,
 			mmc->ddr_mode ? " DDR" : "");
 
-	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
+	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4_41)) {
 		bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
 		puts("User Capacity: ");
 		print_size(mmc->capacity_user,
Signature · 1 line
2.2.1
#13 lore raw

PATCH v4 5/18 mmc: incomplete test to switch to high-capacity group size definitions

In reply to Diego Santa Cruz

The eMMC spec mandates that the high-capacity group size definitions should be enabled when the device is partitioned (by setting ERASE_GROUP_DEF in EXT_CSD). The current test to determine when this is required misses a few cases. In particular a device may have been partitioned without setting the enhanced attribute on any partition or partitioning may be completed without creating any extra partitions.

This change moves the code to set ERASE_GROUP_DEF to after reading all partition information. It is also enabled when PARTITIONING_SETTING_COMPLETED is set as it is necessary to enable ERASE_GROUP_DEF before setting that bit, so it means that the user previously switched to the high capacity definitions.

---
 drivers/mmc/mmc.c | 52 ++++++++++++++++++++++++++++++----------------------
 1 file changed, 30 insertions(+), 22 deletions(-)
drivers/mmc/mmc.c +30 -22
index 9ce15d0..5e9926c 100644
@@ -818,6 +818,7 @@ static int mmc_startup(struct mmc *mmc)
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
 	int timeout = 1000;
+	bool has_parts = false;
 
 #ifdef CONFIG_MMC_SPI_CRC_ON
 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -1006,13 +1007,41 @@ static int mmc_startup(struct mmc *mmc)
 			break;
 		}
 
+		/* store the partition info of emmc */
+		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
+		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+		    ext_csd[EXT_CSD_BOOT_MULT])
+			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+		if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)
+			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
+
+		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+		for (i = 0; i < 4; i++) {
+			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
+				(ext_csd[idx + 1] << 8) + ext_csd[idx];
+			mmc->capacity_gp[i] *=
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+			if (mmc->capacity_gp[i])
+				has_parts = true;
+		}
+
 		/*
 		 * Host needs to enable ERASE_GRP_DEF bit if device is
 		 * partitioned. This bit will be lost every time after a reset
 		 * or power off. This will affect erase size.
 		 */
+		if (ext_csd[EXT_CSD_PARTITION_SETTING] &
+		    EXT_CSD_PARTITION_SETTING_COMPLETED)
+			has_parts = true;
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
-		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
+		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
+			has_parts = true;
+		if (has_parts) {
 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_ERASE_GROUP_DEF, 1);
 
@@ -1048,27 +1077,6 @@ static int mmc_startup(struct mmc *mmc)
 			mmc->erase_grp_size = (erase_gsz + 1)
 				* (erase_gmul + 1);
 		}
-
-		/* store the partition info of emmc */
-		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
-		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
-		    ext_csd[EXT_CSD_BOOT_MULT])
-			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
-		if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)
-			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
-
-		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
-
-		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
-
-		for (i = 0; i < 4; i++) {
-			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
-			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
-				(ext_csd[idx + 1] << 8) + ext_csd[idx];
-			mmc->capacity_gp[i] *=
-				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
-			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-		}
 	}
 
 	err = mmc_set_capacity(mmc, mmc->part_num);
Signature · 1 line
2.2.1
#14 lore raw

PATCH v4 6/18 mmc: computation of eMMC GP partition size was missing 512 KiB factor

In reply to Diego Santa Cruz
---
 drivers/mmc/mmc.c | 1 +
 1 file changed, 1 insertion(+)
drivers/mmc/mmc.c +1 -0
index 5e9926c..86c4db9 100644
@@ -1026,6 +1026,7 @@ static int mmc_startup(struct mmc *mmc)
 			mmc->capacity_gp[i] *=
 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+			mmc->capacity_gp[i] <<= 19;
 			if (mmc->capacity_gp[i])
 				has_parts = true;
 		}
Signature · 1 line
2.2.1
#15 lore raw

PATCH v4 7/18 mmc: read the size of eMMC enhanced user data area

In reply to Diego Santa Cruz

This modification reads the size of the eMMC enhanced user data area upon initialization of an mmc device, it will be used later by mmcinfo.

---
 drivers/mmc/mmc.c | 15 +++++++++++++++
 include/mmc.h     |  4 ++++
 2 files changed, 19 insertions(+)
drivers/mmc/mmc.c +15 -0
index 86c4db9..f07505f 100644
@@ -1031,6 +1031,21 @@ static int mmc_startup(struct mmc *mmc)
 				has_parts = true;
 		}
 
+		mmc->enh_user_size =
+			(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
+			(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
+			ext_csd[EXT_CSD_ENH_SIZE_MULT];
+		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+		mmc->enh_user_size <<= 19;
+		mmc->enh_user_start =
+			(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
+			(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
+			(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
+			ext_csd[EXT_CSD_ENH_START_ADDR];
+		if (mmc->high_capacity)
+			mmc->enh_user_start <<= 9;
+
 		/*
 		 * Host needs to enable ERASE_GRP_DEF bit if device is
 		 * partitioned. This bit will be lost every time after a reset
include/mmc.h +4 -0
index 69c6070..18155c9 100644
@@ -147,6 +147,8 @@
 /*
  * EXT_CSD fields
  */
+#define EXT_CSD_ENH_START_ADDR		136	/* R/W */
+#define EXT_CSD_ENH_SIZE_MULT		140	/* R/W */
 #define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
 #define EXT_CSD_PARTITION_SETTING	155	/* R/W */
 #define EXT_CSD_PARTITIONS_ATTRIBUTE	156	/* R/W */
@@ -319,6 +321,8 @@ struct mmc {
 	u64 capacity_boot;
 	u64 capacity_rpmb;
 	u64 capacity_gp[4];
+	u64 enh_user_start;
+	u64 enh_user_size;
 	block_dev_desc_t block_dev;
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */
Signature · 1 line
2.2.1
#16 lore raw

PATCH v4 8/18 mmc: display size and start of eMMC enhanced user data area in mmcinfo

In reply to Diego Santa Cruz

This adds output to show the eMMC enhanced user data area size and offset along with the partition sizes in mmcinfo's output.

---
 common/cmd_mmc.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
common/cmd_mmc.c +8 -3
index 3f8dbdb..6b0a35f 100644
@@ -97,10 +97,15 @@ static void print_mmcinfo(struct mmc *mmc)
 
 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4_41)) {
 		bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
+		bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR);
 		puts("User Capacity: ");
-		print_size(mmc->capacity_user,
-			   has_enh && (mmc->part_attr & EXT_CSD_ENH_USR) ?
-			   " ENH\n" : "\n");
+		print_size(mmc->capacity_user, usr_enh ? " ENH\n" : "\n");
+		if (usr_enh) {
+			puts("User Enhanced Start: ");
+			print_size(mmc->enh_user_start, "\n");
+			puts("User Enhanced Size: ");
+			print_size(mmc->enh_user_size, "\n");
+		}
 		puts("Boot Capacity: ");
 		print_size(mmc->capacity_boot, has_enh ? " ENH\n" : "\n");
 		puts("RPMB Capacity: ");
Signature · 1 line
2.2.1
#17 lore raw

PATCH v4 9/18 mmc: fix erase_grp_size computation with high-capacity size definition

In reply to Diego Santa Cruz

The erase_grp_size in struct mmc is to be a size in 512-byte sectors but the code used to compute it for eMMC when EXT_CSD_ERASE_GROUP_DEF is enabled computed it as bytes, leading to erase sizes and alignment much larger than what is actually required by the mmc device.

---
 drivers/mmc/mmc.c | 3 +--
 include/mmc.h     | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/mmc/mmc.c +1 -2
index f07505f..be21101 100644
@@ -1068,8 +1068,7 @@ static int mmc_startup(struct mmc *mmc)
 
 			/* Read out group size from ext_csd */
 			mmc->erase_grp_size =
-				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
-					MMC_MAX_BLOCK_LEN * 1024;
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
 			/*
 			 * if high capacity and partition setting completed
 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
include/mmc.h +1 -1
index 18155c9..6c8bbfc 100644
@@ -315,7 +315,7 @@ struct mmc {
 	uint tran_speed;
 	uint read_bl_len;
 	uint write_bl_len;
-	uint erase_grp_size;
+	uint erase_grp_size;	/* in 512-byte sectors */
 	u64 capacity;
 	u64 capacity_user;
 	u64 capacity_boot;
Signature · 1 line
2.2.1
#18 lore raw

PATCH v4 10/18 mmc: read the high capacity WP group size for eMMC

In reply to Diego Santa Cruz

Read the eMMC high capacity write protect group size at mmc device initialization. This is useful to correctly partition an eMMC device, as partitions need to be aligned to this size.

---
 drivers/mmc/mmc.c | 6 ++++++
 include/mmc.h     | 1 +
 2 files changed, 7 insertions(+)
drivers/mmc/mmc.c +6 -0
index be21101..16a7a90 100644
@@ -1065,7 +1065,9 @@ static int mmc_startup(struct mmc *mmc)
 				return err;
 			else
 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+		}
 
+		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
 			/* Read out group size from ext_csd */
 			mmc->erase_grp_size =
 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
@@ -1092,6 +1094,10 @@ static int mmc_startup(struct mmc *mmc)
 			mmc->erase_grp_size = (erase_gsz + 1)
 				* (erase_gmul + 1);
 		}
+
+		mmc->hc_wp_grp_size = 1024
+			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
 	}
 
 	err = mmc_set_capacity(mmc, mmc->part_num);
include/mmc.h +1 -0
index 6c8bbfc..bcaf9f0 100644
@@ -316,6 +316,7 @@ struct mmc {
 	uint read_bl_len;
 	uint write_bl_len;
 	uint erase_grp_size;	/* in 512-byte sectors */
+	uint hc_wp_grp_size;	/* in 512-byte sectors */
 	u64 capacity;
 	u64 capacity_user;
 	u64 capacity_boot;
Signature · 1 line
2.2.1
#19 lore raw

PATCH v4 11/18 mmc: show the erase group size and HC WP group size in mmcinfo output

In reply to Diego Santa Cruz

This adds the erase group size and high-capacity WP group size to mmcinfo's output. The erase group size is necessary to properly align erase requests on eMMC. The high-capacity WP group size is necessary to properly align partitions on eMMC.

---
 common/cmd_mmc.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
common/cmd_mmc.c +10 -0
index 6b0a35f..491a889 100644
@@ -95,9 +95,16 @@ static void print_mmcinfo(struct mmc *mmc)
 	printf("Bus Width: %d-bit%s\n", mmc->bus_width,
 			mmc->ddr_mode ? " DDR" : "");
 
+	puts("Erase Group Size: ");
+	print_size(((u64)mmc->erase_grp_size) << 9, "\n");
+
 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4_41)) {
 		bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
 		bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR);
+
+		puts("HC WP Group Size: ");
+		print_size(((u64)mmc->hc_wp_grp_size) << 9, "\n");
+
 		puts("User Capacity: ");
 		print_size(mmc->capacity_user, usr_enh ? " ENH\n" : "\n");
 		if (usr_enh) {
@@ -106,10 +113,13 @@ static void print_mmcinfo(struct mmc *mmc)
 			puts("User Enhanced Size: ");
 			print_size(mmc->enh_user_size, "\n");
 		}
+
 		puts("Boot Capacity: ");
 		print_size(mmc->capacity_boot, has_enh ? " ENH\n" : "\n");
+
 		puts("RPMB Capacity: ");
 		print_size(mmc->capacity_rpmb, has_enh ? " ENH\n" : "\n");
+
 		for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) {
 			bool is_enh = has_enh &&
 				(mmc->part_attr & EXT_CSD_ENH_GP(i));
Signature · 1 line
2.2.1
#20 lore raw

PATCH v4 12/18 mmc: eMMC partitioning data is not effective till partitioning completed

In reply to Diego Santa Cruz

The eMMC spec says that partitioning is only effective after the PARTITION_SETTING_COMPLETED is set in EXT_CSD (and a power cycle was done, but that we cannot know). Thus the partition sizes and attributes should be ignored when that bit is not set, otherwise the various capacities are not coherent (e.g., the user data capacity will be that of the unpartitioned device while partition sizes would be non-zero).

Prescence of non-zero partitioning data is nevertheless still used to activate the high-capacity size definitions (EXT_CSD_ERASE_GROUP_DEF) as it is necessary to set that to write any of the partitioning fields in EXT_CSD, so having partitioning data means someone previously activated that and we should keep it activated.

---
 drivers/mmc/mmc.c | 58 +++++++++++++++++++++++++++++++++----------------------
 1 file changed, 35 insertions(+), 23 deletions(-)
drivers/mmc/mmc.c +35 -23
index 16a7a90..403843b 100644
@@ -819,6 +819,7 @@ static int mmc_startup(struct mmc *mmc)
 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
 	int timeout = 1000;
 	bool has_parts = false;
+	bool part_completed;
 
 #ifdef CONFIG_MMC_SPI_CRC_ON
 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -1007,12 +1008,21 @@ static int mmc_startup(struct mmc *mmc)
 			break;
 		}
 
+		/* The partition data may be non-zero but it is only
+		 * effective if PARTITION_SETTING_COMPLETED is set in
+		 * EXT_CSD, so ignore any data if this bit is not set,
+		 * except for enabling the high-capacity group size
+		 * definition (see below). */
+		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
+				    EXT_CSD_PARTITION_SETTING_COMPLETED);
+
 		/* store the partition info of emmc */
 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
 		    ext_csd[EXT_CSD_BOOT_MULT])
 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
-		if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)
+		if (part_completed &&
+		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
 
 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
@@ -1021,38 +1031,42 @@ static int mmc_startup(struct mmc *mmc)
 
 		for (i = 0; i < 4; i++) {
 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
-			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
+			uint mult = (ext_csd[idx + 2] << 16) +
 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
+			if (mult)
+				has_parts = true;
+			if (!part_completed)
+				continue;
+			mmc->capacity_gp[i] = mult;
 			mmc->capacity_gp[i] *=
 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
 			mmc->capacity_gp[i] <<= 19;
-			if (mmc->capacity_gp[i])
-				has_parts = true;
 		}
 
-		mmc->enh_user_size =
-			(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
-			(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
-			ext_csd[EXT_CSD_ENH_SIZE_MULT];
-		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
-		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-		mmc->enh_user_size <<= 19;
-		mmc->enh_user_start =
-			(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
-			(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
-			(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
-			ext_csd[EXT_CSD_ENH_START_ADDR];
-		if (mmc->high_capacity)
-			mmc->enh_user_start <<= 9;
+		if (part_completed) {
+			mmc->enh_user_size =
+				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
+				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
+				ext_csd[EXT_CSD_ENH_SIZE_MULT];
+			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+			mmc->enh_user_size <<= 19;
+			mmc->enh_user_start =
+				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
+				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
+				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
+				ext_csd[EXT_CSD_ENH_START_ADDR];
+			if (mmc->high_capacity)
+				mmc->enh_user_start <<= 9;
+		}
 
 		/*
 		 * Host needs to enable ERASE_GRP_DEF bit if device is
 		 * partitioned. This bit will be lost every time after a reset
 		 * or power off. This will affect erase size.
 		 */
-		if (ext_csd[EXT_CSD_PARTITION_SETTING] &
-		    EXT_CSD_PARTITION_SETTING_COMPLETED)
+		if (part_completed)
 			has_parts = true;
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
@@ -1076,9 +1090,7 @@ static int mmc_startup(struct mmc *mmc)
 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
 			 * JEDEC Standard JESD84-B45, 6.2.4
 			 */
-			if (mmc->high_capacity &&
-			    (ext_csd[EXT_CSD_PARTITION_SETTING] &
-			     EXT_CSD_PARTITION_SETTING_COMPLETED)) {
+			if (mmc->high_capacity && part_completed) {
 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
Signature · 1 line
2.2.1
#21 lore raw

PATCH v4 13/18 mmc: the ext_csd data may be used during init even if reading failed

In reply to Diego Santa Cruz

The mmc_startup() function uses the ext_csd data even if reading it from the mmc device failed. This bug was introduced in commit bc897b1d4d86597311430dbe7b3e6c807c8c53e5. We now bail out if reading it fails, this should not be a problem as ext_csd was introduced in MMC 4.0 and this code is conditional on MMC >= 4.0.

---
 drivers/mmc/mmc.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/mmc.c +3 -1
index 403843b..63a1e0c 100644
@@ -972,7 +972,9 @@ static int mmc_startup(struct mmc *mmc)
 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
 		/* check  ext_csd version and capacity */
 		err = mmc_send_ext_csd(mmc, ext_csd);
-		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
+		if (err)
+			return err;
+		if (ext_csd[EXT_CSD_REV] >= 2) {
 			/*
 			 * According to the JEDEC Standard, the value of
 			 * ext_csd's capacity is valid if the value is more
Signature · 1 line
2.2.1
#22 lore raw

PATCH v4 14/18 mmc: add API to do eMMC hardware partitioning

In reply to Diego Santa Cruz

This adds an API to do hardware partitioning on eMMC devices. The new mmc_hwpart_config() function does the partitioning in one go. As the different attributes and partitioning options on eMMC may be interdependent validation has to be done based on the complete partitioning configuration. The function accepts three modes:

- MMC_HWPART_CONF_CHECK: just validates that the configuration is valid.
- MMC_HWPART_CONF_SET: validates and sets all the fields in EXT_CSD but without setting the "partitioning completed" bit, and thus is reversible.
- MMC_HWPART_CONF_COMPLETE: does everything and is thus not reversible.

---
 drivers/mmc/mmc.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/mmc.h     |  20 +++++++
 2 files changed, 175 insertions(+)
drivers/mmc/mmc.c +155 -0
index 63a1e0c..847e323 100644
@@ -605,6 +605,161 @@ int mmc_switch_part(int dev_num, unsigned int part_num)
 	return ret;
 }
 
+int mmc_hwpart_config(struct mmc *mmc,
+		      const struct mmc_hwpart_conf *conf,
+		      enum mmc_hwpart_conf_mode mode)
+{
+	u8 part_attrs = 0;
+	u32 enh_size_mult;
+	u32 enh_start_addr;
+	u32 gp_size_mult[4];
+	u32 max_enh_size_mult;
+	u32 tot_enh_size_mult = 0;
+	int i, pidx, err;
+	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+
+	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
+		return -EINVAL;
+
+	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
+		printf("eMMC >= 4.4 required for enhanced user data area\n");
+		return -EMEDIUMTYPE;
+	}
+
+	if ( ! (mmc->part_support & PART_SUPPORT) ) {
+		printf("Card does not support partitioning\n");
+		return -EMEDIUMTYPE;
+	}
+
+	if ( ! mmc->hc_wp_grp_size ) {
+		printf("Card does not define HC WP group size\n");
+		return -EMEDIUMTYPE;
+	}
+
+	/* check partition alignment and total enhanced size */
+	if (conf->user.enh_size) {
+		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
+		    conf->user.enh_start % mmc->hc_wp_grp_size) {
+			printf("User data enhanced area not HC WP group "
+			       "size aligned\n");
+			return -EINVAL;
+		}
+		part_attrs |= EXT_CSD_ENH_USR;
+		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
+		if (mmc->high_capacity) {
+			enh_start_addr = conf->user.enh_start;
+		} else {
+			enh_start_addr = (conf->user.enh_start << 9);
+		}
+	} else {
+		enh_size_mult = 0;
+		enh_start_addr = 0;
+	}
+	tot_enh_size_mult += enh_size_mult;
+
+	for (pidx = 0; pidx < 4; pidx++) {
+		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
+			printf("GP%i partition not HC WP group size "
+			       "aligned\n", pidx+1);
+			return -EINVAL;
+		}
+		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
+		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
+			part_attrs |= EXT_CSD_ENH_GP(pidx);
+			tot_enh_size_mult += gp_size_mult[pidx];
+		}
+	}
+
+	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
+		printf("Card does not support enhanced attribute\n");
+		return -EMEDIUMTYPE;
+	}
+
+	err = mmc_send_ext_csd(mmc, ext_csd);
+	if (err)
+		return err;
+
+	max_enh_size_mult =
+		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
+		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
+		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
+	if (tot_enh_size_mult > max_enh_size_mult) {
+		printf("Total enhanced size exceeds maximum (%u > %u)\n",
+		       tot_enh_size_mult, max_enh_size_mult);
+		return -EMEDIUMTYPE;
+	}
+
+	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
+	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
+		printf("Card already partitioned\n");
+		return -EPERM;
+	}
+
+	if (mode == MMC_HWPART_CONF_CHECK)
+		return 0;
+
+	/* Partitioning requires high-capacity size definitions */
+	if ( ! (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) ) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_ERASE_GROUP_DEF, 1);
+
+		if (err)
+			return err;
+
+		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+
+		/* update erase group size to be high-capacity */
+		mmc->erase_grp_size =
+			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+
+	}
+
+	/* all OK, write the configuration */
+	for (i = 0; i < 4; i++) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_ENH_START_ADDR+i,
+				 (enh_start_addr >> (i*8)) & 0xFF);
+		if (err)
+			return err;
+	}
+	for (i = 0; i < 3; i++) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_ENH_SIZE_MULT+i,
+				 (enh_size_mult >> (i*8)) & 0xFF);
+		if (err)
+			return err;
+	}
+	for (pidx = 0; pidx < 4; pidx++) {
+		for (i = 0; i < 3; i++) {
+			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
+					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
+			if (err)
+				return err;
+		}
+	}
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
+	if (err)
+		return err;
+
+	if (mode == MMC_HWPART_CONF_SET)
+		return 0;
+
+	/* Setting PART_SETTING_COMPLETED confirms the partition
+	 * configuration but it only becomes effective after power
+	 * cycle, so we do not adjust the partition related settings
+	 * in the mmc struct. */
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_PARTITION_SETTING,
+			 EXT_CSD_PARTITION_SETTING_COMPLETED);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 int mmc_getcd(struct mmc *mmc)
 {
 	int cd;
include/mmc.h +20 -0
index bcaf9f0..aacf820 100644
@@ -152,6 +152,7 @@
 #define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
 #define EXT_CSD_PARTITION_SETTING	155	/* R/W */
 #define EXT_CSD_PARTITIONS_ATTRIBUTE	156	/* R/W */
+#define EXT_CSD_MAX_ENH_SIZE_MULT	157	/* R */
 #define EXT_CSD_PARTITIONING_SUPPORT	160	/* RO */
 #define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
 #define EXT_CSD_RPMB_MULT		168	/* RO */
@@ -332,6 +333,23 @@ struct mmc {
 	int ddr_mode;
 };
 
+struct mmc_hwpart_conf {
+	struct {
+		uint enh_start;	/* in 512-byte sectors */
+		uint enh_size;	/* in 512-byte sectors, if 0 no enh area */
+	} user;
+	struct {
+		uint size;	/* in 512-byte sectors */
+		int enhanced;
+	} gp_part[4];
+};
+
+enum mmc_hwpart_conf_mode {
+	MMC_HWPART_CONF_CHECK,
+	MMC_HWPART_CONF_SET,
+	MMC_HWPART_CONF_COMPLETE,
+};
+
 int mmc_register(struct mmc *mmc);
 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv);
 void mmc_destroy(struct mmc *mmc);
@@ -344,6 +362,8 @@ int mmc_set_dev(int dev_num);
 void print_mmc_devices(char separator);
 int get_mmc_num(void);
 int mmc_switch_part(int dev_num, unsigned int part_num);
+int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf,
+		      enum mmc_hwpart_conf_mode mode);
 int mmc_getcd(struct mmc *mmc);
 int board_mmc_getcd(struct mmc *mmc);
 int mmc_getwp(struct mmc *mmc);
Signature · 1 line
2.2.1
#23 lore raw

PATCH v4 15/18 mmc: add mmc hwpartition sub-command to do eMMC hardware partitioning

In reply to Diego Santa Cruz

Adds the mmc hwpartition sub-command to perform eMMC hardware partitioning on an mmc device. The number of arguments can be large for a complex partitioning, but as the partitioning has to be done in one go it is difficult to make it simpler.

---
 common/cmd_mmc.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 92 insertions(+), 1 deletion(-)
common/cmd_mmc.c +92 -1
index 491a889..3c168ac 100644
@@ -482,6 +482,91 @@ static int do_mmc_list(cmd_tbl_t *cmdtp, int flag,
 	print_mmc_devices('\n');
 	return CMD_RET_SUCCESS;
 }
+
+static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
+			      int argc, char * const argv[])
+{
+	struct mmc *mmc;
+	struct mmc_hwpart_conf pconf = { };
+	enum mmc_hwpart_conf_mode mode = MMC_HWPART_CONF_CHECK;
+	int i, pidx;
+
+	mmc = init_mmc_device(curr_device, false);
+	if (!mmc)
+		return CMD_RET_FAILURE;
+
+	if (argc < 1)
+		return CMD_RET_USAGE;
+	i = 1;
+	while (i < argc) {
+		if (!strcmp(argv[i], "userenh")) {
+			if (i + 2 >= argc)
+				return CMD_RET_USAGE;
+			memset(&pconf.user, 0, sizeof(pconf.user));
+			pconf.user.enh_start =
+				simple_strtoul(argv[i+1], NULL, 10);
+			pconf.user.enh_size =
+				simple_strtoul(argv[i+2], NULL, 10);
+			i += 3;
+		} else if (!strncmp(argv[i], "gp", 2) &&
+			   strlen(argv[i]) == 3 &&
+			   argv[i][2] >= '1' && argv[i][2] <= '4') {
+			if (i + 1 >= argc)
+				return CMD_RET_USAGE;
+			pidx = argv[i][2] - '1';
+			memset(&pconf.gp_part[pidx], 0,
+			       sizeof(pconf.gp_part[pidx]));
+			pconf.gp_part[pidx].size =
+				simple_strtoul(argv[i+1], NULL, 10);
+			i += 2;
+			if (i < argc && !strcmp(argv[i], "enh")) {
+				pconf.gp_part[pidx].enhanced = 1;
+				i++;
+			}
+		} else if (!strcmp(argv[i], "check")) {
+			mode = MMC_HWPART_CONF_CHECK;
+			i++;
+		} else if (!strcmp(argv[i], "set")) {
+			mode = MMC_HWPART_CONF_SET;
+			i++;
+		} else if (!strcmp(argv[i], "complete")) {
+			mode = MMC_HWPART_CONF_COMPLETE;
+			i++;
+		} else {
+			return CMD_RET_USAGE;
+		}
+	}
+
+	puts("Partition configuration:\n");
+	if (pconf.user.enh_size) {
+		puts("\tUser Enhanced Start: ");
+		print_size(((u64)pconf.user.enh_start) << 9, "\n");
+		puts("\tUser Enhanced Size: ");
+		print_size(((u64)pconf.user.enh_size) << 9, "\n");
+	} else {
+		puts("\tNo enhanced user data area\n");
+	}
+	for (pidx = 0; pidx < 4; pidx++) {
+		if (pconf.gp_part[pidx].size) {
+			printf("\tGP%i Capacity: ", pidx+1);
+			print_size(((u64)pconf.gp_part[pidx].size) << 9,
+				   pconf.gp_part[pidx].enhanced ?
+				   " ENH\n" : "\n");
+		} else {
+			printf("\tNo GP%i partition\n", pidx+1);
+		}
+	}
+
+	if (!mmc_hwpart_config(mmc, &pconf, mode)) {
+		if (mode == MMC_HWPART_CONF_COMPLETE)
+			puts("Partitioning successful, "
+			     "power-cycle to make effective\n");
+		return CMD_RET_SUCCESS;
+	} else {
+		return CMD_RET_FAILURE;
+	}
+}
+
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
 static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag,
 			  int argc, char * const argv[])
@@ -639,6 +724,7 @@ static cmd_tbl_t cmd_mmc[] = {
 	U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
 	U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
 	U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
+	U_BOOT_CMD_MKENT(hwpartition, 17, 0, do_mmc_hwpartition, "", ""),
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
 	U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
 	U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
@@ -678,7 +764,7 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 
 U_BOOT_CMD(
-	mmc, 7, 1, do_mmcops,
+	mmc, 18, 1, do_mmcops,
 	"MMC sub system",
 	"info - display info of the current MMC device\n"
 	"mmc read addr blk# cnt\n"
@@ -688,6 +774,11 @@ U_BOOT_CMD(
 	"mmc part - lists available partition on current mmc device\n"
 	"mmc dev [dev] [part] - show or set current mmc device [partition]\n"
 	"mmc list - lists available devices\n"
+	"mmc hwpartition [args...] - does hardware partitioning\n"
+	"  arguments (sizes in 512-byte blocks):\n"
+	"    [userenh start cnt] - sets enhanced user data area\n"
+	"    [gp1|gp2|gp3|gp4 cnt [enh]] - general purpose partition\n"
+	"    [check|set|complete] - mode, complete set partitioning completed\n"
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
 	"mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
 	" - Set the BOOT_BUS_WIDTH field of the specified device\n"
Signature · 1 line
2.2.1
#24 lore raw

PATCH v4 16/18 mmc: extend the mmc hardware partitioning API with write reliability

In reply to Diego Santa Cruz

The eMMC partition write reliability settings are to be set while partitioning a device, as per the eMMC spec, so changes to these attributes needs to be done in the hardware partitioning API. This commit adds such support.

---
 drivers/mmc/mmc.c | 39 +++++++++++++++++++++++++++++++++++++++
 include/mmc.h     | 13 ++++++++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)
drivers/mmc/mmc.c +39 -0
index 847e323..89d26b9 100644
@@ -615,6 +615,7 @@ int mmc_hwpart_config(struct mmc *mmc,
 	u32 gp_size_mult[4];
 	u32 max_enh_size_mult;
 	u32 tot_enh_size_mult = 0;
+	u8 wr_rel_set;
 	int i, pidx, err;
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
 
@@ -689,6 +690,33 @@ int mmc_hwpart_config(struct mmc *mmc,
 		return -EMEDIUMTYPE;
 	}
 
+	/* The default value of EXT_CSD_WR_REL_SET is device
+	 * dependent, the values can only be changed if the
+	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
+	 * changed only once and before partitioning is completed. */
+	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
+	if (conf->user.wr_rel_change) {
+		if (conf->user.wr_rel_set)
+			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
+		else
+			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
+	}
+	for (pidx = 0; pidx < 4; pidx++) {
+		if (conf->gp_part[pidx].wr_rel_change) {
+			if (conf->gp_part[pidx].wr_rel_set)
+				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
+			else
+				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
+		}
+	}
+
+	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
+	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
+		puts("Card does not support host controlled partition write "
+		     "reliability settings\n");
+		return -EMEDIUMTYPE;
+	}
+
 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
 		printf("Card already partitioned\n");
@@ -746,6 +774,17 @@ int mmc_hwpart_config(struct mmc *mmc,
 	if (mode == MMC_HWPART_CONF_SET)
 		return 0;
 
+	/* The WR_REL_SET is a write-once register but shall be
+	 * written before setting PART_SETTING_COMPLETED. As it is
+	 * write-once we can only write it when completing the
+	 * partitioning. */
+	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_WR_REL_SET, wr_rel_set);
+		if (err)
+			return err;
+	}
+
 	/* Setting PART_SETTING_COMPLETED confirms the partition
 	 * configuration but it only becomes effective after power
 	 * cycle, so we do not adjust the partition related settings
include/mmc.h +12 -1
index aacf820..8d41234 100644
@@ -155,6 +155,8 @@
 #define EXT_CSD_MAX_ENH_SIZE_MULT	157	/* R */
 #define EXT_CSD_PARTITIONING_SUPPORT	160	/* RO */
 #define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
+#define EXT_CSD_WR_REL_PARAM		166	/* R */
+#define EXT_CSD_WR_REL_SET		167	/* R/W */
 #define EXT_CSD_RPMB_MULT		168	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_BOOT_BUS_WIDTH		177
@@ -207,6 +209,11 @@
 #define EXT_CSD_ENH_USR		(1 << 0)	/* user data area is enhanced */
 #define EXT_CSD_ENH_GP(x)	(1 << ((x)+1))	/* GP part (x+1) is enhanced */
 
+#define EXT_CSD_HS_CTRL_REL	(1 << 0)	/* host controlled WR_REL_SET */
+
+#define EXT_CSD_WR_DATA_REL_USR		(1 << 0)	/* user data area WR_REL */
+#define EXT_CSD_WR_DATA_REL_GP(x)	(1 << ((x)+1))	/* GP part (x+1) WR_REL */
+
 #define R1_ILLEGAL_COMMAND		(1 << 22)
 #define R1_APP_CMD			(1 << 5)
 
@@ -337,10 +344,14 @@ struct mmc_hwpart_conf {
 	struct {
 		uint enh_start;	/* in 512-byte sectors */
 		uint enh_size;	/* in 512-byte sectors, if 0 no enh area */
+		unsigned wr_rel_change : 1;
+		unsigned wr_rel_set : 1;
 	} user;
 	struct {
 		uint size;	/* in 512-byte sectors */
-		int enhanced;
+		unsigned enhanced : 1;
+		unsigned wr_rel_change : 1;
+		unsigned wr_rel_set : 1;
 	} gp_part[4];
 };
 
Signature · 1 line
2.2.1
#25 lore raw

PATCH v4 17/18 mmc: extend the mmc hwpartition sub-command to change write reliability

In reply to Diego Santa Cruz

This change extends the mmc hwpartition sub-command to change the per-partition write reliability settings. It also changes the syntax used for the enhanced user data area slightly to better accomodate the write reliability option.

---
 common/cmd_mmc.c | 116 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 92 insertions(+), 24 deletions(-)
common/cmd_mmc.c +92 -24
index 3c168ac..f17f9aa 100644
@@ -483,13 +483,81 @@ static int do_mmc_list(cmd_tbl_t *cmdtp, int flag,
 	return CMD_RET_SUCCESS;
 }
 
+static int parse_hwpart_user(struct mmc_hwpart_conf *pconf,
+			     int argc, char * const argv[])
+{
+	int i = 0;
+
+	memset(&pconf->user, 0, sizeof(pconf->user));
+
+	while (i < argc) {
+		if (!strcmp(argv[i], "enh")) {
+			if (i + 2 >= argc)
+				return -1;
+			pconf->user.enh_start =
+				simple_strtoul(argv[i+1], NULL, 10);
+			pconf->user.enh_size =
+				simple_strtoul(argv[i+2], NULL, 10);
+			i += 3;
+		} else if (!strcmp(argv[i], "wrrel")) {
+			if (i + 1 >= argc)
+				return -1;
+			pconf->user.wr_rel_change = 1;
+			if (!strcmp(argv[i+1], "on"))
+				pconf->user.wr_rel_set = 1;
+			else if (!strcmp(argv[i+1], "off"))
+				pconf->user.wr_rel_set = 0;
+			else
+				return -1;
+			i += 2;
+		} else {
+			break;
+		}
+	}
+	return i;
+}
+
+static int parse_hwpart_gp(struct mmc_hwpart_conf *pconf, int pidx,
+			   int argc, char * const argv[])
+{
+	int i;
+
+	memset(&pconf->gp_part[pidx], 0, sizeof(pconf->gp_part[pidx]));
+
+	if (1 >= argc)
+		return -1;
+	pconf->gp_part[pidx].size = simple_strtoul(argv[0], NULL, 10);
+
+	i = 1;
+	while (i < argc) {
+		if (!strcmp(argv[i], "enh")) {
+			pconf->gp_part[pidx].enhanced = 1;
+			i += 1;
+		} else if (!strcmp(argv[i], "wrrel")) {
+			if (i + 1 >= argc)
+				return -1;
+			pconf->gp_part[pidx].wr_rel_change = 1;
+			if (!strcmp(argv[i+1], "on"))
+				pconf->gp_part[pidx].wr_rel_set = 1;
+			else if (!strcmp(argv[i+1], "off"))
+				pconf->gp_part[pidx].wr_rel_set = 0;
+			else
+				return -1;
+			i += 2;
+		} else {
+			break;
+		}
+	}
+	return i;
+}
+
 static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
 			      int argc, char * const argv[])
 {
 	struct mmc *mmc;
 	struct mmc_hwpart_conf pconf = { };
 	enum mmc_hwpart_conf_mode mode = MMC_HWPART_CONF_CHECK;
-	int i, pidx;
+	int i, r, pidx;
 
 	mmc = init_mmc_device(curr_device, false);
 	if (!mmc)
@@ -499,30 +567,21 @@ static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
 		return CMD_RET_USAGE;
 	i = 1;
 	while (i < argc) {
-		if (!strcmp(argv[i], "userenh")) {
-			if (i + 2 >= argc)
+		if (!strcmp(argv[i], "user")) {
+			i++;
+			r = parse_hwpart_user(&pconf, argc-i, &argv[i]);
+			if (r < 0)
 				return CMD_RET_USAGE;
-			memset(&pconf.user, 0, sizeof(pconf.user));
-			pconf.user.enh_start =
-				simple_strtoul(argv[i+1], NULL, 10);
-			pconf.user.enh_size =
-				simple_strtoul(argv[i+2], NULL, 10);
-			i += 3;
+			i += r;
 		} else if (!strncmp(argv[i], "gp", 2) &&
 			   strlen(argv[i]) == 3 &&
 			   argv[i][2] >= '1' && argv[i][2] <= '4') {
-			if (i + 1 >= argc)
-				return CMD_RET_USAGE;
 			pidx = argv[i][2] - '1';
-			memset(&pconf.gp_part[pidx], 0,
-			       sizeof(pconf.gp_part[pidx]));
-			pconf.gp_part[pidx].size =
-				simple_strtoul(argv[i+1], NULL, 10);
-			i += 2;
-			if (i < argc && !strcmp(argv[i], "enh")) {
-				pconf.gp_part[pidx].enhanced = 1;
-				i++;
-			}
+			i++;
+			r = parse_hwpart_gp(&pconf, pidx, argc-i, &argv[i]);
+			if (r < 0)
+				return CMD_RET_USAGE;
+			i += r;
 		} else if (!strcmp(argv[i], "check")) {
 			mode = MMC_HWPART_CONF_CHECK;
 			i++;
@@ -546,6 +605,9 @@ static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
 	} else {
 		puts("\tNo enhanced user data area\n");
 	}
+	if (pconf.user.wr_rel_change)
+		printf("\tUser partition write reliability: %s\n",
+		       pconf.user.wr_rel_set ? "on" : "off");
 	for (pidx = 0; pidx < 4; pidx++) {
 		if (pconf.gp_part[pidx].size) {
 			printf("\tGP%i Capacity: ", pidx+1);
@@ -555,6 +617,9 @@ static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
 		} else {
 			printf("\tNo GP%i partition\n", pidx+1);
 		}
+		if (pconf.gp_part[pidx].wr_rel_change)
+			printf("\tGP%i write reliability: %s\n", pidx+1,
+			       pconf.gp_part[pidx].wr_rel_set ? "on" : "off");
 	}
 
 	if (!mmc_hwpart_config(mmc, &pconf, mode)) {
@@ -563,6 +628,7 @@ static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
 			     "power-cycle to make effective\n");
 		return CMD_RET_SUCCESS;
 	} else {
+		puts("Failed!\n");
 		return CMD_RET_FAILURE;
 	}
 }
@@ -724,7 +790,7 @@ static cmd_tbl_t cmd_mmc[] = {
 	U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
 	U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
 	U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
-	U_BOOT_CMD_MKENT(hwpartition, 17, 0, do_mmc_hwpartition, "", ""),
+	U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
 	U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
 	U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
@@ -764,7 +830,7 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 
 U_BOOT_CMD(
-	mmc, 18, 1, do_mmcops,
+	mmc, 29, 1, do_mmcops,
 	"MMC sub system",
 	"info - display info of the current MMC device\n"
 	"mmc read addr blk# cnt\n"
@@ -776,9 +842,11 @@ U_BOOT_CMD(
 	"mmc list - lists available devices\n"
 	"mmc hwpartition [args...] - does hardware partitioning\n"
 	"  arguments (sizes in 512-byte blocks):\n"
-	"    [userenh start cnt] - sets enhanced user data area\n"
-	"    [gp1|gp2|gp3|gp4 cnt [enh]] - general purpose partition\n"
+	"    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n"
+	"    [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition\n"
 	"    [check|set|complete] - mode, complete set partitioning completed\n"
+	"  WARNING: Partitioning is a write-once setting once it is set to complete.\n"
+	"  Power cycling is required to initialize partitions after set to complete.\n"
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
 	"mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
 	" - Set the BOOT_BUS_WIDTH field of the specified device\n"
Signature · 1 line
2.2.1
#26 lore raw

PATCH v4 18/18 mmc: extend mmcinfo output to show partition write reliability settings

In reply to Diego Santa Cruz

This extends the mmcinfo hardware partition info output to show partitions with write reliability enabled with the "WRREL" string. If the partition does not have write reliability enabled the "WRREL" string is omitted; this is analogous to the ehhanced attribute.

Example output:

Device: OMAP SD/MMC
Manufacturer ID: fe
OEM: 14e
Name: MMC16
Tran Speed: 52000000
Rd Block Len: 512
MMC version 4.41
High Capacity: Yes
Capacity: 13.8 GiB
Bus Width: 4-bit
Erase Group Size: 8 MiB
HC WP Group Size: 16 MiB
User Capacity: 13.8 GiB ENH WRREL
User Enhanced Start: 0 Bytes
User Enhanced Size: 512 MiB
Boot Capacity: 16 MiB ENH
RPMB Capacity: 128 KiB ENH
GP1 Capacity: 64 MiB ENH WRREL
GP2 Capacity: 64 MiB ENH WRREL

---
 common/cmd_mmc.c  | 12 ++++++++++--
 drivers/mmc/mmc.c |  2 ++
 include/mmc.h     |  1 +
 3 files changed, 13 insertions(+), 2 deletions(-)
common/cmd_mmc.c +10 -2
index f17f9aa..305f65f 100644
@@ -106,7 +106,11 @@ static void print_mmcinfo(struct mmc *mmc)
 		print_size(((u64)mmc->hc_wp_grp_size) << 9, "\n");
 
 		puts("User Capacity: ");
-		print_size(mmc->capacity_user, usr_enh ? " ENH\n" : "\n");
+		print_size(mmc->capacity_user, usr_enh ? " ENH" : "");
+		if (mmc->wr_rel_set & EXT_CSD_WR_DATA_REL_USR)
+			puts(" WRREL\n");
+		else
+			putc('\n');
 		if (usr_enh) {
 			puts("User Enhanced Start: ");
 			print_size(mmc->enh_user_start, "\n");
@@ -126,7 +130,11 @@ static void print_mmcinfo(struct mmc *mmc)
 			if (mmc->capacity_gp[i]) {
 				printf("GP%i Capacity: ", i+1);
 				print_size(mmc->capacity_gp[i],
-					   is_enh ? " ENH\n" : "\n");
+					   is_enh ? " ENH" : "");
+				if (mmc->wr_rel_set & EXT_CSD_WR_DATA_REL_GP(i))
+					puts(" WRREL\n");
+				else
+					putc('\n');
 			}
 		}
 	}
drivers/mmc/mmc.c +2 -0
index 89d26b9..a3abed9 100644
@@ -1306,6 +1306,8 @@ static int mmc_startup(struct mmc *mmc)
 		mmc->hc_wp_grp_size = 1024
 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
 	}
 
 	err = mmc_set_capacity(mmc, mmc->part_num);
include/mmc.h +1 -0
index 8d41234..09101e2 100644
@@ -318,6 +318,7 @@ struct mmc {
 	ushort rca;
 	u8 part_support;
 	u8 part_attr;
+	u8 wr_rel_set;
 	char part_config;
 	char part_num;
 	uint tran_speed;
Signature · 1 line
2.2.1
#27 lore raw

v4 cover Support for eMMC partitioning and related fixes

In reply to Diego Santa Cruz

Hi Diego,

Quoted 38 lines · Diego Santa Cruz

I have the need to hardware partition eMMC devices from U-Boot along with setting enhanced and reliable write attributes.

This series of patches adds this support to U-Boot via a new mmc API, a few new members of struct mmc and a new mmc sub-command. It also features several fixes to the eMMC hardware partition support. I have tested this with Micron eMMC 4.41 parts and it is working as expected.

This version resyncs to u-boot.git master d8bec60c1b0de7770f9b56ad092ab9be801d99af as some recent mmc changes conflicted with these patches, in particular the DDR mode support.

Diego Santa Cruz (18):
mmc: show hardware partition sizes in mmcinfo output
mmc: extend mmcinfo to show enhanced partition attribute
mmc: make eMMC general purpose partition numbering match spec
mmc: skip mmcinfo partition info processing for eMMC < 4.41
mmc: incomplete test to switch to high-capacity group size definitions
mmc: computation of eMMC GP partition size was missing 512 KiB factor
mmc: read the size of eMMC enhanced user data area
mmc: display size and start of eMMC enhanced user data area in mmcinfo
mmc: fix erase_grp_size computation with high-capacity size definition
mmc: read the high capacity WP group size for eMMC
mmc: show the erase group size and HC WP group size in mmcinfo output
mmc: eMMC partitioning data is not effective till partitioning
completed
mmc: the ext_csd data may be used during init even if reading failed
mmc: add API to do eMMC hardware partitioning
mmc: add mmc hwpartition sub-command to do eMMC hardware partitioning
mmc: extend the mmc hardware partitioning API with write reliability
mmc: extend the mmc hwpartition sub-command to change write
reliability
mmc: extend mmcinfo output to show partition write reliability
settings

Quoted 8 lines
common/cmd_mmc.c  | 207 ++++++++++++++++++++++++++++++++++++++-
drivers/mmc/mmc.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++++-----
include/mmc.h     |  45 ++++++++-
3 files changed, 515 insertions(+), 25 deletions(-)
Signature · 1 line
2.2.1

Applied, with minor cosmetic edits.

I can?t test every feature of this patchset, but I guess if something?s broken we?ll find out soon enough.

Regards

? Pantelis