diff mbox

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

Message ID 1449131661-9139-1-git-send-email-hl@rock-chips.com
State Changes Requested
Delegated to: Simon Glass
Headers show

Commit Message

Lin Huang Dec. 3, 2015, 8:34 a.m. UTC
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(-)

Comments

Simon Glass Dec. 11, 2015, 3:20 a.m. UTC | #1
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
Lin Huang Dec. 14, 2015, 2:16 a.m. UTC | #2
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
>
>
>
diff mbox

Patch

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
  *