summaryrefslogtreecommitdiffstats
path: root/meta/packages/uboot/u-boot-mkimage-openmoko-native/boot-menu.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/packages/uboot/u-boot-mkimage-openmoko-native/boot-menu.patch')
-rw-r--r--meta/packages/uboot/u-boot-mkimage-openmoko-native/boot-menu.patch769
1 files changed, 769 insertions, 0 deletions
diff --git a/meta/packages/uboot/u-boot-mkimage-openmoko-native/boot-menu.patch b/meta/packages/uboot/u-boot-mkimage-openmoko-native/boot-menu.patch
new file mode 100644
index 0000000000..352967ae06
--- /dev/null
+++ b/meta/packages/uboot/u-boot-mkimage-openmoko-native/boot-menu.patch
@@ -0,0 +1,769 @@
1board/neo1973/bootmenu.c: simple configurable boot menu
2board/neo1973/neo1973.c (neo1973_new_second): return 1 if a new second has
3 started since the last call
4board/neo1973/neo1973.c (neo1973_on_key_pressed): return 1 if the $POWER key is
5 pressed
6board/neo1973/neo1973.c (board_late_init): make use of neo1973_new_second and
7 neo1973_on_key_pressed
8board/neo1973/neo1973.h: added function prototypes
9u-boot/board/neo1973/neo1973.c (board_late_init): enter the boot menu when
10 "AUX" was pressed at least half the time
11u-boot/board/neo1973/neo1973.c (board_late_init): minor code cleanup
12u-boot/common/console.c, include/console.h: added "console_poll_hook" to be
13 called when waiting for console in put in "getc" and "tstc"
14board/neo1973/neo1973.c (board_late_init): poll for the boot menu also on RAM
15 boot, reset, or unknown cause
16board/neo1973/neo1973.c (board_late_init): don't look for the power key if
17 woken up by the charger
18board/neo1973/neo1973.h, board/neo1973/neo1973.c, board/neo1973/bootmenu.c:
19 renamed neo1973_911_key_pressed to neo1973_aux_key_pressed
20
21- Werner Almesberger <werner@openmoko.org>
22
23Index: u-boot/board/neo1973/common/bootmenu.c
24===================================================================
25--- /dev/null
26+++ u-boot/board/neo1973/common/bootmenu.c
27@@ -0,0 +1,120 @@
28+/*
29+ * bootmenu.c - Boot menu
30+ *
31+ * Copyright (C) 2006-2007 by OpenMoko, Inc.
32+ * Written by Werner Almesberger <werner@openmoko.org>
33+ * All Rights Reserved
34+ *
35+ * This program is free software; you can redistribute it and/or modify
36+ * it under the terms of the GNU General Public License as published by
37+ * the Free Software Foundation; either version 2 of the License, or
38+ * (at your option) any later version.
39+ *
40+ * This program is distributed in the hope that it will be useful,
41+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
42+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43+ * GNU General Public License for more details.
44+ *
45+ * You should have received a copy of the GNU General Public License along
46+ * with this program; if not, write to the Free Software Foundation, Inc.,
47+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
48+ */
49+
50+
51+#include <common.h>
52+#include <environment.h>
53+#include <bootmenu.h>
54+#include <asm/atomic.h>
55+
56+#ifdef CONFIG_USBD_DFU
57+#include "usbdcore.h"
58+#include "usb_dfu.h"
59+#endif
60+
61+#include "neo1973.h"
62+
63+
64+#define DEBOUNCE_LOOPS 1000 /* wild guess */
65+
66+
67+static int debounce(int (*fn)(void), int *last)
68+{
69+ int on, i;
70+
71+again:
72+ on = fn();
73+ if (on != *last)
74+ for (i = DEBOUNCE_LOOPS; i; i--)
75+ if (on != fn())
76+ goto again;
77+ *last = on;
78+ return on;
79+}
80+
81+
82+static int aux_key(void *user)
83+{
84+ static int last_aux = -1;
85+
86+ return debounce(neo1973_aux_key_pressed, &last_aux);
87+}
88+
89+
90+static int on_key(void *user)
91+{
92+ static int last_on = -1;
93+
94+ return debounce(neo1973_on_key_pressed, &last_on);
95+}
96+
97+
98+static void factory_reset(void *user)
99+{
100+ default_env();
101+ run_command("dynpart", 0);
102+ run_command("bootd", 0);
103+}
104+
105+
106+static int seconds(void *user)
107+{
108+ return neo1973_new_second();
109+}
110+
111+
112+static int system_idle(void)
113+{
114+#ifdef CONFIG_USBD_DFU
115+ if (system_dfu_state)
116+ return *system_dfu_state == DFU_STATE_appIDLE;
117+#endif
118+ return 1;
119+}
120+
121+
122+static void poweroff_if_idle(void *user)
123+{
124+ unsigned long flags;
125+
126+ local_irq_save(flags);
127+ if (system_idle())
128+ neo1973_poweroff();
129+ local_irq_restore(flags);
130+}
131+
132+
133+static struct bootmenu_setup bootmenu_setup = {
134+ .next_key = aux_key,
135+ .enter_key = on_key,
136+ .seconds = seconds,
137+ .idle_action = poweroff_if_idle,
138+};
139+
140+
141+void neo1973_bootmenu(void)
142+{
143+ bootmenu_add("Boot", NULL, "bootd");
144+ bootmenu_init(&bootmenu_setup);
145+ bootmenu_add("Factory reset", factory_reset, NULL);
146+ bootmenu();
147+}
148Index: u-boot/board/neo1973/gta01/gta01.c
149===================================================================
150--- u-boot.orig/board/neo1973/gta01/gta01.c
151+++ u-boot/board/neo1973/gta01/gta01.c
152@@ -229,10 +229,15 @@ int board_late_init(void)
153 extern unsigned char booted_from_nand;
154 unsigned char tmp;
155 char buf[32];
156+ int menu_vote = 0; /* <= 0: no, > 0: yes */
157+ int seconds = 0;
158
159 /* Initialize the Power Management Unit with a safe register set */
160 pcf50606_init();
161
162+ /* if there's no other reason, must be regular reset */
163+ neo1973_wakeup_cause = NEO1973_WAKEUP_RESET;
164+
165 if (!booted_from_nand)
166 goto woken_by_reset;
167
168@@ -242,45 +247,41 @@ int board_late_init(void)
169 setenv("pcf50606_int1", buf);
170
171 if (tmp & PCF50606_INT1_ALARM) {
172- /* we've been woken up by RTC alarm or charger insert, boot */
173+ /* we've been woken up by RTC alarm, boot */
174 neo1973_wakeup_cause = NEO1973_WAKEUP_ALARM;
175 goto continue_boot;
176 }
177 if (tmp & PCF50606_INT1_EXTONR) {
178+ /* we've been woken up by charger insert */
179 neo1973_wakeup_cause = NEO1973_WAKEUP_CHARGER;
180 }
181
182 if (tmp & PCF50606_INT1_ONKEYF) {
183- int seconds = 0;
184- neo1973_wakeup_cause = NEO1973_WAKEUP_POWER_KEY;
185 /* we've been woken up by a falling edge of the onkey */
186+ neo1973_wakeup_cause = NEO1973_WAKEUP_POWER_KEY;
187+ }
188
189- /* we can't just setenv(bootdelay,-1) because that would
190- * accidentially become permanent if the user does saveenv */
191- if (neo1973_911_key_pressed())
192- nobootdelay = 1;
193-
194- while (1) {
195- u_int8_t int1, oocs;
196-
197- oocs = pcf50606_reg_read(PCF50606_REG_OOCS);
198- if (oocs & PFC50606_OOCS_ONKEY)
199- break;
200-
201- int1 = pcf50606_reg_read(PCF50606_REG_INT1);
202- if (int1 & PCF50606_INT1_SECOND)
203- seconds++;
204-
205- if (seconds >= POWER_KEY_SECONDS)
206- goto continue_boot;
207- }
208- /* Power off if minimum number of seconds not reached */
209- neo1973_poweroff();
210+ if (neo1973_wakeup_cause == NEO1973_WAKEUP_CHARGER) {
211+ /* if we still think it was only a charger insert, boot */
212+ goto continue_boot;
213 }
214
215 woken_by_reset:
216- /* if there's no other reason, must be regular reset */
217- neo1973_wakeup_cause = NEO1973_WAKEUP_RESET;
218+
219+ while (neo1973_wakeup_cause == NEO1973_WAKEUP_RESET ||
220+ neo1973_on_key_pressed()) {
221+ if (neo1973_aux_key_pressed())
222+ menu_vote++;
223+ else
224+ menu_vote--;
225+
226+ if (neo1973_new_second())
227+ seconds++;
228+ if (seconds >= POWER_KEY_SECONDS)
229+ goto continue_boot;
230+ }
231+ /* Power off if minimum number of seconds not reached */
232+ neo1973_poweroff();
233
234 continue_boot:
235 jbt6k74_init();
236@@ -304,6 +305,11 @@ continue_boot:
237 }
238 #endif
239
240+ if (menu_vote > 0) {
241+ neo1973_bootmenu();
242+ nobootdelay = 1;
243+ }
244+
245 return 0;
246 }
247
248@@ -369,7 +375,17 @@ void neo1973_vibrator(int on)
249 #endif
250 }
251
252-int neo1973_911_key_pressed(void)
253+int neo1973_new_second(void)
254+{
255+ return pcf50606_reg_read(PCF50606_REG_INT1) & PCF50606_INT1_SECOND;
256+}
257+
258+int neo1973_on_key_pressed(void)
259+{
260+ return !(pcf50606_reg_read(PCF50606_REG_OOCS) & PFC50606_OOCS_ONKEY);
261+}
262+
263+int neo1973_aux_key_pressed(void)
264 {
265 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
266 if (gpio->GPFDAT & (1 << 6))
267Index: u-boot/board/neo1973/gta01/Makefile
268===================================================================
269--- u-boot.orig/board/neo1973/gta01/Makefile
270+++ u-boot/board/neo1973/gta01/Makefile
271@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk
272
273 LIB = lib$(BOARD).a
274
275-OBJS := gta01.o pcf50606.o ../common/cmd_neo1973.o ../common/jbt6k74.o ../common/udc.o
276+OBJS := gta01.o pcf50606.o ../common/cmd_neo1973.o ../common/jbt6k74.o ../common/udc.o ../common/bootmenu.o
277 SOBJS := ../common/lowlevel_init.o
278
279 .PHONY: all
280Index: u-boot/board/neo1973/common/neo1973.h
281===================================================================
282--- u-boot.orig/board/neo1973/common/neo1973.h
283+++ u-boot/board/neo1973/common/neo1973.h
284@@ -29,4 +29,10 @@ int neo1973_911_key_pressed(void);
285 const char *neo1973_get_charge_status(void);
286 int neo1973_set_charge_mode(enum neo1973_charger_cmd cmd);
287
288+int neo1973_new_second(void);
289+int neo1973_on_key_pressed(void);
290+int neo1973_aux_key_pressed(void);
291+
292+void neo1973_bootmenu(void);
293+
294 #endif
295Index: u-boot/common/console.c
296===================================================================
297--- u-boot.orig/common/console.c
298+++ u-boot/common/console.c
299@@ -160,8 +160,12 @@ void fprintf (int file, const char *fmt,
300
301 /** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/
302
303+void (*console_poll_hook)(int activity);
304+
305 int getc (void)
306 {
307+ while (console_poll_hook && !tstc());
308+
309 if (gd->flags & GD_FLG_DEVINIT) {
310 /* Get from the standard input */
311 return fgetc (stdin);
312@@ -171,7 +175,7 @@ int getc (void)
313 return serial_getc ();
314 }
315
316-int tstc (void)
317+static int do_tstc (void)
318 {
319 if (gd->flags & GD_FLG_DEVINIT) {
320 /* Test the standard input */
321@@ -182,6 +186,16 @@ int tstc (void)
322 return serial_tstc ();
323 }
324
325+int tstc (void)
326+{
327+ int ret;
328+
329+ ret = do_tstc();
330+ if (console_poll_hook)
331+ console_poll_hook(ret);
332+ return ret;
333+}
334+
335 void putc (const char c)
336 {
337 #ifdef CONFIG_SILENT_CONSOLE
338Index: u-boot/include/console.h
339===================================================================
340--- u-boot.orig/include/console.h
341+++ u-boot/include/console.h
342@@ -33,6 +33,8 @@
343 extern device_t *stdio_devices[] ;
344 extern char *stdio_names[MAX_FILES] ;
345
346+extern void (*console_poll_hook)(int activity);
347+
348 int console_realloc(int top);
349
350 #endif
351Index: u-boot/common/Makefile
352===================================================================
353--- u-boot.orig/common/Makefile
354+++ u-boot/common/Makefile
355@@ -50,7 +50,8 @@ COBJS = main.o ACEX1K.o altera.o bedbug.
356 memsize.o miiphybb.o miiphyutil.o \
357 s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \
358 usb.o usb_kbd.o usb_storage.o \
359- virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_mfsl.o
360+ virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_mfsl.o \
361+ bootmenu.o
362
363 SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
364 OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
365Index: u-boot/common/bootmenu.c
366===================================================================
367--- /dev/null
368+++ u-boot/common/bootmenu.c
369@@ -0,0 +1,311 @@
370+/*
371+ * bootmenu.c - Boot menu
372+ *
373+ * Copyright (C) 2006-2007 by OpenMoko, Inc.
374+ * Written by Werner Almesberger <werner@openmoko.org>
375+ * All Rights Reserved
376+ *
377+ * This program is free software; you can redistribute it and/or modify
378+ * it under the terms of the GNU General Public License as published by
379+ * the Free Software Foundation; either version 2 of the License, or
380+ * (at your option) any later version.
381+ *
382+ * This program is distributed in the hope that it will be useful,
383+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
384+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
385+ * GNU General Public License for more details.
386+ *
387+ * You should have received a copy of the GNU General Public License along
388+ * with this program; if not, write to the Free Software Foundation, Inc.,
389+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
390+ */
391+
392+
393+#include <common.h>
394+
395+#ifdef CFG_BOOTMENU
396+
397+#include <malloc.h>
398+#include <devices.h>
399+#include <console.h>
400+#include <bootmenu.h>
401+
402+
403+extern const char version_string[];
404+
405+
406+#define ANSI_CLEAR "\e[2J"
407+#define ANSI_REVERSE "\e[7m"
408+#define ANSI_NORMAL "\e[m"
409+#define ANSI_GOTOYX "\e[%d;%dH"
410+
411+/*
412+ * MIN_BOOT_MENU_TIMEOUT ensures that users can't by accident set the timeout
413+ * unusably short.
414+ */
415+#define MIN_BOOT_MENU_TIMEOUT 10 /* 10 seconds */
416+#define BOOT_MENU_TIMEOUT 60 /* 60 seconds */
417+#define AFTER_COMMAND_WAIT 3 /* wait (2,3] after running commands */
418+#define MAX_MENU_ITEMS 10 /* cut off after that many */
419+
420+#define TOP_ROW 2
421+#define MENU_0_ROW (TOP_ROW+5)
422+
423+
424+struct option {
425+ const char *label;
426+ void (*fn)(void *user); /* run_command if NULL */
427+ void *user;
428+};
429+
430+
431+static const struct bootmenu_setup *setup;
432+static struct option options[MAX_MENU_ITEMS];
433+static int num_options = 0;
434+static int max_width = 0;
435+
436+static device_t *bm_con;
437+
438+
439+static void bm_printf(const char *fmt, ...)
440+{
441+ va_list args;
442+ char printbuffer[CFG_PBSIZE];
443+
444+ va_start(args, fmt);
445+ vsprintf(printbuffer, fmt, args);
446+ va_end(args);
447+
448+ bm_con->puts(printbuffer);
449+}
450+
451+
452+static char *get_option(int n)
453+{
454+ char name[] = "menu_XX";
455+
456+ sprintf(name+5, "%d", n);
457+ return getenv(name);
458+}
459+
460+
461+static void print_option(const struct option *option, int reverse)
462+{
463+ int n = option-options;
464+
465+ bm_printf(ANSI_GOTOYX, MENU_0_ROW+n, 1);
466+ if (reverse)
467+ bm_printf(ANSI_REVERSE);
468+ bm_printf(" %-*s ", max_width, option->label);
469+ if (reverse)
470+ bm_printf(ANSI_NORMAL);
471+}
472+
473+
474+static int get_var_positive_int(char *var, int default_value)
475+{
476+ const char *s;
477+ char *end;
478+ int n;
479+
480+ s = getenv(var);
481+ if (!s)
482+ return default_value;
483+ n = simple_strtoul(s, &end, 0);
484+ if (!*s || *end || n < 1)
485+ return default_value;
486+ return n;
487+}
488+
489+
490+static void show_bootmenu(void)
491+{
492+ const struct option *option;
493+
494+ bm_printf(ANSI_CLEAR ANSI_GOTOYX "%s", TOP_ROW, 1, version_string);
495+ bm_printf(ANSI_GOTOYX "*** BOOT MENU ***", TOP_ROW+3, 1);
496+ bm_printf(ANSI_GOTOYX, MENU_0_ROW, 1);
497+
498+ for (option = options; option != options+num_options; option++)
499+ print_option(option, option == options);
500+
501+ bm_printf("\n\nPress [AUX] to select, [POWER] to execute.\n");
502+}
503+
504+
505+static void redirect_console(int grab)
506+{
507+ static device_t *orig_stdout, *orig_stderr;
508+
509+ if (grab) {
510+ orig_stdout = stdio_devices[stdout];
511+ orig_stderr = stdio_devices[stderr];
512+ stdio_devices[stdout] = bm_con;
513+ stdio_devices[stderr] = bm_con;
514+ }
515+ else {
516+ /*
517+ * Make this conditional, because the command may also change
518+ * the console.
519+ */
520+ if (stdio_devices[stdout] == bm_con)
521+ stdio_devices[stdout] = orig_stdout;
522+ if (stdio_devices[stderr] == bm_con)
523+ stdio_devices[stderr] = orig_stderr;
524+ }
525+}
526+
527+
528+static void do_option(const struct option *option)
529+{
530+ int seconds, aux;
531+
532+ bm_printf(ANSI_CLEAR ANSI_GOTOYX, 1, 1);
533+ redirect_console(1);
534+
535+ if (option->fn)
536+ option->fn(option->user);
537+ else
538+ run_command(option->user, 0);
539+
540+ redirect_console(0);
541+ seconds = get_var_positive_int("after_command_wait",
542+ AFTER_COMMAND_WAIT);
543+ if (seconds)
544+ bm_printf("\nPress [AUX] to %s.",
545+ option ? "return to boot menu" : "power off");
546+ aux = 1; /* require up-down transition */
547+ while (seconds) {
548+ int tmp;
549+
550+ tmp = setup->next_key(setup->user);
551+ if (tmp && !aux)
552+ break;
553+ aux = tmp;
554+ if (setup->seconds(setup->user))
555+ seconds--;
556+ }
557+ if (!option)
558+ setup->idle_action(setup->idle_action);
559+ show_bootmenu();
560+}
561+
562+
563+static void bootmenu_hook(int activity)
564+{
565+ static int aux = 1, on = 1;
566+ static const struct option *option = options;
567+ static int seconds = 0;
568+ int tmp;
569+
570+ if (activity)
571+ seconds = 0;
572+ tmp = setup->next_key(setup->user);
573+ if (tmp && !aux) {
574+ print_option(option, 0);
575+ option++;
576+ if (option == options+num_options)
577+ option = options;
578+ print_option(option, 1);
579+ seconds = 0;
580+ }
581+ aux = tmp;
582+ tmp = setup->enter_key(setup->user);
583+ if (tmp && !on) {
584+ do_option(option);
585+ option = options;
586+ seconds = 0;
587+ }
588+ on = tmp;
589+ if (setup->seconds(setup->user)) {
590+ int timeout;
591+
592+ timeout = get_var_positive_int("boot_menu_timeout",
593+ BOOT_MENU_TIMEOUT);
594+ if (timeout < MIN_BOOT_MENU_TIMEOUT)
595+ timeout = MIN_BOOT_MENU_TIMEOUT;
596+ if (++seconds > timeout) {
597+ setup->idle_action(setup->idle_action);
598+ seconds = 0;
599+ }
600+ }
601+}
602+
603+
604+static device_t *find_console(const char *name)
605+{
606+ int i;
607+
608+ for (i = 1; i != ListNumItems(devlist); i++) {
609+ device_t *dev = ListGetPtrToItem(devlist, i);
610+
611+ if (!strcmp(name, dev->name))
612+ if (dev->flags & DEV_FLAGS_OUTPUT)
613+ return dev;
614+ }
615+ return NULL;
616+}
617+
618+
619+void bootmenu_add(const char *label, void (*fn)(void *user), void *user)
620+{
621+ int len;
622+
623+ options[num_options].label = label;
624+ options[num_options].fn = fn;
625+ options[num_options].user = user;
626+ num_options++;
627+
628+ len = strlen(label);
629+ if (len > max_width)
630+ max_width = len;
631+}
632+
633+
634+void bootmenu_init(struct bootmenu_setup *__setup)
635+{
636+ int n;
637+
638+ setup = __setup;
639+ for (n = 1; n != MAX_MENU_ITEMS+1; n++) {
640+ const char *spec, *colon;
641+
642+ spec = get_option(n);
643+ if (!spec)
644+ continue;
645+ colon = strchr(spec, ':');
646+ if (!colon)
647+ bootmenu_add(spec, NULL, (char *) spec);
648+ else {
649+ char *label;
650+ int len = colon-spec;
651+
652+ label = malloc(len+1);
653+ if (!label)
654+ return;
655+ memcpy(label, spec, len);
656+ label[len] = 0;
657+ bootmenu_add(label, NULL, (char *) colon+1);
658+ }
659+ }
660+}
661+
662+
663+void bootmenu(void)
664+{
665+ bm_con = find_console("vga");
666+ if (bm_con && bm_con->start && bm_con->start() < 0)
667+ bm_con = NULL;
668+ if (!bm_con)
669+ bm_con = stdio_devices[stdout];
670+ if (!bm_con)
671+ return;
672+#if 0
673+ console_assign(stdout, "vga");
674+ console_assign(stderr, "vga");
675+#endif
676+ show_bootmenu();
677+ console_poll_hook = bootmenu_hook;
678+}
679+
680+#endif /* CFG_BOOTMENU */
681Index: u-boot/include/bootmenu.h
682===================================================================
683--- /dev/null
684+++ u-boot/include/bootmenu.h
685@@ -0,0 +1,71 @@
686+/*
687+ * bootmenu.h - Boot menu
688+ *
689+ * Copyright (C) 2006-2007 by OpenMoko, Inc.
690+ * Written by Werner Almesberger <werner@openmoko.org>
691+ * All Rights Reserved
692+ *
693+ * This program is free software; you can redistribute it and/or modify
694+ * it under the terms of the GNU General Public License as published by
695+ * the Free Software Foundation; either version 2 of the License, or
696+ * (at your option) any later version.
697+ *
698+ * This program is distributed in the hope that it will be useful,
699+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
700+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
701+ * GNU General Public License for more details.
702+ *
703+ * You should have received a copy of the GNU General Public License along
704+ * with this program; if not, write to the Free Software Foundation, Inc.,
705+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
706+ */
707+
708+#ifndef BOOTMENU_H
709+#define BOOTMENU_H
710+
711+#define MIN_BOOT_MENU_TIMEOUT 10 /* 10 seconds */
712+#define BOOT_MENU_TIMEOUT 60 /* 60 seconds */
713+#define AFTER_COMMAND_WAIT 3 /* wait (2,3] after running commands */
714+#define MAX_MENU_ITEMS 10 /* cut off after that many */
715+
716+
717+struct bootmenu_setup {
718+ /* non-zero while the "next" key is being pressed */
719+ int (*next_key)(void *user);
720+
721+ /* non-zero while the "enter" key is being pressed */
722+ int (*enter_key)(void *user);
723+
724+ /* return the number of seconds that have passed since the last call
725+ to "seconds". It's okay to limit the range to [0, 1]. */
726+ int (*seconds)(void *user);
727+
728+ /* action to take if the boot menu times out */
729+ void (*idle_action)(void *user);
730+
731+ /* user-specific data, passes "as is" to the functions above */
732+ void *user;
733+};
734+
735+
736+/*
737+ * Initialize the menu from the environment.
738+ */
739+
740+void bootmenu_init(struct bootmenu_setup *setup);
741+
742+/*
743+ * To add entries on top of the boot menu, call bootmenu_add before
744+ * bootmenu_init. To add entries at the end, call it after bootmenu_init.
745+ * If "fn" is NULL, the command specified in "user" is executed.
746+ */
747+
748+void bootmenu_add(const char *label, void (*fn)(void *user), void *user);
749+
750+/*
751+ * Run the boot menu.
752+ */
753+
754+void bootmenu(void);
755+
756+#endif /* !BOOTMENU_H */
757Index: u-boot/include/configs/neo1973_gta01.h
758===================================================================
759--- u-boot.orig/include/configs/neo1973_gta01.h
760+++ u-boot/include/configs/neo1973_gta01.h
761@@ -160,6 +160,8 @@
762 /* valid baudrates */
763 #define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
764
765+#define CFG_BOOTMENU
766+
767 /*-----------------------------------------------------------------------
768 * Stack sizes
769 *