xref: /rk3399_rockchip-uboot/common/spl/spl_decomp.c (revision fcc1058f27dbfc202f6503785bfae78f1009a75b)
153138e05SJoseph Chen /*
253138e05SJoseph Chen  * Copyright (c) 2022 Rockchip Electronics Co., Ltd
353138e05SJoseph Chen  *
453138e05SJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
553138e05SJoseph Chen  */
653138e05SJoseph Chen 
753138e05SJoseph Chen #include <common.h>
853138e05SJoseph Chen #include <dm.h>
953138e05SJoseph Chen #include <malloc.h>
10*fcc1058fSJoseph Chen #include <version.h>
1153138e05SJoseph Chen #include <asm/sections.h>
1253138e05SJoseph Chen #include <asm/io.h>
1353138e05SJoseph Chen #include <asm/u-boot.h>
1453138e05SJoseph Chen #include <lzma/LzmaTools.h>
1553138e05SJoseph Chen #include <asm/arch/rk_atags.h>
1653138e05SJoseph Chen 
17*fcc1058fSJoseph Chen /********************** SPL framework weak ***********************/
1853138e05SJoseph Chen void board_init_f(ulong dummy)
1953138e05SJoseph Chen {
2053138e05SJoseph Chen }
2153138e05SJoseph Chen 
2253138e05SJoseph Chen ulong spl_relocate_stack_gd(void)
2353138e05SJoseph Chen {
2453138e05SJoseph Chen 	return 0;
2553138e05SJoseph Chen }
2653138e05SJoseph Chen 
2753138e05SJoseph Chen int board_fit_config_name_match(const char *name)
2853138e05SJoseph Chen {
2953138e05SJoseph Chen 	return 0;
3053138e05SJoseph Chen }
3153138e05SJoseph Chen 
32*fcc1058fSJoseph Chen /********************** Decomp Header code ***********************/
33*fcc1058fSJoseph Chen #define UART_FIFO_EMPTY                (BIT(6) | BIT(5))
34*fcc1058fSJoseph Chen #define UART_LSR                       0x14
35*fcc1058fSJoseph Chen 
36*fcc1058fSJoseph Chen enum {
37*fcc1058fSJoseph Chen 	E_OK,
38*fcc1058fSJoseph Chen 	E_BD,
39*fcc1058fSJoseph Chen 	E_TLB,
40*fcc1058fSJoseph Chen 	E_MAGIC,
41*fcc1058fSJoseph Chen 	E_HCRC,
42*fcc1058fSJoseph Chen 	E_DCRC,
43*fcc1058fSJoseph Chen 	E_ALGO,
44*fcc1058fSJoseph Chen 	E_UNDEF,
45*fcc1058fSJoseph Chen };
46*fcc1058fSJoseph Chen 
47*fcc1058fSJoseph Chen static const char *err_msg[] = {
48*fcc1058fSJoseph Chen 	"OK", "BD", "TLB", "MAGIC", "HCRC", "DCRC", "ALGO", "UNDEF"
49*fcc1058fSJoseph Chen };
50*fcc1058fSJoseph Chen 
51*fcc1058fSJoseph Chen static ulong g_uart_base = CONFIG_DEBUG_UART_BASE;
52*fcc1058fSJoseph Chen 
5353138e05SJoseph Chen static void put_char(char ch)
5453138e05SJoseph Chen {
5553138e05SJoseph Chen 	ulong base = g_uart_base;
5653138e05SJoseph Chen 
5753138e05SJoseph Chen 	if (!g_uart_base)
5853138e05SJoseph Chen 		return;
5953138e05SJoseph Chen 
6053138e05SJoseph Chen 	writel(ch, base);
6153138e05SJoseph Chen 	if (ch == '\n')
6253138e05SJoseph Chen 		writel('\r', base);
6353138e05SJoseph Chen 
6453138e05SJoseph Chen 	while (!(__arch_getl(base + UART_LSR) & UART_FIFO_EMPTY))
6553138e05SJoseph Chen 		;
6653138e05SJoseph Chen }
6753138e05SJoseph Chen 
6853138e05SJoseph Chen static void put_string(const char *str)
6953138e05SJoseph Chen {
7053138e05SJoseph Chen 	while (*str) {
7153138e05SJoseph Chen 		put_char(*str);
7253138e05SJoseph Chen 		str++;
7353138e05SJoseph Chen 	}
7453138e05SJoseph Chen }
7553138e05SJoseph Chen 
7653138e05SJoseph Chen static void put_dec_0_19(int dec)
7753138e05SJoseph Chen {
7853138e05SJoseph Chen 	if (dec >= 10) {
7953138e05SJoseph Chen 		put_char('1');
8053138e05SJoseph Chen 		dec -= 10;
8153138e05SJoseph Chen 	}
8253138e05SJoseph Chen 
8353138e05SJoseph Chen 	put_char(dec + '0');
8453138e05SJoseph Chen }
8553138e05SJoseph Chen 
86*fcc1058fSJoseph Chen static void put_hex(u32 hex)
8753138e05SJoseph Chen {
88*fcc1058fSJoseph Chen 	uint8_t c, i = 8;
89*fcc1058fSJoseph Chen 
90*fcc1058fSJoseph Chen 	put_string("0x");
91*fcc1058fSJoseph Chen 	while (i--) {
92*fcc1058fSJoseph Chen 		c = (hex & 0xf0000000) >> 28;
93*fcc1058fSJoseph Chen 		put_char(c < 0xa ? c + '0' : c - 0xa + 'a');
94*fcc1058fSJoseph Chen 		hex <<= 4;
95*fcc1058fSJoseph Chen 	}
96*fcc1058fSJoseph Chen }
97*fcc1058fSJoseph Chen 
98*fcc1058fSJoseph Chen static void jump_entry(void *addr)
99*fcc1058fSJoseph Chen {
100*fcc1058fSJoseph Chen 	void (*os_entry)(void) = (void *)addr;
10153138e05SJoseph Chen 
10253138e05SJoseph Chen 	flush_dcache_all();
10353138e05SJoseph Chen 
10453138e05SJoseph Chen 	/*
10553138e05SJoseph Chen 	 * Turn off I-cache and invalidate it
10653138e05SJoseph Chen 	 */
10753138e05SJoseph Chen 	icache_disable();
10853138e05SJoseph Chen 	invalidate_icache_all();
10953138e05SJoseph Chen 
11053138e05SJoseph Chen 	/*
11153138e05SJoseph Chen 	 * Turn off D-cache
11253138e05SJoseph Chen 	 * dcache_disable() in turn flushes the d-cache and disables MMU
11353138e05SJoseph Chen 	 */
11453138e05SJoseph Chen 	dcache_disable();
11553138e05SJoseph Chen 	invalidate_dcache_all();
11653138e05SJoseph Chen 
11753138e05SJoseph Chen 	dsb();
11853138e05SJoseph Chen 	isb();
11953138e05SJoseph Chen 
120*fcc1058fSJoseph Chen 	(*os_entry)();
12153138e05SJoseph Chen }
12253138e05SJoseph Chen 
123*fcc1058fSJoseph Chen static struct tag *uart_init(void)
12453138e05SJoseph Chen {
12553138e05SJoseph Chen #if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) && \
12653138e05SJoseph Chen     defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
12753138e05SJoseph Chen 	struct tag *t;
12853138e05SJoseph Chen 
12953138e05SJoseph Chen 	t = atags_get_tag(ATAG_SERIAL);
13053138e05SJoseph Chen 	if (t) {
13153138e05SJoseph Chen 		if (t->u.serial.enable)
13253138e05SJoseph Chen 			g_uart_base = t->u.serial.addr;
13353138e05SJoseph Chen 		else
13453138e05SJoseph Chen 			g_uart_base = 0;
13553138e05SJoseph Chen 	}
13653138e05SJoseph Chen #endif
137*fcc1058fSJoseph Chen 	return t;
13853138e05SJoseph Chen }
13953138e05SJoseph Chen 
14053138e05SJoseph Chen static void print_ret(int err, int err_algo)
14153138e05SJoseph Chen {
14253138e05SJoseph Chen 	if (err)
14353138e05SJoseph Chen 		put_string("ERR ");
144*fcc1058fSJoseph Chen 
14553138e05SJoseph Chen 	put_string(err_msg[err]);
14653138e05SJoseph Chen 
14753138e05SJoseph Chen 	if (err_algo) {
14853138e05SJoseph Chen 		put_char(' ');
14953138e05SJoseph Chen 		put_dec_0_19(err_algo);
15053138e05SJoseph Chen 	}
15153138e05SJoseph Chen 	put_char('\n');
15253138e05SJoseph Chen }
15353138e05SJoseph Chen 
154*fcc1058fSJoseph Chen #ifdef CONFIG_SPL_LZMA
155*fcc1058fSJoseph Chen static int un_lzma(const image_header_t *hdr, int *err_algo)
15653138e05SJoseph Chen {
15753138e05SJoseph Chen 	const void *data;
15853138e05SJoseph Chen 	ulong load_addr;
15953138e05SJoseph Chen 	SizeT lzma_len;
16053138e05SJoseph Chen 	SizeT src_lenp;
161*fcc1058fSJoseph Chen 	int err;
162*fcc1058fSJoseph Chen 
163*fcc1058fSJoseph Chen 	load_addr = uimage_to_cpu(hdr->ih_load);
164*fcc1058fSJoseph Chen 	src_lenp = *(u32 *)(uimage_to_cpu(hdr->ih_size));
165*fcc1058fSJoseph Chen 	data = (void *)hdr + sizeof(*hdr);
166*fcc1058fSJoseph Chen 	lzma_len = SZ_2M; /* default max size */
167*fcc1058fSJoseph Chen 	err = lzmaBuffToBuffDecompress((uchar *)(load_addr), &lzma_len,
168*fcc1058fSJoseph Chen 				       (uchar *)(data), src_lenp);
169*fcc1058fSJoseph Chen 	if (err) {
170*fcc1058fSJoseph Chen 		*err_algo = err;
171*fcc1058fSJoseph Chen 		err = E_ALGO;
172*fcc1058fSJoseph Chen 	}
173*fcc1058fSJoseph Chen 
174*fcc1058fSJoseph Chen 	return err;
175*fcc1058fSJoseph Chen }
176*fcc1058fSJoseph Chen #endif
177*fcc1058fSJoseph Chen 
178*fcc1058fSJoseph Chen static int decompress_image(const image_header_t *hdr, int *err_algo)
179*fcc1058fSJoseph Chen {
180*fcc1058fSJoseph Chen #ifdef CONFIG_SPL_LZMA
181*fcc1058fSJoseph Chen 	return un_lzma(hdr, err_algo);
182*fcc1058fSJoseph Chen #endif
183*fcc1058fSJoseph Chen 	return E_UNDEF;
184*fcc1058fSJoseph Chen }
185*fcc1058fSJoseph Chen 
186*fcc1058fSJoseph Chen void board_init_r(gd_t *dummy1, ulong dummy2)
187*fcc1058fSJoseph Chen {
188*fcc1058fSJoseph Chen 	const image_header_t *hdr;
189*fcc1058fSJoseph Chen 	struct tag *t;
190*fcc1058fSJoseph Chen 	ulong addr;
19153138e05SJoseph Chen 	int err_algo = 0;
19253138e05SJoseph Chen 	int err = 0;
19353138e05SJoseph Chen 
194*fcc1058fSJoseph Chen 	t = uart_init();
19553138e05SJoseph Chen 
196*fcc1058fSJoseph Chen 	put_string("\nDECOMP " PLAIN_VERSION " (" U_BOOT_DATE " - " \
197*fcc1058fSJoseph Chen 			U_BOOT_TIME ")\n\n");
198*fcc1058fSJoseph Chen 	if (t) {
199*fcc1058fSJoseph Chen 		put_string("PreSerial: ");
200*fcc1058fSJoseph Chen 		put_char('0' + t->u.serial.id);
201*fcc1058fSJoseph Chen 		put_char('\n');
202*fcc1058fSJoseph Chen 	}
203*fcc1058fSJoseph Chen 	put_string("Start... ");
20453138e05SJoseph Chen 
20553138e05SJoseph Chen 	/* init malloc */
20653138e05SJoseph Chen 	gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN);
20753138e05SJoseph Chen 	gd->malloc_ptr = 0;
20853138e05SJoseph Chen 
20953138e05SJoseph Chen 	/* set up bank */
21053138e05SJoseph Chen #ifndef CONFIG_ARM64
21153138e05SJoseph Chen 	if (!gd->bd) {
21253138e05SJoseph Chen 		gd->bd = calloc(1, sizeof(bd_t));
21353138e05SJoseph Chen 		if (!gd->bd) {
214*fcc1058fSJoseph Chen 			err = E_BD;
21553138e05SJoseph Chen 			goto out;
21653138e05SJoseph Chen 		}
21753138e05SJoseph Chen 		gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
218*fcc1058fSJoseph Chen 		gd->bd->bi_dram[0].size  = SZ_64M; /* default */
21953138e05SJoseph Chen 	}
22053138e05SJoseph Chen #endif
22153138e05SJoseph Chen 	/* TLB memory should be SZ_16K base align and 4KB end align */
22253138e05SJoseph Chen 	gd->arch.tlb_size = PGTABLE_SIZE;
22353138e05SJoseph Chen 	gd->arch.tlb_addr = (ulong)memalign(SZ_16K, ALIGN(PGTABLE_SIZE, SZ_4K));
22453138e05SJoseph Chen 	if (!gd->arch.tlb_addr) {
225*fcc1058fSJoseph Chen 		err = E_TLB;
22653138e05SJoseph Chen 		goto out;
22753138e05SJoseph Chen 	}
22853138e05SJoseph Chen 
22953138e05SJoseph Chen 	/* Enable dcache */
23053138e05SJoseph Chen 	dcache_enable();
23153138e05SJoseph Chen 
23253138e05SJoseph Chen 	/* Check */
23353138e05SJoseph Chen 	hdr = (void *)(&__bss_end);
23453138e05SJoseph Chen 	if (!image_check_magic(hdr)) {
235*fcc1058fSJoseph Chen 		err = E_MAGIC;
23653138e05SJoseph Chen 		goto out;
23753138e05SJoseph Chen 	}
23853138e05SJoseph Chen 
23953138e05SJoseph Chen 	if (!image_check_hcrc(hdr)) {
240*fcc1058fSJoseph Chen 		err = E_HCRC;
24153138e05SJoseph Chen 		goto out;
24253138e05SJoseph Chen 	}
24353138e05SJoseph Chen 
24453138e05SJoseph Chen 	if (!image_check_dcrc(hdr)) {
245*fcc1058fSJoseph Chen 		err = E_DCRC;
24653138e05SJoseph Chen 		goto out;
24753138e05SJoseph Chen 	}
24853138e05SJoseph Chen 
24953138e05SJoseph Chen 	/* Decompress... */
250*fcc1058fSJoseph Chen 	err = decompress_image(hdr, &err_algo);
25153138e05SJoseph Chen out:
25253138e05SJoseph Chen 	print_ret(err, err_algo);
253*fcc1058fSJoseph Chen 	if (!err) {
254*fcc1058fSJoseph Chen 		addr = uimage_to_cpu(hdr->ih_load);
255*fcc1058fSJoseph Chen 		put_string("Jumping to ");
256*fcc1058fSJoseph Chen 		put_hex((u32)addr);
257*fcc1058fSJoseph Chen 		put_char('\n');
258*fcc1058fSJoseph Chen 
259*fcc1058fSJoseph Chen 		/* jump! */
260*fcc1058fSJoseph Chen 		jump_entry((void *)addr);
261*fcc1058fSJoseph Chen 	}
26253138e05SJoseph Chen 
26353138e05SJoseph Chen 	/* hang */
264*fcc1058fSJoseph Chen 	put_string("\nPanic hang!");
26553138e05SJoseph Chen 	while (1)
26653138e05SJoseph Chen 		;
26753138e05SJoseph Chen }
268*fcc1058fSJoseph Chen 
269