pandora/video: enable REGEN
[pandora-u-boot.git] / board / pandora / menu.c
1 #include <common.h>
2 #include <asm/io.h>
3 #include <asm/arch/gpio.h>
4 #include <hush.h>
5 #include <malloc.h>
6 #include <lcd.h>
7 #include <twl4030.h>
8
9 /* game buttons as in GPIO bank 4 */
10 #define BTN_R           GPIO9
11 #define BTN_UP          GPIO14
12 #define BTN_DOWN        GPIO7
13 #define BTN_G2          GPIO15
14 #define BTN_G3          GPIO10
15
16 struct menu_item {
17         const char *name;
18         int (*handler)(struct menu_item *item);
19         char *cmd;
20 };
21
22 static struct menu_item *menu_items[24];
23 static int menu_item_count;
24
25 static int do_cmd(const char *fmt, ...)
26 {
27         char cmdbuff[256];
28         va_list args;
29
30         va_start(args, fmt);
31         vsprintf(cmdbuff, fmt, args);
32         va_end(args);
33
34         return !parse_string_outer(cmdbuff,
35                 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
36 }
37
38 static u32 menu_wait_for_input(int down)
39 {
40         struct gpio *gpio4_base = (struct gpio *)OMAP34XX_GPIO4_BASE;
41         u32 btns;
42
43         while (1) {
44                 btns = ~readl(&gpio4_base->datain) &
45                         (BTN_UP|BTN_DOWN|BTN_G2|BTN_G3);
46                 if (!btns == !down)
47                         break;
48                 udelay(5000);
49         }
50
51         return btns;
52 }
53
54 static int menu_do_default(struct menu_item *item)
55 {
56         return 1;
57 }
58
59 static int menu_do_poweroff(struct menu_item *item)
60 {
61         u8 d;
62
63         printf("power off.\n");
64
65         twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER, &d, TWL4030_PM_MASTER_P1_SW_EVENTS);
66         d |= TWL4030_PM_MASTER_SW_EVENTS_DEVOFF;
67         twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, d, TWL4030_PM_MASTER_P1_SW_EVENTS);
68
69         return 0;
70 }
71
72 static int menu_do_usb_serial(struct menu_item *item)
73 {
74         do_cmd("dcache off"); /* doesn't work with dcache */
75         do_cmd("usbinit");
76         printf("Switched to USB serial.\n");
77
78         setenv("stdout", "usbtty");
79         setenv("stdin", "usbtty");
80         setenv("stderr", "usbtty");
81         setenv("bootcmd", "");
82         return 1;
83 }
84
85 static int menu_do_serial(struct menu_item *item)
86 {
87         printf("Switched to serial.\n");
88
89         setenv("stdout", "serial");
90         setenv("bootcmd", "");
91         return 1;
92 }
93
94 static int menu_do_script_cmd(struct menu_item *item)
95 {
96         int failed = 0;
97
98         if (item->cmd == NULL || !do_cmd(item->cmd))
99                 failed = 1;
100
101         printf("script %s.\n", failed ? "failed" : "finished");
102         flush_dcache_all();
103         menu_wait_for_input(0);
104         menu_wait_for_input(1);
105         return 0;
106 }
107
108 static void add_menu_item(const char *name,
109         int (*handler)(struct menu_item *), const char *cmd)
110 {
111         struct menu_item *mitem;
112
113         mitem = malloc(sizeof(*mitem));
114         if (mitem == NULL)
115                 return;
116         mitem->name = strdup(name);
117         mitem->handler = handler;
118         mitem->cmd = strdup(cmd);
119
120         if (menu_item_count < ARRAY_SIZE(menu_items))
121                 menu_items[menu_item_count++] = mitem;
122 }
123
124 static char *bootmenu_next_ctl(char *p)
125 {
126         while (*p && *p != '|' && *p != '\r' && *p != '\n')
127                 p++;
128
129         return p;
130 }
131
132 static char *bootmenu_skip_blanks(char *p)
133 {
134         while (*p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n'))
135                 p++;
136
137         return p;
138 }
139
140 static char *bootmenu_skip_line(char *p)
141 {
142         while (*p && *p != '\r' && *p != '\n')
143                 p++;
144
145         return p;
146 }
147
148 static void parse_bootmenu(char *buf)
149 {
150         char *p = buf, *name, *cmd;
151         int i;
152
153         for (i = 1; ; i++)
154         {
155                 p = bootmenu_skip_blanks(p);
156                 if (*p == 0)
157                         break;
158                 if (*p == '#') {
159                         p = bootmenu_skip_line(p);
160                         continue;
161                 }
162
163                 name = p;
164                 p = bootmenu_next_ctl(p);
165                 if (*p != '|') {
166                         printf("bootmenu.txt: invalid line ~%d\n", i);
167                         p = bootmenu_skip_line(p);
168                         continue;
169                 }
170                 *p++ = 0;
171
172                 cmd = p;
173                 p = bootmenu_skip_line(p);
174                 if (*p != 0)
175                         *p++ = 0;
176
177                 add_menu_item(name, menu_do_script_cmd, cmd);
178         }
179 }
180
181 static struct menu_item default_menu_items[] = {
182         { "default boot",       menu_do_default, },
183         { "power off",          menu_do_poweroff, },
184         { "USB serial prompt",  menu_do_usb_serial, },
185         { "serial prompt",      menu_do_serial, },
186 };
187
188 static void menu_init(void)
189 {
190         const char *check_format1 = "%sload mmc1 0:%d ${loadaddr} boot.scr 4";
191         const char *check_format2 = "%sload mmc1 0:%d ${loadaddr} boot.txt 4";
192         const char *run_format1 = "%sload mmc1 0:%d ${loadaddr} boot.scr;source ${loadaddr}";
193         const char *run_format2 = "%sload mmc1 0:%d ${loadaddr} boot.txt;ssource ${loadaddr} ${filesize}";
194         disk_partition_t part_info;
195         block_dev_desc_t *dev_desc;
196         char tmp_name[32], tmp_cmd[128];
197         int i;
198
199         for (i = 0; i < 2; i++)
200                 menu_items[i] = &default_menu_items[i];
201         menu_item_count = i;
202
203         if (!do_cmd("mmc rescan"))
204                 goto no_mmc;
205
206         dev_desc = get_dev("mmc1", 0);
207         if (dev_desc == NULL) {
208                 printf("dev desc null\n");
209                 goto no_mmc;
210         }
211
212         /* kill stdout while we search for bootfiles */
213         setenv("stdout", "nulldev");
214
215         for (i = 1; menu_item_count < ARRAY_SIZE(menu_items); i++) {
216                 if (get_partition_info(dev_desc, i, &part_info))
217                         break;
218                 if (do_cmd("fatls mmc1 0:%d", i)) {
219                         if (do_cmd(check_format1, "fat", i)) {
220                                 sprintf(tmp_cmd, run_format1, "fat", i);
221                                 goto found;
222                         }
223                         if (do_cmd(check_format2, "fat", i)) {
224                                 sprintf(tmp_cmd, run_format2, "fat", i);
225                                 goto found;
226                         }
227                         continue;
228                 }
229                 if (do_cmd("ext2ls mmc1 0:%d", i)) {
230                         if (do_cmd(check_format1, "ext2", i)) {
231                                 sprintf(tmp_cmd, run_format1, "ext2", i);
232                                 goto found;
233                         }
234                         if (do_cmd(check_format2, "ext2", i)) {
235                                 sprintf(tmp_cmd, run_format2, "ext2", i);
236                                 goto found;
237                         }
238                         continue;
239                 }
240                 continue;
241
242 found:
243                 sprintf(tmp_name, "boot from SD1:%d", i);
244                 add_menu_item(tmp_name, menu_do_script_cmd, tmp_cmd);
245         }
246
247 no_mmc:
248         setenv("stdout", "serial");
249
250         if (do_cmd("ubi part boot && ubifsmount boot")) {
251                 ulong addr = getenv_ulong("loadaddr", 16, 0);
252                 if ((int)addr < (int)0x90000000) {
253                         if (do_cmd("ubifsload ${loadaddr} bootmenu.txt")) {
254                                 ulong size = getenv_ulong("filesize", 16, 0);
255                                 *(char *)(addr + size) = 0;
256                                 parse_bootmenu((char *)addr);
257                         }
258                 }
259         }
260
261         for (i = 2; i < ARRAY_SIZE(default_menu_items); i++) {
262                 if (menu_item_count >= ARRAY_SIZE(menu_items))
263                         break;
264                 menu_items[menu_item_count++] = &default_menu_items[i];
265         }
266
267         setenv("stdout", "lcd");
268 }
269
270 static int boot_menu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
271 {
272         int i, sel = 0, max_sel;
273         int tl_row;
274         u32 btns;
275
276         menu_init();
277
278         tl_row = panel_info.vl_row / 16 / 2 - (menu_item_count + 2) / 2;
279         max_sel = menu_item_count - 1;
280
281         console_col = 3;
282         console_row = tl_row;
283         lcd_printf("Boot menu");
284
285         while (1)
286         {
287                 for (i = 0; i < menu_item_count; i++) {
288                         console_col = 3;
289                         console_row = tl_row + 2 + i;
290                         lcd_printf(menu_items[i]->name);
291                 }
292
293                 for (i = 0; i < menu_item_count; i++) {
294                         console_col = 1;
295                         console_row = tl_row + 2 + i;
296                         lcd_printf(i == sel ? ">" : " ");
297                 }
298
299                 flush_dcache_all();
300                 menu_wait_for_input(0);
301                 btns = menu_wait_for_input(1);
302                 if (btns & BTN_UP) {
303                         sel--;
304                         if (sel < 0)
305                                 sel = max_sel;
306                 }
307                 else if (btns & BTN_DOWN) {
308                         sel++;
309                         if (sel > max_sel)
310                                 sel = 0;
311                 }
312                 else {
313                         do_cmd("cls");
314                         if (menu_items[sel]->handler(menu_items[sel]))
315                                 break;
316                         do_cmd("cls");
317                 }
318         }
319
320         return 0;
321 }
322
323 U_BOOT_CMD(
324         pmenu, 1, 1, boot_menu,
325         "show pandora's boot menu",
326         ""
327 );
328
329 /* helpers */
330 static int do_ssource(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
331 {
332         ulong addr, size = 0;
333
334         if (argc < 2)
335                 return 1;
336
337         addr = simple_strtoul(argv[1], NULL, 16);
338         if (argc >= 3) {
339                 size = simple_strtoul(argv[2], NULL, 16);
340                 *(char *)(addr + size) = 0;
341         }
342
343         printf("## Executing plain script at %08lx, size %ld\n", addr, size);
344         return parse_string_outer((char *)addr, FLAG_PARSE_SEMICOLON);
345 }
346
347 U_BOOT_CMD(
348         ssource, 3, 0, do_ssource,
349         "run script from memory (no header)",
350         "<addr> [size_hex]"     /* note: without size may parse trash after the script */
351 );
352
353 static int do_usbinit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
354 {
355         extern int drv_usbtty_init(void);
356         static int usbinit_done;
357         if (!usbinit_done) {
358                 usbinit_done = 1;
359                 return !drv_usbtty_init();
360         }
361         return 0;
362 }
363
364 U_BOOT_CMD(
365         usbinit, 1, 0, do_usbinit,
366         "initialize USB",
367         ""
368 );
369
370 static int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
371 {
372         menu_do_poweroff(NULL);
373         return 0;
374 }
375
376 U_BOOT_CMD(
377         poweroff, 1, 0, do_poweroff,
378         "power off this device",
379         ""
380 );