Submit FS#11843 v17. Integrate YUV-blitting of nano 2G to nano1G/color LCD driver...
[kugel-rb.git] / bootloader / mpio_hd200_hd300.c
blob14f76354fb16baa183d30a4e1ce4a36392556bea
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;
347 unsigned int event = EVENT_NONE;
348 unsigned int last_event = EVENT_NONE;
350 /* this is default mode after power_init() */
351 bool high_current_charging = true;
353 /* setup GPIOs related to power functions */
354 power_init();
356 system_init();
357 kernel_init();
359 /* run at 45MHz */
360 set_cpu_frequency(CPUFREQ_NORMAL);
362 /* IRQs are needed by button driver */
363 enable_irq();
365 lcd_init();
367 /* only lowlevel functions no queue init */
368 _backlight_init();
369 _backlight_hw_on();
371 /* setup font system*/
372 font_init();
373 lcd_setfont(FONT_SYSFIXED);
375 /* buttons reading init*/
376 adc_init();
377 button_init();
379 usb_init();
380 cpu_idle_mode(true);
382 /* Handle wakeup event. Possibilities are:
383 * RTC alarm (HD300)
384 * ON button (PLAY or RC_PLAY on HD200)
385 * USB insert
386 * AC charger plug
388 while(1)
390 /* read buttons */
391 event = EVENT_NONE;
392 button = button_get_w_tmo(HZ);
394 if ( (button & BUTTON_PLAY)
395 #ifdef MPIO_HD200
396 || (button & BUTTON_RC_PLAY)
397 #endif
399 event |= EVENT_ON;
401 if ( usb_detect() == USB_INSERTED )
402 event |= EVENT_USB;
404 if ( _charger_inserted() )
405 event |= EVENT_AC;
406 #ifdef MPIO_HD300
407 if ( _rtc_alarm() )
408 event |= EVENT_RTC;
409 #endif
410 reset_screen();
411 switch (event)
413 #ifdef MPIO_HD300
414 case EVENT_RTC:
415 case (EVENT_RTC | EVENT_ON):
416 /* start regardles of buttons state */
417 rb_boot();
418 break;
419 #endif
420 case EVENT_ON:
421 case (EVENT_ON | EVENT_AC):
422 /* hold is handled in button driver */
423 cpu_idle_mode(false);
424 ide_power_enable(true);
426 if (button & BUTTON_REC)
427 bootmenu();
428 else
429 rb_boot();
431 break;
433 case EVENT_AC:
434 /* AC plug in */
435 if (!(last_event & EVENT_AC))
437 /* reset charging circuit */
438 and_l(~(1<<23), &GPIO_ENABLE);
441 /* USB unplug */
442 if (last_event & EVENT_USB)
444 usb_enable(false);
445 sleep(HZ);
446 ide_power_enable(false);
447 sleep(HZ);
450 if(!_battery_full())
452 if (blink_toggle)
453 lcd_putstring_centered(charging_msg);
455 blink_toggle = !blink_toggle;
457 else /* end of charge condition */
459 /* put LTC1733 into shutdown mode */
460 or_l((1<<23), &GPIO_ENABLE);
462 if (high_current_charging)
464 /* switch to low current mode */
465 and_l(~(1<<15), &GPIO_OUT);
467 /* reset charging circuit */
468 and_l(~(1<<23), &GPIO_ENABLE);
470 high_current_charging = false;
472 else
474 lcd_putstring_centered(complete_msg);
477 check_battery();
478 break;
480 case EVENT_USB:
481 case (EVENT_USB | EVENT_AC):
482 /* AC plug in while in USB mode */
483 if (!(last_event & EVENT_AC))
485 /* reset charger circuit */
486 and_l(~(1<<23), &GPIO_ENABLE);
489 /* USB plug in */
490 if (!(last_event & EVENT_USB))
492 /* init USB */
493 ide_power_enable(true);
494 sleep(HZ/20);
495 ata_enable(false);
496 usb_enable(true);
499 /* display blinking USB indicator */
500 line = 0;
502 if (blink_toggle)
503 lcd_putstring_centered(usb_connect_msg);
505 check_battery();
506 blink_toggle = !blink_toggle;
507 storage_spin();
508 break;
510 default:
511 /* USB unplug */
512 if (last_event & EVENT_USB)
514 /* disable USB */
515 usb_enable(false);
516 ata_enable(true);
517 sleep(HZ);
518 ide_power_enable(false);
519 sleep(HZ);
522 /* spurious wakeup ?*/
523 __shutdown();
524 break;
526 lcd_update();
527 last_event = event;
532 /* These functions are present in the firmware library, but we reimplement
533 them here because the originals do a lot more than we want */
534 void screen_dump(void)