diff options
-rw-r--r-- | bootloader/ipod.c | 213 | ||||
-rw-r--r-- | firmware/boot.lds | 6 |
2 files changed, 176 insertions, 43 deletions
diff --git a/bootloader/ipod.c b/bootloader/ipod.c index 840b95be9e..591b7608aa 100644 --- a/bootloader/ipod.c +++ b/bootloader/ipod.c | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <stdio.h> | 25 | #include <stdio.h> |
26 | #include <string.h> | ||
26 | #include "cpu.h" | 27 | #include "cpu.h" |
27 | #include "system.h" | 28 | #include "system.h" |
28 | #include "lcd.h" | 29 | #include "lcd.h" |
@@ -34,7 +35,6 @@ | |||
34 | #include "font.h" | 35 | #include "font.h" |
35 | #include "adc.h" | 36 | #include "adc.h" |
36 | #include "backlight.h" | 37 | #include "backlight.h" |
37 | #include "button.h" | ||
38 | #include "panic.h" | 38 | #include "panic.h" |
39 | #include "power.h" | 39 | #include "power.h" |
40 | #include "file.h" | 40 | #include "file.h" |
@@ -44,6 +44,14 @@ | |||
44 | 44 | ||
45 | #define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084))) | 45 | #define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084))) |
46 | 46 | ||
47 | #define BUTTON_LEFT 1 | ||
48 | #define BUTTON_MENU 2 | ||
49 | #define BUTTON_RIGHT 3 | ||
50 | #define BUTTON_PLAY 4 | ||
51 | |||
52 | /* Size of the buffer to store the loaded Rockbox/Linux image */ | ||
53 | #define MAX_LOADSIZE (4*1024*1024) | ||
54 | |||
47 | char version[] = APPSVERSION; | 55 | char version[] = APPSVERSION; |
48 | 56 | ||
49 | #include "rockbox-16bit.h" | 57 | #include "rockbox-16bit.h" |
@@ -115,7 +123,93 @@ int usleep(unsigned int usecs) | |||
115 | return 0; | 123 | return 0; |
116 | } | 124 | } |
117 | 125 | ||
118 | int load_firmware(void) | 126 | |
127 | static void ser_opto_keypad_cfg(int val) | ||
128 | { | ||
129 | int start_time; | ||
130 | |||
131 | outl(inl(0x6000d004) & ~0x80, 0x6000d004); | ||
132 | |||
133 | outl(inl(0x7000c104) | 0xc000000, 0x7000c104); | ||
134 | outl(val, 0x7000c120); | ||
135 | outl(inl(0x7000c100) | 0x80000000, 0x7000c100); | ||
136 | |||
137 | outl(inl(0x6000d024) & ~0x10, 0x6000d024); | ||
138 | outl(inl(0x6000d014) | 0x10, 0x6000d014); | ||
139 | |||
140 | start_time = timer_get_current(); | ||
141 | do { | ||
142 | if ((inl(0x7000c104) & 0x80000000) == 0) { | ||
143 | break; | ||
144 | } | ||
145 | } while (timer_check(start_time, 1500) != 0); | ||
146 | |||
147 | outl(inl(0x7000c100) & ~0x80000000, 0x7000c100); | ||
148 | |||
149 | outl(inl(0x6000d004) | 0x80, 0x6000d004); | ||
150 | outl(inl(0x6000d024) | 0x10, 0x6000d024); | ||
151 | outl(inl(0x6000d014) & ~0x10, 0x6000d014); | ||
152 | |||
153 | outl(inl(0x7000c104) | 0xc000000, 0x7000c104); | ||
154 | outl(inl(0x7000c100) | 0x60000000, 0x7000c100); | ||
155 | } | ||
156 | |||
157 | int opto_keypad_read(void) | ||
158 | { | ||
159 | int loop_cnt, had_io = 0; | ||
160 | |||
161 | for (loop_cnt = 5; loop_cnt != 0;) | ||
162 | { | ||
163 | int key_pressed = 0; | ||
164 | int start_time; | ||
165 | unsigned int key_pad_val; | ||
166 | |||
167 | ser_opto_keypad_cfg(0x8000023a); | ||
168 | |||
169 | start_time = timer_get_current(); | ||
170 | do { | ||
171 | if (inl(0x7000c104) & 0x4000000) { | ||
172 | had_io = 1; | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | if (had_io != 0) { | ||
177 | break; | ||
178 | } | ||
179 | } while (timer_check(start_time, 1500) != 0); | ||
180 | |||
181 | key_pad_val = inl(0x7000c140); | ||
182 | if ((key_pad_val & ~0x7fff0000) != 0x8000023a) { | ||
183 | loop_cnt--; | ||
184 | } else { | ||
185 | key_pad_val = (key_pad_val << 11) >> 27; | ||
186 | key_pressed = 1; | ||
187 | } | ||
188 | |||
189 | outl(inl(0x7000c100) | 0x60000000, 0x7000c100); | ||
190 | outl(inl(0x7000c104) | 0xc000000, 0x7000c104); | ||
191 | |||
192 | if (key_pressed != 0) { | ||
193 | return key_pad_val ^ 0x1f; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int key_pressed(void) | ||
201 | { | ||
202 | unsigned char state; | ||
203 | |||
204 | state = opto_keypad_read(); | ||
205 | if ((state & 0x4) == 0) return BUTTON_LEFT; | ||
206 | if ((state & 0x10) == 0) return BUTTON_MENU; | ||
207 | if ((state & 0x8) == 0) return BUTTON_PLAY; | ||
208 | if ((state & 0x2) == 0) return BUTTON_RIGHT; | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int load_rockbox(unsigned char* buf) | ||
119 | { | 213 | { |
120 | int fd; | 214 | int fd; |
121 | int rc; | 215 | int rc; |
@@ -124,36 +218,31 @@ int load_firmware(void) | |||
124 | char model[5]; | 218 | char model[5]; |
125 | unsigned long sum; | 219 | unsigned long sum; |
126 | int i; | 220 | int i; |
127 | unsigned char *buf = (unsigned char *)DRAM_START; | ||
128 | char str[80]; | 221 | char str[80]; |
129 | 222 | ||
130 | fd = open("/rockbox.ipod", O_RDONLY); | 223 | fd = open("/rockbox.ipod", O_RDONLY); |
131 | if(fd < 0) | 224 | if(fd < 0) |
132 | return -1; | 225 | return -1; |
133 | 226 | ||
134 | len = filesize(fd) - 8; | 227 | len = filesize(fd) - 8; |
135 | 228 | ||
136 | snprintf(str, 80, "Length: %x", len); | 229 | if (len > MAX_LOADSIZE) |
137 | lcd_puts(0, line++, str); | 230 | return -6; |
138 | lcd_update(); | ||
139 | 231 | ||
140 | lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); | 232 | lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); |
141 | 233 | ||
142 | rc = read(fd, &chksum, 4); | 234 | rc = read(fd, &chksum, 4); |
235 | chksum=betoh32(chksum); /* Rockbox checksums are big-endian */ | ||
143 | if(rc < 4) | 236 | if(rc < 4) |
144 | return -2; | 237 | return -2; |
145 | |||
146 | snprintf(str, 80, "Checksum: %x", chksum); | ||
147 | lcd_puts(0, line++, str); | ||
148 | lcd_update(); | ||
149 | 238 | ||
150 | rc = read(fd, model, 4); | 239 | rc = read(fd, model, 4); |
151 | if(rc < 4) | 240 | if(rc < 4) |
152 | return -3; | 241 | return -3; |
153 | 242 | ||
154 | model[4] = 0; | 243 | model[4] = 0; |
155 | 244 | ||
156 | snprintf(str, 80, "Model name: %s", model); | 245 | snprintf(str, 80, "Model: %s, Checksum: %x", model, chksum); |
157 | lcd_puts(0, line++, str); | 246 | lcd_puts(0, line++, str); |
158 | lcd_update(); | 247 | lcd_update(); |
159 | 248 | ||
@@ -161,14 +250,14 @@ int load_firmware(void) | |||
161 | 250 | ||
162 | rc = read(fd, buf, len); | 251 | rc = read(fd, buf, len); |
163 | if(rc < len) | 252 | if(rc < len) |
164 | return -4; | 253 | return -4; |
165 | 254 | ||
166 | close(fd); | 255 | close(fd); |
167 | 256 | ||
168 | sum = MODEL_NUMBER; | 257 | sum = MODEL_NUMBER; |
169 | 258 | ||
170 | for(i = 0;i < len;i++) { | 259 | for(i = 0;i < len;i++) { |
171 | sum += buf[i]; | 260 | sum += buf[i]; |
172 | } | 261 | } |
173 | 262 | ||
174 | snprintf(str, 80, "Sum: %x", sum); | 263 | snprintf(str, 80, "Sum: %x", sum); |
@@ -178,9 +267,40 @@ int load_firmware(void) | |||
178 | if(sum != chksum) | 267 | if(sum != chksum) |
179 | return -5; | 268 | return -5; |
180 | 269 | ||
181 | return 0; | 270 | return len; |
182 | } | 271 | } |
183 | 272 | ||
273 | |||
274 | int load_linux(unsigned char* buf) { | ||
275 | int fd; | ||
276 | int rc; | ||
277 | int len; | ||
278 | char str[80]; | ||
279 | |||
280 | fd=open("/linux.bin",O_RDONLY); | ||
281 | if (fd < 0) | ||
282 | return -1; | ||
283 | |||
284 | len=filesize(fd); | ||
285 | if (len > MAX_LOADSIZE) | ||
286 | return -6; | ||
287 | |||
288 | rc=read(fd,buf,len); | ||
289 | |||
290 | if (rc < len) | ||
291 | return -4; | ||
292 | |||
293 | snprintf(str, 80, "Loaded Linux: %d bytes", len); | ||
294 | lcd_puts(0, line++, str); | ||
295 | lcd_update(); | ||
296 | |||
297 | return len; | ||
298 | } | ||
299 | |||
300 | |||
301 | /* A buffer to load the Linux kernel or Rockbox into */ | ||
302 | unsigned char loadbuffer[MAX_LOADSIZE]; | ||
303 | |||
184 | void* main(void) | 304 | void* main(void) |
185 | { | 305 | { |
186 | char buf[256]; | 306 | char buf[256]; |
@@ -196,7 +316,6 @@ void* main(void) | |||
196 | /* Turn on the backlight */ | 316 | /* Turn on the backlight */ |
197 | 317 | ||
198 | #if CONFIG_BACKLIGHT==BL_IPOD4G | 318 | #if CONFIG_BACKLIGHT==BL_IPOD4G |
199 | |||
200 | /* brightness full */ | 319 | /* brightness full */ |
201 | outl(0x80000000 | (0xff << 16), 0x7000a010); | 320 | outl(0x80000000 | (0xff << 16), 0x7000a010); |
202 | 321 | ||
@@ -277,32 +396,50 @@ void* main(void) | |||
277 | lcd_puts(0, line++, buf); | 396 | lcd_puts(0, line++, buf); |
278 | lcd_update(); | 397 | lcd_update(); |
279 | 398 | ||
399 | /* Check for a keypress */ | ||
400 | i=key_pressed(); | ||
401 | |||
402 | if (i==BUTTON_MENU) { | ||
403 | lcd_puts(0, line, "Loading Rockbox..."); | ||
404 | lcd_update(); | ||
405 | rc=load_rockbox(loadbuffer); | ||
406 | if (rc < 0) { | ||
407 | snprintf(buf, sizeof(buf), "Rockbox error: %d",rc); | ||
408 | lcd_puts(0, line++, buf); | ||
409 | lcd_update(); | ||
410 | } else { | ||
411 | lcd_puts(0, line++, "Rockbox loaded."); | ||
412 | lcd_update(); | ||
280 | #if 0 | 413 | #if 0 |
281 | /* The following code will load and run an ipodlinux kernel - we will | 414 | /* Rockbox is not yet runable, so we disable this */ |
282 | enable it once the button driver is written and we can detect key | 415 | memcpy((void*)DRAM_START,loadbuffer,rc); |
283 | presses */ | 416 | return (void*)DRAM_START; |
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 | 417 | #endif |
418 | } | ||
419 | } | ||
298 | 420 | ||
299 | /* Pause for 5 seconds so we can see what's happened*/ | 421 | if (i==BUTTON_PLAY) { |
300 | usleep(5000000); | 422 | lcd_puts(0, line, "Loading Linux..."); |
423 | lcd_update(); | ||
424 | rc=load_linux(loadbuffer); | ||
425 | if (rc < 0) { | ||
426 | snprintf(buf, sizeof(buf), "Linux error: %d",rc); | ||
427 | lcd_puts(0, line++, buf); | ||
428 | lcd_update(); | ||
429 | } else { | ||
430 | memcpy((void*)DRAM_START,loadbuffer,rc); | ||
431 | return (void*)DRAM_START; | ||
432 | } | ||
433 | } | ||
301 | 434 | ||
302 | /* If everything else failed, try the original firmware */ | 435 | /* If everything else failed, try the original firmware */ |
436 | |||
303 | lcd_puts(0, line, "Loading original firmware..."); | 437 | lcd_puts(0, line, "Loading original firmware..."); |
304 | lcd_update(); | 438 | lcd_update(); |
305 | 439 | ||
440 | /* Pause for 5 seconds so we can see what's happened */ | ||
441 | usleep(5000000); | ||
442 | |||
306 | entry = tblp->addr + tblp->entryOffset; | 443 | entry = tblp->addr + tblp->entryOffset; |
307 | if (imageno || ((int)tblp->addr & 0xffffff) != 0) { | 444 | if (imageno || ((int)tblp->addr & 0xffffff) != 0) { |
308 | memmove16(tblp->addr, tblp->addr + tblp->devOffset - padding, | 445 | memmove16(tblp->addr, tblp->addr + tblp->devOffset - padding, |
@@ -320,10 +457,6 @@ void reset_poweroff_timer(void) | |||
320 | { | 457 | { |
321 | } | 458 | } |
322 | 459 | ||
323 | void screen_dump(void) | ||
324 | { | ||
325 | } | ||
326 | |||
327 | int dbg_ports(void) | 460 | int dbg_ports(void) |
328 | { | 461 | { |
329 | return 0; | 462 | return 0; |
diff --git a/firmware/boot.lds b/firmware/boot.lds index ec8db5ba90..2d320e2b81 100644 --- a/firmware/boot.lds +++ b/firmware/boot.lds | |||
@@ -79,10 +79,10 @@ SECTIONS | |||
79 | stackend = .; | 79 | stackend = .; |
80 | } | 80 | } |
81 | 81 | ||
82 | /* The bss section is too large for IRAM - we just move it near the | 82 | /* The bss section is too large for IRAM - we just move it 16MB into the |
83 | end of the regular RAM. */ | 83 | DRAM */ |
84 | 84 | ||
85 | . = 0x11c00000; | 85 | . = (DRAMORIG+16*1024*1024); |
86 | .bss : { | 86 | .bss : { |
87 | _bssstart = .; | 87 | _bssstart = .; |
88 | *(.bss); | 88 | *(.bss); |