Fuzev1: calibrated charging curve
[kugel-rb.git] / bootloader / mpio_hd200.c
bloba031234b5a45d7f99b751d733e25c19c26b58a55
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"
47 #include <stdarg.h>
49 /* Maximum allowed firmware image size. 10MB is more than enough */
50 #define MAX_LOADSIZE (10*1024*1024)
52 #define DRAM_START 0x31000000
54 #define BOOTMENU_TIMEOUT (10*HZ)
55 #define BOOTMENU_OPTIONS 3
57 #define EVENT_NONE 0x00
58 #define EVENT_ON 0x01
59 #define EVENT_AC 0x02
60 #define EVENT_USB 0x04
62 /* From common.c */
63 extern int line;
64 static const char *bootmenu_options[] = {
65 "Boot rockbox",
66 "Boot MPIO firmware",
67 "Shutdown"
70 enum option_t {
71 rockbox,
72 mpio_firmware,
73 shutdown
76 int usb_screen(void)
78 return 0;
81 char version[] = APPSVERSION;
83 static inline bool _charger_inserted(void)
85 return (GPIO1_READ & (1<<14)) ? false : true;
88 static inline bool _battery_full(void)
90 return (GPIO_READ & (1<<30)) ? true : false;
93 /* Reset the cookie for the crt0 crash check */
94 static inline void __reset_cookie(void)
96 asm(" move.l #0,%d0");
97 asm(" move.l %d0,0x10017ffc");
100 static void start_rockbox(void)
102 adc_close();
103 asm(" move.w #0x2700,%sr");
104 __reset_cookie();
105 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
106 asm(" movec.l %d0,%vbr");
107 asm(" move.l %0,%%sp" :: "m"(*(int *)DRAM_START));
108 asm(" move.l %0,%%a0" :: "m"(*(int *)(DRAM_START+4)));
109 asm(" jmp (%a0)");
112 static void start_mpio_firmware(void)
114 asm(" move.w #0x2700,%sr");
115 __reset_cookie();
116 asm(" movec.l %d0,%vbr");
117 asm(" move.l 0,%sp");
118 asm(" jmp 8");
121 static void __reset(void)
123 asm(" move.w #0x2700,%sr");
124 __reset_cookie();
125 asm(" movec.l %d0,%vbr");
126 asm(" move.l (0), %sp");
127 asm(" movea.l (4),%a0");
128 asm(" jmp (%a0)");
131 static void __shutdown(void)
133 /* We need to gracefully spin down the disk to prevent clicks. */
134 if (ide_powered())
136 /* Make sure ATA has been initialized. */
137 storage_init();
139 /* And put the disk into sleep immediately. */
140 storage_sleepnow();
143 /* Backlight OFF */
144 _backlight_off();
145 __reset_cookie();
147 if (_charger_inserted())
149 /* reset instead of power_off() */
150 __reset();
152 else
154 power_off();
158 /* Print the battery voltage (and a warning message). */
159 static void check_battery(void)
162 int battery_voltage, batt_int, batt_frac;
164 battery_voltage = battery_adc_voltage();
165 batt_int = battery_voltage / 1000;
166 batt_frac = (battery_voltage % 1000) / 10;
168 printf("Battery: %d.%02dV", batt_int, batt_frac);
170 if (battery_voltage <= 3500)
172 printf("WARNING! BATTERY LOW!!");
173 sleep(HZ*2);
179 static void lcd_putstring_centered(const char *string)
181 int w,h;
182 font_getstringsize(string, &w, &h, FONT_SYSFIXED);
183 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, string);
186 static void rb_boot(void)
188 int rc;
190 rc = storage_init();
191 if(rc)
193 printf("ATA error: %d", rc);
194 sleep(HZ*5);
195 return;
198 disk_init();
200 rc = disk_mount_all();
201 if (rc<=0)
203 printf("No partition found");
204 sleep(HZ*5);
205 return;
208 printf("Loading firmware");
210 rc = load_firmware((unsigned char *)DRAM_START,
211 BOOTFILE, MAX_LOADSIZE);
213 if (rc < EOK)
215 printf("Error!");
216 printf("Can't load " BOOTFILE ": ");
217 printf("Result: %s", strerror(rc));
218 sleep(HZ*5);
219 return;
222 start_rockbox();
225 static void bootmenu(void)
227 enum option_t i;
228 enum option_t option = rockbox;
229 int button;
230 const char select[] = "->";
231 long start_tick = current_tick;
233 /* backbone of menu */
234 /* run the loader */
235 printf("Rockbox boot loader");
236 printf("Ver: %s", version);
238 check_battery();
240 printf("");
241 printf("=========================");
243 line += BOOTMENU_OPTIONS+2; /* skip lines */
245 printf("=========================");
246 printf("");
247 printf(" [FF] [PREV] to move ");
248 printf(" [PLAY] to confirm ");
250 /* content of menu and keys handling */
251 while (TIME_BEFORE(current_tick,start_tick + BOOTMENU_TIMEOUT))
253 /* Draw the menu. */
254 line = 6; /* move below header */
256 for (i=0;i<BOOTMENU_OPTIONS;i++)
258 if (i != option)
259 printf(" %s",bootmenu_options[i]);
260 else
261 printf("%s %s",select,bootmenu_options[i]);
264 line = 15;
266 printf("Time left: %ds",(BOOTMENU_TIMEOUT -
267 (current_tick - start_tick))/HZ);
269 lcd_update();
271 button = button_get_w_tmo(HZ);
273 switch (button)
275 case BUTTON_PREV:
276 if (option > rockbox)
277 option--;
278 else
279 option = shutdown;
280 break;
282 case BUTTON_NEXT:
283 if (option < shutdown)
284 option++;
285 else
286 option = rockbox;
287 break;
289 case BUTTON_PLAY:
290 case (BUTTON_PLAY|BUTTON_REC):
291 reset_screen();
293 switch (option)
295 case rockbox:
296 rb_boot();
297 break;
299 case mpio_firmware:
300 start_mpio_firmware();
301 break;
303 default:
304 return;
305 break;
309 /* timeout */
312 void main(void)
314 /* messages */
315 const char usb_connect_msg[] = "Bootloader USB mode";
316 const char charging_msg[] = "Charging...";
317 const char complete_msg[] = "Charging complete";
319 /* helper variable for messages */
320 bool blink_toggle = false;
322 int button;
323 unsigned int event = EVENT_NONE;
324 unsigned int last_event = EVENT_NONE;
326 power_init();
328 system_init();
329 kernel_init();
331 set_cpu_frequency(CPUFREQ_NORMAL);
332 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
334 enable_irq();
335 lcd_init();
337 /* only lowlevel functions no queue init */
338 _backlight_init();
339 _backlight_hw_on();
341 /* setup font system*/
342 font_init();
343 lcd_setfont(FONT_SYSFIXED);
345 /* buttons reading */
346 adc_init();
347 button_init();
349 usb_init();
350 cpu_idle_mode(true);
352 /* Handle wakeup event. Possibilities are:
353 * ON button (PLAY)
354 * USB insert
355 * AC charger plug
358 while(1)
360 /* read buttons */
361 event = EVENT_NONE;
362 button = button_get_w_tmo(HZ);
364 if ( button & BUTTON_PLAY )
365 event |= EVENT_ON;
367 if ( usb_detect() == USB_INSERTED )
368 event |= EVENT_USB;
370 if ( _charger_inserted() )
371 event |= EVENT_AC;
373 reset_screen();
374 switch (event)
376 case EVENT_ON:
377 case (EVENT_ON | EVENT_AC):
378 /* hold is handled in button driver */
379 cpu_idle_mode(false);
381 if (button == (BUTTON_PLAY|BUTTON_REC))
382 bootmenu();
383 else
384 rb_boot();
386 break;
388 case EVENT_AC:
389 /* turn on charging */
390 if (!(last_event & EVENT_AC))
391 or_l((1<<15),&GPIO_OUT);
393 /* USB unplug */
394 if (last_event & EVENT_USB)
395 usb_enable(false);
397 if(!_battery_full())
399 if (blink_toggle)
400 lcd_putstring_centered(charging_msg);
402 blink_toggle = !blink_toggle;
404 else
406 lcd_putstring_centered(complete_msg);
408 check_battery();
409 break;
411 case EVENT_USB:
412 case (EVENT_USB | EVENT_AC):
413 if (!(last_event & EVENT_AC))
414 or_l((1<<15),&GPIO_OUT);
416 if (!(last_event & EVENT_USB))
418 /* init USB */
419 ide_power_enable(true);
420 sleep(HZ/20);
421 usb_enable(true);
424 line = 0;
426 if (blink_toggle)
427 lcd_putstring_centered(usb_connect_msg);
429 check_battery();
430 blink_toggle = !blink_toggle;
431 storage_spin();
432 break;
434 default:
435 /* spurious wakeup */
436 __shutdown();
437 break;
439 lcd_update();
440 last_event = event;
445 /* These functions are present in the firmware library, but we reimplement
446 them here because the originals do a lot more than we want */
447 void screen_dump(void)