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> 1938771996SKever Yang #ifdef CONFIG_DM_CHARGE_DISPLAY 2038771996SKever Yang #include <power/charge_display.h> 2138771996SKever Yang #endif 2238771996SKever Yang #ifdef CONFIG_DM_REGULATOR 2338771996SKever Yang #include <power/regulator.h> 2438771996SKever Yang #endif 2538771996SKever Yang #ifdef CONFIG_DRM_ROCKCHIP 2638771996SKever Yang #include <video_rockchip.h> 2738771996SKever Yang #endif 28c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER 29c563adc7SJoseph Chen #include <rockchip_debugger.h> 30c563adc7SJoseph Chen #endif 31f8aaa2c2SKever Yang #include <mmc.h> 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) { 11838771996SKever Yang printf("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 struct mmc *mmc; 177f8aaa2c2SKever Yang struct udevice *dev; 178f8aaa2c2SKever Yang ulong fdt_addr = 0; 179f8aaa2c2SKever Yang 180f8aaa2c2SKever Yang ret = mmc_initialize(gd->bd); 181f8aaa2c2SKever Yang if (ret) 182f8aaa2c2SKever Yang goto scan_nand; 183f8aaa2c2SKever Yang mmc = find_mmc_device(0); 184f8aaa2c2SKever Yang if (!mmc) { 185f8aaa2c2SKever Yang printf("no mmc device at slot 0\n"); 186f8aaa2c2SKever Yang goto scan_nand; 187f8aaa2c2SKever Yang } 188f8aaa2c2SKever Yang ret = mmc_init(mmc); 189f8aaa2c2SKever Yang if (!ret) 190f8aaa2c2SKever Yang goto init_dtb; 191f8aaa2c2SKever Yang printf("%s mmc init fail %d\n", __func__, ret); 192f8aaa2c2SKever Yang scan_nand: 193f8aaa2c2SKever Yang ret = uclass_get_device(UCLASS_RKNAND, 0, &dev); 194f8aaa2c2SKever Yang if (ret) { 195f8aaa2c2SKever Yang printf("%s: Cannot find rknand device\n", __func__); 196f8aaa2c2SKever Yang return -1; 197f8aaa2c2SKever Yang } 198f8aaa2c2SKever Yang 199f8aaa2c2SKever Yang init_dtb: 200f8aaa2c2SKever Yang fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 201f8aaa2c2SKever Yang if (!fdt_addr) { 202f8aaa2c2SKever Yang printf("No Found FDT Load Address.\n"); 203f8aaa2c2SKever Yang return -1; 204f8aaa2c2SKever Yang } 205f8aaa2c2SKever Yang 206740107bbSJoseph Chen ret = rockchip_read_dtb_file((void *)fdt_addr); 207f8aaa2c2SKever Yang if (ret < 0) { 208f8aaa2c2SKever Yang printf("%s dtb in resource read fail\n", __func__); 209f8aaa2c2SKever Yang return 0; 210f8aaa2c2SKever Yang } 211f8aaa2c2SKever Yang 212f8aaa2c2SKever Yang of_live_build((void *)fdt_addr, (struct device_node **)&gd->of_root); 213f8aaa2c2SKever Yang 214f8aaa2c2SKever Yang dm_scan_fdt((void *)fdt_addr, false); 215f8aaa2c2SKever Yang 216f8aaa2c2SKever Yang gd->fdt_blob = (void *)fdt_addr; 217f8aaa2c2SKever Yang 218a38e17c3SJoseph Chen printf("Using kernel dtb\n"); 219a38e17c3SJoseph Chen 220f8aaa2c2SKever Yang return 0; 221f8aaa2c2SKever Yang } 222f8aaa2c2SKever Yang #endif 223f8aaa2c2SKever Yang 224f8aaa2c2SKever Yang 22538771996SKever Yang int board_init(void) 22638771996SKever Yang { 22738771996SKever Yang int ret; 22838771996SKever Yang 229575777c5SKever Yang #if !defined(CONFIG_SUPPORT_SPL) 230575777c5SKever Yang board_debug_uart_init(); 231575777c5SKever Yang #endif 232f8aaa2c2SKever Yang #ifdef CONFIG_USING_KERNEL_DTB 233f8aaa2c2SKever Yang init_kernel_dtb(); 234f8aaa2c2SKever Yang #endif 2359f8e13d3SFinley Xiao /* 2369f8e13d3SFinley Xiao * pmucru isn't referenced on some platforms, so pmucru driver can't 2379f8e13d3SFinley Xiao * probe that the "assigned-clocks" is unused. 2389f8e13d3SFinley Xiao */ 2399f8e13d3SFinley Xiao clks_probe(); 24038771996SKever Yang #ifdef CONFIG_DM_REGULATOR 24138771996SKever Yang ret = regulators_enable_boot_on(false); 24238771996SKever Yang if (ret) 24338771996SKever Yang debug("%s: Cannot enable boot on regulator\n", __func__); 24438771996SKever Yang #endif 245058e5d94SFinley Xiao set_armclk_rate(); 24638771996SKever Yang 24738771996SKever Yang return rk_board_init(); 24838771996SKever Yang } 24938771996SKever Yang 250c563adc7SJoseph Chen int interrupt_debugger_init(void) 251c563adc7SJoseph Chen { 252c563adc7SJoseph Chen int ret = 0; 253c563adc7SJoseph Chen 254c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER 255c563adc7SJoseph Chen ret = rockchip_debugger_init(); 256c563adc7SJoseph Chen #endif 257c563adc7SJoseph Chen return ret; 258c563adc7SJoseph Chen } 259c563adc7SJoseph Chen 260e09b1e4aSJoseph Chen int board_fdt_fixup(void *blob) 261e09b1e4aSJoseph Chen { 262e09b1e4aSJoseph Chen __maybe_unused int ret = 0; 263e09b1e4aSJoseph Chen 264e09b1e4aSJoseph Chen #ifdef CONFIG_DRM_ROCKCHIP 265e09b1e4aSJoseph Chen rockchip_display_fixup(blob); 266e09b1e4aSJoseph Chen #endif 267e09b1e4aSJoseph Chen 268e09b1e4aSJoseph Chen #ifdef CONFIG_ROCKCHIP_RK3288 269e09b1e4aSJoseph Chen /* RK3288W HDMI Revision ID is 0x1A */ 270e09b1e4aSJoseph Chen if (readl(0xff980004) == 0x1A) { 271e09b1e4aSJoseph Chen ret = fdt_setprop_string(blob, 0, 272e09b1e4aSJoseph Chen "compatible", "rockchip,rk3288w"); 273e09b1e4aSJoseph Chen if (ret) 274e09b1e4aSJoseph Chen printf("fdt set compatible failed: %d\n", ret); 275e09b1e4aSJoseph Chen } 276e09b1e4aSJoseph Chen #endif 277e09b1e4aSJoseph Chen 278e09b1e4aSJoseph Chen return ret; 279e09b1e4aSJoseph Chen } 280e09b1e4aSJoseph Chen 28138771996SKever Yang #if !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_ARM64) 28238771996SKever Yang void enable_caches(void) 28338771996SKever Yang { 28438771996SKever Yang /* Enable D-cache. I-cache is already enabled in start.S */ 28538771996SKever Yang dcache_enable(); 28638771996SKever Yang } 28738771996SKever Yang #endif 28838771996SKever Yang 28938771996SKever Yang #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) 2906f7b6465SFrank Wang #include <fdt_support.h> 29138771996SKever Yang #include <usb.h> 29238771996SKever Yang #include <usb/dwc2_udc.h> 29338771996SKever Yang 29438771996SKever Yang static struct dwc2_plat_otg_data otg_data = { 29538771996SKever Yang .rx_fifo_sz = 512, 29638771996SKever Yang .np_tx_fifo_sz = 16, 29738771996SKever Yang .tx_fifo_sz = 128, 29838771996SKever Yang }; 29938771996SKever Yang 30038771996SKever Yang int board_usb_init(int index, enum usb_init_type init) 30138771996SKever Yang { 30238771996SKever Yang int node; 30338771996SKever Yang const char *mode; 3046f7b6465SFrank Wang fdt_addr_t addr; 3056f7b6465SFrank Wang const fdt32_t *reg; 30638771996SKever Yang bool matched = false; 30738771996SKever Yang const void *blob = gd->fdt_blob; 30838771996SKever Yang 30938771996SKever Yang /* find the usb_otg node */ 31038771996SKever Yang node = fdt_node_offset_by_compatible(blob, -1, 31138771996SKever Yang "snps,dwc2"); 31238771996SKever Yang 31338771996SKever Yang while (node > 0) { 31438771996SKever Yang mode = fdt_getprop(blob, node, "dr_mode", NULL); 31538771996SKever Yang if (mode && strcmp(mode, "otg") == 0) { 31638771996SKever Yang matched = true; 31738771996SKever Yang break; 31838771996SKever Yang } 31938771996SKever Yang 32038771996SKever Yang node = fdt_node_offset_by_compatible(blob, node, 32138771996SKever Yang "snps,dwc2"); 32238771996SKever Yang } 323*e7b5bb3cSWilliam Wu 32438771996SKever Yang if (!matched) { 325*e7b5bb3cSWilliam Wu /* 326*e7b5bb3cSWilliam Wu * With kernel dtb support, rk3288 dwc2 otg node 327*e7b5bb3cSWilliam Wu * use the rockchip legacy dwc2 driver "dwc_otg_310" 328*e7b5bb3cSWilliam Wu * with the compatible "rockchip,rk3288_usb20_otg". 329*e7b5bb3cSWilliam Wu */ 330*e7b5bb3cSWilliam Wu node = fdt_node_offset_by_compatible(blob, -1, 331*e7b5bb3cSWilliam Wu "rockchip,rk3288_usb20_otg"); 332*e7b5bb3cSWilliam Wu if (node > 0) { 333*e7b5bb3cSWilliam Wu matched = true; 334*e7b5bb3cSWilliam Wu } else { 335*e7b5bb3cSWilliam Wu pr_err("Not found usb_otg device\n"); 33638771996SKever Yang return -ENODEV; 33738771996SKever Yang } 338*e7b5bb3cSWilliam Wu } 3396f7b6465SFrank Wang 3406f7b6465SFrank Wang reg = fdt_getprop(blob, node, "reg", NULL); 3416f7b6465SFrank Wang if (!reg) 3426f7b6465SFrank Wang return -EINVAL; 3436f7b6465SFrank Wang 3446f7b6465SFrank Wang addr = fdt_translate_address(blob, node, reg); 3456f7b6465SFrank Wang if (addr == OF_BAD_ADDR) { 3466f7b6465SFrank Wang pr_err("Not found usb_otg address\n"); 3476f7b6465SFrank Wang return -EINVAL; 3486f7b6465SFrank Wang } 3496f7b6465SFrank Wang 3506f7b6465SFrank Wang otg_data.regs_otg = (uintptr_t)addr; 35138771996SKever Yang 35238771996SKever Yang return dwc2_udc_probe(&otg_data); 35338771996SKever Yang } 35438771996SKever Yang 35538771996SKever Yang int board_usb_cleanup(int index, enum usb_init_type init) 35638771996SKever Yang { 35738771996SKever Yang return 0; 35838771996SKever Yang } 35938771996SKever Yang #endif 360