blob: 93950b1a799c786b5dc06f7680feadedd3ff096c [file] [log] [blame]
/*******************************************************************************
* 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 0x10000
/****************************************************************************
* 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;
extern int g_iftype;
/*******************************************************************************
* 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];
if(g_nor_flag == 1)
{
g_iftype = IF_TYPE_NOR;
nand_init();
ret = set_nor_dlflag(sign);
/*Çл»³õʼ»¯spi_nand*/
g_iftype = IF_TYPE_SPI_NAND;
nand_init();
}
else
{
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]",
""
);