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