sdk-hwV1.3/lichee/linux-4.9/modules/nand/common1/phy-nand/nand_boot.c

1270 lines
33 KiB
C
Executable File

/* SPDX-License-Identifier: GPL-2.0 */
/*
************************************************************************************************************************
* eNand
* Nand flash driver scan module
*
* Copyright(C), 2008-2009, SoftWinners Microelectronic Co., Ltd.
* All Rights Reserved
*
* File Name : nand_chip_interface.c
*
* Author :
*
* Version : v0.1
*
* Date : 2013-11-20
*
* Description :
*
* Others : None at present.
*
*
*
************************************************************************************************************************
*/
#define _UBOOTT_C_
/*#include "nand_boot.h"*/
#include "../nfd/nand_osal_for_linux.h"
#include "nand_physic_interface.h"
#include "rawnand/rawnand_boot.h"
#include "rawnand/rawnand_cfg.h"
#include "rawnand/rawnand_debug.h"
#include "spinand/spinand_boot.h"
#include <linux/vmalloc.h>
#include "nand-partition3/sunxi_nand.h"
#include "nand-partition3/sunxi_nand_boot.h"
struct _uboot_info uboot_info = {0};
struct _boot_info *phyinfo_buf;
extern struct kernel_status kernelsta;
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_write_boot0_one(buf, len, counter);
else if (get_storage_type() == 2)
ret = spinand_write_boot0_one(buf, len, counter);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_read_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_read_boot0_one(buf, len, counter);
else if (get_storage_type() == 2)
ret = spinand_read_boot0_one(buf, len, counter);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_write_nboot_data(unsigned char *buf, unsigned int len)
{
int ret = 1;
unsigned int i;
//unsigned char* mbuf;
RAWNAND_DBG("burn boot0 normal mode!\n");
for (i = 0; i < aw_nand_info.boot->uboot_start_block; i++) {
ret &= nand_write_boot0_one(buf, len, i);
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_read_nboot_data(unsigned char *buf, unsigned int len)
{
int ret;
unsigned int i;
RAWNAND_DBG("read boot0 normal mode!\n");
for (i = 0; i < aw_nand_info.boot->uboot_start_block; i++) {
ret = nand_read_boot0_one(buf, len, i);
if (ret == 0) {
return 0;
} else {
RAWNAND_ERR("read boot0 one fail %d!\n", i);
}
}
RAWNAND_ERR("read boot0 fail!\n");
return ERR_NO_106;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int check_nboot_table(unsigned char *buf, unsigned int len, unsigned int counter)
{
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_check_nboot(unsigned char *buf, unsigned int len)
{
int i;
int num = 0;
int flag[NAND_BOOT0_BLK_CNT];
int table_flag[NAND_BOOT0_BLK_CNT];
for (i = 0; i < aw_nand_info.boot->uboot_start_block; i++) {
table_flag[i] = check_nboot_table(buf, len, i);
flag[i] = nand_read_boot0_one(buf, len, i);
}
if (flag[NAND_BOOT0_BLK_CNT - 1] != 0) {
for (i = 0; i < NAND_BOOT0_BLK_CNT; i++) {
if (flag[i] == 0) {
if (nand_read_boot0_one(buf, len, i) == 0) {
num = 1;
break;
}
}
}
if (num == 0) {
RAWNAND_ERR("no boot0 ok!\n");
return ERR_NO_102;
}
}
for (i = 0; i < NAND_BOOT0_BLK_CNT; i++) {
if (table_flag[i] == -1) {
flag[i] = -1;
}
}
if (flag[0] > 0) {
flag[0] = 0;
}
for (i = 0; i < NAND_BOOT0_BLK_CNT; i++) {
if (flag[i] != 0) {
RAWNAND_DBG("recover boot0 %d!\n", i);
nand_write_boot0_one(buf, len, i);
}
}
return 0;
}
int disable_crc_when_ota;
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_write_uboot_one(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
{
int ret = 0;
/*int real_len;*/
RAWNAND_DBG("burn uboot one!\n");
cal_sum_physic_info(phyinfo_buf, PHY_INFO_SIZE);
/*print_physic_info(phyinfo_buf);*/
if (get_storage_type() == 1)
ret = rawnand_write_uboot_one(buf, len, phyinfo_buf, PHY_INFO_SIZE, counter);
else if (get_storage_type() == 2)
ret = spinand_write_uboot_one(buf, len, phyinfo_buf, PHY_INFO_SIZE, counter);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_write_uboot_data(unsigned char *buf, unsigned int len)
{
int ret = 0;
unsigned int i;
unsigned int uboot_block_cnt;
uboot_block_cnt = aw_nand_info.boot->uboot_next_block - aw_nand_info.boot->uboot_start_block;
for (i = 0; i < uboot_block_cnt; i++) {
ret |= nand_write_uboot_one(buf, len, phyinfo_buf, PHY_INFO_SIZE, i);
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok <0:fail 1: ecc limit
*Note :
*****************************************************************************/
int nand_read_uboot_one(unsigned char *buf, unsigned int len, unsigned int counter)
{
int ret = 0;
// RAWNAND_DBG("read uboot one %d!\n",counter);
if (get_storage_type() == 1)
ret = rawnand_read_uboot_one(buf, len, counter);
else if (get_storage_type() == 2)
ret = spinand_read_uboot_one(buf, len, counter);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_read_uboot_data(unsigned char *buf, unsigned int len)
{
int ret = 0;
unsigned int i;
unsigned int uboot_block_cnt;
RAWNAND_DBG("read uboot!\n");
uboot_block_cnt = aw_nand_info.boot->uboot_next_block - aw_nand_info.boot->uboot_start_block;
for (i = 0; i < uboot_block_cnt; i++) {
ret = nand_read_uboot_one(buf, len, i);
if (ret >= 0) {
return 0;
}
}
return -1;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note : must after uboot_info_init
*****************************************************************************/
int nand_check_uboot(unsigned char *buf, unsigned int len)
{
int i;
int num = 0;
int uboot_len;
int counter, first_boot_flag;
int flag[30] = {0};
int boot_flag[30];
//char sbuf[64];
struct _boot_info *boot;
counter = uboot_info.copys;
for (i = 0; i < counter; i++) {
boot_flag[i] = -1;
flag[i] = nand_read_uboot_one(buf, len, i);
if (flag[i] >= 0) {
boot = (struct _boot_info *)(buf + uboot_info.byte_offset_for_nand_info);
if (boot->magic == PHY_INFO_MAGIC) {
boot_flag[i] = 0;
} else {
RAWNAND_ERR("boot magic error %x\n", boot->magic);
}
}
}
if (flag[counter - 1] < 0) {
for (i = 0; i < counter; i++) {
if (flag[i] >= 0) {
if (nand_read_uboot_one(buf, len, i) == 0) {
num = 1;
break;
}
}
}
if (num == 0) {
RAWNAND_ERR("no uboot ok\n");
return -1;
}
}
if (flag[0] > 0) {
flag[0] = 0;
}
first_boot_flag = 1;
for (i = 0; i < counter; i++) {
if (boot_flag[i] == 0) {
first_boot_flag = 0;
}
}
if (first_boot_flag == 1) {
RAWNAND_DBG("first boot flag\n");
boot = (struct _boot_info *)(buf + uboot_info.byte_offset_for_nand_info);
if (boot->magic != PHY_INFO_MAGIC) {
RAWNAND_DBG("recover uboot data\n");
cal_sum_physic_info(aw_nand_info.boot, PHY_INFO_SIZE);
memcpy(boot, aw_nand_info.boot, PHY_INFO_SIZE);
}
}
uboot_len = uboot_info.uboot_len;
for (i = 0; i < (counter / 2); i++) { //if error; change
if ((flag[i] < 0) || (first_boot_flag == 1)) {
RAWNAND_DBG("recover1 uboot %d.\n", i);
nand_write_uboot_one(buf, uboot_len, aw_nand_info.boot, PHY_INFO_SIZE, i);
} else if ((boot_flag[i] < 0) && (first_boot_flag == 0)) {
RAWNAND_DBG("recover2 uboot %d.\n", i);
nand_write_uboot_one(buf, uboot_len, aw_nand_info.boot, PHY_INFO_SIZE, i);
} else {
;
}
}
for (i = (counter / 2); i < counter; i++) { //if ecc limit ; change
if ((flag[i] != 0) || (first_boot_flag == 1)) {
RAWNAND_DBG("recover3 uboot %d.\n", i);
nand_write_uboot_one(buf, uboot_len, aw_nand_info.boot, PHY_INFO_SIZE, i);
} else if ((boot_flag[i] < 0) && (first_boot_flag == 0)) {
RAWNAND_DBG("recover4 uboot %d.\n", i);
nand_write_uboot_one(buf, uboot_len, aw_nand_info.boot, PHY_INFO_SIZE, i);
} else {
;
}
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_get_uboot_total_len(void)
{
int len;
uboot_info_init(&uboot_info);
len = uboot_info.total_len;
if ((len == 0) || (len >= 8 * 1024 * 1024)) {
RAWNAND_ERR("not uboot: %d\n", len);
return 0;
}
return len;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_get_nboot_total_len(void)
{
int len = 0;
return len;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :NAND_GetParam
*****************************************************************************/
int nand_get_param(void *nand_param)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_get_param(nand_param);
else if (get_storage_type() == 2)
ret = spinand_get_param(nand_param);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :NAND_GetParam
*****************************************************************************/
int nand_get_param_for_uboottail(void *nand_param)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_get_param_for_uboottail(nand_param);
else if (get_storage_type() == 2)
ret = spinand_get_param_for_uboottail(nand_param);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int NAND_UpdatePhyArch(void)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_update_phyarch();
else if (get_storage_type() == 2)
ret = SPINAND_UpdatePhyArch();
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_erase_chip(unsigned int chip, unsigned int start_block, unsigned int end_block, unsigned int force_flag)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_erase_chip(chip, start_block, end_block, force_flag);
else if (get_storage_type() == 2)
ret = spinand_erase_chip(chip, start_block, end_block, force_flag);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
void nand_erase_special_block(void)
{
if (get_storage_type() == 1)
rawnand_erase_special_block();
else if (get_storage_type() == 2)
spinand_erase_special_block();
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_uboot_erase_all_chip(UINT32 force_flag)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_uboot_erase_all_chip(force_flag);
else if (get_storage_type() == 2)
ret = spinand_uboot_erase_all_chip(force_flag);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int nand_dragonborad_test_one(unsigned char *buf, unsigned char *oob, unsigned int blk_num)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_dragonborad_test_one(buf, oob, blk_num);
else if (get_storage_type() == 2)
ret = spinand_dragonborad_test_one(buf, oob, blk_num);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int get_default_uboot_block(__u32 *start_block, __u32 *next_block)
{
__u32 uboot_block_size = 0;
__u32 uboot_start_block = 0;
__u32 uboot_next_block = 0;
__u32 page_cnt_per_blk = 0;
page_cnt_per_blk = nand_get_page_cnt_per_block();
uboot_block_size = nand_get_lsb_block_size();
/*small nand:block size < 1MB; reserve 4M for uboot*/
if (uboot_block_size <= 0x20000) { //128K
uboot_start_block = UBOOT_START_BLOCK_SMALLNAND;
uboot_next_block = uboot_start_block + 32;
} else if (uboot_block_size <= 0x40000) { //256k
uboot_start_block = UBOOT_START_BLOCK_SMALLNAND;
uboot_next_block = uboot_start_block + 16;
} else if (uboot_block_size <= 0x80000) { //512k
uboot_start_block = UBOOT_START_BLOCK_SMALLNAND;
uboot_next_block = uboot_start_block + 8;
} else if (uboot_block_size <= 0x100000 && page_cnt_per_blk <= 128) { //1M
uboot_start_block = UBOOT_START_BLOCK_SMALLNAND;
uboot_next_block = uboot_start_block + 4;
}
/* big nand; reserve at least 20M for uboot */
else if (uboot_block_size <= 0x100000 && page_cnt_per_blk > 128) { //BIGNAND 1M
uboot_start_block = UBOOT_START_BLOCK_BIGNAND;
uboot_next_block = uboot_start_block + 20;
} else if (uboot_block_size <= 0x200000) { //BIGNAND 2M
uboot_start_block = UBOOT_START_BLOCK_BIGNAND;
uboot_next_block = uboot_start_block + 10;
} else {
uboot_start_block = UBOOT_START_BLOCK_BIGNAND;
uboot_next_block = uboot_start_block + 8;
}
*start_block = uboot_start_block;
*next_block = uboot_next_block;
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int set_uboot_start_and_end_block(void)
{
__u32 uboot_start_block;
__u32 uboot_next_block;
if (aw_nand_info.boot->uboot_start_block == 0) {
get_default_uboot_block(&uboot_start_block, &uboot_next_block);
aw_nand_info.boot->uboot_start_block = uboot_start_block;
aw_nand_info.boot->uboot_next_block = uboot_next_block;
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int get_uboot_start_block(void)
{
__u32 uboot_start_block;
__u32 uboot_next_block;
if (aw_nand_info.boot->uboot_start_block != 0)
uboot_start_block = aw_nand_info.boot->uboot_start_block;
else
get_default_uboot_block(&uboot_start_block, &uboot_next_block);
return uboot_start_block;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int get_uboot_next_block(void)
{
__u32 uboot_start_block = 0;
__u32 uboot_next_block = 0;
if (aw_nand_info.boot->uboot_next_block != 0)
uboot_next_block = aw_nand_info.boot->uboot_next_block;
else
get_default_uboot_block(&uboot_start_block, &uboot_next_block);
return uboot_next_block;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int get_physic_block_reserved(void)
{
__u32 physic_block_reserved;
physic_block_reserved = PHYSIC_RECV_BLOCK;
if (aw_nand_info.boot->physic_block_reserved != 0)
physic_block_reserved = aw_nand_info.boot->physic_block_reserved;
return physic_block_reserved;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
void print_uboot_info(struct _uboot_info *uboot)
{
int i;
RAWNAND_DBG("uboot->use_lsb_page %d \n", uboot->use_lsb_page);
RAWNAND_DBG("uboot->copys %d \n", uboot->copys);
RAWNAND_DBG("uboot->uboot_len %d \n", uboot->uboot_len);
RAWNAND_DBG("uboot->total_len %d \n", uboot->total_len);
RAWNAND_DBG("uboot->uboot_pages %d \n", uboot->uboot_pages);
RAWNAND_DBG("uboot->total_pages %d \n", uboot->total_pages);
RAWNAND_DBG("uboot->blocks_per_total %d \n", uboot->blocks_per_total);
RAWNAND_DBG("uboot->page_offset_for_nand_info %d \n", uboot->page_offset_for_nand_info);
RAWNAND_DBG("uboot->uboot_block:\n");
for (i = 0; i < 60; i++) {
if (uboot->uboot_block[i] != 0)
RAWNAND_DBG("%d ", uboot->uboot_block[i]);
}
RAWNAND_DBG("\n");
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
static unsigned int is_uboot_block(unsigned int block, char *uboot_buf, unsigned int *pages_offset)
{
int ret = 0;
unsigned char sdata[64];
unsigned int size_per_page;
unsigned int uboot_size;
size_per_page = nand_get_page_size();
ret = nand_physic_read_page(0, block, 0, size_per_page / 512, uboot_buf,
sdata);
if (1 == (is_uboot_magic(uboot_buf))) {
uboot_size = get_uboot_offset(uboot_buf);
*pages_offset = uboot_size / size_per_page;
if (uboot_size % size_per_page)
*pages_offset = (*pages_offset) + 1;
return 1;
} else {
return 0;
}
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int uboot_info_init(struct _uboot_info *uboot)
{
int ret, blcok_offset;
char *uboot_buf;
unsigned int i;
unsigned int jump_size;
unsigned int size_per_page;
//unsigned int uboot_size;
unsigned int lsb_pages;
unsigned int pages_offset;
int uboot_find = 0;
int uboot_ptr = 0;
__u32 page_cnt_per_blk;
page_cnt_per_blk = nand_get_page_cnt_per_block();
size_per_page = nand_get_page_size();
memset(uboot, 0, sizeof(struct _uboot_info));
uboot_buf = nand_malloc(size_per_page);
if (uboot_buf == NULL) {
RAWNAND_ERR("uboot_buf malloc fail\n");
return 1;
}
uboot->use_lsb_page = nand_used_lsb_pages();
blcok_offset = 0;
for (i = aw_nand_info.boot->uboot_start_block; i < aw_nand_info.boot->uboot_next_block; i++) {
ret = nand_physic_bad_block_check(0, i);
if (ret == 0) {
uboot->uboot_block[uboot_ptr] = i;
uboot_ptr++;
}
ret = is_uboot_block(i, uboot_buf, &pages_offset);
if (ret == 1) {
if (blcok_offset == 0) {
uboot_find = 1;
uboot->uboot_len = get_uboot_offset(uboot_buf);
uboot->uboot_pages = uboot->uboot_len / size_per_page;
if (uboot->uboot_len % size_per_page) {
uboot->uboot_pages++;
}
jump_size = size_per_page * uboot->uboot_pages - uboot->uboot_len;
uboot->total_len = uboot->uboot_len + jump_size + PHY_INFO_SIZE;
uboot->total_pages = uboot->total_len / size_per_page;
uboot->page_offset_for_nand_info = uboot->uboot_pages;
uboot->byte_offset_for_nand_info = size_per_page * uboot->uboot_pages;
if (uboot->use_lsb_page == 0) {
uboot->blocks_per_total = uboot->total_pages / page_cnt_per_blk;
if (uboot->total_pages % page_cnt_per_blk) {
uboot->blocks_per_total++;
}
} else {
lsb_pages = nand_get_lsb_pages();
uboot->blocks_per_total = uboot->total_pages / lsb_pages;
if (uboot->total_pages % lsb_pages) {
uboot->blocks_per_total++;
}
}
}
blcok_offset++;
//uboot->copys++;
//i += uboot->blocks_per_total - 1;
}
}
if (uboot_find == 1) {
uboot->copys = uboot_ptr / uboot->blocks_per_total;
} else {
uboot->copys = 0;
}
print_uboot_info(uboot);
nand_free(uboot_buf);
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int init_phyinfo_buf(void)
{
phyinfo_buf = (struct _boot_info *)nand_malloc(PHY_INFO_SIZE);
if (phyinfo_buf == NULL) {
RAWNAND_ERR("init_phyinfo_buf malloc fail\n");
return -1;
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int get_uboot_offset(void *buf)
{
int *toc;
toc = (int *)buf;
return toc[TOC_LEN_OFFSET_BY_INT];
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int is_uboot_magic(void *buf)
{
int *toc;
toc = (int *)buf;
return (toc[TOC_MAGIC_OFFSET_BY_INT] == TOC_MAIN_INFO_MAGIC) ? 1 : 0;
}
/********************************************************************************
* name : check_magic
* func : check the magic of boot0
*
* argu : @mem_base : the start address of boot0;
* @magic : the standard magic;
*
* return: CHECK_IS_CORRECT : magic is ok;
* CHECK_IS_WRONG : magic is wrong;
********************************************************************************/
int check_magic_physic_info(unsigned int *mem_base, char *magic)
{
unsigned int i;
struct _boot_info *bfh;
unsigned int sz;
unsigned char *p;
bfh = (struct _boot_info *)mem_base;
p = (unsigned char *)&(bfh->magic);
for (i = 0, sz = sizeof(bfh->magic); i < sz; i++) {
if (*p++ != *magic++)
return -1;
}
return 0;
}
/********************************************************************************
* name : check_sum
* func : check data using check sum.
*
* argu : @mem_base : the start address of data, it must be 4-byte aligned;
* @size : the size of data;
*
* return: CHECK_IS_CORRECT : the data is right;
* CHECK_IS_WRONG : the data is wrong;
********************************************************************************/
int check_sum_physic_info(unsigned int *mem_base, unsigned int size)
{
unsigned int *buf;
unsigned int count;
unsigned int src_sum;
unsigned int sum;
struct _boot_info *bfh;
bfh = (struct _boot_info *)mem_base;
/* generate check sum */
src_sum = bfh->sum; // get check_sum field from the head of boot0;
bfh->sum = UBOOT_STAMP_VALUE; // replace the check_sum field of the boot0 head with STAMP_VALUE
count = size >> 2; // unit, 4byte
sum = 0;
buf = (unsigned int *)mem_base;
do {
sum += *buf++; // calculate check sum
sum += *buf++;
sum += *buf++;
sum += *buf++;
} while ((count -= 4) > (4 - 1));
while (count-- > 0)
sum += *buf++;
bfh->sum = src_sum; // restore the check_sum field of the boot0 head
//msg("sum:0x%x - src_sum:0x%x\n", sum, src_sum);
if (sum == src_sum)
return 0; // ok
else
return -1; // err
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
unsigned int cal_sum_physic_info(struct _boot_info *mem_base, unsigned int size)
{
unsigned int count, sum;
struct _boot_info *temp_buf;
unsigned int *buf;
temp_buf = mem_base;
temp_buf->sum = UBOOT_STAMP_VALUE;
count = size >> 2;
sum = 0;
buf = (unsigned int *)mem_base;
do {
sum += *buf++;
sum += *buf++;
sum += *buf++;
sum += *buf++;
} while ((count -= 4) > (4 - 1));
while (count-- > 0)
sum += *buf++;
temp_buf->sum = sum;
return sum;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int physic_info_get_offset(unsigned int *pages_offset)
{
unsigned int block;
unsigned int size_per_page;
unsigned int uboot_size;
unsigned char sdata[64] = {
0xFF,
};
int ret;
unsigned int cnt;
void *uboot_buf = NULL;
RAWNAND_DBG("physic_info_get_offset start!!\n");
size_per_page = nand_get_page_size();
uboot_buf = nand_malloc(size_per_page);
if (uboot_buf == NULL) {
RAWNAND_ERR("uboot_buf malloc fail\n");
return -1;
}
cnt = 0;
for (block = UBOOT_SCAN_START_BLOCK; block < UBOOT_MAX_BLOCK_NUM; block++) {
ret = nand_physic_read_page(0, block, 0, size_per_page / 512, uboot_buf, sdata);
if (ret == ERR_ECC) {
RAWNAND_ERR("ecc err:chip 0 block %d page 0\n", block);
continue;
}
#if 0
{
unsigned int i = 0;
for (i = 1; i < 257; i++) {
if ((i % 8) == 0)
RAWNAND_DBG("\n");
RAWNAND_DBG(" %08x", *((unsigned int *)uboot_buf + i - 1));
}
RAWNAND_DBG("\n");
}
#endif
if (1 == (is_uboot_magic(uboot_buf))) {
cnt++;
uboot_size = get_uboot_offset(uboot_buf);
break;
}
}
if (cnt) {
*pages_offset = uboot_size / size_per_page;
if (uboot_size % size_per_page)
*pages_offset = (*pages_offset) + 1;
}
/*RAWNAND_DBG("cnt %d pages_offset %d uboot_size %x\n",cnt,*pages_offset,uboot_size);*/
if (uboot_buf) {
nand_free(uboot_buf);
}
if (cnt)
return 0;
else
return 1;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int physic_info_get_one_copy(unsigned int start_block, unsigned int pages_offset, unsigned int *block_per_copy, unsigned int *buf)
{
int ret = 0;
if (get_storage_type() == 1)
ret = rawnand_physic_info_get_one_copy(start_block, pages_offset, block_per_copy, buf);
else if (get_storage_type() == 2)
ret = spinand_physic_info_get_one_copy(start_block, pages_offset, block_per_copy, buf);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int clean_physic_info(void)
{
memset((char *)phyinfo_buf, 0, PHY_INFO_SIZE);
phyinfo_buf->len = PHY_INFO_SIZE;
phyinfo_buf->magic = PHY_INFO_MAGIC;
RAWNAND_DBG("clean physic info uboot\n");
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int nand_physic_info_read(void)
{
// unsigned int copy;
int ret, ret_sum, ret_flag;
unsigned int pages_offset;
unsigned int start_block, block_per_copy, size_per_page;
char *temp_buf;
static int flag;
RAWNAND_DBG("nand_physic_info_read start!!\n");
if (flag == 1) {
RAWNAND_DBG("nand_physic_info_read already!!\n");
return 0;
}
if (init_phyinfo_buf() != 0) {
return -1;
}
size_per_page = nand_get_page_size();
#if 0
ret = physic_info_get_offset(&pages_offset);
if (ret) {
memset((char *)phyinfo_buf, 0, PHY_INFO_SIZE);
phyinfo_buf->len = PHY_INFO_SIZE;
phyinfo_buf->magic = PHY_INFO_MAGIC;
/*
Exception case, running without crc check
*/
RAWNAND_ERR("can't find uboot head\n");
flag = 1;
return ret;
}
#endif
temp_buf = nand_malloc(size_per_page);
ret_flag = -1;
for (start_block = UBOOT_SCAN_START_BLOCK; start_block <= UBOOT_MAX_BLOCK_NUM; start_block++) {
ret = is_uboot_block(start_block, temp_buf, &pages_offset);
if (ret != 1) {
continue;
}
physic_info_get_one_copy(start_block, pages_offset, &block_per_copy, (unsigned int *)phyinfo_buf);
// RAWNAND_DBG("start_block %d pages_offset %d block_per_copy %d\n", start_block, pages_offset, block_per_copy);
#if 0
{
unsigned int i = 0;
for (i = 1; i < 2049; i++) {
if ((i % 8) == 0)
RAWNAND_DBG("\n");
RAWNAND_DBG(" %08x", *((unsigned int *)phyinfo_buf + i - 1));
}
RAWNAND_DBG("\n");
RAWNAND_DBG("block_per_copy %d\n", block_per_copy);
}
#endif
ret_sum = check_sum_physic_info((unsigned int *)phyinfo_buf, PHY_INFO_SIZE);
if (ret_sum == 0) {
RAWNAND_DBG("physic info copy is ok\n");
ret_flag = 0;
flag = 1;
kernelsta.nand_bootinfo_state.state = BOOT_INFO_OK;
break;
} else {
RAWNAND_DBG("physic info copy is bad\n");
memset((char *)phyinfo_buf, 0, PHY_INFO_SIZE);
phyinfo_buf->len = PHY_INFO_SIZE;
phyinfo_buf->magic = PHY_INFO_MAGIC;
flag = 1;
}
}
nand_free(temp_buf);
if (flag == 0)
kernelsta.nand_bootinfo_state.state = BOOT_INFO_NOEXIST;
return ret_flag;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int is_phyinfo_empty(struct _boot_info *info)
{
if (get_storage_type() == 1) {
if ((info->magic == PHY_INFO_MAGIC) && (info->len == PHY_INFO_SIZE) && (info->storage_info.data.plane_cnt == 0) && (info->sum == 0)) {
return 1;
}
} else if (get_storage_type() == 2) {
if ((info->magic == PHY_INFO_MAGIC) && (info->len == PHY_INFO_SIZE) && (info->storage_info.config.plane_cnt == 0) && (info->sum == 0)) {
return 1;
}
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int add_len_to_uboot_tail(unsigned int uboot_size)
{
int size = 0;
if (get_storage_type() == 1)
size = rawnand_add_len_to_uboot_tail(uboot_size);
else if (get_storage_type() == 2)
size = spinand_add_len_to_uboot_tail(uboot_size);
return size;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int print_physic_info(struct _boot_info *info)
{
unsigned int i = 0;
for (i = 1; i < (PHY_INFO_SIZE / 4) + 1; i++) {
if ((i % 8) == 0)
RAWNAND_DBG("\n");
RAWNAND_DBG(" %08x", *((unsigned int *)info + i - 1));
}
RAWNAND_DBG("end!\n");
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int physic_info_add_to_uboot_tail(unsigned int *buf_dst, unsigned int uboot_size)
{
unsigned int real_len;
real_len = add_len_to_uboot_tail(uboot_size);
cal_sum_physic_info(phyinfo_buf, PHY_INFO_SIZE);
#if 0
{
unsigned int i;
for (i = 1; i < 2049; i++) {
if ((i % 8) == 0)
RAWNAND_DBG("\n");
RAWNAND_DBG(" %08x", *((unsigned int *)phyinfo_buf + i - 1));
}
RAWNAND_DBG("111\n");
}
#endif
RAWNAND_DBG("physic_info_add_to_uboot_tail start2 %p!!\n", phyinfo_buf);
memcpy((char *)buf_dst + (real_len - PHY_INFO_SIZE), phyinfo_buf, PHY_INFO_SIZE);
return 0;
}