| /******************************************************************************* | |
| * 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]", | |
| "" | |
| ); |