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> 1157be1825SJoseph Chen #include <dm/root.h> 12*18b9d982SJoseph Chen #include <dm/uclass-internal.h> 1357be1825SJoseph Chen #include <asm/arch/hotkey.h> 1457be1825SJoseph Chen 1557be1825SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 1657be1825SJoseph Chen 17*18b9d982SJoseph Chen #ifdef CONFIG_USING_KERNEL_DTB_V2 18*18b9d982SJoseph Chen static int dm_rm_kernel_dev(void) 19*18b9d982SJoseph Chen { 20*18b9d982SJoseph Chen struct udevice *dev, *rec[10]; 21*18b9d982SJoseph Chen u32 uclass[] = { UCLASS_CRYPTO }; 22*18b9d982SJoseph Chen int i, j, k; 23*18b9d982SJoseph Chen 24*18b9d982SJoseph Chen for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) { 25*18b9d982SJoseph Chen for (uclass_find_first_device(uclass[i], &dev); dev; 26*18b9d982SJoseph Chen uclass_find_next_device(&dev)) { 27*18b9d982SJoseph Chen if (dev->flags & DM_FLAG_KNRL_DTB) 28*18b9d982SJoseph Chen rec[j++] = dev; 29*18b9d982SJoseph Chen } 30*18b9d982SJoseph Chen 31*18b9d982SJoseph Chen for (k = 0; k < j; k++) 32*18b9d982SJoseph Chen list_del_init(&rec[k]->uclass_node); 33*18b9d982SJoseph Chen } 34*18b9d982SJoseph Chen 35*18b9d982SJoseph Chen return 0; 36*18b9d982SJoseph Chen } 37*18b9d982SJoseph Chen 38*18b9d982SJoseph Chen static int dm_rm_u_boot_dev(void) 39*18b9d982SJoseph Chen { 40*18b9d982SJoseph Chen struct udevice *dev, *rec[10]; 41*18b9d982SJoseph Chen u32 uclass[] = { UCLASS_ETH }; 42*18b9d982SJoseph Chen int del = 0; 43*18b9d982SJoseph Chen int i, j, k; 44*18b9d982SJoseph Chen 45*18b9d982SJoseph Chen for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) { 46*18b9d982SJoseph Chen for (uclass_find_first_device(uclass[i], &dev); dev; 47*18b9d982SJoseph Chen uclass_find_next_device(&dev)) { 48*18b9d982SJoseph Chen if (dev->flags & DM_FLAG_KNRL_DTB) 49*18b9d982SJoseph Chen del = 1; 50*18b9d982SJoseph Chen else 51*18b9d982SJoseph Chen rec[j++] = dev; 52*18b9d982SJoseph Chen } 53*18b9d982SJoseph Chen 54*18b9d982SJoseph Chen /* remove u-boot dev if there is someone from kernel */ 55*18b9d982SJoseph Chen if (del) { 56*18b9d982SJoseph Chen for (k = 0; k < j; k++) 57*18b9d982SJoseph Chen list_del_init(&rec[k]->uclass_node); 58*18b9d982SJoseph Chen } 59*18b9d982SJoseph Chen } 60*18b9d982SJoseph Chen 61*18b9d982SJoseph Chen return 0; 62*18b9d982SJoseph Chen } 63*18b9d982SJoseph Chen 64*18b9d982SJoseph Chen #else 6557be1825SJoseph Chen /* Here, only fixup cru phandle, pmucru is not included */ 6657be1825SJoseph Chen static int phandles_fixup_cru(const void *fdt) 6757be1825SJoseph Chen { 684d85f76cSJoseph Chen const char *props[] = { "clocks", "assigned-clocks", "resets"}; 6957be1825SJoseph Chen struct udevice *dev; 7057be1825SJoseph Chen struct uclass *uc; 7157be1825SJoseph Chen const char *comp; 7257be1825SJoseph Chen u32 id, nclocks; 7357be1825SJoseph Chen u32 *clocks; 7457be1825SJoseph Chen int phandle, ncells; 7557be1825SJoseph Chen int off, offset; 7657be1825SJoseph Chen int ret, length; 7757be1825SJoseph Chen int i, j; 7857be1825SJoseph Chen int first_phandle = -1; 7957be1825SJoseph Chen 8057be1825SJoseph Chen phandle = -ENODATA; 8157be1825SJoseph Chen ncells = -ENODATA; 8257be1825SJoseph Chen 8357be1825SJoseph Chen /* fdt points to kernel dtb, getting cru phandle and "#clock-cells" */ 8457be1825SJoseph Chen for (offset = fdt_next_node(fdt, 0, NULL); 8557be1825SJoseph Chen offset >= 0; 8657be1825SJoseph Chen offset = fdt_next_node(fdt, offset, NULL)) { 8757be1825SJoseph Chen comp = fdt_getprop(fdt, offset, "compatible", NULL); 8857be1825SJoseph Chen if (!comp) 8957be1825SJoseph Chen continue; 9057be1825SJoseph Chen 9157be1825SJoseph Chen /* Actually, this is not a good method to get cru node */ 9257be1825SJoseph Chen off = strlen(comp) - strlen("-cru"); 9357be1825SJoseph Chen if (off > 0 && !strncmp(comp + off, "-cru", 4)) { 9457be1825SJoseph Chen phandle = fdt_get_phandle(fdt, offset); 9557be1825SJoseph Chen ncells = fdtdec_get_int(fdt, offset, 9657be1825SJoseph Chen "#clock-cells", -ENODATA); 9757be1825SJoseph Chen break; 9857be1825SJoseph Chen } 9957be1825SJoseph Chen } 10057be1825SJoseph Chen 10157be1825SJoseph Chen if (phandle == -ENODATA || ncells == -ENODATA) 10257be1825SJoseph Chen return 0; 10357be1825SJoseph Chen 10457be1825SJoseph Chen debug("%s: target cru: clock-cells:%d, phandle:0x%x\n", 10557be1825SJoseph Chen __func__, ncells, fdt32_to_cpu(phandle)); 10657be1825SJoseph Chen 10757be1825SJoseph Chen /* Try to fixup all cru phandle from U-Boot dtb nodes */ 10857be1825SJoseph Chen for (id = 0; id < UCLASS_COUNT; id++) { 10957be1825SJoseph Chen ret = uclass_get(id, &uc); 11057be1825SJoseph Chen if (ret) 11157be1825SJoseph Chen continue; 11257be1825SJoseph Chen 11357be1825SJoseph Chen if (list_empty(&uc->dev_head)) 11457be1825SJoseph Chen continue; 11557be1825SJoseph Chen 11657be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 11757be1825SJoseph Chen /* Only U-Boot node go further */ 11857be1825SJoseph Chen if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 11957be1825SJoseph Chen !dev_read_bool(dev, "u-boot,dm-spl")) 12057be1825SJoseph Chen continue; 12157be1825SJoseph Chen 12257be1825SJoseph Chen for (i = 0; i < ARRAY_SIZE(props); i++) { 12357be1825SJoseph Chen if (!dev_read_prop(dev, props[i], &length)) 12457be1825SJoseph Chen continue; 12557be1825SJoseph Chen 12657be1825SJoseph Chen clocks = malloc(length); 12757be1825SJoseph Chen if (!clocks) 12857be1825SJoseph Chen return -ENOMEM; 12957be1825SJoseph Chen 13057be1825SJoseph Chen /* Read "props[]" which contains cru phandle */ 13157be1825SJoseph Chen nclocks = length / sizeof(u32); 13257be1825SJoseph Chen if (dev_read_u32_array(dev, props[i], 13357be1825SJoseph Chen clocks, nclocks)) { 13457be1825SJoseph Chen free(clocks); 13557be1825SJoseph Chen continue; 13657be1825SJoseph Chen } 13757be1825SJoseph Chen 13857be1825SJoseph Chen /* Fixup with kernel cru phandle */ 13957be1825SJoseph Chen for (j = 0; j < nclocks; j += (ncells + 1)) { 14057be1825SJoseph Chen /* 14157be1825SJoseph Chen * Check: update pmucru phandle with cru 14257be1825SJoseph Chen * phandle by mistake. 14357be1825SJoseph Chen */ 14457be1825SJoseph Chen if (first_phandle == -1) 14557be1825SJoseph Chen first_phandle = clocks[j]; 14657be1825SJoseph Chen 14757be1825SJoseph Chen if (clocks[j] != first_phandle) { 14857be1825SJoseph Chen debug("WARN: %s: first cru phandle=%d, this=%d\n", 14957be1825SJoseph Chen dev_read_name(dev), 15057be1825SJoseph Chen first_phandle, clocks[j]); 15157be1825SJoseph Chen continue; 15257be1825SJoseph Chen } 15357be1825SJoseph Chen 15457be1825SJoseph Chen clocks[j] = phandle; 15557be1825SJoseph Chen } 15657be1825SJoseph Chen 15757be1825SJoseph Chen /* 15857be1825SJoseph Chen * Override live dt nodes but not fdt nodes, 15957be1825SJoseph Chen * because all U-Boot nodes has been imported 16057be1825SJoseph Chen * to live dt nodes, should use "dev_xxx()". 16157be1825SJoseph Chen */ 16257be1825SJoseph Chen dev_write_u32_array(dev, props[i], 16357be1825SJoseph Chen clocks, nclocks); 16457be1825SJoseph Chen free(clocks); 16557be1825SJoseph Chen } 16657be1825SJoseph Chen } 16757be1825SJoseph Chen } 16857be1825SJoseph Chen 16957be1825SJoseph Chen return 0; 17057be1825SJoseph Chen } 17157be1825SJoseph Chen 17257be1825SJoseph Chen static int phandles_fixup_gpio(const void *fdt, void *ufdt) 17357be1825SJoseph Chen { 17457be1825SJoseph Chen struct udevice *dev; 17557be1825SJoseph Chen struct uclass *uc; 17657be1825SJoseph Chen const char *prop = "gpios"; 17757be1825SJoseph Chen const char *comp; 17857be1825SJoseph Chen char *gpio_name[10]; 17957be1825SJoseph Chen int gpio_off[10]; 18057be1825SJoseph Chen int pinctrl; 18157be1825SJoseph Chen int offset; 18257be1825SJoseph Chen int i = 0; 18357be1825SJoseph Chen int n = 0; 18457be1825SJoseph Chen 18557be1825SJoseph Chen pinctrl = fdt_path_offset(fdt, "/pinctrl"); 18657be1825SJoseph Chen if (pinctrl < 0) 18757be1825SJoseph Chen return 0; 18857be1825SJoseph Chen 18957be1825SJoseph Chen memset(gpio_name, 0, sizeof(gpio_name)); 19057be1825SJoseph Chen for (offset = fdt_first_subnode(fdt, pinctrl); 19157be1825SJoseph Chen offset >= 0; 19257be1825SJoseph Chen offset = fdt_next_subnode(fdt, offset)) { 19357be1825SJoseph Chen /* assume the font nodes are gpio node */ 19457be1825SJoseph Chen if (++i >= ARRAY_SIZE(gpio_name)) 19557be1825SJoseph Chen break; 19657be1825SJoseph Chen 19757be1825SJoseph Chen comp = fdt_getprop(fdt, offset, "compatible", NULL); 19857be1825SJoseph Chen if (!comp) 19957be1825SJoseph Chen continue; 20057be1825SJoseph Chen 20157be1825SJoseph Chen if (!strcmp(comp, "rockchip,gpio-bank")) { 20257be1825SJoseph Chen gpio_name[n] = (char *)fdt_get_name(fdt, offset, NULL); 20357be1825SJoseph Chen gpio_off[n] = offset; 20457be1825SJoseph Chen n++; 20557be1825SJoseph Chen } 20657be1825SJoseph Chen } 20757be1825SJoseph Chen 20857be1825SJoseph Chen if (!gpio_name[0]) 20957be1825SJoseph Chen return 0; 21057be1825SJoseph Chen 21157be1825SJoseph Chen if (uclass_get(UCLASS_KEY, &uc) || list_empty(&uc->dev_head)) 21257be1825SJoseph Chen return 0; 21357be1825SJoseph Chen 21457be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 21557be1825SJoseph Chen u32 new_phd, phd_old; 21657be1825SJoseph Chen char *name; 21757be1825SJoseph Chen ofnode ofn; 21857be1825SJoseph Chen 21957be1825SJoseph Chen if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 22057be1825SJoseph Chen !dev_read_bool(dev, "u-boot,dm-spl")) 22157be1825SJoseph Chen continue; 22257be1825SJoseph Chen 22357be1825SJoseph Chen if (dev_read_u32_array(dev, prop, &phd_old, 1)) 22457be1825SJoseph Chen continue; 22557be1825SJoseph Chen 22657be1825SJoseph Chen ofn = ofnode_get_by_phandle(phd_old); 22757be1825SJoseph Chen if (!ofnode_valid(ofn)) 22857be1825SJoseph Chen continue; 22957be1825SJoseph Chen 23057be1825SJoseph Chen name = (char *)ofnode_get_name(ofn); 23157be1825SJoseph Chen if (!name) 23257be1825SJoseph Chen continue; 23357be1825SJoseph Chen 2342a931879SJoseph Chen for (i = 0; i < ARRAY_SIZE(gpio_name); i++) { 23557be1825SJoseph Chen if (gpio_name[i] && !strcmp(name, gpio_name[i])) { 23657be1825SJoseph Chen new_phd = fdt_get_phandle(fdt, gpio_off[i]); 23757be1825SJoseph Chen dev_write_u32_array(dev, prop, &new_phd, 1); 23857be1825SJoseph Chen break; 23957be1825SJoseph Chen } 24057be1825SJoseph Chen } 24157be1825SJoseph Chen } 24257be1825SJoseph Chen 24357be1825SJoseph Chen return 0; 24457be1825SJoseph Chen } 24595eb462eSJoseph Chen #endif 24657be1825SJoseph Chen 24757be1825SJoseph Chen __weak int board_mmc_dm_reinit(struct udevice *dev) 24857be1825SJoseph Chen { 24957be1825SJoseph Chen return 0; 25057be1825SJoseph Chen } 25157be1825SJoseph Chen 25257be1825SJoseph Chen static int mmc_dm_reinit(void) 25357be1825SJoseph Chen { 25457be1825SJoseph Chen struct udevice *dev; 25557be1825SJoseph Chen struct uclass *uc; 25657be1825SJoseph Chen int ret; 25757be1825SJoseph Chen 25857be1825SJoseph Chen if (uclass_get(UCLASS_MMC, &uc) || list_empty(&uc->dev_head)) 25957be1825SJoseph Chen return 0; 26057be1825SJoseph Chen 26157be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 26257be1825SJoseph Chen ret = board_mmc_dm_reinit(dev); 26357be1825SJoseph Chen if (ret) 26457be1825SJoseph Chen return ret; 26557be1825SJoseph Chen } 26657be1825SJoseph Chen 26757be1825SJoseph Chen return 0; 26857be1825SJoseph Chen } 26957be1825SJoseph Chen 27074ec585eSJoseph Chen /* Check by property: "/compatible" */ 27174ec585eSJoseph Chen static int dtb_check_ok(void *kfdt, void *ufdt) 27220647277SJoseph Chen { 27320647277SJoseph Chen const char *compat; 27474ec585eSJoseph Chen int index; 27520647277SJoseph Chen 27684cb34e7SJoseph Chen /* TODO */ 27784cb34e7SJoseph Chen return 1; 27884cb34e7SJoseph Chen 27974ec585eSJoseph Chen for (index = 0; 28074ec585eSJoseph Chen compat = fdt_stringlist_get(ufdt, 0, "compatible", 28174ec585eSJoseph Chen index, NULL), compat; 28274ec585eSJoseph Chen index++) { 28374ec585eSJoseph Chen debug("u-compat: %s\n", compat); 28474ec585eSJoseph Chen if (!fdt_node_check_compatible(kfdt, 0, compat)) 2858f98eecbSJoseph Chen return 1; 28674ec585eSJoseph Chen } 28720647277SJoseph Chen 28820647277SJoseph Chen return 0; 28920647277SJoseph Chen } 29020647277SJoseph Chen 29157be1825SJoseph Chen int init_kernel_dtb(void) 29257be1825SJoseph Chen { 29395eb462eSJoseph Chen #ifndef CONFIG_USING_KERNEL_DTB_V2 29495eb462eSJoseph Chen void *ufdt_blob = (void *)gd->fdt_blob; 29595eb462eSJoseph Chen #endif 296a4fb9a7eSJoseph Chen ulong fdt_addr = 0; 29703781805SJoseph Chen int ret = -ENODEV; 29857be1825SJoseph Chen 299*18b9d982SJoseph Chen printf("DM: v%d\n", IS_ENABLED(CONFIG_USING_KERNEL_DTB_V2) ? 2 : 1); 300*18b9d982SJoseph Chen 301a4fb9a7eSJoseph Chen /* 302a4fb9a7eSJoseph Chen * If memory size <= 128MB, we firstly try to get "fdt_addr1_r". 303a4fb9a7eSJoseph Chen */ 304a4fb9a7eSJoseph Chen if (gd->ram_size <= SZ_128M) 305a4fb9a7eSJoseph Chen fdt_addr = env_get_ulong("fdt_addr1_r", 16, 0); 306a4fb9a7eSJoseph Chen 307a4fb9a7eSJoseph Chen if (!fdt_addr) 30857be1825SJoseph Chen fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 30957be1825SJoseph Chen if (!fdt_addr) { 31057be1825SJoseph Chen printf("No Found FDT Load Address.\n"); 31120647277SJoseph Chen return -ENODEV; 31257be1825SJoseph Chen } 31357be1825SJoseph Chen 31403781805SJoseph Chen if (IS_ENABLED(CONFIG_EMBED_KERNEL_DTB_ALWAYS)) { 31503781805SJoseph Chen printf("Always embed kernel dtb\n"); 31603781805SJoseph Chen goto dtb_embed; 31703781805SJoseph Chen } 31803781805SJoseph Chen 31957be1825SJoseph Chen ret = rockchip_read_dtb_file((void *)fdt_addr); 32020647277SJoseph Chen if (!ret) { 32120647277SJoseph Chen if (!dtb_check_ok((void *)fdt_addr, (void *)gd->fdt_blob)) { 32220647277SJoseph Chen ret = -EINVAL; 32320647277SJoseph Chen printf("Kernel dtb mismatch this platform!\n"); 32420647277SJoseph Chen } else { 32520647277SJoseph Chen goto dtb_okay; 32620647277SJoseph Chen } 32720647277SJoseph Chen } 32820647277SJoseph Chen 32903781805SJoseph Chen dtb_embed: 3303fc8bcd2SJoseph Chen if (gd->fdt_blob_kern) { 33120647277SJoseph Chen if (!dtb_check_ok((void *)gd->fdt_blob_kern, (void *)gd->fdt_blob)) { 33220647277SJoseph Chen printf("Embedded kernel dtb mismatch this platform!\n"); 33320647277SJoseph Chen return -EINVAL; 33420647277SJoseph Chen } 33520647277SJoseph Chen 33657be1825SJoseph Chen fdt_addr = (ulong)memalign(ARCH_DMA_MINALIGN, 33757be1825SJoseph Chen fdt_totalsize(gd->fdt_blob_kern)); 33857be1825SJoseph Chen if (!fdt_addr) 33957be1825SJoseph Chen return -ENOMEM; 34057be1825SJoseph Chen 34103781805SJoseph Chen /* 34203781805SJoseph Chen * Alloc another space for this embed kernel dtb. 34303781805SJoseph Chen * Because "fdt_addr_r" *MUST* be the fdt passed to kernel. 34403781805SJoseph Chen */ 34557be1825SJoseph Chen memcpy((void *)fdt_addr, gd->fdt_blob_kern, 34657be1825SJoseph Chen fdt_totalsize(gd->fdt_blob_kern)); 34703781805SJoseph Chen printf("DTB: %s\n", CONFIG_EMBED_KERNEL_DTB_PATH); 3487952efb8SJoseph Chen } else { 34957be1825SJoseph Chen printf("Failed to get kernel dtb, ret=%d\n", ret); 3507952efb8SJoseph Chen return -ENOENT; 35157be1825SJoseph Chen } 35257be1825SJoseph Chen 35320647277SJoseph Chen dtb_okay: 35457be1825SJoseph Chen gd->fdt_blob = (void *)fdt_addr; 35557be1825SJoseph Chen hotkey_run(HK_FDT); 35657be1825SJoseph Chen 35795eb462eSJoseph Chen #ifndef CONFIG_USING_KERNEL_DTB_V2 35857be1825SJoseph Chen /* 35957be1825SJoseph Chen * There is a phandle miss match between U-Boot and kernel dtb node, 36057be1825SJoseph Chen * we fixup it in U-Boot live dt nodes. 36157be1825SJoseph Chen * 36257be1825SJoseph Chen * CRU: all nodes. 36357be1825SJoseph Chen * GPIO: key nodes. 36457be1825SJoseph Chen */ 36557be1825SJoseph Chen phandles_fixup_cru((void *)gd->fdt_blob); 36657be1825SJoseph Chen phandles_fixup_gpio((void *)gd->fdt_blob, (void *)ufdt_blob); 36795eb462eSJoseph Chen #endif 36857be1825SJoseph Chen 369a85a3b31SJoseph Chen gd->flags |= GD_FLG_KDTB_READY; 370d276a5eaSJoseph Chen gd->of_root_f = gd->of_root; 37157be1825SJoseph Chen of_live_build((void *)gd->fdt_blob, (struct device_node **)&gd->of_root); 37257be1825SJoseph Chen dm_scan_fdt((void *)gd->fdt_blob, false); 37357be1825SJoseph Chen 374*18b9d982SJoseph Chen #ifdef CONFIG_USING_KERNEL_DTB_V2 375*18b9d982SJoseph Chen dm_rm_kernel_dev(); 376*18b9d982SJoseph Chen dm_rm_u_boot_dev(); 377*18b9d982SJoseph Chen #endif 37857be1825SJoseph Chen /* 37957be1825SJoseph Chen * There maybe something for the mmc devices to do after kernel dtb 38057be1825SJoseph Chen * dm setup, eg: regain the clock device binding from kernel dtb. 38157be1825SJoseph Chen */ 38257be1825SJoseph Chen mmc_dm_reinit(); 38357be1825SJoseph Chen 38457be1825SJoseph Chen /* Reserve 'reserved-memory' */ 38557be1825SJoseph Chen ret = boot_fdt_add_sysmem_rsv_regions((void *)gd->fdt_blob); 38657be1825SJoseph Chen if (ret) 38757be1825SJoseph Chen return ret; 38857be1825SJoseph Chen 38957be1825SJoseph Chen return 0; 39057be1825SJoseph Chen } 39195eb462eSJoseph Chen 392