mirror of
https://git.codelinaro.org/clo/qsdk/oss/boot/u-boot-2016.git
synced 2025-12-10 07:44:53 +01:00
ARM: mmc: Added power-on write protection support
Change-Id: Iba7e4bfcbee3f5106ef7d0ecc64e8af175732f7c Signed-off-by: Gokul Sriram Palanisamy <gokulsri@codeaurora.org>
This commit is contained in:
parent
c0270eedf1
commit
201def52b9
3 changed files with 136 additions and 0 deletions
|
|
@ -330,6 +330,31 @@ static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int do_mmc_protect (cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
struct mmc *mmc;
|
||||
unsigned int ret;
|
||||
unsigned int blk, cnt;
|
||||
|
||||
if (argc != 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
blk = (unsigned int)simple_strtoul(argv[1], NULL, 16);
|
||||
cnt = (unsigned int)simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
mmc = init_mmc_device(curr_device, false);
|
||||
if (!mmc)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
ret = mmc_write_protect(mmc, blk, cnt, 1);
|
||||
|
||||
if (!ret)
|
||||
printf("Offset: 0x%x Count: %d blocks\nDone!\n", blk, cnt);
|
||||
|
||||
return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_mmc_read(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
|
|
@ -802,6 +827,7 @@ static cmd_tbl_t cmd_mmc[] = {
|
|||
U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
|
||||
U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
|
||||
U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
|
||||
U_BOOT_CMD_MKENT(protect, 4, 0, do_mmc_protect, "", ""),
|
||||
#ifdef CONFIG_SUPPORT_EMMC_BOOT
|
||||
U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
|
||||
U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
|
||||
|
|
@ -858,6 +884,7 @@ U_BOOT_CMD(
|
|||
" [check|set|complete] - mode, complete set partitioning completed\n"
|
||||
" WARNING: Partitioning is a write-once setting once it is set to complete.\n"
|
||||
" Power cycling is required to initialize partitions after set to complete.\n"
|
||||
"mmc protect start_blk# cnt_blk\n"
|
||||
#ifdef CONFIG_SUPPORT_EMMC_BOOT
|
||||
"mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
|
||||
" - Set the BOOT_BUS_WIDTH field of the specified device\n"
|
||||
|
|
|
|||
|
|
@ -1181,6 +1181,8 @@ static int mmc_startup(struct mmc *mmc)
|
|||
* For SD, its erase group is always one sector
|
||||
*/
|
||||
mmc->erase_grp_size = 1;
|
||||
mmc->wp_grp_size = WP_GRP_SIZE(mmc->csd);
|
||||
mmc->wp_grp_enable = WP_GRP_ENABLE(mmc->csd);
|
||||
mmc->part_config = MMCPART_NOAVAILABLE;
|
||||
if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
|
||||
/* check ext_csd version and capacity */
|
||||
|
|
@ -1836,6 +1838,87 @@ int mmc_initialize(bd_t *bis)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mmc_send_wp_set_clr(struct mmc *mmc, unsigned int start,
|
||||
unsigned int size, int set_clr)
|
||||
{
|
||||
unsigned int err;
|
||||
unsigned int wp_group_size, count, i;
|
||||
struct mmc_cmd cmd;
|
||||
|
||||
wp_group_size = (mmc->wp_grp_size + 1) * mmc->erase_grp_size;
|
||||
count = DIV_ROUND_UP(size, wp_group_size);
|
||||
|
||||
if (set_clr)
|
||||
cmd.cmdidx = MMC_CMD_SET_WRITE_PROT;
|
||||
else
|
||||
cmd.cmdidx = MMC_CMD_CLR_WRITE_PROT;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
cmd.cmdarg = start + (i * wp_group_size);
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err) {
|
||||
printf("%s: Error at block 0x%lx - %d\n", __func__,
|
||||
cmd.cmdarg, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if(MMC_ADDR_OUT_OF_RANGE(cmd.response[0])) {
|
||||
printf("%s: mmc block(0x%lx) out of range", __func__,
|
||||
cmd.cmdarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = mmc_send_status(mmc, MMC_RESP_TIMEOUT);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_write_protect(struct mmc *mmc, unsigned int start_blk,
|
||||
unsigned int cnt_blk, int set_clr)
|
||||
{
|
||||
ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
|
||||
int err;
|
||||
unsigned int wp_group_size;
|
||||
|
||||
if (!mmc->wp_grp_enable)
|
||||
return -1; /* group write protection is not supported */
|
||||
|
||||
err = mmc_send_ext_csd(mmc, ext_csd);
|
||||
|
||||
if (err) {
|
||||
debug("ext_csd register cannot be retrieved\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((ext_csd[EXT_CSD_USER_WP] & EXT_CSD_US_PWR_WP_DIS)
|
||||
|| (ext_csd[EXT_CSD_USER_WP] & EXT_CSD_US_PERM_WP_EN)) {
|
||||
printf("User power-on write protection is disabled. \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP,
|
||||
EXT_CSD_US_PWR_WP_EN);
|
||||
if (err) {
|
||||
printf("Failed to enable user power-on write protection\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
wp_group_size = (mmc->wp_grp_size + 1) * mmc->erase_grp_size;
|
||||
|
||||
if (!cnt_blk || start_blk % wp_group_size || cnt_blk % wp_group_size) {
|
||||
printf("Error: Unaligned offset/count. offset/count should be aligned to 0x%x blocks\n", wp_group_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = mmc_send_wp_set_clr(mmc, start_blk, cnt_blk, set_clr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUPPORT_EMMC_BOOT
|
||||
/*
|
||||
* This function changes the size of boot partition and the size of rpmb
|
||||
|
|
|
|||
|
|
@ -90,6 +90,10 @@
|
|||
#define MMC_CMD_SET_BLOCK_COUNT 23
|
||||
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
|
||||
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
|
||||
#define MMC_CMD_SET_WRITE_PROT 28
|
||||
#define MMC_CMD_CLR_WRITE_PROT 29
|
||||
#define MMC_CMD_SEND_WRITE_PROT 30
|
||||
#define MMC_CMD_SEND_WRITE_PROT_TYPE 31
|
||||
#define MMC_CMD_ERASE_GROUP_START 35
|
||||
#define MMC_CMD_ERASE_GROUP_END 36
|
||||
#define MMC_CMD_ERASE 38
|
||||
|
|
@ -167,6 +171,17 @@
|
|||
#define SD_SWITCH_CHECK 0
|
||||
#define SD_SWITCH_SWITCH 1
|
||||
|
||||
#define MMC_RESP_TIMEOUT 2000
|
||||
#define MMC_ADDR_OUT_OF_RANGE(resp) ((resp >> 31) & 0x01)
|
||||
|
||||
/*
|
||||
* CSD fields
|
||||
*/
|
||||
#define WP_GRP_ENABLE(csd) ((csd[3] & 0x80000000) >> 31)
|
||||
#define WP_GRP_SIZE(csd) ((csd[2] & 0x0000001f))
|
||||
#define ERASE_GRP_MULT(csd) ((csd[2] & 0x000003e0) >> 5)
|
||||
#define ERASE_GRP_SIZE(csd) ((csd[2] & 0x00007c00) >> 10)
|
||||
|
||||
/*
|
||||
* EXT_CSD fields
|
||||
*/
|
||||
|
|
@ -181,6 +196,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 /* R/W */
|
||||
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
|
||||
#define EXT_CSD_BOOT_BUS_WIDTH 177
|
||||
#define EXT_CSD_PART_CONF 179 /* R/W */
|
||||
|
|
@ -241,6 +257,11 @@
|
|||
#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_US_PERM_WP_DIS (1 << 4)
|
||||
#define EXT_CSD_US_PWR_WP_DIS (1 << 3)
|
||||
#define EXT_CSD_US_PERM_WP_EN (1 << 2)
|
||||
#define EXT_CSD_US_PWR_WP_EN (1 << 0)
|
||||
|
||||
#define R1_ILLEGAL_COMMAND (1 << 22)
|
||||
#define R1_APP_CMD (1 << 5)
|
||||
|
||||
|
|
@ -379,6 +400,8 @@ struct mmc {
|
|||
uint write_bl_len;
|
||||
uint erase_grp_size; /* in 512-byte sectors */
|
||||
uint hc_wp_grp_size; /* in 512-byte sectors */
|
||||
uint wp_grp_size;
|
||||
uint wp_grp_enable;
|
||||
u64 capacity;
|
||||
u64 capacity_user;
|
||||
u64 capacity_boot;
|
||||
|
|
@ -506,6 +529,9 @@ struct pci_device_id;
|
|||
int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported,
|
||||
int num_ids);
|
||||
|
||||
int mmc_write_protect(struct mmc *mmc, unsigned int start_blk,
|
||||
unsigned int cnt_blk, int set_clr);
|
||||
|
||||
/* Set block count limit because of 16 bit register limit on some hardware*/
|
||||
#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
|
||||
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue