138771996SKever Yang /* 238771996SKever Yang * (C) Copyright 2017 Rockchip Electronics Co., Ltd. 338771996SKever Yang * 438771996SKever Yang * SPDX-License-Identifier: GPL-2.0+ 538771996SKever Yang */ 638771996SKever Yang #include <common.h> 738771996SKever Yang #include <clk.h> 838771996SKever Yang #include <dm.h> 9575777c5SKever Yang #include <debug_uart.h> 1038771996SKever Yang #include <ram.h> 1138771996SKever Yang #include <syscon.h> 1238771996SKever Yang #include <asm/io.h> 13064b2675SJason Zhu #include <asm/arch/vendor.h> 14064b2675SJason Zhu #include <misc.h> 1538771996SKever Yang #include <asm/gpio.h> 1638771996SKever Yang #include <asm/arch/clock.h> 1738771996SKever Yang #include <asm/arch/periph.h> 1838771996SKever Yang #include <asm/arch/boot_mode.h> 19064eb493SJoseph Chen #include <asm/arch/rk_atags.h> 2038771996SKever Yang #ifdef CONFIG_DM_CHARGE_DISPLAY 2138771996SKever Yang #include <power/charge_display.h> 2238771996SKever Yang #endif 2338771996SKever Yang #ifdef CONFIG_DM_REGULATOR 2438771996SKever Yang #include <power/regulator.h> 2538771996SKever Yang #endif 2638771996SKever Yang #ifdef CONFIG_DRM_ROCKCHIP 2738771996SKever Yang #include <video_rockchip.h> 2838771996SKever Yang #endif 29c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER 30c563adc7SJoseph Chen #include <rockchip_debugger.h> 31c563adc7SJoseph Chen #endif 32f8aaa2c2SKever Yang #include <of_live.h> 33f8aaa2c2SKever Yang #include <dm/root.h> 3438771996SKever Yang 3538771996SKever Yang DECLARE_GLOBAL_DATA_PTR; 36064b2675SJason Zhu /* define serialno max length, the max length is 512 Bytes 37064b2675SJason Zhu * The remaining bytes are used to ensure that the first 512 bytes 38064b2675SJason Zhu * are valid when executing 'env_set("serial#", value)'. 39064b2675SJason Zhu */ 40064b2675SJason Zhu #define VENDOR_SN_MAX 513 41064b2675SJason Zhu #define CPUID_LEN 0x10 42064b2675SJason Zhu #define CPUID_OFF 0x7 43064b2675SJason Zhu 44064b2675SJason Zhu static int rockchip_set_serialno(void) 45064b2675SJason Zhu { 46064b2675SJason Zhu char serialno_str[VENDOR_SN_MAX]; 47064b2675SJason Zhu int ret = 0, i; 48064b2675SJason Zhu u8 cpuid[CPUID_LEN] = {0}; 49064b2675SJason Zhu u8 low[CPUID_LEN / 2], high[CPUID_LEN / 2]; 50064b2675SJason Zhu u64 serialno; 51064b2675SJason Zhu 52064b2675SJason Zhu /* Read serial number from vendor storage part */ 53064b2675SJason Zhu memset(serialno_str, 0, VENDOR_SN_MAX); 54064b2675SJason Zhu #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 55064b2675SJason Zhu ret = vendor_storage_read(VENDOR_SN_ID, serialno_str, (VENDOR_SN_MAX-1)); 56064b2675SJason Zhu if (ret > 0) { 57064b2675SJason Zhu env_set("serial#", serialno_str); 58064b2675SJason Zhu } else { 59064b2675SJason Zhu #endif 60064b2675SJason Zhu #ifdef CONFIG_ROCKCHIP_EFUSE 61064b2675SJason Zhu struct udevice *dev; 62064b2675SJason Zhu 63064b2675SJason Zhu /* retrieve the device */ 64064b2675SJason Zhu ret = uclass_get_device_by_driver(UCLASS_MISC, 65064b2675SJason Zhu DM_GET_DRIVER(rockchip_efuse), &dev); 66064b2675SJason Zhu if (ret) { 67064b2675SJason Zhu printf("%s: could not find efuse device\n", __func__); 68064b2675SJason Zhu return ret; 69064b2675SJason Zhu } 70064b2675SJason Zhu /* read the cpu_id range from the efuses */ 71064b2675SJason Zhu ret = misc_read(dev, CPUID_OFF, &cpuid, sizeof(cpuid)); 72064b2675SJason Zhu if (ret) { 73064b2675SJason Zhu printf("%s: reading cpuid from the efuses failed\n", __func__); 74064b2675SJason Zhu return ret; 75064b2675SJason Zhu } 76064b2675SJason Zhu #else 77064b2675SJason Zhu /* generate random cpuid */ 78064b2675SJason Zhu for (i = 0; i < CPUID_LEN; i++) { 79064b2675SJason Zhu cpuid[i] = (u8)(rand()); 80064b2675SJason Zhu } 81064b2675SJason Zhu #endif 82064b2675SJason Zhu /* Generate the serial number based on CPU ID */ 83064b2675SJason Zhu for (i = 0; i < 8; i++) { 84064b2675SJason Zhu low[i] = cpuid[1 + (i << 1)]; 85064b2675SJason Zhu high[i] = cpuid[i << 1]; 86064b2675SJason Zhu } 87064b2675SJason Zhu serialno = crc32_no_comp(0, low, 8); 88064b2675SJason Zhu serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32; 89064b2675SJason Zhu snprintf(serialno_str, sizeof(serialno_str), "%llx", serialno); 90064b2675SJason Zhu 91064b2675SJason Zhu env_set("serial#", serialno_str); 92064b2675SJason Zhu #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 93064b2675SJason Zhu } 94064b2675SJason Zhu #endif 95064b2675SJason Zhu return ret; 96064b2675SJason Zhu } 9738771996SKever Yang 9838771996SKever Yang #if defined(CONFIG_USB_FUNCTION_FASTBOOT) 9938771996SKever Yang int fb_set_reboot_flag(void) 10038771996SKever Yang { 10138771996SKever Yang printf("Setting reboot to fastboot flag ...\n"); 10238771996SKever Yang /* Set boot mode to fastboot */ 10338771996SKever Yang writel(BOOT_FASTBOOT, CONFIG_ROCKCHIP_BOOT_MODE_REG); 10438771996SKever Yang 10538771996SKever Yang return 0; 10638771996SKever Yang } 10738771996SKever Yang #endif 10838771996SKever Yang 10938771996SKever Yang #ifdef CONFIG_DM_CHARGE_DISPLAY 11038771996SKever Yang static int charge_display(void) 11138771996SKever Yang { 11238771996SKever Yang int ret; 11338771996SKever Yang struct udevice *dev; 11438771996SKever Yang 11538771996SKever Yang ret = uclass_get_device(UCLASS_CHARGE_DISPLAY, 0, &dev); 11638771996SKever Yang if (ret) { 11738771996SKever Yang if (ret != -ENODEV) { 118bb2992faSJoseph Chen debug("Get UCLASS CHARGE DISPLAY failed: %d\n", ret); 11938771996SKever Yang return ret; 120eeb3338cSJoseph Chen } else { 121eeb3338cSJoseph Chen debug("Can't find charge display driver\n"); 12238771996SKever Yang } 12338771996SKever Yang return 0; 12438771996SKever Yang } 12538771996SKever Yang 12638771996SKever Yang return charge_display_show(dev); 12738771996SKever Yang } 12838771996SKever Yang #endif 12938771996SKever Yang 13038771996SKever Yang __weak int rk_board_init(void) 13138771996SKever Yang { 13238771996SKever Yang return 0; 13338771996SKever Yang } 13438771996SKever Yang 13538771996SKever Yang __weak int rk_board_late_init(void) 13638771996SKever Yang { 13738771996SKever Yang return 0; 13838771996SKever Yang } 13938771996SKever Yang 140efdbac34SFinley Xiao __weak int soc_clk_dump(void) 141efdbac34SFinley Xiao { 142efdbac34SFinley Xiao return 0; 143efdbac34SFinley Xiao } 144efdbac34SFinley Xiao 145058e5d94SFinley Xiao __weak int set_armclk_rate(void) 146058e5d94SFinley Xiao { 147058e5d94SFinley Xiao return 0; 148058e5d94SFinley Xiao } 149058e5d94SFinley Xiao 15038771996SKever Yang int board_late_init(void) 15138771996SKever Yang { 15238771996SKever Yang #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0) 15338771996SKever Yang setup_boot_mode(); 15438771996SKever Yang #endif 15538771996SKever Yang 15638771996SKever Yang #ifdef CONFIG_DM_CHARGE_DISPLAY 15738771996SKever Yang charge_display(); 15838771996SKever Yang #endif 15938771996SKever Yang 16038771996SKever Yang #ifdef CONFIG_DRM_ROCKCHIP 16138771996SKever Yang rockchip_show_logo(); 16238771996SKever Yang #endif 163064b2675SJason Zhu rockchip_set_serialno(); 16438771996SKever Yang 165efdbac34SFinley Xiao soc_clk_dump(); 166efdbac34SFinley Xiao 16738771996SKever Yang return rk_board_late_init(); 16838771996SKever Yang } 16938771996SKever Yang 170f8aaa2c2SKever Yang #ifdef CONFIG_USING_KERNEL_DTB 171f8aaa2c2SKever Yang #include <asm/arch/resource_img.h> 172740107bbSJoseph Chen 173f8aaa2c2SKever Yang int init_kernel_dtb(void) 174f8aaa2c2SKever Yang { 175f8aaa2c2SKever Yang int ret = 0; 176f8aaa2c2SKever Yang ulong fdt_addr = 0; 177f8aaa2c2SKever Yang 178f8aaa2c2SKever Yang fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 179f8aaa2c2SKever Yang if (!fdt_addr) { 180f8aaa2c2SKever Yang printf("No Found FDT Load Address.\n"); 181f8aaa2c2SKever Yang return -1; 182f8aaa2c2SKever Yang } 183f8aaa2c2SKever Yang 184740107bbSJoseph Chen ret = rockchip_read_dtb_file((void *)fdt_addr); 185f8aaa2c2SKever Yang if (ret < 0) { 186f8aaa2c2SKever Yang printf("%s dtb in resource read fail\n", __func__); 187f8aaa2c2SKever Yang return 0; 188f8aaa2c2SKever Yang } 189f8aaa2c2SKever Yang 190f8aaa2c2SKever Yang of_live_build((void *)fdt_addr, (struct device_node **)&gd->of_root); 191f8aaa2c2SKever Yang 192f8aaa2c2SKever Yang dm_scan_fdt((void *)fdt_addr, false); 193f8aaa2c2SKever Yang 194f8aaa2c2SKever Yang gd->fdt_blob = (void *)fdt_addr; 195f8aaa2c2SKever Yang 196a38e17c3SJoseph Chen printf("Using kernel dtb\n"); 197a38e17c3SJoseph Chen 198f8aaa2c2SKever Yang return 0; 199f8aaa2c2SKever Yang } 200f8aaa2c2SKever Yang #endif 201f8aaa2c2SKever Yang 202f8aaa2c2SKever Yang 20338771996SKever Yang int board_init(void) 20438771996SKever Yang { 20538771996SKever Yang int ret; 20638771996SKever Yang 207575777c5SKever Yang board_debug_uart_init(); 208ebb6c439SYouMin Chen 209f8aaa2c2SKever Yang #ifdef CONFIG_USING_KERNEL_DTB 210f8aaa2c2SKever Yang init_kernel_dtb(); 211f8aaa2c2SKever Yang #endif 2129f8e13d3SFinley Xiao /* 2139f8e13d3SFinley Xiao * pmucru isn't referenced on some platforms, so pmucru driver can't 2149f8e13d3SFinley Xiao * probe that the "assigned-clocks" is unused. 2159f8e13d3SFinley Xiao */ 2169f8e13d3SFinley Xiao clks_probe(); 21738771996SKever Yang #ifdef CONFIG_DM_REGULATOR 21838771996SKever Yang ret = regulators_enable_boot_on(false); 21938771996SKever Yang if (ret) 22038771996SKever Yang debug("%s: Cannot enable boot on regulator\n", __func__); 22138771996SKever Yang #endif 222058e5d94SFinley Xiao set_armclk_rate(); 22338771996SKever Yang 22438771996SKever Yang return rk_board_init(); 22538771996SKever Yang } 22638771996SKever Yang 227c563adc7SJoseph Chen int interrupt_debugger_init(void) 228c563adc7SJoseph Chen { 229c563adc7SJoseph Chen int ret = 0; 230c563adc7SJoseph Chen 231c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER 232c563adc7SJoseph Chen ret = rockchip_debugger_init(); 233c563adc7SJoseph Chen #endif 234c563adc7SJoseph Chen return ret; 235c563adc7SJoseph Chen } 236c563adc7SJoseph Chen 237e09b1e4aSJoseph Chen int board_fdt_fixup(void *blob) 238e09b1e4aSJoseph Chen { 239e09b1e4aSJoseph Chen __maybe_unused int ret = 0; 240e09b1e4aSJoseph Chen 241e09b1e4aSJoseph Chen #ifdef CONFIG_DRM_ROCKCHIP 242e09b1e4aSJoseph Chen rockchip_display_fixup(blob); 243e09b1e4aSJoseph Chen #endif 244e09b1e4aSJoseph Chen 245e09b1e4aSJoseph Chen #ifdef CONFIG_ROCKCHIP_RK3288 246e09b1e4aSJoseph Chen /* RK3288W HDMI Revision ID is 0x1A */ 247e09b1e4aSJoseph Chen if (readl(0xff980004) == 0x1A) { 248e09b1e4aSJoseph Chen ret = fdt_setprop_string(blob, 0, 249e09b1e4aSJoseph Chen "compatible", "rockchip,rk3288w"); 250e09b1e4aSJoseph Chen if (ret) 251e09b1e4aSJoseph Chen printf("fdt set compatible failed: %d\n", ret); 252e09b1e4aSJoseph Chen } 253e09b1e4aSJoseph Chen #endif 254e09b1e4aSJoseph Chen 255e09b1e4aSJoseph Chen return ret; 256e09b1e4aSJoseph Chen } 257e09b1e4aSJoseph Chen 25838771996SKever Yang void enable_caches(void) 25938771996SKever Yang { 260567735c8SJoseph Chen icache_enable(); 26138771996SKever Yang dcache_enable(); 26238771996SKever Yang } 26338771996SKever Yang 264*2dc2d048SJoseph Chen #ifdef CONFIG_LMB 2652c6a058bSJoseph Chen /* 2662c6a058bSJoseph Chen * Using last bi_dram[...] to initialize "bootm_low" and "bootm_mapsize". 2672c6a058bSJoseph Chen * This makes lmb_alloc_base() always alloc from tail of sdram. 2682c6a058bSJoseph Chen * If we don't assign it, bi_dram[0] is used by default and it may cause 2692c6a058bSJoseph Chen * lmb_alloc_base() fail when bi_dram[0] range is small. 2702c6a058bSJoseph Chen */ 2712c6a058bSJoseph Chen void board_lmb_reserve(struct lmb *lmb) 2722c6a058bSJoseph Chen { 2732c6a058bSJoseph Chen u64 start, size; 2742c6a058bSJoseph Chen char bootm_low[32]; 2752c6a058bSJoseph Chen char bootm_mapsize[32]; 2762c6a058bSJoseph Chen int i; 2772c6a058bSJoseph Chen 2782c6a058bSJoseph Chen for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 2792c6a058bSJoseph Chen if (!gd->bd->bi_dram[i].size) 2802c6a058bSJoseph Chen break; 2812c6a058bSJoseph Chen } 2822c6a058bSJoseph Chen 2832c6a058bSJoseph Chen start = gd->bd->bi_dram[i - 1].start; 2842c6a058bSJoseph Chen size = gd->bd->bi_dram[i - 1].size; 2852c6a058bSJoseph Chen 2862c6a058bSJoseph Chen /* 287*2dc2d048SJoseph Chen * 32-bit kernel: ramdisk/fdt shouldn't be loaded to highmem area(768MB+), 288*2dc2d048SJoseph Chen * otherwise "Unable to handle kernel paging request at virtual address ...". 289*2dc2d048SJoseph Chen * 290*2dc2d048SJoseph Chen * So that we hope limit highest address at 768M, but there comes the the 291*2dc2d048SJoseph Chen * problem: ramdisk is a compressed image and it expands after descompress, 292*2dc2d048SJoseph Chen * so it accesses 768MB+ and brings the above "Unable to handle kernel ...". 293*2dc2d048SJoseph Chen * 294*2dc2d048SJoseph Chen * We make a appointment that the highest memory address is 512MB, it 295*2dc2d048SJoseph Chen * makes lmb alloc safer. 2962c6a058bSJoseph Chen */ 297*2dc2d048SJoseph Chen #ifndef CONFIG_ARM64 298*2dc2d048SJoseph Chen if (start >= ((u64)CONFIG_SYS_SDRAM_BASE + SZ_512M)) { 2992c6a058bSJoseph Chen start = gd->bd->bi_dram[i - 2].start; 3002c6a058bSJoseph Chen size = gd->bd->bi_dram[i - 2].size; 3012c6a058bSJoseph Chen } 3022c6a058bSJoseph Chen 303*2dc2d048SJoseph Chen if ((start + size) > ((u64)CONFIG_SYS_SDRAM_BASE + SZ_512M)) 304*2dc2d048SJoseph Chen size = (u64)CONFIG_SYS_SDRAM_BASE + SZ_512M - start; 3052c6a058bSJoseph Chen #endif 3062c6a058bSJoseph Chen sprintf(bootm_low, "0x%llx", start); 3072c6a058bSJoseph Chen sprintf(bootm_mapsize, "0x%llx", size); 3082c6a058bSJoseph Chen env_set("bootm_low", bootm_low); 3092c6a058bSJoseph Chen env_set("bootm_mapsize", bootm_mapsize); 3102c6a058bSJoseph Chen } 311*2dc2d048SJoseph Chen #endif 3122c6a058bSJoseph Chen 313064eb493SJoseph Chen #ifdef CONFIG_ROCKCHIP_PRELOADER_SERIAL 314064eb493SJoseph Chen int board_init_f_init_serial(void) 315064eb493SJoseph Chen { 316064eb493SJoseph Chen struct tag *t = atags_get_tag(ATAG_SERIAL); 317064eb493SJoseph Chen 318064eb493SJoseph Chen if (t) { 319064eb493SJoseph Chen gd->serial.using_pre_serial = t->u.serial.enable; 320064eb493SJoseph Chen gd->serial.addr = t->u.serial.addr; 321064eb493SJoseph Chen gd->serial.baudrate = t->u.serial.baudrate; 322064eb493SJoseph Chen gd->serial.id = t->u.serial.id; 323064eb493SJoseph Chen 324064eb493SJoseph Chen debug("%s: enable=%d, addr=0x%lx, baudrate=%d, id=%d\n", 325064eb493SJoseph Chen __func__, gd->serial.using_pre_serial, 326064eb493SJoseph Chen gd->serial.addr, gd->serial.baudrate, 327064eb493SJoseph Chen gd->serial.id); 328064eb493SJoseph Chen } 329064eb493SJoseph Chen 330064eb493SJoseph Chen return 0; 331064eb493SJoseph Chen } 332064eb493SJoseph Chen #endif 333064eb493SJoseph Chen 33438771996SKever Yang #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) 3356f7b6465SFrank Wang #include <fdt_support.h> 33638771996SKever Yang #include <usb.h> 33738771996SKever Yang #include <usb/dwc2_udc.h> 33838771996SKever Yang 33938771996SKever Yang static struct dwc2_plat_otg_data otg_data = { 34038771996SKever Yang .rx_fifo_sz = 512, 34138771996SKever Yang .np_tx_fifo_sz = 16, 34238771996SKever Yang .tx_fifo_sz = 128, 34338771996SKever Yang }; 34438771996SKever Yang 34538771996SKever Yang int board_usb_init(int index, enum usb_init_type init) 34638771996SKever Yang { 34738771996SKever Yang int node; 34838771996SKever Yang const char *mode; 3496f7b6465SFrank Wang fdt_addr_t addr; 3506f7b6465SFrank Wang const fdt32_t *reg; 35138771996SKever Yang bool matched = false; 35238771996SKever Yang const void *blob = gd->fdt_blob; 35338771996SKever Yang 35438771996SKever Yang /* find the usb_otg node */ 35538771996SKever Yang node = fdt_node_offset_by_compatible(blob, -1, 35638771996SKever Yang "snps,dwc2"); 35738771996SKever Yang 35838771996SKever Yang while (node > 0) { 35938771996SKever Yang mode = fdt_getprop(blob, node, "dr_mode", NULL); 36038771996SKever Yang if (mode && strcmp(mode, "otg") == 0) { 36138771996SKever Yang matched = true; 36238771996SKever Yang break; 36338771996SKever Yang } 36438771996SKever Yang 36538771996SKever Yang node = fdt_node_offset_by_compatible(blob, node, 36638771996SKever Yang "snps,dwc2"); 36738771996SKever Yang } 368e7b5bb3cSWilliam Wu 36938771996SKever Yang if (!matched) { 370e7b5bb3cSWilliam Wu /* 371e7b5bb3cSWilliam Wu * With kernel dtb support, rk3288 dwc2 otg node 372e7b5bb3cSWilliam Wu * use the rockchip legacy dwc2 driver "dwc_otg_310" 373e0b87408SJoseph Chen * with the compatible "rockchip,rk3288_usb20_otg", 374e0b87408SJoseph Chen * and rk3368 also use the "dwc_otg_310" driver with 375e0b87408SJoseph Chen * the compatible "rockchip,rk3368-usb". 376e7b5bb3cSWilliam Wu */ 377e0b87408SJoseph Chen #if defined(CONFIG_ROCKCHIP_RK3288) 378e7b5bb3cSWilliam Wu node = fdt_node_offset_by_compatible(blob, -1, 379e7b5bb3cSWilliam Wu "rockchip,rk3288_usb20_otg"); 380e0b87408SJoseph Chen #elif defined(CONFIG_ROCKCHIP_RK3368) 381e0b87408SJoseph Chen node = fdt_node_offset_by_compatible(blob, -1, 382e0b87408SJoseph Chen "rockchip,rk3368-usb"); 383e0b87408SJoseph Chen #endif 384e0b87408SJoseph Chen 385e7b5bb3cSWilliam Wu if (node > 0) { 386e7b5bb3cSWilliam Wu matched = true; 387e7b5bb3cSWilliam Wu } else { 388e7b5bb3cSWilliam Wu pr_err("Not found usb_otg device\n"); 38938771996SKever Yang return -ENODEV; 39038771996SKever Yang } 391e7b5bb3cSWilliam Wu } 3926f7b6465SFrank Wang 3936f7b6465SFrank Wang reg = fdt_getprop(blob, node, "reg", NULL); 3946f7b6465SFrank Wang if (!reg) 3956f7b6465SFrank Wang return -EINVAL; 3966f7b6465SFrank Wang 3976f7b6465SFrank Wang addr = fdt_translate_address(blob, node, reg); 3986f7b6465SFrank Wang if (addr == OF_BAD_ADDR) { 3996f7b6465SFrank Wang pr_err("Not found usb_otg address\n"); 4006f7b6465SFrank Wang return -EINVAL; 4016f7b6465SFrank Wang } 4026f7b6465SFrank Wang 4036f7b6465SFrank Wang otg_data.regs_otg = (uintptr_t)addr; 40438771996SKever Yang 40538771996SKever Yang return dwc2_udc_probe(&otg_data); 40638771996SKever Yang } 40738771996SKever Yang 40838771996SKever Yang int board_usb_cleanup(int index, enum usb_init_type init) 40938771996SKever Yang { 41038771996SKever Yang return 0; 41138771996SKever Yang } 41238771996SKever Yang #endif 413