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 <h...@rock-chips.com> --- Changes in v2: - Adviced by Simon: - use standard way of doing function comments 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 | 36 +++++++++++++++++++++++ 2 files changed, 123 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..dd9e803 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) @@ -479,6 +486,35 @@ int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); struct pci_device_id; /** + * mmc_usr_power_on_wp() - Enable power-on write protect + * + * This function specific user area address enable power on write protect + * + * @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 + */ +int mmc_usr_power_on_wp(struct mmc *mmc, lbaint_t addr, unsigned int size); + +/** + * mmc_get_wp_status() - Get write protect status + * + * This function read specific user area address write protect status, + * the data bits 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 + * + * @mmc: pointer for the mmc device strcuture + * @addr: address you want to read the status, use block address + * @status: write protect status you get: + * @return 0 on success, -ve on error + */ +int mmc_get_wp_status(struct mmc *mmc, lbaint_t addr, char *status); + +/** * pci_mmc_init() - set up PCI MMC devices * * This finds all the matching PCI IDs and sets them up as MMC devices. -- 1.9.1
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot