blob: 840b95be9ea41a159722a69fe0a2cb5848ff8a9f [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>
26#include "cpu.h"
27#include "system.h"
28#include "lcd.h"
29#include "kernel.h"
30#include "thread.h"
31#include "ata.h"
32#include "fat.h"
33#include "disk.h"
34#include "font.h"
35#include "adc.h"
36#include "backlight.h"
37#include "button.h"
38#include "panic.h"
39#include "power.h"
40#include "file.h"
41
42#define DRAM_START 0x10000000
43#define IPOD_PP5020_RTC 0x60005010
44
45#define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084)))
46
47char version[] = APPSVERSION;
48
49#include "rockbox-16bit.h"
50#include "ipodlinux-16bit.h"
51
52typedef struct _image {
53 unsigned type; /* '' */
54 unsigned id; /* */
55 unsigned pad1; /* 0000 0000 */
56 unsigned devOffset; /* byte offset of start of image code */
57 unsigned len; /* length in bytes of image */
58 void *addr; /* load address */
59 unsigned entryOffset; /* execution start within image */
60 unsigned chksum; /* checksum for image */
61 unsigned vers; /* image version */
62 unsigned loadAddr; /* load address for image */
63} image_t;
64
65extern image_t boot_table[];
66
67int line=0;
68
69static void memmove16(void *dest, const void *src, unsigned count)
70{
71 struct bufstr {
72 unsigned _buf[4];
73 } *d, *s;
74
75 if (src >= dest) {
76 count = (count + 15) >> 4;
77 d = (struct bufstr *) dest;
78 s = (struct bufstr *) src;
79 while (count--)
80 *d++ = *s++;
81 } else {
82 count = (count + 15) >> 4;
83 d = (struct bufstr *)(dest + (count <<4));
84 s = (struct bufstr *)(src + (count <<4));
85 while (count--)
86 *--d = *--s;
87 }
88}
89
90/* get current usec counter */
91int timer_get_current(void)
92{
93 return inl(IPOD_PP5020_RTC);
94}
95
96/* check if number of seconds has past */
97int timer_check(int clock_start, unsigned int usecs)
98{
99 if ((inl(IPOD_PP5020_RTC) - clock_start) >= usecs) {
100 return 1;
101 } else {
102 return 0;
103 }
104}
105
106/* This isn't a sleep, but let's call it that. */
107int usleep(unsigned int usecs)
108{
109 unsigned int start = inl(IPOD_PP5020_RTC);
110
111 while ((inl(IPOD_PP5020_RTC) - start) < usecs) {
112 // empty
113 }
114
115 return 0;
116}
117
118int load_firmware(void)
119{
120 int fd;
121 int rc;
122 int len;
123 unsigned long chksum;
124 char model[5];
125 unsigned long sum;
126 int i;
127 unsigned char *buf = (unsigned char *)DRAM_START;
128 char str[80];
129
130 fd = open("/rockbox.ipod", O_RDONLY);
131 if(fd < 0)
132 return -1;
133
134 len = filesize(fd) - 8;
135
136 snprintf(str, 80, "Length: %x", len);
137 lcd_puts(0, line++, str);
138 lcd_update();
139
140 lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET);
141
142 rc = read(fd, &chksum, 4);
143 if(rc < 4)
144 return -2;
145
146 snprintf(str, 80, "Checksum: %x", chksum);
147 lcd_puts(0, line++, str);
148 lcd_update();
149
150 rc = read(fd, model, 4);
151 if(rc < 4)
152 return -3;
153
154 model[4] = 0;
155
156 snprintf(str, 80, "Model name: %s", model);
157 lcd_puts(0, line++, str);
158 lcd_update();
159
160 lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
161
162 rc = read(fd, buf, len);
163 if(rc < len)
164 return -4;
165
166 close(fd);
167
168 sum = MODEL_NUMBER;
169
170 for(i = 0;i < len;i++) {
171 sum += buf[i];
172 }
173
174 snprintf(str, 80, "Sum: %x", sum);
175 lcd_puts(0, line++, str);
176 lcd_update();
177
178 if(sum != chksum)
179 return -5;
180
181 return 0;
182}
183
184void* main(void)
185{
186 char buf[256];
187 int imageno=0;
188 int i;
189 int rc;
190 int padding = 0x4400;
191 image_t *tblp = boot_table;
192 void* entry;
193 struct partinfo* pinfo;
194 unsigned short* identify_info;
195
196 /* Turn on the backlight */
197
198#if CONFIG_BACKLIGHT==BL_IPOD4G
199
200 /* brightness full */
201 outl(0x80000000 | (0xff << 16), 0x7000a010);
202
Dave Chapmand8c5d1b2005-11-08 09:07:13 +0000203 /* set port B03 on */
Dave Chapman38e8fb62005-11-08 00:52:39 +0000204 outl(((0x100 | 1) << 3), 0x6000d824);
205
206#elif CONFIG_BACKLIGHT==BL_IPODNANO
207
208 /* set port B03 on */
209 outl(((0x100 | 1) << 3), 0x6000d824);
210
211 /* set port L07 on */
212 outl(((0x100 | 1) << 7), 0x6000d12c);
213
214#endif
215
216 system_init();
217 kernel_init();
218 lcd_init();
219 font_init();
220
221#if 0
222 /* ADC and button drivers are not yet implemented */
223 adc_init();
224 button_init();
225#endif
226
227 /* Notes: iPod Color/Photo LCD is 220x176, Nano is 176x138 */
228
229 /* Display the 42x47 pixel iPodLinux logo */
230 lcd_bitmap((unsigned char*)ipllogo, 20,6, 42,47);
231
232 /* Display the 100x31 pixel Rockbox logo */
233 lcd_bitmap((unsigned char*)rockboxlogo, 74,16, 100,31);
234
235 line=7;
236
237 lcd_setfont(FONT_SYSFIXED);
238
239 lcd_puts(0, line++, "iPodLinux/Rockbox boot loader");
240 snprintf(buf, sizeof(buf), "Version: 20%s", version);
241 lcd_puts(0, line++, buf);
242 snprintf(buf, sizeof(buf), "IPOD version: 0x%08x", IPOD_HW_REVISION);
243 lcd_puts(0, line++, buf);
244 lcd_update();
245
246 i=ata_init();
247 if (i==0) {
248 identify_info=ata_get_identify();
249 /* Show model */
250 for (i=0; i < 20; i++) {
251 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
252 }
253 buf[40]=0;
254 for (i=39; i && buf[i]==' '; i--) {
255 buf[i]=0;
256 }
257 lcd_puts(0, line++, buf);
258 lcd_update();
259 } else {
260 snprintf(buf, sizeof(buf), "ATA: %d", i);
261 lcd_puts(0, line++, buf);
262 lcd_update();
263 }
264
265 disk_init();
266 rc = disk_mount_all();
267 if (rc<=0)
268 {
269 lcd_puts(0, line++, "No partition found");
270 lcd_update();
271// while(button_get(true) != SYS_USB_CONNECTED) {};
272 }
273
274 pinfo = disk_partinfo(1);
275 snprintf(buf, sizeof(buf), "Partition 1: 0x%02x %ld MB",
276 pinfo->type, pinfo->size / 2048);
277 lcd_puts(0, line++, buf);
278 lcd_update();
279
280#if 0
281 /* The following code will load and run an ipodlinux kernel - we will
282 enable it once the button driver is written and we can detect key
283 presses */
284 int fd=open("/linux.bin",O_RDONLY);
285 if (fd >= 0) {
286 i=filesize(fd);
287 int n=read(fd,(void*)DRAM_START,i);
288 if (n==i) {
289 /* We return the entry point for the loaded kernel */
290 return DRAM_START;
291 } else {
292 /* What do we do now? We may have overwritten the copy of the
293 original firmware with our incomplete copy of the Linux
294 kernel... */
295 }
296 }
297#endif
298
299 /* Pause for 5 seconds so we can see what's happened*/
300 usleep(5000000);
301
302 /* If everything else failed, try the original firmware */
303 lcd_puts(0, line, "Loading original firmware...");
304 lcd_update();
305
306 entry = tblp->addr + tblp->entryOffset;
307 if (imageno || ((int)tblp->addr & 0xffffff) != 0) {
308 memmove16(tblp->addr, tblp->addr + tblp->devOffset - padding,
309 tblp->len);
310 }
311
312 /* Return the start address in loaded image */
313 return entry;
314}
315
316/* These functions are present in the firmware library, but we reimplement
317 them here because the originals do a lot more than we want */
318
319void reset_poweroff_timer(void)
320{
321}
322
323void screen_dump(void)
324{
325}
326
327int dbg_ports(void)
328{
329 return 0;
330}
331
332void mpeg_stop(void)
333{
334}
335
336void usb_acknowledge(void)
337{
338}
339
340void usb_wait_for_disconnect(void)
341{
342}
343
344void sys_poweroff(void)
345{
346}