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