diff options
60 files changed, 18873 insertions, 963 deletions
diff --git a/board/amlogic/gxb_p200_v1/gxb_p200_v1.c b/board/amlogic/gxb_p200_v1/gxb_p200_v1.c index 1d5d0804e0..75de877e93 100644 --- a/board/amlogic/gxb_p200_v1/gxb_p200_v1.c +++ b/board/amlogic/gxb_p200_v1/gxb_p200_v1.c @@ -31,6 +31,9 @@ #ifdef CONFIG_VPU_PRESET #include <vpu.h> #endif +#ifdef CONFIG_AML_V2_FACTORY_BURN +#include <amlogic/aml_v2_burning.h> +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN DECLARE_GLOBAL_DATA_PTR; @@ -320,6 +323,12 @@ struct amlogic_usb_config g_usb_config_gx_skt_h={ int board_init(void) { +#ifdef CONFIG_AML_V2_FACTORY_BURN + aml_try_factory_usb_burning(0, gd->bd); +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN + + /*Power on GPIOAO_2 for VCC_5V*/ + clrbits_le32(P_AO_GPIO_O_EN_N, ((1<<2)|(1<<18))); #ifdef CONFIG_USB_DWC_OTG_HCD board_usb_init(&g_usb_config_gx_skt_a,BOARD_USB_MODE_HOST); board_usb_init(&g_usb_config_gx_skt_b,BOARD_USB_MODE_HOST); @@ -335,6 +344,11 @@ int board_init(void) int board_late_init(void){ /*add board late init function here*/ run_command("setenv fdt_high 0x20000000", 1); + +#ifdef CONFIG_AML_V2_FACTORY_BURN + aml_try_factory_sdcard_burning(0, gd->bd); +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN + return 0; } #endif diff --git a/board/amlogic/gxb_p201_v1/gxb_p201_v1.c b/board/amlogic/gxb_p201_v1/gxb_p201_v1.c index 12ed3a910e..dc7e6a2d0e 100644 --- a/board/amlogic/gxb_p201_v1/gxb_p201_v1.c +++ b/board/amlogic/gxb_p201_v1/gxb_p201_v1.c @@ -31,6 +31,9 @@ #ifdef CONFIG_VPU_PRESET #include <vpu.h> #endif +#ifdef CONFIG_AML_V2_FACTORY_BURN +#include <amlogic/aml_v2_burning.h> +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN DECLARE_GLOBAL_DATA_PTR; @@ -320,6 +323,10 @@ struct amlogic_usb_config g_usb_config_gx_skt_h={ int board_init(void) { +#ifdef CONFIG_AML_V2_FACTORY_BURN + aml_try_factory_usb_burning(0, gd->bd); +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN + /*Power on GPIOAO_2 for VCC_5V*/ clrbits_le32(P_AO_GPIO_O_EN_N, ((1<<2)|(1<<18))); #ifdef CONFIG_USB_DWC_OTG_HCD @@ -341,6 +348,11 @@ int board_init(void) int board_late_init(void){ /*add board late init function here*/ run_command("setenv fdt_high 0x20000000", 1); + +#ifdef CONFIG_AML_V2_FACTORY_BURN + aml_try_factory_sdcard_burning(0, gd->bd); +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN + return 0; } #endif diff --git a/board/amlogic/gxb_skt_v1/gxb_skt_v1.c b/board/amlogic/gxb_skt_v1/gxb_skt_v1.c index 4f1b64da8e..56bc0881ba 100644 --- a/board/amlogic/gxb_skt_v1/gxb_skt_v1.c +++ b/board/amlogic/gxb_skt_v1/gxb_skt_v1.c @@ -32,6 +32,9 @@ #ifdef CONFIG_VPU_PRESET #include <vpu.h> #endif +#ifdef CONFIG_AML_V2_FACTORY_BURN +#include <amlogic/aml_v2_burning.h> +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN DECLARE_GLOBAL_DATA_PTR; @@ -321,6 +324,10 @@ struct amlogic_usb_config g_usb_config_gx_skt_h={ int board_init(void) { +#ifdef CONFIG_AML_V2_FACTORY_BURN + aml_try_factory_usb_burning(0, gd->bd); +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN + #ifdef CONFIG_USB_DWC_OTG_HCD //setbits_le32(PREG_PAD_GPIO0_EN_N, 1<<24); //setbits_le32(PREG_PAD_GPIO0_O, 1<<24); @@ -338,6 +345,11 @@ int board_init(void) int board_late_init(void){ /*add board late init function here*/ run_command("setenv fdt_high 0x20000000", 1); + +#ifdef CONFIG_AML_V2_FACTORY_BURN + aml_try_factory_sdcard_burning(0, gd->bd); +#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN + return 0; } #endif diff --git a/common/Makefile b/common/Makefile index f52c46fa83..5b8d897eae 100644 --- a/common/Makefile +++ b/common/Makefile @@ -133,6 +133,8 @@ obj-$(CONFIG_CMD_MII) += cmd_mdio.o endif obj-$(CONFIG_CMD_MISC) += cmd_misc.o obj-$(CONFIG_CMD_MMC) += cmd_mmc.o +obj-$(CONFIG_CMD_MMC) += cmd_aml_mmc.o +obj-$(CONFIG_STORE_COMPATIBLE) += store_interface.o cmd_burnup.o obj-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o obj-$(CONFIG_MP) += cmd_mp.o obj-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o diff --git a/common/cmd_aml_mmc.c b/common/cmd_aml_mmc.c new file mode 100644 index 0000000000..68db30f6f5 --- /dev/null +++ b/common/cmd_aml_mmc.c @@ -0,0 +1,623 @@ +/* + * (C) Copyright 2003 + * Kyle Harris, kharris@nexus-tech.net + * + * 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 <malloc.h> +#include <command.h> +#include <linux/ctype.h> +#include <mmc.h> +#include <partition_table.h> +#include <emmc_partitions.h> + +extern int find_dev_num_by_partition_name (char *name); +bool emmckey_is_protected (struct mmc *mmc) +{ + return 0; +} + +unsigned emmc_cur_partition = 0; + +static int get_off_size(struct mmc * mmc, char * name, uint64_t offset, uint64_t size, u64 * blk, u64 * cnt, u64 * sz_byte) +{ + struct partitions *part_info = NULL; + uint64_t off = 0; + int blk_shift = 0; + + blk_shift = ffs(mmc->read_bl_len) - 1; + // printf("blk_shift:%d , off:0x%llx , size:0x%llx.\n ",blk_shift,off,size ); + part_info = find_mmc_partition_by_name(name); + if (part_info == NULL) { + printf("get partition info failed !!\n"); + return -1; + } + off = part_info->offset + offset; + + // printf("part_info->offset:0x%llx , off:0x%llx , size:0x%llx.\n",part_info->offset ,off,size); + + *blk = off >> blk_shift ; + *cnt = size >> blk_shift ; + *sz_byte = size - ((*cnt)<<blk_shift) ; + + // printf("get_partition_off_size : blk:0x%llx , cnt:0x%llx.\n",*blk,*cnt); + return 0; +} + +static int get_partition_size(unsigned char* name, uint64_t* addr) +{ + struct partitions *part_info = NULL; + part_info = find_mmc_partition_by_name((char *)name); + if (part_info == NULL) { + printf("get partition info failed !!\n"); + return -1; + } + + *addr = part_info->size >> 9; // unit: 512 bytes + return 0; +} + +static inline int isstring(char *p) +{ + char *endptr = p; + while (*endptr != '\0') { + if (!(((*endptr >= '0') && (*endptr <= '9')) + || ((*endptr >= 'a') && (*endptr <= 'f')) + || ((*endptr >= 'A') && (*endptr <= 'F')) + || (*endptr == 'x') || (*endptr == 'X'))) + return 1; + endptr++; + } + + return 0; +} + + +int do_amlmmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + /*printf("%s:%d\n",__func__,__LINE__);*/ + /*printf("argc = %d\n",argc);*/ + switch (argc) { + case 3: + if (strcmp(argv[1], "rescan") == 0) { + int dev = simple_strtoul(argv[2], NULL, 10); + if (dev < 0) { + printf("Cannot find dev.\n"); + return 1; + } + struct mmc *mmc = find_mmc_device(dev); + + if (!mmc) + return 1; + + return mmc_init(mmc); + } else if (strncmp(argv[1], "part", 4) == 0) { + int dev = simple_strtoul(argv[2], NULL, 10); + block_dev_desc_t *mmc_dev; + struct mmc *mmc = find_mmc_device(dev); + + if (!mmc) { + puts("no mmc devices available\n"); + return 1; + } + mmc_init(mmc); + mmc_dev = mmc_get_dev(dev); + if (mmc_dev != NULL && + mmc_dev->type != DEV_TYPE_UNKNOWN) { + print_part(mmc_dev); + return 0; + } + + puts("get mmc type error!\n"); + return 1; + } else if (strcmp(argv[1], "erase") == 0) { + char *name = NULL; + int dev; + u32 n=0; + bool is_part = false;//is argv[2] partition name + bool protect_cache = false; + bool non_loader = false; + int blk_shift; + u64 cnt=0, blk =0,start_blk =0; + struct partitions *part_info; + + if (isstring(argv[2])) { + if (!strcmp(argv[2], "whole")) { + name = "logo"; + dev = find_dev_num_by_partition_name (name); + }else if(!strcmp(argv[2], "non_cache")){ + name = "logo"; + dev = find_dev_num_by_partition_name (name); + protect_cache = true; + } + else if(!strcmp(argv[2], "non_loader")){ + dev = 1; + non_loader = true; + } + else{ + name = argv[2]; + dev = find_dev_num_by_partition_name (name); + is_part = true; + } + }else if(isdigit(argv[2][0])){ + dev = simple_strtoul(argv[2], NULL, 10); + }else{ + printf("Input is invalid, nothing happen.\n"); + return 1; + } + + if (dev < 0) { + printf("Cannot find dev.\n"); + return 1; + } + struct mmc *mmc = find_mmc_device(dev); + + if (!mmc) + return 1; + + mmc_init(mmc); + + blk_shift = ffs(mmc->read_bl_len) -1; + if (is_part) { // erase only one partition + if (emmckey_is_protected(mmc) + && (strncmp(name, MMC_RESERVED_NAME, sizeof(MMC_RESERVED_NAME)) == 0x00)) { + printf("\"%s-partition\" is been protecting and should no be erased!\n", MMC_RESERVED_NAME); + return 1; + } + + part_info = find_mmc_partition_by_name(name); + if (part_info == NULL) { + return 1; + } + + blk = part_info->offset>> blk_shift; + if (emmc_cur_partition && !strncmp(name, "bootloader", strlen("bootloader"))) { + + cnt = mmc->boot_size>> blk_shift; + } + else + cnt = part_info->size>> blk_shift; + n = mmc->block_dev.block_erase(dev, blk, cnt); + } else { // erase the whole card if possible + + if (non_loader) { + part_info = find_mmc_partition_by_name(MMC_BOOT_NAME); + if (part_info == NULL) { + start_blk = 0; + printf("no uboot partition for eMMC boot, just erase from 0\n"); + } + else{ + start_blk = (part_info->offset + part_info->size) >> blk_shift; + } + } + else{ + start_blk = 0; + } + + if (emmckey_is_protected(mmc)) { + part_info = find_mmc_partition_by_name(MMC_RESERVED_NAME); + if (part_info == NULL) { + return 1; + } + + blk = part_info->offset; + if (blk > 0) { // it means: there should be other partitions before reserve-partition. + blk -= PARTITION_RESERVED; + } + blk >>= blk_shift; + + n=0; + + // (1) erase all the area before reserve-partition + if (blk > 0) { + n = mmc->block_dev.block_erase(dev, start_blk, blk); + // printf("(1) erase blk: 0 --> %llx %s\n", blk, (n == 0) ? "OK" : "ERROR"); + } + if (n == 0) { // not error + // (2) erase all the area after reserve-partition + if (protect_cache) { + part_info = find_mmc_partition_by_name(MMC_CACHE_NAME); + if (part_info == NULL) { + return 1; + } + } + start_blk = (part_info->offset + part_info->size + PARTITION_RESERVED) >> blk_shift; + u64 erase_cnt = (mmc->capacity >> blk_shift) - 1 - start_blk; + n = mmc->block_dev.block_erase(dev, start_blk, erase_cnt); + // printf("(2) erase blk: %#llx --> %#llx %s\n", start_blk, start_blk+erase_cnt, (n == 0) ? "OK" : "ERROR"); + } + + } else { + n = mmc->block_dev.block_erase(dev, start_blk, 0); // erase the whole card + } + + //erase boot partition + if (mmc->boot_size && (n == 0) && (non_loader == false)) { + + for (cnt=0;cnt<2;cnt++) { + rc = mmc_switch_part(dev, cnt+1); + if (rc != 0) { + printf("mmc switch %s failed\n", (cnt == 0)?"boot0":"boot1"); + break; + } + + n = mmc->block_dev.block_erase(dev, 0, mmc->boot_size>>blk_shift); + if (n != 0) { + printf("mmc erase %s failed\n", (cnt == 0)?"boot0":"boot1"); + break; + } + } + + rc = mmc_switch_part(dev, 0); + if (rc != 0) { + printf("mmc switch back to user failed\n"); + } + } + } + + // printf("dev # %d, %s, # %#llx blocks erased %s\n", + // dev, (is_part == 0) ? "card":(argv[2]) , + // (cnt == 0) ? (int)(mmc->block_dev.lba): cnt , + // (n == 0) ? "OK" : "ERROR"); + return (n == 0) ? 0 : 1; + } else { + return cmd_usage(cmdtp); + } + + case 0: + case 1: + case 4: + if (strcmp(argv[1], "switch") == 0) { + int dev = simple_strtoul(argv[2], NULL, 10); + struct mmc* mmc = find_mmc_device(dev); + if (!mmc) { + puts("no mmc devices available\n"); + return 1; + } + mmc_init(mmc); + if (strcmp(argv[3], "boot0") == 0) { + rc = mmc_switch_part(dev, 1); + if (rc == 0) + emmc_cur_partition = 1; + } + else if(strcmp(argv[3], "boot1")==0){ + rc = mmc_switch_part(dev, 2); + if (rc == 0) + emmc_cur_partition = 2; + } + else if(strcmp(argv[3], "user")==0){ + rc = mmc_switch_part(dev, 0); + if (rc == 0) + emmc_cur_partition = 0; + } + return rc; + } + + if (strcmp(argv[1], "size") == 0) { + char *name; + uint64_t* addr =NULL; + name = argv[2]; + addr = (uint64_t *)simple_strtoul(argv[3], NULL, 16); + return get_partition_size((unsigned char *)name, addr); + } + + return cmd_usage(cmdtp); + + case 2: + if (!strcmp(argv[1], "list")) { + print_mmc_devices('\n'); + return 0; + } + + if (strcmp(argv[1], "env") == 0) { + printf("herh\n"); + env_relocate(); + return 0 ; + } + +#ifdef CONFIG_SECURITYKEY + if (strcmp(argv[1], "key") == 0) { + struct mmc* mmc; + char *name = "logo"; + int dev = find_dev_num_by_partition_name (name); + mmc = find_mmc_device(dev); + if (!mmc) { + printf("device %d is invalid\n",dev); + return 1; + } + mmc->key_protect = 0; +#ifdef CONFIG_STORE_COMPATIBLE + info_disprotect |= DISPROTECT_KEY; //disprotect +#endif + return 0; + } +#endif + return cmd_usage(cmdtp); + + default: /* at least 5 args */ + if (strcmp(argv[1], "read") == 0) { + int dev; + void *addr =NULL; + u32 flag =0; + u64 cnt =0,n =0, blk =0, sz_byte =0; + char *name=NULL; + u64 offset =0,size =0; + + if (argc != 6) { + printf("Input is invalid, nothing happen.\n"); + return 1; + } + + if (isstring(argv[2])) { + name = argv[2]; + dev = find_dev_num_by_partition_name (name); + addr = (void *)simple_strtoul(argv[3], NULL, 16); + size = simple_strtoull(argv[5], NULL, 16); + offset = simple_strtoull(argv[4], NULL, 16); + /*printf("offset %llx size %llx\n",offset,size);*/ + flag = 1; + if ((strcmp(argv[2], "card") == 0)) { + flag = 2; + } + }else{ + dev = simple_strtoul(argv[2], NULL, 10); + addr = (void *)simple_strtoul(argv[3], NULL, 16); + cnt = simple_strtoull(argv[5], NULL, 16); + blk = simple_strtoull(argv[4], NULL, 16); + } + if (dev < 0) { + printf("Cannot find dev.\n"); + return 1; + } + struct mmc *mmc = find_mmc_device(dev); + if (!mmc) { + printf("dev = %d;, no mmc device found",dev); + return 1; + } + + if (flag == 1) { // emmc or tsd + /*printf("offset %#llx size %#llx\n",offset,size);*/ + get_off_size(mmc, name, offset, size, &blk, &cnt, &sz_byte); + } + else if(flag == 2){ // card + int blk_shift = ffs( mmc->read_bl_len) -1; + cnt = size >> blk_shift; + blk = offset >> blk_shift; + sz_byte = size - (cnt<<blk_shift); + } + + + /*printf("MMC read: dev # %d, block # %#llx, count # %#llx ...\n",*/ + /*dev, blk, cnt);*/ + mmc_init(mmc); + + n = mmc->block_dev.block_read(dev, blk, cnt, addr); + //read sz_byte bytes + if ((n == cnt) && (sz_byte != 0)) { + /*printf("sz_byte=%#llx bytes\n",sz_byte);*/ + void *addr_tmp = malloc(mmc->read_bl_len); + void *addr_byte = (void *)(addr+cnt*(mmc->read_bl_len)); + ulong start_blk = blk+cnt; + + if (addr_tmp == NULL) { + printf("mmc read: malloc fail\n"); + return 1; + } + + if (mmc->block_dev.block_read(dev, start_blk, 1, addr_tmp) != 1) { // read 1 block + free(addr_tmp); + printf("mmc read 1 block fail\n"); + return 1; + } + + memcpy(addr_byte, addr_tmp, sz_byte); + free(addr_tmp); + } + + /* flush cache after read */ + //flush_cache((ulong)addr, cnt * 512); /* FIXME */ + + if (n != cnt) { + printf("MMC read: dev # %d, block # %#llx, count # %#llx, byte_size # %#llx ERROR!\n", + dev, blk, cnt, sz_byte); + printf("%#llx blocks read: %s\n", + n, (n==cnt) ? "OK" : "ERROR"); + } + return (n == cnt) ? 0 : 1; + } else if (strcmp(argv[1], "write") == 0) { + int dev; + void *addr =NULL; + u32 flag =0; + u64 cnt =0,n =0, blk =0,sz_byte =0; + char *name=NULL; + u64 offset =0,size =0; + + if (argc != 6) { + printf("Input is invalid, nothing happen.\n"); + return 1; + } + + if (isstring(argv[2])) { + name = argv[2]; + dev = find_dev_num_by_partition_name (name); + addr = (void *)simple_strtoul(argv[3], NULL, 16); + offset = simple_strtoull(argv[4], NULL, 16); + size = simple_strtoull(argv[5], NULL, 16); + flag = 1; + if ((strcmp(argv[2], "card") == 0)) { + flag = 2; + } + }else{ + dev = simple_strtoul(argv[2], NULL, 10); + addr = (void *)simple_strtoul(argv[3], NULL, 16); + blk = simple_strtoull(argv[4], NULL, 16); + cnt = simple_strtoull(argv[5], NULL, 16); + } + if (dev < 0) { + printf("Cannot find dev.\n"); + return 1; + } + struct mmc *mmc = find_mmc_device(dev); + + if (flag == 1) { // tsd or emmc + get_off_size(mmc, name, offset, size, &blk, &cnt, &sz_byte); + } + else if(flag == 2){ // card + int blk_shift = ffs( mmc->read_bl_len) -1; + cnt = size >> blk_shift; + blk = offset >> blk_shift; + sz_byte = size - (cnt<<blk_shift); + } + + if (!mmc) + return 1; + + // printf("MMC write: dev # %d, block # %#llx, count # %#llx ... ", + // dev, blk, cnt); + + mmc_init(mmc); + + n = mmc->block_dev.block_write(dev, blk, cnt, addr); + + //write sz_byte bytes + if ((n == cnt) && (sz_byte != 0)) { + // printf("sz_byte=%#llx bytes\n",sz_byte); + void *addr_tmp = malloc(mmc->write_bl_len); + void *addr_byte = (void*)(addr+cnt*(mmc->write_bl_len)); + ulong start_blk = blk+cnt; + + if (addr_tmp == NULL) { + printf("mmc write: malloc fail\n"); + return 1; + } + + if (mmc->block_dev.block_read(dev, start_blk, 1, addr_tmp) != 1) { // read 1 block + free(addr_tmp); + printf("mmc read 1 block fail\n"); + return 1; + } + + memcpy(addr_tmp, addr_byte, sz_byte); + if (mmc->block_dev.block_write(dev, start_blk, 1, addr_tmp) != 1) { // write 1 block + free(addr_tmp); + printf("mmc write 1 block fail\n"); + return 1; + } + free(addr_tmp); + } + + if (cnt != n) { + printf("%#llx blocks , %#llx bytes written: ERROR\n", n, sz_byte); + } + return (n == cnt) ? 0 : 1; + } + else if (strcmp(argv[1], "erase") == 0) { + + int dev=0; + u32 flag=0; + u64 cnt = 0, blk = 0, n = 0, sz_byte =0; + char *name=NULL; + u64 offset_addr =0, size=0; + + if (argc != 5) { + printf("Input is invalid, nothing happen.\n"); + return 1; + } + + if (isstring(argv[2])) { + name = argv[2]; + dev = find_dev_num_by_partition_name (name); + offset_addr = simple_strtoull(argv[3], NULL, 16); + size = simple_strtoull(argv[4], NULL, 16); + flag = 1; + if ((strcmp(argv[2], "card") == 0)) { + flag = 2; + } + }else if(isdigit(argv[2][0])){ + dev = simple_strtoul(argv[2], NULL, 10); + blk = simple_strtoull(argv[3], NULL, 16); + cnt = simple_strtoull(argv[4], NULL, 16); + } + + if (dev < 0) { + printf("Cannot find dev.\n"); + return 1; + } + + struct mmc *mmc = find_mmc_device(dev); + + if (flag == 1) { // mmc write logo add offset size + struct partitions *part_info = find_mmc_partition_by_name(name); + + if (offset_addr >= part_info->size) { + printf("Start address out #%s# partition'address region,(addr_byte < 0x%llx)\n", + name, part_info->size); + return 1; + } + if ((offset_addr+size) > part_info->size) { + printf("End address exceeds #%s# partition,(offset = 0x%llx,size = 0x%llx)\n", + name, part_info->offset,part_info->size); + return 1; + } + get_off_size(mmc, name, offset_addr, size, &blk, &cnt, &sz_byte); + } + else if(flag == 2){ + int tmp_shift = ffs( mmc->read_bl_len) -1; + cnt = size >> tmp_shift; + blk = offset_addr >> tmp_shift; + sz_byte = size - (cnt<<tmp_shift); + } + + if (!mmc) + return 1; + + printf("MMC erase: dev # %d, start_erase_address(in block) # %#llx, several blocks # %lld will be erased ...\n ", + dev, blk, cnt); + + mmc_init(mmc); + + if (cnt != 0) + n = mmc->block_dev.block_erase(dev, blk, cnt); + + printf("dev # %d, %s, several blocks erased %s\n", + dev, (flag == 0) ? " ":(argv[2]),(n == cnt) ? "OK" : "ERROR"); + + return (n == cnt) ? 0 : 1; + + } else + rc = cmd_usage(cmdtp); + + return rc; + } +} + +U_BOOT_CMD( + amlmmc, 6, 1, do_amlmmcops, + "AMLMMC sub system", + "amlmmc read <partition name> ram_addr addr_byte# cnt_byte\n" + "amlmmc write <partition name> ram_addr addr_byte# cnt_byte\n" + "amlmmc erase <partition name> addr_byte# cnt_byte\n" + "amlmmc erase <partition name>/<device num>\n" + "amlmmc rescan <device num>\n" + "amlmmc part <device num> - show partition infomation of mmc\n" + "amlmmc list - lists available devices\n" + "amlmmc switch <device num> <part name> - part name : boot0, boot1, user"); diff --git a/common/cmd_burnup.c b/common/cmd_burnup.c new file mode 100644 index 0000000000..c5e39157fe --- /dev/null +++ b/common/cmd_burnup.c @@ -0,0 +1,359 @@ +#include <command.h> +#include <watchdog.h> +#include <malloc.h> +#include <common.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <div64.h> +#include <linux/err.h> +#include <partition_table.h> + +unsigned char *cmd_name = (unsigned char *)("store"); + +/*** +upgrade_read_ops: + +partition_name: env / logo / recovery /boot / system /cache /media + + ***/ + +int store_read_ops(unsigned char *partition_name,unsigned char * buf, uint64_t off, uint64_t size) +{ + unsigned char *name; + uint64_t addr; + char str[128]; + int ret =0; + + if (!buf) { + store_msg("upgrade: no buf!!"); + return -1; + } + + name = partition_name; + addr = (unsigned long)buf; + + sprintf(str, "%s read %s 0x%llx 0x%llx 0x%llx",cmd_name, name, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s failed ",cmd_name); + return -1; + } + + return 0; +} + +/*** +upgrade_write_ops: + +partition_name: env / logo / recovery /boot / system /cache /media + + ***/ + +int store_write_ops(unsigned char *partition_name,unsigned char * buf, uint64_t off, uint64_t size) +{ + unsigned char *name; + uint64_t addr; + char str[128]; + int ret =0; + + if (!buf) { + store_msg("upgrade: no buf!!"); + return -1; + } + + name = partition_name; + addr = (unsigned long)buf; + + sprintf(str, "%s write %s 0x%llx 0x%llx 0x%llx",cmd_name, name, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s failed ",cmd_name); + return -1; + } + + return 0; +} + + +/*** +upgrade_write_ops: + +partition_name: env / logo / recovery /boot / system /cache /media + + ***/ + +int store_get_partititon_size(unsigned char *partition_name, uint64_t *size) +{ + unsigned char *name; + char str[128]; + uint64_t addr; + int ret=0; + unsigned char * buf = malloc(4*sizeof(uint64_t)); + + if (!buf) { + store_msg("store_get_partititon_size : malloc failed"); + return -1; + } + memset(buf,0x0,4*sizeof(uint64_t)); + store_dbg("4*sizeof(uint64_t) =%ld",4*sizeof(uint64_t)); + addr = (unsigned long)size; + name = partition_name; + sprintf(str, "%s size %s 0x%llx ",cmd_name, name, addr); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s size failed ",cmd_name); + return -1; + } + + + + if (buf) { + kfree(buf); + } + return 0; +} + + +/*** +upgrade_erase_ops: + +partition_name: boot / data + +flag = 0; indicate erase partition ; +flag = 1; indicate scurb whole nand; + + ***/ +int store_erase_ops(unsigned char *par_name, uint64_t off, uint64_t size, unsigned char flag) +{ + unsigned char *name; + char str[128]; + int ret=0; + + name = par_name; + if (flag == 0) { + sprintf(str, "%s erase %s 0x%llx 0x%llx",cmd_name, name, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s erase failed",cmd_name); + return -1; + } + + }else if(flag == 1){ + + sprintf(str, "%s rom_protect off ",cmd_name); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s scrub failed ",cmd_name); + return -1; + } + + sprintf(str, "%s scrub 0x%llx ",cmd_name, (long long unsigned int)0); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s scrub failed",cmd_name); + return -1; + } + } + + return 0; +} + +/*** +bootloader: + ***/ +int store_boot_read(unsigned char * buf, uint64_t off, uint64_t size) +{ + //unsigned char *name; + uint64_t addr; + char str[128]; + int ret =0; + + if (!buf) { + store_msg("upgrade: no buf!!"); + return -1; + } + + addr = (unsigned long)buf; + store_dbg("store_boot_read: addr 0x%llx\n",addr); + + sprintf(str, "%s rom_read 0x%llx 0x%llx 0x%llx",cmd_name, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s rom_read failed",cmd_name); + return -1; + } + + return 0; + +} + +int store_boot_write(unsigned char * buf,uint64_t off, uint64_t size) +{ + //unsigned char *name; + uint64_t addr; + char str[128]; + int ret =0; + + if (!buf) { + store_msg("upgrade: no buf!!"); + return -1; + } + + addr = (unsigned long)buf; + + sprintf(str, "%s rom_write 0x%llx 0x%llx 0x%llx",cmd_name, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s rom_write failed",cmd_name); + return -1; + } + + return 0; + +} + + +int store_init(unsigned flag) +{ + //unsigned char *name; + //unsigned long addr; + char str[128]; + int ret =0; + store_dbg("flag : %d",flag); + + sprintf(str, "%s init %d",cmd_name,flag); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd [%s] init failed ",cmd_name); + return -1; + } + + return 0; +} + +int store_exit(void) +{ + //unsigned char *name; + //unsigned long addr; + char str[128]; + int ret =0; + + sprintf(str, "%s exit",cmd_name); + printf("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("cmd %s exit failed",cmd_name); + return -1; + } + + return 0; + +} + +#if 0 +int do_store_test(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int i, init_flag=0,dev, ret = 0; + ulong addr; + uint64_t off, size; + char *cmd, *s, *area; + char str[128]; + unsigned char *buf; + + cmd = argv[1]; + + buf = malloc(0x400000); + if (!buf) { + printf("do_store_test : malloc failed\n"); + return -1; + } + + area ="logo"; + + if (strcmp(cmd, "read") == 0) { + ret = store_read_ops(area,buf,0x0,0x40000); + if (ret < 0) { + printf("store read failed\n"); + return -1; + } + printf("store read OK\n"); + } + + if (strcmp(cmd, "boot_read") == 0) { + ret = store_boot_read(buf,0x0,0x60000); + if (ret < 0) { + printf("store boot_read failed\n"); + return -1; + } + printf("store boot_read OK\n"); + } + + if (strcmp(cmd, "init") == 0) { + ret = store_init(0x0); + if (ret < 0) { + printf("store init failed\n"); + return -1; + } + printf("store init OK\n"); + } + + if (strcmp(cmd, "write") == 0) { + memset(buf,0xa5,0x400000); + ret = store_write_ops(area,buf,0x0,0x40000); + if (ret < 0) { + printf("store write failed\n"); + return -1; + } + printf("store write OK\n"); + } + + if (strcmp(cmd, "erase") == 0) { + area = "data"; + ret = store_erase_ops(area,0x0,0,0); + if (ret < 0) { + printf("store write failed\n"); + return -1; + } + } + + if (strcmp(cmd, "size") == 0) { + uint64_t off=0, size; + + ret = store_get_partititon_size(area,&size); + if (ret < 0) { + printf("store write failed\n"); + return -1; + } + printf("off =%llx size=%llx\n",off,size); + } + + if (buf) + kfree(buf); + return 0; + +} + +U_BOOT_CMD(store_test, CONFIG_SYS_MAXARGS, 1, do_store_test, + "NAND sub-system", + "store read name addr off|partition size\n" + " read 'size' bytes starting at offset 'off'\n" + " to/from memory address 'addr', skipping bad blocks.\n" + "store write name addr off|partition size\n" + " write 'size' bytes starting at offset 'off'\n" + " to/from memory address 'addr', skipping bad blocks.\n" + "store erase boot/data: \n" + "erase the area which is uboot or datas \n" + "store scrub off|partition size\n" + "scrub the area from offset and size \n" + ); +#endif + diff --git a/common/store_interface.c b/common/store_interface.c index 84e0470fa5..2e8bb6c960 100644 --- a/common/store_interface.c +++ b/common/store_interface.c @@ -20,7 +20,7 @@ #define STORE_BOOT_SCRUB_ALL 4 #define _SPI_FLASH_ERASE_SZ (CONFIG_ENV_IN_SPI_OFFSET + CONFIG_ENV_SIZE) - +#define CONFIG_ENV_IN_SPI_OFFSET 0 //Ignore mbr since mmc driver already handled //#define MMC_UBOOT_CLEAR_MBR #define MMC_BOOT_PARTITION_SUPPORT @@ -29,9 +29,9 @@ static char _mbrFlag[4] ; #endif -extern void get_device_boot_flag(void); +//extern void get_device_boot_flag(void); static int _info_disprotect_back_before_mmcinfo1 = 0;//mmcinfo 1 will clear info_disprotect before run_command("mmc erase 1") -int info_disprotect = 0; +extern int info_disprotect; static inline int isstring(char *p) { char *endptr = p; @@ -81,846 +81,850 @@ static inline int str2longlong(char *p, unsigned long long *num) static int get_off_size(int argc, char *argv[], loff_t *off, loff_t *size) { - if (argc >= 1) { - if (!(str2longlong(argv[0], (unsigned long long*)off))) { + if (argc >= 1) { + if (!(str2longlong(argv[0], (unsigned long long*)off))) { store_msg("'%s' is not a number\n", argv[0]); - return -1; + return -1; + } + } else { + *off = 0; + *size = 0; } - } else { - *off = 0; - *size = 0; - } - if (argc >= 2) { - if (!(str2longlong(argv[1], (unsigned long long *)size))) { - store_msg("'%s' is not a number\n", argv[1]); - return -1; + if (argc >= 2) { + if (!(str2longlong(argv[1], (unsigned long long *)size))) { + store_msg("'%s' is not a number\n", argv[1]); + return -1; + } + }else{ + *size = 0; } - }else{ - *size = 0; - } - store_dbg("offset 0x%llx, size 0x%llx", *off, *size); + store_dbg("offset 0x%llx, size 0x%llx", *off, *size); - return 0; + return 0; } int do_store(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { - int i, init_flag=0, ret = 0; - uint64_t addr; - loff_t off=0, size=0; - char *cmd, *s, *area; - char str[128]; - unsigned char *tmp_buf= NULL; - - if (argc < 2) - goto usage; - - cmd = argv[1]; - - if (strcmp(cmd, "erase") == 0) { - - area = argv[2]; - - if (strcmp(area, "boot") == 0) { - if (device_boot_flag == NAND_BOOT_FLAG) { - off = simple_strtoul(argv[3], NULL, 16); - size = simple_strtoul(argv[4], NULL, 16); - store_dbg("NAND BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); - - ret = run_command("amlnf deverase boot 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - return ret; - }else if((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)){ - off = simple_strtoul(argv[3], NULL, 16); - size = simple_strtoul(argv[4], NULL, 16); - - store_dbg("SPI BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__,off,size); - - ret = run_command("sf probe 2",0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } + int i, init_flag=0, ret = 0; + uint64_t addr; + loff_t off=0, size=0; + char *cmd, *s, *area; + char str[128]; + //unsigned char *tmp_buf = NULL; + + if (argc < 2) + goto usage; + + cmd = argv[1]; + + if (strcmp(cmd, "erase") == 0) { + + area = argv[2]; + + if (strcmp(area, "boot") == 0) { + if (device_boot_flag == NAND_BOOT_FLAG) { + off = simple_strtoul(argv[3], NULL, 16); + size = simple_strtoul(argv[4], NULL, 16); + store_dbg("NAND BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); + + ret = run_command("amlnf deverase boot 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + return ret; + }else if((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)){ + off = simple_strtoul(argv[3], NULL, 16); + size = simple_strtoul(argv[4], NULL, 16); + + store_dbg("SPI BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__,off,size); + + ret = run_command("sf probe 2",0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } sprintf(str, "sf erase 0 0x%x", CONFIG_ENV_IN_SPI_OFFSET);//store erase boot shoould NOT erase ENV in flash! ret = run_command(str,0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - }else if(device_boot_flag == EMMC_BOOT_FLAG){ - off = simple_strtoul(argv[3], NULL, 16); - size = simple_strtoul(argv[4], NULL, 16); - - store_dbg("MMC BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__,off,size); - - sprintf(str, "mmc erase bootloader"); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed",cmd); - return -1; - } + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + }else if(device_boot_flag == EMMC_BOOT_FLAG){ + off = simple_strtoul(argv[3], NULL, 16); + size = simple_strtoul(argv[4], NULL, 16); + + store_dbg("MMC BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__,off,size); + + sprintf(str, "amlmmc erase bootloader"); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed",cmd); + return -1; + } #ifdef MMC_BOOT_PARTITION_SUPPORT - for (i=0; i<2; i++) { - //switch to boot partition here - sprintf(str, "mmc switch 1 boot%d", i); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret == -1) { - //store_msg("mmc cmd %s failed \n",cmd); - return 0; - } - else if(ret != 0){ - store_msg("mmc cmd %s failed",cmd); - //return -1; - goto E_SWITCH_BACK; - } - - //erase boot partition - sprintf(str, "mmc erase bootloader"); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed",cmd); - //return -1; - goto E_SWITCH_BACK; - } - } + for (i=0; i<2; i++) { + //switch to boot partition here + sprintf(str, "amlmmc switch 1 boot%d", i); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret == -1) { + //store_msg("mmc cmd %s failed \n",cmd); + return 0; + } + else if(ret != 0){ + store_msg("amlmmc cmd %s failed",cmd); + //return -1; + goto E_SWITCH_BACK; + } + + //erase boot partition + sprintf(str, "amlmmc erase bootloader"); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed",cmd); + //return -1; + goto E_SWITCH_BACK; + } + } E_SWITCH_BACK: - //switch back to urs partition - sprintf(str, "mmc switch 1 user"); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } + //switch back to urs partition + sprintf(str, "amlmmc switch 1 user"); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } #endif - return ret; - }else{ - store_dbg("CARD BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__,off,size); - return 0; - } - } - else if(strcmp(area, "data") == 0){ - - if (device_boot_flag == NAND_BOOT_FLAG) { - store_dbg("NAND BOOT,erase data : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); - - ret = run_command("amlnf deverase data 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - - ret = run_command("amlnf deverase code 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - ret = run_command("amlnf deverase cache 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_NAND_FLAG){ - store_dbg("spi+nand , %s %d ",__func__,__LINE__); - ret = run_command("amlnf deverase data 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - - ret = run_command("amlnf deverase code 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - ret = run_command("amlnf deverase cache 0",0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_EMMC_FLAG){ - store_dbg("spi+mmc , %s %d ",__func__,__LINE__); - off = size =0; - ret = run_command("mmc erase 1",0); // whole - if (ret != 0) { - store_msg("mmc cmd %s failed ",cmd); - return -1; - } + return ret; + }else{ + store_dbg("CARD BOOT,erase uboot : %s %d off =%llx ,size=%llx",__func__,__LINE__,off,size); + return 0; + } + } + else if(strcmp(area, "data") == 0){ + + if (device_boot_flag == NAND_BOOT_FLAG) { + store_dbg("NAND BOOT,erase data : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); + + ret = run_command("amlnf deverase data 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + + ret = run_command("amlnf deverase code 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + ret = run_command("amlnf deverase cache 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_NAND_FLAG){ + store_dbg("spi+nand , %s %d ",__func__,__LINE__); + ret = run_command("amlnf deverase data 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + + ret = run_command("amlnf deverase code 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + ret = run_command("amlnf deverase cache 0",0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_EMMC_FLAG){ + store_dbg("spi+mmc , %s %d ",__func__,__LINE__); + off = size =0; + ret = run_command("mmc erase 1",0); // whole + if (ret != 0) { + store_msg("mmc cmd %s failed ",cmd); + return -1; + } + + return ret; + } + else if(device_boot_flag==EMMC_BOOT_FLAG){ + store_dbg("MMC BOOT,erase data : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); + off = size =0; + ret = run_command("amlmmc erase 1",0); //whole + if (ret != 0) { + store_msg("amlmmc cmd %s failed ",cmd); + return -1; + } + return ret; + }else{ + store_dbg("CARD BOOT,erase data : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); + return 0; + } + } + else { + goto usage; + } - return ret; - } - else if(device_boot_flag==EMMC_BOOT_FLAG){ - store_dbg("MMC BOOT,erase data : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); - off = size =0; - ret = run_command("mmc erase 1",0); //whole - if (ret != 0) { - store_msg("mmc cmd %s failed ",cmd); - return -1; - } - return ret; - }else{ - store_dbg("CARD BOOT,erase data : %s %d off =%llx ,size=%llx",__func__,__LINE__, off, size); - return 0; - } - } - else { - goto usage; - } + } + else if(strcmp(cmd, "read") == 0){ + if (argc < 6) + goto usage; + + s = argv[2]; + addr = (ulong)simple_strtoul(argv[3], NULL, 16); + if (get_off_size(argc - 4, (char **)(argv + 4), &off, &size) != 0) + goto usage; + + store_dbg("addr = %llx off= 0x%llx size=0x%llx",addr,off,size); + if ((device_boot_flag == NAND_BOOT_FLAG)) { + sprintf(str, "amlnf read_byte %s 0x%llx 0x%llx 0x%llx",s, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_NAND_FLAG){ + sprintf(str, "amlnf read_byte %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed \n",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_EMMC_FLAG){ + store_dbg("spi+mmc , %s %d ",__func__,__LINE__); + sprintf(str, "amlmmc read %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag==EMMC_BOOT_FLAG) { + store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); + sprintf(str, "amlmmc read %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + return ret; + }else{ + store_dbg("CARD BOOT, %s %d ",__func__,__LINE__); - } - else if(strcmp(cmd, "read") == 0){ - if (argc < 6) - goto usage; - - s = argv[2]; - addr = (ulong)simple_strtoul(argv[3], NULL, 16); - if (get_off_size(argc - 4, (char **)(argv + 4), &off, &size) != 0) - goto usage; - - store_dbg("addr = %llx off= 0x%llx size=0x%llx",addr,off,size); - if ((device_boot_flag == NAND_BOOT_FLAG)) { - sprintf(str, "amlnf read_byte %s 0x%llx 0x%llx 0x%llx",s, addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_NAND_FLAG){ - sprintf(str, "amlnf read_byte %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed \n",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_EMMC_FLAG){ - store_dbg("spi+mmc , %s %d ",__func__,__LINE__); - sprintf(str, "mmc read %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag==EMMC_BOOT_FLAG) { - store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - sprintf(str, "mmc read %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - return ret; - }else{ - store_dbg("CARD BOOT, %s %d ",__func__,__LINE__); + return 0; + } + } + else if(strcmp(cmd, "write") == 0){ + if (argc < 6) + goto usage; + s = argv[2]; + addr = (ulong)simple_strtoul(argv[3], NULL, 16); + if (get_off_size(argc - 4, (char **)(argv + 4), &off, &size) != 0) + goto usage; + if (device_boot_flag == NAND_BOOT_FLAG) { + + sprintf(str, "amlnf write_byte %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed ",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_NAND_FLAG){ + store_dbg("spi+nand , %s %d ",__func__,__LINE__); + sprintf(str, "amlnf write_byte %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed \n",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_EMMC_FLAG){ + store_dbg("spi+mmc , %s %d ",__func__,__LINE__); + sprintf(str, "amlmmc write %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag==EMMC_BOOT_FLAG){ + store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); + sprintf(str, "amlmmc write %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + return ret; + }else{ + store_dbg("CARD BOOT, %s %d ",__func__,__LINE__); + return 0; + } + return ret; + } + else if(strcmp(cmd, "rom_write") == 0){ + if (argc < 5) + goto usage; + addr = (ulong)simple_strtoul(argv[2], NULL, 16); + if (get_off_size(argc - 3, (char **)(argv + 3), &off, &size) != 0) + goto usage; + if (device_boot_flag == NAND_BOOT_FLAG) { + sprintf(str, "amlnf rom_write 0x%llx 0x%llx 0x%llx", addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + } + else if ((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)){ + ret = run_command("sf probe 2",0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + sprintf(str, "sf erase 0x%llx 0x%llx ", off, size); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + sprintf(str, "sf write 0x%llx 0x%llx 0x%llx ",addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag==EMMC_BOOT_FLAG){ + store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - return 0; - } - } - else if(strcmp(cmd, "write") == 0){ - if (argc < 6) - goto usage; - s = argv[2]; - addr = (ulong)simple_strtoul(argv[3], NULL, 16); - if (get_off_size(argc - 4, (char **)(argv + 4), &off, &size) != 0) - goto usage; - if (device_boot_flag == NAND_BOOT_FLAG) { - - sprintf(str, "amlnf write_byte %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed ",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_NAND_FLAG){ - store_dbg("spi+nand , %s %d ",__func__,__LINE__); - sprintf(str, "amlnf write_byte %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed \n",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_EMMC_FLAG){ - store_dbg("spi+mmc , %s %d ",__func__,__LINE__); - sprintf(str, "mmc write %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag==EMMC_BOOT_FLAG){ - store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - sprintf(str, "mmc write %s 0x%llx 0x%llx 0x%llx", s, addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - return ret; - }else{ - store_dbg("CARD BOOT, %s %d ",__func__,__LINE__); - return 0; - } - return ret; - } - else if(strcmp(cmd, "rom_write") == 0){ - if (argc < 5) - goto usage; - addr = (ulong)simple_strtoul(argv[2], NULL, 16); - if (get_off_size(argc - 3, (char **)(argv + 3), &off, &size) != 0) - goto usage; - if (device_boot_flag == NAND_BOOT_FLAG) { - sprintf(str, "amlnf rom_write 0x%llx 0x%llx 0x%llx", addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - } - else if ((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)){ - ret = run_command("sf probe 2",0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - sprintf(str, "sf erase 0x%llx 0x%llx ", off, size); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - sprintf(str, "sf write 0x%llx 0x%llx 0x%llx ",addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag==EMMC_BOOT_FLAG){ - store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - tmp_buf= (unsigned char *)(int)addr; #ifndef CONFIG_AML_SECU_BOOT_V2 - #ifdef MMC_UBOOT_CLEAR_MBR - //modify the 55 AA info for emmc uboot - _mbrFlag[0] = tmp_buf[510]; - _mbrFlag[1] = tmp_buf[511]; - tmp_buf[510]=0; - tmp_buf[511]=0; - #endif +#ifdef MMC_UBOOT_CLEAR_MBR + //modify the 55 AA info for emmc uboot + unsigned char *tmp_buf= (unsigned char *)addr; + _mbrFlag[0] = tmp_buf[510]; + _mbrFlag[1] = tmp_buf[511]; + tmp_buf[510]=0; + tmp_buf[511]=0; +#endif #endif// #if defined(CONFIG_AML_SECU_BOOT_V2) - sprintf(str, "mmc write bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } + sprintf(str, "amlmmc write bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } #ifdef MMC_BOOT_PARTITION_SUPPORT - for (i=0; i<2; i++) { - //switch to boot partition here - sprintf(str, "mmc switch 1 boot%d", i); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret == -1) { - //store_msg("mmc cmd %s failed \n",cmd); - ret = 0; - return ret; - } - else if(ret != 0){ - store_msg("mmc cmd %s failed",cmd); - //return -1; - goto W_SWITCH_BACK; - } - - //write uboot to boot partition - sprintf(str, "mmc write bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - //return -1; - goto W_SWITCH_BACK; - } - } + for (i=0; i<2; i++) { + //switch to boot partition here + sprintf(str, "amlmmc switch 1 boot%d", i); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret == -1) { + //store_msg("mmc cmd %s failed \n",cmd); + ret = 0; + return ret; + } + else if(ret != 0){ + store_msg("amlmmc cmd %s failed",cmd); + //return -1; + goto W_SWITCH_BACK; + } + + //write uboot to boot partition + sprintf(str, "amlmmc write bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + //return -1; + goto W_SWITCH_BACK; + } + } W_SWITCH_BACK: - //switch back to urs partition - sprintf(str, "mmc switch 1 user"); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } + //switch back to urs partition + sprintf(str, "amlmmc switch 1 user"); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } #endif - return ret; - }else{ - store_dbg("CARD BOOT, %s %d",__func__,__LINE__); - return 0; - } + return ret; + }else{ + store_dbg("CARD BOOT, %s %d",__func__,__LINE__); + return 0; + } - } - else if(strcmp(cmd, "rom_read") == 0){ - if (argc < 5) - goto usage; - addr = (ulong)simple_strtoul(argv[2], NULL, 16); - if (get_off_size(argc - 3, (char **)(argv + 3), &off, &size) != 0) - goto usage; - if (device_boot_flag == NAND_BOOT_FLAG) { - sprintf(str, "amlnf rom_read 0x%llx 0x%llx 0x%llx", addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - }else if ((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)){ - ret = run_command("sf probe 2",0); - if (ret != 0) { - return -1; - } - sprintf(str, "sf read 0x%llx 0x%llx 0x%llx ",addr, off, size); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - }else if (device_boot_flag==EMMC_BOOT_FLAG){ - store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - sprintf(str, "mmc read bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); - store_dbg("command: %s\n", str); - tmp_buf= (unsigned char *)(int)addr; - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } + } + else if(strcmp(cmd, "rom_read") == 0){ + if (argc < 5) + goto usage; + addr = (ulong)simple_strtoul(argv[2], NULL, 16); + if (get_off_size(argc - 3, (char **)(argv + 3), &off, &size) != 0) + goto usage; + if (device_boot_flag == NAND_BOOT_FLAG) { + sprintf(str, "amlnf rom_read 0x%llx 0x%llx 0x%llx", addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + }else if ((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)){ + ret = run_command("sf probe 2",0); + if (ret != 0) { + return -1; + } + sprintf(str, "sf read 0x%llx 0x%llx 0x%llx ",addr, off, size); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + }else if (device_boot_flag==EMMC_BOOT_FLAG){ + store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); + sprintf(str, "amlmmc read bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); + store_dbg("command: %s\n", str); + //tmp_buf= (unsigned char *)addr; + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } #ifdef MMC_BOOT_PARTITION_SUPPORT - for (i=0; i<2; i++) { - //switch to boot partition here - sprintf(str, "mmc switch 1 boot%d", i); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret == -1) { - //store_msg("mmc cmd %s failed \n",cmd); - return 0; - } - else if(ret != 0){ - store_msg("mmc cmd %s failed",cmd); - goto R_SWITCH_BACK; - //return -1; - } - - //write uboot to boot partition - sprintf(str, "mmc read bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - //return -1; - goto R_SWITCH_BACK; - } - } + for (i=0; i<2; i++) { + //switch to boot partition here + sprintf(str, "amlmmc switch 1 boot%d", i); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret == -1) { + //store_msg("mmc cmd %s failed \n",cmd); + return 0; + } + else if(ret != 0){ + store_msg("amlmmc cmd %s failed",cmd); + goto R_SWITCH_BACK; + //return -1; + } + + //write uboot to boot partition + sprintf(str, "amlmmc read bootloader 0x%llx 0x%llx 0x%llx", addr, off, size); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + //return -1; + goto R_SWITCH_BACK; + } + } R_SWITCH_BACK: - //switch back to urs partition - sprintf(str, "mmc switch 1 user"); - store_dbg("command: %s\n", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } + //switch back to urs partition + sprintf(str, "amlmmc switch 1 user"); + store_dbg("command: %s\n", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } #endif #ifndef CONFIG_AML_SECU_BOOT_V2 - #ifdef MMC_UBOOT_CLEAR_MBR - tmp_buf[510]= _mbrFlag[0]; - tmp_buf[511]= _mbrFlag[1]; - #endif +#ifdef MMC_UBOOT_CLEAR_MBR + unsigned char *tmp_buf= (unsigned char *)addr; + tmp_buf[510]= _mbrFlag[0]; + tmp_buf[511]= _mbrFlag[1]; +#endif #endif// #ifndef CONFIG_AML_SECU_BOOT_V2 - return ret; - }else{ - store_dbg("CARD BOOT, %s %d ",__func__,__LINE__); - return 0; - } + return ret; + }else{ + store_dbg("CARD BOOT, %s %d ",__func__,__LINE__); + return 0; + } - } - else if (strcmp(cmd, "rom_protect") == 0){ - if (argc < 3) - goto usage; - - area = argv[2]; - if (device_boot_flag == NAND_BOOT_FLAG) { - sprintf(str, "amlnf rom_protect %s", area); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - } - } - else if (strcmp(cmd, "scrub") == 0){ - off = (ulong)simple_strtoul(argv[2], NULL, 16); - sprintf(str, "amlnf scrub %d", (int)off); - if (device_boot_flag == NAND_BOOT_FLAG) { - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - } - else if(device_boot_flag == SPI_NAND_FLAG){ - store_dbg("spi+nand , %s %d ",__func__,__LINE__); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - ret = run_command("sf probe 2", 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); - ret = run_command(str,0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_EMMC_FLAG){ - store_dbg("spi+mmc , %s %d ",__func__,__LINE__); - ret = run_command("mmc erase whole",0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag==EMMC_BOOT_FLAG){ - store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - device_boot_flag = EMMC_BOOT_FLAG; - ret = run_command("mmcinfo 1", 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { - MsgP("mmc key\n"); - run_command("mmc key", 0); - } - MsgP("mmc erase 1"); - ret = run_command("mmc erase 1", 0); } - return ret; - } - else if(strcmp(cmd, "init") == 0){ + else if (strcmp(cmd, "rom_protect") == 0){ + if (argc < 3) + goto usage; + + area = argv[2]; + if (device_boot_flag == NAND_BOOT_FLAG) { + sprintf(str, "amlnf rom_protect %s", area); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + } + } + else if (strcmp(cmd, "scrub") == 0){ + off = (ulong)simple_strtoul(argv[2], NULL, 16); + sprintf(str, "amlnf scrub %d", (int)off); + if (device_boot_flag == NAND_BOOT_FLAG) { + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + } + else if(device_boot_flag == SPI_NAND_FLAG){ + store_dbg("spi+nand , %s %d ",__func__,__LINE__); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + ret = run_command("sf probe 2", 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); + ret = run_command(str,0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_EMMC_FLAG){ + store_dbg("spi+mmc , %s %d ",__func__,__LINE__); + ret = run_command("amlmmc erase whole",0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag==EMMC_BOOT_FLAG){ + store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); + device_boot_flag = EMMC_BOOT_FLAG; + run_command("mmc dev 1", 0); + ret = run_command("mmcinfo", 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { + MsgP("mmc key\n"); + run_command("mmc key", 0); + } + MsgP("amlmmc erase 1"); + ret = run_command("amlmmc erase 1", 0); + } + return ret; + } + else if(strcmp(cmd, "init") == 0){ - init_flag = (argc > 2) ? (int)simple_strtoul(argv[2], NULL, 16) : 0; - store_dbg("init_flag %d",init_flag); + init_flag = (argc > 2) ? (int)simple_strtoul(argv[2], NULL, 16) : 0; + store_dbg("init_flag %d",init_flag); - if (device_boot_flag == -1) { - get_device_boot_flag(); - } - if (device_boot_flag == NAND_BOOT_FLAG) - { - if ((init_flag >=STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <=STORE_BOOT_SCRUB_ALL)) { - sprintf(str, "amlnf init %d ",init_flag); - run_command(str, 0); - } + if (device_boot_flag == -1) { + //get_device_boot_flag(); + } + if (device_boot_flag == NAND_BOOT_FLAG) + { + if ((init_flag >=STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <=STORE_BOOT_SCRUB_ALL)) { + sprintf(str, "amlnf init %d ",init_flag); + run_command(str, 0); + } - sprintf(str, "amlnf init %d ",1); - printf("command: %s -> %d\n", str, init_flag); - device_boot_flag = NAND_BOOT_FLAG; - ret = run_command(str, 0); - if (ret != 0) { + sprintf(str, "amlnf init %d ",1); + printf("command: %s -> %d\n", str, init_flag); + device_boot_flag = NAND_BOOT_FLAG; + ret = run_command(str, 0); + if (ret != 0) { #if 0 - if ((ret == NAND_INIT_FAILED) && (init_flag == STORE_BOOT_ERASE_ALL)) { - sprintf(str, "amlnf init %d ",4); - ret = run_command(str, 0); - } - if (ret) { - store_msg("nand cmd %s failed,ret=%d ",cmd,ret); - return -1; - } - return 0; + if ((ret == NAND_INIT_FAILED) && (init_flag == STORE_BOOT_ERASE_ALL)) { + sprintf(str, "amlnf init %d ",4); + ret = run_command(str, 0); + } + if (ret) { + store_msg("nand cmd %s failed,ret=%d ",cmd,ret); + return -1; + } + return 0; #else - return -1; + return -1; #endif - } - return ret; - } - else if((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)) - { -/* - if (device_boot_flag == -1) - { - ret = run_command("sf probe 2", 0); - if (ret) { - store_msg(" cmd %s failed \n",cmd); - return -1; - } - if ((init_flag > STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <= STORE_BOOT_SCRUB_ALL)) { - sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); - ret = run_command(str,0); - } - sprintf(str, "amlnf init %d ",init_flag); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret < 0) //fail to init NAND flash - { - store_msg("nand cmd %s failed \n",cmd); - device_boot_flag = SPI_EMMC_FLAG; - store_dbg("spi+mmc , %s %d ",__func__,__LINE__); - ret = run_command("mmcinfo 1", 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -2; - } - if (init_flag == STORE_BOOT_ERASE_PROTECT_CACHE) { // OTA upgrade protect cache - store_msg("mmc erase non_cache \n"); - ret = run_command("mmc erase non_cache", 0); - }else if(init_flag >= STORE_BOOT_ERASE_ALL){ // erase all except reserved area - if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { - MsgP("mmc key;\n"); - run_command("mmc key", 0); } - MsgP("mmc erase 1 \n"); - ret = run_command("mmc erase 1", 0); - } - return 0; - } - else if((ret == NAND_INIT_FAILED)&&(init_flag == STORE_BOOT_ERASE_ALL)){ - sprintf(str, "amlnf init %d ",4); - ret = run_command(str, 0); - } - device_boot_flag = SPI_NAND_FLAG; - return 0; - } -*/ - if (device_boot_flag == SPI_NAND_FLAG) { - store_dbg("spi+nand , %s %d ",__func__,__LINE__); - - if ((init_flag >=STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <=STORE_BOOT_SCRUB_ALL)) { - sprintf(str, "amlnf init %d ",init_flag); - run_command(str, 0); - } - sprintf(str, "amlnf init %d ",1); - store_dbg("command: %s", str); - ret = run_command(str, 0); + return ret; + } + else if((device_boot_flag==SPI_EMMC_FLAG)||(device_boot_flag==SPI_NAND_FLAG)) + { + /* + if (device_boot_flag == -1) + { + ret = run_command("sf probe 2", 0); + if (ret) { + store_msg(" cmd %s failed \n",cmd); + return -1; + } + if ((init_flag > STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <= STORE_BOOT_SCRUB_ALL)) { + sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); + ret = run_command(str,0); + } + sprintf(str, "amlnf init %d ",init_flag); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret < 0) //fail to init NAND flash + { + store_msg("nand cmd %s failed \n",cmd); + device_boot_flag = SPI_EMMC_FLAG; + store_dbg("spi+mmc , %s %d ",__func__,__LINE__); + ret = run_command("mmcinfo 1", 0); + if (ret != 0) { + store_msg("mmc cmd %s failed \n",cmd); + return -2; + } + if (init_flag == STORE_BOOT_ERASE_PROTECT_CACHE) { // OTA upgrade protect cache + store_msg("mmc erase non_cache \n"); + ret = run_command("mmc erase non_cache", 0); + }else if(init_flag >= STORE_BOOT_ERASE_ALL){ // erase all except reserved area + if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { + MsgP("mmc key;\n"); + run_command("mmc key", 0); + } + MsgP("mmc erase 1 \n"); + ret = run_command("mmc erase 1", 0); + } + return 0; + } + else if((ret == NAND_INIT_FAILED)&&(init_flag == STORE_BOOT_ERASE_ALL)){ + sprintf(str, "amlnf init %d ",4); + ret = run_command(str, 0); + } + device_boot_flag = SPI_NAND_FLAG; + return 0; + } + */ + if (device_boot_flag == SPI_NAND_FLAG) { + store_dbg("spi+nand , %s %d ",__func__,__LINE__); + + if ((init_flag >=STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <=STORE_BOOT_SCRUB_ALL)) { + sprintf(str, "amlnf init %d ",init_flag); + run_command(str, 0); + } + sprintf(str, "amlnf init %d ",1); + store_dbg("command: %s", str); + ret = run_command(str, 0); #if 0 - if ((ret == NAND_INIT_FAILED) && (init_flag == STORE_BOOT_ERASE_ALL)) { - sprintf(str, "amlnf init %d ",4); - ret = run_command(str, 0); - } + if ((ret == NAND_INIT_FAILED) && (init_flag == STORE_BOOT_ERASE_ALL)) { + sprintf(str, "amlnf init %d ",4); + ret = run_command(str, 0); + } #else - if (ret == NAND_INIT_FAILED) { - return -1; - } + if (ret == NAND_INIT_FAILED) { + return -1; + } #endif - if ((init_flag > STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <= STORE_BOOT_SCRUB_ALL)) { - ret = run_command("sf probe 2", 0); - sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); - ret = run_command(str,0); - } - } - if (device_boot_flag == SPI_EMMC_FLAG) { - store_dbg("spi+mmc , %s %d ",__func__,__LINE__); - ret = run_command("mmcinfo 1", 0); - - if (init_flag == STORE_BOOT_ERASE_PROTECT_CACHE) { // OTA upgrade protect cache - store_msg("mmc erase non_cache \n"); - ret = run_command("mmc erase non_cache", 0); - }else if(init_flag == STORE_BOOT_ERASE_ALL){ // erase all except reserved area - if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { - run_command("mmc key", 0); - } - MsgP("mmc erase 1 \n"); - ret = run_command("mmc erase 1", 0); - } - if ((init_flag > STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <= STORE_BOOT_SCRUB_ALL)) { - ret = run_command("sf probe 2", 0); - sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); - ret = run_command(str,0); - } - } - - if (ret != 0) { - store_msg("cmd %s failed \n",cmd); - return -1; - } + if ((init_flag > STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <= STORE_BOOT_SCRUB_ALL)) { + ret = run_command("sf probe 2", 0); + sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); + ret = run_command(str,0); + } + } + if (device_boot_flag == SPI_EMMC_FLAG) { + store_dbg("spi+mmc , %s %d ",__func__,__LINE__); + ret = run_command("mmcinfo 1", 0); + + if (init_flag == STORE_BOOT_ERASE_PROTECT_CACHE) { // OTA upgrade protect cache + store_msg("amlmmc erase non_cache \n"); + ret = run_command("amlmmc erase non_cache", 0); + }else if(init_flag == STORE_BOOT_ERASE_ALL){ // erase all except reserved area + if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { + run_command("mmc key", 0); + } + MsgP("amlmmc erase 1 \n"); + ret = run_command("amlmmc erase 1", 0); + } + if ((init_flag > STORE_BOOT_ERASE_PROTECT_CACHE) && (init_flag <= STORE_BOOT_SCRUB_ALL)) { + ret = run_command("sf probe 2", 0); + sprintf(str, "sf erase 0 0x%x", _SPI_FLASH_ERASE_SZ); + ret = run_command(str,0); + } + } - return ret; - } - else if(device_boot_flag == EMMC_BOOT_FLAG){ - store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); - device_boot_flag = EMMC_BOOT_FLAG; - ret = run_command("mmcinfo 1", 0); - if (ret != 0) { - store_msg("mmc cmd %s failed \n",cmd); - return -1; - } - if (init_flag == STORE_BOOT_ERASE_PROTECT_CACHE) { // OTA upgrade protect cache - ret = run_command("mmc erase non_cache", 0); - }else if(init_flag >= STORE_BOOT_ERASE_ALL){ // erase all except reserved area - if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { - MsgP("mmc key\n"); - run_command("mmc key", 0); + if (ret != 0) { + store_msg("cmd %s failed \n",cmd); + return -1; } - MsgP("mmc erase 1"); - ret = run_command("mmc erase 1", 0); + + return ret; } + else if(device_boot_flag == EMMC_BOOT_FLAG){ + store_dbg("MMC BOOT, %s %d \n",__func__,__LINE__); + device_boot_flag = EMMC_BOOT_FLAG; + run_command("mmc dev 1",0); + ret = run_command("mmcinfo", 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed \n",cmd); + return -1; + } + if (init_flag == STORE_BOOT_ERASE_PROTECT_CACHE) { // OTA upgrade protect cache + ret = run_command("amlmmc erase non_cache", 0); + }else if(init_flag >= STORE_BOOT_ERASE_ALL){ // erase all except reserved area + if (_info_disprotect_back_before_mmcinfo1 & DISPROTECT_KEY) { + MsgP("amlmmc key\n"); + run_command("amlmmc key", 0); + } + MsgP("amlmmc erase 1"); + ret = run_command("amlmmc erase 1", 0); + } return ret; - }else{ - store_dbg("CARD BOOT, %s %d",__func__,__LINE__); + }else{ + store_dbg("CARD BOOT, %s %d",__func__,__LINE__); + return 0; + } + } + else if(strcmp(cmd, "size") == 0){ + + if (argc < 4) + goto usage; + + s = argv[2]; + addr = (ulong)simple_strtoul(argv[3], NULL, 16); + if (device_boot_flag == NAND_BOOT_FLAG) { + sprintf(str, "amlnf size %s %llx",s,addr); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_NAND_FLAG){ + sprintf(str, "amlnf size %s %llx",s,addr); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag == SPI_EMMC_FLAG){ + store_dbg("MMC , %s %d ",__func__,__LINE__); + sprintf(str, "amlmmc size %s %llx",s,addr); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag==EMMC_BOOT_FLAG){ + store_dbg("MMC , %s %d ",__func__,__LINE__); + sprintf(str, "amlmmc size %s %llx",s,addr); + store_dbg("command: %s", str); + ret = run_command(str, 0); + if (ret != 0) { + store_msg("amlmmc cmd %s failed",cmd); + return -1; + } + return ret; + } + else if(device_boot_flag==CARD_BOOT_FLAG){ + store_dbg("CARD BOOT , %s %d ",__func__,__LINE__); + return 0; + } + } + else if(strcmp(cmd, "disprotect") == 0){ + area = argv[2]; + if (strcmp(area, "key") == 0) { + MsgP("disprotect key\n"); + info_disprotect |= DISPROTECT_KEY; + _info_disprotect_back_before_mmcinfo1 |= DISPROTECT_KEY; + } + if (strcmp(area, "secure") == 0) { + store_msg("disprotect secure"); + info_disprotect |= DISPROTECT_SECURE; + } + if (strcmp(area, "fbbt") == 0) { + store_msg("disprotect fbbt"); + info_disprotect |= DISPROTECT_FBBT; + } + if (strcmp(area, "hynix") == 0) { + store_msg("disprotect hynix"); + info_disprotect |= DISPROTECT_HYNIX; + } return 0; } - } - else if(strcmp(cmd, "size") == 0){ - - if (argc < 4) - goto usage; - - s = argv[2]; - addr = (ulong)simple_strtoul(argv[3], NULL, 16); - if (device_boot_flag == NAND_BOOT_FLAG) { - sprintf(str, "amlnf size %s %llx",s,addr); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_NAND_FLAG){ - sprintf(str, "amlnf size %s %llx",s,addr); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag == SPI_EMMC_FLAG){ - store_dbg("MMC , %s %d ",__func__,__LINE__); - sprintf(str, "mmc size %s %llx",s,addr); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag==EMMC_BOOT_FLAG){ - store_dbg("MMC , %s %d ",__func__,__LINE__); - sprintf(str, "mmc size %s %llx",s,addr); - store_dbg("command: %s", str); - ret = run_command(str, 0); - if (ret != 0) { - store_msg("mmc cmd %s failed",cmd); - return -1; - } - return ret; - } - else if(device_boot_flag==CARD_BOOT_FLAG){ - store_dbg("CARD BOOT , %s %d ",__func__,__LINE__); - return 0; - } - } - else if(strcmp(cmd, "disprotect") == 0){ - area = argv[2]; - if (strcmp(area, "key") == 0) { - MsgP("disprotect key\n"); - info_disprotect |= DISPROTECT_KEY; - _info_disprotect_back_before_mmcinfo1 |= DISPROTECT_KEY; - } - if (strcmp(area, "secure") == 0) { - store_msg("disprotect secure"); - info_disprotect |= DISPROTECT_SECURE; - } - if (strcmp(area, "fbbt") == 0) { - store_msg("disprotect fbbt"); - info_disprotect |= DISPROTECT_FBBT; - } - if (strcmp(area, "hynix") == 0) { - store_msg("disprotect hynix"); - info_disprotect |= DISPROTECT_HYNIX; - } - return 0; - } - else if(strcmp(cmd, "exit") == 0){ + else if(strcmp(cmd, "exit") == 0){ - if (device_boot_flag == NAND_BOOT_FLAG) { - ret = run_command("amlnf exit", 0); - if (ret != 0) { - store_msg("nand cmd %s failed",cmd); - return -1; - } - } - return 0; - } - else{ - goto usage; - } + if (device_boot_flag == NAND_BOOT_FLAG) { + ret = run_command("amlnf exit", 0); + if (ret != 0) { + store_msg("nand cmd %s failed",cmd); + return -1; + } + } + return 0; + } + else{ + goto usage; + } - return ret; + return ret; usage: - cmd_usage(cmdtp); - return 1; + cmd_usage(cmdtp); + return 1; } diff --git a/drivers/Makefile b/drivers/Makefile index 4e610157f7..def96e58fa 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -25,3 +25,5 @@ obj-y += input/ obj-y += soc/ obj-y += thermal/ obj-$(CONFIG_EFUSE) += efuse/ +obj-$(CONFIG_AML_V2_FACTORY_BURN) += usb/gadget/v2_burning/ + diff --git a/drivers/mmc/aml_sd_emmc.c b/drivers/mmc/aml_sd_emmc.c index ebbb6929b4..662ebd161b 100644 --- a/drivers/mmc/aml_sd_emmc.c +++ b/drivers/mmc/aml_sd_emmc.c @@ -254,162 +254,173 @@ static int sd_inand_staff_init(struct mmc *mmc) */ int aml_sd_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { - int ret = SD_NO_ERROR; - //u32 vconf; - u32 buffer = 0; - u32 resp_buffer; - u32 vstart = 0; - u32 status_irq = 0; - - struct sd_emmc_status *status_irq_reg = (void *)&status_irq; - struct sd_emmc_start *desc_start = (struct sd_emmc_start*)&vstart; - //struct sd_emmc_config* sd_emmc_cfg = (struct sd_emmc_config*)&vconf; - struct aml_card_sd_info *aml_priv = mmc->priv; - struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; - struct cmd_cfg *des_cmd_cur = NULL; - struct sd_emmc_desc_info *desc_cur = (struct sd_emmc_desc_info*)aml_priv->desc_buf; - - //vconf = sd_emmc_reg->gcfg; - - memset(desc_cur, 0, (NEWSD_MAX_DESC_MUN>>2)*sizeof(struct sd_emmc_desc_info)); - - des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); - des_cmd_cur->cmd_index = 0x80 | cmd->cmdidx; //bit:31 owner = 1 bit:24-29 cmdidx - desc_cur->cmd_arg = cmd->cmdarg; - - sd_inand_clear_response(cmd->response); - - //check response type - if (cmd->resp_type & MMC_RSP_PRESENT) { - resp_buffer = (unsigned long)cmd->response;//dma_map_single((void*)cmd->response,sizeof(uint)*4,DMA_FROM_DEVICE); - des_cmd_cur->no_resp = 0; - - //save Resp into Resp addr, and check response from register for RSP_136 - if (cmd->resp_type & MMC_RSP_136) - des_cmd_cur->resp_128 = 1; - - if (cmd->resp_type & MMC_RSP_BUSY) - des_cmd_cur->r1b = 1; //check data0 busy after R1 reponse - - if (!(cmd->resp_type & MMC_RSP_CRC)) - des_cmd_cur->resp_nocrc = 1; - - des_cmd_cur->resp_num = 0; - desc_cur->resp_addr = resp_buffer; - }else - des_cmd_cur->no_resp = 1; - - if (data) { - des_cmd_cur->data_io = 1; // cmd has data read or write - if (data->flags == MMC_DATA_READ) { - des_cmd_cur->data_wr = 0; //read data from sd/emmc - buffer = (unsigned long)data->dest;//dma_map_single((void*)data->dest,data->blocks*data->blocksize,DMA_FROM_DEVICE); - invalidate_dcache_range((unsigned long)data->dest, (unsigned long)(data->dest+data->blocks*data->blocksize)); - }else{ - des_cmd_cur->data_wr = 1; - buffer = (unsigned long)data->src;//dma_map_single((void*)data->src,data->blocks*data->blocksize,DMA_TO_DEVICE);//(char *)data->src; - flush_dcache_range((unsigned long)data->src,(unsigned long)(data->src+data->blocks*data->blocksize)); - } - if (data->blocks > 1) { - des_cmd_cur->block_mode = 1; - des_cmd_cur->length = data->blocks; - }else{ - des_cmd_cur->block_mode = 0; - des_cmd_cur->length = data->blocksize; - } - des_cmd_cur->data_num = 0; - desc_cur->data_addr = buffer; - desc_cur->data_addr &= ~(1<<0); //DDR - - } - if (data) { - if ((data->blocks*data->blocksize <0x200) && (data->flags == MMC_DATA_READ)) { - desc_cur->data_addr = (unsigned long)sd_emmc_reg->gping; - desc_cur->data_addr |= 1<<0; - } - } - /*Prepare desc for config register*/ - des_cmd_cur->owner = 1; - des_cmd_cur->end_of_chain = 0; - - //sd_emmc_reg->gcfg = vconf; - - des_cmd_cur->end_of_chain = 1; //the end flag of descriptor chain - - sd_emmc_reg->gstatus = NEWSD_IRQ_ALL; - - invalidate_dcache_range((unsigned long)aml_priv->desc_buf, - (unsigned long)(aml_priv->desc_buf+NEWSD_MAX_DESC_MUN*(sizeof(struct sd_emmc_desc_info)))); - //start transfer cmd - desc_start->init = 0; - desc_start->busy = 1; - desc_start->addr = (unsigned long)aml_priv->desc_buf >> 2; + int ret = SD_NO_ERROR; + //u32 vconf; + u32 buffer = 0; + u32 resp_buffer; + u32 vstart = 0; + u32 status_irq = 0; + //u32 inalign = 0; + u32 *write_buffer = NULL; + struct sd_emmc_status *status_irq_reg = (void *)&status_irq; + struct sd_emmc_start *desc_start = (struct sd_emmc_start*)&vstart; + //struct sd_emmc_config* sd_emmc_cfg = (struct sd_emmc_config*)&vconf; + struct aml_card_sd_info *aml_priv = mmc->priv; + struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; + struct cmd_cfg *des_cmd_cur = NULL; + struct sd_emmc_desc_info *desc_cur = (struct sd_emmc_desc_info*)aml_priv->desc_buf; + + //vconf = sd_emmc_reg->gcfg; + + memset(desc_cur, 0, (NEWSD_MAX_DESC_MUN>>2)*sizeof(struct sd_emmc_desc_info)); + + des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); + des_cmd_cur->cmd_index = 0x80 | cmd->cmdidx; //bit:31 owner = 1 bit:24-29 cmdidx + desc_cur->cmd_arg = cmd->cmdarg; + + sd_inand_clear_response(cmd->response); + + //check response type + if (cmd->resp_type & MMC_RSP_PRESENT) { + resp_buffer = (unsigned long)cmd->response;//dma_map_single((void*)cmd->response,sizeof(uint)*4,DMA_FROM_DEVICE); + des_cmd_cur->no_resp = 0; + + //save Resp into Resp addr, and check response from register for RSP_136 + if (cmd->resp_type & MMC_RSP_136) + des_cmd_cur->resp_128 = 1; + + if (cmd->resp_type & MMC_RSP_BUSY) + des_cmd_cur->r1b = 1; //check data0 busy after R1 reponse + + if (!(cmd->resp_type & MMC_RSP_CRC)) + des_cmd_cur->resp_nocrc = 1; + + des_cmd_cur->resp_num = 0; + desc_cur->resp_addr = resp_buffer; + }else + des_cmd_cur->no_resp = 1; + + if (data) { + des_cmd_cur->data_io = 1; // cmd has data read or write + if (data->flags == MMC_DATA_READ) { + des_cmd_cur->data_wr = 0; //read data from sd/emmc + buffer = (unsigned long)data->dest;//dma_map_single((void*)data->dest,data->blocks*data->blocksize,DMA_FROM_DEVICE); + invalidate_dcache_range((unsigned long)data->dest, (unsigned long)(data->dest+data->blocks*data->blocksize)); + }else{ + des_cmd_cur->data_wr = 1; + //buffer = (unsigned long)data->src;//dma_map_single((void*)data->src,data->blocks*data->blocksize,DMA_TO_DEVICE);//(char *)data->src; + write_buffer = (u32 *)malloc(128*1024); + memset(write_buffer, 0 ,128*1024); + memcpy(write_buffer, (u32 *)data->src, data->blocks*data->blocksize); + flush_dcache_range((unsigned)(long)write_buffer,(unsigned long)(write_buffer+data->blocks*data->blocksize)); + } + + if (data->blocks > 1) { + des_cmd_cur->block_mode = 1; + des_cmd_cur->length = data->blocks; + }else{ + des_cmd_cur->block_mode = 0; + des_cmd_cur->length = data->blocksize; + } + des_cmd_cur->data_num = 0; + if (des_cmd_cur->data_wr == 1) + desc_cur->data_addr = (unsigned long)write_buffer; + else + desc_cur->data_addr = buffer; + desc_cur->data_addr &= ~(1<<0); //DDR + + } + if (data) { + if ((data->blocks*data->blocksize <0x200) && (data->flags == MMC_DATA_READ)) { + desc_cur->data_addr = (unsigned long)sd_emmc_reg->gping; + desc_cur->data_addr |= 1<<0; + } + } + /*Prepare desc for config register*/ + des_cmd_cur->owner = 1; + des_cmd_cur->end_of_chain = 0; + + //sd_emmc_reg->gcfg = vconf; + + des_cmd_cur->end_of_chain = 1; //the end flag of descriptor chain + + sd_emmc_reg->gstatus = NEWSD_IRQ_ALL; + + invalidate_dcache_range((unsigned long)aml_priv->desc_buf, + (unsigned long)(aml_priv->desc_buf+NEWSD_MAX_DESC_MUN*(sizeof(struct sd_emmc_desc_info)))); + //start transfer cmd + desc_start->init = 0; + desc_start->busy = 1; + desc_start->addr = (unsigned long)aml_priv->desc_buf >> 2; #if 0 - sd_emmc_reg->gstart = vstart; + sd_emmc_reg->gstart = vstart; #else - sd_emmc_reg->gcmd_cfg = desc_cur->cmd_info; - sd_emmc_reg->gcmd_dat = desc_cur->data_addr; - sd_emmc_reg->gcmd_arg = desc_cur->cmd_arg; + sd_emmc_reg->gcmd_cfg = desc_cur->cmd_info; + sd_emmc_reg->gcmd_dat = desc_cur->data_addr; + sd_emmc_reg->gcmd_arg = desc_cur->cmd_arg; #endif - //waiting end of chain - while (1) { - status_irq = sd_emmc_reg->gstatus; - if (status_irq_reg->end_of_chain) - break; - } - - if (status_irq_reg->rxd_err) - ret |= SD_EMMC_RXD_ERROR; - if (status_irq_reg->txd_err) - ret |= SD_EMMC_TXD_ERROR; - if (status_irq_reg->desc_err) - ret |= SD_EMMC_DESC_ERROR; - if (status_irq_reg->resp_err) - ret |= SD_EMMC_RESP_CRC_ERROR; - if (status_irq_reg->resp_timeout) - ret |= SD_EMMC_RESP_TIMEOUT_ERROR; - if (status_irq_reg->desc_timeout) - ret |= SD_EMMC_DESC_TIMEOUT_ERROR; - if (data) { - if ((data->blocks*data->blocksize <0x200) && (data->flags == MMC_DATA_READ)) { - memcpy(data->dest, (const void *)sd_emmc_reg->gping,data->blocks*data->blocksize); - } - } - /*we get response [0]:bit0~31 - * response [1]:bit32~63 - * response [2]:bit64~95 - * response [3]:bit96~127 - * actually mmc driver definition is: - * response [0]:bit96~127 - * response [1]:bit64~95 - * response [2]:bit32~63 - * response [3]:bit0~31 - */ - - if (cmd->resp_type & MMC_RSP_136) { - cmd->response[0] = sd_emmc_reg->gcmd_rsp3; - cmd->response[1] = sd_emmc_reg->gcmd_rsp2; - cmd->response[2] = sd_emmc_reg->gcmd_rsp1; - cmd->response[3] = sd_emmc_reg->gcmd_rsp0; - } else { - cmd->response[0] = sd_emmc_reg->gcmd_rsp0; - } - - - sd_debug("cmd->cmdidx = %d, cmd->cmdarg=0x%x, ret=0x%x\n",cmd->cmdidx,cmd->cmdarg,ret); - sd_debug("cmd->response[0]=0x%x;\n",cmd->response[0]); - sd_debug("cmd->response[1]=0x%x;\n",cmd->response[1]); - sd_debug("cmd->response[2]=0x%x;\n",cmd->response[2]); - sd_debug("cmd->response[3]=0x%x;\n",cmd->response[3]); - - if (ret) { - if (status_irq_reg->resp_timeout) - return TIMEOUT; - else - return ret; - } - - return SD_NO_ERROR; + //waiting end of chain + while (1) { + status_irq = sd_emmc_reg->gstatus; + if (status_irq_reg->end_of_chain) + break; + } + + if (status_irq_reg->rxd_err) + ret |= SD_EMMC_RXD_ERROR; + if (status_irq_reg->txd_err) + ret |= SD_EMMC_TXD_ERROR; + if (status_irq_reg->desc_err) + ret |= SD_EMMC_DESC_ERROR; + if (status_irq_reg->resp_err) + ret |= SD_EMMC_RESP_CRC_ERROR; + if (status_irq_reg->resp_timeout) + ret |= SD_EMMC_RESP_TIMEOUT_ERROR; + if (status_irq_reg->desc_timeout) + ret |= SD_EMMC_DESC_TIMEOUT_ERROR; + if (data) { + if ((data->blocks*data->blocksize <0x200) && (data->flags == MMC_DATA_READ)) { + memcpy(data->dest, (const void *)sd_emmc_reg->gping,data->blocks*data->blocksize); + } + } + /*we get response [0]:bit0~31 + * response [1]:bit32~63 + * response [2]:bit64~95 + * response [3]:bit96~127 + * actually mmc driver definition is: + * response [0]:bit96~127 + * response [1]:bit64~95 + * response [2]:bit32~63 + * response [3]:bit0~31 + */ + + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[0] = sd_emmc_reg->gcmd_rsp3; + cmd->response[1] = sd_emmc_reg->gcmd_rsp2; + cmd->response[2] = sd_emmc_reg->gcmd_rsp1; + cmd->response[3] = sd_emmc_reg->gcmd_rsp0; + } else { + cmd->response[0] = sd_emmc_reg->gcmd_rsp0; + } + + + sd_debug("cmd->cmdidx = %d, cmd->cmdarg=0x%x, ret=0x%x\n",cmd->cmdidx,cmd->cmdarg,ret); + sd_debug("cmd->response[0]=0x%x;\n",cmd->response[0]); + sd_debug("cmd->response[1]=0x%x;\n",cmd->response[1]); + sd_debug("cmd->response[2]=0x%x;\n",cmd->response[2]); + sd_debug("cmd->response[3]=0x%x;\n",cmd->response[3]); + if (des_cmd_cur->data_wr == 1) { + free(write_buffer); + write_buffer = NULL; + } + if (ret) { + if (status_irq_reg->resp_timeout) + return TIMEOUT; + else + return ret; + } + + return SD_NO_ERROR; } int aml_sd_init(struct mmc *mmc) diff --git a/drivers/mmc/emmc_partitions.c b/drivers/mmc/emmc_partitions.c index 7aa9f55ae2..5da31456c5 100644 --- a/drivers/mmc/emmc_partitions.c +++ b/drivers/mmc/emmc_partitions.c @@ -471,30 +471,32 @@ int mmc_device_init (struct mmc *mmc) return ret; } + int find_dev_num_by_partition_name (char *name) { - int port=-1, dev_num; - struct mmc *mmc; + int dev_num=-1; + //struct mmc *mmc; if (!strncmp(name, MMC_CARD_PARTITION_NAME, sizeof(MMC_CARD_PARTITION_NAME))) { // card - port = SDIO_PORT_B; + // port = SDIO_PORT_B; + dev_num = 0; } else { // eMMC OR TSD if (find_mmc_partition_by_name(name)) { // partition name is valid - port = SDIO_PORT_C; + //port = SDIO_PORT_C; + dev_num = 1; } // else port=-1 } - if (port > 0) { - mmc = find_mmc_device_by_port((unsigned)port); - if (!mmc) { // not found - dev_num = -1; - } else { - dev_num = mmc->block_dev.dev; - } - } else { // partition name is invalid - dev_num = -1; - } - // printf("[%s] dev_num = %d\n", __FUNCTION__, dev_num); +// if (port > 0) { +// mmc = find_mmc_device_by_port((unsigned)port); +// if (!mmc) { // not found +// dev_num = -1; +// } else { +// dev_num = mmc->block_dev.dev; +// } +// } else { // partition name is invalid +// dev_num = -1; +// } return dev_num; } diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 3db9669c82..4e8655b43e 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -24,7 +24,7 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) end = (start + blkcnt - 1) * mmc->write_bl_len; start *= mmc->write_bl_len; } - + printf("start = %lu,end = %lu\n",start,end); if (IS_SD(mmc)) { start_cmd = SD_CMD_ERASE_WR_BLK_START; end_cmd = SD_CMD_ERASE_WR_BLK_END; @@ -72,7 +72,10 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) if (!mmc) return -1; - + if (blkcnt == 0) { + blkcnt = mmc->capacity/512 - (mmc->capacity/512)% mmc->erase_grp_size; // erase whole + printf("blkcnt = %lu\n",blkcnt); + } if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) printf("\n\nCaution! Your devices Erase group is 0x%x\n" "The erase range would be change to " @@ -82,7 +85,7 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) & ~(mmc->erase_grp_size - 1)) - 1); while (blk < blkcnt) { - blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? + blk_r = ((blkcnt - blk) < mmc->erase_grp_size) ? mmc->erase_grp_size : (blkcnt - blk); err = mmc_erase_t(mmc, start + blk, blk_r); if (err) @@ -92,10 +95,10 @@ unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) /* Waiting for the ready status */ if (mmc_send_status(mmc, timeout)) - return 0; + return 1; } - return blk; + return 0; } static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, diff --git a/drivers/usb/gadget/v2_burning/Makefile b/drivers/usb/gadget/v2_burning/Makefile new file mode 100644 index 0000000000..aa61f5a479 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/Makefile @@ -0,0 +1,41 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 +# +EXTRA_CFLAGS = -I./v2_common -I./v2_usb_tool -I./v2_sdc_burn + +obj-$(CONFIG_AML_V2_FACTORY_BURN) += aml_v2_burn.o + +aml_v2_burn-y = aml_v2_burning.o +aml_v2_burn-y += v2_common/optimus_download.o v2_common/optimus_buffer_manager.o v2_common/optimus_simg2img.o +aml_v2_burn-y += v2_common/optimus_progress.o v2_common/optimus_img_decoder.o v2_common/optimus_fat.o +aml_v2_burn-y += v2_sdc_burn/optimus_sdc_update.o v2_sdc_burn/optimus_sdc_burn.o v2_sdc_burn/optimus_ini_parser.o +aml_v2_burn-y += v2_sdc_burn/optimus_ini__aml_sdc_burn.o +aml_v2_burn-y += v2_usb_tool/optimus_core.o v2_usb_tool/optimus_transform.o +aml_v2_burn-y += v2_usb_burn/optimus_usb_burn.o v2_usb_burn/optimus_usb_update.o +aml_v2_burn-$(CONFIG_UNIFY_KEY_MANAGE) += v2_common/optimus_download_key.o +aml_v2_burn-$(CONFIG_SD_BURNING_SUPPORT_UI) += v2_common/optimus_progress_ui.o +aml_v2_burn-$(CONFIG_SD_BURNING_SUPPORT_LED) += v2_sdc_burn/optimus_led.o +aml_v2_burn-y += aml_sysrecovery/aml_sysrecovery.o +aml_v2_burn-$(CONFIG_DETECT_SYS_RECOVERY_KEY) += aml_sysrecovery/cmd_detect_sys_recovery_key.o +aml_v2_burn-$(CONFIG_SUPPORT_SDC_KEYBURN) += v2_sdc_burn/sdc_burnkeys/optimus_key_burn.o +aml_v2_burn-$(CONFIG_SUPPORT_SDC_KEYBURN) += v2_sdc_burn/sdc_burnkeys/sdc_keysprovider.o v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.o + diff --git a/drivers/usb/gadget/v2_burning/aml_sysrecovery/aml_sysrecovery.c b/drivers/usb/gadget/v2_burning/aml_sysrecovery/aml_sysrecovery.c new file mode 100644 index 0000000000..780cadf629 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/aml_sysrecovery/aml_sysrecovery.c @@ -0,0 +1,196 @@ +/* + * \file sysrecovery.c + * \brief + * + * \version 1.0.0 + * \date Friday,14/11/21 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2014 Amlogic. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" +#include "../v2_sdc_burn/optimus_sdc_burn_i.h" +#include "../v2_sdc_burn/optimus_led.h" + +#define CONFIG_AML_SYS_RECOVERY_CLEAR_USR_DATA 1 + +static int optimus_sysrec_check_whole_img_before_burn(const char* partName) +{ + //TODO: + return 0; +} + +#if CONFIG_AML_SYS_RECOVERY_CLEAR_USR_DATA +//clear data parts then the parts will formatted when firtsboot +//As fill half parttition need so much time, I just clear 2M +static int optimus_sysrec_clear_usr_data_parts(void) +{ + const char* const _usrDataParts[] = {"data",}; + const int dataPartsNum = sizeof(_usrDataParts)/sizeof(const char*); + const unsigned BufSz = 1U<<20;//1MB + unsigned char* clearBuf= (unsigned char*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + int partIndex = 0; + int ret = 0; + + memset(clearBuf, 0xff, BufSz); + for (partIndex = 0; partIndex < dataPartsNum; ++partIndex) + { + u64 partCap = 0; + unsigned char* thePart = (unsigned char*)_usrDataParts[partIndex]; + int rcode = 0; + u64 offset = 0; + u64 ClearSz = 2U<<20; + + DWN_MSG("To clear data part[%s]\n", thePart); + rcode = store_get_partititon_size(thePart, &partCap); + if (rcode) { + DWN_ERR("Fail to get partSz for part[%s]\n", thePart); + return rcode; + } + partCap <<= 9; + //FIXME: If there is fschk before firstboot, the 2MB to destroy the data if not enough + /*ClearSz = partCap>>1;*/ + DWN_MSG("partCap 0x%llxMB, ClearSz=%llxMb\n", (partCap>>20), (ClearSz>>20)); + + for (; offset < ClearSz; offset += BufSz) + { + rcode = store_write_ops(thePart, clearBuf, offset, BufSz); + if (rcode) { + DWN_ERR("Failed when clear data part[%s], rcode=%d\n", thePart, rcode); + ret += rcode; + } + } + } + + return ret; +} +#endif//#if CONFIG_AML_SYS_RECOVERY_CLEAR_USR_DATA + +/* + *.partName: aml_sysrecovery + *.needVerify: 1 then verify partitions that contain verify file; 0 then not to verify for faster burning + */ +static int optimus_sysrec_burn_package_from_partition(const char* partName, const unsigned needVerifyWhileBurn, + const unsigned verifyPackageBeforeBurn) +{ + extern ConfigPara_t g_sdcBurnPara ; + ConfigPara_t* pSdcCfgPara = &g_sdcBurnPara; + __hdle hUiProgress = NULL; + HIMAGE hImg = NULL; + int ret = 0; + + ret = optimus_storage_init(0);//Init all partitions for burning + + if (verifyPackageBeforeBurn) + { + ret = optimus_sysrec_check_whole_img_before_burn(partName); + if (ret) { + DWN_ERR("Failed in crc check the burning package.\n"); + return __LINE__; + } + } + + hImg = image_open("store", "0", AML_SYS_RECOVERY_PART, ""); + if (!hImg) { + DWN_ERR("Fail to open image in part %s\n", AML_SYS_RECOVERY_PART); + ret = __LINE__; goto _finish; + } + + if (video_res_prepare_for_upgrade(hImg)) { + DWN_ERR("Fail when prepare bm res or init video for upgrade\n"); + ret = __LINE__; goto _finish; + } + show_logo_to_report_burning(); + + hUiProgress = optimus_progress_ui_request_for_sdc_burn(); + if (!hUiProgress) { + DWN_ERR("request progress handle failed!\n"); + ret = __LINE__; goto _finish; + } + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STEPS_AFTER_DISK_INIT_OK); + + int hasBootloader = 0; + u64 datapartsSz = optimus_img_decoder_get_data_parts_size(hImg, &hasBootloader); + DWN_MSG("datapartsSz=[%8u]MB\n", (unsigned)(datapartsSz >> 20)); + ret = optimus_progress_ui_set_smart_mode(hUiProgress, datapartsSz, + UPGRADE_STEPS_FOR_BURN_DATA_PARTS_IN_PKG(!pSdcCfgPara->burnEx.bitsMap.mediaPath)); + if (ret) { + DWN_ERR("Fail to set smart mode\n"); + ret = __LINE__; goto _finish; + } + + pSdcCfgPara->burnParts.burn_num = 0; + ret = optimus_sdc_burn_partitions(pSdcCfgPara, hImg, hUiProgress, needVerifyWhileBurn); + if (ret) { + DWN_ERR("Fail when burn partitions\n"); + ret = __LINE__; goto _finish; + } + + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK); + +#if CONFIG_AML_SYS_RECOVERY_CLEAR_USR_DATA + optimus_sysrec_clear_usr_data_parts(); +#endif// #if CONFIG_AML_SYS_RECOVERY_CLEAR_USR_DATA +#if 1 + if (hasBootloader) + {//burn bootloader + ret = optimus_burn_bootlader(hImg); + if (ret) { + DWN_ERR("Fail in burn bootloader\n"); + goto _finish; + } + ret = optimus_set_burn_complete_flag(); + if (ret) { + DWN_ERR("Fail in set_burn_complete_flag\n"); + ret = __LINE__; goto _finish; + } + } +#endif + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STEPS_AFTER_BURN_BOOTLOADER_OK); + +_finish: + image_close(hImg); + optimus_progress_ui_report_upgrade_stat(hUiProgress, !ret); + optimus_report_burn_complete_sta(ret, 1/*pSdcCfgPara->custom.rebootAfterBurn*/); + optimus_progress_ui_release(hUiProgress); + //optimus_storage_exit();//temporary not exit storage driver when failed as may continue burning after burn + return ret; +} + +static int do_aml_sysrecovery(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + unsigned needVerify = (1 < argc) ? simple_strtoul(argv[1], NULL, 0) : 0; + unsigned verifyPackageBeforeBurn = (2 < argc) ? simple_strtoul(argv[2], NULL, 0) : 0; + + if (argc < 2 ) { + cmd_usage(cmdtp); + return __LINE__; + } + + show_logo_to_report_burning();//indicate enter flow of burning! when 'run update' + if (optimus_led_open(LED_TYPE_PWM)) { + DWN_ERR("Fail to open led for burn\n"); + return __LINE__; + } + optimus_led_show_in_process_of_burning(); + + optimus_work_mode_set(OPTIMUS_WORK_MODE_SYS_RECOVERY); + rcode = optimus_sysrec_burn_package_from_partition(AML_SYS_RECOVERY_PART, needVerify, verifyPackageBeforeBurn); + + return rcode; +} + +U_BOOT_CMD( + aml_sysrecovery, //command name + 3, //maxargs + 0, //repeatable + do_aml_sysrecovery, //command function + "Burning with amlogic format package from partition sysrecovery", //description + "argv: needVerify [,checkWholeImgBeforeBurn]\n"//usage + " --@needVerify: 0 then skip to verify the partition even have verify file." + " --@checkWholeImgBeforeBurn: 1 then crc32 check the burn package in partition sysrecovery before actual burn" + " eg:'aml_sysrecovery 0': burn from partition aml_sysrecovery without verify" +); + diff --git a/drivers/usb/gadget/v2_burning/aml_sysrecovery/cmd_detect_sys_recovery_key.c b/drivers/usb/gadget/v2_burning/aml_sysrecovery/cmd_detect_sys_recovery_key.c new file mode 100644 index 0000000000..0a33f97a24 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/aml_sysrecovery/cmd_detect_sys_recovery_key.c @@ -0,0 +1,108 @@ +/* + * \file cmd_detect_sys_recovery_key.c + * \brief Detect whether user want to enter sys_recovery + * + * \version 1.0.0 + * \date 14/11/25 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2014 Amlogic. All Rights Reserved. + * + */ +#include <config.h> +#include <common.h> +#include <asm/arch/io.h> +#include <command.h> +#include <malloc.h> +#include <amlogic/gpio.h> + +#define debugP(fmt...) //printf("L%d:", __LINE__),printf(fmt) +#define errorP(fmt...) printf("[ERR]L%d:", __LINE__),printf(fmt) +#define MsgP(fmt...) printf("[msg]"fmt) + +static int store_key_open(const char* keyName, const char* keyType) +{ + int pin = -1; + + pin=gpioname_to_pin(keyName); + if (pin<0) { + errorP("wrong gpio name %s\n",keyName); + return -1; + } + udelay(100); + + return pin; +} + +static int is_sys_recovery_key_pressed(int hKey) +{ + int val = -1; + + val=amlogic_get_value(hKey); + + return val != 1; +} + +static int assert_key_is_pressed_in_a_period(unsigned nMillSeconds, const char* keyName, const char* keyType) +{ + unsigned start = 0; + int hKey = -1; + + hKey = store_key_open(keyName, keyType); + if (hKey < 0) { + errorP("Fail to init key for aml_sysrecovery, hKey=%d\n", hKey); + return __LINE__; + } + + if (!is_sys_recovery_key_pressed(hKey)) { + return __LINE__; + } + + MsgP("pin=%d\n",hKey); + start = get_timer(0); + while (is_sys_recovery_key_pressed(hKey)) + { + const unsigned pressTime = (unsigned)get_timer(start) ; + if (pressTime > nMillSeconds) { + MsgP("store key pressed time %d[ms]\n", pressTime); + return 0; + } + } + if (!is_sys_recovery_key_pressed(hKey)) { + MsgP("key released in time %u[ms]\n", (unsigned)get_timer(start)); + return __LINE__; + } + + return 1;//restore key released in time @nMillSeconds +} + +//test If the recovery_key pressed time >= @nMillSeconds +int do_sys_rec_key(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + unsigned nMillSeconds = 0; + const char* keyName = NULL; + const char* keyType = "gpio"; + + if (2 > argc) { + cmd_usage(cmdtp); + return __LINE__; + } + + nMillSeconds = simple_strtoul(argv[1], NULL, 0); + keyName = argc > 2 ? argv[2] :"GPIOX_16"; + rcode = assert_key_is_pressed_in_a_period(nMillSeconds, keyName, keyType); + + return rcode; +} + + +U_BOOT_CMD( + get_restore_key, //command name + 5, //maxargs + 1, //repeatable + do_sys_rec_key, //command function + "check if user press sys_recovery key", //description + "Usage: sys_recovery nMillSeconds [GPIOX_16] [key_type]\n" //usage +); + diff --git a/drivers/usb/gadget/v2_burning/aml_v2_burning.c b/drivers/usb/gadget/v2_burning/aml_v2_burning.c new file mode 100644 index 0000000000..f8b19c30bc --- /dev/null +++ b/drivers/usb/gadget/v2_burning/aml_v2_burning.c @@ -0,0 +1,161 @@ +/* + * \file aml_v2_burning.c + * \brief common interfaces for version 2 burning + * + * \version 1.0.0 + * \date 09/15/2013 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#include "v2_burning_i.h" +#include <mmc.h> +#include <asm/arch/secure_apb.h> +#include <asm/arch/io.h> + +#ifndef BOOT_DEVICE_USB +#define BOOT_DEVICE_SD 4 +#define BOOT_DEVICE_USB 5 +#endif// #ifndef BOOT_DEVICE_USB + +extern int v2_usbburning(unsigned timeout); +extern int optimus_burn_package_in_sdmmc(const char* sdc_cfg_file); +extern void close_usb_phy_clock(int cfg); + +//check ${sdcburncfg} exist in external mmc and internal flash not burned yet! +static int aml_check_is_ready_for_sdc_produce(void) +{ + char* sdc_cfg_file = NULL; + const char* cmd = NULL; + int ret = 0; + + //if reboot_mode is MESON_SDC_BURNER_REBOOT, then this booting is skip_booted for sdc_burning + if (/*MESON_SDC_BURNER_REBOOT != reboot_mode*/ 0) { + /*DWN_MSG("reboot_mode=0x%x\n", (unsigned int)reboot_mode);*/ + return 1;//not ready + } + + cmd = "mmcinfo 0"; + ret = run_command(cmd, 0); + if (ret) { + DWN_MSG("mmcinfo failed!\n"); + return 0;//not ready + } + + sdc_cfg_file = getenv("sdcburncfg"); + if (!sdc_cfg_file) { + sdc_cfg_file = "aml_sdc_burn.ini"; + setenv("sdcburncfg", sdc_cfg_file); + } + + cmd = "fatexist mmc 0 ${sdcburncfg}"; + ret = run_command(cmd, 0); + if (ret) { + DWN_DBG("%s not exist in external mmc\n", sdc_cfg_file); + return 0; + } + + return 1;//is ready for sdcard producing +} + +static unsigned _get_romcode_boot_id(void) +{ + DWN_DBG("P_AO_SEC_GP_CFG0=0x%p\n", P_AO_SEC_GP_CFG0); + const unsigned boot_id = readl(P_AO_SEC_GP_CFG0) & 0xf; + + DWN_DBG("boot_id()=%x\n", boot_id); + return boot_id; +} + +//is the uboot loaded from usb otg +int is_tpl_loaded_from_usb(void) +{ + return (BOOT_DEVICE_USB == _get_romcode_boot_id()); +} + +//is the uboot loaded from sdcard mmc 0 +//note only sdmmc supported by romcode when external device boot +int is_tpl_loaded_from_ext_sdmmc(void) +{ + return (BOOT_DEVICE_SD == _get_romcode_boot_id()); +} + +//Check if uboot loaded from external sdmmc or usb otg +int aml_burn_check_uboot_loaded_for_burn(int flag) +{ + int usb_boot = is_tpl_loaded_from_usb(); + int sdc_boot = is_tpl_loaded_from_ext_sdmmc(); + + return usb_boot || sdc_boot; +} + +//1, is booted from external sdmmc: check if aml_sdc_burn.ini existed +//2, if loaded from usb, ready for burn +int aml_burn_check_is_ready_for_burn(int flag, bd_t* bis) +{ + if (is_tpl_loaded_from_usb()) { + return 1; + } + + if (is_tpl_loaded_from_ext_sdmmc()) + { + return aml_check_is_ready_for_sdc_produce(); + } + + return 0; +} + +//producing mode means boot from raw flash, i.e, uboot is loaded from usb +int aml_burn_usb_producing(int flag, bd_t* bis) +{ + flag = flag; bis = bis;//avoid compile warning + + optimus_work_mode_set(OPTIMUS_WORK_MODE_USB_PRODUCE); + + close_usb_phy_clock(0);//disconect before re-connect to enhance pc compatibility + return v2_usbburning(20000); +} + +int aml_burn_sdc_producing(int flag, bd_t* bis) +{ + optimus_work_mode_set(OPTIMUS_WORK_MODE_SDC_PRODUCE); + + return optimus_burn_package_in_sdmmc(getenv("sdcburncfg")); +} + +//burning flash from romboot stage +int aml_burn_factory_producing(int flag, bd_t* bis) +{ + if (is_tpl_loaded_from_usb()) + { + return aml_burn_usb_producing(flag, bis); + } + + if (is_tpl_loaded_from_ext_sdmmc()) + { + return aml_burn_sdc_producing(flag, bis); + } + + DWN_ERR("Shouldnot reach here!\n"); + return 0; +} + +int aml_try_factory_usb_burning(int flag, bd_t* bis) +{ + if (!is_tpl_loaded_from_usb()) return 1; + +#ifdef CONFIG_GENERIC_MMC + DWN_MSG("MMC init in usb\n"); + mmc_initialize(bis); +#endif + return aml_burn_usb_producing(flag, bis); +} + +int aml_try_factory_sdcard_burning(int flag, bd_t* bis) +{ + if (!is_tpl_loaded_from_ext_sdmmc()) return 1; + + return aml_burn_sdc_producing(flag, bis); +} + diff --git a/drivers/usb/gadget/v2_burning/v2_burning_i.h b/drivers/usb/gadget/v2_burning/v2_burning_i.h new file mode 100644 index 0000000000..97eb21e576 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_burning_i.h @@ -0,0 +1,41 @@ +/* + * \file v2_burning_i.h + * \brief internal include interfaces + * + * \version 1.0.0 + * \date 2013/11/4 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ + +#ifndef __V2_BURNING_I_H__ +#define __V2_BURNING_I_H__ + +#include <common.h> +#include <environment.h> +#include <asm/string.h> +#include <asm-generic/errno.h> +#include <asm/byteorder.h> +#include <malloc.h> +#include <u-boot/sha1.h> + +#ifdef CONFIG_MESON_TRUSTZONE +#include <asm/arch/trustzone.h> +#endif//#ifdef CONFIG_MESON_TRUSTZONE + +#include <amlogic/aml_v2_burning.h> +//#include <asm/arch/reboot.h> +#include <asm/arch/romboot.h> +//#include <amlogic/aml_lcd.h> +#include <amlogic/storage_if.h> +#include "v2_common/sparse_format.h" +#include "v2_common/optimus_download.h" +#include "v2_common/amlImage_if.h" +#include "v2_common/optimus_progress_ui.h" + +extern int cli_simple_parse_line(char *line, char *argv[]); + +#endif//ifndef __V2_BURNING_I_H__ + diff --git a/drivers/usb/gadget/v2_burning/v2_common/amlImage_if.h b/drivers/usb/gadget/v2_burning/v2_common/amlImage_if.h new file mode 100644 index 0000000000..15373c139e --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/amlImage_if.h @@ -0,0 +1,124 @@ +/* * \file amlImage_if.h + * \brief Amlogic firmware image interface + * + * \version 1.0.0 + * \date 2013/5/21 + * \author Sam.Wu <yihui.wu@Amlogic.com> + * + * Copyright (c) 2013 Amlogic Inc. All Rights Reserved. + * + */ +#ifndef __AMLIMAGE_IF_H__ +#define __AMLIMAGE_IF_H__ + +#define IMAGE_MAGIC 0x27b51956 /* Image Magic Number */ + +#define AML_FRMWRM_VER_V1 0X01 +#define AML_FRMWRM_VER_V2 0X02 +#define ITEM_NAME_LEN_V1 0X20 +#define ITEM_NAME_LEN_V2 0X100 + +typedef void* __hdle; + +#pragma pack(push,4) +typedef struct _AmlFirmwareItem_s +{ + __u32 itemId; + __u32 fileType; //image file type, sparse and normal + __u64 curoffsetInItem; //current offset in the item + const __u64 offsetInImage; //item offset in the image + const __u64 itemSz; //item size in the image + char itemMainType[ITEM_NAME_LEN_V1]; //item main type and sub type used to index the item + char itemSubType[ITEM_NAME_LEN_V1]; //item main type and sub type used to index the item + char reserve[32];//don't care fields +}ItemInfo_V1; +#pragma pack(pop) + +#pragma pack(push,4) +typedef struct _AmlFirmwareItem2_s +{ + __u32 itemId; + __u32 fileType; //image file type, sparse and normal + __u64 curoffsetInItem; //current offset in the item + const __u64 offsetInImage; //item offset in the image + const __u64 itemSz; //item size in the image + char itemMainType[ITEM_NAME_LEN_V2]; //item main type and sub type used to index the item + char itemSubType[ITEM_NAME_LEN_V2]; //item main type and sub type used to index the item + char reserve[32];//don't care fields +}ItemInfo_V2; +#pragma pack(pop) + +#pragma pack(push,4) +typedef struct _AmlFirmwareImg_s +{ + __u32 crc; //check sum of the image + __u32 version; //firmware version + __u32 magic; //magic No. to say it is Amlogic firmware image + __u64 imageSz; //total size of this image file + __u32 itemAlginSize; //align size for each item + __u32 itemNum; //item number in the image, each item a file + char reserve[36]; +}AmlFirmwareImg_t; +#pragma pack(pop) + + +typedef void* HIMAGE; +typedef void* HIMAGEITEM; + +#define IMAGE_ITEM_TYPE_NORMAL 0 +#define IMAGE_ITEM_TYPE_SPARSE 0XFE + +enum { + IMAGE_IF_TYPE_MMC = 0XEE, //read amlogic burning package from 'mmc 0/1' + IMAGE_IF_TYPE_USB , //read amlogic burning package from 'usb 0' + IMAGE_IF_TYPE_STORE , //read amlogic burning package using store interface +}; + +#define IMG_OFFSET_IN_PART 0 + +//open a Amlogic firmware image +//return value is a handle +HIMAGE image_open(const char* interface, const char* device, const char* part, const char* imgPath); + +//check the image's crc32 +//return 0 when check ok,otherwise return -1 +int image_check(HIMAGE hImg); + +//close a Amlogic firmware image +int image_close(HIMAGE hImg); + +//get item count of specify main type +int image_get_item_count(HIMAGE hImg, const char* mainType); + +//open a item in the image +//@hImage: image handle; +//@mainType, @subType: main type and subtype to index the item, such as ["IMAGE", "SYSTEM"] +HIMAGEITEM image_item_open(HIMAGE hImg, const char* mainType, const char* subType); + +//close a item +int image_item_close(HIMAGEITEM hItem); + +__u64 image_item_get_size(HIMAGEITEM hItem); + + +//get image item type, current used type is normal or sparse +int image_item_get_type(HIMAGEITEM hItem); + +//read item data, like standard fread +int image_item_read(HIMAGE hImg, HIMAGEITEM hItem, void* pBuf, const __u32 wantSz); + +//relocate the read pointer to read the item data, like standard fseek +int image_item_seek(HIMAGE , HIMAGEITEM , __s64 , __u32 ); + +unsigned image_item_get_first_cluster_size(HIMAGE hImg, HIMAGEITEM hItem); +unsigned image_get_cluster_size(HIMAGEITEM hImg);//Assert read offset and read size is multiple size of thsi unit + +int get_item_name(HIMAGE hImg, int itemId, const char** main_type, const char** sub_type); + +int get_total_itemnr(HIMAGE hImg); + +u64 optimus_img_decoder_get_data_parts_size(HIMAGE hImg, int* hasBootloader); + + +#endif//ifndef __AMLIMAGE_IF_H__ + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_buffer_manager.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_buffer_manager.c new file mode 100644 index 0000000000..71b533fc59 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_buffer_manager.c @@ -0,0 +1,320 @@ +/* + * \file optimus_buffer_manager.c + * \brief buffer manager for download data: A thin layer between receiving partition data and writing flash + * + * \version 1.0.0 + * \date 2013/5/2 + * \author Sam.Wu <yihui.wu@Amlogic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" + +#define OPTIMUS_SLOT_STA_FREE (0)//buffer slot not used yet +#define OPTIMUS_SLOT_STA_USED (0xee)//buffer slot current used for download +#define OPTIMUS_SLOT_STA_LEFT (0xdd)//buffer slot not disposed over + +#define PKT_TRANSFER_STA_EMPTY 0 +#define PKT_TRANSFER_STA_WORKING 1 +#define PKT_TRANSFER_STA_END 2 + +typedef struct bufManager{ + const u8* transferBuf;//transfer buffer address + const u32 transferBufSz;//transfer buffer size to + + const u32 transferUnitSz;//64k + u32 writeBackUnitSz;//for NAND is transferSz, for sparse is transferUnitSz + + u64 tplcmdTotalSz;//total size of a file-system packet + + u32 totalSlotNum;//total slot number that already tranfferred + u32 mediaAlignSz;//nand write align size, 16K/32k + + u32 nextWriteBackSlot;//when reach n* (writeBackUnitSz/transferUnitSz), then write back the recevied data to media + u32 leftDataSz;//left data size, Assert that 'leftDataInBackBuf + leftDataSz == transferBuf' + + s16 isUpload; + s16 pktTransferSta; + u32 destMediaType; + + u32 partBaseOffset;//TODO: change it to memory address when dest media type is memory + u32 itemOffsetNotAlignClusterSz_f;//For sdcard burning, item offset of aml_upgrade_package.img is not aligned to bytespercluster of FAT fs(_f means not changed inited) + +}BufManager; + +//TODO: if want to speed-up such as soft PING-PONG buffer, use multiple BufManager +static BufManager _bufManager = +{ +//constant members + .transferBuf = (const u8*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR, + .transferBufSz = OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ, + .transferUnitSz = OPTIMUS_DOWNLOAD_SLOT_SZ, + +//different for each command, note a command corresponding to a download file +//must create/destroy for a command + .writeBackUnitSz = OPTIMUS_DOWNLOAD_SLOT_SZ, + + .totalSlotNum = 0,//not slot data recevied yet! + + .leftDataSz = 0, + .tplcmdTotalSz = 0, + .nextWriteBackSlot = 0,//always 0 when upload?? + + .isUpload = 0, + .pktTransferSta = PKT_TRANSFER_STA_EMPTY, + + .itemOffsetNotAlignClusterSz_f = 0, +}; + +int optimus_buf_manager_init(const unsigned mediaAlignSz) +{ + if (OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR != (uint64_t)_bufManager.transferBuf) { + DWN_ERR("Fatal fail in init-express, init here instead!\n"); + return OPT_DOWN_FAIL; + } + _bufManager.mediaAlignSz = mediaAlignSz; + + DWN_DBG("transfer=0x%p, transferBufSz=0x%x, transferUnitSz=0x%x, writeBackUnitSz=0x%x, totalSlotNum=%d\n", _bufManager.transferBuf, + _bufManager.transferBufSz, _bufManager.transferUnitSz, _bufManager.writeBackUnitSz, _bufManager.totalSlotNum); + + return OPT_DOWN_OK; +} + +int optimus_buf_manager_exit(void) +{ + return 0; +} + +int optimus_buf_manager_tplcmd_init(const char* mediaType, const char* partName, const u64 partBaseOffset, + const char* imgType, const u64 pktTotalSz, const int isUpload, + const unsigned itemSizeNotAligned /* if item offset 3 and bytepercluste 4k, then it's 4k -3 */) +{ + u32 writeBackUnitSz = OPTIMUS_VFAT_IMG_WRITE_BACK_SZ; + const u64 pktSz4BufManager = pktTotalSz - itemSizeNotAligned; + + if (!strcmp("sparse", imgType) + || itemSizeNotAligned/* use max memory if item 'itemOffset % bytespercluster != 0'*/) + { + writeBackUnitSz = OPTIMUS_SIMG_WRITE_BACK_SZ; + } + + if (!strcmp("bootloader", partName)) + { + if (pktSz4BufManager > _bufManager.transferBufSz) { + DWN_ERR("packet size 0x%x too large, max is 0x%x\n", (u32)pktSz4BufManager, _bufManager.transferBufSz); + return OPT_DOWN_FAIL; + } + /*writeBackUnitSz = OPTIMUS_BOOTLOADER_MAX_SZ;*/ + writeBackUnitSz = pktSz4BufManager + _bufManager.transferUnitSz - 1; + writeBackUnitSz >>= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; + writeBackUnitSz <<= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; + } + + _bufManager.destMediaType = OPTIMUS_MEDIA_TYPE_STORE; + if (!strcmp("mem", mediaType)) + { + writeBackUnitSz = pktSz4BufManager + _bufManager.transferUnitSz - 1; + writeBackUnitSz >>= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; + writeBackUnitSz <<= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; + + _bufManager.destMediaType = OPTIMUS_MEDIA_TYPE_MEM; + + if (partBaseOffset>>32) { + DWN_ERR("partBaseOffset 0x%llx more than 4G!!\n", partBaseOffset); + return OPT_DOWN_FAIL; + } + _bufManager.partBaseOffset = (u32)partBaseOffset; + } + + if (_bufManager.transferBufSz < writeBackUnitSz && strcmp("mem", mediaType)) { + DWN_ERR("write back size 0x%x > max size 0x%x\n", writeBackUnitSz, _bufManager.transferBufSz); + return OPT_DOWN_FAIL; + } + if (_bufManager.transferUnitSz > writeBackUnitSz) { + DWN_ERR("write back size %d < align size %d\n", writeBackUnitSz, _bufManager.mediaAlignSz); + return OPT_DOWN_FAIL; + } + DWN_DBG("writeBackUnitSz = 0x%x, pktSz4BufManager = %lld\n", writeBackUnitSz, pktSz4BufManager); + + _bufManager.writeBackUnitSz = writeBackUnitSz; + _bufManager.totalSlotNum = 0; + _bufManager.isUpload = isUpload; + _bufManager.pktTransferSta = PKT_TRANSFER_STA_EMPTY; + + if (_bufManager.isUpload) + { + _bufManager.nextWriteBackSlot = 0;//always 0 if upload + } + else//has write back if download + { + if (pktSz4BufManager < writeBackUnitSz) + { + _bufManager.nextWriteBackSlot = ((u32)pktSz4BufManager + _bufManager.transferUnitSz - 1)/_bufManager.transferUnitSz;//first slot index to write back to media + } + else + { + _bufManager.nextWriteBackSlot = writeBackUnitSz/_bufManager.transferUnitSz;//first slot index to write back to media + } + + } + + _bufManager.itemOffsetNotAlignClusterSz_f = itemSizeNotAligned; + _bufManager.leftDataSz = itemSizeNotAligned;//data size in the buffer that not write back to media yet in previous transfer + _bufManager.tplcmdTotalSz = pktSz4BufManager; + + optimus_progress_init((u32)(_bufManager.tplcmdTotalSz>>32), (u32)_bufManager.tplcmdTotalSz, 0, 100); + DWN_MSG("totalSlotNum = %d, nextWriteBackSlot %d\n", _bufManager.totalSlotNum, _bufManager.nextWriteBackSlot); + + return OPT_DOWN_OK; +} + +int optimus_buf_manager_get_buf_for_bulk_transfer(char** pBuf, const unsigned wantSz, const unsigned sequenceNo, char* errInfo) +{ + const unsigned totalSlotNum = _bufManager.totalSlotNum; + const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz;//data size already transferred + const u64 leftPktSz = (totalTransferSz > _bufManager.tplcmdTotalSz) ? 0 :(_bufManager.tplcmdTotalSz - totalTransferSz); + const int isLastTransfer = (leftPktSz == wantSz);//totalTransferSz + wantSz >= _bufManager.tplcmdTotalSz; + const u32 bufSzNotDisposed = ((u32)totalTransferSz)% _bufManager.writeBackUnitSz;//buffer data not disposed, bufSz is always writeBackUnitSz + const u8* BufBase = (OPTIMUS_MEDIA_TYPE_MEM != _bufManager.destMediaType) ? _bufManager.transferBuf : + (u8*)(u64)_bufManager.partBaseOffset ; + + if (wantSz < _bufManager.transferUnitSz && !isLastTransfer) { + DWN_ERR("only last transfer can less 64K, this index %d at size 0x%u illegle\n", totalSlotNum + 1, wantSz); + return OPT_DOWN_FAIL; + } + + //TODO: totalSlotNum + 1 == sequenceNo + if (totalSlotNum + 1 != sequenceNo) {//ASSERT it ?? + + } + + *pBuf = (char*)(bufSzNotDisposed + BufBase); + DWN_DBG("bufSzNotDisposed 0x%x, _bufManager.transferBuf 0x%p, _bufManager.partBaseOffset 0x%x, *pBuf 0x%p\n", + bufSzNotDisposed, _bufManager.transferBuf, _bufManager.partBaseOffset, *pBuf); + + _bufManager.pktTransferSta = PKT_TRANSFER_STA_WORKING; + + //prepare data for upload + if (!bufSzNotDisposed && _bufManager.isUpload) + { + u32 wantSz = (leftPktSz > _bufManager.writeBackUnitSz) ? _bufManager.writeBackUnitSz : ((u32)leftPktSz); + DWN_DBG("want size 0x%x\n", wantSz); + + u32 readSz = optimus_dump_storage_data((u8*)BufBase, wantSz, errInfo); + if (readSz != wantSz) { + DWN_ERR("Want read %u, but %u\n", wantSz, readSz); + return OPT_DOWN_FAIL; + } + } + + return OPT_DOWN_OK; +} + +int optimus_buf_manager_report_transfer_complete(const u32 transferSz, char* errInfo) +{ + const unsigned totalSlotNum = _bufManager.totalSlotNum; + const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz + transferSz; + const u64 leftPktSz = (totalTransferSz > _bufManager.tplcmdTotalSz) ? 0 :(_bufManager.tplcmdTotalSz - totalTransferSz); + const u32 thisWriteBackSz = (_bufManager.transferUnitSz == transferSz) ? _bufManager.writeBackUnitSz : ((u32)totalTransferSz % _bufManager.writeBackUnitSz); + const u8* BufBase = (OPTIMUS_MEDIA_TYPE_MEM != _bufManager.destMediaType) ? _bufManager.transferBuf : + (u8*)(u64)_bufManager.partBaseOffset ; + + DWN_DBG("transferSz=0x%x\n", transferSz); + //state fileds to update + _bufManager.totalSlotNum += 1; + if (_bufManager.totalSlotNum == _bufManager.nextWriteBackSlot) + { + u32 burnSz = 0; + u32 leftSz = _bufManager.leftDataSz;//data size not write to media in previous write back, > 0 only when not normal packet + const u32 size = leftSz + thisWriteBackSz; + const u8* data = (u8*)BufBase -leftSz; + const unsigned reserveNotAlignSz = leftPktSz ? _bufManager.itemOffsetNotAlignClusterSz_f : 0;//reserve + + //call cb function to write to media + DWN_DBG("size 0x%x, reserveNotAlignSz 0x%x\n", size, reserveNotAlignSz); + burnSz = optimus_download_img_data(data, size - reserveNotAlignSz, errInfo); + if (burnSz <= leftSz || !burnSz) { + DWN_ERR("this burn size %d <= last left size %d, data 0x%p\n", burnSz, leftSz, data); + return OPT_DOWN_FAIL; + } + if (size - reserveNotAlignSz < burnSz) { + DWN_ERR("Exception:siz 0x%x < burnSz 0x%x\n", size - reserveNotAlignSz, burnSz); + return OPT_DOWN_FAIL; + } + + leftSz = size - burnSz; + if (leftSz) + { + const u8* src = data + burnSz; + u8* dest = (u8*)BufBase - leftSz; + + if (totalTransferSz >= _bufManager.tplcmdTotalSz) { + DWN_ERR("Exception:packet end but data left 0x%x, totalTransferSz 0x%llx, cmd sz 0x%llx!\n", + leftSz, totalTransferSz, _bufManager.tplcmdTotalSz); + return OPT_DOWN_FAIL; + } + + if (leftSz > OPTIMUS_SPARSE_IMG_LEFT_DATA_MAX_SZ) { + DWN_ERR("Exception, left data sz 0x%x > back buf sz 0x%x!\n", leftSz, OPTIMUS_SPARSE_IMG_LEFT_DATA_MAX_SZ); + return OPT_DOWN_FAIL; + } + if (leftSz & 0x03) { + DWN_ERR("Exception, copy size not align to 4! May will copy fail!\n"); + return OPT_DOWN_FAIL; + } + + DWN_DBG("MV:left size 0x%08x, src %p, dest %p\n", leftSz, src, dest); + memcpy(dest, src, leftSz); + } + + //update _bufManager.leftDataSz and _bufManager.nextWriteBackSlot + _bufManager.leftDataSz = leftSz; + if (leftPktSz >= _bufManager.writeBackUnitSz) + { + _bufManager.nextWriteBackSlot += _bufManager.writeBackUnitSz/_bufManager.transferUnitSz; + } + else + { + _bufManager.nextWriteBackSlot += ((u32)leftPktSz + _bufManager.transferUnitSz - 1)/_bufManager.transferUnitSz; + } + } + + optimus_update_progress(transferSz);//report burning steps + return OPT_DOWN_OK; +} + +int is_largest_data_transferring(void) +{ + const unsigned totalSlotNum = _bufManager.totalSlotNum; + const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz;//data size already transferred + + return (PKT_TRANSFER_STA_WORKING == _bufManager.pktTransferSta) + && (_bufManager.tplcmdTotalSz > totalTransferSz);//as last packet may less than 64k, var totalSlotNum may > _bufManager.tplcmdTotalSz +} + +int set_largest_data_transfer_sta_end(void) +{ + _bufManager.pktTransferSta = PKT_TRANSFER_STA_END; + return 0; +} + +//command data format: [0-3]reserver, [4-7]dataLen, [8-11]sequence number, [12-15]check sum +int optimus_buf_manager_get_command_data_for_upload_transfer(u8* cmdDataBuf, const unsigned bufLen) +{ + const unsigned totalSlotNum = _bufManager.totalSlotNum; + const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz; + const u64 leftPktSz = (totalTransferSz > _bufManager.tplcmdTotalSz) ? 0 :(_bufManager.tplcmdTotalSz - totalTransferSz); + const unsigned thisTransDataLen = (leftPktSz > _bufManager.transferUnitSz) ? _bufManager.transferUnitSz : ((u32)leftPktSz); + + DWN_DBG("thisTransDataLen 0x%x, left 0x%x, total 0x%x\n", thisTransDataLen, (u32)leftPktSz, (u32)totalTransferSz); + DWN_DBG("totalSlotNum %d, totalTransferSz 0x%x\n", totalSlotNum, (u32)totalTransferSz); + memset(cmdDataBuf, bufLen, 0); + *(unsigned*)(cmdDataBuf + 0) = 0xefe8; + *(unsigned*)(cmdDataBuf + 4) = thisTransDataLen;//Fill transfer data length of this bulk transfer + + _bufManager.pktTransferSta = PKT_TRANSFER_STA_WORKING; + return 0; +} + + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_download.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_download.c new file mode 100644 index 0000000000..51555fc01a --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_download.c @@ -0,0 +1,1319 @@ +/* + * \file optimu_download.c + * \brief + * + * \version 1.0.0 + * \date 2013/4/25 + * \author Sam.Wu <yihui.wu@amlogic.com> + * + * Copyright (c) 2013 Amlogic Inc. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" +#include <libfdt.h> + +#if defined(CONFIG_ACS) +#include <asm/arch/cpu.h> +#include <asm/arch/acs.h> +#include <partition_table.h> +#define MAGIC_ACS "acs_" +#endif//#if defined(CONFIG_ACS) + +extern unsigned int get_multi_dt_entry(unsigned int fdt_addr); +int is_optimus_storage_inited(void); + +#ifndef CONFIG_UNIFY_KEY_MANAGE +int v2_key_read(const char* keyName, u8* keyVal, const unsigned keyValLen, char* errInfo, unsigned* fmtLen) +{ + DWN_ERR("burn key not supported as CONFIG_UNIFY_KEY_MANAGE undef!!"); + return OPT_DOWN_FAIL; +} + +unsigned v2_key_burn(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo) +{ + DWN_ERR("burn key not supported as CONFIG_UNIFY_KEY_MANAGE undef!!"); + return OPT_DOWN_FAIL; +} +#endif//#ifndef CONFIG_UNIFY_KEY_MANAGE + + +#define IMG_VERIFY_ALG_NONE 0 //not need to veryfy +#define IMG_VERIFY_ALG_SHA1SUM 1 +#define IMG_VERIFY_ALG_CRC32 2 +#define IMG_VERIFY_ALG_ADDSUM 3 + +#define OPTIMUS_IMG_STA_EMPTY 0 +#define OPTIMUS_IMG_STA_PRE_BURN 1 //has get tplcmd load +#define OPTIMUS_IMG_STA_BURN_ING 2 +#define OPTIMUS_IMG_STA_BURN_COMPLETE 3 +#define OPTIMUS_IMG_STA_BURN_FAILED 4 +#define OPTIMUS_IMG_STA_VERIFY_ING 5 +#define OPTIMUS_IMG_STA_VERIFY_END 6 + +#define IMG_TYPE_SPARSE (0xfe) +#define IMG_TYPE_NORMAL 0 +#define IMG_TYPE_BOOTLOADER (0xfd) + +//Image info for burnning and verify +//FIXME: how to assert that image not larger than the partition +#define IMG_BURN_INFO_SZ 64 +struct ImgBurnInfo{ + u8 imgType; //0 normal, 1 sparse + u8 verifyAlgorithm;//0--sha1sum, 1--crc32, 2--addsum + u8 imgBurnSta;// + u8 storageMediaType;//NAND default, + u8 resrv4Align[4]; + + u64 nextMediaOffset;//image size already received + u64 imgPktSz;//total size of the file image + u64 imgSzDisposed;//total size alreay disposed + u64 partBaseOffset;//start offset of this part + + void* devHdle; + char partName[16];// + + u8 burnInfoPrivate[IMG_BURN_INFO_SZ - 16 - sizeof(void*) - sizeof(u64) * 5];//needed private info when verify, for example when we read ext4 to sparse file +}; + +static struct ImgBurnInfo OptimusImgBurnInfo = {0}; + +struct imgBurnInfo_sparse{ + +}; + +struct imgBurnInfo_normal{ +}; + +struct imgBurnInfo_bootloader{ + u32 transferBufAddr; + u32 transferBufSzTotal; + +}; + +COMPILE_TIME_ASSERT(IMG_BURN_INFO_SZ == sizeof(struct ImgBurnInfo)); + +#if defined(CONFIG_ACS) +#if 0 +static void _show_partition_table(const struct partitions* pPartsTab) +{ + int i=0; + const struct partitions* partInfo = pPartsTab; + + for (i=0; i < MAX_PART_NUM; i++, ++partInfo) + { + if (partInfo->size == -1) { + printf("part: %d, name : %10s, size : %-4s\n",i, partInfo->name, "end"); + break; + } + printf("part: %d, name : %10s, size : %-4llx\n",i, partInfo->name, partInfo->size); + } + + return; +} +#endif + +static int _check_partition_table_consistency(const unsigned uboot_bin) +{ + int rc = 0; + unsigned partitionTableSz = 0; + const int acsOffsetInSpl = START_ADDR - AHB_SRAM_BASE; + const int addrMapFromAhb2Bin = AHB_SRAM_BASE - uboot_bin; + + const struct acs_setting* acsSettingInBin = NULL; + unsigned partTabAddrInBin = 0; + const struct partitions* partsTabInBin = NULL; + + const struct acs_setting* acsSettingInSram = NULL; + const struct partitions* partsTabInSram = NULL; + + DWN_DBG("uboot_bin 0x%p, acsOffsetInSpl 0x%x, addrMapFromAhb2Bin 0x%x\n", uboot_bin, acsOffsetInSpl, addrMapFromAhb2Bin); + acsSettingInBin = (struct acs_setting*)(*(unsigned*)(uboot_bin + acsOffsetInSpl) - addrMapFromAhb2Bin); + + if ( (unsigned)acsSettingInBin >= uboot_bin + 64*1024 || (unsigned)acsSettingInBin <= uboot_bin) {//acs not in the spl + DWN_MSG("Acs not in the spl of uboot_bin\n"); + return 0; + } + + if (memcmp(MAGIC_ACS, acsSettingInBin->acs_magic, strlen(MAGIC_ACS)) + || memcmp(TABLE_MAGIC_NAME, acsSettingInBin->partition_table_magic, strlen(TABLE_MAGIC_NAME))) + { + DWN_MSG("acs magic OR part magic in ubootin not match\n"); + return 0;//Not to check partTable as acs magic or part magic not match in u-boot.bin, maybe encrypted by AMLETOOL + } + partTabAddrInBin = acsSettingInBin->partition_table_addr - addrMapFromAhb2Bin; + partsTabInBin = (const struct partitions*)partTabAddrInBin; + +#ifndef CONFIG_MESON_TRUSTZONE + acsSettingInSram = (struct acs_setting*)(*(unsigned*)START_ADDR); +#else + //twice eget value at sram address and copy 1K to memory + acsSettingInSram = (struct acs_setting*)meson_trustzone_acs_addr(START_ADDR); + DWN_MSG("[Trust]acsSettingInSram=0x%p\n", acsSettingInSram); +#endif// #ifndef CONFIG_MESON_TRUSTZONE + partsTabInSram = (const struct partitions*)acsSettingInSram->partition_table_addr; + DWN_MSG("partsTabInSram=0x%p\n", partsTabInSram); + + if (memcmp(MAGIC_ACS, acsSettingInSram->acs_magic, strlen(MAGIC_ACS)) + || memcmp(TABLE_MAGIC_NAME, acsSettingInSram->partition_table_magic, strlen(TABLE_MAGIC_NAME))) + { + DWN_MSG("acs magic OR part magic in SPL not match\n"); + return __LINE__;//Not to check partTable as acs magic or part magic not match in SRAM, assert this!! + } + +#ifdef CONFIG_MESON_TRUSTZONE + partsTabInSram = (const struct partitions*)meson_trustzone_acs_addr((unsigned)&acsSettingInSram->partition_table_addr); +#endif// #ifndef CONFIG_MESON_TRUSTZONE + + partitionTableSz = acsSettingInBin->partition_table_length; + DWN_MSG("acsSettingInBin=0x%x, partTabSz=0x%x\n", (unsigned int)acsSettingInBin, partitionTableSz); + + rc = memcmp(partsTabInSram, partsTabInBin, partitionTableSz); + DWN_MSG("Check parts table %s\n", !rc ? "OK." : "FAILED!"); +#if 0//I comment print as str-prefix function (strcmp, strcmp, and .etc) are all not reliable in uboot + if (rc) + { + DWN_MSG("acs_setting 0x%p, 0x%p\n", acsSettingInBin, acsSettingInSram); + DWN_MSG("partitions 0x%08x, 0x%p\n", partTabAddrInBin, partsTabInSram); + DWN_MSG("partition_table_addr 0x%x, 0x%x\n", acsSettingInSram->partition_table_addr, acsSettingInBin->partition_table_addr); + + DWN_MSG("part in ubootbin:\n"); + _show_partition_table(partsTabInBin); + + DWN_MSG("part in spl:\n"); + _show_partition_table(partsTabInSram); + return __LINE__; + } +#endif//#if 0 + + return rc; +} +#else +#define _check_partition_table_consistency(a) 0 +#endif//#if defined(CONFIG_ACS) + +#if 0 +//asset nand logical partition size equals CFG size in storage.c +//nand often make mistake this size, emmc should always ok +static int _assert_logic_partition_cap(const char* thePartName, const uint64_t nandPartCap) +{ + extern struct partitions * part_table; + + struct partitions * thePart = NULL; + + for (thePart = part_table; NAND_PART_SIZE_FULL != thePart->size; ++thePart) + { + const uint64_t partSzInBytes = thePart->size; + if (strcmp(thePartName, thePart->name)) continue; + if (partSzInBytes != nandPartCap) { + DWN_ERR("partSz in ACS %llx != flash Sz %llx\n", partSzInBytes, nandPartCap); + return __LINE__; + } + + break; + } + + return 0; +} +#else +#define _assert_logic_partition_cap(...) 0 +#endif + +//return value is the actual size it write +static int optimus_download_bootloader_image(struct ImgBurnInfo* pDownInfo, u32 dataSzReceived, const u8* data) +{ + int ret = OPT_DOWN_OK; + uint64_t size = dataSzReceived; + + if (dataSzReceived < pDownInfo->imgPktSz) { + DWN_ERR("please write back bootloader after all data rx end.0x(%x, %x)\n", dataSzReceived, (u32)pDownInfo->imgPktSz); + return 0; + } + + ret = _check_partition_table_consistency((unsigned)data); + if (ret) { + DWN_ERR("Fail in _check_partition_table_consistency\n"); + return 0; + } + if (size > (1U<<20)) { + DWN_ERR("uboot.bin size 0x%llx > 1M unsupported\n", size); + return 0; + } + + size = size <= 0x60000 ? 0x60000 : (1U<<20);//384K when non-secure_os, 1M when secure_os + ret = store_boot_write((unsigned char*)data, 0, size); + + return ret ? 0 : dataSzReceived; +} + +static int optimus_verify_bootloader(struct ImgBurnInfo* pDownInfo, u8* genSum) +{ + int ret = OPT_DOWN_OK; + unsigned char* pBuf = (unsigned char*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + uint64_t size = 0; + + /*size = 0x60000;////////////TODO:hardcode len!!*/ + size=pDownInfo->imgPktSz; + ret = store_boot_read(pBuf, (u64)0, size); + if (ret) { + DWN_ERR("Fail to read bootloader\n"); + return __LINE__; + } + + sha1_csum(pBuf, (u32)pDownInfo->imgPktSz, genSum); + + return ret; +} + + +u32 optimus_cb_simg_write_media(const unsigned destAddrInSec, const unsigned dataSzInBy, const char* data) +{ + int ret = OPT_DOWN_OK; + unsigned char* partName = (unsigned char*)OptimusImgBurnInfo.partName; + + if (OPTIMUS_MEDIA_TYPE_STORE < OptimusImgBurnInfo.storageMediaType) { + DWN_ERR("storage type %d not supported yet!\n", OptimusImgBurnInfo.storageMediaType); + return OPT_DOWN_FAIL; + } + + DWN_DBG("1addrOffset=0x%llx, dataSz=0x%x, data = 0x%p\t", (((u64)destAddrInSec)<<9), dataSzInBy, (void*)data); + //FIXME:why dirty value if not convert to u64 + ret = store_write_ops(partName, (u8*)data, (((u64)destAddrInSec)<<9), (u64)dataSzInBy); + if (ret) { + DWN_ERR("Fail to write to media, ret = %d\n", ret); + return 0; + } + + return dataSzInBy; +} + +//return value: the data size disposed +static u32 optimus_download_sparse_image(struct ImgBurnInfo* pDownInfo, u32 dataSz, const u8* data) +{ + u32 unParsedDataLen = 0; + int flashOffset = 0; + const u64 addrOffset = pDownInfo->nextMediaOffset; + + flashOffset = optimus_simg_to_media((char*)data, dataSz, &unParsedDataLen, ((u32)(addrOffset>>9))); + if (flashOffset < 0) { + DWN_ERR("Fail in parse simg. src 0x%p, size 0x%x, unParsedDataLen 0x%x, ret %d\n", data, dataSz, unParsedDataLen, flashOffset); + return 0; + } + pDownInfo->nextMediaOffset += ((u64)flashOffset)<<9; + + return dataSz - unParsedDataLen; +} + +//Normal image can write directly to NAND, best aligned to 16K when write +//FIXME: check it aligned to 16K when called +//1, write to media 2 -- save the verify info +static u32 optimus_download_normal_image(struct ImgBurnInfo* pDownInfo, u32 dataSz, const u8* data) +{ + int ret = 0; + u64 addrOrOffsetInBy = pDownInfo->nextMediaOffset; + + DWN_DBG("addrOffset=0x%llx, dataSz=0x%x, data = 0x%p\n", addrOrOffsetInBy, dataSz, data); + + ret = store_write_ops((u8*)pDownInfo->partName, (u8*)data, addrOrOffsetInBy, (u64)dataSz); + if (ret) { + DWN_ERR("Fail to write to media\n"); + return 0; + } + + pDownInfo->nextMediaOffset += dataSz; + + return dataSz; +} + +static int optimus_storage_open(struct ImgBurnInfo* pDownInfo, const u8* data, const u32 dataSz) +{ + int ret = OPT_DOWN_OK; + const char* partName = (const char*)pDownInfo->partName; + const int imgType = pDownInfo->imgType; + const int MediaType = pDownInfo->storageMediaType; + + if (!pDownInfo->imgSzDisposed && OPTIMUS_IMG_STA_PRE_BURN == pDownInfo->imgBurnSta) + { + DWN_MSG("Burn Start...\n"); + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_BURN_ING; + } + else if(pDownInfo->imgSzDisposed == pDownInfo->imgPktSz && OPTIMUS_IMG_STA_BURN_COMPLETE == pDownInfo->imgBurnSta) + { + DWN_MSG("Verify Start...\n"); + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_VERIFY_ING; + } + + switch (MediaType) + { + case OPTIMUS_MEDIA_TYPE_NAND: + case OPTIMUS_MEDIA_TYPE_SDMMC: + case OPTIMUS_MEDIA_TYPE_STORE: + { + if (IMG_TYPE_BOOTLOADER != pDownInfo->imgType && !pDownInfo->devHdle) //if not bootloader and device not open + { + /*pDownInfo->devHdle = aml_nftl_get_dev(partName);*/ + pDownInfo->devHdle = (void*)1; + if (!pDownInfo->devHdle) { + DWN_ERR("Fail to open nand part %s\n", partName); + return OPT_DOWN_FAIL; + } + + if (IMG_TYPE_SPARSE == imgType) + { + ret = optimus_simg_probe(data, dataSz); + if (!ret) { + DWN_ERR("Fail in sparse format probe,ret=%d\n", ret); + return OPT_DOWN_FAIL; + } + return optimus_simg_parser_init(data); + } + } + else//is bootloader, than do nothing + { + return OPT_DOWN_OK; + } + } + break; + + case OPTIMUS_MEDIA_TYPE_KEY_UNIFY: + break; + + case OPTIMUS_MEDIA_TYPE_MEM: + break; + + default: + DWN_MSG("Error MediaType %d\n", MediaType); + return OPT_DOWN_FAIL; + } + + return ret; +} + +static int optimus_storage_close(struct ImgBurnInfo* pDownInfo) +{ + if (pDownInfo->imgSzDisposed == pDownInfo->imgPktSz && OPTIMUS_IMG_STA_BURN_ING == pDownInfo->imgBurnSta) + { + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_BURN_COMPLETE; + DWN_MSG("Burn complete\n"); + + return OPT_DOWN_OK; + } + + if (!pDownInfo->imgSzDisposed && OPTIMUS_IMG_STA_VERIFY_ING == pDownInfo->imgBurnSta) + { + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_VERIFY_END; + DWN_MSG("Verify End\n"); + return OPT_DOWN_OK; + } + + return OPT_DOWN_OK; +} + + +//return value is the data size that actual dealed +static u32 optimus_storage_write(struct ImgBurnInfo* pDownInfo, u64 addrOrOffsetInBy, unsigned dataSz, const u8* data, char* errInfo) +{ + u32 burnSz = 0; + const u32 imgType = pDownInfo->imgType; + const int MediaType = pDownInfo->storageMediaType; + + addrOrOffsetInBy += pDownInfo->partBaseOffset; + DWN_DBG("[0x]Data %p, addrOrOffsetInBy %llx, dataSzInBy %x\n", data, addrOrOffsetInBy, dataSz); + + if (OPTIMUS_IMG_STA_BURN_ING != pDownInfo->imgBurnSta) { + sprintf(errInfo, "Error burn sta %d\n", pDownInfo->imgBurnSta); + DWN_ERR(errInfo); + return 0; + } + + switch (MediaType) + { + case OPTIMUS_MEDIA_TYPE_NAND: + case OPTIMUS_MEDIA_TYPE_SDMMC: + case OPTIMUS_MEDIA_TYPE_STORE: + { + switch (imgType) + { + case IMG_TYPE_NORMAL: + burnSz = optimus_download_normal_image(pDownInfo, dataSz, data); + break; + + case IMG_TYPE_BOOTLOADER: + burnSz = optimus_download_bootloader_image(pDownInfo, dataSz, data); + break; + + case IMG_TYPE_SPARSE: + burnSz = optimus_download_sparse_image(pDownInfo, dataSz, data); + break; + + default: + DWN_ERR("error image type %d\n", imgType); + } + } + break; + + case OPTIMUS_MEDIA_TYPE_KEY_UNIFY: + { + burnSz = v2_key_burn(pDownInfo->partName, data, dataSz, errInfo); + if (burnSz != dataSz) {//return value is write size + DWN_ERR("burn key failed\n"); + return 0; + } + } + break; + + case OPTIMUS_MEDIA_TYPE_MEM: + { + u8* buf = (u8*)addrOrOffsetInBy; + if (buf != data) { + DWN_ERR("buf(%llx) != data(%p)\n", addrOrOffsetInBy, data); + return 0; + } + if (!strcmp("dtb", pDownInfo->partName)) //as memory write back size = min[fileSz, 2G], so reach here if downloaded ok! + { + int rc = 0; + char* dtbLoadAddr = NULL;//(char*)CONFIG_DTB_LOAD_ADDR; + const int DtbMaxSz = (2U<<20); + unsigned fdtSz = 0; + unsigned char* destDtb = (unsigned char*)data; + + //Make sure flash already inited before 'run aml_dt' + //old tool will download dtb before 'disk_initial', but new tool will 'disk_initial' first + if (is_optimus_storage_inited() || + (OPTIMUS_WORK_MODE_USB_PRODUCE != optimus_work_mode_get())) + { + /*destDtb = (unsigned char*)(uint64_t)get_multi_dt_entry((unsigned int)data);*/ + destDtb = NULL; + } + rc = fdt_check_header(destDtb); + if (rc) { + sprintf(errInfo, "failed at fdt_check_header\n"); + DWN_ERR(errInfo); + return 0; + } + fdtSz = fdt_totalsize(destDtb); + if (DtbMaxSz <= fdtSz) { + sprintf(errInfo, "failed: fdt header ok but sz 0%x > max 0x%x\n", fdtSz, DtbMaxSz); + DWN_ERR(errInfo); + return 0; + } + + DWN_MSG("load dtb to 0x%p\n", dtbLoadAddr); + memcpy(dtbLoadAddr, destDtb, fdtSz); + } + + burnSz = dataSz; + } + break; + + default: + sprintf(errInfo, "Error MediaType %d\n", MediaType); + DWN_ERR(errInfo); + } + + return burnSz; +} + +//TODO: to consist with optimus_storage_write, return value should be readSzInBy +static int optimus_storage_read(struct ImgBurnInfo* pDownInfo, u64 addrOrOffsetInBy, + unsigned readSzInBy, unsigned char* buff, char* errInfo) +{ + int ret = 0; + const int MediaType = pDownInfo->storageMediaType; + unsigned char* partName = (unsigned char*)pDownInfo->partName; + + addrOrOffsetInBy += pDownInfo->partBaseOffset; + + switch (MediaType) + { + case OPTIMUS_MEDIA_TYPE_NAND: + case OPTIMUS_MEDIA_TYPE_SDMMC: + case OPTIMUS_MEDIA_TYPE_STORE: + { + if (IMG_TYPE_BOOTLOADER == pDownInfo->imgType) + { + ret = store_boot_read(buff, addrOrOffsetInBy, (u64)readSzInBy); + } + else + { + ret = store_read_ops(partName, buff, addrOrOffsetInBy, (u64)readSzInBy); + } + if (ret) { + if (errInfo) sprintf(errInfo, "Read failed\n") ; + DWN_ERR("Read failed\n"); + return OPT_DOWN_FAIL; + } + + } + break; + + case OPTIMUS_MEDIA_TYPE_KEY_UNIFY: + { + unsigned fmtLen = 0; + if (addrOrOffsetInBy) { + DWN_ERR("OH NO, IS key len > 64K!!? addrOrOffsetInBy is 0x%llx not 0\n", addrOrOffsetInBy); + return OPT_DOWN_FAIL; + } + ret = v2_key_read(pDownInfo->partName, buff, readSzInBy, errInfo, &fmtLen); + } + break; + + case OPTIMUS_MEDIA_TYPE_MEM: + { + u8* buf = (u8*)addrOrOffsetInBy; + if (addrOrOffsetInBy >> 32) { + DWN_ERR("mem addr 0x%llx too large\n", addrOrOffsetInBy); + } + if (buf != buff) { + DWN_ERR("buf(%llx) != buff(%p)\n", addrOrOffsetInBy, buff); + } + } + break; + + default: + DWN_MSG("Error MediaType %d\n", MediaType); + return OPT_DOWN_FAIL; + } + + return ret; +} + +//return value is the size actual write to media +//Paras: const char* partName, const char* imgType, const char* verifyAlgorithm +static u32 optimus_func_download_image(struct ImgBurnInfo* pDownInfo, u32 dataSz, const u8* data, char* errInfo) +{ + int burnSz = 0; + int ret = 0; + u64 nextMediaOffset = pDownInfo->nextMediaOffset; + + DWN_DBG("data=0x%p, sz=0x%x, offset=%llx\n", data, dataSz, nextMediaOffset); + + ret = optimus_storage_open(pDownInfo, data, dataSz); + if (OPT_DOWN_OK != ret) { + sprintf(errInfo, "Fail to open stoarge\n"); + DWN_ERR(errInfo); + return 0; + } + + burnSz = optimus_storage_write(pDownInfo, nextMediaOffset, dataSz, data, errInfo); + if (!burnSz) { + DWN_ERR("Fail in optimus_storage_write, data 0x%p, wantSz 0x%x\n", data, dataSz); + goto _err; + } + pDownInfo->imgSzDisposed += burnSz; + + ret = optimus_storage_close(pDownInfo); + if (ret) { + DWN_ERR("Fail to close media\n"); + return 0; + } + + return burnSz; + +_err: + optimus_storage_close(pDownInfo); + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_BURN_FAILED;//// + return 0; +} + +//TODO: add _errInfo as argument to pass more info +static int _parse_img_download_info(struct ImgBurnInfo* pDownInfo, const char* partName, + const u64 imgSz, const char* imgType, const char* mediaType, const u64 partBaseOffset) +{ + u64 partCap = 0; + int ret = 0; + + memset(pDownInfo, 0, sizeof(struct ImgBurnInfo));//clear burnning info + + //TODO: check format is normal/bootloader if upload!! + + if (!strcmp("sparse", imgType)) + { + pDownInfo->imgType = IMG_TYPE_SPARSE; + } + else if(!strcmp("bootloader", partName)) + { + pDownInfo->imgType = IMG_TYPE_BOOTLOADER; + } + else if(!strcmp("normal", imgType)) + { + pDownInfo->imgType = IMG_TYPE_NORMAL; + } + else{ + DWN_ERR("err image type %s\n", imgType); + return __LINE__; + } + + if (!strcmp("store", mediaType)) + { + pDownInfo->storageMediaType = OPTIMUS_MEDIA_TYPE_STORE; + } + else if(!strcmp("nand", mediaType)) + { + pDownInfo->storageMediaType = OPTIMUS_MEDIA_TYPE_NAND; + } + else if(!strcmp("sdmmc", mediaType)) + { + pDownInfo->storageMediaType = OPTIMUS_MEDIA_TYPE_SDMMC; + } + else if(!strcmp("spiflash", mediaType)) + { + pDownInfo->storageMediaType = OPTIMUS_MEDIA_TYPE_SPIFLASH; + } + else if(!strcmp("key", mediaType)) + { + pDownInfo->storageMediaType = OPTIMUS_MEDIA_TYPE_KEY_UNIFY; + + if (OPTIMUS_DOWNLOAD_SLOT_SZ <= imgSz) { + DWN_ERR("size (0x%llx) for key %s invalid!!\n", imgSz, partName); + return __LINE__; + } + } + else if(!strcmp("mem", mediaType)) + { + pDownInfo->storageMediaType = OPTIMUS_MEDIA_TYPE_MEM; + } + else{ + DWN_ERR("error mediaType %s\n", mediaType); + return __LINE__; + } + + pDownInfo->partBaseOffset = partBaseOffset; + memcpy(pDownInfo->partName, partName, strlen(partName)); + + if (OPTIMUS_MEDIA_TYPE_MEM > pDownInfo->storageMediaType) //if command for burning partition + { + if (strcmp("bootloader", partName)) //get size if not bootloader + { + ret = store_get_partititon_size((u8*)partName, &partCap); + if (ret) { + DWN_ERR("Fail to get size for part %s\n", partName); + return __LINE__; + } + partCap <<= 9;//trans sector to byte + DWN_MSG("flash LOGIC partCap 0x%llxB\n", partCap); + if (imgSz > partCap) { + DWN_ERR("imgSz 0x%llx out of cap 0x%llx\n", imgSz, partCap); + return __LINE__; + } + ret = _assert_logic_partition_cap(partName, partCap); + if (ret) { + DWN_ERR("Fail in _assert_logic_partition_cap\n"); + return __LINE__; + } + } + } + + pDownInfo->nextMediaOffset = pDownInfo->imgSzDisposed = 0; + pDownInfo->imgPktSz = imgSz; + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_PRE_BURN; + + DWN_MSG("Down(%s) part(%s) sz(0x%llx) fmt(%s)\n", mediaType, partName, pDownInfo->imgPktSz, imgType); + + return 0; +} + +int optimus_download_init(void) +{ + memset(&OptimusImgBurnInfo, 0, sizeof(struct ImgBurnInfo)); + return 0; +} + +int optimus_download_exit(void) +{ + return 0; +} + +int optimus_parse_img_download_info(const char* partName, const u64 imgSz, const char* imgType, const char* mediaType, const u64 partBaseOffset) +{ + return _parse_img_download_info(&OptimusImgBurnInfo, partName, imgSz, imgType, mediaType, partBaseOffset); +} + +static int _disk_intialed_ok = 0; + +int is_optimus_storage_inited(void) +{ + return _disk_intialed_ok; +} + +int optimus_storage_init(int toErase) +{ + int ret = 0; + char* cmd = NULL; + + if (_disk_intialed_ok) {//To assert only actual disk intialed once + DWN_MSG("Disk inited again.\n"); + return 0; + } + + if (OPTIMUS_WORK_MODE_USB_PRODUCE != optimus_work_mode_get()) //Already inited in other work mode + { + DWN_MSG("Exit before re-init\n"); + store_exit(); + } + + switch (toErase) + { + case 0://NO erase + ret = store_init(1); + break; + + case 3://erase all(with key) + { + cmd = "store disprotect key"; + DWN_MSG("run cmd [%s]\n", cmd); + ret = run_command(cmd, 0); + if (ret) { + DWN_ERR("Fail when run cmd[%s], ret %d\n", cmd, ret); + break; + } + } + case 1://normal erase, store init 3 + ret = store_init(3); + break; + + case 4://force erase all + { + cmd = "store disprotect key; store disprotect hynix"; + DWN_MSG("run cmd [%s]\n", cmd); + ret = run_command(cmd, 0); + if (ret) { + DWN_ERR("Fail when run cmd[%s], ret %d\n", cmd, ret); + break; + } + } + case 2: + ret = store_init(4); + break; + + default: + DWN_ERR("Unsupported erase flag %d\n", toErase); ret = -__LINE__; + break; + } + + if (!ret) + { + _disk_intialed_ok = 1; + _disk_intialed_ok += toErase <<16; + + if (OPTIMUS_WORK_MODE_USB_PRODUCE == optimus_work_mode_get()) //env not relocated in this case + { + DWN_MSG("usb producing env_relocate\n"); + env_relocate(); + } + } + + return ret; +} + +int optimus_storage_exit(void) +{ + _disk_intialed_ok = 0; + DWN_MSG("store_exit yet!!\n"); + return store_exit(); +} + +int is_optimus_on_burn(void)//is now transfering image +{ + return (OPTIMUS_IMG_STA_BURN_ING == OptimusImgBurnInfo.imgBurnSta); +} + +int is_optimus_pre_burn(void) //is now has get "download command" +{ + return (OPTIMUS_IMG_STA_PRE_BURN == OptimusImgBurnInfo.imgBurnSta); +} + +int is_optimus_to_burn_ready(void) +{ + return (OPTIMUS_IMG_STA_PRE_BURN == OptimusImgBurnInfo.imgBurnSta); +} + +int is_optimus_burn_complete(void) +{ + int is_burn_completed = 0; + + is_burn_completed = (OPTIMUS_IMG_STA_BURN_COMPLETE == OptimusImgBurnInfo.imgBurnSta); + if (!is_burn_completed) { + DWN_MSG("imgSzDisposed 0x%llx != imgPktSz 0x%llx\n", OptimusImgBurnInfo.imgSzDisposed, OptimusImgBurnInfo.imgPktSz); + } + + return is_burn_completed; +} + +u32 optimus_download_img_data(const u8* data, const u32 size, char* errInfo) +{ + return optimus_func_download_image(&OptimusImgBurnInfo, size, data, errInfo); +} + +static int optimus_sha1sum_verify_partition(const char* partName, const u64 verifyLen, const u8 imgType, u8* genSum) +{ + int ret = 0; + u8* buff = (u8*) OPTIMUS_SHA1SUM_BUFFER_ADDR; + const u32 buffSz = OPTIMUS_SHA1SUM_BUFFER_LEN; + sha1_context ctx; + u64 leftLen = verifyLen; + + if (strcmp(partName, OptimusImgBurnInfo.partName)) { + DWN_ERR("partName %s err, must %s\n", partName, OptimusImgBurnInfo.partName); + return OPT_DOWN_FAIL; + } + + if (!is_optimus_burn_complete()) { + return OPT_DOWN_FAIL; + } + + memset(buff, 0xde, 1024);//clear 1kb data before verfiy, in case read buffer not overlapped + if (IMG_TYPE_BOOTLOADER == imgType) + { + return optimus_verify_bootloader(&OptimusImgBurnInfo, genSum); + } + else if(IMG_TYPE_SPARSE == imgType)//sparse image + { + ret = optimus_sparse_back_info_probe(); + if (OPT_DOWN_TRUE != ret) { + DWN_ERR("Fail to probe back sparse info\n"); + return OPT_DOWN_FAIL; + } + } + + ret = optimus_storage_open(&OptimusImgBurnInfo, NULL, 0); + if (ret) { + DWN_ERR("Fail to open storage for read\n"); + return OPT_DOWN_FAIL; + } + + sha1_starts(&ctx); + + DWN_MSG("To verify part %s in fmt %s\n", partName, (IMG_TYPE_SPARSE == imgType) ? "sparse": "normal"); + if (IMG_TYPE_SPARSE == imgType) //sparse image + { + for (; leftLen;) + { + u32 spHeadSz = 0; + u32 chunkDataLen = 0; + u64 chunkDataOffset = 0; + u8* head = NULL; + + ret = optimus_sparse_get_chunk_data(&head, &spHeadSz, &chunkDataLen, &chunkDataOffset); + if (ret) { + DWN_ERR("Fail to get chunk data\n"); + goto _finish; + } + + sha1_update(&ctx, head, spHeadSz); + + leftLen -= spHeadSz + chunkDataLen;//update image read info + + for (;chunkDataLen;) + { + const int thisReadLen = (chunkDataLen > buffSz) ? buffSz : chunkDataLen; + + ret = optimus_storage_read(&OptimusImgBurnInfo, chunkDataOffset, thisReadLen, buff, NULL); + if (ret) { + DWN_ERR("Fail to read at offset 0x[%x, %8x], len=0x%8x\n", ((u32)(chunkDataOffset>>32)), (u32)chunkDataOffset, thisReadLen); + goto _finish; + } + + sha1_update(&ctx, buff, thisReadLen); + + chunkDataLen -= thisReadLen; + chunkDataOffset += thisReadLen; + } + + if (leftLen && !spHeadSz) { + DWN_ERR("Fail to read when pkt len left 0x%x\n", (u32)leftLen); + break; + } + } + } + else//normal image + { + for (; leftLen;) + { + int thisReadLen = (leftLen > buffSz) ? buffSz : ((u32)leftLen); + u64 addrOffset = verifyLen - leftLen; + + ret = optimus_storage_read(&OptimusImgBurnInfo, addrOffset, thisReadLen, buff, NULL); + if (ret) { + DWN_ERR("Fail to read at offset 0x[%x, %8x], len=0x%8x\n", ((u32)(addrOffset>>32)), (u32)addrOffset, thisReadLen); + goto _finish; + } + + sha1_update(&ctx, buff, thisReadLen); + + leftLen -= thisReadLen; + } + + } + +_finish: + OptimusImgBurnInfo.imgSzDisposed = leftLen; + sha1_finish(&ctx, genSum); + optimus_storage_close(&OptimusImgBurnInfo); + + return ret; +} + +//usage: verify sha1sum nand srcSum part_name size imgType +int optimus_media_download_verify(const int argc, char * const argv[], char *info) +{ + const char* verifyType = argv[1]; + const char* srcSum = argv[2]; + static u8 verifyResult[20]; + static char sha1Result[42]; + const u8 srcImgType = OptimusImgBurnInfo.imgType; + const char* partName = OptimusImgBurnInfo.partName; + u64 verifyLen = OptimusImgBurnInfo.imgPktSz; + int ret = 0; + + if (argc != 3) { + strcpy(info, "failed:need 3 args\n"); + printf(info); + return -1; + } + + if (strcmp(verifyType, "sha1sum")) { + ret = __LINE__; + sprintf(info, "verifyType [%s] err, ret %d!\n", verifyType, ret); + DWN_ERR(info); + return ret; + } + + ret = optimus_sha1sum_verify_partition(partName, verifyLen, srcImgType, verifyResult); + if (ret) { + DWN_ERR("Fail to gen check sum\n"); + return __LINE__; + } + + ret = optimus_hex_data_2_ascii_str(verifyResult, 20, sha1Result, 42); + if (ret) { + DWN_ERR("Failed when format sha1 to string\n"); + return __LINE__; + } + + /*DWN_MSG("%s %s\n", verifyType, sha1Result);*/ + ret = strcmp(sha1Result, srcSum); + if (ret) { + sprintf(info, "failed:Verify Failed with %s, origin sum \"%s\" != gen sum \"%s\"\n", verifyType, srcSum, sha1Result); + DWN_ERR(info); + return __LINE__; + } + + DWN_MSG("VERIFY OK \n"); + return ret; +} + +int optimus_key_burn_init(const char* keyType) +{ + int ret = 0; + + if (!strcmp("efuse", keyType)) + { + return ret; + } + + if (!strcmp("secure", keyType)) + { + return ret; + } + + DWN_ERR("unsported key type %s\n", keyType); + return OPT_DOWN_FAIL; +} + +//update tplcmd dev0 "download nand part_name imageType imgSz" +//update tplcmd dev0 "download get_status" +int optimus_parse_download_cmd(int argc, char* argv[]) +{ + const int isUpload = !strcmp("upload", argv[0]); + const char* mediaType = argv[1]; + const char* part_name = argv[2]; + const char* imgType = argv[3]; + const char* imgSzStr = argv[4]; + u64 imgSzInBy = 0; + u64 partBaseOffset = 0; + int ret = 0; + + if (!strcmp("get_status", mediaType)) + { + return !is_optimus_burn_complete(); + } + + if (!strcmp("is_ready", mediaType)) + { + return !is_optimus_to_burn_ready(); + } + + if (5 > argc) { + printf("argc[%d] too few, use \"download nand part_name imageType imgSz\"\n", argc); + return __LINE__; + } + + imgSzInBy = simple_strtoull(imgSzStr, NULL, 0); + + if (!strcmp("mem", mediaType)) + { + char* endp = NULL; + partBaseOffset = simple_strtoull(part_name, &endp, 0); + if (0 != *endp) //not a valid 0-terminated c string + { + if (!strcmp("dtb", part_name)) + { + partBaseOffset = OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + DWN_MSG("dtb boot down to %llx\n", partBaseOffset); + } + } + } + + ret = optimus_parse_img_download_info(part_name, imgSzInBy, imgType, mediaType, partBaseOffset); + if (ret) { + DWN_ERR("Fail in init download info\n"); + return __LINE__; + } + + ret = optimus_buf_manager_tplcmd_init(mediaType, part_name, partBaseOffset, imgType, imgSzInBy, isUpload, 0); + if (ret) { + DWN_ERR("Fail in init download info\n"); + return __LINE__; + } + + return OPT_DOWN_OK; +} + +u32 optimus_dump_storage_data(u8* pBuf, const u32 wantSz, char* errInfo) +{ + struct ImgBurnInfo* pDownInfo = &OptimusImgBurnInfo; + u64 nextMediaOffset = pDownInfo->nextMediaOffset; + int ret = 0; + + DWN_DBG("pBuf=0x%p, wantSz=0x%x, nextMediaOffset=%x\n", pBuf, wantSz, (u32)nextMediaOffset); + + ret = optimus_storage_open(pDownInfo, pBuf, wantSz); + if (OPT_DOWN_OK != ret) { + sprintf(errInfo, "Fail to open stoarge\n"); + DWN_ERR(errInfo); + return 0; + } + + ret = optimus_storage_read(pDownInfo, nextMediaOffset, wantSz, pBuf, errInfo); + if (ret) { + DWN_ERR("Failed \n"); + goto _err; + } + pDownInfo->imgSzDisposed += wantSz; + pDownInfo->nextMediaOffset += wantSz; + + ret = optimus_storage_close(pDownInfo); + if (ret) { + DWN_ERR("Fail to close media\n"); + return 0; + } + + return wantSz; + +_err: + optimus_storage_close(pDownInfo); + pDownInfo->imgBurnSta = OPTIMUS_IMG_STA_BURN_FAILED;//// + return 0; +} + +static int _optimusWorkMode = OPTIMUS_WORK_MODE_NONE; + +int optimus_work_mode_get(void) +{ + return _optimusWorkMode; +} + +int optimus_work_mode_set(int workmode) +{ + _optimusWorkMode = workmode; + return 0; +} + +int is_the_flash_first_burned(void) +{ + const char* s = getenv("upgrade_step"); + + DWN_MSG("====>upgrade_step=%s<=====\n", s ? s : "<UNDEFINED>"); + + return !strcmp(s, "0");//"0" indicate first boot +} + +//FIXME: check whether 'saveenv' failed and exception when usb prodcing mode from code boot mode if without env_relocate +int optimus_set_burn_complete_flag(void) +{ + int rc = 0; + const int IsTplLoadedFromBurningPackage = aml_burn_check_uboot_loaded_for_burn(0); + const char* const upgrade_step = IsTplLoadedFromBurningPackage ? "2" : "1"; + + if (IsTplLoadedFromBurningPackage) + { + extern int device_boot_flag; + + char str_store[8]; + + sprintf(str_store, "%d", device_boot_flag); + DWN_MSG("store=%s\n", str_store); + /*rc = run_command("defenv", 0);//use new env directly if uboot is new !!!*/ + set_default_env("## save_setting ##\n");//use new env directly if uboot is new !!! + setenv("store", str_store); + setenv("firstboot", "1"); + if (!strstr(getenv("initargs"), "storage") && getenv("initargs") && 0) { + rc = run_command("setenv initargs ${initargs} storage=${store}", 0); + DWN_MSG("[initargs=%s]\n", getenv("initargs")); + } + else if(!strstr(getenv("bootargs"), "storage") && getenv("bootargs") && 0){//user not configure storage in 'bootargs' of default env + rc = run_command("setenv bootargs ${bootargs} storage=${store}", 0); + DWN_MSG("[bootargs=%s]\n", getenv("bootargs")); + } + } + + DWN_MSG("Set upgrade_step to %s\n", upgrade_step); + rc = setenv("upgrade_step", (char*)upgrade_step); + if (rc) { + DWN_ERR("Fail to set upgraded_step to 1\n"); + } + rc = run_command("saveenv", 0); + if (rc) { + DWN_ERR("Fail to saveenv to flash\n"); + } + udelay(200); + + return rc; +} + +static int _optimus_set_reboot_mode(const int cfgFlag) +{ + switch (cfgFlag) + { + case OPTIMUS_BURN_COMPLETE__REBOOT_UPDATE: + /*reboot_mode = AMLOGIC_UPDATE_REBOOT; */ + break; + + case OPTIMUS_BURN_COMPLETE__REBOOT_SDC_BURN: + /*reboot_mode = MESON_SDC_BURNER_REBOOT; */ + break; + + case OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL: + default: + /*reboot_mode = AMLOGIC_NORMAL_BOOT; */ + break; + } + + return 0; +} + +void optimus_reset(const int cfgFlag) +{ + unsigned i = 0x100; + + //writel(0, CONFIG_TPL_BOOT_ID_ADDR);//clear boot_id + + //set reboot mode + _optimus_set_reboot_mode(cfgFlag); + +#if defined(CONFIG_M6) || defined(CONFIG_M6TV) + //if not clear, uboot command reset will fail -> blocked + *((volatile unsigned long *)P_AO_RTI_STATUS_REG0) = 0; +#endif//#if defined(CONFIG_M6) || defined(CONFIG_M6TV) + printf("Burn Reboot...\n");//Add printf to delay to save env + while (--i) ; + + /*disable_interrupts();*/ + reset_cpu(0); + + while (i++) + { + unsigned ret = i; + unsigned mask = 1U<<20; + + mask -= 1; + ret &= mask; + if (!ret) { + printf("To reseting...\n"); + } + } +} + +void optimus_poweroff(void) +{ + //writel(0, CONFIG_TPL_BOOT_ID_ADDR);//clear boot_id + /*reboot_mode_clear();*/ + +#if CONFIG_POWER_KEY_NOT_SUPPORTED_FOR_BURN + DWN_MSG("stop here as poweroff and powerkey not supported in platform!\n"); + DWN_MSG("You can <Ctrl-c> to reboot\n"); + while (!ctrlc()) continue; + optimus_reset(OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL); +#else + printf("To poweroff\n"); + run_command("poweroff", 0); + printf("!!!After run command poweroff!!\n"); +#endif// #if CONFIG_POWER_KEY_NOT_SUPPORTED_FOR_BURN + + return; +} + +//use choice = 0xfu to query is_burn_completed +int optimus_burn_complete(const int choice) +{ + static unsigned _isBurnComplete = 0; + int rc = 0; + + switch (choice) + { + case OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_POWERKEY://wait power key to power off, for sdc_burn + { +#if CONFIG_POWER_KEY_NOT_SUPPORTED_FOR_BURN + DWN_MSG("stop here as poweroff and powerkey not supported in platform!\n"); + DWN_MSG("You can <Ctrl-c> to reboot\n"); + + while (!ctrlc()) continue; + optimus_reset(OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL); +#endif// #if CONFIG_POWER_KEY_NOT_SUPPORTED_FOR_BURN + DWN_MSG("PLS short-press power key to shut down\n"); + do + { + rc = run_command("getkey", 0); + }while(rc); + } + case OPTIMUS_BURN_COMPLETE__POWEROFF_DIRECT: + optimus_poweroff(); + break; + + case OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_DISCONNECT: + DWN_MSG("Pls un-plug USB line to poweroff\n"); + _isBurnComplete = 0xefe; + break; + case OPTIMUS_BURN_COMPLETE__QUERY: + return (0xefe == _isBurnComplete); + + case OPTIMUS_BURN_COMPLETE__REBOOT_UPDATE: + case OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL: + { + optimus_reset(choice); + } + break; + + + default: + rc = 1; + DWN_ERR("Error burn_complete flag %d\n", choice); + } + + return rc; +} + +#if ROM_BOOT_SKIP_BOOT_ENABLED +int optimus_enable_romboot_skip_boot(void) +{ +#ifdef CONFIG_MESON_TRUSTZONE + writel(meson_trustzone_sram_read_reg32(SKIP_BOOT_REG_BACK_ADDR), P_AO_RTI_STATUS_REG0); //disable watchdog +#else + /*writel(readl(SKIP_BOOT_REG_BACK_ADDR), P_AO_RTI_STATUS_REG0); //disable watchdog*/ +#endif// #ifdef CONFIG_MESON_TRUSTZONE + + //enable romboot skip_boot function to jump to usb boot + /*DWN_MSG("Skip boot flag[%x]\n", (unsigned int)readl(P_AO_RTI_STATUS_REG0));*/ + return 0; +} +#endif// #if ROM_BOOT_SKIP_BOOT_ENABLED diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_download.h b/drivers/usb/gadget/v2_burning/v2_common/optimus_download.h new file mode 100644 index 0000000000..fdb285aeea --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_download.h @@ -0,0 +1,203 @@ +/* + * \file optimus_download.h + * \brief common included files for optimus_*.c + * + * \version 1.0.0 + * \date 2013/5/3 + * \author Sam.Wu <yihui.wu@Amlogic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ + +#ifndef __OPTIMUS_DOWNLOAD_H__ +#define __OPTIMUS_DOWNLOAD_H__ + + +int optimus_buf_manager_init(const unsigned mediaAlignSz); +int optimus_buf_manager_exit(void); +int optimus_buf_manager_tplcmd_init(const char* mediaType, const char* partName, u64 partBaseOffset, + const char* imgType, const u64 pktTotalSz, const int isUpload, + const unsigned itemSizeNotAligned); +int optimus_buf_manager_get_buf_for_bulk_transfer(char** pBuf, const unsigned wantSz, const unsigned sequenceNo, char* errInfo); +int optimus_buf_manager_report_transfer_complete(const u32 transferSz, char* errInfo); +int is_largest_data_transferring(void); +int optimus_buf_manager_get_command_data_for_upload_transfer(u8* cmdDataBuf, const unsigned bufLen); + +int optimus_download_init(void); +int optimus_download_exit(void); +int optimus_parse_download_cmd(int argc, char* argv[]); +int optimus_parse_img_download_info(const char* part_name, const u64 imgSz, const char* imgType, const char* mediaType, const u64 partBaseOffset); +int is_optimus_to_burn_ready(void);//ready before burn +u32 optimus_download_img_data(const u8* data, const u32 size, char* errInfo); +int is_optimus_on_burn(void); //is now transferring image +int is_optimus_pre_burn(void); //is now has get "download command" +int optimus_media_download_verify(const int argc, char * const argv[], char *info); + +u32 optimus_dump_storage_data(u8* pBuf, const u32 wantSz, char* errInfo); + + +//for key opearations +// +int v2_key_command(const int argc, char * const argv[], char *info); + +/* + *This fucntion called by mread command, mread= bulkcmd "upload key .." + n * upload transfer, for key n==1 + *Attentions: return 0 if success, else failed + *@keyName: key name in null-terminated c style string + *@keyVal: the buffer to read back the key value + *@keyValLen: keyVal len is strict when read, i.e, user must know the length of key he/she wnat to read!! + *@errInfo: start it with success if burned ok, or format error info into it tell pc burned failed + */ +int v2_key_read(const char* keyName, u8* keyVal, const unsigned keyValLen, char* errInfo, unsigned* fmtLen); + +/* + *This fucntion called by mwrite command, mread= bulkcmd "download key .." + n * download transfer, for key n==1 + *Attentions: return value is the key length if burn sucess + *@keyName: key name in null-terminated c style string + *@keyVal: key value download from USB, "the value for sepecial keyName" may need de-encrypt by user code + *@keyValLen: the key value downloaded from usb transfer! + *@errInfo: start it with success if burned ok, or format error info into it tell pc burned failed + */ +unsigned v2_key_burn(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo); + +#define DDR_MEM_ADDR_START ( CONFIG_SYS_SDRAM_BASE + (16<<20) ) + +// |<---Back 2M---->|<------------USB transfer Buf 64 ----------->|<--Backed sparse format info for verify-->| +// Back buf Transfer buf +//TODO: move memory mapping to comman shared header file +//FIXME:Make sure [0x818<<20, 0x839<<20] not used by others +//[Buffer 0] DRAM_START, DRAM_START+2M, This range can't be accessed +//[Buffer 1] Buffer to Back up partition image data that not write back to flash, +#define OPTIMUS_SPARSE_IMG_LEFT_DATA_ADDR_LOW (DDR_MEM_ADDR_START + (2U<<20))//Don't access First 1M address +#define OPTIMUS_SPARSE_IMG_LEFT_DATA_MAX_SZ (0X2<<20) //back up address for sparse image, 2M + +//[Buffer 2] This 64M buffer is used to cache image data received from USB download, +// This Buffer size should be 64M, other size has pending bugs when sparse image is very large. +#define OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR (OPTIMUS_SPARSE_IMG_LEFT_DATA_ADDR_LOW + OPTIMUS_SPARSE_IMG_LEFT_DATA_MAX_SZ) +#define OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ (0X40<<20)//64M + +#define OPTIMUS_DOWNLOAD_SLOT_SZ (64<<10) //64K +#define OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS (16) //64K +#define OPTIMUS_DOWNLOAD_SLOT_NUM (OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ/OPTIMUS_DOWNLOAD_SLOT_SZ) + +//[Buffer 3] This buffer is used to Back up sparse chunk headers for verifying sparse image +#define OPTIMUS_DOWNLOAD_SPARSE_INFO_FOR_VERIFY (OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR + OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ) +#define OPTIMUS_DOWNLOAD_SPS_VERIFY_BACK_INFO_SZ (0x2U<<20) + +//[Buffer 4] This buffer is used for filling filled-value CHUNK_TYPE_FILL type sparse chunk, +#define OPTIMUS_SPARSE_IMG_FILL_VAL_BUF (OPTIMUS_DOWNLOAD_SPARSE_INFO_FOR_VERIFY + OPTIMUS_DOWNLOAD_SPS_VERIFY_BACK_INFO_SZ) +#define OPTIMUS_SPARSE_IMG_FILL_BUF_SZ OPTIMUS_DOWNLOAD_SLOT_SZ + +//[Buffer 5] This buffer to cache header of burning package when not usb burning +#define OPTIMUS_BURN_PKG_HEAD_BUF_ADDR (OPTIMUS_SPARSE_IMG_FILL_VAL_BUF + OPTIMUS_SPARSE_IMG_FILL_BUF_SZ) +#define OPTIMUS_BURN_PKG_HEAD_BUF_SZ (1U<<20)//1M should be enough! + +//[Buffer 6] This buffer is used to cache logo resources for upgrading +////buffer to display logo, 10M used now +#define OPTIMUS_DOWNLOAD_DISPLAY_BUF (OPTIMUS_BURN_PKG_HEAD_BUF_ADDR + OPTIMUS_BURN_PKG_HEAD_BUF_SZ) +#define OPTIMUS_DOWNLOAD_BUF_FREE_USE (OPTIMUS_DOWNLOAD_DISPLAY_BUF + (10U<<20))//free buffer not used by downloading, 2 + 64 + 2 + 10 + +#define OPTIMUS_VFAT_IMG_WRITE_BACK_SZ (OPTIMUS_DOWNLOAD_SLOT_SZ*1)//update complete alogrithm if change it +#define OPTIMUS_SIMG_WRITE_BACK_SZ OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ +#define OPTIMUS_MEMORY_WRITE_BACK_SZ (0X2U<<30)//2GBytes +#define OPTIMUS_BOOTLOADER_MAX_SZ (2U<<20)//max size is 2M ?? + +#define OPTIMUS_SHA1SUM_BUFFER_ADDR OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR +#define OPTIMUS_SHA1SUM_BUFFER_LEN (OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ/8) //16M each time + +//As key size < 64K, So buffer [OPTIMUS_SPARSE_IMG_LEFT_DATA_ADDR_LOW, OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR) not used when download key +#define OPTIMUS_KEY_DECRYPT_BUF OPTIMUS_SPARSE_IMG_LEFT_DATA_ADDR_LOW//buffer for decrypt the key +#define OPTIMUS_KEY_DECRYPT_BUF_SZ OPTIMUS_DOWNLOAD_SLOT_SZ + +#define COMPILE_TYPE_CHK(expr, t) typedef char t[(expr) ? 1 : -1] +#define COMPILE_TIME_ASSERT(expr) typedef char assert_type[(expr) ? 1 : -1] + +#define OPT_DOWN_OK 0 +#define OPT_DOWN_FAIL 1 +#define OPT_DOWN_TRUE 1 +#define OPT_DOWN_FALSE 0 + +#define OPTIMUS_MEDIA_TYPE_NAND 0 //nand is default +#define OPTIMUS_MEDIA_TYPE_SDMMC 1 +#define OPTIMUS_MEDIA_TYPE_SPIFLASH 2 +#define OPTIMUS_MEDIA_TYPE_STORE 3 //store stands for one of nand/emmc/spi, which smart identified by stoarge driver +#define OPTIMUS_MEDIA_TYPE_MEM 4 //memory, dram and sram +#define OPTIMUS_MEDIA_TYPE_KEY_UNIFY 5 + +//Following for optimus_simg2img.c +int optimus_simg_probe(const u8* source, const u32 length); +int optimus_simg_parser_init(const u8* source); +u32 optimus_cb_simg_write_media(const unsigned destAddrInSec, const unsigned dataSzInBy, const char* data); +int optimus_simg_to_media(char* simgPktHead, const u32 pktLen, u32* unParsedDataLen, const u32 flashAddrInSec); +int optimus_sparse_get_chunk_data(u8** head, u32* headSz, u32* dataSz, u64* dataOffset); +int optimus_sparse_back_info_probe(void); + +unsigned add_sum(const void* pBuf, const unsigned size);//Add-sum used for 64K transfer + +//outStr will be null-terminater after format +int optimus_hex_data_2_ascii_str(const unsigned char* hexData, const unsigned nBytes, char* outStr, const unsigned strSz); + +//for prompting step info +int optimus_progress_init(const unsigned itemSzHigh, const unsigned itemSzLow, const u32 startStep, const u32 endStep); +int optimus_progress_exit(void); +int optimus_update_progress(const unsigned thisBurnSz); + +#define DWN_ERR(fmt ...) printf("ERR(%s)L%d:", __FILE__, __LINE__);printf(fmt) +#define DWN_MSG(fmt ...) printf("msg:"fmt) +#define DWN_DBG(...) +#define DWN_HERE() printf("f(%s)L%d\n", __FILE__, __LINE__) + +//for fat fs +long do_fat_fopen(const char *filename); +long do_fat_fread(int fd, __u8 *buffer, unsigned long maxsize); +void do_fat_fclose(int fd); +s64 do_fat_get_fileSz(const char* imgItemPath); +int do_fat_fseek(int fd, const __u64 offset, int wherehence); +unsigned do_fat_get_bytesperclust(int fd); +int optimus_device_probe(const char* interface, const char* inPart); + +//<0 if failed, 0 is normal, 1 is sparse, others reserved +int do_fat_get_file_format(const char* imgFilePath, unsigned char* pbuf, const unsigned bufSz); + +//common internal function +int optimus_erase_bootloader(char* info); +void optimus_reset(const int cfgFlag); +int optimus_storage_init(int toErase);//init dest burning staorge +int optimus_storage_exit(void); +int is_optimus_storage_inited(void); +void optimus_poweroff(void); +int optimus_burn_complete(const int choice); +int is_the_flash_first_burned(void); +int optimus_set_burn_complete_flag(void);//set 'upgrade_step 1' after burnning success + +#define OPTIMUS_WORK_MODE_NONE 0 +#define OPTIMUS_WORK_MODE_USB_UPDATE (0xefe5) +#define OPTIMUS_WORK_MODE_USB_PRODUCE (0xefe6) +#define OPTIMUS_WORK_MODE_SDC_UPDATE (0xefe7) +#define OPTIMUS_WORK_MODE_SDC_PRODUCE (0xefe8) +#define OPTIMUS_WORK_MODE_SYS_RECOVERY (0xefe9) +int optimus_work_mode_get(void); +int optimus_work_mode_set(int workmode); + +#define OPTIMUS_BURN_COMPLETE__POWEROFF_DIRECT (0X0) +#define OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL (0x1) +#define OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_POWERKEY (0x2) +#define OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_DISCONNECT (0x3) +#define OPTIMUS_BURN_COMPLETE__REBOOT_SDC_BURN (0xdc) +#define OPTIMUS_BURN_COMPLETE__REBOOT_UPDATE (0xeb) +#define OPTIMUS_BURN_COMPLETE__QUERY (0xe1) + +#if (MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8) +#define ROM_BOOT_SKIP_BOOT_ENABLED 0//skip boot function is supported by romboot +#else +#define ROM_BOOT_SKIP_BOOT_ENABLED 0 +#endif// #if (MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8) +int optimus_enable_romboot_skip_boot(void); + +//ENV for auto jump into producing +#define _ENV_TIME_OUT_TO_AUTO_BURN "identifyWaitTime" +#define AML_SYS_RECOVERY_PART "aml_sysrecovery" + +#endif//ifndef __OPTIMUS_DOWNLOAD_H__ + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_download_key.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_download_key.c new file mode 100644 index 0000000000..e7a8a2f60c --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_download_key.c @@ -0,0 +1,658 @@ +/* + * ===================================================================================== + * + * Filename: v2_download_key.c + * + * Version: 1.0 + * Created: 2013/9/4 14:10:07 + * Compiler: gcc + * + * Author: Sam Wu (yihui.wu@amlogic.com) + * Organization: Amlogic Inc. + * + * Revision: none + * Description: Funcitions and command to burn keys with key_unify driver + * + * ===================================================================================== + */ +#include "../v2_burning_i.h" +#include <amlogic/keyunify.h> + +extern ssize_t uboot_key_put(char *device,char *key_name, char *key_data,int key_data_len,int ascii_flag); +extern ssize_t uboot_key_get(char *device,char *key_name, char *key_data,int key_data_len,int ascii_flag); +extern ssize_t uboot_key_query(char *device,char *key_name,unsigned int *keystate); + +#ifndef CMD_BUFF_SIZE +#define CMD_BUFF_SIZE (512) +#endif// #ifndef CMD_BUFF_SIZE + +#define HDCP2_RX_LC128_LEN (36) +#define HDCP2_RX_KEY_LEN (862) +#pragma pack(push, 1) +typedef struct _Hdcp2RxKeyFmt{ + unsigned version; + char lc128[HDCP2_RX_LC128_LEN]; + char keyVal[HDCP2_RX_KEY_LEN]; +}Hdcp2RxKeyFmt_t; +#pragma pack(pop) + +#define HDCP2_RX_KEY_TOTAL_LEN sizeof(Hdcp2RxKeyFmt_t) +#define HDCP2_RX_KEY_LC128_NAME "hdcp2lc128" +#define HDCP2_RX_KEY_NAME "hdcp2key" +#define HDCP2_RX_KEY_VERSION (0x02000000U) + +static char generalDataChange(const char input) +{ + int i; + char result = 0; + + for (i=0; i<8; i++) { + if ((input & (1<<i)) != 0) + result |= (1<<(7-i)); + else + result &= ~(1<<(7-i)); + } + + return result; +} + +static void hdcp2DataEncryption(const unsigned len, const char *input, char *out) +{ + int i = 0; + + for (i=0; i<len; i++) + *out++ = generalDataChange(*input++); +} + +static void hdcp2DataDecryption(const unsigned len, const char *input, char *out) +{ + int i = 0; + + for (i=0; i<len; i++) + *out++ = generalDataChange(*input++); +} + +static int _hdcp2_rx_key_Encrypt_before_burn(const char* keyName, char* keyVal, const unsigned keyValLen, + const u8** keyRealVal, unsigned* keyRealValLen, char* encryptBuf) +{ + Hdcp2RxKeyFmt_t* pHdcp2RxKey = (Hdcp2RxKeyFmt_t*)keyVal; + + if (HDCP2_RX_KEY_TOTAL_LEN != keyValLen) { + DWN_ERR("hdcp2 rx len unsupported. want %d but get %d\n", HDCP2_RX_KEY_TOTAL_LEN, keyValLen); + return __LINE__; + } + if (HDCP2_RX_KEY_VERSION != pHdcp2RxKey->version) { + DWN_ERR("Version value 0x%x is error, should be 0x%x\n", pHdcp2RxKey->version, HDCP2_RX_KEY_VERSION); + return __LINE__; + } + + hdcp2DataEncryption(keyValLen, keyVal, encryptBuf); + DWN_MSG("Ecnrypt hdcp2 END.\n"); + *keyRealVal = (u8*)encryptBuf; + *keyRealValLen = keyValLen; + + return 0; +} + +static int _hdcp2_rx_key_burn(const char* keyName, char* keyVal, const unsigned keyValLen) +{ + int err = -EINVAL; + const char* keyDevice = NULL; + int ascii_flag = 0; + Hdcp2RxKeyFmt_t* pHdcp2RxKey = (Hdcp2RxKeyFmt_t*)keyVal; + int flashKeyLen = 0; + char* flashKeyVal = NULL; + char* flashKeyName = NULL; + + keyDevice = key_unify_query_key_device((char*)keyName); + if (strcmp(keyDevice, "nandkey")) { + DWN_ERR("hdcp2 rx only support nandkey yet!\n"); + return __LINE__; + } +#if 0//key value already ecnrypted!! in func '_hdcp2_rx_key_Encrypt_before_burn' + if (HDCP2_RX_KEY_TOTAL_LEN != keyValLen) { + DWN_ERR("hdcp2 rx len unsupported. want %d but get %d\n", HDCP2_RX_KEY_TOTAL_LEN, keyValLen); + return __LINE__; + } + if (HDCP2_RX_KEY_VERSION != pHdcp2RxKey->version) { + DWN_ERR("Version value 0x%x is error, should be 0x%x\n", pHdcp2RxKey->version, HDCP2_RX_KEY_VERSION); + return __LINE__; + } +#endif// + + ascii_flag = strcmp("hexascii", key_unify_query_key_format((char*)keyName)) ? 0 : 1 ; + + DWN_MSG("To Burn hdcp2 to flash\n"); + flashKeyLen = HDCP2_RX_LC128_LEN; + flashKeyVal = (char*)&pHdcp2RxKey->lc128; + flashKeyName = (char*)HDCP2_RX_KEY_LC128_NAME; + err = uboot_key_put("auto", flashKeyName, flashKeyVal, flashKeyLen, ascii_flag); + if (err < 0) { + DWN_ERR("Fail to burn \"%s\" to flash\n", flashKeyName); + return __LINE__; + } + DWN_MSG("Burn \"%s\" to flash OK.\n", flashKeyName); + + flashKeyLen = HDCP2_RX_KEY_LEN; + flashKeyVal = (char*)&pHdcp2RxKey->keyVal; + flashKeyName = (char*)HDCP2_RX_KEY_NAME; + /*hdcp2DataEncryption(flashKeyLen, flashKeyVal, encryptBuf);*/ + err = uboot_key_put("auto", flashKeyName, flashKeyVal, flashKeyLen, ascii_flag); + if (err < 0) { + DWN_ERR("Fail to burn \"%s\" to flash\n", flashKeyName); + return __LINE__; + } + DWN_MSG("Burn \"%s\" to flash OK.\n", flashKeyName); + + err = key_unify_write((char*)keyName, (u8*)&pHdcp2RxKey->version, 4); + DWN_MSG("%s, ret 0x%x\n", __func__, err); + err = err >=0 ? 0 : __LINE__; + DWN_MSG("Write HDCP2 version end\n"); + + return err; +} + +static int _hdcp2_rx_key_read(char* keyName, char* keyValBuf, const unsigned keyValBufCap, unsigned* pKeyLen) +{ + int err = -EINVAL; + const char* keyDevice = NULL; + int ascii_flag = 0; + Hdcp2RxKeyFmt_t* pHdcp2RxKey = (Hdcp2RxKeyFmt_t*)keyValBuf; + unsigned flashKeyLen = 0; + char* flashKeyVal = NULL; + const char* flashKeyName = NULL; + + DWN_MSG("To read hdcp2.\n"); + keyDevice = key_unify_query_key_device(keyName); + if (strcmp(keyDevice, "nandkey")) { + DWN_ERR("hdcp2 rx only support nandkey yet!\n"); + return __LINE__; + } + if (HDCP2_RX_KEY_TOTAL_LEN > keyValBufCap) { + DWN_ERR("BufSz for hdcp2 rx len %d < least len %d\n", keyValBufCap, HDCP2_RX_KEY_TOTAL_LEN); + return __LINE__; + } + ascii_flag = strcmp("hexascii", key_unify_query_key_format(keyName)) ? 0 : 1 ; + + flashKeyLen = HDCP2_RX_LC128_LEN; + flashKeyName = HDCP2_RX_KEY_LC128_NAME; + flashKeyVal = (char*)&pHdcp2RxKey->lc128; + err = uboot_key_get("auto", (char*)flashKeyName, flashKeyVal, flashKeyLen, ascii_flag); + if (err < 0) { + DWN_ERR("Fail to read \"%s\" from flash\n", flashKeyName); + return __LINE__; + } + *pKeyLen = flashKeyLen; + + flashKeyLen = HDCP2_RX_KEY_LEN; + flashKeyName = HDCP2_RX_KEY_NAME; + flashKeyVal = (char*)&pHdcp2RxKey->keyVal; + err = uboot_key_get("auto", (char*)flashKeyName, flashKeyVal, flashKeyLen, ascii_flag); + if (err < 0) { + DWN_ERR("Fail to read \"%s\" from flash\n", flashKeyName); + return __LINE__; + } + *pKeyLen += flashKeyLen; + + err = key_unify_read(keyName, (u8*)&pHdcp2RxKey->version, 4, &flashKeyLen); + if (err < 0) { + DWN_ERR("Fail to read \"%s\" from flash\n", keyName); + return __LINE__; + } + *pKeyLen += 4; + + return 0; +} + +int decrypt_hdcp_license_to_raw_value(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo, + const u8** keyRealVal, unsigned* keyRealValLen, + char* decryptBuf, const unsigned decryptBufSz) +{ + int ret = 0; + decryptBuf = decryptBuf;//avoid compiler warning as not used + + DWN_MSG("hdcp down in len %d\n", keyValLen); + if (288 == keyValLen) //288 means license data is raw, not including the 20Bytes sha value + { + return 0;//ok, it's raw data if size is 288 + } + else if(308 == keyValLen) + { + const unsigned shaSumLen = 20; + const unsigned licLen = keyValLen - shaSumLen; + const u8* orgSum = keyVal + licLen; + u8 genSum[shaSumLen]; + + sha1_csum((u8*)keyVal, licLen, genSum); + + ret = memcmp(orgSum, genSum, shaSumLen); + if (ret) { + const unsigned fmtStrLen = shaSumLen * 2 + 2; + char org_sha1Str[fmtStrLen]; + char gen_sha1Str[fmtStrLen]; + + optimus_hex_data_2_ascii_str(orgSum, shaSumLen, org_sha1Str, fmtStrLen); + optimus_hex_data_2_ascii_str(genSum, shaSumLen, gen_sha1Str, fmtStrLen); + sprintf(errInfo, "failed:hdcp, orgSum[%s] != genSum[%s]\n", org_sha1Str, gen_sha1Str); + DWN_ERR(errInfo); + + return EINVAL; + } + DWN_MSG("Verify hdcp key with sha1sum OK\n"); + + *keyRealValLen = licLen; + return 0; + } + else + { + sprintf(errInfo, "failed:hdcp len %d is invalid\n", keyValLen); + DWN_ERR(errInfo); + return -EINVAL; + } + + return 0; +} + +int decrypt_mac_str_fmt_4_media(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo, + const u8** keyRealVal, unsigned* keyRealValLen, + char* decryptBuf, const unsigned decryptBufSz) +{ + int index = 0; + const char* keyDevice = NULL; + + if (17 != keyValLen) //288 means license data is raw, not including the 20Bytes sha value + { + sprintf(errInfo, "failed:mac len %d is invalid, must be 17\n", keyValLen); + DWN_ERR(errInfo); + return -EINVAL; + } + + for (index = 2; index < 17; index += 3) { + const char c = keyVal[index]; + if (':' != c) { + sprintf(errInfo, "failed:L%d:mac str(%s) fmt err at index[%d]\n", __LINE__, keyVal, index); + DWN_ERR(errInfo); + return -EINVAL; + } + } + + for (index = 0; index < 17; index += 3) { + int k = 0; + for (k = 0; k < 2; ++k) { + const char c = keyVal[index + k]; + if (!( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )) { + sprintf(errInfo, "failed:L%d:mac str(%s) fmt err at index[%d]\n", __LINE__, keyVal, index); + DWN_ERR(errInfo); + return -EINVAL; + } + } + } + + keyDevice = key_unify_query_key_device((char*)keyName); + DWN_MSG("write %s as %s\n", keyName, keyDevice); + if (strcmp("efusekey", keyDevice)) //not efusekey, not need to decrypt + { + return 0; + } + + *keyRealVal = (u8*)decryptBuf;//change the keyRealVal to decryptBuf + *keyRealValLen = 6; + + for (index = 0; index < 17; index += 3) { + const char *theByteStr = (const char*)keyVal + index; + int k = 0; + unsigned byteSum = 0; + + for (k = 0; k < 2; ++k) { + const char c = *theByteStr++; + + if (c >= '0' && c <= '9') { + byteSum += c - '0' + 0x0; + } + else if (c >= 'a' && c <= 'f'){ + byteSum += c - 'a' + 0xa; + } + else if (c >= 'A' && c <= 'F'){ + byteSum += c - 'A' + 0XA; + } + else{ + sprintf(errInfo, "failed:Exception when burn key for efuse, c=%x\n", c); + return -EINVAL; + } + byteSum <<= 4 * (1 - k); + } + DWN_DBG("byteSum=0x%x\n", byteSum); + *decryptBuf++ = byteSum; + } + + return 0; +} + +/* + * Check or Decrypt the key from usb to real key value before burn to device + *Only depending the keyName to decide whether the key value needed special disposed !! + * */ +int check_or_decrypt_raw_usb_key_value(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo, + const u8** keyRealVal, unsigned* keyRealValLen) +{ + int ret = 0; + char* keyDecryptBuf = (char*)OPTIMUS_KEY_DECRYPT_BUF; + const unsigned keyDecryptBufSz = OPTIMUS_KEY_DECRYPT_BUF_SZ; + + *keyRealVal = keyVal; + *keyRealValLen = keyValLen; + + //do with the special key value + if (!strcmp("hdcp", keyName)) + { + ret = decrypt_hdcp_license_to_raw_value(keyName, keyVal, keyValLen, errInfo, + keyRealVal, keyRealValLen, keyDecryptBuf, keyDecryptBufSz); + } + else if (!strcmp("mac", keyName) || !strcmp("mac_bt", keyName) || !strcmp("mac_wifi", keyName)) + { + ret = decrypt_mac_str_fmt_4_media(keyName, keyVal, keyValLen, errInfo, + keyRealVal, keyRealValLen, keyDecryptBuf, keyDecryptBufSz); + } + else if(!strcmp("hdcp2", keyName)) + { + ret = _hdcp2_rx_key_Encrypt_before_burn(keyName, (char*)keyVal, keyValLen, keyRealVal, keyRealValLen, keyDecryptBuf); + } + else if(!strcmp("your_key_name", keyName)) + { + //TODO:Add your key decrypt or check code here + } + + return ret; +} + +/* + *This fucntion called by mwrite command, mread= bulkcmd "download key .." + n * download transfer, for key n==1 + *Attentions: "return value is the key length" if burn sucess + + *@keyName: key name in null-terminated c style string + *@keyVal: key value download from USB, "the value for sepecial keyName" may need de-encrypt by user code + *@keyValLen: the key value downloaded from usb transfer! + *@errInfo: start it with success if burned ok, or format error info into it tell pc burned failed + */ +unsigned v2_key_burn(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo) +{ + int ret = 0; + unsigned writtenLen = 0; + const u8* keyRealVal = NULL;//the real value to burn to flash/efuse + unsigned keyRealValLen = 0; + + ret = check_or_decrypt_raw_usb_key_value(keyName, keyVal, keyValLen, errInfo, + &keyRealVal, &keyRealValLen); + if (ret) { + DWN_ERR("Fail to check_or_decrypt_raw_usb_key_value, writtenLen=0x%x\n", writtenLen); + return 0; + } + + if (!strcmp("hdcp2", keyName)) + { + ret = _hdcp2_rx_key_burn(keyName, (char*)keyRealVal, keyValLen); + } + else{//not hdcp2 + ret = key_unify_write((char*)keyName, (unsigned char*)keyRealVal, keyRealValLen); + } + DWN_MSG("%s, ret 0x%x\n", __func__, ret); + writtenLen = ret >=0 ? keyValLen : 0; + + return writtenLen; +} + +//Trnasform data format after read, To make data read back equal to write +static int _key_read_fmt_transform_4_usr(const char* keyName, + const unsigned keyValBufCap, u8* keyVal, const unsigned keyLenInDevice, unsigned* fmtLen) +{ + int rc = 0; + char* decryptBuf = (char*)OPTIMUS_KEY_DECRYPT_BUF; + + if (keyValBufCap < keyLenInDevice) { + DWN_ERR("bufsz %d < real sz %d\n", keyValBufCap, keyLenInDevice); + return __LINE__; + } + //keyValBufCap > keyLenInDevice + if (!strcmp("mac", keyName) || !strcmp("mac_bt", keyName) || !strcmp("mac_wifi", keyName)) + { + if (6 == keyLenInDevice) + { + int i = 0; + + rc = optimus_hex_data_2_ascii_str(keyVal, keyLenInDevice, decryptBuf, keyValBufCap); + if (rc) { + DWN_ERR("Fail to format mac hex data to str, rc=%d\n", rc); + return __LINE__; + } + for (i = 0; i < keyLenInDevice; ++i) { + *keyVal++ = decryptBuf[i * 2]; + *keyVal++ = decryptBuf[i * 2 + 1]; + *keyVal++ = ':'; + } + *--keyVal = 0; + *fmtLen = keyLenInDevice * 3 - 1; + + return 0; + } + else if(17 != keyLenInDevice){ + DWN_ERR("mac/bt/wifi len in device must be 17 or 6, but %d\n", keyLenInDevice); + return __LINE__; + } + } + else if(!strcmp("hdcp2", keyName)) + { + //Decrypt hdcp2_rx key for miracast + hdcp2DataDecryption(keyLenInDevice, (char*)keyVal, decryptBuf); + memcpy(keyVal, decryptBuf, keyLenInDevice); + } + else{ + + } + + return rc; +} + +/* + *This fucntion called by mread command, mread= bulkcmd "upload key .." + n * upload transfer, for key n==1 + *Attentions: return 0 if success, else failed + *@keyName: key name in null-terminated c style string + *@keyVal: the buffer to read back the key value + *@keyValLen: keyVal len is strict when read, i.e, user must know the length of key he/she wnat to read!! + *@errInfo: start it with success if burned ok, or format error info into it tell pc burned failed + */ +int v2_key_read(const char* keyName, u8* keyVal, const unsigned keyValLen, char* errInfo, unsigned* fmtLen) +{ + unsigned reallen = 0; + unsigned keyIsBurned = -1; + unsigned keypermit = -1; + int rc = 0; + + rc = key_unify_query((char*)keyName, &keyIsBurned, &keypermit); + if (rc < 0 || 1 != keyIsBurned) { + sprintf(errInfo, "failed to query key state, rc %d, keyIsBurned=%d\n", rc, keyIsBurned); + DWN_ERR(errInfo); + return __LINE__; + } + + if (!strcmp("hdcp2", keyName)) + { + rc = _hdcp2_rx_key_read((char*)keyName, (char*)keyVal, keyValLen, &reallen); + if (rc) { + sprintf(errInfo, "failed:key_read rc %d\n", rc); + DWN_ERR(errInfo); + return __LINE__; + } + } + else + { + rc = key_unify_read((char*)keyName, keyVal, keyValLen, &reallen); + if (rc < 0 || !reallen) { + sprintf(errInfo, "failed:key_read rc %d, reallen(%d), want len(%d)\n", rc, reallen, keyValLen); + DWN_ERR(errInfo); + return __LINE__; + } + } + + *fmtLen = reallen; + rc = _key_read_fmt_transform_4_usr(keyName, keyValLen, keyVal, reallen, fmtLen); + + return rc; +} + +//key command: 1, key init seed_in_str; 2, key uninit +//argv[0] can be 'key' from usb tool, or 'aml_key_burn/misc' from sdc_burn +int v2_key_command(const int argc, char * const argv[], char *info) +{ + const char* keyCmd = argv[1]; + int rcode = 0; + int subCmd_argc = argc - 1; + char* const * subCmd_argv = argv + 1; + + DWN_DBG("argc=%d, argv[%s, %s, %s, %s]\n", argc, argv[0], argv[1], argv[2], argv[3]); + if (argc < 2) { + sprintf(info, "argc < 2, need key subcmd\n"); + DWN_ERR(info); + return __LINE__; + } + + if (!strcmp("init", keyCmd)) + { + if (argc < 3) { + sprintf(info, "failed:cmd [key init] must take argument (seedNum)\n"); + DWN_ERR(info); + return __LINE__; + } + + u64 seedNum = simple_strtoull(subCmd_argv[1], NULL, 16); + if (!seedNum) { + sprintf(info, "failed:seedNum %s illegal\n", argv[2]); + DWN_ERR(info); + return __LINE__; + } + + rcode = key_unify_init((char*)&seedNum, sizeof(seedNum)); + + DWN_MSG("seedNum is 0x%llx, rcode %d\n", seedNum, rcode); + } + else if(!strcmp("uninit", keyCmd)) + { + rcode = key_unify_uninit(); + } + else if(!strcmp("is_burned", keyCmd)) + { + if (subCmd_argc < 2) { + sprintf(info, "failed: %s %s need a keyName\n", argv[0], argv[1]); + DWN_ERR(info); + return __LINE__; + } + const char* queryKey = subCmd_argv[1]; + unsigned keyIsBurned = -1; + unsigned keypermit = -1; + rcode = key_unify_query((char*)queryKey, &keyIsBurned, &keypermit); + if (rcode < 0) { + sprintf(info, "failed to query key state, rcode %d\n", rcode); + DWN_ERR(info); + return __LINE__; + } + rcode = (1 == keyIsBurned) ? 0 : __LINE__; + sprintf(info, "%s:key[%s] was %s burned yet(keystate %d, keypermit 0x%x)\n", + rcode ? "failed" : "success", queryKey, rcode ? "NOT" : "DO", keyIsBurned, keypermit); + } + else if(!strcmp("can_write", keyCmd) || !strcmp("can_read", keyCmd)) + { + if (subCmd_argc < 2) { + sprintf(info, "failed: %s %s need a keyName\n", argv[0], argv[1]); + DWN_ERR(info); + return __LINE__; + } + const char* queryKey = subCmd_argv[1]; + unsigned keyIsBurned = -1; + unsigned keypermit = -1; + rcode = key_unify_query((char*)queryKey, &keyIsBurned, &keypermit); + if (rcode < 0) { + sprintf(info, "failed to query key state, rcode %d\n", rcode); + DWN_ERR(info); + return __LINE__; + } + int writeCmd = !strcmp("can_write", keyCmd); + unsigned canWrite = ( 0xa == ( (keypermit>>4) & 0xfu ) ); + unsigned canRead = ( 0xa == ( keypermit & 0xfu ) ); + rcode = writeCmd ? !canWrite : !canRead; + sprintf(info, "%s:key[%s] %s %s (keystate %d, keypermit 0x%x)\n", + rcode ? "failed" : "success", queryKey, rcode ? "NOT" : "DO", keyCmd, keyIsBurned, keypermit); + } + else if(!strcmp("write", keyCmd)) + { + /* + * + *key write [keyName keyValueInStr] + *write direct, not support to deencrypt or verify, debug pipe, don't use to in PC tools + *Attentions it support at most 512-6 Bytes! + */ + + const char* keyName = subCmd_argv[1]; + const char* keyValInStr = subCmd_argv[2]; + + if (subCmd_argc < 3) { + sprintf(info, "failed: %s %s need a keyName and keyValInStr\n", argv[0], argv[1]); + DWN_ERR(info); + return __LINE__; + } + + rcode = v2_key_burn(keyName, (u8*)keyValInStr, strlen(keyValInStr), info); + rcode = (strlen(keyValInStr) == rcode) ? 0 : __LINE__; + } + else if(!strcmp("read", keyCmd) || !strcmp("get_len", keyCmd)) + { + /* + *key read [keyName], read directly to info buffer + *debug pipe, support at most 512-6 bytes, and PLS DON'T use in PC tools + * + * + */ + unsigned actualLen = 0; + const int cswBufLen = CMD_BUFF_SIZE - sizeof("success") + 1; + const char* keyName = subCmd_argv[1]; + unsigned char* keyValBuf = (unsigned char*)info + CMD_BUFF_SIZE - cswBufLen; + unsigned ReadBufLen = cswBufLen; + + if (subCmd_argc < 2) { + sprintf(info, "failed: %s %s need a keyName\n", argv[0], argv[1]); + DWN_ERR(info); + return __LINE__; + } + + const int is_query = !strcmp("get_len", keyCmd) ; + if (is_query) { + keyValBuf = (u8*)OPTIMUS_KEY_DECRYPT_BUF; + ReadBufLen = OPTIMUS_KEY_DECRYPT_BUF_SZ; + } + + rcode = v2_key_read((char*)keyName, keyValBuf, ReadBufLen, info, &actualLen); + if (is_query) + { + if (!rcode) + sprintf(info, "success%u", actualLen); + else + sprintf(info, "failed:at get_len rc %d\n", rcode); + } + DWN_MSG("key[%s] len(%d), rc(%d)\n", keyName, actualLen, rcode); + + rcode = rcode >=0 ? 0 : rcode; + } + else if(!strcmp("get_fmt", keyCmd)) + { + const char* fmt = NULL; + fmt = key_unify_query_key_format((char*)subCmd_argv[1]); + sprintf(info, "success:%s\n", fmt); + } + else{ + sprintf(info, "failed:Error keyCmd[%s]\n", keyCmd); + DWN_ERR(info); + rcode = __LINE__; + } + + DWN_DBG("rcode 0x%x\n", rcode); + return rcode; +} + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_fat.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_fat.c new file mode 100644 index 0000000000..3d4b6dd013 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_fat.c @@ -0,0 +1,1268 @@ +/* + * fat.c + * + * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg + * + * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 + * 2003-03-10 - kharris@nexus-tech.net - ported to uboot + * + * 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 "../v2_burning_i.h" +#include <part.h> +#include <fat.h> +#include <partition_table.h> +#include <mmc.h> + +#undef FAT_ERROR +#define FAT_ERROR(fmt...) printf("[FAT_ERR]L%d,", __LINE__),printf(fmt) +#ifndef FAT_DPRINT +#define FAT_DPRINT FAT_ERROR +#endif + +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 512 +#endif +#ifndef FS_BLOCK_SIZE +#define FS_BLOCK_SIZE SECTOR_SIZE +#endif + +#define FAT_MSG(fmt...) printf("fat:"fmt) + +extern int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr); + +int optimus_sdc_burn_switch_to_extmmc(void) +{ + static struct mmc *mmc = NULL; + + //Attention: So far the work flow of sdc_burn or sdc_update after store_init(0), so device_boot_flag is setup yet! + if (SPI_EMMC_FLAG != device_boot_flag && EMMC_BOOT_FLAG != device_boot_flag) { + return 0; + } + + if (!mmc) + { + mmc = find_mmc_device(0); + if (!mmc) { + FAT_ERROR("Fail to find mmc 0 device"); + return __LINE__; + } + } + if (mmc_init(mmc)) { + FAT_ERROR("Fail to init mmc 0 device"); + return __LINE__; + } + + return 0; +} + +static int v2_ext_mmc_read(__u32 startblock, __u32 nBlk, __u8 * bufptr) +{ + int ret = 0; + char* usb_update = getenv("usb_update"); + if (strcmp(usb_update,"1")) + { + ret = optimus_sdc_burn_switch_to_extmmc(); + if (ret) { + FAT_ERROR("failed in switch to extmmc.\n"); + return __LINE__; + } + } + + ret = disk_read(startblock, nBlk, bufptr); + + return ret; +} + +/* + * Convert a string to lowercase. + */ +static void +downcase(char *str) +{ + const int dist = 'a' - 'A'; + for (;*str != '\0'; ++str) { + char c = *str; + if ('A' <= c && c <= 'Z') + c += dist, *str = c; + } +} + +/* + * Get the first occurence of a directory delimiter ('/' or '\') in a string. + * Return index into string if found, -1 otherwise. + */ +static int +dirdelim(char *str) +{ + char *start = str; + + while (*str != '\0') { + if (ISDIRDELIM(*str)) return str - start; + str++; + } + return -1; +} + + +/* + * Match volume_info fs_type strings. + * Return 0 on match, -1 otherwise. + */ +static int +compare_sign(char *str1, char *str2) +{ + char *end = str1+SIGNLEN; + + while (str1 != end) { + if (*str1 != *str2) { + return -1; + } + str1++; + str2++; + } + + return 0; +} + + +/* + * Extract zero terminated short name from a directory entry. + */ +static void get_name (dir_entry *dirent, char *s_name) +{ + char *ptr; + + memcpy (s_name, dirent->name, 8); + s_name[8] = '\0'; + ptr = s_name; + while (*ptr && *ptr != ' ') + ptr++; + if (dirent->ext[0] && dirent->ext[0] != ' ') { + *ptr = '.'; + ptr++; + memcpy (ptr, dirent->ext, 3); + ptr[3] = '\0'; + while (*ptr && *ptr != ' ') + ptr++; + } + *ptr = '\0'; + if (*s_name == DELETED_FLAG) + *s_name = '\0'; + else if (*s_name == aRING) + *s_name = DELETED_FLAG; + downcase (s_name); +} + +/* + * Get the cluster entry at index 'entry' in a FAT (12/16/32) table. + * On failure 0x00 is returned. + */ +static __u32 get_fatent(fsdata *mydata, __u32 entry/*cluster index*/) +{ + __u32 bufnum; + __u32 offset; + __u32 ret = 0x00;//On failure 0x00 is returned. + + switch (mydata->fatsize) { + case 32: + bufnum = entry / FAT32BUFSIZE; + offset = entry - bufnum * FAT32BUFSIZE; + break; + case 16: + bufnum = entry / FAT16BUFSIZE; + offset = entry - bufnum * FAT16BUFSIZE; + break; + case 12: + bufnum = entry / FAT12BUFSIZE; + offset = entry - bufnum * FAT12BUFSIZE; + break; + + default: + /* Unsupported FAT size */ + return ret; + } + + /* Read a new block of FAT entries into the cache. */ + /* this block of FAT entries is not cached */ + if (bufnum != mydata->fatbufnum) { + int getsize = FATBUFSIZE/FS_BLOCK_SIZE;//==6 + __u8 *bufptr = mydata->fatbuf; + __u32 fatlength = mydata->fatlength; + __u32 startblock = bufnum * FATBUFBLOCKS; + + fatlength *= SECTOR_SIZE; /* We want it in bytes now */ + startblock += mydata->fat_sect; /* Offset from start of disk */ + + if (getsize > fatlength) getsize = fatlength; + if (v2_ext_mmc_read(startblock, getsize, bufptr) < 0) { + FAT_DPRINT("Error reading FAT blocks\n"); + return ret; + } + mydata->fatbufnum = bufnum; + } + + /* Get the actual entry from the table */ + switch (mydata->fatsize) { + case 32: + ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]); + break; + case 16: + ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]); + break; + case 12: { + __u32 off16 = (offset*3)/4; + __u16 val1, val2; + + switch (offset & 0x3) { + case 0: + ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); + ret &= 0xfff; + break; + case 1: + val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); + val1 &= 0xf000; + val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); + val2 &= 0x00ff; + ret = (val2 << 4) | (val1 >> 12); + break; + case 2: + val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); + val1 &= 0xff00; + val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); + val2 &= 0x000f; + ret = (val2 << 8) | (val1 >> 8); + break; + case 3: + ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);; + ret = (ret & 0xfff0) >> 4; + break; + default: + break; + } + } + break; + } + FAT_DPRINT("ret: %d, offset: %d\n", ret, offset); + + return ret; +} + + +/* + * Read at most 'size' bytes from the specified cluster into 'buffer'. + * Return 0 on success, -1 otherwise. + */ +static int +get_cluster(fsdata *mydata, const __u32 clustnum, __u8 *buffer, const unsigned long size) +{ + int idx = 0; + __u32 startsect; + + if (clustnum > 0) { + startsect = mydata->data_begin + clustnum*mydata->clust_size; + } else { + startsect = mydata->rootdir_sect; + } + + FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); + if (v2_ext_mmc_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0) { + FAT_DPRINT("Error reading data\n"); + return -1; + } + if (size % FS_BLOCK_SIZE) { + __u8 tmpbuf[FS_BLOCK_SIZE]; + idx= size/FS_BLOCK_SIZE; + if (v2_ext_mmc_read(startsect + idx, 1, tmpbuf) < 0) { + FAT_ERROR("Error reading data\n"); + return -1; + } + buffer += idx*FS_BLOCK_SIZE; + + memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE); + return 0; + } + + return 0; +} + +#ifdef CONFIG_SUPPORT_VFAT +/* + * Extract the file name information from 'slotptr' into 'l_name', + * starting at l_name[*idx]. + * Return 1 if terminator (zero byte) is found, 0 otherwise. + */ +static int +slot2str(dir_slot *slotptr, char *l_name, int *idx) +{ + int j; + + for (j = 0; j <= 8; j += 2) { + l_name[*idx] = slotptr->name0_4[j]; + if (l_name[*idx] == 0x00) return 1; + (*idx)++; + } + for (j = 0; j <= 10; j += 2) { + l_name[*idx] = slotptr->name5_10[j]; + if (l_name[*idx] == 0x00) return 1; + (*idx)++; + } + for (j = 0; j <= 2; j += 2) { + l_name[*idx] = slotptr->name11_12[j]; + if (l_name[*idx] == 0x00) return 1; + (*idx)++; + } + + return 0; +} + + +/* + * Extract the full long filename starting at 'retdent' (which is really + * a slot) into 'l_name'. If successful also copy the real directory entry + * into 'retdent' + * Return 0 on success, -1 otherwise. + */ +__attribute__ ((__aligned__(__alignof__(dir_entry)))) +__u8 get_vfatname_block[MAX_CLUSTSIZE]; +static int +get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, + dir_entry *retdent, char *l_name) +{ + dir_entry *realdent; + dir_slot *slotptr = (dir_slot*) retdent; + __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE; + __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; + int idx = 0; + + while ((__u8*)slotptr < nextclust) { + if (counter == 0) break; + if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) + return -1; + slotptr++; + counter--; + } + + if ((__u8*)slotptr >= nextclust) { + dir_slot *slotptr2; + + slotptr--; + curclust = get_fatent(mydata, curclust); + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_ERROR("curclust: 0x%x\n", curclust); + FAT_ERROR("Invalid FAT entry\n"); + return -1; + } + if (get_cluster(mydata, curclust, get_vfatname_block, + mydata->clust_size * SECTOR_SIZE) != 0) { + FAT_ERROR("Error: reading directory block\n"); + return -1; + } + slotptr2 = (dir_slot*) get_vfatname_block; + while (slotptr2->id > 0x01) { + slotptr2++; + } + /* Save the real directory entry */ + realdent = (dir_entry*)slotptr2 + 1; + while ((__u8*)slotptr2 >= get_vfatname_block) { + slot2str(slotptr2, l_name, &idx); + slotptr2--; + } + } else { + /* Save the real directory entry */ + realdent = (dir_entry*)slotptr; + } + + do { + slotptr--; + if (slot2str(slotptr, l_name, &idx)) break; + } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); + + l_name[idx] = '\0'; + if (*l_name == DELETED_FLAG) *l_name = '\0'; + else if (*l_name == aRING) *l_name = DELETED_FLAG; + downcase(l_name); + + /* Return the real directory entry */ + memcpy(retdent, realdent, sizeof(dir_entry)); + + return 0; +} + + +/* Calculate short name checksum */ +static __u8 +mkcksum(const char *str) +{ + int i; + __u8 ret = 0; + + for (i = 0; i < 11; i++) { + ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i]; + } + + return ret; +} +#endif + + +/* + * Get the directory entry associated with 'filename' from the directory + * starting at 'startsect' + */ +__attribute__ ((__aligned__(__alignof__(dir_entry)))) +static __u8 get_dentfromdir_block[MAX_CLUSTSIZE]; +static dir_entry *get_dentfromdir (fsdata * mydata, int startsect, + char *filename, dir_entry * retdent, + int dols) +{ + __u16 prevcksum = 0xffff; + __u32 curclust = START (retdent); + int files = 0, dirs = 0; + + FAT_DPRINT ("get_dentfromdir: %s\n", filename); + while (1) { + dir_entry *dentptr; + int i; + + if (get_cluster (mydata, curclust, get_dentfromdir_block, + mydata->clust_size * SECTOR_SIZE) != 0) { + FAT_DPRINT ("Error: reading directory block\n"); + return NULL; + } + dentptr = (dir_entry *) get_dentfromdir_block; + for (i = 0; i < DIRENTSPERCLUST; i++) { + char s_name[14], l_name[256]; + + l_name[0] = '\0'; + if (dentptr->name[0] == DELETED_FLAG) { + dentptr++; + continue; + } + if ((dentptr->attr & ATTR_VOLUME)) { +#ifdef CONFIG_SUPPORT_VFAT + if ((dentptr->attr & ATTR_VFAT) && + (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { + prevcksum = ((dir_slot *) dentptr) + ->alias_checksum; + get_vfatname (mydata, curclust, get_dentfromdir_block, + dentptr, l_name); + if (dols) { + int isdir = (dentptr->attr & ATTR_DIR); + char dirc; + int doit = 0; + + if (isdir) { + dirs++; + dirc = '/'; + doit = 1; + } else { + dirc = ' '; + if (l_name[0] != 0) { + files++; + doit = 1; + } + } + if (doit) { + if (dirc == ' ') { + printf (" %8ld %s%c\n", + (long) FAT2CPU32 (dentptr->size), + l_name, dirc); + } else { + printf (" %s%c\n", l_name, dirc); + } + } + dentptr++; + continue; + } + FAT_DPRINT ("vfatname: |%s|\n", l_name); + } else +#endif + { + /* Volume label or VFAT entry */ + dentptr++; + continue; + } + } + if (dentptr->name[0] == 0) { + if (dols) { + printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); + } + FAT_DPRINT ("Dentname == NULL - %d\n", i); + return NULL; + } +#ifdef CONFIG_SUPPORT_VFAT + if (dols && mkcksum (dentptr->name) == prevcksum) { + dentptr++; + continue; + } +#endif + get_name (dentptr, s_name); + if (dols) { + int isdir = (dentptr->attr & ATTR_DIR); + char dirc; + int doit = 0; + + if (isdir) { + dirs++; + dirc = '/'; + doit = 1; + } else { + dirc = ' '; + if (s_name[0] != 0) { + files++; + doit = 1; + } + } + if (doit) { + if (dirc == ' ') { + printf (" %8ld %s%c\n", + (long) FAT2CPU32 (dentptr->size), s_name, + dirc); + } else { + printf (" %s%c\n", s_name, dirc); + } + } + dentptr++; + continue; + } + if (strcmp (filename, s_name) && strcmp (filename, l_name)) { + FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name); + dentptr++; + continue; + } + memcpy (retdent, dentptr, sizeof (dir_entry)); + + FAT_DPRINT ("DentName: %s", s_name); + FAT_DPRINT (", start: 0x%x", START (dentptr)); + FAT_DPRINT (", size: 0x%x %s\n", + FAT2CPU32 (dentptr->size), + (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); + + return retdent; + } + curclust = get_fatent (mydata, curclust); + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_DPRINT ("curclust: 0x%x\n", curclust); + FAT_ERROR ("Invalid FAT entry\n"); + return NULL; + } + } + + return NULL; +} + + +/* + * Read boot sector and volume info from a FAT filesystem + */ +static int +read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) +{ + __u8 block[FS_BLOCK_SIZE]; + volume_info *vistart; + char *fstype; + + if (disk_read(0, 1, block) < 0) { + FAT_ERROR("Error: reading block\n"); + return -1; + } + + memcpy(bs, block, sizeof(boot_sector)); + bs->reserved = FAT2CPU16(bs->reserved); + bs->fat_length = FAT2CPU16(bs->fat_length); + bs->secs_track = FAT2CPU16(bs->secs_track); + bs->heads = FAT2CPU16(bs->heads); +#if 0 /* UNUSED */ + bs->hidden = FAT2CPU32(bs->hidden); +#endif + bs->total_sect = FAT2CPU32(bs->total_sect); + + /* FAT32 entries */ + if (bs->fat_length == 0) { + /* Assume FAT32 */ + bs->fat32_length = FAT2CPU32(bs->fat32_length); + bs->flags = FAT2CPU16(bs->flags); + bs->root_cluster = FAT2CPU32(bs->root_cluster); + bs->info_sector = FAT2CPU16(bs->info_sector); + bs->backup_boot = FAT2CPU16(bs->backup_boot); + vistart = (volume_info*) (block + sizeof(boot_sector)); + *fatsize = 32; + } else { + vistart = (volume_info*) &(bs->fat32_length); + *fatsize = 0; + } + memcpy(volinfo, vistart, sizeof(volume_info)); + + /* + * Terminate fs_type string. Writing past the end of vistart + * is ok - it's just the buffer. + */ + fstype = vistart->fs_type; + fstype[8] = '\0'; + + if (*fatsize == 32) { + if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) { + return 0; + } + } else { + if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) { + *fatsize = 12; + return 0; + } + if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) { + *fatsize = 16; + return 0; + } + } + + FAT_ERROR("Error: broken fs_type sign\n"); + return -1; +} + +__attribute__ ((__aligned__(__alignof__(dir_entry)))) +__u8 do_fat_read_block[MAX_CLUSTSIZE]; + +////////////////////////////////////////////////////////////////////// + +__attribute__ ((__aligned__(__alignof__(dir_entry)))) +__u8 _do_fat_read_block[MAX_CLUSTSIZE]; + + +#define FILE_MAX 2 +struct _fs_info +{ + fsdata datablock; + volume_info volinfo; + boot_sector bs; + + char *fat_buf; + unsigned fat_buf_cluster_index;//remember the index that which cluster was cached +}; + +struct file +{ + dir_entry dent; + unsigned long offset; + unsigned long filesize; + __u32 curclust;//next cluster to read + __u32 headclust; + +}; + +static struct file files[FILE_MAX]; +static struct _fs_info fs_info[FILE_MAX]; +static int _fd[FILE_MAX] = {0}; +#define OPTIMUS_FD_MAGIC (0XEFE80025) +#define OPTIMUS_INVAL_FD (-1) + +static int get_fd(void) +{ + int index = 0; + + for (; index < FILE_MAX; ++index) { + if (OPTIMUS_FD_MAGIC != _fd[index]) {//fd not used + _fd[index] = OPTIMUS_FD_MAGIC; + return index; + } + } + + return OPTIMUS_INVAL_FD; +} + +static void put_fd(int fd_index) +{ + if (fd_index >= 0) + _fd[fd_index] = 0; + return; +} + +/* wherehence: 0 to seek from start of file; 1 to seek from current position from file */ +int do_fat_fseek(int fd, const __u64 offset, int wherehence) +{ + unsigned long curoffset; + unsigned long offset_in_clust; + unsigned long seeked; + const unsigned int bytesperclust = fs_info[fd].datablock.clust_size * SECTOR_SIZE; + const unsigned long filesize = files[fd].filesize; + __u32 curclust; + + if (fd<0) { + FAT_ERROR("invalid fd %d\n", fd); + return -1; + } + + curclust = files[fd].curclust; + curoffset = files[fd].offset; + + if (wherehence == 0) + { + const unsigned long curClusterOffset = curoffset - (curoffset & (bytesperclust - 1)); + + if (offset > filesize) { + FAT_ERROR("offset %llx > filesize %lx\n", offset, filesize); + return -1; + } + + if (offset < curoffset) //seek from head if want to seek backwards + { + curclust = files[fd].headclust; + seeked=0; + } + else if(curClusterOffset + bytesperclust > offset)//Not need to actual seek as just in the right cluster + { + files[fd].offset = offset; + return 0; + } + else//seek from the current cluster + { + seeked = curoffset - (curoffset & (bytesperclust - 1));//curclust not need to change + FAT_MSG("Seek 0x%llx from 0x%lx\n", offset, curoffset); + } + + /* seek to offset */ + while (1) + { + + if (seeked + bytesperclust > offset) + { + fsdata* mydata = &fs_info[fd].datablock; + __u8* clusterCache = (__u8*)fs_info[fd].fat_buf; + + files[fd].curclust = curclust; + files[fd].offset = offset; + + if ((offset & (bytesperclust - 1)) && curclust != fs_info[fd].fat_buf_cluster_index) + {//cache the cluster if want to read from the offset where not align in cluster, and not cached yet + if (get_cluster(mydata, curclust, clusterCache, (int)bytesperclust) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + fs_info[fd].fat_buf_cluster_index = curclust; + } + + break; + } + + curclust = get_fatent(&fs_info[fd].datablock, curclust); + + seeked += bytesperclust; + } + } + else if(wherehence == 1)//this branch not used and not checked! + { + if (offset + curoffset > filesize) { + DWN_ERR("offset 0x%llx + curoffset 0x%lx > filesize 0x%lx\n", offset, curoffset, filesize); + return __LINE__; + } + if (offset == 0) + return 0; + + curclust = files[fd].curclust; + + seeked=0; + /* seek to offset */ + + offset_in_clust = curoffset % bytesperclust; + + if (offset_in_clust + offset <= bytesperclust) + { + files[fd].offset += offset; + return 0; + } + else + { + //round down to cluster boundry. + const __u64 aimOffset = offset + offset_in_clust; + /*offset += offset_in_clust;*/ + + while (1) { + + if (seeked + bytesperclust > aimOffset) + { + files[fd].curclust = curclust; + files[fd].offset = aimOffset; + break; + } + + curclust = get_fatent(&fs_info[fd].datablock, curclust); + + seeked += bytesperclust; + } + } + + } + + return 0; +} + +long do_fat_fopen(const char *filename) +{ +#if CONFIG_NIOS /* NIOS CPU cannot access big automatic arrays */ + static +#endif + unsigned int bytesperclust; + char fnamecopy[2048]; + fsdata *mydata; + int fd; + dir_entry *dentptr; + char *subname = ""; + int rootdir_size, cursect; + int idx, isdir = 0; + /*int firsttime;*/ + + if ((fd = get_fd()) < 0) { + FAT_ERROR("get_fd failed\n"); + return -1; + } + + mydata = &fs_info[fd].datablock; + + if (read_bootsectandvi (&fs_info[fd].bs, &fs_info[fd].volinfo, &mydata->fatsize)) { + FAT_ERROR ("Error: reading boot sector\n"); + put_fd(fd); + return -1; + } + if (mydata->fatsize == 32) { + mydata->fatlength = fs_info[fd].bs.fat32_length; + } else { + mydata->fatlength = fs_info[fd].bs.fat_length; + } + mydata->fat_sect = fs_info[fd].bs.reserved; + cursect = mydata->rootdir_sect + = mydata->fat_sect + mydata->fatlength * fs_info[fd].bs.fats; + mydata->clust_size = fs_info[fd].bs.cluster_size; + if (mydata->fatsize == 32) { + rootdir_size = mydata->clust_size; + mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ + - (mydata->clust_size * 2); + } else { + rootdir_size = ((fs_info[fd].bs.dir_entries[1] * (int) 256 + fs_info[fd].bs.dir_entries[0]) + * sizeof (dir_entry)) / SECTOR_SIZE; + mydata->data_begin = mydata->rootdir_sect + rootdir_size + - (mydata->clust_size * 2); + } + mydata->fatbufnum = -1; + + FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, + mydata->fatlength); + FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" + "Data begins at: %d\n", + mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE, + rootdir_size, mydata->data_begin); + FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); + + /* "cwd" is always the root... */ + while (ISDIRDELIM (*filename)) + filename++; + /* Make a copy of the filename and convert it to lowercase */ + strcpy (fnamecopy, filename); + downcase (fnamecopy); + if (*fnamecopy == '\0') { + put_fd(fd); + return -1; + } else if ((idx = dirdelim (fnamecopy)) >= 0) { + isdir = 1; + fnamecopy[idx] = '\0'; + subname = fnamecopy + idx + 1; + /* Handle multiple delimiters */ + while (ISDIRDELIM (*subname)) + subname++; + } + + while (1) { + int i; + + if (v2_ext_mmc_read(cursect, mydata->clust_size, _do_fat_read_block) < 0) { + FAT_ERROR ("Error: reading rootdir block\n"); + put_fd(fd); + return -1; + } + dentptr = (dir_entry *) _do_fat_read_block; + for (i = 0; i < DIRENTSPERBLOCK; i++) { + char s_name[14], l_name[256]; + + l_name[0] = '\0'; + if ((dentptr->attr & ATTR_VOLUME)) { +#ifdef CONFIG_SUPPORT_VFAT + if (((dentptr->attr & ATTR_VFAT) == ATTR_VFAT) && + (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { + get_vfatname (mydata, 0, _do_fat_read_block, dentptr, l_name); + } else +#endif + { + /* Volume label or VFAT entry */ + dentptr++; + continue; + } + } else if (dentptr->name[0] == 0) { + FAT_DPRINT ("RootDentname == NULL - %d\n", i); + put_fd(fd); + return -1; + } + + get_name (dentptr, s_name); + + if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { + FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name); + dentptr++; + continue; + } + if (isdir && !(dentptr->attr & ATTR_DIR)) + { + put_fd(fd); + return -1; + } + FAT_DPRINT ("RootName: %s", s_name); + FAT_DPRINT (", start: 0x%x", START (dentptr)); + FAT_DPRINT (", size: 0x%x %s\n", + FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : ""); + + goto rootdir_done; /* We got a match */ + } + cursect++; + } + rootdir_done: + + /*firsttime = 1;*/ + while (isdir) { + int startsect = mydata->data_begin + + START (dentptr) * mydata->clust_size; + dir_entry dent; + char *nextname = NULL; + + dent = *dentptr; + dentptr = &dent; + + idx = dirdelim (subname); + if (idx >= 0) { + subname[idx] = '\0'; + nextname = subname + idx + 1; + /* Handle multiple delimiters */ + while (ISDIRDELIM (*nextname)) + nextname++; + } else { + isdir = 0; + } + + if (get_dentfromdir (mydata, startsect, subname, dentptr, 0) == NULL) { + put_fd(fd); + return -1; + } + + if (idx >= 0) { + if (!(dentptr->attr & ATTR_DIR)) + { + put_fd(fd); + return -1; + } + subname = nextname; + } + } + + files[fd].dent = *dentptr; + files[fd].offset = 0; + files[fd].curclust = files[fd].headclust = START(dentptr); + files[fd].filesize = FAT2CPU32(dentptr->size); + FAT_MSG("Filesize is 0x%lxB[%luM]\n", files[fd].filesize, (files[fd].filesize>>20)); + + bytesperclust = fs_info[fd].datablock.clust_size * SECTOR_SIZE; + fs_info[fd].fat_buf_cluster_index = 0;//0 is invalid + fs_info[fd].fat_buf = malloc(bytesperclust); + if (!fs_info[fd].fat_buf) + { + if (fd >= 0) + { + memset(&files[fd], 0, sizeof(struct file)); + memset(&fs_info[fd], 0, sizeof(struct _fs_info)); + } + put_fd(fd); + return -1; + } + return fd; +} + +unsigned do_fat_get_bytesperclust(int fd) +{ + const unsigned bytesperclust = fs_info[fd].datablock.clust_size * SECTOR_SIZE; + + if (fd < 0) { + FAT_ERROR("Invalid fd %d\n", fd); + return -1; + } + + return bytesperclust; +} + +long do_fat_fread(int fd, __u8 *buffer, unsigned long maxsize) +{ + __u32 gotsize = 0; + __u32 curclust; + unsigned long actsize; + unsigned long offset; + unsigned long offset_in_clust; + struct _fs_info* theFsInfo = fs_info + fd; + const unsigned bytesperclust = theFsInfo->datablock.clust_size * SECTOR_SIZE; + fsdata* mydata = &fs_info[fd].datablock; + + if (fd < 0) { + FAT_ERROR("Invalid fd %d\n", fd); + return -1; + } + + offset = files[fd].offset; + + + +#if 0 + seeked=0; + + /* seek to offset */ + while (1) { + + if (seeked + bytesperclust > offset) + { + printf("Seeked to %d, target offset %d, clust %d\n", seeked, offset, curclust); + break; + } + + curclust = get_fatent(&fs_info[fd].datablock, curclust); + + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_DPRINT("curclust: 0x%x\n", curclust); + FAT_DPRINT("Invalid FAT entry\n"); + return 0; + } + + seeked += bytesperclust; + } +#else + + curclust = files[fd].curclust; + +#endif + + /* calc actual size to read */ + if (offset + maxsize > files[fd].filesize) + { + actsize = files[fd].filesize - offset; + } + else + { + actsize = maxsize; + } + + /* Deal with partial data at the first cluster */ + + /* Data occupation in cluster 1 + Case 1: + + cluster1 : |####____| + + Case 2: + cluster1 : |########| + + Case 3: + cluster1 : |__####__| + + Case 4: + cluster1 : |__######| + */ + + offset_in_clust = (offset % bytesperclust); + if (offset_in_clust != 0) + { + if (curclust != theFsInfo->fat_buf_cluster_index) + {//should seldom reach here if the image item consecutive + FAT_MSG("offset_in_clust 0x%lx\n", offset_in_clust); + /* Use vfat_buf as intermedia buffer to deal with the situation that size of _buf_ is smaller than a cluster */ + //FIXME:check if the fat_buf cache the data user wanted, and copy directly if wanted!! + if (get_cluster(mydata, curclust, (__u8*)fs_info[fd].fat_buf, (int)bytesperclust) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + fs_info[fd].fat_buf_cluster_index = curclust; + } + + if (actsize < (bytesperclust - offset_in_clust)) + {/* Case 3: the end of the cluster is not reached */ + memcpy(buffer, fs_info[fd].fat_buf+ offset_in_clust, actsize); + offset += actsize; + gotsize = actsize; + goto exit; + } + else + {/* Case 4 */ + memcpy(buffer, fs_info[fd].fat_buf+ offset_in_clust, bytesperclust - offset_in_clust); + actsize -= (bytesperclust - offset_in_clust); + gotsize = (bytesperclust - offset_in_clust); + offset += (bytesperclust - offset_in_clust); + buffer += gotsize; + + //update cluster index if seeked to next cluster + curclust = get_fatent(mydata, curclust);//get next cluster index + if (CHECK_CLUST(curclust, mydata->fatsize)) { + FAT_ERROR("curclust: 0x%x\n", curclust); + FAT_ERROR("Invalid FAT entry\n"); + goto exit; + } + } + } + + //Following disposing data which 'offset % bytesperclust == 0', that is start from align offset + while (actsize) //left data length + { + __u32 endclust; //last cluster index of this consecutive clusters + __u32 newclust = 0; //new cluster index of next consecutive clusters + unsigned thisConsecutiveLen = 0; + + endclust = curclust; + /* search for consecutive clusters until get enghou size*/ + while (actsize >= bytesperclust) + { + newclust = get_fatent(mydata, endclust);//get next cluster index + if (CHECK_CLUST(newclust, mydata->fatsize)) { + FAT_ERROR("curclust: 0x%x\n", newclust); + FAT_ERROR("Invalid FAT entry\n"); + goto exit; + } + thisConsecutiveLen+= bytesperclust; + actsize -= bytesperclust; + + //clusters not consecutive + if ((newclust -1)!= endclust) break; + endclust =newclust;//update curclust for next read + } + if (thisConsecutiveLen) + { + if (get_cluster(mydata, curclust, buffer, thisConsecutiveLen) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + buffer += thisConsecutiveLen; + gotsize += thisConsecutiveLen; + offset += thisConsecutiveLen; + curclust = newclust; + /*DWN_DBG("thisConsecutiveLen 0x%x\n", thisConsecutiveLen);*/ + } + //data not enough + if (actsize < bytesperclust && actsize) //Left data in the 'next' cluster < bytesperclust + { + __u8* clusterCache = (__u8*)theFsInfo->fat_buf; + + if (get_cluster(mydata, curclust, clusterCache, bytesperclust) != 0) { + FAT_ERROR("Error reading cluster\n"); + return -1; + } + theFsInfo->fat_buf_cluster_index = curclust; + memcpy(buffer, clusterCache, actsize); + + gotsize += actsize; + offset += actsize; + + //If this message printed when burning, we saied the bootloader is above data parts in image.cfg, or + //sdc_burn not burn data partitions in the order in image + FAT_MSG("sz 0x%x gz 0x%x, bps 0x%x\n", (unsigned)actsize, gotsize, bytesperclust);//bpc:bytesperclust + actsize = 0;///end the loop + } + } + +exit: + + files[fd].offset = offset; + files[fd].curclust = curclust; + return gotsize; +} + +void +do_fat_fclose(int fd) +{ + + if (fd >= 0) + { + memset(&files[fd], 0, sizeof(struct file)); + memset(&fs_info[fd], 0, sizeof(struct _fs_info)); + } + + if (fs_info[fd].fat_buf) + { + free(fs_info[fd].fat_buf); + fs_info[fd].fat_buf=0; + } + + put_fd(fd); +} + +// added by scy +//if image not exist, return 0 +s64 do_fat_get_fileSz(const char* imgItemPath) +{ + char cmdBuf[256] = ""; + int rcode = 0; + const char* envFileSz = NULL; + const char* usb_update = getenv("usb_update"); + + if (!strcmp(usb_update,"1")) + { + //fatexist usb host 0 imgItemPath + sprintf(cmdBuf, "fatexist usb 0 %s", imgItemPath); + } + else + { + optimus_sdc_burn_switch_to_extmmc(); + sprintf(cmdBuf, "fatexist mmc 0 %s", imgItemPath); + } + /*SDC_DBG("to run cmd [%s]\n", cmdBuf);*/ + rcode = run_command(cmdBuf, 0); + if (rcode) { + printf("fail in cmd [%s], rcode %d\n", cmdBuf, rcode); + return 0;//item size is 0 + } + envFileSz = getenv("filesize"); + /*SDC_DBG("size of item %s is 0x%s\n", imgItemPath, envFileSz);*/ + + return simple_strtoull(envFileSz, NULL, 16); +} + +//<0 if failed, 0 is normal, 1 is sparse, others reserved +int do_fat_get_file_format(const char* imgFilePath, unsigned char* pbuf, const unsigned bufSz) +{ + int readSz = 0; + + int hFile = do_fat_fopen(imgFilePath); + if (hFile < 0) { + printf("Fail to open file (%s)\n", imgFilePath); + return -1; + } + + readSz = do_fat_fread(hFile, pbuf, bufSz); + if (readSz <= 0) { + printf("Fail to read file(%s), readSz=%d\n", imgFilePath, readSz); + do_fat_fclose(hFile); + return -1; + } + + readSz = optimus_simg_probe(pbuf, readSz); + + do_fat_fclose(hFile); + + return readSz; +} + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_img_decoder.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_img_decoder.c new file mode 100644 index 0000000000..f70664766b --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_img_decoder.c @@ -0,0 +1,601 @@ +/* + * \file optimus_img_decoder.c + * \brief + * + * \version 1.0.0 + * \date 2013-7-8 + * \author Sam.Wu <yihui.wu@amlogic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" + +//FIMXE: +COMPILE_TYPE_CHK(128 == sizeof(ItemInfo_V1), _op_a); +COMPILE_TYPE_CHK(576 == sizeof(ItemInfo_V2), __op_a2); +COMPILE_TYPE_CHK(64 == sizeof(AmlFirmwareImg_t), __op_b); + +typedef struct _ImgSrcIf{ + unsigned devIf; //mmc/usb/store + unsigned devNo; //0/1/2 + unsigned devAlignSz; //64K for store + unsigned reserv2Align64; + uint64_t itemCurSeekOffsetInImg;//fread will auto seek the @readSz, but for STORE we must do it + + char partName[28]; //partIndex <= 28 (+4 if partIndex not used) + unsigned partIndex; //partIndex and part + unsigned char resrv[512 - 32 - 24]; +}ImgSrcIf_t; + +COMPILE_TYPE_CHK(512 == sizeof(ImgSrcIf_t), bb); +#define MAX_ITEM_NUM 48 + +typedef struct _ImgInfo_s +{ + ImgSrcIf_t imgSrcIf; + AmlFirmwareImg_t imgHead;//Must begin align 512, or store read wiill exception + union ItemInfo_u{ + ItemInfo_V1 v1[MAX_ITEM_NUM]; + ItemInfo_V2 v2[MAX_ITEM_NUM]; + }itemInfo; + +}ImgInfo_t; + +typedef struct _AmlFirmwareItem0_s +{ + __u32 itemId; + __u32 fileType; //image file type, sparse and normal + __u64 curoffsetInItem; //current offset in the item + __u64 offsetInImage; //item offset in the image + __u64 itemSz; //item size in the image + const char* itemMainType; + const char* itemSubType; +}ItemInfo; + +static int _hFile = -1; + +//open a Amlogic firmware image +//return value is a handle +HIMAGE image_open(const char* interface, const char* device, const char* part, const char* imgPath) +{ + const int HeadSz = sizeof(ImgInfo_t) - sizeof(ImgSrcIf_t); + ImgInfo_t* hImg = (ImgInfo_t*)OPTIMUS_BURN_PKG_HEAD_BUF_ADDR; + int ret = 0; + ImgSrcIf_t* pImgSrcIf = NULL; + unsigned imgVer = 0; + + pImgSrcIf = &hImg->imgSrcIf; + memset(pImgSrcIf, 0, sizeof(ImgSrcIf_t)); + + if (!strcmp("store", interface)) + { + DWN_DBG("imgHead=0x%x, hImg=%p\n", (unsigned)&hImg->imgHead, hImg); + ret = store_read_ops((u8*)part, (u8*)&hImg->imgHead, IMG_OFFSET_IN_PART, HeadSz); + if (ret) { + DWN_ERR("Fail to read image header.\n"); + ret = __LINE__; goto _err; + } + + pImgSrcIf->devIf = IMAGE_IF_TYPE_STORE; + pImgSrcIf->devAlignSz = 4*1024;//512;//OPTIMUS_DOWNLOAD_SLOT_SZ; + strcpy(pImgSrcIf->partName, part); + } + else + { + int pFile = do_fat_fopen(imgPath); + if (pFile < 0) { + DWN_ERR("Fail to open file %s\n", imgPath); + goto _err; + } + _hFile = pFile; + + ret = do_fat_fread(pFile, (u8*)&hImg->imgHead, HeadSz); + if (ret != HeadSz) { + DWN_ERR("want to read %d, but %d\n", HeadSz, ret); + goto _err; + } + + pImgSrcIf->devAlignSz = do_fat_get_bytesperclust(pFile); + } + + if (IMAGE_MAGIC != hImg->imgHead.magic) { + DWN_ERR("error magic 0x%x\n", hImg->imgHead.magic); + goto _err; + } + imgVer = hImg->imgHead.version; + if (AML_FRMWRM_VER_V1 != imgVer && AML_FRMWRM_VER_V2 != imgVer) { + DWN_ERR("error verison 0x%x\n", hImg->imgHead.version); + goto _err; + } + DWN_MSG("image version [0x%8x]\n", imgVer); + if (MAX_ITEM_NUM < hImg->imgHead.itemNum) { + DWN_ERR("max itemNum(%d)<actual itemNum (%d)\n", MAX_ITEM_NUM, hImg->imgHead.itemNum); + goto _err; + } + + return hImg; +_err: + return NULL; +} + + +//close a Amlogic firmware image +int image_close(HIMAGE hImg) +{ + DWN_MSG("to close image\n"); + + if (_hFile >= 0)do_fat_fclose(_hFile) , _hFile = -1; + + if (hImg) { + hImg = NULL; + } + return 0; +} + +static const ItemInfo* image_item_get_item_info_byid(HIMAGE hImg, const int itemIndex) +{ + ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + const unsigned imgVer = imgInfo->imgHead.version; + static ItemInfo theItem; + + switch (imgVer) + { + case AML_FRMWRM_VER_V2: + { + ItemInfo_V2* pItem = &imgInfo->itemInfo.v2[itemIndex]; + theItem.itemMainType = pItem->itemMainType; + theItem.itemSubType = pItem->itemSubType; + theItem.itemSz = pItem->itemSz; + theItem.offsetInImage = pItem->offsetInImage; + theItem.curoffsetInItem = pItem->curoffsetInItem; + theItem.fileType = pItem->fileType; + theItem.itemId = pItem->itemId; + } + break; + + case AML_FRMWRM_VER_V1: + { + ItemInfo_V1* pItem = &imgInfo->itemInfo.v1[itemIndex]; + theItem.itemMainType = pItem->itemMainType; + theItem.itemSubType = pItem->itemSubType; + theItem.itemSz = pItem->itemSz; + theItem.offsetInImage = pItem->offsetInImage; + theItem.curoffsetInItem = pItem->curoffsetInItem; + theItem.fileType = pItem->fileType; + theItem.itemId = pItem->itemId; + } + break; + + default: + DWN_ERR("Exception, imgVer=0x%x\n", imgVer); + return NULL; + } + + return &theItem; +} + +//open a item in the image +//@hImage: image handle; +//@mainType, @subType: main type and subtype to index the item, such as ["IMAGE", "SYSTEM"] +HIMAGEITEM image_item_open(HIMAGE hImg, const char* mainType, const char* subType) +{ + ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + const int itemNr = imgInfo->imgHead.itemNum; + const ItemInfo* pItem = NULL; + int i = 0; + + for (; i < itemNr ;i++) + { + pItem = image_item_get_item_info_byid(hImg, i); + if (!pItem) { + DWN_ERR("Fail to get item at index %d\n", i); + return NULL; + } + + if (!strcmp(mainType, pItem->itemMainType) && !strcmp(subType, pItem->itemSubType)) + { + break; + } + } + if (i >= itemNr) { + DWN_ERR("Can't find item [%s, %s]\n", mainType, subType); + return NULL; + } + + if (i != pItem->itemId) { + DWN_ERR("itemid %d err, should %d\n", pItem->itemId, i); + return NULL; + } + + if (IMAGE_IF_TYPE_STORE != imgInfo->imgSrcIf.devIf) + { + DWN_DBG("Item offset 0x%llx\n", pItem->offsetInImage); + i = do_fat_fseek(_hFile, pItem->offsetInImage, 0); + if (i) { + DWN_ERR("fail to seek, offset is 0x%x\n", (u32)pItem->offsetInImage); + return NULL; + } + } + imgInfo->imgSrcIf.itemCurSeekOffsetInImg = pItem->offsetInImage; + + return (HIMAGEITEM)pItem; +} + +//Need this if item offset in the image file is not aligned to bytesPerCluster of FAT +unsigned image_item_get_first_cluster_size(HIMAGE hImg, HIMAGEITEM hItem) +{ + const ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + ItemInfo* pItem = (ItemInfo*)hItem; + unsigned itemSizeNotAligned = 0; + const unsigned fat_bytesPerCluste = imgInfo->imgSrcIf.devAlignSz; + + itemSizeNotAligned = pItem->offsetInImage & (fat_bytesPerCluste - 1); + itemSizeNotAligned = fat_bytesPerCluste - itemSizeNotAligned; + + DWN_MSG("itemSizeNotAligned 0x%x\n", itemSizeNotAligned); + return itemSizeNotAligned; +} + +unsigned image_get_cluster_size(HIMAGEITEM hImg) +{ + const ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + const unsigned fat_bytesPerCluste = imgInfo->imgSrcIf.devAlignSz; + + return fat_bytesPerCluste; +} + +//close a item +int image_item_close(HIMAGEITEM hItem) +{ + return 0; +} + +__u64 image_item_get_size(HIMAGEITEM hItem) +{ + ItemInfo* pItem = (ItemInfo*)hItem; + + return pItem->itemSz; +} + + +//get image item type, current used type is normal or sparse +int image_item_get_type(HIMAGEITEM hItem) +{ + ItemInfo* pItem = (ItemInfo*)hItem; + + return pItem->fileType; +} + +//read item data, like standard fread +int image_item_read(HIMAGE hImg, HIMAGEITEM hItem, void* pBuf, const __u32 wantSz) +{ + ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + unsigned readSz = 0; + + if (IMAGE_IF_TYPE_STORE == imgInfo->imgSrcIf.devIf) + { + unsigned char* part = (unsigned char*)imgInfo->imgSrcIf.partName; + const uint64_t offsetInPart = imgInfo->imgSrcIf.itemCurSeekOffsetInImg + IMG_OFFSET_IN_PART; + int rc = 0; + const unsigned storeBlkSz = imgInfo->imgSrcIf.devAlignSz; + const unsigned offsetNotAlign = offsetInPart & (storeBlkSz - 1); + const unsigned sizeNotAlignInFirstBlk = storeBlkSz - offsetNotAlign;//in the the first block and its offset not aligned + + //Attention: deal with the align issue in "optimus_burn_one_partition", then not need to modify "do_fat_fread" + if (offsetNotAlign) + { + unsigned char* bufInABlk = NULL; + const uint64_t readOffset = offsetInPart - offsetNotAlign; + const unsigned bufLen = sizeNotAlignInFirstBlk < wantSz ? sizeNotAlignInFirstBlk : (wantSz); + unsigned thisTotalReadSz = wantSz; + + DWN_MSG("offsetInPart %llx, wantSz=%x\n", offsetInPart, wantSz); + bufInABlk = (u8*)malloc(storeBlkSz); + rc = store_read_ops(part, bufInABlk, readOffset, storeBlkSz); + if (rc) { + DWN_ERR("Fail to read: readOffset=%llx, storeBlkSz=%x\n", readOffset, storeBlkSz); + free(bufInABlk); + return __LINE__; + } + memcpy(pBuf, bufInABlk + offsetNotAlign, bufLen); + thisTotalReadSz -= bufLen; + pBuf += bufLen/sizeof(void); + free(bufInABlk); + + if (sizeNotAlignInFirstBlk < wantSz && offsetNotAlign) + { + rc = store_read_ops(part, (u8*)pBuf, (offsetInPart + sizeNotAlignInFirstBlk), thisTotalReadSz); + if (rc) { + DWN_ERR("Fail in store_read_ops to read %u at offset %llx.\n", wantSz, + offsetInPart + sizeNotAlignInFirstBlk); + return __LINE__; + } + } + } + else + { + rc = store_read_ops(part, (u8*)pBuf, offsetInPart, wantSz); + if (rc) { + DWN_ERR("Fail in store_read_ops to read %u at offset %llx.\n", wantSz, offsetInPart); + return __LINE__; + } + } + + imgInfo->imgSrcIf.itemCurSeekOffsetInImg += wantSz; + } + else + { + readSz = do_fat_fread(_hFile, pBuf, wantSz); + if (readSz != wantSz) { + DWN_ERR("want to read 0x%x, but 0x%x\n", wantSz, readSz); + return __LINE__; + } + } + + return 0; +} + +int get_total_itemnr(HIMAGE hImg) +{ + ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + + return imgInfo->imgHead.itemNum; +} + +HIMAGEITEM get_item(HIMAGE hImg, int itemId) +{ + int ret = 0; + ImgInfo_t* imgInfo = (ImgInfo_t*)hImg; + const ItemInfo* pItem = NULL; + + pItem = image_item_get_item_info_byid(hImg, itemId); + if (!pItem) { + DWN_ERR("Fail to get item at index %d\n", itemId); + return NULL; + } + if (itemId != pItem->itemId) { + DWN_ERR("itemid %d err, should %d\n", pItem->itemId, itemId); + return NULL; + } + DWN_MSG("get item [%s, %s] at %d\n", pItem->itemMainType, pItem->itemSubType, itemId); + + if (IMAGE_IF_TYPE_STORE != imgInfo->imgSrcIf.devIf) + { + ret = do_fat_fseek(_hFile, pItem->offsetInImage, 0); + if (ret) { + DWN_ERR("fail to seek, offset is 0x%x, ret=%d\n", (u32)pItem->offsetInImage, ret); + return NULL; + } + } + imgInfo->imgSrcIf.itemCurSeekOffsetInImg = pItem->offsetInImage; + + return (HIMAGEITEM)pItem; +} + +int get_item_name(HIMAGE hImg, int itemId, const char** main_type, const char** sub_type) +{ + const ItemInfo* pItem = NULL; + + pItem = image_item_get_item_info_byid(hImg, itemId); + if (!pItem) { + DWN_ERR("Fail to get item at index %d\n", itemId); + return __LINE__; + } + if (itemId != pItem->itemId) { + DWN_ERR("itemid %d err, should %d\n", pItem->itemId, itemId); + return __LINE__; + } + DWN_DBG("get item [%s, %s] at %d\n", pItem->itemMainType, pItem->itemSubType, itemId); + + *main_type = pItem->itemMainType; + *sub_type = pItem->itemSubType; + + return OPT_DOWN_OK; +} + +__u64 image_get_item_size_by_index(HIMAGE hImg, const int itemId) +{ + const ItemInfo* pItem = NULL; + + pItem = image_item_get_item_info_byid(hImg, itemId); + if (!pItem) { + DWN_ERR("Fail to get item at index %d\n", itemId); + return 0; + } + if (itemId != pItem->itemId) { + DWN_ERR("itemid %d err, should %d\n", pItem->itemId, itemId); + return __LINE__; + } + DWN_DBG("get item [%s, %s] at %d\n", pItem->itemMainType, pItem->itemSubType, itemId); + + return pItem->itemSz; +} + +u64 optimus_img_decoder_get_data_parts_size(HIMAGE hImg, int* hasBootloader) +{ + int i = 0; + int ret = 0; + u64 dataPartsSz = 0; + const int totalItemNum = get_total_itemnr(hImg); + + *hasBootloader = 0; + for (i = 0; i < totalItemNum; i++) + { + const char* main_type = NULL; + const char* sub_type = NULL; + + ret = get_item_name(hImg, i, &main_type, &sub_type); + if (ret) { + DWN_ERR("Exception:fail to get item name!\n"); + return __LINE__; + } + + if (strcmp("PARTITION", main_type)) { continue; } + if (!strcmp("bootloader", sub_type)) { + *hasBootloader = 1; + continue; + } + if (!strcmp(AML_SYS_RECOVERY_PART, sub_type)) + { + if (OPTIMUS_WORK_MODE_SYS_RECOVERY == optimus_work_mode_get()) continue; + } + + dataPartsSz += image_get_item_size_by_index(hImg, i); + } + + return dataPartsSz; +} + +#define MYDBG 0 +#if MYDBG +static int test_item(HIMAGE hImg, const char* main_type, const char* sub_type, char* pBuf, const int sz) +{ + HIMAGEITEM hItem = NULL; + int ret = 0; + + hItem = image_item_open(hImg, main_type, sub_type); + if (!hItem) { + DWN_ERR("fail to open %s, %s\n", main_type, sub_type); + return __LINE__; + } + + ret = image_item_read(hImg, hItem, pBuf, sz); + if (ret) { + DWN_ERR("fail to read\n"); + goto _err; + } + if (64 >= sz)DWN_MSG("%s\n", pBuf) ; + +_err: + image_item_close(hItem); + return ret; +} + +static int test_pack(const char* interface, const char* device, const char* part, const char* imgPath) +{ + const int ImagBufLen = OPTIMUS_DOWNLOAD_SLOT_SZ; + char* pBuf = (char*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR + ImagBufLen; + int ret = 0; + int i = 0; + HIMAGEITEM hItem = NULL; + + if (!strcmp("store", interface)) + { + ret = run_command("store init 1", 0); + if (ret) { + DWN_ERR("Fail in init mmc, Does sdcard not plugged in?\n"); + return __LINE__; + } + } + else + { + s64 fileSz = 0; + + ret = run_command("mmcinfo", 0); + if (ret) { + DWN_ERR("Fail in init mmc, Does sdcard not plugged in?\n"); + return __LINE__; + } + + fileSz = do_fat_get_fileSz(imgPath); + if (!fileSz) { + DWN_ERR("file %s not exist\n", imgPath); + return __LINE__; + } + } + + HIMAGE hImg = image_open(interface, device, part, imgPath); + if (!hImg) { + DWN_ERR("Fail to open image\n"); + return __LINE__; + } + + const int itemNr = get_total_itemnr(hImg); + for (i = 0; i < itemNr ; i++) + { + __u64 itemSz = 0; + int fileType = 0; + + hItem = get_item(hImg, i); + if (!hItem) { + DWN_ERR("Fail to open item at id %d\n", i); + break; + } + + itemSz = image_item_get_size(hItem); + DWN_MSG("Item Sz is 0x%llx\n", itemSz); + + unsigned wantSz = ImagBufLen > itemSz ? (unsigned)itemSz : ImagBufLen; + unsigned itemSizeNotAligned = 0; + char* readBuf = pBuf; + unsigned readSz = wantSz; + + itemSizeNotAligned = image_item_get_first_cluster_size(hImg, hItem); + if (itemSizeNotAligned) + { + ret = image_item_read(hImg, hItem, readBuf, itemSizeNotAligned); + readSz = (wantSz > itemSizeNotAligned) ? (wantSz - itemSizeNotAligned) : 0; + } + + if (readSz) + { + ret = image_item_read(hImg, hItem, readBuf + itemSizeNotAligned, readSz); + if (ret) { + DWN_ERR("fail to read item data\n"); + break; + } + } + + fileType = image_item_get_type(hItem); + if (IMAGE_ITEM_TYPE_SPARSE == fileType) + { + DWN_MSG("sparse packet\n"); + ret = optimus_simg_probe((const u8*)pBuf, wantSz); + if (!ret) { + DWN_ERR("item data error, should sparse, but no\n"); + break; + } + } + } + +#if 1 + test_item(hImg, "PARTITION", "logo", pBuf, ImagBufLen); + test_item(hImg, "VERIFY", "logo", pBuf, 50); +#endif + + image_close(hImg); + return 0; +} + +static int do_unpack(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + const char* imgPath = "a"; + +#if 1 + if (2 > argc) imgPath = "dt.img"; +#else + if (2 > argc) { + cmd_usage(cmdtp); + return -1; + } +#endif//#if MYDBG + DWN_MSG("argc %d, %s, %s\n", argc, argv[0], argv[1]); + + rcode = test_pack("mmc", "0", "aml_sysrecovery", imgPath); + + DWN_MSG("rcode %d\n", rcode); + return rcode; +} + +U_BOOT_CMD( + unpack, //command name + 5, //maxargs + 1, //repeatable + do_unpack, //command function + "unpack the image in sdmmc ", //description + "Usage: unpack imagPath\n" //usage +); +#endif//#if MYDBG + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_progress.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_progress.c new file mode 100644 index 0000000000..3080fc3dbf --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_progress.c @@ -0,0 +1,142 @@ +/* + * \file optimus_report_progress.c + * \brief display and print progress info when burning a partition + * + * \version 1.0.0 + * \date 2013/6/23 + * \author Sam.Wu <wuehui@allwinnertech.com> + * + * Copyright (c) 2013 Allwinner Technology. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" + +#define OPTIMUS_PROMPT_SIZE_MIN (4U<<20)//mininal size to prompt burning progress step + +struct ProgressInfo{ + u32 itemSzLow; + u32 itemSzHigh; + + u8 startStep; + u8 endStep; + u8 totalStepNum; + u8 currentStep; + + u32 bytesToIncOneStep; + u32 unReportSzInByte; + + u32 bytesToUpdateStep; + u32 reserv; + +}; +static struct ProgressInfo _progressInfo = {0}; + +int optimus_progress_init(const unsigned itemSzHigh, const unsigned itemSzLow, const u32 startStep, const u32 endStep) +{ + _progressInfo.itemSzLow = itemSzLow; + _progressInfo.itemSzHigh = itemSzHigh; + + _progressInfo.startStep = startStep; + _progressInfo.endStep = endStep; + _progressInfo.currentStep = startStep; + _progressInfo.totalStepNum = endStep - startStep; + + _progressInfo.unReportSzInByte = 0;//clear it + + //ATTENTION: as divisor / is lossy, _progressInfo.bytesToIncOneStep * _progressInfo.totalStepNum <= item size, so 100% is sometimes not exactly Burn Completed!! + _progressInfo.bytesToIncOneStep = ((((u64)itemSzHigh)<<32) + itemSzLow) / _progressInfo.totalStepNum; + _progressInfo.bytesToUpdateStep = (OPTIMUS_PROMPT_SIZE_MIN > _progressInfo.bytesToIncOneStep) ? OPTIMUS_PROMPT_SIZE_MIN : _progressInfo.bytesToIncOneStep; + + + DWN_DBG("item size 0x[%x, %x], currentStep %d, totalStepNum %d, bytesToIncOneStep 0x%x\n", + itemSzHigh, itemSzLow, _progressInfo.currentStep, _progressInfo.totalStepNum, _progressInfo.bytesToIncOneStep); + return 0; +} + +int optimus_progress_exit(void) +{ + return 0; +} + +int optimus_update_progress(const unsigned thisBurnSz) +{ + _progressInfo.unReportSzInByte += thisBurnSz; + + if (_progressInfo.bytesToUpdateStep > _progressInfo.unReportSzInByte) { + return 0; + } + + //if it is first time to prompt UI progress steps + if (_progressInfo.unReportSzInByte == thisBurnSz && _progressInfo.startStep + 1 == _progressInfo.currentStep) + { + printf("\n"); + } + + _progressInfo.currentStep += _progressInfo.unReportSzInByte / _progressInfo.bytesToIncOneStep; + _progressInfo.unReportSzInByte %= _progressInfo.bytesToIncOneStep; + + printf("Downloading %%%d\r", _progressInfo.currentStep); + if (_progressInfo.currentStep == _progressInfo.endStep) { + printf("\n"); + } + + return 0; +} + +//outStr will be null-terminater after format +int optimus_hex_data_2_ascii_str(const unsigned char* hexData, const unsigned nBytes, char* outStr, const unsigned strSz) +{ + int i = 1; + if (strSz < 2 * nBytes + 1) { + DWN_ERR("strSz(%d) > 2 * nBytes(%d)\n", strSz, nBytes); + return __LINE__; + } + + sprintf(outStr, "%02x", hexData[0]); + for (; i < nBytes; ++i) + { + sprintf(outStr, "%s%02x", outStr, hexData[i]); + } + + return 0; +} + +unsigned add_sum(const void* pBuf, const unsigned size) +{ + unsigned sum = 0; + const unsigned* data = (const unsigned*)pBuf; + unsigned wordLen = size>>2; + unsigned rest = size & 3; + + for (; wordLen/4; wordLen -= 4) + { + sum += *data++; + sum += *data++; + sum += *data++; + sum += *data++; + } + while (wordLen--) + { + sum += *data++; + } + + if (rest == 0) + { + ; + } + else if(rest == 1) + { + sum += (*data) & 0xff; + } + else if(rest == 2) + { + sum += (*data) & 0xffff; + } + else if(rest == 3) + { + sum += (*data) & 0xffffff; + } + + return sum; +} + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_progress_ui.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_progress_ui.c new file mode 100644 index 0000000000..c23bff1fb2 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_progress_ui.c @@ -0,0 +1,634 @@ +/* + * \file optimus_progress_ui.c + * \brief Show progress info to UI + * + * \version 1.0.0 + * \date 2013/10/13 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" +#include <bmp_layout.h> +#include <lcd.h> +#include <video_font.h> + +#ifdef CONFIG_VIDEO_AMLLCD +extern int lcd_drawchars (ushort x, ushort y, uchar *str, int count); +#else +#define lcd_drawchars(x, y, str, count) +#define lcd_printf(fmt...) +#endif// #ifdef CONFIG_VIDEO_AMLLCD + +#ifdef CONFIG_VIDEO_AMLTVOUT +#define _VIDEO_DEV_OPEN "video dev open ${outputmode};" +#else +#define _VIDEO_DEV_OPEN "video dev bl_on;" +#endif// #ifdef CONFIG_VIDEO_AMLTVOUT + +//if env upgrade_logo_offset exist, use bmp resources existed in memory +int video_res_prepare_for_upgrade(HIMAGE hImg) +{ + const char* env_name = NULL; + int ret = 0; + const char* UpgradeLogoAddr = (const char*)OPTIMUS_DOWNLOAD_DISPLAY_BUF; + char env_buf[32]; + + //imgread res logo ${loadaddr_misc}; + sprintf(env_buf, "imgread res logo 0x%p", UpgradeLogoAddr); + ret = run_command(env_buf, 0); + + if (!ret) { + sprintf(env_buf, "unpackimg 0x%p", UpgradeLogoAddr); + ret = run_command(env_buf, 0); + } + if (ret) + {//Failed to load logo resources from memory, then Load it from package + unsigned imgItemSz = 0; + HIMAGEITEM hItem = NULL; + + DWN_MSG("Use upgrade res in pkg\n"); + hItem = image_item_open(hImg, "PARTITION", "logo"); + if (!hItem) { + DWN_ERR("Fail to get logo.PARTITION for display logo\n"); + return __LINE__; + } + + imgItemSz = (unsigned)image_item_get_size(hItem); + ret = image_item_read(hImg, hItem, (void*)UpgradeLogoAddr, imgItemSz); + if (ret) { + DWN_ERR("Fail to read item logo\n"); + image_item_close(hItem); return __LINE__; + } + image_item_close(hItem); + + ret = run_command(env_buf, 0); + if (ret) { + DWN_ERR("Exception: Fail to unpack image in the package.\n"); + return __LINE__; + } + } + + //video prepare to show upgrade bmp + +#ifdef CONFIG_VIDEO_AMLLCD + if (OPTIMUS_WORK_MODE_SDC_PRODUCE == optimus_work_mode_get()) + { + DWN_MSG("LCD Initialize for upgrade:\n"); + aml_lcd_init(); + } +#endif// #ifdef CONFIG_VIDEO_AMLLCD + + DWN_MSG("echo video prepare for upgrade\n"); +#ifdef CONFIG_CMD_LOGO + DWN_MSG("outputmode=%s\n", getenv("outputmode")); + env_name = "logo size ${outputmode}"; + ret = run_command(env_name, 0); + if (ret) goto _fail; +#endif// #ifdef CONFIG_CMD_LOGO + env_name = "video open; video clear;"; + ret = run_command(env_name, 0); + if (ret) goto _fail; + + env_name = _VIDEO_DEV_OPEN; + ret = run_command(env_name, 0); + if (ret) goto _fail; + + ret = run_command("video clear", 0);//twice clear it + + return 0; + +_fail: + DWN_ERR("Fail in run_command[%s]\n", env_name); + return ret; +} + +static int _show_burn_logo(const char* bmpOffsetName) //Display logo to report burning result is failed +{ + int ret = 0; + char bmpCmd[64] = "bmp display %s"; + char* bmpAddrEnv = getenv((char*)bmpOffsetName); + + if (!bmpAddrEnv) { + const char* UpgradeLogoAddr = (const char*)OPTIMUS_DOWNLOAD_DISPLAY_BUF; + char env_buf[32]; + sprintf(env_buf, "unpackimg 0x%p", UpgradeLogoAddr); + + ret = run_command(env_buf, 0);//need re-unpack after 'defenv' + if (ret) { + DWN_ERR("Fail in re-unpack res img\n"); + return __LINE__; + } + bmpAddrEnv = getenv((char*)bmpOffsetName); + } + sprintf(bmpCmd, "bmp display %s ", bmpAddrEnv); + + ret = run_command(bmpCmd, 0); + if (ret) { + DWN_ERR("Fail in run[%s], bmpOffsetName=%s\n", bmpCmd, bmpOffsetName); + return __LINE__; + } +#ifdef CONFIG_OSD_SCALE_ENABLE + run_command("bmp scale", 0); +#endif// #ifdef CONFIG_OSD_SCALE_ENABLE + + return 0; +} + +//Display logo to report platform is in burning state +int show_logo_to_report_burning(void) +{ + return _show_burn_logo("upgrade_upgrading_offset"); +} + +int show_logo_to_report_burn_success(void) +{ + int ret = 0; + + ret = _show_burn_logo("upgrade_success_offset"); + if (ret) { + DWN_ERR("Fail in display logo upgrade_success_offset\n"); + return __LINE__; + } + lcd_printf("PLS short-press the power key to shut down\n"); + + return 0; +} + +static int show_logo_report_burn_ui_error(void) +{ + int ret = 0; + + ret = _show_burn_logo("upgrade_error_offset"); + if (ret) { + DWN_ERR("Fail in display logo upgrade_error\n"); + return __LINE__; + } + + return 0; +} + +//Horizontal progress bar +//_f means not changed after initialized +typedef struct _uiProgress{ + //For smart mode + u64 smartModeTotalBytes_f;//fixed + u64 smartModeLeftBytes; + + unsigned nDownBytesOnePercent_f;//update 1% if .nDownBytesOnePercent, (==.totalDownloadBytes/totalPercents) + +//For total + int totalPercents_f; //Total width for display the progress bar, should < 'display_width' + + int curPercent;//curent percent of the progress + int endPercent_f;//.endPercent + 1 - .startPerCent = .totalPercents, this field is fixed + + int progressBarWidth_f;//pixel width of the progress bar bmp + int progressBarHeight_f;//pixel height of the progress bar bmp + + unsigned totalProgressBarWidth_f;//total pixel width of the progress bar, use 'display_width'/100*100 ? + unsigned nProgressBarOnePercent_f;//times to display bar.if .totalProgressBarWidth=2000, .progressBarWidth=2, .totalPercents=100, then .nProgressBarOnePercent=10 + + int nextProgressBarX; + int progressBarY_f;//As this is a horizon progress bar, y coordinate is fixed. + + int upgradeStepX_f; + int upgradeStepY_f; + + unsigned bmpAddr_f; + unsigned reservToAlign64; +}UiProgress_t; + + +__hdle optimus_progress_ui_request(int totalPercents_f, int startPercent, unsigned bmpBarAddr, + int display_width, int progressBarY_f ) +{ + UiProgress_t* pUiProgress = NULL; + bmp_header_t* bmpHeadInfo = (bmp_header_t*)bmpBarAddr; + const unsigned commonMultiple = totalPercents_f * bmpHeadInfo->width; + + if (display_width < commonMultiple) { + DWN_ERR("pic width too large!! width(%d) * totalPercents_f(%d) >= display_width(%d)\n", + bmpHeadInfo->width, totalPercents_f, display_width); + show_logo_report_burn_ui_error(); return NULL; + } + pUiProgress = (UiProgress_t*)malloc(sizeof(UiProgress_t)); + if (!pUiProgress) { + DWN_ERR("Fail when malloc for UiProgress_t\n"); + show_logo_report_burn_ui_error(); return NULL; + } + + pUiProgress->totalPercents_f = totalPercents_f; + pUiProgress->curPercent = startPercent; + pUiProgress->endPercent_f = startPercent + totalPercents_f; + + + pUiProgress->bmpAddr_f = bmpBarAddr; + pUiProgress->progressBarWidth_f = bmpHeadInfo->width; + pUiProgress->progressBarHeight_f = bmpHeadInfo->height; + DWN_MSG("w,h[%u,%u]\n", pUiProgress->progressBarWidth_f, pUiProgress->progressBarHeight_f); + + pUiProgress->totalProgressBarWidth_f = /* common multiple of totalPercents_f and progress bar width */ + (display_width / commonMultiple) * commonMultiple; + pUiProgress->nProgressBarOnePercent_f = pUiProgress->totalProgressBarWidth_f / totalPercents_f; + + pUiProgress->nextProgressBarX = display_width - pUiProgress->totalProgressBarWidth_f; + pUiProgress->nextProgressBarX /= 2; + + pUiProgress->progressBarY_f = progressBarY_f; + DWN_DBG("barYCor %d\n", progressBarY_f); + + pUiProgress->upgradeStepX_f = pUiProgress->nextProgressBarX; + pUiProgress->upgradeStepY_f = progressBarY_f - VIDEO_FONT_HEIGHT; + DWN_DBG("upgradeStepX_f %d, upgradeStepY_f %d\n", pUiProgress->upgradeStepX_f, pUiProgress->upgradeStepY_f); + + DWN_DBG("totalProgressBarWidth_f %d, nProgressBarOnePercent_f %d, nextProgressBarX %d\n", + pUiProgress->totalProgressBarWidth_f, pUiProgress->nProgressBarOnePercent_f, pUiProgress->nextProgressBarX); + + return (__hdle)pUiProgress; +} + +int optimus_progress_ui_set_smart_mode(__hdle hUiProgress, const u64 smartModeTotalBytes_f, const unsigned smartModePercents) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiProgress; + + if (!smartModeTotalBytes_f || !smartModePercents) { + DWN_ERR("arg error!, smartModeTotalBytes_f %lld, smartModePercents %u\n", smartModeTotalBytes_f, smartModePercents); + show_logo_report_burn_ui_error(); + return __LINE__; + } + pUiProgress->smartModeTotalBytes_f = smartModeTotalBytes_f; + pUiProgress->nDownBytesOnePercent_f = smartModeTotalBytes_f/smartModePercents; + DWN_DBG("nDownBytesOnePercent_f %d\n", pUiProgress->nDownBytesOnePercent_f); + pUiProgress->smartModeLeftBytes = 0; + + return 0; +} + +int optimus_progress_ui_set_unfocus_bkg(__hdle hUiProgress, unsigned unfocusBmpAddr) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiProgress; + bmp_header_t* bkgBmpHead = (bmp_header_t*)unfocusBmpAddr; + const unsigned barHeight = pUiProgress->progressBarHeight_f; + const unsigned bkgHeight = bkgBmpHead->height; + const unsigned bkgWidth = bkgBmpHead->width; + const int nProgressBar = pUiProgress->totalPercents_f + * pUiProgress->nProgressBarOnePercent_f / bkgWidth; + int progressBarX = pUiProgress->nextProgressBarX; + const int progressBarY = pUiProgress->progressBarY_f; + + int i = 0; + + //allow width not equal, but height must equal! + if (barHeight != bkgHeight) { + DWN_ERR("barHeight %d != bkgHeight %d\n", barHeight, bkgHeight); + show_logo_report_burn_ui_error(); + return __LINE__; + } + + //show the progress bar to update progress to video device + for (i=0; i < nProgressBar; ++i) + { + char cmd[64]; + + sprintf(cmd, "bmp display 0x%x %d %d 1", unfocusBmpAddr, progressBarX, progressBarY); + if (run_command(cmd, 0)) { + DWN_ERR("Fail to in cmd[%s]\n", cmd); + show_logo_report_burn_ui_error(); + return __LINE__; + } + + progressBarX += bkgWidth; + } + +#ifdef CONFIG_OSD_SCALE_ENABLE + run_command("bmp scale", 0); +#endif// #ifdef CONFIG_OSD_SCALE_ENABLE + + return 0; +} + +static int optimus_progress_ui_set_steps(__hdle hUiProgress, int steps) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiProgress; + const int curPercent = pUiProgress->curPercent; + char strStep[16]; + + sprintf(strStep, "%d%%", steps); + lcd_drawchars((ushort)pUiProgress->upgradeStepX_f, (ushort)pUiProgress->upgradeStepY_f, (uchar*)strStep, strlen(strStep)); + + if (UPGRADE_STEPS_AFTER_IMAGE_OPEN_OK == curPercent) + { + lcd_printf("[OK]Open image\n"); + } + if (UPGRADE_STEPS_AFTER_DISK_INIT_OK == curPercent) + { + lcd_printf("[OK]Disk initial\n"); + } + else if(UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK == curPercent) + { + lcd_printf("[OK]Burn Data Partitons\n"); + } + else if(UPGRADE_STEPS_AFTER_BURN_BOOTLOADER_OK == curPercent) + { + lcd_printf("[OK]Burn bootloader\n"); + } + + return 0; +} + +int optimus_progress_ui_direct_update_progress(__hdle hUiProgress, const int percents) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiProgress; + const int nPercents = percents - pUiProgress->curPercent; + const int nProgressBar= nPercents * pUiProgress->nProgressBarOnePercent_f / pUiProgress->progressBarWidth_f; + int i = 0; + + //if already up to this user percents, not need to update yet! + if (percents > pUiProgress->endPercent_f) { + DWN_ERR("user percents(%d) beyond max (%d)\n", percents, pUiProgress->endPercent_f); + show_logo_report_burn_ui_error(); + return __LINE__; + } + if (nPercents <= 0) { + DWN_MSG("curPercent(%d) >= percents(%d)\n", pUiProgress->curPercent, percents); + show_logo_report_burn_ui_error(); + return 0; + } + + DWN_DBG("curPercent %d, percents %d, nPercents %d\n", pUiProgress->curPercent, percents, nPercents); + DWN_DBG("nProgressBar %d, %d\n", nProgressBar, pUiProgress->progressBarWidth_f); + + //show the progress bar to update progress to video device + for (i=0; i < nProgressBar; ++i) + { + const int progressBarX = pUiProgress->nextProgressBarX; + const int progressBarY = pUiProgress->progressBarY_f; + const unsigned bmpAddr = pUiProgress->bmpAddr_f; + char cmd[64]; + + sprintf(cmd, "bmp display %x %d %d 1", bmpAddr, progressBarX, progressBarY); + if (run_command(cmd, 0)) { + DWN_ERR("Fail to in cmd[%s]\n", cmd); + show_logo_report_burn_ui_error(); + return __LINE__; + } + + pUiProgress->nextProgressBarX += pUiProgress->progressBarWidth_f; + } +#ifdef CONFIG_OSD_SCALE_ENABLE + run_command("bmp scale", 0); +#endif// #ifdef CONFIG_OSD_SCALE_ENABLE + + pUiProgress->curPercent = percents; + + optimus_progress_ui_set_steps(hUiProgress, percents); + + return 0; +} + +//intelligent mode, update progress by download bytes +int optimus_progress_ui_update_by_bytes(__hdle hUiPrgress, const unsigned nBytes) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiPrgress; + const unsigned nDownBytesOnePercent_f = pUiProgress->nDownBytesOnePercent_f; + const unsigned bytesNotReport = nBytes + pUiProgress->smartModeLeftBytes; + int percentsIncreased = 0; + unsigned leftBytes = 0; + int ret = 0; + int percentsToReport = 0; + + //bytes not enghout to update one percent + if (bytesNotReport < nDownBytesOnePercent_f) + { + pUiProgress->smartModeLeftBytes = bytesNotReport; + return 0; + } + percentsIncreased = bytesNotReport / nDownBytesOnePercent_f; + leftBytes = bytesNotReport - percentsIncreased * nDownBytesOnePercent_f; + + percentsToReport = percentsIncreased + pUiProgress->curPercent; + DWN_DBG("update ui to [%d%%]\n", percentsToReport); + ret = optimus_progress_ui_direct_update_progress(hUiPrgress, percentsToReport); + pUiProgress->smartModeLeftBytes = leftBytes; + + return ret; +} + +int optimus_progress_ui_release(__hdle hUiPrgress) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiPrgress; + + DWN_MSG("Release prgress bar res\n"); + if (pUiProgress) + { + free(pUiProgress), pUiProgress = NULL; + } + + return 0; +} + +__hdle optimus_progress_ui_request_for_sdc_burn(void) +{ + __hdle hUiProgress = NULL; + unsigned barAddr = simple_strtoul(getenv("upgrade_bar_offset"), NULL, 0); + unsigned display_width = simple_strtoul(getenv("display_width"), NULL, 0); + unsigned display_height = simple_strtoul(getenv("display_height"), NULL, 0); + bmp_header_t* upgrading = (bmp_header_t*)simple_strtoul(getenv("upgrade_upgrading_offset"), NULL, 0); + const unsigned loadingHeight = upgrading->height; + const unsigned barYCor = + (3* display_height + loadingHeight)/4;//display_height - (display_height/2 - loadingHeight/2)/2; + unsigned unfocusBmpAddr = simple_strtoul(getenv("upgrade_unfocus_offset"), NULL, 0); + + if (!barAddr) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "upgrade_bar_offset", getenv("upgrade_bar_offset")); + show_logo_report_burn_ui_error(); + return NULL; + } + if (!display_width) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "display_width", getenv("display_width")); + show_logo_report_burn_ui_error(); return NULL; + } + if (!display_height) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "display_height", getenv("display_height")); return NULL; + } + if (!upgrading) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "upgrade_upgrading_offset", getenv("upgrade_upgrading_offset")); + show_logo_report_burn_ui_error(); return NULL; + } + if (!unfocusBmpAddr) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "upgrade_unfocus_offset", getenv("upgrade_unfocus_offset")); + show_logo_report_burn_ui_error(); return NULL; + } + DWN_DBG("upgrade_unfocus_offset=%s\n", getenv("upgrade_unfocus_offset")); + + DWN_MSG("dw,dh[%u, %u]\n", display_width, display_height); + hUiProgress = optimus_progress_ui_request(100, 0,barAddr, display_width, barYCor); + if (!hUiProgress) { + DWN_ERR("Fail to request progress bar\n"); + return NULL; + } + + if (optimus_progress_ui_set_unfocus_bkg(hUiProgress, unfocusBmpAddr)) { + DWN_ERR("Fail to set bkg\n"); + return NULL;; + } + + return hUiProgress; +} + +int optimus_progress_ui_report_upgrade_stat(__hdle hUiProgress, const int isSuccess) +{ + UiProgress_t* pUiProgress = (UiProgress_t*)hUiProgress; + const int curPercent = pUiProgress->curPercent; + + if (isSuccess) + { + optimus_progress_ui_direct_update_progress(hUiProgress, 100); + _show_burn_logo("upgrade_success_offset"); + lcd_printf("Burning Success^^\nPLS SHORT-PRESS the power key to shut down\n"); + return 0; + } + + _show_burn_logo("upgrade_fail_offset"); + lcd_printf("[Failed] at "); + //Followings failure + if (UPGRADE_STEPS_AFTER_IMAGE_OPEN_OK == curPercent) + { + lcd_printf("Disk initial!!\n"); + } + else if(UPGRADE_STEPS_AFTER_DISK_INIT_OK < curPercent && UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK > curPercent) + { + lcd_printf("Burning Data Partitons[%d%%]\n", curPercent); + } + else if(UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK == curPercent) + { + lcd_printf("Burning bootloader\n"); + } + else if(UPGRADE_STEPS_AFTER_BURN_BOOTLOADER_OK == curPercent) + { + lcd_printf("Burn complete\n"); + } + lcd_printf("PLS LONG-PRESS the power key to shut down\n"); + + return 0; +} + +int optimus_progress_ui_printf(const char* fmt, ...) +{ + va_list args; + char buf[CONFIG_SYS_PBSIZE]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + lcd_printf(buf); + return 0; +} + +#define PROGRESS_BAR_TEST 0 +#if PROGRESS_BAR_TEST +static int do_progress_bar_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + //bmp display $upgrade_bar_offset x,y,width + static __hdle hProgressBar = NULL; + int percents = 0; + + if (argc < 2) { + cmd_usage(cmdtp); + return __LINE__; + } + + if (!strcmp("rel", argv[1])) { + optimus_progress_ui_release(hProgressBar); + hProgressBar = NULL; + return 0; + } + + if (!hProgressBar) + { + unsigned barAddr = simple_strtoul(getenv("upgrade_bar_offset"), NULL, 0); + unsigned display_width = simple_strtoul(getenv("display_width"), NULL, 0); + unsigned display_height = simple_strtoul(getenv("display_height"), NULL, 0); + bmp_header_t* upgrading = (bmp_header_t*)simple_strtoul(getenv("upgrade_upgrading_offset"), NULL, 0); + const unsigned loadingHeight = upgrading->height; + const unsigned barYCor = + (3* display_height + loadingHeight)/4;//display_height - (display_height/2 - loadingHeight/2)/2; + unsigned unfocusBmpAddr = simple_strtoul(getenv("upgrade_unfocus_offset"), NULL, 0); + + if (!barAddr) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "upgrade_bar_offset", getenv("upgrade_bar_offset")); return __LINE__; + } + if (!display_width) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "display_width", getenv("display_width")); return __LINE__; + } + if (!display_height) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "display_height", getenv("display_height")); return __LINE__; + } + if (!upgrading) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "upgrade_upgrading_offset", getenv("upgrade_upgrading_offset")); return __LINE__; + } + if (!unfocusBmpAddr) { + DWN_ERR("Fail to getenv[%s=%s]\n", + "upgrade_unfocus_offset", getenv("upgrade_unfocus_offset")); return __LINE__; + } + + hProgressBar = optimus_progress_ui_request(100, 0, barAddr, display_width, barYCor); + if (!hProgressBar) { + DWN_ERR("Fail to request progress bar\n"); + return __LINE__; + } + + if (optimus_progress_ui_set_unfocus_bkg(hProgressBar, unfocusBmpAddr)) { + DWN_ERR("Fail to set bkg\n"); + return __LINE__; + } + lcd_printf("-----25%%"); + } + + if (!strcmp("dir", argv[1])) + { + percents = simple_strtoul(argv[2], NULL, 10); + optimus_progress_ui_direct_update_progress(hProgressBar, percents); + } + else if(!strcmp("nb", argv[1])) + { + static u64 dataBytes = 0; + unsigned nBytes = simple_strtoul(argv[2], NULL, 10); + + if (!dataBytes) { + dataBytes = 2u*1024*1024*1024; + if (optimus_progress_ui_set_smart_mode(hProgressBar, dataBytes, 90)) { + DWN_ERR("Fail to set smart mode\n"); + return __LINE__; + } + } + optimus_progress_ui_update_by_bytes(hProgressBar, nBytes); + } + + + return 0; +} + +U_BOOT_CMD( + bar, //command name + 5, //maxargs + 0, //repeatable + do_progress_bar_test, //command function + "Test dynamic upgrade progress bar", //description + "argv: [percents]\n"//usage + " -10 means 10%\n" +); +#endif//#if PROGRESS_BAR_TEST + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_progress_ui.h b/drivers/usb/gadget/v2_burning/v2_common/optimus_progress_ui.h new file mode 100644 index 0000000000..3c5b176dd0 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_progress_ui.h @@ -0,0 +1,82 @@ +/* + * \file optimus_progress_ui.h + * \brief interfaces of optimus_progress_ui.c + * + * \version 1.0.0 + * \date 2013/10/13 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ +#ifndef __OPTIMUS_PROGRESS_UI__ +#define __OPTIMUS_PROGRESS_UI__ + +//after erase_bootloader, before store_init +#define UPGRADE_STEPS_AFTER_IMAGE_OPEN_OK 2//disk_initialed failed if hang up here +#define UPGRADE_STEPS_AFTER_DISK_INIT_OK 5//burn data parts failed if hang up in [6, 95] +#define UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK 95 +#define UPGRADE_STEPS_AFTER_BURN_BOOTLOADER_OK 98 + +#define UPGRADE_STEPS_FOR_BURN_DATA_PARTS_IN_PKG(allInPkg) \ + ((allInPkg) ? (UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK - UPGRADE_STEPS_AFTER_DISK_INIT_OK - 1) : (UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK - UPGRADE_STEPS_AFTER_DISK_INIT_OK - 10)) + +#if CONFIG_SD_BURNING_SUPPORT_UI +int show_logo_to_report_burning(void);//show bmp 'upgrade_upgrading' + +int show_logo_to_report_burn_failed(void); //Display logo to report burning result is failed + +int show_logo_to_report_burn_success(void); + +__hdle optimus_progress_ui_request(const int totalPercents_f, int startPercent, + unsigned bmpBarAddr, int display_width, int progressBarY_f ); +__hdle optimus_progress_ui_request_for_sdc_burn(void); + +int optimus_progress_ui_release(__hdle hUiPrgress); + +int optimus_progress_ui_set_unfocus_bkg(__hdle hUiProgress, unsigned unfocusBmpAddr); + +int optimus_progress_ui_direct_update_progress(__hdle hUiProgress, const int percents); + +int optimus_progress_ui_report_upgrade_stat(__hdle hUiProgress, const int isSuccess); + +//smart mode with bytes +int optimus_progress_ui_set_smart_mode(__hdle hUiProgress, const u64 smartModeTotalBytes_f, const unsigned smartModePercents); +int optimus_progress_ui_update_by_bytes(__hdle hUiPrgress, const unsigned nBytes); + +int optimus_progress_ui_printf(const char* fmt, ...); + +int video_res_prepare_for_upgrade(HIMAGE hImg); + +#else + +#define video_res_prepare_for_upgrade(hImg) 0 + +#define show_logo_to_report_burning() + +#define show_logo_to_report_burn_failed() 0 + +#define show_logo_to_report_burn_success() 0 + +#define optimus_progress_ui_request(totalPercents_f,startPercent, bmpBarAddr,display_width,progressBarY_f ) 1 + +#define optimus_progress_ui_request_for_sdc_burn() (void*)1 + +#define optimus_progress_ui_release(hUiPrgress) do{}while(0) + +#define optimus_progress_ui_set_unfocus_bkg(hUiProgress, unfocusBmpAddr) 0 + +#define optimus_progress_ui_direct_update_progress(a ...) do{}while(0) + +//smart mode with bytes +#define optimus_progress_ui_set_smart_mode(a ...) 0 +#define optimus_progress_ui_update_by_bytes(hUiPrgress, nBytes) do{}while(0) + +#define optimus_progress_ui_report_upgrade_stat(a ...) do{}while(0) + +#define optimus_progress_ui_printf(a ...) do{}while(0) + +#endif//#if CONFIG_SD_BURNING_SUPPORT_UI + +#endif//ifndef __OPTIMUS_PROGRESS_UI__ + diff --git a/drivers/usb/gadget/v2_burning/v2_common/optimus_simg2img.c b/drivers/usb/gadget/v2_burning/v2_common/optimus_simg2img.c new file mode 100644 index 0000000000..7f9e8636e3 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/optimus_simg2img.c @@ -0,0 +1,436 @@ +/* + * \file optimus_simg2img.c + * \brief sparse image to ext4 image in optimus system + * a sparse image consit of "file_header + chunk_num * (chunk_header + [chunk_data]), + * chunk data can be empty when chunk type is CHUNK_TYPE_DONT_CARE" + * + * \version 1.0.0 + * \date 2013/5/6 + * \author Sam.Wu <yihui.wu@Amlogic.com> + * + * Copyright (c) 2013 Amlogic Inc. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" +#include <partition_table.h> + +#define sperr DWN_ERR +#define spmsg(fmt ...) //printf("spmsg:"fmt) +#define spdbg(fmt ...) //printf("SP:"), printf(__VA_ARGS__) + +#define SPARSE_HEADER_MAJOR_VER 1 +#define CHUNK_HEAD_SIZE sizeof(chunk_header_t) +#define FILE_HEAD_SIZE sizeof(sparse_header_t) + +//states for a sparse packet, initialized when sparse packet probed +static struct +{ + unsigned leftChunkNum;//chunks that not parsed yet + unsigned chunksBufLen;//>=OPTIMUS_DOWNLOAD_SPARSE_TRANSFER_SZ + + unsigned sparseBlkSz;//block size of sparse format packet + unsigned parsedPacketCrc;//crc value for packet that already parsed + + int pktHeadLen; + u32 reservetoAlign64; + + //If long chunk data sz > write back size(e.g. 64M), write it at next write back time, This can't reduce copy and use less buffer + u32 notWrBackSz4LongChunk; + u32 nextFlashAddr4LastLongChunk; //flash start Addr not write back chunk data , in sector + + //back up infomation for verify + u32 chunkInfoBackAddr;//file header and chunk info back address + u32 backChunkNum; //chunk number backed + u64 chunkOffset; + +}_spPacketStates; + +//0 is not sparse packet header, else is sparse packet_header +int optimus_simg_probe(const u8* source, const u32 length) +{ + sparse_header_t *header = (sparse_header_t*) source; + + if (length < sizeof(sparse_header_t)) { + sperr("length %d < sparse_header_t len %d\n", length, (int)FILE_HEAD_SIZE); + return 0; + } + if (header->magic != SPARSE_HEADER_MAGIC) { + sperr("sparse bad magic, expect 0x%x but 0x%x\n", SPARSE_HEADER_MAGIC, header->magic); + return 0; + } + + if(!(SPARSE_HEADER_MAJOR_VER == header->major_version + && FILE_HEAD_SIZE == header->file_hdr_sz + && CHUNK_HEAD_SIZE == header->chunk_hdr_sz)) + { + sperr("want 0x [%x, %x, %x], but [%x, %x, %x]\n", + SPARSE_HEADER_MAJOR_VER, (unsigned)FILE_HEAD_SIZE, (unsigned)CHUNK_HEAD_SIZE, + header->major_version, header->file_hdr_sz, header->chunk_hdr_sz); + return 0; + } + + + return 1; +} + +int optimus_simg_parser_init(const u8* source) +{ + sparse_header_t *header = (sparse_header_t*) source; + + memset(&_spPacketStates, 0, sizeof(_spPacketStates)); + _spPacketStates.leftChunkNum = header->total_chunks; + _spPacketStates.parsedPacketCrc = 0; + _spPacketStates.pktHeadLen = header->file_hdr_sz; + _spPacketStates.sparseBlkSz = header->blk_sz;//often 4k + spmsg("totalChunkNum %d, fileHeadSz 0x%x, chunkHeadSz 0x%x\n", _spPacketStates.leftChunkNum, _spPacketStates.pktHeadLen, CHUNK_HEAD_SIZE); + + //for verify + _spPacketStates.chunkInfoBackAddr = OPTIMUS_DOWNLOAD_SPARSE_INFO_FOR_VERIFY; + _spPacketStates.backChunkNum = 0; + memcpy((void*)(u64)_spPacketStates.chunkInfoBackAddr, header, sizeof(sparse_header_t)); + spmsg("back header addr 0x%x\n", _spPacketStates.chunkInfoBackAddr); + + return OPT_DOWN_OK; +} + +//return value: flash address offset in sector in this time dispose +//call this method to parse sparse format data and write it to media +//@flashAddrInSec: flash write address of first chunk +//@simgPktHead : buffered sparse image +//@pktLen : buffered sparse data len +//@unParsedDataLen: data length need write at next write back time +// Take care the size to align 64K for flash and and addres to align sector!!!! +int optimus_simg_to_media(char* simgPktHead, const u32 pktLen, u32* unParsedDataLen, const u32 flashAddrInSec) +{ + const unsigned notWrBackSz4LongChunk = _spPacketStates.notWrBackSz4LongChunk; + unsigned unParsedBufLen = pktLen - _spPacketStates.pktHeadLen; + u32 flashAddrStart = flashAddrInSec; + chunk_header_t* pChunk = (chunk_header_t*)(simgPktHead + _spPacketStates.pktHeadLen); + chunk_header_t* backChunkHead = (chunk_header_t*)(_spPacketStates.chunkInfoBackAddr + FILE_HEAD_SIZE) + _spPacketStates.backChunkNum; + + if (notWrBackSz4LongChunk && !_spPacketStates.pktHeadLen/*0 if head*/) + { + //const chunk_header_t* pLastLongChunk = backChunkHead - 1;//// + //const unsigned leftLongChunk_dataLen = pLastLongChunk->total_sz; + const unsigned leftLongChunk_flashAddr = _spPacketStates.nextFlashAddr4LastLongChunk; + unsigned writeLen = 0; + unsigned thisWriteLen = 0; + + thisWriteLen = notWrBackSz4LongChunk >= pktLen ? pktLen : notWrBackSz4LongChunk; + if (notWrBackSz4LongChunk > thisWriteLen) { + //Align write size to 64K for flash write until last flash write + //At least make sure align to sector as flashAddress in sector here!!! + thisWriteLen >>= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; thisWriteLen <<= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; + spmsg("pktLen(0x%08x) < long chunk leftLen 0x%x08\n", pktLen, notWrBackSz4LongChunk); + } + spmsg("notWrBackSz4LongChunk 0x%08x, thisWriteLen 0x%08x, flashAddr 0x%08xSec\n", notWrBackSz4LongChunk, thisWriteLen, leftLongChunk_flashAddr); + + writeLen = optimus_cb_simg_write_media(leftLongChunk_flashAddr, thisWriteLen, simgPktHead); + if (thisWriteLen != writeLen) { + sperr("Want to write left chunk sz 0x%x, but only 0x%x\n", thisWriteLen, writeLen); + return -__LINE__; + } + + unParsedBufLen -= thisWriteLen; + _spPacketStates.notWrBackSz4LongChunk -= thisWriteLen; + + if (notWrBackSz4LongChunk >= pktLen) //packet data ended + { + _spPacketStates.nextFlashAddr4LastLongChunk += thisWriteLen>>9;//address needed next write time + *unParsedDataLen = unParsedBufLen; + return 0;//the long chunk not disposed all yet! + } + + pChunk = (chunk_header_t*)(simgPktHead + notWrBackSz4LongChunk + _spPacketStates.pktHeadLen); + } + + + spdbg("headLen=0x%x, leftNum=%d, backNum %d\n", _spPacketStates.pktHeadLen, _spPacketStates.leftChunkNum, _spPacketStates.backChunkNum); + for (;_spPacketStates.leftChunkNum && !_spPacketStates.notWrBackSz4LongChunk; _spPacketStates.leftChunkNum--) + { + //chunk data for ext4, but maybe empty in sparse, that is why called sparse format + const unsigned chunkDataLen = pChunk->chunk_sz * _spPacketStates.sparseBlkSz; + unsigned thisWriteLen = 0; + + if (CHUNK_HEAD_SIZE > unParsedBufLen) {//total size not enough for CHUNK_HEAD_SIZE yet!! + spmsg("unParsedBufLen 0x%x < head sz 0x%x\n", unParsedBufLen, CHUNK_HEAD_SIZE); + break; + } + + switch (pChunk->chunk_type) + { + case CHUNK_TYPE_RAW: + { + unsigned wantWrLen = chunkDataLen; + + if (CHUNK_HEAD_SIZE + chunkDataLen != pChunk->total_sz) { + sperr("sparse: bad chunk size: head 0x%x + data 0x%x != total 0x%x\n", + (unsigned)CHUNK_HEAD_SIZE, chunkDataLen, pChunk->total_sz); + return -__LINE__; + } + + if (pChunk->total_sz > unParsedBufLen)//left data not enough for this chunk (chunk header + chunk data) + { + const unsigned unParseChunkDataLen = unParsedBufLen - CHUNK_HEAD_SIZE; + + wantWrLen = (unParseChunkDataLen >> OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS) << OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS; + _spPacketStates.notWrBackSz4LongChunk = chunkDataLen - wantWrLen; + _spPacketStates.nextFlashAddr4LastLongChunk = flashAddrStart + (wantWrLen>>9); + spmsg("Not enough one chunk: unParseChunkDataLen 0x%x ,chunk data len 0x%x, wantWrLen 0x%x, left 0x%08x\n", + unParseChunkDataLen, chunkDataLen, wantWrLen, _spPacketStates.notWrBackSz4LongChunk); + } + + if (wantWrLen) + { + thisWriteLen = optimus_cb_simg_write_media(flashAddrStart, wantWrLen, (char*)pChunk + CHUNK_HEAD_SIZE); + if (thisWriteLen != wantWrLen) { + sperr("Fail to write to flash, want to write %dB, but %dB\n", wantWrLen, thisWriteLen); + return -__LINE__; + } + } + } + break; + + case CHUNK_TYPE_DONT_CARE: + { + DWN_DBG("don't care chunk\n"); + if (CHUNK_HEAD_SIZE != pChunk->total_sz) { + sperr("bogus DONT CARE chunk\n"); + return -__LINE__; + } + + } + break; + + case CHUNK_TYPE_FILL: + { + const unsigned fillVal = *(unsigned*)(pChunk + 1); + unsigned LeftDataLen = chunkDataLen; + unsigned temp_flashAddrStart = flashAddrStart; + unsigned* pFillValBuf = (unsigned*)OPTIMUS_SPARSE_IMG_FILL_VAL_BUF; + const unsigned FillBufSz = OPTIMUS_SPARSE_IMG_FILL_BUF_SZ; + static unsigned _filledBufValidLen = 0; + const unsigned thisChunkFilledLen = min(chunkDataLen, FillBufSz); + int _NeedFillAsNotErasedYet = 0; + + spdbg("CHUNK_TYPE_FILL,fillVal=0x%8x, chunkDataLen=0x%8x, thisChunkFilledLen=0x%x\n", + fillVal, chunkDataLen, thisChunkFilledLen); + if (CHUNK_HEAD_SIZE + 4 != pChunk->total_sz) { + sperr("error FILL chunk\n"); + return -__LINE__; + } + switch (device_boot_flag) { + case EMMC_BOOT_FLAG: + case SPI_EMMC_FLAG: + _NeedFillAsNotErasedYet = (fillVal != 0); + break; + + case NAND_BOOT_FLAG: + case SPI_NAND_FLAG: + _NeedFillAsNotErasedYet = (fillVal != 0XFFFFFFFFU); + break; + default: + _NeedFillAsNotErasedYet = 1; + break; + } + //for, emmc, if fillVal is 0, then _NeedFillAsNotErasedYet = false if "disk_inital > 0" + if (!_NeedFillAsNotErasedYet)_NeedFillAsNotErasedYet = (is_optimus_storage_inited()>>16) == 0;// == 0 means 'disk_inital 0' + + if (_NeedFillAsNotErasedYet) + { + if (!_filledBufValidLen) { + DWN_MSG("CHUNK_TYPE_FILL\n"); + } + if (fillVal != *pFillValBuf && _filledBufValidLen) { + _filledBufValidLen = 0; + } + if (_filledBufValidLen < thisChunkFilledLen) { + int i = _filledBufValidLen>>2; + unsigned* temBuf = pFillValBuf + i; + + while (i++ < (thisChunkFilledLen>>2)) *temBuf++ = fillVal; + _filledBufValidLen = thisChunkFilledLen; + } + + do { + unsigned actualWrLen = 0; + + thisWriteLen = min(LeftDataLen, thisChunkFilledLen); + + actualWrLen = optimus_cb_simg_write_media(temp_flashAddrStart, thisWriteLen, (char*)pFillValBuf); + if (actualWrLen != thisWriteLen) { + sperr("FILL_CHUNK:Want write 0x%x Bytes, but 0x%x\n", thisWriteLen, actualWrLen); + break; + } + + temp_flashAddrStart += thisWriteLen >> 9; + LeftDataLen -= thisWriteLen; + }while(LeftDataLen); + } + thisWriteLen = 4;/////////// + } + break; + case CHUNK_TYPE_CRC32: + sperr("CHUNK_TYPE_CRC32 unsupported yet!\n"); + return -__LINE__; + default: + sperr("unknown chunk ID 0x%x at %p\n", pChunk->chunk_type, pChunk); + return -__LINE__; + } + + /////update for next chunk + unParsedBufLen -= CHUNK_HEAD_SIZE + thisWriteLen; + flashAddrStart += chunkDataLen>>9; + memcpy(backChunkHead, pChunk, CHUNK_HEAD_SIZE);//back up verify chunk info + spdbg("index %d ,tp 0x%x\n", _spPacketStates.backChunkNum, backChunkHead->chunk_type); + ++_spPacketStates.backChunkNum; + ++backChunkHead; + + pChunk = (chunk_header_t*)((u64)pChunk + pChunk->total_sz); + } + + spmsg("leftChunkNum %d, bak num %d\n", _spPacketStates.leftChunkNum, _spPacketStates.backChunkNum); + + _spPacketStates.pktHeadLen = 0;//>0 only when first time + + *unParsedDataLen = unParsedBufLen; + return (flashAddrStart - flashAddrInSec); +} + +int optimus_sparse_back_info_probe(void) +{ + int ret = 0; + + if (_spPacketStates.leftChunkNum) + { + DWN_ERR("%d chunk left, image not burn completed!!\n", _spPacketStates.leftChunkNum); + return OPT_DOWN_FALSE; + } + + ret = optimus_simg_probe((u8*)(u64)_spPacketStates.chunkInfoBackAddr, FILE_HEAD_SIZE); + DWN_DBG("back h addr 0x%x\n", _spPacketStates.chunkInfoBackAddr); + + return ret; +} + +//get next chunk data to read from ext4 partition +int optimus_sparse_get_chunk_data(u8** head, u32* headSz, u32* dataSz, u64* dataOffset) +{ + chunk_header_t* pChunk = (chunk_header_t*)(_spPacketStates.chunkInfoBackAddr + FILE_HEAD_SIZE) + _spPacketStates.leftChunkNum;//chunk header + + *headSz = *dataOffset = *dataSz = 0; + DWN_DBG("leftNum %d\n", _spPacketStates.backChunkNum); + + if (!_spPacketStates.leftChunkNum) //file header + { + *headSz = FILE_HEAD_SIZE; + *head = (u8*)(u64)_spPacketStates.chunkInfoBackAddr; + } + else + { + *head = (u8*)pChunk; + } + + //parse until RAW chunk or no chunk left + for (;_spPacketStates.leftChunkNum < _spPacketStates.backChunkNum;) + { + const unsigned chunkDataLen = pChunk->chunk_sz * _spPacketStates.sparseBlkSz; + + switch (pChunk->chunk_type) + { + case CHUNK_TYPE_RAW: + { + if (CHUNK_HEAD_SIZE + chunkDataLen != pChunk->total_sz) { + sperr("sparse: bad chunk size!\n"); + return OPT_DOWN_FAIL; + } + + *dataSz = chunkDataLen; + } + break; + + case CHUNK_TYPE_DONT_CARE: + { + spdbg("don't care chunk\n"); + if (CHUNK_HEAD_SIZE != pChunk->total_sz) { + sperr("bogus DONT CARE chunk\n"); + return OPT_DOWN_FAIL; + } + } + break; + + case CHUNK_TYPE_FILL: + { + spdbg("CHUNK_TYPE_FILL\n"); + if (CHUNK_HEAD_SIZE + 4 != pChunk->total_sz) { + sperr("bogus DONT CARE chunk\n"); + return OPT_DOWN_FAIL; + } + *dataSz = 4;/////// + } + break; + + + default: + sperr("unknown chunk ID 0x%x, parsed %d, total %d\n", pChunk->chunk_type, _spPacketStates.leftChunkNum, _spPacketStates.backChunkNum); + return OPT_DOWN_FAIL; + } + + //update backed chunk info + *dataOffset = _spPacketStates.chunkOffset;//attention that offset < totalDataLen + + _spPacketStates.chunkOffset += chunkDataLen;; + *headSz += CHUNK_HEAD_SIZE; + ++pChunk; + ++_spPacketStates.leftChunkNum; + + if (*dataSz) break; + } + + spdbg("left %d, total %d\n", _spPacketStates.leftChunkNum, _spPacketStates.backChunkNum); + return OPT_DOWN_OK; +} + + +#if 0 +int do_timestamp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +/*const char* optimus_time_stamp(void)*/ +{ + const char* _formatStr = "[%5d.%03d]"; + static char TimeStr[32] ; + int timeMSec = 0; + ulong curTimeInUSec = 0; +static ulong timeInUSec = 0; + + if (!timeInUSec) + { + timeInUSec = get_timer(timeInUSec); + return 0; + } + timeInUSec = curTimeInUSec = get_timer(timeInUSec);//timer unit is in uS + + /*printf("time %x, %x\n", (u32)(timeInUSec>>32), (u32)timeInUSec);*/ + /*if(!timeInUSec) return "";//As eFG_printf and uart_printf use while(*str) to determin whether to print, here make use it to not to print*/ + + /*curTimeInUSec /= 1000;//time to mSec*/ + timeMSec = curTimeInUSec % 1000; + curTimeInUSec /= 1000;//time to Second + + sprintf(TimeStr, _formatStr, (u32)curTimeInUSec, timeMSec); + printf(TimeStr); + printf("\n"); + + /*return TimeStr;*/ + return 0; +} + +U_BOOT_CMD( + timestamp, //command name + 5, //maxargs + 1, //repeatable + do_timestamp, //command function + "Burning a partition from sdmmc ", //description + "Usage: sdc_update partiton image_file_path fileFmt(sparse or normal)\n" //usage +); +#endif//#if 0 + diff --git a/drivers/usb/gadget/v2_burning/v2_common/sparse_format.h b/drivers/usb/gadget/v2_burning/v2_common/sparse_format.h new file mode 100644 index 0000000000..6c62c34c75 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_common/sparse_format.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +typedef struct sparse_header { + __le32 magic; /* 0xed26ff3a */ + __le16 major_version; /* (0x1) - reject images with higher major versions */ + __le16 minor_version; /* (0x0) - allow images with higer minor versions */ + __le16 file_hdr_sz; /* 28 bytes for first revision of the file format */ + __le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ + __le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */ + __le32 total_blks; /* total blocks in the non-sparse output image */ + __le32 total_chunks; /* total chunks in the sparse input image */ + __le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */ + /* as 0. Standard 802.3 polynomial, use a Public Domain */ + /* table implementation */ +} sparse_header_t; + +#define SPARSE_HEADER_MAGIC 0xed26ff3a + +#define CHUNK_TYPE_RAW 0xCAC1 +#define CHUNK_TYPE_FILL 0xCAC2 +#define CHUNK_TYPE_DONT_CARE 0xCAC3 +#define CHUNK_TYPE_CRC32 0xCAC4 + +typedef struct chunk_header { + __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */ + __le16 reserved1; + __le32 chunk_sz; /* in blocks in output image */ + __le32 total_sz; /* in bytes of chunk input file including chunk header and data */ +} chunk_header_t; + +/* Following a Raw or Fill or CRC32 chunk is data. + * For a Raw chunk, it's the data in chunk_sz * blk_sz. + * For a Fill chunk, it's 4 bytes of the fill data. + * For a CRC32 chunk, it's 4 bytes of CRC32 + */ + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_ini__aml_sdc_burn.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_ini__aml_sdc_burn.c new file mode 100644 index 0000000000..267138b501 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_ini__aml_sdc_burn.c @@ -0,0 +1,444 @@ +/* + * \file optimus_ini__aml_sdc_burn.c + * \brief parse the aml_sdc_burn.ini + * + * \version 1.0.0 + * \date 2015/2/3 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2015 Amlogic. All Rights Reserved. + * + */ +#include "optimus_sdc_burn_i.h" + +#define dbg(fmt ...) //printf(fmt) +#define msg DWN_MSG +#define err DWN_ERR + +#define SET_BURN_PARTS "burn_parts" +#define SET_CUSTOM_PARA "common" +#define SET_BURN_PARA_EX "burn_ex" + +static const char* _iniSets[] = { + SET_BURN_PARTS , + SET_CUSTOM_PARA , + SET_BURN_PARA_EX , +}; + +#define TOTAL_SET_NUM ( sizeof(_iniSets)/sizeof(const char*) ) + +ConfigPara_t g_sdcBurnPara = { + .setsBitMap.burnParts = 0, + .setsBitMap.custom = 0, + .setsBitMap.burnEx = 0, + + .burnParts = { + .burn_num = 0, + .bitsMap4BurnParts = 0, + }, + + .custom = { + .eraseBootloader = 1,//default to erase bootloader! + .eraseFlash = 0, + .bitsMap.eraseBootloader = 0, + .bitsMap.eraseFlash = 0, + }, + + .burnEx = { + .bitsMap.pkgPath = 0, + .bitsMap.mediaPath = 0, + }, +}; + +static int init_config_para(ConfigPara_t* pCfgPara) +{ + memset(pCfgPara, 0, sizeof(ConfigPara_t)); + + pCfgPara->setsBitMap.burnParts = 0; + pCfgPara->setsBitMap.custom = 0; + pCfgPara->setsBitMap.burnEx = 0; + + pCfgPara->burnParts.burn_num = 0; + pCfgPara->burnParts.bitsMap4BurnParts = 0; + + pCfgPara->custom.eraseBootloader = 1;//default to erase bootloader! + pCfgPara->custom.eraseFlash = 0; + pCfgPara->custom.bitsMap.eraseBootloader = 0; + pCfgPara->custom.bitsMap.eraseFlash = 0; + + pCfgPara->burnEx.bitsMap.pkgPath = 0; + pCfgPara->burnEx.bitsMap.mediaPath = 0; + + return 0; +} + +int print_burn_parts_para(const BurnParts_t* pBurnParts) +{ + int partIndex = 0; + + printf("[%s]\n", SET_BURN_PARTS); + printf("burn_num = %d\n", pBurnParts->burn_num); + + for (; partIndex < pBurnParts->burn_num; ++partIndex) + { + printf("burn_part%d = %s\n", partIndex, pBurnParts->burnParts[partIndex]); + } + printf("\n"); + + return 0; +} + +static int print_sdc_burn_para(const ConfigPara_t* pCfgPara) +{ + printf("\n=========sdc_burn_paras=====>>>\n"); + + { + const CustomPara_t* pCustom = &pCfgPara->custom; + + printf("[%s]\n", SET_CUSTOM_PARA); + printf("erase_bootloader = %d\n", pCustom->eraseBootloader); + printf("erase_flash = %d\n", pCustom->eraseFlash); + printf("reboot = 0x%x\n", pCustom->rebootAfterBurn); + printf("key_overwrite = 0x%x\n", pCustom->keyOverwrite); + printf("\n"); + } + + { + const BurnEx_t* pBurnEx = &pCfgPara->burnEx; + + printf("[%s]\n", SET_BURN_PARA_EX); + printf("package = %s\n", pBurnEx->pkgPath); + printf("media = %s\n", pBurnEx->mediaPath); + printf("\n"); + } + + print_burn_parts_para(&pCfgPara->burnParts); + + printf("<<<<=====sdc_burn_paras======\n\n"); + + return 0; +} + +static int parse_set_burnEx(const char* key, const char* strVal) +{ + BurnEx_t* pBurnEx = &g_sdcBurnPara.burnEx; + + if (!strcmp("package", key)) + { + if (pBurnEx->bitsMap.pkgPath) { + err("key package in burn_ex is duplicated!\n"); + return __LINE__; + } + if (!strVal) { + err("value for package in set burn_ex can't be empty!\n"); + return __LINE__; + } + + strcpy(pBurnEx->pkgPath, strVal); + pBurnEx->bitsMap.pkgPath = 1; + + return 0; + } + + if (!strcmp("media", key)) + { + if (pBurnEx->bitsMap.mediaPath) { + err("key media in burn_ex is duplicated!\n"); + return __LINE__; + } + if (strVal) + { + strcpy(pBurnEx->mediaPath, strVal); + pBurnEx->bitsMap.mediaPath = 1; + } + + return 0; + } + + return 0; +} + +static int parse_set_custom_para(const char* key, const char* strVal) +{ + CustomPara_t* pCustome = &g_sdcBurnPara.custom; + const unsigned cfgVal = strVal ? simple_strtoul(strVal, NULL, 0) : 0; + + if (!strcmp(key, "erase_bootloader")) + { + if (pCustome->bitsMap.eraseBootloader) { + goto _key_dup; + } + + if (strVal) + { + pCustome->eraseBootloader = cfgVal; + pCustome->bitsMap.eraseBootloader = 1; + } + + } + + if (!strcmp(key, "erase_flash")) + { + if (pCustome->bitsMap.eraseFlash) { + goto _key_dup; + } + + if (strVal) + { + pCustome->eraseFlash = cfgVal; + pCustome->bitsMap.eraseFlash = 1; + } + + } + + if (!strcmp(key, "reboot")) + { + if (pCustome->bitsMap.rebootAfterBurn) { + goto _key_dup; + } + + if (strVal) + { + pCustome->rebootAfterBurn = cfgVal; + pCustome->bitsMap.rebootAfterBurn = 1; + } + + } + + if (!strcmp(key, "key_overwrite")) + { + if (pCustome->bitsMap.keyOverwrite) { + goto _key_dup; + } + + if (strVal) + { + pCustome->keyOverwrite = cfgVal; + pCustome->bitsMap.keyOverwrite = 1; + } + + } + + return 0; + +_key_dup: + err("key %s is duplicated!\n", key); + return -1; +} + +#if 0 +int check_custom_para(const CustomPara_t* pCustome) +{ + //TODO: not completed!! + return 0; +} +#endif + +static int parse_burn_parts(const char* key, const char* strVal) +{ + BurnParts_t* pBurnParts = &g_sdcBurnPara.burnParts; + + if ( !strcmp("burn_num", key) ) + { + if (!strVal) { + err("burn_num in burn_parts can't be empty!!"); + return __LINE__; + } + + pBurnParts->burn_num = simple_strtoul(strVal, NULL, 0); + if (pBurnParts->burn_num < 1) { + err("value for burn_num in burn_parts in invalid\n"); + return __LINE__; + } + + return 0; + } + + if (pBurnParts->burn_num < 1) { + err("burn_num is not config or 0 ??\n"); + return __LINE__; + } + + { + const char burn_partx[] = "burn_partx"; + const int validKeyLen = sizeof(burn_partx) - 2; + const int totalBurnNum = pBurnParts->burn_num; + int burnIndex = 0; + char* partName = NULL; + + if (strncmp(burn_partx, key, validKeyLen)) + { + err("error burn part name [%s]\n", key); + return __LINE__; + } + + burnIndex = key[validKeyLen] - '0'; + if (!(burnIndex >= 0 && burnIndex < totalBurnNum)) + { + err("Error \"%s\", only burn_part[0~%d] is valid as burn_num is %d\n", + key, totalBurnNum - 1, totalBurnNum); + return __LINE__; + } + + if (pBurnParts->bitsMap4BurnParts & (1U<<burnIndex)) { + err("key %s is duplicated in burn_parts\n", key); + return __LINE__; + } + pBurnParts->bitsMap4BurnParts |= 1U<<burnIndex; + + partName = (char*)pBurnParts->burnParts[burnIndex]; + if (!strVal) { + err("value of %s can't empty\n", key); + return __LINE__; + } + + if (!strcmp("bootloader", strVal)) { + err("bootloader not need to configure at burn_parts\n"); + return __LINE__; + } + + strcpy(partName, strVal); + } + + return 0; +} + +int check_cfg_burn_parts(const ConfigPara_t* burnPara) +{ + const BurnParts_t* pBurnParts = &burnPara->burnParts; + const int cfgBurnNum = pBurnParts->burn_num; + const unsigned bitsMap = pBurnParts->bitsMap4BurnParts; + int mediaPathHasCfg = burnPara->burnEx.bitsMap.mediaPath; + int i = 0; + + + for (i = 0; i < cfgBurnNum; i++) + { + int b = bitsMap & (1U<<i); + + if (!b) { + err("Please cfg burn_part%d\n", i); + return __LINE__; + } + + if (mediaPathHasCfg) + { + if (!strcmp(pBurnParts->burnParts[i], "media")) { + DWN_ERR("media can't cfg in both media_path and burn_parts\n"); + return __LINE__; + } + } + } + + return 0; +} + +static int optimus_aml_sdc_ini_check_set_valid(const char* setName) +{ + const char* pName = NULL; + int i = 0; + int isValid = 0; + + for (; i < TOTAL_SET_NUM && !isValid; ++i) + { + pName = _iniSets[i]; + isValid = !strcmp(setName, pName); + } + + + return isValid; +} + +static int optimus_aml_sdc_burn_ini_parse_usr_cfg(const char* setName, const char* keyName, const char* usrKeyVal) +{ + int ret = 0; + + if (!strcmp(SET_BURN_PARTS, setName)) + { + return parse_burn_parts(keyName, usrKeyVal); + } + if (!strcmp(SET_CUSTOM_PARA, setName)) + { + return parse_set_custom_para(keyName, usrKeyVal); + } + if (!strcmp(SET_BURN_PARA_EX, setName)) + { + return parse_set_burnEx(keyName, usrKeyVal); + } + + return ret; +} + +int parse_ini_cfg_file(const char* filePath) +{ + const int MaxFileSz = OPTIMUS_DOWNLOAD_SLOT_SZ; + char* CfgFileLoadAddr = (char*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + int rcode = 0; + const int MaxLines = 1024;// + char* lines[MaxLines]; + int validLineNum = 0; + + init_config_para(&g_sdcBurnPara); + + validLineNum = parse_ini_file_2_valid_lines(filePath, CfgFileLoadAddr, MaxFileSz, lines); + if (!validLineNum) { + err("error in parse ini file\n"); + return __LINE__; + } + + rcode = optimus_ini_trans_lines_2_usr_params((const char* *)lines, validLineNum, + optimus_aml_sdc_ini_check_set_valid, + optimus_aml_sdc_burn_ini_parse_usr_cfg); + if (rcode) { + err("Fail in get cfg from %s\n", filePath); + return __LINE__; + } + + rcode = check_cfg_burn_parts(&g_sdcBurnPara); + if (rcode) { + err("Fail in check burn parts.\n"); + return __LINE__; + } + + print_sdc_burn_para(&g_sdcBurnPara); + + return 0; +} + +#define MYDBG 0 +#if MYDBG +int do_ini_parser(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + const char* filePath = "dos_dc_burn.ini"; + + //mmc info to ensure sdcard inserted and inited, mmcinfo outer as there U-disk later + rcode = run_command("mmcinfo", 0); + if (rcode) { + err("Fail in init mmc, Does sdcard not plugged in?\n"); + return __LINE__; + } + + if (2 <= argc) { + filePath = argv[1]; + } + + rcode = parse_ini_cfg_file(filePath); + if (rcode) { + err("error in parse ini file\n"); + return __LINE__; + } + + return 0; +} + +U_BOOT_CMD( + ini_parser, //command name + 5, //maxargs + 0, //repeatable + do_ini_parser, //command function + "Burning a partition from sdmmc ", //description + "Usage: sdc_update partiton image_file_path fileFmt(android sparse, other normal) [,verify_file]\n" //usage +); +#endif//#if MYDBG + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_ini_parser.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_ini_parser.c new file mode 100644 index 0000000000..c02b377107 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_ini_parser.c @@ -0,0 +1,429 @@ +/* + * \file optimus_ini_parser.c + * \brief ini parsing utilities for sdc burnning + * + * \version 1.0.0 + * \date 2013-7-11 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#include "optimus_sdc_burn_i.h" + +#define dbg(fmt ...) //printf(fmt) +#define msg DWN_MSG +#define err DWN_ERR + +#define MAX_ARGS 4 +#define is_space_char(c) ('\t' == c || ' ' == c) +#define is_delimeter(c) ('[' == c || ']' == c || '=' == c) + +#define is_valid_char(c) ( ('0' <= c && '9' >= c) || ('_' == c)\ + || ('a' <= c && 'z' >= c) || ('A' <= c && 'Z' >= c) ) \ + || ('.' == c) || ('\\' == c) || ('/' == c) || ('-' == c) \ + || (':' == c) + +static int line_is_valid(const char* line) +{ + char c = 0; + + while (c = *line++, c) + { + int ret = is_delimeter(c) || is_valid_char(c) || is_space_char(c); + + if (!ret) { + err("invalid chars! ascii val(0x%x)\n", c); + return 0; + } + } + + return 1;//line is valid +} + +//valid lines type: set or key/value pair +enum _INI_LINE_TYPE{ + INI_LINE_TYPE_ERR = 0, + INI_LINE_TYPE_SET , + INI_LINE_TYPE_KE_VALUE , +}; + +//this func is used after line_is_valid +static int line_2_words(char* line, char* argv[], const int maxWords) +{ + int nargs = 0; + char cur = 0; + + for (cur = *line; is_space_char(cur); cur = *++line) {} + + argv[nargs++] = line; + for (;cur = *line, cur; ++line) + { + if (!is_space_char(cur)) continue; + //following do with space character + + *line = 0; + for (cur = *++line; is_space_char(cur) && cur; cur = *++line) {}//ignore all space between words + + if (!cur) break;//line ended + + argv[nargs++] = line; + if (maxWords <= nargs) { + err("too many words num %d, max is %d\n", nargs, maxWords); + return 0; + } + } + + return nargs; +} + +//step1:first loop to seprate buffer to lines +int _optimus_parse_buf_2_lines(char* pTextBuf, const unsigned textSz, + const char* lines[], unsigned* totalLineNum, const unsigned MaxLines) +{ + const char* curLine = pTextBuf; + char* pTemp = pTextBuf; + unsigned i = 0; + unsigned lineNum = 0; + + pTextBuf[textSz] = '\0'; + //loop to seprate buffer to lines + for (i = 0; i < textSz ; i++, ++pTemp) + { + char c = *pTemp; + int isFileEnd = i + 1 >= textSz; + + if (MaxLines <= lineNum) { + DWN_ERR("total line number %d too many, at most %d lines!\n", lineNum, MaxLines); + break; + } + + if ('\r' != c && '\n' != c) { + continue; + } + *pTemp = 0;/// + + if (isFileEnd) + { + lines[lineNum++] = curLine; + break;//End to read file if file ended + } + + DWN_DBG("%3d: %s\n", lineNum, curLine); + if ('\r' == c) //for DOS \r\n mode + { + if ('\n' == pTemp[1]) + { + lines[lineNum++] = curLine; + + ++pTemp; + curLine = pTemp + 1; + ++i;//skip '\n' which follows '\r' + } + else + { + DWN_ERR("Syntax error at line %d, DOS end \\r\\n, but \\r%x\n", lineNum + 1, pTemp[1]); + return __LINE__; + } + } + else if('\n' == c)//for UNIX '\n' mode + { + lines[lineNum++] = curLine; + curLine = pTemp + 1; + } + } + + *totalLineNum = lineNum; + return 0; +} + +//abandon comments lines and space lines, +//but not decrease thie line numbers +int _optimus_abandon_ini_comment_lines(char* lines[], const unsigned lineNum) +{ + unsigned lineIndex = 0; + for (lineIndex = 0; lineIndex < lineNum ; lineIndex++) + { + int isSpaceLine = 1; + char c = 0; + char* thisLine = lines[lineIndex]; + + while (c = *thisLine++, c) + { + //escape space and tab + if (is_space_char(c)) + { + continue; + } + + isSpaceLine = 0;//no space line + //test if frist char is comment delimeter + if (';' == c) + { + lines[lineIndex] = NULL;//invalid comment lines + } + } + + //if all character is space or tab, also invlalid it + if (isSpaceLine) + { + lines[lineIndex] = NULL; + } + } + + return 0; +} + +//Return value is the valid line numbers +//1, Read the whole file content to buffer +//2, parse file content to lines +//3, parse each valid line +int parse_ini_file_2_valid_lines(const char* filePath, char* iniBuf, const unsigned bufSz, char* lines[]) +{ + const int MaxLines = 1024;// + int ret = 0; + unsigned fileSz = bufSz; + unsigned lineNum = 0; + int hFile = -1; + unsigned readLen = 0; + + fileSz = (unsigned)do_fat_get_fileSz(filePath); + if (!fileSz) { + err("File %s not exist in sdcard??\n", filePath); + return __LINE__; + } + if (fileSz >= bufSz) { + err("file size 0x%x illegal, > bufSz 0x%x\n", fileSz, bufSz); + return __LINE__; + } + DWN_MSG("ini sz 0x%xB\n", fileSz); + + hFile = do_fat_fopen(filePath); + if (hFile < 0) { + err("Fail to open file %s\n", filePath); + return 0; + } + + readLen = do_fat_fread(hFile, (u8*)iniBuf, fileSz); + if (readLen != fileSz) { + err("failed to load cfg file, want size 0x%x, but 0x%x\n", fileSz, readLen); + do_fat_fclose(hFile); + return 0; + } + iniBuf[fileSz] = 0; + + do_fat_fclose(hFile); + + dbg("\\r is 0x%x\t, \\n is 0x%x\n", '\r', '\n'); + + //step1:first loop to seprate buffer to lines + ret = _optimus_parse_buf_2_lines(iniBuf, fileSz, (const char**)lines, &lineNum, MaxLines); + if (ret) { + err("Fail to parse buf to lines.ret=%d\n", ret); + return 0; + } + + //step 2: abandon comment or space lines + ret = _optimus_abandon_ini_comment_lines(lines, lineNum); + + return lineNum; +} + +int optimus_ini_trans_lines_2_usr_params(const char* const lines[], const unsigned lineNum, + int (*pCheckSetUseFul)(const char* setName), + int (*pParseCfgVal)(const char* setName, const char* keyName, const char* keyVal)) +{ + const int MaxWordsALine = 32; + char* wordsALine[MaxWordsALine]; + int ret = 0; + int nwords = 0; + unsigned i = 0; + unsigned lineIndex = 0; + const int MaxUsefulSets = 8; + const char* cacheSetNames[MaxUsefulSets]; + const char* CurrentSetName = NULL; + + while (i < MaxUsefulSets) cacheSetNames[i++] = NULL; + + dbg("\nvalid lines:\n"); + for (lineIndex = 0; lineIndex < lineNum ; lineIndex++) + { + int lineType = INI_LINE_TYPE_ERR; + const char* iniKey = NULL; + const char* iniVal = NULL; + const char* iniSet = NULL; + + const char* const curLine = lines[lineIndex]; + + if (!curLine) continue;//comment or space lines + + if (!line_is_valid(curLine)) //only comment lines can contain non-ASCII letters + { + err("line %d contain invalid chars\n", lineIndex + 1); + ret = __LINE__; + break; + } + dbg("%3d: %s\n",lineIndex, curLine); + + nwords = line_2_words((char*)curLine, wordsALine, MaxWordsALine); + if (nwords <= 0) { + ret = __LINE__; + break; + } + if (nwords > 3) { + err("line %d error: ini support at most 3 words, but %d\n", lineIndex + 1, nwords); + ret = __LINE__; + break; + } + + switch (nwords) + { + case 3: + { + if (!strcmp("=", wordsALine[1]))//k/v pair + { + lineType = INI_LINE_TYPE_KE_VALUE; + iniKey = wordsALine[0]; iniVal = wordsALine[2]; + break; + } + else if(!strcmp("[" , wordsALine[0]) && !strcmp("]" , wordsALine[2]))//set line + { + lineType = INI_LINE_TYPE_SET; + iniSet = wordsALine[1]; + break; + } + else + { + lineType = INI_LINE_TYPE_ERR; + err("Ini syntax error when parse line %d\n", lineIndex + 1); + ret = __LINE__; break; + } + } + break; + + case 2: + { + if ('[' == wordsALine[0][0]) //set like "[set ]" or "[ set]" + { + if (!strcmp("]", wordsALine[1])) + { + lineType = INI_LINE_TYPE_SET; + iniSet = wordsALine[0] + 1; + break; + } + else if (']' == wordsALine[1][strlen(wordsALine[1]) - 1] && !strcmp("[", wordsALine[0])) + { + lineType = INI_LINE_TYPE_SET; + iniSet = wordsALine[1]; + wordsALine[1][strlen(wordsALine[1]) - 1] = 0; + break; + } + } + else if(!strcmp("=", wordsALine[1]))//k/v pair like "key = " + { + lineType = INI_LINE_TYPE_KE_VALUE; + iniKey = wordsALine[0]; + break; + } + else if('=' == wordsALine[1][0])//k/v pair like "key =v" or "key= v" + { + lineType = INI_LINE_TYPE_KE_VALUE; + iniKey = wordsALine[0]; + iniVal = wordsALine[1] + 1; + break; + } + else if ('=' == wordsALine[0][strlen(wordsALine[0]) - 1])//k/v pair like "key= v" + { + wordsALine[0][strlen(wordsALine[0]) - 1] = 0; + lineType = INI_LINE_TYPE_KE_VALUE; + iniKey = wordsALine[0]; + iniVal = wordsALine[1]; + } + } + break; + + case 1: + { + char* word = wordsALine[0]; + char firstChar = word[0]; + char lastChar = word[strlen(word) - 1]; + + if ('[' == firstChar && ']' == lastChar) + { + lineType = INI_LINE_TYPE_SET; + iniSet = word + 1; + word[strlen(word) - 1] = 0; + break; + } + else + { + char c = 0; + + iniKey = word; + while (c = *word++, c) + { + if ('=' == c)//TODO: not assert only delimeter in a line yet + { + lineType = INI_LINE_TYPE_KE_VALUE; + *--word = 0; + iniVal = ++word; + iniVal = *iniVal ? iniVal : NULL; + break; + } + } + } + } + break; + + default: + break; + } + + if (INI_LINE_TYPE_SET == lineType) + { + int setIndex = 0; + + dbg("set line, set is %s\n", iniSet); + CurrentSetName = NULL; + ret = pCheckSetUseFul(iniSet); + if (!ret) {//the set don't care + continue; + } + + //Check the useful set name is not duplicated! + for (setIndex = 0; setIndex < MaxUsefulSets; ++setIndex) { + const char* pset = cacheSetNames[setIndex]; + if (!pset) { + CurrentSetName = cacheSetNames[setIndex] = iniSet; + break; + } + ret = strcmp(pset, iniSet); + if (!ret) { + ret = __LINE__; + goto _set_duplicated; + } + } + } + else if(INI_LINE_TYPE_KE_VALUE == lineType && CurrentSetName) + { + dbg("k/v line, key (%s), val (%s)\n", iniKey, iniVal); + + ret = pParseCfgVal(CurrentSetName, iniKey, iniVal); + if (ret) { + goto _line_err; + } + } + } + + return ret; + +_line_err: + err("Fail to parse line %d\n", lineIndex + 1); + return ret; + +_set_duplicated: + err("line %d err:set is duplicated!!\n", lineIndex + 1); + return ret; +} + + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_led.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_led.c new file mode 100644 index 0000000000..8c8623598c --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_led.c @@ -0,0 +1,155 @@ +/* + * \file optimus_led.c + * \brief use led to indicate burning states + * + * \version 1.0.0 + * \date 2013/11/9 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ +#include "../v2_burning_i.h" +#include "optimus_led.h" + +#define OPTIMUS_LED_SRC_IS_PWM 1//pwm type led + +typedef enum{ + OPTIMUS_LED_STATE_INVALID = 0XF0 , + OPTIMUS_LED_STATE_RED ,//Burning failed if stay on this state + OPTIMUS_LED_STATE_GREEN , + OPTIMUS_LED_STATE_SLOW_FLICKERING , + OPTIMUS_LED_STATE_FAST_FLICKERING ,//fast flickering to catch the eye that it's burning successful + +}OptimusLedStates_e; + +#if OPTIMUS_LED_SRC_IS_PWM +#define PWM_CHANNEL_INDEX 5 + +static int optimus_pwm_led_show_state(OptimusLedStates_e ledState) +{ + int rc = 0; + int PwmHighLevelPeriod = 0; + int PwmLowLevelPeriod = 0; + char cmdStr[64]; + + switch (ledState) + { + case OPTIMUS_LED_STATE_SLOW_FLICKERING: + { + PwmHighLevelPeriod = 0xfffe; + PwmLowLevelPeriod = PwmHighLevelPeriod; + + sprintf(cmdStr, "pwm config %d %d %d", PWM_CHANNEL_INDEX, PwmHighLevelPeriod, PwmLowLevelPeriod); + } + break; + + case OPTIMUS_LED_STATE_FAST_FLICKERING: + { + PwmHighLevelPeriod = 0x2000; + PwmLowLevelPeriod = PwmHighLevelPeriod; + + sprintf(cmdStr, "pwm config %d %d %d", PWM_CHANNEL_INDEX, PwmHighLevelPeriod, PwmLowLevelPeriod); + } + break; + + case OPTIMUS_LED_STATE_GREEN: + { + PwmHighLevelPeriod = 0; + PwmLowLevelPeriod = 0xffffu;//always low level + + sprintf(cmdStr, "pwm config %d %d %d", PWM_CHANNEL_INDEX, PwmHighLevelPeriod, PwmLowLevelPeriod); + } + break; + + case OPTIMUS_LED_STATE_RED: + { + PwmHighLevelPeriod = 0xffffu;//always high level + PwmLowLevelPeriod = 0; + + sprintf(cmdStr, "pwm config %d %d %d", PWM_CHANNEL_INDEX, PwmHighLevelPeriod, PwmLowLevelPeriod); + } + break; + default: + DWN_ERR("invlaid pwm state %d\n", ledState); + return __LINE__; + } + + rc = run_command(cmdStr, 0); + if (rc) { + DWN_ERR("Fail in run_cmd[%s], ret=%d\n", cmdStr, rc); + return __LINE__; + } + + return 0; +} + +int optimus_led_open(int ledType) +{ + const int clkSel = 0; + const int clkDiv = 0x7f; + const int pinIndex = 0; + char cmdStr[64]; + int rc = 0; + + sprintf(cmdStr, "pwm enable %d %d %d %d", PWM_CHANNEL_INDEX, pinIndex, clkSel, clkDiv); + rc = run_command(cmdStr, 0); + if (rc) { + DWN_ERR("Fail in run_cmd[%s], ret=%d\n", cmdStr, rc); + return __LINE__; + } + + return 0; +} + +int optimus_led_close(void) +{ + int rc = 0; + char cmdStr[64]; + + sprintf(cmdStr, "pwm disable %d", PWM_CHANNEL_INDEX); + rc = run_command(cmdStr, 0); + + return rc; +} + +int optimus_led_show_in_process_of_burning(void) +{ + return optimus_pwm_led_show_state(OPTIMUS_LED_STATE_SLOW_FLICKERING); +} + +int optimus_led_show_burning_success(void) +{ + optimus_pwm_led_show_state(OPTIMUS_LED_STATE_FAST_FLICKERING); + + return 0; +} + +int optimus_led_show_burning_failure(void) +{ + return optimus_pwm_led_show_state(OPTIMUS_LED_STATE_RED); +} + +#else +int optimus_led_open(int ledType) +{ + return 0; +} + +int optimus_led_close(void) +{ + return 0; +} + +int optimus_led_show_in_process_of_burning(void) +{ + return 0; +} + +int optimus_led_show_burning_success(void) +{ + return 0; +} +#endif// #if OPTIMUS_LED_SRC_IS_PWM + + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_led.h b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_led.h new file mode 100644 index 0000000000..40ae2c38ff --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_led.h @@ -0,0 +1,40 @@ +/* + * \file optimus_led.h + * \brief show burning states by LED + * current supported LED source is PWM, other type not supported yet! + * + * \version 1.0.0 + * \date 2013/11/9 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic Inc.. All Rights Reserved. + * + */ +#ifndef __OPTIMUS_LED_H__ +#define __OPTIMUS_LED_H__ + +#define LED_TYPE_PWM 0xabcd + +#if CONFIG_SD_BURNING_SUPPORT_LED + +int optimus_led_open(int ledType);//open the led for show burning states + +int optimus_led_close(void); + +int optimus_led_show_in_process_of_burning(void); + +int optimus_led_show_burning_success(void); + +int optimus_led_show_burning_failure(void); + +#else +#define optimus_led_open(ledType) 0 +#define optimus_led_close() 0 +#define optimus_led_show_in_process_of_burning() do{}while(0) +#define optimus_led_show_burning_success() do{}while(0) +#define optimus_led_show_burning_failure() do{}while(0) + +#endif// #if CONFIG_SD_BURNING_SUPPORT_LED + +#endif//ifndef __OPTIMUS_LED_H__ + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_burn.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_burn.c new file mode 100644 index 0000000000..919fc3f803 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_burn.c @@ -0,0 +1,764 @@ +/* + * \file optimus_sdc_burn.c + * \brief burning itself from Pheripheral tf/sdmmc card + * + * \version 1.0.0 + * \date 2013-7-11 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#include "optimus_sdc_burn_i.h" +#include "optimus_led.h" + +static int is_bootloader_old(void) +{ + int sdc_boot = is_tpl_loaded_from_ext_sdmmc(); + + return !sdc_boot; +} + +int get_burn_parts_from_img(HIMAGE hImg, ConfigPara_t* pcfgPara) +{ + BurnParts_t* pburnPartsCfg = &pcfgPara->burnParts; + int i = 0; + int ret = 0; + int burnNum = 0; + const int totalItemNum = get_total_itemnr(hImg); + + for (i = 0; i < totalItemNum; i++) + { + const char* main_type = NULL; + const char* sub_type = NULL; + + ret = get_item_name(hImg, i, &main_type, &sub_type); + if (ret) { + DWN_ERR("Exception:fail to get item name!\n"); + return __LINE__; + } + + if (!strcmp("PARTITION", main_type)) + { + char* partName = pburnPartsCfg->burnParts[burnNum]; + + if (!strcmp("bootloader", sub_type)) continue; + if (!strcmp(AML_SYS_RECOVERY_PART, sub_type)) + { + if (OPTIMUS_WORK_MODE_SYS_RECOVERY == optimus_work_mode_get()) continue; + } + + strcpy(partName, sub_type); + pburnPartsCfg->bitsMap4BurnParts |= 1U<<burnNum; + burnNum += 1; + } + } + + if (burnNum) + { + pburnPartsCfg->burn_num = burnNum; + + ret = check_cfg_burn_parts(pcfgPara); + if (ret) { + DWN_ERR("Fail in check burn parts\n"); + return __LINE__; + } + print_burn_parts_para(pburnPartsCfg); + } + + return OPT_DOWN_OK; +} + +#define ITEM_NOT_EXIST 0x55 + +int optimus_verify_partition(const char* partName, HIMAGE hImg, char* _errInfo) +{ +#define MaxSz (64 - 7) //verify file to at most 64B to corresponding to USB burn, strlen("verify ") == 7 + + char* argv[4]; + int ret = 0; + HIMAGEITEM hImgItem = NULL; + int imgItemSz = 0; + char CmdVerify[MaxSz + 7] = {0}; + + hImgItem = image_item_open(hImg, "VERIFY", partName); + if (!hImgItem) { + DWN_ERR("Fail to open verify file for part (%s)\n", partName); + return ITEM_NOT_EXIST; + } + + imgItemSz = (int)image_item_get_size(hImgItem); + if (imgItemSz > MaxSz || !imgItemSz) { + DWN_ERR("verify file size %d for part %s invalid, max is %d\n", imgItemSz, partName, MaxSz); + ret = __LINE__; goto _finish; + } + DWN_DBG("item sz %u\n", imgItemSz); + + ret = image_item_read(hImg, hImgItem, CmdVerify, imgItemSz); + if (ret) { + DWN_ERR("Fail to read verify item for part %s\n", partName); + goto _finish; + } + CmdVerify[imgItemSz] = 0; + DWN_DBG("verify[%s]\n", CmdVerify); + + argv[0] = "verify"; + ret = cli_simple_parse_line(CmdVerify, argv + 1); + if (ret != 2) { + DWN_ERR("verify cmd argc must be 2, but %d\n", ret); + return __LINE__; + } + + ret = optimus_media_download_verify(3, argv, _errInfo); + if (ret) { + DWN_ERR("Fail when verify\n"); + return __LINE__; + } + +_finish: + image_item_close(hImgItem); + return ret; +} + +//.NeedVerify: Try to get verify file if .NeedVerify == 1 +static int optimus_burn_one_partition(const char* partName, HIMAGE hImg, __hdle hUiProgress, int NeedVerify) +{ + int rcode = 0; + s64 imgItemSz = 0; + s64 leftItemSz = 0; + u32 thisReadLen = 0; + __hdle hImgItem = NULL; + char* downTransBuf = NULL;//get buffer from optimus_buffer_manager + const unsigned ItemReadBufSz = OPTIMUS_DOWNLOAD_SLOT_SZ;//read this size from image item each time + unsigned sequenceNo = 0; + const char* fileFmt = NULL; + /*static */char _errInfo[512]; + unsigned itemSizeNotAligned = 0; + + printf("\n"); + DWN_MSG("=====>To burn part [%s]\n", partName); + optimus_progress_ui_printf("Burning part[%s]\n", partName); + hImgItem = image_item_open(hImg, "PARTITION", partName); + if (!hImgItem) { + DWN_ERR("Fail to open item for part (%s)\n", partName); + return __LINE__; + } + + imgItemSz = leftItemSz = image_item_get_size(hImgItem); + if (!imgItemSz) { + DWN_ERR("image size is 0 , image of part (%s) not exist ?\n", partName); + return __LINE__; + } + + fileFmt = (IMAGE_ITEM_TYPE_SPARSE == image_item_get_type(hImgItem)) ? "sparse" : "normal"; + + itemSizeNotAligned = image_item_get_first_cluster_size(hImg, hImgItem); + leftItemSz -= itemSizeNotAligned; + rcode = sdc_burn_buf_manager_init(partName, imgItemSz, fileFmt, itemSizeNotAligned); + if (rcode) { + DWN_ERR("fail in sdc_burn_buf_manager_init, rcode %d\n", rcode); + return __LINE__; + } + + //for each loop: + //1, get buffer from buffer_manager, + //2, read item data to buffer, + //3, report data ready to buffer_manager + for (; leftItemSz > 0; leftItemSz -= thisReadLen, sequenceNo++) + { + thisReadLen = leftItemSz > ItemReadBufSz ? ItemReadBufSz: (u32)leftItemSz; + + rcode = optimus_buf_manager_get_buf_for_bulk_transfer(&downTransBuf, thisReadLen, sequenceNo, _errInfo); + if (rcode) { + DWN_ERR("fail in get buf, msg[%s]\n", _errInfo); + goto _finish; + } + + //If the item head is not alinged to FAT cluster, Read it firstly to speed up mmc read + if (itemSizeNotAligned && !sequenceNo) + { + DWN_MSG("itemSizeNotAligned 0x%x\n", itemSizeNotAligned); + rcode = image_item_read(hImg, hImgItem, downTransBuf - itemSizeNotAligned, itemSizeNotAligned); + if (rcode) { + DWN_ERR("fail in read data from item,rcode %d, len 0x%x, sequenceNo %d\n", rcode, itemSizeNotAligned, sequenceNo); + goto _finish; + } + } + + rcode = image_item_read(hImg, hImgItem, downTransBuf, thisReadLen); + if (rcode) { + DWN_ERR("fail in read data from item,rcode %d\n", rcode); + goto _finish; + } + + rcode = optimus_buf_manager_report_transfer_complete(thisReadLen, _errInfo); + if (rcode) { + DWN_ERR("fail in report data ready, rcode %d\n", rcode); + goto _finish; + } + if (hUiProgress)optimus_progress_ui_update_by_bytes(hUiProgress, thisReadLen) ; + } + + DWN_DBG("BURN part %s %s!\n", partName, leftItemSz ? "FAILED" : "SUCCESS"); + +_finish: + image_item_close(hImgItem); + + if (rcode) { + DWN_ERR("Fail to burn part(%s) with in format (%s) before verify\n", partName, fileFmt); + optimus_progress_ui_printf("Failed at burn part[%s] befor VERIFY\n", partName); + return rcode; + } + +#if 1 + if (!NeedVerify) { + return rcode; + } + rcode = optimus_verify_partition(partName, hImg, _errInfo); + if (ITEM_NOT_EXIST == rcode) + { + printf("WRN:part(%s) NOT verified\n", partName); + return 0; + } + if (rcode) { + printf("Fail in verify part(%s)\n", partName); + optimus_progress_ui_printf("Failed at VERIFY part[%s]\n", partName); + return __LINE__; + } +#endif//#fi 0 + + return rcode; +} + +int optimus_sdc_burn_partitions(ConfigPara_t* pCfgPara, HIMAGE hImg, __hdle hUiProgress, int NeedVerify) +{ + BurnParts_t* cfgParts = &pCfgPara->burnParts; + int burnNum = cfgParts->burn_num; + int i = 0; + int rcode = 0; + + //update burn_parts para if burnNum is 0, i.e, not configured + if (!burnNum) + { + rcode = get_burn_parts_from_img(hImg, pCfgPara); + if (rcode) { + DWN_ERR("Fail to get burn parts from image\n"); + return __LINE__; + } + burnNum = cfgParts->burn_num; + DWN_DBG("Data part num %d\n", burnNum); + } + if (!burnNum) { + DWN_ERR("Data part num is 0!!\n"); + return __LINE__; + } + + for (i = 0; i < burnNum; i++) + { + const char* partName = cfgParts->burnParts[i]; + + rcode = optimus_burn_one_partition(partName, hImg, hUiProgress, NeedVerify); + if (rcode) { + DWN_ERR("Fail in burn part %s\n", partName); + return __LINE__; + } + } + + return rcode; +} + +//not need to verify as not config ?? +int optimus_sdc_burn_media_partition(const char* mediaImgPath, const char* verifyFile) +{ + //TODO:change configure to 'partName = image' and work it using cmd 'sdc_update' + return optimus_burn_partition_image("media", mediaImgPath, "normal", verifyFile, 0); +} + +int optimus_burn_bootlader(HIMAGE hImg) +{ + int rcode = 0; + int NeedVerify = 1; + + rcode = optimus_burn_one_partition("bootloader", hImg, NULL, NeedVerify); + if (rcode) { + DWN_ERR("Fail when burn bootloader\n"); + return __LINE__; + } + + return rcode; +} + +//flag, 0 is burn completed, else burn failed +int optimus_report_burn_complete_sta(int isFailed, int rebootAfterBurn) +{ + if (isFailed) + { + DWN_MSG("======sdc burn Failed!!!!!\n"); + DWN_MSG("PLS long-press power key to shut down\n"); + optimus_led_show_burning_failure(); + while (1) { + /*if(ctrlc())*/ + } + + return __LINE__; + } + + DWN_MSG("======sdc burn SUCCESS.\n"); + optimus_led_show_burning_success(); + optimus_burn_complete(rebootAfterBurn ? rebootAfterBurn : OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_POWERKEY);//set complete flag and poweroff if burn successful + return 0; +} + +static int sdc_burn_dtb_load(HIMAGE hImg) +{ + s64 itemSz = 0; + HIMAGEITEM hImgItem = NULL; + int rc = 0; + const char* partName = "dtb"; + const u64 partBaseOffset = OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + unsigned char* dtbTransferBuf = (unsigned char*)partBaseOffset; + + hImgItem = image_item_open(hImg, partName, "meson"); + if (!hImgItem) { + DWN_ERR("Fail to open verify file for part (%s)\n", partName); + return ITEM_NOT_EXIST; + } + + itemSz = image_item_get_size(hImgItem); + if (!itemSz) { + DWN_ERR("Item size 0\n"); + image_item_close(hImgItem); return __LINE__; + } + + rc = image_item_read(hImg, hImgItem, dtbTransferBuf, (unsigned)itemSz); + if (rc) { + DWN_ERR("Failed at item read, rc = %d\n", rc); + image_item_close(hImgItem); return __LINE__; + } + image_item_close(hImgItem); + + rc = optimus_parse_img_download_info(partName, itemSz, "normal", "mem", partBaseOffset); + if (rc) { + DWN_ERR("Failed in init down info\n"); return __LINE__; + } + + { + unsigned wrLen = 0; + char errInfo[512]; + + wrLen = optimus_download_img_data(dtbTransferBuf, (unsigned)itemSz, errInfo); + rc = (wrLen == itemSz) ? 0 : wrLen; + } + + return rc; +} + +#if CONFIG_SUPPORT_SDC_KEYBURN +//fetch the keys names which need be burned from item[conf, keys] +static int sdc_burn_get_user_key_names(HIMAGE hImg, const char* **pKeysName, unsigned* keysNum) +{ + int rc = 0; + HIMAGEITEM hImgItem = NULL; + unsigned itemSz = 0; + unsigned char* thisReadBuf = (unsigned char*)OPTIMUS_SPARSE_IMG_FILL_VAL_BUF;//This buf is not used and not need reuse when burning keys + const unsigned thisReadBufSz = (OPTIMUS_SPARSE_IMG_FILL_BUF_SZ >> 1); + const char* *keysName = (const char**)(thisReadBuf + thisReadBufSz); + + hImgItem = image_item_open(hImg, "conf", "keys"); + if (!hImgItem) { + DWN_ERR("Fail to open keys.conf\n"); + return ITEM_NOT_EXIST; + } + + itemSz = (unsigned)image_item_get_size(hImgItem); + if (!itemSz) { + DWN_ERR("Item size 0\n"); + image_item_close(hImgItem); return __LINE__; + } + + rc = image_item_read(hImg, hImgItem, thisReadBuf, itemSz); + if (rc) { + DWN_ERR("Failed at item read, rc = %d\n", rc); + image_item_close(hImgItem); return __LINE__; + } + image_item_close(hImgItem); + + if (itemSz >= thisReadBufSz) { + DWN_ERR("itemSz(0x%x) of keys.conf too large, > max 0x%x.\n", itemSz, thisReadBufSz); + return __LINE__; + } + + rc = _optimus_parse_buf_2_lines((char*)thisReadBuf, itemSz, keysName, keysNum, 16); + if (rc) { + DWN_ERR("Fail in parse buf_2_lines\n"); + return __LINE__; + } + + rc = _optimus_abandon_ini_comment_lines((char**)keysName, *keysNum); + + *pKeysName = keysName; + return rc; +} + +//check key is burned yet --> need keyOverWrite -->can_write +static int sdc_check_key_need_to_burn(const char* keyName, const int keyOverWrite) +{ + int rc = 0; + char _cmd[96]; + + sprintf(_cmd, "aml_key_burn misc is_burned %s", keyName); + rc = run_command(_cmd, 0); + if (rc < 0) { + DWN_ERR("Fail in check key is_burned\n"); + return -__LINE__; + } + DWN_MSG("key[%s] is %s burned\n", keyName, rc ? "NOT" : "DO"); + if (rc) {//not success + return 1;//need burn as not burned yet. + } + if (!keyOverWrite) { + DWN_MSG("User choose not to overwrite the key\n"); + return 0; + } + + sprintf(_cmd, "aml_key_burn misc can_write %s", keyName); + rc = run_command(_cmd, 0); + if (rc) { + DWN_ERR("Fail in check key[%s] is_burned\n", keyName); + return -__LINE__; + } + DWN_MSG("key[%s] is %s can_write\n", keyName, rc ? "NOT" : "DO"); + return !rc; +} + +//burn the amlogic keys like USB_Burning_Tool +static int sdc_burn_aml_keys(HIMAGE hImg, const int keyOverWrite) +{ + int rc = 0; + const char* *keysName = NULL; + unsigned keysNum = 0; + const char** pCurKeysName = NULL; + unsigned index = 0; + + rc = run_command("aml_key_burn probe vfat sdc", 0); + if (rc) { + DWN_ERR("Fail in probe for aml_key_burn\n"); + return __LINE__; + } + + { + unsigned random32 = 0; + unsigned seed = 0; + char cmd[96]; + + random32 = seed = get_utimer(0) + 12345;//make it random + /*random32 = random_u32(seed);*/ + DWN_MSG("random value is 0x%x\n", random32); + sprintf(cmd, "aml_key_burn init 0x%x", random32); + + rc = run_command(cmd, 0); + if (rc) { + DWN_ERR("Fail in cmd[%s]\n", cmd); + return __LINE__; + } + } + + rc = sdc_burn_get_user_key_names(hImg, &keysName, &keysNum); + if (ITEM_NOT_EXIST != rc && rc) { + DWN_ERR("Fail to parse keys.conf, rc =%d\n", rc); + return __LINE__; + } + DWN_MSG("keys.conf:\n"); + for (index = 0; index < keysNum; ++index)printf("\tkey[%d]\t%s\n", index, keysName[index]) ; + + rc = optimus_sdc_keysprovider_init(); + if (rc) { + DWN_ERR("Fail in optimus_sdc_keysprovider_init\n"); + return __LINE__; + } + + pCurKeysName = keysName; + for (index = 0; index < keysNum; ++index) + { + const char* const keyName = *pCurKeysName++; + + if (!keyName) continue; + DWN_MSG("\n"); + DWN_MSG("Now to burn key <---- [%s] ----> %d \n", keyName, index); + rc = sdc_check_key_need_to_burn(keyName, keyOverWrite); + if (rc < 0) { + DWN_ERR("Fail when when check stauts for key(%s)\n", keyName); + return __LINE__; + } + if (!rc) continue;//not need to burn this key + + //0, init the key license parser + const void* pHdle = NULL; + rc = optimus_sdc_keysprovider_open(keyName, &pHdle); + if (rc) { + DWN_ERR("Fail in init license for key[%s]\n", keyName); + return __LINE__; + } + + //1,using cmd_keysprovider to read a key to memory + u8* keyValue = (u8*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + unsigned keySz = OPTIMUS_DOWNLOAD_SLOT_SZ;//buffer size + rc = optimus_sdc_keysprovider_get_keyval(pHdle, keyValue, &keySz); + if (rc) { + DWN_ERR("Fail to get value for key[%s]\n", keyName); + return __LINE__; + } + + //3, burn the key + rc = optimus_keysburn_onekey(keyName, (u8*)keyValue, keySz); + if (rc) { + DWN_ERR("Fail in burn the key[%s] at addr=%p, sz=%d\n", keyName, keyValue, keySz); + return __LINE__; + } + + //3,report burn result to cmd_keysprovider + rc = optimus_sdc_keysprovider_update_license(pHdle); + if (rc) { + DWN_ERR("Fail in update license for key[%s]\n", keyName); + return __LINE__; + } + } + + rc = optimus_sdc_keysprovider_exit(); + if (rc) { + DWN_ERR("Fail in optimus_sdc_keysprovider_exit\n"); + return __LINE__; + } + + rc = run_command("aml_key_burn uninit", 0); + if (rc) { + DWN_ERR("Fail in uninit for aml_key_burn\n"); + return __LINE__; + } + + return 0; +} +#else +#define sdc_burn_aml_keys(fmt...) 0 +#endif// #if CONFIG_SUPPORT_SDC_KEYBURN + +int optimus_burn_with_cfg_file(const char* cfgFile) +{ + extern ConfigPara_t g_sdcBurnPara ; + + int ret = 0; + HIMAGE hImg = NULL; + ConfigPara_t* pSdcCfgPara = &g_sdcBurnPara; + const char* pkgPath = pSdcCfgPara->burnEx.pkgPath; + __hdle hUiProgress = NULL; + + ret = parse_ini_cfg_file(cfgFile); + if (ret) { + DWN_ERR("Fail to parse file %s\n", cfgFile); + ret = __LINE__; goto _finish; + } + + if (pSdcCfgPara->custom.eraseBootloader) + { + if (is_bootloader_old()) + { + DWN_MSG("To erase OLD bootloader !\n"); + ret = optimus_erase_bootloader(NULL); + if (ret) { + DWN_ERR("Fail to erase bootloader\n"); + ret = __LINE__; goto _finish; + } + +#if defined(CONFIG_VIDEO_AMLLCD) + //axp to low power off LCD, no-charging + DWN_MSG("To close LCD\n"); + ret = run_command("video dev disable", 0); + if (ret) { + printf("Fail to close back light\n"); + /*return __LINE__;*/ + } +#endif// #if defined(CONFIG_VIDEO_AMLLCD) + + DWN_MSG("Reset to load NEW uboot from ext-mmc!\n"); + optimus_reset(OPTIMUS_BURN_COMPLETE__REBOOT_SDC_BURN); + return __LINE__;//should never reach here!! + } + } + + if (OPTIMUS_WORK_MODE_SDC_PRODUCE == optimus_work_mode_get()) //led not depend on image res, can init early + { + if (optimus_led_open(LED_TYPE_PWM)) { + DWN_ERR("Fail to open led for sdc_produce\n"); + return __LINE__; + } + optimus_led_show_in_process_of_burning(); + } + + hImg = image_open("mmc", "0", "1", pkgPath); + if (!hImg) { + DWN_ERR("Fail to open image %s\n", pkgPath); + ret = __LINE__; goto _finish; + } + + //update dtb for burning drivers + ret = sdc_burn_dtb_load(hImg); + if (ret) { + DWN_ERR("Fail in load dtb for sdc_burn\n"); + ret = __LINE__; goto _finish; + } + + if (video_res_prepare_for_upgrade(hImg)) { + DWN_ERR("Fail when prepare bm res or init video for upgrade\n"); + ret = __LINE__; goto _finish; + } + show_logo_to_report_burning(); + + hUiProgress = optimus_progress_ui_request_for_sdc_burn(); + if (!hUiProgress) { + DWN_ERR("request progress handle failed!\n"); + ret = __LINE__; goto _finish; + } + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STEPS_AFTER_IMAGE_OPEN_OK); + + int hasBootloader = 0; + u64 datapartsSz = optimus_img_decoder_get_data_parts_size(hImg, &hasBootloader); + + int eraseFlag = pSdcCfgPara->custom.eraseFlash; + if (!datapartsSz) { + eraseFlag = 0; + DWN_MSG("Disable erase as data parts size is 0\n"); + } + ret = optimus_storage_init(eraseFlag); + if (ret) { + DWN_ERR("Fail to init stoarge for sdc burn\n"); + return __LINE__; + } + + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STEPS_AFTER_DISK_INIT_OK); + + if (datapartsSz) + { + ret = optimus_progress_ui_set_smart_mode(hUiProgress, datapartsSz, + UPGRADE_STEPS_FOR_BURN_DATA_PARTS_IN_PKG(!pSdcCfgPara->burnEx.bitsMap.mediaPath)); + if (ret) { + DWN_ERR("Fail to set smart mode\n"); + ret = __LINE__; goto _finish; + } + + ret = optimus_sdc_burn_partitions(pSdcCfgPara, hImg, hUiProgress, 1); + if (ret) { + DWN_ERR("Fail when burn partitions\n"); + ret = __LINE__; goto _finish; + } + } + + if (pSdcCfgPara->burnEx.bitsMap.mediaPath) //burn media image + { + const char* mediaPath = pSdcCfgPara->burnEx.mediaPath; + + ret = optimus_sdc_burn_media_partition(mediaPath, NULL);//no progress bar info if have partition image not in package + if (ret) { + DWN_ERR("Fail to burn media partition with image %s\n", mediaPath); + optimus_storage_exit(); + ret = __LINE__;goto _finish; + } + } + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STPES_AFTER_BURN_DATA_PARTS_OK); + + //TO burn nandkey/securekey/efusekey + ret = sdc_burn_aml_keys(hImg, pSdcCfgPara->custom.keyOverwrite); + if (ret) { + DWN_ERR("Fail in sdc_burn_aml_keys\n"); + ret = __LINE__;goto _finish; + } + +#if 1 + if (hasBootloader) + {//burn bootloader + ret = optimus_burn_bootlader(hImg); + if (ret) { + DWN_ERR("Fail in burn bootloader\n"); + goto _finish; + } + else + {//update bootloader ENV only when bootloader image is burned + ret = optimus_set_burn_complete_flag(); + if (ret) { + DWN_ERR("Fail in set_burn_complete_flag\n"); + ret = __LINE__; goto _finish; + } + } + } +#endif + optimus_progress_ui_direct_update_progress(hUiProgress, UPGRADE_STEPS_AFTER_BURN_BOOTLOADER_OK); + +_finish: + image_close(hImg); + optimus_progress_ui_report_upgrade_stat(hUiProgress, !ret); + optimus_report_burn_complete_sta(ret, pSdcCfgPara->custom.rebootAfterBurn); + optimus_progress_ui_release(hUiProgress); + //optimus_storage_exit();//temporary not exit storage driver when failed as may continue burning after burn + return ret; +} + +int optimus_burn_package_in_sdmmc(const char* sdc_cfg_file) +{ + int rcode = 0; + +#if (MESON_CPU_TYPE_MESON8 <= MESON_CPU_TYPE) + //AML_WATCH_DOG_DISABLE(); //disable watchdog +#endif// #if (MESON_CPU_TYPE_MESON8 <= MESON_CPU_TYPE) + + DWN_MSG("mmcinfo\n"); + rcode = run_command("mmcinfo", 0); + if (rcode) { + DWN_ERR("Fail in init mmc, Does sdcard not plugged in?\n"); + return __LINE__; + } + +#if 0//this asserted by 'run update' and 'aml_check_is_ready_for_sdc_produce' + rcode = do_fat_get_fileSz(sdc_cfg_file); + if (!rcode) { + printf("The [%s] not exist in bootable mmc card\n", sdc_cfg_file); + return __LINE__; + } +#endif//#if 0 + + rcode = optimus_burn_with_cfg_file(sdc_cfg_file); + + return rcode; +} + +int do_sdc_burn(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + const char* sdc_cfg_file = argv[1]; + + if (argc < 2 ) { + cmd_usage(cmdtp); + return __LINE__; + } + + optimus_work_mode_set(OPTIMUS_WORK_MODE_SDC_UPDATE); + show_logo_to_report_burning();//indicate enter flow of burning! when 'run update' + if (optimus_led_open(LED_TYPE_PWM)) { + DWN_ERR("Fail to open led for burn\n"); + return __LINE__; + } + optimus_led_show_in_process_of_burning(); + + rcode = optimus_burn_package_in_sdmmc(sdc_cfg_file); + + return rcode; +} + +U_BOOT_CMD( + sdc_burn, //command name + 5, //maxargs + 0, //repeatable + do_sdc_burn, //command function + "Burning with amlogic format package in sdmmc ", //description + "argv: [sdc_burn_cfg_file]\n"//usage + " -aml_sdc_burn.ini is usually used configure file\n" +); + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_burn_i.h b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_burn_i.h new file mode 100644 index 0000000000..2ad2203233 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_burn_i.h @@ -0,0 +1,108 @@ +/* + * \file optimus_sdc_burn_i.h + * \brief internal struct types and interfaces for sdc burn + * + * \version 1.0.0 + * \date 2013-7-12 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#ifndef __OPTIMUS_SDC_BURN_I_H__ +#define __OPTIMUS_SDC_BURN_I_H__ + +#include "../v2_burning_i.h" +#include <fat.h> +#include <part.h> + +typedef struct _burnEx{ + char pkgPath[128]; + char mediaPath[128]; + struct { + unsigned pkgPath : 1; + unsigned mediaPath : 1; + unsigned reserv : 32 - 2; + }bitsMap; +}BurnEx_t; + +typedef struct _customPara{ + int eraseBootloader; + int eraseFlash; + int rebootAfterBurn; + int keyOverwrite; + struct{ + unsigned eraseBootloader : 1; + unsigned eraseFlash : 1; + unsigned rebootAfterBurn : 1; + unsigned keyOverwrite : 1; + unsigned resev : 32 - 4; + }bitsMap; +}CustomPara_t; + +#define MAX_BURN_PARTS (32) +#define PART_NAME_LEN_MAX (32) + +typedef struct _burnParts{ + int burn_num; + char burnParts[MAX_BURN_PARTS][PART_NAME_LEN_MAX]; + unsigned bitsMap4BurnParts; +}BurnParts_t; + +typedef struct _ConfigPara{ + BurnParts_t burnParts; + CustomPara_t custom; + BurnEx_t burnEx; + struct { + unsigned burnParts : 1; + unsigned custom : 1; + unsigned burnEx : 1; + unsigned reserv : 32 - 3; + }setsBitMap; +}ConfigPara_t; + +//ini parser +int _optimus_parse_buf_2_lines(char* pTextBuf, const unsigned textSz, const char* lines[], + unsigned* totalLineNum, const unsigned MaxLines);//parse text context to linces delimitted by (\r)\n +int parse_ini_file_2_valid_lines(const char* filePath, char* iniBuf, const unsigned bufSz, char* lines[]); +int _optimus_abandon_ini_comment_lines(char* lines[], const unsigned lineNum); +int optimus_ini_trans_lines_2_usr_params(const char* const lines[], const unsigned lineNum, + int (*pCheckSetUseFul)(const char* setName), + int (*pParseCfgVal)(const char* setName, const char* keyName, const char* keyVal)); + +int parse_ini_cfg_file(const char* filePath); + +int check_cfg_burn_parts(const ConfigPara_t* burnPara); +int print_burn_parts_para(const BurnParts_t* pBurnParts); + +int sdc_burn_verify(const char* verifyFile); + +//burn a partition with a image file +int optimus_burn_partition_image(const char* partName, const char* imgItemPath, const char* fileFmt, const char* verifyFile, const unsigned itemSizeNotAligned); + +int sdc_burn_buf_manager_init(const char* partName, s64 imgItemSz, const char* fileFmt, + const unsigned itemSizeNotAligned /* if item offset 3 and bytepercluste 4k, then it's 4k -3 */); + +int get_burn_parts_from_img(HIMAGE hImg, ConfigPara_t* pcfg); + +//declare for aml_sysrecovery +int optimus_sdc_burn_partitions(ConfigPara_t* pCfgPara, HIMAGE hImg, __hdle hUiProgress, int needVerify); + +int optimus_burn_bootlader(HIMAGE hImg); + +int optimus_report_burn_complete_sta(int isFailed, int rebootAfterBurn); + + +int optimus_sdc_burn_switch_to_extmmc(void); + +//Followings are For burn keys only +int optimus_sdc_keysprovider_init(void); +int optimus_sdc_keysprovider_exit(void); +int optimus_sdc_keysprovider_open(const char* keyName, const void** pHdle); +int optimus_sdc_keysprovider_get_keyval(const void* pHdle, u8* pBuf, unsigned* keySz); +int optimus_sdc_keysprovider_update_license(const void* pHdle); + +int optimus_keysburn_onekey(const char* keyName, u8* keyVal, unsigned keyValLen); + +#endif//#ifndef __OPTIMUS_SDC_BURN_I_H__ + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_update.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_update.c new file mode 100644 index 0000000000..73000865f9 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/optimus_sdc_update.c @@ -0,0 +1,352 @@ +/* + * \file optimus_sdc_update.c + * \brief sdc_update command to burn a parition image from mmc + * this update based on the burner is latest: (uboot for burnner can run from peripherals such as sdmmc/usb) + * + * \version 1.0.0 + * \date 2014-9-15 + * \author Sam.Wu <yihui.wu@amlogic.com> + * Chunyu.Song <chunyu.song@amlogic.com> + * Copyright (c) 2014 Amlogic. All Rights Reserved. + * + */ +#include "optimus_sdc_burn_i.h" + +typedef int __hFileHdl; + +#define BURN_DBG 0 +#if BURN_DBG +#define SDC_DBG(fmt...) printf(fmt) +#else +#define SDC_DBG(fmt...) +#endif//if BURN_DBG + +#define SDC_MSG DWN_MSG +#define SDC_ERR DWN_ERR + +static char _errInfo[512] = ""; + +//default is mmc 0:1, i.e, part 1 of first registered mmc device +int optimus_device_probe(const char* interface, const char* inPart) +{ + block_dev_desc_t *dev_desc=NULL; + int dev=0; + int part=1; + char *ep; + + dev = (int)simple_strtoul(inPart, &ep, 16); + dev_desc = get_dev((char*)interface,dev); + if (dev_desc == NULL) { + puts("\n** Invalid boot device **\n"); + return 1; + } + if (*ep) { + if (*ep != ':') { + puts("\n** Invalid boot device, use `dev[:part]' **\n"); + return 1; + } + part = (int)simple_strtoul(++ep, NULL, 16); + } + if (fat_register_device(dev_desc,part) != 0) { + printf("\n** Unable to use %s %d:%d for device probe **\n", + interface, dev, part); + return 1; + } + + return 0; +} + + +__hFileHdl opt_file_open(const char* imgItemPath) +{ + __hFileHdl hFile = 0; + +#if 0 + //FIXME: Check this probe needed!!! + if (device_probe("mmc", "0")) { + SDC_ERR("Fail to probe mmc 0"); + return -1; + } +#endif//#if 0 + + hFile = do_fat_fopen(imgItemPath); + + return hFile; +} + +int opt_file_read(__hFileHdl hFile, u8* buffer, const unsigned size) +{ + unsigned readSz = do_fat_fread(hFile, buffer, size); + if (readSz != size) { + SDC_ERR("Want to read 0x%x, but 0x%x\n", size, readSz); + return __LINE__; + } + + return 0; +} + +int opt_file_close(__hFileHdl hFile) +{ + do_fat_fclose(hFile); + + return 0; +} + +//part size 0 if failed +s64 storage_get_partition_size_in_byte(const char* partName) +{ + int ret = 0; + u64 size = 0; + +#if 1 + ret = store_get_partititon_size((u8*)partName, &size); + if (ret) { + SDC_ERR("Fail to get size for part %s\n", partName); + return 0; + } + size <<= 9;//trans sector to byte +#endif + + return size; +} + +//0 is OK, others failed +int sdc_burn_buf_manager_init(const char* partName, s64 imgItemSz, const char* fileFmt, + const unsigned itemSizeNotAligned /* if item offset 3 and bytepercluste 4k, then it's 4k -3 */) +{ + int rcode = 0; + s64 partCapInByte = 0; + const char* destMediaType = "store"; + const u64 partBaseOffset = 0; + + if (strcmp("bootloader", partName)) //TODO:bootloader size can't get yet! + { + partCapInByte = storage_get_partition_size_in_byte(partName); + if (partCapInByte < imgItemSz || !partCapInByte) { + SDC_ERR("partCapInByte 0x[%x, %x] < imgItemSz 0x[%x, %x]\n", + (u32)(partCapInByte>>32), (u32)partCapInByte, (u32)(imgItemSz>>32), (u32)imgItemSz); + return __LINE__; + } + } + + rcode = optimus_parse_img_download_info(partName, imgItemSz, fileFmt, destMediaType, partBaseOffset); + if (rcode) { + SDC_ERR("fail in init down info, rcode %d\n", rcode); + return __LINE__; + } + rcode = optimus_buf_manager_tplcmd_init(destMediaType, partName, 0, fileFmt, imgItemSz, 0, itemSizeNotAligned); + if (rcode) { + SDC_ERR("Fail in buf manager init\n"); + return __LINE__; + } + + return rcode; +} + +int sdc_burn_verify(const char* verifyFile) +{ + int rcode = 0; + char* argv[8]; + char verifyCmd[64] = ""; + char cmdBuf[64]; + char *usb_update = getenv("usb_update"); + + if (!strcmp(usb_update,"1")) { + sprintf(cmdBuf, "%s 0x%p %s", "fatload usb 0 ", verifyCmd, verifyFile); + } + else{ + sprintf(cmdBuf, "%s 0x%p %s", "fatload mmc 0 ", verifyCmd, verifyFile); + } + SDC_DBG("To run cmd [%s]\n", cmdBuf); + rcode = run_command(cmdBuf, 0); + if (rcode < 0) { + SDC_ERR("Fail in cmd fatload\n"); + return __LINE__; + } + SDC_MSG("cmd verify[%s]\n", verifyCmd); + + rcode = cli_simple_parse_line(verifyCmd, argv + 1); + if (rcode != 2) { + SDC_ERR("verify cmd argc must be 2, but %d\n", rcode); + return __LINE__; + } + argv[0] = "verify"; + + rcode = optimus_media_download_verify(3, argv, _errInfo); + if (rcode) { + SDC_ERR("Fail to verify\n"); + return __LINE__; + } + return 0; +} + +int optimus_burn_partition_image(const char* partName, const char* imgItemPath, const char* fileFmt, const char* verifyFile, const unsigned itemSizeNotAligned) +{ + int rcode = 0; + s64 imgItemSz = 0; + s64 leftItemSz = 0; + u32 thisReadLen = 0; + __hFileHdl hImgItem = 0; + char* downTransBuf = NULL;//get buffer from optimus_buffer_manager + const unsigned ItemReadBufSz = OPTIMUS_DOWNLOAD_SLOT_SZ;//read this size from image item each time + unsigned sequenceNo = 0; + + imgItemSz = leftItemSz = do_fat_get_fileSz(imgItemPath); + if (!imgItemSz) { + SDC_ERR("Fail to get image %s from mmc\n", imgItemPath); + return __LINE__; + } + + rcode = sdc_burn_buf_manager_init(partName, imgItemSz, fileFmt, itemSizeNotAligned); + if (rcode) { + SDC_ERR("fail in sdc_burn_buf_manager_init, rcode %d\n", rcode); + return __LINE__; + } + + hImgItem = opt_file_open(imgItemPath); + if (hImgItem < 0) { + SDC_ERR("Fail to open the item %s\n", imgItemPath); + return __LINE__; + } + + /*optimus_progress_init((u32)(imgItemSz>>32), (u32)imgItemSz, 0, 100);*/ + + //for each loop: + //1, get buffer from buffer_manager, + //2, read item data to buffer, + //3, report data ready to buffer_manager + for (; leftItemSz > 0; leftItemSz -= thisReadLen, sequenceNo++) + { + thisReadLen = leftItemSz > ItemReadBufSz ? ItemReadBufSz: (u32)leftItemSz; + + rcode = optimus_buf_manager_get_buf_for_bulk_transfer(&downTransBuf, thisReadLen, sequenceNo, _errInfo); + if (rcode) { + SDC_ERR("fail in get buf, msg[%s]\n", _errInfo); + goto _finish; + } + + rcode = opt_file_read(hImgItem, (u8*)downTransBuf, thisReadLen); + if (rcode) { + SDC_ERR("fail in read data from item,rcode %d\n", rcode); + goto _finish; + } + + rcode = optimus_buf_manager_report_transfer_complete(thisReadLen, _errInfo); + if (rcode) { + SDC_ERR("fail in report data ready, rcode %d\n", rcode); + goto _finish; + } + + /*optimus_update_progress(thisReadLen);//report burning steps*/ + } + + if (leftItemSz <= 0) { + printf("BURN %s to part %s OK!\n", imgItemPath, partName); + } + +_finish: + opt_file_close(hImgItem); + + if (!rcode && verifyFile) + { + rcode = sdc_burn_verify(verifyFile); + } + + printf("=====>Burn part %s in fmt %s %s<======\n\n", partName, fileFmt, rcode ? "FAILED!!": "OK"); + return rcode; +} + +//step 1: get script file size, and get script file contents +//step 2: read image file +//"Usage: sdc_update partiton image_file_path [imgFmt, verifyFile]\n" //usage +int do_sdc_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + const char* partName = argv[1]; + const char* imgItemPath = argv[2]; + const char* fileFmt = argc > 3 ? argv[3] : NULL; + const char* verifyFile = argc > 4 ? argv[4] : NULL; + + setenv("usb_update",0); +#if BURN_DBG + printf("argc %d, %s, %s\n", argc, argv[0], argv[1]); + if (argc < 3) + { + partName = "system"; + imgItemPath = "rec.img"; + fileFmt = "normal"; + verifyFile = "recovery.verify"; + } +#else + if (argc < 3) { + cmd_usage(cmdtp); + return __LINE__; + } +#endif//#if BURN_DBG + + //mmc info to ensure sdcard inserted and inited + rcode = run_command("mmcinfo", 0); + if (rcode) { + SDC_ERR("Fail in init mmc, Does sdcard not plugged in?\n"); + return __LINE__; + } + +#if 0 + if (!do_fat_get_fileSz(imgItemPath)) { + SDC_ERR("file (%s) not existed\n", imgItemPath); + return __LINE__; + } +#else + rcode = optimus_device_probe("mmc", "0"); + if (rcode) { + SDC_ERR("Fail to detect device mmc 0\n"); + return __LINE__; + } +#endif//#if 0 + + if (!fileFmt) + { + rcode = do_fat_get_file_format(imgItemPath, (u8*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR, (8*1024)); + if (rcode < 0) { + SDC_ERR("Fail when parse file format\n"); + return __LINE__; + } + fileFmt = rcode ? "sparse" : "normal"; + } + +#if 0 + if (!getenv("disk_initial")) //if disk_initial command not executed for burning + { + rcode = optimus_storage_init(0);//can't erase as not full updating + if (rcode) { + SDC_ERR("Fail in init storage, rcode %d\n", rcode); + return rcode; + } + setenv("disk_initial", "0"); + } +#endif//#if 0 + + rcode = optimus_burn_partition_image(partName, imgItemPath, fileFmt, verifyFile, 0); + if (rcode) { + SDC_ERR("Fail to burn partition (%s) with image file (%s) in format (%s)\n", partName, imgItemPath, fileFmt); + } + + return rcode; +} + +U_BOOT_CMD( + sdc_update, //command name + 5, //maxargs + 0, //repeatable + do_sdc_update, //command function + "Burning a partition with image file in sdmmc card", //description + " argv: <part_name> <image_file_path> <[,fileFmt]> <[,verify_file]> \n" //usage + " - <fileFmt> parameter is optional, if you know it you can specify it.\n" + " for Android, system.img and data.img is \"sparse\" format, other is \"normal\"\n" //usage + " - <verify_file> parameter is optional, if you have it you can specify it.\n" + " - e.g. \n" + " to burn partition boot with boot.img of mmc 0 : \"sdc_update boot boot.img\"\n" //usage + " to burn partition system with system.img of mmc 0 : \"sdc_update system system.img\"\n" //usage +); + + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/optimus_key_burn.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/optimus_key_burn.c new file mode 100644 index 0000000000..cf16043cb1 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/optimus_key_burn.c @@ -0,0 +1,299 @@ +/* + * \file optimus_key_burn.c + * \brief burning keys from sdcard like update.exe + * + * \version 1.0.0 + * \date 2014/12/25 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2014 Amlogic. All Rights Reserved. + * + */ + +/* + * + * This cmd [aml_key_burn] aim to burn keys like 'update.exe', and mainly used for myself. + * like update.exe, the key in here is single and not need to sperate + * e.g, for comparison, here to burn a hdcp key using aml_key_burn and update.exe + * 0. update.exe identify . <-----> aml_key_burn probe vfat sdc + * 1. update.exe mwrite meson.dtb mem dtb normal . <-----> aml_key_burn meson_dtb meson.dtb + * 2, update.exe bulkcmd "key init 0x1234" <-----> aml_key_burn init 0x1234 + * 3, update.exe mwrite key hdcp normal hdcp308.val <-----> aml_key_burn burn hdcp hdcp308.val + * other keys + * 4, update.exe bulkcmd "key uninit" <-----> aml_key_burn uninit + * + */ +#include "../optimus_sdc_burn_i.h" +#include <amlogic/keyunify.h> + +#define _AML_KEY_ERR(fmt...) sprintf(_errInfo, fmt), DWN_ERR(_errInfo) + +static char _errInfo[512] = ""; + + +typedef enum{ + DEV_FILE_FMT_VFAT = 0xee, + DEV_FILE_FMT_EXT2 +}DevFileFmt_e; + +typedef enum{ + DEV_INTF_EXT_SDMMC = 0xdd, + DEV_INTF_EXT_UDISK , +}DevIntf_e; + +static struct optKeyInfo_s{ + DevFileFmt_e fileFmt; + DevIntf_e intf;//interface +} _optKeyInfo; +/* + * <aml_key_burn probe> device_format interface + */ +static int do_opt_keysburn_probe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + const char* device_format = argv[2];//vfat + const char* device_interf = argv[3];//sdc/udisk + + if (4 > argc) { + _AML_KEY_ERR("failed:argc: %d < 4\n", argc); + return __LINE__; + } + if (!strcmp(device_format, "vfat")) { + _optKeyInfo.fileFmt = DEV_FILE_FMT_VFAT; + } + else{ + _AML_KEY_ERR("failed:device_format %s unsupported yet\n", device_format); + return __LINE__; + } + + if (!strcmp("sdc", device_interf)) + { + static int _mmcprobe = 0; + + if (!_mmcprobe) + { + rc = run_command("mmcinfo 0", 0); + if (rc) { + _AML_KEY_ERR("failed: in mmcinfo\n"); + return __LINE__; + } + rc = optimus_device_probe("mmc", "0"); + if (rc) { + _AML_KEY_ERR("Fail to detect device mmc 0\n"); + return __LINE__; + } + _mmcprobe = 1; + } + _optKeyInfo.intf = DEV_INTF_EXT_SDMMC; + } + else if(!strcmp("udisk", device_interf)) + { + static int _udiskProbe = 0; + + if (!_udiskProbe) + { + rc = run_command("usb start 0", 0); + if (rc) { + _AML_KEY_ERR("Fail in mmcinfo\n"); + return __LINE__; + } + rc = optimus_device_probe("usb", "0"); + if (rc) { + _AML_KEY_ERR("Fail to detect device mmc 0\n"); + return __LINE__; + } + _udiskProbe = 1; + } + _optKeyInfo.intf = DEV_INTF_EXT_UDISK; + } + else{ + _AML_KEY_ERR("device_interf %s unsupported\n", device_interf); + return -__LINE__; + } + + return rc; +} + +static int do_opt_keysburn_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + + if (3 > argc) + { + cmd_usage(cmdtp); + return __LINE__; + } + rc = v2_key_command(argc, argv, _errInfo); + if (rc) { + DWN_ERR("Fail to init key driver.\n"); + return -__LINE__; + } + + return rc; +} + +static int do_opt_keysburn_uninit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + + rc = v2_key_command(argc, argv, _errInfo); + if (rc) { + DWN_ERR("Fail to init key driver.\n"); + return -__LINE__; + } + return rc; +} + +static int do_opt_keysburn_misc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + + --argc, ++argv;//skip the misc subcmd + rc = v2_key_command(argc, argv, _errInfo); + if (rc < 0) { + return -__LINE__; + } + + return rc; +} + +static int optimus_read_keyfile_2_mem(const char* filePath, u8* buf, unsigned* keyValLen) +{ + int rc = 0; + unsigned keySz = 0; + + if (DEV_FILE_FMT_VFAT == _optKeyInfo.fileFmt) + { + long hFile = -1; + unsigned readSz = 0; + +#if 1//FIXME: remove this mmcinfo + /*rc = run_command("mmcinfo 0", 0);*/ + rc = optimus_sdc_burn_switch_to_extmmc(); + if (rc) { + DWN_ERR("Fail in mmcinfo\n"); + return __LINE__; + } +#endif// + keySz = (unsigned)do_fat_get_fileSz(filePath);//can support both sdc and udisk + if (!keySz) { + DWN_ERR("size is 0 of file [%s]\n", filePath); + return __LINE__; + } + + hFile = do_fat_fopen(filePath); + if (hFile < 0) { + DWN_ERR("Fail to open file[%s]\n", filePath); + return __LINE__; + } + + readSz = do_fat_fread(hFile, buf, keySz); + if (readSz != keySz) { + DWN_ERR("Want read %d bytes, but %d\n", keySz, readSz); + return __LINE__; + } + + do_fat_fclose(hFile); + } + + *keyValLen = keySz; + return rc; +} + +int optimus_keysburn_onekey(const char* keyName, u8* keyVal, unsigned keyValLen) +{ + int rc = 0; + unsigned wrLen = 0; + + DWN_MSG("keyName[%s], keyValAddr=%p,len=%d\n", keyName, keyVal, keyValLen); + wrLen = v2_key_burn(keyName, keyVal, keyValLen, _errInfo); + DWN_MSG("writeLen=====%d\n", wrLen); + rc = wrLen != keyValLen; + _AML_KEY_ERR("%s in burn key[%s]\n", rc ? "failed" : "success", keyName); + + return rc; +} + +static int do_opt_keysburn_burn(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + const char* keyName = argv[2]; + u8* keyVal = (u8*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR; + unsigned keyValLen = 0; + + if (4 > argc) { + _AML_KEY_ERR("argc=%d < 4\n", argc); + return __LINE__; + } + if (argc > 4) + { + keyVal = (u8*)simple_strtoul(argv[3], NULL, 16); + keyValLen = simple_strtoul(argv[4], NULL, 0); + } + else//The key is file in the specified device + { + const char* filePath = argv[3]; + + rc = optimus_read_keyfile_2_mem(filePath, keyVal, &keyValLen); + if (rc) { + _AML_KEY_ERR("Fail to read file[%s]\n", filePath); + return __LINE__; + } + } + rc = optimus_keysburn_onekey(keyName, keyVal, keyValLen); + + return rc; +} + + +static cmd_tbl_t cmd_opt_key_burn[] = { + U_BOOT_CMD_MKENT(probe, 4, 0, do_opt_keysburn_probe, "", ""), + U_BOOT_CMD_MKENT(init, 3, 0, do_opt_keysburn_init, "", ""), + U_BOOT_CMD_MKENT(uninit, 2, 0, do_opt_keysburn_uninit, "", ""), + U_BOOT_CMD_MKENT(burn, 5, 0, do_opt_keysburn_burn, "", ""), + U_BOOT_CMD_MKENT(misc, 6, 0, do_opt_keysburn_misc, "", ""), +}; + +static int do_aml_key_burn(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + cmd_tbl_t *c; + + sprintf(_errInfo, "success"); + c = find_cmd_tbl(argv[1], cmd_opt_key_burn, ARRAY_SIZE(cmd_opt_key_burn)); + + if (!c) { + DWN_ERR("Can't find subcmd[%s]\n", argv[1]); + return 1; + } + + rc = c->cmd(cmdtp, flag, argc, argv); + DWN_MSG("[key]%s\n", _errInfo); + if (rc < 0) { + DWN_ERR("Fail in cmd[%s %s].ret=%d\n", argv[1], argv[2], rc); + return -__LINE__; + } + rc = strncmp("success", _errInfo, 7); + + return rc; +} + +U_BOOT_CMD( + aml_key_burn, //command name + 6, //maxargs + 0, //repeatable + do_aml_key_burn, //command function + "Burning keys from external device(sdmmc/udisk/memory) other than usb device", //description + "argv: aml_key_burn ...\n"//usage + "<probe> file_system interface --- init external device/interface\n"//usage + " - e.g.1, for fat sdcard : <aml_key_burn probe> vfat sdc\n" + " - e.g.2, for fat udisk : <aml_key_burn probe> vfat udisk\n" + "\n" + "<init/uninit> random_value --- init nandkey/efusekey driver\n"//usage + "\n" + "<burn> keyName keyFilePath(keyBufAddr keySize) --- init external device/interface\n"//usage + " - e.g.1, write hdcp key with hdcp308.key from sdcard: <aml_key_burn burn> hdcp hdcp308.key\n" + " - e.g.2, write hdcp key in addr 0x200000 : <aml_key_burn burn> hdcp 0x200000 308\n" + "\n" +); + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.c new file mode 100644 index 0000000000..46c7fef071 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.c @@ -0,0 +1,239 @@ +/* + * \file sdc_bootPart_license.c + * \brief + * + * \version 1.0.0 + * \date 2015/3/10 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2015 Amlogic. All Rights Reserved. + * + */ +#include "../optimus_sdc_burn_i.h" +#include "sdc_bootPart_license.h" +#include <crc.h> + +COMPILE_TYPE_CHK(AML_BOOT_PART_KEY_HEAD_SZ == sizeof(BootPartKeyInf_head_t), _aa1); +COMPILE_TYPE_CHK(AML_BOOT_PART_KEY_ITEM_SZ == sizeof(BootPartKeyInf_Item_t), _aa2); + +#define _OPT_BOOT_PART_LIC_INFO_LOADADDR (OPTIMUS_DOWNLOAD_SPARSE_INFO_FOR_VERIFY) +#define _pOptBootPartLicHeadInf (BootPartKeyInf_head_t*)(_OPT_BOOT_PART_LIC_INFO_LOADADDR) + +//Load boot part license info from external emmc to memory +//As "mmc read" is slow, I load it from external mmc only once +int optimus_sdc_bootPart_lic_download(void) +{ + const unsigned maxLen = 2U<<20;// + const unsigned firstReadLen = 2U<<10;//2K + const char* _cmdStr = "mmc read 1 0x%x, 0x%x 0x%x"; + BootPartKeyInf_head_t* pBootPartKeyInfHead = _pOptBootPartLicHeadInf; + char _cmdBuf[96]; + int rc = 0; + +//1, Read from _OPT_BOOT_PART_LIC_INFO_LOADADDR + rc = run_command("mmcinfo 0", 0); + if (rc) { + DWN_ERR("Fail to init external sdcard\n"); + return __LINE__; + } + + memset(pBootPartKeyInfHead, 0, AML_BOOT_PART_KEY_HEAD_SZ + AML_BOOT_PART_KEY_ITEM_SZ * 64); + sprintf(_cmdBuf, _cmdStr, _OPT_BOOT_PART_LIC_INFO_LOADADDR, AML_BOOT_PART_KEY_HEAD_OFFSET, firstReadLen); + DWN_MSG("cmd[%s]\n", _cmdBuf); + rc = run_command(_cmdBuf, 0); + if (rc) { + DWN_ERR("Fail in cmd[%s]\n", _cmdBuf); + return __LINE__; + } + + rc = (AML_BOOT_PART_KEY_HEAD_VERSION == pBootPartKeyInfHead->version) + && (AML_BOOT_PART_KEY_HEAD_MAGIC == pBootPartKeyInfHead->magic); + if (!rc) + { + DWN_MSG("Ver[0x%x] or magic[0x%8x] error\n", + pBootPartKeyInfHead->version, pBootPartKeyInfHead->magic); + //Create the image header + pBootPartKeyInfHead->magic = AML_BOOT_PART_KEY_HEAD_MAGIC; + pBootPartKeyInfHead->version = AML_BOOT_PART_KEY_HEAD_VERSION; + pBootPartKeyInfHead->alignSz = AML_BOOT_PART_ALIGN_SZ; + pBootPartKeyInfHead->imgSz = sizeof(BootPartKeyInf_head_t); + pBootPartKeyInfHead->imgItemNum = 0; + + return 0; + } + const unsigned totalLen = pBootPartKeyInfHead->imgSz; + if (totalLen > maxLen) { + DWN_ERR("totalLen=0x%x > max=0x%x\n", totalLen, maxLen); + return __LINE__; + } + + DWN_MSG("totalLen=0x%x\n", totalLen); + const unsigned genCrc = crc32(0, (u8*)&pBootPartKeyInfHead->magic, + totalLen - sizeof(unsigned int)); + if (genCrc != pBootPartKeyInfHead->hcrc) { + DWN_ERR("genCrc(0x%x) != savedCrc(0x%x), pls clear the card using tool\n", + genCrc, pBootPartKeyInfHead->hcrc); + return __LINE__; + } + DWN_MSG("genCrc=0x%x\n", genCrc); + + if (totalLen > firstReadLen) + { + const unsigned leftLen = totalLen - firstReadLen; + sprintf(_cmdBuf, _cmdStr, _OPT_BOOT_PART_LIC_INFO_LOADADDR, + AML_BOOT_PART_KEY_HEAD_OFFSET + firstReadLen, leftLen); + DWN_MSG("cmd[%s]\n", _cmdBuf); + rc = run_command(_cmdBuf, 0); + if (rc) { + DWN_ERR("Fail in cmd[%s]\n", _cmdBuf); + return __LINE__; + } + } + + return 0; +} + +int optimus_sdc_bootPart_lic_upload(void) +{ + const char* _cmdStr = "mmc write 1 0x%x, 0x%x 0x%x"; + BootPartKeyInf_head_t* pBootPartKeyInfHead = _pOptBootPartLicHeadInf; + char _cmdBuf[96]; + int rc = 0; + + rc = (AML_BOOT_PART_KEY_HEAD_VERSION == pBootPartKeyInfHead->version) + && (AML_BOOT_PART_KEY_HEAD_MAGIC == pBootPartKeyInfHead->magic); + if (!rc) { + DWN_MSG("Ver[0x%x] or magic[0x%8x] error\n", + pBootPartKeyInfHead->version, pBootPartKeyInfHead->magic); + return __LINE__; + } + + rc = run_command("mmcinfo 0", 0); + if (rc) { + DWN_ERR("Fail to init external sdcard\n"); + return __LINE__; + } + DWN_MSG("imgSz=0x%x\n", pBootPartKeyInfHead->imgSz); + //Update crc32 in image header + const unsigned genCrc = crc32(0, (u8*)&pBootPartKeyInfHead->magic, + pBootPartKeyInfHead->imgSz - sizeof(unsigned int)); + pBootPartKeyInfHead->hcrc = genCrc; + DWN_MSG("genCrc=0x%x\n", genCrc); + + const unsigned totalLen = pBootPartKeyInfHead->imgSz; + sprintf(_cmdBuf, _cmdStr, _OPT_BOOT_PART_LIC_INFO_LOADADDR, AML_BOOT_PART_KEY_HEAD_OFFSET, totalLen); + rc = run_command(_cmdBuf, 0); + if (rc) { + DWN_ERR("Fail in cmd[%s]\n", _cmdBuf); + return __LINE__; + } + + return 0; +} + +//* keyInfAddr is sizeof the key info +// +//*/ +int optimus_sdc_bootPart_lic_get_key_infdata(const char* keyName, void** keyInfAddr) +{ + BootPartKeyInf_head_t* pBootPartKeyInfHead = _pOptBootPartLicHeadInf; + BootPartKeyInf_Item_t* pBootPartKeyItemInf = (BootPartKeyInf_Item_t*)(pBootPartKeyInfHead + 1); + const unsigned itemCnt = pBootPartKeyInfHead->imgItemNum; + int rc = 0; + int itemIndex = 0; + + *keyInfAddr = NULL; + + DWN_MSG("Get lic info for key[%s]\n", keyName); + //2, check _pOptBootPartLicHeadInf + rc = (AML_BOOT_PART_KEY_HEAD_VERSION == pBootPartKeyInfHead->version) + && (AML_BOOT_PART_KEY_HEAD_MAGIC == pBootPartKeyInfHead->magic); + if (!rc) { + DWN_MSG("Ver[0x%x] or magic[0x%8x]\n", + pBootPartKeyInfHead->version, pBootPartKeyInfHead->magic); + return 0; + } + + //3, find the item and return the count, return 0 if not found + for(itemIndex = 0; itemIndex < itemCnt; ++itemIndex, + pBootPartKeyItemInf = (BootPartKeyInf_Item_t*)(pBootPartKeyItemInf->nextItemInfOffset + _OPT_BOOT_PART_LIC_INFO_LOADADDR)) + { + const unsigned char* theKeyName = pBootPartKeyItemInf->keyName; + + rc = memcmp(keyName, theKeyName, strlen(keyName)); + if (rc) continue; + *keyInfAddr = ++pBootPartKeyItemInf; + return 0; + } + + return 0; +} + +//add an key info item if any, or update it +int optimus_sdc_bootPart_lic_update_key_inf(const char* keyName, unsigned char* keyVal, unsigned int keyLen) +{ + BootPartKeyInf_head_t* pBootPartKeyInfHead = _pOptBootPartLicHeadInf; + BootPartKeyInf_Item_t* pBootPartKeyItemInf = (BootPartKeyInf_Item_t*)(pBootPartKeyInfHead + 1); + const unsigned itemCnt = pBootPartKeyInfHead->imgItemNum; + int rc = 0; + int itemIndex = 0; + + DWN_MSG("update lic info for key[%s]\n", keyName); + //2, check _pOptBootPartLicHeadInf + rc = (AML_BOOT_PART_KEY_HEAD_VERSION == pBootPartKeyInfHead->version) + && (AML_BOOT_PART_KEY_HEAD_MAGIC == pBootPartKeyInfHead->magic); + if (!rc) { + DWN_MSG("Ver[0x%x] or magic[0x%8x]\n", + pBootPartKeyInfHead->version, pBootPartKeyInfHead->magic); + return __LINE__; + } + + BootPartKeyInf_Item_t* prevItemInf = NULL; + //3, find the item and return the count, return 0 if not found + for(itemIndex = 0; itemIndex < itemCnt; ++itemIndex, + prevItemInf = pBootPartKeyItemInf, + pBootPartKeyItemInf = (BootPartKeyInf_Item_t*)(pBootPartKeyItemInf->itemSz + (unsigned)pBootPartKeyItemInf)) + { + const unsigned char* theKeyName = pBootPartKeyItemInf->keyName; + + rc = memcmp(keyName, theKeyName, strlen(keyName)); + if (rc) continue; + + if (AML_BOOT_PART_KEY_ITEM_MAGIC != pBootPartKeyItemInf->magic) { + DWN_ERR("Excp: item magic 0x%x eror, must be 0x%x\n", + pBootPartKeyItemInf->magic, AML_BOOT_PART_KEY_ITEM_MAGIC); + return __LINE__; + } + //write key founded, update the total data + DWN_MSG("Find item at index %d\n", itemIndex); + if (pBootPartKeyItemInf->itemSz != keyLen + sizeof(BootPartKeyInf_Item_t)) { + DWN_ERR("Excp: oldlen %d != newlen %d\n", pBootPartKeyItemInf->itemSz, keyLen); + return __LINE__; + } + return 0;//To simple it just return + } + if (prevItemInf) + { + prevItemInf->nextItemInfOffset = (unsigned)pBootPartKeyItemInf - _OPT_BOOT_PART_LIC_INFO_LOADADDR; + } + + if (itemIndex != itemCnt) { + DWN_ERR("Exp:itemIndex[%d] != itemCnt[%d]\n", itemIndex, itemCnt); + return __LINE__; + } + memcpy(pBootPartKeyItemInf + 1, keyVal, keyLen); + //update item info + pBootPartKeyItemInf->itemIndex = itemIndex; + pBootPartKeyItemInf->itemSz = keyLen + sizeof(BootPartKeyInf_Item_t); + memcpy(pBootPartKeyItemInf->keyName, keyName, strlen(keyName)); + pBootPartKeyItemInf->version = AML_BOOT_PART_KEY_ITEM_VERSION; + pBootPartKeyItemInf->magic = AML_BOOT_PART_KEY_ITEM_MAGIC; + // + //Update head info + pBootPartKeyInfHead->imgSz += keyLen; + ++pBootPartKeyInfHead->imgItemNum; + + return 0; + +} + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.h b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.h new file mode 100644 index 0000000000..37503ad806 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_bootPart_license.h @@ -0,0 +1,70 @@ +/* + * \file sdc_bootPart_license.h + * \brief Interfaces to read/update license in boot part + * + * \version 1.0.0 + * \date 2015/3/10 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2015 Amlogic. All Rights Reserved. + * + */ +#ifndef __V2_SDC_BURN_SDC_BOOTPART_LICENSE_H__ +#define __V2_SDC_BURN_SDC_BOOTPART_LICENSE_H__ + +#define AML_BOOT_PART_KEY_HEAD_OFFSET (0x4U<<20) +#define AML_BOOT_PART_KEY_HEAD_MAGIC 0X2143494C //"LIC!" +#define AML_BOOT_PART_KEY_HEAD_VERSION 0x01 +#define AML_BOOT_PART_KEY_HEAD_SZ (128) +#define AML_BOOT_PART_ALIGN_SZ (16) + +#define AML_BOOT_PART_KEY_ITEM_MAGIC 0X4D455449 //"ITEM!" +#define AML_BOOT_PART_KEY_ITEM_VERSION 0x01 +#define AML_BOOT_PART_KEY_ITEM_SZ (128) +#define AML_BOOT_PART_KEY_ITEM_NAME_LEN 16 + +#pragma pack(push, 4) +typedef struct _bootPartKeyInf_head{ + unsigned int hcrc; + unsigned int magic; + + unsigned int version; + unsigned int alignSz; + + unsigned int imgSz; + unsigned int imgItemNum; + + unsigned char reserv[AML_BOOT_PART_KEY_HEAD_SZ - sizeof(unsigned int) * 6]; +}BootPartKeyInf_head_t; +#pragma pack(pop) + +#pragma pack(push, 4) +typedef struct _bootPartKeyInf_Item{ + unsigned int magic; + unsigned int version; + + unsigned int itemIndex; + unsigned int itemSz;//including this inf head + + unsigned int nextItemInfOffset; + unsigned int reserv; + + unsigned char keyName[AML_BOOT_PART_KEY_ITEM_NAME_LEN]; + + unsigned char resv1[AML_BOOT_PART_KEY_ITEM_SZ - sizeof(unsigned) * 6 - AML_BOOT_PART_KEY_ITEM_NAME_LEN]; +}BootPartKeyInf_Item_t; +#pragma pack(pop) + +//Read license inf from external emmc boot part +int optimus_sdc_bootPart_lic_download(void); + +//update the license inf to external mmc boot part +int optimus_sdc_bootPart_lic_upload(void); + +int optimus_sdc_bootPart_lic_get_key_infdata(const char* keyName, void** keyInfAddr); + +//add an key info item if any, or update it +int optimus_sdc_bootPart_lic_update_key_inf(const char* keyName, unsigned char* keyVal, unsigned int keyLen); + +#endif//ifndef __V2_SDC_BURN_SDC_BOOTPART_LICENSE_H__ + diff --git a/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_keysprovider.c b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_keysprovider.c new file mode 100644 index 0000000000..e40ba0e23c --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_sdc_burn/sdc_burnkeys/sdc_keysprovider.c @@ -0,0 +1,507 @@ +/* + * \file sdc_keysprovider.c + * \brief Parse users' nankey/efusekey like PC's keysprovider.dll in sdcard burning mode + * + * \version 1.0.0 + * \date 2014/12/25 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2014 Amlogic. All Rights Reserved. + * + */ +#include "../optimus_sdc_burn_i.h" +#include "sdc_bootPart_license.h" + +#define _KEYS_PRV_DBG(fmt...) //DWN_MSG(fmt) +#define _KEYS_PRV_ITEM_INF_ADDR_4_CONSIST (OPTIMUS_DOWNLOAD_DISPLAY_BUF + 48 * 1024) +#define _KEYS_PRV_ITEM_INF_ADDR_MISC (OPTIMUS_DOWNLOAD_DISPLAY_BUF + 52 * 1024) + +#define _KEY_VAL_TMP_BUF (OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR - OPTIMUS_DOWNLOAD_SLOT_SZ) +static struct { + char* keyBuf; + unsigned keySize; +}_currentKey = {0}; + +//Note: keys which read only is not need to update license, and so not need stored in boot partition +//Typedef for keys structs in sdcard boot partition +#if 1 +#define AML_BOOT_PART_KEY_IMG_OFFSET (0X2U<<20) +#define AML_BOOT_PART_KEY_IMG_MAGIC_LEN 8 +#define AML_BOOT_PART_KEY_IMG_MAGIC_V1 "AML_KEY!" +#define AML_BOOT_PART_KEY_IMG_ALIGN_SZ 512 +#define AML_BOOT_PART_KEY_IMG_HEAD_SZ (64) + +#define AML_BOOT_PART_KEY_ITEM_INF_LEN (64) +#define AML_BOOT_PART_KEY_ITEM_NAME_LEN_MAX (16) + +//struct for the keys head which stored in boot partition +#pragma pack(push, 4) +typedef struct { + __u32 crc; + __s32 version; + + __u8 magic[AML_BOOT_PART_KEY_IMG_MAGIC_LEN]; + + __u32 imgSz; + __u32 imgItemNum; + + __u32 alignSz;//512 + __u8 resrv[AML_BOOT_PART_KEY_IMG_HEAD_SZ - 8 * 3 - 4]; + +}AmlBootPartKeysHead_t; +#pragma pack(pop) + +#pragma pack(push, 4) +typedef struct { + __u8 keyName[AML_BOOT_PART_KEY_ITEM_NAME_LEN_MAX]; + + __u32 itemIndex; + __u32 itemSz; //equl to sizeof of each key + + __u32 itemBodyOffset; + __u32 itemHasConf;//this item name is configured in keys.conf + + __u8 resrv[32]; + +}KeyInfo_t; +#pragma pack(pop) + +#define MAX_KEY_INF_NUM 5 //the max key numbers supported at the same time + +typedef struct { + AmlBootPartKeysHead_t bootPartKeyHead; + KeyInfo_t keysInf[MAX_KEY_INF_NUM]; +}BootPartKeyInf_t; + +#endif//image for keys END #if 1 + +#define debugP(fmt...) //printf("L%d:", __LINE__),printf(fmt) +#define errorP(fmt...) printf("Err[keyspr]L%d:", __LINE__),printf(fmt) +#define wrnP(fmt...) printf("Wrn[keyspr]L%d:", __LINE__),printf(fmt) +#define MsgP(fmt...) printf("Msg[keyspr]L%d:", __LINE__),printf(fmt) + +#define KEY_MAP_MAGIC 0xeeffaa00 + +enum { + KEY_FMT__MAC = 0XBB, //string format like 00:01:02:03:04:05 + KEY_FMT__ONLEYONE , //only one format means read the total license file as key value + KEY_FMT__HDCP , + KEY_FMT__HDCP2 , +}; + +//Different keyNames can have the same key format +typedef int (*pFunc_getKeyValByLic)(const char* licensePath, u8* keyVal, unsigned* keyValLen, const char* keyName); +typedef int (*pFunc_updateLic)(const char* keyName, const char* licensePath);//update the licnese file when burn succeed + +typedef struct _keyFmtMapping{ + unsigned magic; + const char* const keyName; + const char* const licenseFile; + const unsigned keyFmt; + pFunc_getKeyValByLic get_key_val; + pFunc_updateLic update_license; +}KeyFmtMap_t; + +static int get_key_val_for_fmt_mac(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName); +static int get_key_val_for_fmt_hdcp(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName); +static int get_key_val_for_fmt_hdcp2rx(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName); +static int get_key_val_for_fmt_onlyone(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName); + +static int update_lic_for_fmt_mac(const char* keyName, const char* licenseName); +static int update_lic_for_fmt_hdcp(const char* keyName, const char* licenseName); +static int update_lic_for_fmt_hdcp2rx(const char* keyName, const char* licenseName); + +static const KeyFmtMap_t _keysFmtMapping[] = { + /* magic, keyname license file name keyFmt*/ + [0] = {KEY_MAP_MAGIC, "mac", "license/mac_ether.ini" , KEY_FMT__MAC , get_key_val_for_fmt_mac , update_lic_for_fmt_mac }, + [1] = {KEY_MAP_MAGIC, "mac_bt", "license/mac_bt.ini" , KEY_FMT__MAC , get_key_val_for_fmt_mac , update_lic_for_fmt_mac }, + [2] = {KEY_MAP_MAGIC, "mac_wifi", "license/mac_wifi.ini" , KEY_FMT__MAC , get_key_val_for_fmt_mac , update_lic_for_fmt_mac }, + [3] = {KEY_MAP_MAGIC, "hdcp", "license/HDCP_LIENCE" , KEY_FMT__HDCP , get_key_val_for_fmt_hdcp , update_lic_for_fmt_hdcp }, + [4] = {KEY_MAP_MAGIC, "hdcp2", "license/HDCP2_LIENCE" , KEY_FMT__HDCP2 , get_key_val_for_fmt_hdcp2rx, update_lic_for_fmt_hdcp2rx}, + [5] = {KEY_MAP_MAGIC, "secure_boot_set", "license/SECURE_BOOT_SET", KEY_FMT__ONLEYONE, get_key_val_for_fmt_onlyone, NULL}, +}; +#define _SupportKeysNum (sizeof(_keysFmtMapping)/sizeof(KeyFmtMap_t)) + +#if 1 //mac begin +static int optimus_sdc_burn_check_mac_ini_set_is_valid(const char* setName) +{ + const char* macSets[] = {"Group1", "Group2", "Group3"}; + const int nSet = sizeof(macSets)/sizeof(char*); + int index = 0; + int rc = 0; + + for (; index < nSet && !rc; ++index) + { + rc = !strcmp(setName, macSets[index]); + } + + return rc; +} + +typedef struct { + char startMac[17 + 3]; //+2 to align 4 + char endMac[17 + 3]; //+2 to align 4 + unsigned total; + unsigned used; +}MacGroup_t; + +typedef struct { + unsigned actualGroup; + MacGroup_t groups[3];//max group is 3 +}KeyInf_mac_t; + +typedef struct { + const char* start; + const char* end; + unsigned used; + unsigned total;//total = end + 1 - start +}MacCfg_t; + +/*static KeyInf_mac_t _bootPart_keyInf_Mac;//Mac key info stored in boot partition*/ + +static int optimus_update_mac_str_current_val(char* startVal, unsigned used) +{ + int i = 0; + + if (17 != strlen(startVal)) { + DWN_ERR("start(%s) fmt error.\n", startVal); + return __LINE__; + } + + MsgP("start[%s], used=%d\n", startVal, used); + for (i = 5; i >= 0 && used; --i, (used >>= 8)) + { + char* grp2 = startVal + i * 3; + unsigned grp2Val = simple_strtoul(grp2, NULL, 16); + + DWN_DBG("gpp2(%s)grep2=%d, used=%d\n", grp2, grp2Val, used); + grp2Val += used & 0xff; + if (grp2Val > 0xff) + { + used += 0x100; + grp2Val &= 0xff; + } + sprintf(grp2, "%02x", grp2Val); + DWN_DBG("grp[%d]%s\n", i, grp2); + } + DWN_MSG("Update mac [%s]\n", startVal); + + return 0; +} + +static int _optimus_get_mac_diff(MacCfg_t* macCfg) +{ + const char* start = macCfg->start; + const char* end = macCfg->end; + __u64 startVal = 0; + __u64 endVal = 0; + int i = 0; + + for (i = 0; i < 6; ++i, start += 3, end += 3) + { + startVal += simple_strtoul(start, NULL, 16); + endVal += simple_strtoul(end, NULL, 16); + + startVal <<= 8; + endVal <<= 8; + } + startVal >>= 8; + endVal >>= 8; + DWN_MSG("mac range[%04x%08x, %04x%08x]\n", + (unsigned)(startVal>>32), (unsigned)(startVal), + (unsigned)(endVal>>32), (unsigned)endVal ); + macCfg->total = (unsigned)(endVal + 1 - startVal); + return 0; +} + +//update the mac value extracted from mac.ini +//To simplest the case, currently one group is supported +static int optimus_sdc_burn_parse_mac_ini_key_value(const char* setName, const char* keyName, const char* usrKeyVal) +{ + int rc = 0; + int grpN = 0; + MacCfg_t* currentMacCfg = (MacCfg_t*)_KEYS_PRV_ITEM_INF_ADDR_MISC; + char* keyBuf = (char*)_KEY_VAL_TMP_BUF; + KeyInf_mac_t* pKeyInf4Consist = (KeyInf_mac_t*)_KEYS_PRV_ITEM_INF_ADDR_4_CONSIST; + + rc = strncmp("Group", setName, 5) || ( 6 != strlen(setName) ); + if (rc) {//mac.ini only care Groupn + return 0; + } + grpN = setName[5] - '1'; //'1' not '0' + if (grpN > 3) { + DWN_ERR("Can only support grp1 ~ grp3 now!, grp[%s] not ok\n", setName); + return __LINE__; + } + pKeyInf4Consist->actualGroup = grpN + 1; + MacGroup_t* pKeyConsist = pKeyInf4Consist->groups + grpN; + + _KEYS_PRV_DBG("grp[%d]key=[%s], val=[%s]\n", grpN, keyName, usrKeyVal); + //the mac cfg must be in the order: start + end (+used) + if (!strcmp("start", keyName)) + { + currentMacCfg->start = usrKeyVal;//value in memory + _currentKey.keySize = strlen(usrKeyVal); + strcpy(keyBuf, currentMacCfg->start); + keyBuf[_currentKey.keySize] = 0; + _currentKey.keyBuf = keyBuf; + DWN_DBG("keybuf[%s]\n", keyBuf); + memcpy(pKeyConsist->startMac, usrKeyVal, strlen(usrKeyVal)); + } + else if (!strcmp("end", keyName)) + { + currentMacCfg->end = usrKeyVal; + _currentKey.keySize = strlen(usrKeyVal); + _optimus_get_mac_diff(currentMacCfg); + memcpy(pKeyConsist->endMac, usrKeyVal, strlen(usrKeyVal)); + pKeyConsist->total = currentMacCfg->total; + } + else if(!strcmp("used", keyName)) + { + currentMacCfg->used = simple_strtoul(usrKeyVal, NULL, 0); + if (currentMacCfg->used >= currentMacCfg->total) { + DWN_ERR("mac used(%d) >= total(%d)\n", currentMacCfg->used , currentMacCfg->total); + return __LINE__; + } + pKeyConsist->used = currentMacCfg->used; + } + + if (17 != _currentKey.keySize) { + errorP("key size %d of mac(%s) is error, must be 17\n", _currentKey.keySize, usrKeyVal); + return __LINE__; + } + + return 0; +} + +static int _update_mac_with_cfg_and_bootpart(KeyInf_mac_t* pKeyInf4Consist, KeyInf_mac_t* pKeyInfInBootPart, + u8* keyVal, unsigned* keyValLen) +{ + const int grpNum = pKeyInf4Consist->actualGroup; + MacGroup_t* theMacGrpCfg = NULL; + MacGroup_t* theMacGrpInBootPart = NULL; + unsigned currentUsed = 0; + int i = 0; + + theMacGrpCfg = pKeyInf4Consist->groups; + currentUsed = theMacGrpCfg->used; + for (; i < grpNum; ++i, ++theMacGrpCfg) + { + const unsigned leftInCfg = theMacGrpCfg->total - theMacGrpCfg->used; + unsigned leftCnt = leftInCfg; + if (pKeyInfInBootPart) + { + theMacGrpInBootPart = pKeyInfInBootPart->groups + i; + const unsigned leftInBoot = theMacGrpInBootPart->total - theMacGrpInBootPart->used; + DWN_MSG("leftInCfg=%u, leftInBoot=%u, used=%u\n", leftCnt, leftInBoot, theMacGrpInBootPart->used); + if (leftCnt < leftInBoot) { + DWN_ERR("Excp:leftInCfg[%u] < leftInBoot[%u]\n", leftCnt, leftInBoot); + return __LINE__; + } + if (theMacGrpInBootPart->total != theMacGrpCfg->total) { + DWN_ERR("Excp:cfg total[%u] != boot total[%u]\n", + theMacGrpCfg->total, theMacGrpInBootPart->total); + return __LINE__; + } + currentUsed = ++theMacGrpInBootPart->used;//used is saved by prev burned + } + if (currentUsed < theMacGrpCfg->total) {//Find it + DWN_MSG("Found available at grp[%d], total=%u, used=%u\n", + i, theMacGrpCfg->total, currentUsed); + break; + } + } + + if (i == grpNum) { + DWN_ERR("Can't find available grp,i=%d\n", i); + return __LINE__; + } + + *keyValLen = strlen(theMacGrpCfg->startMac); + memcpy(keyVal, theMacGrpCfg->startMac, *keyValLen); + i = optimus_update_mac_str_current_val((char*)keyVal, currentUsed); + return i; +} + +//step 1: parsing license/mac.ini to get 'start' and 'used' +//step 2: search the key info in the boot key, if not existed , then append the keyinfo and update total count +//step 3: check the 'start' and 'used' is same as which in the boot partition if existed +//step 3: get the count recorded in the uboot partition +static int get_key_val_for_fmt_mac(const char* licPath, u8* keyVal, unsigned* keyValLen, const char* keyName) +{ + const int MaxLines = 256;// + char* lines[MaxLines]; + int rc = __LINE__; + int validLineNum = 0; + KeyInf_mac_t* pKeyInfInBootPart = NULL; + KeyInf_mac_t* pKeyInf4Consist = (KeyInf_mac_t*)_KEYS_PRV_ITEM_INF_ADDR_4_CONSIST; + + memset(pKeyInf4Consist, 0, sizeof(KeyInf_mac_t)); + validLineNum = parse_ini_file_2_valid_lines(licPath, (char*)keyVal, *keyValLen, lines); + if (!validLineNum) { + DWN_ERR("error in parse ini file\n"); + return __LINE__; + } + + rc = optimus_ini_trans_lines_2_usr_params((const char* *)lines, validLineNum, + optimus_sdc_burn_check_mac_ini_set_is_valid, + optimus_sdc_burn_parse_mac_ini_key_value); + if (rc) { + DWN_ERR("Fail in get cfg from %s\n", licPath); + return __LINE__; + } + *keyValLen = _currentKey.keySize; + memcpy(keyVal, _currentKey.keyBuf, _currentKey.keySize); + keyVal[_currentKey.keySize] = 0; + +#if 1 + rc = optimus_sdc_bootPart_lic_get_key_infdata(keyName, (void**)&pKeyInfInBootPart); + if (rc) { + DWN_ERR("Fail in get key inf from boot part\n"); + return __LINE__; + } +#endif + rc = _update_mac_with_cfg_and_bootpart(pKeyInf4Consist, pKeyInfInBootPart, keyVal, keyValLen); + + return rc; +} + +static int update_lic_for_fmt_mac(const char* keyName, const char* licenseName) +{ + int rc = 0; + + rc = optimus_sdc_bootPart_lic_update_key_inf(keyName, (u8*)_KEYS_PRV_ITEM_INF_ADDR_4_CONSIST, sizeof(KeyInf_mac_t)); + + return rc; +} +#endif//MAC + + +static int get_key_val_for_fmt_hdcp(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName) +{ + int rc = __LINE__; + + + return rc; +} + +static int get_key_val_for_fmt_hdcp2rx(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName) +{ + int rc = __LINE__; + + + return rc; +} + +static int get_key_val_for_fmt_onlyone(const char* licenseName, u8* keyVal, unsigned* keyValLen, const char* keyName) +{ + int rc = 0; + char _cmd[96]; + + optimus_sdc_burn_switch_to_extmmc(); + sprintf(_cmd, "fatexist mmc 0:1 %s", licenseName); + rc = run_command(_cmd, 0); + if (rc) { + errorP("file[%s] is not existed\n", licenseName); + return __LINE__; + } + + sprintf(_cmd, "fatload mmc 0:1 0x%p %s", keyVal, licenseName); + rc = run_command(_cmd, 0); + if (rc) { + errorP("failed in cmd[%s]\n", _cmd); + return __LINE__; + } + + *keyValLen = simple_strtoul(getenv("filesize"), NULL, 16); + + return rc; +} + +static int update_lic_for_fmt_hdcp(const char* keyName, const char* licenseName) +{ + int rc = 0; + + + return rc; +} + +static int update_lic_for_fmt_hdcp2rx(const char* keyName, const char* licenseName) +{ + int rc = 0; + + + return rc; +} + +int optimus_sdc_keysprovider_init(void) +{ + return optimus_sdc_bootPart_lic_download(); +} + +int optimus_sdc_keysprovider_exit(void) +{ + + return optimus_sdc_bootPart_lic_upload(); +} + +//check whether the key license is existed and supported +//keyName is getted from keys.conf in package like PC burning tool +int optimus_sdc_keysprovider_open(const char* keyName, const void** pHdle) +{ + int i = 0; + int rc = __LINE__; + + const KeyFmtMap_t* pMappedKey = &_keysFmtMapping[0]; + for (i=0; i < _SupportKeysNum; ++i, ++pMappedKey) { + rc = strcmp(keyName, pMappedKey->keyName); + if (rc) continue;//keyName not mapped + *pHdle = pMappedKey; + return 0; + } + + return rc; +} + +int optimus_sdc_keysprovider_get_keyval(const void* pHdle, u8* pBuf, unsigned* keySz) +{ + const KeyFmtMap_t* pMappedKey = (const KeyFmtMap_t*)pHdle; + const char* const keyName = pMappedKey->keyName; + const char* licPath = pMappedKey->licenseFile; + int rc = 0; + + if (KEY_MAP_MAGIC != pMappedKey->magic) { + errorP("magic should be %x, but %x\n", KEY_MAP_MAGIC, pMappedKey->magic); + return __LINE__; + } + rc = pMappedKey->get_key_val(licPath, pBuf, keySz, keyName); + if (rc) { + errorP("Fail in getKeyVal for key[%s] at lic path[%s]\n", keyName, licPath); + return __LINE__; + } + + return rc; +} + +int optimus_sdc_keysprovider_update_license(const void* pHdle) +{ + const KeyFmtMap_t* pMappedKey = (const KeyFmtMap_t*)pHdle; + const char* const keyName = pMappedKey->keyName; + const char* licPath = pMappedKey->licenseFile; + int rc = 0; + + if (KEY_MAP_MAGIC != pMappedKey->magic) { + errorP("magic should be %x, but %x\n", KEY_MAP_MAGIC, pMappedKey->magic); + return __LINE__; + } + if (!pMappedKey->update_license) return 0; + + rc = pMappedKey->update_license(keyName, licPath); + if (rc) { + errorP("Fail in getKeyVal for key[%s] at lic path[%s]\n", keyName, licPath); + return __LINE__; + } + + return 0; +} + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_burn/optimus_usb_burn.c b/drivers/usb/gadget/v2_burning/v2_usb_burn/optimus_usb_burn.c new file mode 100644 index 0000000000..77ca54e50c --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_burn/optimus_usb_burn.c @@ -0,0 +1,80 @@ +/* + * \file optimus_usb_burn.c + * \brief burning itself from Pheripheral usb host + * + * \version 1.0.0 + * \date 2014-9-15 + * \author Sam.Wu <yihui.wu@amlgic.com> + * Chunyu.Song <chunyu.song@amlogic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#include "../v2_sdc_burn/optimus_sdc_burn_i.h" +#include "../v2_sdc_burn/optimus_led.h" + +extern int optimus_burn_with_cfg_file(const char* cfgFile); + +// added by scy +int optimus_burn_package_in_usb(const char* sdc_cfg_file) +{ + int rcode = 0; + + DWN_MSG("usb start\n"); + rcode = run_command("usb start", 0); + if (rcode) { + DWN_ERR("Fail in init usb host, Does usb host not plugged in?\n"); + return __LINE__; + } + +#if 0//this asserted by 'run update' and 'aml_check_is_ready_for_sdc_produce' + rcode = do_fat_get_fileSz(sdc_cfg_file); + if (!rcode) { + printf("The [%s] not exist in bootable mmc card\n", sdc_cfg_file); + return __LINE__; + } +#endif//#if 0 + + rcode = optimus_burn_with_cfg_file(sdc_cfg_file); + + return rcode; +} + + +// added by scy +int do_usb_burn(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + + int rcode = 0; + const char* sdc_cfg_file = argv[1]; + + setenv("usb_update","1"); + + if (argc < 2 ) { + cmd_usage(cmdtp); + return __LINE__; + } + + optimus_work_mode_set(OPTIMUS_WORK_MODE_SDC_UPDATE); + show_logo_to_report_burning();//indicate enter flow of burning! when 'run update' + if (optimus_led_open(LED_TYPE_PWM)) { + DWN_ERR("Fail to open led for burn\n"); + return __LINE__; + } + optimus_led_show_in_process_of_burning(); + + rcode = optimus_burn_package_in_usb(sdc_cfg_file); + + return rcode; +} + +// added by scy +U_BOOT_CMD( + usb_burn, //command name + 5, //maxargs + 0, //repeatable + do_usb_burn, //command function + "Burning with amlogic format package in usb ", //description + "argv: [sdc_burn_cfg_file]\n"//usage + " -aml_sdc_burn.ini is usually used configure file\n" +); diff --git a/drivers/usb/gadget/v2_burning/v2_usb_burn/optimus_usb_update.c b/drivers/usb/gadget/v2_burning/v2_usb_burn/optimus_usb_update.c new file mode 100644 index 0000000000..d31f51bd22 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_burn/optimus_usb_update.c @@ -0,0 +1,131 @@ +/* + * \file optimus_usb_update.c + * \brief usb_update command to burn a parition image from usb host + * this update based on the burner is latest: (uboot for burnner can run from peripherals such as sdmmc/usb) + * + * \version 1.0.0 + * \date 2014-9-15 + * \author Chunyu.Song<chunyu.song@amlogic.com> + * Sam.Wu <yihui.wu@amlogic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#include "../v2_sdc_burn/optimus_sdc_burn_i.h" + +typedef int __hFileHdl; + +#define BURN_DBG 0 +#if BURN_DBG +#define SDC_DBG(fmt...) printf(fmt) +#else +#define SDC_DBG(fmt...) +#endif//if BURN_DBG + +#define SDC_MSG DWN_MSG +#define SDC_ERR DWN_ERR + +//static char _errInfo[512] = ""; +// count usb start,to reduce the time-consuming of excuting usb start +int usb_start_count = 0; + +//step 1: get script file size, and get script file contents +//step 2: read image file +//"Usage: usb_update partiton image_file_path [imgFmt, verifyFile]\n" //usage +int do_usb_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rcode = 0; + + const char* partName = argv[1]; + const char* imgItemPath = argv[2]; + const char* fileFmt = argc > 3 ? argv[3] : NULL; + const char* verifyFile = argc > 4 ? argv[4] : NULL; + + setenv("usb_update", "1"); + printf("usb_start_count %d\n", usb_start_count); +#if BURN_DBG + printf("argc %d, %s, %s\n", argc, argv[0], argv[1]); + if (argc < 3) + { + partName = "system"; + imgItemPath = "rec.img"; + fileFmt = "normal"; + verifyFile = "recovery.verify"; + } +#else + if (argc < 3) { + cmd_usage(cmdtp); + return __LINE__; + } +#endif//#if BURN_DBG + +if (usb_start_count == 0) +{ + //usb start to ensure usb host inserted and inited + rcode = run_command("usb start", 0); + usb_start_count++; + if (rcode) { + SDC_ERR("Fail in init usb, Does usb host not plugged in?\n"); + return __LINE__; + } +} + +#if 0 + if (!do_fat_get_fileSz(imgItemPath)) { + SDC_ERR("file (%s) not existed\n", imgItemPath); + return __LINE__; + } +#else + rcode = optimus_device_probe("usb", "0"); +/* + if (rcode) { + SDC_ERR("Fail to detect device usb 0\n"); + return __LINE__; + } + */ +#endif//#if 0 + + if (!fileFmt) + { + rcode = do_fat_get_file_format(imgItemPath, (u8*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR, (8*1024)); + if (rcode < 0) { + SDC_ERR("Fail when parse file format\n"); + return __LINE__; + } + fileFmt = rcode ? "sparse" : "normal"; + } + +#if 0 + if (!getenv("disk_initial")) //if disk_initial command not executed for burning + { + rcode = optimus_storage_init(0);//can't erase as not full updating + if (rcode) { + SDC_ERR("Fail in init storage, rcode %d\n", rcode); + return rcode; + } + setenv("disk_initial", "0"); + } +#endif//#if 0 + + rcode = optimus_burn_partition_image(partName, imgItemPath, fileFmt, verifyFile, 0); + if (rcode) { + SDC_ERR("Fail to burn partition (%s) with image file (%s) in format (%s)\n", partName, imgItemPath, fileFmt); + } + + return rcode; +} + +U_BOOT_CMD( + usb_update, //command name + 5, //maxargs + 0, //repeatable + do_usb_update, //command function + "Burning a partition with image file in usb host", //description + " argv: <part_name> <image_file_path> <[,fileFmt]> <[,verify_file]> \n" //usage + " - <fileFmt> parameter is optional, if you know it you can specify it.\n" + " for Android, system.img and data.img is \"sparse\" format, other is \"normal\"\n" //usage + " - <verify_file> parameter is optional, if you have it you can specify it.\n" + " - e.g. \n" + " to burn partition boot with boot.img of usb 0 : \"usb_update boot boot.img\"\n" //usage + " to burn partition system with system.img of usb 0 : \"usb_update system system.img\"\n" //usage +); diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd.c b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd.c new file mode 100644 index 0000000000..f1a8e31bab --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd.c @@ -0,0 +1,739 @@ +/* dwc controller pcd drivers */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-24 @ Shanghai + * + */ +#include "../v2_burning_i.h" +#include "platform.h" +#include "usb_ch9.h" +#include "dwc_pcd.h" +#include "dwc_pcd_irq.h" + +pcd_struct_t this_pcd ;//FIXME:This PCD should point to different or cause bug!! + +dwc_ep_t g_dwc_eps[NUM_EP]; + +int dwc_core_init(void) +{ + gotgctl_data_t gctrldata; + int32_t snpsid; + + memset(&this_pcd, 0, sizeof(this_pcd)); + + DBG("DWC_REG_GSNPSID 0x%x\n", DWC_REG_GSNPSID+DWC_REG_BASE); + snpsid = dwc_read_reg32(DWC_REG_GSNPSID); + + if ( !( 0x4F542000 == (snpsid & 0xFFFFF000) || 0x4F543000 == (snpsid & 0xFFFFF000) ) ) { + printf("%s,Bad value for SNPSID: 0x%08x\n", __func__, snpsid); + return -1; + } + +#if 1 + /*GOTGCTL*/ + gctrldata.d32 = dwc_read_reg32(DWC_REG_GOTGCTL);//Can this GOTGCTL read before dwc_otg_core_init() ?? + if (!gctrldata.b.asesvld || !gctrldata.b.bsesvld) { + printf("GOTGCTL=0x%08x, asesvld=%x, bsesvld=%x\n", + gctrldata.d32, gctrldata.b.asesvld, gctrldata.b.bsesvld); + return __LINE__; + + } +#endif// + + DBG("dwc core init is ok!\n");// show printf is ok. + /* + * Disable the global interrupt until all the interrupt + * handlers are installed. + */ + gahbcfg_data_t ahbcfg = {.d32 = 0 }; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts bit */ + dwc_modify_reg32(DWC_REG_GAHBCFG, ahbcfg.d32, 0); + /* + * Initialize the DWC_otg core. + */ + dwc_otg_core_init(); + + dwc_modify_reg32(DWC_REG_DCTL,0,2);// Disconnect data line + dwc_otg_pcd_init(); + dwc_modify_reg32(DWC_REG_DCTL,2,0);// Connect data line + + /* + * Enable the global interrupt after all the interrupt + * handlers are installed. + */ + dwc_otg_enable_global_interrupts(); + + return 0; +} + +int dwc_otg_irq(void) +{ + int ret1,ret2; + + ret1 = dwc_common_irq(); + ret2 = dwc_pcd_irq(); + return (ret1+ret2); +} + +void dwc_otg_pullup(int is_on) +{ + if (is_on) + dwc_modify_reg32(DWC_REG_DCTL,2,0);// connect data line + else dwc_modify_reg32(DWC_REG_DCTL,0,2);// disconnect data line +} +static void dwc_otg_core_init() //Elvis Fool, add 'static' +{ + gahbcfg_data_t ahbcfg = {.d32 = 0 }; + gusbcfg_data_t usbcfg = {.d32 = 0 }; + // gi2cctl_data_t i2cctl = {.d32 = 0 }; +// hcfg_data_t hcfg; +#ifndef USE_FULL_SPEED + usbcfg.d32 = dwc_read_reg32(DWC_REG_GUSBCFG); + + usbcfg.b.ulpi_ext_vbus_drv = 0; + usbcfg.b.term_sel_dl_pulse = 0; + dwc_write_reg32(DWC_REG_GUSBCFG,usbcfg.d32); +#endif + /* + * Reset the Controller + */ + dwc_otg_core_reset(); + + usbcfg.d32 = dwc_read_reg32(DWC_REG_GUSBCFG); + usbcfg.b.srpcap = 0; + usbcfg.b.hnpcap = 0; +#ifdef USE_FULL_SPEED + dcfg_data_t dcfg; + printf("Full Speed\n"); + usbcfg.b.physel = 1; // Work at full speed + dwc_write_reg32(DWC_REG_GUSBCFG, usbcfg.d32); + + dwc_otg_core_reset(); +/* for HOST + hcfg.d32 = dwc_read_reg32(DWC_REG_ hcfg); + hcfg.b.fslspclksel = val; + dwc_write_reg32(&_core_if->host_if->host_global_regs->hcfg, hcfg.d32); +*/ +// for Device + dcfg.d32 = dwc_read_reg32(DWC_REG_DCFG); + dcfg.b.devspd = 1;//Hi speed phy run at Full speed + dwc_write_reg32(DWC_REG_DCFG, dcfg.d32); +#else + DBG("High Speed\n"); + usbcfg.b.ulpi_utmi_sel = 1; + usbcfg.b.phyif = 0; // 16 bit + usbcfg.b.ddrsel = 0; + dwc_write_reg32(DWC_REG_GUSBCFG, usbcfg.d32); + + dwc_otg_core_reset(); +#endif + ahbcfg.b.dmaenable = 0; + dwc_write_reg32(DWC_REG_GAHBCFG, ahbcfg.d32); + + + /* + * Enable common interrupts + */ + dwc_otg_enable_common_interrupts(); + + /* + * Do device or host intialization based on mode during PCD and HCD + * initialization + */ + if (dwc_read_reg32(DWC_REG_GINTSTS) & 0x1) { + DBG("Host Mode\n"); + return ; + } else { + DBG("Device Mode\n"); + dwc_otg_core_dev_init(); + } + +} + +/** + * This function initialized the PCD portion of the driver. + * + */ +static int dwc_otg_pcd_init() +{ + return 0; +} + + +/** + * Do core a soft reset of the core. Be careful with this because it + * resets all the internal state machines of the core. + */ +static void dwc_otg_core_reset(void) //Elvis Fool, add 'static' +{ + grstctl_t greset = {.d32 = 0 }; + int count = 0; + + /* + * Wait for AHB master IDLE state. + */ + do { + udelay(10); + greset.d32 = dwc_read_reg32(DWC_REG_GRSTCTL); + if (++count > 100000) { + //DBG("%s() HANG! AHB Idle GRSTCTL=%0x\n", dwc_otg_core_reset, greset.d32); + return; + } + } + while (greset.b.ahbidle == 0); + + /* + * Core Soft Reset + */ + count = 0; + greset.b.csftrst = 1; + dwc_write_reg32(DWC_REG_GRSTCTL, greset.d32); + do { + greset.d32 = dwc_read_reg32(DWC_REG_GRSTCTL); + if (++count > 1000000) { + //DBG("%s() HANG! Soft Reset GRSTCTL=%0x\n", dwc_otg_core_reset, greset.d32); + break; + } + } + while (greset.b.csftrst == 1); + + /* + * Wait for 3 PHY Clocks + */ + wait_ms(10); +} + +static void dwc_otg_enable_common_interrupts() +{ + gintmsk_data_t intr_mask = { 0}; + /* Clear any pending OTG Interrupts */ + dwc_write_reg32(DWC_REG_GOTGINT, 0xFFFFFFFF); + /* Clear any pending interrupts */ + dwc_write_reg32(DWC_REG_GINTSTS, 0xFFFFFFFF); + /* + * Enable the interrupts in the GINTMSK. + */ + intr_mask.b.modemismatch = 1; + intr_mask.b.otgintr = 1; + intr_mask.b.rxstsqlvl = 1; + intr_mask.b.conidstschng = 1; + intr_mask.b.wkupintr = 1; + intr_mask.b.disconnect = 1; + intr_mask.b.usbsuspend = 1; + intr_mask.b.sessreqintr = 1; + dwc_write_reg32(DWC_REG_GINTMSK, intr_mask.d32); +} + +/** + * This function enables the Device mode interrupts. + * + * @param _core_if Programming view of DWC_otg controller + */ +static void dwc_otg_enable_device_interrupts() +{ + gintmsk_data_t intr_mask = { 0}; + + /* Disable all interrupts. */ + dwc_write_reg32( DWC_REG_GINTMSK, 0); + + /* Clear any pending interrupts */ + dwc_write_reg32( DWC_REG_GINTSTS, 0xFFFFFFFF); + + /* Enable the common interrupts */ + dwc_otg_enable_common_interrupts( ); + + /* Enable interrupts */ + intr_mask.b.usbreset = 1; + intr_mask.b.enumdone = 1; + intr_mask.b.epmismatch = 1; + intr_mask.b.inepintr = 1; + intr_mask.b.outepintr = 1; + intr_mask.b.erlysuspend = 1; + + dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, intr_mask.d32); + +} +/** + * This function enables the controller's Global Interrupt in the AHB Config + * register. + * + * @param[in] _core_if Programming view of DWC_otg controller. + */ +static void dwc_otg_enable_global_interrupts( ) +{ + gahbcfg_data_t ahbcfg = { 0}; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + dwc_modify_reg32(DWC_REG_GAHBCFG, 0, ahbcfg.d32); +} + + +/** + * This function initializes the DWC_otg controller registers for + * device mode. + * + * @param _core_if Programming view of DWC_otg controller + * + */ +static void dwc_otg_core_dev_init(void) +{ + dcfg_data_t dcfg = { 0}; + grstctl_t resetctl = { 0 }; + int i; + fifosize_data_t nptxfifosize; + + /* Restart the Phy Clock */ + dwc_write_reg32(DWC_REG_PCGCCTL, 0); + + /* Device configuration register */ + dcfg.d32 = dwc_read_reg32(DWC_REG_DCFG); +#ifdef USE_FULL_SPEED + dcfg.b.devspd = 1;//Hi speed phy run at Full speed +#else + dcfg.b.devspd = 0; +#endif + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80; + dwc_write_reg32(DWC_REG_DCFG, dcfg.d32); + + /* Configure data FIFO sizes */ + + /* Rx FIFO */ + dwc_write_reg32(DWC_REG_GRXFSIZ, 256 ); + //DBG("new grxfsiz=%08x\n",dwc_read_reg32(DWC_REG_GRXFSIZ)); + + /* Non-periodic Tx FIFO */ + nptxfifosize.b.depth = 256; + nptxfifosize.b.startaddr = 256; + dwc_write_reg32(DWC_REG_GNPTXFSIZ, nptxfifosize.d32 ); + //DBG("new gnptxfsiz=%08x\n",dwc_read_reg32(DWC_REG_GNPTXFSIZ)); + + /* Flush the FIFOs */ + dwc_otg_flush_tx_fifo( 0x10); /* all Tx FIFOs */ + dwc_otg_flush_rx_fifo(); + + /* Flush the Learning Queue. */ + resetctl.b.intknqflsh = 1; + dwc_write_reg32( DWC_REG_GRSTCTL, resetctl.d32); + + /* Clear all pending Device Interrupts */ + dwc_write_reg32( DWC_REG_DIEPMSK, 0 ); + dwc_write_reg32( DWC_REG_DOEPMSK, 0 ); + dwc_write_reg32( DWC_REG_DAINT, 0xFFFFFFFF ); + dwc_write_reg32( DWC_REG_DAINTMSK, 0 ); + + for (i=0; i < NUM_EP; i++) { + depctl_data_t depctl; + depctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(i)); + if (depctl.b.epena) { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } else { + depctl.d32 = 0; + } + dwc_write_reg32( DWC_REG_IN_EP_REG(i),depctl.d32); + + depctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(i)); + if (depctl.b.epena) { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } else { + depctl.d32 = 0; + } + dwc_write_reg32( DWC_REG_OUT_EP_REG(i), depctl.d32); + + /* Device IN/OUT Endpoint Transfer Size */ + dwc_write_reg32(DWC_REG_IN_EP_TSIZE(i), 0); + dwc_write_reg32(DWC_REG_OUT_EP_TSIZE(i), 0); + /* Device IN/OUT Endpoint DMA Address Register */ + dwc_write_reg32( DWC_REG_IN_EP_DMA(i), 0); + dwc_write_reg32( DWC_REG_OUT_EP_DMA(i), 0); + /* Device IN/OUT Endpoint Interrupt Register */ + //dwc_write_reg32( DWC_REG_IN_EP_DMA(i), 0xFF); + //dwc_write_reg32( DWC_REG_OUT_EP_INTR(i), 0xFF); + } + + //d wc_otg_set_vbus_power(_core_if, 0); //Power off VBus + + dwc_otg_enable_device_interrupts(); + + DBG("init gintmsk: 0x%x\n",dwc_read_reg32(DWC_REG_GINTMSK)); +} +/** + * Flush a Tx FIFO. + * + * @param _core_if Programming view of DWC_otg controller. + * @param _num Tx FIFO to flush. + */ +static void dwc_otg_flush_tx_fifo( const int _num ) //Elvis Fool, add 'static' +{ + grstctl_t greset = { 0}; + int count = 0; + + + DBG("dwc_otg_flush_tx_fifo: %d\n",_num); + greset.b.txfflsh = 1; + greset.b.txfnum = _num; + dwc_write_reg32(DWC_REG_GRSTCTL, greset.d32 ); + + do { + greset.d32 = dwc_read_reg32( DWC_REG_GRSTCTL); + if (++count > 10000) { + // ERR("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", + // "dwc_otg_flush_tx_fifo", greset.d32, + // dwc_read_reg32( DWC_REG_GNPTXSTS)); + break; + } + + } while (greset.b.txfflsh == 1); + /* Wait for 3 PHY Clocks*/ + udelay(1); +} + +/** + * Flush Rx FIFO. + * + * @param _core_if Programming view of DWC_otg controller. + */ +static void dwc_otg_flush_rx_fifo( ) +{ + grstctl_t greset = { 0}; + int count = 0; + + DBG("dwc_otg_flush_rx_fifo\n"); + greset.b.rxfflsh = 1; + dwc_write_reg32( DWC_REG_GRSTCTL, greset.d32 ); + + do { + greset.d32 = dwc_read_reg32( DWC_REG_GRSTCTL); + if (++count > 10000) { + //ERR("%s() HANG! GRSTCTL=%0x\n", "dwc_otg_flush_rx_fifo", + // greset.d32); + break; + } + } while (greset.b.rxfflsh == 1); + /* Wait for 3 PHY Clocks*/ + udelay(1); +} +/** + * This function does the setup for a data transfer for EP0 and starts + * the transfer. For an IN transfer, the packets will be loaded into + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are + * unloaded from the Rx FIFO in the ISR. + * + * @param _core_if Programming view of DWC_otg controller. + * @param _ep The EP0 data. + */ + #if 0 +void dwc_otg_ep0_start_transfer(dwc_ep_t *_ep) +{ + depctl_data_t depctl; + deptsiz0_data_t deptsiz; + gintmsk_data_t intr_mask = { 0}; + + _ep->total_len = _ep->xfer_len; + + //DBG("dwc_otg_ep0_start_transfer: xfer_len:%d\n",_ep->xfer_len); + /* IN endpoint */ + if (_ep->is_in == 1) { + gnptxsts_data_t tx_status = { 0}; + + tx_status.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS); + if (tx_status.b.nptxqspcavail == 0) { + return; + } + + depctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(0)); + deptsiz.d32 = dwc_read_reg32(DWC_REG_IN_EP_TSIZE(0)); + + /* Zero Length Packet? */ + if (_ep->xfer_len == 0) { + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 1; + } else { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + if (_ep->xfer_len > _ep->maxpacket) { + _ep->xfer_len = _ep->maxpacket; + deptsiz.b.xfersize = _ep->maxpacket; + } + else { + deptsiz.b.xfersize = _ep->xfer_len; + } + deptsiz.b.pktcnt = 1; + + } + dwc_write_reg32(DWC_REG_IN_EP_TSIZE(0), deptsiz.d32); + //DBG( "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", + // _ep->xfer_len,deptsiz.b.xfersize, deptsiz.b.pktcnt, deptsiz.d32); + + + flush_cpu_cache(); + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(DWC_REG_IN_EP_REG(0), depctl.d32); + + /** + * Enable the Non-Periodic Tx FIFO empty interrupt, the + * data will be written into the fifo by the ISR. + */ + + /* First clear it from GINTSTS */ + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32( DWC_REG_GINTSTS,intr_mask.d32, 0); + dwc_modify_reg32( DWC_REG_GINTMSK,intr_mask.d32, intr_mask.d32); + + + } else { /* OUT endpoint */ + + depctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0)); + deptsiz.d32 = dwc_read_reg32(DWC_REG_OUT_EP_TSIZE(0)); + + /* Program the transfer size and packet count as follows: + * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) + * pktcnt = N */ +#if 0 + if (_ep->xfer_len == 0) { + /* Zero Length Packet */ + deptsiz.b.xfersize = _ep->maxpacket; + deptsiz.b.pktcnt = 1; + } else { + deptsiz.b.pktcnt = + (_ep->xfer_len + (_ep->maxpacket - 1)) /_ep->maxpacket; + deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; + } +#else // ep0 pktcnt is 1 bit + + deptsiz.b.xfersize = _ep->maxpacket; + deptsiz.b.pktcnt = 1; + udelay(1); // This is needed, don't know reason. +#endif + + + dwc_write_reg32(DWC_REG_OUT_EP_TSIZE(0), deptsiz.d32); + //DBG( "OUT len=%d xfersize=%d pktcnt=%d\n", + // _ep->xfer_len,deptsiz.b.xfersize, deptsiz.b.pktcnt); + + + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32 (DWC_REG_OUT_EP_REG(0), depctl.d32); + } + + flush_cpu_cache(); +} + #endif + +void dwc_otg_ep_start_transfer(dwc_ep_t *_ep) +{ + depctl_data_t depctl; + deptsiz_data_t deptsiz; + int epctl_reg,epctltsize_reg; + int ep_num = _ep->num; + int is_in = _ep->is_in; + int ep_mps = _ep->maxpacket; + + //DBG("dwc_otg_ep_start_transfer: xfer_len:%d\n",_ep->xfer_len); + + _ep->total_len = _ep->xfer_len; + + if (is_in) { + epctl_reg = DWC_REG_IN_EP_REG(ep_num); + epctltsize_reg = DWC_REG_IN_EP_TSIZE(ep_num); + }else{ + epctl_reg = DWC_REG_OUT_EP_REG(ep_num); + epctltsize_reg = DWC_REG_OUT_EP_TSIZE(ep_num); + } + + depctl.d32 = dwc_read_reg32(epctl_reg); + deptsiz.d32 = dwc_read_reg32(epctltsize_reg); + + /* Zero Length Packet? */ + if (_ep->xfer_len == 0) { + deptsiz.b.xfersize = is_in?0:ep_mps; + deptsiz.b.pktcnt = 1; + } + else { + deptsiz.b.pktcnt = (_ep->xfer_len + (ep_mps - 1)) /ep_mps; + if (is_in && _ep->xfer_len < ep_mps) + deptsiz.b.xfersize = _ep->xfer_len; + else + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep_mps; + /*deptsiz.b.xfersize = _ep->xfer_len - _ep->xfer_count;////////victor fixed*/ + } + + /* Fill size and count */ + dwc_write_reg32(epctltsize_reg,deptsiz.d32); + + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32 (epctl_reg, depctl.d32); + + /* IN endpoint */ + if (is_in) { + gintmsk_data_t intr_mask = {0}; + //gnptxsts_data_t tx_status = { 0}; + + //tx_status.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS); + //if (tx_status.b.nptxqspcavail == 0){ + // return; + //} + + /** + * Enable the Non-Periodic Tx FIFO empty interrupt, the + * data will be written into the fifo by the ISR. + */ + + /* First clear it from GINTSTS */ + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32( DWC_REG_GINTSTS,intr_mask.d32, 0); + dwc_modify_reg32( DWC_REG_GINTMSK,intr_mask.d32, intr_mask.d32); + + } + +} + +int dwc_otg_ep_req_start(pcd_struct_t *pcd,int ep_num) +{ + dwc_ep_t *ep = &g_dwc_eps[ep_num]; + + ep->num = ep_num; + //DBG("dwc_otg_ep_req_start: ep%d\n",ep_num); + /* EP0 Transfer? */ + if (ep_num == 0) + { + //DBG("EP0 State: %d\n",pcd->ep0state); + switch (pcd->ep0state) + { + case EP0_IN_DATA_PHASE: + break; + + case EP0_OUT_DATA_PHASE: + if (pcd->request_config) { + /* Work around for SetConfig cmd */ + /* Complete STATUS PHASE */ + ep->is_in = 1; + pcd->ep0state = EP0_STATUS; + } + else if(pcd->length == 0) + { + /* Work around for MSC Reset cmd */ + /* Complete STATUS PHASE */ + ep->is_in = 1; + pcd->ep0state = EP0_STATUS; + } + break; + + default: + return -1; + } + + ep->start_xfer_buff = (uint8_t*)pcd->buf; + ep->xfer_buff = (uint8_t*)pcd->buf; + ep->xfer_len = pcd->length; + ep->xfer_count = 0; + ep->sent_zlp = 0; + ep->total_len = ep->xfer_len; + ep->maxpacket = 64; + dwc_otg_ep_start_transfer( ep ); + + } + else { + /* Setup and start the Transfer for Bulk */ + ep->start_xfer_buff = (uint8_t*)pcd->bulk_buf + pcd->bulk_xfer_len; + ep->xfer_buff = (uint8_t*)pcd->bulk_buf + pcd->bulk_xfer_len; + ep->xfer_len = pcd->bulk_len; + /*ep->xfer_len = MIN(pcd->bulk_data_len , pcd->bulk_len);////Victor fixed!!*/ + ep->xfer_count = 0; + ep->sent_zlp = 0; + ep->total_len = ep->xfer_len; + ep->maxpacket = BULK_EP_MPS; + ep->is_in = (ep_num == BULK_IN_EP_NUM); + //tranfer failed here after printf here + + dwc_otg_bulk_ep_activate( ep ); + /*printf("start_xfer_buf=0x%x, xfer_buf=0x%x, xfer_len 0x%x\n", ep->start_xfer_buff, ep->xfer_buff, ep->xfer_len);*/ + dwc_otg_ep_start_transfer( ep ); + } + + return 0; + +} + +static void dwc_otg_bulk_ep_activate(dwc_ep_t *ep) +{ + depctl_data_t depctl = {0}; + daint_data_t daintmsk = {0}; + int epctl; + int ep_num = ep->num; + + if (ep->is_in) { + epctl = DWC_REG_IN_EP_REG(ep_num); + daintmsk.ep.in = 1<<BULK_IN_EP_NUM; //ep1:BULK_IN + } + else{ + epctl = DWC_REG_OUT_EP_REG(ep_num); + daintmsk.ep.out = 1<<BULK_OUT_EP_NUM;//ep2:BULK_OUT + } + + depctl.d32 = dwc_read_reg32(epctl); + if (!depctl.b.usbactep) { + depctl.b.mps = BULK_EP_MPS; + depctl.b.eptype = 2;//BULK_STYLE + depctl.b.setd0pid = 1; + depctl.b.txfnum = 0; //Non-Periodic TxFIFO + depctl.b.usbactep = 1; + + dwc_write_reg32(epctl, depctl.d32); + } + + dwc_modify_reg32(DWC_REG_DAINTMSK, 0, daintmsk.d32); + + return; +} + +int dwc_otg_bulk_ep_enable(int is_in) +{ + depctl_data_t depctl = {0}; + daint_data_t daintmsk = {0}; + int epctl; + const int ep_num = is_in ? BULK_IN_EP_NUM : BULK_OUT_EP_NUM; + + if (is_in) { + epctl = DWC_REG_IN_EP_REG(ep_num); + daintmsk.ep.in = 1<<BULK_IN_EP_NUM; //ep1:BULK_IN + } + else{ + epctl = DWC_REG_OUT_EP_REG(ep_num); + daintmsk.ep.out = 1<<BULK_OUT_EP_NUM;//ep2:BULK_OUT + } + + depctl.d32 = dwc_read_reg32(epctl); + if (!depctl.b.usbactep) { + depctl.b.mps = BULK_EP_MPS; + depctl.b.eptype = 2;//BULK_STYLE + depctl.b.setd0pid = 1; + depctl.b.txfnum = 0; //Non-Periodic TxFIFO + depctl.b.usbactep = 1; + + dwc_write_reg32(epctl, depctl.d32); + } + + dwc_modify_reg32(DWC_REG_DAINTMSK, 0, daintmsk.d32); + + return 0; +} + +void dwc_otg_power_off_phy(void) +{ + dwc_write_reg32(DWC_REG_PCGCCTL, 0xF); +} diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd.h b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd.h new file mode 100644 index 0000000000..5b7a69eca5 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd.h @@ -0,0 +1,2079 @@ +/* dwc controller pcd drivers header */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-24 @ Shanghai + * From synopsys head file + */ + +#ifndef __DWC_PCD_H__ +#define __DWC_PCD_H__ + +//#define USE_FULL_SPEED + +#define NUM_EP 4 + +#define BULK_IN_EP_NUM 1 +#define BULK_OUT_EP_NUM 2 + +#ifdef USE_FULL_SPEED +#define BULK_EP_MPS (64) //only for full speed +#else +#define BULK_EP_MPS (512) +#endif + +#define DWC_REG_GOTGCTL 0x000 /** OTG Control and Status Register. <i>Offset: 000h</i> */ +#define DWC_REG_GOTGINT 0x004 /** OTG Interrupt Register. <i>Offset: 004h</i> */ +#define DWC_REG_GAHBCFG 0x008 /**Core AHB Configuration Register. <i>Offset: 008h</i> */ +#define DWC_REG_GUSBCFG 0x00C /**Core USB Configuration Register. <i>Offset: 00Ch</i> */ +#define DWC_REG_GRSTCTL 0x010 /**Core Reset Register. <i>Offset: 010h</i> */ +#define DWC_REG_GINTSTS 0x014 /**Core Interrupt Register. <i>Offset: 014h</i> */ +#define DWC_REG_GINTMSK 0x018 /**Core Interrupt Mask Register. <i>Offset: 018h</i> */ +#define DWC_REG_GRXSTSR 0x01C /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */ +#define DWC_REG_GRXSTSP 0x020 /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/ +#define DWC_REG_GRXFSIZ 0x024 /**Receive FIFO Size Register. <i>Offset: 024h</i> */ +#define DWC_REG_GNPTXFSIZ 0x028 /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */ +#define DWC_REG_GNPTXSTS 0x02C /**Non Periodic Transmit FIFO/Queue Status Register (Read * Only). <i>Offset: 02Ch</i> */ +#define DWC_REG_GI2CCTL 0x030 /**I2C Access Register. <i>Offset: 030h</i> */ +#define DWC_REG_GPVNDCTL 0x034 /**PHY Vendor Control Register. <i>Offset: 034h</i> */ +#define DWC_REG_GGPIO 0x038 /**General Purpose Input/Output Register. <i>Offset: 038h</i> */ +#define DWC_REG_GUID 0x03C /**User ID Register. <i>Offset: 03Ch</i> */ +#define DWC_REG_GSNPSID 0x040 /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */ +#define DWC_REG_GHWCFG1 0x044 /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */ +#define DWC_REG_GHWCFG2 0x048 /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */ +#define DWC_REG_GHWCFG3 0x04C /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */ +#define DWC_REG_GHWCFG4 0x050 /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/ +#define DWC_REG_HPTXFSIZ 0x100 /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */ + +/** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, + otherwise Device Transmit FIFO#n Register. + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */ +#define DWC_REG_DPTXFSIZ_DIEPTXF 0x104 + +#define DWC_REG_DCFG 0x800 /** Device Configuration Register. <i>Offset 800h</i> */ +#define DWC_REG_DCTL 0x804 /** Device Control Register. <i>Offset: 804h</i> */ +#define DWC_REG_DSTS 0x808 /** Device Status Register (Read Only). <i>Offset: 808h</i> */ +#define DWC_REG_DIEPMSK 0x810 /** Device IN Endpoint Common Interrupt Mask Register. <i>Offset: 810h</i> */ +#define DWC_REG_DOEPMSK 0x814 /** Device OUT Endpoint Common Interrupt Mask Register. <i>Offset: 814h</i> */ +#define DWC_REG_DAINT 0x818 /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */ +#define DWC_REG_DAINTMSK 0x81C /** Device All Endpoints Interrupt Mask Register. <i>Offset: 81Ch</i> */ +#define DWC_REG_DTKNQR1 0x820 /** Device IN Token Queue Read Register-1 (Read Only). <i>Offset: 820h</i> */ +#define DWC_REG_DTKNQR2 0x824 /** Device IN Token Queue Read Register-2 (Read Only). <i>Offset: 824h</i> */ +#define DWC_REG_DVBUGDIS 0x828 /** Device VBUS discharge Register. <i>Offset: 828h</i> */ +#define DWC_REG_DVBUSPULSE 0x82C /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */ +#define DWC_REG_DTKNQR3 0x830 + /** Device IN Token Queue Read Register-3 (Read Only). / + * Device Thresholding control register (Read/Write) + * <i>Offset: 830h</i> */ +#define DWC_REG_DTKNQR4 0x834 + /** Device IN Token Queue Read Register-4 (Read Only). / + * Device IN EPs empty Inr. Mask Register (Read/Write) + * <i>Offset: 834h</i> */ +#define DWC_REG_PCGCCTL 0xE00 /** Power and Clock Gating Control Register */ + +#define DWC_EP_REGS_OFFSET 0x00 +#define DWC_EP_INTR_OFFSET 0x08 +#define DWC_EP_TSIZE_OFFSET 0x10 +#define DWC_EP_DMA_OFFSET 0x14 + +#define DWC_IN_EP_REG_START 0x900 +#define DWC_OUT_EP_REG_START 0xB00 + +#define DWC_REG_IN_EP_REG(x) (DWC_IN_EP_REG_START + x*0x20 + DWC_EP_REGS_OFFSET) +#define DWC_REG_IN_EP_INTR(x) (DWC_IN_EP_REG_START + x*0x20 + DWC_EP_INTR_OFFSET) +#define DWC_REG_IN_EP_TSIZE(x) (DWC_IN_EP_REG_START + x*0x20 + DWC_EP_TSIZE_OFFSET) +#define DWC_REG_IN_EP_DMA(x) (DWC_IN_EP_REG_START + x*0x20 + DWC_EP_DMA_OFFSET) + +#define DWC_REG_OUT_EP_REG(x) (DWC_OUT_EP_REG_START + x*0x20 + DWC_EP_REGS_OFFSET) +#define DWC_REG_OUT_EP_INTR(x) (DWC_OUT_EP_REG_START + x*0x20 + DWC_EP_INTR_OFFSET) +#define DWC_REG_OUT_EP_TSIZE(x) (DWC_OUT_EP_REG_START + x*0x20 + DWC_EP_TSIZE_OFFSET) +#define DWC_REG_OUT_EP_DMA(x) (DWC_OUT_EP_REG_START + x*0x20 + DWC_EP_DMA_OFFSET) + + +#define DWC_REG_DATA_FIFO_START 0x1000 +#define DWC_REG_DATA_FIFO(ep) (DWC_REG_DATA_FIFO_START + ep * 0x1000) + +/** + * The <code>dwc_ep</code> structure represents the state of a single + * endpoint when acting in device mode. It contains the data items + * needed for an endpoint to be activated and transfer packets. + */ +typedef struct dwc_ep { + /** EP number used for register address lookup */ + uint8_t num; + /** EP direction 0 = OUT */ + unsigned is_in : 1; + /** EP active. */ + unsigned active : 1; + + unsigned stopped : 1; + unsigned disabling : 1; + + /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO */ + unsigned tx_fifo_num : 4; + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */ + unsigned type : 2; +#define DWC_OTG_EP_TYPE_CONTROL 0 +#define DWC_OTG_EP_TYPE_ISOC 1 +#define DWC_OTG_EP_TYPE_BULK 2 +#define DWC_OTG_EP_TYPE_INTR 3 + + /** DATA start PID for INTR and BULK EP */ + unsigned data_pid_start : 1; + /** Frame (even/odd) for ISOC EP */ + unsigned even_odd_frame : 1; + /** Max Packet bytes */ + unsigned maxpacket : 11; + + /** @name Transfer state */ + /** @{ */ + + /** + * Pointer to the beginning of the transfer buffer -- do not modify + * during transfer. + */ + + uint32_t dma_addr; + + uint8_t *start_xfer_buff; + /** pointer to the transfer buffer */ + uint8_t *xfer_buff; + /** Number of bytes to transfer */ + unsigned xfer_len : 19; + /** Number of bytes transferred. */ + unsigned xfer_count : 19; + /** Sent ZLP */ + unsigned sent_zlp : 1; + /** Total len for control transfer */ + unsigned total_len : 19; + + /** @} */ +} dwc_ep_t; + +typedef struct pcd_struct_s{ + /** SETUP packet for EP0 + * This structure is allocated as a DMA buffer on PCD initialization + * with enough space for up to 3 setup packets. + */ + union { + struct usb_ctrlrequest req; + uint32_t d32[2]; + }setup_pkt; + int ep0state; + + /* for USB_REQ_GET_STATUS */ + unsigned status; + + struct { + u8 type;//1-->setup+out+in, others: reseved + u8 setup_complete; + u8 out_complete; + u8 in_complete; + }cmdtype; + + /* request */ + volatile char * buf; + + int length; + + /* bulk req */ + char * bulk_buf; + int bulk_len; // one bulk transfer length + int bulk_num; // number of bulk transfer + int bulk_data_len;// data len of all data + int xfer_len; + char bulk_out; // flag + char bulk_lock; // bulk transfering + //short bulk_seq; + + short isPktResended;//is this 64K transfer is re-send + int bulk_xfer_len;//data len already transferred //added by Sam.Wu + unsigned origiSum;//data checksum in every 64K transfer //added by Sam.Wu + unsigned sequenceNo; + int xferNeedReply; + + unsigned request_config : 1; + unsigned request_enable : 1; + unsigned request_reserv : 30; + +}pcd_struct_t; + +extern pcd_struct_t this_pcd; +extern dwc_ep_t g_dwc_eps[NUM_EP]; + +/** + * @file + * + * This file contains the data structures for accessing the DWC_otg core registers. + * + * The application interfaces with the HS OTG core by reading from and + * writing to the Control and Status Register (CSR) space through the + * AHB Slave interface. These registers are 32 bits wide, and the + * addresses are 32-bit-block aligned. + * CSRs are classified as follows: + * - Core Global Registers + * - Device Mode Registers + * - Device Global Registers + * - Device Endpoint Specific Registers + * - Host Mode Registers + * - Host Global Registers + * - Host Port CSRs + * - Host Channel Specific Registers + * + * Only the Core Global registers can be accessed in both Device and + * Host modes. When the HS OTG core is operating in one mode, either + * Device or Host, the application must not access registers from the + * other mode. When the core switches from one mode to another, the + * registers in the new mode of operation must be reprogrammed as they + * would be after a power-on reset. + */ + +/****************************************************************************/ +/** DWC_otg Core registers . + * The dwc_otg_core_global_regs structure defines the size + * and relative field offsets for the Core Global registers. + */ +typedef struct dwc_otg_core_global_regs +{ + /** OTG Control and Status Register. <i>Offset: 000h</i> */ + volatile uint32_t gotgctl; + /** OTG Interrupt Register. <i>Offset: 004h</i> */ + volatile uint32_t gotgint; + /**Core AHB Configuration Register. <i>Offset: 008h</i> */ + volatile uint32_t gahbcfg; + +#define DWC_GLBINTRMASK 0x0001 +#define DWC_DMAENABLE 0x0020 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 + + /**Core USB Configuration Register. <i>Offset: 00Ch</i> */ + volatile uint32_t gusbcfg; + /**Core Reset Register. <i>Offset: 010h</i> */ + volatile uint32_t grstctl; + /**Core Interrupt Register. <i>Offset: 014h</i> */ + volatile uint32_t gintsts; + /**Core Interrupt Mask Register. <i>Offset: 018h</i> */ + volatile uint32_t gintmsk; + /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */ + volatile uint32_t grxstsr; + /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/ + volatile uint32_t grxstsp; + /**Receive FIFO Size Register. <i>Offset: 024h</i> */ + volatile uint32_t grxfsiz; + /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */ + volatile uint32_t gnptxfsiz; + /**Non Periodic Transmit FIFO/Queue Status Register (Read + * Only). <i>Offset: 02Ch</i> */ + volatile uint32_t gnptxsts; + /**I2C Access Register. <i>Offset: 030h</i> */ + volatile uint32_t gi2cctl; + /**PHY Vendor Control Register. <i>Offset: 034h</i> */ + volatile uint32_t gpvndctl; + /**General Purpose Input/Output Register. <i>Offset: 038h</i> */ + volatile uint32_t ggpio; + /**User ID Register. <i>Offset: 03Ch</i> */ + volatile uint32_t guid; + /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */ + volatile uint32_t gsnpsid; + /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */ + volatile uint32_t ghwcfg1; + /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */ + volatile uint32_t ghwcfg2; +#define DWC_SLAVE_ONLY_ARCH 0 +#define DWC_EXT_DMA_ARCH 1 +#define DWC_INT_DMA_ARCH 2 + +#define DWC_MODE_HNP_SRP_CAPABLE 0 +#define DWC_MODE_SRP_ONLY_CAPABLE 1 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_MODE_SRP_CAPABLE_HOST 5 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 + + /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */ + volatile uint32_t ghwcfg3; + /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/ + volatile uint32_t ghwcfg4; + /** Core LPM Configuration register <i>Offset: 054h</i>*/ + volatile uint32_t glpmcfg; + /** Global PowerDn Register <i>Offset: 058h</i> */ + volatile uint32_t gpwrdn; + /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */ + volatile uint32_t gdfifocfg; + /** ADP Control Register <i>Offset: 060h</i> */ + volatile uint32_t adpctl; + /** Reserved <i>Offset: 064h-0FFh</i> */ + volatile uint32_t reserved39[39]; + /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */ + volatile uint32_t hptxfsiz; + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, + otherwise Device Transmit FIFO#n Register. + * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */ + volatile uint32_t dptxfsiz_dieptxf[15]; +} dwc_otg_core_global_regs_t; + +/** + * This union represents the bit fields of the Core OTG Control + * and Status Register (GOTGCTL). Set the bits using the bit + * fields then write the <i>d32</i> value to the register. + */ +typedef union gotgctl_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned sesreqscs : 1; + unsigned sesreq : 1; + unsigned reserved2_7 : 6; + unsigned hstnegscs : 1; + unsigned hnpreq : 1; + unsigned hstsethnpen : 1; + unsigned devhnpen : 1; + unsigned reserved12_15 : 4; + unsigned conidsts : 1; + unsigned reserved17 : 1; + unsigned asesvld : 1; + unsigned bsesvld : 1; + unsigned currmod : 1; + unsigned reserved21_31 : 11; + } b; +} gotgctl_data_t; + +/** + * This union represents the bit fields of the Core OTG Interrupt Register + * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i> + * value to the register. + */ +typedef union gotgint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Current Mode */ + unsigned reserved0_1 : 2; + + /** Session End Detected */ + unsigned sesenddet : 1; + + unsigned reserved3_7 : 5; + + /** Session Request Success Status Change */ + unsigned sesreqsucstschng : 1; + /** Host Negotiation Success Status Change */ + unsigned hstnegsucstschng : 1; + + unsigned reserver10_16 : 7; + + /** Host Negotiation Detected */ + unsigned hstnegdet : 1; + /** A-Device Timeout Change */ + unsigned adevtoutchng : 1; + /** Debounce Done */ + unsigned debdone : 1; + + unsigned reserved31_20 : 12; + + } b; +} gotgint_data_t; + + +/** + * This union represents the bit fields of the Core AHB Configuration + * Register (GAHBCFG). Set/clear the bits using the bit fields then + * write the <i>d32</i> value to the register. + */ +typedef union gahbcfg_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned glblintrmsk : 1; +#define DWC_GAHBCFG_GLBINT_ENABLE 1 + + unsigned hburstlen : 4; +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 + + unsigned dmaenable : 1; +#define DWC_GAHBCFG_DMAENABLE 1 + unsigned reserved : 1; + unsigned nptxfemplvl_txfemplvl : 1; + unsigned ptxfemplvl : 1; +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 + unsigned reserved9_31 : 23; + } b; +} gahbcfg_data_t; + +/** + * This union represents the bit fields of the Core USB Configuration + * Register (GUSBCFG). Set the bits using the bit fields then write + * the <i>d32</i> value to the register. + */ +typedef union gusbcfg_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned toutcal : 3; + unsigned phyif : 1; + unsigned ulpi_utmi_sel : 1; + unsigned fsintf : 1; + unsigned physel : 1; + unsigned ddrsel : 1; + unsigned srpcap : 1; + unsigned hnpcap : 1; + unsigned usbtrdtim : 4; + unsigned nptxfrwnden : 1; + unsigned phylpwrclksel : 1; + unsigned otgutmifssel : 1; + unsigned ulpi_fsls : 1; + unsigned ulpi_auto_res : 1; + unsigned ulpi_clk_sus_m : 1; + unsigned ulpi_ext_vbus_drv : 1; + unsigned ulpi_int_vbus_indicator : 1; + unsigned term_sel_dl_pulse : 1; + unsigned reserved : 9; + } b; +} gusbcfg_data_t; + +/** + * This union represents the bit fields of the Core Reset Register + * (GRSTCTL). Set/clear the bits using the bit fields then write the + * <i>d32</i> value to the register. + */ +typedef union grstctl_data +{ + /** raw register data */ + unsigned int d32; + /** register bits */ + struct + { + /** Core Soft Reset (CSftRst) (Device and Host) + * + * The application can flush the control logic in the + * entire core using this bit. This bit resets the + * pipelines in the AHB Clock domain as well as the + * PHY Clock domain. + * + * The state machines are reset to an IDLE state, the + * control bits in the CSRs are cleared, all the + * transmit FIFOs and the receive FIFO are flushed. + * + * The status mask bits that control the generation of + * the interrupt, are cleared, to clear the + * interrupt. The interrupt status bits are not + * cleared, so the application can get the status of + * any events that occurred in the core after it has + * set this bit. + * + * Any transactions on the AHB are terminated as soon + * as possible following the protocol. Any + * transactions on the USB are terminated immediately. + * + * The configuration settings in the CSRs are + * unchanged, so the software doesn't have to + * reprogram these registers (Device + * Configuration/Host Configuration/Core System + * Configuration/Core PHY Configuration). + * + * The application can write to this bit, any time it + * wants to reset the core. This is a self clearing + * bit and the core clears this bit after all the + * necessary logic is reset in the core, which may + * take several clocks, depending on the current state + * of the core. + */ + unsigned csftrst : 1; + /** Hclk Soft Reset + * + * The application uses this bit to reset the control logic in + * the AHB clock domain. Only AHB clock domain pipelines are + * reset. + */ + unsigned hsftrst : 1; + /** Host Frame Counter Reset (Host Only)<br> + * + * The application can reset the (micro)frame number + * counter inside the core, using this bit. When the + * (micro)frame counter is reset, the subsequent SOF + * sent out by the core, will have a (micro)frame + * number of 0. + */ + unsigned hstfrm : 1; + /** In Token Sequence Learning Queue Flush + * (INTknQFlsh) (Device Only) + */ + unsigned intknqflsh : 1; + /** RxFIFO Flush (RxFFlsh) (Device and Host) + * + * The application can flush the entire Receive FIFO + * using this bit. <p>The application must first + * ensure that the core is not in the middle of a + * transaction. <p>The application should write into + * this bit, only after making sure that neither the + * DMA engine is reading from the RxFIFO nor the MAC + * is writing the data in to the FIFO. <p>The + * application should wait until the bit is cleared + * before performing any other operations. This bit + * will takes 8 clocks (slowest of PHY or AHB clock) + * to clear. + */ + unsigned rxfflsh : 1; + /** TxFIFO Flush (TxFFlsh) (Device and Host). + * + * This bit is used to selectively flush a single or + * all transmit FIFOs. The application must first + * ensure that the core is not in the middle of a + * transaction. <p>The application should write into + * this bit, only after making sure that neither the + * DMA engine is writing into the TxFIFO nor the MAC + * is reading the data out of the FIFO. <p>The + * application should wait until the core clears this + * bit, before performing any operations. This bit + * will takes 8 clocks (slowest of PHY or AHB clock) + * to clear. + */ + unsigned txfflsh : 1; + + /** TxFIFO Number (TxFNum) (Device and Host). + * + * This is the FIFO number which needs to be flushed, + * using the TxFIFO Flush bit. This field should not + * be changed until the TxFIFO Flush bit is cleared by + * the core. + * - 0x0 : Non Periodic TxFIFO Flush + * - 0x1 : Periodic TxFIFO #1 Flush in device mode + * or Periodic TxFIFO in host mode + * - 0x2 : Periodic TxFIFO #2 Flush in device mode. + * - ... + * - 0xF : Periodic TxFIFO #15 Flush in device mode + * - 0x10: Flush all the Transmit NonPeriodic and + * Transmit Periodic FIFOs in the core + */ + unsigned txfnum : 5; + /** Reserved */ + unsigned reserved11_29 : 19; + /** DMA Request Signal. Indicated DMA request is in + * probress. Used for debug purpose. */ + unsigned dmareq : 1; + /** AHB Master Idle. Indicates the AHB Master State + * Machine is in IDLE condition. */ + unsigned ahbidle : 1; + } b; +} grstctl_t; + + +/** + * This union represents the bit fields of the Core Interrupt Mask + * Register (GINTMSK). Set/clear the bits using the bit fields then + * write the <i>d32</i> value to the register. + */ +typedef union gintmsk_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned reserved0 : 1; + unsigned modemismatch : 1; + unsigned otgintr : 1; + unsigned sofintr : 1; + unsigned rxstsqlvl : 1; + unsigned nptxfempty : 1; + unsigned ginnakeff : 1; + unsigned goutnakeff : 1; + unsigned reserved8 : 1; + unsigned i2cintr : 1; + unsigned erlysuspend : 1; + unsigned usbsuspend : 1; + unsigned usbreset : 1; + unsigned enumdone : 1; + unsigned isooutdrop : 1; + unsigned eopframe : 1; + unsigned reserved16 : 1; + unsigned epmismatch : 1; + unsigned inepintr : 1; + unsigned outepintr : 1; + unsigned incomplisoin : 1; + unsigned incomplisoout : 1; + unsigned reserved22_23 : 2; + unsigned portintr : 1; + unsigned hcintr : 1; + unsigned ptxfempty : 1; + unsigned reserved27 : 1; + unsigned conidstschng : 1; + unsigned disconnect : 1; + unsigned sessreqintr : 1; + unsigned wkupintr : 1; + } b; +} gintmsk_data_t; +/** + * This union represents the bit fields of the Core Interrupt Register + * (GINTSTS). Set/clear the bits using the bit fields then write the + * <i>d32</i> value to the register. + */ +typedef union gintsts_data +{ + /** raw register data */ + uint32_t d32; +#define DWC_SOF_INTR_MASK 0x0008 + /** register bits */ + struct + { +#define DWC_HOST_MODE 1 + unsigned curmode : 1; + unsigned modemismatch : 1; + unsigned otgintr : 1; + unsigned sofintr : 1; + unsigned rxstsqlvl : 1; + unsigned nptxfempty : 1; + unsigned ginnakeff : 1; + unsigned goutnakeff : 1; + unsigned reserved8 : 1; + unsigned i2cintr : 1; + unsigned erlysuspend : 1; + unsigned usbsuspend : 1; + unsigned usbreset : 1; + unsigned enumdone : 1; + unsigned isooutdrop : 1; + unsigned eopframe : 1; + unsigned intokenrx : 1; + unsigned epmismatch : 1; + unsigned inepint: 1; + unsigned outepintr : 1; + unsigned incomplisoin : 1; + unsigned incomplisoout : 1; + unsigned reserved22_23 : 2; + unsigned portintr : 1; + unsigned hcintr : 1; + unsigned ptxfempty : 1; + unsigned reserved27 : 1; + unsigned conidstschng : 1; + unsigned disconnect : 1; + unsigned sessreqintr : 1; + unsigned wkupintr : 1; + } b; +} gintsts_data_t; + + +/** + * This union represents the bit fields in the Device Receive Status Read and + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> + * element then read out the bits using the <i>b</i>it elements. + */ +typedef union device_grxsts_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned epnum : 4; + unsigned bcnt : 11; + unsigned dpid : 2; + +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete + +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet + unsigned pktsts : 4; + unsigned fn : 4; + unsigned reserved : 7; + } b; +} device_grxsts_data_t; + +/** + * This union represents the bit fields in the Host Receive Status Read and + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> + * element then read out the bits using the <i>b</i>it elements. + */ +typedef union host_grxsts_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned chnum : 4; + unsigned bcnt : 11; + unsigned dpid : 2; + + unsigned pktsts : 4; +#define DWC_GRXSTS_PKTSTS_IN 0x2 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 + + unsigned reserved : 11; + } b; +} host_grxsts_data_t; + +/** + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element then + * read out the bits using the <i>b</i>it elements. + */ +typedef union fifosize_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned startaddr : 16; + unsigned depth : 16; + } b; +} fifosize_data_t; + +/** + * This union represents the bit fields in the Non-Periodic Transmit + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the + * <i>d32</i> element then read out the bits using the <i>b</i>it + * elements. + */ +typedef union gnptxsts_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned nptxfspcavail : 16; + unsigned nptxqspcavail : 8; + /** Top of the Non-Periodic Transmit Request Queue + * - bit 24 - Terminate (Last entry for the selected + * channel/EP) + * - bits 26:25 - Token Type + * - 2'b00 - IN/OUT + * - 2'b01 - Zero Length OUT + * - 2'b10 - PING/Complete Split + * - 2'b11 - Channel Halt + * - bits 30:27 - Channel/EP Number + */ + unsigned nptxqtop_terminate : 1; + unsigned nptxqtop_token : 2; + unsigned nptxqtop_chnep : 4; + unsigned reserved : 1; + } b; +} gnptxsts_data_t; + +/** + * This union represents the bit fields in the Transmit + * FIFO Status Register (DTXFSTS). Read the register into the + * <i>d32</i> element then read out the bits using the <i>b</i>it + * elements. + */ +typedef union dtxfsts_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned txfspcavail : 16; + unsigned reserved : 16; + } b; +} dtxfsts_data_t; + +/** + * This union represents the bit fields in the I2C Control Register + * (I2CCTL). Read the register into the <i>d32</i> element then read out the + * bits using the <i>b</i>it elements. + */ +typedef union gi2cctl_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned rwdata : 8; + unsigned regaddr : 8; + unsigned addr : 7; + unsigned i2cen : 1; + unsigned ack : 1; + unsigned i2csuspctl : 1; + unsigned i2cdevaddr : 2; + unsigned reserved : 2; + unsigned rw : 1; + unsigned bsydne : 1; + } b; +} gi2cctl_data_t; + +/** + * This union represents the bit fields in the User HW Config1 + * Register. Read the register into the <i>d32</i> element then read + * out the bits using the <i>b</i>it elements. + */ +typedef union hwcfg1_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned ep_dir0 : 2; + unsigned ep_dir1 : 2; + unsigned ep_dir2 : 2; + unsigned ep_dir3 : 2; + unsigned ep_dir4 : 2; + unsigned ep_dir5 : 2; + unsigned ep_dir6 : 2; + unsigned ep_dir7 : 2; + unsigned ep_dir8 : 2; + unsigned ep_dir9 : 2; + unsigned ep_dir10 : 2; + unsigned ep_dir11 : 2; + unsigned ep_dir12 : 2; + unsigned ep_dir13 : 2; + unsigned ep_dir14 : 2; + unsigned ep_dir15 : 2; + } b; +} hwcfg1_data_t; + +/** + * This union represents the bit fields in the User HW Config2 + * Register. Read the register into the <i>d32</i> element then read + * out the bits using the <i>b</i>it elements. + */ +typedef union hwcfg2_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /* GHWCFG2 */ + unsigned op_mode : 3; +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 + + unsigned architecture : 2; + unsigned point2point : 1; + unsigned hs_phy_type : 2; +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 + + unsigned fs_phy_type : 2; + unsigned num_dev_ep : 4; + unsigned num_host_chan : 4; + unsigned perio_ep_supported : 1; + unsigned dynamic_fifo : 1; + unsigned rx_status_q_depth : 2; + unsigned nonperio_tx_q_depth : 2; + unsigned host_perio_tx_q_depth : 2; + unsigned dev_token_q_depth : 5; + unsigned reserved31 : 1; + } b; +} hwcfg2_data_t; + +/** + * This union represents the bit fields in the User HW Config3 + * Register. Read the register into the <i>d32</i> element then read + * out the bits using the <i>b</i>it elements. + */ +typedef union hwcfg3_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /* GHWCFG3 */ + unsigned xfer_size_cntr_width : 4; + unsigned packet_size_cntr_width : 3; + unsigned otg_func : 1; + unsigned i2c : 1; + unsigned vendor_ctrl_if : 1; + unsigned optional_features : 1; + unsigned synch_reset_type : 1; + unsigned ahb_phy_clock_synch : 1; + unsigned reserved15_13 : 3; + unsigned dfifo_depth : 16; + } b; +} hwcfg3_data_t; + +/** + * This union represents the bit fields in the User HW Config4 + * Register. Read the register into the <i>d32</i> element then read + * out the bits using the <i>b</i>it elements. + */ +typedef union hwcfg4_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned num_dev_perio_in_ep : 4; + unsigned power_optimiz : 1; + unsigned min_ahb_freq : 9; + unsigned utmi_phy_data_width : 2; + unsigned num_dev_mode_ctrl_ep : 4; + unsigned iddig_filt_en : 1; + unsigned vbus_valid_filt_en : 1; + unsigned a_valid_filt_en : 1; + unsigned b_valid_filt_en : 1; + unsigned session_end_filt_en : 1; + unsigned ded_fifo_en : 1; + unsigned num_in_eps : 4; + unsigned reserved31_30 : 2; + } b; +} hwcfg4_data_t; + +//////////////////////////////////////////// +// Device Registers +/** + * Device Global Registers. <i>Offsets 800h-BFFh</i> + * + * The following structures define the size and relative field offsets + * for the Device Mode Registers. + * + * <i>These registers are visible only in Device mode and must not be + * accessed in Host mode, as the results are unknown.</i> + */ +typedef struct dwc_otg_dev_global_regs +{ + /** Device Configuration Register. <i>Offset 800h</i> */ + volatile uint32_t dcfg; + /** Device Control Register. <i>Offset: 804h</i> */ + volatile uint32_t dctl; + /** Device Status Register (Read Only). <i>Offset: 808h</i> */ + volatile uint32_t dsts; + /** Reserved. <i>Offset: 80Ch</i> */ + uint32_t unused; + /** Device IN Endpoint Common Interrupt Mask + * Register. <i>Offset: 810h</i> */ + volatile uint32_t diepmsk; + /** Device OUT Endpoint Common Interrupt Mask + * Register. <i>Offset: 814h</i> */ + volatile uint32_t doepmsk; + /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */ + volatile uint32_t daint; + /** Device All Endpoints Interrupt Mask Register. <i>Offset: + * 81Ch</i> */ + volatile uint32_t daintmsk; + /** Device IN Token Queue Read Register-1 (Read Only). + * <i>Offset: 820h</i> */ + volatile uint32_t dtknqr1; + /** Device IN Token Queue Read Register-2 (Read Only). + * <i>Offset: 824h</i> */ + volatile uint32_t dtknqr2; + /** Device VBUS discharge Register. <i>Offset: 828h</i> */ + volatile uint32_t dvbusdis; + /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */ + volatile uint32_t dvbuspulse; + /** Device IN Token Queue Read Register-3 (Read Only). / + * Device Thresholding control register (Read/Write) + * <i>Offset: 830h</i> */ + volatile uint32_t dtknqr3_dthrctl; + /** Device IN Token Queue Read Register-4 (Read Only). / + * Device IN EPs empty Inr. Mask Register (Read/Write) + * <i>Offset: 834h</i> */ + volatile uint32_t dtknqr4_fifoemptymsk; +} dwc_otg_device_global_regs_t; + +/** + * This union represents the bit fields in the Device Configuration + * Register. Read the register into the <i>d32</i> member then + * set/clear the bits using the <i>b</i>it elements. Write the + * <i>d32</i> member to the dcfg register. + */ +typedef union dcfg_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Device Speed */ + unsigned devspd : 2; + /** Non Zero Length Status OUT Handshake */ + unsigned nzstsouthshk : 1; +#define DWC_DCFG_SEND_STALL 1 + + unsigned reserved3 : 1; + /** Device Addresses */ + unsigned devaddr : 7; + /** Periodic Frame Interval */ + unsigned perfrint : 2; +#define DWC_DCFG_FRAME_INTERVAL_80 0 +#define DWC_DCFG_FRAME_INTERVAL_85 1 +#define DWC_DCFG_FRAME_INTERVAL_90 2 +#define DWC_DCFG_FRAME_INTERVAL_95 3 + + unsigned reserved13_17 : 5; + /** In Endpoint Mis-match count */ + unsigned epmscnt : 4; + } b; +} dcfg_data_t; + +/** + * This union represents the bit fields in the Device Control + * Register. Read the register into the <i>d32</i> member then + * set/clear the bits using the <i>b</i>it elements. + */ +typedef union dctl_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Remote Wakeup */ + unsigned rmtwkupsig : 1; + /** Soft Disconnect */ + unsigned sftdiscon : 1; + /** Global Non-Periodic IN NAK Status */ + unsigned gnpinnaksts : 1; + /** Global OUT NAK Status */ + unsigned goutnaksts : 1; + /** Test Control */ + unsigned tstctl : 3; + /** Set Global Non-Periodic IN NAK */ + unsigned sgnpinnak : 1; + /** Clear Global Non-Periodic IN NAK */ + unsigned cgnpinnak : 1; + /** Set Global OUT NAK */ + unsigned sgoutnak : 1; + /** Clear Global OUT NAK */ + unsigned cgoutnak : 1; + + unsigned reserved : 21; + } b; +} dctl_data_t; + +/** + * This union represents the bit fields in the Device Status + * Register. Read the register into the <i>d32</i> member then + * set/clear the bits using the <i>b</i>it elements. + */ +typedef union dsts_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Suspend Status */ + unsigned suspsts : 1; + /** Enumerated Speed */ + unsigned enumspd : 2; +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 + /** Erratic Error */ + unsigned errticerr : 1; + unsigned reserved4_7: 4; + /** Frame or Microframe Number of the received SOF */ + unsigned soffn : 14; + unsigned reserved22_31 : 10; + } b; +} dsts_data_t; + + +/** + * This union represents the bit fields in the Device IN EP Interrupt + * Register and the Device IN EP Common Mask Register. + * + * - Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. + */ +typedef union diepint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Transfer complete mask */ + unsigned xfercompl : 1; + /** Endpoint disable mask */ + unsigned epdisabled : 1; + /** AHB Error mask */ + unsigned ahberr : 1; + /** TimeOUT Handshake mask (non-ISOC EPs) */ + unsigned timeout : 1; + /** IN Token received with TxF Empty mask */ + unsigned intktxfemp : 1; + /** IN Token Received with EP mismatch mask */ + unsigned intknepmis : 1; + /** IN Endpoint HAK Effective mask */ + unsigned inepnakeff : 1; + /** IN Endpoint HAK Effective mask */ + unsigned emptyintr : 1; + + unsigned txfifoundrn : 1; + + unsigned reserved08_31 : 23; + } b; +} diepint_data_t; +/** + * This union represents the bit fields in the Device IN EP Common + * Interrupt Mask Register. + */ +typedef union diepint_data diepmsk_data_t; + +/** + * This union represents the bit fields in the Device OUT EP Interrupt + * Registerand Device OUT EP Common Interrupt Mask Register. + * + * - Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. + */ +typedef union doepint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Transfer complete */ + unsigned xfercompl : 1; + /** Endpoint disable */ + unsigned epdisabled : 1; + /** AHB Error */ + unsigned ahberr : 1; + /** Setup Phase Done (contorl EPs) */ + unsigned setup : 1; + unsigned reserved04_31 : 28; + } b; +} doepint_data_t; +/** + * This union represents the bit fields in the Device OUT EP Common + * Interrupt Mask Register. + */ +typedef union doepint_data doepmsk_data_t; + + +/** + * This union represents the bit fields in the Device All EP Interrupt + * and Mask Registers. + * - Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. + */ +typedef union daint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** IN Endpoint bits */ + unsigned in : 16; + /** OUT Endpoint bits */ + unsigned out : 16; + } ep; + struct + { + /** IN Endpoint bits */ + unsigned inep0 : 1; + unsigned inep1 : 1; + unsigned inep2 : 1; + unsigned inep3 : 1; + unsigned inep4 : 1; + unsigned inep5 : 1; + unsigned inep6 : 1; + unsigned inep7 : 1; + unsigned inep8 : 1; + unsigned inep9 : 1; + unsigned inep10 : 1; + unsigned inep11 : 1; + unsigned inep12 : 1; + unsigned inep13 : 1; + unsigned inep14 : 1; + unsigned inep15 : 1; + /** OUT Endpoint bits */ + unsigned outep0 : 1; + unsigned outep1 : 1; + unsigned outep2 : 1; + unsigned outep3 : 1; + unsigned outep4 : 1; + unsigned outep5 : 1; + unsigned outep6 : 1; + unsigned outep7 : 1; + unsigned outep8 : 1; + unsigned outep9 : 1; + unsigned outep10 : 1; + unsigned outep11 : 1; + unsigned outep12 : 1; + unsigned outep13 : 1; + unsigned outep14 : 1; + unsigned outep15 : 1; + } b; +} daint_data_t; + +/** + * This union represents the bit fields in the Device IN Token Queue + * Read Registers. + * - Read the register into the <i>d32</i> member. + * - READ-ONLY Register + */ +typedef union dtknq1_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** In Token Queue Write Pointer */ + unsigned intknwptr : 5; + /** Reserved */ + unsigned reserved05_06 : 2; + /** write pointer has wrapped. */ + unsigned wrap_bit : 1; + /** EP Numbers of IN Tokens 0 ... 4 */ + unsigned epnums0_5 : 24; + }b; +} dtknq1_data_t; + +/** + * This union represents Threshold control Register + * - Read and write the register into the <i>d32</i> member. + * - READ-WRITABLE Register + */ +typedef union dthrctl_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** non ISO Tx Thr. Enable */ + unsigned non_iso_thr_en : 1; + /** ISO Tx Thr. Enable */ + unsigned iso_thr_en : 1; + /** Tx Thr. Length */ + unsigned tx_thr_len : 9; + /** Reserved */ + unsigned reserved11_15 : 5; + /** Rx Thr. Enable */ + unsigned rx_thr_en : 1; + /** Rx Thr. Length */ + unsigned rx_thr_len : 9; + /** Reserved */ + unsigned reserved26_31 : 6; + }b; +} dthrctl_data_t; + + +/** + * Device Logical IN Endpoint-Specific Registers. <i>Offsets + * 900h-AFCh</i> + * + * There will be one set of endpoint registers per logical endpoint + * implemented. + * + * <i>These registers are visible only in Device mode and must not be + * accessed in Host mode, as the results are unknown.</i> + */ +typedef struct dwc_otg_dev_in_ep_regs +{ + /** Device IN Endpoint Control Register. <i>Offset:900h + + * (ep_num * 20h) + 00h</i> */ + volatile uint32_t diepctl; + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */ + uint32_t reserved04; + /** Device IN Endpoint Interrupt Register. <i>Offset:900h + + * (ep_num * 20h) + 08h</i> */ + volatile uint32_t diepint; + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */ + uint32_t reserved0C; + /** Device IN Endpoint Transfer Size + * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */ + volatile uint32_t dieptsiz; + /** Device IN Endpoint DMA Address Register. <i>Offset:900h + + * (ep_num * 20h) + 14h</i> */ + volatile uint32_t diepdma; + /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h + + * (ep_num * 20h) + 18h</i> */ + volatile uint32_t dtxfsts; + /** Reserved. <i>Offset:900h + (ep_num * 20h) + 1Ch - 900h + + * (ep_num * 20h) + 1Ch</i>*/ + uint32_t reserved18; +} dwc_otg_dev_in_ep_regs_t; + +/** + * Device Logical OUT Endpoint-Specific Registers. <i>Offsets: + * B00h-CFCh</i> + * + * There will be one set of endpoint registers per logical endpoint + * implemented. + * + * <i>These registers are visible only in Device mode and must not be + * accessed in Host mode, as the results are unknown.</i> + */ +typedef struct dwc_otg_dev_out_ep_regs +{ + /** Device OUT Endpoint Control Register. <i>Offset:B00h + + * (ep_num * 20h) + 00h</i> */ + volatile uint32_t doepctl; + /** Device OUT Endpoint Frame number Register. <i>Offset: + * B00h + (ep_num * 20h) + 04h</i> */ + volatile uint32_t doepfn; + /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h + + * (ep_num * 20h) + 08h</i> */ + volatile uint32_t doepint; + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */ + uint32_t reserved0C; + /** Device OUT Endpoint Transfer Size Register. <i>Offset: + * B00h + (ep_num * 20h) + 10h</i> */ + volatile uint32_t doeptsiz; + /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h + * + (ep_num * 20h) + 14h</i> */ + volatile uint32_t doepdma; + /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 18h - B00h + + * (ep_num * 20h) + 1Ch</i> */ + uint32_t unused[2]; +} dwc_otg_dev_out_ep_regs_t; + +/** + * This union represents the bit fields in the Device EP Control + * Register. Read the register into the <i>d32</i> member then + * set/clear the bits using the <i>b</i>it elements. + */ +typedef union depctl_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Maximum Packet Size + * IN/OUT EPn + * IN/OUT EP0 - 2 bits + * 2'b00: 64 Bytes + * 2'b01: 32 + * 2'b10: 16 + * 2'b11: 8 */ + unsigned mps : 11; +#define DWC_DEP0CTL_MPS_64 0 +#define DWC_DEP0CTL_MPS_32 1 +#define DWC_DEP0CTL_MPS_16 2 +#define DWC_DEP0CTL_MPS_8 3 + + /** Next Endpoint + * IN EPn/IN EP0 + * OUT EPn/OUT EP0 - reserved */ + unsigned nextep : 4; + + /** USB Active Endpoint */ + unsigned usbactep : 1; + + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) + * This field contains the PID of the packet going to + * be received or transmitted on this endpoint. The + * application should program the PID of the first + * packet going to be received or transmitted on this + * endpoint , after the endpoint is + * activated. Application use the SetD1PID and + * SetD0PID fields of this register to program either + * D0 or D1 PID. + * + * The encoding for this field is + * - 0: D0 + * - 1: D1 + */ + unsigned dpid : 1; + + /** NAK Status */ + unsigned naksts : 1; + + /** Endpoint Type + * 2'b00: Control + * 2'b01: Isochronous + * 2'b10: Bulk + * 2'b11: Interrupt */ + unsigned eptype : 2; + + /** Snoop Mode + * OUT EPn/OUT EP0 + * IN EPn/IN EP0 - reserved */ + unsigned snp : 1; + + /** Stall Handshake */ + unsigned stall : 1; + + /** Tx Fifo Number + * IN EPn/IN EP0 + * OUT EPn/OUT EP0 - reserved */ + unsigned txfnum : 4; + + /** Clear NAK */ + unsigned cnak : 1; + /** Set NAK */ + unsigned snak : 1; + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) + * Writing to this field sets the Endpoint DPID (DPID) + * field in this register to DATA0. Set Even + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) + * Writing to this field sets the Even/Odd + * (micro)frame (EO_FrNum) field to even (micro) + * frame. + */ + unsigned setd0pid : 1; + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) + * Writing to this field sets the Endpoint DPID (DPID) + * field in this register to DATA1 Set Odd + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) + * Writing to this field sets the Even/Odd + * (micro)frame (EO_FrNum) field to odd (micro) frame. + */ + unsigned setd1pid : 1; + + /** Endpoint Disable */ + unsigned epdis : 1; + /** Endpoint Enable */ + unsigned epena : 1; + } b; +} depctl_data_t; + +/** + * This union represents the bit fields in the Device EP Transfer + * Size Register. Read the register into the <i>d32</i> member then + * set/clear the bits using the <i>b</i>it elements. + */ +typedef union deptsiz_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer size */ + unsigned xfersize : 19; + /** Packet Count */ + unsigned pktcnt : 10; + /** Multi Count - Periodic IN endpoints */ + unsigned mc : 2; + unsigned reserved : 1; + } b; +} deptsiz_data_t; + +/** + * This union represents the bit fields in the Device EP 0 Transfer + * Size Register. Read the register into the <i>d32</i> member then + * set/clear the bits using the <i>b</i>it elements. + */ +typedef union deptsiz0_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer size */ + unsigned xfersize : 7; + /** Reserved */ + unsigned reserved7_18 : 12; + /** Packet Count */ + unsigned pktcnt : 1; + /** Reserved */ + unsigned reserved20_28 : 9; + /**Setup Packet Count (DOEPTSIZ0 Only) */ + unsigned supcnt : 2; + unsigned reserved31; + } b; +} deptsiz0_data_t; + + +/** Maximum number of Periodic FIFOs */ +#define MAX_PERIO_FIFOS 15 +/** Maximum number of Periodic FIFOs */ +#define MAX_TX_FIFOS 15 + +/** Maximum number of Endpoints/HostChannels */ +#define MAX_EPS_CHANNELS 16 + +/** + * The dwc_otg_dev_if structure contains information needed to manage + * the DWC_otg controller acting in device mode. It represents the + * programming view of the device-specific aspects of the controller. + */ +typedef struct dwc_otg_dev_if +{ + /** Pointer to device Global registers. + * Device Global Registers starting at offset 800h + */ + dwc_otg_device_global_regs_t *dev_global_regs; +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 + + /** + * Device Logical IN Endpoint-Specific Registers 900h-AFCh + */ + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; +#define DWC_DEV_IN_EP_REG_OFFSET 0x900 +#define DWC_EP_REG_OFFSET 0x20 + + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS]; +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 + + /* Device configuration information*/ + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */ + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */ + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/ + + /** Size of periodic FIFOs (Bytes) */ + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS]; + + /** Size of Tx FIFOs (Bytes) */ + uint16_t tx_fifo_size[MAX_TX_FIFOS]; + + /** Thresholding enable flags and length varaiables **/ + uint16_t rx_thr_en; + uint16_t iso_tx_thr_en; + uint16_t non_iso_tx_thr_en; + + uint16_t rx_thr_length; + uint16_t tx_thr_length; + +} dwc_otg_dev_if_t; + + + + +///////////////////////////////////////////////// +// Host Mode Register Structures +// +/** + * The Host Global Registers structure defines the size and relative + * field offsets for the Host Mode Global Registers. Host Global + * Registers offsets 400h-7FFh. +*/ +typedef struct dwc_otg_host_global_regs +{ + /** Host Configuration Register. <i>Offset: 400h</i> */ + volatile uint32_t hcfg; + /** Host Frame Interval Register. <i>Offset: 404h</i> */ + volatile uint32_t hfir; + /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */ + volatile uint32_t hfnum; + /** Reserved. <i>Offset: 40Ch</i> */ + uint32_t reserved40C; + /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */ + volatile uint32_t hptxsts; + /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */ + volatile uint32_t haint; + /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */ + volatile uint32_t haintmsk; +} dwc_otg_host_global_regs_t; + +/** + * This union represents the bit fields in the Host Configuration Register. + * Read the register into the <i>d32</i> member then set/clear the bits using + * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register. + */ +typedef union hcfg_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** FS/LS Phy Clock Select */ + unsigned fslspclksel : 2; +#define DWC_HCFG_30_60_MHZ 0 +#define DWC_HCFG_48_MHZ 1 +#define DWC_HCFG_6_MHZ 2 + + /** FS/LS Only Support */ + unsigned fslssupp : 1; + } b; +} hcfg_data_t; + +/** + * This union represents the bit fields in the Host Frame Remaing/Number + * Register. + */ +typedef union hfir_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + unsigned frint : 16; + unsigned reserved : 16; + } b; +} hfir_data_t; + +/** + * This union represents the bit fields in the Host Frame Remaing/Number + * Register. + */ +typedef union hfnum_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + unsigned frnum : 16; +#define DWC_HFNUM_MAX_FRNUM 0x3FFF + unsigned frrem : 16; + } b; +} hfnum_data_t; + +typedef union hptxsts_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + unsigned ptxfspcavail : 16; + unsigned ptxqspcavail : 8; + /** Top of the Periodic Transmit Request Queue + * - bit 24 - Terminate (last entry for the selected channel) + * - bits 26:25 - Token Type + * - 2'b00 - Zero length + * - 2'b01 - Ping + * - 2'b10 - Disable + * - bits 30:27 - Channel Number + * - bit 31 - Odd/even microframe + */ + unsigned ptxqtop_terminate : 1; + unsigned ptxqtop_token : 2; + unsigned ptxqtop_chnum : 4; + unsigned ptxqtop_odd : 1; + } b; +} hptxsts_data_t; + +/** + * This union represents the bit fields in the Host Port Control and Status + * Register. Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the + * hprt0 register. + */ +typedef union hprt0_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned prtconnsts : 1; + unsigned prtconndet : 1; + unsigned prtena : 1; + unsigned prtenchng : 1; + unsigned prtovrcurract : 1; + unsigned prtovrcurrchng : 1; + unsigned prtres : 1; + unsigned prtsusp : 1; + unsigned prtrst : 1; + unsigned reserved9 : 1; + unsigned prtlnsts : 2; + unsigned prtpwr : 1; + unsigned prttstctl : 4; + unsigned prtspd : 2; +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 + unsigned reserved19_31 : 13; + } b; +} hprt0_data_t; + +/** + * This union represents the bit fields in the Host All Interrupt + * Register. + */ +typedef union haint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned ch0 : 1; + unsigned ch1 : 1; + unsigned ch2 : 1; + unsigned ch3 : 1; + unsigned ch4 : 1; + unsigned ch5 : 1; + unsigned ch6 : 1; + unsigned ch7 : 1; + unsigned ch8 : 1; + unsigned ch9 : 1; + unsigned ch10 : 1; + unsigned ch11 : 1; + unsigned ch12 : 1; + unsigned ch13 : 1; + unsigned ch14 : 1; + unsigned ch15 : 1; + unsigned reserved : 16; + } b; + + struct + { + unsigned chint : 16; + unsigned reserved : 16; + } b2; +} haint_data_t; + +/** + * This union represents the bit fields in the Host All Interrupt + * Register. + */ +typedef union haintmsk_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned ch0 : 1; + unsigned ch1 : 1; + unsigned ch2 : 1; + unsigned ch3 : 1; + unsigned ch4 : 1; + unsigned ch5 : 1; + unsigned ch6 : 1; + unsigned ch7 : 1; + unsigned ch8 : 1; + unsigned ch9 : 1; + unsigned ch10 : 1; + unsigned ch11 : 1; + unsigned ch12 : 1; + unsigned ch13 : 1; + unsigned ch14 : 1; + unsigned ch15 : 1; + unsigned reserved : 16; + } b; + + struct + { + unsigned chint : 16; + unsigned reserved : 16; + } b2; +} haintmsk_data_t; + +/** + * Host Channel Specific Registers. <i>500h-5FCh</i> + */ +typedef struct dwc_otg_hc_regs +{ + /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */ + volatile uint32_t hcchar; + /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */ + volatile uint32_t hcsplt; + /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */ + volatile uint32_t hcint; + /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */ + volatile uint32_t hcintmsk; + /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */ + volatile uint32_t hctsiz; + /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */ + volatile uint32_t hcdma; + /** Reserved. <i>Offset: 500h + (chan_num * 20h) + 18h - 500h + (chan_num * 20h) + 1Ch</i> */ + uint32_t reserved[2]; +} dwc_otg_hc_regs_t; + +/** + * This union represents the bit fields in the Host Channel Characteristics + * Register. Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the + * hcchar register. + */ +typedef union hcchar_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** Maximum packet size in bytes */ + unsigned mps : 11; + + /** Endpoint number */ + unsigned epnum : 4; + + /** 0: OUT, 1: IN */ + unsigned epdir : 1; + + unsigned reserved : 1; + + /** 0: Full/high speed device, 1: Low speed device */ + unsigned lspddev : 1; + + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ + unsigned eptype : 2; + + /** Packets per frame for periodic transfers. 0 is reserved. */ + unsigned multicnt : 2; + + /** Device address */ + unsigned devaddr : 7; + + /** + * Frame to transmit periodic transaction. + * 0: even, 1: odd + */ + unsigned oddfrm : 1; + + /** Channel disable */ + unsigned chdis : 1; + + /** Channel enable */ + unsigned chen : 1; + } b; +} hcchar_data_t; + +typedef union hcsplt_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** Port Address */ + unsigned prtaddr : 7; + + /** Hub Address */ + unsigned hubaddr : 7; + + /** Transaction Position */ + unsigned xactpos : 2; +#define DWC_HCSPLIT_XACTPOS_MID 0 +#define DWC_HCSPLIT_XACTPOS_END 1 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2 +#define DWC_HCSPLIT_XACTPOS_ALL 3 + + /** Do Complete Split */ + unsigned compsplt : 1; + + /** Reserved */ + unsigned reserved : 14; + + /** Split Enble */ + unsigned spltena : 1; + } b; +} hcsplt_data_t; + + +/** + * This union represents the bit fields in the Host All Interrupt + * Register. + */ +typedef union hcint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Transfer Complete */ + unsigned xfercomp : 1; + /** Channel Halted */ + unsigned chhltd : 1; + /** AHB Error */ + unsigned ahberr : 1; + /** STALL Response Received */ + unsigned stall : 1; + /** NAK Response Received */ + unsigned nak : 1; + /** ACK Response Received */ + unsigned ack : 1; + /** NYET Response Received */ + unsigned nyet : 1; + /** Transaction Err */ + unsigned xacterr : 1; + /** Babble Error */ + unsigned bblerr : 1; + /** Frame Overrun */ + unsigned frmovrun : 1; + /** Data Toggle Error */ + unsigned datatglerr : 1; + /** Reserved */ + unsigned reserved : 21; + } b; +} hcint_data_t; + +/** + * This union represents the bit fields in the Host Channel Transfer Size + * Register. Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the + * hcchar register. + */ +typedef union hctsiz_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** Total transfer size in bytes */ + unsigned xfersize : 19; + + /** Data packets to transfer */ + unsigned pktcnt : 10; + + /** + * Packet ID for next data packet + * 0: DATA0 + * 1: DATA2 + * 2: DATA1 + * 3: MDATA (non-Control), SETUP (Control) + */ + unsigned pid : 2; +#define DWC_HCTSIZ_DATA0 0 +#define DWC_HCTSIZ_DATA1 2 +#define DWC_HCTSIZ_DATA2 1 +#define DWC_HCTSIZ_MDATA 3 +#define DWC_HCTSIZ_SETUP 3 + + /** Do PING protocol when 1 */ + unsigned dopng : 1; + } b; +} hctsiz_data_t; + +/** + * This union represents the bit fields in the Host Channel Interrupt Mask + * Register. Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the + * hcintmsk register. + */ +typedef union hcintmsk_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + unsigned xfercompl : 1; + unsigned chhltd : 1; + unsigned ahberr : 1; + unsigned stall : 1; + unsigned nak : 1; + unsigned ack : 1; + unsigned nyet : 1; + unsigned xacterr : 1; + unsigned bblerr : 1; + unsigned frmovrun : 1; + unsigned datatglerr : 1; + unsigned reserved : 21; + } b; +} hcintmsk_data_t; + +/** OTG Host Interface Structure. + * + * The OTG Host Interface Structure structure contains information + * needed to manage the DWC_otg controller acting in host mode. It + * represents the programming view of the host-specific aspects of the + * controller. + */ +typedef struct dwc_otg_host_if +{ + /** Host Global Registers starting at offset 400h.*/ + dwc_otg_host_global_regs_t *host_global_regs; +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 + + /** Host Port 0 Control and Status Register */ + volatile uint32_t *hprt0; +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 + + + /** Host Channel Specific Registers at offsets 500h-5FCh. */ + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20 + + + /* Host configuration information */ + /** Number of Host Channels (range: 1-16) */ + uint8_t num_host_channels; + /** Periodic EPs supported (0: no, 1: yes) */ + uint8_t perio_eps_supported; + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */ + uint16_t perio_tx_fifo_size; + +} dwc_otg_host_if_t; + + +/** + * This union represents the bit fields in the Power and Clock Gating Control + * Register. Read the register into the <i>d32</i> member then set/clear the + * bits using the <i>b</i>it elements. + */ +typedef union pcgcctl_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** Stop Pclk */ + unsigned stoppclk : 1; + /** Gate Hclk */ + unsigned gatehclk : 1; + /** Power Clamp */ + unsigned pwrclmp : 1; + /** Reset Power Down Modules */ + unsigned rstpdwnmodule : 1; + /** PHY Suspended */ + unsigned physuspended : 1; + + unsigned reserved : 27; + } b; +} pcgcctl_data_t; + +#define DWC_OTG_EP_TYPE_CONTROL 0 +#define DWC_OTG_EP_TYPE_ISOC 1 +#define DWC_OTG_EP_TYPE_BULK 2 +#define DWC_OTG_EP_TYPE_INTR 3 + + +int dwc_core_init(void); + +static void dwc_otg_core_init(void); +static int dwc_otg_pcd_init(void); +static void dwc_otg_core_reset(void); +static void dwc_otg_enable_common_interrupts(void); +static void dwc_otg_enable_device_interrupts(void); +static void dwc_otg_enable_global_interrupts(void); +static void dwc_otg_core_dev_init(void); +static void dwc_otg_flush_tx_fifo( const int _num ) ; +static void dwc_otg_flush_rx_fifo(void) ; +int dwc_otg_ep_req_start(pcd_struct_t * _pcd,int ep_num); +void dwc_otg_ep_start_transfer(dwc_ep_t *_ep); +static void dwc_otg_bulk_ep_activate(dwc_ep_t *ep); +void dwc_otg_power_off_phy(void); +void dwc_otg_pullup(int is_on); +int dwc_otg_bulk_ep_enable(int is_in);//Added by Sam + +#endif diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd_irq.c b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd_irq.c new file mode 100644 index 0000000000..da5d371280 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd_irq.c @@ -0,0 +1,1286 @@ +/* dwc controller pcd interrupt drivers */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-30 @ Shanghai + * + */ +#include "platform.h" +#include "usb_ch9.h" +#include "dwc_pcd.h" +#include "dwc_pcd_irq.h" +//#define flush_cpu_cache() +extern void do_gadget_setup( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl); +extern void do_vendor_request( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl); +extern void do_vendor_out_complete( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl); +extern void do_bulk_complete( pcd_struct_t *_pcd); +extern void do_modify_memory(u16 opcode,char * inbuff); + +static void ep0_out_start(void); +static int32_t ep0_complete_request( pcd_struct_t * pcd); +/** + * This function starts the Zero-Length Packet for the IN status phase + * of a 2 stage control transfer. + */ +static void do_setup_in_status_phase( pcd_struct_t *_pcd) +{ + dwc_ep_t *ep0 = &g_dwc_eps[0]; + if (_pcd->ep0state == EP0_STALL) { + return; + } + + _pcd->ep0state = EP0_STATUS; + + DBG( "EP0 IN ZLP\n"); + ep0->xfer_len = 0; + ep0->xfer_count = 0; + ep0->is_in = 1; + + dwc_otg_ep_start_transfer( ep0 ); + + /* Prepare for more SETUP Packets */ + ep0_out_start(); + +} +/** + * This function starts the Zero-Length Packet for the OUT status phase + * of a 2 stage control transfer. + */ +static void do_setup_out_status_phase( pcd_struct_t *_pcd) +{ + dwc_ep_t *ep0 = &g_dwc_eps[0]; + if (_pcd->ep0state == EP0_STALL) { + return; + } + _pcd->ep0state = EP0_STATUS; + + /* Prepare for more SETUP Packets */ + //ep0_out_start( GET_CORE_IF(_pcd), _pcd ); + + DBG( "EP0 OUT ZLP\n"); + ep0->xfer_len = 0; + ep0->xfer_count = 0; + ep0->is_in = 0; + dwc_otg_ep_start_transfer( ep0 ); + + /* Prepare for more SETUP Packets */ + ep0_out_start( ); + +} + +static void pcd_out_completed(pcd_struct_t *_pcd) +{ + if (_pcd->cmdtype.out_complete && _pcd->cmdtype.in_complete) + { + _pcd->cmdtype.setup_complete = _pcd->cmdtype.out_complete = _pcd->cmdtype.in_complete = 0; + do_vendor_out_complete(_pcd,(struct usb_ctrlrequest*)&_pcd->setup_pkt); + } +} + +static void pcd_in_completed(pcd_struct_t *_pcd) +{ + do_vendor_in_complete(_pcd,(struct usb_ctrlrequest*)&_pcd->setup_pkt); +} + + +static void pcd_setup( pcd_struct_t *_pcd ) +{ + + struct usb_ctrlrequest ctrl = _pcd->setup_pkt.req; + dwc_ep_t *ep0 = &g_dwc_eps[0]; + /*deptsiz0_data_t doeptsize0 = { 0};*/ + + if (_pcd->request_enable == 0) + return; + + // _pcd->setup_pkt.d32[0] = 0; + // _pcd->setup_pkt.d32[1] = 0; + _pcd->status = 0; + _pcd->request_enable = 0; + + /*doeptsize0.d32 = dwc_read_reg32( DWC_REG_OUT_EP_TSIZE(0));*/ + + if (ctrl.bRequestType & USB_DIR_IN) { + ep0->is_in = 1; + _pcd->ep0state = EP0_IN_DATA_PHASE; + } else { + ep0->is_in = 0; + _pcd->ep0state = EP0_OUT_DATA_PHASE; + } + + + if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) + { + /* handle non-standard (class/vendor) requests in the gadget driver */ + //do_gadget_setup(_pcd, &ctrl ); + DBG("Vendor requset\n"); + do_vendor_request(_pcd, &ctrl ); + dwc_otg_ep_req_start(_pcd,0); + return; + } + + /** @todo NGS: Handle bad setup packet? */ + + switch (ctrl.bRequest) + { + case USB_REQ_GET_STATUS: + + _pcd->status = 0; + switch (ctrl.bRequestType & USB_RECIP_MASK) { + + case USB_RECIP_DEVICE: + _pcd->status = 0; /* Default Bus Powered, no Remote wakeup */ + //_pcd->status |= 0x1; /* Self powered */ + //_pcd->status |= 0x2;//_pcd->remote_wakeup_enable << 1; + break; + + case USB_RECIP_INTERFACE: + _pcd->status = 0; + break; + } + _pcd->buf = (char *)&_pcd->status; + _pcd->length = 2; + dwc_otg_ep_req_start(_pcd,0); + break; +#if 0 + case USB_RECIP_INTERFACE: + *status = 0; + break; + + case USB_RECIP_ENDPOINT: + ep = get_ep_by_addr(_pcd, ctrl.wIndex); + if ( ep == 0 || ctrl.wLength > 2) { + ep0_do_stall(_pcd, -EOPNOTSUPP); + return; + } + /** @todo check for EP stall */ + *status = ep->stopped; + break; + _pcd->ep0_pending = 1; + + ep0->dwc_ep.start_xfer_buff = (uint8_t *)status; + ep0->dwc_ep.xfer_buff = (uint8_t *)status; + ep0->dwc_ep.dma_addr = _pcd->status_buf_dma_handle; + ep0->dwc_ep.xfer_len = 2; + ep0->dwc_ep.xfer_count = 0; + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len; + dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep ); + break; + + case USB_REQ_CLEAR_FEATURE: + do_clear_feature( _pcd ); + break; + + case USB_REQ_SET_FEATURE: + do_set_feature( _pcd ); + break; +#endif + case USB_REQ_SET_ADDRESS: + if (ctrl.bRequestType == USB_RECIP_DEVICE) + { + dcfg_data_t dcfg = { 0 }; + + printf("Set Addr %d\n",ctrl.wValue); + dcfg.b.devaddr = ctrl.wValue; + dwc_modify_reg32(DWC_REG_DCFG,0, dcfg.d32); + do_setup_in_status_phase( _pcd ); + return; + } + break; + + case USB_REQ_SET_INTERFACE: + case USB_REQ_SET_CONFIGURATION: + _pcd->request_config = 1; /* Configuration changed */ + do_gadget_setup(_pcd, &ctrl ); + dwc_otg_ep_req_start(_pcd,0); + break; + + default: + /* Call the Gadget Driver's setup functions */ + do_gadget_setup(_pcd, &ctrl ); + dwc_otg_ep_req_start(_pcd,0); + break; + } +} + +/** + * This function handles EP0 Control transfers. + * + * The state of the control tranfers are tracked in + * <code>ep0state</code>. + * is_in : 1 -- IN Trans + * is_in : 0 -- OUT/SETUP Trans + */ +static void handle_ep0( int is_in ) +{ + pcd_struct_t * _pcd = &this_pcd;//Oh, this_pcd + dwc_ep_t * ep0 = &g_dwc_eps[0]; + + switch (_pcd->ep0state) + { + case EP0_DISCONNECT: + DBG("EP0 DISCONNECT\n"); + break; + + case EP0_IDLE: + _pcd->request_config = 0; + DBG("Enter PCD Setup()\n"); + pcd_setup( _pcd ); + break; + + case EP0_IN_DATA_PHASE: + + if (ep0->xfer_count < ep0->total_len) { + DBG("FIX ME!! dwc_otg_ep0_continue_transfer!\n"); + //dwc_otg_ep0_continue_transfer ( GET_CORE_IF(_pcd), &ep0->dwc_ep ); + } + else { + ep0_complete_request( _pcd ); + pcd_in_completed(_pcd);///////////// + } + break; + + case EP0_OUT_DATA_PHASE: + ep0_complete_request(_pcd ); + _pcd->cmdtype.in_complete = 1; + pcd_out_completed(_pcd); + break; + + + case EP0_STATUS: + + ep0_complete_request( _pcd ); + _pcd->ep0state = EP0_IDLE; + ep0->stopped = 1; + ep0->is_in = 0; /* OUT for next SETUP */ + + break; + + case EP0_STALL: + ERR("EP0 STALLed, should not get here pcd_setup()\n"); + break; + } + + return ; +} + +/** + * This function completes the request for the EP. If there are + * additional requests for the EP in the queue they will be started. + */ +static void complete_ep( int ep_num,int is_in ) +{ + deptsiz_data_t deptsiz; + pcd_struct_t *pcd = &this_pcd; + dwc_ep_t *ep = &g_dwc_eps[ep_num]; + + if (is_in) + { + pcd->xfer_len = ep->xfer_count;//////////////// + + deptsiz.d32 = dwc_read_reg32(DWC_REG_IN_EP_TSIZE(ep_num)); + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0 && + ep->xfer_count == ep->xfer_len) + { + + ep->start_xfer_buff = 0; + ep->xfer_buff = 0; + ep->xfer_len = 0; + } + } + else + {/* OUT Transfer */ + + deptsiz.d32 = dwc_read_reg32(DWC_REG_OUT_EP_TSIZE(ep_num)); + + pcd->xfer_len = ep->xfer_count; + + ep->start_xfer_buff = 0; + ep->xfer_buff = 0; + ep->xfer_len = 0; + } + + do_bulk_complete(pcd); +} +/** + * This function completes the ep0 control transfer. + */ +static int32_t ep0_complete_request( pcd_struct_t * pcd) +{ + + deptsiz0_data_t deptsiz; + int is_last = 0; + dwc_ep_t* ep = &g_dwc_eps[0]; + + DBG("ep0_complete_request()\n"); + if (pcd->ep0state == EP0_STATUS) + { + is_last = 1; + } + else if (ep->xfer_len == 0) + { + ep->xfer_len = 0; + ep->xfer_count = 0; + ep->sent_zlp = 1; + dwc_otg_ep_start_transfer( ep ); + return 1; + } + else if (ep->is_in) + { + deptsiz.d32 = dwc_read_reg32(DWC_REG_IN_EP_TSIZE(0) ); + if (deptsiz.b.xfersize == 0) { + /* Is a Zero Len Packet needed? */ + do_setup_out_status_phase(pcd); + } + } + else { + /* ep0-OUT */ + do_setup_in_status_phase(pcd); + } + + /* Complete the request */ + if (is_last) { + ep->start_xfer_buff = 0; + ep->xfer_buff = 0; + ep->xfer_len = 0; + return 1; + } + return 0; +} + +/** + * This function reads a packet from the Rx FIFO into the destination + * buffer. To read SETUP data use dwc_otg_read_setup_packet. + * + * @param _dest Destination buffer for the packet. + * @param _bytes Number of bytes to copy to the destination. + */ +static void dwc_otg_read_packet(uint8_t *_dest, uint16_t _bytes) //Elvis Fool, add 'static' +{ + int i; + /*const char* str = (char*)_dest;*/ + uint32_t* pu32 = (uint32_t*)_dest; + const unsigned lenIn32 = (_bytes>>2); + const unsigned rest = (_bytes & 3); + + /** + * @todo Account for the case where _dest is not dword aligned. This + * requires reading data from the FIFO into a uint32_t temp buffer, + * then moving it into the data buffer. + */ + //DBG("dwc_otg_read_packet() dest: %p, len: %d\n",_dest,_bytes); + for (i = 0; i < lenIn32; ++i) + { + *pu32++ = dwc_read_reg32(DWC_REG_DATA_FIFO_START); + } + if (rest) + { + const unsigned fifoVal = dwc_read_reg32(DWC_REG_DATA_FIFO_START); + uint8_t* pBufDst8 = (uint8_t*)pu32; + const uint8_t* pBufSrc8 = (const uint8_t*)&fifoVal; + for (i = 0; i < rest; ++i) + { + *pBufDst8++ = *pBufSrc8++; + } + } + + /* + *if(!strcmp("power", str)) + * printf("%d>", _bytes),printf(str),printf("\n"); + */ + + return; +} + +/** + * This function writes a packet into the Tx FIFO associated with the + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For + * periodic EPs the periodic Tx FIFO associated with the EP is written + * with all packets for the next micro-frame. + * + * @param _core_if Programming view of DWC_otg controller. + * @param _ep The EP to write packet for. + * @param _dma Indicates if DMA is being used. + */ +void dwc_otg_ep_write_packet( dwc_ep_t *_ep) +{ + /** + * The buffer is padded to DWORD on a per packet basis in + * slave/dma mode if the MPS is not DWORD aligned. The last + * packet, if short, is also padded to a multiple of DWORD. + * + * ep->xfer_buff always starts DWORD aligned in memory and is a + * multiple of DWORD in length + * + * ep->xfer_len can be any number of bytes + * + * ep->xfer_count is a multiple of ep->maxpacket until the last + * packet + * + * FIFO access is DWORD */ + + uint32_t i; + uint32_t byte_count; + uint32_t dword_count; + uint32_t fifo; + uint8_t *data_buff = _ep->xfer_buff; + uint32_t temp_data ; + + //DBG("dwc_otg_ep_write_packet() : %d\n",_ep->xfer_len); + if (_ep->xfer_count >= _ep->xfer_len) { + //DWC_WARN("%s() No data for EP%d!!!\n", "dwc_otg_ep_write_packet", _ep->num); + return; + } + + /* Find the byte length of the packet either short packet or MPS */ + if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) { + byte_count = _ep->xfer_len - _ep->xfer_count; + } + else { + byte_count = _ep->maxpacket; + } + + /* Find the DWORD length, padded by extra bytes as neccessary if MPS + * is not a multiple of DWORD */ + dword_count = (byte_count + 3) / 4; + + + //fifo = _core_if->data_fifo[_ep->num]; + fifo = DWC_REG_DATA_FIFO(_ep->num); + + + for (i=0; i<dword_count; i++) { + temp_data =get_unaligned(data_buff); + dwc_write_reg32( fifo, temp_data ); + data_buff += 4; + } + + + _ep->xfer_count += byte_count; + _ep->xfer_buff += byte_count; + + flush_cpu_cache(); + +} +/** + * This function reads a setup packet from the Rx FIFO into the destination + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl) + * Interrupt routine when a SETUP packet has been received in Slave mode. + * + * @param _core_if Programming view of DWC_otg controller. + * @param _dest Destination buffer for packet data. + */ +void dwc_otg_read_setup_packet(uint32_t *_dest) +{ + /* Get the 8 bytes of a setup transaction data */ + + DBG("dwc_otg_read_setup_packet()\n"); + /* Pop 2 DWORDS off the receive data FIFO into memory */ + _dest[0] = dwc_read_reg32(DWC_REG_DATA_FIFO_START); + _dest[1] = dwc_read_reg32(DWC_REG_DATA_FIFO_START); +} + + + +/** + * handle the IN EP disable interrupt. + */ +static void handle_in_ep_disable_intr(uint32_t _epnum) +{ +#if 0 + deptsiz_data_t dieptsiz = { 0 }; + dctl_data_t dctl = { 0 }; + depctl_data_t diepctl = { 0 }; + dwc_ep_t *ep = &g_dwc_eps[_epnum]; + + if (ep->stopped) { + /* Flush the Tx FIFO */ + /** @todo NGS: This is not the correct FIFO */ + dwc_otg_flush_tx_fifo( core_if, 0 ); + /* Clear the Global IN NP NAK */ + dctl.d32 = 0; + dctl.b.cgnpinnak = 1; + dwc_modify_reg32(&dev_if->in_ep_regs[_epnum]->diepctl, + diepctl.d32, diepctl.d32); + /* Restart the transaction */ + if (dieptsiz.b.pktcnt != 0 || + dieptsiz.b.xfersize != 0) { + restart_transfer( _pcd, _epnum ); + } + } +#endif +} + +/** + * Handler for the IN EP timeout handshake interrupt. + */ +static void handle_in_ep_timeout_intr(uint32_t _epnum) +{ + + dctl_data_t dctl = { 0 }; + dwc_ep_t *ep = &g_dwc_eps[_epnum]; + + gintmsk_data_t intr_mask = {0}; + + + /* Disable the NP Tx Fifo Empty Interrrupt */ + + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0); + /** @todo NGS Check EP type. + * Implement for Periodic EPs */ + /* + * Non-periodic EP + */ + /* Enable the Global IN NAK Effective Interrupt */ + intr_mask.b.ginnakeff = 1; + dwc_modify_reg32( DWC_REG_GINTMSK, 0, intr_mask.d32); + + /* Set Global IN NAK */ + dctl.b.sgnpinnak = 1; + dwc_modify_reg32( DWC_REG_DCTL,dctl.d32, dctl.d32); + + ep->stopped = 1; + +} + +/////////////////////////////////////////////////////////////////////// +/** + * This function handles the Rx Status Queue Level Interrupt, which + * indicates that there is a least one packet in the Rx FIFO. The + * packets are moved from the FIFO to memory, where they will be + * processed when the Endpoint Interrupt Register indicates Transfer + * Complete or SETUP Phase Done. + * + * Repeat the following until the Rx Status Queue is empty: + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet + * info + * -# If Receive FIFO is empty then skip to step Clear the interrupt + * and exit + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the + * SETUP data to the buffer + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data + * to the destination buffer + */ +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(void) +{ + gintmsk_data_t gintmask = { 0 }; + device_grxsts_data_t status; + gintsts_data_t gintsts; + dwc_ep_t *ep; + + + DBG("dwc_otg_pcd_handle_rx_status_q_level_intr()\n"); + /* Disable the Rx Status Queue Level interrupt */ + gintmask.b.rxstsqlvl= 1; + dwc_modify_reg32( DWC_REG_GINTMSK, gintmask.d32, 0); + + /* Get the Status from the top of the FIFO */ + status.d32 = dwc_read_reg32( DWC_REG_GRXSTSP); + + //DBG("rx status: ep%d, pktsts: %d\n",status.b.epnum,status.b.pktsts); + + /* Get pointer to EP structure */ + ep = &g_dwc_eps[status.b.epnum]; + + switch (status.b.pktsts) + { + case DWC_DSTS_GOUT_NAK: + DBG( "Global OUT NAK\n"); + break; + + case DWC_STS_DATA_UPDT: + DBG( "OUT Data Packet\n"); + { + if (status.b.bcnt && ep->xfer_buff) + { + /** @todo NGS Check for buffer overflow? */ + dwc_otg_read_packet( ep->xfer_buff,status.b.bcnt); + ep->xfer_count += status.b.bcnt; + ep->xfer_buff += status.b.bcnt; + + if (!status.b.epnum) + { + /*const char* p = ep->xfer_buff - status.b.bcnt;*/ + this_pcd.cmdtype.out_complete = 1; + /* + *if(!strcmp("power", p) || !strcmp("low_power", p)){ + * printf("%s, bcnt %d, cnt %d, %d\n", p, status.b.bcnt, ep->xfer_count, this_pcd.cmdtype.in_complete); + *} + */ + } + } + } + break; + + case DWC_STS_XFER_COMP: + DBG("OUT Complete\n"); + break; + + case DWC_DSTS_SETUP_COMP: + DBG("SETUP Complete\n"); + break; + + case DWC_DSTS_SETUP_UPDT: + DBG("SETUP update\n"); + { + static int _is_first_setup_out_in_cmd = 1; + + dwc_otg_read_setup_packet( this_pcd.setup_pkt.d32); + this_pcd.request_enable = 1; + ep->xfer_count += status.b.bcnt; + + DBG("set %d, %d\n", status.b.bcnt, ep->xfer_count); + if (_is_first_setup_out_in_cmd) //first tplcmd/bulkcmd that in sequence 'setup + out + in' + { + struct usb_ctrlrequest request = this_pcd.setup_pkt.req; + if ( USB_TYPE_VENDOR == (request.bRequestType & USB_TYPE_MASK) ) + { + unsigned bRequest = request.bRequest; + + if ((AM_REQ_WR_LARGE_MEM == bRequest) || (AM_REQ_RD_LARGE_MEM == bRequest) + ||(AM_REQ_TPL_CMD == bRequest) || (AM_REQ_TPL_STAT == bRequest) + || (AM_REQ_DOWNLOAD == bRequest) || (AM_REQ_BULKCMD == bRequest)) + { + __udelay(20);//delay for first command that consisted of consecutive 'ep0 out', i.e. 'setup + out + in' + _is_first_setup_out_in_cmd = 0; + } + } + } + } + break; + + default: + //DBG( "Invalid Packet Status (0x%0x)\n", status.b.pktsts); + break; + + } + + /* Enable the Rx Status Queue Level interrupt */ + dwc_modify_reg32( DWC_REG_GINTMSK, 0, gintmask.d32); + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.rxstsqlvl = 1; + dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32); + + return 1; +} + + +/** + * This interrupt occurs when the non-periodic Tx FIFO is half-empty. + * The active request is checked for the next packet to be loaded into + * the non-periodic Tx FIFO. + */ +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(void) +{ + gnptxsts_data_t txstatus = {0}; + gintsts_data_t gintsts; + + int epnum = 0; + dwc_ep_t *ep = 0; + uint32_t len = 0; + int dwords; + depctl_data_t depctl; + + DBG("dwc_otg_pcd_handle_np_tx_fifo_empty_intr()\n"); + /* Get the epnum from the IN Token Learning Queue. */ + for (epnum=0; epnum < NUM_EP; epnum++) + { + + ep = &g_dwc_eps[epnum]; + + + /* IN endpoint ? */ + if (epnum && !ep->is_in ) { + continue; + } + depctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(epnum)); + if (depctl.b.epena != 1) + continue; + + if (ep->type == DWC_OTG_EP_TYPE_INTR && ep->xfer_len == 0) + continue; + + flush_cpu_cache(); + + len = ep->xfer_len - ep->xfer_count; + if (len > ep->maxpacket) { + len = ep->maxpacket; + } + dwords = (len + 3)/4; + + //DBG("nptx: write data to fifo, ep%d , size %d\n",epnum,len); + /* While there is space in the queue and space in the FIFO and + * More data to tranfer, Write packets to the Tx FIFO */ + txstatus.d32 = dwc_read_reg32( DWC_REG_GNPTXSTS ); + while (txstatus.b.nptxqspcavail > 0 && + txstatus.b.nptxfspcavail > dwords && + ep->xfer_count < ep->xfer_len) { + + flush_cpu_cache(); + + /* Write the FIFO */ + dwc_otg_ep_write_packet( ep ); + + len = ep->xfer_len - ep->xfer_count; + if (len > ep->maxpacket) { + len = ep->maxpacket; + } + dwords = (len + 3)/4; + flush_cpu_cache(); + //txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS); +#if 1 + /* + TODO: Remove these code. + Because, if code break from "while"(Line427), an incomplete-in-trans will occour. + Then the tansfer will break. + */ + int retry = 50000; //retry times + while (retry--) + { + txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS); + if(txstatus.b.nptxqspcavail > 0 || //txstatus.b.nptxfspcavail <= dwords || + ep->xfer_count >= ep->xfer_len) + break; + else + { + flush_cpu_cache(); + } + + } + if (retry <= 0) + { + //DWC_ERROR("TxFIFO FULL: Can't trans data to HOST !\n"); + } + + /* END todo */ +#endif + } + + } + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.nptxfempty = 1; + dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32); + + return 1; +} +/** + * Read the device status register and set the device speed in the + * data structure. + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate. + */ +int32_t dwc_otg_pcd_handle_enum_done_intr(void) +{ + gintsts_data_t gintsts; + gusbcfg_data_t gusbcfg; + /*dsts_data_t dsts;*/ + depctl_data_t diepctl; + depctl_data_t doepctl; + dctl_data_t dctl ={0}; + + DBG("SPEED ENUM\n"); + + /* Read the Device Status and Endpoint 0 Control registers */ + /*dsts.d32 = dwc_read_reg32(DWC_REG_DSTS);*/ + diepctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(0) ); + doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0)); + + /* Set the MPS of the IN EP based on the enumeration speed */ + diepctl.b.mps = DWC_DEP0CTL_MPS_64; + dwc_write_reg32(DWC_REG_IN_EP_REG(0) , diepctl.d32); + + /* Enable OUT EP for receive */ + doepctl.b.epena = 1; + dwc_write_reg32(DWC_REG_OUT_EP_REG(0), doepctl.d32); + + dctl.b.cgnpinnak = 1; + dwc_modify_reg32(DWC_REG_DCTL, dctl.d32, dctl.d32); + + if (this_pcd.ep0state == EP0_DISCONNECT) { + this_pcd.ep0state = EP0_IDLE; + } else if (this_pcd.ep0state == EP0_STALL) { + this_pcd.ep0state = EP0_IDLE; + } + + this_pcd.ep0state = EP0_IDLE; + + + /* Set USB turnaround time based on device speed and PHY interface. */ + gusbcfg.d32 = dwc_read_reg32(DWC_REG_GUSBCFG); +#if 0 + if (_pcd->gadget.speed == USB_SPEED_HIGH) { + if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_ULPI) { + /* ULPI interface */ + gusbcfg.b.usbtrdtim = 9; + } + if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI) { + /* UTMI+ interface */ + if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) { + gusbcfg.b.usbtrdtim = 5; + } else { + gusbcfg.b.usbtrdtim = 9; + } + } + if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) { + /* UTMI+ OR ULPI interface */ + if (gusbcfg.b.ulpi_utmi_sel == 1) { + /* ULPI interface */ + gusbcfg.b.usbtrdtim = 9; + } else { + /* UTMI+ interface */ + if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) { + gusbcfg.b.usbtrdtim = 5; + } else { + gusbcfg.b.usbtrdtim = 9; + } + } + } + } else { + /* Full or low speed */ + gusbcfg.b.usbtrdtim = 9; + } +#else + /* Full or low speed */ + gusbcfg.b.usbtrdtim = 5; +#endif + dwc_write_reg32(DWC_REG_GUSBCFG, gusbcfg.d32); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.enumdone = 1; + dwc_write_reg32(DWC_REG_GINTSTS,gintsts.d32 ); + return 1; +} +/////////////////////////////////////////////////////////////////// +/** + * This interrupt indicates that an OUT EP has a pending Interrupt. + * The sequence for handling the OUT EP interrupt is shown below: + * -# Read the Device All Endpoint Interrupt register + * -# Repeat the following for each OUT EP interrupt bit set (from + * LSB to MSB). + * -# Read the Device Endpoint Interrupt (DOEPINTn) register + * -# If "Transfer Complete" call the request complete function + * -# If "Endpoint Disabled" complete the EP disable procedure. + * -# If "AHB Error Interrupt" log error + * -# If "Setup Phase Done" process Setup Packet (See Standard USB + * Command Processing) + */ +static int32_t dwc_otg_pcd_handle_out_ep_intr(void) +{ +#define CLEAR_OUT_EP_INTR(__epnum,__intr) \ +do { \ + doepint_data_t doepint = { 0 }; \ + doepint.b.__intr = 1; \ + dwc_write_reg32(DWC_REG_OUT_EP_INTR(__epnum), \ + doepint.d32); \ +} while (0) + + uint32_t ep_intr; + doepint_data_t doepint = { 0 }; + uint32_t epnum = 0; +// uint32_t epnum_trans = 0; + gintsts_data_t gintsts; + + DBG( "dwc_otg_pcd_handle_out_ep_intr()\n" ); + + /* Read in the device interrupt bits */ + ep_intr = (dwc_read_reg32(DWC_REG_DAINT) & + dwc_read_reg32( DWC_REG_DAINTMSK)); + ep_intr =( (ep_intr & 0xffff0000) >> 16); + + /* Clear the OUTEPINT in GINTSTS */ + gintsts.d32 = 0; + gintsts.b.outepintr = 1; + dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32); + dwc_write_reg32(DWC_REG_DAINT, 0xFFFF0000 ); + + while ( ep_intr ) { + if (ep_intr&0x1) { + doepint.d32 = (dwc_read_reg32( DWC_REG_OUT_EP_INTR(epnum)) & + dwc_read_reg32(DWC_REG_DOEPMSK)); + + /* Transfer complete */ + if ( doepint.b.xfercompl ) { + DBG("EP%d OUT Xfer Complete\n", epnum); + + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(epnum,xfercompl); + + if (epnum == 0) { + handle_ep0( 0 ); + } else { + complete_ep( epnum,0 ); + } + } + /* Endpoint disable */ + if ( doepint.b.epdisabled ) { + DBG("EP%d OUT disabled\n", epnum); + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(epnum,epdisabled); + } + /* AHB Error */ + if ( doepint.b.ahberr ) { + DBG("EP%d OUT AHB Error\n", epnum); + CLEAR_OUT_EP_INTR(epnum,ahberr); + } + /* Setup Phase Done (contorl EPs) */ + if ( doepint.b.setup ) { + handle_ep0( 0 ); + CLEAR_OUT_EP_INTR(epnum,setup); + } + } + epnum++; + ep_intr >>=1; + } + + return 1; + +#undef CLEAR_OUT_EP_INTR +} +/** + * This interrupt indicates that an IN EP has a pending Interrupt. + * The sequence for handling the IN EP interrupt is shown below: + * -# Read the Device All Endpoint Interrupt register + * -# Repeat the following for each IN EP interrupt bit set (from + * LSB to MSB). + * -# Read the Device Endpoint Interrupt (DIEPINTn) register + * -# If "Transfer Complete" call the request complete function + * -# If "Endpoint Disabled" complete the EP disable procedure. + * -# If "AHB Error Interrupt" log error + * -# If "Time-out Handshake" log error + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx + * FIFO. + * -# If "IN Token EP Mismatch" (disable, this is handled by EP + * Mismatch Interrupt) + */ +static int32_t dwc_otg_pcd_handle_in_ep_intr(void) +{ +#define CLEAR_IN_EP_INTR(__epnum,__intr) \ +do { \ + diepint_data_t diepint = { 0 }; \ + diepint.b.__intr = 1; \ + dwc_write_reg32(DWC_REG_IN_EP_INTR(__epnum), \ + diepint.d32); \ +} while (0) + + diepint_data_t diepint = { 0 }; +// depctl_data_t diepctl = { 0 }; + uint32_t ep_intr; + uint32_t epnum = 0; + gintmsk_data_t intr_mask = {0}; + gintsts_data_t gintsts; + + DBG( "dwc_otg_pcd_handle_in_ep_intr()\n" ); + + /* Read in the device interrupt bits */ + ep_intr = (dwc_read_reg32(DWC_REG_DAINT) & + dwc_read_reg32( DWC_REG_DAINTMSK)); + ep_intr =( (ep_intr & 0xffff) ); + + + /* Clear the INEPINT in GINTSTS */ + /* Clear all the interrupt bits for all IN endpoints in DAINT */ + gintsts.d32 = 0; + gintsts.b.inepint = 1; + dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32); + dwc_write_reg32(DWC_REG_DAINT, 0xFFFF ); + flush_cpu_cache(); + + /* Service the Device IN interrupts for each endpoint */ + while ( ep_intr ) { + if (ep_intr&0x1) { + + diepint.d32 = (dwc_read_reg32( DWC_REG_IN_EP_INTR(epnum)) & + dwc_read_reg32(DWC_REG_DAINTMSK)); + /* Transfer complete */ + if ( diepint.b.xfercompl ) { + + + /* Disable the NP Tx FIFO Empty + * Interrrupt */ + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0); + + /* Clear the bit in DIEPINTn for this interrupt */ + CLEAR_IN_EP_INTR(epnum,xfercompl); + + /* Complete the transfer */ + if (epnum == 0) { + handle_ep0( 0 ); + } else { + complete_ep( epnum,1 ); + } + } + /* Endpoint disable */ + if ( diepint.b.epdisabled ) { + handle_in_ep_disable_intr( epnum ); + + /* Clear the bit in DIEPINTn for this interrupt */ + CLEAR_IN_EP_INTR(epnum,epdisabled); + } + /* AHB Error */ + if ( diepint.b.ahberr ) { + /* Clear the bit in DIEPINTn for this interrupt */ + CLEAR_IN_EP_INTR(epnum,ahberr); + } + /* TimeOUT Handshake (non-ISOC IN EPs) */ + if ( diepint.b.timeout ) { + handle_in_ep_timeout_intr( epnum ); + + CLEAR_IN_EP_INTR(epnum,timeout); + } + /** IN Token received with TxF Empty */ + if (diepint.b.intktxfemp) { +#if 0 + if (!ep->stopped && epnum != 0) { + diepmsk_data_t diepmsk = { 0}; + diepmsk.b.intktxfemp = 1; + dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 ); + start_next_request(ep); + } +#endif + CLEAR_IN_EP_INTR(epnum,intktxfemp); + } + /** IN Token Received with EP mismatch */ + if (diepint.b.intknepmis) { + CLEAR_IN_EP_INTR(epnum,intknepmis); + } + /** IN Endpoint NAK Effective */ + if (diepint.b.inepnakeff) { + CLEAR_IN_EP_INTR(epnum,inepnakeff); + } + } + epnum++; + ep_intr >>=1; + } + + return 1; + +#undef CLEAR_IN_EP_INTR +} +/** + * This function configures EP0 to receive SETUP packets. + * + * @todo NGS: Update the comments from the HW FS. + * + * -# Program the following fields in the endpoint specific registers + * for Control OUT EP 0, in order to receive a setup packet + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back + * setup packets) + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back + * to back setup packets) + * - In DMA mode, DOEPDMA0 Register with a memory address to + * store any setup packets received + * + */ +static void ep0_out_start(void) +{ + deptsiz0_data_t doeptsize0 = { 0}; + depctl_data_t doepctl = { 0 }; + + doeptsize0.b.supcnt = 3; + doeptsize0.b.pktcnt = 1; + doeptsize0.b.xfersize = 8*3; + + DBG("ep0_out_start()\n"); + dwc_write_reg32( DWC_REG_OUT_EP_TSIZE(0),doeptsize0.d32 ); + + + // EP enable + doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0)); + doepctl.b.epena = 1; + + doepctl.d32 = 0x80008000; + dwc_write_reg32(DWC_REG_OUT_EP_REG(0),doepctl.d32); + + flush_cpu_cache(); +} +/** + * This interrupt occurs when a USB Reset is detected. When the USB + * Reset Interrupt occurs the device state is set to DEFAULT and the + * EP0 state is set to IDLE. + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1) + * -# Unmask the following interrupt bits + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint) + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint) + * - DOEPMSK.SETUP = 1 + * - DOEPMSK.XferCompl = 1 + * - DIEPMSK.XferCompl = 1 + * - DIEPMSK.TimeOut = 1 + * -# Program the following fields in the endpoint specific registers + * for Control OUT EP 0, in order to receive a setup packet + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back + * setup packets) + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back + * to back setup packets) + * - In DMA mode, DOEPDMA0 Register with a memory address to + * store any setup packets received + * At this point, all the required initialization, except for enabling + * the control 0 OUT endpoint is done, for receiving SETUP packets. + */ +int32_t dwc_otg_pcd_handle_usb_reset_intr(void) +{ + + depctl_data_t doepctl = { 0}; + daint_data_t daintmsk = { 0}; + doepmsk_data_t doepmsk = { 0}; + diepmsk_data_t diepmsk = { 0}; + dcfg_data_t dcfg = { 0 }; + depctl_data_t diepctl = { 0}; + depctl_data_t diepctl_rd = { 0}; + grstctl_t resetctl = { 0 }; + dctl_data_t dctl = { 0 }; + int i = 0; + gintsts_data_t gintsts; + + + DBG("\nUSB RESET\n"); + + + /* Clear the Remote Wakeup Signalling */ + dctl.b.rmtwkupsig = 1; + dwc_modify_reg32( DWC_REG_DCTL,dctl.d32, 0 ); + + /* Disable all active IN EPs */ + diepctl.b.epdis = 1; + diepctl.b.snak = 1; + for (i=0; i < NUM_EP; i++) { + diepctl_rd.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(i)); + if (diepctl_rd.b.epena) { + dwc_write_reg32(DWC_REG_IN_EP_REG(i),diepctl.d32 ); + } + } + + /* Set NAK for all OUT EPs */ + doepctl.b.snak = 1; + for (i=0; i < NUM_EP; i++) { + dwc_write_reg32(DWC_REG_OUT_EP_REG(i), doepctl.d32 ); + } + + /* Flush the NP Tx FIFO */ + dwc_otg_flush_tx_fifo( 0 ); + /* Flush the Learning Queue */ + resetctl.b.intknqflsh = 1; + dwc_write_reg32( DWC_REG_GRSTCTL, resetctl.d32); + + daintmsk.b.inep0 = 1; + daintmsk.b.outep0 = 1; + dwc_write_reg32( DWC_REG_DAINTMSK, daintmsk.d32 ); + + doepmsk.b.setup = 1; + doepmsk.b.xfercompl = 1; + doepmsk.b.ahberr = 1; + doepmsk.b.epdisabled = 1; + dwc_write_reg32( DWC_REG_DOEPMSK, doepmsk.d32 ); + + diepmsk.b.xfercompl = 1; + diepmsk.b.timeout = 1; + diepmsk.b.epdisabled = 1; + diepmsk.b.ahberr = 1; + dwc_write_reg32( DWC_REG_DIEPMSK, diepmsk.d32 ); + /* Reset Device Address */ + dcfg.d32 = dwc_read_reg32( DWC_REG_DCFG); + dcfg.b.devaddr = 0; + dwc_write_reg32( DWC_REG_DCFG, dcfg.d32); + + /* setup EP0 to receive SETUP packets */ + ep0_out_start(); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.usbreset = 1; + dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32); + + flush_cpu_cache(); + return 1; +} + + +/////////////////////////////////////////////////////////////////// +int dwc_common_irq(void) +{ + int ret = 0; + gotgint_data_t gotgint; + + gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT); + if (gotgint.d32 == 0) + return 0; + if (gotgint.b.sesreqsucstschng) { + ERR("Session Request Success Status Change\n"); + } + if (gotgint.b.sesenddet) { + ERR("Session End Detected, Line Disconected\n"); + cb_4_dis_connect_intr(); + } + + dwc_write_reg32(DWC_REG_GOTGINT,gotgint.d32); // clear intr + + return ret; +} + +int dwc_pcd_irq(void) +{ + gintsts_data_t gintr_status; + gintsts_data_t gintr_msk; + + gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK); + gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS); + + if ((gintr_status.d32 & gintr_msk.d32)== 0) + return 0; + + DBG("irq gintmsk: 0x%08x\n",gintr_msk.d32); + DBG("irq gintrsts: 0x%08x\n",gintr_status.d32); + + gintr_status.d32 = gintr_status.d32 & gintr_msk.d32; + DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32); + + if (gintr_status.b.rxstsqlvl) { + dwc_otg_pcd_handle_rx_status_q_level_intr(); + pcd_out_completed(&this_pcd); + } + if (gintr_status.b.nptxfempty) { + dwc_otg_pcd_handle_np_tx_fifo_empty_intr( ); + } + + if (gintr_status.b.usbreset) { + dwc_otg_pcd_handle_usb_reset_intr( ); + } + if (gintr_status.b.enumdone) { + dwc_otg_pcd_handle_enum_done_intr(); + } + if (gintr_status.b.epmismatch) { + //dwc_otg_pcd_handle_ep_mismatch_intr( core_if ); + } + if (gintr_status.b.inepint) { + dwc_otg_pcd_handle_in_ep_intr(); + } + if (gintr_status.b.outepintr) { + dwc_otg_pcd_handle_out_ep_intr( ); + } + +#if 0 + if (gintr_status.b.otgintr) + { + gotgint_data_t gotgint; + + gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT); + if (gotgint.b.sesenddet) + { + printf("dis-connect-intr\n"); + cb_4_dis_connect_intr(); + } + } +#endif//#if 0 + + dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32); + flush_cpu_cache(); + return 0; +} + + + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd_irq.h b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd_irq.h new file mode 100644 index 0000000000..48cc165eac --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/dwc_pcd_irq.h @@ -0,0 +1,30 @@ +/* dwc driver irq header */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-30 @ Shanghai + * + */ +#ifndef __DWC_PCD_IRQ_H__ +#define __DWC_PCD_IRQ_H__ + +int dwc_pcd_irq(void); +int dwc_otg_irq(void); + +/** + * States of EP0. + */ +typedef enum ep0_state { + EP0_DISCONNECT, /* no host */ + EP0_IDLE, + EP0_IN_DATA_PHASE, + EP0_OUT_DATA_PHASE, + EP0_STATUS, + EP0_STALL, +} ep0state_e; + +extern int dwc_common_irq(void); + +extern int cb_4_dis_connect_intr(void); +#endif diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/optimus_core.c b/drivers/usb/gadget/v2_burning/v2_usb_tool/optimus_core.c new file mode 100644 index 0000000000..0f90ef18a4 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/optimus_core.c @@ -0,0 +1,65 @@ +#include <common.h> +#include "platform.h" +#include "usb_pcd.h" + +#include "usb_pcd.c" +#include "platform.c" +#include "dwc_pcd.c" +#include "dwc_pcd_irq.c" + +DECLARE_GLOBAL_DATA_PTR; + +int v2_usbburning(unsigned timeout) +{ + int cfg = EXT_CLOCK; + +#if defined(CONFIG_SILENT_CONSOLE) + gd->flags &= ~GD_FLG_SILENT; +#endif + + printf("Enter USB burn\n"); + set_usb_phy_config(cfg); + + usb_parameter_init(timeout); + + if (usb_pcd_init()) { + printf("Fail in usb_pcd_init\n"); + return __LINE__; + } + +#if (MESON_CPU_TYPE_MESON8 <= MESON_CPU_TYPE) + //AML_WATCH_DOG_DISABLE(); //disable watchdog +#endif// #if (MESON_CPU_TYPE_MESON8 <= MESON_CPU_TYPE) + + while (1) + { + //watchdog_clear(); //Elvis Fool + if (usb_pcd_irq()) + break; + } + return 0; +} + +int do_v2_usbtool (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int rc = 0; + unsigned timeout = (2 <= argc) ? simple_strtoul(argv[1], NULL, 0) : 0; + //if get burning tool identify command in pcToolWaitTime, then auto jump into burning mode + unsigned pcToolWaitTime = (3 <= argc) ? simple_strtoul(argv[2], NULL, 0) : 0; + + optimus_work_mode_set(OPTIMUS_WORK_MODE_USB_UPDATE); + setenv(_ENV_TIME_OUT_TO_AUTO_BURN, pcToolWaitTime ? argv[2] : ""); + + rc = v2_usbburning(timeout); + /*close_usb_phy_clock(0);*/ + + return rc; +} + + +U_BOOT_CMD( + update, 3, 0, do_v2_usbtool, + "Enter v2 usbburning mode", + "usbburning timeout" +); + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/optimus_transform.c b/drivers/usb/gadget/v2_burning/v2_usb_tool/optimus_transform.c new file mode 100644 index 0000000000..eba0668d50 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/optimus_transform.c @@ -0,0 +1,545 @@ +#include "../v2_burning_i.h" +#include "usb_pcd.h" +#include "platform.h" +#include <partition_table.h> + +#define MYDBG(fmt ...) printf("OPT]"fmt) + +#ifdef CONFIG_CMD_AML +#define USB_BURN_POWER_CONTROL 1 +#endif// #ifdef CONFIG_CMD_AML + +#ifndef CONFIG_UNIFY_KEY_MANAGE +int v2_key_command(const int argc, char * const argv[], char *info) +{ + + DWN_ERR("burn key not supported as CONFIG_UNIFY_KEY_MANAGE undef!!\n"); + return OPT_DOWN_FAIL; +} +#endif//#ifndef CONFIG_UNIFY_KEY_MANAGE + +static inline int str2long(const char *p, unsigned long *num) +{ + char *endptr; + *num = simple_strtoul(p, &endptr, 0); + return (*p != '\0' && *endptr == '\0') ? 1 : 0; +} + +static inline int str2longlong(char *p, unsigned long long *num) +{ + char *endptr; + + *num = simple_strtoull(p, &endptr, 16); + if (*endptr != '\0') + { + switch (*endptr) + { + case 'g': + case 'G': + *num<<=10; + case 'm': + case 'M': + *num<<=10; + case 'k': + case 'K': + *num<<=10; + endptr++; + break; + } + } + + return (*p != '\0' && *endptr == '\0') ? 1 : 0; +} + +static int opimus_func_write_bootloader(unsigned long addr) +{ + int ret = 0; + loff_t size = 0; + + size = 0x60000;//FIXME: 256K at most ?? + + ret = store_boot_write((u8*)addr, (loff_t)0, size); + + return ret; +} + +//[0]write_raw_img [1]part_name [2]address, [3]offset, [4]size +int opimus_func_write_raw_img(int argc, char *argv[], char *info) +{ + int ret = 0; + u64 addr; + u64 off, size; + const char* partName = argv[1]; + + if (strcmp(partName, "bootloader") == 0) + { + addr = simple_strtoul(argv[2], NULL, 0); + return opimus_func_write_bootloader(addr); + } + + addr = simple_strtoull(argv[2], NULL, 0); + off = simple_strtoull(argv[3], NULL, 0); + size = simple_strtoul(argv[4], NULL, 0); + + printf("write_raw_img part %s offset 0x%x, size 0x%x, addr 0x%llx\n", argv[1], (u32)off, (u32)size, addr); + ret = store_write_ops((u8*)partName, (u8*)addr, off, size); + + return ret; +} + + +//read_raw_img partName memAddr partOffset readSzInBytes +int opimus_func_read_raw_img(int argc, char *argv[], char *info) +{ + int ret = 0; + unsigned long addr; + u64 off, size; + unsigned char* partName = (unsigned char*)argv[1]; + + MYDBG("%s, %s, %s, %s\n", __func__, argv[0], argv[1], argv[2]); + + if (!(str2long(argv[2], &addr))) + { + sprintf(info, "failed:'%s' is not a number\n", argv[2]); + return -1; + } + if (!(str2longlong(argv[3], &off))) + { + sprintf(info, "failed:'%s' is not a number\n", argv[3]); + return -1; + } + if (!(str2longlong(argv[4], &size))) + { + sprintf(info, "failed:'%s' is not a number\n", argv[4]); + return -1; + } + + ret = store_read_ops(partName, (u8*)addr, off, size); + + return ret; +} + +int optimus_simg2part (int argc, char * const argv[], char *info) +{ + int ret = -1; + const char* partition_name = argv[1]; + u8* simg_addr = (u8*)simple_strtoul(argv[2], NULL, 16); + u32 pktSz = simple_strtoul(argv[3], NULL, 0); + const unsigned memAddrTop = OPTIMUS_DOWNLOAD_SPARSE_INFO_FOR_VERIFY;//this address backup the chunk info, don't overwrite it! + + if (argc < 4) { + sprintf(info, "failed: used [%s partName memAddr, pktSz]\n", argv[0]); + DWN_ERR(info); + return __LINE__; + } + if (!pktSz || !simg_addr) { + sprintf(info, "simg_addr(%s) or pktSz(%s)error\n", argv[2], argv[3]); + DWN_ERR(info); + return __LINE__; + } + + if ((unsigned long)simg_addr + pktSz > memAddrTop) { + sprintf(info, "failed:simg_addr(0x%p) + pktSz(0x%x) > memAddrTop(0x%x)\n", simg_addr, pktSz, memAddrTop); + DWN_ERR(info); + return __LINE__; + } + +#if 0 + ret = simg_write_to_partition(partition_name, simg_addr); +#else /* ----- not 0 ----- */ +#if 0 + ret = optimus_simg_probe(simg_addr, pktSz); + if (!ret) { + sprintf(info, "failed:format error, not a sparse image at addr %s\n", argv[2]); + DWN_ERR(info); + return __LINE__; + } +#endif /* ----- 0 ----- */ + ret = optimus_parse_img_download_info(partition_name, pktSz, "sparse", "store", 0); + if (ret) { + sprintf(info, "failed:init download info for part(%s)\n", partition_name); + DWN_ERR(info); + return __LINE__; + } + unsigned writeLen = optimus_download_img_data(simg_addr, pktSz, info); + if (writeLen != pktSz) { + DWN_ERR("failed when burn simg!, want(0x%x), write(0x%x)\n", pktSz, writeLen); + return __LINE__; + } +#endif /* ----- not 0 ----- */ + + return ret; +} + +int optimus_sha1sum (int argc, char * const argv[], char *info) +{ + unsigned buffermax = 64<<20; + unsigned char* sha1_addr = (u8*)0x81000000; + int ret = -1; + char *partition_name; + unsigned long long Bits_need_read = 0,partition_offset = 0; + unsigned long long verify_len = 0; + u8 output[20]; + char *sha1_verify = NULL; + char sha1_value[41]; + int i = 1; + + memset(sha1_value, 0, sizeof(sha1_value)); + + if (3 == argc) //test to sha1sum memory: sha1sum memAddr, length + { + unsigned verify_len = 0; + unsigned char* pBuf = NULL; + + pBuf = (unsigned char*)simple_strtoul(argv[1], NULL, 0); + verify_len = simple_strtoul(argv[2], NULL, 0); + + printf("Gen sha1sum: addr 0x%p, len 0x%x\n", pBuf, verify_len); + sha1_csum(pBuf, verify_len, output); + + sprintf(sha1_value, "%02x", output[0]); + for (i = 1; i < 20; ++i) + { + sprintf(sha1_value, "%02x", output[0]); + for (; i < 20; ++i) + { + sprintf(sha1_value, "%s%02x", sha1_value, output[i]); + } + /*sprintf(sha1_value, "%s%02x", sha1_value, output[i]);*/ + } + printf("gen sha1sum %s\n", sha1_value); + return 0; + } + + if (argc != 4)//argv:cmd,partition_name,verify_len,sha1_verify + { + printf("bad args---sha1sum cmd need 3 args\n"); + strcpy(info, "failed:need 3 args"); + return -1; + } + + partition_name = argv[1]; + + verify_len = simple_strtoull (argv[2], NULL, 10); + sha1_verify = argv[3]; + + //circularly verify 128M datas readed in memory 0x81000000 + sha1_context ctx; + sha1_starts (&ctx); + + Bits_need_read = verify_len; + partition_offset = 0; + while (Bits_need_read > buffermax) + { + ret = store_read_ops((unsigned char*)partition_name, (unsigned char *) sha1_addr, partition_offset, buffermax); + if (ret) { + DWN_ERR("Fail to read data from %s at offset %llx size %x\n", partition_name, partition_offset, buffermax); + return __LINE__; + } + sha1_update (&ctx, (unsigned char *) sha1_addr, buffermax); + Bits_need_read = Bits_need_read - buffermax; + partition_offset += buffermax; + printf("current Bits_need_read is 0x%llx, buffermax is : 0x%x\n",Bits_need_read,buffermax); + for (i = 0; i < 5; i++)sprintf(sha1_value,"%s%08x", sha1_value, (unsigned)ctx.state[i]) ;//5*8=40 + printf("current sha1_value is %s\n", sha1_value); + } + + ret = store_read_ops((unsigned char*)partition_name, (unsigned char *) sha1_addr, partition_offset, Bits_need_read); + if (ret) { + DWN_ERR("Fail to read data from %s at offset %llx size %x\n", partition_name, partition_offset, buffermax); + return __LINE__; + } + + sha1_update (&ctx, (unsigned char *) sha1_addr, Bits_need_read); + sha1_finish (&ctx, output); + //????????????? + printf("SHA1 for %s %p,verify_len:0x%llx ==>",partition_name, sha1_addr,verify_len); + + for (i = 0; i < 20; i++) + { + printf("%02x", output[i]); + //sha1_value[i] = output[i]; + sprintf(sha1_value,"%s%02x", sha1_value, output[i]); + } + //sha1_value[21] = '\0'; + printf("\n"); + + printf("sha1_verify= %s\n", sha1_verify); + printf("sha1_value = %s\n", sha1_value); + if (strncmp(sha1_verify, sha1_value, 40) == 0) + { + ret = 0; + strcpy(info, "success"); + } + else + { + ret = -1; + strcpy(info, "failed"); + } + + return ret; +} + + +int optimus_mem_md (int argc, char * const argv[], char *info) +{ + ulong addr, length = 0x100; + int size; + int rc = 0; + + if ((size = cmd_get_data_size(argv[0], 4)) < 0) + return 1; + + /* Address is specified since argc > 1 + */ + addr = simple_strtoul(argv[1], NULL, 16); + + /* If another parameter, it is the length to display. + * Length is the number of objects, not number of bytes. + */ + if (argc > 2) + length = simple_strtoul(argv[2], NULL, 16); + + /* Print the lines. */ + print_buffer(addr, (void*)addr, size, length, 16/size); + strcpy(info, "success"); + return rc; +} + +int set_low_power_for_usb_burn(int arg, char* buff) +{ + if (OPTIMUS_WORK_MODE_USB_PRODUCE == optimus_work_mode_get()) { + return 0;//just return ok as usb producing mode as LCD not initialized yet! + } + +#if defined(CONFIG_VIDEO_AMLLCD) + int ret1=0; + //axp to low power off LCD, no-charging + MYDBG("To close LCD\n"); + ret1 = run_command("video dev disable", 0); + if (ret1) { + if (buff) sprintf(buff, "Fail to close back light") ; + printf("Fail to close back light\n"); + /*return __LINE__;*/ + } +#endif// #if defined(CONFIG_VIDEO_AMLLCD) + +#if USB_BURN_POWER_CONTROL + int ret2=0; + //limit vbus curretn to 500mA, i.e, if hub is 4A, 8 devices at most, arg3 to not set_env as it's not inited yet!! + MYDBG("set_usbcur_limit 500 0\n"); + ret2 = run_command("set_usbcur_limit 500 0", 0); + if (ret2) { + if (buff) sprintf(buff, "Fail to set_usb_cur_limit") ; + printf("Fail to set_usb_cur_limit\n"); + return __LINE__; + } +#endif//#if USB_BURN_POWER_CONTROL + + return 0; +} + +//I assume that store_inited yet when "bootloader_is_old"!!!! +int optimus_erase_bootloader(char* info) +{ + int ret = 0; + +#if ROM_BOOT_SKIP_BOOT_ENABLED + optimus_enable_romboot_skip_boot(); +#else + if (SPI_EMMC_FLAG == device_boot_flag || SPI_NAND_FLAG == device_boot_flag) { + run_command("sf probe 2", 0); + } + ret = store_erase_ops((u8*)"boot", 0, 0, 0); +#endif// #if ROM_BOOT_SKIP_BOOT_ENABLED + + return ret; +} + +int cb_4_dis_connect_intr(void) +{ + if (optimus_burn_complete(OPTIMUS_BURN_COMPLETE__QUERY)) + { + close_usb_phy_clock(0);//disconnect to avoid k200 platfrom which can't relally poweroff + DWN_MSG("User Want poweroff after disconnect\n"); + optimus_poweroff(); + } + + return 0; +} + +static int _cpu_temp_in_valid_range(int argc, char* argv[], char* errInfo) +{ + int ret = 0; + int minTemp = 0; + int maxTemp = 0; + int cpu_temp = 0; + char* env_cpu_temp = NULL; + + if (3 > argc) { + sprintf(errInfo, "argc %d < 3 is invalid\n", argc); + return __LINE__; + } + minTemp = simple_strtol(argv[1], NULL, 0); + maxTemp = simple_strtol(argv[2], NULL, 0); + if (minTemp <=0 || maxTemp <= 0 || minTemp >= maxTemp) { + sprintf(errInfo, "Invalid:minTemp=%s, maxTemp=%s\n", argv[1], argv[2]); + return __LINE__; + } + ret = run_command("cpu_temp -p", 0); + if (ret < 0) { + sprintf(errInfo, "cmd[cpu_temp] failed\n"); + return __LINE__; + } + env_cpu_temp = getenv("tempa"); + if (!env_cpu_temp) { + sprintf(errInfo, "Can't get cpu_temp, cpu is not calibrated.\n"); + return __LINE__; + } + cpu_temp = simple_strtol(env_cpu_temp, NULL, 0); + ret = (cpu_temp >= minTemp && cpu_temp <= maxTemp) ? 0 : __LINE__; + if (!ret) { + sprintf(errInfo, "%s", env_cpu_temp); + } + else{ + sprintf(errInfo, "%s is out of temp range[%d, %d], errInfo[%s]\n", env_cpu_temp, minTemp, maxTemp, getenv("err_info_tempa")); + } + + return ret; +} + +int optimus_working (const char *cmd, char* buff) +{ + static char cmdBuf[CMD_BUFF_SIZE] = {0}; + int ret = 0; + int argc = 33; + char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ + /*printf("reboot_mode [%8x, %8x]\n", P_AO_RTI_STATUS_REG1);*/ + const char* optCmd = NULL; + + memset(buff, 0, CMD_BUFF_SIZE); + memcpy(cmdBuf, cmd, CMD_BUFF_SIZE); + if ((argc = cli_simple_parse_line(cmdBuf, argv)) == 0) + { + strcpy(buff, "failed:no command at all"); + printf("no command at all\n"); + return -1; /* no command at all */ + } + optCmd = argv[0]; + + if (!strcmp("low_power", optCmd)) + { + ret = set_low_power_for_usb_burn(1, buff); + } + else if(strcmp(optCmd, "disk_initial") == 0) + { + unsigned erase = argc > 1 ? simple_strtoul(argv[1], NULL, 0) : 0; + + ret = optimus_storage_init(erase); + } + else if(!strcmp(optCmd, "bootloader_is_old")) + { + ret = is_tpl_loaded_from_usb(); + if (ret)sprintf(buff, "Failed, bootloader is new\n") ; + } + else if(!strcmp(optCmd, "erase_bootloader")) + { + ret = optimus_erase_bootloader(buff); + + if (ret)sprintf(buff, "Failed to erase bootloader\n") ; + } + else if(strcmp(optCmd, "write_raw_img") == 0) + { + ret = opimus_func_write_raw_img(argc, argv, buff); + } + else if(strcmp(optCmd, "read_raw_img") == 0) + { + ret = opimus_func_read_raw_img(argc, argv, buff); + } + else if(strcmp(optCmd, "simg2part") == 0) + { + ret = optimus_simg2part(argc, argv, buff); + } + else if(strcmp(optCmd, "reset") == 0) + { + close_usb_phy_clock(0); + optimus_reset(OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL); + } + else if(strcmp(optCmd, "poweroff") == 0) + { + optimus_poweroff(); + } + else if(strncmp(optCmd, "md", 2) == 0) + { + ret = optimus_mem_md(argc, argv, buff); + } + else if(!strcmp(optCmd, "download") || !strcmp("upload", optCmd)) + { + ret = optimus_parse_download_cmd(argc, argv); + } + else if(!strcmp("key", optCmd)) + { + ret = v2_key_command(argc, argv, buff); + } + else if(!strcmp("verify", optCmd)) + { + ret = optimus_media_download_verify(argc, argv, buff); + } + else if(!strcmp("save_setting", optCmd)) + { + ret = optimus_set_burn_complete_flag(); + } + else if(!strcmp("burn_complete", optCmd)) + { + unsigned choice = simple_strtoul(argv[1], NULL, 0);//0 is poweroff, 1 is reset system + + if (OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_DISCONNECT != choice) {//disconnect except OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_DISCONNECT + close_usb_phy_clock(0);//some platform can't poweroff but dis-connect needed by pc + } + ret = optimus_burn_complete(choice); + } + else if(strncmp(cmd,"sha1sum",(sizeof("sha1sum")-1)) == 0) + { + ret = optimus_sha1sum(argc, argv, buff); + } + else if(!strcmp(optCmd, "support_tempcontrol")) + { +#ifndef CONFIG_CMD_CPU_TEMP + ret = __LINE__; +#else + ret = run_command("cpu_temp -p", 0); + if (ret <= 0) { + DWN_MSG("Fail in cmd[cpu_temp]\n"); + ret = __LINE__; + } + else{ + ret = 0; + } +#endif// #ifdef CONFIG_CMD_CPU_TEMP + sprintf(buff + 7, "cpu temp control cmd %s supported.\n", ret ? "NOT" : "DO");//7 == strlen("failed") + } + else if(!strcmp(optCmd, "tempcontrol")) + { + ret = _cpu_temp_in_valid_range(argc, argv, buff + 7); + } + else + { + int flag = 0; + ret = run_command(cmd, flag); + DWN_MSG("ret = %d\n", ret); + ret = ret < 0 ? ret : 0; + } + + if (ret) + { + memcpy(buff, "failed:", strlen("failed:"));//use memcpy but not strcpy to not overwrite storage/key info + } + else + { + memcpy(buff, "success", strlen("success"));//use memcpy but not strcpy to not overwrite storage/key info + } + + printf("[info]%s\n",buff); + return ret; +} + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/platform.c b/drivers/usb/gadget/v2_burning/v2_usb_tool/platform.c new file mode 100644 index 0000000000..8c4fc4b74c --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/platform.c @@ -0,0 +1,161 @@ +/* platform dirver header */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-24 @ Shanghai + * + */ + #include "platform.h" + +/*CONFIG_AML_MESON_8 include m8, m8baby, m8m2, etc... defined in cpu.h*/ +#if !( defined(CONFIG_AML_MESON_GX) ) +#error "platform is not GX !!" +#endif//#if + +/* + cfg = 0 : EXT clock + cfg = 1 : INT clock + */ + +#if 1 +#define PREI_USB_PHY_A_REG_BASE 0xC0000000 //0x2100 +#define PREI_USB_PHY_B_REG_BASE 0xC1108420 //0X2108 +#else +#define PREI_USB_PHY_A_REG_BASE P_USB_ADDR0 +#define PREI_USB_PHY_B_REG_BASE P_USB_ADDR1 +#endif//#if 0 + +#ifdef __USE_PORT_B +#define PREI_USB_PHY_REG_BASE PREI_USB_PHY_B_REG_BASE +#else +#define PREI_USB_PHY_REG_BASE PREI_USB_PHY_A_REG_BASE +#endif +//#define P_RESET1_REGISTER (volatile unsigned long *)0xc1104408 +#define P_RESET1_REGISTER_USB (volatile unsigned long *)0xc1104408 + +#define USB_CLK_SEL_XTAL 0 +#define USB_CLK_SEL_XTAL_DIV_2 1 +#define USB_CLK_SEL_DDR_PLL 2 +#define USB_CLK_SEL_MPLL_OUT0 3 +#define USB_CLK_SEL_MPLL_OUT1 4 +#define USB_CLK_SEL_MPLL_OUT2 5 +#define USB_CLK_SEL_FCLK_DIV2 6 +#define USB_CLK_SEL_FCLK_DIV3 7 + +typedef struct usb_aml_regs { + volatile uint32_t config; + volatile uint32_t ctrl; + volatile uint32_t endp_intr; + volatile uint32_t adp_bc; + volatile uint32_t dbg_uart; + volatile uint32_t test; + volatile uint32_t tune; +} usb_aml_regs_t; + +typedef union usb_config_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned clk_en :1; + unsigned clk_sel :3; + unsigned clk_div :7; + unsigned reserved0 :1; + unsigned clk_32k_alt_sel:1; + unsigned reserved1 :15; + unsigned test_trig :1; + } b; +} usb_config_data_t; + +typedef union usb_ctrl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned soft_prst:1; + unsigned soft_hreset:1; + unsigned ss_scaledown_mode:2; + unsigned clk_det_rst:1; + unsigned intr_sel:1; + unsigned reserved:2; + unsigned clk_detected:1; + unsigned sof_sent_rcvd_tgl:1; + unsigned sof_toggle_out:1; + unsigned not_used:4; + unsigned por:1; + unsigned sleepm:1; + unsigned txbitstuffennh:1; + unsigned txbitstuffenn:1; + unsigned commononn:1; + unsigned refclksel:2; + unsigned fsel:3; + unsigned portreset:1; + unsigned thread_id:6; + } b; +} usb_ctrl_data_t; + +void set_usb_phy_config(int cfg) +{ + + const int time_dly = 5000; + usb_aml_regs_t * usb_aml_regs = (usb_aml_regs_t * )PREI_USB_PHY_REG_BASE; + usb_config_data_t config; + usb_ctrl_data_t control; + + /*CLK_GATE_ON(USB0);*/ + //if(!IS_CLK_GATE_ON(USB0)){ + // SET_CBUS_REG_MASK(GCLK_REG_USB0, GCLK_MASK_USB0); + //} + /*printf("%s %d\n", __func__, __LINE__);*/ + cfg = cfg;//avoid compiler warning + /**P_RESET1_REGISTER = (1<<2);//usb reset*/ + *P_RESET1_REGISTER_USB = (1<<2);//usb reset + udelay(time_dly);//by Sam: delay after reset + + config.d32 = usb_aml_regs->config; + +// config.b.clk_sel = 0; +// config.b.clk_div = 1; +// config.b.clk_32k_alt_sel = 1; + usb_aml_regs->config = config.d32; + + control.d32 = usb_aml_regs->ctrl; + control.b.fsel = 5; + control.b.por = 1; + usb_aml_regs->ctrl = control.d32; + udelay(time_dly); + + control.b.por = 0; + usb_aml_regs->ctrl = control.d32; + udelay(time_dly);//by Sam: delay 0.5s to wait usb clam down + + control.d32 = usb_aml_regs->ctrl; + if (!control.b.clk_detected) { + printf("Error, usb phy clock not detected!\n"); + } + + return; +} + +#if 0 +int chip_watchdog(void) +{ + watchdog_clear(); + return 0; +}; +#endif + +void close_usb_phy_clock(int cfg) +{ + cfg = cfg;//avoid compiler warning + + dwc_otg_pullup(0);//disconnect + __udelay(20); + /*dwc_otg_power_off_phy();*///Don't call this as it may cause pull-down failed!!!! + run_command("sleep 1", 0);//sleep sometime to improve pc compatibility!! + + return; +} + + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/platform.h b/drivers/usb/gadget/v2_burning/v2_usb_tool/platform.h new file mode 100644 index 0000000000..b8c9227075 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/platform.h @@ -0,0 +1,155 @@ +/* platform header */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-24 @ Shanghai + * + */ + +#ifndef __PLATFORM_H__ +#define __PLATFORM_H__ + +#include <asm/arch/register.h> + +//#include "romboot.h" +//Elvis Fool +//#pragma Offwarn(88) /* disable "Expression has no side-effects" print debug info*/ + +/* A3,CS2,M3 chip, PORT_A is OTG, work as ROM Boot port */ +#ifdef __USE_PORT_B +#define PORT_REG_OFFSET 0x80000 +#else +#define PORT_REG_OFFSET 0 +#endif + + +#define DWC_REG_BASE (0xC9000000 + PORT_REG_OFFSET) + +#define PERI_BASE_ADDR 0xc1100000 +#define ISABASE 0x01000000 + +#define PREI_USB_PHY_REG 0xc0000000 //0xC1108400 + +#define PREI_USB_PHY_A_REG3 0xc0000000 +#define PREI_USB_PHY_B_REG4 0xc0000020 + +#define PREI_USB_PHY_A_POR (1 << 0) +#define PREI_USB_PHY_B_POR (1 << 1) +#define PREI_USB_PHY_CLK_SEL (7 << 5) // changed from A1H +#define PREI_USB_PHY_CLK_GATE (1 << 8) +#define PREI_USB_PHY_B_AHB_RSET (1 << 11) +#define PREI_USB_PHY_B_CLK_RSET (1 << 12) +#define PREI_USB_PHY_B_PLL_RSET (1 << 13) +#define PREI_USB_PHY_A_AHB_RSET (1 << 17) +#define PREI_USB_PHY_A_CLK_RSET (1 << 18) +#define PREI_USB_PHY_A_PLL_RSET (1 << 19) +#define PREI_USB_PHY_A_DRV_VBUS (1 << 20) +#define PREI_USB_PHY_B_DRV_VBUS (1 << 21) +#define PREI_USB_PHY_B_CLK_DETECT (1 << 22) +#define PREI_USB_PHY_CLK_DIV (0x7f << 24) +#define PREI_USB_PHY_A_CLK_DETECT (1 << 31) + +#define PREI_USB_PHY_A_REG3_IDDIG_OVR (1 << 23) +#define PREI_USB_PHY_A_REG3_IDDIG_VAL (1 << 24) + +#define PREI_USB_PHY_B_REG4_IDDIG_OVR (1 << 23) +#define PREI_USB_PHY_B_REG4_IDDIG_VAL (1 << 24) + + + +/***********************************************/ +#define WRITE_PERI_REG(reg, val) *(volatile unsigned *)(PERI_BASE_ADDR + ((reg)<<2)) = (val) +#define READ_PERI_REG(reg) (*(volatile unsigned *)(PERI_BASE_ADDR + ((reg)<<2))) + +#define CLEAR_PERIPHS_REG_BITS(reg, mask) WRITE_PERI_REG(reg, (READ_PERI_REG(reg)&(~(mask)))) +#define SET_PERIPHS_REG_BITS(reg, mask) WRITE_PERI_REG(reg, (READ_PERI_REG(reg)|(mask))) + +#define WRITE_ISA_REG(reg, val) *(volatile unsigned *)(ISABASE + (reg)) = (val) +#define READ_ISA_REG(reg) (*(volatile unsigned *)(ISABASE + (reg))) + +#define CLEAR_ISA_REG_MASK(reg, mask) WRITE_ISA_REG(reg, (READ_ISA_REG(reg)&(~mask))) +#define SET_ISA_REG_MASK(reg, mask) WRITE_ISA_REG(reg, (READ_ISA_REG(reg)|(mask))) +/***********************************************/ + + + + + +#define IREG_TIMER_E_COUNT 0x2655 + + +#define flush_cpu_cache() + + +#define dwc_write_reg32(x, v) (*(volatile uint32_t *)(unsigned long)(x + DWC_REG_BASE))=v +#define dwc_read_reg32(x) (*(volatile uint32_t*)(unsigned long)(x + DWC_REG_BASE)) +// void dwc_modify_reg32( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) +#define dwc_modify_reg32(x, c, s) (*(volatile uint32_t *)(x + DWC_REG_BASE))=( ((dwc_read_reg32(x)) & (~c)) | (s)) + +#define get_unaligned(ptr) (((__u8 *)ptr)[0] | (((__u8 *)ptr)[1]<<8) | (((__u8 *)ptr)[2]<<16) | (((__u8 *)ptr)[3]<<24)) +#define get_unaligned_16(ptr) (((__u8 *)ptr)[0] | (((__u8 *)ptr)[1]<<8)) +#define get_unaligned_32(ptr) (((__u8 *)ptr)[0] | (((__u8 *)ptr)[1]<<8) | (((__u8 *)ptr)[2]<<16) | (((__u8 *)ptr)[3]<<24)) + +#if 0 +#define __constant_cpu_to_le16(x) (x) +#define __constant_cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) + +#ifndef max +#define max(a, b) (((a) > (b))? (a): (b)) +#endif +#ifndef min +#define min(a, b) (((a) < (b))? (a): (b)) +#endif + +#endif//#if 0 + +#define EXT_CLOCK 0 +#define INT_CLOCK 1 + + +// 32 bit TimerE, 1us +#define USB_ROM_CONN_TIMEOUT 5*1000*1000 //us (5s timeout,) + + +/* Meet with spec */ +#define USB_ROM_VER_MAJOR 0 +#define USB_ROM_STAGE_MAJOR 0 +#define USB_ROM_STAGE_MINOR 16 // IPL = 0, SPL = 8, TPL = 16 + +#ifdef CONFIG_M6 +#define USB_ROM_VER_MINOR 8 // SPEC Version +#else +#define USB_ROM_VER_MINOR 7 // SPEC Version +#endif + +#if 1 +#define PRINTF(x...) do{}while(0) +#else +#define PRINTF(x...) printf(x) +#endif + +#define ERR(x...) printf(x) +#define DBG(x...) PRINTF(x) +#define USB_ERR(x...) printf("USBErr:%d", __LINE__),printf(x) +#define USB_DBG(x...) PRINTF(x) + + +void set_usb_phy_config(int cfg); +void close_usb_phy_clock(int cfg); +void usb_parameter_init(int timeout); +int chip_utimer_set(int val); +int chip_watchdog(void); +#define udelay __udelay +#define wait_ms(a) udelay(a*1000); +int update_utime(void); +int get_utime(void); +//int chip_watchdog(void); +//#define usb_memcpy(dst,src,len) rom_memcpy((unsigned)src,(unsigned)dst,(unsigned)len) +//#define usb_memcpy_32bits(dst,src,len) rom_memcpy((unsigned)src,(unsigned)dst,(unsigned)len) + +#endif diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_ch9.h b/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_ch9.h new file mode 100644 index 0000000000..9b52b67352 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_ch9.h @@ -0,0 +1,676 @@ +#ifndef __LINUX_USB_CH9_H +#define __LINUX_USB_CH9_H + +/** + * @file usb_ch9.h + * @brief This file holds USB constants and structures that are needed for USB + * device APIs. These are used by the USB device model, which is defined + * in chapter 9 of the USB 2.0 specification. Linux has several APIs in C + * that need these: + * + * - the master/host side Linux-USB kernel driver API; + * - the "usbfs" user space API; and + * - the Linux "gadget" slave/device/peripheral side driver API. + * + * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems + * act either as a USB master/host or as a USB slave/device. That means + * the master and slave side APIs benefit from working well together. + * + * There's also "Wireless USB", using low power short range radios for + * peripheral interconnection but otherwise building on the USB framework. + * + * @addtogroup usb_core + */ +/*@{*/ + +#include <linux/types.h> + +/******************************************************* +* CONTROL REQUEST SUPPORT +********************************************************/ + +/// USB directions, to device +/// This bit flag is used in endpoint descriptors' bEndpointAddress field. +/// It's also one of three fields in control requests bRequestType. +#define USB_DIR_OUT 0 +/// USB directions, to host +/// This bit flag is used in endpoint descriptors' bEndpointAddress field. +/// It's also one of three fields in control requests bRequestType. +#define USB_DIR_IN 0x80 + +/// USB types, the second of three bRequestType fields +#define USB_TYPE_MASK (0x03 << 5) +/// USB types, the second of three bRequestType fields +#define USB_TYPE_STANDARD (0x00 << 5) +/// USB types, the second of three bRequestType fields +#define USB_TYPE_CLASS (0x01 << 5) +/// USB types, the second of three bRequestType fields +#define USB_TYPE_VENDOR (0x02 << 5) +/// USB types, the second of three bRequestType fields +#define USB_TYPE_RESERVED (0x03 << 5) + +/// USB recipients, the third of three bRequestType fields +#define USB_RECIP_MASK 0x1f +/// USB recipients, the third of three bRequestType fields +#define USB_RECIP_DEVICE 0x00 +/// USB recipients, the third of three bRequestType fields +#define USB_RECIP_INTERFACE 0x01 +/// USB recipients, the third of three bRequestType fields +#define USB_RECIP_ENDPOINT 0x02 +/// USB recipients, the third of three bRequestType fields +#define USB_RECIP_OTHER 0x03 + +/* + * Standard requests, for the bRequest field of a SETUP packet. + * + * These are qualified by the bRequestType field, so that for example + * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved + * by a GET_STATUS request. + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +/// Wireless USB +#define USB_REQ_SET_ENCRYPTION 0x0D/ + +#define USB_REQ_GET_ENCRYPTION 0x0E +#define USB_REQ_SET_HANDSHAKE 0x0F +#define USB_REQ_GET_HANDSHAKE 0x10 +#define USB_REQ_SET_CONNECTION 0x11 +#define USB_REQ_SET_SECURITY_DATA 0x12 +#define USB_REQ_GET_SECURITY_DATA 0x13 +#define USB_REQ_SET_WUSB_DATA 0x14 +#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 +#define USB_REQ_LOOPBACK_DATA_READ 0x16 +#define USB_REQ_SET_INTERFACE_DS 0x17 + +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +/// (read only) +#define USB_DEVICE_SELF_POWERED 0 + +/// dev may initiate wakeup +#define USB_DEVICE_REMOTE_WAKEUP 1 + +/// (wired high speed only) +#define USB_DEVICE_TEST_MODE 2 + +/// (wireless) +#define USB_DEVICE_BATTERY 2 + +/// (otg) dev may initiate HNP +#define USB_DEVICE_B_HNP_ENABLE 3 + +/// (wireless +#define USB_DEVICE_WUSB_DEVICE 3 + +/// (otg) RH port supports HNP +#define USB_DEVICE_A_HNP_SUPPORT 4 + +/// (otg) other RH port does +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 + +/// (special devices only) +#define USB_DEVICE_DEBUG_MODE 6 + + + + + + +/// IN/OUT will STALL +#define USB_ENDPOINT_HALT 0 + + +#define USB_SETUP_PACKET_SIZE 8 + +/** + * SETUP data for a USB device control request + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + * + * Note that the driver for any interface can issue control requests. + * For most devices, interfaces don't coordinate with each other, so + * such requests may be made at any time. + */ +struct usb_ctrlrequest { + /// matches the USB bmRequestType field + __u8 bRequestType; + + /// matches the USB bRequest field + __u8 bRequest; + + /// matches the USB wValue field (le16 byte order) + __u16 wValue; + + /// matches the USB wIndex field (le16 byte order) + __u16 wIndex; + + /// matches the USB wLength field (le16 byte order) + __u16 wLength; +} __attribute__ ((packed)); +typedef struct usb_ctrlrequest usb_ctrlrequest_t; + + +/* + * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or + * (rarely) accepted by SET_DESCRIPTOR. + * + * Note that all multi-byte values here are encoded in little endian + * byte order "on the wire". But when exposed through Linux-USB APIs, + * they've been converted to cpu byte order. + */ + +/* + * Descriptor types ... USB 2.0 spec table 9.5 + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 +/* these are from a minor usb 2.0 revision (ECN) */ +#define USB_DT_OTG 0x09 +#define USB_DT_DEBUG 0x0a +#define USB_DT_INTERFACE_ASSOCIATION 0x0b +/* these are from the Wireless USB spec */ +#define USB_DT_SECURITY 0x0c +#define USB_DT_KEY 0x0d +#define USB_DT_ENCRYPTION_TYPE 0x0e +#define USB_DT_BOS 0x0f +#define USB_DT_DEVICE_CAPABILITY 0x10 +#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 + +/// conventional codes for class-specific descriptors +#define USB_DT_CS_DEVICE 0x21 +/// conventional codes for class-specific descriptors +#define USB_DT_CS_CONFIG 0x22 +/// conventional codes for class-specific descriptors +#define USB_DT_CS_STRING 0x23 +/// conventional codes for class-specific descriptors +#define USB_DT_CS_INTERFACE 0x24 +/// conventional codes for class-specific descriptors +#define USB_DT_CS_ENDPOINT 0x25 + +/** All standard descriptors have these 2 fields at the beginning */ +struct usb_descriptor_header { + __u8 bLength; + __u8 bDescriptorType; +} __attribute__ ((packed)); +typedef struct usb_descriptor_header usb_descriptor_header_t; + + + +/** USB_DT_DEVICE: Device descriptor */ +struct usb_device_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice; + __u8 iManufacturer; + __u8 iProduct; + __u8 iSerialNumber; + __u8 bNumConfigurations; +} __attribute__ ((packed)); +typedef struct usb_device_descriptor usb_device_descriptor_t; + +#define USB_DT_DEVICE_SIZE 18 + + +/* + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ +/// for DeviceClass +#define USB_CLASS_PER_INTERFACE 0 + +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a + +/// chip+ smart card +#define USB_CLASS_CSCID 0x0b + +/// content security +#define USB_CLASS_CONTENT_SEC 0x0d + +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_MISC 0xef +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + + +/** + * USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG + * descriptors. + */ +struct usb_config_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 wTotalLength; + __u8 bNumInterfaces; + __u8 bConfigurationValue; + __u8 iConfiguration; + __u8 bmAttributes; + __u8 bMaxPower; + +} __attribute__ ((packed)); +//typedef struct usb_config_descriptor usb_config_descriptor_t; + +#define USB_DT_CONFIG_SIZE 9 + +/* from config descriptor bmAttributes */ +/// from config descriptor bmAttributes: must be set +#define USB_CONFIG_ATT_ONE (1 << 7) + +/// from config descriptor bmAttributes: self powered +#define USB_CONFIG_ATT_SELFPOWER (1 << 6) + +/// from config descriptor bmAttributes: can wakeup +#define USB_CONFIG_ATT_WAKEUP (1 << 5) + +/// from config descriptor bmAttributes: battery powered +#define USB_CONFIG_ATT_BATTERY (1 << 4) + + +/** USB_DT_STRING: String descriptor */ +struct usb_string_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + /// UTF-16LE encoded + __u16 wData[1]; +} __attribute__ ((packed)); +typedef struct usb_string_descriptor usb_string_descriptor_t; + +/* + * note that "string" zero is special, it holds language codes that + * the device supports, not Unicode characters. + */ + + +/** USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + __u8 bNumEndpoints; + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + __u8 iInterface; + + struct usb_endpoint_descriptor *endpoint; + + /// Extra descriptors + unsigned char *extra; + + int extralen; +} __attribute__ ((packed)); +typedef struct usb_interface_descriptor usb_interface_descriptor_t; + +#if 0 +typedef struct usb_interface { + struct usb_interface_descriptor *altsetting; + + int act_altsetting; /* active alternate setting */ + int num_altsetting; /* number of alternate settings */ + int max_altsetting; /* total memory allocated */ + + void *private_data; +} usb_interface_t; +#endif + +#define USB_DT_INTERFACE_SIZE 9 + + +/** USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEndpointAddress; + __u8 bmAttributes; + __u16 wMaxPacketSize; + __u8 bInterval; + + /// NOTE: these two are _only_ in audio endpoints. + /// use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. + __u8 bRefresh; + __u8 bSynchAddress; + + /// Extra descriptors + + unsigned char *extra; + int extralen; +} __attribute__ ((packed)); +typedef struct usb_endpoint_descriptor usb_endpoint_descriptor_t; + +#define USB_DT_ENDPOINT_SIZE 7 + +/// Audio extension +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 + + +/* + * Endpoints Macro + */ +/// in bEndpointAddress +#define USB_ENDPOINT_NUMBER_MASK 0x0f + +#define USB_ENDPOINT_DIR_MASK 0x80 + +/// in bmAttributes +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 + +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 + + + +/** USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u8 bNumConfigurations; + __u8 bRESERVED; +} __attribute__ ((packed)); + + + +/** USB_DT_OTG (from OTG 1.0a supplement) */ +struct usb_otg_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + /// support for HNP, SRP, etc + __u8 bmAttributes; +} __attribute__ ((packed)); + +/// from usb_otg_descriptor.bmAttributes +#define USB_OTG_SRP (1 << 0) +/// swap host/device roles +#define USB_OTG_HNP (1 << 1) + + +/** USB_DT_DEBUG: for special highspeed devices, replacing serial console */ +struct usb_debug_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + /// bulk endpoints with 8 byte maxpacket + __u8 bDebugInEndpoint; + __u8 bDebugOutEndpoint; +}; + + +/** USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ +struct usb_interface_assoc_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bFirstInterface; + __u8 bInterfaceCount; + __u8 bFunctionClass; + __u8 bFunctionSubClass; + __u8 bFunctionProtocol; + __u8 iFunction; +}; + + + +/** + * USB_DT_SECURITY: group of wireless security descriptors, including + * encryption types available for setting up a CC/association. + */ +struct usb_security_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumEncryptionTypes; +}; + + +/** + * USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys + * may be retrieved. + */ +struct usb_key_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 tTKID[3]; + __u8 bReserved; + __u8 bKeyData[0]; +}; + + +/** USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ +struct usb_encryption_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEncryptionType; +#define USB_ENC_TYPE_UNSECURE 0 + +/// non-wireless mode +#define USB_ENC_TYPE_WIRED 1 + +/// aes128/cbc session +#define USB_ENC_TYPE_CCM_1 2 + +/// rsa3072/sha1 auth +#define USB_ENC_TYPE_RSA_1 3 + + /// use in SET_ENCRYPTION + __u8 bEncryptionValue; + + __u8 bAuthKeyIndex; +}; + + + +/** USB_DT_BOS: group of wireless capabilities */ +struct usb_bos_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumDeviceCaps; +}; + + +/** USB_DT_DEVICE_CAPABILITY: grouped with BOS */ +struct usb_dev_cap_header { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; +}; + +#define USB_CAP_TYPE_WIRELESS_USB 1 + +/** Ultra Wide Band */ +struct usb_wireless_cap_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; + + __u8 bmAttributes; +#define USB_WIRELESS_P2P_DRD (1 << 1) +#define USB_WIRELESS_BEACON_MASK (3 << 2) +#define USB_WIRELESS_BEACON_SELF (1 << 2) +#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) +#define USB_WIRELESS_BEACON_NONE (3 << 2) + + /// bit rates, Mbps + __le16 wPHYRates; + +/// always set +#define USB_WIRELESS_PHY_53 (1 << 0) + +#define USB_WIRELESS_PHY_80 (1 << 1) + +/// always set +#define USB_WIRELESS_PHY_107 (1 << 2) + +#define USB_WIRELESS_PHY_160 (1 << 3) + +/// always set +#define USB_WIRELESS_PHY_200 (1 << 4) + +#define USB_WIRELESS_PHY_320 (1 << 5) +#define USB_WIRELESS_PHY_400 (1 << 6) +#define USB_WIRELESS_PHY_480 (1 << 7) + + /// TFI power levels + __u8 bmTFITXPowerInfo; + + /// FFI power levels + __u8 bmFFITXPowerInfo; + + __le16 bmBandGroup; + __u8 bReserved; +}; + + +/** + * USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with + * each endpoint descriptor for a wireless device + */ +struct usb_wireless_ep_comp_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bMaxBurst; + __u8 bMaxSequence; + __le16 wMaxStreamDelay; + __le16 wOverTheAirPacketSize; + __u8 bOverTheAirInterval; + __u8 bmCompAttributes; + +/// in bmCompAttributes +#define USB_ENDPOINT_SWITCH_MASK 0x03 + +#define USB_ENDPOINT_SWITCH_NO 0 +#define USB_ENDPOINT_SWITCH_SWITCH 1 +#define USB_ENDPOINT_SWITCH_SCALE 2 +}; + + +/** + * USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless + * host and a device for connection set up, mutual authentication, and + * exchanging short lived session keys. The handshake depends on a CC. + */ +struct usb_handshake { + __u8 bMessageNumber; + __u8 bStatus; + __u8 tTKID[3]; + __u8 bReserved; + __u8 CDID[16]; + __u8 nonce[16]; + __u8 MIC[8]; +}; + + +/** + * USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). + * A CC may also be set up using non-wireless secure channels (including + * wired USB!), and some devices may support CCs with multiple hosts. + */ +struct usb_connection_context { + /// persistent host id + __u8 CHID[16]; + + /// device id (unique w/in host context) + __u8 CDID[16]; + + /// connection key + __u8 CK[16]; +}; + + + +/** USB 2.0 defines three speeds, here's how Linux identifies them */ + +enum usb_device_speed { + USB_SPEED_UNKNOWN = 0, /** enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /** usb 1.1 */ + USB_SPEED_HIGH, /** usb 2.0 */ + USB_SPEED_VARIABLE, /** wireless (usb 2.5) */ +}; + +/** + * USB device state + */ +enum usb_device_state { + /** NOTATTACHED isn't in the USB spec, and this state acts + * the same as ATTACHED ... but it's clearer this way. + */ + USB_STATE_NOTATTACHED = 0, + + /** the chapter 9 device states */ + USB_STATE_ATTACHED, + USB_STATE_POWERED, + USB_STATE_DEFAULT, /** limited function */ + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, /** most functions */ + + USB_STATE_SUSPENDED /** Note: there are actually four different SUSPENDED + states, returning to POWERED, DEFAULT, ADDRESS, or + CONFIGURED respectively when SOF tokens flow again. + */ +}; + + +/*@}*/ +#endif /* __LINUX_USB_CH9_H */ + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_pcd.c b/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_pcd.c new file mode 100644 index 0000000000..abb21aefc2 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_pcd.c @@ -0,0 +1,980 @@ +/* usb pcd driver */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-24 @ Shanghai + * + */ +#include "../v2_burning_i.h" +#include "platform.h" +#include "usb_ch9.h" +#include "dwc_pcd.h" +#include "dwc_pcd_irq.h" +#include "usb_pcd.h" + +#define COMPILE_TYPE_CHK(expr, t) typedef char t[(expr) ? 1 : -1] + +static int do_bulk_cmd(char* cmd); + +#define DWC_BLK_MAX_LEN 0X1000 +#define DWC_BLK_LEN(leftSz) ((leftSz) >= DWC_BLK_MAX_LEN ? DWC_BLK_MAX_LEN : (leftSz >= BULK_EP_MPS ? BULK_EP_MPS : leftSz))//FIXME:block length 4K, can be 64K ??? +#define DWC_BLK_NUM(totalTransLen) ( (totalTransLen/DWC_BLK_MAX_LEN) + ( (totalTransLen & (DWC_BLK_MAX_LEN - 1)) + (BULK_EP_MPS - 1) )/BULK_EP_MPS ) + +#define DRIVER_VENDOR_ID 0x1B8E //Amlogic's VerdorID +#define DRIVER_PRODUCT_ID 0xC003 +#define DRIVER_VERSION 0x0100 + + +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_SERIAL 3 +#define STRING_CONFIG 4 +#define STRING_INTERFACE 5 +static const struct usb_device_descriptor +device_desc = { + sizeof device_desc, //__u8 bLength; + USB_DT_DEVICE, //__u8 bDescriptorType; +#ifdef USE_FULL_SPEED + __constant_cpu_to_le16(0x0110), //__u16 bcdUSB; +#else + __constant_cpu_to_le16(0x0200), //__u16 bcdUSB; +#endif + USB_CLASS_PER_INTERFACE, //__u8 bDeviceClass; + 0, //__u8 bDeviceSubClass; + 0, //__u8 bDeviceProtocol; + 64, //__u8 bMaxPacketSize0; + __constant_cpu_to_le16(DRIVER_VENDOR_ID), //__u16 idVendor; + __constant_cpu_to_le16(DRIVER_PRODUCT_ID), //__u16 idProduct; + __constant_cpu_to_le16(0x0007), //__u16 bcdDevice; + 0/*STRING_MANUFACTURER*/, //__u8 iManufacturer; + 0/*STRING_PRODUCT*/, //__u8 iProduct; + 0/*STRING_SERIAL*/, //__u8 iSerialNumber; + 1 //__u8 bNumConfigurations; +}; + +#define INTF_CONFIG_DESC_LEN 23 +#define TOTAL_CONFIG_DESC_LEN (INTF_CONFIG_DESC_LEN + USB_DT_CONFIG_SIZE) + +#pragma pack(push, 1) +struct _ConfigDesTotal_s{ + struct usb_config_descriptor configDesc; + char intfDesc[INTF_CONFIG_DESC_LEN] ; +}; +#pragma pack(pop) +COMPILE_TYPE_CHK(TOTAL_CONFIG_DESC_LEN == sizeof(struct _ConfigDesTotal_s), a); + +static const struct _ConfigDesTotal_s _configDescTotal = { + .configDesc = + { + USB_DT_CONFIG_SIZE, //__u8 bLength; + USB_DT_CONFIG, //__u8 bDescriptorType; + TOTAL_CONFIG_DESC_LEN, //__u16 wTotalLength; + 1, //__u8 bNumInterfaces; + 1, //__u8 bConfigurationValue; + 0,//STRING_CONFIG, //__u8 iConfiguration; + USB_CONFIG_ATT_ONE | + USB_CONFIG_ATT_SELFPOWER, //__u8 bmAttributes; + 1 //__u8 MaxPower; + }, + + .intfDesc = + { + 0x09,// length + 0x04,//USB_DT_INTERFACE + 0x00,//bInterfaceNumber + 0x00,//bAlternateSetting + 0x02,//bNumEndpoints + 0xFF,//bInterfaceClass, 0xFF = USB_CLASS_VENDOR_SPEC + 0x00,//bInterfaceSubClass + 0x00,//bInterfaceProtocol + 0x00,//iInterface + + 0x07,//Length + 0x05,//USB_DT_ENDPOINT + 0x80 | BULK_IN_EP_NUM,// 1 -- IN + 0x02,// Bulk +#ifndef USE_FULL_SPEED + 0x00,// + 0x02,// 64 bytes MPS +#else + 0x40,// + 0x00,// 64 bytes MPS +#endif + 0x00, + + 0x07,//Length + 0x05,//USB_DT_ENDPOINT + 0x00 | BULK_OUT_EP_NUM,// 2 -- OUT + 0x02,// Bulk +#ifndef USE_FULL_SPEED + 0x00,// + 0x02,// 64 bytes MPS +#else + 0x40,// + 0x00,// 64 bytes MPS +#endif + 0x00 + } +}; + +/*static const struct usb_config_descriptor* config_desc = &_configDescTotal.configDesc;*/ +/*static const unsigned char* intf_desc = &_configDescTotal.intfDesc;*/ + +#define DT_STRING_ID_LEN 4 +static const char dt_string_id[DT_STRING_ID_LEN]={ + DT_STRING_ID_LEN, + USB_DT_STRING, + 0x09, + 0x04, +}; +#define DT_STRING_VID_LEN 16 +static const char dt_string_vid[DT_STRING_VID_LEN]= +{ + DT_STRING_VID_LEN, + USB_DT_STRING, + 'A', + 0, + 'm', + 0, + 'l', + 0, + 'o', + 0, + 'g', + 0, + 'i', + 0, + 'c', + 0 +}; + +#define _PLATFORM_CHIP_INDEX '8' + +#define DT_STRING_PID_LEN 16 +static const char dt_string_pid[DT_STRING_PID_LEN]= +{ + DT_STRING_PID_LEN, + USB_DT_STRING, + 'M', + 0, + _PLATFORM_CHIP_INDEX, + 0, + '-', + 0, + 'C', + 0, + 'H', + 0, + 'I', + 0, + 'P', + 0 +}; + +#define DT_STRING_SERIAL_LEN 18 +static const char dt_string_serial[DT_STRING_SERIAL_LEN]= +{ + DT_STRING_SERIAL_LEN, + USB_DT_STRING, + '2', + 0, + '0', + 0, + '1', + 0, + '1', + 0, + '0', + 0, + '4', + 0, + '0', + 0, + '6', + 0 +}; + +static char _resultInfo[AM_BULK_REPLY_LEN] = {0}; +/*static char _bulkCmdBuf[AM_BULK_REPLY_LEN] = {0};*/ +/*#define buff ((char*)PCD_BUFF)*/ +static volatile char _pcd_buff[512] ; +#define buff _pcd_buff + +int usb_pcd_init(void) +{ + flush_cache((unsigned long)buff, 512); + return dwc_core_init(); +} + +static unsigned int need_check_timeout; +static unsigned int time_out_val; +static unsigned int _auto_burn_time_out_base = 0; + +void usb_parameter_init(int time_out) +{ + need_check_timeout = 0; + /* clear utimer */ + need_check_timeout=get_timer(need_check_timeout)?get_timer(need_check_timeout):1; + if (time_out) + { + time_out_val = time_out; // wait PC GetDescriptor command for 1us changed by Elvis + + } + else + { + time_out_val = USB_ROM_CONN_TIMEOUT; // wait PC GetDescriptor command + } + //printf("need_check_timeout %d, time_out_val %d, time_out %d\n", need_check_timeout, time_out_val, time_out); + + //Added by Sam Wu + optimus_buf_manager_init(16*1024); + optimus_download_init(); + return; +} + +int usb_pcd_irq(void) +{ + if (need_check_timeout) + { + unsigned curTime = get_timer(need_check_timeout); + if (curTime > time_out_val) { + dwc_otg_power_off_phy(); + ERR("Try connect time out %u, %u, %u\n", curTime, time_out_val, need_check_timeout); + return 2;// return to other device boot + } + } + if (_auto_burn_time_out_base) { + unsigned waitIdentifyTime = get_timer(_auto_burn_time_out_base); + unsigned timeout = simple_strtoul(getenv(_ENV_TIME_OUT_TO_AUTO_BURN), NULL, 0); + if (waitIdentifyTime > timeout) { + ERR("waitIdentifyTime(%u) > timeout(%u)\n", waitIdentifyTime, timeout); + _auto_burn_time_out_base = 0;//clear it to allow enter burning next time + return __LINE__; + } + } + + return dwc_otg_irq(); +} + +void start_bulk_transfer(pcd_struct_t *_pcd) +{ + _pcd->bulk_lock = 1; // TODO : add lock code. + dwc_otg_ep_req_start(_pcd,_pcd->bulk_out?BULK_OUT_EP_NUM:BULK_IN_EP_NUM); +} +/** + * This functions delegates the setup command to the gadget driver. + */ +void do_gadget_setup( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl) +{ + int value; + u16 w_index = ctrl->wIndex; + u16 w_value = ctrl->wValue; + u16 w_length = ctrl->wLength; + + /* usually this just stores reply data in the pre-allocated ep0 buffer, + * but config change events will also reconfigure hardware. */ + switch (ctrl->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + { + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + //time_out_val = USB_ROM_DRIVER_TIMEOUT;// Wait SetConfig (PC install driver OK) + /*need_check_timeout = 0;*/ + switch (w_value >> 8) + { + case USB_DT_DEVICE: + DBG("get dev desc\n"); + value = min(w_length, (u16) sizeof device_desc); + /*usb_memcpy(buff, (char*)&device_desc, value);*/ + /* + *memcpy((void*)buff, &device_desc, value); + *_pcd->buf = buff; + */ + _pcd->buf = (volatile char*)&device_desc; + _pcd->length = value; + break; + case USB_DT_DEVICE_QUALIFIER: + DBG("get dev qual\n"); + break; + case USB_DT_OTHER_SPEED_CONFIG: + DBG("--get other speed configuration descriptor\n"); + DBG("--other speed configuration descriptor length :%d\n", value); + break; + case USB_DT_CONFIG: + { + USB_DBG("--get configuration descriptor: size %d\n",w_length); + if (w_length > USB_DT_CONFIG_SIZE) {//request USB_DT_CONFIG_SIZE only + value = TOTAL_CONFIG_DESC_LEN; + } + else{ + value = w_length; + } + _pcd->buf = (volatile char*)&_configDescTotal; + _pcd->length = value; + /*printf("--get configuration descriptor: size %d, ret length :%d\n\n", w_length, value); */ + printf("Get DT cfg\n"); + + } + break; + + case USB_DT_STRING: + { + const char* str = NULL; + + /*DBG("--get string Desc: id %d\n", w_value & 0xff);*/ + printf("Get str %x\n", w_value); + switch (w_value & 0xff) + { + case 0: // IDs + /*usb_memcpy(buff,(void*)dt_string_id,DT_STRING_ID_LEN);*/ + str = dt_string_id; + break; + + case 1: // STRING_MANUFACTURER + /*usb_memcpy(buff,(void*)dt_string_vid,DT_STRING_VID_LEN);*/ + str = dt_string_vid; + break; + + case 2://STRING_PRODUCT + /*usb_memcpy(buff,(void*)dt_string_pid,DT_STRING_PID_LEN);*/ + str = dt_string_pid; + break; + + case 3://STRING_SERIAL + /*usb_memcpy(buff,(void*)dt_string_serial,DT_STRING_SERIAL_LEN);*/ + str = dt_string_serial; + break; + + default: + USB_ERR("Error string id!\n"); + /*buff[0] = 0;*/ + str = NULL; + break; + } + _pcd->buf = (char*)str; + _pcd->length = str[0]; + /*printf("--get str DESC: id %d ,return length %d\n", (w_value & 0xff), _pcd->length);*/ + } + break; + + } + + } + break; + + case USB_REQ_SET_CONFIGURATION: + { + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | + USB_RECIP_DEVICE)) + break; + printf("set CFG\n"); + _pcd->buf = 0; + _pcd->length = 0; + _pcd->request_config = 1; /* Configuration changed */ + need_check_timeout = 0; + if (OPTIMUS_WORK_MODE_USB_UPDATE == optimus_work_mode_get()) {//not booting from usb + if (getenv(_ENV_TIME_OUT_TO_AUTO_BURN))_auto_burn_time_out_base = get_timer(0) ; + } + } + break; + + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + printf("get CFG\n"); + buff[0] = 1; + _pcd->buf = buff; + _pcd->length = 1; + break; + + default: + USB_ERR("--unknown control req %02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + w_index = 0; //remove compile warning + return ; +} + +/** + * This functions delegates vendor ctrl request. + */ +void do_vendor_request( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl) +{ + unsigned long value =0; + u16 w_index = ctrl->wIndex; + u16 w_value = ctrl->wValue; + u16 w_length = ctrl->wLength; + + switch (ctrl->bRequest) + { + case AM_REQ_WRITE_MEM: + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + USB_DBG("--am req write memory\n"); + value = (w_value << 16) + w_index; + USB_DBG("addr = 0x%08X, size = %d\n\n",value,w_length); + _pcd->buf = (char *)value; // copy to dst memory directly + _pcd->length = w_length; + break; + + case AM_REQ_READ_MEM: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + value = (w_value << 16) + w_index; + + /*usb_memcpy((char *)buff,(char*)value,w_length);*/ + memcpy((void*)buff,(void*)value,w_length); + + _pcd->buf = buff; + _pcd->length = w_length; + break; + + case AM_REQ_READ_AUX: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + /*unsigned int data = 0;*/ + value = (w_value << 16) + w_index; + + //data = _lr(value); + /**(unsigned int *)(unsigned)buff = data;*/ + memset((char*)buff, 0, sizeof(unsigned)); + + _pcd->buf = buff; + _pcd->length = w_length; + break; + + case AM_REQ_FILL_MEM: + case AM_REQ_WRITE_AUX: + case AM_REQ_MODIFY_MEM: + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + _pcd->buf = buff; + _pcd->length = w_length; + break; + + case AM_REQ_RUN_IN_ADDR: + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + value = (w_value << 16) + w_index; + USB_DBG("--am req run in addr %p\n\n",value); + _pcd->buf = buff; + _pcd->length = w_length; + break; + + case AM_REQ_WR_LARGE_MEM: + value = 1; + case AM_REQ_RD_LARGE_MEM: + USB_DBG("--am req large %s mem \n\n",value?"write":"read"); + + _pcd->bulk_len = w_value; // block length + _pcd->bulk_num = w_index; // number of block + _pcd->buf = buff; //EP0 command data buffer + _pcd->length = w_length; //EP0 command data length + /*FIXME: cann't delay when writelargeMem, or it will fail??*/ + /* + *printf("f(%s)L%d: bulk_len=0x%x, bulk_num=%d, bufAddr=0x%x, len=0x%x\n", + * __func__, __LINE__, _pcd->bulk_len, _pcd->bulk_num, _pcd->buf, _pcd->length); + */ + break; + + case AM_REQ_DOWNLOAD: + { + value = 1;//is out + _pcd->bulk_len = w_value;//block length + _pcd->bulk_num = w_index;//how many times to transfer + _pcd->buf = buff; + _pcd->length = w_length; + } + break; + + case AM_REQ_UPLOAD: + { + _pcd->buf = _resultInfo; + _pcd->length = w_length;//assert that lenght == 16 ???? + + optimus_buf_manager_get_command_data_for_upload_transfer((u8*)_resultInfo, w_length); + } + break; + + + case AM_REQ_IDENTIFY_HOST: + { + static const char id[4] = + { + [0] = USB_ROM_VER_MAJOR, + [1] = USB_ROM_VER_MINOR, + [2] = USB_ROM_STAGE_MAJOR, + [3] = USB_ROM_STAGE_MINOR, + }; + + _pcd->buf = (char*)id; + _pcd->length = w_length;//FIXME:asset w_length == 4 ?? + _auto_burn_time_out_base = 0;//get burning tool identify command, so clear the timeout flag + printf("\nID[%d]\n", _pcd->buf[3]); + } + break; + + case AM_REQ_BULKCMD://Added by Sam + { + _pcd->bulk_len = w_value; // block length + _pcd->bulk_num = w_index; // number of block + _pcd->buf = buff; //EP0 command data buffer, out buffer after set_up command + _pcd->length = w_length; //EP0 command data length + /*printf("blkc:len %d\n", _pcd->length);*/ + _pcd->cmdtype.setup_complete = 1; + } + break; + + case AM_REQ_TPL_CMD: + { + _pcd->buf = buff; + _pcd->length = w_length; + } + break; + + case AM_REQ_TPL_STAT: + { + _pcd->buf = _resultInfo; + _pcd->length = w_length; + } + break; + + default: + USB_ERR("--unknown vendor req %02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + break; + } + + return; +} + +/* + * This function will be called after a whole SETUP-OUT-IN transfer. + */ +void do_vendor_out_complete( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl) +{ + unsigned long value = 0; + u16 w_index = ctrl->wIndex; + u16 w_value = ctrl->wValue; + u16 w_length = ctrl->wLength; + void (*fp)(void); + volatile char * buf; + + //USB_DBG("do_vendor_out_complete(0x%x)\n", ctrl->bRequest); + switch (ctrl->bRequest) + { + case AM_REQ_WRITE_MEM: + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + USB_DBG("--am req write memory completed\n\n"); + break; + + case AM_REQ_FILL_MEM: + buf = (char*)_pcd->buf; + unsigned long addr,i; + for (i = 0; i < _pcd->length; i+=8) { + addr = *((unsigned int *)&buf[i]) ; + value = *((unsigned int *)&buf[i+4]) ; + *(unsigned int*)addr = value; + } + break; + + case AM_REQ_WRITE_AUX: + buf = _pcd->buf; + unsigned int data =0; + + data = *((unsigned int *)&buf[0]) ; //reg value + value = (w_value << 16) + w_index; //aux reg + + dwc_write_reg32(value, data); + break; + + case AM_REQ_MODIFY_MEM: + do_modify_memory(w_value,(char*)_pcd->buf); + break; + + case AM_REQ_RUN_IN_ADDR: + if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE)) + break; + value = (w_value << 16) + w_index; + USB_DBG("run addr = 0x%08X\n",value); + fp = (void(*)(void))value; + dwc_otg_power_off_phy(); + fp(); + break; + + case AM_REQ_WR_LARGE_MEM: + value = 1; // is_out = 1 + case AM_REQ_RD_LARGE_MEM: + { + const unsigned* intBuf = (unsigned*)buff; + _pcd->bulk_out = (char)value; // read or write + _pcd->bulk_buf = (char*)(u64)intBuf[0]; + _pcd->bulk_data_len = intBuf[1]; // data length + + //added by Sam.Wu + _pcd->bulk_xfer_len = 0; + _pcd->xferNeedReply = 0; + + _pcd->bulk_len = DWC_BLK_LEN(_pcd->bulk_data_len); + _pcd->bulk_num = DWC_BLK_NUM(_pcd->bulk_data_len); + start_bulk_transfer(_pcd); + } + break; + + case AM_REQ_DOWNLOAD: + value = 2;//2 to differ from write_large_mem + { + const unsigned* intBuf = (unsigned*)buff; + unsigned isPktResended = intBuf[0]; + unsigned sequenceNo = intBuf[2]; + _pcd->bulk_out = value; + _pcd->bulk_data_len = intBuf[1]; + _pcd->bulk_xfer_len = 0; + _pcd->origiSum = intBuf[3]; + _pcd->isPktResended = isPktResended; + + if (!isPktResended) //request next buffer slot only if transfer packet not re-sended packet + { + int ret = optimus_buf_manager_get_buf_for_bulk_transfer(&_pcd->bulk_buf, _pcd->bulk_data_len, sequenceNo, NULL); + if (ret) _pcd->bulk_data_len = _pcd->bulk_len = _pcd->bulk_num = 0; + } + + _pcd->sequenceNo = sequenceNo; + + _pcd->bulk_len = DWC_BLK_LEN(_pcd->bulk_data_len); + _pcd->bulk_num = DWC_BLK_NUM(_pcd->bulk_data_len); + _pcd->xferNeedReply= 1;/////// + start_bulk_transfer(_pcd); + } + break; + + case AM_REQ_UPLOAD: + { + //command foramt: [4-7]dataLen, other don't care now + const u8* cmdData = (const u8*)_resultInfo; + const u32 sequenceNo = *(unsigned*)(cmdData + 8); + const u32 leftDataLen = *(unsigned*)(cmdData + 4); + int ret = 0; + + _pcd->bulk_out = 0; + _pcd->bulk_xfer_len = 0; + _pcd->bulk_data_len = leftDataLen; + + _pcd->bulk_len = DWC_BLK_LEN(leftDataLen); + _pcd->bulk_num = DWC_BLK_NUM(leftDataLen); + + ret = optimus_buf_manager_get_buf_for_bulk_transfer(&_pcd->bulk_buf, _pcd->bulk_data_len, sequenceNo, _resultInfo); + if (ret) _pcd->bulk_data_len = _pcd->bulk_len = _pcd->bulk_num = 0;//respond 0 byte data to stop transfer + + DWN_DBG("up 0x:len %x, buf %p, bulk_num %d\n", _pcd->bulk_data_len, _pcd->bulk_buf, _pcd->bulk_num); + _pcd->xferNeedReply= 1;/////// + start_bulk_transfer(_pcd); + } + break; + + + case AM_REQ_TPL_CMD: + /* this is an example for any command */ + if (!w_index) {/* assume subcode is 0 */ +/* ??????????????????????????? + char dev[16] = {0}; + u64 offset = 0; + u64 tmp = 0; + u32 mem_addr = (*(unsigned int*)buff); + offset |= (*(unsigned int*)&buff[16]); + tmp = (*(unsigned int*)&buff[20]); + offset |= (tmp << 32); + + u32 size = (*(unsigned int*)&buff[12]); + usb_memcpy(dev,&buff[32],16); + burn_board(dev, mem_addr, offset, size); +*/ + } + else if(w_index == 1){ + char cmd[CMD_BUFF_SIZE]; + memcpy(cmd, (void*)buff, CMD_BUFF_SIZE); + if (strncmp(cmd,"bootm",(sizeof("bootm")-1)) == 0) { + dwc_otg_pullup(0);//disconnect + } + printf("tplcmd[%s]\n", cmd); + optimus_working(cmd, _resultInfo); + } + break; + + case AM_REQ_BULKCMD: + { + do_bulk_cmd((char*)buff); + } + break; + + default: + USB_ERR("--unknown vendor req comp %02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + w_length = 0;//remove compile warning + return; +} + +/* + * This function will be called after a whole SETUP-IN-OUT transfer. + */ +void do_vendor_in_complete( pcd_struct_t *_pcd, struct usb_ctrlrequest * ctrl) +{ + u16 w_index = ctrl->wIndex; + u16 w_value = ctrl->wValue; + u16 w_length = ctrl->wLength; + + //USB_DBG("do_vendor_out_complete(0x%x)\n", ctrl->bRequest); + switch (ctrl->bRequest) + { + case AM_REQ_IDENTIFY_HOST: + case AM_REQ_TPL_STAT: + break; + + case USB_REQ_GET_DESCRIPTOR: + break; + + case AM_REQ_UPLOAD: + { + //command foramt: [4-7]dataLen, other don't care now + const u8* cmdData = (const u8*)_resultInfo; + const u32 sequenceNo = *(unsigned*)(cmdData + 8); + const u32 leftDataLen = *(unsigned*)(cmdData + 4); + int ret = 0; + + _pcd->bulk_out = 0; + _pcd->bulk_xfer_len = 0; + _pcd->bulk_data_len = leftDataLen; + + _pcd->bulk_len = DWC_BLK_LEN(leftDataLen); + _pcd->bulk_num = DWC_BLK_NUM(leftDataLen); + + ret = optimus_buf_manager_get_buf_for_bulk_transfer(&_pcd->bulk_buf, _pcd->bulk_data_len, sequenceNo, _resultInfo); + if (ret) _pcd->bulk_data_len = _pcd->bulk_len = _pcd->bulk_num = 0;//respond 0 byte data to stop transfer + + DWN_DBG("up 0x:len %x, buf %p, bulk_num %d\n", _pcd->bulk_data_len, _pcd->bulk_buf, _pcd->bulk_num); + _pcd->xferNeedReply= 1;/////// + start_bulk_transfer(_pcd); + } + break; + + default: + USB_ERR("--unknown vendor req comp %02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + w_length = 0;//remove compile warning + return; +} + + +int bulk_transfer_reply(const pcd_struct_t* _pcd) +{ + static int _mediaErr = 0; + static pcd_struct_t pcd; + char* replyBuf = _resultInfo; + const void* data = _pcd->bulk_buf; + const unsigned len = _pcd->bulk_xfer_len; + const unsigned sequenceNo = _pcd->sequenceNo; + int isOut = !_pcd->bulk_out;//handshake direction is opposite + const u32 origiSum = _pcd->origiSum; + unsigned genSum = 0; + int ret = 0; + const int isPktResended = _pcd->isPktResended; + + dwc_otg_bulk_ep_enable(!isOut);//enable the bulk in ep first before optimus_working!! + + if(0 == _pcd->sequenceNo + && !isPktResended)//media error can't resolved by reseneded, only memory(dram) error can + { + _mediaErr = 0;//set error none if download a new file + } + + if (_mediaErr) { + sprintf(replyBuf, "media error %d at seq %d, resend %d\n", _mediaErr, sequenceNo, isPktResended); + DWN_ERR(replyBuf); + ret = __LINE__; + } + else + { + genSum = add_sum(data, len); + + if (origiSum != genSum) + { + sprintf(replyBuf, "0x: genSum %x != org %x at seq %x, len %x, resend %d\n", genSum, origiSum, sequenceNo, len, isPktResended); + DWN_ERR(replyBuf); + ret = __LINE__; + } + } + + if (!ret) //add-sum checked ok and no media error + { + _mediaErr = optimus_buf_manager_report_transfer_complete(_pcd->bulk_xfer_len, replyBuf); + if (_mediaErr) { + sprintf(replyBuf, "media error %d at seq %d\n", _mediaErr, sequenceNo); + DWN_ERR(replyBuf); + ret = __LINE__; + } + } + + if (!ret) + { + memcpy(replyBuf, "OK!!", 4); + } + + //PCD fields needed for reply + //see implementation of dwc_otg_ep_req_start + pcd.bulk_data_len = AM_BULK_REPLY_LEN;//total length <= 4k + pcd.bulk_len = DWC_BLK_LEN(pcd.bulk_data_len);//total length <= 4k + pcd.bulk_num = DWC_BLK_NUM(pcd.bulk_data_len); + pcd.bulk_buf = replyBuf; + pcd.bulk_xfer_len = 0; + + DWN_DBG("replyBuf %s\n", replyBuf); + dwc_otg_ep_req_start(&pcd, isOut?BULK_OUT_EP_NUM:BULK_IN_EP_NUM); + + return ret; +} + +/* + * This function will be called after a whole bulk out transfer. + * Attention That All bulk transfer will reach here after completed!! + */ +void do_bulk_complete( pcd_struct_t *_pcd) +{ + _pcd->bulk_lock = 0; + _pcd->bulk_num--; + /*_pcd->bulk_data_len -= _pcd->xfer_len;*/ + _pcd->bulk_xfer_len += _pcd->xfer_len; + + //open this debug info if see if _pcd->bulk_num is 0 has been reponsed! i.e, all data transfrred ended + //if not bulk in tranferred, open in printf will let down the csw of mwrite(csw will be invalid transfer) + DWN_DBG("left blk %d, this len 0x%x, bulk_xfer_len 0x%x\n", _pcd->bulk_num, _pcd->xfer_len, _pcd->bulk_xfer_len); + + if(_pcd->bulk_num > 0 + && _pcd->bulk_len)//if earlier packet length is 0, no next xfer here!! + { + const u32 leftDataLen = _pcd->bulk_data_len - _pcd->bulk_xfer_len; + + _pcd->bulk_len = DWC_BLK_LEN(leftDataLen); + + /*_pcd->bulk_buf += _pcd->bulk_len;*/ + start_bulk_transfer(_pcd); + + return;///////////////// + } + + if (this_pcd.xferNeedReply) //get download command and is out + { + this_pcd.xferNeedReply = 0;//// + + if (2 == _pcd->bulk_out) //2 means download command 0x32, only this command need handshake??!!!!! + { + bulk_transfer_reply(_pcd); + return;//////// + } + + if (!_pcd->bulk_out) + { + optimus_buf_manager_report_transfer_complete(_pcd->bulk_xfer_len, NULL); + } + } +} + +static int bulk_cmd_reply(const char* replyBuf) +{ + static pcd_struct_t pcd; + + //PCD fields needed for reply + //see implementation of dwc_otg_ep_req_start + pcd.bulk_len = AM_BULK_REPLY_LEN; + pcd.bulk_buf = (char*)replyBuf; + pcd.bulk_xfer_len = 0; + + this_pcd.bulk_out = 0;//////////////////////////////OH NO!!!! I don't like the common pcd, FIXME to use various PCD !! + this_pcd.xferNeedReply = 0; + dwc_otg_ep_req_start(&pcd, BULK_IN_EP_NUM);//bulk in to reply result, it is ALWAYS IN + + return 0; +} + +static int do_bulk_cmd(char* cmd) +{ + int ret = 0; + const int is_in = 1; + + ret = dwc_otg_bulk_ep_enable(is_in);//enable the bulk in ep first before optimus_working!! + + printf("BULKcmd[%s]\n", cmd); + ret = optimus_working(cmd, _resultInfo); + + ret = bulk_cmd_reply(_resultInfo); + + return ret; +} + +void do_modify_memory(u16 opcode, char *inbuff) +{ + unsigned int *mem,*mem2; + unsigned int data,mask; + + mem = *(unsigned int**)&inbuff[0]; + data = *(unsigned int*)&inbuff[4]; + mask = *(unsigned int*)&inbuff[8]; + mem2= *(unsigned int**)&inbuff[12]; + + switch (opcode) { + case 0: //*mem = data + *mem = data; + break; + + case 1:// *mem = (data & mask) + *mem = data & mask; + break; + + case 2:// *mem =(*mem | mask) + *mem = *mem | mask; + break; + + case 3:// *mem = (data & (~mask)) + *mem = (data & (~mask)); + break; + + case 4:// *mem = (data & mask) |(*mem & ~mask) + *mem = (data & mask) |(*mem & ~mask); + break; + + case 5:// *mem = *mem2 + *mem = *mem2; + break; + + case 6:// *mem = (*mem2 & mask) + *mem = (*mem2 & mask); + break; + + case 7:// while(data--) {*mem++ = *mem2++} + while (data--) { + *mem++ = *mem2++; + } + break; + + default: + break; + } + +} + diff --git a/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_pcd.h b/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_pcd.h new file mode 100644 index 0000000000..d4f9827171 --- /dev/null +++ b/drivers/usb/gadget/v2_burning/v2_usb_tool/usb_pcd.h @@ -0,0 +1,41 @@ +/* usb pcd driver header */ +/* + * (C) Copyright 2010 Amlogic, Inc + * + * Victor Wan, victor.wan@amlogic.com, + * 2010-03-24 @ Shanghai + * + */ +#ifndef __USB_PCD_H__ +#define __USB_PCD_H__ +#include <asm/types.h> + +#define CMD_BUFF_SIZE 512 + +int usb_pcd_init(void); +int usb_pcd_irq(void); +extern int optimus_working (const char *cmd, char* buff); + +// Vendor request defines +#define AM_REQ_WRITE_MEM 0x01 +#define AM_REQ_READ_MEM 0x02 +#define AM_REQ_FILL_MEM 0x03 +#define AM_REQ_MODIFY_MEM 0x04 +#define AM_REQ_RUN_IN_ADDR 0x05 +#define AM_REQ_WRITE_AUX 0x06 +#define AM_REQ_READ_AUX 0x07 + +#define AM_REQ_WR_LARGE_MEM 0x11 +#define AM_REQ_RD_LARGE_MEM 0x12 +#define AM_REQ_IDENTIFY_HOST 0x20 + +#define AM_REQ_TPL_CMD 0x30 +#define AM_REQ_TPL_STAT 0x31 +void do_modify_memory(u16 opcode, char *inbuff); + +#define AM_REQ_DOWNLOAD 0X32 +#define AM_REQ_UPLOAD 0X33 +#define AM_REQ_BULKCMD 0X34 +#define AM_BULK_REPLY_LEN CMD_BUFF_SIZE + +#endif diff --git a/fs/fat/fat.c b/fs/fat/fat.c index bccc3e3ed8..57af24941a 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -43,7 +43,7 @@ static disk_partition_t cur_part_info; #define DOS_FS_TYPE_OFFSET 0x36 #define DOS_FS32_TYPE_OFFSET 0x52 -static int disk_read(__u32 block, __u32 nr_blocks, void *buf) +int disk_read(__u32 block, __u32 nr_blocks, void *buf) { if (!cur_dev || !cur_dev->block_read) return -1; diff --git a/include/amlogic/aml_v2_burning.h b/include/amlogic/aml_v2_burning.h new file mode 100644 index 0000000000..1ecdad65b0 --- /dev/null +++ b/include/amlogic/aml_v2_burning.h @@ -0,0 +1,31 @@ +/* + * \file aml_v2_burning.h + * \brief common interfaces for version burning + * + * \version 1.0.0 + * \date 09/15/2013 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ + +//is the uboot loaded from usb otg +int is_tpl_loaded_from_usb(void); + +//is the uboot loaded from sdcard mmc 0 +//note only sdmmc supported by romcode when external device boot +int is_tpl_loaded_from_ext_sdmmc(void); + +//Check if uboot loaded from external sdmmc or usb otg +int aml_burn_check_uboot_loaded_for_burn(int flag); + +int aml_burn_factory_producing(int flag, bd_t* bis); + +//usb producing mode, if tpl loaded from usb pc tool and auto enter producing mode +int aml_try_factory_usb_burning(int flag, bd_t* bis); + +//Auto enter sdcard burning if booted from sdcard and aml_sdc_burn.ini existed +int aml_try_factory_sdcard_burning(int flag, bd_t* bis); + + diff --git a/include/amlogic/storage_if.h b/include/amlogic/storage_if.h new file mode 100644 index 0000000000..725c238559 --- /dev/null +++ b/include/amlogic/storage_if.h @@ -0,0 +1,66 @@ +/* + * \file storage_if.h + * \brief interfaces declarations for storage operations + * + * \version 1.0.0 + * \date 2013-7-16 + * \author Sam.Wu <yihui.wu@amlgic.com> + * + * Copyright (c) 2013 Amlogic. All Rights Reserved. + * + */ +#ifndef __STOARGE_IF_H__ +#define __STOARGE_IF_H__ + + +/*** +upgrade_read_ops: + +partition_name: env / logo / recovery /boot / system /cache /media + +***/ +int store_read_ops(unsigned char *partition_name,unsigned char * buf, uint64_t off, uint64_t size); + + +/*** +upgrade_write_ops: + +partition_name: env / logo / recovery /boot / system /cache /media + +***/ +int store_write_ops(unsigned char *partition_name,unsigned char * buf,uint64_t off, uint64_t size); + + +/*** +upgrade_write_ops: + +partition_name: env / logo / recovery /boot / system /cache /media + +***/ +int store_get_partititon_size(unsigned char *partition_name, uint64_t *size); + + +/*** +upgrade_erase_ops: + +partition_name: boot / data + +flag = 0; indicate erase partition ; +flag = 1; indicate scurb whole nand; + +***/ +int store_erase_ops(unsigned char *par_name, uint64_t off, uint64_t size, unsigned char flag); + +/*** +bootloader: +***/ +int store_boot_read(unsigned char * buf, uint64_t off, uint64_t size); + +int store_boot_write(unsigned char * buf,uint64_t off, uint64_t size); + +int store_init(unsigned flag); + +int store_exit(void); + +#endif//ifndef __STOARGE_IF_H__ + diff --git a/include/configs/gxb_p200_v1.h b/include/configs/gxb_p200_v1.h index 5451128513..559c4da71b 100644 --- a/include/configs/gxb_p200_v1.h +++ b/include/configs/gxb_p200_v1.h @@ -104,7 +104,8 @@ #define CONFIG_USB_DWC_OTG_HCD 1 #define CONFIG_USB_DWC_OTG_294 1 #endif //#if defined(CONFIG_CMD_USB) -#define CONFIG_AML_TINY_USBTOOL 1 +//#define CONFIG_AML_TINY_USBTOOL 1 +#define CONFIG_AML_V2_FACTORY_BURN 1 /* net */ #define CONFIG_CMD_NET 1 @@ -156,6 +157,7 @@ #define CONFIG_NEED_BL301 1 #define CONFIG_BOOTDELAY 1 //delay 1s #define CONFIG_SYS_LONGHELP 1 +#define CONFIG_CMD_MISC 1 #endif diff --git a/include/configs/gxb_p201_v1.h b/include/configs/gxb_p201_v1.h index 8dc107f8f2..335d96bbfa 100644 --- a/include/configs/gxb_p201_v1.h +++ b/include/configs/gxb_p201_v1.h @@ -103,7 +103,8 @@ #define CONFIG_USB_DWC_OTG_HCD 1 #define CONFIG_USB_DWC_OTG_294 1 #endif //#if defined(CONFIG_CMD_USB) -#define CONFIG_AML_TINY_USBTOOL 1 +//#define CONFIG_AML_TINY_USBTOOL 1 +#define CONFIG_AML_V2_FACTORY_BURN 1 /* net */ #define CONFIG_CMD_NET 1 @@ -155,6 +156,7 @@ #define CONFIG_NEED_BL301 1 #define CONFIG_BOOTDELAY 1 //delay 1s #define CONFIG_SYS_LONGHELP 1 +#define CONFIG_CMD_MISC 1 #endif diff --git a/include/configs/gxb_skt_v1.h b/include/configs/gxb_skt_v1.h index 434d867799..20d6d47895 100644 --- a/include/configs/gxb_skt_v1.h +++ b/include/configs/gxb_skt_v1.h @@ -134,7 +134,8 @@ #define CONFIG_USB_DWC_OTG_HCD 1 #define CONFIG_USB_DWC_OTG_294 1 #endif //#if defined(CONFIG_CMD_USB) -#define CONFIG_AML_TINY_USBTOOL 1 +//#define CONFIG_AML_TINY_USBTOOL 1 +#define CONFIG_AML_V2_FACTORY_BURN 1 /* net */ #define CONFIG_CMD_NET 1 @@ -186,6 +187,7 @@ #define CONFIG_NEED_BL301 1 #define CONFIG_BOOTDELAY 1 #define CONFIG_SYS_LONGHELP 1 +#define CONFIG_CMD_MISC 1 //support secure boot //#define CONFIG_AML_SECURE_UBOOT 1 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8438490fe4..b717292132 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -65,7 +65,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); * adjust this accordingly. */ #define NAND_MAX_OOBSIZE 744 -#define NAND_MAX_PAGESIZE 8192 +//#define NAND_MAX_PAGESIZE 8192 #endif /* @@ -561,10 +561,10 @@ struct nand_buffers { uint8_t *ecccalc; uint8_t *ecccode; uint8_t *databuf; -#else - uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; - uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; - uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, +//#else +// uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; +// uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; +// uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; #endif }; @@ -1009,8 +1009,9 @@ static inline int nand_opcode_8bits(unsigned int command) /* return the supported JEDEC features. */ static inline int jedec_feature(struct nand_chip *chip) { - return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features) - : 0; + //return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features) + // : 0; + return 0; } #ifdef __UBOOT__ diff --git a/include/mmc.h b/include/mmc.h index 7ec255d882..a5c0bcbef1 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -313,6 +313,7 @@ struct mmc { u64 capacity_boot; u64 capacity_rpmb; u64 capacity_gp[4]; + u64 boot_size; block_dev_desc_t block_dev; char op_cond_pending; /* 1 if we are waiting on an op_cond command */ char init_in_progress; /* 1 if we have done mmc_start_init() */ @@ -354,6 +355,8 @@ int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, unsigned short cnt, unsigned char *key); int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, unsigned short cnt, unsigned char *key); + +int mmc_switch_partition(struct mmc* mmc, unsigned int part); /** * Start device initialization and return immediately; it does not block on * polling OCR (operation condition register) status. Then you should call |