489 lines
11 KiB
C
489 lines
11 KiB
C
/*
|
|
* nand_ota_burn.c for SUNXI NAND .
|
|
*
|
|
* Copyright (C) 2016 Allwinner.
|
|
*
|
|
*
|
|
* This file is licensed under the terms of the GNU General Public
|
|
* License version 2. This program is licensed "as is" without any
|
|
* warranty of any kind, whether express or implied.
|
|
*/
|
|
#include "nand_ota_burn.h"
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
void test_dram_para(void *buffer)
|
|
{
|
|
int *data;
|
|
int i;
|
|
|
|
data = (int *)buffer;
|
|
for (i = 0; i < 40; i += 4) {
|
|
NAND_Print("%x %x %x %x\n", data[i + 0], data[i + 1],
|
|
data[i + 2], data[i + 3]);
|
|
}
|
|
|
|
NAND_Print("\n");
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int gen_check_sum(void *boot_buf)
|
|
{
|
|
standard_boot_file_head_t *head_p;
|
|
unsigned int length;
|
|
unsigned int *buf;
|
|
unsigned int loop;
|
|
unsigned int i;
|
|
unsigned int sum;
|
|
unsigned int *p;
|
|
toc0_private_head_t *toc0_head;
|
|
|
|
if (NAND_IS_Secure_sys() == 1) {
|
|
/* secure */
|
|
toc0_head = (toc0_private_head_t *) boot_buf;
|
|
length = toc0_head->length;
|
|
p = &(toc0_head->check_sum);
|
|
} else {
|
|
head_p = (standard_boot_file_head_t *) boot_buf;
|
|
length = head_p->length;
|
|
p = &(head_p->check_sum);
|
|
}
|
|
|
|
if ((length & 0x3) != 0) /* must 4-byte-aligned */
|
|
return -1;
|
|
buf = (unsigned int *)boot_buf;
|
|
*p = STAMP_VALUE; /* fill stamp */
|
|
loop = length >> 2;
|
|
|
|
for (i = 0, sum = 0; i < loop; i++)
|
|
sum += buf[i];
|
|
|
|
|
|
*p = sum;
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int gen_uboot_check_sum(void *boot_buf)
|
|
{
|
|
boot_file_head_t *head_p;
|
|
unsigned int length;
|
|
unsigned int *buf;
|
|
unsigned int loop;
|
|
unsigned int i;
|
|
unsigned int sum;
|
|
|
|
head_p = (boot_file_head_t *) boot_buf;
|
|
length = head_p->length;
|
|
if ((length & 0x3) != 0) /* must 4-byte-aligned */
|
|
return -1;
|
|
buf = (unsigned int *)boot_buf;
|
|
head_p->check_sum = STAMP_VALUE; /* fill stamp */
|
|
loop = length >> 2;
|
|
|
|
for (i = 0, sum = 0; i < loop; i++)
|
|
sum += buf[i];
|
|
|
|
/* write back check sum */
|
|
head_p->check_sum = sum;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int get_nand_para(void *boot_buf)
|
|
{
|
|
boot0_file_head_t *boot0_buf;
|
|
char *data_buf;
|
|
void *nand_para;
|
|
sbrom_toc0_config_t *secure_toc0_buf;
|
|
|
|
if (NAND_IS_Secure_sys() == 1) {
|
|
/*secure*/
|
|
secure_toc0_buf =
|
|
(sbrom_toc0_config_t *) (boot_buf + SBROM_TOC0_HEAD_SPACE);
|
|
data_buf = secure_toc0_buf->storage_data;
|
|
nand_para = (void *)data_buf;
|
|
} else {
|
|
/*nonsecure*/
|
|
boot0_buf = (boot0_file_head_t *) boot_buf;
|
|
data_buf = boot0_buf->prvt_head.storage_data;
|
|
nand_para = (void *)data_buf;
|
|
}
|
|
nand_get_param(nand_para);
|
|
nand_get_param_for_uboottail(nand_para);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int get_dram_para(void *boot_buf)
|
|
{
|
|
boot0_file_head_t *src_boot0;
|
|
boot0_file_head_t *dst_boot0;
|
|
sbrom_toc0_config_t *secure_src_toc0;
|
|
sbrom_toc0_config_t *secure_dst_toc0;
|
|
char *buffer = NULL;
|
|
|
|
buffer = kmalloc(32 * 1024, GFP_KERNEL);
|
|
if (buffer == NULL) {
|
|
NAND_Print("get_dram_para, kmalloc failed!\n");
|
|
return -1;
|
|
}
|
|
memset(buffer, 0, 32 * 1024);
|
|
if (nand_read_nboot_data(buffer, 32 * 1024) != 0)
|
|
goto error;
|
|
|
|
test_dram_para(buffer);
|
|
if (NAND_IS_Secure_sys() == 1) {
|
|
/*secure*/
|
|
secure_src_toc0 =
|
|
(sbrom_toc0_config_t *) (buffer + SBROM_TOC0_HEAD_SPACE);
|
|
secure_dst_toc0 =
|
|
(sbrom_toc0_config_t *) (boot_buf + SBROM_TOC0_HEAD_SPACE);
|
|
memcpy(&secure_dst_toc0->dram_para[0],
|
|
&secure_src_toc0->dram_para[0], 32 * 4);
|
|
} else {
|
|
/*nonsecure*/
|
|
src_boot0 = (boot0_file_head_t *) buffer;
|
|
dst_boot0 = (boot0_file_head_t *) boot_buf;
|
|
memcpy(&dst_boot0->prvt_head, &src_boot0->prvt_head, 40 * 4);
|
|
}
|
|
|
|
test_dram_para(boot_buf);
|
|
kfree(buffer);
|
|
buffer = NULL;
|
|
return 0;
|
|
|
|
error:
|
|
kfree(buffer);
|
|
buffer = NULL;
|
|
return -1;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int get_nand_para_for_boot1(void *boot_buf)
|
|
{
|
|
boot1_file_head_t *boot1_buf;
|
|
boot_nand_para_t *nand_para;
|
|
|
|
boot1_buf = (boot1_file_head_t *) boot_buf;
|
|
nand_para = (boot_nand_para_t *) boot1_buf->prvt_head.nand_spare_data;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int NAND_ReadBoot0(unsigned int length, void *buf)
|
|
{
|
|
void *buffer;
|
|
__u32 ret;
|
|
|
|
NAND_PhysicLock();
|
|
|
|
buffer = vmalloc(length);
|
|
if (buffer == NULL) {
|
|
NAND_Print("read boot0 malloc failed!\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
if (nand_read_nboot_data(buffer, length) != 0) {
|
|
vfree(buffer);
|
|
NAND_Print("read boot0 failed\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
ret = copy_to_user(buf, buffer, length);
|
|
if (ret != 0) {
|
|
vfree(buffer);
|
|
NAND_Print("copy_to_user failed\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
vfree(buffer);
|
|
NAND_Print("read boot0 success\n");
|
|
NAND_PhysicUnLock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int NAND_ReadBoot1(unsigned int length, void *buf)
|
|
{
|
|
void *buffer;
|
|
__u32 ret;
|
|
|
|
NAND_PhysicLock();
|
|
|
|
buffer = vmalloc(length);
|
|
if (buffer == NULL) {
|
|
NAND_Print("read boot1 malloc failed!\n\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
if (nand_read_uboot_data(buffer, length) != 0) {
|
|
vfree(buffer);
|
|
NAND_Print("read boot1 failed\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
ret = copy_to_user(buf, buffer, length);
|
|
if (ret != 0) {
|
|
vfree(buffer);
|
|
NAND_Print("copy_to_user failed\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
vfree(buffer);
|
|
NAND_Print("read boot1 success\n");
|
|
NAND_PhysicUnLock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int NAND_BurnBoot0(unsigned int length, void *buf)
|
|
{
|
|
void *buffer;
|
|
__u32 ret;
|
|
|
|
NAND_PhysicLock();
|
|
|
|
NAND_Print("buf_from %x\n", buf);
|
|
|
|
buffer = kmalloc(length + 16 * 1024, GFP_KERNEL);
|
|
if (buffer == NULL) {
|
|
NAND_Print("no memory!\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
ret = copy_from_user(buffer, (const void *)buf, length);
|
|
NAND_Print("buffer from %x\n", buffer);
|
|
get_nand_para(buffer);
|
|
gen_check_sum(buffer);
|
|
|
|
if (nand_write_nboot_data(buffer, length) != 0) {
|
|
NAND_Print("burn boot 0 failed\n");
|
|
kfree(buffer);
|
|
buffer = NULL;
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
kfree(buffer);
|
|
buffer = NULL;
|
|
NAND_PhysicUnLock();
|
|
NAND_Print("burn boot 0 success\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int NAND_BurnBoot1(unsigned int length, void *buf)
|
|
{
|
|
void *buffer = NULL;
|
|
|
|
NAND_PhysicLock();
|
|
|
|
buffer = vmalloc(length + 0x10000);
|
|
if (buffer == NULL) {
|
|
NAND_Print("no memory!\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
if (copy_from_user(buffer, (const void *)buf, length)) {
|
|
NAND_Print("NAND_BurnBoot1, copy_from_user error!\n");
|
|
vfree(buffer);
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
if (nand_write_uboot_data(buffer, length) != 0) {
|
|
NAND_Print("burn boot1 failed\n");
|
|
vfree(buffer);
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
vfree(buffer);
|
|
NAND_PhysicUnLock();
|
|
NAND_Print("burn boot1 success\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int NAND_CheckBoot(void)
|
|
{
|
|
unsigned int len;
|
|
unsigned char *buf;
|
|
int ret;
|
|
|
|
NAND_PhysicLock();
|
|
|
|
len = nand_get_uboot_total_len();
|
|
if (len == 0) {
|
|
NAND_Print("not uboot\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
buf = vmalloc(len + 32 * 1024);
|
|
if (buf == NULL) {
|
|
NAND_Print("check uboot no memory\n");
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
ret = nand_check_uboot(buf, len);
|
|
if (ret != 0) {
|
|
NAND_Print("check uboot fail\n");
|
|
vfree(buf);
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
#if 0
|
|
len = nand_get_nboot_total_len();
|
|
if (len == 0) {
|
|
NAND_Print("not nboot\n");
|
|
vfree(buf);
|
|
NAND_PhysicUnLock();
|
|
return -1;
|
|
}
|
|
|
|
nand_check_nboot(buf, len);
|
|
#endif
|
|
|
|
vfree(buf);
|
|
NAND_PhysicUnLock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
__s32 NAND_DragonboardTest(void)
|
|
{
|
|
__u32 i, blk_ok;
|
|
__u8 oob_buf[32];
|
|
void *main_buf;
|
|
__s32 ret;
|
|
struct _nand_info *local_nand_info = NULL;
|
|
|
|
NAND_Print("dragon board test start!\n");
|
|
|
|
local_nand_info = NandHwInit();
|
|
if (local_nand_info == NULL) {
|
|
NAND_Print("dragonboard test fail\n");
|
|
return -1;
|
|
}
|
|
main_buf = kmalloc(1024 * 32, GFP_KERNEL);
|
|
if (main_buf == NULL) {
|
|
NAND_Print("no memory!\n");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < 32; i++)
|
|
oob_buf[i] = 0xff & i;
|
|
|
|
blk_ok = 0;
|
|
for (i = 10; i < 15; i++) {
|
|
NAND_Print("test blk %x\n", i);
|
|
|
|
ret = 0;
|
|
|
|
ret = nand_dragonborad_test_one(main_buf, oob_buf, i);
|
|
if (ret == 0)
|
|
blk_ok++;
|
|
|
|
}
|
|
if (blk_ok < 3) {
|
|
NAND_Print("dragon board test fail\n");
|
|
kfree(main_buf);
|
|
return -1;
|
|
}
|
|
kfree(main_buf);
|
|
return 0;
|
|
}
|