summaryrefslogtreecommitdiff
path: root/bootloader/mpio_hd200.c
diff options
context:
space:
mode:
Diffstat (limited to 'bootloader/mpio_hd200.c')
-rw-r--r--bootloader/mpio_hd200.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/bootloader/mpio_hd200.c b/bootloader/mpio_hd200.c
new file mode 100644
index 0000000000..68152f3c2d
--- /dev/null
+++ b/bootloader/mpio_hd200.c
@@ -0,0 +1,459 @@
1/***************************************************************************
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"
46
47#include <stdarg.h>
48
49/* Maximum allowed firmware image size. 10MB is more than enough */
50#define MAX_LOADSIZE (10*1024*1024)
51
52#define DRAM_START 0x31000000
53
54#define BOOTMENU_TIMEOUT (10*HZ)
55#define BOOTMENU_OPTIONS 3
56
57/* From common.c */
58extern int line;
59static const char *bootmenu_options[] = {
60 "Boot rockbox",
61 "Boot MPIO firmware",
62 "Shutdown"
63};
64
65enum option_t {
66 rockbox,
67 mpio_firmware,
68 shutdown
69};
70
71int usb_screen(void)
72{
73 return 0;
74}
75
76char version[] = APPSVERSION;
77
78bool _charger_inserted(void)
79{
80 return (GPIO1_READ & (1<<14)) ? false : true;
81}
82
83bool _battery_full(void)
84{
85 return (GPIO_READ & (1<<30)) ? true : false;
86}
87
88/* Reset the cookie for the crt0 crash check */
89inline void __reset_cookie(void)
90{
91 asm(" move.l #0,%d0");
92 asm(" move.l %d0,0x10017ffc");
93}
94
95void start_rockbox(void)
96{
97 adc_close();
98 asm(" move.w #0x2700,%sr");
99 __reset_cookie();
100 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
101 asm(" movec.l %d0,%vbr");
102 asm(" move.l %0,%%sp" :: "m"(*(int *)DRAM_START));
103 asm(" move.l %0,%%a0" :: "m"(*(int *)(DRAM_START+4)));
104 asm(" jmp (%a0)");
105}
106
107void start_mpio_firmware(void)
108{
109 asm(" move.w #0x2700,%sr");
110 __reset_cookie();
111 asm(" movec.l %d0,%vbr");
112 asm(" move.l 0,%sp");
113 asm(" jmp 8");
114}
115
116void __reset(void)
117{
118 asm(" move.w #0x2700,%sr");
119 __reset_cookie();
120 asm(" movec.l %d0,%vbr");
121 asm(" move.l (0), %sp");
122 asm(" movea.l (4),%a0");
123 asm(" jmp (%a0)");
124}
125
126void __shutdown(void)
127{
128 /* We need to gracefully spin down the disk to prevent clicks. */
129 if (ide_powered())
130 {
131 /* Make sure ATA has been initialized. */
132 storage_init();
133
134 /* And put the disk into sleep immediately. */
135 storage_sleepnow();
136 }
137
138 /* Backlight OFF */
139 _backlight_off();
140 __reset_cookie();
141
142 if (_charger_inserted())
143 {
144 /* reset instead of power_off() */
145 __reset();
146 }
147 else
148 {
149 power_off();
150 }
151}
152
153/* Print the battery voltage (and a warning message). */
154void check_battery(void)
155{
156
157 int battery_voltage, batt_int, batt_frac;
158
159 battery_voltage = battery_adc_voltage();
160 batt_int = battery_voltage / 1000;
161 batt_frac = (battery_voltage % 1000) / 10;
162
163 printf("Battery: %d.%02dV", batt_int, batt_frac);
164
165 if (battery_voltage <= 3500)
166 {
167 printf("WARNING! BATTERY LOW!!");
168 sleep(HZ*2);
169 }
170
171}
172
173
174void lcd_putstring_centered(const char *string)
175{
176 int w,h;
177 font_getstringsize(string, &w, &h, FONT_SYSFIXED);
178 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, string);
179}
180
181void bootmenu(void)
182{
183 int rc;
184 enum option_t i;
185 enum option_t option = rockbox;
186 int button;
187 const char select[] = "->";
188 long start_tick = current_tick;
189
190 /* backbone of menu */
191 /* run the loader */
192 printf("Rockbox boot loader");
193 printf("Ver: %s", version);
194
195 check_battery();
196
197 printf("");
198 printf("=========================");
199
200 line += BOOTMENU_OPTIONS+2; /* skip lines */
201
202 printf("=========================");
203 printf("");
204 printf(" [FF] [PREV] to move ");
205 printf(" [PLAY] to confirm ");
206
207 /* content of menu and keys handling */
208 while (TIME_BEFORE(current_tick,start_tick + BOOTMENU_TIMEOUT))
209 {
210 /* Draw the menu. */
211 line = 6; /* move below header */
212
213 for (i=0;i<BOOTMENU_OPTIONS;i++)
214 {
215 if (i != option)
216 printf(" %s",bootmenu_options[i]);
217 else
218 printf("%s %s",select,bootmenu_options[i]);
219 }
220
221 line = 15;
222
223 printf("Time left: %ds",(BOOTMENU_TIMEOUT -
224 (current_tick - start_tick))/HZ);
225
226 lcd_update();
227
228 button = button_get_w_tmo(HZ);
229
230 switch (button)
231 {
232 case BUTTON_PREV:
233 if (option > rockbox)
234 option--;
235 else
236 option = shutdown;
237 break;
238
239 case BUTTON_NEXT:
240 if (option < shutdown)
241 option++;
242 else
243 option = rockbox;
244 break;
245
246 case BUTTON_PLAY:
247 case (BUTTON_PLAY|BUTTON_REC):
248 reset_screen();
249
250 switch (option)
251 {
252 case rockbox:
253 rc = storage_init();
254 if(rc)
255 {
256 printf("ATA error: %d", rc);
257 sleep(HZ*5);
258 __shutdown();
259 }
260
261 disk_init();
262
263 rc = disk_mount_all();
264 if (rc<=0)
265 {
266 printf("No partition found");
267 sleep(HZ*5);
268 __shutdown();
269 }
270
271 printf("Loading firmware");
272 rc = load_firmware((unsigned char *)DRAM_START,
273 BOOTFILE, MAX_LOADSIZE);
274 printf("Result: %s", strerror(rc));
275
276 if (rc < EOK)
277 {
278 printf("Error!");
279 printf("Can't load " BOOTFILE ": ");
280 printf(strerror(rc));
281 sleep(HZ*5);
282 __shutdown();
283 }
284 else
285 {
286 start_rockbox();
287 }
288
289 break;
290
291 case mpio_firmware:
292 start_mpio_firmware();
293 break;
294
295 default:
296 __shutdown();
297 break;
298 }
299 }
300}
301/* timeout */
302__shutdown();
303}
304
305void main(void)
306{
307 /* messages */
308 const char usb_connect_msg[] = "Bootloader USB mode";
309 const char charging_msg[] = "Charging...";
310 const char complete_msg[] = "Charging complete";
311 const char hold_msg[] = "Hold switch on";
312 const char shutdown_msg[] = "Shutting down...";
313
314 /* helper variables for messages */
315 bool blink_toggle = false;
316 const char *msg;
317
318 bool on_button = false;
319 int button;
320
321 /* We want to read the buttons as early as possible, before the user
322 releases the ON button */
323
324 or_l( ((1<<24)|(1<<4)), &GPIO1_FUNCTION); /* main Hold & Play */
325 and_l( ~((1<<24)|(1<<4)), &GPIO1_ENABLE); /* HiZ */
326
327 if (GPIO1_READ & (1<<24))
328 on_button = true;
329
330 power_init();
331
332 system_init();
333 kernel_init();
334
335 set_cpu_frequency(CPUFREQ_NORMAL);
336 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
337
338 enable_irq();
339 lcd_init();
340
341 backlight_init();
342 font_init();
343 lcd_setfont(FONT_SYSFIXED);
344
345 adc_init();
346 button_init();
347 usb_init();
348
349 /* handle charging */
350 if( _charger_inserted())
351 {
352 or_l((1<<15),&GPIO_OUT);
353
354 cpu_idle_mode(true);
355
356 while( _charger_inserted() &&
357 usb_detect() != USB_INSERTED &&
358 !on_button)
359 {
360 button = button_get_w_tmo(HZ);
361
362 switch(button)
363 {
364 case BUTTON_ON:
365 on_button = true;
366 reset_screen();
367 break;
368
369 case BUTTON_NONE: /* Timeout */
370
371 if(!_battery_full())
372 {
373 /* To be replaced with a nice animation */
374 blink_toggle = !blink_toggle;
375 msg = charging_msg;
376 }
377 else
378 {
379 blink_toggle = true;
380 msg = complete_msg;
381 }
382
383 reset_screen();
384 if(blink_toggle)
385 lcd_putstring_centered(msg);
386
387 check_battery();
388 break;
389 }
390
391 }
392 cpu_idle_mode(false);
393 }
394
395 /* handle USB in bootloader */
396 if (usb_detect() == USB_INSERTED)
397 {
398 ide_power_enable(true);
399 sleep(HZ/20);
400 usb_enable(true);
401 cpu_idle_mode(true);
402
403 while (usb_detect() == USB_INSERTED)
404 {
405 line = 0;
406
407 reset_screen();
408
409 if(blink_toggle)
410 {
411 lcd_putstring_centered(usb_connect_msg);
412 }
413
414 check_battery();
415 blink_toggle = !blink_toggle;
416
417 storage_spin(); /* Prevent the drive from spinning down */
418 sleep(HZ);
419 }
420
421 cpu_idle_mode(false);
422 usb_enable(false);
423
424 sleep(HZ);
425 reset_screen();
426 lcd_update();
427 }
428
429 /* handle ON button press */
430 if (on_button)
431 {
432 if (button_hold() &&
433 !_charger_inserted() &&
434 usb_detect() != USB_INSERTED)
435 {
436 lcd_putstring_centered(hold_msg);
437 lcd_update();
438 sleep(HZ*3);
439 __shutdown();
440 }
441
442 }
443 else
444 {
445 lcd_putstring_centered(shutdown_msg);
446 lcd_update();
447 sleep(HZ*3);
448 __shutdown();
449 }
450
451
452 bootmenu();
453}
454
455/* These functions are present in the firmware library, but we reimplement
456 them here because the originals do a lot more than we want */
457void screen_dump(void)
458{
459}