blob: 0d0a4c53d16090488352e24de30c50c107ebaedf [file] [log] [blame]
Cástor Muñoz882921e2016-02-05 02:02:02 +01001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Dave Chapman
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 <stdlib.h>
22#include <stdio.h>
23#include <stdarg.h>
24#include <string.h>
25
26#include "config.h"
27
28#include "inttypes.h"
29#include "cpu.h"
30#include "system.h"
31#include "lcd.h"
32#include "../kernel-internal.h"
33#include "file_internal.h"
34#include "storage.h"
Cástor Muñoz882921e2016-02-05 02:02:02 +010035#include "disk.h"
36#include "font.h"
37#include "backlight.h"
38#include "backlight-target.h"
39#include "button.h"
40#include "panic.h"
41#include "power.h"
42#include "file.h"
43#include "common.h"
44#include "rb-loader.h"
45#include "loader_strerror.h"
46#include "version.h"
47#include "powermgmt.h"
48#include "usb.h"
49#ifdef HAVE_SERIAL
50#include "serial.h"
51#endif
52
53#include "s5l8702.h"
54#include "clocking-s5l8702.h"
55#include "spi-s5l8702.h"
56#include "i2c-s5l8702.h"
57#include "gpio-s5l8702.h"
58#include "pmu-target.h"
59#include "nor-target.h"
60
61
62#define FW_ROCKBOX 0
63#define FW_APPLE 1
64
65#define ERR_RB 0
66#define ERR_OF 1
67#define ERR_HDD 2
68
69/* Safety measure - maximum allowed firmware image size.
70 The largest known current (October 2009) firmware is about 6.2MB so
71 we set this to 8MB.
72*/
73#define MAX_LOADSIZE (8*1024*1024)
74
75#define LCD_RBYELLOW LCD_RGBPACK(255,192,0)
76#define LCD_REDORANGE LCD_RGBPACK(255,70,0)
77
78extern void bss_init(void);
79extern uint32_t _movestart;
80extern uint32_t start_loc;
81
82extern int line;
83
84#ifdef HAVE_BOOTLOADER_USB_MODE
85static void usb_mode(void)
86{
87 int button;
88
89 verbose = true;
90
91 printf("Entering USB mode...");
92
93 powermgmt_init();
94
95 /* The code will ask for the maximum possible value */
96 usb_charging_enable(USB_CHARGING_ENABLE);
97
98 usb_init();
99 usb_start_monitoring();
100
101 /* Wait until USB is plugged */
102 while (usb_detect() != USB_INSERTED)
103 {
104 printf("Plug USB cable");
105 line--;
106 sleep(HZ/10);
107 }
108
109 while(1)
110 {
111 button = button_get_w_tmo(HZ/10);
112
113 if (button == SYS_USB_CONNECTED)
114 break; /* Hit */
115
116 if (usb_detect() == USB_EXTRACTED)
117 break; /* Cable pulled */
118
119 /* Wait for threads to connect or cable is pulled */
120 printf("USB: Connecting...");
121 line--;
122 }
123
124 if (button == SYS_USB_CONNECTED)
125 {
126 /* Got the message - wait for disconnect */
127 printf("Bootloader USB mode");
128
129 /* Ack the SYS_USB_CONNECTED polled from the button queue */
130 usb_acknowledge(SYS_USB_CONNECTED_ACK);
131
132 while(1)
133 {
134 button = button_get_w_tmo(HZ/2);
135 if (button == SYS_USB_DISCONNECTED)
136 break;
137 }
138 }
139
140 /* We don't want the HDD to spin up if the USB is attached again */
141 usb_close();
142 printf("USB mode exit ");
143}
144#endif /* HAVE_BOOTLOADER_USB_MODE */
145
146void fatal_error(int err)
147{
148 verbose = true;
149
150 /* System font is 6 pixels wide */
151 line++;
152 switch (err)
153 {
154 case ERR_RB:
155#ifdef HAVE_BOOTLOADER_USB_MODE
156 usb_mode();
157 printf("Hold MENU+SELECT to reboot");
158 break;
159#endif
160 case ERR_HDD:
161 printf("Hold MENU+SELECT to reboot");
162 printf("then SELECT+PLAY for disk mode");
163 break;
164 case ERR_OF:
165 printf("Hold MENU+SELECT to reboot");
166 printf("and enter Rockbox firmware");
167 break;
168 }
169
170 if (ide_powered())
171 ata_sleepnow(); /* Immediately spindown the disk. */
172
173 line++;
174 lcd_set_foreground(LCD_REDORANGE);
175 while (1) {
176 lcd_puts(0, line, button_hold() ? "Hold switch on!"
177 : " ");
178 lcd_update();
179 }
180}
181
182static void battery_trap(void)
183{
184 int vbat, old_verb;
185 int th = 50;
186
187 old_verb = verbose;
188 verbose = true;
189
190 usb_charging_maxcurrent_change(100);
191
192 while (1)
193 {
194 vbat = _battery_voltage();
195
196 /* Two reasons to use this threshold (may require adjustments):
197 * - when USB (or wall adaptor) is plugged/unplugged, Vbat readings
198 * differ as much as more than 200 mV when charge current is at
199 * maximum (~340 mA).
200 * - RB uses some sort of average/compensation for battery voltage
201 * measurements, battery icon blinks at battery_level_dangerous,
202 * when the HDD is used heavily (large database) the level drops
203 * to battery_level_shutoff quickly.
204 */
205 if (vbat >= battery_level_dangerous[0] + th)
206 break;
207 th = 200;
208
209 if (power_input_status() != POWER_INPUT_NONE) {
210 lcd_set_foreground(LCD_RBYELLOW);
211 printf("Low battery: %d mV, charging... ", vbat);
212 sleep(HZ*3);
213 }
214 else {
215 /* Wait for the user to insert a charger */
216 int tmo = 10;
217 lcd_set_foreground(LCD_REDORANGE);
218 while (1) {
219 vbat = _battery_voltage();
220 printf("Low battery: %d mV, power off in %d ", vbat, tmo);
221 if (!tmo--) {
222 /* Raise Vsysok (hyst=0.02*Vsysok) to avoid PMU
223 standby<->active looping */
224 if (vbat < 3200)
225 pmu_write(PCF5063X_REG_SVMCTL, 0xA /*3200mV*/);
226 power_off();
227 }
228 sleep(HZ*1);
229 if (power_input_status() != POWER_INPUT_NONE)
230 break;
231 line--;
232 }
233 }
234 line--;
235 }
236
237 verbose = old_verb;
238 lcd_set_foreground(LCD_WHITE);
239 printf("Battery status ok: %d mV ", vbat);
240}
241
242static int launch_onb(int clkdiv)
243{
244 /* SPI clock = PClk/(clkdiv+1) */
245 spi_clkdiv(SPI_PORT, clkdiv);
246
247 /* Actually IRAM1_ORIG contains current RB bootloader IM3 header,
248 it will be replaced by ONB IM3 header, so this function must
249 be called once!!! */
250 struct Im3Info *hinfo = (struct Im3Info*)IRAM1_ORIG;
251
252 /* Loads ONB in IRAM0, exception vector table is destroyed !!! */
253 int rc = im3_read(
254 NORBOOT_OFF + im3_nor_sz(hinfo), hinfo, (void*)IRAM0_ORIG);
255
256 if (rc != 0) {
257 /* Restore exception vector table */
258 memcpy((void*)IRAM0_ORIG, &_movestart, 4*(&start_loc-&_movestart));
259 commit_discard_idcache();
260 return rc;
261 }
262
263 /* Disable all external interrupts */
264 eint_init();
265
266 commit_discard_idcache();
267
268 /* Branch to start of IRAM */
269 asm volatile("mov pc, %0"::"r"(IRAM0_ORIG));
270 while(1);
271}
272
273/* Launch OF when kernel mode is running */
274static int kernel_launch_onb(void)
275{
276 disable_irq();
277 int rc = launch_onb(3); /* 54/4 = 13.5 MHz. */
278 enable_irq();
279 return rc;
280}
281
282static bool pmu_is_hibernated(void)
283{
284 /* OF sets GPIO3 to low when SDRAM is hibernated */
285 return !(pmu_rd(PCF5063X_REG_GPIO3CFG) & 7) &&
286 !(pmu_rd(PCF5063X_REG_OOCSHDWN) & PCF5063X_OOCSHDWN_COLDBOOT);
287}
288
289/* The boot sequence is executed on power-on or reset. After power-up
290 * the device could come from a state of hibernation, OF hibernates
291 * the iPod after an inactive period of ~30 minutes (FW 1.1.2), on
292 * this state the SDRAM is in self-refresh mode.
293 *
294 * t0 = 0
295 * S5L8702 BOOTROM loads an IM3 image located at NOR:
296 * - IM3 header (first 0x800 bytes) is loaded at IRAM1_ORIG
297 * - IM3 body (decrypted RB bootloader) is loaded at IRAM0_ORIG
298 * The time needed to load the RB bootloader (~90 Kb) is estimated
299 * on 200~250 ms. Once executed, RB booloader moves itself from
300 * IRAM0_ORIG to IRAM1_ORIG+0x800, preserving current IM3 header
301 * that contains the NOR offset where the ONB (original NOR boot),
302 * is located (see dualboot.c for details).
303 *
304 * t1 = ~250 ms.
305 * If the PMU is hibernated, decrypted ONB (size 128Kb) is loaded
306 * and executed, it takes ~120 ms. Then the ONB restores the
307 * iPod to the state prior to hibernation.
308 * If not, initialize system and RB kernel, wait for t2.
309 *
310 * t2 = ~650 ms.
311 * Check user button selection.
312 * If OF, diagmode, or diskmode is selected then launch ONB.
313 * If not, wait for LCD initialization.
314 *
315 * t3 = ~700,~900 ms. (lcd_type_01,lcd_type_23)
316 * LCD is initialized, baclight ON.
317 * Wait for HDD spin-up.
318 *
319 * t4 = ~2600,~2800 ms.
320 * HDD is ready.
321 * If hold switch is locked, then load and launch ONB.
322 * If not, load rockbox.ipod file from HDD.
323 *
324 * t5 = ~2800,~3000 ms.
325 * rockbox.ipod is executed.
326 */
327void main(void)
328{
329 int fw = FW_ROCKBOX;
330 int rc = 0;
331 unsigned char *loadbuffer;
332 int (*kernel_entry)(void);
333
334 usec_timer_init();
335
336 /* Configure I2C0 */
337 i2c_preinit(0);
338
339 if (pmu_is_hibernated()) {
340 fw = FW_APPLE;
341 rc = launch_onb(1); /* 27/2 = 13.5 MHz. */
342 }
343
344 system_preinit();
345 memory_init();
346 /*
347 * XXX: BSS is initialized here, do not use .bss before this line
348 */
349 bss_init();
350
351 system_init();
352 kernel_init();
353 i2c_init();
354 power_init();
355
356 enable_irq();
357
358#ifdef HAVE_SERIAL
359 serial_setup();
360#endif
361
362 button_init();
363 if (rc == 0) {
364 /* User button selection timeout */
365 while (USEC_TIMER < 400000);
366 int btn = button_read_device();
367 /* This prevents HDD spin-up when the user enters DFU */
368 if (btn == (BUTTON_SELECT|BUTTON_MENU)) {
369 while (button_read_device() == (BUTTON_SELECT|BUTTON_MENU))
370 sleep(HZ/10);
371 sleep(HZ);
372 btn = button_read_device();
373 }
374 /* Enter OF, diagmode and diskmode using ONB */
375 if ((btn == BUTTON_MENU)
376 || (btn == (BUTTON_SELECT|BUTTON_LEFT))
377 || (btn == (BUTTON_SELECT|BUTTON_PLAY))) {
378 fw = FW_APPLE;
379 rc = kernel_launch_onb();
380 }
381 }
382
383 lcd_init();
384 lcd_set_foreground(LCD_WHITE);
385 lcd_set_background(LCD_BLACK);
386 lcd_clear_display();
387 font_init();
388 lcd_setfont(FONT_SYSFIXED);
389 lcd_update();
390 sleep(HZ/40);
391
392 verbose = true;
393
394 printf("Rockbox boot loader");
395 printf("Version: %s", rbversion);
396
397 backlight_init(); /* Turns on the backlight */
398
399 if (rc == 0) {
400 /* Wait until there is enought power to spin-up HDD */
401 battery_trap();
402
403 rc = storage_init();
404 if (rc != 0) {
405 printf("ATA error: %d", rc);
406 fatal_error(ERR_HDD);
407 }
408
409 filesystem_init();
410
411 /* We wait until HDD spins up to check for hold button */
412 if (button_hold()) {
413 fw = FW_APPLE;
414 printf("Executing OF...");
415 ata_sleepnow();
416 rc = kernel_launch_onb();
417 }
418 }
419
420 if (rc != 0) {
421 printf("Load OF error: %d", rc);
422 fatal_error(ERR_OF);
423 }
424
425#ifdef HAVE_BOOTLOADER_USB_MODE
426 /* Enter USB mode if SELECT+RIGHT are pressed */
427 if (button_read_device() == (BUTTON_SELECT|BUTTON_RIGHT))
428 usb_mode();
429#endif
430
431 rc = disk_mount_all();
432 if (rc <= 0) {
433 printf("No partition found");
434 fatal_error(ERR_RB);
435 }
436
437 printf("Loading Rockbox...");
438 loadbuffer = (unsigned char *)DRAM_ORIG;
439 rc = load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
440
441 if (rc <= EFILE_EMPTY) {
442 printf("Error!");
443 printf("Can't load " BOOTFILE ": ");
444 printf(loader_strerror(rc));
445 fatal_error(ERR_RB);
446 }
447
448 printf("Rockbox loaded.");
449
450 /* If we get here, we have a new firmware image at 0x08000000, run it */
451 disable_irq();
452
453 kernel_entry = (void*) loadbuffer;
454 commit_discard_idcache();
455 rc = kernel_entry();
456
457 /* End stop - should not get here */
458 enable_irq();
459 printf("ERR: Failed to boot");
460 while(1);
461}