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