diff mbox

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

Message ID 1450073159-7738-1-git-send-email-hl@rock-chips.com
State Deferred
Delegated to: Pantelis Antoniou
Headers show

Commit Message

Lin Huang Dec. 14, 2015, 6:05 a.m. UTC
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 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(+)

Comments

Simon Glass Dec. 14, 2015, 10:14 p.m. UTC | #1
+Pantelis

On 13 December 2015 at 23:05, Lin Huang <hl@rock-chips.com> wrote:
> 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 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(+)

Reviewed-by: Simon Glass <sjg@chromium.org>
diff mbox

Patch

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.