blob: 0eec84d6d5c1c8f2c69e47e1449974de459d64b9 [file] [log] [blame]
Marcin Bukat28d54c62010-04-26 21:40:16 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:$
9 *
10 * Copyright (C) 2010 Marcin Bukat
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22
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"
44
45#include "common.h"
Rafaël Carré5d236b22010-05-27 09:41:46 +000046#include "version.h"
Marcin Bukat28d54c62010-04-26 21:40:16 +000047
48#include <stdarg.h>
49
50/* Maximum allowed firmware image size. 10MB is more than enough */
51#define MAX_LOADSIZE (10*1024*1024)
52
53#define DRAM_START 0x31000000
54
55#define BOOTMENU_TIMEOUT (10*HZ)
56#define BOOTMENU_OPTIONS 3
57
Marcin Bukat69fa42d2010-05-04 11:16:17 +000058#define EVENT_NONE 0x00
59#define EVENT_ON 0x01
60#define EVENT_AC 0x02
61#define EVENT_USB 0x04
62
Marcin Bukat28d54c62010-04-26 21:40:16 +000063/* From common.c */
64extern int line;
65static const char *bootmenu_options[] = {
66 "Boot rockbox",
67 "Boot MPIO firmware",
68 "Shutdown"
69};
70
71enum option_t {
72 rockbox,
73 mpio_firmware,
74 shutdown
75};
76
77int usb_screen(void)
78{
79 return 0;
80}
81
Marcin Bukat69fa42d2010-05-04 11:16:17 +000082static inline bool _charger_inserted(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +000083{
84 return (GPIO1_READ & (1<<14)) ? false : true;
85}
86
Marcin Bukat69fa42d2010-05-04 11:16:17 +000087static inline bool _battery_full(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +000088{
89 return (GPIO_READ & (1<<30)) ? true : false;
90}
91
92/* Reset the cookie for the crt0 crash check */
Marcin Bukat69fa42d2010-05-04 11:16:17 +000093static inline void __reset_cookie(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +000094{
95 asm(" move.l #0,%d0");
96 asm(" move.l %d0,0x10017ffc");
97}
98
Marcin Bukat69fa42d2010-05-04 11:16:17 +000099static void start_rockbox(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000100{
101 adc_close();
102 asm(" move.w #0x2700,%sr");
103 __reset_cookie();
104 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
105 asm(" movec.l %d0,%vbr");
106 asm(" move.l %0,%%sp" :: "m"(*(int *)DRAM_START));
107 asm(" move.l %0,%%a0" :: "m"(*(int *)(DRAM_START+4)));
108 asm(" jmp (%a0)");
109}
110
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000111static void start_mpio_firmware(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000112{
113 asm(" move.w #0x2700,%sr");
114 __reset_cookie();
115 asm(" movec.l %d0,%vbr");
116 asm(" move.l 0,%sp");
117 asm(" jmp 8");
118}
119
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000120static void __reset(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000121{
122 asm(" move.w #0x2700,%sr");
123 __reset_cookie();
124 asm(" movec.l %d0,%vbr");
125 asm(" move.l (0), %sp");
126 asm(" movea.l (4),%a0");
127 asm(" jmp (%a0)");
128}
129
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000130static void __shutdown(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000131{
132 /* We need to gracefully spin down the disk to prevent clicks. */
133 if (ide_powered())
134 {
135 /* Make sure ATA has been initialized. */
136 storage_init();
137
138 /* And put the disk into sleep immediately. */
139 storage_sleepnow();
140 }
141
142 /* Backlight OFF */
143 _backlight_off();
144 __reset_cookie();
145
146 if (_charger_inserted())
147 {
148 /* reset instead of power_off() */
149 __reset();
150 }
151 else
152 {
153 power_off();
154 }
155}
156
157/* Print the battery voltage (and a warning message). */
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000158static void check_battery(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000159{
160
161 int battery_voltage, batt_int, batt_frac;
162
163 battery_voltage = battery_adc_voltage();
164 batt_int = battery_voltage / 1000;
165 batt_frac = (battery_voltage % 1000) / 10;
166
167 printf("Battery: %d.%02dV", batt_int, batt_frac);
168
169 if (battery_voltage <= 3500)
170 {
171 printf("WARNING! BATTERY LOW!!");
172 sleep(HZ*2);
173 }
174
175}
176
177
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000178static void lcd_putstring_centered(const char *string)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000179{
180 int w,h;
181 font_getstringsize(string, &w, &h, FONT_SYSFIXED);
182 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, string);
183}
184
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000185static void rb_boot(void)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000186{
187 int rc;
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000188
Marcin Bukat57484bd2010-07-06 17:30:10 +0000189 /* boost to speedup rb image loading */
190 cpu_boost(true);
191
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000192 rc = storage_init();
193 if(rc)
194 {
195 printf("ATA error: %d", rc);
196 sleep(HZ*5);
197 return;
198 }
199
200 disk_init();
201
202 rc = disk_mount_all();
203 if (rc<=0)
204 {
205 printf("No partition found");
206 sleep(HZ*5);
207 return;
208 }
209
210 printf("Loading firmware");
211
212 rc = load_firmware((unsigned char *)DRAM_START,
213 BOOTFILE, MAX_LOADSIZE);
214
215 if (rc < EOK)
216 {
217 printf("Error!");
218 printf("Can't load " BOOTFILE ": ");
219 printf("Result: %s", strerror(rc));
220 sleep(HZ*5);
221 return;
222 }
223
Marcin Bukat57484bd2010-07-06 17:30:10 +0000224 cpu_boost(false);
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000225 start_rockbox();
226}
227
228static void bootmenu(void)
229{
Marcin Bukat28d54c62010-04-26 21:40:16 +0000230 enum option_t i;
231 enum option_t option = rockbox;
232 int button;
233 const char select[] = "->";
234 long start_tick = current_tick;
235
236 /* backbone of menu */
237 /* run the loader */
238 printf("Rockbox boot loader");
Rafaël Carré5d236b22010-05-27 09:41:46 +0000239 printf("Ver: " RBVERSION);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000240
241 check_battery();
242
243 printf("");
244 printf("=========================");
245
246 line += BOOTMENU_OPTIONS+2; /* skip lines */
247
248 printf("=========================");
249 printf("");
250 printf(" [FF] [PREV] to move ");
251 printf(" [PLAY] to confirm ");
252
253 /* content of menu and keys handling */
254 while (TIME_BEFORE(current_tick,start_tick + BOOTMENU_TIMEOUT))
255 {
256 /* Draw the menu. */
257 line = 6; /* move below header */
258
259 for (i=0;i<BOOTMENU_OPTIONS;i++)
260 {
261 if (i != option)
262 printf(" %s",bootmenu_options[i]);
263 else
264 printf("%s %s",select,bootmenu_options[i]);
265 }
266
267 line = 15;
268
269 printf("Time left: %ds",(BOOTMENU_TIMEOUT -
270 (current_tick - start_tick))/HZ);
271
272 lcd_update();
273
274 button = button_get_w_tmo(HZ);
275
276 switch (button)
277 {
278 case BUTTON_PREV:
Marcin Bukat57484bd2010-07-06 17:30:10 +0000279 case BUTTON_RC_PREV:
Marcin Bukat28d54c62010-04-26 21:40:16 +0000280 if (option > rockbox)
281 option--;
282 else
283 option = shutdown;
284 break;
285
286 case BUTTON_NEXT:
Marcin Bukat57484bd2010-07-06 17:30:10 +0000287 case BUTTON_RC_NEXT:
Marcin Bukat28d54c62010-04-26 21:40:16 +0000288 if (option < shutdown)
289 option++;
290 else
291 option = rockbox;
292 break;
293
294 case BUTTON_PLAY:
Marcin Bukat57484bd2010-07-06 17:30:10 +0000295 case BUTTON_RC_PLAY:
Marcin Bukat28d54c62010-04-26 21:40:16 +0000296 case (BUTTON_PLAY|BUTTON_REC):
297 reset_screen();
298
299 switch (option)
300 {
301 case rockbox:
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000302 rb_boot();
Marcin Bukat28d54c62010-04-26 21:40:16 +0000303 break;
304
305 case mpio_firmware:
306 start_mpio_firmware();
307 break;
308
309 default:
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000310 return;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000311 break;
312 }
313 }
314}
315/* timeout */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000316}
317
318void main(void)
319{
320 /* messages */
321 const char usb_connect_msg[] = "Bootloader USB mode";
322 const char charging_msg[] = "Charging...";
323 const char complete_msg[] = "Charging complete";
Marcin Bukat28d54c62010-04-26 21:40:16 +0000324
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000325 /* helper variable for messages */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000326 bool blink_toggle = false;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000327
Marcin Bukat28d54c62010-04-26 21:40:16 +0000328 int button;
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000329 unsigned int event = EVENT_NONE;
330 unsigned int last_event = EVENT_NONE;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000331
Marcin Bukat57484bd2010-07-06 17:30:10 +0000332 /* this is default mode after power_init() */
333 bool high_current_charging = true;
334
Marcin Bukat28d54c62010-04-26 21:40:16 +0000335 power_init();
336
337 system_init();
338 kernel_init();
339
340 set_cpu_frequency(CPUFREQ_NORMAL);
341 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
342
343 enable_irq();
344 lcd_init();
345
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000346 /* only lowlevel functions no queue init */
347 _backlight_init();
348 _backlight_hw_on();
349
350 /* setup font system*/
Marcin Bukat28d54c62010-04-26 21:40:16 +0000351 font_init();
352 lcd_setfont(FONT_SYSFIXED);
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000353
354 /* buttons reading */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000355 adc_init();
356 button_init();
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000357
Marcin Bukat28d54c62010-04-26 21:40:16 +0000358 usb_init();
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000359 cpu_idle_mode(true);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000360
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000361 /* Handle wakeup event. Possibilities are:
362 * ON button (PLAY)
363 * USB insert
364 * AC charger plug
365 */
366
367 while(1)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000368 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000369 /* read buttons */
370 event = EVENT_NONE;
371 button = button_get_w_tmo(HZ);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000372
Marcin Bukat57484bd2010-07-06 17:30:10 +0000373 if ( (button & BUTTON_PLAY) || (button & BUTTON_RC_PLAY) )
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000374 event |= EVENT_ON;
375
376 if ( usb_detect() == USB_INSERTED )
377 event |= EVENT_USB;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000378
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000379 if ( _charger_inserted() )
380 event |= EVENT_AC;
381
382 reset_screen();
383 switch (event)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000384 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000385 case EVENT_ON:
386 case (EVENT_ON | EVENT_AC):
387 /* hold is handled in button driver */
388 cpu_idle_mode(false);
Marcin Bukatcd879712010-06-14 10:42:45 +0000389 ide_power_enable(true);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000390
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000391 if (button == (BUTTON_PLAY|BUTTON_REC))
392 bootmenu();
393 else
394 rb_boot();
395
Marcin Bukat28d54c62010-04-26 21:40:16 +0000396 break;
397
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000398 case EVENT_AC:
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000399 if (!(last_event & EVENT_AC))
Marcin Bukatcd879712010-06-14 10:42:45 +0000400 {
Marcin Bukat57484bd2010-07-06 17:30:10 +0000401 /* reset charging circuit */
Marcin Bukatcd879712010-06-14 10:42:45 +0000402 and_l(~(1<<23), &GPIO_ENABLE);
403 }
Marcin Bukat28d54c62010-04-26 21:40:16 +0000404
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000405 /* USB unplug */
406 if (last_event & EVENT_USB)
Marcin Bukatcd879712010-06-14 10:42:45 +0000407 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000408 usb_enable(false);
Marcin Bukatcd879712010-06-14 10:42:45 +0000409 ide_power_enable(false);
410 }
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000411
Marcin Bukat28d54c62010-04-26 21:40:16 +0000412 if(!_battery_full())
413 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000414 if (blink_toggle)
415 lcd_putstring_centered(charging_msg);
416
Marcin Bukat28d54c62010-04-26 21:40:16 +0000417 blink_toggle = !blink_toggle;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000418 }
Marcin Bukat57484bd2010-07-06 17:30:10 +0000419 else /* end of charge condition */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000420 {
Marcin Bukat57484bd2010-07-06 17:30:10 +0000421 /* put LTC1733 into shutdown mode */
422 or_l((1<<23), &GPIO_ENABLE);
423
424 if (high_current_charging)
425 {
426 /* switch to low current mode */
427 and_l(~(1<<15), &GPIO_OUT);
428
429 /* reset charging circuit */
430 and_l(~(1<<23), &GPIO_ENABLE);
431
432 high_current_charging = false;
433 }
434 else
435 {
436 lcd_putstring_centered(complete_msg);
437 }
Marcin Bukat28d54c62010-04-26 21:40:16 +0000438 }
Marcin Bukat28d54c62010-04-26 21:40:16 +0000439 check_battery();
440 break;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000441
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000442 case EVENT_USB:
443 case (EVENT_USB | EVENT_AC):
444 if (!(last_event & EVENT_AC))
Marcin Bukatcd879712010-06-14 10:42:45 +0000445 {
Marcin Bukat57484bd2010-07-06 17:30:10 +0000446 /* reset charger circuit */
Marcin Bukatcd879712010-06-14 10:42:45 +0000447 and_l(~(1<<23), &GPIO_ENABLE);
448 }
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000449
450 if (!(last_event & EVENT_USB))
451 {
452 /* init USB */
453 ide_power_enable(true);
454 sleep(HZ/20);
455 usb_enable(true);
456 }
457
458 line = 0;
459
460 if (blink_toggle)
461 lcd_putstring_centered(usb_connect_msg);
462
463 check_battery();
464 blink_toggle = !blink_toggle;
465 storage_spin();
466 break;
467
468 default:
Marcin Bukat57484bd2010-07-06 17:30:10 +0000469 if (last_event & EVENT_USB)
470 {
471 /* USB unplug */
472 usb_enable(false);
473 ide_power_enable(false);
474 }
475
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000476 /* spurious wakeup */
477 __shutdown();
478 break;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000479 }
Marcin Bukat28d54c62010-04-26 21:40:16 +0000480 lcd_update();
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000481 last_event = event;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000482 }
483
Marcin Bukat28d54c62010-04-26 21:40:16 +0000484}
485
486/* These functions are present in the firmware library, but we reimplement
487 them here because the originals do a lot more than we want */
488void screen_dump(void)
489{
490}