[U-Boot] [PATCH] mmc: implement mmc power on write protect function
Lin Huang
hl at rock-chips.com
Thu Dec 3 09:34:21 CET 2015
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 at 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
*
--
1.9.1
More information about the U-Boot
mailing list