From: Grazvydas Ignotas Date: Tue, 27 Dec 2011 15:08:02 +0000 (+0200) Subject: pandora: add a boot menu and it's helpers X-Git-Tag: sz_175~19 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be180f2324bd002433ed4fc0ef4b66ff761c17a9;p=pandora-u-boot.git pandora: add a boot menu and it's helpers --- diff --git a/board/pandora/Makefile b/board/pandora/Makefile index 4b4870e5811..8ebad1f850c 100644 --- a/board/pandora/Makefile +++ b/board/pandora/Makefile @@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).o -COBJS := pandora.o video.o +COBJS := pandora.o video.o menu.o SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/pandora/menu.c b/board/pandora/menu.c new file mode 100644 index 00000000000..15f5306b60d --- /dev/null +++ b/board/pandora/menu.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include +#include +#include +#include + +/* game buttons as in GPIO bank 4 */ +#define BTN_R GPIO9 +#define BTN_UP GPIO14 +#define BTN_DOWN GPIO7 +#define BTN_G2 GPIO15 +#define BTN_G3 GPIO10 + +struct menu_item { + const char *name; + int (*handler)(struct menu_item *item); + char *cmd; +}; + +static struct menu_item *menu_items[24]; +static int menu_item_count; + +static int do_cmd(const char *fmt, ...) +{ + char cmdbuff[256]; + va_list args; + + va_start(args, fmt); + vsprintf(cmdbuff, fmt, args); + va_end(args); + + return !parse_string_outer(cmdbuff, + FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); +} + +static u32 menu_wait_for_input(int down) +{ + struct gpio *gpio4_base = (struct gpio *)OMAP34XX_GPIO4_BASE; + u32 btns; + + while (1) { + btns = ~readl(&gpio4_base->datain) & + (BTN_UP|BTN_DOWN|BTN_G2|BTN_G3); + if (!btns == !down) + break; + udelay(5000); + } + + return btns; +} + +static int menu_do_default(struct menu_item *item) +{ + return 1; +} + +static int menu_do_poweroff(struct menu_item *item) +{ + u8 d; + + printf("power off.\n"); + + twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER, &d, TWL4030_PM_MASTER_P1_SW_EVENTS); + d |= TWL4030_PM_MASTER_SW_EVENTS_DEVOFF; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, d, TWL4030_PM_MASTER_P1_SW_EVENTS); + + return 0; +} + +static int menu_do_usb_serial(struct menu_item *item) +{ + do_cmd("dcache off"); /* doesn't work with dcache */ + do_cmd("usbinit"); + printf("Switched to USB serial.\n"); + + setenv("stdout", "usbtty"); + setenv("stdin", "usbtty"); + setenv("stderr", "usbtty"); + setenv("bootcmd", ""); + return 1; +} + +static int menu_do_serial(struct menu_item *item) +{ + printf("Switched to serial.\n"); + + setenv("stdout", "serial"); + setenv("bootcmd", ""); + return 1; +} + +static int menu_do_script_cmd(struct menu_item *item) +{ + int failed = 0; + + if (item->cmd == NULL || !do_cmd(item->cmd)) + failed = 1; + + printf("script %s.\n", failed ? "failed" : "finished"); + flush_dcache_all(); + menu_wait_for_input(0); + menu_wait_for_input(1); + return 0; +} + +static void add_menu_item(const char *name, + int (*handler)(struct menu_item *), const char *cmd) +{ + struct menu_item *mitem; + + mitem = malloc(sizeof(*mitem)); + if (mitem == NULL) + return; + mitem->name = strdup(name); + mitem->handler = handler; + mitem->cmd = strdup(cmd); + + if (menu_item_count < ARRAY_SIZE(menu_items)) + menu_items[menu_item_count++] = mitem; +} + +static char *bootmenu_next_ctl(char *p) +{ + while (*p && *p != '|' && *p != '\r' && *p != '\n') + p++; + + return p; +} + +static char *bootmenu_skip_blanks(char *p) +{ + while (*p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) + p++; + + return p; +} + +static char *bootmenu_skip_line(char *p) +{ + while (*p && *p != '\r' && *p != '\n') + p++; + + return p; +} + +static void parse_bootmenu(char *buf) +{ + char *p = buf, *name, *cmd; + int i; + + for (i = 1; ; i++) + { + p = bootmenu_skip_blanks(p); + if (*p == 0) + break; + if (*p == '#') { + p = bootmenu_skip_line(p); + continue; + } + + name = p; + p = bootmenu_next_ctl(p); + if (*p != '|') { + printf("bootmenu.txt: invalid line ~%d\n", i); + p = bootmenu_skip_line(p); + continue; + } + *p++ = 0; + + cmd = p; + p = bootmenu_skip_line(p); + if (*p != 0) + *p++ = 0; + + add_menu_item(name, menu_do_script_cmd, cmd); + } +} + +static struct menu_item default_menu_items[] = { + { "default boot", menu_do_default, }, + { "power off", menu_do_poweroff, }, + { "USB serial prompt", menu_do_usb_serial, }, + { "serial prompt", menu_do_serial, }, +}; + +static void menu_init(void) +{ + const char *check_format1 = "%sload mmc1 0:%d ${loadaddr} boot.scr 4"; + const char *check_format2 = "%sload mmc1 0:%d ${loadaddr} boot.txt 4"; + const char *run_format1 = "%sload mmc1 0:%d ${loadaddr} boot.scr;source ${loadaddr}"; + const char *run_format2 = "mw.l ${loadaddr} 0 1024;%sload mmc1 0:%d ${loadaddr} boot.txt;" + "ssource ${loadaddr}"; + disk_partition_t part_info; + block_dev_desc_t *dev_desc; + char tmp_name[32], tmp_cmd[128]; + int i; + + for (i = 0; i < 2; i++) + menu_items[i] = &default_menu_items[i]; + menu_item_count = i; + + if (!do_cmd("mmc rescan")) + goto no_mmc; + + dev_desc = get_dev("mmc1", 0); + if (dev_desc == NULL) { + printf("dev desc null\n"); + goto no_mmc; + } + + /* kill stdout while we search for bootfiles */ + setenv("stdout", "nulldev"); + + for (i = 1; menu_item_count < ARRAY_SIZE(menu_items); i++) { + if (get_partition_info(dev_desc, i, &part_info)) + break; + if (do_cmd("fatls mmc1 0:%d", i)) { + if (do_cmd(check_format1, "fat", i)) { + sprintf(tmp_cmd, run_format1, "fat", i); + goto found; + } + if (do_cmd(check_format2, "fat", i)) { + sprintf(tmp_cmd, run_format2, "fat", i); + goto found; + } + continue; + } + if (do_cmd("ext2ls mmc1 0:%d", i)) { + if (do_cmd(check_format1, "ext2", i)) { + sprintf(tmp_cmd, run_format1, "ext2", i); + goto found; + } + if (do_cmd(check_format2, "ext2", i)) { + sprintf(tmp_cmd, run_format2, "ext2", i); + goto found; + } + continue; + } + continue; + +found: + sprintf(tmp_name, "boot from SD1:%d", i); + add_menu_item(tmp_name, menu_do_script_cmd, tmp_cmd); + } + +no_mmc: + setenv("stdout", "serial"); + + if (do_cmd("ubi part boot && ubifsmount boot")) { + ulong addr = getenv_ulong("loadaddr", 16, 0); + if ((int)addr < (int)0x90000000) { + if (do_cmd("ubifsload ${loadaddr} bootmenu.txt")) { + ulong size = getenv_ulong("filesize", 16, 0); + *(char *)(addr + size) = 0; + parse_bootmenu((char *)addr); + } + } + } + + for (i = 2; i < ARRAY_SIZE(default_menu_items); i++) { + if (menu_item_count >= ARRAY_SIZE(menu_items)) + break; + menu_items[menu_item_count++] = &default_menu_items[i]; + } + + setenv("stdout", "lcd"); +} + +static int boot_menu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int i, sel = 0, max_sel; + int tl_row; + u32 btns; + + menu_init(); + + tl_row = panel_info.vl_row / 16 / 2 - (menu_item_count + 2) / 2; + max_sel = menu_item_count - 1; + + console_col = 3; + console_row = tl_row; + lcd_printf("Boot menu"); + + while (1) + { + for (i = 0; i < menu_item_count; i++) { + console_col = 3; + console_row = tl_row + 2 + i; + lcd_printf(menu_items[i]->name); + } + + for (i = 0; i < menu_item_count; i++) { + console_col = 1; + console_row = tl_row + 2 + i; + lcd_printf(i == sel ? ">" : " "); + } + + flush_dcache_all(); + menu_wait_for_input(0); + btns = menu_wait_for_input(1); + if (btns & BTN_UP) { + sel--; + if (sel < 0) + sel = max_sel; + } + else if (btns & BTN_DOWN) { + sel++; + if (sel > max_sel) + sel = 0; + } + else { + do_cmd("cls"); + if (menu_items[sel]->handler(menu_items[sel])) + break; + do_cmd("cls"); + } + } + + return 0; +} + +U_BOOT_CMD( + pmenu, 1, 1, boot_menu, + "show pandora's boot menu", + "" +); + +/* helpers */ +static int do_ssource(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ulong addr; + + if (argc < 2) + return 1; + + addr = simple_strtoul(argv[1], NULL, 16); + + printf("## Executing plain script at %08lx\n", addr); + return parse_string_outer((char *)addr, FLAG_PARSE_SEMICOLON); +} + +U_BOOT_CMD( + ssource, 2, 0, do_ssource, + "run script from memory (no header)", + "" +); + +static int do_usbinit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + extern int drv_usbtty_init(void); + static int usbinit_done; + if (!usbinit_done) { + usbinit_done = 1; + return !drv_usbtty_init(); + } + return 0; +} + +U_BOOT_CMD( + usbinit, 1, 0, do_usbinit, + "initialize USB", + "" +); + +static int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + menu_do_poweroff(NULL); + return 0; +} + +U_BOOT_CMD( + poweroff, 1, 0, do_poweroff, + "power off this device", + "" +); diff --git a/board/pandora/pandora.c b/board/pandora/pandora.c index 82b71a75efc..d942b095e24 100644 --- a/board/pandora/pandora.c +++ b/board/pandora/pandora.c @@ -120,6 +120,10 @@ int misc_init_r(void) dieid_num_r(); + /* show boot menu? */ + if (!gpio_get_value(105)) + setenv("preboot", "pmenu"); + return 0; } diff --git a/include/configs/omap3_pandora.h b/include/configs/omap3_pandora.h index f2b39966a10..de69291d4ff 100644 --- a/include/configs/omap3_pandora.h +++ b/include/configs/omap3_pandora.h @@ -65,7 +65,11 @@ #define CONFIG_LCD 1 #define LCD_BPP LCD_COLOR16 #define CONFIG_SYS_WHITE_ON_BLACK 1 + +/* used by menu code */ +#define CONFIG_PREBOOT #define CONFIG_SYS_CONSOLE_IS_IN_ENV 1 +#define CONFIG_SYS_DEVICE_NULLDEV 1 /* * Hardware drivers @@ -174,7 +178,7 @@ #endif /* Environment information */ -#define CONFIG_BOOTDELAY 1 +#define CONFIG_BOOTDELAY 0 #define CONFIG_EXTRA_ENV_SETTINGS \ "usbtty=cdc_acm\0" \ @@ -184,11 +188,13 @@ "mtdparts=" MTDPARTS_DEFAULT "\0" \ #define CONFIG_BOOTCOMMAND \ - "if mmc rescan && fatload mmc1 0 ${loadaddr} autoboot.scr || " \ - "ext2load mmc1 0 ${loadaddr} autoboot.scr; then " \ - "source ${loadaddr}; " \ + "if mmc rescan && fatload mmc1 0 ${loadaddr} autoboot.txt || " \ + "ext2load mmc1 0 ${loadaddr} autoboot.txt; then " \ + "ssource ${loadaddr}; " \ "fi; " \ - "ubi part boot && ubifsmount boot && ubifsload ${loadaddr} uImage && bootm ${loadaddr}" + "ubi part boot && ubifsmount boot && ubifsload ${loadaddr} uImage && bootm ${loadaddr}; " \ + "setenv stdout lcd; echo Failed to load kernel, you may need to reflash the firmware.; " \ + "pmenu" #define CONFIG_AUTO_COMPLETE 1 /*