/* 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 #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; }