[U-Boot] [PATCH] mmc: implement mmc power on write protect function

set the mmc specific addresss and range as power on write protection, and can't earse and write this range if you enable it after mmc power on.
Signed-off-by: Lin Huang hl@rock-chips.com --- drivers/mmc/mmc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 10 ++++++- 2 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2a58702..60ff5be 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1819,6 +1819,95 @@ int mmc_initialize(bd_t *bis) return 0; }
+int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status) +{ + struct mmc_cmd cmd; + struct mmc_data data; + int err; + + cmd.cmdidx = MMC_CMD_WRITE_PROT_TYPE; + cmd.resp_type = MMC_RSP_R1; + cmd.cmdarg = addr; + + data.dest = status; + data.blocksize = 8; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + if (err) + return err; + return err; +} + +int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size) +{ + int err; + unsigned int wp_group_size, wp_grp_num, i; + struct mmc_cmd cmd; + unsigned int timeout = 1000; + + ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); + + size = size / MMC_MAX_BLOCK_LEN; + + err = mmc_send_ext_csd(mmc, ext_csd); + if (err) + return err; + + if ((ext_csd[EXT_CSD_USER_WP] & EXT_CSD_USER_PERM_WP_EN) || + (ext_csd[EXT_CSD_USER_WP] & EXT_CSD_USER_PWR_WP_DIS)) { + printf("Power on protection is disabled\n"); + return -1; + } + + if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) + wp_group_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE] * + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; + else { + int erase_gsz, erase_gmul, wp_grp_size; + + erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; + erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; + wp_grp_size = (mmc->csd[2] & 0x0000001f); + wp_group_size = (erase_gsz + 1) * (erase_gmul + 1) * + (wp_grp_size + 1); + } + + if (size < wp_group_size) { + printf("wrong size, fail to set power on wp\n"); + return -1; + } + + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_USER_WP, EXT_CSD_USER_PWR_WP_EN); + if (err) + return err; + + wp_grp_num = DIV_ROUND_UP(size, wp_group_size); + cmd.cmdidx = MMC_CMD_WRITE_PROT; + cmd.resp_type = MMC_RSP_R1b; + + for (i = 0; i < wp_grp_num; i++) { + cmd.cmdarg = addr + i * wp_group_size; + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + /* CMD28/CMD29 ON failure returns address out of range error */ + if ((cmd.response[0] >> 31) & 0x01) { + printf("address for CMD28/29 out of range\n"); + return -1; + } + + err = mmc_send_status(mmc, timeout); + if (err) + return err; + } + + return 0; +} + #ifdef CONFIG_SUPPORT_EMMC_BOOT /* * This function changes the size of boot partition and the size of rpmb diff --git a/include/mmc.h b/include/mmc.h index cda9a19..448d5a8 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -89,6 +89,8 @@ #define MMC_CMD_SET_BLOCK_COUNT 23 #define MMC_CMD_WRITE_SINGLE_BLOCK 24 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 +#define MMC_CMD_WRITE_PROT 28 +#define MMC_CMD_WRITE_PROT_TYPE 31 #define MMC_CMD_ERASE_GROUP_START 35 #define MMC_CMD_ERASE_GROUP_END 36 #define MMC_CMD_ERASE 38 @@ -175,6 +177,7 @@ #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_USER_WP 171 #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_PART_CONF 179 /* R/W */ @@ -231,6 +234,10 @@ #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 EXT_CSD_USER_PWR_WP_DIS (1 << 3) /* disable power-on write protect*/ +#define EXT_CSD_USER_PERM_WP_EN (1 << 2) /* enable permanent write protect */ +#define EXT_CSD_USER_PWR_WP_EN (1 << 0) /* enable power-on write protect */ + #define R1_ILLEGAL_COMMAND (1 << 22) #define R1_APP_CMD (1 << 5)
@@ -477,7 +484,8 @@ int cpu_mmc_init(bd_t *bis); int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
struct pci_device_id; - +int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size); +int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status); /** * pci_mmc_init() - set up PCI MMC devices *

Hi Lin,
On 3 December 2015 at 01:34, Lin Huang hl@rock-chips.com wrote:
set the mmc specific addresss and range as power on write protection, and can't earse and write this range if you enable it after mmc power on.
Signed-off-by: Lin Huang hl@rock-chips.com
drivers/mmc/mmc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 10 ++++++- 2 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2a58702..60ff5be 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1819,6 +1819,95 @@ int mmc_initialize(bd_t *bis) return 0; }
+int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status) +{
struct mmc_cmd cmd;
struct mmc_data data;
int err;
cmd.cmdidx = MMC_CMD_WRITE_PROT_TYPE;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = addr;
data.dest = status;
data.blocksize = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err)
return err;
return err;
return 0 I think
Unless you just want to always return err.
+}
+int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size) +{
int err;
unsigned int wp_group_size, wp_grp_num, i;
struct mmc_cmd cmd;
unsigned int timeout = 1000;
drop blank line
ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
size = size / MMC_MAX_BLOCK_LEN;
err = mmc_send_ext_csd(mmc, ext_csd);
if (err)
return err;
if ((ext_csd[EXT_CSD_USER_WP] & EXT_CSD_USER_PERM_WP_EN) ||
(ext_csd[EXT_CSD_USER_WP] & EXT_CSD_USER_PWR_WP_DIS)) {
printf("Power on protection is disabled\n");
return -1;
Can you run a real error in errno.h to return?
}
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF])
wp_group_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE] *
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
else {
int erase_gsz, erase_gmul, wp_grp_size;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
wp_grp_size = (mmc->csd[2] & 0x0000001f);
wp_group_size = (erase_gsz + 1) * (erase_gmul + 1) *
(wp_grp_size + 1);
}
if (size < wp_group_size) {
printf("wrong size, fail to set power on wp\n");
return -1;
Can you run a real error in errno.h to return?
}
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_USER_WP, EXT_CSD_USER_PWR_WP_EN);
if (err)
return err;
wp_grp_num = DIV_ROUND_UP(size, wp_group_size);
cmd.cmdidx = MMC_CMD_WRITE_PROT;
cmd.resp_type = MMC_RSP_R1b;
for (i = 0; i < wp_grp_num; i++) {
cmd.cmdarg = addr + i * wp_group_size;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
/* CMD28/CMD29 ON failure returns address out of range error */
if ((cmd.response[0] >> 31) & 0x01) {
printf("address for CMD28/29 out of range\n");
return -1;
-EINVAL?
}
err = mmc_send_status(mmc, timeout);
if (err)
return err;
}
return 0;
+}
#ifdef CONFIG_SUPPORT_EMMC_BOOT /*
- This function changes the size of boot partition and the size of rpmb
diff --git a/include/mmc.h b/include/mmc.h index cda9a19..448d5a8 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -89,6 +89,8 @@ #define MMC_CMD_SET_BLOCK_COUNT 23 #define MMC_CMD_WRITE_SINGLE_BLOCK 24 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 +#define MMC_CMD_WRITE_PROT 28 +#define MMC_CMD_WRITE_PROT_TYPE 31 #define MMC_CMD_ERASE_GROUP_START 35 #define MMC_CMD_ERASE_GROUP_END 36 #define MMC_CMD_ERASE 38 @@ -175,6 +177,7 @@ #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_USER_WP 171 #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_PART_CONF 179 /* R/W */ @@ -231,6 +234,10 @@ #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 EXT_CSD_USER_PWR_WP_DIS (1 << 3) /* disable power-on write protect*/ +#define EXT_CSD_USER_PERM_WP_EN (1 << 2) /* enable permanent write protect */ +#define EXT_CSD_USER_PWR_WP_EN (1 << 0) /* enable power-on write protect */
#define R1_ILLEGAL_COMMAND (1 << 22) #define R1_APP_CMD (1 << 5)
@@ -477,7 +484,8 @@ int cpu_mmc_init(bd_t *bis); int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
struct pci_device_id;
+int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size); +int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status);
Can you please add full function comments for these?
/**
- pci_mmc_init() - set up PCI MMC devices
-- 1.9.1
Regards, Simon

Hi Simon,
Thanks for reviewing, i have upload a new patch to fix your comment.
On 11/12/15 11:20, Simon Glass wrote:
Hi Lin,
On 3 December 2015 at 01:34, Lin Huang hl@rock-chips.com wrote:
set the mmc specific addresss and range as power on write protection, and can't earse and write this range if you enable it after mmc power on.
Signed-off-by: Lin Huang hl@rock-chips.com
drivers/mmc/mmc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 10 ++++++- 2 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2a58702..60ff5be 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1819,6 +1819,95 @@ int mmc_initialize(bd_t *bis) return 0; }
+int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status) +{
struct mmc_cmd cmd;
struct mmc_data data;
int err;
cmd.cmdidx = MMC_CMD_WRITE_PROT_TYPE;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = addr;
data.dest = status;
data.blocksize = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err)
return err;
return err;
return 0 I think
Unless you just want to always return err.
+}
+int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size) +{
int err;
unsigned int wp_group_size, wp_grp_num, i;
struct mmc_cmd cmd;
unsigned int timeout = 1000;
drop blank line
ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
size = size / MMC_MAX_BLOCK_LEN;
err = mmc_send_ext_csd(mmc, ext_csd);
if (err)
return err;
if ((ext_csd[EXT_CSD_USER_WP] & EXT_CSD_USER_PERM_WP_EN) ||
(ext_csd[EXT_CSD_USER_WP] & EXT_CSD_USER_PWR_WP_DIS)) {
printf("Power on protection is disabled\n");
return -1;
Can you run a real error in errno.h to return?
}
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF])
wp_group_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE] *
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
else {
int erase_gsz, erase_gmul, wp_grp_size;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
wp_grp_size = (mmc->csd[2] & 0x0000001f);
wp_group_size = (erase_gsz + 1) * (erase_gmul + 1) *
(wp_grp_size + 1);
}
if (size < wp_group_size) {
printf("wrong size, fail to set power on wp\n");
return -1;
Can you run a real error in errno.h to return?
}
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_USER_WP, EXT_CSD_USER_PWR_WP_EN);
if (err)
return err;
wp_grp_num = DIV_ROUND_UP(size, wp_group_size);
cmd.cmdidx = MMC_CMD_WRITE_PROT;
cmd.resp_type = MMC_RSP_R1b;
for (i = 0; i < wp_grp_num; i++) {
cmd.cmdarg = addr + i * wp_group_size;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
/* CMD28/CMD29 ON failure returns address out of range error */
if ((cmd.response[0] >> 31) & 0x01) {
printf("address for CMD28/29 out of range\n");
return -1;
-EINVAL?
}
err = mmc_send_status(mmc, timeout);
if (err)
return err;
}
return 0;
+}
- #ifdef CONFIG_SUPPORT_EMMC_BOOT /*
- This function changes the size of boot partition and the size of rpmb
diff --git a/include/mmc.h b/include/mmc.h index cda9a19..448d5a8 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -89,6 +89,8 @@ #define MMC_CMD_SET_BLOCK_COUNT 23 #define MMC_CMD_WRITE_SINGLE_BLOCK 24 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 +#define MMC_CMD_WRITE_PROT 28 +#define MMC_CMD_WRITE_PROT_TYPE 31 #define MMC_CMD_ERASE_GROUP_START 35 #define MMC_CMD_ERASE_GROUP_END 36 #define MMC_CMD_ERASE 38 @@ -175,6 +177,7 @@ #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_USER_WP 171 #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_PART_CONF 179 /* R/W */ @@ -231,6 +234,10 @@ #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 EXT_CSD_USER_PWR_WP_DIS (1 << 3) /* disable power-on write protect*/ +#define EXT_CSD_USER_PERM_WP_EN (1 << 2) /* enable permanent write protect */ +#define EXT_CSD_USER_PWR_WP_EN (1 << 0) /* enable power-on write protect */
- #define R1_ILLEGAL_COMMAND (1 << 22) #define R1_APP_CMD (1 << 5)
@@ -477,7 +484,8 @@ int cpu_mmc_init(bd_t *bis); int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
struct pci_device_id;
+int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size); +int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status);
Can you please add full function comments for these?
/**
- pci_mmc_init() - set up PCI MMC devices
-- 1.9.1
Regards, Simon
participants (3)
-
hl
-
Lin Huang
-
Simon Glass