arm64 device tree加载过程

代码平台Android7.1.2 硬件RK3288 ROC-RK3288-CC
Android7.1.2/ROC-RK3328-CC_Android7.1.2_git_20171204/kernel/arch/arm64/mach-rockchip

dts文件为板级设备描述文件,被编译后为dtb,由bootloader读入,并作为参数传递给linux kernel,入口地址为__fdt_pointer,定义在汇编文件head.S (arch\arm64\kernel)中

/ / arch/arm64/kernel/head.S

__switch_data:
.quad __mmap_switched
.quad __bss_start // x6
.quad __bss_stop // x7
.quad processor_id // x4
.quad __fdt_pointer // x5
.quad memstart_addr // x6
.quad init_thread_union + THREAD_START_SP // sp

ENTRY(stext)
mov x21, x0 // x21=FDT //FDT代表设备树
bl el2_setup // Drop to EL1, w20=cpu_boot_mode
bl __calc_phys_offset // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
bl set_cpu_boot_mode_flag
mrs x22, midr_el1 // x22=cpuid
mov x0, x22
bl lookup_processor_type
mov x23, x0 // x23=current cpu_table
cbz x23, __error_p // invalid processor (x23=0)?
bl __vet_fdt // 检查device tree的合法性
bl __create_page_tables // x25=TTBR0, x26=TTBR1
/*
* The following calls CPU specific code in a position independent
* manner. See arch/arm64/mm/proc.S for details. x23 = base of
* cpu_info structure selected by lookup_processor_type above.
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
ldr x27, __switch_data // address to jump to after
// MMU has been enabled
adr lr, __enable_mmu // return (PIC) address
ldr x12, [x23, #CPU_INFO_SETUP]
add x12, x12, x28 // __virt_to_phys
br x12 // initialise processor
ENDPROC(stext)

/ / arch/arm64/kernel/head.S

  • Determine validity of the x21 FDT pointer.
  • The dtb must be 8-byte aligned and live in the first 512M of memory.
    */
    __vet_fdt: // 检查device tree的合法性
    tst x21, #0x7 // 是否字节对齐
    b.ne 1f // 不对齐直接跳转到标号1处,将x21清0,并返回
    cmp x21, x24 // x21保存的是device tree的物理地址,x24保存的是kernel起始的物理内存地址
    b.lt 1f // 当device tree的物理地址小于kernel起始的物理地址时,直接跳转到标号1处,将x21清0,并返回
    mov x0, #(1 << 29) // x0 = 0x40000000 = 512M
    add x0, x0, x24 // 判断device tree的物理地址是否在kernel起始的512M内存空间内部
    cmp x21, x0
    b.ge 1f
    ret
    1:
    mov x21, #0
    ret
    ENDPROC(__vet_fdt)

/ / arch/arm64/kernel/head.S

/*

  • Setup the initial page tables. We only setup the barest amount which is
  • required to get the kernel running. The following sections are required:
    • identity mapping to enable the MMU (low address, TTBR0)
    • first few MB of the kernel linear mapping to jump to once the MMU has
  • been enabled, including the FDT blob (TTBR1)
    
    • pgd entry for fixed mappings (TTBR1)
      */
      __create_page_tables:
      pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses
      mov x27, lr
/*
 * Invalidate the idmap and swapper page tables to avoid potential
 * dirty cache lines being evicted.
 */
mov    x0, x25
add    x1, x26, #SWAPPER_DIR_SIZE
bl    __inval_cache_range

/*
 * Clear the idmap and swapper page tables.
 */
mov    x0, x25
add    x6, x26, #SWAPPER_DIR_SIZE

1: stp xzr, xzr, [x0], #16
stp xzr, xzr, [x0], #16
stp xzr, xzr, [x0], #16
stp xzr, xzr, [x0], #16
cmp x0, x6
b.lo 1b

ldr    x7, =MM_MMUFLAGS

/*
 * Create the identity mapping.
 */
add    x0, x25, #PAGE_SIZE        // section table address
ldr    x3, =KERNEL_START
add    x3, x3, x28            // __pa(KERNEL_START)
create_pgd_entry x25, x0, x3, x5, x6
ldr    x6, =KERNEL_END
mov    x5, x3                // __pa(KERNEL_START)
add    x6, x6, x28            // __pa(KERNEL_END)
create_block_map x0, x7, x3, x5, x6

/*
 * Map the kernel image (starting with PHYS_OFFSET).
 */
add    x0, x26, #PAGE_SIZE        // section table address
mov    x5, #PAGE_OFFSET
create_pgd_entry x26, x0, x5, x3, x6
ldr    x6, =KERNEL_END
mov    x3, x24                // phys offset
create_block_map x0, x7, x3, x5, x6

/*
 * Map the FDT blob (maximum 2MB; must be within 512MB of
 * PHYS_OFFSET).
 */
mov    x3, x21                // FDT phys address      // x21保存的是device tree的物理地址
and    x3, x3, #~((1 << 21) - 1)    // 2MB aligned  // x3= x3 & 0xffffffffffe00000 // 2MB对齐
mov    x6, #PAGE_OFFSET                 // PAGE_OFFSET等于0xffffffc000000000   PAGE_OFFSET是Linux内核空间的虚拟起始地址
sub    x5, x3, x24            // subtract PHYS_OFFSET  // x5等于device tree相对于kernel起始的物理内存地址的偏移
                                             x24 = PHYS_OFFSET  PHYS_OFFSET是物理内存的起始地址


tst    x5, #~((1 << 29) - 1)        // within 512MB? // 是否小于512MB
csel    x21, xzr, x21, ne        // zero the FDT pointer    // 如果x5大于512MB,则将x21清0
b.ne    1f                                 // 如果x5大于512MB,跳转到标号1处
add    x5, x5, x6            // __va(FDT blob) // x5等于device tree的虚拟内存地址
add    x6, x5, #1 << 21        // 2MB for the FDT blob
sub    x6, x6, #1            // inclusive range
create_block_map x0, x7, x3, x5, x6      
                                // 创建pud页表,x0是pud的基地址,x7是flag,x3是需要创建pud页表的内存地址 // 2MB block

1:
/*
* Since the page tables have been populated with non-cacheable
* accesses (MMU disabled), invalidate the idmap and swapper page
* tables again to remove any speculatively loaded cache lines.
*/
mov x0, x25
add x1, x26, #SWAPPER_DIR_SIZE
bl __inval_cache_range // 再次将idmap和swapper对应的cacheline设为无效

mov    lr, x27   // 恢复lr
ret         //返回

ENDPROC(__create_page_tables)

//
arch/arm64/kernel/setup.c

phys_addr_t __fdt_pointer __initdata;

void __init setup_arch(char **cmdline_p)
{
setup_processor();

setup_machine_fdt(__fdt_pointer);



unflatten_device_tree();

}

static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
struct boot_param_header *devtree;
unsigned long dt_root;

cpuinfo_store_cpu();

/* Check we have a non-NULL DT pointer */
if (!dt_phys) {
    early_print("\n"
        "Error: NULL or invalid device tree blob\n"
        "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
        "\nPlease check your bootloader.\n");

    while (true)
        cpu_relax();

}

devtree = phys_to_virt(dt_phys);

/* Check device tree validity */
if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) {
    early_print("\n"
        "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
        "Expected 0x%x, found 0x%x\n"
        "\nPlease check your bootloader.\n",
        dt_phys, devtree, OF_DT_HEADER,
        be32_to_cpu(devtree->magic));

    while (true)
        cpu_relax();
}

initial_boot_params = devtree;
dt_root = of_get_flat_dt_root();

machine_name = of_get_flat_dt_prop(dt_root, "model", NULL);
if (!machine_name)
    machine_name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
if (!machine_name)
    machine_name = "";
pr_info("Machine: %s\n", machine_name);

/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* Initialize {size,address}-cells info */
// 解析   #address-cells = <2>;        #size-cells = <2>;这样的信息

of_scan_flat_dt(early_init_dt_scan_root, NULL);
/* Setup memory, calling early_init_dt_add_memory_arch */
of_scan_flat_dt(early_init_dt_scan_memory, NULL);

}


Android7.1.2/ROC-RK3328-CC_Android7.1.2_git_20171204/kernel/arch/arm64/mach-rockchip/rk322xh.c

arch_initcall(rk322xh_dt_init);

static __init int rk322xh_dt_init(void)
{
struct device_node *node, *gp, *cp;
int avs_delta = -5;

node = of_find_compatible_node(NULL, NULL, "rockchip,rk322xh-grf");
if (node) {
    grf = of_iomap(node, 0);
    if (!grf) {
        pr_err("%s: could not map grf registers\n", __func__);
        return -ENXIO;
    }
} else {
    pr_err("%s: could not find grf dt node\n", __func__);
    return -ENODEV;
}
rockchip_pmu_ops.set_idle_request = rk322xh_set_idle_request;

node = of_find_compatible_node(NULL, NULL, "rockchip,avs");
if (node)
    of_property_read_u32(node, "avs-delta", &avs_delta);

rockchip_avs_delta = avs_delta;

node = of_find_compatible_node(NULL, NULL, "rockchip,cpu_axi_bus");
if (!node)
    return -ENODEV;

#define MAP(name)
do {
cp = of_get_child_by_name(gp, #name);
if (cp)
name##_qos_base = of_iomap(cp, 0);
if (!name##_qos_base)
pr_err(“%s: could not map qos %s register\n”,
func, #name);
} while (0)

gp = of_get_child_by_name(node, "qos");
if (gp) {
    MAP(cpu);
    MAP(gpu0);
    MAP(gpu1);
    MAP(emmc);
    MAP(gmac2io);
    MAP(sdio);
    MAP(sdmmc);
    MAP(usbhost0);
    MAP(usb3otg);
    MAP(usbotg);
    MAP(gmac2phy);
    MAP(sdmmc_ext);
    MAP(dma);
    MAP(crypto);
    MAP(tsp);
    MAP(rkvdec_r);
    MAP(rkvdec_w);
    MAP(hdcp);
    MAP(vop);
    MAP(iep);
    MAP(vip);
    MAP(rga_r);
    MAP(rga_w);
    MAP(h265);
    MAP(h264);
    MAP(vpu);
}

#undef MAP

return 0;

}
/
设备树在 RK3288/Android7.1.2/ROC-RK3328-CC_Android7.1.2_git_20171204/kernel/arch/arm64/boot/dts/rk3328-roc-cc.dts

/// kernel/drivers/of/fdt.c
/**

  • early_init_dt_scan_root - fetch the top level address and size cells
    */
    int __init early_init_dt_scan_root(unsigned long node, const char *uname,
    int depth, void *data)
    {
    const __be32 *prop;

    if (depth != 0)
    return 0;

    dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
    dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;

    prop = of_get_flat_dt_prop(node, “#size-cells”, NULL);
    if (prop)
    dt_root_size_cells = be32_to_cpup(prop);
    pr_debug(“dt_root_size_cells = %x\n”, dt_root_size_cells);

    prop = of_get_flat_dt_prop(node, “#address-cells”, NULL);
    if (prop)
    dt_root_addr_cells = be32_to_cpup(prop);
    pr_debug(“dt_root_addr_cells = %x\n”, dt_root_addr_cells);

    /* break now */
    return 1;
    }

///

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx-xx-xxx-xxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值