diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile | 8 | ||||
-rw-r--r-- | common/cmd_bdinfo.c | 36 | ||||
-rw-r--r-- | common/cmd_bootm.c | 3 | ||||
-rw-r--r-- | common/cmd_load.c | 2 | ||||
-rw-r--r-- | common/cmd_mdcom.c | 1360 | ||||
-rw-r--r-- | common/cmd_mem.c | 26 | ||||
-rw-r--r-- | common/cmd_misc.c | 692 | ||||
-rw-r--r-- | common/cmd_mmc.c | 310 | ||||
-rw-r--r-- | common/cmd_mtdparts.c | 388 | ||||
-rw-r--r-- | common/cmd_nand.c | 406 | ||||
-rw-r--r-- | common/cmd_net.c | 39 | ||||
-rw-r--r-- | common/cmd_nvedit.c | 20 | ||||
-rw-r--r-- | common/cmd_onenand.c | 2 | ||||
-rw-r--r-- | common/cmd_sata.c | 9 | ||||
-rw-r--r-- | common/cmd_test.c | 217 | ||||
-rw-r--r-- | common/cmd_ubi.c | 296 | ||||
-rw-r--r-- | common/cmd_usb.c | 3 | ||||
-rw-r--r-- | common/cmd_version.c | 2 | ||||
-rw-r--r-- | common/cmd_yaffs2.c | 383 | ||||
-rw-r--r-- | common/env_onenand.c | 2 | ||||
-rw-r--r-- | common/env_remote.c | 79 | ||||
-rw-r--r-- | common/hush.c | 2 | ||||
-rw-r--r-- | common/image.c | 14 | ||||
-rw-r--r-- | common/main.c | 83 | ||||
-rw-r--r-- | common/usb.c | 25 | ||||
-rw-r--r-- | common/usb_hub.c | 27 | ||||
-rw-r--r-- | common/usb_storage.c | 59 |
27 files changed, 4117 insertions, 376 deletions
diff --git a/common/Makefile b/common/Makefile index d9f10f3f6e..7c828fc587 100644 --- a/common/Makefile +++ b/common/Makefile @@ -59,6 +59,7 @@ COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o +COBJS-$(CONFIG_ENV_IS_IN_REMOTE) += env_remote.o COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o # command @@ -123,6 +124,7 @@ ifdef CONFIG_PHYLIB COBJS-$(CONFIG_CMD_MII) += cmd_mdio.o endif COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o +COBJS-$(CONFIG_CMD_MDCOM) += cmd_mdcom.o COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o COBJS-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o COBJS-$(CONFIG_MP) += cmd_mp.o @@ -189,6 +191,7 @@ endif ifdef CONFIG_SPL_BUILD COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o +COBJS-$(CONFIG_SPL_IMAGE_SUPPORT) += image.o endif COBJS-y += console.o COBJS-y += dlmalloc.o @@ -204,6 +207,11 @@ XOBJS := $(addprefix $(obj),$(XCOBJS)) CPPFLAGS += -I.. +ifeq ($(REBOOT_WHEN_CRASH),1) +CPPFLAGS_common/cmd_misc.o += -DREBOOT_WHEN_CRASH +CPPFLAGS_common/main.o += -DREBOOT_WHEN_CRASH +endif + all: $(LIB) $(XOBJS) $(LIB): $(obj).depend $(OBJS) diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index 5359a47859..42f08fdd0d 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -119,6 +119,14 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) print_mhz("pevfreq", bd->bi_pevfreq); #endif +#ifdef CONFIG_ENABLE_36BIT_PHYS +#ifdef CONFIG_PHYS_64BIT + puts("addressing = 36-bit\n"); +#else + puts("addressing = 32-bit\n"); +#endif +#endif + print_eth(0); #if defined(CONFIG_HAS_ETH1) print_eth(1); @@ -139,7 +147,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #ifdef CONFIG_HERMES print_mhz("ethspeed", bd->bi_ethspeed); #endif - printf("IP addr = %pI4\n", &bd->bi_ip_addr); + printf("IP addr = %s\n", getenv("ipaddr")); printf("baudrate = %6ld bps\n", bd->bi_baudrate); print_num("relocaddr", gd->relocaddr); return 0; @@ -164,7 +172,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %ld bps\n", bd->bi_baudrate); @@ -188,7 +196,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %ld bps\n", (ulong)bd->bi_baudrate); return 0; @@ -221,7 +229,7 @@ int do_bdinfo(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %6ld bps\n", bd->bi_baudrate); return 0; @@ -267,7 +275,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) print_eth(3); #endif - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %ld bps\n", bd->bi_baudrate); @@ -295,7 +303,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) print_num("flashoffset", (ulong)bd->bi_flashoffset); print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); printf("baudrate = %d bps\n", bd->bi_baudrate); return 0; @@ -315,7 +323,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) print_num("flashoffset", (ulong)bd->bi_flashoffset); print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); printf("baudrate = %d bps\n", bd->bi_baudrate); return 0; @@ -335,7 +343,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) print_num("flashoffset", (ulong)bd->bi_flashoffset); print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); printf("baudrate = %lu bps\n", bd->bi_baudrate); return 0; @@ -359,7 +367,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %d bps\n", bd->bi_baudrate); #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) @@ -395,7 +403,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %ld bps\n", (ulong)bd->bi_baudrate); return 0; @@ -428,7 +436,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); print_mhz("ethspeed", bd->bi_ethspeed); #endif printf("baudrate = %d bps\n", bd->bi_baudrate); @@ -453,7 +461,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif print_num("FB base ", gd->fb_base); return 0; @@ -477,7 +485,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %d bps\n", bd->bi_baudrate); @@ -498,7 +506,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #if defined(CONFIG_CMD_NET) print_eth(0); - printf("ip_addr = %pI4\n", &bd->bi_ip_addr); + printf("ip_addr = %s\n", getenv("ipaddr")); #endif printf("baudrate = %ld bps\n", bd->bi_baudrate); diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 5685232892..45e726af8b 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -1587,7 +1587,6 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc, static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - ulong iflag; bootm_headers_t images; if (bootz_start(cmdtp, flag, argc, argv, &images)) @@ -1598,7 +1597,7 @@ static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ - iflag = disable_interrupts(); + disable_interrupts(); #if defined(CONFIG_CMD_USB) /* diff --git a/common/cmd_load.c b/common/cmd_load.c index f4d66deae3..cd00ad1251 100644 --- a/common/cmd_load.c +++ b/common/cmd_load.c @@ -975,7 +975,7 @@ static ulong load_serial_ymodem (ulong offset) ulong addr = 0; size = 0; - info.mode = xyzModem_ymodem; + info.mode = xyzModem_xmodem; res = xyzModem_stream_open (&info, &err); if (!res) { diff --git a/common/cmd_mdcom.c b/common/cmd_mdcom.c new file mode 100644 index 0000000000..a2bc1bac59 --- /dev/null +++ b/common/cmd_mdcom.c @@ -0,0 +1,1360 @@ +/* + * (C) Copyright 2001 + * 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 + */ + +/* + * Misc functions + */ +#include <common.h> +#include <command.h> +#include <usb/usbserial.h> +#include <nand.h> +#include <jffs2/jffs2.h> +#include <asm/arch/mdcom.h> +#include <asm/arch/hwcfg.h> +#include <asm/arch/factory.h> +#include <asm/arch/prdinfo.h> +#include <asm/arch/rda_sys.h> +#include <part.h> +#include <mmc.h> +#include <mmc/mmcpart.h> +#include <nand.h> +#include <malloc.h> +#include <linux/mtd/nand.h> +#include <mtd/nand/rda_nand.h> + + +#if 1 +#define bb_dbg(fmt, args...) printf(fmt, ##args) +#else +#define bb_dbg(fmt, args...) do {} while(0) +#endif + +#define RDA_ADD_ROUNDUP(x) (((x) + 3) & ~3) +#define RDA_CHN_BUF_LEN 140 + +struct rda_sys_hdr { + u16 magic; + u16 mod_id; + u32 req_id; + u32 ret_val; + u16 msg_id; + u16 ext_len; + u8 ext_data[]; +}; + +struct rda_bp_info { + u32 bm_ver; + u32 bm_commit_rev; + u32 bm_build_date; + u32 bs_ver; + u32 bs_commit_rev; + u32 bs_build_date; +}; + +extern int mtdparts_init_default(void); +extern int find_dev_and_part(const char *id, struct mtd_device **dev, + u8 *part_num, struct part_info **part); + +#ifdef REBOOT_WHEN_CRASH +#define ROLLBACK_TO_RECOVERY_MODE 0 +#endif + +/* + * Syntax: + * mdcom_send {channel} {adress} {size} [{timeout} {mode}] + */ +int do_mdcom_send(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int channel; + void *buf; + int size; + int timeout = 0; + int mode = 0; + + if (argc < 4) + return CMD_RET_USAGE; + + channel = simple_strtoul(argv[1], NULL, 10); + buf = (void*) simple_strtoul(argv[2], NULL, 16); + size = simple_strtoul(argv[3], NULL, 10); + if (argc >4) + timeout = simple_strtoul(argv[4], NULL, 10); + if (argc >5) + mode = simple_strtoul(argv[5], NULL, 10); + + if (mode) { + bb_dbg("MDCOM send %d bytes stream to channel %d with returned value %d.\n", + size, channel, rda_mdcom_channel_buf_send_stream(channel, buf, + size, timeout)); + } else { + bb_dbg("MDCOM send %d bytes dgram to channel %d with returned value %d.\n", + size, channel, rda_mdcom_channel_buf_send_dgram(channel, buf, + size, timeout)); + } + + rda_mdcom_channel_show(channel); + return 0; +} + +/* + * Syntax: + * mdcom_recv {channel} {adress} {size} [{timeout} {mode}] + */ +int do_mdcom_recv(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int channel; + void *buf; + int size; + int timeout = 0; + int mode = 0; + + if (argc < 4) + return CMD_RET_USAGE; + + channel = simple_strtoul(argv[1], NULL, 10); + buf = (void*) simple_strtoul(argv[2], NULL, 16); + size = simple_strtoul(argv[3], NULL, 10); + if (argc >4) + timeout = simple_strtoul(argv[4], NULL, 10); + if (argc >5) + mode = simple_strtoul(argv[5], NULL, 10); + + if (mode) { + bb_dbg("MDCOM receive %d bytes stream from channel %d with returned value %d.\n", + size, channel, rda_mdcom_channel_buf_recv_stream(channel, buf, + size, timeout)); + } else { + bb_dbg("MDCOM receive %d bytes dgram from channel %d with returned value %d.\n", + size, channel, rda_mdcom_channel_buf_recv_dgram(channel, buf, + size, timeout)); + } + + rda_mdcom_channel_show(channel); + return 0; +} + +static int rda_image_verify_header(const image_header_t *hdr) +{ + bb_dbg(" Verifying Image Header ... "); + if (!image_check_magic(hdr)) { + bb_dbg("Bad Magic Number\n"); + return CMD_RET_FAILURE; + } + + if (!image_check_hcrc(hdr)) { + bb_dbg("Bad Header Checksum\n"); + return CMD_RET_FAILURE; + } + bb_dbg("OK\n"); + + image_print_contents(hdr); + + return CMD_RET_SUCCESS; +} + +static int rda_image_verify_data(const image_header_t *hdr) +{ + bb_dbg(" Verifying Data Checksum ... "); + if (!image_check_dcrc(hdr)) { + bb_dbg("Bad Data CRC\n"); + return CMD_RET_FAILURE; + } + bb_dbg("OK\n"); + + return CMD_RET_SUCCESS; +} + +static int rda_image_verify(const image_header_t *hdr) +{ + int ret; + + ret = rda_image_verify_header(hdr); + if (ret == CMD_RET_SUCCESS) { + ret = rda_image_verify_data(hdr); + } + return ret; +} + +int rda_modem_image_load(const image_header_t *hdr, int cal_en) +{ + u32 pc, param; + u32 modem_load_addr = image_get_load(hdr); + u32 ap_load_addr = rda_mdcom_address_modem2ap(modem_load_addr); + + bb_dbg("%08x (AP address %08x) ...\n", modem_load_addr, ap_load_addr); + + memcpy((void *)ap_load_addr, (const void *)image_get_data(hdr), + image_get_size(hdr)); + + pc = image_get_ep(hdr); + param = cal_en ? 0xCA1BCA1B : 0; + if (rda_mdcom_setup_run_env(pc, param)) + return -1; + + bb_dbg(" pc = %08x\n", pc); + bb_dbg(" param = %08x\n", param); + bb_dbg("Done\n"); + + return 0; +} + +int rda_modem_cal_save(void) +{ + u32 addr, size; + int ret; + + /* update all data to factorydata part. */ + rda_mdcom_get_calib_section(&addr, &size); + factory_set_modem_calib((unsigned char *)addr); + rda_mdcom_get_ext_calib_section(&addr, &size); + factory_set_modem_ext_calib((unsigned char *)addr); + rda_mdcom_get_factory_section(&addr, &size); + factory_set_modem_factory((unsigned char *)addr); + rda_mdcom_get_ap_factory_section(&addr, &size); + factory_set_ap_factory((unsigned char *)addr); + + ret = factory_burn(); + if (ret) { + bb_dbg("Error when saving calibration data\n"); + return ret; + } + return 0; +} + +static void rda_modem_handle_syscmd(void) +{ + u8 md_com_buf[RDA_CHN_BUF_LEN / sizeof(u8)]; + struct rda_sys_hdr *phdr = (struct rda_sys_hdr *)md_com_buf; + +#ifdef TEST_SYS + static int test_num = 0; + u8 tx_buf[RDA_CHN_BUF_LEN / sizeof(u8)]; + struct rda_sys_hdr *ptx_hdr; + u32 *pext; + int ret; + + if (test_num < 40) { + ptx_hdr = (struct rda_sys_hdr *) tx_buf; + + ptx_hdr->magic = 0xA8B1; + ptx_hdr->mod_id = 0x1; + ptx_hdr->msg_id = 0x2000 + test_num; + ptx_hdr->req_id = 0xA1234567; + ptx_hdr->ret_val = 0xF7654321; + + ptx_hdr->ext_len = 4; + pext = (u32 *)ptx_hdr->ext_data; + pext[0] = 0x1000123F; + + ret = rda_mdcom_channel_buf_send_dgram(RDA_MDCOM_CHANNEL_SYSTEM, tx_buf, 16, 0); + if (!ret) { + rda_mdcom_line_set(RDA_MDCOM_PORT1, 2); + test_num++; + } + } +#endif /* TEST_SYS */ + + if (!rda_mdcom_tstc(RDA_MDCOM_CHANNEL_SYSTEM)) + return; + + if (rda_mdcom_channel_buf_recv_dgram( + RDA_MDCOM_CHANNEL_SYSTEM, + md_com_buf, + 16, + usec2ticks(1000))) + return; + + if (phdr->magic == 0xA8B1) { + u16 len; + u8 *pdata; + u32 i; + u32 *pret; + + len = phdr->ext_len; + + bb_dbg("## RECEIVED SYSTEM CMD:\n"); + bb_dbg("MODID - 0x%04x\n", phdr->mod_id); + bb_dbg("REQID - 0x%08x\n", phdr->req_id); + bb_dbg("RETVAL - 0x%08x\n", phdr->ret_val); + bb_dbg("MSGID - 0x%04x\n", phdr->msg_id); + bb_dbg("LEN - 0x%04x\n", phdr->ext_len); + + if (len) { + pdata = phdr->ext_data; + + if (len > 128) { + bb_dbg("Length is invalid!\n"); + } else if (len != rda_mdcom_channel_buf_recv_stream( + RDA_MDCOM_CHANNEL_SYSTEM, pdata, len, 0)) { + bb_dbg("Read Parameters Failed!\n"); + } else { + bb_dbg("Params - "); + for (i = 0; i < len; i++) { + bb_dbg("%02x ", pdata[i]); + } + bb_dbg("\n\n"); + } + } else { + if ((phdr->mod_id == 1) && (phdr->msg_id == 2)) { + bb_dbg("Calibration done\n"); + phdr->msg_id = 0x1001; + phdr->ext_len = 4; + pret = (u32 *) phdr->ext_data; + + if (rda_modem_cal_save()) { + pret[0] = 0x0; + bb_dbg("Calibration data save failed\n"); + } else { + pret[0] = 0x1; + bb_dbg("Calibration data save succeed\n"); + prdinfo_set_cali_result(1); + } + + rda_mdcom_channel_buf_send_dgram( + RDA_MDCOM_CHANNEL_SYSTEM, md_com_buf, 20, 0); + rda_mdcom_line_set(RDA_MDCOM_PORT1, 2); + } + } + } +} + +static void rda_modem_handle_trace(void) +{ + u8 md_com_buf[RDA_CHN_BUF_LEN / sizeof(u8)]; + int ch; + + while (rda_mdcom_tstc(RDA_MDCOM_CHANNEL_TRACE)) { + int len = rda_mdcom_channel_buf_recv_stream( + RDA_MDCOM_CHANNEL_TRACE, + md_com_buf, + 128, + 0); + usbser_write(USB_ACM_CHAN_0, (unsigned char *) md_com_buf, len); + } + + while (usbser_tstc(USB_ACM_CHAN_0) && + rda_mdcom_channel_buf_send_available(RDA_MDCOM_CHANNEL_TRACE)) { + ch = usbser_getc(USB_ACM_CHAN_0); + rda_mdcom_putc((char) ch, RDA_MDCOM_CHANNEL_TRACE); + } +} + +static void rda_modem_handle_atcmd(void) +{ + u8 md_com_buf[RDA_CHN_BUF_LEN / sizeof(u8)]; + if (!rda_mdcom_tstc(RDA_MDCOM_CHANNEL_AT)) + return; + + bb_dbg("## RECEIVED AT CMD:"); + do { + unsigned short len = rda_mdcom_channel_buf_recv_stream( + RDA_MDCOM_CHANNEL_AT, + md_com_buf, + 128, + 0); + *((char*) md_com_buf + len) = 0; + puts((const char *) md_com_buf); + } while (rda_mdcom_tstc(RDA_MDCOM_CHANNEL_AT)); + bb_dbg("\n"); +} + +int rda_modem_cal_load(void) +{ + u32 addr, size; + const u8 *data; + + /* extended calibration data */ + rda_mdcom_get_ext_calib_section(&addr, &size); + data = factory_get_modem_ext_calib(); + memcpy((u8 *)addr, data, size); + bb_dbg("MOMEM EXT CALIB address %08x ...\n", addr); + + /* calibration data */ + rda_mdcom_get_calib_section(&addr, &size); + data = factory_get_modem_calib(); + memcpy((u8 *)addr, data, size); + bb_dbg("MOMEM CALIB address %08x ...\n", addr); + + /* modem fact data */ + rda_mdcom_get_factory_section(&addr, &size); + data = factory_get_modem_factory(); + memcpy((u8 *)addr, data, size); + bb_dbg("MOMEM FACT address %08x ...\n", addr); + + /* ap fact data */ + rda_mdcom_get_ap_factory_section(&addr, &size); + data = factory_get_ap_factory(); + memcpy((u8 *)addr, data, size); + bb_dbg("AP FACT address %08x ...\n", addr); + + return 0; +} + +static int rda_check_ap_calib_msg(void) +{ + unsigned int msg_id = 0; + unsigned int msg_size = 0; + unsigned char *msg_data = malloc(RDA_AP_CALIB_MSG_DATA_LEN); + + if (!msg_data) + return -1; + + if (factory_get_ap_calib_msg(&msg_id, &msg_size, msg_data)) { + free(msg_data); + return -1; + } + + if (msg_id & RDA_AP_CALIB_MSG_SET_PRDINFO) + prdinfo_set_data((struct prdinfo *)msg_data); + + free(msg_data); + return 0; +} + +/* use this function after factorydata is loaded */ +static int rda_send_prdinfo_data(void) +{ + unsigned int msg_id = 0; + unsigned int msg_size = 0; + unsigned char *msg_data = malloc(RDA_AP_CALIB_MSG_DATA_LEN); + + if (!msg_data) + return -1; + + memset(msg_data, 0, RDA_AP_CALIB_MSG_DATA_LEN); + prdinfo_get_data((struct prdinfo *)msg_data); + + msg_id = RDA_AP_CALIB_MSG_GET_PRDINFO; + msg_size = sizeof(struct prdinfo); + factory_set_ap_calib_msg(msg_id, msg_size, msg_data); + free(msg_data); + return 0; +} + +void rda_modem_cal_loop(void) +{ + /* send prdinfo data to calib tool */ + rda_send_prdinfo_data(); + + while (1) { +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + WATCHDOG_RESET(); +#endif + /* check Ctrl-C */ + ctrlc(); + if ((had_ctrlc())) { + bb_dbg("\n## ABORT MANUALLY!\n\n"); + return; + } + + rda_modem_handle_syscmd(); + + rda_modem_handle_trace(); + + rda_modem_handle_atcmd(); + + /* check message to u-boot from PC calib tool*/ + rda_check_ap_calib_msg(); + } +} + +int rda_modem_bbimages_load_from_nand(const image_header_t **hdrInit, + const image_header_t **hdrWork) +{ + struct mtd_info *nand; + struct mtd_device *dev; + struct part_info *part; + size_t page_size, block_size; + loff_t offset; + size_t read_size, image_size; + u8 pnum; + int ret; + u_char *buffer; + image_header_t *hdr; + u32 bad_blocks; + char buf[256]; + u32 ih_len; + int i; + + ret = mtdparts_init_default(); + if (ret != 0) { + bb_dbg("mtdparts init error\n"); + return ret; + } + + ret = find_dev_and_part("modem", &dev, &pnum, &part); + if (ret) { + bb_dbg("unknown partition name - modem\n"); + return ret; + } else if (dev->id->type != MTD_DEV_TYPE_NAND) { + bb_dbg("mtd dev type error"); + return CMD_RET_FAILURE; + } + bb_dbg("found modem part '%s' offset: 0x%llx length: 0x%llx\n", + part->name, part->offset, part->size); + + nand = &nand_info[dev->id->num]; + page_size = nand->writesize; + block_size = nand->erasesize; + + bb_dbg("\n## Checking Modem Code Image ...\n\n"); + + for (i = 0; i < 2; ++i) { + if (i == 0) { + offset = part->offset; + buffer = (u_char *)SCRATCH_ADDR; + hdr = (image_header_t *)buffer; + } else { + hdr = (image_header_t *)((u8 *)hdr + image_size); + } + + if (buffer < (u8 *)hdr + sizeof(image_header_t)) { + read_size = (u8 *)hdr + sizeof(image_header_t) - buffer; + if (is_power_of_2(page_size)) + read_size = ROUND(read_size, page_size); + else + read_size = roundup(read_size, page_size); + bad_blocks = 0; + + bb_dbg("read 0x%x bytes from '%s' offset: 0x%08x\n", + read_size, part->name, (u32)offset); + ret = nand_read_skip_bad_new(nand, offset, &read_size, + buffer, &bad_blocks); + if (ret) { + bb_dbg("nand read fail\n"); + return ret; + } + + offset += read_size + block_size * bad_blocks; + buffer += read_size; + } + + ret = rda_image_verify_header(hdr); + if (ret) + return ret; + + image_size = image_get_image_size(hdr); + + if (buffer < (u8 *)hdr + image_size) { + read_size = (u8 *)hdr + image_size - buffer; + if (is_power_of_2(page_size)) + read_size = ROUND(read_size, page_size); + else + read_size = roundup(read_size, page_size); + + bb_dbg("\nread 0x%x bytes from '%s' offset: 0x%08x\n", + read_size, part->name, (u32)offset); + ret = nand_read_skip_bad_new(nand, offset, &read_size, + buffer, &bad_blocks); + if (ret) { + bb_dbg("nand read fail\n"); + return ret; + } + + offset += read_size + block_size * bad_blocks; + buffer += read_size; + } + + ret = rda_image_verify_data(hdr); + if (ret) + return ret; + + if (i == 0) { + ih_len = min(sizeof(buf), IH_NMLEN); + strncpy(buf, (const char *)hdr->ih_name, ih_len); + buf[ih_len - 1] = '\0'; + } + if (i == 0 && strstr(buf, "raminit")) { + bb_dbg("## Raminit Image Detected\n"); + bb_dbg("\n"); + *hdrInit = hdr; + } else { + bb_dbg("## Work Image Detected\n"); + bb_dbg("\n"); + *hdrWork = hdr; + break;; + } + } + + return CMD_RET_SUCCESS; +} + +int rda_modem_bbimages_load_from_mmc(const image_header_t **hdrInit, + const image_header_t **hdrWork) +{ + u64 offset = 0; + size_t read_size, image_size; + u_char *buffer; + image_header_t *hdr; + char buf[256]; + u32 ih_len; + int i; + int ret; + disk_partition_t *ptn; + block_dev_desc_t *mmc_blkdev; + struct mmc *mmc; + + mmc_blkdev = get_dev_by_name(CONFIG_MMC_DEV_NAME); + if (mmc_blkdev) + mmc = container_of(mmc_blkdev, struct mmc, block_dev); + else + return CMD_RET_FAILURE; + + if (!mmc) { + bb_dbg("mmc doesn't exist"); + return CMD_RET_FAILURE; + } + + ptn = partition_find_ptn("modem"); + if(ptn == 0) { + bb_dbg("mmc partition table doesn't exist"); + return -1; + } + + bb_dbg("found modem part offset: 0x%lx\n", ptn->start); + + bb_dbg("\n## Checking Modem Code Image ...\n\n"); + + for (i = 0; i < 2; ++i) { + if (i == 0) { + offset = ptn->start * ptn->blksz; + buffer = (u_char *)SCRATCH_ADDR; + hdr = (image_header_t *)buffer; + } else { + hdr = (image_header_t *)((u8 *)hdr + image_size); + } + + if (buffer < (u8 *)hdr + sizeof(image_header_t)) { + read_size = (u8 *)hdr + sizeof(image_header_t) - buffer; + read_size = ROUND(read_size, 512); + + bb_dbg("read 0x%x bytes offset: 0x%08x\n", + read_size, (u32)offset); + ret = mmc_read(mmc, offset, buffer, read_size); + if (ret <= 0) { + bb_dbg("mmc read fail\n"); + return ret; + } + + offset += read_size; + buffer += read_size; + } + + ret = rda_image_verify_header(hdr); + if (ret) + return ret; + + image_size = image_get_image_size(hdr); + + if (buffer < (u8 *)hdr + image_size) { + read_size = (u8 *)hdr + image_size - buffer; + read_size = ROUND(read_size, 512); + + bb_dbg("\nread 0x%x bytes offset: 0x%08x\n", + read_size, (u32)offset); + ret = mmc_read(mmc, offset, buffer, read_size); + if (ret <= 0) { + bb_dbg("mmc read fail\n"); + return ret; + } + + offset += read_size; + buffer += read_size; + } + + ret = rda_image_verify_data(hdr); + if (ret) + return ret; + + if (i == 0) { + ih_len = min(sizeof(buf), IH_NMLEN); + strncpy(buf, (const char *)hdr->ih_name, ih_len); + buf[ih_len - 1] = '\0'; + } + if (i == 0 && strstr(buf, "raminit")) { + bb_dbg("## Raminit Image Detected\n"); + bb_dbg("\n"); + *hdrInit = hdr; + } else { + bb_dbg("## Work Image Detected\n"); + bb_dbg("\n"); + *hdrWork = hdr; + break;; + } + } + + return CMD_RET_SUCCESS; +} + +void rdaHexPuts(char* p, int l) +{ + char strBuf[64]; + char* s = strBuf; + if (l > 20) + l = 20; + + while (l--) { + unsigned char c = (unsigned char) *p++; + *s = ((c >> 4) & 0xF) + '0'; + if (*s > '9') + *s = *s + 'A' - '9' - 1; + + *++s = (c & 0xF) + '0'; + if (*s > '9') + *s = *s + 'A' - '9' - 1; + + *++s = ' '; + ++s; + } + *s = '\r'; + *++s = '\n'; + *++s = 0; + puts((const char *) strBuf); +} + +void rda_modem_cal_test(void) +{ + char cmdbuf[16]; + unsigned long long end_time = get_ticks(); + + while (1) { +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + WATCHDOG_RESET(); +#endif + /* check Ctrl-C */ + ctrlc(); + if ((had_ctrlc())) { + bb_dbg("\n## ABORT MANUALLY!\n\n"); + return; + } + + if (end_time < get_ticks()) { + char* p = cmdbuf; + *p++ = 0xad; + *p++ = 0x00; + *p++ = 0x0a; + *p++ = 0xFF; + *p++ = 0x82; + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0x82; + *p++ = (char)((end_time >> 0) & 0xFF); + *p++ = (char)((end_time >> 8) & 0xFF); + *p++ = (char)((end_time >> 16) & 0xFF); + *p++ = (char)((end_time >> 24) & 0xFF); + *p++ = 0xFF; + bb_dbg("## Send write cmd to modem: "); + rdaHexPuts(cmdbuf, rda_mdcom_channel_buf_send_stream( + RDA_MDCOM_CHANNEL_TRACE, cmdbuf, 14, 0)); + + p = cmdbuf; + *p++ = 0xad; + *p++ = 0x00; + *p++ = 0x07; + *p++ = 0xFF; + *p++ = 0x02; + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0x82; + *p++ = (char)((end_time >> 24) & 0xFF); + *p++ = 0xFF; + bb_dbg("## Send read cmd to modem: "); + rdaHexPuts(cmdbuf, rda_mdcom_channel_buf_send_stream( + RDA_MDCOM_CHANNEL_TRACE, cmdbuf, 11, 0)); + + end_time = get_ticks() + usec2ticks(20000); + } + + if (rda_mdcom_tstc(RDA_MDCOM_CHANNEL_TRACE)) { + bb_dbg("## received from modem:"); + do { + rdaHexPuts(cmdbuf, rda_mdcom_channel_buf_recv_stream( + RDA_MDCOM_CHANNEL_TRACE, cmdbuf, + sizeof(cmdbuf), 0)); + } while (rda_mdcom_tstc(RDA_MDCOM_CHANNEL_TRACE)); + } + } +} + +static void rda_show_modem_exception(void) +{ + char *addr; + unsigned int len; + char buf[256]; + + rda_mdcom_get_modem_exception_info((u32 *)&addr, &len); + snprintf(buf, sizeof(buf), "%s\n", addr); + buf[sizeof(buf) - 1] = '\0'; + puts("\n"); + if (addr) { + puts("Modem exception info:\n"); + puts("---------------------\n"); + puts(buf); + puts("---------------------\n"); + } else { + puts("No valid modem exception info\n"); + } +} + +extern void shutdown_system(void); + +static void rda_modem_shutdown_system(void) +{ + struct rda_sys_hdr hdr; + + bb_dbg("\n## System is being shutdown ... "); + + hdr.magic = 0xA8B1; + hdr.mod_id = 0x0; + hdr.msg_id = 0x1001; + hdr.req_id = 0x0; + hdr.ret_val = 0x0; + hdr.ext_len = 0; + + rda_mdcom_channel_buf_send_dgram( + RDA_MDCOM_CHANNEL_SYSTEM, &hdr, sizeof(hdr), + usec2ticks(100000)); + rda_mdcom_line_set(RDA_MDCOM_PORT1, 2); + /* Wait sometime until modem shutdowns the system (about 1.8s) */ + udelay(5000000); + /* Modem is in trouble. Shutdown the system directly. */ + bb_dbg("\n## Bootloader directly shutdown ... "); + shutdown_system(); +} + +int bbimages_get_header(const u8 *p_image, const image_header_t **hdrInit, + const image_header_t **hdrWork) +{ + int retVal; + char buf[256]; + u32 ih_len; + int i; + image_header_t *hdr; + + for (i = 0; i < 2; i++) { + hdr = (image_header_t *) RDA_ADD_ROUNDUP((int) p_image); + + bb_dbg("\n## Checking Modem Code Image at %08x ...\n", + (unsigned int)hdr); + retVal = rda_image_verify(hdr); + if (retVal) { + /* If there is no image, we initialize channels + * still. Otherwise kernel would not be + * loaded. */ + rda_mdcom_channel_all_init(); + return retVal; + } + + if (i == 0) { + ih_len = min(sizeof(buf), IH_NMLEN); + strncpy(buf, (const char *)hdr->ih_name, ih_len); + buf[ih_len - 1] = '\0'; + } + if (i == 0 && strstr(buf, "raminit")) { + bb_dbg("## Raminit Image Detected\n"); + p_image += image_get_image_size(hdr); + *hdrInit = hdr; + } else { + bb_dbg("## Work Image Detected\n"); + *hdrWork = hdr; + break; + } + } + + return CMD_RET_SUCCESS; +} + +int mdcom_check_and_wait_modem(int check_boot_key) +{ + int shutdown = 0; + unsigned long long end_time; + u32 reset_cause; + u32 itf_version; + + /* Set a timeout of 2 seconds to wait for BP */ + bb_dbg("\n## Waiting for modem response ... "); + + end_time = get_ticks() + usec2ticks(2000000); + while (!rda_mdcom_line_set_wait(RDA_MDCOM_PORT0, + RDA_MDCOM_LINE_CMD_START, 100)) { + /* check exception */ + if (rda_mdcom_line_set_check(RDA_MDCOM_PORT0, + RDA_MDCOM_LINE_EXCEPTION)) { + bb_dbg("\n\n"); + bb_dbg("**********************************\n"); + bb_dbg("*** Error: Detect modem exception!\n"); + rda_show_modem_exception(); +#ifdef REBOOT_WHEN_CRASH + bb_dbg("Rebooting ...\n\n\n"); + udelay(5000); + disable_interrupts(); + if (ROLLBACK_TO_RECOVERY_MODE) + rda_reboot(REBOOT_TO_RECOVERY_MODE); + else + rda_reboot(REBOOT_TO_NORMAL_MODE); +#endif + return CMD_RET_FAILURE; + } + /* check timeout */ + if (get_ticks() > end_time) { +#ifdef REBOOT_WHEN_CRASH + bb_dbg("\n\n## Error: Timeout when waiting for " + "modem response. Rebooting ...\n\n\n"); + udelay(5000); + disable_interrupts(); + if (ROLLBACK_TO_RECOVERY_MODE) + rda_reboot(REBOOT_TO_RECOVERY_MODE); + else + rda_reboot(REBOOT_TO_NORMAL_MODE); +#else + end_time = -1; + bb_dbg("\n\n## Warning: Timeout when waiting for " + "modem response. Press Ctrl-C to abort.\n"); +#endif + } + /* check Ctrl-C */ + ctrlc(); + if ((had_ctrlc())) { + bb_dbg("\n## ABORT MANUALLY!\n\n"); + return CMD_RET_FAILURE; + } + } + bb_dbg("Done\n"); + + reset_cause = rda_mdcom_get_reset_cause(); + itf_version = rda_mdcom_get_interface_version(); + bb_dbg("\n## Reset cause : 0x%08x\n", reset_cause); + bb_dbg("\n## Communication interface version : 0x%08x\n", itf_version); + if (itf_version != RDA_BP_VER) { + bb_dbg("*** Error: Unsupported version. 0x%08x is expected.\n", + RDA_BP_VER); + return CMD_RET_FAILURE; + } + + if (reset_cause == RDA_RESET_CAUSE_NORMAL) { + /* Check power-on key status */ + if (check_boot_key && !get_saved_boot_key_state()) { + shutdown = 0; + bb_dbg("\n## Power-on key is not pressed for normal boot."); + bb_dbg("\n## ****** Shutdown is needed later ******\n"); + } + } + + bb_dbg("\n## Init mdcom channels ... "); + rda_mdcom_channel_all_init(); + rda_mdcom_line_clear(RDA_MDCOM_PORT0, RDA_MDCOM_LINE_CMD_START); + bb_dbg("Done\n"); + + /* Check if shutdown is needed after modem fully starts up */ + if (shutdown) + rda_modem_shutdown_system(); + + /* rda_mdcom_show_software_version(); */ + return CMD_RET_SUCCESS; +} + +static int do_check_and_wait_modem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int check_boot_key = 0; + + if (argc >= 2) + check_boot_key = (int) simple_strtoul(argv[1], NULL, 10); + + return mdcom_check_and_wait_modem(check_boot_key); +} + +int bbimages_load(const image_header_t *hdrInit, const image_header_t *hdrWork, + int cal_en) +{ + unsigned long long end_time; + u32 addr, len; + char buf[256]; + int update_calib = 0, update_factory = 0, update_ap_factory = 0; + u32 modem_load_addr = image_get_load(hdrWork); + + /* set modem logic base address for modem side, + by the work code loading address in image header */ + rda_mdcom_set_logic_base_addr(modem_load_addr); + + bb_dbg("\n## Init mdcom ports ... "); + rda_mdcom_init_port(RDA_MDCOM_PORT0); + rda_mdcom_init_port(RDA_MDCOM_PORT1); + bb_dbg("Done\n"); + + if (hdrInit) { + bb_dbg("\n## Load Raminit Code to modem at "); + rda_modem_image_load(hdrInit, 0); + + bb_dbg("\n## Start modem and waiting for response ... "); + rda_mdcom_line_set(RDA_MDCOM_PORT0, RDA_MDCOM_LINE_DL_HANDSHAKE); + /* Set a timeout of 2 seconds to wait for BP */ + end_time = get_ticks() + usec2ticks(2000000); + while (!rda_mdcom_line_set_wait(RDA_MDCOM_PORT0, + RDA_MDCOM_LINE_DL_HANDSHAKE, 100)) { + /* check timeout */ + if (get_ticks() > end_time) { +#ifdef REBOOT_WHEN_CRASH + bb_dbg("\n\n## Error: Timeout when waiting for " + "modem response. Rebooting ...\n\n\n"); + udelay(5000); + disable_interrupts(); + if (ROLLBACK_TO_RECOVERY_MODE) + rda_reboot(REBOOT_TO_RECOVERY_MODE); + else + rda_reboot(REBOOT_TO_NORMAL_MODE); +#else + end_time = -1; + bb_dbg("\n\n## Warning: Timeout when waiting for " + "modem response. Press Ctrl-C to abort.\n"); +#endif + } + /* check Ctrl-C */ + ctrlc(); + if ((had_ctrlc())) { + bb_dbg("\n## ABORT MANUALLY!\n\n"); + return CMD_RET_FAILURE; + } + } + rda_mdcom_line_clear(RDA_MDCOM_PORT0, RDA_MDCOM_LINE_DL_HANDSHAKE); + bb_dbg("Done\n"); + } + + /* Check whether modem crashed in the last run */ + if (rda_mdcom_modem_crashed_before()) { + rda_mdcom_get_modem_exception_info(&addr, &len); + buf[0] = '\0'; + if (addr) { + snprintf(buf, sizeof(buf), "%s", (char *)addr); + buf[sizeof(buf) - 1] = '\0'; + /* TODO: Save the exception info to nand/sdmmc */ + } + rda_mdcom_get_modem_log_info(&addr, &len); + if (addr) { + /* TODO: Save the log info to nand/sdmmc */ + /* NOTE: The log is in binary format! */ + } + } + /* Check whether to udpate modem calib and factory data */ + if (system_rebooted()) { + update_calib = rda_mdcom_calib_update_cmd_valid(); + if (update_calib) { + bb_dbg("\n## Detect calib update command\n"); + rda_mdcom_get_calib_section(&addr, &len); + factory_set_modem_calib((unsigned char *)addr); + rda_mdcom_get_ext_calib_section(&addr, &len); + factory_set_modem_ext_calib((unsigned char *)addr); + } + update_factory = rda_mdcom_factory_update_cmd_valid(); + if (update_factory) { + bb_dbg("\n## Detect factory update command\n"); + rda_mdcom_get_factory_section(&addr, &len); + factory_set_modem_factory((unsigned char *)addr); + } + update_ap_factory = rda_mdcom_ap_factory_update_cmd_valid(); + if (update_ap_factory) { + bb_dbg("\n## Detect AP factory update command\n"); + rda_mdcom_get_ap_factory_section(&addr, &len); + factory_set_ap_factory((unsigned char *)addr); + } + if (update_calib || update_factory || update_ap_factory) { + bb_dbg("\n## Burn calib and/or factory data\n"); + if (factory_burn()) + bb_dbg("\n** Error when burning data\n"); + } + } + /* Init all log info and some magic numbers */ + rda_mdcom_init_all_log_info(); + + bb_dbg("\n## Load Work Code to modem at "); + if (rda_modem_image_load(hdrWork, cal_en)) { + printf("\n## Load modem failed!\n"); + return CMD_RET_FAILURE; + } + + bb_dbg("\n## Load Calib Data to modem at "); + rda_modem_cal_load(); + + bb_dbg("\n## Start modem ...\n"); + rda_mdcom_line_set(RDA_MDCOM_PORT0, RDA_MDCOM_LINE_DL_HANDSHAKE); + + return CMD_RET_SUCCESS; +} + +int mdcom_load_from_mem(const u8 *data, int cal_en) +{ + const image_header_t *hdrInit = NULL; + const image_header_t *hdrWork = NULL; + + if (bbimages_get_header(data, &hdrInit, &hdrWork)) { + /* If there is no image, we initialize channels still. + * Otherwise kernel would not be loaded. */ + rda_mdcom_channel_all_init(); + return CMD_RET_FAILURE; + } + + return bbimages_load(hdrInit, hdrWork, cal_en); +} + +int mdcom_load_from_flash(int cal_en) +{ + int ret; + const image_header_t *hdrInit = NULL; + const image_header_t *hdrWork = NULL; + + /* + * Save the boot key state now. + * It takes about 1.9s to run into here if boot delay is 1s. + */ + save_current_boot_key_state(); + + if (rda_media_get() == MEDIA_MMC) + ret = rda_modem_bbimages_load_from_mmc(&hdrInit, &hdrWork); + else + ret = rda_modem_bbimages_load_from_nand(&hdrInit, &hdrWork); + + if (ret) { + /* + * If there is no image, we initialize channels still. + * Otherwise kernel would not be loaded. + */ + rda_mdcom_channel_all_init(); + return CMD_RET_FAILURE; + } + return bbimages_load(hdrInit, hdrWork, cal_en); +} + +/* + * Syntax: + * mdcom_loadm {adress} [cal_en] + */ +int do_mdcom_loadm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int cal_en = 0; + const u8 *data; + + if (argc < 2) + return CMD_RET_USAGE; + if (argc >= 3) + cal_en = (int) simple_strtoul(argv[2], NULL, 10); + + data = (const u8 *)simple_strtoul(argv[1], NULL, 16); + + return mdcom_load_from_mem(data, cal_en); +} + +int do_mdcom_cal_loadm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const u8 *data; + if (argc != 2) + return CMD_RET_USAGE; + + data = (const u8 *)simple_strtoul(argv[1], NULL, 16); + if (rda_image_verify_header((const image_header_t *)data)) + return CMD_RET_FAILURE; + + if (factory_copy_from_mem(data)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +/* + * Syntax: + * mdcom_loadf [cal_en] + */ +int do_mdcom_loadf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int cal_en = 0; + + if (argc >= 2) + cal_en = (int) simple_strtoul(argv[1], NULL, 10); + + return mdcom_load_from_flash(cal_en); +} + +int do_mdcom_cal_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + rda_modem_cal_test(); + return CMD_RET_SUCCESS; +} + +int do_mdcom_cal(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + drv_usbser_init(); + rda_modem_cal_loop(); + return CMD_RET_SUCCESS; +} + +int do_mdcom_ch_show(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + bb_dbg("\n## MDCOM Channel AT Show:\n"); + rda_mdcom_channel_show(RDA_MDCOM_CHANNEL_AT); + bb_dbg("\n## MDCOM Channel SYS Show:\n"); + rda_mdcom_channel_show(RDA_MDCOM_CHANNEL_SYSTEM); + bb_dbg("\n## MDCOM Channel TRACE Show:\n"); + rda_mdcom_channel_show(RDA_MDCOM_CHANNEL_TRACE); + return CMD_RET_SUCCESS; +} + +int do_mdcom_cal_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (rda_modem_cal_save()) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + +int do_mdcom_cal_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (rda_modem_cal_load()) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + +int do_mdcom_diag(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + rda_mdcom_show_xcpu_info(); + return CMD_RET_SUCCESS; +} + +int do_mdcom_ver(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + rda_mdcom_show_software_version(); + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + mdcom_send , 6, 1, do_mdcom_send, + "send data to mdCom channels", + "Syntax:\n" + " - mdcom_send {channel} {adress} {size} [{timeout} {mode}]" + "Parameters:\n" + " - channel: the mdcom channel number\n" + " - adress: the address of the data buffer to send\n" + " - size: the size of the sending buffer\n" + " - timeout: (optional) the timeout with unit ms\n" + " - mode: (optional) 0 - stream mode; else - dgram mode\n" +); + +U_BOOT_CMD( + mdcom_recv , 6, 1, do_mdcom_recv, + "send data to mdCom channels", + "Syntax:\n" + " - mdcom_recv {channel} {address} {size} [{timeout} {mode}]\n" + "Parameters:\n" + " - channel: the mdcom channel number\n" + " - adress: the address of the buffer to receive data\n" + " - size: the size of the receiving buffer\n" + " - timeout: (optional) the timeout with unit ms\n" + " - mode: (optional) 0 - stream mode; else - dgram mode\n" +); + +U_BOOT_CMD( + mdcom_cal_loadm , 2, 1, do_mdcom_cal_loadm, + "load modem calibration data from memory", + "Syntax:\n" + " - mdcom_cal_loadm {address} \n" + "Parameters:\n" + " - address: the address of the buffer to receive data\n" +); + +U_BOOT_CMD( + mdcom_loadm , 3, 1, do_mdcom_loadm, + "load modem codes from memory", + "Syntax:\n" + " - mdcom_loadm {adress} [{cal_en}] \n" + "Parameters:\n" + " - address: the address of the buffer to receive data\n" + " - cal_en: enable calibration\n" +); + +U_BOOT_CMD( + mdcom_loadf , 2, 1, do_mdcom_loadf, + "load modem codes from flash", + "Syntax:\n" + " - mdcom_loadf [{cal_en}] \n" + "Parameters:\n" + " - cal_en: enable calibration\n" +); + +U_BOOT_CMD( + mdcom_calt , 1, 1, do_mdcom_cal_test, + "modem calibration test", + "Syntax:\n" + " - mdcom_calt\n" +); + +U_BOOT_CMD( + mdcom_cal , 1, 1, do_mdcom_cal, + "modem calibration", + "Syntax:\n" + " - mdcom_cal\n" +); + +U_BOOT_CMD( + mdcom_show , 1, 1, do_mdcom_ch_show, + "show mdcom all channels", + "Syntax:\n" + " - mdcom_show\n" +); + +U_BOOT_CMD( + mdcom_cal_save , 1, 1, do_mdcom_cal_save, + "modem calibration data save", + "Syntax:\n" + " - mdcom_cal_save\n" +); + +U_BOOT_CMD( + mdcom_cal_load , 1, 1, do_mdcom_cal_load, + "modem calibration data load", + "Syntax:\n" + " - mdcom_cal_load\n" +); + +U_BOOT_CMD( + mdcom_diag, 1, 1, do_mdcom_diag, + "Show modem XCPU diagostic information", + "Syntax:\n" + " - mdcom_diag\n" +); + +U_BOOT_CMD( + mdcom_ver, 1, 1, do_mdcom_ver, + "Show modem software versions", + "Syntax:\n" + " - mdcom_ver\n" +); + +U_BOOT_CMD( + mdcom_check, 2, 1, do_check_and_wait_modem, + "check modem status, may wait", + "Syntax:\n" + " - mdcom_check {[check_boot_key]}\n" + "Parameters:\n" + " - check_boot_key: whether to check boot key status\n" +); + diff --git a/common/cmd_mem.c b/common/cmd_mem.c index fa6f5991a5..38e4fa264e 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -261,7 +261,7 @@ int do_mem_mwc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - ulong addr1, addr2, count, ngood; + ulong addr1, addr2, count, ngood, nbad; int size; int rcode = 0; @@ -296,6 +296,7 @@ int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif ngood = 0; + nbad = 0; while (count-- > 0) { if (size == 4) { @@ -306,7 +307,8 @@ int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) "!= word at 0x%08lx (0x%08lx)\n", addr1, word1, addr2, word2); rcode = 1; - break; + nbad++; + //break; } } else if (size == 2) { @@ -317,7 +319,8 @@ int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) "!= halfword at 0x%08lx (0x%04x)\n", addr1, hword1, addr2, hword2); rcode = 1; - break; + nbad++; + //break; } } else { @@ -328,10 +331,20 @@ int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) "!= byte at 0x%08lx (0x%02x)\n", addr1, byte1, addr2, byte2); rcode = 1; - break; + nbad++; + // break; } } - ngood++; + + if(rcode == 1){ + rcode = 0; + if(nbad > 100){ + return 1; + } + } + else + ngood++; + addr1 += size; addr2 += size; @@ -343,6 +356,9 @@ int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Total of %ld %s%s were the same\n", ngood, size == 4 ? "word" : size == 2 ? "halfword" : "byte", ngood == 1 ? "" : "s"); + printf("Total of %ld %s%s were different\n", + nbad, size == 4 ? "word" : size == 2 ? "halfword" : "byte", + nbad == 1 ? "" : "s"); return rcode; } diff --git a/common/cmd_misc.c b/common/cmd_misc.c index 973b1c2082..5d2a0a30e9 100644 --- a/common/cmd_misc.c +++ b/common/cmd_misc.c @@ -26,8 +26,39 @@ */ #include <common.h> #include <command.h> +#include <usb/usbserial.h> +#include <nand.h> +#include <jffs2/jffs2.h> +#include <asm/arch/mdcom.h> +#include <asm/arch/hwcfg.h> +#include <asm/arch/factory.h> +#include <asm/arch/prdinfo.h> +#include <asm/arch/rda_sys.h> +#include <part.h> +#include <mmc.h> +#include <mmc/mmcpart.h> +#include <nand.h> +#include <linux/mtd/nand.h> +#include <mtd/nand/rda_nand.h> +#include <android/android_boot.h> +#include <android/android_bootimg.h> +#include <rda/tgt_ap_panel_setting.h> +#include <asm/arch/spl_board_info.h> -int do_sleep (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +#ifdef FLASH_PAGE_SIZE +#undef FLASH_PAGE_SIZE +#endif +#define FLASH_PAGE_SIZE 2048 + +#define rda_dbg(fmt, args...) printf(fmt, ##args) + +extern int mtdparts_init_default(void); +extern int find_dev_and_part(const char *id, struct mtd_device **dev, + u8 *part_num, struct part_info **part); + +static int rollback_to_recovery_mode = 0; + +int do_sleep(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { ulong start = get_timer(0); ulong delay; @@ -38,18 +69,673 @@ int do_sleep (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) delay = simple_strtoul(argv[1], NULL, 10) * CONFIG_SYS_HZ; while (get_timer(start) < delay) { - if (ctrlc ()) + if (ctrlc()) return (-1); - udelay (100); + udelay(100); + } + + return 0; +} + +int do_flush_dcache(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned long start_addr = 0; + unsigned long end_addr = 0; + + if (argc < 3) { + printf("do flush dcache all...\n"); + flush_dcache_all(); + return 0; + } + + start_addr = simple_strtoul(argv[1], NULL, 16); + end_addr = simple_strtoul(argv[2], NULL, 16); + + printf("flush dcache %#x -> %#x\n", (unsigned int)start_addr, (unsigned int)end_addr); + flush_dcache_range(start_addr, end_addr); + return 0; +} + + +int do_mytest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ulong usec; + + if (argc != 2) + return CMD_RET_USAGE; + + usec = simple_strtoul(argv[1], NULL, 10) * 1000000; + + udelay(usec); + + return 0; +} + +int do_rdaswcfg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u16 swcfg; + + if (argc != 2) + return CMD_RET_USAGE; + + swcfg = (u16)simple_strtoul(argv[1], NULL, 10); + rda_swcfg_reg_set(swcfg); + + return 0; +} + +int do_rdahwcfg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + printf("RDA: HW_CFG 0x%04x\n", rda_hwcfg_get()); + return 0; +} + +int do_rdabm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + printf("RDA: Boot_Mode %d\n", rda_bm_get()); + return 0; +} + +int do_rdabminit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + rda_bm_init(); + + return 0; +} + +static int get_lcd_name(void) +{ + char lcd_paras[50] = "lcd="; + char *lcd_name = (char *)factory_get_lcd_name(); + +#define PANEL_PARM "lcd="PANEL_NAME + + setenv("lcd", PANEL_PARM); + if (!lcd_name || strlen(lcd_name) == 0) { + rda_dbg("factorydata does not contain lcd name, using default\n"); + return 0; + } + + if (strstr(RDA_PANEL_SUPPORT_LIST, lcd_name) == NULL) { + rda_dbg("RDA does not support %s lcd panel\n", lcd_name); + rda_dbg("Using default, please contact RDA.n"); + return 0; + } + + strncat(lcd_paras, lcd_name, 50); + setenv("lcd", lcd_paras); + return 0; +} + + +static int get_bootlogo_name(void) +{ + char logo_paras[50] = "bootlogo="; +#ifdef CONFIG_MACH_RDA8810E//need debug in future + char *name = NULL;//(char *)factory_get_bootlogo_name(); +#else + char *name = (char *)factory_get_bootlogo_name(); +#endif + + if (!name || strlen(name) == 0) { + rda_dbg("Does not find bootlogo name, using default\n"); + return 0; } + strncat(logo_paras, name, 50); + setenv("bootlogo", logo_paras); return 0; } +int do_get_bootlogo_name(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (get_bootlogo_name()) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + +int do_ap_factory_use(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u8* addr; + + if (argc != 2) + return CMD_RET_USAGE; + addr = (u8*)simple_strtoul(argv[1], NULL, 16); + + if (factory_set_ap_factory(addr)) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + +int do_ap_factory_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u8* addr; + + if (argc != 2) + return CMD_RET_USAGE; + addr = (u8*)simple_strtoul(argv[1], NULL, 16); + + if (factory_update_ap_factory(addr)) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + +int do_get_lcd_name(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (get_lcd_name()) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + +int do_get_emmc_id(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct spl_emmc_info * emmc_info = get_bd_spl_emmc_info(); + char emmc_id[16] = {0}; + + if(CONFIG_MMC_DEV_NUM == 0) + return CMD_RET_SUCCESS; + + sprintf(emmc_id, "emmc_id=%d", emmc_info->manufacturer_id); + + setenv("emmc_id", emmc_id); + + return CMD_RET_SUCCESS; +} + +extern int rda_flash_intf_is_spi(void); + +static int do_get_flash_intf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (rda_media_get() == MEDIA_MMC ) { +#ifdef CONFIG_SDMMC_BOOT + setenv("flash_if", "flash_if=sdcard"); +#else + setenv("flash_if", "flash_if=emmc"); +#endif + } else { + if(rda_flash_intf_is_spi()) + setenv("flash_if", "flash_if=spi"); + else + setenv("flash_if", "flash_if=normal"); + } + + return CMD_RET_SUCCESS; +} + +extern int hal_BoardSetup(void); + +static int do_board_mux_config(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +#ifdef CONFIG_RDA_MUX_CONFIG + int ret = 0; + ret = hal_BoardSetup(); + if(ret == CMD_RET_SUCCESS) + puts("Board Mux : Done. \n"); + else + puts("Board Mux : Error. \n"); + + return ret; +#else + puts("Board Mux : Bypass bootloader board mux config. \n"); + return CMD_RET_SUCCESS; +#endif +} + +static int do_get_android_bm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + enum rda_bm_type bm; + u32 reset_cause; + + setenv("chargerboot", "0"); + bm = rda_bm_get(); + switch (bm) { + case RDA_BM_RECOVERY: + setenv("androidboot", "androidboot.mode=recovery"); + break; + case RDA_BM_FACTORY: + setenv("androidboot", "androidboot.mode=factory"); + break; + default: + reset_cause = rda_mdcom_get_reset_cause(); + if (reset_cause == RDA_RESET_CAUSE_CHARGER) { + setenv("androidboot", "androidboot.mode=charger"); +#ifdef CHARGER_IN_RECOVERY +/* only move charger to recovery partition after aosp 4.4 (including)*/ + setenv("chargerboot", "1"); +#endif + } else { + setenv("androidboot", "androidboot.mode=normal"); + } + break; + } + + return CMD_RET_SUCCESS; +} + +static u8 *recovery_image = (u8 *)SCRATCH_ADDR; + +static int load_recovery_from_nand(void) +{ + void *data = (void *)recovery_image; + struct mtd_info *nand; + struct mtd_device *dev; + struct part_info *part; + size_t size = 0; + u8 pnum; + int ret; + + ret = find_dev_and_part("recovery", &dev, &pnum, &part); + if (ret) { + serial_printf("unknown partition name"); + return CMD_RET_FAILURE; + } else if (dev->id->type != MTD_DEV_TYPE_NAND) { + serial_printf("mtd dev type error"); + return CMD_RET_FAILURE; + } + nand = &nand_info[dev->id->num]; + serial_printf("found part '%s' offset: 0x%llx length: 0x%llx\n", + part->name, part->offset, part->size); + + size = part->size; + + serial_printf("read 0x%x bytes from '%s' offset: 0x%llx\n", + size, part->name, part->offset); + ret = nand_read_skip_bad(nand, part->offset, &size, (u_char *) data); + if (ret) { + serial_printf("nand read fail"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int load_recovery_from_mmc(void) +{ + void *data = (void *)recovery_image; + disk_partition_t *ptn; + block_dev_desc_t *mmc_blkdev; + loff_t size = 0; + + serial_printf("%s\n", __func__); + mmc_blkdev = get_dev_by_name(CONFIG_MMC_DEV_NAME); + ptn = partition_find_ptn("recovery"); + + if (ptn == 0) { + serial_printf("mmc partition table doesn't exist"); + puts("Board Mux : Done. \n"); + return CMD_RET_FAILURE; + } + + size = ptn->size * ptn->blksz; + + serial_printf("read 0x%x bytes from recovery offset: %lx\n", (unsigned int)size, + ptn->start); + if (partition_read_bytes(mmc_blkdev, ptn, &size, data)) { + serial_printf("mmc read failure"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int check_recovery_image(void) +{ + boot_img_hdr *hdr; + + /* Check recovery image header */ + hdr = (boot_img_hdr *)recovery_image; + if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + serial_printf("Invalid magic\n"); + return CMD_RET_FAILURE; + } + + if (hdr->page_size != FLASH_PAGE_SIZE) { + serial_printf("Invalid page size: %d (expecting %d)\n", + hdr->page_size, FLASH_PAGE_SIZE); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + + +static int load_ap_recovery(void) +{ + int ret = CMD_RET_SUCCESS; + enum media_type media; + + media = rda_media_get(); + if (media == MEDIA_MMC) + ret = load_recovery_from_mmc(); + else if ((media == MEDIA_NAND) || media == MEDIA_SPINAND) + ret = load_recovery_from_nand(); + else { + serial_printf("%s can't find boot media\n", __func__); + ret = CMD_RET_FAILURE; + } + + if (ret != CMD_RET_SUCCESS) { + serial_printf("%s failed, ret is %d\n", __func__, ret); + return ret; + } + ret = check_recovery_image(); + + return ret; +} + +/* + * For moving charger to recovery image to save 500KB in ramdisk + * CHARGER BOOT mode will need to load recovery kernel and rootfs + * 1. load modem from boot image and normal boot image first, so no extra delay + * for normal boot. (rda_mdcom_get_reset_cause only works after modem is up) + * 2. after modem is up and CHARGER MODE detected, load recovery image + */ +static int do_load_ap_recovery(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return load_ap_recovery(); +} + +extern int mdcom_load_from_flash(int cal_en); +extern int mdcom_load_from_mem(const u8 *data, int cal_en); +extern int mdcom_check_and_wait_modem(int check_boot_key); + +static int do_load_recovery(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret = CMD_RET_SUCCESS; + enum rda_bm_type bm; + boot_img_hdr *hdr; + unsigned kernel_actual; + unsigned ramdisk_actual; + unsigned second_actual; + unsigned size; + + /* Load recovery modem only in recovery mode, and + * load normal modem in factory mode */ + bm = rda_bm_get(); + if (bm != RDA_BM_RECOVERY) { + rollback_to_recovery_mode = 1; + ret = mdcom_load_from_flash(0); + if (ret != CMD_RET_SUCCESS) { + serial_printf("Bad modem image. Try recovery mode\n"); + udelay(5000); + rda_reboot(REBOOT_TO_RECOVERY_MODE); + } + } + + ret = load_ap_recovery(); + if (ret != CMD_RET_SUCCESS) + return ret; + + + if (bm == RDA_BM_RECOVERY) { + hdr = (boot_img_hdr *)recovery_image; + kernel_actual = ROUND(hdr->kernel_size, FLASH_PAGE_SIZE); + ramdisk_actual = ROUND(hdr->ramdisk_size, FLASH_PAGE_SIZE); + second_actual = ROUND(hdr->second_size, FLASH_PAGE_SIZE); + size = FLASH_PAGE_SIZE + kernel_actual + ramdisk_actual + + second_actual; + + ret = mdcom_load_from_mem(recovery_image + size, 0); + + if (ret != CMD_RET_SUCCESS) + return ret; + } + + ret = mdcom_check_and_wait_modem(0); + if (ret != CMD_RET_SUCCESS && bm != RDA_BM_RECOVERY) { + serial_printf("Modem no response. Try recovery mode\n"); + udelay(5000); + rda_reboot(REBOOT_TO_RECOVERY_MODE); + } + + return ret; +} + +int load_boot_from_nand(void) +{ + boot_img_hdr *hdr; + void *data = (void *)SCRATCH_ADDR; + struct mtd_info *nand; + struct mtd_device *dev; + struct part_info *part; + size_t size = 0; + u8 pnum; + unsigned kernel_actual; + unsigned ramdisk_actual; + int ret; + + ret = find_dev_and_part("boot", &dev, &pnum, &part); + if (ret) { + rda_dbg("unknown partition name\n"); + return CMD_RET_FAILURE; + } else if (dev->id->type != MTD_DEV_TYPE_NAND) { + rda_dbg("mtd dev type error\n"); + return CMD_RET_FAILURE; + } + nand = &nand_info[dev->id->num]; + rda_dbg("found part '%s' offset: 0x%llx length: 0x%llx\n", + part->name, part->offset, part->size); + + /* get hdr first */ + size = ROUND(2048, FLASH_PAGE_SIZE); + rda_dbg("read 0x%x bytes from '%s' offset: 0x%llx\n", + size, part->name, part->offset); + + ret = nand_read_skip_bad(nand, part->offset, &size, (u_char *) data); + if (ret) { + rda_dbg("nand read fail\n"); + return CMD_RET_FAILURE; + } + + /* get size from hdr */ + hdr = (boot_img_hdr *) data; + kernel_actual = ROUND(hdr->kernel_size, FLASH_PAGE_SIZE); + ramdisk_actual = ROUND(hdr->ramdisk_size, FLASH_PAGE_SIZE); + size = 2048 + kernel_actual + ramdisk_actual; + + /* load whole boot.img */ + rda_dbg("read 0x%x bytes from '%s' offset: 0x%llx\n", + size, part->name, part->offset); + ret = nand_read_skip_bad(nand, part->offset, &size, (u_char *) data); + if (ret) { + rda_dbg("nand read fail\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static block_dev_desc_t *mmc_blkdev; +int load_boot_from_mmc(void) +{ + void *data = (void *)SCRATCH_ADDR; + disk_partition_t *ptn; + loff_t size = 0; + + rda_dbg("%s\n", __func__); + mmc_blkdev = get_dev_by_name(CONFIG_MMC_DEV_NAME); + ptn = partition_find_ptn("boot"); + + if (ptn == 0) { + rda_dbg("mmc partition table doesn't exist\n"); + return CMD_RET_FAILURE; + } + + size = ptn->size * ptn->blksz; + + rda_dbg("read 0x%x bytes from boot offset: %lx\n", (unsigned int)size, + ptn->start); + if (partition_read_bytes(mmc_blkdev, ptn, &size, data)) { + rda_dbg("mmc read failure\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int do_load_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret = CMD_RET_FAILURE; + enum media_type media; + + media = rda_media_get(); + serial_printf("load boot image ...\n"); + if (media == MEDIA_MMC) + ret = load_boot_from_mmc(); + else if ((media == MEDIA_NAND) || (media == MEDIA_SPINAND)) + ret = load_boot_from_nand(); + else + serial_printf("load_boot can't find boot media\n"); + + return ret; +} + +static int do_adjust_bootdelay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int bootmode; + + bootmode = rda_bm_get(); + if (bootmode == RDA_BM_FASTBOOT) + setenv("bootdelay", "3"); + + return CMD_RET_SUCCESS; +} U_BOOT_CMD( sleep , 2, 1, do_sleep, "delay execution for some time", "N\n" " - delay execution for N seconds (N is _decimal_ !!!)" ); + +U_BOOT_CMD( + flush_dcache , 3, 1, do_flush_dcache, + "flush dcache", + "start_addr end_addr\n" + " - flush dcache from [start_addr] to [end_addr]" +); + +U_BOOT_CMD( + mytest , 2, 1, do_mytest, + "exec certain test routine", + "arg\n" + " - exec with arg (arg is _decimal_ !!!)" +); + +U_BOOT_CMD( + rdaswcfg , 2, 1, do_rdaswcfg, + "set rda swcfg", + "Syntax:\n" + " - rdaswcfg swcfg\n" +); + +U_BOOT_CMD( + rdahwcfg , 1, 1, do_rdahwcfg, + "get rda hwcfg", + "Syntax:\n" + " - rdahwcfg\n" +); + +U_BOOT_CMD( + rdabm , 1, 1, do_rdabm, + "get rda boot_mode", + "Syntax:\n" + " - rdabm\n" +); + +U_BOOT_CMD( + rdabminit , 1, 1, do_rdabminit, + "init rda boot_mode", + "Syntax:\n" + " - rdabminit\n" +); + +U_BOOT_CMD( + ap_factory_use , 2, 1, do_ap_factory_use, + "use ap factory data from specified memory", + "Syntax:\n" + " - factory_use addr\n" +); + + +U_BOOT_CMD( + ap_factory_update , 2, 1, do_ap_factory_update, + "update ap factory data from specified memory", + "Syntax:\n" + " - factory_update addr\n" +); + +U_BOOT_CMD( + get_lcd_name , 1, 1, do_get_lcd_name, + "ap find lcd panel name", + "Syntax:\n" + " - find_lcd_name\n" +); + +U_BOOT_CMD( + get_flash_intf, 1, 1, do_get_flash_intf, + "ap find flash interface", + "Syntax:\n" + " - get_flash_intf\n" +); + +U_BOOT_CMD( + get_emmc_id, 1, 1, do_get_emmc_id, + "ap find emmc manufacturer id and pass it to kernel", + "Syntax:\n" + " - get_emmc_id\n" +); + +U_BOOT_CMD( + mux_config, 1, 1, do_board_mux_config, + "check and set board mux config (pinmux,io drive,io pin mode...)", + "Syntax:\n" + " - mux_config\n" +); + +U_BOOT_CMD( + get_android_bm, 1, 1, do_get_android_bm, + "get android bootmode", + "Syntax:\n" + " - get_android_bm \n" +); + +U_BOOT_CMD( + load_ap_recovery, 1, 1, do_load_ap_recovery, + "load recovery kernel and ramdisk to address", + "Syntax:\n" + " - load_ap_recovery address \n" +); + +U_BOOT_CMD( + load_recovery, 1, 1, do_load_recovery, + "load recovery image to address", + "Syntax:\n" + " - load_recovery address \n" +); + +U_BOOT_CMD( + load_boot, 1, 1, do_load_boot, + "load boot image to address", + "Syntax:\n" + " - load_boot address \n" +); + +U_BOOT_CMD( + get_bootlogo_name , 1, 1, do_get_bootlogo_name, + "find bootlogo name", + "Syntax:\n" + " - get_bootlogo_name\n" +); + +U_BOOT_CMD( + adjust_bootdelay , 1, 1, do_adjust_bootdelay, + "re-adjust bootdelay according to bootmode", + "Syntax:\n" + " - adjust_bootdelay\n" +); diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 750509da5e..674c1f5a7e 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -2,23 +2,7 @@ * (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 + * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> @@ -92,6 +76,8 @@ enum mmc_state { MMC_READ, MMC_WRITE, MMC_ERASE, + MMC_ERASE_PART, + MMC_TEST, }; static void print_mmcinfo(struct mmc *mmc) { @@ -106,7 +92,7 @@ static void print_mmcinfo(struct mmc *mmc) printf("Rd Block Len: %d\n", mmc->read_bl_len); printf("%s version %d.%d\n", IS_SD(mmc) ? "SD" : "MMC", - (mmc->version >> 4) & 0xf, mmc->version & 0xf); + (mmc->version >> 8) & 0xf, mmc->version & 0xff); printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No"); puts("Capacity: "); @@ -115,13 +101,13 @@ static void print_mmcinfo(struct mmc *mmc) printf("Bus Width: %d-bit\n", mmc->bus_width); } -int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct mmc *mmc; if (curr_device < 0) { if (get_mmc_num() > 0) - curr_device = 0; + curr_device = 1; else { puts("No MMC device available\n"); return 1; @@ -144,11 +130,40 @@ int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) U_BOOT_CMD( mmcinfo, 1, 0, do_mmcinfo, "display MMC info", - " - device number of the device to dislay info of\n" - "" + "- display info of the current MMC device" ); -int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +#ifdef CONFIG_SUPPORT_EMMC_BOOT +static int boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) +{ + int err; + err = mmc_boot_part_access(mmc, ack, part_num, access); + + if ((err == 0) && (access != 0)) { + printf("\t\t\t!!!Notice!!!\n"); + + printf("!You must close EMMC boot Partition"); + printf("after all images are written\n"); + + printf("!EMMC boot partition has continuity"); + printf("at image writing time.\n"); + + printf("!So, do not close the boot partition"); + printf("before all images are written.\n"); + return 0; + } else if ((err == 0) && (access == 0)) + return 0; + else if ((err != 0) && (access != 0)) { + printf("EMMC boot partition-%d OPEN Failed.\n", part_num); + return 1; + } else { + printf("EMMC boot partition-%d CLOSE Failed.\n", part_num); + return 1; + } +} +#endif + +static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { enum mmc_state state; @@ -157,7 +172,7 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (curr_device < 0) { if (get_mmc_num() > 0) - curr_device = 0; + curr_device = 1; else { puts("No MMC device available\n"); return 1; @@ -165,8 +180,12 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } if (strcmp(argv[1], "rescan") == 0) { - struct mmc *mmc = find_mmc_device(curr_device); + struct mmc *mmc; + + if (argc != 2) + return CMD_RET_USAGE; + mmc = find_mmc_device(curr_device); if (!mmc) { printf("no mmc device at slot %x\n", curr_device); return 1; @@ -180,8 +199,12 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } else if (strncmp(argv[1], "part", 4) == 0) { block_dev_desc_t *mmc_dev; - struct mmc *mmc = find_mmc_device(curr_device); + struct mmc *mmc; + + if (argc != 2) + return CMD_RET_USAGE; + mmc = find_mmc_device(curr_device); if (!mmc) { printf("no mmc device at slot %x\n", curr_device); return 1; @@ -197,8 +220,56 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) puts("get mmc type error!\n"); return 1; } else if (strcmp(argv[1], "list") == 0) { + if (argc != 2) + return CMD_RET_USAGE; print_mmc_devices('\n'); return 0; + } else if (strncmp(argv[1], "speed", 5) == 0) { + struct mmc *mmc; + int ret; + u64 offset; + unsigned long long start_clock, end_clock; + unsigned long duration, mmc_read_speed, mmc_write_speed; + u_char *datbuf; + size_t test_data_size; + + if (argc < 5) { + datbuf = (u_char *)(0x80000000); + offset = (u64)(0x00100000); + test_data_size = (size_t)(0x00A00000); + } else { + datbuf = (u_char *)simple_strtoul(argv[2], NULL, 16); + offset = (u64)simple_strtoul(argv[3], NULL, 16); + test_data_size = (size_t)simple_strtoul(argv[4], NULL, 16); + } + + mmc = find_mmc_device(curr_device); + mmc_init(mmc); + + start_clock = get_ticks(); + ret = mmc_read(mmc, offset, datbuf, test_data_size); + end_clock = get_ticks(); + duration = (unsigned long)(end_clock - start_clock); + mmc_read_speed = (unsigned long)(test_data_size / (duration * 1000 / get_tbclk()) * 1000 / 1024); + if (ret == test_data_size) + printf("\nMmc Read speed = %ld Kbyte/s\n", mmc_read_speed); + else { + printf("\nRead data from Mmc failed\n"); + return 1; + } + + start_clock = get_ticks(); + ret = mmc_write(mmc, offset, datbuf, test_data_size); + end_clock = get_ticks(); + duration = (unsigned long)(end_clock - start_clock); + mmc_write_speed = (unsigned long)(test_data_size / (duration * 1000 / get_tbclk()) * 1000 / 1024); + if (ret == test_data_size) + printf("\nMmc Write speed = %ld Kbyte/s\n", mmc_write_speed); + else { + printf("\nWrite data to Mmc failed\n"); + return 1; + } + return 0; } else if (strcmp(argv[1], "dev") == 0) { int dev, part = -1; struct mmc *mmc; @@ -237,7 +308,7 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!ret) mmc->part_num = part; - printf("switch to partions #%d, %s\n", + printf("switch to partitions #%d, %s\n", part, (!ret) ? "OK" : "ERROR"); } } @@ -249,41 +320,132 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) curr_device, mmc->part_num); return 0; - } +#ifdef CONFIG_SUPPORT_EMMC_BOOT + } else if ((strcmp(argv[1], "open") == 0) || + (strcmp(argv[1], "close") == 0)) { + int dev; + struct mmc *mmc; + u8 part_num, access = 0; - if (strcmp(argv[1], "read") == 0) + if (argc == 4) { + dev = simple_strtoul(argv[2], NULL, 10); + part_num = simple_strtoul(argv[3], NULL, 10); + } else { + return CMD_RET_USAGE; + } + + mmc = find_mmc_device(dev); + if (!mmc) { + printf("no mmc device at slot %x\n", dev); + return 1; + } + + if (IS_SD(mmc)) { + printf("SD device cannot be opened/closed\n"); + return 1; + } + + if ((part_num <= 0) || (part_num > MMC_NUM_BOOT_PARTITION)) { + printf("Invalid boot partition number:\n"); + printf("Boot partition number cannot be <= 0\n"); + printf("EMMC44 supports only 2 boot partitions\n"); + return 1; + } + + if (strcmp(argv[1], "open") == 0) + access = part_num; /* enable R/W access to boot part*/ + else + access = 0; /* No access to boot partition */ + + /* acknowledge to be sent during boot operation */ + return boot_part_access(mmc, 1, part_num, access); + + } else if (strcmp(argv[1], "bootpart") == 0) { + int dev; + dev = simple_strtoul(argv[2], NULL, 10); + + u32 bootsize = simple_strtoul(argv[3], NULL, 10); + u32 rpmbsize = simple_strtoul(argv[4], NULL, 10); + struct mmc *mmc = find_mmc_device(dev); + if (!mmc) { + printf("no mmc device at slot %x\n", dev); + return 1; + } + + if (IS_SD(mmc)) { + printf("It is not a EMMC device\n"); + return 1; + } + + if (0 == mmc_boot_partition_size_change(mmc, + bootsize, rpmbsize)) { + printf("EMMC boot partition Size %d MB\n", bootsize); + printf("EMMC RPMB partition Size %d MB\n", rpmbsize); + return 0; + } else { + printf("EMMC boot partition Size change Failed.\n"); + return 1; + } +#endif /* CONFIG_SUPPORT_EMMC_BOOT */ + } + state = MMC_INVALID; + if (argc == 5 && strcmp(argv[1], "read") == 0) state = MMC_READ; - else if (strcmp(argv[1], "write") == 0) + else if (argc == 5 && strcmp(argv[1], "write") == 0) state = MMC_WRITE; - else if (strcmp(argv[1], "erase") == 0) + else if (argc == 6 && strcmp(argv[1], "test") == 0) + state = MMC_TEST; + else if (argc == 4 && strcmp(argv[1], "erase") == 0) state = MMC_ERASE; - else - state = MMC_INVALID; + else if (argc == 3 && strcmp(argv[1], "erase.part") == 0) + state = MMC_ERASE_PART; if (state != MMC_INVALID) { struct mmc *mmc = find_mmc_device(curr_device); int idx = 2; u32 blk, cnt, n; - void *addr; - - if (state != MMC_ERASE) { - addr = (void *)simple_strtoul(argv[idx], NULL, 16); - ++idx; - } else - addr = 0; - blk = simple_strtoul(argv[idx], NULL, 16); - cnt = simple_strtoul(argv[idx + 1], NULL, 16); + void *addr = NULL; + int times = 10; if (!mmc) { printf("no mmc device at slot %x\n", curr_device); return 1; } - printf("\nMMC %s: dev # %d, block # %d, count %d ... ", - argv[1], curr_device, blk, cnt); - mmc_init(mmc); + if ((state == MMC_WRITE || state == MMC_ERASE)) { + if (mmc_getwp(mmc) == 1) { + printf("Error: card is write protected!\n"); + return 1; + } + } + + if (state == MMC_ERASE_PART) { + disk_partition_t *ptn; + ptn = partition_find_ptn(argv[idx]); + if (!ptn) { + printf("Error: not found part [%s]\n", argv[idx]); + return 1; + } + blk = ptn->start; + cnt = ptn->size; + state = MMC_ERASE; + + } else { + if (state != MMC_ERASE) { + addr = (void *)simple_strtoul(argv[idx], NULL, 16); + ++idx; + } + blk = simple_strtoul(argv[idx], NULL, 16); + cnt = simple_strtoul(argv[idx + 1], NULL, 16); + if (state == MMC_TEST) + times = simple_strtoul(argv[idx + 2], NULL, 10); + } + + printf("\nMMC %s: dev # %d, block # %d, count %d ... ", + argv[1], curr_device, blk, cnt); + switch (state) { case MMC_READ: n = mmc->block_dev.block_read(curr_device, blk, @@ -298,6 +460,51 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) case MMC_ERASE: n = mmc->block_dev.block_erase(curr_device, blk, cnt); break; + case MMC_TEST: + { + u32 pat = 0x5a5a1234; + u32 *dat = addr; + u32 crc1 = 0, crc2 = 0; + u32 siz = cnt * 512; + int i, t; + + /* test write/read */ + n = cnt; + printf("\nTest start...\n"); + for(t = 1; t <= times; t++) + { + /* fill buffer by pattern */ + dat = addr; + for(i = 0; i < siz; i += 4) + { + *dat++ = pat; + pat += 0x10001; + } + crc1 = crc32(0, (void *)addr, siz); + pat = ~pat; + + /* write to device */ + mmc->block_dev.block_write(curr_device, blk, cnt, addr); + + /* clear buffer */ + memset((void*)addr, 0, siz); + + /* read back */ + mmc->block_dev.block_read(curr_device, blk, cnt, addr); + flush_cache((ulong)addr, cnt * 512); + + /* compare and show result */ + crc2 = crc32(0, (void *)addr, siz); + printf("Test %02d: expect crc = 0x%08x, got = 0x%08x, %s\n", + t, crc1, crc2, + (crc1==crc2) ? "SUCCESS!" : "FAIL!"); + + /* make fail tag */ + if(crc1 != crc2) + n = cnt - 1; + } + } + break; default: BUG(); } @@ -315,9 +522,20 @@ U_BOOT_CMD( "MMC sub system", "read addr blk# cnt\n" "mmc write addr blk# cnt\n" + "mmc test addr blk# cnt times\n" "mmc erase blk# cnt\n" + "mmc erase.part part_name\n" "mmc rescan\n" "mmc part - lists available partition on current mmc device\n" "mmc dev [dev] [part] - show or set current mmc device [partition]\n" - "mmc list - lists available devices"); + "mmc list - lists available devices\n" +#ifdef CONFIG_SUPPORT_EMMC_BOOT + "mmc open <dev> <boot_partition>\n" + " - Enable boot_part for booting and enable R/W access of boot_part\n" + "mmc close <dev> <boot_partition>\n" + " - Enable boot_part for booting and disable access to boot_part\n" + "mmc bootpart <device num> <boot part size MB> <RPMB part size MB>\n" + " - change sizes of boot and RPMB partitions of specified device\n" #endif + ); +#endif /* !CONFIG_GENERIC_MMC */ diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c index 22688293ae..add0585037 100644 --- a/common/cmd_mtdparts.c +++ b/common/cmd_mtdparts.c @@ -99,6 +99,7 @@ #if defined(CONFIG_CMD_NAND) #include <linux/mtd/nand.h> #include <nand.h> +#include <mtd/nand/rda_nand.h> #endif #if defined(CONFIG_CMD_ONENAND) @@ -325,7 +326,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) { struct mtd_info *mtd = NULL; int i, j; - ulong start; + u64 start; if (get_mtd_info(id->type, id->num, &mtd)) return 1; @@ -337,7 +338,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) * Only one eraseregion (NAND, OneNAND or uniform NOR), * checking for alignment is easy here */ - if ((unsigned long)part->offset % mtd->erasesize) { + if (part->offset % (u64)mtd->erasesize) { printf("%s%d: partition (%s) start offset" "alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); @@ -412,19 +413,20 @@ static int part_validate(struct mtdids *id, struct part_info *part) part->size = id->size - part->offset; if (part->offset > id->size) { - printf("%s: offset %08x beyond flash size %08x\n", + printf("%s: offset %llx beyond flash size 0x%llx\n", id->mtd_id, part->offset, id->size); return 1; } - if ((part->offset + part->size) <= part->offset) { + if (((u64)part->offset + (u64)part->size) <= (u64)part->offset) { printf("%s%d: partition (%s) size too big\n", MTD_DEV_TYPE(id->type), id->num, part->name); return 1; } if (part->offset + part->size > id->size) { - printf("%s: partitioning exceeds flash size\n", id->mtd_id); + printf("%s: partitioning exceeds flash size %llx, part %llx+%llx\n", + id->mtd_id, id->size, part->offset, part->size); return 1; } @@ -462,7 +464,7 @@ static int part_del(struct mtd_device *dev, struct part_info *part) if (curr_pi == part) { printf("current partition deleted, resetting current to 0\n"); current_mtd_partnum = 0; - } else if (part->offset <= curr_pi->offset) { + } else if (part->offset <= (u64)curr_pi->offset) { current_mtd_partnum--; } current_save_needed = 1; @@ -595,8 +597,7 @@ static int part_add(struct mtd_device *dev, struct part_info *part) static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart) { struct part_info *part; - unsigned long size; - unsigned long offset; + u64 size, offset; const char *name; int name_len; unsigned int mask_flags; @@ -615,7 +616,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i } else { size = memsize_parse(p, &p); if (size < MIN_PART_SIZE) { - printf("partition size too small (%lx)\n", size); + printf("partition size too small (%llx)\n", size); return 1; } } @@ -680,6 +681,8 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i part->offset = offset; part->mask_flags = mask_flags; part->name = (char *)(part + 1); + /*we set the mtdpart is dirty and force erase before program if needed*/ + part->dirty = 1; if (name) { /* copy user provided name */ @@ -687,14 +690,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i part->auto_name = 0; } else { /* auto generated name in form of size@offset */ - sprintf(part->name, "0x%08lx@0x%08lx", size, offset); + sprintf(part->name, "0x%llx@0x%llx", size, offset); part->auto_name = 1; } part->name[name_len - 1] = '\0'; INIT_LIST_HEAD(&part->link); - debug("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n", + debug("+ partition: name %-22s size 0x%llx offset 0x%llx mask flags %d\n", part->name, part->size, part->offset, part->mask_flags); @@ -710,7 +713,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i * @param size a pointer to the size of the mtd device (output) * @return 0 if device is valid, 1 otherwise */ -int mtd_device_validate(u8 type, u8 num, u32 *size) +int mtd_device_validate(u8 type, u8 num, u64 *size) { struct mtd_info *mtd = NULL; @@ -843,7 +846,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ LIST_HEAD(tmp_list); struct list_head *entry, *n; u16 num_parts; - u32 offset; + u64 offset; int err = 1; debug("===device_parse===\n"); @@ -1087,7 +1090,8 @@ static int generate_mtdparts(char *buf, u32 buflen) struct part_info *part, *prev_part; char *p = buf; char tmpbuf[32]; - u32 size, offset, len, part_cnt; + u64 size, offset; + u32 len, part_cnt; u32 maxlen = buflen - 1; debug("--- generate_mtdparts ---\n"); @@ -1274,7 +1278,7 @@ static void print_partition_table(void) part = list_entry(pentry, struct part_info, link); net_size = net_part_size(mtd, part); size_note = part->size == net_size ? " " : " (!)"; - printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n", + printf("%2d: %-20s0x%llx\t0x%08x%s\t0x%llx\t%d\n", part_num, part->name, part->size, net_size, size_note, part->offset, part->mask_flags); @@ -1286,7 +1290,7 @@ static void print_partition_table(void) list_for_each(pentry, &dev->parts) { part = list_entry(pentry, struct part_info, link); - printf("%2d: %-20s0x%08x\t0x%08x\t%d\n", + printf("%2d: %-20s0x%llx\t0x%llx\t%d\n", part_num, part->name, part->size, part->offset, part->mask_flags); #endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ @@ -1299,6 +1303,41 @@ static void print_partition_table(void) } /** + * Given nand partition number find the partition info and + * corresponding nand device + * + * @param part_num nand partition number + * @param part pointer to requested partition (output) + * @param nand pointer to the nand device (output) + * @return 0 on success, -1 otherwise + */ +int find_nand_part_info(int part_num, struct part_info **part, + struct mtd_info **nand) +{ + struct list_head *dentry; + struct mtd_device *dev; + + if (list_empty(&devices)) { + printf("no partitions defined\n"); + return -1; + } + + list_for_each(dentry, &devices) { + dev = list_entry(dentry, struct mtd_device, link); + /* list partitions for given device */ + + if (dev->id->type == MTD_DEV_TYPE_NAND) { + *part = mtd_part_info(dev, part_num); + if (!part) + return -1; + *nand = &nand_info[dev->id->num]; + return 0; + } + } + + return -1; +} +/** * Format and print out a partition list for each device from global device * list. */ @@ -1313,7 +1352,7 @@ static void list_partitions(void) if (current_mtd_dev) { part = mtd_part_info(current_mtd_dev, current_mtd_partnum); if (part) { - printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n", + printf("\nactive partition: %s%d,%d - (%s) 0x%llx @ 0x%llx\n", MTD_DEV_TYPE(current_mtd_dev->id->type), current_mtd_dev->id->num, current_mtd_partnum, part->name, part->size, part->offset); @@ -1413,7 +1452,7 @@ static int delete_partition(const char *id) if (find_dev_and_part(id, &dev, &pnum, &part) == 0) { - debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08x@0x%08x\n", + debug("delete_partition: device = %s%d, partition %d = (%s) 0x%llx@0x%llx\n", MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum, part->name, part->size, part->offset); @@ -1502,7 +1541,7 @@ static int spread_partitions(void) part = list_entry(pentry, struct part_info, link); debug("spread_partitions: device = %s%d, partition %d =" - " (%s) 0x%08x@0x%08x\n", + " (%s) 0x%08x@0x%llx\n", MTD_DEV_TYPE(dev->id->type), dev->id->num, part_num, part->name, part->size, part->offset); @@ -1599,7 +1638,7 @@ static int parse_mtdids(const char *const ids) struct list_head *entry, *n; struct mtdids *id_tmp; u8 type, num; - u32 size; + u64 size; int ret = 1; debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids); @@ -1673,7 +1712,7 @@ static int parse_mtdids(const char *const ids) id->mtd_id[mtd_id_len - 1] = '\0'; INIT_LIST_HEAD(&id->link); - debug("+ id %s%d\t%16d bytes\t%s\n", + debug("+ id %s%d\t%lld bytes\t%s\n", MTD_DEV_TYPE(id->type), id->num, id->size, id->mtd_id); @@ -1829,6 +1868,296 @@ int mtdparts_init(void) return 0; } +/* Load mtd partition table from flash */ +static int mtdparts_ptbl_read(char *data) +{ + nand_info_t *nand; + int dev = nand_curr_device; + int ret = 0; + char *buff; + size_t rsize; + u32 offs = CONFIG_MTD_PTBL_OFFS; + u32 data_size, data_crc; + + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || + !nand_info[dev].name) { + printf("%s: nand not init.\n", __func__); + return -1; + } + nand = &nand_info[dev]; + + { + struct nand_chip *this = nand->priv; + struct rda_nand_info *info = this->priv; + offs = (offs * info->spl_adjust_ratio) / 2; + } + + buff = malloc(CONFIG_MTD_PTBL_SIZE); + if(!buff) { + printf("%s: can't malloc memory.\n", __func__); + return -1; + } + + /* calculate read size */ + rsize = nand->erasesize - (offs % nand->erasesize); + if(rsize > CONFIG_MTD_PTBL_SIZE) { + rsize = CONFIG_MTD_PTBL_SIZE; + } + + /* read data from flash */ + ret = nand_read_skip_bad(nand, offs, &rsize, (u_char *)buff); + if(ret) { + printf("%s: flash read error %d\n", __func__, ret); + ret = -1; + goto exit; + } + + memcpy((void*)&data_size, (void*)&buff[0], 4); + memcpy((void*)&data_crc, (void*)&buff[4], 4); + if(!data_size || data_size > (CONFIG_MTD_PTBL_SIZE - 8)) { + printf("%s: partition table is invalid.\n", __func__); + ret = -1; + goto exit; + } + + /* crc checking */ + if(data_crc != crc32(0, (const unsigned char *)(&buff[8]), data_size)) { + printf("%s: crc checking failed.\n", __func__); + ret = -1; + goto exit; + } + + memcpy(data, (void*)&buff[8], data_size); + printf("%s: load partition table from %#x\n", __func__, offs); + printf("partition table: %s\n", data); + +exit: + free(buff); + return ret; +} + +/* save mtd partition table to flash */ +static int mtdparts_ptbl_write(char *data, int need_erase) +{ + nand_info_t *nand; + int dev = nand_curr_device; + int ret = 0; + size_t wsize, rsize; + char *buff; + u32 offs = CONFIG_MTD_PTBL_OFFS; + nand_erase_options_t opts; + u32 data_size = strlen(data) + 1; + u32 data_crc; + + buff = malloc(CONFIG_MTD_PTBL_SIZE); + if(!buff) { + printf("%s: can't malloc memory.\n", __func__); + return -1; + } + + /* check if the new table is same as old */ + if(mtdparts_ptbl_read(buff) == 0) { + if(strcmp(buff, data) == 0) { + printf("%s: same as old, do nothing.\n", __func__); + free(buff); + return 0; + } + } + free(buff); + + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || + !nand_info[dev].name) { + printf("%s: nand not init.\n", __func__); + return -1; + } + nand = &nand_info[dev]; + + { + printf("mtdparts_ptbl_write0: offs = 0x%x \n", offs); + struct nand_chip *this = nand->priv; + struct rda_nand_info *info = this->priv; + offs = (offs * info->spl_adjust_ratio) / 2; + printf("mtdparts_ptbl_write1: offs = 0x%x \n", offs); + } + + printf("%s: save partition table to %#x\n", __func__, offs); + printf("%s: %s\n", __func__, data); + + /* Limit data in one block */ + if(data_size > (CONFIG_MTD_PTBL_SIZE - 8) || + data_size > (nand->erasesize - (offs % nand->erasesize) - 8)) { + printf("%s: data size is too large.\n", __func__); + return -1; + } + + buff = malloc(nand->erasesize); + if(!buff) { + printf("%s: can't malloc memory.\n", __func__); + return -1; + } + + /* not need to do erase */ + if(!need_erase) { + /* fill buffer */ + data_crc = crc32(0, (const unsigned char *)data, data_size); + memcpy((void *)(buff), &data_size, 4); + memcpy((void *)(buff+4), &data_crc, 4); + memcpy((void *)(buff+8), data, data_size); + + /* write data to flash */ + wsize = data_size + 8; + ret = nand_write_skip_bad(nand, offs, &wsize, (u_char *)buff, 0); + if(ret) { + printf("%s: flash write error %d\n", __func__, ret); + } + goto exit; + } + + /* need to do erase */ + + memset(&opts, 0, sizeof(opts)); + opts.offset = (loff_t) (offs - (offs % nand->erasesize)); + opts.length = (loff_t) nand->erasesize; + opts.jffs2 = 0; + opts.quiet = 0; + + /* Read this block data to buffer */ + rsize = nand->erasesize; + ret = nand_read_skip_bad(nand, opts.offset, &rsize, (u_char *)buff); + if(ret) { + printf("%s: flash read error %d\n", __func__, ret); + goto exit; + } + + /* erase block */ + ret = nand_erase_opts(nand, &opts); + if(ret) { + printf("%s: flash erase error %d\n", __func__, ret); + goto exit; + } + + /* fill buffer */ + data_crc = crc32(0, (const unsigned char *)data, data_size); + memcpy((void *)(buff+(offs % nand->erasesize)), &data_size, 4); + memcpy((void *)(buff+(offs % nand->erasesize)+4), &data_crc, 4); + memcpy((void *)(buff+(offs % nand->erasesize)+8), data, data_size); + + /* write data to flash */ + wsize = nand->erasesize; + ret = nand_write_skip_bad(nand, opts.offset, &wsize, (u_char *)buff, 0); + if(ret) { + printf("%s: flash write error %d\n", __func__, ret); + } + +exit: + free(buff); + return ret; +} + +int mtdparts_init_from_ptbl(void) +{ + char *mtdparts_str = malloc(CONFIG_MTD_PTBL_SIZE); + + setenv("mtdparts", (char *)mtdparts_default); + + /* load partition table from flash */ + if(mtdparts_str){ + if(mtdparts_ptbl_read(mtdparts_str) == 0) { + setenv("mtdparts", mtdparts_str); + } + free(mtdparts_str); + } + + setenv("mtdids", (char *)mtdids_default); + setenv("partition", NULL); + + return mtdparts_init(); +} + +int mtdparts_save_ptbl(int need_erase) +{ + if(mtdparts_ptbl_write((char *)mtdparts_default, need_erase)){ + printf("%s: save partition table failed.\n", __func__); + return -1; + } + return 0; +} + +int mtdparts_init_default(void) +{ + setenv("mtdids", (char *)mtdids_default); + setenv("mtdparts", (char *)mtdparts_default); + setenv("partition", NULL); + + return mtdparts_init(); +} + +/* Check if the partition table is same with the table stored in flash */ +int mtdparts_ptbl_check(int *same) +{ + int ret; + char *buff; + + if(!same) return -1; + *same = 0; + + if(!mtdparts_default) { + return -1; + } + + buff = malloc(CONFIG_MTD_PTBL_SIZE); + if(!buff) { + printf("%s: can't malloc memory.\n", __func__); + return -1; + } + + ret = mtdparts_ptbl_read(buff); + if(!ret) { + printf("mtdparts_default: %s\n", mtdparts_default); + printf("mtdparts_in_flash: %s\n", buff); + if(strcmp(buff, mtdparts_default) == 0) { + *same = 1; + } + } + + free(buff); + return ret; +} + +/* Check if the part(bootloader & factorydata) of partition + table is same with the table stored in flash */ +int mtdparts_ptbl_check_factorydata(int *same) +{ + int ret; + char *buff; + + if(!same) return -1; + *same = 0; + + if(!mtdparts_default) { + return -1; + } + + buff = malloc(CONFIG_MTD_PTBL_SIZE); + if(!buff) { + printf("%s: can't malloc memory.\n", __func__); + return -1; + } + + ret = mtdparts_ptbl_read(buff); + if(!ret) { + int len = strstr(buff, "factorydata") - buff; + //printf("mtdparts_default: %s\n", mtdparts_default); + //printf("mtdparts_in_flash: %s\n", buff); + if(strncmp(buff, mtdparts_default, len) == 0) { + *same = 1; + } + } + + free(buff); + return ret; +} + /** * Return pointer to the partition of a requested number from a requested * device. @@ -1870,6 +2199,23 @@ static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part return NULL; } +int mtdparts_clear_all_dirty(struct mtd_device *dev) +{ + struct list_head *entry; + struct part_info *part; + + if(!dev) + return -1; + + printf("clear all %d mtdparts's dirty\n", dev->num_parts); + list_for_each(entry, &dev->parts) { + part = list_entry(entry, struct part_info, link); + if (part) + part->dirty = 0; + } + return 0; + +} /***************************************************/ /* U-boot commands */ /***************************************************/ diff --git a/common/cmd_nand.c b/common/cmd_nand.c index bae630dfb6..cdd1258b1b 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -11,7 +11,7 @@ * Added 16-bit nand support * (C) 2004 Texas Instruments * - * Copyright 2010 Freescale Semiconductor + * Copyright 2010, 2012 Freescale Semiconductor * The portions of this file whose copyright is held by Freescale and which * are not considered a derived work of GPL v2-only code may be distributed * and/or modified under the terms of the GNU General Public License as @@ -27,6 +27,7 @@ #include <asm/byteorder.h> #include <jffs2/jffs2.h> #include <nand.h> +#include <mtd/nand/rda_nand.h> #if defined(CONFIG_CMD_MTDPARTS) @@ -37,11 +38,17 @@ int find_dev_and_part(const char *id, struct mtd_device **dev, u8 *part_num, struct part_info **part); #endif -static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) +static int nand_dump(nand_info_t *nand, uint64_t off, int only_oob, int repeat) { int i; u_char *datbuf, *oobbuf, *p; static loff_t last; + struct nand_chip *chip = nand->priv; + struct rda_nand_info *info = chip->priv; + + /* just for dump nand first 16k bytes in nand driver V3,*/ + /* no care to nand driver V1. */ + info->dump_debug_flag = 1; if (repeat) off = last + nand->writesize; @@ -54,7 +61,13 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) puts("No memory for page buffer\n"); return 1; } - off &= ~(nand->writesize - 1); + + /* off is 64 bit*/ + if(chip->page_shift == 0) + off = (loff_t)mtd_div_by_ws(off, nand) * nand->writesize; + else + off &= ~((loff_t)nand->writesize - 1); + loff_t addr = (loff_t) off; struct mtd_oob_ops ops; memset(&ops, 0, sizeof(ops)); @@ -65,12 +78,12 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) ops.mode = MTD_OOB_RAW; i = nand->read_oob(nand, addr, &ops); if (i < 0) { - printf("Error (%d) reading page %08lx\n", i, off); + printf("Error (%d) reading page 0x%llx\n", i, off); free(datbuf); free(oobbuf); return 1; } - printf("Page %08lx dump:\n", off); + printf("Page 0x%llx dump:\n", off); i = nand->writesize >> 4; p = datbuf; @@ -91,6 +104,8 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); p += 8; } + + info->dump_debug_flag = 0; free(datbuf); free(oobbuf); @@ -191,7 +206,7 @@ static int arg_off_size(int argc, char *const argv[], int *idx, loff_t *off, loff_t *size) { int ret; - loff_t maxsize; + loff_t maxsize = 0; if (argc == 0) { *off = 0; @@ -277,6 +292,7 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[]) int ret; uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)]; nand_info_t *nand = &nand_info[0]; + struct nand_chip *chip = nand->priv; char *cmd = argv[1]; if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !nand->name) { @@ -319,9 +335,16 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[]) return 1; } - if ((addr & (nand->erasesize - 1)) != 0) { - printf("Environment offset must be block-aligned\n"); - return 1; + if (chip->bbt_erase_shift == 0) { + if(mtd_mod_by_eb(addr, nand) != 0){ + printf("Environment offset must be block-aligned\n"); + return 1; + } + } else { + if ((addr & (nand->erasesize - 1)) != 0) { + printf("Environment offset must be block-aligned\n"); + return 1; + } } ops.datbuf = NULL; @@ -390,6 +413,47 @@ static void nand_print_and_set_info(int idx) setenv("nand_erasesize", buf); } +static void nand_print_ID(void) +{ + nand_info_t *nand = &nand_info[0]; + struct nand_chip *chip = nand->priv; + + chip->read_nand_ID(nand); +} + +static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, + int read) +{ + int ret = 0; + + while (count--) { + /* Raw access */ + mtd_oob_ops_t ops = { + .datbuf = (u8 *)addr, + .oobbuf = ((u8 *)addr) + nand->writesize, + .len = nand->writesize, + .ooblen = nand->oobsize, + .mode = MTD_OOB_RAW + }; + + if (read) + ret = nand->read_oob(nand, off, &ops); + else + ret = nand->write_oob(nand, off, &ops); + + if (ret) { + printf("%s: error at offset %llx, ret %d\n", + __func__, (long long)off, ret); + break; + } + + addr += nand->writesize + nand->oobsize; + off += nand->writesize; + } + + return ret; +} + int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int i, ret = 0; @@ -429,6 +493,11 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return 0; } + if (strcmp(cmd, "id") == 0 || strcmp(cmd, "ID") == 0) { + nand_print_ID(); + return 0; + } + if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); @@ -560,15 +629,75 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) if (argc < 3) goto usage; - off = (int)simple_strtoul(argv[2], NULL, 16); + off = simple_strtoull(argv[2], NULL, 16); ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat); return ret == 0 ? 1 : 0; } + if (strncmp(cmd, "speed", 5) == 0) { + + unsigned long long start_clock, end_clock; + unsigned long duration, nand_speed; + u_char *datbuf; + nand_erase_options_t opts; + uint32_t test_data_size; + + if (argc < 5){ + datbuf = (u_char *)(0x80000000); + off = (ulong)(0x00100000); + test_data_size = (ulong)(0x00A00000); + } else { + datbuf = (u_char *)simple_strtoul(argv[2], NULL, 16); + off = (ulong)simple_strtoul(argv[3], NULL, 16); + test_data_size = (ulong)simple_strtoul(argv[4], NULL, 16); + } + + start_clock = get_ticks(); + ret = nand_read_skip_bad(nand, off, &test_data_size, datbuf); + end_clock = get_ticks(); + duration = (unsigned long)(end_clock - start_clock); + nand_speed = (unsigned long)(test_data_size / (duration * 1000 / get_tbclk()) * 1000 / 1024); + if (!ret) + printf("\nNand Read speed = %ld Kbyte/s\n\n", nand_speed); + else { + printf("\nRead data from Nand failed\n"); + return 1; + } + + /* set nand erasing parameters */ + memset(&opts, 0, sizeof(opts)); + opts.offset = off; + opts.length = test_data_size; + opts.jffs2 = 0; + opts.quiet = 0; + opts.spread = 0; + + /* erase flash */ + start_clock = get_ticks(); + ret = nand_erase_opts(nand, &opts); + if(ret != 0) { + printf("erase nand flash error, returned value: ret = %d\n", ret); + return 1; + } + ret = nand_write_skip_bad(nand, off, &test_data_size, datbuf, 0); + end_clock = get_ticks(); + duration = (unsigned long)(end_clock - start_clock); + nand_speed = (unsigned long)(test_data_size / (duration * 1000 / get_tbclk()) * 1000 / 1024); + if (!ret) + printf("\nNand Write speed = %ld Kbyte/s\n", nand_speed); + else { + printf("\nWrite data to Nand failed\n"); + return 1; + } + return ret == 0 ? 0 : 1; + } + if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { size_t rwsize; + ulong pagecount = 1; int read; + int raw; if (argc < 4) goto usage; @@ -577,13 +706,36 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); - if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size) != 0) - return 1; nand = &nand_info[dev]; - rwsize = size; s = strchr(cmd, '.'); + + if (!strcmp(s, ".raw")) { + raw = 1; + + if (arg_off(argv[3], &dev, &off, &size)) + return 1; + + if (argc > 4 && !str2long(argv[4], &pagecount)) { + printf("'%s' is not a number\n", argv[4]); + return 1; + } + + if (pagecount * nand->writesize > size) { + puts("Size exceeds partition or device limit\n"); + return -1; + } + + rwsize = pagecount * (nand->writesize + nand->oobsize); + } else { + if (arg_off_size(argc - 3, argv + 3, &dev, + &off, &size) != 0) + return 1; + + rwsize = size; + } + if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) @@ -609,7 +761,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return 1; } ret = nand_write_skip_bad(nand, off, &rwsize, - (u_char *)addr, WITH_YAFFS_OOB); + (u_char *)addr, + WITH_YAFFS_OOB); // WITH_INLINE_OOB); ??? #endif } else if (!strcmp(s, ".oob")) { /* out-of-band data */ @@ -623,22 +776,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); - } else if (!strcmp(s, ".raw")) { - /* Raw access */ - mtd_oob_ops_t ops = { - .datbuf = (u8 *)addr, - .oobbuf = ((u8 *)addr) + nand->writesize, - .len = nand->writesize, - .ooblen = nand->oobsize, - .mode = MTD_OOB_RAW - }; - - rwsize = nand->writesize + nand->oobsize; - - if (read) - ret = nand->read_oob(nand, off, &ops); - else - ret = nand->write_oob(nand, off, &ops); + } else if (raw) { + ret = raw_access(nand, addr, off, pagecount, read); } else { printf("Unknown nand command suffix '%s'.\n", s); return 1; @@ -726,15 +865,16 @@ usage: U_BOOT_CMD( nand, CONFIG_SYS_MAXARGS, 1, do_nand, "NAND sub-system", + "id or ID - print nand ID \n" "info - show available NAND devices\n" "nand device [dev] - show or set current device\n" "nand read - addr off|partition size\n" "nand write - addr off|partition size\n" " read/write 'size' bytes starting at offset 'off'\n" " to/from memory address 'addr', skipping bad blocks.\n" - "nand read.raw - addr off|partition\n" - "nand write.raw - addr off|partition\n" - " Use read.raw/write.raw to avoid ECC and access the page as-is.\n" + "nand read.raw - addr off|partition [count]\n" + "nand write.raw - addr off|partition [count]\n" + " Use read.raw/write.raw to avoid ECC and access the flash as-is.\n" #ifdef CONFIG_CMD_NAND_TRIMFFS "nand write.trimffs - addr off|partition size\n" " write 'size' bytes starting at offset 'off' from memory address\n" @@ -754,6 +894,7 @@ U_BOOT_CMD( "nand erase.chip [clean] - erase entire chip'\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" + "nand speed [-addr -off -test data length]- show read speed and write speed of NAND\n" "nand scrub [-y] off size | scrub.part partition | scrub.chip\n" " really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n" @@ -936,3 +1077,202 @@ U_BOOT_CMD(nboot, 4, 1, do_nandboot, "boot from NAND device", "[partition] | [[[loadAddr] dev] offset]" ); + +static char test_buf[4096 + 224]; +static char temp_buf[4096 + 224]; + +int erase_block(nand_info_t *nand, loff_t off) +{ + int ret; + nand_erase_options_t opts; + struct nand_chip *chip = nand->priv; + + if (chip->phys_erase_shift == 0) { + if(mtd_mod_by_eb(off, nand) != 0){ + printf("not aligned erase size\n"); + return 1; + } + } else { + if ((off & (nand->erasesize - 1)) != 0 ) { + printf("not aligned erase size\n"); + return 1; + } + } + + memset(&opts, 0, sizeof(opts)); + opts.offset = off; + opts.length = nand->erasesize; + opts.jffs2 = 0; + opts.quiet = 0; + opts.spread = 0; + + ret = nand_erase_opts(nand, &opts); + printf("%s\n", ret ? "ERROR" : "OK"); + + return ret == 0 ? 0 : 1; +} + +static void dump_flash_buf(nand_info_t *nand, char *new) +{ + int i; + + printf("flash data:\n"); + for (i = 0; i < nand->writesize; i+=8) + printf("%04x: %2x %2x %2x %2x %2x %2x %2x %2x\n",i, new[i], new[i+1], new[i+2], + new[i+3], new[i+4], new[i+5], new[i+6], new[i+7]); + + printf("flash oob:\n"); + for (; i < (nand->writesize + nand->oobsize); i+=8) + printf("%04x: %2x %2x %2x %2x %2x %2x %2x %2x\n",i, new[i], new[i+1], new[i+2], + new[i+3], new[i+4], new[i+5], new[i+6], new[i+7]); +} + +/* + * use lcd backlight as trigger of digital analyzer + */ +#include <asm/arch/reg_nand.h> +#include <asm/io.h> +static void trigger_gpio(int high) +{ +#define RDA_GPIO_DIR (RDA_GPIO_A_BASE + 0x04) +#define RDA_GPIO_VAL (RDA_GPIO_A_BASE + 0x0c) +#define RDA_GPIO_SET (RDA_GPIO_A_BASE + 0x10) +#define RDA_GPIO_CLR (RDA_GPIO_A_BASE + 0x14) + + __raw_writel(0xffffffff, RDA_GPIO_DIR); + if (high) { + __raw_writel(0x0f, RDA_GPIO_SET); + } else { + __raw_writel(0x0f, RDA_GPIO_CLR); + } +} +int do_nandstress(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) +{ + int i; + int dev = nand_curr_device; + int ret; + nand_info_t *nand; + unsigned long long count_h, count_l; + loff_t off = 0; + char * s; + int need_erase = 1; + + if (argc < 2) + goto usage; + + off = simple_strtoul(argv[1], NULL, 16); + printf("nand stress test offset %llx\n", off); + s = argv[2]; + + /* + DANGROUS!!!!!!! + if you dont erase the block and write/read + the page, the page maybe damaged for ever. + this test used as test the hardware ecc functions: + write the page repeatedly until the page error, and test if + the handware ecc can detect and correct them; + */ + if (!strcmp(s, "noerase")) { + const char *noerase_warning = + "!!!!!DANGROUS test!!!!!!\n" + "This may damage the flash page for ever ....y/N\n"; + puts(noerase_warning); + if (getc() == 'y') { + puts("y"); + if (getc() == '\r') { + printf("\nwill don't erase the block anyway...\n"); + need_erase = 0; + } + } + } + + printf("nand stress test erase/write/read ....\n"); + + count_h = 0; + count_l = 0; + nand = &nand_info[dev]; + + for (i = 0; i < (nand->writesize + nand->oobsize); i++) { + test_buf[i] = i+255; + } + + trigger_gpio(1); + while (1) { + int error_count; + /* Raw access */ + mtd_oob_ops_t ops_w= { + .datbuf = (u8 *)test_buf, + .oobbuf = ((u8 *)test_buf) + nand->writesize, + .len = nand->writesize, + .ooblen = nand->oobsize, + .mode = MTD_OOB_RAW + }; + mtd_oob_ops_t ops_r= { + .datbuf = (u8 *)temp_buf, + .oobbuf = ((u8 *)temp_buf) + nand->writesize, + .len = nand->writesize, + .ooblen = nand->oobsize, + .mode = MTD_OOB_RAW + }; + + if (need_erase) { + if (erase_block(nand, off)){ + trigger_gpio(0); + printf("oops, erase error\n"); + goto error; + } + } + ret = nand->write_oob(nand, off, &ops_w); + if (ret) { + trigger_gpio(0); + printf("%s: error at offset %llx, ret %d\n", + __func__, (long long)off, ret); + goto error; + } + ret = nand->read_oob(nand, off, &ops_r); + if (ret) { + printf("%s: error at offset %llx, ret %d\n", + __func__, (long long)off, ret); + goto error; + } + + error_count = 0; + //for (i = 0; i < (nand->writesize + nand->oobsize); i++) { + for (i = 0; i < (nand->writesize); i++) { + if(test_buf[i] != temp_buf[i]) { + trigger_gpio(0); + printf("oops, read/write is error at %x, source %02x, flash %02x\n", + i, test_buf[i], temp_buf[i]); + printf("nand interrupt stauts %x\n",__raw_readl(NANDFC_REG_INT_STAT)); + printf("nand busy flag %x\n",__raw_readl(NANDFC_REG_BUSY_FLAG)); + error_count ++; + } + } + + if (error_count) { + printf("oops, error num %d, \n",error_count); + dump_flash_buf(nand, temp_buf); + printf("read nand fifo \n"); + goto error; + } + count_l++; + if (count_l == 0) { + count_h++; + } + printf("###################NAND testing... the loop is:high %lld, low %lld\n" + , count_h, count_l); + }; + + return 1; +usage: + return CMD_RET_USAGE; +error: + printf("NAND stress test end, the loop is:high %lld, low %lld\n", count_h, count_l); + return 1; +} + +U_BOOT_CMD(nandstress, 3, 1, do_nandstress, + "nand stress test for one page read/write: nandstress off", + "[ off ]\n" + " - test nand from page offset 'off'" +); diff --git a/common/cmd_net.c b/common/cmd_net.c index 65f32bceef..a9ade8b927 100644 --- a/common/cmd_net.c +++ b/common/cmd_net.c @@ -153,12 +153,16 @@ static void netboot_update_env (void) ip_to_string (NetOurIP, tmp); setenv ("ipaddr", tmp); } - +#if !defined(CONFIG_BOOTP_SERVERIP) + /* + * Only attempt to change serverip if net/bootp.c:BootpCopyNetParams() + * could have set it + */ if (NetServerIP) { ip_to_string (NetServerIP, tmp); setenv ("serverip", tmp); } - +#endif if (NetOurDNSIP) { ip_to_string (NetOurDNSIP, tmp); setenv ("dnsip", tmp); @@ -424,3 +428,34 @@ U_BOOT_CMD( ); #endif /* CONFIG_CMD_DNS */ + +#if defined(CONFIG_CMD_LINK_LOCAL) +static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + char tmp[22]; + + if (NetLoop(LINKLOCAL) < 0) + return 1; + + NetOurGatewayIP = 0; + ip_to_string(NetOurGatewayIP, tmp); + setenv("gatewayip", tmp); + + ip_to_string(NetOurSubnetMask, tmp); + setenv("netmask", tmp); + + ip_to_string(NetOurIP, tmp); + setenv("ipaddr", tmp); + setenv("llipaddr", tmp); /* store this for next time */ + + return 0; +} + +U_BOOT_CMD( + linklocal, 1, 1, do_link_local, + "acquire a network IP address using the link-local protocol", + "" +); + +#endif /* CONFIG_CMD_LINK_LOCAL */ diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index b1494dcb0c..271200266c 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -66,9 +66,10 @@ DECLARE_GLOBAL_DATA_PTR; !defined(CONFIG_ENV_IS_IN_NVRAM) && \ !defined(CONFIG_ENV_IS_IN_ONENAND) && \ !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ + !defined(CONFIG_ENV_IS_IN_REMOTE) && \ !defined(CONFIG_ENV_IS_NOWHERE) # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\ -SPI_FLASH|MG_DISK|NVRAM|MMC|FAT} or CONFIG_ENV_IS_NOWHERE +SPI_FLASH|MG_DISK|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE #endif #define XMK_STR(x) #x @@ -203,7 +204,6 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, */ int _do_env_set(int flag, int argc, char * const argv[]) { - bd_t *bd = gd->bd; int i, len; int console = -1; char *name, *value, *s; @@ -342,21 +342,7 @@ int _do_env_set(int flag, int argc, char * const argv[]) * Some variables should be updated when the corresponding * entry in the environment is changed */ - if (strcmp(name, "ipaddr") == 0) { - char *s = argv[2]; /* always use only one arg */ - char *e; - unsigned long addr; - bd->bi_ip_addr = 0; - for (addr = 0, i = 0; i < 4; ++i) { - ulong val = s ? simple_strtoul(s, &e, 10) : 0; - addr <<= 8; - addr |= val & 0xFF; - if (s) - s = *e ? e + 1 : e; - } - bd->bi_ip_addr = htonl(addr); - return 0; - } else if (strcmp(argv[1], "loadaddr") == 0) { + if (strcmp(argv[1], "loadaddr") == 0) { load_addr = simple_strtoul(argv[2], NULL, 16); return 0; } diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c index 0f2e208717..a0d25e5521 100644 --- a/common/cmd_onenand.c +++ b/common/cmd_onenand.c @@ -13,7 +13,7 @@ #include <command.h> #include <malloc.h> -#include <linux/mtd/compat.h> +#include <linux/compat.h> #include <linux/mtd/mtd.h> #include <linux/mtd/onenand.h> diff --git a/common/cmd_sata.c b/common/cmd_sata.c index 7b1703fe41..3f98235a38 100644 --- a/common/cmd_sata.c +++ b/common/cmd_sata.c @@ -48,9 +48,12 @@ int __sata_initialize(void) sata_dev_desc[i].block_write = sata_write; rc = init_sata(i); - rc = scan_sata(i); - if ((sata_dev_desc[i].lba > 0) && (sata_dev_desc[i].blksz > 0)) - init_part(&sata_dev_desc[i]); + if (!rc) { + rc = scan_sata(i); + if (!rc && (sata_dev_desc[i].lba > 0) && + (sata_dev_desc[i].blksz > 0)) + init_part(&sata_dev_desc[i]); + } } sata_curr_device = 0; return rc; diff --git a/common/cmd_test.c b/common/cmd_test.c index fcb5ef2f71..cd9a1a2836 100644 --- a/common/cmd_test.c +++ b/common/cmd_test.c @@ -171,3 +171,220 @@ U_BOOT_CMD( "do nothing, successfully", NULL ); + +#ifdef CONFIG_VPU_TEST +#include <asm/arch/hw_test.h> +int do_vpu_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + if(argc > 1) { + times = simple_strtoul(argv[1], NULL, 10); + } + vpu_sta_test(times); + return 0; +} +U_BOOT_CMD( + vpu_test, CONFIG_SYS_MAXARGS, 1, do_vpu_test, + "vpu test", + NULL +); + +#ifdef CONFIG_VPU_MD5_TEST +int do_vpu_md5_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + if(argc > 1) { + times = simple_strtoul(argv[1], NULL, 10); + } + vpu_md5_test(times); + return 0; +} +U_BOOT_CMD( + vpu_md5_test, CONFIG_SYS_MAXARGS, 1, do_vpu_md5_test, + "vpu md5 test", + NULL +); +#endif //CONFIG_VPU_MD5_TEST +#endif //CONFIG_VPU_TEST + +#ifdef CONFIG_CPU_TEST +#include <asm/arch/hw_test.h> +int do_cpu_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + if(argc > 1) { + times = simple_strtoul(argv[1], NULL, 10); + } + cpu_pll_test(times); + return 0; +} +U_BOOT_CMD( + cpu_test, CONFIG_SYS_MAXARGS, 1, do_cpu_test, + "cpu test", + NULL +); +#endif //CONFIG_VPU_TEST + +#ifdef CONFIG_DDR_TEST +#include <asm/arch/hw_test.h> +int do_ddr_mem_copy_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + unsigned int src_addr = 0x80000000,des_addr = 0x83000000,n = 0x10; + + if(argc > 1) { + times = simple_strtoul(argv[1], NULL, 10); + } + if(argc > 2) { + src_addr = simple_strtoul(argv[2],NULL,16); + } + if(argc > 3) { + des_addr = simple_strtoul(argv[3],NULL,16); + } + if(argc > 4) { + n = simple_strtoul(argv[4],NULL,16); + } + ddr_mem_copy_test(times,src_addr,des_addr,n); + return 0; +} + +U_BOOT_CMD( + ddr_mem_cp, 5, 1, do_ddr_mem_copy_test, + "ddr memory copy test", + NULL +); +#endif //CONFIG_DDR_TEST + +#ifdef CONFIG_TIMER_TEST +#include <asm/arch/hw_test.h> +int do_timer_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + unsigned int timer_id = 0; + + if(argc > 1) { + timer_id = simple_strtoul(argv[1], NULL, 10); + } + if(argc > 2) { + times = simple_strtoul(argv[2],NULL,16); + } + tim_test(timer_id,times); + return 0; +} + +U_BOOT_CMD( + timer_test, 5, 1, do_timer_test, + "timer_test timer_id(0~2) times", + NULL +); +#endif /* CONFIG_TIMER_TEST */ + +#ifdef CONFIG_UART_TEST +#include <asm/arch/hw_test.h> +int do_uart_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + unsigned int uart_id = 2;// uart3 as default test port + + if(argc > 1) { + uart_id = simple_strtoul(argv[1], NULL, 10); + } + if(argc > 2) { + times = simple_strtoul(argv[2],NULL,16); + } + uart_test(uart_id,times); + return 0; +} + +U_BOOT_CMD( + uart_test, 5, 1, do_uart_test, + "uart_test uart_id(0~2) times", + NULL +); +#endif /* CONFIG_UART_TEST */ + +#ifdef CONFIG_GIC_TEST +#include <asm/arch/hw_test.h> +int do_gic_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + + if(argc > 1) { + times = simple_strtoul(argv[1], NULL, 10); + } + gic_test(times); + return 0; +} + +U_BOOT_CMD( + gic_test, 5, 1, do_gic_test, + "gic_test times", + NULL +); +#endif /* CONFIG_GIC_TEST */ + +#ifdef CONFIG_CACHE_TEST +#include <asm/arch/hw_test.h> +int do_cache_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + + if(argc > 1) { + times = simple_strtoul(argv[1], NULL, 10); + } + cpu_cache_test(times); + return 0; +} + +U_BOOT_CMD( + cache_test, 5, 1, do_cache_test, + "cpu L1/L2 D-cache I-cache test", + NULL +); +#endif /* CONFIG_CACHE_TEST */ + +#ifdef CONFIG_MIPI_LOOP_TEST +#include<asm/arch/hw_test.h> +int do_mipi_loop_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + + if (argc > 1) + times = simple_strtoull(argv[1], NULL, 10); + if (times < 1) { + printf("Invalid parameter\n"); + return 1; + } + test_dsi_csi_loop(times); + + return 0; +} + +U_BOOT_CMD( + mipi_loop, 5, 5, do_mipi_loop_test, + "mipi loop test", + NULL +); +#endif /* CONFIG_MIPI_LOOP_TEST */ + +#ifdef CONFIG_I2C_TEST +#include<asm/arch/hw_test.h> +int do_i2c_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int times = 1; + int id = 2; /* I2C id number:0,1,2,I2C 2 is default device */ + + if(argc > 1) + times = simple_strtoull(argv[1], NULL, 10); + if(argc > 2) + id = simple_strtoul(argv[2],NULL,10); + test_i2c(id,times); + return 0; +} + +U_BOOT_CMD( + i2c_test, 5, 5, do_i2c_test, + "i2c test", + NULL +); +#endif /* CONFIG_I2C_TET */ diff --git a/common/cmd_ubi.c b/common/cmd_ubi.c index 35b1d31f9c..aff6d69de5 100644 --- a/common/cmd_ubi.c +++ b/common/cmd_ubi.c @@ -149,7 +149,10 @@ static int verify_mkvol_req(const struct ubi_device *ubi, if (req->alignment > ubi->leb_size) goto bad; - n = req->alignment % ubi->min_io_size; + if (is_power_of_2(ubi->min_io_size)) + n = req->alignment & (ubi->min_io_size -1); + else + n = req->alignment % ubi->min_io_size; if (req->alignment != 1 && n) goto bad; @@ -164,7 +167,7 @@ bad: return err; } -static int ubi_create_vol(char *volume, int size, int dynamic) +static int ubi_create_vol(const char *volume, int64_t size, int dynamic) { struct ubi_mkvol_req req; int err; @@ -188,13 +191,13 @@ static int ubi_create_vol(char *volume, int size, int dynamic) printf("verify_mkvol_req failed %d\n", err); return err; } - printf("Creating %s volume %s of size %d\n", + printf("Creating %s volume %s of size 0x%llx\n", dynamic ? "dynamic" : "static", volume, size); /* Call real ubi create volume */ return ubi_create_volume(ubi, &req); } -static struct ubi_volume *ubi_find_volume(char *volume) +static struct ubi_volume *ubi_find_volume(const char *volume) { struct ubi_volume *vol = NULL; int i; @@ -209,7 +212,7 @@ static struct ubi_volume *ubi_find_volume(char *volume) return NULL; } -static int ubi_remove_vol(char *volume) +static int ubi_remove_vol(const char *volume) { int err, reserved_pebs, i; struct ubi_volume *vol; @@ -263,7 +266,7 @@ out_err: return err; } -static int ubi_volume_write(char *volume, void *buf, size_t size) +static int ubi_volume_write(const char *volume, void *buf, size_t size) { int err = 1; int rsvd_bytes = 0; @@ -313,13 +316,12 @@ static int ubi_volume_write(char *volume, void *buf, size_t size) return 0; } -static int ubi_volume_read(char *volume, char *buf, size_t size) +static int ubi_volume_read(const char *volume, loff_t offp, char *buf, size_t size) { int err, lnum, off, len, tbuf_size; void *tbuf; unsigned long long tmp; struct ubi_volume *vol; - loff_t offp = 0; vol = ubi_find_volume(volume); if (vol == NULL) @@ -349,8 +351,12 @@ static int ubi_volume_read(char *volume, char *buf, size_t size) size = vol->used_bytes - offp; tbuf_size = vol->usable_leb_size; - if (size < tbuf_size) - tbuf_size = ALIGN(size, ubi->min_io_size); + if (size < tbuf_size) { + if (is_power_of_2(ubi->min_io_size)) + tbuf_size = ALIGN(size, ubi->min_io_size); + else + tbuf_size = roundup(size, ubi->min_io_size); + } tbuf = malloc(tbuf_size); if (!tbuf) { printf("NO MEM\n"); @@ -390,7 +396,7 @@ static int ubi_volume_read(char *volume, char *buf, size_t size) return err; } -static int ubi_dev_scan(struct mtd_info *info, char *ubidev, +static int ubi_dev_scan(struct mtd_info *info, const char *ubidev, const char *vid_header_offset) { struct mtd_device *dev; @@ -431,6 +437,272 @@ static int ubi_dev_scan(struct mtd_info *info, char *ubidev, return 0; } +#ifdef MTDPARTS_UBI_DEF +int ubi_part_scan(const char *part_name) +{ + struct mtd_info *info; + struct mtd_device *dev; + struct part_info *part; + nand_erase_options_t opts; + char mtd_dev[20]; + u8 pnum; + int ret = 0; + + if(ubi_initialized){ + ubi = ubi_devices[0]; + return 0; + } + /* + * Search the mtd device number where this partition + * is located + */ + if (find_dev_and_part(part_name, &dev, &pnum, &part)) { + printf("Partition %s not found!\n", part_name); + return -1; + } + sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num); + info = get_mtd_device_nm(mtd_dev); + if (IS_ERR(info)) { + printf("Partition %s not found on device %s!\n", part_name, mtd_dev); + return 1; + } + printf("found part '%s' offset: 0x%llx length: 0x%llx id: %d\n", + part->name, part->offset, part->size, dev->id->num); + + ret = ubi_dev_scan(info, part_name, NULL); + /* if fail, erase the part, try again */ + if(ret) { + memset(&opts, 0, sizeof(opts)); + opts.offset = (loff_t) part->offset; + opts.length = (loff_t) part->size; + opts.jffs2 = 0; + opts.quiet = 0; + + ret = nand_erase_opts(info, &opts); + if(ret) + return ret; + ret = ubi_dev_scan(info, part_name, NULL); + if(ret) + return ret; + } + + ubi = ubi_devices[0]; + return ret; +} + +struct ubi_vol_info { + char name[20]; + size_t size; +}; +static int ubi_parse_ubi_str(const char *ubi_default_str, + struct ubi_vol_info **ubivol_info, int *ubivol_count) +{ + char *def_str = malloc(strlen(ubi_default_str)+1); + char *p = def_str; + char *q; + int i = 0; + struct ubi_vol_info *info; + + if(!def_str) + return -1; + strcpy(def_str, ubi_default_str); + + while(1) { + q = strstr(p, "M("); + if(!q) { + q = strstr(p, "-("); + if(!q) + break; + } + i++; + p = q + 2; + } + + info = (struct ubi_vol_info *)malloc(sizeof(struct ubi_vol_info) * i); + *ubivol_info = info; + *ubivol_count = i; + + p = def_str; + i = 0; + while(1) { + /* size */ + q = strstr(p, "M("); + if(q) { + *q = '\0'; + info[i].size = simple_strtoul(p, NULL, 10) * 1024 * 1024; + p = q + 2; + } else { + q = strstr(p, "-("); + if(q) { + info[i].size = 0; + p = q + 2; + } else { + break; + } + } + + /* name */ + q = strstr(p, ")"); + if(q) + *q = '\0'; + strcpy(info[i].name, p); + if(!q) + break; + p = q + 1; + if(*p == ',') + p++; + + i++; + } + free(def_str); + return 0; +} + +int ubi_check_default_vols(const char *ubi_default_str) +{ + int ret = 0; + struct ubi_vol_info *info = NULL; + int count = 0, i; + int checked = 1; + struct ubi_volume *vol; + + if(ubi_parse_ubi_str(ubi_default_str, &info, &count)) + return -1; + if(count <= 0 || !info) + return -1; + + for(i = 0; i < count; i++) { + vol = ubi_find_volume(info[i].name); + if(vol == NULL) { + checked = 0; + break; + } + } + + /* format */ + if(!checked) { + /* remove all volumes */ + for(i = 0; i < (ubi->vtbl_slots + 1); i++) { + if(!ubi->volumes[i]) + continue; + ret = ubi_remove_vol(ubi->volumes[i]->name); + if(ret) break; + } + /* create new volumes */ + for(i = 0; i < count; i++) { + /* Use maximum available size */ + if (!info[i].size) { + info[i].size = ubi->avail_pebs * ubi->leb_size; + printf("No size specified -> Using max size (%u)\n", info[i].size); + } + ret = ubi_create_vol(info[i].name, info[i].size, 1); + if(ret) break; + } + } + + free(info); + return ret; +} + +int ubi_erase_vol(const char *vol_name) +{ + struct ubi_volume *vol; + + vol = ubi_find_volume(vol_name); + if(vol == NULL) { /* not need to erase */ + return 0; + } + return ubi_volume_write(vol_name, "", 0); +} + +int ubi_read_vol(const char *vol_name, loff_t offp, void *buf, size_t size) +{ + return ubi_volume_read(vol_name, offp, buf, size); +} + +int ubi_prepare_write_vol(const char *volume, size_t size) +{ + int err = 1; + int rsvd_bytes = 0; + struct ubi_volume *vol; + + vol = ubi_find_volume(volume); + if (vol == NULL) + return -ENODEV; + + rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad); + if (size < 0 || size > rsvd_bytes) { + printf("size > volume size! Aborting!\n"); + return -EINVAL; + } + + err = ubi_start_update(ubi, vol, size); + if (err < 0) { + printf("Cannot start volume update\n"); + return err; + } + + printf("prepare to write %d bytes to volume %s\n", size, volume); + return 0; +} + +int ubi_do_write_vol(const char *volume, void *buf, size_t size) +{ + int err = 1; + struct ubi_volume *vol; + + vol = ubi_find_volume(volume); + if (vol == NULL) + return -ENODEV; + + err = ubi_more_update_data(ubi, vol, buf, size); + if (err < 0) { + printf("Couldnt or partially wrote data\n"); + return err; + } + + printf("%d bytes written to volume %s\n", size, volume); + return 0; +} + +int ubi_finish_write_vol(const char *volume) +{ + int err = 1; + struct ubi_volume *vol; + + vol = ubi_find_volume(volume); + if (vol == NULL) + return -ENODEV; + + err = ubi_check_volume(ubi, vol->vol_id); + if (err < 0) + return err; + + if (err) { + ubi_warn("volume %d on UBI device %d is corrupted", + vol->vol_id, ubi->ubi_num); + vol->corrupted = 1; + } + + vol->checked = 1; + ubi_gluebi_updated(vol); + + printf("finish to write volume %s\n", volume); + return 0; +} + +int ubi_update_vol(const char *vol_name, void *buf, size_t size) +{ + return ubi_volume_write(vol_name, buf, size); +} + +size_t ubi_sizeof_vol(const char *vol_name) +{ + struct ubi_volume *vol = ubi_find_volume(vol_name); + return vol->used_bytes; +} +#endif /* MTDPARTS_UBI_DEF */ + static int do_ubi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { size_t size = 0; @@ -598,7 +870,7 @@ static int do_ubi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) } if (argc == 3) - return ubi_volume_read(argv[3], (char *)addr, size); + return ubi_volume_read(argv[3], 0, (char *)addr, size); } printf("Please see usage\n"); diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 9eba2713ea..a8e3ae5b67 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -150,7 +150,8 @@ void usb_display_class_sub(unsigned char dclass, unsigned char subclass, void usb_display_string(struct usb_device *dev, int index) { - char buffer[256]; + ALLOC_CACHE_ALIGN_BUFFER(char, buffer, 256); + if (index != 0) { if (usb_string(dev, index, &buffer[0], 256) > 0) printf("String: \"%s\"", buffer); diff --git a/common/cmd_version.c b/common/cmd_version.c index e4b2ac1efc..bdb476df94 100644 --- a/common/cmd_version.c +++ b/common/cmd_version.c @@ -25,6 +25,8 @@ #include <command.h> #include <version.h> #include <linux/compiler.h> +#include <timestamp.h> +#include "generated/version_autogenerated.h" const char __weak version_string[] = U_BOOT_VERSION_STRING; diff --git a/common/cmd_yaffs2.c b/common/cmd_yaffs2.c index 0e22d90e7a..d43a9d444c 100644 --- a/common/cmd_yaffs2.c +++ b/common/cmd_yaffs2.c @@ -1,18 +1,37 @@ +/* Yaffs commands. + * Modified by Charles Manning by adding ydevconfig command. + * + * Use ydevconfig to configure a mountpoint before use. + * For example: + * # Configure mountpt xxx using nand device 0 using blocks 100-500 + * ydevconfig xxx 0 100 500 + * # Mount it + * ymount xxx + * # yls, yrdm etc + * yls -l xxx + * yrdm xxx/boot-image 82000000 + * ... + */ + #include <common.h> #include <config.h> #include <command.h> -#ifdef YAFFS2_DEBUG -#define PRINTF(fmt,args...) printf (fmt ,##args) +#ifdef YAFFS2_DEBUG +#define PRINTF(fmt, args...) printf(fmt, ##args) #else -#define PRINTF(fmt,args...) +#define PRINTF(fmt, args...) do { } while (0) #endif +extern void cmd_yaffs_dev_ls(void); +extern void cmd_yaffs_tracemask(unsigned set, unsigned mask); +extern void cmd_yaffs_devconfig(char *mp, int flash_dev, + int start_block, int end_block); extern void cmd_yaffs_mount(char *mp); extern void cmd_yaffs_umount(char *mp); extern void cmd_yaffs_read_file(char *fn); -extern void cmd_yaffs_write_file(char *fn,char bval,int sizeOfFile); +extern void cmd_yaffs_write_file(char *fn, char bval, int sizeOfFile); extern void cmd_yaffs_ls(const char *mountpt, int longlist); extern void cmd_yaffs_mwrite_file(char *fn, char *addr, int size); extern void cmd_yaffs_mread_file(char *fn, char *addr); @@ -21,193 +40,287 @@ extern void cmd_yaffs_rmdir(const char *dir); extern void cmd_yaffs_rm(const char *path); extern void cmd_yaffs_mv(const char *oldPath, const char *newPath); -extern int yaffs_DumpDevStruct(const char *path); +extern int yaffs_dump_dev(const char *path); + +/* ytrace - show/set yaffs trace mask */ +int do_ytrace(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + if (argc > 1) + cmd_yaffs_tracemask(1, simple_strtol(argv[1], NULL, 16)); + else + cmd_yaffs_tracemask(0, 0); + return 0; +} -int do_ymount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +/* ydevls - lists yaffs mount points. */ +int do_ydevls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *mtpoint = argv[1]; - cmd_yaffs_mount(mtpoint); + cmd_yaffs_dev_ls(); - return(0); + return 0; } -int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +/* ydevconfig mount_pt mtd_dev_num start_block end_block */ +int do_ydevconfig(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *mtpoint = argv[1]; - cmd_yaffs_umount(mtpoint); + char *mtpoint; + int mtd_dev; + int start_block; + int end_block; + + if (argc != 5) { + printf + ("Bad arguments: ydevconfig mount_pt mtd_dev start_block end_block\n"); + return -1; + } + + mtpoint = argv[1]; + mtd_dev = simple_strtol(argv[2], NULL, 16); + start_block = simple_strtol(argv[3], NULL, 16); + end_block = simple_strtol(argv[4], NULL, 16); - return(0); + cmd_yaffs_devconfig(mtpoint, mtd_dev, start_block, end_block); + + return 0; } -int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_ymount(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *dirname = argv[argc-1]; + char *mtpoint; + + if (argc != 2) { + printf("Bad arguments: ymount mount_pt\n"); + return -1; + } + + mtpoint = argv[1]; + printf("Mounting yaffs2 mount point %s\n", mtpoint); - cmd_yaffs_ls(dirname, (argc>2)?1:0); + cmd_yaffs_mount(mtpoint); - return(0); + return 0; } -int do_yrd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_yumount(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *filename = argv[1]; - printf ("Reading file %s ", filename); + char *mtpoint; - cmd_yaffs_read_file(filename); + if (argc != 2) { + printf("Bad arguments: yumount mount_pt\n"); + return -1; + } - printf ("done\n"); - return(0); + mtpoint = argv[1]; + printf("Unmounting yaffs2 mount point %s\n", mtpoint); + cmd_yaffs_umount(mtpoint); + + return 0; } -int do_ywr (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_yls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *filename = argv[1]; - ulong value = simple_strtoul(argv[2], NULL, 16); - ulong numValues = simple_strtoul(argv[3], NULL, 16); + char *dirname; + + if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-l"))) { + printf("Bad arguments: yls [-l] dir\n"); + return -1; + } - printf ("Writing value (%lx) %lx times to %s... ", value, numValues, filename); + dirname = argv[argc - 1]; - cmd_yaffs_write_file(filename,value,numValues); + cmd_yaffs_ls(dirname, (argc > 2) ? 1 : 0); - printf ("done\n"); - return(0); + return 0; } -int do_yrdm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_yrd(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *filename = argv[1]; - ulong addr = simple_strtoul(argv[2], NULL, 16); + char *filename; + + if (argc != 2) { + printf("Bad arguments: yrd file_name\n"); + return -1; + } - cmd_yaffs_mread_file(filename, (char *)addr); + filename = argv[1]; - return(0); + printf("Reading file %s ", filename); + + cmd_yaffs_read_file(filename); + + printf("done\n"); + return 0; } -int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_ywr(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *filename = argv[1]; - ulong addr = simple_strtoul(argv[2], NULL, 16); - ulong size = simple_strtoul(argv[3], NULL, 16); + char *filename; + ulong value; + ulong numValues; + + if (argc != 4) { + printf("Bad arguments: ywr file_name value n_values\n"); + return -1; + } - cmd_yaffs_mwrite_file(filename, (char *)addr, size); + filename = argv[1]; + value = simple_strtoul(argv[2], NULL, 16); + numValues = simple_strtoul(argv[3], NULL, 16); - return(0); + printf("Writing value (%lx) %lx times to %s... ", value, numValues, + filename); + + cmd_yaffs_write_file(filename, value, numValues); + + printf("done\n"); + return 0; } -int do_ymkdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_yrdm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *dirname = argv[1]; + char *filename; + ulong addr; + + if (argc != 3) { + printf("Bad arguments: yrdm file_name addr\n"); + return -1; + } - cmd_yaffs_mkdir(dirname); + filename = argv[1]; + addr = simple_strtoul(argv[2], NULL, 16); - return(0); + cmd_yaffs_mread_file(filename, (char *)addr); + + return 0; } -int do_yrmdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_ywrm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *dirname = argv[1]; + char *filename; + ulong addr; + ulong size; + + if (argc != 4) { + printf("Bad arguments: ywrm file_name addr size\n"); + return -1; + } + + filename = argv[1]; + addr = simple_strtoul(argv[2], NULL, 16); + size = simple_strtoul(argv[3], NULL, 16); - cmd_yaffs_rmdir(dirname); + cmd_yaffs_mwrite_file(filename, (char *)addr, size); - return(0); + return 0; } -int do_yrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_ymkdir(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *path = argv[1]; + char *dirname; - cmd_yaffs_rm(path); + if (argc != 2) { + printf("Bad arguments: ymkdir dir_name\n"); + return -1; + } - return(0); + dirname = argv[1]; + cmd_yaffs_mkdir(dirname); + + return 0; } -int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_yrmdir(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *oldPath = argv[1]; - char *newPath = argv[2]; + char *dirname; + + if (argc != 2) { + printf("Bad arguments: yrmdir dir_name\n"); + return -1; + } - cmd_yaffs_mv(newPath, oldPath); + dirname = argv[1]; + cmd_yaffs_rmdir(dirname); - return(0); + return 0; } -int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_yrm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - char *dirname = argv[1]; - if (yaffs_DumpDevStruct(dirname) != 0) - printf("yaffs_DumpDevStruct returning error when dumping path: , %s\n", dirname); - return 0; + char *name; + + if (argc != 2) { + printf("Bad arguments: yrm name\n"); + return -1; + } + + name = argv[1]; + + cmd_yaffs_rm(name); + + return 0; +} + +int do_ymv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + char *oldPath; + char *newPath; + + if (argc != 3) { + printf("Bad arguments: ymv old_path new_path\n"); + return -1; + } + + oldPath = argv[1]; + newPath = argv[2]; + + cmd_yaffs_mv(newPath, oldPath); + + return 0; } -U_BOOT_CMD( - ymount, 3, 0, do_ymount, - "mount yaffs", - "" -); - -U_BOOT_CMD( - yumount, 3, 0, do_yumount, - "unmount yaffs", - "" -); - -U_BOOT_CMD( - yls, 4, 0, do_yls, - "yaffs ls", - "[-l] name" -); - -U_BOOT_CMD( - yrd, 2, 0, do_yrd, - "read file from yaffs", - "filename" -); - -U_BOOT_CMD( - ywr, 4, 0, do_ywr, - "write file to yaffs", - "filename value num_vlues" -); - -U_BOOT_CMD( - yrdm, 3, 0, do_yrdm, - "read file to memory from yaffs", - "filename offset" -); - -U_BOOT_CMD( - ywrm, 4, 0, do_ywrm, - "write file from memory to yaffs", - "filename offset size" -); - -U_BOOT_CMD( - ymkdir, 2, 0, do_ymkdir, - "YAFFS mkdir", - "dirname" -); - -U_BOOT_CMD( - yrmdir, 2, 0, do_yrmdir, - "YAFFS rmdir", - "dirname" -); - -U_BOOT_CMD( - yrm, 2, 0, do_yrm, - "YAFFS rm", - "path" -); - -U_BOOT_CMD( - ymv, 4, 0, do_ymv, - "YAFFS mv", - "oldPath newPath" -); - -U_BOOT_CMD( - ydump, 2, 0, do_ydump, - "YAFFS device struct", - "dirname" -); +U_BOOT_CMD(ytrace, 2, 0, do_ytrace, + "show/set yaffs trace mask", + "ytrace [new_mask] show/set yaffs trace mask"); + +U_BOOT_CMD(ydevls, 1, 0, do_ydevls, + "list yaffs mount points", "list yaffs mount points"); + +U_BOOT_CMD(ydevconfig, 5, 0, do_ydevconfig, + "configure yaffs mount point", + "ydevconfig mtpoint mtd_id start_block end_block configures a yaffs2 mount point"); + +U_BOOT_CMD(ymount, 2, 0, do_ymount, + "mount yaffs", "ymount mtpoint mounts a yaffs2 mount point"); + +U_BOOT_CMD(yumount, 2, 0, do_yumount, + "unmount yaffs", "yunmount mtpoint unmounts a yaffs2 mount point"); + +U_BOOT_CMD(yls, 3, 0, do_yls, "yaffs ls", "yls [-l] dirname"); + +U_BOOT_CMD(yrd, 2, 0, do_yrd, + "read file from yaffs", "yrd path read file from yaffs"); + +U_BOOT_CMD(ywr, 4, 0, do_ywr, + "write file to yaffs", + "ywr filename value num_vlues write values to yaffs file"); + +U_BOOT_CMD(yrdm, 3, 0, do_yrdm, + "read file to memory from yaffs", + "yrdm filename offset reads yaffs file into memory"); + +U_BOOT_CMD(ywrm, 4, 0, do_ywrm, + "write file from memory to yaffs", + "ywrm filename offset size writes memory to yaffs file"); + +U_BOOT_CMD(ymkdir, 2, 0, do_ymkdir, + "YAFFS mkdir", "ymkdir dir create a yaffs directory"); + +U_BOOT_CMD(yrmdir, 2, 0, do_yrmdir, + "YAFFS rmdir", "yrmdir dirname removes a yaffs directory"); + +U_BOOT_CMD(yrm, 2, 0, do_yrm, "YAFFS rm", "yrm path removes a yaffs file"); + +U_BOOT_CMD(ymv, 4, 0, do_ymv, + "YAFFS mv", + "ymv old_path new_path moves/rename files within a yaffs mount point"); diff --git a/common/env_onenand.c b/common/env_onenand.c index 652665a189..7197ab6585 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -33,7 +33,7 @@ #include <errno.h> #include <onenand_uboot.h> -#include <linux/mtd/compat.h> +#include <linux/compat.h> #include <linux/mtd/mtd.h> #include <linux/mtd/onenand.h> diff --git a/common/env_remote.c b/common/env_remote.c new file mode 100644 index 0000000000..3bf0f957b3 --- /dev/null +++ b/common/env_remote.c @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2011-2012 Freescale Semiconductor, Inc. + * + * 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 + */ + +/* #define DEBUG */ + +#include <common.h> +#include <command.h> +#include <environment.h> +#include <linux/stddef.h> + +char *env_name_spec = "Remote"; + +#ifdef ENV_IS_EMBEDDED +env_t *env_ptr = &environment; +#else /* ! ENV_IS_EMBEDDED */ +env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR; +#endif /* ENV_IS_EMBEDDED */ + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CONFIG_ENV_OFFSET) +#define CONFIG_ENV_OFFSET 0 +#endif + +uchar env_get_char_spec(int index) +{ + return *((uchar *)(gd->env_addr + index)); +} + +int env_init(void) +{ + if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { + gd->env_addr = (ulong)&(env_ptr->data); + gd->env_valid = 1; + return 0; + } + + gd->env_addr = (ulong)default_environment; + gd->env_valid = 0; + return 0; +} + +#ifdef CONFIG_CMD_SAVEENV +int saveenv(void) +{ +#ifdef CONFIG_SRIOBOOT_SLAVE + printf("Can not support the 'saveenv' when boot from SRIO!\n"); + return 1; +#else + return 0; +#endif +} +#endif /* CONFIG_CMD_SAVEENV */ + +void env_relocate_spec(void) +{ +#ifndef ENV_IS_EMBEDDED + env_import((char *)env_ptr, 1); +#endif +} diff --git a/common/hush.c b/common/hush.c index 672ab9e157..888c4a1a32 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1042,7 +1042,7 @@ static void get_user_input(struct in_str *i) else { if (console_buffer[0] != '\n') { strcpy(the_command,console_buffer); - flag_repeat = 1; + /* flag_repeat = 1; */ } else { do_repeat = 1; diff --git a/common/image.c b/common/image.c index 342b315918..ba6f010ac6 100644 --- a/common/image.c +++ b/common/image.c @@ -78,12 +78,13 @@ static const table_entry_t uimage_arch[] = { { IH_ARCH_INVALID, NULL, "Invalid ARCH", }, { IH_ARCH_ALPHA, "alpha", "Alpha", }, { IH_ARCH_ARM, "arm", "ARM", }, + { IH_ARCH_MIPS, "mips", "MIPS", }, + { IH_ARCH_MIPS64, "mips64", "MIPS 64 Bit", }, +#ifndef CONFIG_SPL_BUILD { IH_ARCH_I386, "x86", "Intel x86", }, { IH_ARCH_IA64, "ia64", "IA64", }, { IH_ARCH_M68K, "m68k", "M68K", }, { IH_ARCH_MICROBLAZE, "microblaze", "MicroBlaze", }, - { IH_ARCH_MIPS, "mips", "MIPS", }, - { IH_ARCH_MIPS64, "mips64", "MIPS 64 Bit", }, { IH_ARCH_NIOS2, "nios2", "NIOS II", }, { IH_ARCH_PPC, "powerpc", "PowerPC", }, { IH_ARCH_PPC, "ppc", "PowerPC", }, @@ -95,19 +96,21 @@ static const table_entry_t uimage_arch[] = { { IH_ARCH_AVR32, "avr32", "AVR32", }, { IH_ARCH_NDS32, "nds32", "NDS32", }, { IH_ARCH_OPENRISC, "or1k", "OpenRISC 1000",}, +#endif { -1, "", "", }, }; static const table_entry_t uimage_os[] = { { IH_OS_INVALID, NULL, "Invalid OS", }, { IH_OS_LINUX, "linux", "Linux", }, + { IH_OS_U_BOOT, "u-boot", "U-Boot", }, +#ifndef CONFIG_SPL_BUILD #if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC) { IH_OS_LYNXOS, "lynxos", "LynxOS", }, #endif { IH_OS_NETBSD, "netbsd", "NetBSD", }, { IH_OS_OSE, "ose", "Enea OSE", }, { IH_OS_RTEMS, "rtems", "RTEMS", }, - { IH_OS_U_BOOT, "u-boot", "U-Boot", }, #if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC) { IH_OS_QNX, "qnx", "QNX", }, { IH_OS_VXWORKS, "vxworks", "VxWorks", }, @@ -128,6 +131,7 @@ static const table_entry_t uimage_os[] = { { IH_OS_SOLARIS, "solaris", "Solaris", }, { IH_OS_SVR4, "svr4", "SVR4", }, #endif +#endif { -1, "", "", }, }; @@ -1829,7 +1833,7 @@ static int fit_parse_spec(const char *spec, char sepc, ulong addr_curr, * addr and conf_name are set accordingly * 0 otherwise */ -inline int fit_parse_conf(const char *spec, ulong addr_curr, +int fit_parse_conf(const char *spec, ulong addr_curr, ulong *addr, const char **conf_name) { return fit_parse_spec(spec, '#', addr_curr, addr, conf_name); @@ -1855,7 +1859,7 @@ inline int fit_parse_conf(const char *spec, ulong addr_curr, * addr and image_name are set accordingly * 0 otherwise */ -inline int fit_parse_subimage(const char *spec, ulong addr_curr, +int fit_parse_subimage(const char *spec, ulong addr_curr, ulong *addr, const char **image_name) { return fit_parse_spec(spec, ':', addr_curr, addr, image_name); diff --git a/common/main.c b/common/main.c index 3b9e39a980..8b7fd8fffe 100644 --- a/common/main.c +++ b/common/main.c @@ -43,6 +43,8 @@ #include <linux/ctype.h> #include <menu.h> +/* #define DEBUG_BOOTKEYS 1 */ + #if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING) DECLARE_GLOBAL_DATA_PTR; #endif @@ -50,7 +52,7 @@ DECLARE_GLOBAL_DATA_PTR; /* * Board-specific Platform code can reimplement show_boot_progress () if needed */ -void inline __show_boot_progress (int val) {} +void __show_boot_progress (int val) {} void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress"))); #if defined(CONFIG_UPDATE_TFTP) @@ -95,7 +97,7 @@ static inline int abortboot(int bootdelay) { int abort = 0; - uint64_t etime = endtick(bootdelay); + uint64_t etime = endtick(1); struct { char* str; u_int len; @@ -113,10 +115,6 @@ int abortboot(int bootdelay) u_int presskey_max = 0; u_int i; -# ifdef CONFIG_AUTOBOOT_PROMPT - printf(CONFIG_AUTOBOOT_PROMPT); -# endif - # ifdef CONFIG_AUTOBOOT_DELAY_STR if (delaykey[0].str == NULL) delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; @@ -134,6 +132,10 @@ int abortboot(int bootdelay) delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; # endif +# if DEBUG_BOOTKEYS + printf("\n"); +# endif + for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { delaykey[i].len = delaykey[i].str == NULL ? 0 : strlen (delaykey[i].str); @@ -144,16 +146,46 @@ int abortboot(int bootdelay) presskey_max : delaykey[i].len; # if DEBUG_BOOTKEYS - printf("%s key:<%s>\n", - delaykey[i].retry ? "delay" : "stop", - delaykey[i].str ? delaykey[i].str : "NULL"); + u_int j; + printf("%s key: <", delaykey[i].retry ? "Delay" : "Stop "); + if (delaykey[i].str) { + for (j = 0; j < delaykey[i].len; j++) { + if (delaykey[i].str[j] < 0x80 && + isprint(delaykey[i].str[j])) { + printf("%c", delaykey[i].str[j]); + } else { + printf("\\x%02X", delaykey[i].str[j]); + } + } + } else { + printf("NULL"); + } + printf(">\n"); # endif } +# if DEBUG_BOOTKEYS + printf("\n"); +# endif + +# ifdef CONFIG_AUTOBOOT_PROMPT + printf(CONFIG_AUTOBOOT_PROMPT); +# else + printf("Hit delay/stop key to delay/stop autoboot: %2d ", bootdelay); +# endif + /* In order to keep up with incoming data, check timeout only * when catch up. */ - do { + while (!abort && bootdelay > 0) { + if (get_ticks() > etime) { + etime = endtick(1); + --bootdelay; +# ifndef CONFIG_AUTOBOOT_PROMPT + printf("\b\b\b%2d ", bootdelay); +# endif + } + if (tstc()) { if (presskey_len < presskey_max) { presskey [presskey_len ++] = getc(); @@ -172,11 +204,14 @@ int abortboot(int bootdelay) memcmp (presskey + presskey_len - delaykey[i].len, delaykey[i].str, delaykey[i].len) == 0) { +# ifndef CONFIG_AUTOBOOT_PROMPT + puts("\n"); +# endif # if DEBUG_BOOTKEYS - printf("got %skey\n", + printf("Got %s key\n", delaykey[i].retry ? "delay" : "stop"); # endif - + puts("\n"); # ifdef CONFIG_BOOT_RETRY_TIME /* don't retry auto boot */ if (! delaykey[i].retry) @@ -185,12 +220,17 @@ int abortboot(int bootdelay) abort = 1; } } - } while (!abort && get_ticks() <= etime); + } + if (!abort) { +# ifndef CONFIG_AUTOBOOT_PROMPT + puts("\n"); +# endif # if DEBUG_BOOTKEYS - if (!abort) - puts("key timeout\n"); + puts("Key timeout\n"); # endif + puts("\n"); + } #ifdef CONFIG_SILENT_CONSOLE if (abort) @@ -227,7 +267,9 @@ int abortboot(int bootdelay) if (bootdelay >= 0) { if (tstc()) { /* we got a key press */ (void) getc(); /* consume input */ +#ifndef CONFIG_MENUPROMPT puts ("\b\b\b 0"); +#endif abort = 1; /* don't auto boot */ } } @@ -252,7 +294,9 @@ int abortboot(int bootdelay) udelay(10000); } +#ifndef CONFIG_MENUPROMPT printf("\b\b\b%2d ", bootdelay); +#endif } putc('\n'); @@ -271,6 +315,7 @@ int abortboot(int bootdelay) void main_loop (void) { + int autoboot; #ifndef CONFIG_SYS_HUSH_PARSER static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; int len; @@ -376,7 +421,12 @@ void main_loop (void) debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); - if (bootdelay >= 0 && s && !abortboot (bootdelay)) { +# ifdef REBOOT_WHEN_CRASH + autoboot = (s != NULL); +# else + autoboot = (bootdelay >= 0 && s && !abortboot (bootdelay)); +# endif + if (autoboot) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ # endif @@ -973,7 +1023,6 @@ int readline_into_buffer(const char *const prompt, char *buffer, int timeout) #ifdef CONFIG_SHOW_ACTIVITY while (!tstc()) { - extern void show_activity(int arg); show_activity(0); WATCHDOG_RESET(); } diff --git a/common/usb.c b/common/usb.c index 1ec30bc058..c80155ce76 100644 --- a/common/usb.c +++ b/common/usb.c @@ -47,6 +47,7 @@ #include <common.h> #include <command.h> #include <asm/processor.h> +#include <linux/compiler.h> #include <linux/ctype.h> #include <asm/byteorder.h> #include <asm/unaligned.h> @@ -169,7 +170,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned short value, unsigned short index, void *data, unsigned short size, int timeout) { - struct devrequest setup_packet; + ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1); if ((timeout == 0) && (!asynch_allowed)) { /* request for a asynch control pipe is not allowed */ @@ -177,17 +178,17 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, } /* set setup command */ - setup_packet.requesttype = requesttype; - setup_packet.request = request; - setup_packet.value = cpu_to_le16(value); - setup_packet.index = cpu_to_le16(index); - setup_packet.length = cpu_to_le16(size); + setup_packet->requesttype = requesttype; + setup_packet->request = request; + setup_packet->value = cpu_to_le16(value); + setup_packet->index = cpu_to_le16(index); + setup_packet->length = cpu_to_le16(size); USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \ "value 0x%X index 0x%X length 0x%X\n", request, requesttype, value, index, size); dev->status = USB_ST_NOT_PROC; /*not yet processed */ - submit_control_msg(dev, pipe, data, size, &setup_packet); + submit_control_msg(dev, pipe, data, size, setup_packet); if (timeout == 0) return (int)size; @@ -261,7 +262,7 @@ int usb_maxpacket(struct usb_device *dev, unsigned long pipe) * * NOTE: Similar behaviour was observed with GCC4.6 on ARMv5. */ -static void __attribute__((noinline)) +static void noinline usb_set_maxpacket_ep(struct usb_device *dev, int if_idx, int ep_idx) { int b; @@ -681,7 +682,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, */ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) { - unsigned char mybuf[USB_BUFSIZ]; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, mybuf, USB_BUFSIZ); unsigned char *tbuf; int err; unsigned int u, idx; @@ -781,7 +782,7 @@ int usb_new_device(struct usb_device *dev) { int addr, err; int tmp; - unsigned char tmpbuf[USB_BUFSIZ]; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ); /* We still haven't set the Address yet */ addr = dev->devnum; @@ -908,8 +909,8 @@ int usb_new_device(struct usb_device *dev) le16_to_cpus(&dev->descriptor.idProduct); le16_to_cpus(&dev->descriptor.bcdDevice); /* only support for one config for now */ - usb_get_configuration_no(dev, &tmpbuf[0], 0); - usb_parse_config(dev, &tmpbuf[0], 0); + usb_get_configuration_no(dev, tmpbuf, 0); + usb_parse_config(dev, tmpbuf, 0); usb_set_maxpacket(dev); /* we set the default configuration here */ if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) { diff --git a/common/usb_hub.c b/common/usb_hub.c index e0edaad56b..f35ad95324 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -153,7 +153,7 @@ int hub_port_reset(struct usb_device *dev, int port, unsigned short *portstat) { int tries; - struct usb_port_status portsts; + ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port); @@ -162,13 +162,13 @@ int hub_port_reset(struct usb_device *dev, int port, usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET); mdelay(200); - if (usb_get_port_status(dev, port + 1, &portsts) < 0) { + if (usb_get_port_status(dev, port + 1, portsts) < 0) { USB_HUB_PRINTF("get_port_status failed status %lX\n", dev->status); return -1; } - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); + portstatus = le16_to_cpu(portsts->wPortStatus); + portchange = le16_to_cpu(portsts->wPortChange); USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange, @@ -206,19 +206,19 @@ int hub_port_reset(struct usb_device *dev, int port, void usb_hub_port_connect_change(struct usb_device *dev, int port) { struct usb_device *usb; - struct usb_port_status portsts; + ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus; /* Check status */ - if (usb_get_port_status(dev, port + 1, &portsts) < 0) { + if (usb_get_port_status(dev, port + 1, portsts) < 0) { USB_HUB_PRINTF("get_port_status failed\n"); return; } - portstatus = le16_to_cpu(portsts.wPortStatus); + portstatus = le16_to_cpu(portsts->wPortStatus); USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, - le16_to_cpu(portsts.wPortChange), + le16_to_cpu(portsts->wPortChange), portspeed(portstatus)); /* Clear the connection change status */ @@ -267,7 +267,8 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) static int usb_hub_configure(struct usb_device *dev) { int i; - unsigned char buffer[USB_BUFSIZ], *bitmap; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ); + unsigned char *bitmap; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; #ifdef USB_HUB_DEBUG @@ -389,16 +390,16 @@ static int usb_hub_configure(struct usb_device *dev) usb_hub_power_on(hub); for (i = 0; i < dev->maxchild; i++) { - struct usb_port_status portsts; + ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; - if (usb_get_port_status(dev, i + 1, &portsts) < 0) { + if (usb_get_port_status(dev, i + 1, portsts) < 0) { USB_HUB_PRINTF("get_port_status failed\n"); continue; } - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); + portstatus = le16_to_cpu(portsts->wPortStatus); + portchange = le16_to_cpu(portsts->wPortChange); USB_HUB_PRINTF("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); diff --git a/common/usb_storage.c b/common/usb_storage.c index 12083337b0..faad23706f 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -79,8 +79,7 @@ static const unsigned char us_direction[256/8] = { }; #define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1) -static unsigned char usb_stor_buf[512]; -static ccb usb_ccb; +static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN))); /* * CBI style @@ -210,17 +209,17 @@ int usb_stor_info(void) static unsigned int usb_get_max_lun(struct us_data *us) { int len; - unsigned char result; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1); len = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev, 0), US_BBB_GET_MAX_LUN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 0, us->ifnum, - &result, sizeof(result), + result, sizeof(char), USB_CNTL_TIMEOUT * 5); USB_STOR_PRINTF("Get Max LUN -> len = %i, result = %i\n", - len, (int) result); - return (len > 0) ? result : 0; + len, (int) *result); + return (len > 0) ? *result : 0; } /******************************************************************************* @@ -233,9 +232,6 @@ int usb_stor_scan(int mode) unsigned char i; struct usb_device *dev; - /* GJ */ - memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); - if (mode == 1) printf(" scanning bus for storage devices... "); @@ -499,7 +495,7 @@ int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) int actlen; int dir_in; unsigned int pipe; - umass_bbb_cbw_t cbw; + ALLOC_CACHE_ALIGN_BUFFER(umass_bbb_cbw_t, cbw, 1); dir_in = US_DIRECTION(srb->cmd[0]); @@ -522,16 +518,16 @@ int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) /* always OUT to the ep */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - cbw.dCBWSignature = cpu_to_le32(CBWSIGNATURE); - cbw.dCBWTag = cpu_to_le32(CBWTag++); - cbw.dCBWDataTransferLength = cpu_to_le32(srb->datalen); - cbw.bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT); - cbw.bCBWLUN = srb->lun; - cbw.bCDBLength = srb->cmdlen; + cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE); + cbw->dCBWTag = cpu_to_le32(CBWTag++); + cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen); + cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT); + cbw->bCBWLUN = srb->lun; + cbw->bCDBLength = srb->cmdlen; /* copy the command data into the CBW command data buffer */ /* DST SRC LEN!!! */ - memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen); - result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, + memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen); + result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT * 5); if (result < 0) USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); @@ -675,7 +671,7 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us) int dir_in; int actlen, data_actlen; unsigned int pipe, pipein, pipeout; - umass_bbb_csw_t csw; + ALLOC_CACHE_ALIGN_BUFFER(umass_bbb_csw_t, csw, 1); #ifdef BBB_XPORT_TRACE unsigned char *ptr; int index; @@ -733,7 +729,7 @@ st: retry = 0; again: USB_STOR_PRINTF("STATUS phase\n"); - result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, + result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); /* special handling of STALL in STATUS phase */ @@ -753,28 +749,28 @@ again: return USB_STOR_TRANSPORT_FAILED; } #ifdef BBB_XPORT_TRACE - ptr = (unsigned char *)&csw; + ptr = (unsigned char *)csw; for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) printf("ptr[%d] %#x ", index, ptr[index]); printf("\n"); #endif /* misuse pipe to get the residue */ - pipe = le32_to_cpu(csw.dCSWDataResidue); + pipe = le32_to_cpu(csw->dCSWDataResidue); if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) pipe = srb->datalen - data_actlen; - if (CSWSIGNATURE != le32_to_cpu(csw.dCSWSignature)) { + if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) { USB_STOR_PRINTF("!CSWSIGNATURE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; - } else if ((CBWTag - 1) != le32_to_cpu(csw.dCSWTag)) { + } else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) { USB_STOR_PRINTF("!Tag\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; - } else if (csw.bCSWStatus > CSWSTATUS_PHASE) { + } else if (csw->bCSWStatus > CSWSTATUS_PHASE) { USB_STOR_PRINTF(">PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; - } else if (csw.bCSWStatus == CSWSTATUS_PHASE) { + } else if (csw->bCSWStatus == CSWSTATUS_PHASE) { USB_STOR_PRINTF("=PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; @@ -782,7 +778,7 @@ again: USB_STOR_PRINTF("transferred %dB instead of %ldB\n", data_actlen, srb->datalen); return USB_STOR_TRANSPORT_FAILED; - } else if (csw.bCSWStatus == CSWSTATUS_FAILED) { + } else if (csw->bCSWStatus == CSWSTATUS_FAILED) { USB_STOR_PRINTF("FAILED\n"); return USB_STOR_TRANSPORT_FAILED; } @@ -1343,7 +1339,8 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, block_dev_desc_t *dev_desc) { unsigned char perq, modi; - unsigned long cap[2]; + ALLOC_CACHE_ALIGN_BUFFER(unsigned long, cap, 2); + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, usb_stor_buf, 36); unsigned long *capacity, *blksz; ccb *pccb = &usb_ccb; @@ -1367,9 +1364,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, /* drive is removable */ dev_desc->removable = 1; } - memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8); - memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16); - memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4); + memcpy(&dev_desc->vendor[0], (const void *) &usb_stor_buf[8], 8); + memcpy(&dev_desc->product[0], (const void *) &usb_stor_buf[16], 16); + memcpy(&dev_desc->revision[0], (const void *) &usb_stor_buf[32], 4); dev_desc->vendor[8] = 0; dev_desc->product[16] = 0; dev_desc->revision[4] = 0; |