Calibrate iPod Classic battery gauge a bit better
[kugel-rb.git] / bootloader / iriver_h1x0.c
blob1afbafa8309c74c27d4df9f0d0f52862b1363538
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Linus Nielsen Feltzing
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 "lcd-remote.h"
31 #include "scroll_engine.h"
32 #include "kernel.h"
33 #include "thread.h"
34 #include "storage.h"
35 #include "usb.h"
36 #include "disk.h"
37 #include "font.h"
38 #include "adc.h"
39 #include "backlight.h"
40 #include "backlight-target.h"
41 #include "button.h"
42 #include "panic.h"
43 #include "power.h"
44 #include "powermgmt.h"
45 #include "file.h"
46 #include "eeprom_settings.h"
47 #include "rbunicode.h"
48 #include "common.h"
49 #include "version.h"
51 #include <stdarg.h>
53 /* Maximum allowed firmware image size. 10MB is more than enough */
54 #define MAX_LOADSIZE (10*1024*1024)
56 #define DRAM_START 0x31000000
58 #ifdef HAVE_EEPROM_SETTINGS
59 static bool recovery_mode = false;
60 #endif
62 /* Reset the cookie for the crt0 crash check */
63 inline void __reset_cookie(void)
65 asm(" move.l #0,%d0");
66 asm(" move.l %d0,0x10017ffc");
69 void start_iriver_fw(void)
71 asm(" move.w #0x2700,%sr");
72 __reset_cookie();
73 asm(" movec.l %d0,%vbr");
74 asm(" move.l 0,%sp");
75 asm(" lea.l 8,%a0");
76 asm(" jmp (%a0)");
79 void start_firmware(void)
81 asm(" move.w #0x2700,%sr");
82 __reset_cookie();
83 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
84 asm(" movec.l %d0,%vbr");
85 asm(" move.l %0,%%sp" :: "m"(*(int *)DRAM_START));
86 asm(" move.l %0,%%a0" :: "m"(*(int *)(DRAM_START+4)));
87 asm(" jmp (%a0)");
90 #ifdef IRIVER_H100_SERIES
91 void start_flashed_romimage(void)
93 uint8_t *src = (uint8_t *)FLASH_ROMIMAGE_ENTRY;
94 int *reset_vector;
96 if (!detect_flashed_romimage())
97 return ;
99 reset_vector = (int *)(&src[sizeof(struct flash_header)+4]);
101 asm(" move.w #0x2700,%sr");
102 __reset_cookie();
104 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
105 asm(" movec.l %d0,%vbr");
106 asm(" move.l %0,%%sp" :: "m"(reset_vector[0]));
107 asm(" move.l %0,%%a0" :: "m"(reset_vector[1]));
108 asm(" jmp (%a0)");
110 /* Failure */
111 power_off();
114 void start_flashed_ramimage(void)
116 struct flash_header hdr;
117 unsigned char *buf = (unsigned char *)DRAM_START;
118 uint8_t *src = (uint8_t *)FLASH_RAMIMAGE_ENTRY;
120 if (!detect_flashed_ramimage())
121 return;
123 /* Load firmware from flash */
124 cpu_boost(true);
125 memcpy(&hdr, src, sizeof(struct flash_header));
126 src += sizeof(struct flash_header);
127 memcpy(buf, src, hdr.length);
128 cpu_boost(false);
130 start_firmware();
132 /* Failure */
133 power_off();
135 #endif /* IRIVER_H100_SERIES */
137 void shutdown(void)
139 printf("Shutting down...");
140 #ifdef HAVE_EEPROM_SETTINGS
141 /* Reset the rockbox crash check. */
142 firmware_settings.bl_version = 0;
143 eeprom_settings_store();
144 #endif
146 /* We need to gracefully spin down the disk to prevent clicks. */
147 if (ide_powered())
149 /* Make sure ATA has been initialized. */
150 storage_init();
152 /* And put the disk into sleep immediately. */
153 storage_sleepnow();
156 sleep(HZ*2);
158 /* Backlight OFF */
159 _backlight_off();
160 #ifdef HAVE_REMOTE_LCD
161 _remote_backlight_off();
162 #endif
164 __reset_cookie();
165 power_off();
168 /* Print the battery voltage (and a warning message). */
169 void check_battery(void)
171 int battery_voltage, batt_int, batt_frac;
173 battery_voltage = battery_adc_voltage();
174 batt_int = battery_voltage / 1000;
175 batt_frac = (battery_voltage % 1000) / 10;
177 printf("Batt: %d.%02dV", batt_int, batt_frac);
179 if (battery_voltage <= 310)
181 printf("WARNING! BATTERY LOW!!");
182 sleep(HZ*2);
186 #ifdef HAVE_EEPROM_SETTINGS
187 void initialize_eeprom(void)
189 if (detect_original_firmware())
190 return ;
192 if (!eeprom_settings_init())
194 recovery_mode = true;
195 return ;
198 /* If bootloader version has not been reset, disk might
199 * not be intact. */
200 if (firmware_settings.bl_version || !firmware_settings.disk_clean)
202 firmware_settings.disk_clean = false;
203 recovery_mode = true;
206 firmware_settings.bl_version = EEPROM_SETTINGS_BL_MINVER;
207 eeprom_settings_store();
210 void try_flashboot(void)
212 if (!firmware_settings.initialized)
213 return ;
215 switch (firmware_settings.bootmethod)
217 case BOOT_DISK:
218 return;
220 case BOOT_ROM:
221 start_flashed_romimage();
222 recovery_mode = true;
223 break;
225 case BOOT_RAM:
226 start_flashed_ramimage();
227 recovery_mode = true;
228 break;
230 default:
231 recovery_mode = true;
232 return;
236 static const char *options[] = {
237 "Boot from disk",
238 "Boot RAM image",
239 "Boot ROM image",
240 "Shutdown"
243 #define FAILSAFE_OPTIONS 4
244 #define TIMEOUT (15*HZ)
245 void failsafe_menu(void)
247 long start_tick = current_tick;
248 int option = 3;
249 int button;
250 int defopt = -1;
251 char buf[32];
252 int i;
253 extern int line;
255 reset_screen();
256 printf("Bootloader " RBVERSION);
257 check_battery();
258 printf("=========================");
259 line += FAILSAFE_OPTIONS;
260 printf("");
261 printf(" [NAVI] to confirm.");
262 printf(" [REC] to set as default.");
263 printf("");
265 if (firmware_settings.initialized)
267 defopt = firmware_settings.bootmethod;
268 if (defopt < 0 || defopt >= FAILSAFE_OPTIONS)
269 defopt = option;
272 while (current_tick - start_tick < TIMEOUT)
274 /* Draw the menu. */
275 line = 3;
276 for (i = 0; i < FAILSAFE_OPTIONS; i++)
278 char *def = "[DEF]";
279 char *arrow = "->";
281 if (i != defopt)
282 def = "";
283 if (i != option)
284 arrow = " ";
286 printf("%s %s %s", arrow, options[i], def);
289 snprintf(buf, sizeof(buf), "Time left: %lds",
290 (TIMEOUT - (current_tick - start_tick)) / HZ);
291 lcd_puts(0, 10, buf);
292 lcd_update();
293 button = button_get_w_tmo(HZ);
295 if (button == BUTTON_NONE || button & SYS_EVENT)
296 continue ;
298 start_tick = current_tick;
300 /* Ignore the ON/PLAY -button because it can cause trouble
301 with the RTC alarm mod. */
302 switch (button & ~(BUTTON_ON))
304 case BUTTON_UP:
305 case BUTTON_RC_REW:
306 if (option > 0)
307 option--;
308 break ;
310 case BUTTON_DOWN:
311 case BUTTON_RC_FF:
312 if (option < FAILSAFE_OPTIONS-1)
313 option++;
314 break ;
316 case BUTTON_SELECT:
317 case BUTTON_RC_ON:
318 goto execute;
320 case BUTTON_REC:
321 case BUTTON_RC_REC:
322 if (firmware_settings.initialized)
324 firmware_settings.bootmethod = option;
325 eeprom_settings_store();
326 defopt = option;
328 break ;
332 execute:
334 lcd_puts(0, 10, "Executing command...");
335 lcd_update();
336 sleep(HZ);
337 reset_screen();
339 switch (option)
341 case BOOT_DISK:
342 return ;
344 case BOOT_RAM:
345 start_flashed_ramimage();
346 printf("Image not found");
347 break;
349 case BOOT_ROM:
350 start_flashed_romimage();
351 printf("Image not found");
352 break;
355 shutdown();
357 #endif
359 /* get rid of a nasty humming sound during boot
360 -> RESET signal */
361 inline static void __uda1380_reset_hi(void)
363 #ifdef HAVE_UDA1380
364 or_l(1<<29, &GPIO_OUT);
365 or_l(1<<29, &GPIO_ENABLE);
366 or_l(1<<29, &GPIO_FUNCTION);
367 #endif
370 inline static void __uda1380_reset_lo(void)
372 #ifdef HAVE_UDA1380
373 and_l(~(1<<29), &GPIO_OUT);
374 #endif
377 void main(void)
379 int i;
380 int rc;
381 bool rc_on_button = false;
382 bool on_button = false;
383 bool rec_button = false;
384 bool hold_status = false;
385 int data;
386 extern int line; /* From common.c */
387 extern int remote_line; /* From common.c */
389 /* We want to read the buttons as early as possible, before the user
390 releases the ON button */
392 /* Set GPIO33, GPIO37, GPIO38 and GPIO52 as general purpose inputs
393 (The ON and Hold buttons on the main unit and the remote) */
394 or_l(0x00100062, &GPIO1_FUNCTION);
395 and_l(~0x00100062, &GPIO1_ENABLE);
397 data = GPIO1_READ;
398 if ((data & 0x20) == 0)
399 on_button = true;
401 if ((data & 0x40) == 0)
402 rc_on_button = true;
404 /* Set the default state of the hard drive power to OFF */
405 ide_power_enable(false);
407 power_init();
409 /* Turn off if neither ON button is pressed */
410 if (!(on_button || rc_on_button))
412 __reset_cookie();
413 power_off();
416 __uda1380_reset_hi();
418 /* Start with the main backlight OFF. */
419 _backlight_init();
420 _backlight_off();
422 /* Remote backlight ON */
423 #ifdef HAVE_REMOTE_LCD
424 _remote_backlight_on();
425 #endif
427 system_init();
428 kernel_init();
430 __uda1380_reset_lo();
432 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
433 /* Set up waitstates for the peripherals */
434 set_cpu_frequency(0); /* PLL off */
435 #ifdef CPU_COLDFIRE
436 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
437 #endif
438 #endif
439 enable_irq();
441 #ifdef HAVE_EEPROM_SETTINGS
442 initialize_eeprom();
443 #endif
445 usb_init();
446 /* A small delay after usb_init is necessary to read the I/O port correctly
447 (if ports are read _immediately_ after the init). */
448 /* sleep(1); */
450 adc_init();
451 button_init();
453 /* Only check remote hold status if remote power button was actually used. */
454 if (rc_on_button)
456 lcd_remote_init();
458 /* Allow the button driver to check the buttons */
459 sleep(HZ/50);
461 if (remote_button_hold())
462 hold_status = true;
465 /* Check main hold switch status too. */
466 if (on_button && button_hold())
468 hold_status = true;
471 /* Power on the hard drive early, to speed up the loading. */
472 if (!hold_status
473 # ifdef HAVE_EEPROM_SETTINGS
474 && !recovery_mode
475 # endif
478 ide_power_enable(true);
481 # ifdef HAVE_EEPROM_SETTINGS
482 if (!hold_status && (usb_detect() != USB_INSERTED) && !recovery_mode)
483 try_flashboot();
484 # endif
486 backlight_init();
489 lcd_init();
491 if (!rc_on_button)
492 lcd_remote_init();
494 /* Bootloader uses simplified backlight thread, so we need to enable
495 remote display here. */
496 if (remote_detect())
497 lcd_remote_on();
499 font_init();
501 lcd_setfont(FONT_SYSFIXED);
503 printf("Rockbox boot loader");
504 printf("Version " RBVERSION);
506 /* No need to wait here more because lcd_init and others already do that. */
507 // sleep(HZ/50); /* Allow the button driver to check the buttons */
508 rec_button = ((button_status() & BUTTON_REC) == BUTTON_REC)
509 || ((button_status() & BUTTON_RC_REC) == BUTTON_RC_REC);
511 check_battery();
513 /* Don't start if the Hold button is active on the device you
514 are starting with */
515 if ((usb_detect() != USB_INSERTED) && (hold_status
516 #ifdef HAVE_EEPROM_SETTINGS
517 || recovery_mode
518 #endif
521 if (detect_original_firmware())
523 printf("Hold switch on");
524 shutdown();
527 #ifdef HAVE_EEPROM_SETTINGS
528 failsafe_menu();
529 #endif
532 /* Holding REC while starting runs the original firmware */
533 if (detect_original_firmware() && rec_button)
535 printf("Starting original firmware...");
536 start_iriver_fw();
539 /* A hack to enter USB mode without using the USB thread */
540 if(usb_detect() == USB_INSERTED)
542 const char msg[] = "Bootloader USB mode";
543 int w, h;
544 font_getstringsize(msg, &w, &h, FONT_SYSFIXED);
545 reset_screen();
546 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, msg);
547 lcd_update();
549 #ifdef HAVE_REMOTE_LCD
550 lcd_remote_puts(0, 3, msg);
551 lcd_remote_update();
552 #endif
554 #ifdef HAVE_EEPROM_SETTINGS
555 if (firmware_settings.initialized)
557 firmware_settings.disk_clean = false;
558 eeprom_settings_store();
560 #endif
561 ide_power_enable(true);
562 storage_enable(false);
563 sleep(HZ/20);
564 usb_enable(true);
565 cpu_idle_mode(true);
566 while (usb_detect() == USB_INSERTED)
568 /* Print the battery status. */
569 line = 0;
570 remote_line = 0;
571 check_battery();
573 storage_spin(); /* Prevent the drive from spinning down */
574 sleep(HZ);
576 /* Backlight OFF */
577 _backlight_off();
580 cpu_idle_mode(false);
581 usb_enable(false);
583 reset_screen();
584 lcd_update();
587 rc = storage_init();
588 if(rc)
590 reset_screen();
591 printf("ATA error: %d", rc);
592 printf("Insert USB cable and press");
593 printf("a button");
594 while(!(button_get(true) & BUTTON_REL));
598 disk_init();
600 rc = disk_mount_all();
601 if (rc<=0)
603 reset_screen();
604 printf("No partition found");
605 while(button_get(true) != SYS_USB_CONNECTED) {};
608 printf("Loading firmware");
609 i = load_firmware((unsigned char *)DRAM_START, BOOTFILE, MAX_LOADSIZE);
610 if(i < 0)
611 printf("Error: %s", strerror(i));
613 if (i == EOK)
614 start_firmware();
616 if (!detect_original_firmware())
618 printf("No firmware found on disk");
619 sleep(HZ*2);
620 shutdown();
622 else {
623 sleep(HZ*2);
624 start_iriver_fw();
628 /* These functions are present in the firmware library, but we reimplement
629 them here because the originals do a lot more than we want */
630 void screen_dump(void)
634 int usb_screen(void)
636 return 0;
639 unsigned short *bidi_l2v(const unsigned char *str, int orientation)
641 static unsigned short utf16_buf[SCROLL_LINE_SIZE];
642 unsigned short *target;
643 (void)orientation;
645 target = utf16_buf;
647 while (*str)
648 str = utf8decode(str, target++);
649 *target = 0;
650 return utf16_buf;