Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / flash / bootloader / bootloader.c
blobdc094d1b2eb1d1287e8aba7d69ae8eda3ef1eb71
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2003 by Jörg Hohensohn
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
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
25 ****************************************************************************/
27 #include "sh7034.h"
28 #include "bootloader.h"
31 #ifdef NO_ROM
32 /* start with the vector table */
33 UINT32 vectors[] __attribute__ ((section (".vectors"))) =
35 (UINT32)_main, /* entry point, the copy routine */
36 (UINT32)(end_stack - 1), /* initial stack pointer */
37 FLASH_BASE + 0x200, /* source of image in flash */
38 (UINT32)total_size, /* size of image */
39 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,
40 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,
41 0x03020080 /* mask and version (just as a suggestion) */
43 #else
44 /* our binary has to start with a vector to the entry point */
45 tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main};
46 #endif
48 #ifdef NO_ROM /* some code which is only needed for the romless variant */
49 void _main(void)
51 UINT32* pSrc;
52 UINT32* pDest;
53 UINT32* pEnd;
55 asm volatile ("ldc %0,sr" : : "r"(0xF0)); // disable interrupts
56 asm volatile ("mov.l @%0,r15" : : "r"(4)); // load stack
57 asm volatile ("ldc %0,vbr" : : "r"(0)); // load vector base
59 /* copy everything to IRAM and continue there */
60 pSrc = begin_iramcopy;
61 pDest = begin_text;
62 pEnd = pDest + (begin_stack - begin_text);
66 *pDest++ = *pSrc++;
68 while (pDest < pEnd);
70 main(); /* jump to the real main() */
74 void BootInit(void)
76 /* inits from the boot ROM, whether they make sense or not */
77 PBDR &= 0xFFBF; /* LED off (0x131E) */
78 PBCR2 = 0; /* all GPIO */
79 PBIOR |= 0x0040; /* LED output */
80 PBIOR &= 0xFFF1; /* LCD lines input */
82 /* init DRAM like the boot ROM does */
83 PACR2 &= 0xFFFB;
84 PACR2 |= 0x0008;
85 CASCR = 0xAF;
86 BCR |= 0x8000;
87 WCR1 &= 0xFDFD;
88 DCR = 0x0E00;
89 RCR = 0x5AB0;
90 RTCOR = 0x9605;
91 RTCSR = 0xA518;
93 #endif /* #ifdef NO_ROM */
96 int main(void)
98 int nButton;
100 PlatformInit(); /* model-specific inits */
102 nButton = ButtonPressed();
104 if (nButton == 3)
105 { /* F3 means start monitor */
106 MiniMon();
108 else
110 tImage* pImage;
111 pImage = GetStartImage(nButton); /* which image */
112 DecompressStart(pImage); /* move into place and start it */
115 return 0; /* I guess we won't return ;-) */
119 /* init code that is specific to certain platform */
120 void PlatformInit(void)
122 #ifdef NO_ROM
123 BootInit(); /* if not started by boot ROM, we need to init what it did */
124 #endif
126 #if defined PLATFORM_PLAYER
127 BRR1 = 0x19; /* 14400 Baud for monitor */
128 PBDRL |= 0x10; /* set PB4 to 1 to power the hd early (and prepare for
129 * probing in case the charger is connected) */
130 PBIORL |= 0x10; /* make PB4 an output */
131 PACR2 &= 0xFFFC; /* GPIO for PA0 (charger detection, input by default) */
132 if (!(PADRL & 0x01)) /* charger plugged? */
133 { /* we need to probe whether the box is able to control hd power */
134 int i;
136 PBIORL &= ~0x10; /* set PB4 to input */
137 /* wait whether it goes low, max. ~1 ms */
138 for (i = 0; (PBDRL & 0x10) && i < 1000; i++);
140 if (~(PBDRL & 0x10)) /* pulled low -> power controllable */
141 PBDRL &= 0x10; /* set PB4 low */
142 else /* still floating high -> not controllable */
143 PBDRL |= 0x10; /* set PB4 high */
144 PBIORL |= 0x10; /* ..and output again */
146 #elif defined PLATFORM_RECORDER
147 BRR1 = 0x02; /* 115200 Baud for monitor */
148 if (ReadADC(7) > 0x100) /* charger plugged? */
149 { /* switch off the HD, else a flat battery may not start */
150 PACR2 &= 0xFBFF; /* GPIO for PA5 */
151 PAIOR |= 0x0020; /* make PA5 an output (low by default) */
153 #elif defined PLATFORM_FM
154 BRR1 = 0x02; /* 115200 Baud for monitor */
155 PBDR |= 0x0020; /* set PB5 to keep power (fixes the ON-holding problem) */
156 PBIOR |= 0x0020; /* make PB5 an output */
157 if (ReadADC(0) < 0x1FF) /* charger plugged? */
158 { /* switch off the HD, else a flat battery may not start */
159 PACR2 &= 0xFBFF; /* GPIO for PA5 */
160 PAIOR |= 0x0020; /* make PA5 an output (low by default) */
162 #elif defined PLATFORM_ONDIO
163 BRR1 = 0x19; /* 14400 Baud for monitor */
164 PBDR |= 0x0020; /* set PB5 to keep power (fixes the ON-holding problem) */
165 PBIOR |= 0x0020; /* make PB5 an output */
166 #endif
168 /* platform-independent inits */
169 DCR |= 0x1000; /* enable burst mode on DRAM */
170 BCR |= 0x2000; /* activate Warp mode (simultaneous internal and external
171 * mem access) */
175 /* Thinned out version of the UCL 2e decompression sourcecode
176 * Original (C) Markus F.X.J Oberhumer under GNU GPL license */
177 #define GETBIT(bb, src, ilen) \
178 (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)
180 int ucl_nrv2e_decompress_8(
181 const UINT8 *src, UINT8 *dst, UINT32* dst_len)
183 UINT32 bb = 0;
184 unsigned ilen = 0, olen = 0, last_m_off = 1;
186 for (;;)
188 unsigned m_off, m_len;
190 while (GETBIT(bb,src,ilen))
192 dst[olen++] = src[ilen++];
194 m_off = 1;
195 for (;;)
197 m_off = m_off*2 + GETBIT(bb,src,ilen);
198 if (GETBIT(bb,src,ilen)) break;
199 m_off = (m_off-1)*2 + GETBIT(bb,src,ilen);
201 if (m_off == 2)
203 m_off = last_m_off;
204 m_len = GETBIT(bb,src,ilen);
206 else
208 m_off = (m_off-3)*256 + src[ilen++];
209 if (m_off == 0xffffffff)
210 break;
211 m_len = (m_off ^ 0xffffffff) & 1;
212 m_off >>= 1;
213 last_m_off = ++m_off;
215 if (m_len)
216 m_len = 1 + GETBIT(bb,src,ilen);
217 else if (GETBIT(bb,src,ilen))
218 m_len = 3 + GETBIT(bb,src,ilen);
219 else
221 m_len++;
222 do {
223 m_len = m_len*2 + GETBIT(bb,src,ilen);
224 } while (!GETBIT(bb,src,ilen));
225 m_len += 3;
227 m_len += (m_off > 0x500);
229 const UINT8 *m_pos;
230 m_pos = dst + olen - m_off;
231 dst[olen++] = *m_pos++;
232 do dst[olen++] = *m_pos++; while (--m_len > 0);
235 *dst_len = olen;
237 return ilen;
241 /* move the image into place and start it */
242 void DecompressStart(tImage* pImage)
244 UINT32* pSrc;
245 UINT32* pDest;
247 pSrc = pImage->image;
248 pDest = pImage->pDestination;
250 if (pSrc != pDest) /* if not linked to that flash address */
252 if (pImage->flags & IF_UCL_2E)
253 { /* UCL compressed, algorithm 2e */
254 UINT32 dst_len; /* dummy */
255 ucl_nrv2e_decompress_8((UINT8*)pSrc, (UINT8*)pDest, &dst_len);
257 else
258 { /* uncompressed, copy it */
259 UINT32 size = pImage->size;
260 UINT32* pEnd;
261 size = (size + 3) / 4; /* round up to 32bit-words */
262 pEnd = pDest + size;
266 *pDest++ = *pSrc++;
268 while (pDest < pEnd);
272 pImage->pExecute();
275 #ifdef USE_ADC
276 int ReadADC(int channel)
278 /* after channel 3, the ports wrap and get re-used */
279 volatile UINT16* pResult = (UINT16*)(ADDRAH_ADDR + 2 * (channel & 0x03));
280 int timeout = 266; /* conversion takes 266 clock cycles */
282 ADCSR = 0x20 | channel; /* start single conversion */
283 while (((ADCSR & 0x80) == 0) && (--timeout)); /* 6 instructions per round*/
285 return (timeout == 0) ? -1 : *pResult>>6;
287 #endif
290 /* This function is platform-dependent,
291 * until I figure out how to distinguish at runtime. */
292 int ButtonPressed(void) /* return 1,2,3 for F1,F2,F3, 0 if none pressed */
294 #ifdef USE_ADC
295 int value = ReadADC(CHANNEL);
297 if (value >= F1_LOWER && value <= F1_UPPER) /* in range */
298 return 1;
299 else if (value >= F2_LOWER && value <= F2_UPPER) /* in range */
300 return 2;
301 else if (value >= F3_LOWER && value <= F3_UPPER) /* in range */
302 return 3;
303 #else
304 int value = PCDR;
306 if (!(value & F1_MASK))
307 return 1;
308 else if (!(value & F2_MASK))
309 return 2;
310 else if (!(value & F3_MASK))
311 return 3;
312 #endif
314 return 0;
318 /* Determine the image to be started */
319 tImage* GetStartImage(int nPreferred)
321 tImage* pImage1;
322 tImage* pImage2 = NULL; /* default to not present */
323 UINT32 pos;
324 UINT32* pFlash = (UINT32*)FLASH_BASE;
326 /* determine the first image position */
327 pos = pFlash[2] + pFlash[3]; /* position + size of the bootloader
328 * = after it */
329 pos = (pos + 3) & ~3; /* be sure it's 32 bit aligned */
331 pImage1 = (tImage*)pos;
333 if (pImage1->size != 0)
334 { /* check for second image */
335 pos = (UINT32)(&pImage1->image) + pImage1->size;
336 pImage2 = (tImage*)pos;
338 /* does it make sense? (not in FF or 00 erazed space) */
339 if (pImage2->pDestination == (void*)0xFFFFFFFF
340 || pImage2->size == 0xFFFFFFFF
341 || pImage2->pExecute == (void*)0xFFFFFFFF
342 || pImage2->flags == 0xFFFFFFFF
343 || pImage2->pDestination == NULL)
344 /* size, execute and flags can legally be 0 */
346 pImage2 = NULL; /* invalidate */
350 if (pImage2 == NULL || nPreferred == 1)
351 { /* no second image or overridden: return the first */
352 return pImage1;
355 return pImage2; /* return second image */
358 /* diagnostic functions */
360 void SetLed(BOOL bOn)
362 if (bOn)
363 PBDR |= 0x0040;
364 else
365 PBDR &= ~0x0040;
369 void UartInit(void)
371 PBIOR &= 0xFBFF; /* input: RXD1 remote pin */
372 PBCR1 |= 0x00A0; /* set PB11+PB10 to UART */
373 PBCR1 &= 0xFFAF; /* clear bits 6, 4 -> UART */
374 SMR1 = 0x00; /* async format 8N1, baud generator input is CPU clock */
375 SCR1 = 0x30; /* transmit+receive enable */
376 PBCR1 &= 0x00FF; /* set bit 12...15 as GPIO */
377 SSR1 &= 0xBF; /* clear bit 6 (RDRF, receive data register full) */
381 UINT8 UartRead(void)
383 UINT8 byte;
384 while (!(SSR1 & SCI_RDRF)); /* wait for char to be available */
385 byte = RDR1;
386 SSR1 &= ~SCI_RDRF;
387 return byte;
391 void UartWrite(UINT8 byte)
393 while (!(SSR1 & SCI_TDRE)); /* wait for transmit buffer empty */
394 TDR1 = byte;
395 SSR1 &= ~SCI_TDRE;
399 /* include the mini monitor as a rescue feature, started with F3 */
400 void MiniMon(void)
402 UINT8 cmd;
403 UINT32 addr;
404 UINT32 size;
405 UINT32 content;
406 volatile UINT8* paddr = NULL;
407 volatile UINT8* pflash = NULL; /* flash base address */
409 UartInit();
411 while (1)
413 cmd = UartRead();
414 switch (cmd)
416 case BAUDRATE:
417 content = UartRead();
418 UartWrite(cmd); /* acknowledge by returning the command value */
419 while (!(SSR1 & SCI_TEND)); /* wait for empty shift register,
420 * before changing baudrate */
421 BRR1 = content;
422 break;
424 case ADDRESS:
425 addr = (UartRead() << 24) | (UartRead() << 16)
426 | (UartRead() << 8) | UartRead();
427 paddr = (UINT8*)addr;
428 pflash = (UINT8*)(addr & 0xFFF80000); /* round down to 512k align*/
429 UartWrite(cmd); /* acknowledge by returning the command value */
430 break;
432 case BYTE_READ:
433 content = *paddr++;
434 UartWrite(content); /* the content is the ack */
435 break;
437 case BYTE_WRITE:
438 content = UartRead();
439 *paddr++ = content;
440 UartWrite(cmd); /* acknowledge by returning the command value */
441 break;
443 case BYTE_READ16:
444 size = 16;
445 while (size--)
447 content = *paddr++;
448 UartWrite(content); /* the content is the ack */
450 break;
452 case BYTE_WRITE16:
453 size = 16;
454 while (size--)
456 content = UartRead();
457 *paddr++ = content;
459 UartWrite(cmd); /* acknowledge by returning the command value */
460 break;
462 case BYTE_FLASH:
463 content = UartRead();
464 pflash[0x5555] = 0xAA; /* set flash to command mode */
465 pflash[0x2AAA] = 0x55;
466 pflash[0x5555] = 0xA0; /* byte program command */
467 *paddr++ = content;
468 UartWrite(cmd); /* acknowledge by returning the command value */
469 break;
471 case BYTE_FLASH16:
472 size = 16;
473 while (size--)
475 content = UartRead();
476 pflash[0x5555] = 0xAA; /* set flash to command mode */
477 pflash[0x2AAA] = 0x55;
478 pflash[0x5555] = 0xA0; /* byte program command */
479 *paddr++ = content;
481 UartWrite(cmd); /* acknowledge by returning the command value */
482 break;
484 case HALFWORD_READ:
485 content = *(UINT16*)paddr;
486 paddr += 2;
487 UartWrite(content >> 8); /* highbyte */
488 UartWrite(content & 0xFF); /* lowbyte */
489 break;
491 case HALFWORD_WRITE:
492 content = UartRead() << 8 | UartRead();
493 *(UINT16*)paddr = content;
494 paddr += 2;
495 UartWrite(cmd); /* acknowledge by returning the command value */
496 break;
498 case EXECUTE:
500 tpFunc pFunc = (tpFunc)paddr;
501 pFunc();
502 UartWrite(cmd); /* acknowledge by returning the command value*/
504 break;
506 case VERSION:
507 UartWrite(1); /* return our version number */
508 break;
510 default:
512 SetLed(TRUE);
513 UartWrite(~cmd); /* error acknowledge */
516 } /* case */
517 } /* while (1) */