| /* |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * * |
| 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. |
| * * |
| Description: |
| */ |
| |
| #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> |
| #include <mmc.h> |
| |
| #define DbgP(fmt...) //printf("[burnupDbg]"fmt) |
| #define MsgP(fmt...) printf("[burnup]"fmt) |
| #define ErrP(fmt...) printf("[burnup]Err:%s,L%d:", __func__, __LINE__),printf(fmt) |
| |
| static unsigned char *cmd_name = (unsigned char *)("store"); |
| const char* _usbDownPartImgType = ""; |
| |
| #define MtdAlignBits (12) //32k |
| #define MtdAlignSz (1U << MtdAlignBits) |
| #define MtdAlignMask (MtdAlignSz - 1) |
| |
| /*** |
| 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) { |
| ErrP("upgrade: no buf!!"); |
| return -1; |
| } |
| |
| name = partition_name; |
| addr = (unsigned long)buf; |
| if ((EMMC_BOOT_FLAG == device_boot_flag) && !strcmp("1", (char*)name)) |
| { |
| if (off & 0x1ff) { |
| ErrP("emmc1 invalid offset 0x%llx\n", off); |
| return -__LINE__; |
| } |
| if (size & 0xff) { |
| MsgP("NOT align sz 0x%llx\n", size); |
| } |
| sprintf(str, "mmc read 0x%p 0x%llx 0x%llx", buf, (off>>9), (size>>9)); |
| ret = run_command(str, 0); |
| if (ret) { |
| ErrP("Fail in cmd[%s]\n", str); |
| return -__LINE__; |
| } |
| return ret; |
| } |
| |
| #if CONFIG_AML_MTD |
| if ((size & MtdAlignMask) && (NAND_BOOT_FLAG == device_boot_flag )) { |
| MsgP("Rd:Up sz 0x%llx to align 0x%x\n", size, MtdAlignSz); |
| size = ((size + MtdAlignMask)>>MtdAlignBits) << MtdAlignBits; |
| } |
| #if defined(UBIFS_IMG) || defined(CONFIG_CMD_UBIFS) |
| if (!strcmp(_usbDownPartImgType, "ubifs")) { |
| sprintf(str, "%s read 0x%llx %s 0x%llx", "ubi", addr, name, size); |
| MsgP("cmd[%s]", str); |
| } else |
| #endif |
| #endif//#if CONFIG_AML_MTD |
| {// not ubi part |
| sprintf(str, "%s read %s 0x%llx 0x%llx 0x%llx", cmd_name, name, addr, off, size); |
| } |
| |
| DbgP("run cmd[%s]\n", str); |
| ret = run_command(str, 0); |
| if (ret != 0) { |
| ErrP("cmd failed, ret=%d, [%s]\n", ret, str); |
| 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; |
| if ((EMMC_BOOT_FLAG == device_boot_flag) && !strcmp("1", (char*)name)) |
| { |
| if (off & 0x1ff) { |
| ErrP("emmc1 invalid offset 0x%llx\n", off); |
| return -__LINE__; |
| } |
| if (size & 0xff) { |
| MsgP("NOT align sz 0x%llx\n", size); |
| } |
| sprintf(str, "mmc write 0x%p 0x%llx 0x%llx", buf, (off>>9), (size>>9)); |
| ret = run_command(str, 0); |
| if (ret) { |
| ErrP("Fail in cmd[%s]\n", str); |
| return -__LINE__; |
| } |
| return ret; |
| } |
| |
| #if CONFIG_AML_MTD |
| if ((size & MtdAlignMask) && (NAND_BOOT_FLAG == device_boot_flag )) { |
| MsgP("Wr:Up sz 0x%llx to align 0x%x\n", size, MtdAlignSz); |
| size = ((size + MtdAlignMask)>>MtdAlignBits) << MtdAlignBits; |
| } |
| #if defined(UBIFS_IMG) || defined(CONFIG_CMD_UBIFS) |
| if (!strcmp(_usbDownPartImgType, "ubifs")) {//ubi part |
| sprintf(str, "%s write 0x%llx %s 0x%llx ", "ubi", addr, name, size); |
| } else |
| #endif// #if defined(UBIFS_IMG) || defined(CONFIG_CMD_UBIFS) |
| #endif// #if CONFIG_AML_MTD |
| { |
| sprintf(str, "%s write %s 0x%llx 0x%llx 0x%llx", cmd_name, name, addr, off, size); |
| } |
| |
| DbgP("run cmd[%s]\n", str); |
| ret = run_command(str, 0); |
| if (ret != 0) { |
| ErrP("cmd [%s] failed ", str); |
| 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) |
| { |
| char str[128]; |
| int ret=0; |
| |
| if (isdigit(*partition_name) && 1 == strlen((char*)partition_name)) |
| { |
| const int curDev = *partition_name - '0'; |
| sprintf(str, "mmc dev %d", curDev); |
| MsgP("cmd[%s]\n", str); |
| if (run_command(str, 0)) { |
| ErrP("Fail probe dev %d\n", curDev); |
| return 0; |
| } |
| struct mmc *mmc = find_mmc_device(curDev); |
| if (!mmc) { |
| ErrP("Fail find mmc %s\n", partition_name); |
| return 0; |
| } |
| if (mmc_init(mmc)) { |
| ErrP("FAil init mmc %s\n", partition_name); |
| return 0; |
| } |
| MsgP("mmc %s capacity 0x%llx\n", partition_name, mmc->capacity); |
| *size = mmc->capacity; |
| run_command("store disprotect key", 0); |
| MsgP("cmd[%s]\n", str); |
| return 0; |
| } |
| |
| sprintf(str, "%s size %s 0x%p ",cmd_name, partition_name, size); |
| store_dbg("command: %s", str); |
| ret = run_command(str, 0); |
| if (ret != 0) { |
| ErrP("cmd [%s] size failed ", str); |
| return -1; |
| } |
| |
| return ret; |
| } |
| |
| |
| /*** |
| 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 ",str); |
| 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; |
| |
| } |
| |
| //store dtb read/write buf sz |
| //@rwFlag: 0---read, 1---write, 2---iread |
| int store_dtb_rw(void* buf, unsigned dtbSz, int rwFlag) |
| { |
| char _cmdBuf[128]; |
| char* ops = !rwFlag ? "read" : ((1==rwFlag) ? "write" : "iread"); |
| |
| sprintf(_cmdBuf, "store dtb %s 0x%p 0x%x", ops, buf, dtbSz); |
| return run_command(_cmdBuf, 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 |
| |