Add FlipIt to the Player manual
[Rockbox.git] / bootloader / ipod.c
blob26e5ae2937c6844d960609f61fd2e65a7873940f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Dave Chapman
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include "cpu.h"
28 #include "system.h"
29 #include "lcd.h"
30 #include "kernel.h"
31 #include "thread.h"
32 #include "ata.h"
33 #include "fat.h"
34 #include "disk.h"
35 #include "font.h"
36 #include "adc.h"
37 #include "backlight.h"
38 #include "panic.h"
39 #include "power.h"
40 #include "file.h"
42 #define XSC(X) #X
43 #define SC(X) XSC(X)
45 #if (CONFIG_CPU == PP5020)
46 #define DRAM_START 0x10000000
47 #else
48 #define IPOD_LCD_BASE 0xc0001000
49 #define DRAM_START 0x28000000
50 #endif
51 #define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084)))
53 /* We copy the hardware revision to the last four bytes of SDRAM and then
54 re-read it after we have re-mapped SDRAM to 0x0 in Rockbox */
55 #define TMP_IPOD_HW_REVISION (*((volatile unsigned long*)(0x11fffffc)))
57 #define BUTTON_LEFT 1
58 #define BUTTON_MENU 2
59 #define BUTTON_RIGHT 3
60 #define BUTTON_PLAY 4
61 #define BUTTON_HOLD 5
63 /* Size of the buffer to store the loaded Rockbox/Linux image */
64 #define MAX_LOADSIZE (4*1024*1024)
66 char version[] = APPSVERSION;
68 typedef struct _image {
69 unsigned type; /* '' */
70 unsigned id; /* */
71 unsigned pad1; /* 0000 0000 */
72 unsigned devOffset; /* byte offset of start of image code */
73 unsigned len; /* length in bytes of image */
74 void *addr; /* load address */
75 unsigned entryOffset; /* execution start within image */
76 unsigned chksum; /* checksum for image */
77 unsigned vers; /* image version */
78 unsigned loadAddr; /* load address for image */
79 } image_t;
81 extern image_t boot_table[];
83 int line=0;
85 static void memmove16(void *dest, const void *src, unsigned count)
87 struct bufstr {
88 unsigned _buf[4];
89 } *d, *s;
91 if (src >= dest) {
92 count = (count + 15) >> 4;
93 d = (struct bufstr *) dest;
94 s = (struct bufstr *) src;
95 while (count--)
96 *d++ = *s++;
97 } else {
98 count = (count + 15) >> 4;
99 d = (struct bufstr *)(dest + (count <<4));
100 s = (struct bufstr *)(src + (count <<4));
101 while (count--)
102 *--d = *--s;
106 #if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
107 /* check if number of seconds has past */
108 int timer_check(int clock_start, unsigned int usecs)
110 if ((USEC_TIMER - clock_start) >= usecs) {
111 return 1;
112 } else {
113 return 0;
117 static void ser_opto_keypad_cfg(int val)
119 int start_time;
121 outl(inl(0x6000d004) & ~0x80, 0x6000d004);
123 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
124 outl(val, 0x7000c120);
125 outl(inl(0x7000c100) | 0x80000000, 0x7000c100);
127 outl(inl(0x6000d024) & ~0x10, 0x6000d024);
128 outl(inl(0x6000d014) | 0x10, 0x6000d014);
130 start_time = USEC_TIMER;
131 do {
132 if ((inl(0x7000c104) & 0x80000000) == 0) {
133 break;
135 } while (timer_check(start_time, 1500) != 0);
137 outl(inl(0x7000c100) & ~0x80000000, 0x7000c100);
139 outl(inl(0x6000d004) | 0x80, 0x6000d004);
140 outl(inl(0x6000d024) | 0x10, 0x6000d024);
141 outl(inl(0x6000d014) & ~0x10, 0x6000d014);
143 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
144 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
147 int opto_keypad_read(void)
149 int loop_cnt, had_io = 0;
151 for (loop_cnt = 5; loop_cnt != 0;)
153 int key_pressed = 0;
154 int start_time;
155 unsigned int key_pad_val;
157 ser_opto_keypad_cfg(0x8000023a);
159 start_time = USEC_TIMER;
160 do {
161 if (inl(0x7000c104) & 0x4000000) {
162 had_io = 1;
163 break;
166 if (had_io != 0) {
167 break;
169 } while (timer_check(start_time, 1500) != 0);
171 key_pad_val = inl(0x7000c140);
172 if ((key_pad_val & ~0x7fff0000) != 0x8000023a) {
173 loop_cnt--;
174 } else {
175 key_pad_val = (key_pad_val << 11) >> 27;
176 key_pressed = 1;
179 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
180 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
182 if (key_pressed != 0) {
183 return key_pad_val ^ 0x1f;
187 return 0;
189 #endif
191 static int key_pressed(void)
193 unsigned char state;
195 #if CONFIG_KEYPAD == IPOD_4G_PAD
196 #ifdef IPOD_MINI /* mini 1G only */
197 state = GPIOA_INPUT_VAL & 0x3f;
198 if ((state & 0x10) == 0) return BUTTON_LEFT;
199 if ((state & 0x2) == 0) return BUTTON_MENU;
200 if ((state & 0x4) == 0) return BUTTON_PLAY;
201 if ((state & 0x8) == 0) return BUTTON_RIGHT;
202 #else
203 state = opto_keypad_read();
204 if ((state & 0x4) == 0) return BUTTON_LEFT;
205 if ((state & 0x10) == 0) return BUTTON_MENU;
206 if ((state & 0x8) == 0) return BUTTON_PLAY;
207 if ((state & 0x2) == 0) return BUTTON_RIGHT;
208 #endif
209 #elif CONFIG_KEYPAD == IPOD_3G_PAD
210 state = inb(0xcf000030);
211 if (((state & 0x20) == 0)) return BUTTON_HOLD; /* hold on */
212 if ((state & 0x08) == 0) return BUTTON_LEFT;
213 if ((state & 0x10) == 0) return BUTTON_MENU;
214 if ((state & 0x04) == 0) return BUTTON_PLAY;
215 if ((state & 0x01) == 0) return BUTTON_RIGHT;
216 #endif
217 return 0;
220 int load_rockbox(unsigned char* buf)
222 int fd;
223 int rc;
224 int len;
225 unsigned long chksum;
226 char model[5];
227 unsigned long sum;
228 int i;
229 char str[80];
231 fd = open("/.rockbox/" BOOTFILE, O_RDONLY);
232 if(fd < 0)
234 fd = open("/" BOOTFILE, O_RDONLY);
235 if(fd < 0)
236 return -1;
239 len = filesize(fd) - 8;
241 if (len > MAX_LOADSIZE)
242 return -6;
244 lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
246 rc = read(fd, &chksum, 4);
247 chksum=betoh32(chksum); /* Rockbox checksums are big-endian */
248 if(rc < 4)
249 return -2;
251 rc = read(fd, model, 4);
252 if(rc < 4)
253 return -3;
255 model[4] = 0;
257 snprintf(str, 80, "Model: %s", model);
258 lcd_puts(0, line++, str);
259 snprintf(str, 80, "Checksum: %x", chksum);
260 lcd_puts(0, line++, str);
261 lcd_update();
263 lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
265 rc = read(fd, buf, len);
266 if(rc < len)
267 return -4;
269 close(fd);
271 sum = MODEL_NUMBER;
273 for(i = 0;i < len;i++) {
274 sum += buf[i];
277 snprintf(str, 80, "Sum: %x", sum);
278 lcd_puts(0, line++, str);
279 lcd_update();
281 if(sum != chksum)
282 return -5;
284 return len;
288 int load_linux(unsigned char* buf) {
289 int fd;
290 int rc;
291 int len;
292 char str[80];
294 fd=open("/linux.bin",O_RDONLY);
295 if (fd < 0)
296 return -1;
298 len=filesize(fd);
299 if (len > MAX_LOADSIZE)
300 return -6;
302 rc=read(fd,buf,len);
304 if (rc < len)
305 return -4;
307 snprintf(str, 80, "Loaded Linux: %d bytes", len);
308 lcd_puts(0, line++, str);
309 lcd_update();
311 return len;
315 /* A buffer to load the Linux kernel or Rockbox into */
316 unsigned char loadbuffer[MAX_LOADSIZE];
318 void* main(void)
320 char buf[256];
321 int imageno=0;
322 int i;
323 int rc;
324 int padding = 0x4400;
325 image_t *tblp = boot_table;
326 void* entry;
327 struct partinfo* pinfo;
328 unsigned short* identify_info;
330 /* Turn on the backlight */
332 #if CONFIG_BACKLIGHT==BL_IPOD4G
333 /* brightness full */
334 outl(0x80000000 | (0xff << 16), 0x7000a010);
336 /* set port B03 on */
337 outl(((0x100 | 1) << 3), 0x6000d824);
339 #elif CONFIG_BACKLIGHT==BL_IPODMINI
340 /* set port B03 on */
341 outl(((0x100 | 1) << 3), 0x6000d824);
343 #elif CONFIG_BACKLIGHT==BL_IPODNANO
345 /* set port B03 on */
346 outl(((0x100 | 1) << 3), 0x6000d824);
348 /* set port L07 on */
349 outl(((0x100 | 1) << 7), 0x6000d12c);
350 #elif CONFIG_BACKLIGHT==BL_IPOD3G
351 outl(inl(IPOD_LCD_BASE) | 0x2, IPOD_LCD_BASE);
352 #endif
354 TMP_IPOD_HW_REVISION = IPOD_HW_REVISION;
355 ipod_hw_rev = IPOD_HW_REVISION;
357 system_init();
358 kernel_init();
359 lcd_init();
360 font_init();
362 #if 0
363 /* ADC and button drivers are not yet implemented */
364 adc_init();
365 button_init();
366 #endif
368 line=0;
370 lcd_setfont(FONT_SYSFIXED);
372 lcd_puts(0, line++, "Rockbox boot loader");
373 snprintf(buf, sizeof(buf), "Version: 20%s", version);
374 lcd_puts(0, line++, buf);
375 snprintf(buf, sizeof(buf), "IPOD version: 0x%08x", IPOD_HW_REVISION);
376 lcd_puts(0, line++, buf);
377 lcd_update();
379 i=ata_init();
380 if (i==0) {
381 identify_info=ata_get_identify();
382 /* Show model */
383 for (i=0; i < 20; i++) {
384 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
386 buf[40]=0;
387 for (i=39; i && buf[i]==' '; i--) {
388 buf[i]=0;
390 lcd_puts(0, line++, buf);
391 lcd_update();
392 } else {
393 snprintf(buf, sizeof(buf), "ATA: %d", i);
394 lcd_puts(0, line++, buf);
395 lcd_update();
398 disk_init();
399 rc = disk_mount_all();
400 if (rc<=0)
402 lcd_puts(0, line++, "No partition found");
403 lcd_update();
404 // while(button_get(true) != SYS_USB_CONNECTED) {};
407 pinfo = disk_partinfo(1);
408 snprintf(buf, sizeof(buf), "Partition 1: 0x%02x %ld MB",
409 pinfo->type, pinfo->size / 2048);
410 lcd_puts(0, line++, buf);
411 lcd_update();
413 /* Check for a keypress */
414 i=key_pressed();
416 if ((i!=BUTTON_MENU) && (i!=BUTTON_PLAY)) {
417 lcd_puts(0, line, "Loading Rockbox...");
418 lcd_update();
419 rc=load_rockbox(loadbuffer);
420 if (rc < 0) {
421 snprintf(buf, sizeof(buf), "Rockbox error: %d",rc);
422 lcd_puts(0, line++, buf);
423 lcd_update();
424 } else {
425 lcd_puts(0, line++, "Rockbox loaded.");
426 lcd_update();
427 memcpy((void*)DRAM_START,loadbuffer,rc);
428 return (void*)DRAM_START;
432 if (i==BUTTON_PLAY) {
433 lcd_puts(0, line, "Loading Linux...");
434 lcd_update();
435 rc=load_linux(loadbuffer);
436 if (rc < 0) {
437 snprintf(buf, sizeof(buf), "Linux error: %d",rc);
438 lcd_puts(0, line++, buf);
439 lcd_update();
440 } else {
441 memcpy((void*)DRAM_START,loadbuffer,rc);
442 return (void*)DRAM_START;
446 /* If everything else failed, try the original firmware */
447 lcd_puts(0, line, "Loading original firmware...");
448 lcd_update();
450 /* Pause for 5 seconds so we can see what's happened */
451 // udelay(5000000);
453 entry = tblp->addr + tblp->entryOffset;
454 if (imageno || ((int)tblp->addr & 0xffffff) != 0) {
455 memmove16(tblp->addr, tblp->addr + tblp->devOffset - padding,
456 tblp->len);
459 /* Return the start address in loaded image */
460 return entry;
463 /* These functions are present in the firmware library, but we reimplement
464 them here because the originals do a lot more than we want */
466 void reset_poweroff_timer(void)
470 int dbg_ports(void)
472 return 0;
475 void mpeg_stop(void)
479 void usb_acknowledge(void)
483 void usb_wait_for_disconnect(void)
487 void sys_poweroff(void)