Message ID | 1450059256-5617-1-git-send-email-hl@rock-chips.com |
---|---|
State | Superseded |
Delegated to: | Pantelis Antoniou |
Headers | show |
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
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 *
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(+)