1 /* 2 * (C) Copyright 2019 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <boot_rkimg.h> 8 #include <dm.h> 9 #include <malloc.h> 10 #include <of_live.h> 11 #include <dm/device-internal.h> 12 #include <dm/root.h> 13 #include <dm/uclass-internal.h> 14 #include <asm/arch/hotkey.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 #ifdef CONFIG_USING_KERNEL_DTB_V2 19 static int dm_rm_kernel_dev(void) 20 { 21 struct udevice *dev, *rec[10]; 22 u32 uclass[] = { UCLASS_CRYPTO }; 23 int i, j, k; 24 25 for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) { 26 for (uclass_find_first_device(uclass[i], &dev); dev; 27 uclass_find_next_device(&dev)) { 28 if (dev->flags & DM_FLAG_KNRL_DTB) 29 rec[j++] = dev; 30 } 31 32 for (k = 0; k < j; k++) { 33 device_remove(rec[k], DM_REMOVE_NORMAL); 34 device_unbind(rec[k]); 35 } 36 } 37 38 return 0; 39 } 40 41 static int dm_rm_u_boot_dev(void) 42 { 43 struct udevice *dev, *rec[10]; 44 u32 uclass[] = { UCLASS_ETH }; 45 int del = 0; 46 int i, j, k; 47 48 for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) { 49 for (uclass_find_first_device(uclass[i], &dev); dev; 50 uclass_find_next_device(&dev)) { 51 if (dev->flags & DM_FLAG_KNRL_DTB) 52 del = 1; 53 else 54 rec[j++] = dev; 55 } 56 57 /* remove u-boot dev if there is someone from kernel */ 58 if (del) { 59 for (k = 0; k < j; k++) { 60 device_remove(rec[k], DM_REMOVE_NORMAL); 61 device_unbind(rec[k]); 62 } 63 } 64 } 65 66 return 0; 67 } 68 69 #else 70 /* Here, only fixup cru phandle, pmucru is not included */ 71 static int phandles_fixup_cru(const void *fdt) 72 { 73 const char *props[] = { "clocks", "assigned-clocks", "resets"}; 74 struct udevice *dev; 75 struct uclass *uc; 76 const char *comp; 77 u32 id, nclocks; 78 u32 *clocks; 79 int phandle, ncells; 80 int off, offset; 81 int ret, length; 82 int i, j; 83 int first_phandle = -1; 84 85 phandle = -ENODATA; 86 ncells = -ENODATA; 87 88 /* fdt points to kernel dtb, getting cru phandle and "#clock-cells" */ 89 for (offset = fdt_next_node(fdt, 0, NULL); 90 offset >= 0; 91 offset = fdt_next_node(fdt, offset, NULL)) { 92 comp = fdt_getprop(fdt, offset, "compatible", NULL); 93 if (!comp) 94 continue; 95 96 /* Actually, this is not a good method to get cru node */ 97 off = strlen(comp) - strlen("-cru"); 98 if (off > 0 && !strncmp(comp + off, "-cru", 4)) { 99 phandle = fdt_get_phandle(fdt, offset); 100 ncells = fdtdec_get_int(fdt, offset, 101 "#clock-cells", -ENODATA); 102 break; 103 } 104 } 105 106 if (phandle == -ENODATA || ncells == -ENODATA) 107 return 0; 108 109 debug("%s: target cru: clock-cells:%d, phandle:0x%x\n", 110 __func__, ncells, fdt32_to_cpu(phandle)); 111 112 /* Try to fixup all cru phandle from U-Boot dtb nodes */ 113 for (id = 0; id < UCLASS_COUNT; id++) { 114 ret = uclass_get(id, &uc); 115 if (ret) 116 continue; 117 118 if (list_empty(&uc->dev_head)) 119 continue; 120 121 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 122 /* Only U-Boot node go further */ 123 if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 124 !dev_read_bool(dev, "u-boot,dm-spl")) 125 continue; 126 127 for (i = 0; i < ARRAY_SIZE(props); i++) { 128 if (!dev_read_prop(dev, props[i], &length)) 129 continue; 130 131 clocks = malloc(length); 132 if (!clocks) 133 return -ENOMEM; 134 135 /* Read "props[]" which contains cru phandle */ 136 nclocks = length / sizeof(u32); 137 if (dev_read_u32_array(dev, props[i], 138 clocks, nclocks)) { 139 free(clocks); 140 continue; 141 } 142 143 /* Fixup with kernel cru phandle */ 144 for (j = 0; j < nclocks; j += (ncells + 1)) { 145 /* 146 * Check: update pmucru phandle with cru 147 * phandle by mistake. 148 */ 149 if (first_phandle == -1) 150 first_phandle = clocks[j]; 151 152 if (clocks[j] != first_phandle) { 153 debug("WARN: %s: first cru phandle=%d, this=%d\n", 154 dev_read_name(dev), 155 first_phandle, clocks[j]); 156 continue; 157 } 158 159 clocks[j] = phandle; 160 } 161 162 /* 163 * Override live dt nodes but not fdt nodes, 164 * because all U-Boot nodes has been imported 165 * to live dt nodes, should use "dev_xxx()". 166 */ 167 dev_write_u32_array(dev, props[i], 168 clocks, nclocks); 169 free(clocks); 170 } 171 } 172 } 173 174 return 0; 175 } 176 177 static int phandles_fixup_gpio(const void *fdt, void *ufdt) 178 { 179 struct udevice *dev; 180 struct uclass *uc; 181 const char *prop = "gpios"; 182 const char *comp; 183 char *gpio_name[10]; 184 int gpio_off[10]; 185 int pinctrl; 186 int offset; 187 int i = 0; 188 int n = 0; 189 190 pinctrl = fdt_path_offset(fdt, "/pinctrl"); 191 if (pinctrl < 0) 192 return 0; 193 194 memset(gpio_name, 0, sizeof(gpio_name)); 195 for (offset = fdt_first_subnode(fdt, pinctrl); 196 offset >= 0; 197 offset = fdt_next_subnode(fdt, offset)) { 198 /* assume the font nodes are gpio node */ 199 if (++i >= ARRAY_SIZE(gpio_name)) 200 break; 201 202 comp = fdt_getprop(fdt, offset, "compatible", NULL); 203 if (!comp) 204 continue; 205 206 if (!strcmp(comp, "rockchip,gpio-bank")) { 207 gpio_name[n] = (char *)fdt_get_name(fdt, offset, NULL); 208 gpio_off[n] = offset; 209 n++; 210 } 211 } 212 213 if (!gpio_name[0]) 214 return 0; 215 216 if (uclass_get(UCLASS_KEY, &uc) || list_empty(&uc->dev_head)) 217 return 0; 218 219 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 220 u32 new_phd, phd_old; 221 char *name; 222 ofnode ofn; 223 224 if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 225 !dev_read_bool(dev, "u-boot,dm-spl")) 226 continue; 227 228 if (dev_read_u32_array(dev, prop, &phd_old, 1)) 229 continue; 230 231 ofn = ofnode_get_by_phandle(phd_old); 232 if (!ofnode_valid(ofn)) 233 continue; 234 235 name = (char *)ofnode_get_name(ofn); 236 if (!name) 237 continue; 238 239 for (i = 0; i < ARRAY_SIZE(gpio_name); i++) { 240 if (gpio_name[i] && !strcmp(name, gpio_name[i])) { 241 new_phd = fdt_get_phandle(fdt, gpio_off[i]); 242 dev_write_u32_array(dev, prop, &new_phd, 1); 243 break; 244 } 245 } 246 } 247 248 return 0; 249 } 250 #endif 251 252 __weak int board_mmc_dm_reinit(struct udevice *dev) 253 { 254 return 0; 255 } 256 257 static int mmc_dm_reinit(void) 258 { 259 struct udevice *dev; 260 struct uclass *uc; 261 int ret; 262 263 if (uclass_get(UCLASS_MMC, &uc) || list_empty(&uc->dev_head)) 264 return 0; 265 266 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 267 ret = board_mmc_dm_reinit(dev); 268 if (ret) 269 return ret; 270 } 271 272 return 0; 273 } 274 275 /* Check by property: "/compatible" */ 276 static int dtb_check_ok(void *kfdt, void *ufdt) 277 { 278 const char *compat; 279 int index; 280 281 /* TODO */ 282 return 1; 283 284 for (index = 0; 285 compat = fdt_stringlist_get(ufdt, 0, "compatible", 286 index, NULL), compat; 287 index++) { 288 debug("u-compat: %s\n", compat); 289 if (!fdt_node_check_compatible(kfdt, 0, compat)) 290 return 1; 291 } 292 293 return 0; 294 } 295 296 int init_kernel_dtb(void) 297 { 298 #ifndef CONFIG_USING_KERNEL_DTB_V2 299 void *ufdt_blob = (void *)gd->fdt_blob; 300 #endif 301 ulong fdt_addr = 0; 302 int ret = -ENODEV; 303 304 printf("DM: v%d\n", IS_ENABLED(CONFIG_USING_KERNEL_DTB_V2) ? 2 : 1); 305 306 /* 307 * If memory size <= 128MB, we firstly try to get "fdt_addr1_r". 308 */ 309 if (gd->ram_size <= SZ_128M) 310 fdt_addr = env_get_ulong("fdt_addr1_r", 16, 0); 311 312 if (!fdt_addr) 313 fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 314 if (!fdt_addr) { 315 printf("No Found FDT Load Address.\n"); 316 return -ENODEV; 317 } 318 319 if (IS_ENABLED(CONFIG_EMBED_KERNEL_DTB_ALWAYS)) { 320 printf("Always embed kernel dtb\n"); 321 goto dtb_embed; 322 } 323 324 ret = rockchip_read_dtb_file((void *)fdt_addr); 325 if (!ret) { 326 if (!dtb_check_ok((void *)fdt_addr, (void *)gd->fdt_blob)) { 327 ret = -EINVAL; 328 printf("Kernel dtb mismatch this platform!\n"); 329 } else { 330 goto dtb_okay; 331 } 332 } 333 334 dtb_embed: 335 if (gd->fdt_blob_kern) { 336 if (!dtb_check_ok((void *)gd->fdt_blob_kern, (void *)gd->fdt_blob)) { 337 printf("Embedded kernel dtb mismatch this platform!\n"); 338 return -EINVAL; 339 } 340 341 fdt_addr = (ulong)memalign(ARCH_DMA_MINALIGN, 342 fdt_totalsize(gd->fdt_blob_kern)); 343 if (!fdt_addr) 344 return -ENOMEM; 345 346 /* 347 * Alloc another space for this embed kernel dtb. 348 * Because "fdt_addr_r" *MUST* be the fdt passed to kernel. 349 */ 350 memcpy((void *)fdt_addr, gd->fdt_blob_kern, 351 fdt_totalsize(gd->fdt_blob_kern)); 352 printf("DTB: %s\n", CONFIG_EMBED_KERNEL_DTB_PATH); 353 } else { 354 printf("Failed to get kernel dtb, ret=%d\n", ret); 355 return -ENOENT; 356 } 357 358 dtb_okay: 359 gd->fdt_blob = (void *)fdt_addr; 360 hotkey_run(HK_FDT); 361 362 #ifndef CONFIG_USING_KERNEL_DTB_V2 363 /* 364 * There is a phandle miss match between U-Boot and kernel dtb node, 365 * we fixup it in U-Boot live dt nodes. 366 * 367 * CRU: all nodes. 368 * GPIO: key nodes. 369 */ 370 phandles_fixup_cru((void *)gd->fdt_blob); 371 phandles_fixup_gpio((void *)gd->fdt_blob, (void *)ufdt_blob); 372 #endif 373 374 gd->flags |= GD_FLG_KDTB_READY; 375 gd->of_root_f = gd->of_root; 376 of_live_build((void *)gd->fdt_blob, (struct device_node **)&gd->of_root); 377 dm_scan_fdt((void *)gd->fdt_blob, false); 378 379 #ifdef CONFIG_USING_KERNEL_DTB_V2 380 dm_rm_kernel_dev(); 381 dm_rm_u_boot_dev(); 382 #endif 383 /* 384 * There maybe something for the mmc devices to do after kernel dtb 385 * dm setup, eg: regain the clock device binding from kernel dtb. 386 */ 387 mmc_dm_reinit(); 388 389 /* Reserve 'reserved-memory' */ 390 ret = boot_fdt_add_sysmem_rsv_regions((void *)gd->fdt_blob); 391 if (ret) 392 return ret; 393 394 return 0; 395 } 396 397