[U-Boot] [PATCH 1/7 V3] mmc: Add some usefull macro definition

From: Haijun Zhang Haijun.Zhang@freescale.com
Add command class define. Add mmc erase and secure erase define. Add secure erase and trim support bit define.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com --- changes for V3: - No changes
include/mmc.h | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/include/mmc.h b/include/mmc.h index cb558da..08f0f3e 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -53,6 +53,7 @@ #define COMM_ERR -18 /* Communications Error */ #define TIMEOUT -19 #define IN_PROGRESS -20 /* operation is in progress */ +#define NOT_SUPPORT -21 /* Operation is not support */
#define MMC_CMD_GO_IDLE_STATE 0 #define MMC_CMD_SEND_OP_COND 1 @@ -105,6 +106,39 @@ #define OCR_VOLTAGE_MASK 0x007FFF80 #define OCR_ACCESS_MODE 0x60000000
+/* + * Card Command Classes (CCC) + * + * (0) Basic protocol functions (CMD0,1,2,3,4,7,9,10,12,13,15) + * (and for SPI, CMD58,59) + * (1) Stream read commands (CMD11) + * (2) Block read commands (CMD16,17,18) + * (3) Stream write commands (CMD20) + * (4) Block write commands (CMD16,24,25,26,27) + * (5) Ability to erase blocks (CMD32,33,34,35,36,37,38,39) + * (6) Able to write protect blocks (CMD28,29,30) + * (7) Able to lock down card (CMD16,CMD42) + * (8) Application specific (CMD55,56,57,ACMD*) + * (9) I/O mode (CMD5,39,40,52,53) + * (10) High speed switch (CMD6,34,35,36,37,50) + */ +#define CCC_BASIC (1<<0) +#define CCC_STREAM_READ (1<<1) +#define CCC_BLOCK_READ (1<<2) +#define CCC_STREAM_WRITE (1<<3) +#define CCC_BLOCK_WRITE (1<<4) +#define CCC_ERASE (1<<5) +#define CCC_WRITE_PROT (1<<6) +#define CCC_LOCK_CARD (1<<7) +#define CCC_APP_SPEC (1<<8) +#define CCC_IO_MODE (1<<9) +#define CCC_SWITCH (1<<10) + +#define MMC_ERASE_ARG 0x00000000 +#define MMC_SECURE_ERASE_ARG 0x80000000 +#define MMC_TRIM_ARG 0x00000001 +#define MMC_DISCARD_ARG 0x00000003 + #define SECURE_ERASE 0x80000000
#define MMC_STATUS_MASK (~0x0206BF7F) @@ -160,8 +194,12 @@ #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ +#define EXT_CSD_REL_WR_SEC_C 222 /* RO */ +#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
/* * EXT_CSD field definitions @@ -178,6 +216,12 @@ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
+/* EXT_CSD[231] */ +#define EXT_CSD_SEC_ER_EN (1<<0) +#define EXT_CSD_SEC_BD_BLK_EN (1<<2) +#define EXT_CSD_SEC_GB_CL_EN (1<<4) +#define EXT_CSD_SEC_SANITIZE (1<<6) /* v4.5 later */ + #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) #define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0) @@ -187,7 +231,6 @@ #define EXT_CSD_BOOT_PART_NUM(x) (x << 3) #define EXT_CSD_PARTITION_ACCESS(x) (x << 0)
- #define R1_ILLEGAL_COMMAND (1 << 22) #define R1_APP_CMD (1 << 5)
@@ -268,10 +311,15 @@ struct mmc { ushort rca; char part_config; char part_num; + ushort cmdclass; uint tran_speed; uint read_bl_len; uint write_bl_len; uint erase_grp_size; + uint erase_timeout_mult; + char sec_feature_support; + uint sec_erase_mult; + uint sec_erase_timeout; u64 capacity; u64 capacity_user; u64 capacity_boot;

Read command class from csd register and secure erase support bit from ext csd register. Also calculate the erase timeout and secure erase timeout.
If read ext csd error, error status should be returned instead of give some incorrect information.
Error log: => => mmcinfo Device: FSL_SDHC Manufacturer ID: 0 OEM: 0 Name: Tran Speed: 0 Rd Block Len: 0 MMC version 0.0 High Capacity: No Capacity: 0 Bytes Bus Width: 1-bit =>
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com --- changes for V3: - Change the erase group size to be block aligned.
drivers/mmc/mmc.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..e8dbb8c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -871,6 +871,8 @@ static int mmc_startup(struct mmc *mmc) } }
+ mmc->cmdclass = cmd.response[1] >> 20; + /* divide frequency by 10, since the mults are 10x bigger */ freq = fbase[(cmd.response[0] & 0x7)]; mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; @@ -939,7 +941,8 @@ static int mmc_startup(struct mmc *mmc) capacity *= MMC_MAX_BLOCK_LEN; if ((capacity >> 20) > 2 * 1024) mmc->capacity_user = capacity; - } + } else + return COMM_ERR;
switch (ext_csd[EXT_CSD_REV]) { case 1: @@ -960,6 +963,39 @@ static int mmc_startup(struct mmc *mmc) }
/* + * The granularity of the erasable units is the Erase Group:The + * smallest number of consecutive write blocks which can be + * addressed for erase. The size of the Erase Group is card + * specific and stored in the CSD when ERASE_GROUP_DEF is + * disabled, and in the EXT_CSD when ERASE_GROUP_DEF is + * enabled. + */ + if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) { + mmc->erase_grp_size = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; + + mmc->erase_timeout_mult = 300 * + ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; + } else { + /* Calculate the group size from the csd value. */ + int erase_gsz, erase_gmul; + erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; + erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; + mmc->erase_grp_size = (erase_gsz + 1) + * (erase_gmul + 1); + } + + if (ext_csd[EXT_CSD_REV] >= 4) { + mmc->sec_feature_support = + ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; + mmc->sec_erase_mult = + ext_csd[EXT_CSD_SEC_ERASE_MULT]; + mmc->sec_erase_timeout = 300 * + ext_csd[EXT_CSD_SEC_ERASE_MULT] * + ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; + } + + /* * 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. @@ -968,23 +1004,11 @@ static int mmc_startup(struct mmc *mmc) (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) { err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GROUP_DEF, 1); - if (err) return err; - - /* Read out group size from ext_csd */ - mmc->erase_grp_size = - ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * - MMC_MAX_BLOCK_LEN * 1024; - } else { - /* Calculate the group size from the csd value. */ - int erase_gsz, erase_gmul; - erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; - erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; - mmc->erase_grp_size = (erase_gsz + 1) - * (erase_gmul + 1); }
+ /* store the partition info of emmc */ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || ext_csd[EXT_CSD_BOOT_MULT])

Hi Haijun,
On Dec 10, 2013, at 7:39 AM, Haijun Zhang wrote:
Read command class from csd register and secure erase support bit from ext csd register. Also calculate the erase timeout and secure erase timeout.
If read ext csd error, error status should be returned instead of give some incorrect information.
s/give some/giving/
Error log: => => mmcinfo Device: FSL_SDHC Manufacturer ID: 0 OEM: 0 Name: Tran Speed: 0 Rd Block Len: 0 MMC version 0.0 High Capacity: No Capacity: 0 Bytes Bus Width: 1-bit =>
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3:
- Change the erase group size to be block aligned.
drivers/mmc/mmc.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..e8dbb8c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -871,6 +871,8 @@ static int mmc_startup(struct mmc *mmc) } }
- mmc->cmdclass = cmd.response[1] >> 20;
^ use mask of cmd class maximum width (even if class is 12 bit wide)
/* divide frequency by 10, since the mults are 10x bigger */ freq = fbase[(cmd.response[0] & 0x7)]; mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; @@ -939,7 +941,8 @@ static int mmc_startup(struct mmc *mmc) capacity *= MMC_MAX_BLOCK_LEN; if ((capacity >> 20) > 2 * 1024) mmc->capacity_user = capacity;
}
} else
return COMM_ERR;
switch (ext_csd[EXT_CSD_REV]) { case 1:
@@ -960,6 +963,39 @@ static int mmc_startup(struct mmc *mmc) }
/*
* The granularity of the erasable units is the Erase Group:The
* smallest number of consecutive write blocks which can be
* addressed for erase. The size of the Erase Group is card
* specific and stored in the CSD when ERASE_GROUP_DEF is
* disabled, and in the EXT_CSD when ERASE_GROUP_DEF is
* enabled.
*/
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) {
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
mmc->erase_timeout_mult = 300 *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
mmc->erase_grp_size = (erase_gsz + 1)
* (erase_gmul + 1);
}
if (ext_csd[EXT_CSD_REV] >= 4) {
mmc->sec_feature_support =
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
mmc->sec_erase_mult =
ext_csd[EXT_CSD_SEC_ERASE_MULT];
mmc->sec_erase_timeout = 300 *
ext_csd[EXT_CSD_SEC_ERASE_MULT] *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
}
/*
- 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.
@@ -968,23 +1004,11 @@ static int mmc_startup(struct mmc *mmc) (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) { err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GROUP_DEF, 1);
^ removed line for no reason
if (err) return err;
/* Read out group size from ext_csd */
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
MMC_MAX_BLOCK_LEN * 1024;
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
mmc->erase_grp_size = (erase_gsz + 1)
}* (erase_gmul + 1);
^ extra line
/* store the partition info of emmc */ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || ext_csd[EXT_CSD_BOOT_MULT])
-- 1.8.4.1

Hi, Haijun.
On 12/10/2013 02:39 PM, Haijun Zhang wrote:
Read command class from csd register and secure erase support bit from ext csd register. Also calculate the erase timeout and secure erase timeout.
If read ext csd error, error status should be returned instead of give some incorrect information.
Error log: => => mmcinfo Device: FSL_SDHC Manufacturer ID: 0 OEM: 0 Name: Tran Speed: 0 Rd Block Len: 0 MMC version 0.0 High Capacity: No Capacity: 0 Bytes Bus Width: 1-bit =>
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3:
- Change the erase group size to be block aligned.
drivers/mmc/mmc.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..e8dbb8c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -871,6 +871,8 @@ static int mmc_startup(struct mmc *mmc) } }
- mmc->cmdclass = cmd.response[1] >> 20;
- /* divide frequency by 10, since the mults are 10x bigger */ freq = fbase[(cmd.response[0] & 0x7)]; mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
@@ -939,7 +941,8 @@ static int mmc_startup(struct mmc *mmc) capacity *= MMC_MAX_BLOCK_LEN; if ((capacity >> 20) > 2 * 1024) mmc->capacity_user = capacity;
}
} else
return COMM_ERR;
Well, I think this point need to consider more. When error is returned, then this return is right. but it's also satisfied "ext_csd[EXT_CSD_REV] >= 2".
switch (ext_csd[EXT_CSD_REV]) { case 1:
@@ -960,6 +963,39 @@ static int mmc_startup(struct mmc *mmc) }
/*
* The granularity of the erasable units is the Erase Group:The
* smallest number of consecutive write blocks which can be
* addressed for erase. The size of the Erase Group is card
* specific and stored in the CSD when ERASE_GROUP_DEF is
* disabled, and in the EXT_CSD when ERASE_GROUP_DEF is
* enabled.
*/
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) {
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
mmc->erase_timeout_mult = 300 *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
mmc->erase_grp_size = (erase_gsz + 1)
* (erase_gmul + 1);
}
if (ext_csd[EXT_CSD_REV] >= 4) {
mmc->sec_feature_support =
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
mmc->sec_erase_mult =
ext_csd[EXT_CSD_SEC_ERASE_MULT];
mmc->sec_erase_timeout = 300 *
ext_csd[EXT_CSD_SEC_ERASE_MULT] *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
}
/*
- 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.
@@ -968,23 +1004,11 @@ static int mmc_startup(struct mmc *mmc) (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) { err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GROUP_DEF, 1);
if (err) return err;
/* Read out group size from ext_csd */
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
MMC_MAX_BLOCK_LEN * 1024;
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
mmc->erase_grp_size = (erase_gsz + 1)
}* (erase_gmul + 1);
remove the blank.
Best Regards, Jaehoon Chung
/* store the partition info of emmc */ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || ext_csd[EXT_CSD_BOOT_MULT])

On 12/27/2013 07:13 PM, Jaehoon Chung wrote:
Hi, Haijun.
On 12/10/2013 02:39 PM, Haijun Zhang wrote:
Read command class from csd register and secure erase support bit from ext csd register. Also calculate the erase timeout and secure erase timeout.
If read ext csd error, error status should be returned instead of give some incorrect information.
Error log: => => mmcinfo Device: FSL_SDHC Manufacturer ID: 0 OEM: 0 Name: Tran Speed: 0 Rd Block Len: 0 MMC version 0.0 High Capacity: No Capacity: 0 Bytes Bus Width: 1-bit =>
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3:
- Change the erase group size to be block aligned.
drivers/mmc/mmc.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..e8dbb8c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -871,6 +871,8 @@ static int mmc_startup(struct mmc *mmc) } }
- mmc->cmdclass = cmd.response[1] >> 20;
- /* divide frequency by 10, since the mults are 10x bigger */ freq = fbase[(cmd.response[0] & 0x7)]; mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
@@ -939,7 +941,8 @@ static int mmc_startup(struct mmc *mmc) capacity *= MMC_MAX_BLOCK_LEN; if ((capacity >> 20) > 2 * 1024) mmc->capacity_user = capacity;
}
} else
return COMM_ERR;
Well, I think this point need to consider more. When error is returned, then this return is right. but it's also satisfied "ext_csd[EXT_CSD_REV] >= 2".
Yes you are right. I'll change this.
Thanks.
-- Haijun
switch (ext_csd[EXT_CSD_REV]) { case 1:
@@ -960,6 +963,39 @@ static int mmc_startup(struct mmc *mmc) }
/*
* The granularity of the erasable units is the Erase Group:The
* smallest number of consecutive write blocks which can be
* addressed for erase. The size of the Erase Group is card
* specific and stored in the CSD when ERASE_GROUP_DEF is
* disabled, and in the EXT_CSD when ERASE_GROUP_DEF is
* enabled.
*/
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) {
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
mmc->erase_timeout_mult = 300 *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
mmc->erase_grp_size = (erase_gsz + 1)
* (erase_gmul + 1);
}
if (ext_csd[EXT_CSD_REV] >= 4) {
mmc->sec_feature_support =
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
mmc->sec_erase_mult =
ext_csd[EXT_CSD_SEC_ERASE_MULT];
mmc->sec_erase_timeout = 300 *
ext_csd[EXT_CSD_SEC_ERASE_MULT] *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
}
/*
- 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.
@@ -968,23 +1004,11 @@ static int mmc_startup(struct mmc *mmc) (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) { err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GROUP_DEF, 1);
if (err) return err;
/* Read out group size from ext_csd */
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
MMC_MAX_BLOCK_LEN * 1024;
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
mmc->erase_grp_size = (erase_gsz + 1)
}* (erase_gmul + 1);
remove the blank.
Best Regards, Jaehoon Chung
/* store the partition info of emmc */ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || ext_csd[EXT_CSD_BOOT_MULT])

This patch enhances the currently implemented erase procedure in u-boot, which has the following problems/missing features..."
Erass sequence: 1. check if erase command is support by card. If not return. 2. Check the erase range to see if it was aligned. The min erase size should be one erase group. SD card it was one block(512), mmc card it should be one erase group. 3. If not, aligned the erase rang according to the erase group size. 4. Send erase command to erase card once one erase group. 5. If it was SD card, erase with arg 0x00000000 should be send. else if support secure feature, erase with arg 0x80000000(Spec eMMC 4.41). else erase with arg 0x00000000.(Trim and discard is ingnored here) 6. Check card status after erase.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com --- changes for V3: - update the commit message and secure feature supporting judgment.
drivers/mmc/mmc_write.c | 68 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index aa2fdef..c2dafa3 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -17,6 +17,10 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) struct mmc_cmd cmd; ulong end; int err, start_cmd, end_cmd; + uint arg = 0; + + if (!(mmc->cmdclass & CCC_ERASE)) + return NOT_SUPPORT;
if (mmc->high_capacity) { end = start + blkcnt - 1; @@ -48,8 +52,15 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) if (err) goto err_out;
+ /* SD card only support %MMC_ERASE_ARG */ + if (!IS_SD(mmc) && + (mmc->sec_feature_support & EXT_CSD_SEC_ER_EN)) + arg = MMC_SECURE_ERASE_ARG; + else + arg = MMC_ERASE_ARG; + cmd.cmdidx = MMC_CMD_ERASE; - cmd.cmdarg = SECURE_ERASE; + cmd.cmdarg = arg; cmd.resp_type = MMC_RSP_R1b;
err = mmc_send_cmd(mmc, &cmd, NULL); @@ -69,24 +80,61 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; int timeout = 1000; + int res; + bool align = true;
if (!mmc) return -1;
+ if (!(mmc->cmdclass & CCC_ERASE)) { + printf("\nErase operation is not support by card\n"); + return NOT_SUPPORT; + } + if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) + align = false; + + res = start % mmc->erase_grp_size; + if (res) { + res = mmc->erase_grp_size - res; + start += res; + if (blkcnt > res) + blkcnt -= res; + else { + printf("\nErase size smaller than Erase group " + "size [0x%x] is not support by the device.\n", + mmc->erase_grp_size); + return NOT_SUPPORT; + } + } + + res = blkcnt % mmc->erase_grp_size; + if (res) + blkcnt -= res; + + if (!blkcnt) { + printf("\nErase size smaller than Erase group size [0x%x] " + "is not support by the device.\n", + mmc->erase_grp_size); + return NOT_SUPPORT; + } + + if (!align) printf("\n\nCaution! Your devices Erase group is 0x%x\n" - "The erase range would be change to " - "0x" LBAF "~0x" LBAF "\n\n", - mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), - ((start + blkcnt + mmc->erase_grp_size) - & ~(mmc->erase_grp_size - 1)) - 1); + "The erase range would be change to " + "0x" LBAF "~0x" LBAF "\n\n", + mmc->erase_grp_size, start, start + blkcnt); +
while (blk < blkcnt) { - blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? - mmc->erase_grp_size : (blkcnt - blk); + if ((blkcnt - blk) >= mmc->erase_grp_size) + blk_r = mmc->erase_grp_size; err = mmc_erase_t(mmc, start + blk, blk_r); - if (err) - break; + if (err) { + printf("\nErase range from 0x" LBAF "~0x" LBAF + " Failed\n", start + blk, blkcnt); + return COMM_ERR; + }
blk += blk_r;

Hi Haijun,
On Dec 10, 2013, at 7:39 AM, Haijun Zhang wrote:
This patch enhances the currently implemented erase procedure in u-boot, which has the following problems/missing features..."
^ this is exactly what I responded earlier.
What are the problems? What are the missing features?
Erass sequence:
- check if erase command is support by card. If not return.
- Check the erase range to see if it was aligned. The min erase size
should be one erase group. SD card it was one block(512), mmc card it should be one erase group. 3. If not, aligned the erase rang according to the erase group size. 4. Send erase command to erase card once one erase group. 5. If it was SD card, erase with arg 0x00000000 should be send. else if support secure feature, erase with arg 0x80000000(Spec eMMC 4.41). else erase with arg 0x00000000.(Trim and discard is ingnored here) 6. Check card status after erase.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3:
- update the commit message and secure feature supporting judgment.
drivers/mmc/mmc_write.c | 68 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index aa2fdef..c2dafa3 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -17,6 +17,10 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) struct mmc_cmd cmd; ulong end; int err, start_cmd, end_cmd;
uint arg = 0;
if (!(mmc->cmdclass & CCC_ERASE))
return NOT_SUPPORT;
if (mmc->high_capacity) { end = start + blkcnt - 1;
@@ -48,8 +52,15 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) if (err) goto err_out;
- /* SD card only support %MMC_ERASE_ARG */
- if (!IS_SD(mmc) &&
(mmc->sec_feature_support & EXT_CSD_SEC_ER_EN))
arg = MMC_SECURE_ERASE_ARG;
- else
arg = MMC_ERASE_ARG;
- cmd.cmdidx = MMC_CMD_ERASE;
- cmd.cmdarg = SECURE_ERASE;
cmd.cmdarg = arg; cmd.resp_type = MMC_RSP_R1b;
err = mmc_send_cmd(mmc, &cmd, NULL);
@@ -69,24 +80,61 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; int timeout = 1000;
int res;
bool align = true;
if (!mmc) return -1;
if (!(mmc->cmdclass & CCC_ERASE)) {
printf("\nErase operation is not support by card\n");
return NOT_SUPPORT;
}
if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
align = false;
res = start % mmc->erase_grp_size;
if (res) {
res = mmc->erase_grp_size - res;
start += res;
if (blkcnt > res)
blkcnt -= res;
else {
printf("\nErase size smaller than Erase group "
"size [0x%x] is not support by the device.\n",
mmc->erase_grp_size);
return NOT_SUPPORT;
}
}
res = blkcnt % mmc->erase_grp_size;
if (res)
blkcnt -= res;
if (!blkcnt) {
printf("\nErase size smaller than Erase group size [0x%x] "
"is not support by the device.\n",
mmc->erase_grp_size);
return NOT_SUPPORT;
}
if (!align) printf("\n\nCaution! Your devices Erase group is 0x%x\n"
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
((start + blkcnt + mmc->erase_grp_size)
& ~(mmc->erase_grp_size - 1)) - 1);
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start, start + blkcnt);
while (blk < blkcnt) {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
if ((blkcnt - blk) >= mmc->erase_grp_size)
err = mmc_erase_t(mmc, start + blk, blk_r);blk_r = mmc->erase_grp_size;
if (err)
break;
if (err) {
printf("\nErase range from 0x" LBAF "~0x" LBAF
" Failed\n", start + blk, blkcnt);
return COMM_ERR;
}
blk += blk_r;
-- 1.8.4.1

Hi
On Tue, Dec 10, 2013 at 6:39 AM, Haijun Zhang haijun.zhang@freescale.com wrote:
This patch enhances the currently implemented erase procedure in u-boot, which has the following problems/missing features..."
Erass sequence:
- check if erase command is support by card. If not return.
- Check the erase range to see if it was aligned. The min erase size
should be one erase group. SD card it was one block(512), mmc card it should be one erase group. 3. If not, aligned the erase rang according to the erase group size. 4. Send erase command to erase card once one erase group. 5. If it was SD card, erase with arg 0x00000000 should be send. else if support secure feature, erase with arg 0x80000000(Spec eMMC 4.41). else erase with arg 0x00000000.(Trim and discard is ingnored here) 6. Check card status after erase.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3: - update the commit message and secure feature supporting judgment.
drivers/mmc/mmc_write.c | 68 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index aa2fdef..c2dafa3 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -17,6 +17,10 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) struct mmc_cmd cmd; ulong end; int err, start_cmd, end_cmd;
uint arg = 0;
if (!(mmc->cmdclass & CCC_ERASE))
return NOT_SUPPORT; if (mmc->high_capacity) { end = start + blkcnt - 1;
@@ -48,8 +52,15 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) if (err) goto err_out;
/* SD card only support %MMC_ERASE_ARG */
if (!IS_SD(mmc) &&
(mmc->sec_feature_support & EXT_CSD_SEC_ER_EN))
arg = MMC_SECURE_ERASE_ARG;
else
arg = MMC_ERASE_ARG;
cmd.cmdidx = MMC_CMD_ERASE;
cmd.cmdarg = SECURE_ERASE;
cmd.cmdarg = arg; cmd.resp_type = MMC_RSP_R1b; err = mmc_send_cmd(mmc, &cmd, NULL);
@@ -69,24 +80,61 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; int timeout = 1000;
int res;
bool align = true; if (!mmc) return -1;
if (!(mmc->cmdclass & CCC_ERASE)) {
printf("\nErase operation is not support by card\n");
return NOT_SUPPORT;
}
if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
align = false;
res = start % mmc->erase_grp_size;
if (res) {
...
Well I don't know if it works end = start + bkcnt; start += group_size - (start % group_size); end -= (end % group_size); if (start >= end) printf("invalid size\n");
But why not somenthing like this? Michael
start += mmc->erase_grp_size - res;
if (res < blkcnt) {
}
if (blkcnt > res)
blkcnt -= res;
else {
printf("\nErase size smaller than Erase group "
"size [0x%x] is not support by the device.\n",
mmc->erase_grp_size);
return NOT_SUPPORT;
}
}
res = (blkcnt - res) % mmc->erase_grp_size;
if (res)
blkcnt -= res;
if (!blkcnt) {
printf("\nErase size smaller than Erase group size [0x%x] "
"is not support by the device.\n",
mmc->erase_grp_size);
return NOT_SUPPORT;
}
if (!align) printf("\n\nCaution! Your devices Erase group is 0x%x\n"
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
((start + blkcnt + mmc->erase_grp_size)
& ~(mmc->erase_grp_size - 1)) - 1);
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start, start + blkcnt);
while (blk < blkcnt) {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
if ((blkcnt - blk) >= mmc->erase_grp_size)
blk_r = mmc->erase_grp_size; err = mmc_erase_t(mmc, start + blk, blk_r);
if (err)
break;
if (err) {
printf("\nErase range from 0x" LBAF "~0x" LBAF
" Failed\n", start + blk, blkcnt);
return COMM_ERR;
} blk += blk_r;
-- 1.8.4.1

Regards & Thanks.
-- Haijun
-----Original Message----- From: Michael Trimarchi [mailto:michael@amarulasolutions.com] Sent: Wednesday, December 11, 2013 11:10 AM To: Zhang Haijun-B42677 Cc: panto@antoniou-consulting.com; u-boot@lists.denx.de; Xie Xiaobo- R63061; Sun York-R58495; Tom Rini; Stefano Babic; rjbarnet@rockwellcollins.com; jh80.chung@samsung.com Subject: Re: [PATCH 3/7 V3] mmc: Enhance erase handling procedure
Hi
On Tue, Dec 10, 2013 at 6:39 AM, Haijun Zhang haijun.zhang@freescale.com wrote:
This patch enhances the currently implemented erase procedure in u-boot, which has the following problems/missing features..."
Erass sequence:
- check if erase command is support by card. If not return.
- Check the erase range to see if it was aligned. The min erase size
should be one erase group. SD card it was one block(512), mmc card it should be one erase group. 3. If not, aligned the erase rang according to the erase group size. 4. Send erase command to erase card once one erase group. 5. If it was SD card, erase with arg 0x00000000 should be send. else if support secure feature, erase with arg 0x80000000(Spec eMMC
4.41).
else erase with arg 0x00000000.(Trim and discard is ingnored here) 6. Check card status after erase.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3: - update the commit message and secure feature supporting
judgment.
drivers/mmc/mmc_write.c | 68 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index aa2fdef..c2dafa3 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -17,6 +17,10 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong
start, lbaint_t blkcnt)
struct mmc_cmd cmd; ulong end; int err, start_cmd, end_cmd;
uint arg = 0;
if (!(mmc->cmdclass & CCC_ERASE))
return NOT_SUPPORT; if (mmc->high_capacity) { end = start + blkcnt - 1; @@ -48,8 +52,15 @@ static
ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) if (err) goto err_out;
/* SD card only support %MMC_ERASE_ARG */
if (!IS_SD(mmc) &&
(mmc->sec_feature_support & EXT_CSD_SEC_ER_EN))
arg = MMC_SECURE_ERASE_ARG;
else
arg = MMC_ERASE_ARG;
cmd.cmdidx = MMC_CMD_ERASE;
cmd.cmdarg = SECURE_ERASE;
cmd.cmdarg = arg; cmd.resp_type = MMC_RSP_R1b; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -69,24 +80,61 @@
unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; int timeout = 1000;
int res;
bool align = true; if (!mmc) return -1;
if (!(mmc->cmdclass & CCC_ERASE)) {
printf("\nErase operation is not support by card\n");
return NOT_SUPPORT;
}
if ((start % mmc->erase_grp_size) || (blkcnt %
mmc->erase_grp_size))
align = false;
res = start % mmc->erase_grp_size;
if (res) {
...
Well I don't know if it works end = start + bkcnt; start += group_size - (start % group_size); end -= (end % group_size); if (start >= end) printf("invalid size\n");
But why not somenthing like this? Michael
Yes, it's simpler. I'll update it in my next patch version V5. And how about other patches?
Haijun
start += mmc->erase_grp_size - res;
if (res < blkcnt) {
}
if (blkcnt > res)
blkcnt -= res;
else {
printf("\nErase size smaller than Erase group "
"size [0x%x] is not support by the
device.\n",
mmc->erase_grp_size);
return NOT_SUPPORT;
}
}
res = (blkcnt - res) % mmc->erase_grp_size;
if (res)
blkcnt -= res;
if (!blkcnt) {
printf("\nErase size smaller than Erase group size
[0x%x] "
"is not support by the device.\n",
mmc->erase_grp_size);
return NOT_SUPPORT;
}
if (!align) printf("\n\nCaution! Your devices Erase group is
0x%x\n"
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start & ~(mmc-
erase_grp_size - 1),
((start + blkcnt + mmc->erase_grp_size)
& ~(mmc->erase_grp_size - 1)) - 1);
"The erase range would be change to "
"0x" LBAF "~0x" LBAF "\n\n",
mmc->erase_grp_size, start, start + blkcnt);
while (blk < blkcnt) {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
if ((blkcnt - blk) >= mmc->erase_grp_size)
blk_r = mmc->erase_grp_size; err = mmc_erase_t(mmc, start + blk, blk_r);
if (err)
break;
if (err) {
printf("\nErase range from 0x" LBAF "~0x" LBAF
" Failed\n", start + blk, blkcnt);
return COMM_ERR;
} blk += blk_r;
-- 1.8.4.1

If the block rang was not algined, We tried to algined the range, then erase the block. So the block range erased should be less or equal to the block range sent. If error occured during erase procedure part of them will be erased. And use should resend the block rang to continue erase the reset of them.
Error number and zero number mean erase operation was failed.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com --- changes for V3: - no changes
common/cmd_mmc.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 67a94a7..c124df0 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -397,6 +397,13 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) BUG(); }
+ if (state == MMC_ERASE) { + printf("%d blocks %s: %s\n", + ((n <= cnt) && (n > 0)) ? n : 0, argv[1], + ((n <= cnt) && (n > 0)) ? "OK" : "ERROR"); + return ((n <= cnt) && (n > 0)) ? 0 : 1; + } + printf("%d blocks %s: %s\n", n, argv[1], (n == cnt) ? "OK" : "ERROR"); return (n == cnt) ? 0 : 1;

Hi Haijun,
On Dec 10, 2013, at 7:39 AM, Haijun Zhang wrote:
If the block rang was not algined, We tried to algined the range,
range, aligned,
We try to align
then erase the block. So the block range erased should be less or equal to the block range sent. If error occured during erase procedure part of them will be erased. And use should resend the block rang to
User? range
continue erase the reset of them.
the rest
Error number and zero number mean erase operation was failed.
Error return, zero return, has failed.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com
changes for V3:
- no changes
common/cmd_mmc.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 67a94a7..c124df0 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -397,6 +397,13 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) BUG(); }
if (state == MMC_ERASE) {
printf("%d blocks %s: %s\n",
((n <= cnt) && (n > 0)) ? n : 0, argv[1],
((n <= cnt) && (n > 0)) ? "OK" : "ERROR");
return ((n <= cnt) && (n > 0)) ? 0 : 1;
}
Drop the inside parentheses (n <= cnt && n > 0)
Or use a variable like
int valid = n <= cnt && n > 0;
printf("%d blocks %s: %s\n", n, argv[1], (n == cnt) ? "OK" : "ERROR"); return (n == cnt) ? 0 : 1;
-- 1.8.4.1

Once mmc initialization was faild has_init should be set to 0, prepard for the next initialization to recover from error.
Once mmcinfo command failed, error should be report instead of printing incorrect mmc device information.
Error log: => mmcinfo Device: FSL_SDHC Manufacturer ID: 0 OEM: 0 Name: Tran Speed: 0 Rd Block Len: 0 MMC version 0.0 High Capacity: No Capacity: 0 Bytes Bus Width: 1-bit => mmcinfo Device: FSL_SDHC Manufacturer ID: 0 OEM: 0 Name: Tran Speed: 0 Rd Block Len: 0 MMC version 0.0 High Capacity: No Capacity: 0 Bytes Bus Width: 1-bit
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com --- changes for V3: - Remove the error printings.
common/cmd_mmc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index c124df0..46443c8 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -115,7 +115,8 @@ static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) mmc = find_mmc_device(curr_device);
if (mmc) { - mmc_init(mmc); + if (mmc_init(mmc)) + return 1;
print_mmcinfo(mmc); return 0; @@ -191,9 +192,10 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
mmc->has_init = 0;
- if (mmc_init(mmc)) + if (mmc_init(mmc)) { + mmc->has_init = 0; return 1; - else + } else return 0; } else if (strncmp(argv[1], "part", 4) == 0) { block_dev_desc_t *mmc_dev;

From: Haijun Zhang Haijun.Zhang@freescale.com
Esdhc host version number is incorrect in host capacity register. The value read from was 0x14. Correct it to 0x13.
Signed-off-by: Haijun Zhang haijun.zhang@freescale.com --- changes for V3: - no changes
arch/powerpc/include/asm/config_mpc85xx.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h index 99e16bd..15affdc 100644 --- a/arch/powerpc/include/asm/config_mpc85xx.h +++ b/arch/powerpc/include/asm/config_mpc85xx.h @@ -591,6 +591,7 @@ #define CONFIG_SYS_NUM_FM2_DTSEC 8 #define CONFIG_SYS_NUM_FM2_10GEC 2 #define CONFIG_NUM_DDR_CONTROLLERS 3 +#define CONFIG_FSL_SDHC_V2_3 #else #define CONFIG_MAX_CPUS 8 #define CONFIG_SYS_FSL_CLUSTER_CLOCKS { 1, 1 }

The max timeout value esdhc host can accept was about 2.69 sec At 50 Mhz SD_CLK period, the max busy timeout value = 2^27 * SD_CLK period ~= 2.69 sec.
In case erase command CMD38 timeout is caculated by mult * 300ms * num(unit by erase group), so the time one erase group need should be more than 300ms, 5000ms should be enough.
1. Add data reset procedure for data error and command with busy error. 2. Add timeout value detecting during waiting for transfer complete. 3. Ignore Command inhibit (DAT) state when excuting CMD12. 4. Add command CRC error detecting. 5. Enlarged the timeout value used for busy state release.
Signed-off-by: Haijun Zhang Haijun.Zhang@freescale.com --- changes for V3: - changed the '-1' to '0xffffffffU' - redundant check command and data error after while loop.
drivers/mmc/fsl_esdhc.c | 164 +++++++++++++++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 58 deletions(-)
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 9f4d3a2..134a02d 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -266,26 +266,36 @@ static int esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp; - uint irqstat; + uint irqstat = 0, mask; struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; + int ret = 0, timeout; + + esdhc_write32(®s->irqstat, 0xffffffffU); + + sync(); + + mask = PRSSTAT_CICHB | PRSSTAT_CIDHB;
#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) return 0; +#else + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + mask &= ~PRSSTAT_CIDHB; #endif
- esdhc_write32(®s->irqstat, -1); - - sync(); - /* Wait for the bus to be idle */ - while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || - (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) - ; - - while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) - ; + timeout = 1000; + while (esdhc_read32(®s->prsstat) & mask) { + if (timeout == 0) { + printf("\nController never released inhibit bit(s).\n"); + ret = COMM_ERR; + goto reset; + } + timeout--; + mdelay(1); + }
/* Wait at least 8 SD clock cycles before the next command */ /* @@ -296,11 +306,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Set up for a data transfer if we have one */ if (data) { - int err; - - err = esdhc_setup_data(mmc, data); - if(err) - return err; + ret = esdhc_setup_data(mmc, data); + if (ret) + goto reset; }
/* Figure out the transfer arguments */ @@ -325,43 +333,14 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
irqstat = esdhc_read32(®s->irqstat);
- /* Reset CMD and DATA portions on error */ - if (irqstat & CMD_ERR) { - esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | - SYSCTL_RSTC); - while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) - ; - - if (data) { - esdhc_write32(®s->sysctl, - esdhc_read32(®s->sysctl) | - SYSCTL_RSTD); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) - ; - } + if (irqstat & IRQSTAT_CTOE) { + ret = TIMEOUT; + goto reset; }
- if (irqstat & IRQSTAT_CTOE) - return TIMEOUT; - - if (irqstat & CMD_ERR) - return COMM_ERR; - - /* Workaround for ESDHC errata ENGcm03648 */ - if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { - int timeout = 2500; - - /* Poll on DATA0 line for cmd with busy signal for 250 ms */ - while (timeout > 0 && !(esdhc_read32(®s->prsstat) & - PRSSTAT_DAT0)) { - udelay(100); - timeout--; - } - - if (timeout <= 0) { - printf("Timeout waiting for DAT0 to go high!\n"); - return TIMEOUT; - } + if (irqstat & CMD_ERR) { + ret = COMM_ERR; + goto reset; }
/* Copy the response to the response buffer */ @@ -379,7 +358,20 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) } else cmd->response[0] = esdhc_read32(®s->cmdrsp0);
- /* Wait until all of the blocks are transferred */ + /* + * At 50 Mhz SD_CLK period, the max busy timeout + * value or data transfer time need was about + * = 2^27 * SD_CLK period ~= 2.69 sec. + * So wait max 10 sec for data transfer complete or busy + * state release. + */ + timeout = 10000; + + /* + * eSDHC host V2.3 has response busy interrupt, so + * we should wait for busy state to be released and data + * was out of programing state before next command send. + */ if (data) { #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO esdhc_pio_read_write(mmc, data); @@ -387,20 +379,76 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) do { irqstat = esdhc_read32(®s->irqstat);
- if (irqstat & IRQSTAT_DTOE) - return TIMEOUT; + if (irqstat & IRQSTAT_DTOE) { + ret = TIMEOUT; + break; + }
- if (irqstat & DATA_ERR) - return COMM_ERR; - } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); + if (irqstat & DATA_ERR) { + ret = COMM_ERR; + break; + } + + if (timeout <= 0) { + ret = TIMEOUT; + break; + } + mdelay(1); + timeout--; + } while (((irqstat & DATA_COMPLETE) != DATA_COMPLETE) && + (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); #endif if (data->flags & MMC_DATA_READ) check_and_invalidate_dcache_range(cmd, data); }
- esdhc_write32(®s->irqstat, -1); + /* Workaround for ESDHC errata ENGcm03648 */ + if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { + int timeout = 5000; + + /* Poll on DATA0 line for cmd with busy signal for 5 sec */ + while (timeout > 0 && !(esdhc_read32(®s->prsstat) & + PRSSTAT_DAT0)) { + mdelay(1); + timeout--; + } + + if (timeout <= 0) { + printf("\nTimeout waiting for DAT0 to go high!\n"); + ret = TIMEOUT; + goto reset; + } + } + + if (esdhc_read32(®s->irqstat) & (DATA_ERR | CMD_ERR)) + ret = COMM_ERR; + + if (ret) + goto reset; + + esdhc_write32(®s->irqstat, 0xffffffffU);
return 0; + +reset: + + /* Reset CMD and DATA portions on error */ + esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | + SYSCTL_RSTC); + while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) + ; + + if (data || (cmd->resp_type & MMC_RSP_BUSY)) { + esdhc_write32(®s->sysctl, + esdhc_read32(®s->sysctl) | + SYSCTL_RSTD); + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) + ; + } + + esdhc_write32(®s->irqstat, 0xffffffffU); + + return ret; }
static void set_sysctl(struct mmc *mmc, uint clock)
participants (6)
-
Haijun Zhang
-
Haijun.Zhang@freescale.com
-
Jaehoon Chung
-
Michael Trimarchi
-
Pantelis Antoniou
-
Zhang Haijun