diff options
Diffstat (limited to 'bootloader')
-rw-r--r-- | bootloader/mpio_hd200.c | 459 |
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 */ | ||
58 | extern int line; | ||
59 | static const char *bootmenu_options[] = { | ||
60 | "Boot rockbox", | ||
61 | "Boot MPIO firmware", | ||
62 | "Shutdown" | ||
63 | }; | ||
64 | |||
65 | enum option_t { | ||
66 | rockbox, | ||
67 | mpio_firmware, | ||
68 | shutdown | ||
69 | }; | ||
70 | |||
71 | int usb_screen(void) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | char version[] = APPSVERSION; | ||
77 | |||
78 | bool _charger_inserted(void) | ||
79 | { | ||
80 | return (GPIO1_READ & (1<<14)) ? false : true; | ||
81 | } | ||
82 | |||
83 | bool _battery_full(void) | ||
84 | { | ||
85 | return (GPIO_READ & (1<<30)) ? true : false; | ||
86 | } | ||
87 | |||
88 | /* Reset the cookie for the crt0 crash check */ | ||
89 | inline void __reset_cookie(void) | ||
90 | { | ||
91 | asm(" move.l #0,%d0"); | ||
92 | asm(" move.l %d0,0x10017ffc"); | ||
93 | } | ||
94 | |||
95 | void 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 | |||
107 | void 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 | |||
116 | void __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 | |||
126 | void __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). */ | ||
154 | void 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 | |||
174 | void 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 | |||
181 | void 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 | |||
305 | void 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 */ | ||
457 | void screen_dump(void) | ||
458 | { | ||
459 | } | ||