diff options
Diffstat (limited to 'drivers/mmc/mmc.c')
| -rw-r--r-- | drivers/mmc/mmc.c | 134 | 
1 files changed, 134 insertions, 0 deletions
| diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2590f1bcc..9c0652d9a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1374,3 +1374,137 @@ int mmc_initialize(bd_t *bis)  	return 0;  } + +#ifdef CONFIG_SUPPORT_EMMC_BOOT +/* + * This function changes the size of boot partition and the size of rpmb + * partition present on EMMC devices. + * + * Input Parameters: + * struct *mmc: pointer for the mmc device strcuture + * bootsize: size of boot partition + * rpmbsize: size of rpmb partition + * + * Returns 0 on success. + */ + +int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, +				unsigned long rpmbsize) +{ +	int err; +	struct mmc_cmd cmd; + +	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = MMC_CMD62_ARG1; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error1 = %d\n", err); +		return err; +	} + +	/* Boot partition changing mode */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = MMC_CMD62_ARG2; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error2 = %d\n", err); +		return err; +	} +	/* boot partition size is multiple of 128KB */ +	bootsize = (bootsize * 1024) / 128; + +	/* Arg: boot partition size */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = bootsize; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error3 = %d\n", err); +		return err; +	} +	/* RPMB partition size is multiple of 128KB */ +	rpmbsize = (rpmbsize * 1024) / 128; +	/* Arg: RPMB partition size */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = rpmbsize; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error4 = %d\n", err); +		return err; +	} +	return 0; +} + +/* + * This function shall form and send the commands to open / close the + * boot partition specified by user. + * + * Input Parameters: + * ack: 0x0 - No boot acknowledge sent (default) + *	0x1 - Boot acknowledge sent during boot operation + * part_num: User selects boot data that will be sent to master + *	0x0 - Device not boot enabled (default) + *	0x1 - Boot partition 1 enabled for boot + *	0x2 - Boot partition 2 enabled for boot + * access: User selects partitions to access + *	0x0 : No access to boot partition (default) + *	0x1 : R/W boot partition 1 + *	0x2 : R/W boot partition 2 + *	0x3 : R/W Replay Protected Memory Block (RPMB) + * + * Returns 0 on success. + */ +int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) +{ +	int err; +	struct mmc_cmd cmd; + +	/* Boot ack enable, boot partition enable , boot partition access */ +	cmd.cmdidx = MMC_CMD_SWITCH; +	cmd.resp_type = MMC_RSP_R1b; + +	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +			(EXT_CSD_PART_CONF << 16) | +			((EXT_CSD_BOOT_ACK(ack) | +			EXT_CSD_BOOT_PART_NUM(part_num) | +			EXT_CSD_PARTITION_ACCESS(access)) << 8); + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		if (access) { +			debug("mmc boot partition#%d open fail:Error1 = %d\n", +			      part_num, err); +		} else { +			debug("mmc boot partition#%d close fail:Error = %d\n", +			      part_num, err); +		} +		return err; +	} + +	if (access) { +		/* 4bit transfer mode at booting time. */ +		cmd.cmdidx = MMC_CMD_SWITCH; +		cmd.resp_type = MMC_RSP_R1b; + +		cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +				(EXT_CSD_BOOT_BUS_WIDTH << 16) | +				((1 << 0) << 8); + +		err = mmc_send_cmd(mmc, &cmd, NULL); +		if (err) { +			debug("mmc boot partition#%d open fail:Error2 = %d\n", +			      part_num, err); +			return err; +		} +	} +	return 0; +} +#endif |