blob: 8062f7ef2271cd9ec6492ba8076605b1de95ccc2 [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
189 rc = storage_init();
190 if(rc)
191 {
192 printf("ATA error: %d", rc);
193 sleep(HZ*5);
194 return;
195 }
196
197 disk_init();
198
199 rc = disk_mount_all();
200 if (rc<=0)
201 {
202 printf("No partition found");
203 sleep(HZ*5);
204 return;
205 }
206
207 printf("Loading firmware");
208
209 rc = load_firmware((unsigned char *)DRAM_START,
210 BOOTFILE, MAX_LOADSIZE);
211
212 if (rc < EOK)
213 {
214 printf("Error!");
215 printf("Can't load " BOOTFILE ": ");
216 printf("Result: %s", strerror(rc));
217 sleep(HZ*5);
218 return;
219 }
220
221 start_rockbox();
222}
223
224static void bootmenu(void)
225{
Marcin Bukat28d54c62010-04-26 21:40:16 +0000226 enum option_t i;
227 enum option_t option = rockbox;
228 int button;
229 const char select[] = "->";
230 long start_tick = current_tick;
231
232 /* backbone of menu */
233 /* run the loader */
234 printf("Rockbox boot loader");
Rafaël Carré5d236b22010-05-27 09:41:46 +0000235 printf("Ver: " RBVERSION);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000236
237 check_battery();
238
239 printf("");
240 printf("=========================");
241
242 line += BOOTMENU_OPTIONS+2; /* skip lines */
243
244 printf("=========================");
245 printf("");
246 printf(" [FF] [PREV] to move ");
247 printf(" [PLAY] to confirm ");
248
249 /* content of menu and keys handling */
250 while (TIME_BEFORE(current_tick,start_tick + BOOTMENU_TIMEOUT))
251 {
252 /* Draw the menu. */
253 line = 6; /* move below header */
254
255 for (i=0;i<BOOTMENU_OPTIONS;i++)
256 {
257 if (i != option)
258 printf(" %s",bootmenu_options[i]);
259 else
260 printf("%s %s",select,bootmenu_options[i]);
261 }
262
263 line = 15;
264
265 printf("Time left: %ds",(BOOTMENU_TIMEOUT -
266 (current_tick - start_tick))/HZ);
267
268 lcd_update();
269
270 button = button_get_w_tmo(HZ);
271
272 switch (button)
273 {
274 case BUTTON_PREV:
275 if (option > rockbox)
276 option--;
277 else
278 option = shutdown;
279 break;
280
281 case BUTTON_NEXT:
282 if (option < shutdown)
283 option++;
284 else
285 option = rockbox;
286 break;
287
288 case BUTTON_PLAY:
289 case (BUTTON_PLAY|BUTTON_REC):
290 reset_screen();
291
292 switch (option)
293 {
294 case rockbox:
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000295 rb_boot();
Marcin Bukat28d54c62010-04-26 21:40:16 +0000296 break;
297
298 case mpio_firmware:
299 start_mpio_firmware();
300 break;
301
302 default:
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000303 return;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000304 break;
305 }
306 }
307}
308/* timeout */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000309}
310
311void main(void)
312{
313 /* messages */
314 const char usb_connect_msg[] = "Bootloader USB mode";
315 const char charging_msg[] = "Charging...";
316 const char complete_msg[] = "Charging complete";
Marcin Bukat28d54c62010-04-26 21:40:16 +0000317
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000318 /* helper variable for messages */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000319 bool blink_toggle = false;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000320
Marcin Bukat28d54c62010-04-26 21:40:16 +0000321 int button;
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000322 unsigned int event = EVENT_NONE;
323 unsigned int last_event = EVENT_NONE;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000324
325 power_init();
326
327 system_init();
328 kernel_init();
329
330 set_cpu_frequency(CPUFREQ_NORMAL);
331 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
332
333 enable_irq();
334 lcd_init();
335
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000336 /* only lowlevel functions no queue init */
337 _backlight_init();
338 _backlight_hw_on();
339
340 /* setup font system*/
Marcin Bukat28d54c62010-04-26 21:40:16 +0000341 font_init();
342 lcd_setfont(FONT_SYSFIXED);
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000343
344 /* buttons reading */
Marcin Bukat28d54c62010-04-26 21:40:16 +0000345 adc_init();
346 button_init();
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000347
Marcin Bukat28d54c62010-04-26 21:40:16 +0000348 usb_init();
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000349 cpu_idle_mode(true);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000350
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000351 /* Handle wakeup event. Possibilities are:
352 * ON button (PLAY)
353 * USB insert
354 * AC charger plug
355 */
356
357 while(1)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000358 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000359 /* read buttons */
360 event = EVENT_NONE;
361 button = button_get_w_tmo(HZ);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000362
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000363 if ( button & BUTTON_PLAY )
364 event |= EVENT_ON;
365
366 if ( usb_detect() == USB_INSERTED )
367 event |= EVENT_USB;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000368
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000369 if ( _charger_inserted() )
370 event |= EVENT_AC;
371
372 reset_screen();
373 switch (event)
Marcin Bukat28d54c62010-04-26 21:40:16 +0000374 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000375 case EVENT_ON:
376 case (EVENT_ON | EVENT_AC):
377 /* hold is handled in button driver */
378 cpu_idle_mode(false);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000379
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000380 if (button == (BUTTON_PLAY|BUTTON_REC))
381 bootmenu();
382 else
383 rb_boot();
384
Marcin Bukat28d54c62010-04-26 21:40:16 +0000385 break;
386
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000387 case EVENT_AC:
388 /* turn on charging */
389 if (!(last_event & EVENT_AC))
390 or_l((1<<15),&GPIO_OUT);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000391
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000392 /* USB unplug */
393 if (last_event & EVENT_USB)
394 usb_enable(false);
395
Marcin Bukat28d54c62010-04-26 21:40:16 +0000396 if(!_battery_full())
397 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000398 if (blink_toggle)
399 lcd_putstring_centered(charging_msg);
400
Marcin Bukat28d54c62010-04-26 21:40:16 +0000401 blink_toggle = !blink_toggle;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000402 }
403 else
404 {
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000405 lcd_putstring_centered(complete_msg);
Marcin Bukat28d54c62010-04-26 21:40:16 +0000406 }
Marcin Bukat28d54c62010-04-26 21:40:16 +0000407 check_battery();
408 break;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000409
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000410 case EVENT_USB:
411 case (EVENT_USB | EVENT_AC):
412 if (!(last_event & EVENT_AC))
413 or_l((1<<15),&GPIO_OUT);
414
415 if (!(last_event & EVENT_USB))
416 {
417 /* init USB */
418 ide_power_enable(true);
419 sleep(HZ/20);
420 usb_enable(true);
421 }
422
423 line = 0;
424
425 if (blink_toggle)
426 lcd_putstring_centered(usb_connect_msg);
427
428 check_battery();
429 blink_toggle = !blink_toggle;
430 storage_spin();
431 break;
432
433 default:
434 /* spurious wakeup */
435 __shutdown();
436 break;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000437 }
Marcin Bukat28d54c62010-04-26 21:40:16 +0000438 lcd_update();
Marcin Bukat69fa42d2010-05-04 11:16:17 +0000439 last_event = event;
Marcin Bukat28d54c62010-04-26 21:40:16 +0000440 }
441
Marcin Bukat28d54c62010-04-26 21:40:16 +0000442}
443
444/* These functions are present in the firmware library, but we reimplement
445 them here because the originals do a lot more than we want */
446void screen_dump(void)
447{
448}