[U-Boot] [PATCH v1] set the mmc specific addresss and range as power on write protection, you can't earse and write this range of data if you enable it after mmc power on.

Signed-off-by: Lin Huang hl@rock-chips.com --- Changes in v1: - Adviced by Simon: - use real error in errno.h to return - add full function comments for new function
drivers/mmc/mmc.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 37 +++++++++++++++++++++++ 2 files changed, 124 insertions(+)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 3a34028..1308ce9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1821,6 +1821,93 @@ 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); + + 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 -EINVAL; + } + + 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 -EINVAL; + } + + 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 -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..2f13eea 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)
@@ -478,6 +485,36 @@ int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
struct pci_device_id;
+/* + * This function specific user area address enable + * power on write protect + * + * Input Parameters: + * struct *mmc: pointer for the mmc device strcuture + * addr: address of power on write protect area, use block address + * size: size of power on write protect area, count by bytes + * + * Returns 0 on success. + */ +int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size); + +/* + * This function read specific user area address + * write protect status + * + * Input Parameters: + * struct *mmc: pointer for the mmc device strcuture + * addr: address you want to read the status, use block address + * status: write protect status you get, the value represent: + * “00” Write protection group not protected + * “01” Write protection group is protected by temporary write protection + * “10” Write protection group is protected by power-on write protection + * “11” Write protection group is protected by permanent write protection + * + * Returns 0 on success. + */ +int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status); + /** * pci_mmc_init() - set up PCI MMC devices *

Hi Lin,
On 13 December 2015 at 19:14, Lin Huang hl@rock-chips.com wrote:
Signed-off-by: Lin Huang hl@rock-chips.com
Changes in v1:
- Adviced by Simon:
- use real error in errno.h to return
- add full function comments for new function
drivers/mmc/mmc.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 37 +++++++++++++++++++++++ 2 files changed, 124 insertions(+)
This looks OK except that you seem to have put the commit message into the subject. Can you please fix that?
Also we have a standard way of doing function comments - please see below.
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 3a34028..1308ce9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1821,6 +1821,93 @@ 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);
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 -EINVAL;
}
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 -EINVAL;
}
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 -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..2f13eea 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)
@@ -478,6 +485,36 @@ int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
struct pci_device_id;
+/*
- This function specific user area address enable
- power on write protect
- Input Parameters:
- struct *mmc: pointer for the mmc device strcuture
- addr: address of power on write protect area, use block address
- size: size of power on write protect area, count by bytes
- Returns 0 on success.
- */
+int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size);
Function style should follow conventions. Something like this:
/** * mmc_usr_power_on_wp() - Enable power-on write protect * * Description goes here if needed. * * @mmc: pointer to the mmc device structure * @addr: address of power-on write protect area, use block address * @size: size of power on write protect area, in bytes * @return 0 success, -ve on error */
+/*
- This function read specific user area address
- write protect status
- Input Parameters:
- struct *mmc: pointer for the mmc device strcuture
- addr: address you want to read the status, use block address
- status: write protect status you get, the value represent:
- “00” Write protection group not protected
- “01” Write protection group is protected by temporary write protection
- “10” Write protection group is protected by power-on write protection
- “11” Write protection group is protected by permanent write protection
- Returns 0 on success.
- */
+int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status);
/**
- pci_mmc_init() - set up PCI MMC devices
-- 1.9.1
Regards, Simon
participants (2)
-
Lin Huang
-
Simon Glass