1143 lines
31 KiB
C
1143 lines
31 KiB
C
/* 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_SPINAND_C_
|
|
|
|
#include "spinand_boot.h"
|
|
#include "../../nfd/nand_osal_for_linux.h"
|
|
#include "../nand-partition/phy.h"
|
|
#include "../nand_boot.h"
|
|
#include "../nand_physic_interface.h"
|
|
#include "../nand_secure_storage.h"
|
|
#include "../version.h"
|
|
#include "spinand.h"
|
|
#include "spinand_debug.h"
|
|
#include "spinand_type.h"
|
|
#include <linux/mtd/aw-spinand-nftl.h>
|
|
#include <linux/sunxi-boot.h>
|
|
|
|
#define VALID_PAGESIZE_FOR_BOOT0 2048
|
|
|
|
extern struct _nand_info aw_nand_info;
|
|
extern struct _boot_info *phyinfo_buf;
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter)
|
|
{
|
|
__u32 i, j;
|
|
__u8 oob_buf[64];
|
|
__u32 pages_per_block, blocks_per_copy, start_block, count, pagesize;
|
|
int ret = 0;
|
|
struct boot_physical_param para;
|
|
|
|
SPINAND_DBG("SPINAND burn boot0!\n");
|
|
memset(¶, 0, sizeof(struct boot_physical_param));
|
|
|
|
for (i = 0; i < 64; i++)
|
|
oob_buf[i] = 0xff;
|
|
|
|
/* get nand driver version */
|
|
nand_get_version(oob_buf);
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get flash driver version error!");
|
|
goto error;
|
|
}
|
|
|
|
pagesize = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
blocks_per_copy = 1;
|
|
start_block = blocks_per_copy * counter;
|
|
if ((start_block + blocks_per_copy) > aw_nand_info.boot->uboot_start_block) {
|
|
return 0;
|
|
}
|
|
|
|
SPINAND_DBG("boot0 count %d!\n", counter);
|
|
|
|
count = 0;
|
|
for (i = start_block; i < (start_block + blocks_per_copy); i++) {
|
|
para.chip = 0;
|
|
para.block = i;
|
|
if (spinand_nftl_erase_single_block(para.chip, para.block) < 0) {
|
|
SPINAND_DBG("Fail in erasing block %d.\n", i);
|
|
//continue;
|
|
}
|
|
|
|
for (j = 0; j < pages_per_block; j++) {
|
|
para.chip = 0;
|
|
para.block = i;
|
|
para.page = j;
|
|
if (count < len / VALID_PAGESIZE_FOR_BOOT0)
|
|
para.mainbuf = (__u8 *)(buf + VALID_PAGESIZE_FOR_BOOT0 * ((i - start_block) * pages_per_block + j));
|
|
else
|
|
para.mainbuf = (__u8 *)buf;
|
|
para.oobbuf = oob_buf;
|
|
if (pagesize == 2048)
|
|
para.sectorbitmap = 0xf;
|
|
else if (pagesize == 4096)
|
|
para.sectorbitmap = 0xff;
|
|
|
|
ret = spinand_nftl_write_single_page(para.chip, para.block, para.page, para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret < 0) {
|
|
SPINAND_DBG("Warning. Fail in writing page %d in block %d.\n", j, i);
|
|
}
|
|
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_read_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter)
|
|
{
|
|
__u32 i, j, m;
|
|
__u8 oob_buf[64];
|
|
__u32 pages_per_block, blocks_per_copy, start_block, count;
|
|
__u32 flag;
|
|
int ret = 0;
|
|
unsigned char *ptr;
|
|
struct boot_physical_param para;
|
|
|
|
SPINAND_DBG("spinand_read_boot0_one\n");
|
|
|
|
for (i = 0; i < 64; i++)
|
|
oob_buf[i] = 0xff;
|
|
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
blocks_per_copy = 1;
|
|
start_block = blocks_per_copy * counter;
|
|
if ((start_block + blocks_per_copy) > aw_nand_info.boot->uboot_start_block) {
|
|
return 0;
|
|
}
|
|
|
|
SPINAND_DBG("boot0 count %d!\n", counter);
|
|
|
|
ptr = (__u8 *)nand_malloc(512 * SECTOR_CNT_OF_SINGLE_PAGE);
|
|
|
|
count = 0;
|
|
flag = 0;
|
|
for (i = start_block; i < (start_block + blocks_per_copy); i++) {
|
|
for (j = 0; j < pages_per_block; j++) {
|
|
para.chip = 0;
|
|
para.block = i;
|
|
para.page = j;
|
|
para.mainbuf = (void *)ptr;
|
|
para.oobbuf = oob_buf;
|
|
para.sectorbitmap = 0xf;
|
|
for (m = 0; m < 32; m++)
|
|
oob_buf[m] = 0x55;
|
|
ret = spinand_nftl_read_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret < 0) {
|
|
SPINAND_DBG("Warning. Fail in read page %d in block %d.\n", j, i);
|
|
goto error;
|
|
}
|
|
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get flash driver version error!");
|
|
goto error;
|
|
}
|
|
|
|
memcpy(buf + count * VALID_PAGESIZE_FOR_BOOT0, ptr, VALID_PAGESIZE_FOR_BOOT0);
|
|
|
|
count++;
|
|
if (count == (len / VALID_PAGESIZE_FOR_BOOT0)) {
|
|
flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (flag == 1)
|
|
break;
|
|
}
|
|
nand_free(ptr);
|
|
return 0;
|
|
|
|
error:
|
|
nand_free(ptr);
|
|
return -1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_write_uboot_one_in_block(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
|
|
{
|
|
int ret = 0;
|
|
unsigned int j, boot_len, page_index, t_len;
|
|
unsigned char oob_buf[64];
|
|
int uboot_flag, info_flag;
|
|
unsigned char *kernel_buf;
|
|
unsigned char *ptr;
|
|
struct boot_physical_param para;
|
|
int pagesize, pages_per_block;
|
|
|
|
SPINAND_DBG("spinand burn uboot in one block!\n");
|
|
|
|
memset(¶, 0, sizeof(struct boot_physical_param));
|
|
pagesize = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
uboot_flag = 0;
|
|
info_flag = 0;
|
|
boot_len = 0;
|
|
t_len = 0;
|
|
|
|
kernel_buf = nand_malloc(pagesize);
|
|
|
|
memset(oob_buf, 0xff, 64);
|
|
|
|
nand_get_version(oob_buf);
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get flash driver version error!");
|
|
nand_free(kernel_buf);
|
|
return ERR_NO_105;
|
|
}
|
|
|
|
para.chip = 0;
|
|
para.block = info_buf->uboot_start_block + counter;
|
|
if (spinand_nftl_erase_single_block(para.chip, para.block) < 0) {
|
|
SPINAND_DBG("Fail in erasing block %d.\n", para.block);
|
|
//continue;
|
|
}
|
|
|
|
page_index = 0;
|
|
for (j = 0; j < pages_per_block; j++) {
|
|
para.chip = 0;
|
|
para.block = info_buf->uboot_start_block + counter;
|
|
|
|
para.page = j;
|
|
if (pagesize == 2048)
|
|
para.sectorbitmap = 0xf;
|
|
else if (pagesize == 4096)
|
|
para.sectorbitmap = 0xff;
|
|
para.oobbuf = oob_buf;
|
|
|
|
if (uboot_flag == 0) {
|
|
boot_len = page_index * pagesize;
|
|
memcpy(kernel_buf, buf + boot_len, pagesize);
|
|
ptr = kernel_buf;
|
|
if ((len - boot_len) == (pagesize)) {
|
|
uboot_flag = page_index + 1;
|
|
}
|
|
} else if (info_flag == 0) {
|
|
SPINAND_DBG("uboot info: page %d in block %d.\n", para.page, para.block);
|
|
t_len = (page_index - uboot_flag) * pagesize;
|
|
ptr = (unsigned char *)info_buf;
|
|
ptr += t_len;
|
|
if ((info_len - t_len) == pagesize) {
|
|
info_flag = page_index;
|
|
}
|
|
} else {
|
|
ptr = kernel_buf;
|
|
}
|
|
|
|
para.mainbuf = ptr;
|
|
|
|
ret = spinand_nftl_write_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret < 0) {
|
|
SPINAND_DBG("Warning. Fail in writing page %d in block %d.\n", j, para.block);
|
|
}
|
|
page_index++;
|
|
}
|
|
|
|
nand_free(kernel_buf);
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_write_uboot_one_in_many_block(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
|
|
{
|
|
int ret = 0;
|
|
unsigned int j, boot_len, page_index, total_len, t_len, total_pages, pages_per_block, good_block_offset, blocks_one_uboot, uboot_block_offset, m;
|
|
unsigned int write_blocks;
|
|
unsigned char oob_buf[64];
|
|
int uboot_flag, info_flag;
|
|
unsigned char *kernel_buf;
|
|
unsigned char *ptr;
|
|
struct boot_physical_param para;
|
|
int pagesize;
|
|
|
|
memset(¶, 0, sizeof(struct boot_physical_param));
|
|
pagesize = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
SPINAND_DBG("spinand burn uboot in many block %d!\n", counter);
|
|
|
|
uboot_flag = 0;
|
|
info_flag = 0;
|
|
boot_len = 0;
|
|
t_len = 0;
|
|
|
|
kernel_buf = nand_malloc(pagesize);
|
|
|
|
memset(oob_buf, 0xff, 64);
|
|
|
|
nand_get_version(oob_buf);
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get flash driver version error!");
|
|
nand_free(kernel_buf);
|
|
return ERR_NO_105;
|
|
}
|
|
|
|
if (len % pagesize) {
|
|
SPINAND_DBG("uboot length check error!\n");
|
|
nand_free(kernel_buf);
|
|
return ERR_NO_104;
|
|
}
|
|
|
|
total_len = len + info_len;
|
|
if (total_len % pagesize) {
|
|
SPINAND_DBG("uboot length check error!\n");
|
|
nand_free(kernel_buf);
|
|
return ERR_NO_104;
|
|
}
|
|
total_pages = total_len / pagesize;
|
|
blocks_one_uboot = total_pages / pages_per_block;
|
|
|
|
if (total_pages % pages_per_block) {
|
|
blocks_one_uboot++;
|
|
}
|
|
|
|
good_block_offset = blocks_one_uboot * counter;
|
|
|
|
for (m = 0, j = info_buf->uboot_start_block; j < info_buf->uboot_next_block; j++) {
|
|
if (m == good_block_offset) {
|
|
break;
|
|
}
|
|
ret = spinand_nftl_single_badblock_check(0, j);
|
|
if (ret == 0) {
|
|
m++;
|
|
}
|
|
}
|
|
|
|
uboot_block_offset = j;
|
|
|
|
if ((uboot_block_offset + blocks_one_uboot) > info_buf->uboot_next_block) {
|
|
nand_free(kernel_buf);
|
|
return 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
uboot_flag = 0;
|
|
info_flag = 0;
|
|
boot_len = 0;
|
|
page_index = 0;
|
|
write_blocks = 0;
|
|
|
|
for (j = uboot_block_offset; j < info_buf->uboot_next_block; j++) {
|
|
para.chip = 0;
|
|
para.block = j;
|
|
|
|
ret = spinand_nftl_single_badblock_check(0, j);
|
|
if (ret != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (spinand_nftl_erase_single_block(para.chip, para.block) < 0) {
|
|
SPINAND_DBG("Fail in erasing block %d.\n", para.block);
|
|
//continue;
|
|
}
|
|
|
|
write_blocks++;
|
|
|
|
SPINAND_DBG("write uboot many block %d!\n", para.block);
|
|
|
|
for (m = 0; m < pages_per_block; m++) {
|
|
para.chip = 0;
|
|
para.block = j;
|
|
para.page = m;
|
|
if (pagesize == 2048)
|
|
para.sectorbitmap = 0xf;
|
|
else if (pagesize == 4096)
|
|
para.sectorbitmap = 0xff;
|
|
para.oobbuf = oob_buf;
|
|
|
|
if (uboot_flag == 0) {
|
|
boot_len = page_index * pagesize;
|
|
memcpy(kernel_buf, buf + boot_len, pagesize);
|
|
ptr = kernel_buf;
|
|
if ((len - boot_len) == pagesize) {
|
|
uboot_flag = page_index + 1;
|
|
}
|
|
} else if (info_flag == 0) {
|
|
SPINAND_DBG("uboot info: page %d in block %d.\n", para.page, para.block);
|
|
t_len = (page_index - uboot_flag) * pagesize;
|
|
ptr = (unsigned char *)info_buf;
|
|
ptr += t_len;
|
|
if ((info_len - t_len) == pagesize) {
|
|
info_flag = page_index;
|
|
}
|
|
} else {
|
|
ptr = kernel_buf;
|
|
}
|
|
|
|
para.mainbuf = ptr;
|
|
|
|
ret = spinand_nftl_write_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
|
|
if (ret < 0) {
|
|
SPINAND_DBG("Warning. Fail in writing page %d in block %d.\n", para.page, para.block);
|
|
}
|
|
page_index++;
|
|
}
|
|
|
|
if (blocks_one_uboot == write_blocks) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
nand_free(kernel_buf);
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_write_uboot_one(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
|
|
{
|
|
int ret;
|
|
int real_len;
|
|
|
|
SPINAND_DBG("spinand burn uboot one!\n");
|
|
|
|
real_len = spinand_add_len_to_uboot_tail(len);
|
|
|
|
//print_physic_info(phyinfo_buf);
|
|
|
|
if (real_len <= spinand_nftl_get_single_block_size(BYTE)) {
|
|
ret = spinand_write_uboot_one_in_block(buf, len, info_buf, info_len, counter);
|
|
} else {
|
|
ret = spinand_write_uboot_one_in_many_block(buf, len, info_buf, info_len, counter);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail 1: ecc limit
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_read_uboot_one_in_block(unsigned char *buf, unsigned int len, unsigned int counter)
|
|
{
|
|
int ret = 0, data_error = 0, ecc_limit = 0;
|
|
unsigned int j, page_index, total_pages = 0;
|
|
unsigned char oob_buf[64];
|
|
unsigned char *ptr;
|
|
struct boot_physical_param para;
|
|
int pagesize, pages_per_block;
|
|
|
|
memset(¶, 0, sizeof(para));
|
|
pagesize = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
SPINAND_DBG("spinand read uboot in one block %d!\n", counter);
|
|
|
|
|
|
ptr = nand_malloc(pagesize);
|
|
|
|
memset(oob_buf, 0xff, 64);
|
|
|
|
if (len % pagesize) {
|
|
SPINAND_DBG("uboot length check error!\n");
|
|
nand_free(ptr);
|
|
return 0;
|
|
}
|
|
|
|
total_pages = len / pagesize;
|
|
|
|
for (j = 0, page_index = 0; j < pages_per_block; j++) {
|
|
para.chip = 0;
|
|
para.block = phyinfo_buf->uboot_start_block + counter;
|
|
|
|
para.page = j;
|
|
if (pagesize == 2048)
|
|
para.sectorbitmap = 0xf;
|
|
else if (pagesize == 4096)
|
|
para.sectorbitmap = 0xff;
|
|
para.oobbuf = oob_buf;
|
|
para.mainbuf = ptr;
|
|
|
|
ret = spinand_nftl_read_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret == 0) {
|
|
;
|
|
} else if (ret == ECC_LIMIT) {
|
|
ecc_limit = 1;
|
|
SPINAND_DBG("Warning. Fail in read page %d in block %d \n", para.page, para.block);
|
|
} else {
|
|
data_error = 1;
|
|
break;
|
|
}
|
|
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get uboot flash driver version error!\n");
|
|
data_error = 1;
|
|
break;
|
|
}
|
|
|
|
memcpy(buf + page_index * pagesize, ptr, pagesize);
|
|
|
|
page_index++;
|
|
|
|
if (total_pages == page_index) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
nand_free(ptr);
|
|
|
|
if (data_error == 1) {
|
|
ret = -1;
|
|
} else if (ecc_limit == 1) {
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail 1: ecc limit
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_read_uboot_one_in_many_block(unsigned char *buf, unsigned int len, unsigned int counter)
|
|
{
|
|
int ret = 0, data_error = 0, ecc_limit = 0;
|
|
unsigned int j, page_index, total_len, total_pages, pages_per_block, good_block_offset, blocks_one_uboot, uboot_block_offset, m;
|
|
unsigned char oob_buf[64];
|
|
unsigned char *kernel_buf;
|
|
//unsigned char* ptr;
|
|
struct boot_physical_param para;
|
|
int pagesize;
|
|
|
|
memset(¶, 0, sizeof(para));
|
|
pagesize = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
SPINAND_DBG("spinand read uboot in many block %d!\n", counter);
|
|
|
|
|
|
kernel_buf = nand_malloc(pagesize);
|
|
|
|
memset(oob_buf, 0xff, 64);
|
|
|
|
nand_get_version(oob_buf);
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get flash driver version error!");
|
|
nand_free(kernel_buf);
|
|
return ERR_NO_105;
|
|
}
|
|
|
|
if (len % pagesize) {
|
|
SPINAND_DBG("uboot length check error!\n");
|
|
nand_free(kernel_buf);
|
|
return ERR_NO_104;
|
|
}
|
|
|
|
total_len = len;
|
|
total_pages = total_len / pagesize;
|
|
blocks_one_uboot = total_pages / pages_per_block;
|
|
|
|
if (total_pages % pages_per_block) {
|
|
blocks_one_uboot++;
|
|
}
|
|
|
|
good_block_offset = blocks_one_uboot * counter;
|
|
|
|
for (m = 0, j = phyinfo_buf->uboot_start_block; j < phyinfo_buf->uboot_next_block; j++) {
|
|
if (m == good_block_offset) {
|
|
break;
|
|
}
|
|
ret = spinand_nftl_single_badblock_check(0, j);
|
|
if (ret == 0) {
|
|
m++;
|
|
}
|
|
}
|
|
|
|
uboot_block_offset = j;
|
|
if ((uboot_block_offset + blocks_one_uboot) > phyinfo_buf->uboot_next_block) {
|
|
nand_free(kernel_buf);
|
|
return 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
page_index = 0;
|
|
|
|
for (j = uboot_block_offset; j < phyinfo_buf->uboot_next_block; j++) {
|
|
ret = spinand_nftl_single_badblock_check(0, j);
|
|
if (ret != 0) {
|
|
continue;
|
|
}
|
|
|
|
SPINAND_DBG("read uboot many block %d!\n", para.block);
|
|
|
|
for (m = 0; m < pages_per_block; m++) {
|
|
para.chip = 0;
|
|
para.block = j;
|
|
para.page = m;
|
|
if (pagesize == 2048)
|
|
para.sectorbitmap = 0xf;
|
|
else if (pagesize == 4096)
|
|
para.sectorbitmap = 0xff;
|
|
para.oobbuf = oob_buf;
|
|
para.mainbuf = kernel_buf;
|
|
|
|
ret = spinand_nftl_read_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret == 0) {
|
|
;
|
|
} else if (ret == ECC_LIMIT) {
|
|
ecc_limit = 1;
|
|
SPINAND_DBG("Warning. Fail in read page %d in block %d \n", para.page, para.block);
|
|
} else {
|
|
SPINAND_DBG("error read page: %d in block %d \n", para.page, para.block);
|
|
data_error = 1;
|
|
break;
|
|
}
|
|
|
|
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
|
|
SPINAND_DBG("get uboot flash driver version error!\n");
|
|
data_error = 1;
|
|
break;
|
|
}
|
|
|
|
memcpy(buf + page_index * pagesize, para.mainbuf, pagesize);
|
|
page_index++;
|
|
if (total_pages == page_index) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (total_pages == page_index) {
|
|
break;
|
|
}
|
|
if (data_error == 1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
nand_free(kernel_buf);
|
|
|
|
if (data_error == 1) {
|
|
ret = -1;
|
|
} else if (ecc_limit == 1) {
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok <0:fail 1: ecc limit
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_read_uboot_one(unsigned char *buf, unsigned int len, unsigned int counter)
|
|
{
|
|
int ret = 0;
|
|
|
|
SPINAND_DBG("spinand read uboot one %d!\n", counter);
|
|
|
|
if (len <= spinand_nftl_get_single_block_size(BYTE)) {
|
|
ret = spinand_read_uboot_one_in_block(buf, len, counter);
|
|
} else {
|
|
ret = spinand_read_uboot_one_in_many_block(buf, len, counter);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :NAND_GetParam
|
|
*****************************************************************************/
|
|
int spinand_get_param(void *nand_param)
|
|
{
|
|
__u32 i;
|
|
boot_spinand_para_t *nand_param_temp;
|
|
|
|
nand_param_temp = (boot_spinand_para_t *)nand_param;
|
|
|
|
nand_param_temp->ChipCnt = spinand_storage_info.ChipCnt;
|
|
nand_param_temp->ChipConnectInfo = spinand_storage_info.ChipConnectInfo;
|
|
nand_param_temp->ConnectMode = spinand_storage_info.ConnectMode;
|
|
nand_param_temp->BankCntPerChip = spinand_storage_info.BankCntPerChip;
|
|
nand_param_temp->DieCntPerChip = spinand_storage_info.DieCntPerChip;
|
|
nand_param_temp->PlaneCntPerDie = spinand_storage_info.PlaneCntPerDie;
|
|
nand_param_temp->SectorCntPerPage = spinand_storage_info.SectorCntPerPage;
|
|
nand_param_temp->PageCntPerPhyBlk = spinand_storage_info.PageCntPerPhyBlk;
|
|
nand_param_temp->BlkCntPerDie = spinand_storage_info.BlkCntPerDie;
|
|
nand_param_temp->OperationOpt = spinand_storage_info.OperationOpt;
|
|
nand_param_temp->FrequencePar = 30; // wait to process,at present uboot can't to get it
|
|
nand_param_temp->SpiMode = 0; // wait to process,at present uboot can't to get it
|
|
nand_param_temp->MaxEraseTimes = spinand_storage_info.MaxEraseTimes;
|
|
nand_param_temp->MultiPlaneBlockOffset = 1; //wait to process
|
|
nand_param_temp->pagewithbadflag = 0; //wait to process
|
|
nand_param_temp->EccLimitBits = 4; // wait to process
|
|
nand_param_temp->MaxEccBits = 8; // wait to process
|
|
// nand_param->spi_nand_function = NandStorageInfo.spi_nand_function ;
|
|
|
|
// spic_set_trans_mode(0, NandStorageInfo.SpiMode);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
nand_param_temp->NandChipId[i] = spinand_storage_info.NandChipId[i];
|
|
|
|
return 0;
|
|
}
|
|
|
|
int spinand_get_param_for_uboottail(void *nand_param)
|
|
{
|
|
boot_spinand_para_t *nand_param_temp;
|
|
|
|
nand_param_temp = (boot_spinand_para_t *)nand_param;
|
|
|
|
nand_param_temp->uboot_start_block = aw_nand_info.boot->uboot_start_block;
|
|
nand_param_temp->uboot_next_block = aw_nand_info.boot->uboot_next_block;
|
|
nand_param_temp->logic_start_block = aw_nand_info.boot->logic_start_block;
|
|
nand_param_temp->nand_specialinfo_page = aw_nand_info.boot->nand_specialinfo_page;
|
|
nand_param_temp->nand_specialinfo_offset = aw_nand_info.boot->nand_specialinfo_offset;
|
|
nand_param_temp->physic_block_reserved = aw_nand_info.boot->physic_block_reserved;
|
|
|
|
SPINAND_DBG("uboot_start_block: %x\n", nand_param_temp->uboot_start_block);
|
|
SPINAND_DBG("uboot_next_block: %x\n", nand_param_temp->uboot_next_block);
|
|
SPINAND_DBG("logic_start_block:%x\n", nand_param_temp->logic_start_block);
|
|
SPINAND_DBG("nand_specialinfo_page:%x\n", nand_param_temp->nand_specialinfo_page);
|
|
SPINAND_DBG("nand_specialinfo_offset: %x\n", nand_param_temp->nand_specialinfo_offset);
|
|
SPINAND_DBG("physic_block_reserved: %x\n", nand_param_temp->physic_block_reserved);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
__s32 SPINAND_SetPhyArch_V3(struct _boot_info *ram_arch, void *phy_arch)
|
|
{
|
|
struct _spinand_config_para_info *config_para;
|
|
|
|
config_para = (struct _spinand_config_para_info *)phy_arch;
|
|
|
|
ram_arch->storage_info.config.support_two_plane = config_para->support_two_plane;
|
|
ram_arch->storage_info.config.support_v_interleave = config_para->support_v_interleave;
|
|
ram_arch->storage_info.config.support_dual_channel = config_para->support_dual_channel;
|
|
|
|
ram_arch->storage_info.config.support_dual_read = config_para->support_dual_read;
|
|
ram_arch->storage_info.config.support_dual_write = config_para->support_dual_write;
|
|
ram_arch->storage_info.config.support_quad_write = config_para->support_quad_write;
|
|
ram_arch->storage_info.config.support_quad_read = config_para->support_quad_read;
|
|
ram_arch->storage_info.config.frequence = config_para->frequence;
|
|
|
|
if (config_para->support_two_plane == 0) {
|
|
ram_arch->storage_info.config.plane_cnt = 1;
|
|
} else {
|
|
ram_arch->storage_info.config.plane_cnt = 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int SPINAND_UpdatePhyArch(void)
|
|
{
|
|
int ret;
|
|
//unsigned int id_number_ctl, para;
|
|
struct _spinand_config_para_info config_para;
|
|
|
|
SPINAND_DBG("SPINAND UpdatePhyArch\n");
|
|
/*due to physic layer don't need these parameters, actually these parameter is not significance */
|
|
config_para.support_two_plane = spinand_nftl_get_multi_plane_flag() ? 1 : 0;
|
|
config_para.support_v_interleave = 0; // now not support in physic layer
|
|
config_para.support_dual_read = 0; //don't care
|
|
config_para.support_dual_write = 0; //don't care
|
|
config_para.support_quad_write = 0; //don't care
|
|
config_para.support_quad_read = 0; //don't care
|
|
config_para.frequence = 75; //don't care
|
|
|
|
//ret = set_nand_structure((void*)&nand_permanent_data);
|
|
ret = SPINAND_SetPhyArch_V3(aw_nand_info.boot, &config_para);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_erase_chip(unsigned int chip, unsigned int start_block, unsigned int end_block, unsigned int force_flag)
|
|
{
|
|
int ret, i;
|
|
struct boot_physical_param para;
|
|
int blocks_per_chip;
|
|
|
|
blocks_per_chip = spinand_nftl_get_chip_size(BLOCK);
|
|
|
|
if ((end_block >= blocks_per_chip) || (end_block == 0))
|
|
end_block = blocks_per_chip;
|
|
|
|
if (start_block > end_block)
|
|
return 0;
|
|
|
|
for (i = start_block; i < end_block; i++) {
|
|
para.chip = 0;
|
|
para.block = i;
|
|
para.page = 0;
|
|
|
|
ret = spinand_nftl_single_badblock_check(para.chip, i);
|
|
if (force_flag == 1)
|
|
ret = 0;
|
|
|
|
if (ret == 0) {
|
|
ret = spinand_nftl_erase_single_block(para.chip, i);
|
|
if (i % 128 == 0)
|
|
SPINAND_DBG("erase block%d\n", i);
|
|
if (ret != 0) {
|
|
SPINAND_DBG("erase blk%d failed, mark bad block\n", i);
|
|
spinand_nftl_single_badblock_mark(para.chip, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return :
|
|
*Note :
|
|
*****************************************************************************/
|
|
void spinand_erase_special_block(void)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return : 0:ok -1:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_uboot_erase_all_chip(UINT32 force_flag)
|
|
{
|
|
int i, start, end, secure_block_start;
|
|
int uboot_start_block, uboot_next_block;
|
|
int chip_cnt;
|
|
|
|
uboot_start_block = get_uboot_start_block();
|
|
uboot_next_block = get_uboot_next_block();
|
|
secure_block_start = uboot_next_block;
|
|
|
|
chip_cnt = spinand_nftl_get_chip_cnt();
|
|
|
|
for (i = 0; i < chip_cnt; i++) {
|
|
start = 0;
|
|
end = 0xfffff;
|
|
|
|
if (i == 0) {
|
|
if (force_flag == 1)
|
|
start = secure_block_start;
|
|
else
|
|
start = nand_secure_storage_first_build(secure_block_start);
|
|
}
|
|
|
|
spinand_erase_chip(i, start, end, force_flag);
|
|
}
|
|
|
|
nand_erase_special_block();
|
|
|
|
clean_physic_info();
|
|
|
|
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:fail
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_dragonborad_test_one(unsigned char *buf, unsigned char *oob, unsigned int blk_num)
|
|
{
|
|
int ret = 0;
|
|
unsigned int j;
|
|
unsigned char oob_buf[64];
|
|
struct boot_physical_param para;
|
|
int pagesize, pages_per_block;
|
|
|
|
SPINAND_DBG("dragonborad test in one block!\n");
|
|
|
|
pagesize = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
for (j = 0; j < pagesize / 4; j++)
|
|
*((unsigned int *)buf + j) = 0x55aaaa55;
|
|
|
|
para.chip = 0;
|
|
para.block = blk_num;
|
|
para.page = 0;
|
|
|
|
ret = spinand_nftl_erase_single_block(para.chip, para.block);
|
|
if (ret) {
|
|
SPINAND_DBG("Fail in erasing block %d!\n", para.block);
|
|
return 0;
|
|
}
|
|
|
|
for (j = 0; j < pages_per_block; j++) {
|
|
para.chip = 0;
|
|
para.block = blk_num;
|
|
para.page = j;
|
|
para.sectorbitmap = 0xf;
|
|
para.oobbuf = oob;
|
|
|
|
para.mainbuf = buf;
|
|
|
|
ret = spinand_nftl_write_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret != 0)
|
|
SPINAND_DBG("Warning. Fail in writing page %d in block %d.\n", para.page, para.block);
|
|
}
|
|
for (j = 0; j < pages_per_block; j++) {
|
|
para.chip = 0;
|
|
para.block = blk_num;
|
|
para.page = j;
|
|
para.oobbuf = (unsigned char *)oob_buf;
|
|
para.sectorbitmap = 0xf;
|
|
para.mainbuf = buf;
|
|
|
|
memset(oob_buf, 0xff, 64);
|
|
memset(buf, 0xff, pagesize);
|
|
|
|
if (spinand_nftl_read_single_page(para.chip, para.block, para.page, para.sectorbitmap, para.mainbuf, para.oobbuf) != 0) {
|
|
SPINAND_DBG("Warning. Fail in read page %d in block %d.\n", j, para.block);
|
|
return -1;
|
|
}
|
|
if ((oob_buf[0] != oob[0]) || (oob_buf[1] != oob[1]) || (oob_buf[2] != oob[2]) || (oob_buf[3] != oob[3])) {
|
|
SPINAND_DBG("oob data error\n!");
|
|
return -1;
|
|
}
|
|
if (*((unsigned int *)buf) != 0x55aaaa55) {
|
|
SPINAND_DBG("main data error\n!");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return :
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_physic_info_get_one_copy(unsigned int start_block, unsigned int pages_offset, unsigned int *block_per_copy, unsigned int *buf)
|
|
{
|
|
unsigned int page, block;
|
|
unsigned int flag;
|
|
unsigned int size_per_page, pages_per_block, lsbblock_size;
|
|
unsigned char sdata[64];
|
|
int ret;
|
|
unsigned int phyinfo_page_cnt, page_cnt;
|
|
unsigned int badblk_num = 0;
|
|
unsigned int pages_per_phyinfo;
|
|
void *tempbuf = NULL;
|
|
struct boot_physical_param para;
|
|
|
|
SPINAND_DBG("physic_info_get_one_copy start!!\n");
|
|
size_per_page = nand_get_page_size();
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
pages_per_phyinfo = PHY_INFO_SIZE / size_per_page;
|
|
if (PHY_INFO_SIZE % size_per_page)
|
|
pages_per_phyinfo++;
|
|
|
|
// SPINAND_DBG("pages_per_phyinfo %d\n",pages_per_phyinfo);
|
|
|
|
tempbuf = (void *)nand_malloc(32 * 1024);
|
|
if (tempbuf == NULL) {
|
|
SPINAND_DBG("tempbuf malloc fail\n");
|
|
return -1;
|
|
}
|
|
|
|
page_cnt = 0;
|
|
phyinfo_page_cnt = 0;
|
|
flag = 0;
|
|
for (block = start_block;; block++) {
|
|
para.chip = 0;
|
|
para.block = block;
|
|
para.page = 0;
|
|
para.oobbuf = sdata;
|
|
para.sectorbitmap = 0;
|
|
para.mainbuf = NULL;
|
|
|
|
ret = spinand_nftl_read_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if ((sdata[0] == 0x0)) {
|
|
badblk_num++;
|
|
SPINAND_DBG("bad block:chip %d block %d\n", para.chip, para.block);
|
|
continue;
|
|
}
|
|
for (page = 0; page < pages_per_block; page++) {
|
|
if (page_cnt >= pages_offset) {
|
|
para.chip = 0;
|
|
para.block = block;
|
|
para.page = page;
|
|
para.oobbuf = sdata;
|
|
para.sectorbitmap = FULL_BITMAP_OF_SINGLE_PAGE;
|
|
para.mainbuf = (void *)((char *)tempbuf + phyinfo_page_cnt * size_per_page);
|
|
SPINAND_DBG("block %d page %d\n", para.block, para.page);
|
|
|
|
ret = spinand_nftl_read_single_page(para.chip, para.block, para.page,
|
|
para.sectorbitmap, para.mainbuf, para.oobbuf);
|
|
if (ret == ERR_ECC) {
|
|
SPINAND_DBG("ecc err:chip %d block %d page %d\n", para.chip, para.block, para.page);
|
|
break;
|
|
}
|
|
|
|
phyinfo_page_cnt++;
|
|
if (phyinfo_page_cnt == pages_per_phyinfo) {
|
|
flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
page_cnt++;
|
|
}
|
|
|
|
if (ret == ERR_ECC)
|
|
break;
|
|
|
|
if (flag == 1)
|
|
break;
|
|
}
|
|
|
|
memcpy(buf, tempbuf, PHY_INFO_SIZE);
|
|
|
|
lsbblock_size = nand_get_lsb_block_size();
|
|
|
|
*block_per_copy = (pages_offset + pages_per_phyinfo) * size_per_page / lsbblock_size + badblk_num;
|
|
if (((pages_offset + pages_per_phyinfo) * size_per_page) % lsbblock_size)
|
|
*block_per_copy = (*block_per_copy) + 1;
|
|
// SPINAND_DBG("block_per_copy %d pages_offset+pages_per_phyinfo %d\n",*block_per_copy,(pages_offset+pages_per_phyinfo));
|
|
|
|
if (tempbuf) {
|
|
nand_free(tempbuf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*Name :
|
|
*Description :
|
|
*Parameter :
|
|
*Return :
|
|
*Note :
|
|
*****************************************************************************/
|
|
int spinand_add_len_to_uboot_tail(unsigned int uboot_size)
|
|
{
|
|
unsigned int size_per_page, pages_per_uboot, pages_per_block, page_in_lsb_block;
|
|
unsigned int jump_size;
|
|
|
|
size_per_page = nand_get_page_size();
|
|
|
|
pages_per_uboot = uboot_size / size_per_page;
|
|
if (uboot_size % size_per_page)
|
|
pages_per_uboot++;
|
|
|
|
jump_size = size_per_page * pages_per_uboot - uboot_size;
|
|
|
|
pages_per_block = nand_get_page_cnt_per_block();
|
|
|
|
page_in_lsb_block = pages_per_uboot % pages_per_block;
|
|
|
|
return (uboot_size + jump_size + PHY_INFO_SIZE);
|
|
}
|