RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / shared / load.c
blobf2d75ec3f4b4f0d8face01dad7e34d8c87a67640
1 /*
2 * Initialization and support routines for self-booting
3 * compressed image.
5 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * $Id: load.c,v 1.24.10.1 2010-10-13 04:00:32 Exp $
22 #include <typedefs.h>
23 #include <bcmdefs.h>
24 #include <osl.h>
25 #include <bcmutils.h>
26 #include <bcmdevs.h>
27 #include <hndsoc.h>
28 #include <siutils.h>
29 #include <sbchipc.h>
30 #include <bcmnvram.h>
31 #ifdef NFLASH_SUPPORT
32 #include <nflash.h>
33 #endif
35 void c_main(unsigned long ra);
37 extern unsigned char text_start[], text_end[];
38 extern unsigned char data_start[], data_end[];
39 extern char bss_start[], bss_end[];
41 #define INBUFSIZ 4096 /* Buffer size */
42 #define WSIZE 0x8000 /* window size--must be a power of two, and */
43 /* at least 32K for zip's deflate method */
45 static uchar *inbuf; /* input buffer */
46 #if !defined(USE_LZMA)
47 static ulong insize; /* valid bytes in inbuf */
48 static ulong inptr; /* index of next byte to be processed in inbuf */
49 #endif /* USE_GZIP */
51 static uchar *outbuf; /* output buffer */
52 static ulong bytes_out; /* valid bytes in outbuf */
54 static uint32 *inbase; /* input data from flash */
56 #if !defined(USE_LZMA)
57 static int
58 fill_inbuf(void)
60 for (insize = 0; insize < INBUFSIZ; insize += sizeof(uint32), inbase++)
61 *((uint32 *)&inbuf[insize]) = *inbase;
62 inptr = 1;
64 return inbuf[0];
67 /* Defines for gzip/bzip */
68 #define malloc(size) MALLOC(NULL, size)
69 #define free(addr) MFREE(NULL, addr, 0)
71 static void
72 error(char *x)
74 printf("\n\n%s\n\n -- System halted", x);
76 for (;;);
78 #endif /* USE_LZMA */
80 #if defined(USE_GZIP)
83 * gzip declarations
86 #define OF(args) args
87 #define STATIC static
89 #define memzero(s, n) memset ((s), 0, (n))
91 typedef unsigned char uch;
92 typedef unsigned short ush;
93 typedef unsigned long ulg;
95 #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
97 /* Diagnostic functions (stubbed out) */
99 #define Assert(cond, msg)
100 #define Trace(x)
101 #define Tracev(x)
102 #define Tracevv(x)
103 #define Tracec(c, x)
104 #define Tracecv(c, x)
106 static uchar *window; /* Sliding window buffer */
107 static unsigned outcnt; /* bytes in window buffer */
109 static void
110 gzip_mark(void **ptr)
112 /* I'm not sure what the pourpose of this is, there are no malloc
113 * calls without free's in the gunzip code.
117 static void
118 gzip_release(void **ptr)
122 static void flush_window(void);
124 #include "gzip_inflate.c"
126 /* ===========================================================================
127 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
128 * (Used for the decompressed data only.)
130 static void
131 flush_window(void)
133 ulg c = crc;
134 unsigned n;
135 uch *in, *out, ch;
137 in = window;
138 out = &outbuf[bytes_out];
139 for (n = 0; n < outcnt; n++) {
140 ch = *out++ = *in++;
141 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
143 crc = c;
144 bytes_out += (ulg)outcnt;
145 outcnt = 0;
146 putc('.');
149 #elif defined(USE_BZIP2)
151 #include "bzip2_inflate.c"
154 * bzip2 declarations
157 void bz_internal_error(int i)
159 char msg[128];
161 sprintf(msg, "Bzip2 internal error: %d", i);
162 error(msg);
165 static int
166 bunzip2(void)
168 bz_stream bzstream;
169 int ret = 0;
171 bzstream.bzalloc = 0;
172 bzstream.bzfree = 0;
173 bzstream.opaque = 0;
174 bzstream.avail_in = 0;
176 if ((ret = BZ2_bzDecompressInit(&bzstream, 0, 1)) != BZ_OK)
177 return ret;
179 for (;;) {
180 if (bzstream.avail_in == 0) {
181 fill_inbuf();
182 bzstream.next_in = inbuf;
183 bzstream.avail_in = insize;
185 bzstream.next_out = &outbuf[bytes_out];
186 bzstream.avail_out = WSIZE;
187 if ((ret = BZ2_bzDecompress(&bzstream)) != BZ_OK)
188 break;
189 bytes_out = bzstream.total_out_lo32;
190 putc('.');
193 if (ret == BZ_STREAM_END)
194 ret = BZ2_bzDecompressEnd(&bzstream);
196 if (ret == BZ_OK)
197 ret = 0;
199 return ret;
201 #elif defined(USE_LZMA)
203 #include "LzmaDec.c"
204 #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
206 static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
207 static void SzFree(void *p, void *address) { p = p; free(address); }
208 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
210 extern int _memsize;
212 * call LZMA decoder to decompress a LZMA block
214 static int
215 decompressLZMA(unsigned char *src, unsigned int srcLen, unsigned char *dest, unsigned int destLen)
217 int res;
218 SizeT inSizePure;
219 ELzmaStatus status;
220 SizeT outSize;
222 if (srcLen < LZMA_HEADER_SIZE)
223 return SZ_ERROR_INPUT_EOF;
225 inSizePure = srcLen - LZMA_HEADER_SIZE;
226 outSize = destLen;
227 res = LzmaDecode(dest, &outSize, src + LZMA_HEADER_SIZE, &inSizePure,
228 src, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
229 srcLen = inSizePure + LZMA_HEADER_SIZE;
231 if ((res == SZ_OK) ||
232 ((res == SZ_ERROR_INPUT_EOF) && (srcLen == inSizePure + LZMA_HEADER_SIZE)))
233 res = 0;
234 return res;
237 #endif /* defined(USE_GZIP) */
239 extern char input_data[];
240 extern int input_len;
242 static void
243 load(si_t *sih)
245 int inoff, ret = 0;
246 #ifdef NFLASH_SUPPORT
247 chipcregs_t *cc;
248 struct nflash *nfl_info;
249 uchar *copy_buf, *nand_ptr;
250 int copy_len, offset, len;
251 #endif
253 /* Offset from beginning of flash */
254 #ifdef CONFIG_XIP
255 inoff = ((ulong)text_end - (ulong)text_start) + ((ulong)input_data - (ulong)data_start);
256 #else
257 inoff = (ulong)input_data - (ulong)text_start;
258 #endif /* CONFIG_XIP */
259 #ifdef NFLASH_SUPPORT
260 if ((sih->ccrev == 38) && ((sih->chipst & (1 << 4)) != 0)) {
261 cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
262 nfl_info = nflash_init(sih, cc);
263 if (nfl_info) {
264 nand_ptr = OSL_CACHED(SI_FLASH1);
265 /* 512KB of buffer ahead of LOADADDR */
266 copy_buf = (unsigned char *)(LOADADDR - 0x80000);
267 inbase = (uint32 *)(copy_buf + inoff);
268 copy_len = inoff + input_len;
269 offset = 0;
270 while (copy_len > 0) {
271 if (nflash_checkbadb(sih, cc, offset) != 0) {
272 offset += nfl_info->blocksize;
273 continue;
275 len = (copy_len < nfl_info->blocksize)?
276 copy_len: nfl_info->blocksize;
277 memcpy(copy_buf, nand_ptr + offset, len);
278 copy_len -= len;
279 offset += len;
280 copy_buf += len;
283 } else
284 #endif /* NFLASH_SUPPORT */
285 if (sih->ccrev == 12)
286 inbase = OSL_UNCACHED(SI_FLASH2 + inoff);
287 else
288 inbase = OSL_CACHED(SI_FLASH2 + inoff);
290 outbuf = (uchar *)LOADADDR;
291 bytes_out = 0;
292 inbuf = malloc(INBUFSIZ); /* input buffer */
294 #if defined(USE_GZIP)
295 window = malloc(WSIZE);
296 printf("Decompressing...");
297 makecrc();
298 ret = gunzip();
299 #elif defined(USE_BZIP2)
300 /* Small decompression algorithm uses up to 2300k of memory */
301 printf("Decompressing...");
302 ret = bunzip2();
303 #elif defined(USE_LZMA)
304 printf("Decompressing...");
305 bytes_out = (ulong)_memsize - (ulong)PHYSADDR(outbuf);
306 ret = decompressLZMA((unsigned char *)inbase, input_len, outbuf, bytes_out);
307 #else
308 printf("Copying...");
309 while (bytes_out < input_len) {
310 fill_inbuf();
311 memcpy(&outbuf[bytes_out], inbuf, insize);
312 bytes_out += insize;
314 #endif /* defined(USE_GZIP) */
315 if (ret) {
316 printf("error %d\n", ret);
317 } else
318 printf("done\n");
321 static void
322 set_sflash_div(si_t *sih)
324 uint idx;
325 chipcregs_t *cc;
326 struct nvram_header *nvh = NULL;
327 uintptr flbase;
328 uint32 fltype, off, clkdiv, bpclock, sflmaxclk, sfldiv;
330 /* Check for sflash */
331 idx = si_coreidx(sih);
332 cc = si_setcoreidx(sih, SI_CC_IDX);
333 ASSERT(cc);
335 #ifdef NFLASH_SUPPORT
336 if ((sih->ccrev == 38) && ((sih->chipst & (1 << 4)) != 0))
337 goto out;
338 #endif /* NFLASH_SUPPORT */
339 fltype = sih->cccaps & CC_CAP_FLASH_MASK;
340 if ((fltype != SFLASH_ST) && (fltype != SFLASH_AT))
341 goto out;
343 flbase = (uintptr)OSL_UNCACHED((void *)SI_FLASH2);
344 off = FLASH_MIN;
345 while (off <= 16 * 1024 * 1024) {
346 nvh = (struct nvram_header *)(flbase + off - NVRAM_SPACE);
347 if (R_REG(osh, &nvh->magic) == NVRAM_MAGIC)
348 break;
349 off <<= 1;
350 nvh = NULL;
353 if (nvh == NULL) {
354 nvh = (struct nvram_header *)(flbase + 1024);
355 if (R_REG(osh, &nvh->magic) != NVRAM_MAGIC) {
356 goto out;
360 sflmaxclk = R_REG(osh, &nvh->crc_ver_init) >> 16;
361 if ((sflmaxclk == 0xffff) || (sflmaxclk == 0x0419))
362 goto out;
364 sflmaxclk &= 0xf;
365 if (sflmaxclk == 0)
366 goto out;
368 bpclock = si_clock(sih);
369 sflmaxclk *= 10000000;
370 for (sfldiv = 2; sfldiv < 16; sfldiv += 2) {
371 if ((bpclock / sfldiv) < sflmaxclk)
372 break;
374 if (sfldiv > 14)
375 sfldiv = 14;
377 clkdiv = R_REG(osh, &cc->clkdiv);
378 if (((clkdiv & CLKD_SFLASH) >> CLKD_SFLASH_SHIFT) != sfldiv) {
379 clkdiv = (clkdiv & ~CLKD_SFLASH) | (sfldiv << CLKD_SFLASH_SHIFT);
380 W_REG(osh, &cc->clkdiv, clkdiv);
383 out:
384 si_setcoreidx(sih, idx);
385 return;
388 void
389 c_main(unsigned long ra)
391 si_t *sih;
393 BCMDBG_TRACE(0x4c4400);
395 #ifndef CFG_UNCACHED
396 /* Discover cache configuration and if not already on,
397 * initialize and turn them on.
399 caches_on();
400 #endif /* CFG_UNCACHED */
402 BCMDBG_TRACE(0x4c4401);
404 /* Basic initialization */
405 sih = (si_t *)osl_init();
407 BCMDBG_TRACE(0x4c4402);
409 /* Only do this for newer chips, since the SB ones did not have
410 * space in the nvram header for the sflash divider.
412 if (sih->socitype == SOCI_AI)
413 set_sflash_div(sih);
415 BCMDBG_TRACE(0x4c4403);
417 /* Load binary */
418 load(sih);
420 BCMDBG_TRACE(0x4c4404);
422 /* Flush all caches */
423 blast_dcache();
424 blast_icache();
426 BCMDBG_TRACE(0x4c4405);
428 /* Jump to load address */
429 ((void (*)(void))LOADADDR)();