1/* 2 * Initialization and support routines for self-booting 3 * compressed image. 4 * 5 * Copyright (C) 2015, 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. 10 * 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. 18 * 19 * $Id: load.c 410377 2013-07-01 01:34:53Z $ 20 */ 21 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 34 35extern void cpu_inv_cache_all(void); 36 37void c_main(unsigned long ra); 38 39extern unsigned char text_start[], text_end[]; 40extern unsigned char data_start[], data_end[]; 41extern char bss_start[], bss_end[]; 42 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 */ 46 47static uchar *inbuf; /* input buffer */ 48#if !defined(USE_LZMA) 49static ulong insize; /* valid bytes in inbuf */ 50static ulong inptr; /* index of next byte to be processed in inbuf */ 51#endif /* USE_GZIP */ 52 53static uchar *outbuf; /* output buffer */ 54static ulong bytes_out; /* valid bytes in outbuf */ 55 56static uint32 *inbase; /* input data from flash */ 57 58#if !defined(USE_LZMA) 59static int 60fill_inbuf(void) 61{ 62 for (insize = 0; insize < INBUFSIZ; insize += sizeof(uint32), inbase++) 63 *((uint32 *)&inbuf[insize]) = *inbase; 64 inptr = 1; 65 66 return inbuf[0]; 67} 68 69/* Defines for gzip/bzip */ 70#define malloc(size) MALLOC(NULL, size) 71#define free(addr) MFREE(NULL, addr, 0) 72 73static void 74error(char *x) 75{ 76 printf("\n\n%s\n\n -- System halted", x); 77 78 for (;;); 79} 80#endif /* USE_LZMA */ 81 82#if defined(USE_GZIP) 83extern int _memsize; 84/* 85 * gzip declarations 86 */ 87 88#define OF(args) args 89#define STATIC static 90 91#define memzero(s, n) memset ((s), 0, (n)) 92 93typedef unsigned char uch; 94typedef unsigned short ush; 95typedef unsigned long ulg; 96 97#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) 98 99/* Diagnostic functions (stubbed out) */ 100 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) 107 108static uchar *window; /* Sliding window buffer */ 109static unsigned outcnt; /* bytes in window buffer */ 110 111static void 112gzip_mark(void **ptr) 113{ 114 /* I'm not sure what the pourpose of this is, there are no malloc 115 * calls without free's in the gunzip code. 116 */ 117} 118 119static void 120gzip_release(void **ptr) 121{ 122} 123 124static void flush_window(void); 125 126#include "gzip_inflate.c" 127 128/* =========================================================================== 129 * Write the output window window[0..outcnt-1] and update crc and bytes_out. 130 * (Used for the decompressed data only.) 131 */ 132static void 133flush_window(void) 134{ 135 ulg c = crc; 136 unsigned n; 137 uch *in, *out, ch; 138 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); 144 } 145 crc = c; 146 bytes_out += (ulg)outcnt; 147 outcnt = 0; 148 putc('.'); 149} 150 151#elif defined(USE_BZIP2) 152 153#include "bzip2_inflate.c" 154 155/* 156 * bzip2 declarations 157 */ 158 159void bz_internal_error(int i) 160{ 161 char msg[128]; 162 163 sprintf(msg, "Bzip2 internal error: %d", i); 164 error(msg); 165} 166 167static int 168bunzip2(void) 169{ 170 bz_stream bzstream; 171 int ret = 0; 172 173 bzstream.bzalloc = 0; 174 bzstream.bzfree = 0; 175 bzstream.opaque = 0; 176 bzstream.avail_in = 0; 177 178 if ((ret = BZ2_bzDecompressInit(&bzstream, 0, 1)) != BZ_OK) 179 return ret; 180 181 for (;;) { 182 if (bzstream.avail_in == 0) { 183 fill_inbuf(); 184 bzstream.next_in = inbuf; 185 bzstream.avail_in = insize; 186 } 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('.'); 193 } 194 195 if (ret == BZ_STREAM_END) 196 ret = BZ2_bzDecompressEnd(&bzstream); 197 198 if (ret == BZ_OK) 199 ret = 0; 200 201 return ret; 202} 203#elif defined(USE_LZMA) 204 205#include "LzmaDec.c" 206#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8) 207 208static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } 209static void SzFree(void *p, void *address) { p = p; free(address); } 210static ISzAlloc g_Alloc = { SzAlloc, SzFree }; 211 212extern int _memsize; 213/* 214 * call LZMA decoder to decompress a LZMA block 215 */ 216static int 217decompressLZMA(unsigned char *src, unsigned int srcLen, unsigned char *dest, unsigned int destLen) 218{ 219 int res; 220 SizeT inSizePure; 221 ELzmaStatus status; 222 SizeT outSize; 223 224 if (srcLen < LZMA_HEADER_SIZE) 225 return SZ_ERROR_INPUT_EOF; 226 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; 232 233 if ((res == SZ_OK) || 234 ((res == SZ_ERROR_INPUT_EOF) && (srcLen == inSizePure + LZMA_HEADER_SIZE))) 235 res = 0; 236 return res; 237} 238#else 239extern int _memsize; 240 241#endif /* defined(USE_GZIP) */ 242 243extern char input_data[], input_data_end[]; 244extern int input_len; 245 246static void 247load(si_t *sih) 248{ 249 int ret = 0; 250 uint32 image_len; 251#ifdef CONFIG_XIP 252 int inoff; 253 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; 264 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 */ 277 278 outbuf = (uchar *)LOADADDR; 279 bytes_out = 0; 280 inbuf = malloc(INBUFSIZ); /* input buffer */ 281 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; 301 } 302#endif /* defined(USE_GZIP) */ 303 if (ret) { 304 printf("error %d\n", ret); 305 } else 306 printf("done\n"); 307} 308 309static void 310set_sflash_div(si_t *sih) 311{ 312 uint idx = si_coreidx(sih); 313 osl_t *osh = si_osh(sih); 314 chipcregs_t *cc; 315 struct nvram_header *nvh = NULL; 316 uintptr flbase; 317 uint32 fltype, off, clkdiv, bpclock, sflmaxclk, sfldiv; 318 319 /* Check for sflash */ 320 cc = si_setcoreidx(sih, SI_CC_IDX); 321 ASSERT(cc); 322 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; 330 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; 339 }; 340 341 if (nvh == NULL) { 342 nvh = (struct nvram_header *)(flbase + 1024); 343 if (R_REG(osh, &nvh->magic) != NVRAM_MAGIC) { 344 goto out; 345 } 346 } 347 348 sflmaxclk = R_REG(osh, &nvh->crc_ver_init) >> 16; 349 if ((sflmaxclk == 0xffff) || (sflmaxclk == 0x0419)) 350 goto out; 351 352 sflmaxclk &= 0xf; 353 if (sflmaxclk == 0) 354 goto out; 355 356 bpclock = si_clock(sih); 357 sflmaxclk *= 10000000; 358 for (sfldiv = 2; sfldiv < 16; sfldiv += 2) { 359 if ((bpclock / sfldiv) < sflmaxclk) 360 break; 361 } 362 if (sfldiv > 14) 363 sfldiv = 14; 364 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); 369 } 370 371out: 372 si_setcoreidx(sih, idx); 373 return; 374} 375 376void 377c_main(unsigned long ra) 378{ 379 si_t *sih; 380 381 BCMDBG_TRACE(0x4c4400); 382 383#ifndef CFG_UNCACHED 384 /* Discover cache configuration and if not already on, 385 * initialize and turn them on. 386 */ 387#ifndef CFG_SHMOO 388 caches_on(); 389#endif 390#endif /* CFG_UNCACHED */ 391 392 BCMDBG_TRACE(0x4c4401); 393 394 /* Basic initialization */ 395 sih = (si_t *)osl_init(); 396 397 BCMDBG_TRACE(0x4c4402); 398 399 /* Only do this for 4716, we need to reuse the 400 * space in the nvram header for TREF on 5357. 401 */ 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); 406 407 BCMDBG_TRACE(0x4c4403); 408 409 /* Load binary */ 410 load(sih); 411 412 BCMDBG_TRACE(0x4c4404); 413 414 /* Flush all caches */ 415 blast_dcache(); 416 blast_icache(); 417 418 BCMDBG_TRACE(0x4c4405); 419 420 /* Jump to load address */ 421 ((void (*)(void))LOADADDR)(); 422} 423