1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <clk.h> 8 #include <dm.h> 9 #include <debug_uart.h> 10 #include <ram.h> 11 #include <syscon.h> 12 #include <asm/io.h> 13 #include <asm/arch/vendor.h> 14 #include <misc.h> 15 #include <asm/gpio.h> 16 #include <asm/arch/clock.h> 17 #include <asm/arch/periph.h> 18 #include <asm/arch/boot_mode.h> 19 #ifdef CONFIG_DM_CHARGE_DISPLAY 20 #include <power/charge_display.h> 21 #endif 22 #ifdef CONFIG_DM_REGULATOR 23 #include <power/regulator.h> 24 #endif 25 #ifdef CONFIG_DRM_ROCKCHIP 26 #include <video_rockchip.h> 27 #endif 28 #ifdef CONFIG_ROCKCHIP_DEBUGGER 29 #include <rockchip_debugger.h> 30 #endif 31 #ifdef CONFIG_DM_RAMDISK 32 #include <ramdisk.h> 33 #endif 34 #include <mmc.h> 35 #include <of_live.h> 36 #include <dm/root.h> 37 38 DECLARE_GLOBAL_DATA_PTR; 39 /* define serialno max length, the max length is 512 Bytes 40 * The remaining bytes are used to ensure that the first 512 bytes 41 * are valid when executing 'env_set("serial#", value)'. 42 */ 43 #define VENDOR_SN_MAX 513 44 #define CPUID_LEN 0x10 45 #define CPUID_OFF 0x7 46 47 static int rockchip_set_serialno(void) 48 { 49 char serialno_str[VENDOR_SN_MAX]; 50 int ret = 0, i; 51 u8 cpuid[CPUID_LEN] = {0}; 52 u8 low[CPUID_LEN / 2], high[CPUID_LEN / 2]; 53 u64 serialno; 54 55 /* Read serial number from vendor storage part */ 56 memset(serialno_str, 0, VENDOR_SN_MAX); 57 #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 58 ret = vendor_storage_read(VENDOR_SN_ID, serialno_str, (VENDOR_SN_MAX-1)); 59 if (ret > 0) { 60 env_set("serial#", serialno_str); 61 } else { 62 #endif 63 #ifdef CONFIG_ROCKCHIP_EFUSE 64 struct udevice *dev; 65 66 /* retrieve the device */ 67 ret = uclass_get_device_by_driver(UCLASS_MISC, 68 DM_GET_DRIVER(rockchip_efuse), &dev); 69 if (ret) { 70 printf("%s: could not find efuse device\n", __func__); 71 return ret; 72 } 73 /* read the cpu_id range from the efuses */ 74 ret = misc_read(dev, CPUID_OFF, &cpuid, sizeof(cpuid)); 75 if (ret) { 76 printf("%s: reading cpuid from the efuses failed\n", __func__); 77 return ret; 78 } 79 #else 80 /* generate random cpuid */ 81 for (i = 0; i < CPUID_LEN; i++) { 82 cpuid[i] = (u8)(rand()); 83 } 84 #endif 85 /* Generate the serial number based on CPU ID */ 86 for (i = 0; i < 8; i++) { 87 low[i] = cpuid[1 + (i << 1)]; 88 high[i] = cpuid[i << 1]; 89 } 90 serialno = crc32_no_comp(0, low, 8); 91 serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32; 92 snprintf(serialno_str, sizeof(serialno_str), "%llx", serialno); 93 94 env_set("serial#", serialno_str); 95 #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 96 } 97 #endif 98 return ret; 99 } 100 101 #if defined(CONFIG_USB_FUNCTION_FASTBOOT) 102 int fb_set_reboot_flag(void) 103 { 104 printf("Setting reboot to fastboot flag ...\n"); 105 /* Set boot mode to fastboot */ 106 writel(BOOT_FASTBOOT, CONFIG_ROCKCHIP_BOOT_MODE_REG); 107 108 return 0; 109 } 110 #endif 111 112 #ifdef CONFIG_DM_CHARGE_DISPLAY 113 static int charge_display(void) 114 { 115 int ret; 116 struct udevice *dev; 117 118 ret = uclass_get_device(UCLASS_CHARGE_DISPLAY, 0, &dev); 119 if (ret) { 120 if (ret != -ENODEV) { 121 debug("Get UCLASS CHARGE DISPLAY failed: %d\n", ret); 122 return ret; 123 } else { 124 debug("Can't find charge display driver\n"); 125 } 126 return 0; 127 } 128 129 return charge_display_show(dev); 130 } 131 #endif 132 133 __weak int rk_board_init(void) 134 { 135 return 0; 136 } 137 138 __weak int rk_board_late_init(void) 139 { 140 return 0; 141 } 142 143 __weak int soc_clk_dump(void) 144 { 145 return 0; 146 } 147 148 __weak int set_armclk_rate(void) 149 { 150 return 0; 151 } 152 153 int board_late_init(void) 154 { 155 #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0) 156 setup_boot_mode(); 157 #endif 158 159 #ifdef CONFIG_DM_CHARGE_DISPLAY 160 charge_display(); 161 #endif 162 163 #ifdef CONFIG_DRM_ROCKCHIP 164 rockchip_show_logo(); 165 #endif 166 rockchip_set_serialno(); 167 168 soc_clk_dump(); 169 170 return rk_board_late_init(); 171 } 172 173 #ifdef CONFIG_USING_KERNEL_DTB 174 #include <asm/arch/resource_img.h> 175 176 int init_kernel_dtb(void) 177 { 178 int ret = 0; 179 ulong fdt_addr = 0; 180 181 #ifdef CONFIG_DM_MMC 182 ret = mmc_initialize(gd->bd); 183 if (ret) 184 debug("%s: mmc initialized failed, ret=%d\n", __func__ ,ret); 185 #else 186 ret = bramdisk_initialize(); 187 if (ret) 188 debug("%s: bramdisk initialized failed, ret=%d\n", __func__, ret); 189 #endif 190 191 fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 192 if (!fdt_addr) { 193 printf("No Found FDT Load Address.\n"); 194 return -1; 195 } 196 197 ret = rockchip_read_dtb_file((void *)fdt_addr); 198 if (ret < 0) { 199 printf("%s dtb in resource read fail\n", __func__); 200 return 0; 201 } 202 203 of_live_build((void *)fdt_addr, (struct device_node **)&gd->of_root); 204 205 dm_scan_fdt((void *)fdt_addr, false); 206 207 gd->fdt_blob = (void *)fdt_addr; 208 209 printf("Using kernel dtb\n"); 210 211 return 0; 212 } 213 #endif 214 215 216 int board_init(void) 217 { 218 int ret; 219 220 board_debug_uart_init(); 221 222 #ifdef CONFIG_USING_KERNEL_DTB 223 init_kernel_dtb(); 224 #endif 225 /* 226 * pmucru isn't referenced on some platforms, so pmucru driver can't 227 * probe that the "assigned-clocks" is unused. 228 */ 229 clks_probe(); 230 #ifdef CONFIG_DM_REGULATOR 231 ret = regulators_enable_boot_on(false); 232 if (ret) 233 debug("%s: Cannot enable boot on regulator\n", __func__); 234 #endif 235 set_armclk_rate(); 236 237 return rk_board_init(); 238 } 239 240 int interrupt_debugger_init(void) 241 { 242 int ret = 0; 243 244 #ifdef CONFIG_ROCKCHIP_DEBUGGER 245 ret = rockchip_debugger_init(); 246 #endif 247 return ret; 248 } 249 250 int board_fdt_fixup(void *blob) 251 { 252 __maybe_unused int ret = 0; 253 254 #ifdef CONFIG_DRM_ROCKCHIP 255 rockchip_display_fixup(blob); 256 #endif 257 258 #ifdef CONFIG_ROCKCHIP_RK3288 259 /* RK3288W HDMI Revision ID is 0x1A */ 260 if (readl(0xff980004) == 0x1A) { 261 ret = fdt_setprop_string(blob, 0, 262 "compatible", "rockchip,rk3288w"); 263 if (ret) 264 printf("fdt set compatible failed: %d\n", ret); 265 } 266 #endif 267 268 return ret; 269 } 270 271 void enable_caches(void) 272 { 273 icache_enable(); 274 dcache_enable(); 275 } 276 277 #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) 278 #include <fdt_support.h> 279 #include <usb.h> 280 #include <usb/dwc2_udc.h> 281 282 static struct dwc2_plat_otg_data otg_data = { 283 .rx_fifo_sz = 512, 284 .np_tx_fifo_sz = 16, 285 .tx_fifo_sz = 128, 286 }; 287 288 int board_usb_init(int index, enum usb_init_type init) 289 { 290 int node; 291 const char *mode; 292 fdt_addr_t addr; 293 const fdt32_t *reg; 294 bool matched = false; 295 const void *blob = gd->fdt_blob; 296 297 /* find the usb_otg node */ 298 node = fdt_node_offset_by_compatible(blob, -1, 299 "snps,dwc2"); 300 301 while (node > 0) { 302 mode = fdt_getprop(blob, node, "dr_mode", NULL); 303 if (mode && strcmp(mode, "otg") == 0) { 304 matched = true; 305 break; 306 } 307 308 node = fdt_node_offset_by_compatible(blob, node, 309 "snps,dwc2"); 310 } 311 312 if (!matched) { 313 /* 314 * With kernel dtb support, rk3288 dwc2 otg node 315 * use the rockchip legacy dwc2 driver "dwc_otg_310" 316 * with the compatible "rockchip,rk3288_usb20_otg", 317 * and rk3368 also use the "dwc_otg_310" driver with 318 * the compatible "rockchip,rk3368-usb". 319 */ 320 #if defined(CONFIG_ROCKCHIP_RK3288) 321 node = fdt_node_offset_by_compatible(blob, -1, 322 "rockchip,rk3288_usb20_otg"); 323 #elif defined(CONFIG_ROCKCHIP_RK3368) 324 node = fdt_node_offset_by_compatible(blob, -1, 325 "rockchip,rk3368-usb"); 326 #endif 327 328 if (node > 0) { 329 matched = true; 330 } else { 331 pr_err("Not found usb_otg device\n"); 332 return -ENODEV; 333 } 334 } 335 336 reg = fdt_getprop(blob, node, "reg", NULL); 337 if (!reg) 338 return -EINVAL; 339 340 addr = fdt_translate_address(blob, node, reg); 341 if (addr == OF_BAD_ADDR) { 342 pr_err("Not found usb_otg address\n"); 343 return -EINVAL; 344 } 345 346 otg_data.regs_otg = (uintptr_t)addr; 347 348 return dwc2_udc_probe(&otg_data); 349 } 350 351 int board_usb_cleanup(int index, enum usb_init_type init) 352 { 353 return 0; 354 } 355 #endif 356