blob: 26e5ae2937c6844d960609f61fd2e65a7873940f [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>
Dave Chapman38e8fb62005-11-08 00:52:39 +000027#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"
Dave Chapman38e8fb62005-11-08 00:52:39 +000038#include "panic.h"
39#include "power.h"
40#include "file.h"
41
Dave Chapman8adc81d2006-02-21 21:13:03 +000042#define XSC(X) #X
43#define SC(X) XSC(X)
44
Dave Chapmanfa743562006-02-05 19:05:55 +000045#if (CONFIG_CPU == PP5020)
46#define DRAM_START 0x10000000
47#else
48#define IPOD_LCD_BASE 0xc0001000
49#define DRAM_START 0x28000000
50#endif
Dave Chapman38e8fb62005-11-08 00:52:39 +000051#define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084)))
52
Dave Chapmanf9dac402006-01-31 01:50:07 +000053/* 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)))
56
Dave Chapman061f3802005-11-13 20:59:30 +000057#define BUTTON_LEFT 1
58#define BUTTON_MENU 2
59#define BUTTON_RIGHT 3
60#define BUTTON_PLAY 4
Dave Chapmanfa743562006-02-05 19:05:55 +000061#define BUTTON_HOLD 5
Dave Chapman061f3802005-11-13 20:59:30 +000062
63/* Size of the buffer to store the loaded Rockbox/Linux image */
64#define MAX_LOADSIZE (4*1024*1024)
65
Dave Chapman38e8fb62005-11-08 00:52:39 +000066char version[] = APPSVERSION;
67
Dave Chapman38e8fb62005-11-08 00:52:39 +000068typedef 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;
80
81extern image_t boot_table[];
82
83int line=0;
84
85static void memmove16(void *dest, const void *src, unsigned count)
86{
87 struct bufstr {
88 unsigned _buf[4];
89 } *d, *s;
90
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;
103 }
104}
105
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000106#if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
Dave Chapman38e8fb62005-11-08 00:52:39 +0000107/* check if number of seconds has past */
108int timer_check(int clock_start, unsigned int usecs)
109{
Dave Chapmanfa743562006-02-05 19:05:55 +0000110 if ((USEC_TIMER - clock_start) >= usecs) {
Dave Chapman38e8fb62005-11-08 00:52:39 +0000111 return 1;
112 } else {
113 return 0;
114 }
115}
116
Dave Chapman061f3802005-11-13 20:59:30 +0000117static void ser_opto_keypad_cfg(int val)
118{
119 int start_time;
120
121 outl(inl(0x6000d004) & ~0x80, 0x6000d004);
122
123 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
124 outl(val, 0x7000c120);
125 outl(inl(0x7000c100) | 0x80000000, 0x7000c100);
126
127 outl(inl(0x6000d024) & ~0x10, 0x6000d024);
128 outl(inl(0x6000d014) | 0x10, 0x6000d014);
129
Dave Chapmanfa743562006-02-05 19:05:55 +0000130 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +0000131 do {
132 if ((inl(0x7000c104) & 0x80000000) == 0) {
133 break;
134 }
135 } while (timer_check(start_time, 1500) != 0);
136
137 outl(inl(0x7000c100) & ~0x80000000, 0x7000c100);
138
139 outl(inl(0x6000d004) | 0x80, 0x6000d004);
140 outl(inl(0x6000d024) | 0x10, 0x6000d024);
141 outl(inl(0x6000d014) & ~0x10, 0x6000d014);
142
143 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
144 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
145}
146
147int opto_keypad_read(void)
148{
149 int loop_cnt, had_io = 0;
150
151 for (loop_cnt = 5; loop_cnt != 0;)
152 {
153 int key_pressed = 0;
154 int start_time;
155 unsigned int key_pad_val;
156
157 ser_opto_keypad_cfg(0x8000023a);
158
Dave Chapmanfa743562006-02-05 19:05:55 +0000159 start_time = USEC_TIMER;
Dave Chapman061f3802005-11-13 20:59:30 +0000160 do {
161 if (inl(0x7000c104) & 0x4000000) {
162 had_io = 1;
163 break;
164 }
165
166 if (had_io != 0) {
167 break;
168 }
169 } while (timer_check(start_time, 1500) != 0);
170
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;
177 }
178
179 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
180 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
181
182 if (key_pressed != 0) {
183 return key_pad_val ^ 0x1f;
184 }
185 }
186
187 return 0;
188}
Dave Chapmanfa743562006-02-05 19:05:55 +0000189#endif
Dave Chapman061f3802005-11-13 20:59:30 +0000190
191static int key_pressed(void)
192{
193 unsigned char state;
194
Dave Chapmanfa743562006-02-05 19:05:55 +0000195#if CONFIG_KEYPAD == IPOD_4G_PAD
Jens Arnold7f880882006-04-02 00:20:11 +0000196#ifdef IPOD_MINI /* mini 1G only */
Dave Chapman28507912006-02-27 12:35:05 +0000197 state = GPIOA_INPUT_VAL & 0x3f;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000198 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;
Dave Chapman28507912006-02-27 12:35:05 +0000202#else
Dave Chapman061f3802005-11-13 20:59:30 +0000203 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;
Frank Dischner5d9eccd2006-04-19 18:06:56 +0000208#endif
Dave Chapmanfa743562006-02-05 19:05:55 +0000209#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
Dave Chapman061f3802005-11-13 20:59:30 +0000217 return 0;
218}
219
220int load_rockbox(unsigned char* buf)
Dave Chapman38e8fb62005-11-08 00:52:39 +0000221{
222 int fd;
223 int rc;
224 int len;
225 unsigned long chksum;
226 char model[5];
227 unsigned long sum;
228 int i;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000229 char str[80];
230
Dave Chapman20eed882005-11-20 10:57:53 +0000231 fd = open("/.rockbox/" BOOTFILE, O_RDONLY);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000232 if(fd < 0)
Dave Chapman20eed882005-11-20 10:57:53 +0000233 {
234 fd = open("/" BOOTFILE, O_RDONLY);
235 if(fd < 0)
236 return -1;
237 }
Dave Chapman38e8fb62005-11-08 00:52:39 +0000238
239 len = filesize(fd) - 8;
240
Dave Chapman061f3802005-11-13 20:59:30 +0000241 if (len > MAX_LOADSIZE)
242 return -6;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000243
244 lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
245
246 rc = read(fd, &chksum, 4);
Dave Chapman061f3802005-11-13 20:59:30 +0000247 chksum=betoh32(chksum); /* Rockbox checksums are big-endian */
Dave Chapman38e8fb62005-11-08 00:52:39 +0000248 if(rc < 4)
Dave Chapman061f3802005-11-13 20:59:30 +0000249 return -2;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000250
251 rc = read(fd, model, 4);
252 if(rc < 4)
Dave Chapman061f3802005-11-13 20:59:30 +0000253 return -3;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000254
255 model[4] = 0;
256
Thom Johansen1c69caf2006-01-18 23:02:00 +0000257 snprintf(str, 80, "Model: %s", model);
258 lcd_puts(0, line++, str);
259 snprintf(str, 80, "Checksum: %x", chksum);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000260 lcd_puts(0, line++, str);
261 lcd_update();
262
263 lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
264
265 rc = read(fd, buf, len);
266 if(rc < len)
Dave Chapman061f3802005-11-13 20:59:30 +0000267 return -4;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000268
269 close(fd);
270
271 sum = MODEL_NUMBER;
272
273 for(i = 0;i < len;i++) {
Dave Chapman061f3802005-11-13 20:59:30 +0000274 sum += buf[i];
Dave Chapman38e8fb62005-11-08 00:52:39 +0000275 }
276
277 snprintf(str, 80, "Sum: %x", sum);
278 lcd_puts(0, line++, str);
279 lcd_update();
280
281 if(sum != chksum)
282 return -5;
283
Dave Chapman061f3802005-11-13 20:59:30 +0000284 return len;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000285}
286
Dave Chapman061f3802005-11-13 20:59:30 +0000287
288int load_linux(unsigned char* buf) {
289 int fd;
290 int rc;
291 int len;
292 char str[80];
293
294 fd=open("/linux.bin",O_RDONLY);
295 if (fd < 0)
296 return -1;
297
298 len=filesize(fd);
299 if (len > MAX_LOADSIZE)
300 return -6;
301
302 rc=read(fd,buf,len);
303
304 if (rc < len)
305 return -4;
306
307 snprintf(str, 80, "Loaded Linux: %d bytes", len);
308 lcd_puts(0, line++, str);
309 lcd_update();
310
311 return len;
312}
313
314
315/* A buffer to load the Linux kernel or Rockbox into */
316unsigned char loadbuffer[MAX_LOADSIZE];
317
Dave Chapman38e8fb62005-11-08 00:52:39 +0000318void* main(void)
319{
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;
329
330 /* Turn on the backlight */
331
332#if CONFIG_BACKLIGHT==BL_IPOD4G
Dave Chapman38e8fb62005-11-08 00:52:39 +0000333 /* brightness full */
334 outl(0x80000000 | (0xff << 16), 0x7000a010);
335
Dave Chapmand8c5d1b2005-11-08 09:07:13 +0000336 /* set port B03 on */
Dave Chapman38e8fb62005-11-08 00:52:39 +0000337 outl(((0x100 | 1) << 3), 0x6000d824);
338
Dave Chapman8b1297a2006-02-21 15:01:25 +0000339#elif CONFIG_BACKLIGHT==BL_IPODMINI
340 /* set port B03 on */
341 outl(((0x100 | 1) << 3), 0x6000d824);
342
Dave Chapman38e8fb62005-11-08 00:52:39 +0000343#elif CONFIG_BACKLIGHT==BL_IPODNANO
344
345 /* set port B03 on */
346 outl(((0x100 | 1) << 3), 0x6000d824);
347
348 /* set port L07 on */
349 outl(((0x100 | 1) << 7), 0x6000d12c);
Dave Chapmanfa743562006-02-05 19:05:55 +0000350#elif CONFIG_BACKLIGHT==BL_IPOD3G
351 outl(inl(IPOD_LCD_BASE) | 0x2, IPOD_LCD_BASE);
Dave Chapman38e8fb62005-11-08 00:52:39 +0000352#endif
353
Dave Chapmanf9dac402006-01-31 01:50:07 +0000354 TMP_IPOD_HW_REVISION = IPOD_HW_REVISION;
Dave Chapman1446b212006-01-31 09:40:21 +0000355 ipod_hw_rev = IPOD_HW_REVISION;
Dave Chapmanf9dac402006-01-31 01:50:07 +0000356
Dave Chapman38e8fb62005-11-08 00:52:39 +0000357 system_init();
358 kernel_init();
359 lcd_init();
360 font_init();
361
362#if 0
363 /* ADC and button drivers are not yet implemented */
364 adc_init();
365 button_init();
366#endif
367
Dave Chapman3ded3ce2006-01-18 19:52:02 +0000368 line=0;
Dave Chapman38e8fb62005-11-08 00:52:39 +0000369
370 lcd_setfont(FONT_SYSFIXED);
371
Dave Chapman3ded3ce2006-01-18 19:52:02 +0000372 lcd_puts(0, line++, "Rockbox boot loader");
Dave Chapman38e8fb62005-11-08 00:52:39 +0000373 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();
378
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]);
385 }
386 buf[40]=0;
387 for (i=39; i && buf[i]==' '; i--) {
388 buf[i]=0;
389 }
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();
396 }
397
398 disk_init();
399 rc = disk_mount_all();
400 if (rc<=0)
401 {
402 lcd_puts(0, line++, "No partition found");
403 lcd_update();
404// while(button_get(true) != SYS_USB_CONNECTED) {};
405 }
406
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();
412
Dave Chapman061f3802005-11-13 20:59:30 +0000413 /* Check for a keypress */
414 i=key_pressed();
Dave Chapman38e8fb62005-11-08 00:52:39 +0000415
Dave Chapman20eed882005-11-20 10:57:53 +0000416 if ((i!=BUTTON_MENU) && (i!=BUTTON_PLAY)) {
Dave Chapman061f3802005-11-13 20:59:30 +0000417 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();
Dave Chapman061f3802005-11-13 20:59:30 +0000427 memcpy((void*)DRAM_START,loadbuffer,rc);
Daniel Ankerscec7cdc2006-08-03 16:29:42 +0000428 return (void*)DRAM_START;
Dave Chapman061f3802005-11-13 20:59:30 +0000429 }
430 }
431
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;
443 }
444 }
Dave Chapman38e8fb62005-11-08 00:52:39 +0000445
446 /* If everything else failed, try the original firmware */
447 lcd_puts(0, line, "Loading original firmware...");
448 lcd_update();
449
Dave Chapman061f3802005-11-13 20:59:30 +0000450 /* Pause for 5 seconds so we can see what's happened */
Dave Chapmanfa743562006-02-05 19:05:55 +0000451// udelay(5000000);
Dave Chapman061f3802005-11-13 20:59:30 +0000452
Dave Chapman38e8fb62005-11-08 00:52:39 +0000453 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);
457 }
458
459 /* Return the start address in loaded image */
460 return entry;
461}
462
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 */
465
466void reset_poweroff_timer(void)
467{
468}
469
Dave Chapman38e8fb62005-11-08 00:52:39 +0000470int dbg_ports(void)
471{
472 return 0;
473}
474
475void mpeg_stop(void)
476{
477}
478
479void usb_acknowledge(void)
480{
481}
482
483void usb_wait_for_disconnect(void)
484{
485}
486
487void sys_poweroff(void)
488{
489}