blob: 73b4fffc7124c61381f09c8e847dc2d1fac73610 [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 *
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "config.h"
23
24#include <stdlib.h>
25#include <stdio.h>
Dave Chapman061f3802005-11-13 20:59:30 +000026#include <string.h>
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +000027#include <stdarg.h>
Dave Chapman38e8fb62005-11-08 00:52:39 +000028#include "cpu.h"
29#include "system.h"
30#include "lcd.h"
31#include "kernel.h"
32#include "thread.h"
33#include "ata.h"
34#include "fat.h"
35#include "disk.h"
36#include "font.h"
37#include "adc.h"
38#include "backlight.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000039#include "panic.h"
40#include "power.h"
41#include "file.h"
Barry Wardell84b509d2007-01-28 18:42:11 +000042#include "common.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000043
Dave Chapman8adc81d2006-02-21 21:13:03 +000044#define XSC(X) #X
45#define SC(X) XSC(X)
46
Barry Wardell84b509d2007-01-28 18:42:11 +000047/* Maximum allowed firmware image size. The largest known current
48 (December 2006) firmware is about 7.5MB (Apple's firmware for the ipod video)
49 so we set this to 8MB. */
50#define MAX_LOADSIZE (8*1024*1024)
51
52/* A buffer to load the Linux kernel or Rockbox into */
53unsigned char *loadbuffer = (unsigned char *)DRAM_START;
54
55/* Bootloader version */
56char version[] = APPSVERSION;
57
Dave Chapman38e8fb62005-11-08 00:52:39 +000058#define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084)))
59
Dave Chapmanf9dac402006-01-31 01:50:07 +000060/* We copy the hardware revision to the last four bytes of SDRAM and then
61 re-read it after we have re-mapped SDRAM to 0x0 in Rockbox */
62#define TMP_IPOD_HW_REVISION (*((volatile unsigned long*)(0x11fffffc)))
63
Dave Chapman061f3802005-11-13 20:59:30 +000064#define BUTTON_LEFT 1
65#define BUTTON_MENU 2
66#define BUTTON_RIGHT 3
67#define BUTTON_PLAY 4
Dave Chapmanfa743562006-02-05 19:05:55 +000068#define BUTTON_HOLD 5
Dave Chapman061f3802005-11-13 20:59:30 +000069
Frank Dischner5d9eccd2006-04-19 18:06:56 +000070#if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
Dave Chapman38e8fb62005-11-08 00:52:39 +000071/* check if number of seconds has past */
72int timer_check(int clock_start, unsigned int usecs)
73{
Dave Chapmanfa743562006-02-05 19:05:55 +000074 if ((USEC_TIMER - clock_start) >= usecs) {
Dave Chapman38e8fb62005-11-08 00:52:39 +000075 return 1;
76 } else {
77 return 0;
78 }
79}
80
Dave Chapman061f3802005-11-13 20:59:30 +000081static void ser_opto_keypad_cfg(int val)
82{
83 int start_time;
84
85 outl(inl(0x6000d004) & ~0x80, 0x6000d004);
86
87 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
88 outl(val, 0x7000c120);
89 outl(inl(0x7000c100) | 0x80000000, 0x7000c100);
90
91 outl(inl(0x6000d024) & ~0x10, 0x6000d024);
92 outl(inl(0x6000d014) | 0x10, 0x6000d014);
93
Dave Chapmanfa743562006-02-05 19:05:55 +000094 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +000095 do {
96 if ((inl(0x7000c104) & 0x80000000) == 0) {
97 break;
98 }
99 } while (timer_check(start_time, 1500) != 0);
100
101 outl(inl(0x7000c100) & ~0x80000000, 0x7000c100);
102
103 outl(inl(0x6000d004) | 0x80, 0x6000d004);
104 outl(inl(0x6000d024) | 0x10, 0x6000d024);
105 outl(inl(0x6000d014) & ~0x10, 0x6000d014);
106
107 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
108 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
109}
110
111int opto_keypad_read(void)
112{
113 int loop_cnt, had_io = 0;
114
115 for (loop_cnt = 5; loop_cnt != 0;)
116 {
117 int key_pressed = 0;
118 int start_time;
119 unsigned int key_pad_val;
120
121 ser_opto_keypad_cfg(0x8000023a);
122
Dave Chapmanfa743562006-02-05 19:05:55 +0000123 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +0000124 do {
125 if (inl(0x7000c104) & 0x4000000) {
126 had_io = 1;
127 break;
128 }
129
130 if (had_io != 0) {
131 break;
132 }
133 } while (timer_check(start_time, 1500) != 0);
134
135 key_pad_val = inl(0x7000c140);
136 if ((key_pad_val & ~0x7fff0000) != 0x8000023a) {
137 loop_cnt--;
138 } else {
139 key_pad_val = (key_pad_val << 11) >> 27;
140 key_pressed = 1;
141 }
142
143 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
144 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
145
146 if (key_pressed != 0) {
147 return key_pad_val ^ 0x1f;
148 }
149 }
150
151 return 0;
152}
Dave Chapmanfa743562006-02-05 19:05:55 +0000153#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000154
155static int key_pressed(void)
156{
157 unsigned char state;
158
Dave Chapmanfa743562006-02-05 19:05:55 +0000159#if CONFIG_KEYPAD == IPOD_4G_PAD
Jens Arnold7f880882006-04-02 00:20:11 +0000160#ifdef IPOD_MINI /* mini 1G only */
Dave Chapman28507912006-02-27 12:35:05 +0000161 state = GPIOA_INPUT_VAL & 0x3f;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000162 if ((state & 0x10) == 0) return BUTTON_LEFT;
163 if ((state & 0x2) == 0) return BUTTON_MENU;
164 if ((state & 0x4) == 0) return BUTTON_PLAY;
165 if ((state & 0x8) == 0) return BUTTON_RIGHT;
Dave Chapman28507912006-02-27 12:35:05 +0000166#else
Dave Chapman061f3802005-11-13 20:59:30 +0000167 state = opto_keypad_read();
168 if ((state & 0x4) == 0) return BUTTON_LEFT;
169 if ((state & 0x10) == 0) return BUTTON_MENU;
170 if ((state & 0x8) == 0) return BUTTON_PLAY;
171 if ((state & 0x2) == 0) return BUTTON_RIGHT;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000172#endif
Dave Chapmanfa743562006-02-05 19:05:55 +0000173#elif CONFIG_KEYPAD == IPOD_3G_PAD
174 state = inb(0xcf000030);
175 if (((state & 0x20) == 0)) return BUTTON_HOLD; /* hold on */
176 if ((state & 0x08) == 0) return BUTTON_LEFT;
177 if ((state & 0x10) == 0) return BUTTON_MENU;
178 if ((state & 0x04) == 0) return BUTTON_PLAY;
179 if ((state & 0x01) == 0) return BUTTON_RIGHT;
180#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000181 return 0;
182}
183
Dave Chapman02aeacb2006-12-17 00:32:54 +0000184/* This function is the same on all ipods */
185bool button_hold(void)
186{
187 return (GPIOA_INPUT_VAL & 0x20)?false:true;
188}
189
Dave Chapman02aeacb2006-12-17 00:32:54 +0000190void fatal_error(void)
191{
Barry Wardell84b509d2007-01-28 18:42:11 +0000192 extern int line;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000193 bool holdstatus=false;
194
Dave Chapman0025a972006-12-17 10:23:51 +0000195 /* System font is 6 pixels wide */
196#if LCD_WIDTH >= (30*6)
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000197 printf("Press MENU+SELECT to reboot");
198 printf("then SELECT+PLAY for disk mode");
Dave Chapman0025a972006-12-17 10:23:51 +0000199#else
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000200 printf("Press MENU+SELECT to");
201 printf("reboot then SELECT+PLAY");
202 printf("for disk mode");
Dave Chapman0025a972006-12-17 10:23:51 +0000203#endif
Dave Chapman02aeacb2006-12-17 00:32:54 +0000204
205 while (1) {
206 if (button_hold() != holdstatus) {
207 if (button_hold()) {
208 holdstatus=true;
209 lcd_puts(0, line, "Hold switch on!");
210 } else {
211 holdstatus=false;
212 lcd_puts(0, line, " ");
213 }
214 lcd_update();
215 }
216 udelay(100000); /* 100ms */
217 }
218
219}
220
221
Dave Chapman38e8fb62005-11-08 00:52:39 +0000222void* main(void)
223{
224 char buf[256];
Dave Chapman38e8fb62005-11-08 00:52:39 +0000225 int i;
226 int rc;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000227 bool haveretailos;
228 bool button_was_held;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000229 struct partinfo* pinfo;
230 unsigned short* identify_info;
231
Dave Chapman02aeacb2006-12-17 00:32:54 +0000232 /* Check the button hold status as soon as possible - to
233 give the user maximum chance to turn it off in order to
234 reset the settings in rockbox. */
235 button_was_held = button_hold();
236
Dave Chapman38e8fb62005-11-08 00:52:39 +0000237 /* Turn on the backlight */
238
239#if CONFIG_BACKLIGHT==BL_IPOD4G
Dave Chapman38e8fb62005-11-08 00:52:39 +0000240 /* brightness full */
241 outl(0x80000000 | (0xff << 16), 0x7000a010);
242
Dave Chapmand8c5d1b2005-11-08 09:07:13 +0000243 /* set port B03 on */
Dave Chapman38e8fb62005-11-08 00:52:39 +0000244 outl(((0x100 | 1) << 3), 0x6000d824);
245
Dave Chapman8b1297a2006-02-21 15:01:25 +0000246#elif CONFIG_BACKLIGHT==BL_IPODMINI
247 /* set port B03 on */
248 outl(((0x100 | 1) << 3), 0x6000d824);
249
Dave Chapman38e8fb62005-11-08 00:52:39 +0000250#elif CONFIG_BACKLIGHT==BL_IPODNANO
251
252 /* set port B03 on */
253 outl(((0x100 | 1) << 3), 0x6000d824);
254
255 /* set port L07 on */
256 outl(((0x100 | 1) << 7), 0x6000d12c);
Dave Chapmanfa743562006-02-05 19:05:55 +0000257#elif CONFIG_BACKLIGHT==BL_IPOD3G
258 outl(inl(IPOD_LCD_BASE) | 0x2, IPOD_LCD_BASE);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000259#endif
260
Dave Chapmanf9dac402006-01-31 01:50:07 +0000261 TMP_IPOD_HW_REVISION = IPOD_HW_REVISION;
Dave Chapman1446b212006-01-31 09:40:21 +0000262 ipod_hw_rev = IPOD_HW_REVISION;
Dave Chapmanf9dac402006-01-31 01:50:07 +0000263
Dave Chapman38e8fb62005-11-08 00:52:39 +0000264 system_init();
265 kernel_init();
266 lcd_init();
267 font_init();
268
Dave Chapman02aeacb2006-12-17 00:32:54 +0000269#ifdef HAVE_LCD_COLOR
270 lcd_set_foreground(LCD_WHITE);
271 lcd_set_background(LCD_BLACK);
272 lcd_clear_display();
273#endif
274
Dave Chapman38e8fb62005-11-08 00:52:39 +0000275#if 0
276 /* ADC and button drivers are not yet implemented */
277 adc_init();
278 button_init();
279#endif
280
Dave Chapman38e8fb62005-11-08 00:52:39 +0000281
282 lcd_setfont(FONT_SYSFIXED);
283
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000284 printf("Rockbox boot loader");
285 printf("Version: 20%s", version);
286 printf("IPOD version: 0x%08x", IPOD_HW_REVISION);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000287
288 i=ata_init();
289 if (i==0) {
290 identify_info=ata_get_identify();
291 /* Show model */
292 for (i=0; i < 20; i++) {
293 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
294 }
295 buf[40]=0;
296 for (i=39; i && buf[i]==' '; i--) {
297 buf[i]=0;
298 }
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000299 printf(buf);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000300 } else {
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000301 printf("ATA: %d", i);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000302 }
303
304 disk_init();
305 rc = disk_mount_all();
306 if (rc<=0)
307 {
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000308 printf("No partition found");
Dave Chapman02aeacb2006-12-17 00:32:54 +0000309 fatal_error();
Dave Chapman38e8fb62005-11-08 00:52:39 +0000310 }
311
312 pinfo = disk_partinfo(1);
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000313 printf("Partition 1: 0x%02x %ld MB",
314 pinfo->type, pinfo->size / 2048);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000315
Barry Wardell84b509d2007-01-28 18:42:11 +0000316
317 /* Check for a keypress */
318 i=key_pressed();
Dave Chapman38e8fb62005-11-08 00:52:39 +0000319
Barry Wardell84b509d2007-01-28 18:42:11 +0000320 if (button_was_held || (i==BUTTON_MENU)) {
321 /* If either the hold switch was on, or the Menu button was held, then
322 try the Apple firmware */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000323
Barry Wardell84b509d2007-01-28 18:42:11 +0000324 printf("Loading original firmware...");
325
326 /* First try an apple_os.ipod file on the FAT32 partition
327 (either in .rockbox or the root)
328 */
329
330 rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE);
331
332 if(rc==EFILE_NOT_FOUND) {
333 /* If apple_os.ipod doesn't exist, then check if there is an Apple
334 firmware image in RAM */
335 haveretailos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0);
336 if (haveretailos) {
337 /* We have a copy of the retailos in RAM, lets just run it. */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000338 return (void*)DRAM_START;
339 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000340 } else if (rc < EFILE_NOT_FOUND) {
341 printf("Error!");
342 printf("Can't load apple_os.ipod:");
343 printf(strerror(rc));
344 } else if (rc > 0) {
345 printf("apple_os.ipod loaded.");
346 return (void*)DRAM_START;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000347 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000348
349 /* Everything failed - just loop forever */
350 printf("No RetailOS detected");
351
352 } else if (i==BUTTON_PLAY) {
353 printf("Loading Linux...");
354 rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE);
355 if (rc < EOK) {
356 printf("Error!");
357 printf("Can't load linux.bin:");
358 printf(strerror(rc));
359 } else {
360 return (void*)DRAM_START;
361 }
362 } else {
363 printf("Loading Rockbox...");
364 rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
365 if (rc < EOK) {
366 printf("Error!");
367 printf("Can't load rockbox.ipod:");
368 printf(strerror(rc));
369 } else {
370 printf("Rockbox loaded.");
371 return (void*)DRAM_START;
Dave Chapman061f3802005-11-13 20:59:30 +0000372 }
373 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000374
375 /* If we get to here, then we haven't been able to load any firmware */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000376 fatal_error();
Barry Wardell84b509d2007-01-28 18:42:11 +0000377
Dave Chapman02aeacb2006-12-17 00:32:54 +0000378 /* We never get here, but keep gcc happy */
379 return (void*)0;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000380}
381
382/* These functions are present in the firmware library, but we reimplement
383 them here because the originals do a lot more than we want */
Dave Chapman38e8fb62005-11-08 00:52:39 +0000384void usb_acknowledge(void)
385{
386}
387
388void usb_wait_for_disconnect(void)
389{
390}