summaryrefslogtreecommitdiff
path: root/flash/bootloader/bootloader.c
diff options
context:
space:
mode:
Diffstat (limited to 'flash/bootloader/bootloader.c')
-rw-r--r--flash/bootloader/bootloader.c480
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
31UINT32 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
42tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main};
43#endif
44
45#ifdef NO_ROM // some code which is only needed for the romless variant
46void _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
71void 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
93int 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
117void 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
158int 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
220void 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
254int 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.
269int 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
285tImage* 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
324void SetLed(BOOL bOn)
325{
326 if (bOn)
327 PBDR |= 0x40;
328 else
329 PBDR &= ~0x40;
330}
331
332
333void 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
345UINT8 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
355void 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
364void 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}