blob: c755ed069e1f0175ea12799ba167bad1e0bf46d2 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
#include <amlogic/storage.h>
#include <dm/pinctrl.h>
#include <partition_table.h>
#include <emmc_partitions.h>
#include <asm/arch-g12a/cpu_id.h>
#include <asm/arch-g12a/bl31_apis.h>
#include <linux/compat.h>
#include <amlogic/aml_mmc.h>
#define USER_PARTITION 0
#define BOOT0_PARTITION 1
#define BOOT1_PARTITION 2
#define RPMB_PARTITION 3
#define NOMAL_INIT 0
#define ERASE_ALL 3
#define ERASE_RESERVED 2
#define GXB_START_BLK 0
#define GXL_START_BLK 1
#define STORAGE_EMMC 1
/* max 2MB for emmc in blks */
#define UBOOT_SIZE (0x1000)
#define BLOCK_SIZE 512
extern int find_dev_num_by_partition_name (char const *name);
extern bool emmckey_is_protected (struct mmc *mmc);
extern int info_disprotect;
extern int dtb_read(void *addr);
extern int dtb_write(void *addr);
extern int renew_partition_tbl(unsigned char *buffer);
static int storage_range_check(struct mmc *mmc,char const *part_name,loff_t offset, size_t *size,loff_t *off) {
struct partitions *part_info = NULL;
cpu_id_t cpu_id = get_cpu_id();
if (strcmp(part_name, "bootloader") == 0) {
*off = 0;
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXL) {
*off += 512;
}
if (*size == 0) {
*size =mmc->capacity_boot;
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXL) {
*size = *size - 512;
}
}
} else {
part_info = find_mmc_partition_by_name(part_name);
if (!part_info) {
printf("error partition name!\n");
return 1;
}
*off = part_info->offset+offset;
if (offset >= part_info->size) {
printf("Start address out #%s# partition'address region,(off < 0x%llx)\n",
part_name, part_info->size);
return 1;
}
if ((*off+*size) > (part_info->size+part_info->offset)) {
printf("End address exceeds #%s# partition,(offset = 0x%llx,size = 0x%llx)\n",
part_name, part_info->offset,part_info->size);
return 1;
}
if (*size == 0) {
*size = part_info->size - offset;
}
}
return 0;
}
static int storage_rsv_range_check(char const *part_name, size_t *size,loff_t *off) {
struct partitions *part = NULL;
struct virtual_partition *vpart = NULL;
vpart = aml_get_virtual_partition_by_name(part_name);
if (!vpart) {
printf("error partition name!\n");
return 1;
}
part = aml_get_partition_by_name(MMC_RESERVED_NAME);
if (!part) {
printf("error partition name!\n");
return 1;
}
*off = part->offset + vpart->offset;
if ((*size) > vpart->size) {
printf("End address exceeds #%s# partition,(offset = 0x%llx,size = 0x%llx)\n",
part_name, vpart->offset,vpart->size);
return 1;
}
if (*size == 0)
*size = vpart->size;
return 0;
}
static int storage_byte_read(struct mmc *mmc,loff_t off, size_t size,void *addr) {
int blk_shift = 0;
u64 cnt = 0, n = 0, blk = 0, sz_byte = 0;
ulong start_blk;
void *addr_tmp;
void *addr_byte;
blk_shift = ffs(mmc->read_bl_len) - 1;
blk = off >> blk_shift ;
cnt = size >> blk_shift ;
sz_byte = size - ((cnt) << blk_shift) ;
mmc_init(mmc);
pr_info("blk:%lld cnt:%lld \n",blk,cnt);
n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
if ((n == cnt) && (sz_byte != 0)) {
/*printf("sz_byte=%#llx bytes\n",sz_byte);*/
addr_tmp = malloc(mmc->read_bl_len);
addr_byte = (void *)(addr+cnt*(mmc->read_bl_len));
start_blk = blk+cnt;
if (addr_tmp == NULL) {
printf("mmc read: malloc fail\n");
return 1;
}
if (blk_dread(mmc_get_blk_desc(mmc), start_blk, 1, addr_tmp) != 1) { // read 1 block
free(addr_tmp);
printf("mmc read 1 block fail\n");
return 1;
}
memcpy(addr_byte, addr_tmp, sz_byte);
free(addr_tmp);
}
return (n == cnt) ? 0 : 1;
}
static int storage_byte_write(struct mmc *mmc,loff_t off, size_t size, const void *addr) {
int blk_shift = 0;
u64 cnt = 0, n = 0, blk = 0, sz_byte = 0;
blk_shift = ffs(mmc->read_bl_len) - 1;
blk = off >> blk_shift ;
cnt = size >> blk_shift ;
sz_byte = size - ((cnt) << blk_shift);
mmc_init(mmc);
pr_info("blk:%lld cnt:%lld \n",blk,cnt);
n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
if ((n == cnt) && (sz_byte != 0)) {
// printf("sz_byte=%#llx bytes\n",sz_byte);
void *addr_tmp = malloc(mmc->write_bl_len);
void *addr_byte = (void*)(addr+cnt*(mmc->write_bl_len));
ulong start_blk = blk+cnt;
if (addr_tmp == NULL) {
printf("mmc write: malloc fail\n");
return 1;
}
if (blk_dread(mmc_get_blk_desc(mmc), start_blk, 1, addr_tmp) != 1) { // read 1 block
free(addr_tmp);
printf("mmc read 1 block fail\n");
return 1;
}
memcpy(addr_tmp, addr_byte, sz_byte);
if (blk_dwrite(mmc_get_blk_desc(mmc), start_blk, 1, addr_tmp) != 1) { // write 1 block
free(addr_tmp);
printf("mmc write 1 block fail\n");
return 1;
}
free(addr_tmp);
}
//printf("%#llx blocks , %#llx bytes written: %s\n", n, sz_byte, (n==cnt) ? "OK" : "ERROR");
return (n == cnt) ? 0 : 1;
}
static int storage_byte_erase(struct mmc *mmc,loff_t off, size_t size) {
int blk_shift = 0;
u64 cnt = 0, n = 0, blk = 0;
blk_shift = ffs(mmc->read_bl_len) - 1;
blk = off >> blk_shift ;
cnt = size >> blk_shift ;
mmc_init(mmc);
pr_info("blk:%lld cnt:%lld \n",blk,cnt);
if (cnt)
n = blk_derase(mmc_get_blk_desc(mmc), blk, cnt);
printf("%lld blocks erased: %s\n", cnt, (n == 0) ? "OK" : "ERROR");
return (n == 0) ? 0 : 1;
}
static int storage_erase_in_part(char const *part_name, loff_t off, size_t size)
{
int ret = 1;
struct mmc *mmc;
loff_t offset;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc)
return 1;
ret = storage_range_check(mmc,part_name, off, &size, &offset);
if (ret)
return ret;
ret = storage_byte_erase(mmc, offset, size);
return (ret == 0) ? 0 : 1;
}
static int storage_read_in_part(char const *part_name, loff_t off, size_t size, void *dest)
{
int ret =1;
struct mmc *mmc;
loff_t offset;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc)
return 1;
ret = storage_range_check(mmc,part_name,off,&size,&offset);
if (ret) return ret;
ret = storage_byte_read(mmc, offset, size, dest);
return ret;
}
static int storage_write_in_part(char const *part_name, loff_t off, size_t size, const void *source)
{
int ret = 1;
loff_t offset;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc) {
printf("Cannot find mmc. \n");
return 1;
}
ret = storage_range_check(mmc,part_name, off, &size, &offset);
if (ret) return ret;
ret = storage_byte_write(mmc, offset, size, source);
return ret;
}
static int storage_mmc_erase(int flag, struct mmc *mmc) {
int ret = 0;
loff_t off = 0;
size_t size = 0;
if (flag >= ERASE_ALL) {//erase all
info_disprotect |= DISPROTECT_KEY;
ret = blk_derase(mmc_get_blk_desc(mmc), 0, 0);
printf("user partition erased: %s\n", (ret == 0) ? "OK" : "ERROR");
info_disprotect &= ~DISPROTECT_KEY;
if (ret != 0) {
return -1;
}
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, BOOT0_PARTITION);
if (ret) goto R_SWITCH_BACK;
ret = blk_derase(mmc_get_blk_desc(mmc), 0, 0);
printf("boot0 partition erased: %s\n", (ret == 0) ? "OK" : "ERROR");
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, BOOT1_PARTITION);
if (ret) goto R_SWITCH_BACK;
ret = blk_derase(mmc_get_blk_desc(mmc), 0, 0);
printf("boot1 partition erased: %s\n", (ret == 0) ? "OK" : "ERROR");
R_SWITCH_BACK:
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, USER_PARTITION);
} else if (flag == ERASE_RESERVED) {//erase reserved
info_disprotect |= DISPROTECT_KEY;
ret = storage_rsv_range_check("reserved", &size, &off);
if (ret != 0) {
return -1;
}
ret = storage_erase_in_part("reserved", off, size);
info_disprotect &= ~DISPROTECT_KEY;
}
return ret;
}
int mmc_storage_init(unsigned char init_flag) {
int ret =1;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
mmc->init_in_progress = 0;
mmc->has_init=0;
pinctrl_select_state(mmc->dev, "default");
if (!mmc) {
return -1;
}
ret = mmc_init(mmc);
if (ret != 0) {
return -1;
}
ret = storage_mmc_erase(init_flag, mmc);
return ret;
}
uint64_t mmc_storage_get_part_size(const char *part_name) {
struct partitions *part_info = NULL;
part_info = find_mmc_partition_by_name(part_name);
if (part_info == NULL) {
printf("get partition info failed !!\n");
return -1;
}
return part_info->size;
}
int mmc_storage_read(const char *part_name, loff_t off, size_t size, void *dest) {
int ret=1;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc)
return 1;
if (!part_name) {//the operating object is the device,the unit of operation is block.
info_disprotect |= DISPROTECT_KEY;
ret = blk_dread(mmc_get_blk_desc(mmc), off, size, dest);
info_disprotect &= ~DISPROTECT_KEY;
printf("%d blocks read: %s\n", ret, (ret == size) ? "OK" : "ERROR");
return (ret == size) ? 0 : 1;
} else {//the opering object is partition,the unit of operation is byte.
ret = storage_read_in_part(part_name, off,size, dest);
}
return ret;
}
int mmc_storage_write(const char *part_name, loff_t off, size_t size, const void *source) {
int ret=1;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc)
return 1;
if (!part_name) {//the operating object is the device,the unit of operation is block.
info_disprotect |= DISPROTECT_KEY;
ret = blk_dwrite(mmc_get_blk_desc(mmc), off, size, source);
info_disprotect &= ~DISPROTECT_KEY;
printf("%d blocks written: %s\n", ret, (ret == size) ? "OK" : "ERROR");
return (ret == size) ? 0 : 1;
} else {//the opering object is partition,the unit of operation is byte.
ret = storage_write_in_part(part_name, off, size, source);
}
return ret;
}
int mmc_storage_erase(const char *part_name, loff_t off, size_t size, int scrub_flag) {
int ret=1;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc)
return 1;
if (!part_name) {//the operating object is the device,the unit of operation is block.
info_disprotect |= DISPROTECT_KEY;
ret = blk_derase(mmc_get_blk_desc(mmc), off, size);
info_disprotect &= ~DISPROTECT_KEY;
printf("%d blocks erased: %s\n", ret, (ret == 0) ? "OK" : "ERROR");
return (ret == 0) ? 0 : 1;
} else {//the opering object is partition,the unit of operation is byte.
ret = storage_erase_in_part(part_name, off, size);
}
return ret;
}
uint8_t mmc_storage_get_copies(const char *part_name) {
char ret=3;
return ret;
}
uint64_t mmc_get_copy_size(const char *part_name) {
#ifdef CONFIG_AML_GPT
return UBOOT_SIZE*512;
#else
struct partitions *part_info = find_mmc_partition_by_name("bootloader");
if (part_info == NULL) {
printf("get partition info failed !!\n");
return -1;
}
return part_info->size;
#endif
}
/* dtb read&write operation with backup updates */
static u32 _calc_boot_info_checksum(struct storage_emmc_boot_info *boot_info)
{
u32 *buffer = (u32*)boot_info;
u32 checksum = 0;
int i = 0;
do {
checksum += buffer[i];
} while (i++ < ((EMMC_BOOT_INFO_SIZE >> 2) - 2));
return checksum;
}
static int amlmmc_write_info_sector(struct mmc *mmc)
{
struct storage_emmc_boot_info *boot_info;
struct virtual_partition *ddr_part;
struct partitions *part;
u8 *buffer;
int ret = 0;
buffer = malloc(MMC_BLOCK_SIZE);
if (!buffer)
return -ENOMEM;
memset(buffer, 0, sizeof(*boot_info));
boot_info = (struct storage_emmc_boot_info *)buffer;
part = aml_get_partition_by_name(MMC_RESERVED_NAME);
boot_info->rsv_base_addr = part->offset / MMC_BLOCK_SIZE;
ddr_part = aml_get_virtual_partition_by_name(MMC_DDR_PARAMETER_NAME);
boot_info->ddr.addr = ddr_part->offset / MMC_BLOCK_SIZE;
boot_info->ddr.size = ddr_part->size / MMC_BLOCK_SIZE;
boot_info->version = 1;
boot_info->checksum = _calc_boot_info_checksum(boot_info);
printf("boot_info.rsv_base_addr\t:\t%04x\n", boot_info->rsv_base_addr);
printf("boot_info.ddr.addr\t:\t%04x\n", boot_info->ddr.addr);
printf("boot_info.ddr.size\t:\t%04x\n", boot_info->ddr.size);
printf("boot_info.version\t:\t%04x\n", boot_info->version);
printf("boot_info.checksum\t:\t%04x\n", boot_info->checksum);
if (blk_dwrite(mmc_get_blk_desc(mmc), 0, 1, buffer) != 1)
ret = -EIO;
free(buffer);
return ret;
}
#define MAX_REACHABLE_RSV_RANGE 0x30000
static int amlmmc_boot_info_check(struct mmc *mmc)
{
struct storage_emmc_boot_info *boot_info;
struct virtual_partition *ddr_part;
u64 src;
u32 *buffer, checksum = 0;
int i = 0, ret = -1;
buffer = malloc(MMC_BLOCK_SIZE);
if (!buffer)
return -ENOMEM;
if (blk_dread(mmc_get_blk_desc(mmc), 0, 1, buffer) != 1) {
ret = -EIO;
goto _err;
}
boot_info = (struct storage_emmc_boot_info *)buffer;
ddr_part = aml_get_virtual_partition_by_name(MMC_DDR_PARAMETER_NAME);
if (boot_info->ddr.addr != ddr_part->offset / MMC_BLOCK_SIZE)
goto _err;
if (!boot_info->checksum || boot_info->version != 0x01)
goto _err;
src = boot_info->rsv_base_addr + boot_info->ddr.addr;
if (!src || src == (uint64_t)(-1) || src > MAX_REACHABLE_RSV_RANGE)
goto _err;
do {
checksum += buffer[i];
} while (i++ < ((EMMC_BOOT_INFO_SIZE >> 2) - 2));
if (!checksum)
goto _err;
if (checksum == boot_info->checksum)
ret = 0;
_err:
free(buffer);
return ret;
}
int amlmmc_check_and_update_boot_info(void)
{
struct mmc *mmc;
int ret = 0, i;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc)
return -ENODEV;
for (i = 1; i < 3; i++) {
if (blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, i)) {
printf("switch dev %d to boot%d fail\n",
STORAGE_EMMC, i - 1);
continue;
}
if (!amlmmc_boot_info_check(mmc))
break;
ret = amlmmc_write_info_sector(mmc);
if (ret)
return -EIO;
}
blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, USER_PARTITION);
return ret;
}
int mmc_boot_read(const char *part_name, uint8_t cpy, size_t size, void *dest) {
char ret=1;
int i;
if (cpy == 0)
cpy = 1;
else if (cpy == 1)
cpy = 2;
else if (cpy == 2)
cpy = 4;
else if (cpy == 0xff)
cpy = 7;
for (i=0;i<3;i++) {//cpy:
if (cpy & 1) {
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, i);
if (ret) goto R_SWITCH_BACK;
#ifdef CONFIG_AML_GPT
if (i == 0)
continue;
#endif
ret = storage_read_in_part(part_name, 0, size, dest);
if (ret != 0) {
printf("storage read bootloader failed \n");
goto R_SWITCH_BACK;
}
}
cpy = cpy >> 1;
}
R_SWITCH_BACK:
if (blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, USER_PARTITION)) {
printf("switch part failed \n");
return -1;
}
return ret;
}
int mmc_boot_write(const char *part_name, uint8_t cpy, size_t size, const void *source) {
char ret=1;
int i = 0;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
if (cpy == 0)
cpy = 1;
else if (cpy == 1)
cpy = 2;
else if (cpy == 2)
cpy = 4;
else if (cpy == 0xff)
cpy = 7;
for (i=0;i<3;i++) {//cpy:bin 100 is oprate boot1,bin 010 is oprate boot0,bin 001 is oprate user bootloader.bin 111 is operate all boot.
if (cpy & 1) {
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, i);
if (ret) goto W_SWITCH_BACK;
#ifdef CONFIG_EMMC_BOOT1_TOUCH_REGION
if (i == 2) {
size = CONFIG_EMMC_BOOT1_TOUCH_REGION;
}
#endif
#ifdef CONFIG_AML_GPT
if (i == 0)
continue;
#endif
ret = storage_write_in_part(part_name, 0, size, source);
if (ret != 0) {
printf("storage write bootloader failed \n");
goto W_SWITCH_BACK;
}
if (i != 0)
amlmmc_write_info_sector(mmc);
}
cpy = cpy >> 1;
}
W_SWITCH_BACK:
if (blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, USER_PARTITION)) {
printf("switch part failed \n");
return -1;
}
return ret;
}
int mmc_boot_erase(const char *part_name, uint8_t cpy) {
char ret=1;
int i;
size_t size = 0;
if (cpy == 0)
cpy = 1;
else if (cpy == 1)
cpy = 2;
else if (cpy == 2)
cpy = 4;
else if (cpy == 0xff)
cpy = 7;
for (i=0;i<3;i++) {//cpy:
if (cpy & 1) {
ret = blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, i);
if (ret) goto E_SWITCH_BACK;
#ifdef CONFIG_EMMC_BOOT1_TOUCH_REGION
if (i == 2) {
size = CONFIG_EMMC_BOOT1_TOUCH_REGION;
}
#endif
#ifdef CONFIG_AML_GPT
if (i == 0)
continue;
#endif
ret = storage_erase_in_part(part_name, 0, size);
if (ret != 0) {
printf("storage read bootloader failed \n");
goto E_SWITCH_BACK;
}
}
cpy = cpy >> 1;
}
E_SWITCH_BACK:
if (blk_select_hwpart_devnum(IF_TYPE_MMC, STORAGE_EMMC, USER_PARTITION)) {
printf("switch part faild \n");
return -1;
}
return ret;
}
uint32_t mmc_get_rsv_size(const char *rsv_name) {
struct virtual_partition *vpart = NULL;
vpart = aml_get_virtual_partition_by_name(rsv_name);
printf("the %s partition size is:%llx byte\n",rsv_name,vpart->size);
return vpart->size;
}
int mmc_read_rsv(const char *rsv_name, size_t size, void *buf) {
char ret=1;
struct mmc *mmc;
loff_t off =0;
ret = !strcmp("key", rsv_name) || !strcmp("dtb", rsv_name)||!strcmp("fastboot", rsv_name)||!strcmp("ddr-parameter", rsv_name);
if (!ret) return 1;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc) {
puts("no mmc devices available\n");
return 1;
}
ret = storage_rsv_range_check(rsv_name, &size, &off);
if (ret) return ret;
if (!strcmp("dtb", rsv_name)) {
ret = dtb_read(buf);
return ret;
}
if (!strcmp("key", rsv_name))
info_disprotect |= DISPROTECT_KEY;
ret = storage_byte_read(mmc, off, size, buf);
if (!strcmp("key", rsv_name))
info_disprotect &= ~DISPROTECT_KEY;
if (ret != 0) {
printf("read resv failed\n");
}
return ret;
}
int mmc_write_rsv(const char *rsv_name, size_t size, void *buf) {
struct mmc *mmc;
loff_t off =0;
int ret = 1;
ret = !strcmp("key", rsv_name) || !strcmp("dtb", rsv_name)||!strcmp("fastboot", rsv_name)||!strcmp("ddr-parameter", rsv_name);
if (!ret)
return 1;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc) {
puts("no mmc devices available\n");
return 1;
}
ret = storage_rsv_range_check(rsv_name, &size, &off);
if (ret) return ret;
if (!strcmp("dtb", rsv_name)) {
ret = dtb_write(buf);
ret |= renew_partition_tbl(buf);
return ret;
}
if (!strcmp("key", rsv_name))
info_disprotect |= DISPROTECT_KEY;
if (!strcmp("ddr-parameter", rsv_name))
amlmmc_check_and_update_boot_info();
ret = storage_byte_write(mmc, off, size, buf);
if (!strcmp("key", rsv_name))
info_disprotect &= ~DISPROTECT_KEY;
if (ret != 0) {
printf("write resv failed\n");
}
return ret;
}
int mmc_erase_rsv(const char *rsv_name) {
char ret=1;
struct mmc *mmc;
loff_t off = 0;
size_t size = 0;
ret = !strcmp("key", rsv_name) || !strcmp("dtb", rsv_name)||!strcmp("fastboot", rsv_name)||!strcmp("ddr-parameter", rsv_name);
if (!ret) return 1;
mmc = find_mmc_device(STORAGE_EMMC);
if (!mmc) {
puts("no mmc devices available\n");
return 1;
}
ret = storage_rsv_range_check(rsv_name, &size, &off);
if (ret) return ret;
if (!strcmp("key", rsv_name))
info_disprotect |= DISPROTECT_KEY;
ret = storage_byte_erase(mmc, off, size);
if (!strcmp("key", rsv_name))
info_disprotect &= ~DISPROTECT_KEY;
if (ret != 0) {
printf("erase resv failed\n");
}
return ret;
}
int mmc_protect_rsv(const char *rsv_name, bool ops) {
char ret=1;
ret = strcmp("key", rsv_name);
if (ret) return 1;
if (ops) {
info_disprotect &= ~DISPROTECT_KEY;
printf("Protect the key partition!\n");
} else {
info_disprotect |= DISPROTECT_KEY;
printf("Disprotect the key partition!\n");
}
return ret;
}
int emmc_pre(void)
{
char ret = 1;
struct mmc *mmc;
mmc = find_mmc_device(STORAGE_EMMC);
ret = mmc_start_init(mmc);
if (ret == 0)
printf("emmc init success!\n");
else
printf("emmc init fail!\n");
return ret;
}
int emmc_probe(uint32_t init_flag)
{
char ret = 0;
struct mmc *mmc;
static struct storage_t *storage_dev = NULL;
/*struct store_operation *storage_opera = NULL;*/
storage_dev = kzalloc(sizeof(struct storage_t), GFP_KERNEL);
if (storage_dev == NULL) {
printf("malloc failed for storage_dev\n");
ret = -1;
goto exit_error;
}
mmc = find_mmc_device(STORAGE_EMMC);
if (init_flag != 0xff)
ret = mmc_storage_init(init_flag); /*flag 0*/
if (ret) {
printf("mmc init failed ret:%x\n", ret);
goto exit_error;
}
/******basic info*******/
storage_dev->init_flag = init_flag;
storage_dev->type = BOOT_EMMC;
#ifdef BL33_DEBUG_PRINT
printf("store flag: %d, types: %d\n",storage_dev->init_flag,storage_dev->type);
#endif
/*storage_dev->info.name = mmc->cid[0] & 0xff,
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff;
storage_dev->info.id = mmc->cid[0] >> 24;*/
storage_dev->info.read_unit = mmc->read_bl_len;
storage_dev->info.write_unit = mmc->write_bl_len;
storage_dev->info.erase_unit = mmc->erase_grp_size;
storage_dev->info.caps = mmc->capacity_user;
storage_dev->info.mode = DISCRETE_BOOTLOADER;
storage_dev->get_part_size = mmc_storage_get_part_size;
storage_dev->read = mmc_storage_read;
storage_dev->write = mmc_storage_write;
storage_dev->erase = mmc_storage_erase;
storage_dev->get_copies = mmc_storage_get_copies;
storage_dev->get_copy_size = mmc_get_copy_size;
storage_dev->boot_read = mmc_boot_read;
storage_dev->boot_write = mmc_boot_write;
storage_dev->boot_erase = mmc_boot_erase;
storage_dev->get_rsv_size = mmc_get_rsv_size;
storage_dev->read_rsv = mmc_read_rsv;
storage_dev->write_rsv = mmc_write_rsv;
storage_dev->erase_rsv = mmc_erase_rsv;
storage_dev->protect_rsv = mmc_protect_rsv;
store_register(storage_dev);
printf("emmc probe success\n");
if (init_flag != 0xff)
return !is_partition_checked;
exit_error:
return ret;
}