platform/msm_shared/mmc.c
static unsigned int
mmc_boot_set_clr_power_on_wp_user(struct mmc_boot_card *card,
				  unsigned int addr,
				  unsigned int size, unsigned char set_clear_wp)
{
	struct mmc_boot_command cmd;
	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
	unsigned int wp_group_size, loop_count;
	unsigned int status;

	memset((struct mmc_boot_command *)&cmd, 0,
	       sizeof(struct mmc_boot_command));

	/* Disabling PERM_WP for USER AREA (CMD6) */
	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
				      MMC_BOOT_EXT_USER_WP,
				      MMC_BOOT_US_PERM_WP_DIS);

	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}

	/* Sending CMD13 to check card status */
	do {
		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
			break;
	}
	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}

	mmc_ret = mmc_boot_send_ext_cmd(card, ext_csd_buf);

	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}

	/* Make sure power-on write protection for user area is not disabled
	   and permanent write protection for user area is not enabled */

	if ((IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PERM_WP_EN))
	    ||
	    (IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PWR_WP_DIS)))
	{
		return MMC_BOOT_E_FAILURE;
	}

	if (ext_csd_buf[MMC_BOOT_EXT_ERASE_GROUP_DEF]) {
		/* wp_group_size = 512KB * HC_WP_GRP_SIZE * HC_ERASE_GRP_SIZE.
		   Getting write protect group size in sectors here. */

		wp_group_size =
		    (512 * 1024) * ext_csd_buf[MMC_BOOT_EXT_HC_WP_GRP_SIZE] *
		    ext_csd_buf[MMC_BOOT_EXT_HC_ERASE_GRP_SIZE] /
		    MMC_BOOT_WR_BLOCK_LEN;
	} else {
		/* wp_group_size = (WP_GRP_SIZE + 1) * (ERASE_GRP_SIZE + 1)
		 * (ERASE_GRP_MULT + 1).
		 This is defined as the number of write blocks directly */

		wp_group_size = (card->csd.erase_grp_size + 1) *
		    (card->csd.erase_grp_mult + 1) * (card->csd.wp_grp_size +
						      1);
	}

	if (wp_group_size == 0) {
		return MMC_BOOT_E_FAILURE;
	}

	/* Setting POWER_ON_WP for USER AREA (CMD6) */

	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
				      MMC_BOOT_EXT_USER_WP,
				      MMC_BOOT_US_PWR_WP_EN);

	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}

	/* Sending CMD13 to check card status */
	do {
		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
			break;
	}
	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}

	/* Calculating the loop count for sending SET_WRITE_PROTECT (CMD28)
	   or CLEAR_WRITE_PROTECT (CMD29).
	   We are write protecting the partitions in blocks of write protect
	   group sizes only */

	if (size % wp_group_size) {
		loop_count = (size / wp_group_size) + 1;
	} else {
		loop_count = (size / wp_group_size);
	}

	if (set_clear_wp)
		cmd.cmd_index = CMD28_SET_WRITE_PROTECT;
	else
		cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT;

	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
	cmd.resp_type = MMC_BOOT_RESP_R1B;

	for (unsigned int i = 0; i < loop_count; i++) {
		/* Sending CMD28 for each WP group size
		   address is in sectors already */
		cmd.argument = (addr + (i * wp_group_size));

		mmc_ret = mmc_boot_send_command(&cmd);

		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
			return mmc_ret;
		}

		/* Checking ADDR_OUT_OF_RANGE error in CMD28 response */
		if (IS_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
			return MMC_BOOT_E_FAILURE;
		}

		/* Sending CMD13 to check card status */
		do {
			mmc_ret = mmc_boot_get_card_status(card, 0, &status);
			if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
				break;
		}
		while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
		       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
			return mmc_ret;
		}
	}

	return MMC_BOOT_E_SUCCESS;
}
/*
 * Function to set/clear power-on write protection for the user area partitions
 */
Function to set/clear power-on write protection for the user area partitions
Function to set / clear power - on write protection for the user area partitions
static unsigned int
mmc_boot_set_clr_power_on_wp_user(struct mmc_boot_card *card,
				  unsigned int addr,
				  unsigned int size, unsigned char set_clear_wp)
{
	struct mmc_boot_command cmd;
	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
	unsigned int wp_group_size, loop_count;
	unsigned int status;
	memset((struct mmc_boot_command *)&cmd, 0,
	       sizeof(struct mmc_boot_command));
	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
				      MMC_BOOT_EXT_USER_WP,
				      MMC_BOOT_US_PERM_WP_DIS);
	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}
	do {
		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
			break;
	}
	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}
	mmc_ret = mmc_boot_send_ext_cmd(card, ext_csd_buf);
	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}
	if ((IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PERM_WP_EN))
	    ||
	    (IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PWR_WP_DIS)))
	{
		return MMC_BOOT_E_FAILURE;
	}
	if (ext_csd_buf[MMC_BOOT_EXT_ERASE_GROUP_DEF]) {
		wp_group_size =
		    (512 * 1024) * ext_csd_buf[MMC_BOOT_EXT_HC_WP_GRP_SIZE] *
		    ext_csd_buf[MMC_BOOT_EXT_HC_ERASE_GRP_SIZE] /
		    MMC_BOOT_WR_BLOCK_LEN;
	} else {
		wp_group_size = (card->csd.erase_grp_size + 1) *
		    (card->csd.erase_grp_mult + 1) * (card->csd.wp_grp_size +
						      1);
	}
	if (wp_group_size == 0) {
		return MMC_BOOT_E_FAILURE;
	}
	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
				      MMC_BOOT_EXT_USER_WP,
				      MMC_BOOT_US_PWR_WP_EN);
	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}
	do {
		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
			break;
	}
	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		return mmc_ret;
	}
	if (size % wp_group_size) {
		loop_count = (size / wp_group_size) + 1;
	} else {
		loop_count = (size / wp_group_size);
	}
	if (set_clear_wp)
		cmd.cmd_index = CMD28_SET_WRITE_PROTECT;
	else
		cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT;
	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
	cmd.resp_type = MMC_BOOT_RESP_R1B;
	for (unsigned int i = 0; i < loop_count; i++) {
		cmd.argument = (addr + (i * wp_group_size));
		mmc_ret = mmc_boot_send_command(&cmd);
		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
			return mmc_ret;
		}
		if (IS_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
			return MMC_BOOT_E_FAILURE;
		}
		do {
			mmc_ret = mmc_boot_get_card_status(card, 0, &status);
			if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
				break;
		}
		while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
		       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
			return mmc_ret;
		}
	}
	return MMC_BOOT_E_SUCCESS;
}
static unsigned int mmc_boot_set_clr_power_on_wp_user ( struct mmc_boot_card * card , unsigned int addr , unsigned int size , unsigned char set_clear_wp ) { struct mmc_boot_command cmd ; unsigned int mmc_ret = MMC_BOOT_E_SUCCESS ; unsigned int wp_group_size , loop_count ; unsigned int status ; memset ( ( struct mmc_boot_command * ) & cmd , 0 , sizeof ( struct mmc_boot_command ) ) ; mmc_ret = mmc_boot_switch_cmd ( card , MMC_BOOT_ACCESS_WRITE , MMC_BOOT_EXT_USER_WP , MMC_BOOT_US_PERM_WP_DIS ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } do { mmc_ret = mmc_boot_get_card_status ( card , 0 , & status ) ; if ( MMC_BOOT_CARD_STATUS ( status ) == MMC_BOOT_TRAN_STATE ) break ; } while ( ( mmc_ret == MMC_BOOT_E_SUCCESS ) && ( MMC_BOOT_CARD_STATUS ( status ) == MMC_BOOT_PROG_STATE ) ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } mmc_ret = mmc_boot_send_ext_cmd ( card , ext_csd_buf ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } if ( ( IS_BIT_SET_EXT_CSD ( MMC_BOOT_EXT_USER_WP , MMC_BOOT_US_PERM_WP_EN ) ) || ( IS_BIT_SET_EXT_CSD ( MMC_BOOT_EXT_USER_WP , MMC_BOOT_US_PWR_WP_DIS ) ) ) { return MMC_BOOT_E_FAILURE ; } if ( ext_csd_buf [ MMC_BOOT_EXT_ERASE_GROUP_DEF ] ) { wp_group_size = ( 512 * 1024 ) * ext_csd_buf [ MMC_BOOT_EXT_HC_WP_GRP_SIZE ] * ext_csd_buf [ MMC_BOOT_EXT_HC_ERASE_GRP_SIZE ] / MMC_BOOT_WR_BLOCK_LEN ; } else { wp_group_size = ( card -> csd . erase_grp_size + 1 ) * ( card -> csd . erase_grp_mult + 1 ) * ( card -> csd . wp_grp_size + 1 ) ; } if ( wp_group_size == 0 ) { return MMC_BOOT_E_FAILURE ; } mmc_ret = mmc_boot_switch_cmd ( card , MMC_BOOT_ACCESS_WRITE , MMC_BOOT_EXT_USER_WP , MMC_BOOT_US_PWR_WP_EN ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } do { mmc_ret = mmc_boot_get_card_status ( card , 0 , & status ) ; if ( MMC_BOOT_CARD_STATUS ( status ) == MMC_BOOT_TRAN_STATE ) break ; } while ( ( mmc_ret == MMC_BOOT_E_SUCCESS ) && ( MMC_BOOT_CARD_STATUS ( status ) == MMC_BOOT_PROG_STATE ) ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } if ( size % wp_group_size ) { loop_count = ( size / wp_group_size ) + 1 ; } else { loop_count = ( size / wp_group_size ) ; } if ( set_clear_wp ) cmd . cmd_index = CMD28_SET_WRITE_PROTECT ; else cmd . cmd_index = CMD29_CLEAR_WRITE_PROTECT ; cmd . cmd_type = MMC_BOOT_CMD_ADDRESS ; cmd . resp_type = MMC_BOOT_RESP_R1B ; for ( unsigned int i = 0 ; i < loop_count ; i ++ ) { cmd . argument = ( addr + ( i * wp_group_size ) ) ; mmc_ret = mmc_boot_send_command ( & cmd ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } if ( IS_ADDR_OUT_OF_RANGE ( cmd . resp [ 0 ] ) ) { return MMC_BOOT_E_FAILURE ; } do { mmc_ret = mmc_boot_get_card_status ( card , 0 , & status ) ; if ( MMC_BOOT_CARD_STATUS ( status ) == MMC_BOOT_TRAN_STATE ) break ; } while ( ( mmc_ret == MMC_BOOT_E_SUCCESS ) && ( MMC_BOOT_CARD_STATUS ( status ) == MMC_BOOT_PROG_STATE ) ) ; if ( mmc_ret != MMC_BOOT_E_SUCCESS ) { return mmc_ret ; } } return MMC_BOOT_E_SUCCESS ; }
Function to set/clear power-on write protection for the user area partitions
Function to set / clear power - on write protection for the user area partitions
/* Disabling PERM_WP for USER AREA (CMD6) */ /* Sending CMD13 to check card status */ /* Make sure power-on write protection for user area is not disabled
	   and permanent write protection for user area is not enabled */ /* wp_group_size = 512KB * HC_WP_GRP_SIZE * HC_ERASE_GRP_SIZE.
		   Getting write protect group size in sectors here. */ /* wp_group_size = (WP_GRP_SIZE + 1) * (ERASE_GRP_SIZE + 1)
		 * (ERASE_GRP_MULT + 1).
		 This is defined as the number of write blocks directly */ /* Setting POWER_ON_WP for USER AREA (CMD6) */ /* Sending CMD13 to check card status */ /* Calculating the loop count for sending SET_WRITE_PROTECT (CMD28)
	   or CLEAR_WRITE_PROTECT (CMD29).
	   We are write protecting the partitions in blocks of write protect
	   group sizes only */ /* Sending CMD28 for each WP group size
		   address is in sectors already */ /* Checking ADDR_OUT_OF_RANGE error in CMD28 response */ /* Sending CMD13 to check card status */