u-boot-2018/drivers/mmc/sunxi_mmc_interface.c
2024-05-31 13:50:08 +08:00

1659 lines
40 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* MMC driver for allwinner sunxi platform.
*
*/
#include <config.h>
#include <common.h>
#include <command.h>
#include <errno.h>
#include <mmc.h>
#include <part.h>
#include <malloc.h>
#include <linux/list.h>
#include <div64.h>
#include "mmc_private.h"
#include "mmc_def.h"
int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value);
#if 0
static int mmc_wp_grp_aligned(struct mmc *mmc, unsigned int from, unsigned int nr)
{
if (!mmc->wp_grp_size)
return 0;
if (from % mmc->wp_grp_size || nr % mmc->wp_grp_size)
return 0;
return 1;
}
static void mmc_align_wp_grp(struct mmc *mmc, unsigned int from,
unsigned int nr, unsigned int *align_from, unsigned int *align_nr)
{
unsigned int rem, start, cnt;
MMCDBG("--1-- from: %d, nr: %d, wp_grp: %d\n", from, nr, mmc->wp_grp_size);
start = from;
cnt = nr;
rem = start % mmc->wp_grp_size;
if (rem) {
rem = mmc->wp_grp_size - rem;
start += rem;
if (cnt > rem)
cnt -= rem;
else {
MMCINFO("after adjust start addr, no more space need to wp!!\n");
goto RET;
}
}
rem = cnt % mmc->wp_grp_size;
if (rem)
cnt -= rem;
if (cnt == 0)
MMCINFO("after adjust nr, no more space need to wp!!\n");
RET:
MMCINFO("after adjust(0x%x): from %d, nr %d\n", mmc->wp_grp_size, start, cnt);
*align_from = start;
*align_nr = cnt;
return ;
}
static int mmc_set_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
struct mmc_cmd cmd;
int err = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.cmdidx = MMC_CMD_SET_WRITE_PROT;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = mmc->high_capacity ? wp_grp_sect_addr : wp_grp_sect_addr*512;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
MMCINFO("mmc set wp failed\n");
return 0;
}
static int mmc_clr_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
struct mmc_cmd cmd;
int err = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.cmdidx = MMC_CMD_CLR_WRITE_PROT;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = mmc->high_capacity ? wp_grp_sect_addr : wp_grp_sect_addr*512;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
MMCINFO("mmc clr wp failed\n");
return 0;
}
static int mmc_clear_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
struct mmc_cmd cmd;
int err = 0;
memset(&cmd, 0, sizeof(cmd));
cmd.cmdidx = MMC_CMD_CLR_WRITE_PROT;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = mmc->high_capacity ? wp_grp_sect_addr : wp_grp_sect_addr*512;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
MMCINFO("mmc clear wp failed\n");
return 0;
}
static int mmc_send_wp(struct mmc *mmc, u32 wp_grp_sect_addr, u8 *wp_sta)
{
struct mmc_cmd cmd;
struct mmc_data data;
int err = 0;
memset(&cmd, 0, sizeof(cmd));
memset(&data, 0, sizeof(data));
cmd.cmdidx = MMC_CMD_SEND_WRITE_PROT;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->high_capacity ? wp_grp_sect_addr : wp_grp_sect_addr*512;
data.dest = (char *)wp_sta;
data.blocks = 1;
data.blocksize = 4; /*32bit*/
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err)
MMCINFO("mmc send wp failed\n");
return 0;
}
static int mmc_send_wp_type(struct mmc *mmc, u32 wp_grp_sect_addr, u8 *wp_type)
{
struct mmc_cmd cmd;
struct mmc_data data;
int err = 0;
memset(&cmd, 0, sizeof(cmd));
memset(&data, 0, sizeof(data));
cmd.cmdidx = MMC_CMD_SEND_WRITE_PROT_TYPE;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->high_capacity ? wp_grp_sect_addr : wp_grp_sect_addr*512;
data.dest = (char *)wp_type;
data.blocks = 1;
data.blocksize = 8; /*64bit*/
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err)
MMCINFO("mmc send wp type failed\n");
return err;
}
s32 mmc_switch_user_wp(struct mmc *mmc, u32 val)
{
return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP, val);
}
static int mmc_set_one_poweron_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
s32 err = 0, ret = 0;
u32 rval = 0;
u8 ext_csd[512];
if (mmc->csd_perm_wp) {
MMCINFO("the entire device are write protected by csd[13]\n");
return 0;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("get ext_csd fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
rval = ext_csd[EXT_CSD_USER_WP];
/*this bit is R/W, one time programable and readable, it will PERMANENTLY disable the use of
* permanent write protection for write protection groups within all the partitions in the user
* area from the point this bit is set forward.
*/
/*rval |= (MMC_SWITCH_USER_WP_US_PERM_WP_DIS);*/
rval &= (~MMC_SWITCH_USER_WP_US_PERM_WP_EN);
rval &= (~MMC_SWITCH_USER_WP_US_PWR_WP_DIS);
rval |= (MMC_SWITCH_USER_WP_US_PWR_WP_EN);
ret = mmc_switch_user_wp(mmc, rval);
if (ret) {
MMCINFO("mmc_swtich_user_wp fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("get ext_csd fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
if (/*(card->extcsd.user_wp & MMC_SWITCH_USER_WP_US_PERM_WP_DIS) || */
(ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PERM_WP_EN)
|| (ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PWR_WP_DIS)
|| !(ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PWR_WP_EN)) {
MMCINFO("set US_PWR_WP_EN fail 0x%x -- %d\n", ext_csd[EXT_CSD_USER_WP], __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_set_wp(mmc, wp_grp_sect_addr);
if (ret) {
MMCINFO("mmc_set_wp error -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
mdelay(100);
ERR_OUT:
return err;
}
static int mmc_set_one_permanent_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
s32 err = 0, ret = 0;
u32 rval = 0;
u8 ext_csd[512];
if (mmc->csd_perm_wp) {
MMCINFO("the entire device are write protected by csd[13]\n");
return 0;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("get ext_csd fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
rval = ext_csd[EXT_CSD_USER_WP];
rval &= (~MMC_SWITCH_USER_WP_US_PERM_WP_DIS);
rval |= (MMC_SWITCH_USER_WP_US_PERM_WP_EN);
rval |= (MMC_SWITCH_USER_WP_US_PWR_WP_DIS);
rval &= (~MMC_SWITCH_USER_WP_US_PWR_WP_EN);
ret = mmc_switch_user_wp(mmc, rval);
if (ret) {
MMCINFO("mmc_swtich_user_wp fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("get ext_csd fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
if ((ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PERM_WP_DIS)
|| !(ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PERM_WP_EN)
|| !(ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PWR_WP_DIS)
|| (ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PWR_WP_EN)) {
MMCINFO("set US_PERM_WP_EN fail 0x%x -- %d\n", ext_csd[EXT_CSD_USER_WP], __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_set_wp(mmc, wp_grp_sect_addr);
if (ret) {
MMCINFO("mmc_set_wp error -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
mdelay(100);
ERR_OUT:
return err;
}
static int mmc_set_one_temporary_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
s32 err = 0, ret = 0;
u32 rval = 0;
u8 ext_csd[512];
if (mmc->csd_perm_wp) {
MMCINFO("the entire device are write protected by csd[13]\n");
return 0;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("get ext_csd fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
rval = ext_csd[EXT_CSD_USER_WP];
rval &= (~MMC_SWITCH_USER_WP_US_PERM_WP_DIS);
rval &= (~MMC_SWITCH_USER_WP_US_PWR_WP_DIS);
rval &= (~MMC_SWITCH_USER_WP_US_PERM_WP_EN);
rval &= (~MMC_SWITCH_USER_WP_US_PWR_WP_EN);
ret = mmc_switch_user_wp(mmc, rval);
if (ret) {
MMCINFO("mmc_swtich_user_wp fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("get ext_csd fail -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
if ((ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PERM_WP_DIS)
|| (ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PWR_WP_DIS)
|| (ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PERM_WP_EN)
|| (ext_csd[EXT_CSD_USER_WP] & MMC_SWITCH_USER_WP_US_PWR_WP_EN)) {
MMCINFO("set US_TEM_WP_EN fail 0x%x -- %d\n", ext_csd[EXT_CSD_USER_WP], __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_set_wp(mmc, wp_grp_sect_addr);
if (ret) {
MMCINFO("mmc_set_wp error -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
mdelay(100);
MMCINFO("******set US_TEM_WP_EN ok\n");
ERR_OUT:
return err;
}
static int mmc_clr_one_tem_wp(struct mmc *mmc, u32 wp_grp_sect_addr)
{
s32 err = 0, ret = 0;
if (mmc->csd_perm_wp) {
MMCINFO("the entire device are write protected by csd[13]\n");
return 0;
}
ret = mmc_clr_wp(mmc, wp_grp_sect_addr);
if (ret) {
MMCINFO("mmc_clr_wp error -- %d\n", __LINE__);
err = -1;
}
mdelay(100);
return err;
}
static int mmc_get_current_wp_info(struct mmc *mmc, u32 wp_grp_addr,
u8 *wp_sta, u8 *wp_type)
{
s32 err = 0, ret = 0;
u8 tmp_wp_sta[4] = {0};
u8 tmp_wp_type[8] = {0};
ret = mmc_send_wp(mmc, wp_grp_addr, &tmp_wp_sta[0]);
if (ret) {
MMCINFO("mmc_send_wp error -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
ret = mmc_send_wp_type(mmc, wp_grp_addr, &tmp_wp_type[0]);
if (ret) {
MMCINFO("mmc_send_wp_type error -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
{
MMCINFO("mmc_get_current_wp_info: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
tmp_wp_type[0], tmp_wp_type[1], tmp_wp_type[2], tmp_wp_type[3], tmp_wp_type[4], tmp_wp_type[5], tmp_wp_type[6], tmp_wp_type[7]);
}
/*e.g. 0x0, 0x02000000, big-endian ???*/
switch (tmp_wp_type[7] & 0x3) {
case 0:
MMCINFO("not protected - %d\n", (tmp_wp_type[7]&0x3));
break;
case 1:
MMCINFO("temporary wp - %d\n", (tmp_wp_type[7]&0x3));
break;
case 2:
MMCINFO("power-no wp - %d\n", (tmp_wp_type[7]&0x3));
break;
case 3:
MMCINFO("permanent wp - %d\n", (tmp_wp_type[7]&0x3));
break;
default:
MMCINFO("unknown wp type!!!!!\n");
break;
}
*wp_sta = tmp_wp_sta[3] & 0x1;
*wp_type = tmp_wp_type[7] & 0x3;
ERR_OUT:
return err;
}
#endif
/*
* --argument
* @mmc:
* @wp_type: write protection type
* 0-power-no write protection
* 1-permanent write protection
2-temporary write protection
* @align_type:
* 0-only support write protect group size aligned @from and @nr.
* 1-support any @from and @nr, but only execute write protect aligned write protect group size.
* @from: start sector
* @nr: the number of sectors
*
* --return
* 0-ok, execute write protect operation successfully.
* others-fail.
*/
#if 0
int mmc_user_write_protect(struct mmc *mmc, u32 wp_type, u32 align_type,
u32 from, u32 nr)
{
s32 ret = 0;
u32 align_from, align_nr;
u32 iwp, wp_start, wp_cnt, wp_addr;
u8 wp_sta = 0;
u8 wp_tp = 0;
#if 0
if (wp_type) {
MMCINFO("!!!!!!!!!!!!!! wp_type %d, return !!!!!!!!!!!!!!!\n", wp_type);
return 0;
}
if (!(mmc->drv_wp_feature & DRV_PARA_ENABLE_EMMC_USER_PART_WP)) {
MMCINFO("don't support write protect operation!!\n");
return -1;
}
if (IS_SD(mmc)) {
MMCINFO("SD Card don't support write protect operation!!!\n");
return -1;
}
#endif
if (mmc_wp_grp_aligned(mmc, from, nr) == 0) {
MMCINFO("@from and(or) @nr are not wp grp size(0x%x)aligned.\n", mmc->wp_grp_size);
if (align_type == 0) {
MMCINFO("input @from and(or) @nr error!");
return -1;
}
mmc_align_wp_grp(mmc, from, nr, &align_from, &align_nr);
} else {
align_from = from;
align_nr = nr;
}
wp_start = align_from;
wp_cnt = align_nr / mmc->wp_grp_size;
for (iwp = 0; iwp < wp_cnt; iwp++) {
wp_addr = wp_start + iwp*mmc->wp_grp_size;
/* if wp grp has already been protected, jump to next wp grp */
ret = mmc_get_current_wp_info(mmc, wp_addr, &wp_sta, &wp_tp);
if (ret) {
MMCINFO("mmc get wp info fail, before execute write protect!\n");
ret = -1;
goto ERR_OUT;
}
if (wp_type) {
if (wp_tp == 0x3) {
MMCINFO("already permanent wp\n");
continue;
} else if (wp_tp == 0x1) {
MMCINFO("already temporary wp\n");
continue;
}
} else {
if (wp_tp == 0x2) {
MMCINFO("already power-on wp\n");
continue;
}
}
/* execute write protect operation */
if (wp_type) {
if (wp_type == 1)
ret = mmc_set_one_permanent_wp(mmc, wp_addr);
else
ret = mmc_set_one_temporary_wp(mmc, wp_addr);
} else
ret = mmc_set_one_poweron_wp(mmc, wp_addr);
if (ret) {
MMCINFO("mmc set wp error\n");
ret = -1;
goto ERR_OUT;
}
/* check write protect status */
ret = mmc_get_current_wp_info(mmc, wp_addr, &wp_sta, &wp_tp);
if (ret) {
MMCINFO("mmc get wp info error!\n");
ret = -1;
goto ERR_OUT;
}
if (wp_type) {
if (wp_type == 1) {
if (wp_tp != 0x3) {
MMCINFO("mmc set permanent wp fail\n");
ret = -1;
goto ERR_OUT;
}
} else {
if (wp_type == 2) {
if (wp_tp != 1) {
MMCINFO("mmc set temporary wp fail\n");
ret = -1;
goto ERR_OUT;
}
}
}
} else {
if (wp_tp != 0x2) {
MMCINFO("mmc set power-on wp fail\n");
ret = -1;
goto ERR_OUT;
}
}
}
ERR_OUT:
return ret;
}
#endif
/*
* --argument
* @mmc:
* @align_type:
* 0-only support write protect group size aligned @from and @nr.
* 1-support any @from and @nr, but only execute write protect aligned write protect group size.
* @from: start sector
* @nr: the number of sectors
*
* --return
* 0-ok, execute clear temporary write protection successfully.
* others-fail.
*/
#if 0
int mmc_user_clr_tem_write_protect(struct mmc *mmc, u32 align_type,
u32 from, u32 nr)
{
s32 ret = 0;
u32 align_from, align_nr;
u32 iwp, wp_start, wp_cnt, wp_addr;
u8 wp_sta = 0;
u8 wp_tp = 0;
#if 0
if (wp_type) {
MMCINFO("!!!!!!!!!!!!!! wp_type %d, return !!!!!!!!!!!!!!!\n", wp_type);
return 0;
}
if (!(mmc->drv_wp_feature & DRV_PARA_ENABLE_EMMC_USER_PART_WP)) {
MMCINFO("don't support write protect operation!!\n");
return -1;
}
if (IS_SD(mmc)) {
MMCINFO("SD Card don't support write protect operation!!!\n");
return -1;
}
#endif
MMCINFO("!!!!!!!!!!!!!! clr tem !!!!!!!!!!!!!!!\n");
if (mmc_wp_grp_aligned(mmc, from, nr) == 0) {
MMCINFO("@from and(or) @nr are not wp grp size(0x%x)aligned.\n", mmc->wp_grp_size);
if (align_type == 0) {
MMCINFO("input @from and(or) @nr error!");
return -1;
}
mmc_align_wp_grp(mmc, from, nr, &align_from, &align_nr);
} else {
align_from = from;
align_nr = nr;
}
wp_start = align_from;
wp_cnt = align_nr / mmc->wp_grp_size;
for (iwp = 0; iwp < wp_cnt; iwp++) {
wp_addr = wp_start + iwp*mmc->wp_grp_size;
/* if wp grp has already been protected, jump to next wp grp */
ret = mmc_get_current_wp_info(mmc, wp_addr, &wp_sta, &wp_tp);
if (ret) {
MMCINFO("mmc get wp info fail, before execute write protect!\n");
ret = -1;
goto ERR_OUT;
}
if (wp_tp != 0x1) {
MMCINFO("no temporary wp\n");
continue;
}
/* execute write protect operation */
ret = mmc_clr_one_tem_wp(mmc, wp_addr);
if (ret) {
MMCINFO("mmc clear temporary error\n");
ret = -1;
goto ERR_OUT;
}
/* check write protect status */
ret = mmc_get_current_wp_info(mmc, wp_addr, &wp_sta, &wp_tp);
if (ret) {
MMCINFO("mmc get wp info error!\n");
ret = -1;
goto ERR_OUT;
}
if (wp_tp != 0x0) {
MMCINFO("clear temporary wp failed\n");
ret = -1;
goto ERR_OUT;
}
}
ERR_OUT:
return ret;
}
#endif
/*
* --argument
* @dev_num: card number
* @from: start sector
* @nr: the number of sectors
*
* --return
* 0-ok, execute clear temporary write protection successfully.
* others-fail.
* only support write protect group size aligned @from and @nr.
*/
#if 0
int mmc_clr_tem_wp(int dev_num, unsigned start, unsigned blkcnt)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support write protect!\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
if (!(mmc->cfg->drv_wp_feature & DRV_PARA_ENABLE_EMMC_USER_PART_WP)) {
MMCINFO("don't support write protect operation!!\n");
ret = -1;
goto ERR_RET;
}
ret = mmc_user_clr_tem_write_protect(mmc, 0, start, blkcnt);
if (ret)
MMCINFO("mmc_user_write_protect error!\n");
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_user_scan_wp_sta(struct mmc *mmc)
{
s32 err = 0, ret = 0;
u32 wp_addr = 0;
u8 wp_type[8] = {0};
u32 wp_hit_addr[10] = {0}; /* record the first 10 wp group info */
u32 wp_hit_type[10] = {0};
u32 wp_hit_cnt = 0;
u32 wp_grp_cnt = mmc->block_dev.lba / mmc->wp_grp_size;
u32 sta, val = 0;
int i, j, k;
if (!(mmc->cfg->drv_wp_feature & DRV_PARA_ENABLE_EMMC_USER_PART_WP)) {
MMCINFO("don't support write protect operation!!\n");
return -1;
}
if (IS_SD(mmc)) {
MMCINFO("SD Card don't support write protect operation!!!\n");
return -1;
}
MMCINFO("total wp cnt: %d(0x%x/0x%x)\n", wp_grp_cnt, mmc->block_dev.lba, mmc->wp_grp_size);
/*mmc_user_write_protect(mmc,2,0,32768,32768);*/
/*mmc_user_clr_tem_write_protect(mmc,0,32768,32768);*/
/*mmc_clr_tem_wp(2, 32768,32768);*/
for (i = 0; i < wp_grp_cnt; i += 32) /*#define WP_GRP_CNT_EACH_CMD 32*/ {
wp_addr = i * mmc->wp_grp_size;
memset(wp_type, 0, 8);
ret = mmc_send_wp_type(mmc, wp_addr, &wp_type[0]);
if (ret) {
MMCINFO("mmc_send_wp_type error -- %d\n", __LINE__);
err = -1;
goto ERR_OUT;
}
{
/*
MMCINFO("mmc_user_scan_wp_sta: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
wp_type[0], wp_type[1], wp_type[2], wp_type[3], wp_type[4], wp_type[5], wp_type[6], wp_type[7]);
*/
}
/* e.g. 0 x0, 0x02000000, big-endian ??? */
for (j = 0; j < 8; j++) {
val = wp_type[7-j];
/*MMCINFO("j%d, val 0x%x\n", j, val);*/
for (k = 0; k < 4 ; k++) {
sta = (val>>(2*k)) & 0x3;
if (sta) {
wp_addr = mmc->wp_grp_size * (i + j*4 + k);
/*MMCINFO("%d %d %d, 0x%x, sta %d\n", i, j, k, wp_addr, sta);
*/
if (wp_hit_cnt < 10) {
wp_hit_addr[wp_hit_cnt] = wp_addr;
wp_hit_type[wp_hit_cnt] = sta;
}
wp_hit_cnt++;
}
}
}
}
if (wp_hit_cnt) {
MMCINFO("%d wp are write protected, some wp are as follow: \n", wp_hit_cnt);
if (wp_hit_cnt > 10)
k = 10;
else
k = wp_hit_cnt;
for (i = 0; i < k; i++) {
switch (wp_hit_type[i]) {
case 0:
MMCINFO("wp grp %d-0x%x: not protected\n",
wp_hit_addr[i]/mmc->wp_grp_size, wp_hit_addr[i]);
break;
case 1:
MMCINFO("wp grp %d-0x%x: temporary wp\n",
wp_hit_addr[i]/mmc->wp_grp_size, wp_hit_addr[i]);
break;
case 2:
MMCINFO("wp grp %d-0x%x: power-no wp\n",
wp_hit_addr[i]/mmc->wp_grp_size, wp_hit_addr[i]);
break;
case 3:
MMCINFO("wp grp %d-0x%x: permanent wp\n",
wp_hit_addr[i]/mmc->wp_grp_size, wp_hit_addr[i]);
break;
default:
MMCINFO("unknown wp type!!!!!\n");
break;
}
}
}
ERR_OUT:
return err;
}
#endif
/*
* --argument
* @dev_num: card number
* @wp_type: write protection type
* 0-power-no write protection
* 1-permanent write protection
2-temporary write protection
* @from: start sector
* @nr: the number of sectors
*
* --return
* 0-ok, execute write protect operation successfully.
* others-fail.
* only support write protect group size aligned @from and @nr.
*/
#if 0
int mmc_mmc_user_write_protect(int dev_num, unsigned wp_type, unsigned start, unsigned blkcnt)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support write protect!\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
if (!(mmc->cfg->drv_wp_feature & DRV_PARA_ENABLE_EMMC_USER_PART_WP)) {
MMCINFO("don't support write protect operation!!\n");
ret = -1;
goto ERR_RET;
}
ret = mmc_user_write_protect(mmc, wp_type, 0, start, blkcnt);
if (ret)
MMCINFO("mmc_user_write_protect error!\n");
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
/*
* --argument
* @dev_num: card number
* @wp_grp_size:
* return the wp group size
* --return
* 0-ok,
* others-fail.
*/
int mmc_mmc_user_get_wp_grp_size(int dev_num, unsigned int *wp_grp_size)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support write protect!\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
*wp_grp_size = mmc->wp_grp_size;
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
static ulong mmc_do_burn_boot(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src)
{
s32 err = 0;
ulong rblk, blocks_do = 0;
void *dst = NULL;
struct mmc *mmc = find_mmc_device(dev_num);
dst = (void *)malloc(blkcnt * mmc->write_bl_len);
if (dst == NULL) {
MMCINFO("%s: request memory fail\n", __FUNCTION__);
return 0;
}
/* write boot0 */
blocks_do = mmc_bwrite(dev_num, start, blkcnt, src);
if (blocks_do != blkcnt) {
MMCINFO("%s: write boot0 fail\n", __FUNCTION__);
err = -1;
goto ERR_RET;
}
/* read and check */
rblk = mmc_bread(dev_num, start, blkcnt, dst);
if ((rblk < blkcnt) || memcmp(src, dst, blkcnt * mmc->write_bl_len)) {
MMCINFO("%s: check boot0 fail\n", __FUNCTION__);
err = -1;
} else
MMCDBG("%s: check boot0 ok\n", __FUNCTION__);
ERR_RET:
free(dst);
if (err)
return 0;
else
return blocks_do;
}
static ulong mmc_burn_boot(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src)
{
lbaint_t blocks_do_user = 0, blocks_do_boot = 0;
ulong start_todo = start;
signed int err = 0;
struct mmc *mmc = find_mmc_device(dev_num);
if ((mmc->cfg->platform_caps.drv_burn_boot_pos & DRV_PARA_BURN_EMMC_BOOT_PART)
&& mmc->boot_support) {
MMCDBG("%s: start burn emmc boot part: %d...\n", __func__, (int)start);
/* enable boot mode */
err = mmc_switch_boot_bus_cond(dev_num,
MMC_SWITCH_BOOT_SDR_NORMAL,
MMC_SWITCH_BOOT_RST_BUS_COND,
MMC_SWITCH_BOOT_BUS_SDRx4_DDRx4);
if (err) {
MMCINFO("mmc switch boot bus condition failed\n");
goto DISABLE_BOOT_MODE;
}
/* configure boot mode */
err = mmc_switch_boot_part(dev_num,
MMC_SWITCH_PART_BOOT_ACK_ENB,
MMC_SWITCH_PART_BOOT_PART_1);
if (err) {
MMCINFO("mmc configure boot partition failed\n");
goto DISABLE_BOOT_MODE;
}
err = mmc_switch_part(dev_num, MMC_SWITCH_PART_BOOT_PART_1);
if (err) {
MMCINFO("switch to boot1 partition failed\n");
goto DISABLE_BOOT_MODE;
}
/*for smhc2, in eMMC boot partition,boot0.bin start from 0 sector,so we must change start form 16 to 0
* for smhc3, in eMMC boot partition,boot0.bin start from 0 sector,so we must change start form 16 to 1
*/
if (dev_num == 3)
start_todo = 1;
else
start_todo = 0;
blocks_do_boot = mmc_do_burn_boot(dev_num, start_todo, blkcnt, src);
if (blocks_do_boot != blkcnt)
MMCINFO("burn boot to emmc boot1 partition failed" LBAF "\n", blocks_do_boot);
/* switch back to user partiton */
err = mmc_switch_part(dev_num, 0);
if (err) {
MMCINFO("switch back to user partition failed\n");
return 0;
}
}
DISABLE_BOOT_MODE:
if ((err || !(mmc->cfg->platform_caps.drv_burn_boot_pos & DRV_PARA_BURN_EMMC_BOOT_PART))
&& mmc->boot_support) {
/* disable boot mode */
err = mmc_switch_boot_part(dev_num, 0, MMC_SWITCH_PART_BOOT_PART_NONE);
if (err)
MMCINFO("mmc disable boot mode failed\n");
}
/* burn boot to user partition */
if (!(mmc->cfg->platform_caps.drv_burn_boot_pos & DRV_PARA_NOT_BURN_USER_PART)) {
MMCDBG("%s: start burn emmc user part: %d...\n", __func__, (int)start);
blocks_do_user = mmc_do_burn_boot(dev_num, start, blkcnt, src);
if (blocks_do_user != blkcnt)
MMCINFO("burn boot to user partition failed," LBAFU "\n", blocks_do_user);
}
if (blocks_do_user == blkcnt || blocks_do_boot == blkcnt)
return blkcnt;
else
return 0;
}
/* use same memory, if get a good boot0, exit.*/
static ulong mmc_get_boot(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
{
lbaint_t blocks_do = 0;
ulong start_todo = start;
struct mmc *mmc = find_mmc_device(dev_num);
if (!(mmc->cfg->platform_caps.drv_burn_boot_pos & DRV_PARA_NOT_BURN_USER_PART)) {
blocks_do = mmc_bread(dev_num, start_todo, blkcnt, dst);
if (blocks_do != blkcnt) {
MMCINFO("%s: get boot0 from user part err\n", __FUNCTION__);
} else {
MMCDBG("%s: get boot0 from user part ok, return..\n", __FUNCTION__);
goto RET;
}
}
if ((mmc->cfg->platform_caps.drv_burn_boot_pos & DRV_PARA_BURN_EMMC_BOOT_PART)
&& mmc->boot_support) {
if (mmc_switch_part(dev_num, MMC_SWITCH_PART_BOOT_PART_1)) {
MMCINFO("%s: switch to boot1 part failed\n", __FUNCTION__);
goto RET;
}
/*for smhc2, in eMMC boot partition,boot0.bin start from 0 sector,so we must change start form 16 to 0
* for smhc3, in eMMC boot partition,boot0.bin start from 0 sector,so we must change start form 16 to 1
*/
if (dev_num == 3)
start_todo = 1;
else
start_todo = 0;
blocks_do = mmc_bread(dev_num, start_todo, blkcnt, dst);
if (blocks_do != blkcnt) {
MMCINFO("%s: get boot0 from boot part err\n", __FUNCTION__);
} else {
MMCDBG("%s: get boot0 from boot part ok\n", __FUNCTION__);
}
if (mmc_switch_part(dev_num, 0)) {
MMCINFO("%s: switch back to user part failed,"
"it maybe still in boot part!!!\n", __FUNCTION__);
goto RET;
}
}
RET:
return blocks_do;
}
static ulong mmc_bwrite_mass_pro(int dev_num, ulong start, lbaint_t blkcnt, const void *src)
{
MMCDBG("%s: dev %d, start %ld, blkcnt %ld src 0x%x\n", __FUNCTION__, dev_num, start, blkcnt, (u32)src);
if ((((dev_num == 2) && (start == BOOT0_SDMMC_START_ADDR)) || ((dev_num == 3) && (start == BOOT0_EMMC3_START_ADDR)))
&& ((start+blkcnt) < CONFIG_MMC_LOGICAL_OFFSET)) {
MMCDBG("%s: start burn boot data...\n", __FUNCTION__);
return mmc_burn_boot(dev_num, start, blkcnt, src);
} else /*if (start > CONFIG_MMC_LOGICAL_OFFSET)*/ {
MMCDBG("%s: start burn user data...\n", __FUNCTION__);
return mmc_bwrite(dev_num, start, blkcnt, src);
}
/*
else
{
MMCINFO("%s: input parameter error!\n", __FUNCTION__);
}
*/
return 0;
}
static ulong mmc_bread_mass_pro(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
MMCDBG("%s: dev %d, start %ld, blkcnt %ld src 0x%x\n", __FUNCTION__, dev_num, start, blkcnt, (u32)dst);
if ((((dev_num == 2) && (start == BOOT0_SDMMC_START_ADDR)) || ((dev_num == 3) && (start == BOOT0_EMMC3_START_ADDR)))
&& ((start+blkcnt) < CONFIG_MMC_LOGICAL_OFFSET)) {
MMCDBG("%s: start read boot data...\n", __FUNCTION__);
return mmc_get_boot(dev_num, start, blkcnt, dst);
} else /*if (start > CONFIG_MMC_LOGICAL_OFFSET)*/ {
MMCDBG("%s: start read user data...\n", __FUNCTION__);
return mmc_bread(dev_num, start, blkcnt, dst);
}
/*
else
{
MMCINFO("%s: input parameter error!\n", __FUNCTION__);
}
*/
return 0;
}
/**
* mmc_enable_bootop - enable boot mode.
* @dev_num: card number
* @part_nu: emmc boot partition number,should be 1 or 2
* @enable: 1 enable boot operation,0 disable
*
* return 0 means ok,-1 means failed;
*/
int mmc_enable_bootop(int dev_num,
int part_nu,
int enable)
{
struct mmc *mmc = find_mmc_device(dev_num);
int err = 0;
if (mmc->boot_support) {
if ((part_nu != MMC_SWITCH_PART_BOOT_PART_1)
&& part_nu != MMC_SWITCH_PART_BOOT_PART_2) {
MMCINFO("%s,%d:wrong mmc boot partition num %d:\n",
__FUNCTION__, __LINE__, part_nu);
return -1;
}
if (enable) {
/* enable boot mode */
err = mmc_switch_boot_bus_cond(dev_num,
MMC_SWITCH_BOOT_SDR_NORMAL,
MMC_SWITCH_BOOT_RST_BUS_COND,
MMC_SWITCH_BOOT_BUS_SDRx4_DDRx4);
if (err) {
MMCINFO("mmc switch boot bus condition failed\n");
return -1;
}
/* configure boot mode */
err = mmc_switch_boot_part(dev_num,
MMC_SWITCH_PART_BOOT_ACK_ENB,
part_nu);
if (err) {
MMCINFO("mmc set boot partition failed\n");
return -1;
}
MMCINFO("mmc enable boot mode ok\n");
} else {
/* disable boot mode */
err = mmc_switch_boot_part(dev_num,
0,
MMC_SWITCH_PART_BOOT_PART_NONE);
if (err) {
MMCINFO("mmc disable boot mode failed\n");
return -1;
}
MMCINFO("mmc disable boot mode ok\n");
}
return 0;
} else {
MMCINFO("don't support boot partition\n");
return -1;
}
}
/**
* mmc_write_bootp - write data to boot partition.
* @dev_num: card number
* @start:start sector
* @blkcnt:count of sector data to transfer
* @part_nu: emmc boot partition number,should be 1 or 2
* @src: data buffer address to be writen to emmc
*
* return number of sector has been writen to emmc,if return 0, it mean failed;
*/
unsigned long mmc_write_bootp(int dev_num,
lbaint_t start,
lbaint_t blkcnt,
int part_nu,
const void *src)
{
lbaint_t blocks_do_boot = 0;
ulong start_todo = start;
signed int err = 0;
struct mmc *mmc = find_mmc_device(dev_num);
if (mmc->boot_support) {
if ((part_nu != MMC_SWITCH_PART_BOOT_PART_1)
&& part_nu != MMC_SWITCH_PART_BOOT_PART_2) {
MMCINFO("%s,%d: wrong mmc boot partition num %d:\n",
__FUNCTION__, __LINE__, part_nu);
return 0;
}
if ((start + blkcnt) > (mmc->capacity_boot/512)) {
MMCINFO("%s,%d: over mmc boot part size\n",
__FUNCTION__, __LINE__);
return 0;
}
MMCDBG("%s: start write emmc boot part: %d...\n",
__FUNCTION__, (int)start);
err = mmc_switch_part(dev_num, part_nu);
if (err) {
MMCINFO("switch to boot%d partition failed\n",
part_nu);
return 0;
}
blocks_do_boot = mmc_do_burn_boot(dev_num,
start_todo,
blkcnt,
src);
if (blocks_do_boot != blkcnt) {
MMCINFO("burn boot to mmc boot%d partition failed"LBAF"\n",
part_nu, blocks_do_boot);
return 0;
}
/* switch back to user partiton */
err = mmc_switch_part(dev_num, 0);
if (err) {
MMCINFO("switch back to user partition failed\n");
return 0;
}
return blocks_do_boot;
} else {
MMCINFO("%s,%d: don't support boot partition\n",
__FUNCTION__, __LINE__);
return 0;
}
}
/**
* mmc_read_bootp - read boot partition data
* @dev_num: card number
* @start:start sector
* @blkcnt:count of sector data to transfer
* @part_nu: emmc boot partition number,should be 1 or 2
* @dst: data buffer address to be writen from emmc
*
* return number of sector has been read from emmc,if return 0, it mean failed;
*/
unsigned long mmc_read_bootp(int dev_num,
lbaint_t start,
lbaint_t blkcnt,
int part_nu,
void *dst)
{
lbaint_t blocks_do_boot = 0;
ulong start_todo = start;
struct mmc *mmc = find_mmc_device(dev_num);
if (mmc->boot_support) {
if ((part_nu != MMC_SWITCH_PART_BOOT_PART_1)
&& part_nu != MMC_SWITCH_PART_BOOT_PART_2) {
MMCINFO("%s,%d: wrong mmc boot partition num %d:\n",
__FUNCTION__, __LINE__, part_nu);
return 0;
}
if ((start + blkcnt) > (mmc->capacity_boot/512)) {
MMCINFO("%s,%d: over emmc boot part size\n",
__FUNCTION__, __LINE__);
return 0;
}
if (mmc_switch_part(dev_num, part_nu)) {
MMCINFO("%s: switch to boot%d part failed\n",
__FUNCTION__, part_nu);
return 0;
}
blocks_do_boot = mmc_bread(dev_num, start_todo, blkcnt, dst);
if (blocks_do_boot != blkcnt) {
MMCINFO("%s: get boot0 from boot part err\n",
__FUNCTION__);
return 0;
} else {
MMCDBG("%s: get boot0 from boot part ok\n",
__FUNCTION__);
}
if (mmc_switch_part(dev_num, 0)) {
MMCINFO("%s: switch back to user part failed\n",
__FUNCTION__);
return 0;
}
return blocks_do_boot;
} else {
MMCINFO("%s,%d: don't support boot partition\n",
__FUNCTION__, __LINE__);
return 0;
}
}
/**
* mmc_get_boot_cap - get emmc boot partition capacity
* @dev_num: card number
*
* return number of sector of emmc boot partition capacity;
*/
u64 mmc_get_boot_cap(int dev_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
return mmc->capacity_boot/512;
}
#ifdef CONFIG_SUNXI_SECURE_STORAGE
static int
check_secure_area(ulong start, lbaint_t blkcnt)
{
u32 sta_add = start;
u32 end_add = start + blkcnt -1;
u32 se_sta_add = SDMMC_SECURE_STORAGE_START_ADD;
u32 se_end_add = SDMMC_SECURE_STORAGE_START_ADD + (SDMMC_ITEM_SIZE * 2 * MAX_SECURE_STORAGE_MAX_ITEM) - 1;
if (blkcnt <= (SDMMC_ITEM_SIZE * 2 * MAX_SECURE_STORAGE_MAX_ITEM)) {
if (((sta_add >= se_sta_add) && (sta_add <= se_end_add))
|| ((end_add >= se_sta_add) && (end_add <= se_end_add))) {
return 1;
}
} else {
if (((se_sta_add >= sta_add) && (se_sta_add <= end_add))
|| ((se_end_add >= sta_add) && (se_end_add <= end_add))) {
return 1;
}
}
return 0;
}
static ulong
mmc_bread_secure(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %ld,end %ld\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_bread(dev_num, start, blkcnt, dst);
}
static ulong
mmc_bwrite_secure(int dev_num, ulong start, lbaint_t blkcnt, const void *src)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %ld,end %ld\n",\
__FUNCTION__, __LINE__, start, start + blkcnt - 1);
return -1;
}
return mmc_bwrite(dev_num, start, blkcnt, src);
}
static ulong
mmc_berase_secure(int dev_num, unsigned long start, lbaint_t blkcnt)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %ld,end %ld\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_berase(dev_num, start, blkcnt);
}
static ulong
mmc_bwrite_mass_pro_secure(int dev_num, ulong start, lbaint_t blkcnt, const void *src)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %ld,end %ld\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_bwrite_mass_pro(dev_num, start, blkcnt, src);
}
static ulong
mmc_bread_mass_pro_secure(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d\n",
__FUNCTION__, __LINE__);
MMCINFO("start %ld,end %ld\n",
start, start + blkcnt-1);
return -1;
}
return mmc_bread_mass_pro(dev_num, start, blkcnt, dst);
}
static int
mmc_secure_wipe_secure(int dev_num, unsigned int start, unsigned int blkcnt, unsigned int *skip_space)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d\n",
__FUNCTION__, __LINE__);
MMCINFO("start %ld,end %ld\n",
start, start + blkcnt-1);
return -1;
}
return mmc_secure_wipe(dev_num, start, blkcnt, skip_space);
}
static int
mmc_mmc_erase_secure(int dev_num, unsigned int start, unsigned int blkcnt, unsigned int *skip_space)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_mmc_erase(dev_num, start, blkcnt, skip_space);
}
static int
mmc_mmc_trim_secure(int dev_num, unsigned int start, unsigned int blkcnt)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_mmc_trim(dev_num, start, blkcnt);
}
static int
mmc_mmc_discard_secure(int dev_num, unsigned int start, unsigned int blkcnt)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_mmc_discard(dev_num, start, blkcnt);
}
static int
mmc_mmc_sanitize_secure(int dev_num)
{
return mmc_mmc_sanitize(dev_num);
}
static int
mmc_mmc_secure_erase_secure(int dev_num, unsigned int start, unsigned int blkcnt, unsigned int *skip_space)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_mmc_secure_erase(dev_num, start, blkcnt, skip_space);
}
static int
mmc_mmc_secure_trim_secure(int dev_num, unsigned int start, unsigned int blkcnt)
{
if (check_secure_area(start, blkcnt)) {
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__, __LINE__, start, start + blkcnt-1);
return -1;
}
return mmc_mmc_secure_trim(dev_num, start, blkcnt);
}
static int
get_sdmmc_secure_storage_max_item(void)
{
return MAX_SECURE_STORAGE_MAX_ITEM;
}
static int
sdmmc_secure_storage_write(s32 dev_num, u32 item, u8 *buf, lbaint_t blkcnt)
{
s32 ret = 0;
if (buf == NULL) {
MMCINFO("intput buf is NULL \n");
return -1;
}
if (item > MAX_SECURE_STORAGE_MAX_ITEM) {
MMCINFO("item exceed %d\n", MAX_SECURE_STORAGE_MAX_ITEM);
return -1;
}
if (blkcnt > SDMMC_ITEM_SIZE) {
MMCINFO("block count exceed %d\n", SDMMC_ITEM_SIZE);
return -1;
}
/* first backups*/
ret = mmc_bwrite(dev_num, SDMMC_SECURE_STORAGE_START_ADD + SDMMC_ITEM_SIZE * 2 * item, blkcnt, buf);
if (ret != blkcnt) {
MMCINFO("Write first backup failed\n");
return -1;
}
/*second backups*/
ret = mmc_bwrite(dev_num, SDMMC_SECURE_STORAGE_START_ADD + SDMMC_ITEM_SIZE * 2 * item + SDMMC_ITEM_SIZE, blkcnt, buf);
if (ret != blkcnt) {
MMCINFO("Write second backup failed\n");
return -1;
}
return blkcnt;
}
static int
sdmmc_secure_storage_read(s32 dev_num, u32 item, u8 *buf, lbaint_t blkcnt)
{
s32 ret = 0;
s32 *fst_bak = NULL;
s32 *sec_bak = NULL;
if (buf == NULL) {
MMCINFO("intput buf is NULL\n");
ret = -1;
goto out;
}
if (item > MAX_SECURE_STORAGE_MAX_ITEM) {
MMCINFO("item exceed %d\n", MAX_SECURE_STORAGE_MAX_ITEM);
ret = -1;
goto out;
}
if (blkcnt > SDMMC_ITEM_SIZE) {
MMCINFO("block count exceed %d\n", SDMMC_ITEM_SIZE);
ret = -1;
goto out;
}
fst_bak = malloc(blkcnt*512);
if (fst_bak == NULL) {
MMCINFO("malloc buff failed in fun %s line %d\n", __FUNCTION__, __LINE__);
ret = -1;
goto out;
}
sec_bak = malloc(blkcnt*512);
if (sec_bak == NULL) {
MMCINFO("malloc buff failed in fun %s line %d\n", __FUNCTION__, __LINE__);
ret = -1;
goto out_fst;
}
/*first backups*/
ret = mmc_bread(dev_num, SDMMC_SECURE_STORAGE_START_ADD + SDMMC_ITEM_SIZE * 2 * item, blkcnt, fst_bak);
if (ret != blkcnt) {
MMCINFO("read first backup failed in fun %s line %d\n", __FUNCTION__, __LINE__);
ret = -1;
goto out_sec;
}
/*second backups*/
ret = mmc_bread(dev_num, SDMMC_SECURE_STORAGE_START_ADD + SDMMC_ITEM_SIZE * 2 * item + SDMMC_ITEM_SIZE, blkcnt, sec_bak);
if (ret != blkcnt) {
MMCINFO("read second backup failed fun %s line %d\n", __FUNCTION__, __LINE__);
ret = -1;
goto out_sec;
}
if (memcmp(fst_bak, sec_bak, blkcnt * 512)) {
MMCINFO("first and second bak compare failed fun %s line %d\n", __FUNCTION__, __LINE__);
ret = -1;
} else {
memcpy(buf, fst_bak, blkcnt * 512);
ret = blkcnt;
}
out_sec:
free(sec_bak);
out_fst:
free(fst_bak);
out:
return ret;
}
static int sdmmc_secure_storage_read_backup(s32 dev_num, u32 item, u8 *buf, lbaint_t blkcnt)
{
s32 ret = 0;
s32 *sec_bak = (s32 *)buf;
if (buf == NULL) {
MMCINFO("intput buf is NULL\n");
ret = -1;
goto out;
}
if (item > MAX_SECURE_STORAGE_MAX_ITEM) {
MMCINFO("item exceed %d\n", MAX_SECURE_STORAGE_MAX_ITEM);
ret = -1;
goto out;
}
if (blkcnt > SDMMC_ITEM_SIZE) {
MMCINFO("block count exceed %d\n", SDMMC_ITEM_SIZE);
ret = -1;
goto out;
}
//second backups
ret = mmc_bread(dev_num, SDMMC_SECURE_STORAGE_START_ADD + SDMMC_ITEM_SIZE * 2 * item + SDMMC_ITEM_SIZE, blkcnt, sec_bak);
if (ret != blkcnt) {
MMCINFO("read second backup failed fun %s line %d\n", __FUNCTION__, __LINE__);
ret = -1;
}
out:
return ret;
}
#endif
#endif
int mmc_init_blk_ops(struct mmc *mmc)
{
mmc->block_dev.block_read = mmc_bread;
mmc->block_dev.block_write = mmc_bwrite;
mmc->block_dev.block_mmc_erase = mmc_mmc_erase;
mmc->block_dev.block_erase = mmc_berase;
mmc->block_dev.block_mmc_trim = mmc_mmc_trim;
mmc->block_dev.block_mmc_discard = mmc_mmc_discard;
mmc->block_dev.block_mmc_sanitize = mmc_mmc_sanitize;
mmc->block_dev.block_mmc_secure_erase = mmc_mmc_secure_erase;
mmc->block_dev.block_mmc_secure_trim = mmc_mmc_secure_trim;
mmc->block_dev.block_mmc_secure_wipe = mmc_mmc_secure_wipe;
//mmc->block_dev.block_mmc_user_get_wp_grp_size = mmc_mmc_user_get_wp_grp_size;
//mmc->block_dev.block_mmc_user_write_protect = mmc_mmc_user_write_protect;
//mmc->block_dev.block_mmc_clr_tem_wp = mmc_clr_tem_wp;
return 0;
}