blob: b3ff7bcedba45bde21ae7d8f23869aead45549ef [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"
Jens Arnoldafd51742007-11-21 21:28:46 +000038#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 Chapmanebc076b2007-07-25 13:12:38 +000043#include "hwcompat.h"
Dave Chapman38e8fb62005-11-08 00:52:39 +000044
Dave Chapman8adc81d2006-02-21 21:13:03 +000045#define XSC(X) #X
46#define SC(X) XSC(X)
47
Barry Wardell84b509d2007-01-28 18:42:11 +000048/* Maximum allowed firmware image size. The largest known current
49 (December 2006) firmware is about 7.5MB (Apple's firmware for the ipod video)
50 so we set this to 8MB. */
51#define MAX_LOADSIZE (8*1024*1024)
52
53/* A buffer to load the Linux kernel or Rockbox into */
54unsigned char *loadbuffer = (unsigned char *)DRAM_START;
55
56/* Bootloader version */
57char version[] = APPSVERSION;
58
Dave Chapman061f3802005-11-13 20:59:30 +000059#define BUTTON_LEFT 1
60#define BUTTON_MENU 2
61#define BUTTON_RIGHT 3
62#define BUTTON_PLAY 4
Dave Chapmanfa743562006-02-05 19:05:55 +000063#define BUTTON_HOLD 5
Dave Chapman061f3802005-11-13 20:59:30 +000064
Frank Dischner5d9eccd2006-04-19 18:06:56 +000065#if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
Dave Chapman38e8fb62005-11-08 00:52:39 +000066/* check if number of seconds has past */
67int timer_check(int clock_start, unsigned int usecs)
68{
Dave Chapmanfa743562006-02-05 19:05:55 +000069 if ((USEC_TIMER - clock_start) >= usecs) {
Dave Chapman38e8fb62005-11-08 00:52:39 +000070 return 1;
71 } else {
72 return 0;
73 }
74}
75
Dave Chapman061f3802005-11-13 20:59:30 +000076static void ser_opto_keypad_cfg(int val)
77{
78 int start_time;
79
Barry Wardell8b061252007-03-03 17:25:20 +000080 GPIOB_ENABLE &=~ 0x80;
Dave Chapman061f3802005-11-13 20:59:30 +000081
82 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
83 outl(val, 0x7000c120);
84 outl(inl(0x7000c100) | 0x80000000, 0x7000c100);
85
Barry Wardell8b061252007-03-03 17:25:20 +000086 GPIOB_OUTPUT_VAL &=~ 0x10;
87 GPIOB_OUTPUT_EN |= 0x10;
Dave Chapman061f3802005-11-13 20:59:30 +000088
Dave Chapmanfa743562006-02-05 19:05:55 +000089 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +000090 do {
91 if ((inl(0x7000c104) & 0x80000000) == 0) {
92 break;
93 }
94 } while (timer_check(start_time, 1500) != 0);
95
96 outl(inl(0x7000c100) & ~0x80000000, 0x7000c100);
97
Barry Wardell8b061252007-03-03 17:25:20 +000098 GPIOB_ENABLE |= 0x80;
99 GPIOB_OUTPUT_VAL |= 0x10;
100 GPIOB_OUTPUT_EN &=~0x10;
Dave Chapman061f3802005-11-13 20:59:30 +0000101
102 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
103 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
104}
105
106int opto_keypad_read(void)
107{
108 int loop_cnt, had_io = 0;
109
110 for (loop_cnt = 5; loop_cnt != 0;)
111 {
112 int key_pressed = 0;
113 int start_time;
114 unsigned int key_pad_val;
115
116 ser_opto_keypad_cfg(0x8000023a);
117
Dave Chapmanfa743562006-02-05 19:05:55 +0000118 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +0000119 do {
120 if (inl(0x7000c104) & 0x4000000) {
121 had_io = 1;
122 break;
123 }
124
125 if (had_io != 0) {
126 break;
127 }
128 } while (timer_check(start_time, 1500) != 0);
129
130 key_pad_val = inl(0x7000c140);
131 if ((key_pad_val & ~0x7fff0000) != 0x8000023a) {
132 loop_cnt--;
133 } else {
134 key_pad_val = (key_pad_val << 11) >> 27;
135 key_pressed = 1;
136 }
137
138 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
139 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
140
141 if (key_pressed != 0) {
142 return key_pad_val ^ 0x1f;
143 }
144 }
145
146 return 0;
147}
Dave Chapmanfa743562006-02-05 19:05:55 +0000148#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000149
150static int key_pressed(void)
151{
152 unsigned char state;
153
Dave Chapmanfa743562006-02-05 19:05:55 +0000154#if CONFIG_KEYPAD == IPOD_4G_PAD
Jens Arnold7f880882006-04-02 00:20:11 +0000155#ifdef IPOD_MINI /* mini 1G only */
Dave Chapman28507912006-02-27 12:35:05 +0000156 state = GPIOA_INPUT_VAL & 0x3f;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000157 if ((state & 0x10) == 0) return BUTTON_LEFT;
158 if ((state & 0x2) == 0) return BUTTON_MENU;
159 if ((state & 0x4) == 0) return BUTTON_PLAY;
160 if ((state & 0x8) == 0) return BUTTON_RIGHT;
Dave Chapman28507912006-02-27 12:35:05 +0000161#else
Dave Chapman061f3802005-11-13 20:59:30 +0000162 state = opto_keypad_read();
163 if ((state & 0x4) == 0) return BUTTON_LEFT;
164 if ((state & 0x10) == 0) return BUTTON_MENU;
165 if ((state & 0x8) == 0) return BUTTON_PLAY;
166 if ((state & 0x2) == 0) return BUTTON_RIGHT;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000167#endif
Jens Arnold90eacb22007-07-27 07:32:55 +0000168#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_1G2G_PAD)
169 state = GPIOA_INPUT_VAL;
Dave Chapmanfa743562006-02-05 19:05:55 +0000170 if ((state & 0x08) == 0) return BUTTON_LEFT;
171 if ((state & 0x10) == 0) return BUTTON_MENU;
172 if ((state & 0x04) == 0) return BUTTON_PLAY;
173 if ((state & 0x01) == 0) return BUTTON_RIGHT;
174#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000175 return 0;
176}
177
Dave Chapman02aeacb2006-12-17 00:32:54 +0000178bool button_hold(void)
179{
Jens Arnold90eacb22007-07-27 07:32:55 +0000180#if CONFIG_KEYPAD == IPOD_1G2G_PAD
181 return (GPIOA_INPUT_VAL & 0x20);
182#else
183 return !(GPIOA_INPUT_VAL & 0x20);
184#endif
Dave Chapman02aeacb2006-12-17 00:32:54 +0000185}
186
Dave Chapman02aeacb2006-12-17 00:32:54 +0000187void fatal_error(void)
188{
Barry Wardell84b509d2007-01-28 18:42:11 +0000189 extern int line;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000190 bool holdstatus=false;
191
Dave Chapman0025a972006-12-17 10:23:51 +0000192 /* System font is 6 pixels wide */
Jens Arnold90eacb22007-07-27 07:32:55 +0000193#if defined(IPOD_1G2G) || defined(IPOD_3G)
194 printf("Hold MENU+PLAY to");
195 printf("reboot then REW+FF");
196 printf("for disk mode");
197#elif LCD_WIDTH >= (30*6)
Dave Chapmanc5302d52007-05-23 07:18:40 +0000198 printf("Hold MENU+SELECT to reboot");
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000199 printf("then SELECT+PLAY for disk mode");
Dave Chapman0025a972006-12-17 10:23:51 +0000200#else
Dave Chapmanc5302d52007-05-23 07:18:40 +0000201 printf("Hold MENU+SELECT to");
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000202 printf("reboot then SELECT+PLAY");
203 printf("for disk mode");
Dave Chapman0025a972006-12-17 10:23:51 +0000204#endif
Dave Chapman7d79db22007-05-22 19:05:14 +0000205 lcd_update();
Dave Chapman02aeacb2006-12-17 00:32:54 +0000206
207 while (1) {
208 if (button_hold() != holdstatus) {
209 if (button_hold()) {
210 holdstatus=true;
211 lcd_puts(0, line, "Hold switch on!");
212 } else {
213 holdstatus=false;
214 lcd_puts(0, line, " ");
215 }
216 lcd_update();
217 }
218 udelay(100000); /* 100ms */
219 }
220
221}
222
223
Dave Chapman38e8fb62005-11-08 00:52:39 +0000224void* main(void)
225{
226 char buf[256];
Dave Chapman38e8fb62005-11-08 00:52:39 +0000227 int i;
Dave Chapman4d25bff2007-03-05 23:56:28 +0000228 int btn;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000229 int rc;
Dave Chapman02aeacb2006-12-17 00:32:54 +0000230 bool haveretailos;
231 bool button_was_held;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000232 struct partinfo* pinfo;
233 unsigned short* identify_info;
234
Dave Chapman02aeacb2006-12-17 00:32:54 +0000235 /* Check the button hold status as soon as possible - to
236 give the user maximum chance to turn it off in order to
237 reset the settings in rockbox. */
238 button_was_held = button_hold();
239
Dave Chapman38e8fb62005-11-08 00:52:39 +0000240 system_init();
241 kernel_init();
Jens Arnoldafd51742007-11-21 21:28:46 +0000242
243#ifndef HAVE_BACKLIGHT_INVERSION
244 backlight_init(); /* Turns on the backlight */
245#endif
246
Dave Chapman38e8fb62005-11-08 00:52:39 +0000247 lcd_init();
248 font_init();
249
Dave Chapman02aeacb2006-12-17 00:32:54 +0000250#ifdef HAVE_LCD_COLOR
251 lcd_set_foreground(LCD_WHITE);
252 lcd_set_background(LCD_BLACK);
253 lcd_clear_display();
254#endif
255
Dave Chapman38e8fb62005-11-08 00:52:39 +0000256#if 0
257 /* ADC and button drivers are not yet implemented */
258 adc_init();
259 button_init();
260#endif
261
Dave Chapman4d25bff2007-03-05 23:56:28 +0000262 btn=key_pressed();
263
264 /* Enable bootloader messages */
265 if (btn==BUTTON_RIGHT)
266 verbose = true;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000267
268 lcd_setfont(FONT_SYSFIXED);
269
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000270 printf("Rockbox boot loader");
Dave Chapmandc1fc3c2007-03-06 09:49:09 +0000271 printf("Version: %s", version);
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000272 printf("IPOD version: 0x%08x", IPOD_HW_REVISION);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000273
274 i=ata_init();
275 if (i==0) {
276 identify_info=ata_get_identify();
277 /* Show model */
278 for (i=0; i < 20; i++) {
279 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
280 }
281 buf[40]=0;
282 for (i=39; i && buf[i]==' '; i--) {
283 buf[i]=0;
284 }
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000285 printf(buf);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000286 } else {
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000287 printf("ATA: %d", i);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000288 }
289
290 disk_init();
291 rc = disk_mount_all();
292 if (rc<=0)
293 {
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000294 printf("No partition found");
Dave Chapman02aeacb2006-12-17 00:32:54 +0000295 fatal_error();
Dave Chapman38e8fb62005-11-08 00:52:39 +0000296 }
297
298 pinfo = disk_partinfo(1);
Linus Nielsen Feltzingf3f0d1c2007-01-16 23:12:02 +0000299 printf("Partition 1: 0x%02x %ld MB",
300 pinfo->type, pinfo->size / 2048);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000301
Dave Chapman4d25bff2007-03-05 23:56:28 +0000302 if (button_was_held || (btn==BUTTON_MENU)) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000303 /* If either the hold switch was on, or the Menu button was held, then
304 try the Apple firmware */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000305
Barry Wardell84b509d2007-01-28 18:42:11 +0000306 printf("Loading original firmware...");
307
308 /* First try an apple_os.ipod file on the FAT32 partition
309 (either in .rockbox or the root)
310 */
311
312 rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE);
313
Dave Chapmana02c4262007-03-06 14:05:43 +0000314 if (rc == EOK) {
315 printf("apple_os.ipod loaded.");
316 return (void*)DRAM_START;
317 } else if (rc == EFILE_NOT_FOUND) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000318 /* If apple_os.ipod doesn't exist, then check if there is an Apple
319 firmware image in RAM */
320 haveretailos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0);
321 if (haveretailos) {
322 /* We have a copy of the retailos in RAM, lets just run it. */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000323 return (void*)DRAM_START;
324 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000325 } else if (rc < EFILE_NOT_FOUND) {
326 printf("Error!");
327 printf("Can't load apple_os.ipod:");
328 printf(strerror(rc));
Dave Chapman02aeacb2006-12-17 00:32:54 +0000329 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000330
331 /* Everything failed - just loop forever */
332 printf("No RetailOS detected");
333
Dave Chapman4d25bff2007-03-05 23:56:28 +0000334 } else if (btn==BUTTON_PLAY) {
Barry Wardell84b509d2007-01-28 18:42:11 +0000335 printf("Loading Linux...");
336 rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE);
337 if (rc < EOK) {
338 printf("Error!");
339 printf("Can't load linux.bin:");
340 printf(strerror(rc));
341 } else {
342 return (void*)DRAM_START;
343 }
344 } else {
345 printf("Loading Rockbox...");
346 rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
347 if (rc < EOK) {
348 printf("Error!");
349 printf("Can't load rockbox.ipod:");
350 printf(strerror(rc));
351 } else {
352 printf("Rockbox loaded.");
353 return (void*)DRAM_START;
Dave Chapman061f3802005-11-13 20:59:30 +0000354 }
355 }
Barry Wardell84b509d2007-01-28 18:42:11 +0000356
357 /* If we get to here, then we haven't been able to load any firmware */
Dave Chapman02aeacb2006-12-17 00:32:54 +0000358 fatal_error();
Barry Wardell84b509d2007-01-28 18:42:11 +0000359
Dave Chapman02aeacb2006-12-17 00:32:54 +0000360 /* We never get here, but keep gcc happy */
361 return (void*)0;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000362}
363
364/* These functions are present in the firmware library, but we reimplement
365 them here because the originals do a lot more than we want */
Dave Chapman38e8fb62005-11-08 00:52:39 +0000366void usb_acknowledge(void)
367{
368}
369
370void usb_wait_for_disconnect(void)
371{
372}