OSHW-DEIMOS/SOFTWARE/A64-TERES/u-boot_new/drivers/sunxi_flash/sunxi_flash.c
Dimitar Gamishev 093685c7d8 u-boot
2017-10-13 14:02:55 +03:00

483 lines
12 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (C) Copyright 2007-2013
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Jerry Wang <wangflord@allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <mmc.h>
#include <boot_type.h>
#include <sunxi_board.h>
#include <sunxi_flash.h>
#include <sys_config.h>
#include <sys_partition.h>
#include <malloc.h>
#include "flash_interface.h"
int sunxi_flash_init_uboot(int verbose);
extern int sunxi_card_fill_boot0_magic(void);
/*
************************************************************************************************************
*
* function
*
*
*
*
*
*
*
*
************************************************************************************************************
*/
static int
sunxi_null_op(unsigned int start_block, unsigned int nblock, void *buffer){
return 0;
}
static int
sunxi_null_erase(int erase, void *mbr_buffer)
{
return 0;
}
static uint
sunxi_null_size(void){
return 0;
}
static int
sunxi_null_init(int flag){
return -1;
}
static int
sunxi_null_exit(int force){
return -1;
}
static int
sunxi_null_flush(void){
return 0;
}
static int
sunxi_null_force_erase(void){
return 0;
}
#ifdef CONFIG_SUNXI_SPINOR
static int
sunxi_null_datafinish(void){
return 0;
}
#endif
/*
************************************************************************************************************
*
* function
*
*
*
*
*
*
*
*
************************************************************************************************************
*/
int (* sunxi_flash_init_pt)(int stage) = sunxi_null_init;
int (* sunxi_flash_read_pt) (uint start_block, uint nblock, void *buffer) = sunxi_null_op;
//int (* sunxi_flash_read_sequence) (uint start_block, uint nblock, void *buffer) = sunxi_null_op;
int (* sunxi_flash_write_pt)(uint start_block, uint nblock, void *buffer) = sunxi_null_op;
uint (* sunxi_flash_size_pt)(void) = sunxi_null_size;
int (* sunxi_flash_exit_pt) (int force) = sunxi_null_exit;
int (* sunxi_flash_flush_pt) (void) = sunxi_null_flush;
int (* sunxi_flash_phyread_pt) (unsigned int start_block, unsigned int nblock, void *buffer) = sunxi_null_op;
int (* sunxi_flash_phywrite_pt)(unsigned int start_block, unsigned int nblock, void *buffer) = sunxi_null_op;
int (* sunxi_sprite_init_pt)(int stage) = sunxi_null_init;
int (* sunxi_sprite_read_pt) (uint start_block, uint nblock, void *buffer) = sunxi_null_op;
int (* sunxi_sprite_write_pt)(uint start_block, uint nblock, void *buffer) = sunxi_null_op;
int (* sunxi_sprite_erase_pt)(int erase, void *mbr_buffer) = sunxi_null_erase;
uint (* sunxi_sprite_size_pt)(void) = sunxi_null_size;
int (* sunxi_sprite_exit_pt) (int force) = sunxi_null_exit;
int (* sunxi_sprite_flush_pt)(void) = sunxi_null_flush;
int (* sunxi_sprite_force_erase_pt)(void) = sunxi_null_force_erase;
int (* sunxi_sprite_phyread_pt) (unsigned int start_block, unsigned int nblock, void *buffer) = sunxi_null_op;
int (* sunxi_sprite_phywrite_pt)(unsigned int start_block, unsigned int nblock, void *buffer) = sunxi_null_op;
#ifdef CONFIG_SUNXI_SPINOR
int (* sunxi_sprite_datafinish_pt) (void) = sunxi_null_datafinish;
#endif
//-------------------------------------noraml interface start--------------------------------------------
int sunxi_flash_read (uint start_block, uint nblock, void *buffer)
{
debug("sunxi flash read : start %d, sector %d\n", start_block, nblock);
return sunxi_flash_read_pt(start_block, nblock, buffer);
}
int sunxi_flash_write(uint start_block, uint nblock, void *buffer)
{
debug("sunxi flash write : start %d, sector %d\n", start_block, nblock);
return sunxi_flash_write_pt(start_block, nblock, buffer);
}
uint sunxi_flash_size(void)
{
return sunxi_flash_size_pt();
}
int sunxi_flash_exit(int force)
{
return sunxi_flash_exit_pt(force);
}
int sunxi_flash_flush(void)
{
return sunxi_flash_flush_pt();
}
int sunxi_flash_phyread (uint start_block, uint nblock, void *buffer)
{
return sunxi_flash_phyread_pt(start_block, nblock, buffer);
}
int sunxi_flash_phywrite(uint start_block, uint nblock, void *buffer)
{
return sunxi_flash_phywrite_pt(start_block, nblock, buffer);
}
//-----------------------------------noraml interface end---------------------------------------------------
//-------------------------------------sprite interface start-----------------------------------------------
int sunxi_sprite_init(int stage)
{
return sunxi_sprite_init_pt(stage);
}
int sunxi_sprite_read (uint start_block, uint nblock, void *buffer)
{
return sunxi_sprite_read_pt(start_block, nblock, buffer);
}
int sunxi_sprite_write(uint start_block, uint nblock, void *buffer)
{
return sunxi_sprite_write_pt(start_block, nblock, buffer);
}
int sunxi_sprite_erase(int erase, void *mbr_buffer)
{
return sunxi_sprite_erase_pt(erase, mbr_buffer);
}
uint sunxi_sprite_size(void)
{
return sunxi_sprite_size_pt();
}
int sunxi_sprite_exit(int force)
{
return sunxi_sprite_exit_pt(force);
}
int sunxi_sprite_flush(void)
{
return sunxi_sprite_flush_pt();
}
int sunxi_sprite_phyread (uint start_block, uint nblock, void *buffer)
{
return sunxi_sprite_phyread_pt(start_block, nblock, buffer);
}
int sunxi_sprite_phywrite(uint start_block, uint nblock, void *buffer)
{
return sunxi_sprite_phywrite_pt(start_block, nblock, buffer);
}
int sunxi_sprite_force_erase(void)
{
return sunxi_sprite_force_erase_pt();
}
//-------------------------------------sprite interface end-----------------------------------------------
//sunxi flash boot interface init
int sunxi_flash_boot_handle(int storage_type,int workmode )
{
int card_no;
int state;
switch(storage_type)
{
case STORAGE_NAND:
{
//nand handle init
state = nand_init_for_boot(workmode);
}
break;
case STORAGE_SD:
case STORAGE_EMMC:
{
//sdmmc handle init
card_no = (storage_type == 1)?0:2;
state = sdmmc_init_for_boot(workmode,card_no);
}
break;
case STORAGE_NOR:
default:
{
printf("not support\n");
state = -1;
}
break;
}
if(state != 0)
{
return -1;
}
//script_parser_patch("target", "storage_type", &storage_type, 1);
tick_printf("sunxi flash init ok\n");
return 0;
}
int sunxi_flash_sprite_handle(int storage_type,int workmode)
{
int state = 0;
//try nand ,spi-nor ,mmc2
state = nand_init_for_sprite(workmode);
if(state !=0 )
{
printf("try nand fail\n");
state = sdmmc_init_for_sprite(workmode);
if(state != 0)
{
printf("try emmc fail\n");
return -1;
}
}
//sdcard burn mode
if((workmode == WORK_MODE_CARD_PRODUCT) || (workmode == 0x30))
{
state = sdmmc_init_card0_for_sprite();
if(state != 0)
{
return -1;
}
}
return 0;
}
int sunxi_flash_handle_init(void)
{
int workmode = 0;
int storage_type = 0;
int state = 0;
workmode = uboot_spare_head.boot_data.work_mode;
storage_type = uboot_spare_head.boot_data.storage_type;
printf("workmode = %d,storage type = %d\n", workmode,storage_type);
if (workmode == WORK_MODE_BOOT || workmode == WORK_MODE_SPRITE_RECOVERY || workmode == 0x55)
{
state = sunxi_flash_boot_handle(storage_type,workmode);
}
else if((workmode & WORK_MODE_PRODUCT) || (workmode == 0x30))
{
state = sunxi_flash_sprite_handle(storage_type,workmode);
}
else if(workmode & WORK_MODE_UPDATE) /* <20><><EFBFBD><EFBFBD>ģʽ */
{
}
else /* undefined mode */
{
}
//init blk dev for fat
sunxi_flash_init_uboot(0);
return state;
}
//-------------------------------------------------------------------------------------------
//sunxi flash blk device for fat
//-------------------------------------------------------------------------------------------
static block_dev_desc_t sunxi_flash_blk_dev;
block_dev_desc_t *sunxi_flash_get_dev(int dev)
{
sunxi_flash_blk_dev.dev = dev;
sunxi_flash_blk_dev.lba = sunxi_partition_get_size(dev);
return ((block_dev_desc_t *) & sunxi_flash_blk_dev);
}
unsigned long sunxi_flash_part_read(int dev_num, unsigned long start, lbaint_t blkcnt, void *dst)
{
uint offset;
offset = sunxi_partition_get_offset(dev_num);
if(!offset)
{
printf("sunxi flash error: cant get part %d offset\n", dev_num);
return 0;
}
start += offset;
debug("nand try to read from %x, length %x block\n", (int )start, (int )blkcnt);
return sunxi_flash_read((uint)start, (uint )blkcnt, dst);
}
unsigned long sunxi_flash_part_write(int dev_num, unsigned long start, lbaint_t blkcnt, const void *dst)
{
uint offset;
offset = sunxi_partition_get_offset(dev_num);
if(!offset)
{
printf("sunxi flash error: cant get part %d offset\n", dev_num);
return 0;
}
start += offset;
debug("nand try to write from %x, length %x block\n", (int )start, (int )blkcnt);
return sunxi_flash_write((uint)start, (uint )blkcnt, (void *)dst);
}
int sunxi_flash_init_uboot(int verbose)
{
debug("sunxi flash init uboot\n");
sunxi_flash_blk_dev.if_type = IF_TYPE_SUNXI_FLASH;
sunxi_flash_blk_dev.part_type = PART_TYPE_DOS;
sunxi_flash_blk_dev.dev = 0;
sunxi_flash_blk_dev.lun = 0;
sunxi_flash_blk_dev.type = 0;
/* FIXME fill in the correct size (is set to 32MByte) */
sunxi_flash_blk_dev.blksz = 512;
sunxi_flash_blk_dev.lba = 0;
sunxi_flash_blk_dev.removable = 0;
sunxi_flash_blk_dev.block_read = sunxi_flash_part_read;
sunxi_flash_blk_dev.block_write = sunxi_flash_part_write;
return 0;
}
extern int sunxi_sprite_download_uboot(void *buffer, int production_media, int mode);
extern int nand_read_uboot_data(unsigned char *buf,unsigned int len);
int sunxi_flash_update_fdt(void* fdt_buf, size_t size)
{
int storage_type = 0;
void* uboot_buf = NULL;
int total_length = 0;
int new_uboot_length = 0;
struct spare_boot_head_t *uboot_head = NULL;
int ret = 0;
int uboot_length =0;
int dtb_offset = 0;
int fdt_size = size;
total_length = uboot_spare_head.boot_head.length;
uboot_length = uboot_spare_head.boot_head.uboot_length;
dtb_offset = uboot_spare_head.boot_data.dtb_offset;
new_uboot_length = ALIGN((total_length + fdt_size),uboot_spare_head.boot_head.align_size);
uboot_buf = (char*)malloc(new_uboot_length);
if(uboot_buf == NULL)
{
printf("%s: malloc fail\n", __func__);
return -1;
}
memset(uboot_buf,0,new_uboot_length);
uboot_head = (struct spare_boot_head_t *)uboot_buf;
printf("total_length = 0x%x, uboot_length = 0x%x, dtb_offset = 0x%x\n",
total_length,uboot_length,dtb_offset);
storage_type = get_boot_storage_type();
if(storage_type == STORAGE_NAND)
{
ret = nand_read_uboot_data(uboot_buf, total_length);
}
else if(storage_type == STORAGE_EMMC || storage_type == STORAGE_SD)
{
ret = sunxi_sprite_phyread(UBOOT_START_SECTOR_IN_SDMMC, total_length/512, uboot_buf);
}
else if(storage_type == STORAGE_NOR)
{
}
printf("read uboot from flash: ret %d\n",ret);
if(strncmp((const char *)uboot_head->boot_head.magic, UBOOT_MAGIC, MAGIC_SIZE))
{
printf("%s: uboot magic is error\n",__func__);
goto _UPDATE_END;
}
if(dtb_offset < uboot_length)
{
printf("first time update fdt\n");
//copy new fdt memory to the end fo uboot.fex
memcpy(uboot_buf+total_length,fdt_buf, fdt_size);
//update dtb_offset and uboot_len
uboot_head->boot_data.dtb_offset = total_length;
uboot_head->boot_head.length = new_uboot_length;
}
else
{
//just use the previous dtb_offset, and cover it
memcpy(uboot_buf+dtb_offset,fdt_buf, fdt_size);
//only need to update uboot total len
//note:dtb at the end of uboot
uboot_head->boot_head.length = ALIGN(dtb_offset+fdt_size,uboot_spare_head.boot_head.align_size);
}
ret = sunxi_sprite_download_uboot(uboot_buf,storage_type,1);
_UPDATE_END:
free(uboot_buf);
return ret;
}