RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / shared / load.c
blobfc082d98b78e27640dec749b64d58c32a3eca1cc
1 /*
2 * Initialization and support routines for self-booting
3 * compressed image.
5 * Copyright (C) 2012, 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 368663 2012-11-14 09:42:37Z $
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 extern void cpu_inv_cache_all(void);
37 void c_main(unsigned long ra);
39 extern unsigned char text_start[], text_end[];
40 extern unsigned char data_start[], data_end[];
41 extern char bss_start[], bss_end[];
43 #define INBUFSIZ 4096 /* Buffer size */
44 #define WSIZE 0x8000 /* window size--must be a power of two, and */
45 /* at least 32K for zip's deflate method */
47 static uchar *inbuf; /* input buffer */
48 #if !defined(USE_LZMA)
49 static ulong insize; /* valid bytes in inbuf */
50 static ulong inptr; /* index of next byte to be processed in inbuf */
51 #endif /* USE_GZIP */
53 static uchar *outbuf; /* output buffer */
54 static ulong bytes_out; /* valid bytes in outbuf */
56 static uint32 *inbase; /* input data from flash */
58 #if !defined(USE_LZMA)
59 static int
60 fill_inbuf(void)
62 for (insize = 0; insize < INBUFSIZ; insize += sizeof(uint32), inbase++)
63 *((uint32 *)&inbuf[insize]) = *inbase;
64 inptr = 1;
66 return inbuf[0];
69 /* Defines for gzip/bzip */
70 #define malloc(size) MALLOC(NULL, size)
71 #define free(addr) MFREE(NULL, addr, 0)
73 static void
74 error(char *x)
76 printf("\n\n%s\n\n -- System halted", x);
78 for (;;);
80 #endif /* USE_LZMA */
82 #if defined(USE_GZIP)
83 extern int _memsize;
85 * gzip declarations
88 #define OF(args) args
89 #define STATIC static
91 #define memzero(s, n) memset ((s), 0, (n))
93 typedef unsigned char uch;
94 typedef unsigned short ush;
95 typedef unsigned long ulg;
97 #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
99 /* Diagnostic functions (stubbed out) */
101 #define Assert(cond, msg)
102 #define Trace(x)
103 #define Tracev(x)
104 #define Tracevv(x)
105 #define Tracec(c, x)
106 #define Tracecv(c, x)
108 static uchar *window; /* Sliding window buffer */
109 static unsigned outcnt; /* bytes in window buffer */
111 static void
112 gzip_mark(void **ptr)
114 /* I'm not sure what the pourpose of this is, there are no malloc
115 * calls without free's in the gunzip code.
119 static void
120 gzip_release(void **ptr)
124 static void flush_window(void);
126 #include "gzip_inflate.c"
128 /* ===========================================================================
129 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
130 * (Used for the decompressed data only.)
132 static void
133 flush_window(void)
135 ulg c = crc;
136 unsigned n;
137 uch *in, *out, ch;
139 in = window;
140 out = &outbuf[bytes_out];
141 for (n = 0; n < outcnt; n++) {
142 ch = *out++ = *in++;
143 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
145 crc = c;
146 bytes_out += (ulg)outcnt;
147 outcnt = 0;
148 putc('.');
151 #elif defined(USE_BZIP2)
153 #include "bzip2_inflate.c"
156 * bzip2 declarations
159 void bz_internal_error(int i)
161 char msg[128];
163 sprintf(msg, "Bzip2 internal error: %d", i);
164 error(msg);
167 static int
168 bunzip2(void)
170 bz_stream bzstream;
171 int ret = 0;
173 bzstream.bzalloc = 0;
174 bzstream.bzfree = 0;
175 bzstream.opaque = 0;
176 bzstream.avail_in = 0;
178 if ((ret = BZ2_bzDecompressInit(&bzstream, 0, 1)) != BZ_OK)
179 return ret;
181 for (;;) {
182 if (bzstream.avail_in == 0) {
183 fill_inbuf();
184 bzstream.next_in = inbuf;
185 bzstream.avail_in = insize;
187 bzstream.next_out = &outbuf[bytes_out];
188 bzstream.avail_out = WSIZE;
189 if ((ret = BZ2_bzDecompress(&bzstream)) != BZ_OK)
190 break;
191 bytes_out = bzstream.total_out_lo32;
192 putc('.');
195 if (ret == BZ_STREAM_END)
196 ret = BZ2_bzDecompressEnd(&bzstream);
198 if (ret == BZ_OK)
199 ret = 0;
201 return ret;
203 #elif defined(USE_LZMA)
205 #include "LzmaDec.c"
206 #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
208 static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
209 static void SzFree(void *p, void *address) { p = p; free(address); }
210 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
212 extern int _memsize;
214 * call LZMA decoder to decompress a LZMA block
216 static int
217 decompressLZMA(unsigned char *src, unsigned int srcLen, unsigned char *dest, unsigned int destLen)
219 int res;
220 SizeT inSizePure;
221 ELzmaStatus status;
222 SizeT outSize;
224 if (srcLen < LZMA_HEADER_SIZE)
225 return SZ_ERROR_INPUT_EOF;
227 inSizePure = srcLen - LZMA_HEADER_SIZE;
228 outSize = destLen;
229 res = LzmaDecode(dest, &outSize, src + LZMA_HEADER_SIZE, &inSizePure,
230 src, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
231 srcLen = inSizePure + LZMA_HEADER_SIZE;
233 if ((res == SZ_OK) ||
234 ((res == SZ_ERROR_INPUT_EOF) && (srcLen == inSizePure + LZMA_HEADER_SIZE)))
235 res = 0;
236 return res;
238 #else
239 extern int _memsize;
241 #endif /* defined(USE_GZIP) */
243 extern char input_data[], input_data_end[];
244 extern int input_len;
246 static void
247 load(si_t *sih)
249 int ret = 0;
250 uint32 image_len;
251 #ifdef CONFIG_XIP
252 int inoff;
254 inoff = ((ulong)text_end - (ulong)text_start) + ((ulong)input_data - (ulong)data_start);
255 if (sih->ccrev == 12)
256 inbase = OSL_UNCACHED(SI_FLASH2 + inoff);
257 else
258 inbase = OSL_CACHED(SI_FLASH2 + inoff);
259 image_len = input_len;
260 #else
261 #if defined(CFG_SHMOO)
262 int inoff;
263 int bootdev;
265 inoff = (ulong)input_data - (ulong)text_start;
266 bootdev = soc_boot_dev((void *)sih);
267 if (bootdev == SOC_BOOTDEV_NANDFLASH)
268 inbase = (uint32 *)(SI_NS_NANDFLASH + inoff);
269 else
270 inbase = (uint32 *)(SI_NS_NORFLASH + inoff);
271 image_len = *(uint32 *)((ulong)inbase - 4);
272 #else
273 inbase = (uint32 *)input_data;
274 image_len = input_len;
275 #endif /* CFG_SHMOO */
276 #endif /* CONFIG_XIP */
278 outbuf = (uchar *)LOADADDR;
279 bytes_out = 0;
280 inbuf = malloc(INBUFSIZ); /* input buffer */
282 #if defined(USE_GZIP)
283 window = malloc(WSIZE);
284 printf("Decompressing...");
285 makecrc();
286 ret = gunzip();
287 #elif defined(USE_BZIP2)
288 /* Small decompression algorithm uses up to 2300k of memory */
289 printf("Decompressing...");
290 ret = bunzip2();
291 #elif defined(USE_LZMA)
292 printf("Decompressing...");
293 bytes_out = (ulong)_memsize - (ulong)PHYSADDR(outbuf);
294 ret = decompressLZMA((unsigned char *)inbase, image_len, outbuf, bytes_out);
295 #else
296 printf("Copying...");
297 while (bytes_out < image_len) {
298 fill_inbuf();
299 memcpy(&outbuf[bytes_out], inbuf, insize);
300 bytes_out += insize;
302 #endif /* defined(USE_GZIP) */
303 if (ret) {
304 printf("error %d\n", ret);
305 } else
306 printf("done\n");
309 static void
310 set_sflash_div(si_t *sih)
312 uint idx;
313 chipcregs_t *cc;
314 struct nvram_header *nvh = NULL;
315 uintptr flbase;
316 uint32 fltype, off, clkdiv, bpclock, sflmaxclk, sfldiv;
318 /* Check for sflash */
319 idx = si_coreidx(sih);
320 cc = si_setcoreidx(sih, SI_CC_IDX);
321 ASSERT(cc);
323 #ifdef NFLASH_SUPPORT
324 if ((sih->ccrev == 38) && ((sih->chipst & (1 << 4)) != 0))
325 goto out;
326 #endif /* NFLASH_SUPPORT */
327 fltype = sih->cccaps & CC_CAP_FLASH_MASK;
328 if ((fltype != SFLASH_ST) && (fltype != SFLASH_AT))
329 goto out;
331 flbase = (uintptr)OSL_UNCACHED((void *)SI_FLASH2);
332 off = FLASH_MIN;
333 while (off <= 16 * 1024 * 1024) {
334 nvh = (struct nvram_header *)(flbase + off - MAX_NVRAM_SPACE);
335 if (R_REG(osh, &nvh->magic) == NVRAM_MAGIC)
336 break;
337 off += DEF_NVRAM_SPACE;
338 nvh = NULL;
341 if (nvh == NULL) {
342 nvh = (struct nvram_header *)(flbase + 1024);
343 if (R_REG(osh, &nvh->magic) != NVRAM_MAGIC) {
344 goto out;
348 sflmaxclk = R_REG(osh, &nvh->crc_ver_init) >> 16;
349 if ((sflmaxclk == 0xffff) || (sflmaxclk == 0x0419))
350 goto out;
352 sflmaxclk &= 0xf;
353 if (sflmaxclk == 0)
354 goto out;
356 bpclock = si_clock(sih);
357 sflmaxclk *= 10000000;
358 for (sfldiv = 2; sfldiv < 16; sfldiv += 2) {
359 if ((bpclock / sfldiv) < sflmaxclk)
360 break;
362 if (sfldiv > 14)
363 sfldiv = 14;
365 clkdiv = R_REG(osh, &cc->clkdiv);
366 if (((clkdiv & CLKD_SFLASH) >> CLKD_SFLASH_SHIFT) != sfldiv) {
367 clkdiv = (clkdiv & ~CLKD_SFLASH) | (sfldiv << CLKD_SFLASH_SHIFT);
368 W_REG(osh, &cc->clkdiv, clkdiv);
371 out:
372 si_setcoreidx(sih, idx);
373 return;
376 void
377 c_main(unsigned long ra)
379 si_t *sih;
381 BCMDBG_TRACE(0x4c4400);
383 #ifndef CFG_UNCACHED
384 /* Discover cache configuration and if not already on,
385 * initialize and turn them on.
387 #ifndef CFG_SHMOO
388 caches_on();
389 #endif
390 #endif /* CFG_UNCACHED */
392 BCMDBG_TRACE(0x4c4401);
394 /* Basic initialization */
395 sih = (si_t *)osl_init();
397 BCMDBG_TRACE(0x4c4402);
399 /* Only do this for 4716, we need to reuse the
400 * space in the nvram header for TREF on 5357.
402 if ((CHIPID(sih->chip) == BCM4716_CHIP_ID) ||
403 (CHIPID(sih->chip) == BCM4748_CHIP_ID) ||
404 (CHIPID(sih->chip) == BCM47162_CHIP_ID))
405 set_sflash_div(sih);
407 BCMDBG_TRACE(0x4c4403);
409 /* Load binary */
410 load(sih);
412 BCMDBG_TRACE(0x4c4404);
414 /* Flush all caches */
415 blast_dcache();
416 blast_icache();
418 BCMDBG_TRACE(0x4c4405);
420 /* Jump to load address */
421 ((void (*)(void))LOADADDR)();