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