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> 1257be1825SJoseph Chen #include <asm/arch/hotkey.h> 1357be1825SJoseph Chen 1457be1825SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 1557be1825SJoseph Chen 1657be1825SJoseph Chen /* Here, only fixup cru phandle, pmucru is not included */ 1757be1825SJoseph Chen static int phandles_fixup_cru(const void *fdt) 1857be1825SJoseph Chen { 194d85f76cSJoseph Chen const char *props[] = { "clocks", "assigned-clocks", "resets"}; 2057be1825SJoseph Chen struct udevice *dev; 2157be1825SJoseph Chen struct uclass *uc; 2257be1825SJoseph Chen const char *comp; 2357be1825SJoseph Chen u32 id, nclocks; 2457be1825SJoseph Chen u32 *clocks; 2557be1825SJoseph Chen int phandle, ncells; 2657be1825SJoseph Chen int off, offset; 2757be1825SJoseph Chen int ret, length; 2857be1825SJoseph Chen int i, j; 2957be1825SJoseph Chen int first_phandle = -1; 3057be1825SJoseph Chen 3157be1825SJoseph Chen phandle = -ENODATA; 3257be1825SJoseph Chen ncells = -ENODATA; 3357be1825SJoseph Chen 3457be1825SJoseph Chen /* fdt points to kernel dtb, getting cru phandle and "#clock-cells" */ 3557be1825SJoseph Chen for (offset = fdt_next_node(fdt, 0, NULL); 3657be1825SJoseph Chen offset >= 0; 3757be1825SJoseph Chen offset = fdt_next_node(fdt, offset, NULL)) { 3857be1825SJoseph Chen comp = fdt_getprop(fdt, offset, "compatible", NULL); 3957be1825SJoseph Chen if (!comp) 4057be1825SJoseph Chen continue; 4157be1825SJoseph Chen 4257be1825SJoseph Chen /* Actually, this is not a good method to get cru node */ 4357be1825SJoseph Chen off = strlen(comp) - strlen("-cru"); 4457be1825SJoseph Chen if (off > 0 && !strncmp(comp + off, "-cru", 4)) { 4557be1825SJoseph Chen phandle = fdt_get_phandle(fdt, offset); 4657be1825SJoseph Chen ncells = fdtdec_get_int(fdt, offset, 4757be1825SJoseph Chen "#clock-cells", -ENODATA); 4857be1825SJoseph Chen break; 4957be1825SJoseph Chen } 5057be1825SJoseph Chen } 5157be1825SJoseph Chen 5257be1825SJoseph Chen if (phandle == -ENODATA || ncells == -ENODATA) 5357be1825SJoseph Chen return 0; 5457be1825SJoseph Chen 5557be1825SJoseph Chen debug("%s: target cru: clock-cells:%d, phandle:0x%x\n", 5657be1825SJoseph Chen __func__, ncells, fdt32_to_cpu(phandle)); 5757be1825SJoseph Chen 5857be1825SJoseph Chen /* Try to fixup all cru phandle from U-Boot dtb nodes */ 5957be1825SJoseph Chen for (id = 0; id < UCLASS_COUNT; id++) { 6057be1825SJoseph Chen ret = uclass_get(id, &uc); 6157be1825SJoseph Chen if (ret) 6257be1825SJoseph Chen continue; 6357be1825SJoseph Chen 6457be1825SJoseph Chen if (list_empty(&uc->dev_head)) 6557be1825SJoseph Chen continue; 6657be1825SJoseph Chen 6757be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 6857be1825SJoseph Chen /* Only U-Boot node go further */ 6957be1825SJoseph Chen if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 7057be1825SJoseph Chen !dev_read_bool(dev, "u-boot,dm-spl")) 7157be1825SJoseph Chen continue; 7257be1825SJoseph Chen 7357be1825SJoseph Chen for (i = 0; i < ARRAY_SIZE(props); i++) { 7457be1825SJoseph Chen if (!dev_read_prop(dev, props[i], &length)) 7557be1825SJoseph Chen continue; 7657be1825SJoseph Chen 7757be1825SJoseph Chen clocks = malloc(length); 7857be1825SJoseph Chen if (!clocks) 7957be1825SJoseph Chen return -ENOMEM; 8057be1825SJoseph Chen 8157be1825SJoseph Chen /* Read "props[]" which contains cru phandle */ 8257be1825SJoseph Chen nclocks = length / sizeof(u32); 8357be1825SJoseph Chen if (dev_read_u32_array(dev, props[i], 8457be1825SJoseph Chen clocks, nclocks)) { 8557be1825SJoseph Chen free(clocks); 8657be1825SJoseph Chen continue; 8757be1825SJoseph Chen } 8857be1825SJoseph Chen 8957be1825SJoseph Chen /* Fixup with kernel cru phandle */ 9057be1825SJoseph Chen for (j = 0; j < nclocks; j += (ncells + 1)) { 9157be1825SJoseph Chen /* 9257be1825SJoseph Chen * Check: update pmucru phandle with cru 9357be1825SJoseph Chen * phandle by mistake. 9457be1825SJoseph Chen */ 9557be1825SJoseph Chen if (first_phandle == -1) 9657be1825SJoseph Chen first_phandle = clocks[j]; 9757be1825SJoseph Chen 9857be1825SJoseph Chen if (clocks[j] != first_phandle) { 9957be1825SJoseph Chen debug("WARN: %s: first cru phandle=%d, this=%d\n", 10057be1825SJoseph Chen dev_read_name(dev), 10157be1825SJoseph Chen first_phandle, clocks[j]); 10257be1825SJoseph Chen continue; 10357be1825SJoseph Chen } 10457be1825SJoseph Chen 10557be1825SJoseph Chen clocks[j] = phandle; 10657be1825SJoseph Chen } 10757be1825SJoseph Chen 10857be1825SJoseph Chen /* 10957be1825SJoseph Chen * Override live dt nodes but not fdt nodes, 11057be1825SJoseph Chen * because all U-Boot nodes has been imported 11157be1825SJoseph Chen * to live dt nodes, should use "dev_xxx()". 11257be1825SJoseph Chen */ 11357be1825SJoseph Chen dev_write_u32_array(dev, props[i], 11457be1825SJoseph Chen clocks, nclocks); 11557be1825SJoseph Chen free(clocks); 11657be1825SJoseph Chen } 11757be1825SJoseph Chen } 11857be1825SJoseph Chen } 11957be1825SJoseph Chen 12057be1825SJoseph Chen return 0; 12157be1825SJoseph Chen } 12257be1825SJoseph Chen 12357be1825SJoseph Chen static int phandles_fixup_gpio(const void *fdt, void *ufdt) 12457be1825SJoseph Chen { 12557be1825SJoseph Chen struct udevice *dev; 12657be1825SJoseph Chen struct uclass *uc; 12757be1825SJoseph Chen const char *prop = "gpios"; 12857be1825SJoseph Chen const char *comp; 12957be1825SJoseph Chen char *gpio_name[10]; 13057be1825SJoseph Chen int gpio_off[10]; 13157be1825SJoseph Chen int pinctrl; 13257be1825SJoseph Chen int offset; 13357be1825SJoseph Chen int i = 0; 13457be1825SJoseph Chen int n = 0; 13557be1825SJoseph Chen 13657be1825SJoseph Chen pinctrl = fdt_path_offset(fdt, "/pinctrl"); 13757be1825SJoseph Chen if (pinctrl < 0) 13857be1825SJoseph Chen return 0; 13957be1825SJoseph Chen 14057be1825SJoseph Chen memset(gpio_name, 0, sizeof(gpio_name)); 14157be1825SJoseph Chen for (offset = fdt_first_subnode(fdt, pinctrl); 14257be1825SJoseph Chen offset >= 0; 14357be1825SJoseph Chen offset = fdt_next_subnode(fdt, offset)) { 14457be1825SJoseph Chen /* assume the font nodes are gpio node */ 14557be1825SJoseph Chen if (++i >= ARRAY_SIZE(gpio_name)) 14657be1825SJoseph Chen break; 14757be1825SJoseph Chen 14857be1825SJoseph Chen comp = fdt_getprop(fdt, offset, "compatible", NULL); 14957be1825SJoseph Chen if (!comp) 15057be1825SJoseph Chen continue; 15157be1825SJoseph Chen 15257be1825SJoseph Chen if (!strcmp(comp, "rockchip,gpio-bank")) { 15357be1825SJoseph Chen gpio_name[n] = (char *)fdt_get_name(fdt, offset, NULL); 15457be1825SJoseph Chen gpio_off[n] = offset; 15557be1825SJoseph Chen n++; 15657be1825SJoseph Chen } 15757be1825SJoseph Chen } 15857be1825SJoseph Chen 15957be1825SJoseph Chen if (!gpio_name[0]) 16057be1825SJoseph Chen return 0; 16157be1825SJoseph Chen 16257be1825SJoseph Chen if (uclass_get(UCLASS_KEY, &uc) || list_empty(&uc->dev_head)) 16357be1825SJoseph Chen return 0; 16457be1825SJoseph Chen 16557be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 16657be1825SJoseph Chen u32 new_phd, phd_old; 16757be1825SJoseph Chen char *name; 16857be1825SJoseph Chen ofnode ofn; 16957be1825SJoseph Chen 17057be1825SJoseph Chen if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") && 17157be1825SJoseph Chen !dev_read_bool(dev, "u-boot,dm-spl")) 17257be1825SJoseph Chen continue; 17357be1825SJoseph Chen 17457be1825SJoseph Chen if (dev_read_u32_array(dev, prop, &phd_old, 1)) 17557be1825SJoseph Chen continue; 17657be1825SJoseph Chen 17757be1825SJoseph Chen ofn = ofnode_get_by_phandle(phd_old); 17857be1825SJoseph Chen if (!ofnode_valid(ofn)) 17957be1825SJoseph Chen continue; 18057be1825SJoseph Chen 18157be1825SJoseph Chen name = (char *)ofnode_get_name(ofn); 18257be1825SJoseph Chen if (!name) 18357be1825SJoseph Chen continue; 18457be1825SJoseph Chen 1852a931879SJoseph Chen for (i = 0; i < ARRAY_SIZE(gpio_name); i++) { 18657be1825SJoseph Chen if (gpio_name[i] && !strcmp(name, gpio_name[i])) { 18757be1825SJoseph Chen new_phd = fdt_get_phandle(fdt, gpio_off[i]); 18857be1825SJoseph Chen dev_write_u32_array(dev, prop, &new_phd, 1); 18957be1825SJoseph Chen break; 19057be1825SJoseph Chen } 19157be1825SJoseph Chen } 19257be1825SJoseph Chen } 19357be1825SJoseph Chen 19457be1825SJoseph Chen return 0; 19557be1825SJoseph Chen } 19657be1825SJoseph Chen 19757be1825SJoseph Chen __weak int board_mmc_dm_reinit(struct udevice *dev) 19857be1825SJoseph Chen { 19957be1825SJoseph Chen return 0; 20057be1825SJoseph Chen } 20157be1825SJoseph Chen 20257be1825SJoseph Chen static int mmc_dm_reinit(void) 20357be1825SJoseph Chen { 20457be1825SJoseph Chen struct udevice *dev; 20557be1825SJoseph Chen struct uclass *uc; 20657be1825SJoseph Chen int ret; 20757be1825SJoseph Chen 20857be1825SJoseph Chen if (uclass_get(UCLASS_MMC, &uc) || list_empty(&uc->dev_head)) 20957be1825SJoseph Chen return 0; 21057be1825SJoseph Chen 21157be1825SJoseph Chen list_for_each_entry(dev, &uc->dev_head, uclass_node) { 21257be1825SJoseph Chen ret = board_mmc_dm_reinit(dev); 21357be1825SJoseph Chen if (ret) 21457be1825SJoseph Chen return ret; 21557be1825SJoseph Chen } 21657be1825SJoseph Chen 21757be1825SJoseph Chen return 0; 21857be1825SJoseph Chen } 21957be1825SJoseph Chen 22020647277SJoseph Chen /* 22120647277SJoseph Chen * Simply check cru node: 22220647277SJoseph Chen * This kernel dtb is belong to current platform ? 22320647277SJoseph Chen */ 22420647277SJoseph Chen static int dtb_check_ok(void *fdt, void *ufdt) 22520647277SJoseph Chen { 22620647277SJoseph Chen const char *compare[2] = { NULL, NULL, }; 22720647277SJoseph Chen const char *compat; 22820647277SJoseph Chen void *blob = fdt; 22920647277SJoseph Chen int offset; 23020647277SJoseph Chen int i; 23120647277SJoseph Chen 23220647277SJoseph Chen for (i = 0; i < 2; i++) { 23320647277SJoseph Chen for (offset = fdt_next_node(blob, 0, NULL); 23420647277SJoseph Chen offset >= 0; 23520647277SJoseph Chen offset = fdt_next_node(blob, offset, NULL)) { 23620647277SJoseph Chen compat = fdt_getprop(blob, offset, "compatible", NULL); 23720647277SJoseph Chen if (!compat) 23820647277SJoseph Chen continue; 23920647277SJoseph Chen debug("[%d] compat: %s\n", i, compat); 24020647277SJoseph Chen if (strstr(compat, "-cru")) { 24120647277SJoseph Chen compare[i] = compat; 24220647277SJoseph Chen blob = ufdt; 24320647277SJoseph Chen break; 24420647277SJoseph Chen } 24520647277SJoseph Chen } 24620647277SJoseph Chen } 24720647277SJoseph Chen 2488f98eecbSJoseph Chen if (!compare[0]) 2498f98eecbSJoseph Chen return 1; 2508f98eecbSJoseph Chen 25120647277SJoseph Chen if (compare[0] && compare[1]) 25220647277SJoseph Chen return !memcmp(compare[0], compare[1], strlen(compare[0])); 25320647277SJoseph Chen 25420647277SJoseph Chen return 0; 25520647277SJoseph Chen } 25620647277SJoseph Chen 25757be1825SJoseph Chen int init_kernel_dtb(void) 25857be1825SJoseph Chen { 259*a4fb9a7eSJoseph Chen ulong fdt_addr = 0; 26057be1825SJoseph Chen void *ufdt_blob; 26103781805SJoseph Chen int ret = -ENODEV; 26257be1825SJoseph Chen 263*a4fb9a7eSJoseph Chen /* 264*a4fb9a7eSJoseph Chen * If memory size <= 128MB, we firstly try to get "fdt_addr1_r". 265*a4fb9a7eSJoseph Chen */ 266*a4fb9a7eSJoseph Chen if (gd->ram_size <= SZ_128M) 267*a4fb9a7eSJoseph Chen fdt_addr = env_get_ulong("fdt_addr1_r", 16, 0); 268*a4fb9a7eSJoseph Chen 269*a4fb9a7eSJoseph Chen if (!fdt_addr) 27057be1825SJoseph Chen fdt_addr = env_get_ulong("fdt_addr_r", 16, 0); 27157be1825SJoseph Chen if (!fdt_addr) { 27257be1825SJoseph Chen printf("No Found FDT Load Address.\n"); 27320647277SJoseph Chen return -ENODEV; 27457be1825SJoseph Chen } 27557be1825SJoseph Chen 27603781805SJoseph Chen if (IS_ENABLED(CONFIG_EMBED_KERNEL_DTB_ALWAYS)) { 27703781805SJoseph Chen printf("Always embed kernel dtb\n"); 27803781805SJoseph Chen goto dtb_embed; 27903781805SJoseph Chen } 28003781805SJoseph Chen 28157be1825SJoseph Chen ret = rockchip_read_dtb_file((void *)fdt_addr); 28220647277SJoseph Chen if (!ret) { 28320647277SJoseph Chen if (!dtb_check_ok((void *)fdt_addr, (void *)gd->fdt_blob)) { 28420647277SJoseph Chen ret = -EINVAL; 28520647277SJoseph Chen printf("Kernel dtb mismatch this platform!\n"); 28620647277SJoseph Chen } else { 28720647277SJoseph Chen goto dtb_okay; 28820647277SJoseph Chen } 28920647277SJoseph Chen } 29020647277SJoseph Chen 29103781805SJoseph Chen dtb_embed: 2923fc8bcd2SJoseph Chen if (gd->fdt_blob_kern) { 29320647277SJoseph Chen if (!dtb_check_ok((void *)gd->fdt_blob_kern, (void *)gd->fdt_blob)) { 29420647277SJoseph Chen printf("Embedded kernel dtb mismatch this platform!\n"); 29520647277SJoseph Chen return -EINVAL; 29620647277SJoseph Chen } 29720647277SJoseph Chen 29857be1825SJoseph Chen fdt_addr = (ulong)memalign(ARCH_DMA_MINALIGN, 29957be1825SJoseph Chen fdt_totalsize(gd->fdt_blob_kern)); 30057be1825SJoseph Chen if (!fdt_addr) 30157be1825SJoseph Chen return -ENOMEM; 30257be1825SJoseph Chen 30303781805SJoseph Chen /* 30403781805SJoseph Chen * Alloc another space for this embed kernel dtb. 30503781805SJoseph Chen * Because "fdt_addr_r" *MUST* be the fdt passed to kernel. 30603781805SJoseph Chen */ 30757be1825SJoseph Chen memcpy((void *)fdt_addr, gd->fdt_blob_kern, 30857be1825SJoseph Chen fdt_totalsize(gd->fdt_blob_kern)); 30903781805SJoseph Chen printf("DTB: %s\n", CONFIG_EMBED_KERNEL_DTB_PATH); 31003781805SJoseph Chen } 31103781805SJoseph Chen 31203781805SJoseph Chen if (fdt_check_header((void *)fdt_addr)) { 31357be1825SJoseph Chen printf("Failed to get kernel dtb, ret=%d\n", ret); 31457be1825SJoseph Chen return ret; 31557be1825SJoseph Chen } 31657be1825SJoseph Chen 31720647277SJoseph Chen dtb_okay: 31857be1825SJoseph Chen ufdt_blob = (void *)gd->fdt_blob; 31957be1825SJoseph Chen gd->fdt_blob = (void *)fdt_addr; 32057be1825SJoseph Chen 32157be1825SJoseph Chen hotkey_run(HK_FDT); 32257be1825SJoseph Chen 32357be1825SJoseph Chen /* 32457be1825SJoseph Chen * There is a phandle miss match between U-Boot and kernel dtb node, 32557be1825SJoseph Chen * we fixup it in U-Boot live dt nodes. 32657be1825SJoseph Chen * 32757be1825SJoseph Chen * CRU: all nodes. 32857be1825SJoseph Chen * GPIO: key nodes. 32957be1825SJoseph Chen */ 33057be1825SJoseph Chen phandles_fixup_cru((void *)gd->fdt_blob); 33157be1825SJoseph Chen phandles_fixup_gpio((void *)gd->fdt_blob, (void *)ufdt_blob); 33257be1825SJoseph Chen 333a85a3b31SJoseph Chen gd->flags |= GD_FLG_KDTB_READY; 33457be1825SJoseph Chen of_live_build((void *)gd->fdt_blob, (struct device_node **)&gd->of_root); 33557be1825SJoseph Chen dm_scan_fdt((void *)gd->fdt_blob, false); 33657be1825SJoseph Chen 33757be1825SJoseph Chen /* 33857be1825SJoseph Chen * There maybe something for the mmc devices to do after kernel dtb 33957be1825SJoseph Chen * dm setup, eg: regain the clock device binding from kernel dtb. 34057be1825SJoseph Chen */ 34157be1825SJoseph Chen mmc_dm_reinit(); 34257be1825SJoseph Chen 34357be1825SJoseph Chen /* Reserve 'reserved-memory' */ 34457be1825SJoseph Chen ret = boot_fdt_add_sysmem_rsv_regions((void *)gd->fdt_blob); 34557be1825SJoseph Chen if (ret) 34657be1825SJoseph Chen return ret; 34757be1825SJoseph Chen 34857be1825SJoseph Chen return 0; 34957be1825SJoseph Chen } 350