/******************************************************************************* | |
* Copyright (C) 2016, ZIXC Corporation. | |
* | |
* File Name:cmd_set.c | |
* File Mark: | |
* Description: | |
* Others: | |
* Version: 1.0 | |
* Author: zangxiaofeng | |
* Date: 2013-6-8 | |
* History 1: | |
* Date: | |
* Version: | |
* Author: | |
* Modification: | |
* History 2: | |
********************************************************************************/ | |
/**************************************************************************** | |
* Include files | |
****************************************************************************/ | |
#include <common.h> | |
#include <command.h> | |
#include <net.h> | |
#include <jffs2/load_kernel.h> | |
#include <nand.h> | |
#include <linux/mtd/spi-nor.h> | |
#include <linux/mtd/nor_spifc.h> | |
#include "downloader_config.h" | |
#include "downloader_nand.h" | |
#include "downloader_serial.h" | |
#include "errno.h" | |
#include "boot_mode.h" | |
#define ZLOAD_PARTITION_SIZE 0x3000 | |
/**************************************************************************** | |
* Global Function Prototypes | |
****************************************************************************/ | |
extern partition_table_t * g_partition_table; | |
int set_partitions(unsigned int size); | |
partition_entry_t * get_partitions(const char *partname, partition_table_t *table); | |
partition_table_t * g_partition_table_dl = NULL; | |
extern char *tsp_console_buffer; | |
extern struct fsl_qspi spi_nor_flash; | |
/******************************************************************************* | |
* Function:do_set | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* | |
* Others: | |
********************************************************************************/ | |
int do_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
{ | |
char *par = NULL; | |
unsigned int size = 0; | |
unsigned int ret = 0; | |
if(argc<3) | |
{ | |
return cmd_usage(cmdtp); | |
} | |
par = argv[1]; | |
size = (unsigned int)simple_strtoul (argv[2], NULL, 16); | |
if(strcmp(par,"partitions") == 0) | |
{ | |
sprintf(tsp_console_buffer,"OKAY RECV_TABLES"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
ret = set_partitions(size); | |
return ret; | |
} | |
else | |
{ | |
sprintf(tsp_console_buffer,"FAIL COMMAND ERROR"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
return -1; | |
} | |
} | |
U_BOOT_CMD( | |
set, CONFIG_SYS_MAXARGS, 0, do_set, | |
"set : set [module] [size]", | |
"" | |
); | |
static unsigned int gen_crc(char *pInput, int InputLen) | |
{ | |
char pOutput[4]; | |
unsigned int *pcrc = (unsigned int *)pOutput; | |
int OutputLen = 4; | |
char *check = pOutput; | |
int i, j; | |
memcpy(check, pInput, OutputLen); | |
pInput += OutputLen; | |
for(i = 0; i < InputLen; i += OutputLen) | |
{ | |
for(j = 0; j < OutputLen; j++) | |
{ | |
check[j] ^= pInput[i + j]; | |
} | |
} | |
return *pcrc; | |
} | |
/******************************************************************************* | |
* Function:set_partitions | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* | |
* Others: | |
********************************************************************************/ | |
int set_partitions(unsigned int size) | |
{ | |
partition_entry_t *part_nvr = NULL; | |
partition_entry_t *part_nvr_dl = NULL; | |
partition_table_t *table_dl = NULL; | |
char *table_new = (char*)(CONFIG_USB_DMA_BUF_ADDR); /*USB DMA BUFFER*/ | |
uint32_t crc_cal = 0; | |
/* UE´ÓPC»ñÈ¡·ÖÇø±í */ | |
downloader_serial_read_actuallen((char *)table_new, size); | |
table_dl = (partition_table_t *)table_new; | |
g_partition_table_dl = kzalloc(4096, GFP_KERNEL); | |
if(g_partition_table_dl == NULL) | |
{ | |
printf("set_partitions kzalloc failed.\n"); | |
return -1; | |
} | |
/*·ÖÇø±ícrcУÑé*/ | |
crc_cal = gen_crc(((unsigned char*)table_dl) + 32, table_dl->entrys * sizeof(partition_entry_t)); | |
memcpy(g_partition_table_dl,table_dl,size); | |
if((table_dl->magic != PARTITION_MAGIC) || crc_cal != table_dl->crc) | |
{ | |
sprintf(tsp_console_buffer,"FAIL INVALID_PARTITION_TABLE"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
return -1; | |
} | |
/* ·ÖÇø±íÆ¥Åä»òûÓзÖÇø±í */ | |
if(memcmp( g_partition_table, table_dl, sizeof(partition_table_t))==0 | |
|| g_partition_table->magic != PARTITION_MAGIC) | |
{ | |
g_partition_table = g_partition_table_dl; | |
sprintf(tsp_console_buffer,"OKAY"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
return 0; | |
} | |
else | |
{ | |
/* UE´ÓPC»ñÈ¡NV·ÖÇøÐÅÏ¢ */ | |
part_nvr_dl = get_partitions("nvrofs", table_dl); | |
if(part_nvr_dl == NULL) | |
{ | |
printf("pc part nvrofs get failed.\n"); | |
return -1; | |
} | |
/* ´ÓUEµÄNAND¶ÁÈ¡NV·ÖÇøÐÅÏ¢ */ | |
part_nvr = get_partitions("nvrofs", g_partition_table); | |
if(part_nvr == NULL) | |
{ | |
printf("part_nvrofs get failed.\n"); | |
sprintf(tsp_console_buffer,"FAIL UNACCEPTABLE_PARTITION_CHANGE"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
return -1; | |
} | |
if((part_nvr->part_offset == part_nvr_dl->part_offset) | |
&&(part_nvr->part_size == part_nvr_dl->part_size)) | |
{ | |
sprintf(tsp_console_buffer,"FAIL ACCEPTABLE_PARTITION_CHANGE"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
return 0; | |
} | |
else | |
{ | |
sprintf(tsp_console_buffer,"FAIL UNACCEPTABLE_PARTITION_CHANGE"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
return -1; | |
} | |
} | |
} | |
/******************************************************************************* | |
* Function:get_partitions | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* | |
* Others: | |
********************************************************************************/ | |
partition_entry_t * get_partitions(const char *partname, partition_table_t *table) | |
{ | |
partition_entry_t *entry = &table->table[0]; | |
uint32_t entry_nums = table->entrys; | |
while( entry_nums-- ) | |
{ | |
if ( strcmp((const char *)entry->part_name,partname) == 0 ) | |
return entry; | |
entry++; | |
} | |
return NULL; | |
} | |
/******************************************************************************* | |
* Function:set_nand_dlflag | |
* Description: open or close USB DL PORT, based on nand | |
* dl on :open DL port ; dl off :close DL port | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* | |
* Others: | |
********************************************************************************/ | |
int set_nand_dlflag( char * sign) | |
{ | |
char value = 0; | |
int bootflag = 0; | |
int times = 0; | |
int i =0; | |
int ret = 0; | |
struct erase_info ei; | |
nand_info_t *nand = &nand_info[nand_curr_device]; | |
u_char *buffer = kzalloc(6*(nand->writesize + nand->oobsize),GFP_KERNEL); | |
u_char *p_buffer = buffer; | |
if( buffer == NULL ) | |
return 1; | |
times = 12*1024/nand->writesize; | |
for(i=0;i<times;i++) | |
{ | |
nand_read_page_with_ecc(nand, | |
((loff_t)i*nand->writesize), | |
0, | |
p_buffer); | |
p_buffer += nand->writesize; | |
} | |
if (strcmp((const char *)sign,"on") == 0) | |
{ | |
bootflag = 0x00; | |
memset(&value, bootflag, 1); | |
} | |
else if (strcmp((const char *)sign,"off") == 0) | |
{ | |
bootflag = 0x5a; | |
memset(&value, bootflag, 1); | |
} | |
memcpy(buffer+2, &value, 1); | |
memset(&ei, 0, sizeof(struct erase_info)); | |
ei.mtd = nand; | |
ei.addr = (uint64_t)(0); | |
ei.len = (uint64_t)nand->erasesize; | |
ret = nand->erase(nand, &ei); /*²Á³ýµÚÒ»¿é*/ | |
p_buffer = buffer; | |
for(i=0;i<times;i++) | |
{ | |
nand_write_page_with_ecc(nand, ((loff_t)i*nand->writesize), p_buffer); | |
p_buffer += nand->writesize; | |
} | |
sprintf(tsp_console_buffer,"DL OKAY"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
kfree(buffer); | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:set_nor_dlflag | |
* Description: open or close USB DL PORT, based on nand | |
* dl on :open DL port ; dl off :close DL port | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* | |
* Others: | |
********************************************************************************/ | |
int set_nor_dlflag(char *sign) | |
{ | |
int ret = 0; | |
char value = 0; | |
int bootflag = 0; | |
uint32_t load_addr = 0x0; | |
uint32_t size_read = ZLOAD_PARTITION_SIZE; | |
uint32_t size_write = ZLOAD_PARTITION_SIZE; | |
struct fsl_qspi *nor = &spi_nor_flash; | |
u_char *buffer = kzalloc(ZLOAD_PARTITION_SIZE,GFP_KERNEL); | |
if(buffer == NULL) | |
{ | |
return -1; | |
} | |
ret = nand_read(&(nor->nor[0].mtd), load_addr, &size_read, buffer); | |
if(ret != 0) | |
{ | |
printf("nand_read error.\n"); | |
return -1; | |
} | |
if (strcmp((const char *)sign,"on") == 0) | |
{ | |
bootflag = 0x00; | |
memset(&value, bootflag, 1); | |
} | |
else if (strcmp((const char *)sign,"off") == 0) | |
{ | |
bootflag = 0x5a; | |
memset(&value, bootflag, 1); | |
} | |
memcpy(buffer+2, &value, 1); | |
ret = nand_erase(&(nor->nor[0].mtd), load_addr, nor->nor[0].mtd.erasesize); | |
if(ret != 0) | |
{ | |
printf("nand_erase error.\n"); | |
return -1; | |
} | |
ret = nand_write(&(nor->nor[0].mtd), load_addr, &size_write, buffer); | |
if(ret != 0) | |
{ | |
printf("nand_write error.\n"); | |
return -1; | |
} | |
sprintf(tsp_console_buffer,"DL OKAY"); | |
downloader_serial_write(tsp_console_buffer, strlen(tsp_console_buffer)+1); | |
kfree(buffer); | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:do_dlflag | |
* Description: open or close USB DL PORT, | |
* dl on :open DL port ; dl off :close DL port | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* | |
* Others: | |
********************************************************************************/ | |
int do_dlflag(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
{ | |
int ret = 0; | |
u_char *sign = NULL; | |
int type = 0; | |
if(argc<2) | |
{ | |
return cmd_usage(cmdtp); | |
} | |
sign = argv[1]; | |
type = read_boot_flashtype(); | |
if(type == IF_TYPE_NAND || type == IF_TYPE_SPI_NAND) | |
{ | |
ret = set_nand_dlflag(sign); | |
} | |
else if(type == IF_TYPE_NOR) | |
{ | |
ret = set_nor_dlflag(sign); | |
} | |
if(ret != 0) | |
{ | |
return -1; | |
} | |
return 0; | |
} | |
U_BOOT_CMD( | |
dl, CONFIG_SYS_MAXARGS, 0, do_dlflag, | |
"dl : dl [sign]", | |
"" | |
); |