Fix buffer size used for realpath() call
[maemo-rb.git] / bootloader / mpio_hd200_hd300.c
blobbe36daf2effdca9290fcc3a76b1a74e0d1f5ba35
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2010 Marcin Bukat
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include "inttypes.h"
26 #include "string.h"
27 #include "cpu.h"
28 #include "system.h"
29 #include "lcd.h"
30 #include "kernel.h"
31 #include "thread.h"
32 #include "storage.h"
33 #include "usb.h"
34 #include "disk.h"
35 #include "font.h"
36 #include "adc.h"
37 #include "backlight.h"
38 #include "backlight-target.h"
39 #include "button.h"
40 #include "panic.h"
41 #include "power.h"
42 #include "powermgmt.h"
43 #include "file.h"
45 #include "common.h"
46 #include "version.h"
48 #include <stdarg.h>
50 /* Maximum allowed firmware image size. 10MB is more than enough */
51 #define MAX_LOADSIZE (10*1024*1024)
53 #define DRAM_START 0x31000000
55 #define BOOTMENU_TIMEOUT (10*HZ)
56 #define BOOTMENU_OPTIONS 3
58 #define EVENT_NONE 0x00
59 #define EVENT_ON 0x01
60 #define EVENT_AC 0x02
61 #define EVENT_USB 0x04
62 #define EVENT_RTC 0x08
64 /* From common.c */
65 extern int line;
66 static const char *bootmenu_options[] = {
67 "Boot rockbox",
68 "Boot MPIO firmware",
69 "Shutdown"
72 enum option_t {
73 rockbox,
74 mpio_firmware,
75 shutdown
78 int usb_screen(void)
80 return 0;
83 /* return true if charger is present */
84 static inline bool _charger_inserted(void)
86 return (GPIO1_READ & (1<<14)) ? false : true;
89 /* returns true if end of charge condition is reached */
90 static inline bool _battery_full(void)
92 return (GPIO_READ & (1<<30)) ? true : false;
95 #ifdef MPIO_HD300
96 /* returns true if startup is due to RTC alarm */
97 static inline bool _rtc_alarm(void)
99 if ( (GPIO1_READ & (1<<4)) && (GPIO1_READ & (1<<5)) )
100 return false;
102 return true;
104 #endif
106 /* Reset the cookie for the crt0 crash check */
107 static inline void __reset_cookie(void)
109 asm(" move.l #0,%d0");
110 asm(" move.l %d0,0x10017ffc");
113 static void start_rockbox(void)
115 adc_close();
116 asm(" move.w #0x2700,%sr");
117 __reset_cookie();
118 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
119 asm(" movec.l %d0,%vbr");
120 asm(" move.l %0,%%sp" :: "m"(*(int *)DRAM_START));
121 asm(" move.l %0,%%a0" :: "m"(*(int *)(DRAM_START+4)));
122 asm(" jmp (%a0)");
125 static void start_mpio_firmware(void)
127 asm(" move.w #0x2700,%sr");
128 __reset_cookie();
129 asm(" movec.l %d0,%vbr");
130 asm(" move.l 0,%sp");
131 asm(" jmp 8");
134 static void __shutdown(void)
136 if (_charger_inserted())
137 /* if AC power do nothing */
138 return;
140 /* We need to gracefully spin down the disk to prevent clicks. */
141 if (ide_powered())
143 /* Make sure ATA has been initialized. */
144 storage_init();
146 /* And put the disk into sleep immediately. */
147 storage_sleepnow();
150 /* Backlight OFF */
151 _backlight_off();
152 __reset_cookie();
154 power_off();
157 /* Print the battery voltage (and a warning message). */
158 static void check_battery(void)
161 int battery_voltage, batt_int, batt_frac;
163 battery_voltage = battery_adc_voltage();
164 batt_int = battery_voltage / 1000;
165 batt_frac = (battery_voltage % 1000) / 10;
167 printf("Battery: %d.%02dV", batt_int, batt_frac);
169 if (battery_voltage <= 3500)
171 printf("WARNING! BATTERY LOW!!");
172 sleep(HZ*2);
178 static void lcd_putstring_centered(const char *string)
180 int w,h;
181 font_getstringsize(string, &w, &h, FONT_SYSFIXED);
182 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, string);
185 /* This function initializes ATA driver, mounts partitions,
186 * loads rockbox image from disk to ram and finally
187 * jumps to entry point in ram
189 static void rb_boot(void)
191 int rc;
193 /* boost to speedup rb image loading */
194 cpu_boost(true);
196 reset_screen();
197 printf("Rockbox boot loader");
198 printf("Version " RBVERSION);
200 rc = storage_init();
201 if(rc)
203 printf("ATA error: %d", rc);
204 sleep(HZ*5);
205 return;
208 disk_init();
210 rc = disk_mount_all();
211 if (rc<=0)
213 printf("No partition found");
214 sleep(HZ*5);
215 return;
218 printf("Loading firmware");
220 rc = load_firmware((unsigned char *)DRAM_START,
221 BOOTFILE, MAX_LOADSIZE);
223 if (rc < EOK)
225 printf("Error!");
226 printf("Can't load " BOOTFILE ": ");
227 printf("Result: %s", strerror(rc));
228 sleep(HZ*5);
229 return;
232 cpu_boost(false);
233 start_rockbox();
236 /* This function prints small bootmenu where
237 * you can choose to boot OF, rockbox or just shutdown
239 static void bootmenu(void)
241 enum option_t i;
242 enum option_t option = rockbox;
243 int button;
244 const char select[] = "->";
245 long start_tick = current_tick;
247 /* backbone of menu */
248 /* run the loader */
249 printf("Rockbox boot loader");
250 printf("Ver: " RBVERSION);
252 check_battery();
254 printf("");
255 printf("=========================");
257 line += BOOTMENU_OPTIONS+2; /* skip lines */
259 printf("=========================");
260 printf("");
261 printf(" [FF] [REW] to move ");
262 printf(" [PLAY] to confirm ");
264 /* content of menu and keys handling */
265 while (TIME_BEFORE(current_tick,start_tick + BOOTMENU_TIMEOUT))
267 /* Draw the menu. */
268 line = 6; /* move below header */
270 for (i=0;i<BOOTMENU_OPTIONS;i++)
272 if (i != option)
273 printf(" %s",bootmenu_options[i]);
274 else
275 printf("%s %s",select,bootmenu_options[i]);
278 line = 15;
280 printf("Time left: %ds",(BOOTMENU_TIMEOUT -
281 (current_tick - start_tick))/HZ);
283 lcd_update();
285 button = BUTTON_NONE;
286 button = button_get_w_tmo(HZ);
288 switch (button)
290 case BUTTON_REW:
291 #ifdef MPIO_HD200
292 case BUTTON_RC_REW:
293 #endif
294 if (option > rockbox)
295 option--;
296 else
297 option = shutdown;
298 break;
300 case BUTTON_FF:
301 #ifdef MPIO_HD200
302 case BUTTON_RC_FF:
303 #endif
304 if (option < shutdown)
305 option++;
306 else
307 option = rockbox;
308 break;
310 case BUTTON_PLAY:
311 #ifdef MPIO_HD200
312 case BUTTON_RC_PLAY:
313 case (BUTTON_PLAY|BUTTON_REC):
314 #endif
315 reset_screen();
317 switch (option)
319 case rockbox:
320 rb_boot();
321 break;
323 case mpio_firmware:
324 start_mpio_firmware();
325 break;
327 default:
328 __shutdown();
329 break;
333 /* timeout */
336 void main(void)
338 /* messages */
339 const char usb_connect_msg[] = "Bootloader USB mode";
340 const char charging_msg[] = "Charging...";
341 const char complete_msg[] = "Charging complete";
343 /* helper variable for messages */
344 bool blink_toggle = false;
346 int button;
348 /* hold status variables
349 * this two must have different
350 * values in the begining
352 bool hold = false;
353 bool last_hold = true;
355 unsigned int event = EVENT_NONE;
356 unsigned int last_event = EVENT_NONE;
358 /* this is default mode after power_init() */
359 bool high_current_charging = true;
361 /* setup GPIOs related to power functions */
362 power_init();
364 system_init();
365 kernel_init();
367 /* run at 45MHz */
368 set_cpu_frequency(CPUFREQ_NORMAL);
370 /* IRQs are needed by button driver */
371 enable_irq();
373 lcd_init();
375 /* setup font system */
376 font_init();
377 lcd_setfont(FONT_SYSFIXED);
379 /* buttons reading init */
380 adc_init();
381 button_init();
383 usb_init();
384 cpu_idle_mode(true);
386 /* lowlevel init only */
387 _backlight_init();
389 /* Handle wakeup event. Possibilities are:
390 * RTC alarm (HD300)
391 * ON button (PLAY or RC_PLAY on HD200)
392 * USB insert
393 * AC charger plug
395 while(1)
397 /* check hold status */
398 hold = button_hold();
400 /* backlight handling
401 * change only on hold toggle */
402 if ( hold != last_hold )
404 if ( hold )
405 _backlight_hw_off();
406 else
407 _backlight_hw_on();
409 last_hold = hold;
412 /* read buttons */
413 event = EVENT_NONE;
414 button = button_get_w_tmo(HZ);
416 if ( (button & BUTTON_PLAY)
417 #ifdef MPIO_HD200
418 || (button & BUTTON_RC_PLAY)
419 #endif
421 event |= EVENT_ON;
423 if ( usb_detect() == USB_INSERTED )
424 event |= EVENT_USB;
426 if ( _charger_inserted() )
427 event |= EVENT_AC;
428 #ifdef MPIO_HD300
429 if ( _rtc_alarm() )
430 event |= EVENT_RTC;
431 #endif
433 reset_screen();
434 switch (event)
436 #ifdef MPIO_HD300
437 case EVENT_RTC:
438 case (EVENT_RTC | EVENT_ON):
439 /* start regardles of buttons state */
440 rb_boot();
441 break;
442 #endif
443 case EVENT_ON:
444 case (EVENT_ON | EVENT_AC):
445 /* hold is handled in button driver */
446 cpu_idle_mode(false);
447 ide_power_enable(true);
449 if (button & BUTTON_REC)
450 bootmenu();
451 else
452 rb_boot();
454 break;
456 case EVENT_AC:
457 /* AC plug in */
458 if (!(last_event & EVENT_AC))
460 /* reset charging circuit */
461 and_l(~(1<<23), &GPIO_ENABLE);
464 /* USB unplug */
465 if (last_event & EVENT_USB)
467 usb_enable(false);
468 sleep(HZ);
469 ide_power_enable(false);
470 sleep(HZ);
473 if(!_battery_full())
475 if (blink_toggle)
476 lcd_putstring_centered(charging_msg);
478 blink_toggle = !blink_toggle;
480 else /* end of charge condition */
482 /* put LTC1733 into shutdown mode */
483 or_l((1<<23), &GPIO_ENABLE);
485 if (high_current_charging)
487 /* switch to low current mode */
488 and_l(~(1<<15), &GPIO_OUT);
490 /* reset charging circuit */
491 and_l(~(1<<23), &GPIO_ENABLE);
493 high_current_charging = false;
495 else
497 lcd_putstring_centered(complete_msg);
500 check_battery();
501 break;
503 case EVENT_USB:
504 case (EVENT_USB | EVENT_AC):
505 /* AC plug in while in USB mode */
506 if (!(last_event & EVENT_AC))
508 /* reset charger circuit */
509 and_l(~(1<<23), &GPIO_ENABLE);
512 /* USB plug in */
513 if (!(last_event & EVENT_USB))
515 /* init USB */
516 ide_power_enable(true);
517 sleep(HZ/20);
518 ata_enable(false);
519 usb_enable(true);
522 /* display blinking USB indicator */
523 line = 0;
525 if (blink_toggle)
526 lcd_putstring_centered(usb_connect_msg);
528 check_battery();
529 blink_toggle = !blink_toggle;
530 storage_spin();
531 break;
533 default:
534 /* USB unplug */
535 if (last_event & EVENT_USB)
537 /* disable USB */
538 usb_enable(false);
539 ata_enable(true);
540 sleep(HZ);
541 ide_power_enable(false);
542 sleep(HZ);
545 /* spurious wakeup ?*/
546 __shutdown();
547 break;
549 lcd_update();
550 last_event = event;
555 /* These functions are present in the firmware library, but we reimplement
556 them here because the originals do a lot more than we want */
557 void screen_dump(void)