| /* |
| * Copyright (C) 2009 Texas Instruments Incorporated |
| * |
| * Copyright (C) 2011 |
| * Heiko Schocher, DENX Software Engineering, hs@denx.de. |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <cli.h> |
| #include <errno.h> |
| #include <linux/mtd/nand.h> |
| #include <nand.h> |
| #include <miiphy.h> |
| #include <netdev.h> |
| #include <asm/io.h> |
| #include <asm/arch/hardware.h> |
| #include <asm/ti-common/davinci_nand.h> |
| #include <asm/arch/davinci_misc.h> |
| #ifdef CONFIG_DAVINCI_MMC |
| #include <mmc.h> |
| #include <asm/arch/sdmmc_defs.h> |
| #endif |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| #ifndef CONFIG_SPL_BUILD |
| static struct davinci_timer *timer = |
| (struct davinci_timer *)DAVINCI_TIMER3_BASE; |
| |
| static unsigned long get_timer_val(void) |
| { |
| unsigned long now = readl(&timer->tim34); |
| |
| return now; |
| } |
| |
| static int timer_running(void) |
| { |
| return readl(&timer->tcr) & |
| (DV_TIMER_TCR_ENAMODE_MASK << DV_TIMER_TCR_ENAMODE34_SHIFT); |
| } |
| |
| static void stop_timer(void) |
| { |
| writel(0x0, &timer->tcr); |
| return; |
| } |
| |
| int checkboard(void) |
| { |
| printf("Board: AIT CAM ENC 4XX\n"); |
| return 0; |
| } |
| |
| int board_init(void) |
| { |
| gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; |
| |
| return 0; |
| } |
| |
| #ifdef CONFIG_DRIVER_TI_EMAC |
| static int cam_enc_4xx_check_network(void) |
| { |
| char *s; |
| |
| s = getenv("ethaddr"); |
| if (!s) |
| return -EINVAL; |
| |
| if (!is_valid_ether_addr((const u8 *)s)) |
| return -EINVAL; |
| |
| s = getenv("ipaddr"); |
| if (!s) |
| return -EINVAL; |
| |
| s = getenv("netmask"); |
| if (!s) |
| return -EINVAL; |
| |
| s = getenv("serverip"); |
| if (!s) |
| return -EINVAL; |
| |
| s = getenv("gatewayip"); |
| if (!s) |
| return -EINVAL; |
| |
| return 0; |
| } |
| int board_eth_init(bd_t *bis) |
| { |
| int ret; |
| |
| ret = cam_enc_4xx_check_network(); |
| if (ret) |
| return ret; |
| |
| davinci_emac_initialize(); |
| |
| return 0; |
| } |
| #endif |
| |
| #ifdef CONFIG_NAND_DAVINCI |
| static int |
| davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, |
| uint8_t *buf, int oob_required, int page) |
| { |
| struct nand_chip *this = mtd->priv; |
| int i, eccsize = chip->ecc.size; |
| int eccbytes = chip->ecc.bytes; |
| int eccsteps = chip->ecc.steps; |
| uint8_t *p = buf; |
| uint8_t *oob = chip->oob_poi; |
| |
| chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); |
| |
| chip->read_buf(mtd, oob, mtd->oobsize); |
| |
| chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page & this->pagemask); |
| |
| |
| for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
| int stat; |
| |
| chip->ecc.hwctl(mtd, NAND_ECC_READ); |
| chip->read_buf(mtd, p, eccsize); |
| chip->ecc.hwctl(mtd, NAND_ECC_READSYN); |
| |
| if (chip->ecc.prepad) |
| oob += chip->ecc.prepad; |
| |
| stat = chip->ecc.correct(mtd, p, oob, NULL); |
| |
| if (stat == -1) |
| mtd->ecc_stats.failed++; |
| else |
| mtd->ecc_stats.corrected += stat; |
| |
| oob += eccbytes; |
| |
| if (chip->ecc.postpad) |
| oob += chip->ecc.postpad; |
| } |
| |
| /* Calculate remaining oob bytes */ |
| i = mtd->oobsize - (oob - chip->oob_poi); |
| if (i) |
| chip->read_buf(mtd, oob, i); |
| |
| return 0; |
| } |
| |
| static int davinci_std_write_page_syndrome(struct mtd_info *mtd, |
| struct nand_chip *chip, const uint8_t *buf, |
| int oob_required) |
| { |
| unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE]; |
| struct nand_chip *this = mtd->priv; |
| int i, eccsize = chip->ecc.size; |
| int eccbytes = chip->ecc.bytes; |
| int eccsteps = chip->ecc.steps; |
| int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; |
| int offset = 0; |
| const uint8_t *p = buf; |
| uint8_t *oob = chip->oob_poi; |
| |
| for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
| chip->ecc.hwctl(mtd, NAND_ECC_WRITE); |
| chip->write_buf(mtd, p, eccsize); |
| |
| /* Calculate ECC without prepad */ |
| chip->ecc.calculate(mtd, p, oob + chip->ecc.prepad); |
| |
| if (chip->ecc.prepad) { |
| offset = (chip->ecc.steps - eccsteps) * chunk; |
| memcpy(&davinci_ecc_buf[offset], oob, chip->ecc.prepad); |
| oob += chip->ecc.prepad; |
| } |
| |
| offset = ((chip->ecc.steps - eccsteps) * chunk) + |
| chip->ecc.prepad; |
| memcpy(&davinci_ecc_buf[offset], oob, eccbytes); |
| oob += eccbytes; |
| |
| if (chip->ecc.postpad) { |
| offset = ((chip->ecc.steps - eccsteps) * chunk) + |
| chip->ecc.prepad + eccbytes; |
| memcpy(&davinci_ecc_buf[offset], oob, |
| chip->ecc.postpad); |
| oob += chip->ecc.postpad; |
| } |
| } |
| |
| /* |
| * Write the sparebytes into the page once |
| * all eccsteps have been covered |
| */ |
| for (i = 0; i < mtd->oobsize; i++) |
| writeb(davinci_ecc_buf[i], this->IO_ADDR_W); |
| |
| /* Calculate remaining oob bytes */ |
| i = mtd->oobsize - (oob - chip->oob_poi); |
| if (i) |
| chip->write_buf(mtd, oob, i); |
| return 0; |
| } |
| |
| static int davinci_std_write_oob_syndrome(struct mtd_info *mtd, |
| struct nand_chip *chip, int page) |
| { |
| int pos, status = 0; |
| const uint8_t *bufpoi = chip->oob_poi; |
| |
| pos = mtd->writesize; |
| |
| chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); |
| |
| chip->write_buf(mtd, bufpoi, mtd->oobsize); |
| |
| chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); |
| status = chip->waitfunc(mtd, chip); |
| |
| return status & NAND_STATUS_FAIL ? -1 : 0; |
| } |
| |
| static int davinci_std_read_oob_syndrome(struct mtd_info *mtd, |
| struct nand_chip *chip, int page) |
| { |
| struct nand_chip *this = mtd->priv; |
| uint8_t *buf = chip->oob_poi; |
| uint8_t *bufpoi = buf; |
| |
| chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); |
| |
| chip->read_buf(mtd, bufpoi, mtd->oobsize); |
| |
| return 0; |
| } |
| |
| static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip) |
| { |
| struct nand_chip *this = mtd->priv; |
| unsigned long wbase = (unsigned long) this->IO_ADDR_W; |
| unsigned long rbase = (unsigned long) this->IO_ADDR_R; |
| |
| if (chip == 1) { |
| __set_bit(14, &wbase); |
| __set_bit(14, &rbase); |
| } else { |
| __clear_bit(14, &wbase); |
| __clear_bit(14, &rbase); |
| } |
| this->IO_ADDR_W = (void *)wbase; |
| this->IO_ADDR_R = (void *)rbase; |
| } |
| |
| int board_nand_init(struct nand_chip *nand) |
| { |
| davinci_nand_init(nand); |
| nand->select_chip = nand_dm365evm_select_chip; |
| |
| return 0; |
| } |
| |
| struct nand_ecc_ctrl org_ecc; |
| static int notsaved = 1; |
| |
| static int nand_switch_hw_func(int mode) |
| { |
| struct nand_chip *nand; |
| struct mtd_info *mtd; |
| |
| if (nand_curr_device < 0 || |
| nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || |
| !nand_info[nand_curr_device].name) { |
| printf("Error: Can't switch hw functions," \ |
| " no devices available\n"); |
| return -1; |
| } |
| |
| mtd = &nand_info[nand_curr_device]; |
| nand = mtd->priv; |
| |
| if (mode == 0) { |
| if (notsaved == 0) { |
| printf("switching to uboot hw functions.\n"); |
| memcpy(&nand->ecc, &org_ecc, |
| sizeof(struct nand_ecc_ctrl)); |
| } |
| } else { |
| /* RBL */ |
| printf("switching to RBL hw functions.\n"); |
| if (notsaved == 1) { |
| memcpy(&org_ecc, &nand->ecc, |
| sizeof(struct nand_ecc_ctrl)); |
| notsaved = 0; |
| } |
| nand->ecc.mode = NAND_ECC_HW_SYNDROME; |
| nand->ecc.prepad = 6; |
| nand->ecc.read_page = davinci_std_read_page_syndrome; |
| nand->ecc.write_page = davinci_std_write_page_syndrome; |
| nand->ecc.read_oob = davinci_std_read_oob_syndrome; |
| nand->ecc.write_oob = davinci_std_write_oob_syndrome; |
| } |
| return mode; |
| } |
| |
| static int hwmode; |
| |
| static int do_switch_ecc(cmd_tbl_t *cmdtp, int flag, int argc, |
| char *const argv[]) |
| { |
| if (argc != 2) |
| goto usage; |
| if (strncmp(argv[1], "rbl", 2) == 0) |
| hwmode = nand_switch_hw_func(1); |
| else if (strncmp(argv[1], "uboot", 2) == 0) |
| hwmode = nand_switch_hw_func(0); |
| else |
| goto usage; |
| |
| return 0; |
| |
| usage: |
| printf("Usage: nandrbl %s\n", cmdtp->usage); |
| return 1; |
| } |
| |
| U_BOOT_CMD( |
| nandrbl, 2, 1, do_switch_ecc, |
| "switch between rbl/uboot NAND ECC calculation algorithm", |
| "[rbl/uboot] - Switch between rbl/uboot NAND ECC algorithm" |
| ); |
| |
| |
| #endif /* #ifdef CONFIG_NAND_DAVINCI */ |
| |
| #ifdef CONFIG_DAVINCI_MMC |
| static struct davinci_mmc mmc_sd0 = { |
| .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD0_BASE, |
| .input_clk = 121500000, |
| .host_caps = MMC_MODE_4BIT, |
| .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, |
| .version = MMC_CTLR_VERSION_2, |
| }; |
| |
| int board_mmc_init(bd_t *bis) |
| { |
| int err; |
| |
| /* Add slot-0 to mmc subsystem */ |
| err = davinci_mmc_init(bis, &mmc_sd0); |
| |
| return err; |
| } |
| #endif |
| |
| int board_late_init(void) |
| { |
| struct davinci_gpio *gpio = davinci_gpio_bank45; |
| |
| /* 24MHz InputClock / 15 prediv -> 1.6 MHz timer running */ |
| while ((get_timer_val() < CONFIG_AIT_TIMER_TIMEOUT) && |
| timer_running()) |
| ; |
| |
| /* 1 sec reached -> stop timer, clear all LED */ |
| stop_timer(); |
| clrbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); |
| return 0; |
| } |
| |
| void reset_phy(void) |
| { |
| char *name = "GENERIC @ 0x00"; |
| |
| /* reset the phy */ |
| miiphy_reset(name, 0x0); |
| } |
| |
| #else /* #ifndef CONFIG_SPL_BUILD */ |
| static void cam_enc_4xx_set_all_led(void) |
| { |
| struct davinci_gpio *gpio = davinci_gpio_bank45; |
| |
| setbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); |
| } |
| |
| /* |
| * TIMER 0 is used for tick |
| */ |
| static struct davinci_timer *timer = |
| (struct davinci_timer *)DAVINCI_TIMER3_BASE; |
| |
| #define TIMER_LOAD_VAL 0xffffffff |
| #define TIM_CLK_DIV 16 |
| |
| static int cam_enc_4xx_timer_init(void) |
| { |
| /* We are using timer34 in unchained 32-bit mode, full speed */ |
| writel(0x0, &timer->tcr); |
| writel(0x0, &timer->tgcr); |
| writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &timer->tgcr); |
| writel(0x0, &timer->tim34); |
| writel(TIMER_LOAD_VAL, &timer->prd34); |
| writel(2 << 22, &timer->tcr); |
| return 0; |
| } |
| |
| void board_gpio_init(void) |
| { |
| struct davinci_gpio *gpio; |
| |
| cam_enc_4xx_set_all_led(); |
| cam_enc_4xx_timer_init(); |
| gpio = davinci_gpio_bank01; |
| clrbits_le32(&gpio->dir, ~0xfdfffffe); |
| /* clear LED D14 = GPIO25 */ |
| clrbits_le32(&gpio->out_data, 0x02000000); |
| gpio = davinci_gpio_bank23; |
| clrbits_le32(&gpio->dir, ~0x5ff0afef); |
| /* set GPIO61 to 1 -> intern UART0 as Console */ |
| setbits_le32(&gpio->out_data, 0x20000000); |
| /* |
| * PHY out of reset GIO 50 = 1 |
| * NAND WP off GIO 51 = 1 |
| */ |
| setbits_le32(&gpio->out_data, 0x000c0004); |
| gpio = davinci_gpio_bank45; |
| clrbits_le32(&gpio->dir, ~(0xdb2fffff) | CONFIG_CAM_ENC_LED_MASK); |
| /* |
| * clear LED: |
| * D17 = GPIO86 |
| * D11 = GPIO87 |
| * GPIO88 |
| * GPIO89 |
| * D13 = GPIO90 |
| * GPIO91 |
| */ |
| clrbits_le32(&gpio->out_data, CONFIG_CAM_ENC_LED_MASK); |
| gpio = davinci_gpio_bank67; |
| clrbits_le32(&gpio->dir, ~0x000007ff); |
| } |
| |
| /* |
| * functions for the post memory test. |
| */ |
| int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset) |
| { |
| *vstart = CONFIG_SYS_SDRAM_BASE; |
| *size = PHYS_SDRAM_1_SIZE; |
| *phys_offset = 0; |
| return 0; |
| } |
| |
| void arch_memory_failure_handle(void) |
| { |
| cam_enc_4xx_set_all_led(); |
| puts("mem failure\n"); |
| while (1) |
| ; |
| } |
| #endif |
| #if defined(CONFIG_MENU) |
| #include "menu.h" |
| |
| #define MENU_EXIT -1 |
| #define MENU_EXIT_BOOTCMD -2 |
| #define MENU_STAY 0 |
| #define MENU_MAIN 1 |
| #define MENU_UPDATE 2 |
| #define MENU_NETWORK 3 |
| #define MENU_LOAD 4 |
| |
| static int menu_start; |
| |
| #define FIT_SUBTYPE_UNKNOWN 0 |
| #define FIT_SUBTYPE_UBL_HEADER 1 |
| #define FIT_SUBTYPE_SPL_IMAGE 2 |
| #define FIT_SUBTYPE_UBOOT_IMAGE 3 |
| #define FIT_SUBTYPE_DF_ENV_IMAGE 4 |
| #define FIT_SUBTYPE_RAMDISK_IMAGE 5 |
| |
| struct fit_images_info { |
| u_int8_t type; |
| int subtype; |
| char desc[200]; |
| const void *data; |
| size_t size; |
| }; |
| |
| static struct fit_images_info imgs[10]; |
| |
| struct menu_display { |
| char title[50]; |
| int timeout; /* in sec */ |
| int id; /* MENU_* */ |
| char **menulist; |
| int (*menu_evaluate)(char *choice); |
| }; |
| |
| char *menu_main[] = { |
| "(1) Boot", |
| "(2) Update Software", |
| "(3) Reset to default setting and boot", |
| "(4) Enter U-Boot console", |
| NULL |
| }; |
| |
| char *menu_update[] = { |
| "(1) Network settings", |
| "(2) load image", |
| "(3) back to main", |
| NULL |
| }; |
| |
| char *menu_load[] = { |
| "(1) install image", |
| "(2) cancel", |
| NULL |
| }; |
| |
| char *menu_network[] = { |
| "(1) ipaddr ", |
| "(2) netmask ", |
| "(3) serverip ", |
| "(4) gatewayip", |
| "(5) tftp image name", |
| "(6) back to update software", |
| NULL |
| }; |
| |
| static void ait_menu_print(void *data) |
| { |
| printf("%s\n", (char *)data); |
| return; |
| } |
| |
| static char *menu_handle(struct menu_display *display) |
| { |
| struct menu *m; |
| int i; |
| void *choice = NULL; |
| char key[2]; |
| int ret; |
| char *s; |
| char temp[6][200]; |
| |
| m = menu_create(display->title, display->timeout, 1, ait_menu_print, |
| NULL, NULL); |
| |
| for (i = 0; display->menulist[i]; i++) { |
| sprintf(key, "%d", i + 1); |
| if (display->id == MENU_NETWORK) { |
| switch (i) { |
| case 0: |
| s = getenv("ipaddr"); |
| break; |
| case 1: |
| s = getenv("netmask"); |
| break; |
| case 2: |
| s = getenv("serverip"); |
| break; |
| case 3: |
| s = getenv("gatewayip"); |
| break; |
| case 4: |
| s = getenv("img_file"); |
| break; |
| default: |
| s = NULL; |
| break; |
| } |
| if (s) { |
| sprintf(temp[i], "%s: %s", |
| display->menulist[i], s); |
| ret = menu_item_add(m, key, temp[i]); |
| } else { |
| ret = menu_item_add(m, key, |
| display->menulist[i]); |
| } |
| } else { |
| ret = menu_item_add(m, key, display->menulist[i]); |
| } |
| |
| if (ret != 1) { |
| printf("failed to add item!"); |
| menu_destroy(m); |
| return NULL; |
| } |
| } |
| sprintf(key, "%d", 1); |
| menu_default_set(m, key); |
| |
| if (menu_get_choice(m, &choice) != 1) |
| debug("Problem picking a choice!\n"); |
| |
| menu_destroy(m); |
| |
| return choice; |
| } |
| |
| static int ait_menu_show(struct menu_display *display, int bootdelay) |
| { |
| int end = MENU_STAY; |
| char *choice; |
| |
| if ((menu_start == 0) && (display->id == MENU_MAIN)) |
| display->timeout = bootdelay; |
| else |
| display->timeout = 0; |
| |
| while (end == MENU_STAY) { |
| choice = menu_handle(display); |
| if (choice) |
| end = display->menu_evaluate(choice); |
| |
| if (end == display->id) |
| end = MENU_STAY; |
| if (display->id == MENU_MAIN) { |
| if (menu_start == 0) |
| end = MENU_EXIT_BOOTCMD; |
| else |
| display->timeout = 0; |
| } |
| } |
| return end; |
| } |
| |
| static int ait_writeublheader(void) |
| { |
| char s[20]; |
| unsigned long i; |
| int ret; |
| |
| for (i = CONFIG_SYS_NAND_BLOCK_SIZE; |
| i < CONFIG_SYS_NAND_U_BOOT_OFFS; |
| i += CONFIG_SYS_NAND_BLOCK_SIZE) { |
| sprintf(s, "%lx", i); |
| ret = setenv("header_addr", s); |
| if (ret == 0) |
| ret = run_command("run img_writeheader", 0); |
| if (ret != 0) |
| break; |
| } |
| return ret; |
| } |
| |
| static int ait_menu_install_images(void) |
| { |
| int ret = 0; |
| int count = 0; |
| char s[100]; |
| char *t; |
| |
| /* |
| * possible image types: |
| * FIT_SUBTYPE_UNKNOWN |
| * FIT_SUBTYPE_UBL_HEADER |
| * FIT_SUBTYPE_SPL_IMAGE |
| * FIT_SUBTYPE_UBOOT_IMAGE |
| * FIT_SUBTYPE_DF_ENV_IMAGE |
| * FIT_SUBTYPE_RAMDISK_IMAGE |
| * |
| * use Envvariables: |
| * img_addr_r: image start addr |
| * header_addr: addr where to write to UBL header |
| * img_writeheader: write ubl header to nand |
| * img_writespl: write spl to nand |
| * img_writeuboot: write uboot to nand |
| * img_writedfenv: write default environment to ubi volume |
| * img_volume: which ubi volume should be updated with img_writeramdisk |
| * filesize: size of data for updating ubi volume |
| * img_writeramdisk: write ramdisk to ubi volume |
| */ |
| |
| while (imgs[count].type != IH_TYPE_INVALID) { |
| printf("Installing %s\n", |
| genimg_get_type_name(imgs[count].type)); |
| sprintf(s, "%p", imgs[count].data); |
| setenv("img_addr_r", s); |
| sprintf(s, "%lx", (unsigned long)imgs[count].size); |
| setenv("filesize", s); |
| switch (imgs[count].subtype) { |
| case FIT_SUBTYPE_DF_ENV_IMAGE: |
| ret = run_command("run img_writedfenv", 0); |
| break; |
| case FIT_SUBTYPE_RAMDISK_IMAGE: |
| t = getenv("img_volume"); |
| if (!t) { |
| ret = setenv("img_volume", "rootfs1"); |
| } else { |
| /* switch to other volume */ |
| if (strncmp(t, "rootfs1", 7) == 0) |
| ret = setenv("img_volume", "rootfs2"); |
| else |
| ret = setenv("img_volume", "rootfs1"); |
| } |
| if (ret != 0) |
| break; |
| |
| ret = run_command("run img_writeramdisk", 0); |
| break; |
| case FIT_SUBTYPE_SPL_IMAGE: |
| ret = run_command("run img_writespl", 0); |
| break; |
| case FIT_SUBTYPE_UBL_HEADER: |
| ret = ait_writeublheader(); |
| break; |
| case FIT_SUBTYPE_UBOOT_IMAGE: |
| ret = run_command("run img_writeuboot", 0); |
| break; |
| default: |
| /* not supported type */ |
| break; |
| } |
| count++; |
| } |
| /* now save dvn_* and img_volume env vars to new values */ |
| if (ret == 0) { |
| t = getenv("x_dvn_boot_vers"); |
| if (t) |
| setenv("dvn_boot_vers", t); |
| |
| t = getenv("x_dvn_app_vers"); |
| if (t) |
| setenv("dvn_boot_vers", t); |
| |
| setenv("x_dvn_boot_vers", NULL); |
| setenv("x_dvn_app_vers", NULL); |
| ret = run_command("run savenewvers", 0); |
| } |
| |
| return ret; |
| } |
| |
| static int ait_menu_evaluate_load(char *choice) |
| { |
| if (!choice) |
| return -1; |
| |
| switch (choice[1]) { |
| case '1': |
| /* install image */ |
| ait_menu_install_images(); |
| break; |
| case '2': |
| /* cancel, back to main */ |
| setenv("x_dvn_boot_vers", NULL); |
| setenv("x_dvn_app_vers", NULL); |
| break; |
| } |
| |
| return MENU_MAIN; |
| } |
| |
| struct menu_display ait_load = { |
| .title = "AIT load image", |
| .timeout = 0, |
| .id = MENU_LOAD, |
| .menulist = menu_load, |
| .menu_evaluate = ait_menu_evaluate_load, |
| }; |
| |
| static void ait_menu_read_env(char *name) |
| { |
| char output[CONFIG_SYS_CBSIZE]; |
| char cbuf[CONFIG_SYS_CBSIZE]; |
| int readret; |
| int ret; |
| |
| sprintf(output, "%s old: %s value: ", name, getenv(name)); |
| memset(cbuf, 0, CONFIG_SYS_CBSIZE); |
| readret = cli_readline_into_buffer(output, cbuf, 0); |
| |
| if (readret >= 0) { |
| ret = setenv(name, cbuf); |
| if (ret) { |
| printf("Error setting %s\n", name); |
| return; |
| } |
| } |
| return; |
| } |
| |
| static int ait_menu_evaluate_network(char *choice) |
| { |
| if (!choice) |
| return MENU_MAIN; |
| |
| switch (choice[1]) { |
| case '1': |
| ait_menu_read_env("ipaddr"); |
| break; |
| case '2': |
| ait_menu_read_env("netmask"); |
| break; |
| case '3': |
| ait_menu_read_env("serverip"); |
| break; |
| case '4': |
| ait_menu_read_env("gatewayip"); |
| break; |
| case '5': |
| ait_menu_read_env("img_file"); |
| break; |
| case '6': |
| return MENU_UPDATE; |
| break; |
| } |
| |
| return MENU_STAY; |
| } |
| |
| struct menu_display ait_network = { |
| .title = "AIT network settings", |
| .timeout = 0, |
| .id = MENU_NETWORK, |
| .menulist = menu_network, |
| .menu_evaluate = ait_menu_evaluate_network, |
| }; |
| |
| static int fit_get_subtype(const void *fit, int noffset, char **subtype) |
| { |
| int len; |
| |
| *subtype = (char *)fdt_getprop(fit, noffset, "subtype", &len); |
| if (*subtype == NULL) |
| return -1; |
| |
| return 0; |
| } |
| |
| static int ait_subtype_nr(char *subtype) |
| { |
| int ret = FIT_SUBTYPE_UNKNOWN; |
| |
| if (!strncmp("ublheader", subtype, strlen("ublheader"))) |
| return FIT_SUBTYPE_UBL_HEADER; |
| if (!strncmp("splimage", subtype, strlen("splimage"))) |
| return FIT_SUBTYPE_SPL_IMAGE; |
| if (!strncmp("ubootimage", subtype, strlen("ubootimage"))) |
| return FIT_SUBTYPE_UBOOT_IMAGE; |
| if (!strncmp("dfenvimage", subtype, strlen("dfenvimage"))) |
| return FIT_SUBTYPE_DF_ENV_IMAGE; |
| |
| return ret; |
| } |
| |
| static int ait_menu_check_image(void) |
| { |
| char *s; |
| unsigned long fit_addr; |
| void *addr; |
| int format; |
| char *desc; |
| char *subtype; |
| int images_noffset; |
| int noffset; |
| int ndepth; |
| int count = 0; |
| int ret; |
| int i; |
| int found_uboot = -1; |
| int found_ramdisk = -1; |
| |
| memset(imgs, 0, sizeof(imgs)); |
| s = getenv("fit_addr_r"); |
| fit_addr = s ? (unsigned long)simple_strtol(s, NULL, 16) : \ |
| CONFIG_BOARD_IMG_ADDR_R; |
| |
| addr = (void *)fit_addr; |
| /* check if it is a FIT image */ |
| format = genimg_get_format(addr); |
| if (format != IMAGE_FORMAT_FIT) |
| return -EINVAL; |
| |
| if (!fit_check_format(addr)) |
| return -EINVAL; |
| |
| /* print the FIT description */ |
| ret = fit_get_desc(addr, 0, &desc); |
| printf("FIT description: "); |
| if (ret) |
| printf("unavailable\n"); |
| else |
| printf("%s\n", desc); |
| |
| /* find images */ |
| images_noffset = fdt_path_offset(addr, FIT_IMAGES_PATH); |
| if (images_noffset < 0) { |
| printf("Can't find images parent node '%s' (%s)\n", |
| FIT_IMAGES_PATH, fdt_strerror(images_noffset)); |
| return -EINVAL; |
| } |
| |
| /* Process its subnodes, print out component images details */ |
| for (ndepth = 0, count = 0, |
| noffset = fdt_next_node(addr, images_noffset, &ndepth); |
| (noffset >= 0) && (ndepth > 0); |
| noffset = fdt_next_node(addr, noffset, &ndepth)) { |
| if (ndepth == 1) { |
| /* |
| * Direct child node of the images parent node, |
| * i.e. component image node. |
| */ |
| printf("Image %u (%s)\n", count, |
| fit_get_name(addr, noffset, NULL)); |
| |
| fit_image_print(addr, noffset, ""); |
| |
| fit_image_get_type(addr, noffset, |
| &imgs[count].type); |
| /* Mandatory properties */ |
| ret = fit_get_desc(addr, noffset, &desc); |
| printf("Description: "); |
| if (ret) |
| printf("unavailable\n"); |
| else |
| printf("%s\n", desc); |
| |
| ret = fit_get_subtype(addr, noffset, &subtype); |
| printf("Subtype: "); |
| if (ret) { |
| printf("unavailable\n"); |
| } else { |
| imgs[count].subtype = ait_subtype_nr(subtype); |
| printf("%s %d\n", subtype, |
| imgs[count].subtype); |
| } |
| |
| sprintf(imgs[count].desc, "%s", desc); |
| |
| ret = fit_image_get_data(addr, noffset, |
| &imgs[count].data, |
| &imgs[count].size); |
| |
| printf("Data Size: "); |
| if (ret) |
| printf("unavailable\n"); |
| else |
| genimg_print_size(imgs[count].size); |
| printf("Data @ %p\n", imgs[count].data); |
| count++; |
| } |
| } |
| |
| for (i = 0; i < count; i++) { |
| if (imgs[i].subtype == FIT_SUBTYPE_UBOOT_IMAGE) |
| found_uboot = i; |
| if (imgs[i].type == IH_TYPE_RAMDISK) { |
| found_ramdisk = i; |
| imgs[i].subtype = FIT_SUBTYPE_RAMDISK_IMAGE; |
| } |
| } |
| |
| /* dvn_* env var update, if the FIT descriptors are different */ |
| if (found_uboot >= 0) { |
| s = getenv("dvn_boot_vers"); |
| if (s) { |
| ret = strcmp(s, imgs[found_uboot].desc); |
| if (ret != 0) { |
| setenv("x_dvn_boot_vers", |
| imgs[found_uboot].desc); |
| } else { |
| found_uboot = -1; |
| printf("no new uboot version\n"); |
| } |
| } else { |
| setenv("dvn_boot_vers", imgs[found_uboot].desc); |
| } |
| } |
| if (found_ramdisk >= 0) { |
| s = getenv("dvn_app_vers"); |
| if (s) { |
| ret = strcmp(s, imgs[found_ramdisk].desc); |
| if (ret != 0) { |
| setenv("x_dvn_app_vers", |
| imgs[found_ramdisk].desc); |
| } else { |
| found_ramdisk = -1; |
| printf("no new ramdisk version\n"); |
| } |
| } else { |
| setenv("dvn_app_vers", imgs[found_ramdisk].desc); |
| } |
| } |
| if ((found_uboot == -1) && (found_ramdisk == -1)) |
| return -EINVAL; |
| |
| return 0; |
| } |
| |
| static int ait_menu_evaluate_update(char *choice) |
| { |
| int ret; |
| |
| if (!choice) |
| return MENU_MAIN; |
| |
| switch (choice[1]) { |
| case '1': |
| return ait_menu_show(&ait_network, 0); |
| break; |
| case '2': |
| /* load image */ |
| ret = run_command("run load_img", 0); |
| printf("ret: %d\n", ret); |
| if (ret) |
| return MENU_UPDATE; |
| |
| ret = ait_menu_check_image(); |
| if (ret) |
| return MENU_UPDATE; |
| |
| return ait_menu_show(&ait_load, 0); |
| break; |
| case '3': |
| return MENU_MAIN; |
| break; |
| |
| } |
| |
| return MENU_MAIN; |
| } |
| |
| struct menu_display ait_update = { |
| .title = "AIT Update Software", |
| .timeout = 0, |
| .id = MENU_UPDATE, |
| .menulist = menu_update, |
| .menu_evaluate = ait_menu_evaluate_update, |
| }; |
| |
| static int ait_menu_evaluate_main(char *choice) |
| { |
| if (!choice) |
| return MENU_STAY; |
| |
| menu_start = 1; |
| switch (choice[1]) { |
| case '1': |
| /* run bootcmd */ |
| return MENU_EXIT_BOOTCMD; |
| break; |
| case '2': |
| return ait_menu_show(&ait_update, 0); |
| break; |
| case '3': |
| /* reset to default settings */ |
| setenv("app_reset", "yes"); |
| return MENU_EXIT_BOOTCMD; |
| break; |
| case '4': |
| /* u-boot shell */ |
| return MENU_EXIT; |
| break; |
| } |
| |
| return MENU_EXIT; |
| } |
| |
| struct menu_display ait_main = { |
| .title = "AIT Main", |
| .timeout = CONFIG_BOOTDELAY, |
| .id = MENU_MAIN, |
| .menulist = menu_main, |
| .menu_evaluate = ait_menu_evaluate_main, |
| }; |
| |
| int menu_show(int bootdelay) |
| { |
| int ret; |
| |
| run_command("run saveparms", 0); |
| ret = ait_menu_show(&ait_main, bootdelay); |
| run_command("run restoreparms", 0); |
| |
| if (ret == MENU_EXIT_BOOTCMD) |
| return 0; |
| |
| return MENU_EXIT; |
| } |
| |
| void menu_display_statusline(struct menu *m) |
| { |
| char *s1, *s2; |
| |
| s1 = getenv("x_dvn_boot_vers"); |
| if (!s1) |
| s1 = getenv("dvn_boot_vers"); |
| |
| s2 = getenv("x_dvn_app_vers"); |
| if (!s2) |
| s2 = getenv("dvn_app_vers"); |
| |
| printf("State: dvn_boot_vers: %s dvn_app_vers: %s\n", s1, s2); |
| return; |
| } |
| #endif |