diff options
Diffstat (limited to 'flash/bootloader/bootloader.c')
-rw-r--r-- | flash/bootloader/bootloader.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/flash/bootloader/bootloader.c b/flash/bootloader/bootloader.c new file mode 100644 index 0000000000..7179bbef95 --- /dev/null +++ b/flash/bootloader/bootloader.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2003 by Jörg Hohensohn | ||
11 | * | ||
12 | * Second-level bootloader, with dual-boot feature by holding F1/Menu | ||
13 | * This is the image being descrambled and executed by the boot ROM. | ||
14 | * It's task is to copy Rockbox from Flash to DRAM. | ||
15 | * The image(s) in flash may optionally be compressed with UCL 2e | ||
16 | * | ||
17 | * All files in this archive are subject to the GNU General Public License. | ||
18 | * See the file COPYING in the source tree root for full license agreement. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #include "sh7034.h" | ||
26 | #include "bootloader.h" | ||
27 | |||
28 | |||
29 | #ifdef NO_ROM | ||
30 | // start with the vector table | ||
31 | UINT32 vectors[] __attribute__ ((section (".vectors"))) = | ||
32 | { | ||
33 | (UINT32)_main, // entry point, the copy routine | ||
34 | (UINT32)(end_stack - 1), // initial stack pointer | ||
35 | FLASH_BASE + 0x200, // source of image in flash | ||
36 | (UINT32)total_size, // size of image | ||
37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
38 | 0x03020080 // mask and version (just as a suggestion) | ||
39 | }; | ||
40 | #else | ||
41 | // our binary has to start with a vector to the entry point | ||
42 | tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main}; | ||
43 | #endif | ||
44 | |||
45 | #ifdef NO_ROM // some code which is only needed for the romless variant | ||
46 | void _main(void) | ||
47 | { | ||
48 | UINT32* pSrc; | ||
49 | UINT32* pDest; | ||
50 | UINT32* pEnd; | ||
51 | /* | ||
52 | asm volatile ("ldc %0,sr" : : "r"(0xF0)); // disable interrupts | ||
53 | asm volatile ("mov.l @%0,r15" : : "r"(4)); // load stack | ||
54 | asm volatile ("ldc %0,vbr" : : "r"(0)); // load vector base | ||
55 | */ | ||
56 | // copy everything to IRAM and continue there | ||
57 | pSrc = begin_iramcopy; | ||
58 | pDest = begin_text; | ||
59 | pEnd = pDest + (begin_stack - begin_text); | ||
60 | |||
61 | do | ||
62 | { | ||
63 | *pDest++ = *pSrc++; | ||
64 | } | ||
65 | while (pDest < pEnd); | ||
66 | |||
67 | main(); // jump to the real main() | ||
68 | } | ||
69 | |||
70 | |||
71 | void BootInit(void) | ||
72 | { | ||
73 | // inits from the boot ROM, whether they make sense or not | ||
74 | PBDR &= 0xFFBF; // LED off (0x131E) | ||
75 | PBCR2 = 0; // all GPIO | ||
76 | PBIOR |= 0x40; // LED output | ||
77 | PBIOR &= 0xFFF1; // LCD lines input | ||
78 | |||
79 | // init DRAM like the boot ROM does | ||
80 | PACR2 &= 0xFFFB; | ||
81 | PACR2 |= 0x0008; | ||
82 | CASCR = 0xAF; | ||
83 | BCR |= 0x8000; | ||
84 | WCR1 &= 0xFDFD; | ||
85 | DCR = 0x0E00; | ||
86 | RCR = 0x5AB0; | ||
87 | RTCOR = 0x9605; | ||
88 | RTCSR = 0xA518; | ||
89 | } | ||
90 | #endif // #ifdef NO_ROM | ||
91 | |||
92 | |||
93 | int main(void) | ||
94 | { | ||
95 | int nButton; | ||
96 | |||
97 | PlatformInit(); // model-specific inits | ||
98 | |||
99 | nButton = ButtonPressed(); | ||
100 | |||
101 | if (nButton == 3) | ||
102 | { // F3 means start monitor | ||
103 | MiniMon(); | ||
104 | } | ||
105 | else | ||
106 | { | ||
107 | tImage* pImage; | ||
108 | pImage = GetStartImage(nButton); // which image | ||
109 | DecompressStart(pImage); // move into place and start it | ||
110 | } | ||
111 | |||
112 | return 0; // I guess we won't return ;-) | ||
113 | } | ||
114 | |||
115 | |||
116 | // init code that is specific to certain platform | ||
117 | void PlatformInit(void) | ||
118 | { | ||
119 | #ifdef NO_ROM | ||
120 | BootInit(); // if not started by boot ROM, we need to init what it did | ||
121 | #endif | ||
122 | |||
123 | #if defined PLATFORM_PLAYER | ||
124 | BRR1 = 0x0019; // 14400 Baud for monitor | ||
125 | if (FW_VERSION > 451) // "new" Player? | ||
126 | { | ||
127 | PBDR &= ~0x10; // set PB4 to 0 to power-up the harddisk early | ||
128 | PBIOR |= 0x10; // make PB4 an output | ||
129 | } | ||
130 | #elif defined PLATFORM_RECORDER | ||
131 | BRR1 = 0x0002; // 115200 Baud for monitor | ||
132 | if (ReadADC(7) > 0x100) // charger plugged? | ||
133 | { // switch off the HD, else a flat battery may not start | ||
134 | PACR2 &= 0xFBFF; // GPIO for PA5 | ||
135 | PAIOR |= 0x20; // make PA5 an output (low by default) | ||
136 | } | ||
137 | #elif defined PLATFORM_FM | ||
138 | BRR1 = 0x0002; // 115200 Baud for monitor | ||
139 | PBDR |= 0x20; // set PB5 to keep power (fixes the ON-holding problem) | ||
140 | PBIOR |= 0x20; // make PB5 an output | ||
141 | if (ReadADC(0) < 0x1FF) // charger plugged? | ||
142 | { | ||
143 | // how do we switch this off? | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | // platform-independent inits | ||
148 | DCR |= 0x1000; // enable burst mode on DRAM | ||
149 | BCR |= 0x2000; // activate Warp mode (simultaneous internal and external mem access) | ||
150 | } | ||
151 | |||
152 | |||
153 | // Thinned out version of the UCL 2e decompression sourcecode | ||
154 | // Original (C) Markus F.X.J Oberhumer under GNU GPL license | ||
155 | #define GETBIT(bb, src, ilen) \ | ||
156 | (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1) | ||
157 | |||
158 | int ucl_nrv2e_decompress_8( | ||
159 | const UINT8 *src, UINT8 *dst, UINT32* dst_len) | ||
160 | { | ||
161 | UINT32 bb = 0; | ||
162 | unsigned ilen = 0, olen = 0, last_m_off = 1; | ||
163 | |||
164 | for (;;) | ||
165 | { | ||
166 | unsigned m_off, m_len; | ||
167 | |||
168 | while (GETBIT(bb,src,ilen)) | ||
169 | { | ||
170 | dst[olen++] = src[ilen++]; | ||
171 | } | ||
172 | m_off = 1; | ||
173 | for (;;) | ||
174 | { | ||
175 | m_off = m_off*2 + GETBIT(bb,src,ilen); | ||
176 | if (GETBIT(bb,src,ilen)) break; | ||
177 | m_off = (m_off-1)*2 + GETBIT(bb,src,ilen); | ||
178 | } | ||
179 | if (m_off == 2) | ||
180 | { | ||
181 | m_off = last_m_off; | ||
182 | m_len = GETBIT(bb,src,ilen); | ||
183 | } | ||
184 | else | ||
185 | { | ||
186 | m_off = (m_off-3)*256 + src[ilen++]; | ||
187 | if (m_off == 0xffffffff) | ||
188 | break; | ||
189 | m_len = (m_off ^ 0xffffffff) & 1; | ||
190 | m_off >>= 1; | ||
191 | last_m_off = ++m_off; | ||
192 | } | ||
193 | if (m_len) | ||
194 | m_len = 1 + GETBIT(bb,src,ilen); | ||
195 | else if (GETBIT(bb,src,ilen)) | ||
196 | m_len = 3 + GETBIT(bb,src,ilen); | ||
197 | else | ||
198 | { | ||
199 | m_len++; | ||
200 | do { | ||
201 | m_len = m_len*2 + GETBIT(bb,src,ilen); | ||
202 | } while (!GETBIT(bb,src,ilen)); | ||
203 | m_len += 3; | ||
204 | } | ||
205 | m_len += (m_off > 0x500); | ||
206 | { | ||
207 | const UINT8 *m_pos; | ||
208 | m_pos = dst + olen - m_off; | ||
209 | dst[olen++] = *m_pos++; | ||
210 | do dst[olen++] = *m_pos++; while (--m_len > 0); | ||
211 | } | ||
212 | } | ||
213 | *dst_len = olen; | ||
214 | |||
215 | return ilen; | ||
216 | } | ||
217 | |||
218 | |||
219 | // move the image into place and start it | ||
220 | void DecompressStart(tImage* pImage) | ||
221 | { | ||
222 | UINT32* pSrc; | ||
223 | UINT32* pDest; | ||
224 | |||
225 | pSrc = pImage->image; | ||
226 | pDest = pImage->pDestination; | ||
227 | |||
228 | if (pSrc != pDest) // if not linked to that flash address | ||
229 | { | ||
230 | if (pImage->flags & IF_UCL_2E) | ||
231 | { // UCL compressed, algorithm 2e | ||
232 | UINT32 dst_len; // dummy | ||
233 | ucl_nrv2e_decompress_8((UINT8*)pSrc, (UINT8*)pDest, &dst_len); | ||
234 | } | ||
235 | else | ||
236 | { // uncompressed, copy it | ||
237 | UINT32 size = pImage->size; | ||
238 | UINT32* pEnd; | ||
239 | size = (size + 3) / 4; // round up to 32bit-words | ||
240 | pEnd = pDest + size; | ||
241 | |||
242 | do | ||
243 | { | ||
244 | *pDest++ = *pSrc++; | ||
245 | } | ||
246 | while (pDest < pEnd); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | pImage->pExecute(); | ||
251 | } | ||
252 | |||
253 | |||
254 | int ReadADC(int channel) | ||
255 | { | ||
256 | // after channel 3, the ports wrap and get re-used | ||
257 | volatile UINT16* pResult = (UINT16*)(ADDRAH_ADDR + 2 * (channel & 0x03)); | ||
258 | int timeout = 266; // conversion takes 266 clock cycles | ||
259 | |||
260 | ADCSR = 0x20 | channel; // start single conversion | ||
261 | while (((ADCSR & 0x80) == 0) && (--timeout)); // 6 instructions per round | ||
262 | |||
263 | return (timeout == 0) ? -1 : *pResult>>6; | ||
264 | } | ||
265 | |||
266 | |||
267 | // This function is platform-dependent, | ||
268 | // until I figure out how to distinguish at runtime. | ||
269 | int ButtonPressed(void) // return 1,2,3 for F1,F2,F3, 0 if none pressed | ||
270 | { | ||
271 | int value = ReadADC(CHANNEL); | ||
272 | |||
273 | if (value >= F1_LOWER && value <= F1_UPPER) // in range | ||
274 | return 1; | ||
275 | else if (value >= F2_LOWER && value <= F2_UPPER) // in range | ||
276 | return 2; | ||
277 | else if (value >= F3_LOWER && value <= F3_UPPER) // in range | ||
278 | return 3; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | |||
284 | // Determine the image to be started | ||
285 | tImage* GetStartImage(int nPreferred) | ||
286 | { | ||
287 | tImage* pImage1; | ||
288 | tImage* pImage2 = NULL; // default to not present | ||
289 | UINT32 pos; | ||
290 | UINT32* pFlash = (UINT32*)FLASH_BASE; | ||
291 | |||
292 | // determine the first image position | ||
293 | pos = pFlash[2] + pFlash[3]; // position + size of the bootloader = after it | ||
294 | pos = (pos + 3) & ~3; // be shure it's 32 bit aligned | ||
295 | |||
296 | pImage1 = (tImage*)pos; | ||
297 | |||
298 | if (pImage1->size != 0) | ||
299 | { // check for second image | ||
300 | pos = (UINT32)(&pImage1->image) + pImage1->size; | ||
301 | pImage2 = (tImage*)pos; | ||
302 | |||
303 | // does it make sense? (not in FF or 00 erazed space) | ||
304 | if (pImage2->pDestination == (void*)0xFFFFFFFF | ||
305 | || pImage2->size == 0xFFFFFFFF | ||
306 | || pImage2->pExecute == (void*)0xFFFFFFFF | ||
307 | || pImage2->flags == 0xFFFFFFFF | ||
308 | || pImage2->pDestination == NULL) // size, execute and flags can legally be 0 | ||
309 | { | ||
310 | pImage2 = NULL; // invalidate | ||
311 | } | ||
312 | } | ||
313 | |||
314 | if (pImage2 == NULL || nPreferred == 1) | ||
315 | { // no second image or overridden: return the first | ||
316 | return pImage1; | ||
317 | } | ||
318 | |||
319 | return pImage2; // return second image | ||
320 | } | ||
321 | |||
322 | // diagnostic functions | ||
323 | |||
324 | void SetLed(BOOL bOn) | ||
325 | { | ||
326 | if (bOn) | ||
327 | PBDR |= 0x40; | ||
328 | else | ||
329 | PBDR &= ~0x40; | ||
330 | } | ||
331 | |||
332 | |||
333 | void UartInit(void) | ||
334 | { | ||
335 | PBIOR &= 0xFBFF; // input: RXD1 remote pin | ||
336 | PBCR1 |= 0x00A0; // set PB3+PB2 to UART | ||
337 | PBCR1 &= 0xFFAF; // clear bits 6, 4 -> UART | ||
338 | SMR1 = 0x0000; // async format 8N1, baud generator input is CPU clock | ||
339 | SCR1 = 0x0030; // transmit+receive enable | ||
340 | PBCR1 &= 0x00FF; // set bit 12...15 as GPIO | ||
341 | SSR1 &= 0x00BF; // clear bit 6 (RDRF, receive data register full) | ||
342 | } | ||
343 | |||
344 | |||
345 | UINT8 UartRead(void) | ||
346 | { | ||
347 | UINT8 byte; | ||
348 | while (!(SSR1 & SCI_RDRF)); // wait for char to be available | ||
349 | byte = RDR1; | ||
350 | SSR1 &= ~SCI_RDRF; | ||
351 | return byte; | ||
352 | } | ||
353 | |||
354 | |||
355 | void UartWrite(UINT8 byte) | ||
356 | { | ||
357 | while (!(SSR1 & SCI_TDRE)); // wait for transmit buffer empty | ||
358 | TDR1 = byte; | ||
359 | SSR1 &= ~SCI_TDRE; | ||
360 | } | ||
361 | |||
362 | |||
363 | // include the mini monitor as a rescue feature, started with F3 | ||
364 | void MiniMon(void) | ||
365 | { | ||
366 | UINT8 cmd; | ||
367 | UINT32 addr; | ||
368 | UINT32 size; | ||
369 | UINT32 content; | ||
370 | volatile UINT8* paddr = NULL; | ||
371 | volatile UINT8* pflash = NULL; // flash base address | ||
372 | |||
373 | UartInit(); | ||
374 | |||
375 | while (1) | ||
376 | { | ||
377 | cmd = UartRead(); | ||
378 | switch (cmd) | ||
379 | { | ||
380 | case BAUDRATE: | ||
381 | content = UartRead(); | ||
382 | UartWrite(cmd); // acknowledge by returning the command value | ||
383 | while (!(SSR1 & SCI_TEND)); // wait for empty shift register, before changing baudrate | ||
384 | BRR1 = content; | ||
385 | break; | ||
386 | |||
387 | case ADDRESS: | ||
388 | addr = (UartRead() << 24) | (UartRead() << 16) | (UartRead() << 8) | UartRead(); | ||
389 | paddr = (UINT8*)addr; | ||
390 | pflash = (UINT8*)(addr & 0xFFF80000); // round down to 512k align | ||
391 | UartWrite(cmd); // acknowledge by returning the command value | ||
392 | break; | ||
393 | |||
394 | case BYTE_READ: | ||
395 | content = *paddr++; | ||
396 | UartWrite(content); // the content is the ack | ||
397 | break; | ||
398 | |||
399 | case BYTE_WRITE: | ||
400 | content = UartRead(); | ||
401 | *paddr++ = content; | ||
402 | UartWrite(cmd); // acknowledge by returning the command value | ||
403 | break; | ||
404 | |||
405 | case BYTE_READ16: | ||
406 | size = 16; | ||
407 | while (size--) | ||
408 | { | ||
409 | content = *paddr++; | ||
410 | UartWrite(content); // the content is the ack | ||
411 | } | ||
412 | break; | ||
413 | |||
414 | case BYTE_WRITE16: | ||
415 | size = 16; | ||
416 | while (size--) | ||
417 | { | ||
418 | content = UartRead(); | ||
419 | *paddr++ = content; | ||
420 | } | ||
421 | UartWrite(cmd); // acknowledge by returning the command value | ||
422 | break; | ||
423 | |||
424 | case BYTE_FLASH: | ||
425 | content = UartRead(); | ||
426 | pflash[0x5555] = 0xAA; // set flash to command mode | ||
427 | pflash[0x2AAA] = 0x55; | ||
428 | pflash[0x5555] = 0xA0; // byte program command | ||
429 | *paddr++ = content; | ||
430 | UartWrite(cmd); // acknowledge by returning the command value | ||
431 | break; | ||
432 | |||
433 | case BYTE_FLASH16: | ||
434 | size = 16; | ||
435 | while (size--) | ||
436 | { | ||
437 | content = UartRead(); | ||
438 | pflash[0x5555] = 0xAA; // set flash to command mode | ||
439 | pflash[0x2AAA] = 0x55; | ||
440 | pflash[0x5555] = 0xA0; // byte program command | ||
441 | *paddr++ = content; | ||
442 | } | ||
443 | UartWrite(cmd); // acknowledge by returning the command value | ||
444 | break; | ||
445 | |||
446 | case HALFWORD_READ: | ||
447 | content = *(UINT16*)paddr; | ||
448 | paddr += 2; | ||
449 | UartWrite(content >> 8); // highbyte | ||
450 | UartWrite(content & 0xFF); // lowbyte | ||
451 | break; | ||
452 | |||
453 | case HALFWORD_WRITE: | ||
454 | content = UartRead() << 8 | UartRead(); | ||
455 | *(UINT16*)paddr = content; | ||
456 | paddr += 2; | ||
457 | UartWrite(cmd); // acknowledge by returning the command value | ||
458 | break; | ||
459 | |||
460 | case EXECUTE: | ||
461 | { | ||
462 | tpFunc pFunc = (tpFunc)paddr; | ||
463 | pFunc(); | ||
464 | UartWrite(cmd); // acknowledge by returning the command value | ||
465 | } | ||
466 | break; | ||
467 | |||
468 | case VERSION: | ||
469 | UartWrite(1); // return our version number | ||
470 | break; | ||
471 | |||
472 | default: | ||
473 | { | ||
474 | SetLed(TRUE); | ||
475 | UartWrite(~cmd); // error acknowledge | ||
476 | } | ||
477 | |||
478 | } // case | ||
479 | } // while (1) | ||
480 | } | ||