blob: 8e5bd08a42611d52268feae6be9e04eaa1839320 [file] [log] [blame]
Dave Chapman38e8fb62005-11-08 00:52:39 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Dave Chapman
11 *
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
14 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000015 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
Dave Chapman38e8fb62005-11-08 00:52:39 +000019 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include "config.h"
25
26#include <stdlib.h>
27#include <stdio.h>
Dave Chapman061f3802005-11-13 20:59:30 +000028#include <string.h>
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +000029#include <stdarg.h>
Dave Chapman38e8fb62005-11-08 00:52:39 +000030#include "cpu.h"
31#include "system.h"
32#include "lcd.h"
Michael Sevakis4ea4cdf2014-08-08 02:28:11 -040033#include "../kernel-internal.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000034#include "ata.h"
Michael Sevakis7d1a47c2013-08-05 22:02:45 -040035#include "file_internal.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000036#include "disk.h"
37#include "font.h"
38#include "adc.h"
Jens Arnoldafd51742007-11-21 21:28:46 +000039#include "backlight.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000040#include "panic.h"
41#include "power.h"
42#include "file.h"
Barry Wardell84b509d2007-01-28 18:42:11 +000043#include "common.h"
Marcin Bukat0b296912012-03-04 15:34:29 +010044#include "rb-loader.h"
45#include "loader_strerror.h"
Dave Chapmanebc076b2007-07-25 13:12:38 +000046#include "hwcompat.h"
Torne Wuff0d24df82010-04-13 22:17:42 +000047#include "usb.h"
Rafaël Carré5d236b22010-05-27 09:41:46 +000048#include "version.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000049
Dave Chapman8adc81d2006-02-21 21:13:03 +000050#define XSC(X) #X
51#define SC(X) XSC(X)
52
Barry Wardell84b509d2007-01-28 18:42:11 +000053/* Maximum allowed firmware image size. The largest known current
54 (December 2006) firmware is about 7.5MB (Apple's firmware for the ipod video)
55 so we set this to 8MB. */
56#define MAX_LOADSIZE (8*1024*1024)
57
58/* A buffer to load the Linux kernel or Rockbox into */
59unsigned char *loadbuffer = (unsigned char *)DRAM_START;
60
Frank Dischner5d9eccd2006-04-19 18:06:56 +000061#if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
Dave Chapman38e8fb62005-11-08 00:52:39 +000062/* check if number of seconds has past */
63int timer_check(int clock_start, unsigned int usecs)
64{
Dave Chapmanfa743562006-02-05 19:05:55 +000065 if ((USEC_TIMER - clock_start) >= usecs) {
Dave Chapman38e8fb62005-11-08 00:52:39 +000066 return 1;
67 } else {
68 return 0;
69 }
70}
71
Dave Chapman061f3802005-11-13 20:59:30 +000072static void ser_opto_keypad_cfg(int val)
73{
74 int start_time;
75
Barry Wardell8b061252007-03-03 17:25:20 +000076 GPIOB_ENABLE &=~ 0x80;
Dave Chapman061f3802005-11-13 20:59:30 +000077
78 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
79 outl(val, 0x7000c120);
80 outl(inl(0x7000c100) | 0x80000000, 0x7000c100);
81
Barry Wardell8b061252007-03-03 17:25:20 +000082 GPIOB_OUTPUT_VAL &=~ 0x10;
83 GPIOB_OUTPUT_EN |= 0x10;
Dave Chapman061f3802005-11-13 20:59:30 +000084
Dave Chapmanfa743562006-02-05 19:05:55 +000085 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +000086 do {
87 if ((inl(0x7000c104) & 0x80000000) == 0) {
88 break;
89 }
90 } while (timer_check(start_time, 1500) != 0);
91
92 outl(inl(0x7000c100) & ~0x80000000, 0x7000c100);
93
Barry Wardell8b061252007-03-03 17:25:20 +000094 GPIOB_ENABLE |= 0x80;
95 GPIOB_OUTPUT_VAL |= 0x10;
96 GPIOB_OUTPUT_EN &=~0x10;
Dave Chapman061f3802005-11-13 20:59:30 +000097
98 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
99 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
100}
101
102int opto_keypad_read(void)
103{
104 int loop_cnt, had_io = 0;
105
106 for (loop_cnt = 5; loop_cnt != 0;)
107 {
108 int key_pressed = 0;
109 int start_time;
110 unsigned int key_pad_val;
111
112 ser_opto_keypad_cfg(0x8000023a);
113
Dave Chapmanfa743562006-02-05 19:05:55 +0000114 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +0000115 do {
116 if (inl(0x7000c104) & 0x4000000) {
117 had_io = 1;
118 break;
119 }
120
121 if (had_io != 0) {
122 break;
123 }
124 } while (timer_check(start_time, 1500) != 0);
125
126 key_pad_val = inl(0x7000c140);
127 if ((key_pad_val & ~0x7fff0000) != 0x8000023a) {
128 loop_cnt--;
129 } else {
130 key_pad_val = (key_pad_val << 11) >> 27;
131 key_pressed = 1;
132 }
133
134 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
135 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
136
137 if (key_pressed != 0) {
138 return key_pad_val ^ 0x1f;
139 }
140 }
141
142 return 0;
143}
Dave Chapmanfa743562006-02-05 19:05:55 +0000144#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000145
146static int key_pressed(void)
147{
148 unsigned char state;
149
Dave Chapmanfa743562006-02-05 19:05:55 +0000150#if CONFIG_KEYPAD == IPOD_4G_PAD
Jens Arnold7f880882006-04-02 00:20:11 +0000151#ifdef IPOD_MINI /* mini 1G only */
Dave Chapman28507912006-02-27 12:35:05 +0000152 state = GPIOA_INPUT_VAL & 0x3f;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000153 if ((state & 0x10) == 0) return BUTTON_LEFT;
154 if ((state & 0x2) == 0) return BUTTON_MENU;
155 if ((state & 0x4) == 0) return BUTTON_PLAY;
156 if ((state & 0x8) == 0) return BUTTON_RIGHT;
Dave Chapman28507912006-02-27 12:35:05 +0000157#else
Dave Chapman061f3802005-11-13 20:59:30 +0000158 state = opto_keypad_read();
159 if ((state & 0x4) == 0) return BUTTON_LEFT;
160 if ((state & 0x10) == 0) return BUTTON_MENU;
161 if ((state & 0x8) == 0) return BUTTON_PLAY;
162 if ((state & 0x2) == 0) return BUTTON_RIGHT;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000163#endif
Jens Arnold90eacb22007-07-27 07:32:55 +0000164#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_1G2G_PAD)
165 state = GPIOA_INPUT_VAL;
Dave Chapmanfa743562006-02-05 19:05:55 +0000166 if ((state & 0x08) == 0) return BUTTON_LEFT;
167 if ((state & 0x10) == 0) return BUTTON_MENU;
168 if ((state & 0x04) == 0) return BUTTON_PLAY;
169 if ((state & 0x01) == 0) return BUTTON_RIGHT;
170#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000171 return 0;
172}
173
Dave Chapman02aeacb2006-12-17 00:32:54 +0000174bool button_hold(void)
175{
Jens Arnold90eacb22007-07-27 07:32:55 +0000176#if CONFIG_KEYPAD == IPOD_1G2G_PAD
177 return (GPIOA_INPUT_VAL & 0x20);
178#else
179 return !(GPIOA_INPUT_VAL & 0x20);
180#endif
Dave Chapman02aeacb2006-12-17 00:32:54 +0000181}
182
Dave Chapman02aeacb2006-12-17 00:32:54 +0000183void fatal_error(void)
184{
Barry Wardell84b509d2007-01-28 18:42:11 +0000185 extern int line;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000186 bool holdstatus=false;
187
Dave Chapman0025a972006-12-17 10:23:51 +0000188 /* System font is 6 pixels wide */
Jens Arnold90eacb22007-07-27 07:32:55 +0000189#if defined(IPOD_1G2G) || defined(IPOD_3G)
Torne Wuff0d24df82010-04-13 22:17:42 +0000190 printf("Insert Firewire cable, or");
191 printf("hold MENU+PLAY to reboot");
192 printf("then REW+FF for disk mode");
Jens Arnold90eacb22007-07-27 07:32:55 +0000193#elif LCD_WIDTH >= (30*6)
Torne Wuff0d24df82010-04-13 22:17:42 +0000194 printf("Insert USB cable, or");
195 printf("hold MENU+SELECT to reboot");
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000196 printf("then SELECT+PLAY for disk mode");
Dave Chapman0025a972006-12-17 10:23:51 +0000197#else
Torne Wuff0d24df82010-04-13 22:17:42 +0000198 printf("Insert USB cable, or");
199 printf("hold MENU+SELECT to");
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000200 printf("reboot then SELECT+PLAY");
201 printf("for disk mode");
Dave Chapman0025a972006-12-17 10:23:51 +0000202#endif
Dave Chapman7d79db22007-05-22 19:05:14 +0000203 lcd_update();
Dave Chapman02aeacb2006-12-17 00:32:54 +0000204
Torne Wuff0d24df82010-04-13 22:17:42 +0000205 usb_init();
Dave Chapman02aeacb2006-12-17 00:32:54 +0000206 while (1) {
207 if (button_hold() != holdstatus) {
208 if (button_hold()) {
209 holdstatus=true;
210 lcd_puts(0, line, "Hold switch on!");
211 } else {
212 holdstatus=false;
213 lcd_puts(0, line, " ");
214 }
215 lcd_update();
216 }
Torne Wuff0d24df82010-04-13 22:17:42 +0000217 if (usb_detect() == USB_INSERTED) {
218 ata_sleepnow(); /* Immediately spindown the disk. */
219 sleep(HZ*2);
220#if CONFIG_CPU == PP5020
221 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
222#elif CONFIG_CPU == PP5022
223 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
224#elif CONFIG_CPU == PP5002
225 memcpy((void *)0x40017f00, "diskmodehotstuff\1", 17);
226#endif /* CONFIG_CPU */
227 system_reboot(); /* Reboot */
228 }
Dave Chapman02aeacb2006-12-17 00:32:54 +0000229 udelay(100000); /* 100ms */
230 }
231
232}
233
Dave Chapman49fccaf2009-05-12 20:41:44 +0000234/* The bootloader is started from the OSOS image on the firmware
235 * partition. There are several ways it can be installed there:
236 * appended to the Apple firmware, on its own, or appended to
237 * Rockbox itself. The Apple ROM loader loads the entire OSOS
238 * image to DRAM_START, whatever it contains. If the bootloader
239 * is appended to another image then it will've modified the
240 * entry point in the OSOS header such that the ROM will call the
241 * bootloader rather than the main image.
242 *
243 * So, once the bootloader has control:
244 *
245 * 1) If the hold switch is on, or the menu button is being held,
246 * try to boot the Apple firmware.
247 * 1a) First, it looks for apple_os.ipod on the FAT32 partition,
248 * in .rockbox or the root directory. If found it loads that
249 * without further checking and runs it.
250 * 1b) Next, it checks to see if the OSOS image already loaded
251 * into RAM is in fact the Apple firmware with the bootloader
252 * appended. It looks at DRAM_START+0x20 for the string
253 * "portalplayer", and if it's there, just jumps back to
254 * DRAM_START where the entry point was before the bootloader
255 * was appended.
256 * 1c) If neither of those worked, it displays an error and dies.
257 *
258 * 2) If the play button is being held, try to boot Linux. It looks
259 * for linux.bin in the root directory, and if it's not there,
260 * it displays an error and dies.
261 *
262 * 3) Otherwise, try to boot Rockbox.
263 * 3a) First, it looks for rockbox.ipod on the FAT32 partition,
264 * in .rockbox or the root directory. If found it loads that
265 * without further checking and runs it.
266 * 3b) Next, it checks to see if the OSOS image already loaded
267 * into RAM is in fact Rockbox with the bootloader appended.
268 * It looks at DRAM_START+0x20 for the string "Rockbox\1"
269 * (which is inserted there in crt0-pp.S), and if it's there,
270 * just humps back to DRAM_START where the entry point was
271 * before the bootloader was appended.
272 * 3c) If neither of those worked, it displays an error and dies.
273 *
274 * The result is that any of the three install configurations work,
275 * and that images of apple_os.ipod or rockbox.ipod on the FAT32
276 * partition take priority over the contents of OSOS (this avoids
277 * upgrades failing to work if OSOS is not updated).
278 *
279 * Loading from OSOS is somewhat faster than loading from FAT32,
280 * because the Apple ROM doesn't have to deal with filesystems or
281 * fragmentation, and is already loading from OSOS anyway. Thus,
282 * the fastest boot configuration that still allows dual booting
283 * is to install Rockbox into OSOS with the bootloader appended
284 * (and delete/rename rockbox.ipod from the FAT32 partition).
285 *
286 * It is of course faster to just install Rockbox to OSOS alone,
287 * but then it's impossible to boot the Apple firmware.
288 */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000289
Dave Chapman38e8fb62005-11-08 00:52:39 +0000290void* main(void)
291{
292 char buf[256];
Dave Chapman38e8fb62005-11-08 00:52:39 +0000293 int i;
Dave Chapman4d25bff2007-03-05 23:56:28 +0000294 int btn;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000295 int rc;
Dave Chapman49fccaf2009-05-12 20:41:44 +0000296 bool haveramos;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000297 bool button_was_held;
Michael Sevakis7d1a47c2013-08-05 22:02:45 -0400298 struct partinfo pinfo;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000299 unsigned short* identify_info;
300
Dave Chapman02aeacb2006-12-17 00:32:54 +0000301 /* Check the button hold status as soon as possible - to
302 give the user maximum chance to turn it off in order to
303 reset the settings in rockbox. */
304 button_was_held = button_hold();
305
Dave Chapman38e8fb62005-11-08 00:52:39 +0000306 system_init();
307 kernel_init();
Jens Arnoldafd51742007-11-21 21:28:46 +0000308
309#ifndef HAVE_BACKLIGHT_INVERSION
310 backlight_init(); /* Turns on the backlight */
311#endif
312
Dave Chapman38e8fb62005-11-08 00:52:39 +0000313 lcd_init();
314 font_init();
315
Dave Chapman02aeacb2006-12-17 00:32:54 +0000316#ifdef HAVE_LCD_COLOR
317 lcd_set_foreground(LCD_WHITE);
318 lcd_set_background(LCD_BLACK);
319 lcd_clear_display();
320#endif
321
Dave Chapman38e8fb62005-11-08 00:52:39 +0000322#if 0
323 /* ADC and button drivers are not yet implemented */
324 adc_init();
325 button_init();
326#endif
327
Dave Chapman4d25bff2007-03-05 23:56:28 +0000328 btn=key_pressed();
329
330 /* Enable bootloader messages */
331 if (btn==BUTTON_RIGHT)
332 verbose = true;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000333
334 lcd_setfont(FONT_SYSFIXED);
335
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000336 printf("Rockbox boot loader");
Michael Sevakis95a4c3a2014-08-28 10:26:45 -0400337 printf("Version: %s", rbversion);
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000338 printf("IPOD version: 0x%08x", IPOD_HW_REVISION);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000339
340 i=ata_init();
341 if (i==0) {
342 identify_info=ata_get_identify();
343 /* Show model */
344 for (i=0; i < 20; i++) {
345 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
346 }
347 buf[40]=0;
348 for (i=39; i && buf[i]==' '; i--) {
349 buf[i]=0;
350 }
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000351 printf(buf);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000352 } else {
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000353 printf("ATA: %d", i);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000354 }
355
Michael Sevakis7d1a47c2013-08-05 22:02:45 -0400356 filesystem_init();
357
Dave Chapman38e8fb62005-11-08 00:52:39 +0000358 rc = disk_mount_all();
359 if (rc<=0)
360 {
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000361 printf("No partition found");
Dave Chapman02aeacb2006-12-17 00:32:54 +0000362 fatal_error();
Dave Chapman38e8fb62005-11-08 00:52:39 +0000363 }
364
Michael Sevakis7d1a47c2013-08-05 22:02:45 -0400365 disk_partinfo(1, &pinfo);
Frank Gevaertsac355de2008-11-21 15:20:25 +0000366 printf("Partition 1: 0x%02x %ld sectors",
Michael Sevakis7d1a47c2013-08-05 22:02:45 -0400367 pinfo.type, pinfo.size);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000368
Dave Chapman4d25bff2007-03-05 23:56:28 +0000369 if (button_was_held || (btn==BUTTON_MENU)) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000370 /* If either the hold switch was on, or the Menu button was held, then
371 try the Apple firmware */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000372
Barry Wardell84b509d2007-01-28 18:42:11 +0000373 printf("Loading original firmware...");
374
375 /* First try an apple_os.ipod file on the FAT32 partition
376 (either in .rockbox or the root)
377 */
378
379 rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE);
380
Marcin Bukat0b296912012-03-04 15:34:29 +0100381 if (rc > 0) {
Dave Chapmana02c4262007-03-06 14:05:43 +0000382 printf("apple_os.ipod loaded.");
383 return (void*)DRAM_START;
384 } else if (rc == EFILE_NOT_FOUND) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000385 /* If apple_os.ipod doesn't exist, then check if there is an Apple
386 firmware image in RAM */
Dave Chapman49fccaf2009-05-12 20:41:44 +0000387 haveramos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0);
388 if (haveramos) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000389 /* We have a copy of the retailos in RAM, lets just run it. */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000390 return (void*)DRAM_START;
391 }
Marcin Bukat0b296912012-03-04 15:34:29 +0100392 } else {
Barry Wardell84b509d2007-01-28 18:42:11 +0000393 printf("Error!");
394 printf("Can't load apple_os.ipod:");
Marcin Bukat0b296912012-03-04 15:34:29 +0100395 printf(loader_strerror(rc));
Dave Chapman02aeacb2006-12-17 00:32:54 +0000396 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000397
398 /* Everything failed - just loop forever */
399 printf("No RetailOS detected");
400
Dave Chapman4d25bff2007-03-05 23:56:28 +0000401 } else if (btn==BUTTON_PLAY) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000402 printf("Loading Linux...");
403 rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE);
Marcin Bukat0b296912012-03-04 15:34:29 +0100404 if (rc <= EFILE_EMPTY) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000405 printf("Error!");
406 printf("Can't load linux.bin:");
Marcin Bukat0b296912012-03-04 15:34:29 +0100407 printf(loader_strerror(rc));
Barry Wardell84b509d2007-01-28 18:42:11 +0000408 } else {
409 return (void*)DRAM_START;
410 }
411 } else {
412 printf("Loading Rockbox...");
413 rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
Marcin Bukat0b296912012-03-04 15:34:29 +0100414 if (rc > 0) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000415 printf("Rockbox loaded.");
416 return (void*)DRAM_START;
Dave Chapman49fccaf2009-05-12 20:41:44 +0000417 } else if (rc == EFILE_NOT_FOUND) {
418 /* if rockbox.ipod doesn't exist, then check if there is a Rockbox
419 image in RAM */
420 haveramos = (memcmp((void*)(DRAM_START+0x20),"Rockbox\1",8)==0);
421 if (haveramos) {
422 /* We have a copy of Rockbox in RAM, lets just run it. */
423 return (void*)DRAM_START;
424 }
Dave Chapman061f3802005-11-13 20:59:30 +0000425 }
Dave Chapman49fccaf2009-05-12 20:41:44 +0000426
427 printf("Error!");
428 printf("Can't load " BOOTFILE ": ");
Marcin Bukat0b296912012-03-04 15:34:29 +0100429 printf(loader_strerror(rc));
Dave Chapman061f3802005-11-13 20:59:30 +0000430 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000431
432 /* If we get to here, then we haven't been able to load any firmware */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000433 fatal_error();
Barry Wardell84b509d2007-01-28 18:42:11 +0000434
Dave Chapman02aeacb2006-12-17 00:32:54 +0000435 /* We never get here, but keep gcc happy */
436 return (void*)0;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000437}