157be1825SJoseph Chen /* 257be1825SJoseph Chen * (C) Copyright 2019 Rockchip Electronics Co., Ltd 357be1825SJoseph Chen * 457be1825SJoseph Chen * SPDX-License-Identifier: GPL-2.0+ 557be1825SJoseph Chen */ 657be1825SJoseph Chen #include <common.h> 757be1825SJoseph Chen #include <boot_rkimg.h> 857be1825SJoseph Chen #include <dm.h> 957be1825SJoseph Chen #include <malloc.h> 1057be1825SJoseph Chen #include <of_live.h> 11*7bedd730SJoseph Chen #include <dm/device-internal.h> 1257be1825SJoseph Chen #include <dm/root.h> 1318b9d982SJoseph Chen #include <dm/uclass-internal.h> 1457be1825SJoseph Chen #include <asm/arch/hotkey.h> 1557be1825SJoseph Chen 1657be1825SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 1757be1825SJoseph Chen 1818b9d982SJoseph Chen #ifdef CONFIG_USING_KERNEL_DTB_V2 1918b9d982SJoseph Chen static int dm_rm_kernel_dev(void) 2018b9d982SJoseph Chen { 2118b9d982SJoseph Chen struct udevice *dev, *rec[10]; 2218b9d982SJoseph Chen u32 uclass[] = { UCLASS_CRYPTO }; 2318b9d982SJoseph Chen int i, j, k; 2418b9d982SJoseph Chen 2518b9d982SJoseph Chen for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) { 2618b9d982SJoseph Chen for (uclass_find_first_device(uclass[i], &dev); dev; 2718b9d982SJoseph Chen uclass_find_next_device(&dev)) { 2818b9d982SJoseph Chen if (dev->flags & DM_FLAG_KNRL_DTB) 2918b9d982SJoseph Chen rec[j++] = dev; 3018b9d982SJoseph Chen } 3118b9d982SJoseph Chen 32*7bedd730SJoseph Chen for (k = 0; k < j; k++) { 33*7bedd730SJoseph Chen device_remove(rec[k], DM_REMOVE_NORMAL); 34*7bedd730SJoseph Chen device_unbind(rec[k]); 35*7bedd730SJoseph Chen } 3618b9d982SJoseph Chen } 3718b9d982SJoseph Chen 3818b9d982SJoseph Chen return 0; 3918b9d982SJoseph Chen } 4018b9d982SJoseph Chen 4118b9d982SJoseph Chen static int dm_rm_u_boot_dev(void) 4218b9d982SJoseph Chen { 4318b9d982SJoseph Chen struct udevice *dev, *rec[10]; 4418b9d982SJoseph Chen u32 uclass[] = { UCLASS_ETH }; 4518b9d982SJoseph Chen int del = 0; 4618b9d982SJoseph Chen int i, j, k; 4718b9d982SJoseph Chen 4818b9d982SJoseph Chen for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) { 4918b9d982SJoseph Chen for (uclass_find_first_device(uclass[i], &dev); dev; 5018b9d982SJoseph Chen uclass_find_next_device(&dev)) { 5118b9d982SJoseph Chen if (dev->flags & DM_FLAG_KNRL_DTB) 5218b9d982SJoseph Chen del = 1; 5318b9d982SJoseph Chen else 5418b9d982SJoseph Chen rec[j++] = dev; 5518b9d982SJoseph Chen } 5618b9d982SJoseph Chen 5718b9d982SJoseph Chen /* remove u-boot dev if there is someone from kernel */ 5818b9d982SJoseph Chen if (del) { 59*7bedd730SJoseph Chen for (k = 0; k < j; k++) { 60*7bedd730SJoseph Chen device_remove(rec[k], DM_REMOVE_NORMAL); 61*7bedd730SJoseph Chen device_unbind(rec[k]); 62*7bedd730SJoseph Chen } 6318b9d982SJoseph Chen } 6418b9d982SJoseph Chen } 6518b9d982SJoseph Chen 6618b9d982SJoseph Chen return 0; 6718b9d982SJoseph Chen } 6818b9d982SJoseph Chen 6918b9d982SJoseph Chen #else 7057be1825SJoseph Chen /* Here, only fixup cru phandle, pmucru is not included */ 7157be1825SJoseph Chen static int phandles_fixup_cru(const void *fdt) 7257be1825SJoseph Chen { 734d85f76cSJoseph Chen const char *props[] = { "clocks", "assigned-clocks", "resets"}; 7457be1825SJoseph Chen struct udevice *dev; 7557be1825SJoseph Chen struct uclass *uc; 7657be1825SJoseph Chen const char *comp; 7757be1825SJoseph Chen u32 id, nclocks; 7857be1825SJoseph Chen u32 *clocks; 7957be1825SJoseph Chen int phandle, ncells; 8057be1825SJoseph Chen int off, offset; 8157be1825SJoseph Chen int ret, length; 8257be1825SJoseph Chen int i, j; 8357be1825SJoseph Chen int first_phandle = -1; 8457be1825SJoseph Chen 8557be1825SJoseph Chen phandle = -ENODATA; 8657be1825SJoseph Chen ncells = -ENODATA; 8757be1825SJoseph Chen 8857be1825SJoseph Chen /* fdt points to kernel dtb, getting cru phandle and "#clock-cells" */ 8957be1825SJoseph Chen for (offset = fdt_next_node(fdt, 0, NULL); 9057be1825SJoseph Chen offset >= 0; 9157be1825SJoseph Chen offset = fdt_next_node(fdt, offset, NULL)) { 9257be1825SJoseph Chen comp = fdt_getprop(fdt, offset, "compatible", NULL); 9357be1825SJoseph Chen if (!comp) 9457be1825SJoseph Chen continue; 9557be1825SJoseph Chen 9657be1825SJoseph Chen /* Actually, this is not a good method to get cru node */ 9757be1825SJoseph Chen off = strlen(comp) - strlen("-cru"); 9857be1825SJoseph Chen if (off > 0 && !strncmp(comp + off, "-cru", 4)) { 9957be1825SJoseph Chen phandle = fdt_get_phandle(fdt, offset); 10057be1825SJoseph Chen ncells = fdtdec_get_int(fdt, offset, 10157be1825SJoseph Chen "#clock-cells", -ENODATA); 10257be1825SJoseph Chen break; 10357be1825SJoseph Chen } 10457be1825SJoseph Chen } 10557be1825SJoseph Chen 10657be1825SJoseph Chen if (phandle == -ENODATA || ncells == -ENODATA) 10757be1825SJoseph Chen return 0; 10857be1825SJoseph Chen 10957be1825SJoseph Chen debug("%s: target cru: clock-cells:%d, phandle:0x%x\n", 11057be1825SJoseph Chen __func__, ncells, fdt32_to_cpu(phandle)); 11157be1825SJoseph Chen 11257be1825SJoseph Chen /* Try to fixup all cru phandle from U-Boot dtb nodes */ 11357be1825SJoseph Chen for (id = 0; id < UCLASS_COUNT; id++) { 11457be1825SJoseph Chen ret = uclass_get(id, &uc); 11557be1825SJoseph Chen if (ret) 11657be1825SJoseph Chen continue; 11757be1825SJoseph Chen 11857be1825SJoseph Chen if (list_empty(&uc->dev_head)) 11957be1825SJoseph Chen continue; 12057be1825SJoseph Chen 12157be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 12257be1825SJoseph Chen /* Only U-Boot node go further */ 12357be1825SJoseph Chen if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 12457be1825SJoseph Chen !dev_read_bool(dev, "u-boot,dm-spl")) 12557be1825SJoseph Chen continue; 12657be1825SJoseph Chen 12757be1825SJoseph Chen for (i = 0; i < ARRAY_SIZE(props); i++) { 12857be1825SJoseph Chen if (!dev_read_prop(dev, props[i], &length)) 12957be1825SJoseph Chen continue; 13057be1825SJoseph Chen 13157be1825SJoseph Chen clocks = malloc(length); 13257be1825SJoseph Chen if (!clocks) 13357be1825SJoseph Chen return -ENOMEM; 13457be1825SJoseph Chen 13557be1825SJoseph Chen /* Read "props[]" which contains cru phandle */ 13657be1825SJoseph Chen nclocks = length / sizeof(u32); 13757be1825SJoseph Chen if (dev_read_u32_array(dev, props[i], 13857be1825SJoseph Chen clocks, nclocks)) { 13957be1825SJoseph Chen free(clocks); 14057be1825SJoseph Chen continue; 14157be1825SJoseph Chen } 14257be1825SJoseph Chen 14357be1825SJoseph Chen /* Fixup with kernel cru phandle */ 14457be1825SJoseph Chen for (j = 0; j < nclocks; j += (ncells + 1)) { 14557be1825SJoseph Chen /* 14657be1825SJoseph Chen * Check: update pmucru phandle with cru 14757be1825SJoseph Chen * phandle by mistake. 14857be1825SJoseph Chen */ 14957be1825SJoseph Chen if (first_phandle == -1) 15057be1825SJoseph Chen first_phandle = clocks[j]; 15157be1825SJoseph Chen 15257be1825SJoseph Chen if (clocks[j] != first_phandle) { 15357be1825SJoseph Chen debug("WARN: %s: first cru phandle=%d, this=%d\n", 15457be1825SJoseph Chen dev_read_name(dev), 15557be1825SJoseph Chen first_phandle, clocks[j]); 15657be1825SJoseph Chen continue; 15757be1825SJoseph Chen } 15857be1825SJoseph Chen 15957be1825SJoseph Chen clocks[j] = phandle; 16057be1825SJoseph Chen } 16157be1825SJoseph Chen 16257be1825SJoseph Chen /* 16357be1825SJoseph Chen * Override live dt nodes but not fdt nodes, 16457be1825SJoseph Chen * because all U-Boot nodes has been imported 16557be1825SJoseph Chen * to live dt nodes, should use "dev_xxx()". 16657be1825SJoseph Chen */ 16757be1825SJoseph Chen dev_write_u32_array(dev, props[i], 16857be1825SJoseph Chen clocks, nclocks); 16957be1825SJoseph Chen free(clocks); 17057be1825SJoseph Chen } 17157be1825SJoseph Chen } 17257be1825SJoseph Chen } 17357be1825SJoseph Chen 17457be1825SJoseph Chen return 0; 17557be1825SJoseph Chen } 17657be1825SJoseph Chen 17757be1825SJoseph Chen static int phandles_fixup_gpio(const void *fdt, void *ufdt) 17857be1825SJoseph Chen { 17957be1825SJoseph Chen struct udevice *dev; 18057be1825SJoseph Chen struct uclass *uc; 18157be1825SJoseph Chen const char *prop = "gpios"; 18257be1825SJoseph Chen const char *comp; 18357be1825SJoseph Chen char *gpio_name[10]; 18457be1825SJoseph Chen int gpio_off[10]; 18557be1825SJoseph Chen int pinctrl; 18657be1825SJoseph Chen int offset; 18757be1825SJoseph Chen int i = 0; 18857be1825SJoseph Chen int n = 0; 18957be1825SJoseph Chen 19057be1825SJoseph Chen pinctrl = fdt_path_offset(fdt, "/pinctrl"); 19157be1825SJoseph Chen if (pinctrl < 0) 19257be1825SJoseph Chen return 0; 19357be1825SJoseph Chen 19457be1825SJoseph Chen memset(gpio_name, 0, sizeof(gpio_name)); 19557be1825SJoseph Chen for (offset = fdt_first_subnode(fdt, pinctrl); 19657be1825SJoseph Chen offset >= 0; 19757be1825SJoseph Chen offset = fdt_next_subnode(fdt, offset)) { 19857be1825SJoseph Chen /* assume the font nodes are gpio node */ 19957be1825SJoseph Chen if (++i >= ARRAY_SIZE(gpio_name)) 20057be1825SJoseph Chen break; 20157be1825SJoseph Chen 20257be1825SJoseph Chen comp = fdt_getprop(fdt, offset, "compatible", NULL); 20357be1825SJoseph Chen if (!comp) 20457be1825SJoseph Chen continue; 20557be1825SJoseph Chen 20657be1825SJoseph Chen if (!strcmp(comp, "rockchip,gpio-bank")) { 20757be1825SJoseph Chen gpio_name[n] = (char *)fdt_get_name(fdt, offset, NULL); 20857be1825SJoseph Chen gpio_off[n] = offset; 20957be1825SJoseph Chen n++; 21057be1825SJoseph Chen } 21157be1825SJoseph Chen } 21257be1825SJoseph Chen 21357be1825SJoseph Chen if (!gpio_name[0]) 21457be1825SJoseph Chen return 0; 21557be1825SJoseph Chen 21657be1825SJoseph Chen if (uclass_get(UCLASS_KEY, &uc) || list_empty(&uc->dev_head)) 21757be1825SJoseph Chen return 0; 21857be1825SJoseph Chen 21957be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 22057be1825SJoseph Chen u32 new_phd, phd_old; 22157be1825SJoseph Chen char *name; 22257be1825SJoseph Chen ofnode ofn; 22357be1825SJoseph Chen 22457be1825SJoseph Chen if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 22557be1825SJoseph Chen !dev_read_bool(dev, "u-boot,dm-spl")) 22657be1825SJoseph Chen continue; 22757be1825SJoseph Chen 22857be1825SJoseph Chen if (dev_read_u32_array(dev, prop, &phd_old, 1)) 22957be1825SJoseph Chen continue; 23057be1825SJoseph Chen 23157be1825SJoseph Chen ofn = ofnode_get_by_phandle(phd_old); 23257be1825SJoseph Chen if (!ofnode_valid(ofn)) 23357be1825SJoseph Chen continue; 23457be1825SJoseph Chen 23557be1825SJoseph Chen name = (char *)ofnode_get_name(ofn); 23657be1825SJoseph Chen if (!name) 23757be1825SJoseph Chen continue; 23857be1825SJoseph Chen 2392a931879SJoseph Chen for (i = 0; i < ARRAY_SIZE(gpio_name); i++) { 24057be1825SJoseph Chen if (gpio_name[i] && !strcmp(name, gpio_name[i])) { 24157be1825SJoseph Chen new_phd = fdt_get_phandle(fdt, gpio_off[i]); 24257be1825SJoseph Chen dev_write_u32_array(dev, prop, &new_phd, 1); 24357be1825SJoseph Chen break; 24457be1825SJoseph Chen } 24557be1825SJoseph Chen } 24657be1825SJoseph Chen } 24757be1825SJoseph Chen 24857be1825SJoseph Chen return 0; 24957be1825SJoseph Chen } 25095eb462eSJoseph Chen #endif 25157be1825SJoseph Chen 25257be1825SJoseph Chen __weak int board_mmc_dm_reinit(struct udevice *dev) 25357be1825SJoseph Chen { 25457be1825SJoseph Chen return 0; 25557be1825SJoseph Chen } 25657be1825SJoseph Chen 25757be1825SJoseph Chen static int mmc_dm_reinit(void) 25857be1825SJoseph Chen { 25957be1825SJoseph Chen struct udevice *dev; 26057be1825SJoseph Chen struct uclass *uc; 26157be1825SJoseph Chen int ret; 26257be1825SJoseph Chen 26357be1825SJoseph Chen if (uclass_get(UCLASS_MMC, &uc) || list_empty(&uc->dev_head)) 26457be1825SJoseph Chen return 0; 26557be1825SJoseph Chen 26657be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 26757be1825SJoseph Chen ret = board_mmc_dm_reinit(dev); 26857be1825SJoseph Chen if (ret) 26957be1825SJoseph Chen return ret; 27057be1825SJoseph Chen } 27157be1825SJoseph Chen 27257be1825SJoseph Chen return 0; 27357be1825SJoseph Chen } 27457be1825SJoseph Chen 27574ec585eSJoseph Chen /* Check by property: "/compatible" */ 27674ec585eSJoseph Chen static int dtb_check_ok(void *kfdt, void *ufdt) 27720647277SJoseph Chen { 27820647277SJoseph Chen const char *compat; 27974ec585eSJoseph Chen int index; 28020647277SJoseph Chen 28184cb34e7SJoseph Chen /* TODO */ 28284cb34e7SJoseph Chen return 1; 28384cb34e7SJoseph Chen 28474ec585eSJoseph Chen for (index = 0; 28574ec585eSJoseph Chen compat = fdt_stringlist_get(ufdt, 0, "compatible", 28674ec585eSJoseph Chen index, NULL), compat; 28774ec585eSJoseph Chen index++) { 28874ec585eSJoseph Chen debug("u-compat: %s\n", compat); 28974ec585eSJoseph Chen if (!fdt_node_check_compatible(kfdt, 0, compat)) 2908f98eecbSJoseph Chen return 1; 29174ec585eSJoseph Chen } 29220647277SJoseph Chen 29320647277SJoseph Chen return 0; 29420647277SJoseph Chen } 29520647277SJoseph Chen 29657be1825SJoseph Chen int init_kernel_dtb(void) 29757be1825SJoseph Chen { 29895eb462eSJoseph Chen #ifndef CONFIG_USING_KERNEL_DTB_V2 29995eb462eSJoseph Chen void *ufdt_blob = (void *)gd->fdt_blob; 30095eb462eSJoseph Chen #endif 301a4fb9a7eSJoseph Chen ulong fdt_addr = 0; 30203781805SJoseph Chen int ret = -ENODEV; 30357be1825SJoseph Chen 30418b9d982SJoseph Chen printf("DM: v%d\n", IS_ENABLED(CONFIG_USING_KERNEL_DTB_V2) ? 2 : 1); 30518b9d982SJoseph Chen 306a4fb9a7eSJoseph Chen /* 307a4fb9a7eSJoseph Chen * If memory size <= 128MB, we firstly try to get "fdt_addr1_r". 308a4fb9a7eSJoseph Chen */ 309a4fb9a7eSJoseph Chen if (gd->ram_size <= SZ_128M) 310a4fb9a7eSJoseph Chen fdt_addr = env_get_ulong("fdt_addr1_r", 16, 0); 311a4fb9a7eSJoseph Chen 312a4fb9a7eSJoseph Chen if (!fdt_addr) 31357be1825SJoseph Chen fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 31457be1825SJoseph Chen if (!fdt_addr) { 31557be1825SJoseph Chen printf("No Found FDT Load Address.\n"); 31620647277SJoseph Chen return -ENODEV; 31757be1825SJoseph Chen } 31857be1825SJoseph Chen 31903781805SJoseph Chen if (IS_ENABLED(CONFIG_EMBED_KERNEL_DTB_ALWAYS)) { 32003781805SJoseph Chen printf("Always embed kernel dtb\n"); 32103781805SJoseph Chen goto dtb_embed; 32203781805SJoseph Chen } 32303781805SJoseph Chen 32457be1825SJoseph Chen ret = rockchip_read_dtb_file((void *)fdt_addr); 32520647277SJoseph Chen if (!ret) { 32620647277SJoseph Chen if (!dtb_check_ok((void *)fdt_addr, (void *)gd->fdt_blob)) { 32720647277SJoseph Chen ret = -EINVAL; 32820647277SJoseph Chen printf("Kernel dtb mismatch this platform!\n"); 32920647277SJoseph Chen } else { 33020647277SJoseph Chen goto dtb_okay; 33120647277SJoseph Chen } 33220647277SJoseph Chen } 33320647277SJoseph Chen 33403781805SJoseph Chen dtb_embed: 3353fc8bcd2SJoseph Chen if (gd->fdt_blob_kern) { 33620647277SJoseph Chen if (!dtb_check_ok((void *)gd->fdt_blob_kern, (void *)gd->fdt_blob)) { 33720647277SJoseph Chen printf("Embedded kernel dtb mismatch this platform!\n"); 33820647277SJoseph Chen return -EINVAL; 33920647277SJoseph Chen } 34020647277SJoseph Chen 34157be1825SJoseph Chen fdt_addr = (ulong)memalign(ARCH_DMA_MINALIGN, 34257be1825SJoseph Chen fdt_totalsize(gd->fdt_blob_kern)); 34357be1825SJoseph Chen if (!fdt_addr) 34457be1825SJoseph Chen return -ENOMEM; 34557be1825SJoseph Chen 34603781805SJoseph Chen /* 34703781805SJoseph Chen * Alloc another space for this embed kernel dtb. 34803781805SJoseph Chen * Because "fdt_addr_r" *MUST* be the fdt passed to kernel. 34903781805SJoseph Chen */ 35057be1825SJoseph Chen memcpy((void *)fdt_addr, gd->fdt_blob_kern, 35157be1825SJoseph Chen fdt_totalsize(gd->fdt_blob_kern)); 35203781805SJoseph Chen printf("DTB: %s\n", CONFIG_EMBED_KERNEL_DTB_PATH); 3537952efb8SJoseph Chen } else { 35457be1825SJoseph Chen printf("Failed to get kernel dtb, ret=%d\n", ret); 3557952efb8SJoseph Chen return -ENOENT; 35657be1825SJoseph Chen } 35757be1825SJoseph Chen 35820647277SJoseph Chen dtb_okay: 35957be1825SJoseph Chen gd->fdt_blob = (void *)fdt_addr; 36057be1825SJoseph Chen hotkey_run(HK_FDT); 36157be1825SJoseph Chen 36295eb462eSJoseph Chen #ifndef CONFIG_USING_KERNEL_DTB_V2 36357be1825SJoseph Chen /* 36457be1825SJoseph Chen * There is a phandle miss match between U-Boot and kernel dtb node, 36557be1825SJoseph Chen * we fixup it in U-Boot live dt nodes. 36657be1825SJoseph Chen * 36757be1825SJoseph Chen * CRU: all nodes. 36857be1825SJoseph Chen * GPIO: key nodes. 36957be1825SJoseph Chen */ 37057be1825SJoseph Chen phandles_fixup_cru((void *)gd->fdt_blob); 37157be1825SJoseph Chen phandles_fixup_gpio((void *)gd->fdt_blob, (void *)ufdt_blob); 37295eb462eSJoseph Chen #endif 37357be1825SJoseph Chen 374a85a3b31SJoseph Chen gd->flags |= GD_FLG_KDTB_READY; 375d276a5eaSJoseph Chen gd->of_root_f = gd->of_root; 37657be1825SJoseph Chen of_live_build((void *)gd->fdt_blob, (struct device_node **)&gd->of_root); 37757be1825SJoseph Chen dm_scan_fdt((void *)gd->fdt_blob, false); 37857be1825SJoseph Chen 37918b9d982SJoseph Chen #ifdef CONFIG_USING_KERNEL_DTB_V2 38018b9d982SJoseph Chen dm_rm_kernel_dev(); 38118b9d982SJoseph Chen dm_rm_u_boot_dev(); 38218b9d982SJoseph Chen #endif 38357be1825SJoseph Chen /* 38457be1825SJoseph Chen * There maybe something for the mmc devices to do after kernel dtb 38557be1825SJoseph Chen * dm setup, eg: regain the clock device binding from kernel dtb. 38657be1825SJoseph Chen */ 38757be1825SJoseph Chen mmc_dm_reinit(); 38857be1825SJoseph Chen 38957be1825SJoseph Chen /* Reserve 'reserved-memory' */ 39057be1825SJoseph Chen ret = boot_fdt_add_sysmem_rsv_regions((void *)gd->fdt_blob); 39157be1825SJoseph Chen if (ret) 39257be1825SJoseph Chen return ret; 39357be1825SJoseph Chen 39457be1825SJoseph Chen return 0; 39557be1825SJoseph Chen } 39695eb462eSJoseph Chen 397