代码平台Android7.1.2 硬件RK3288 ROC-RK3288-CCAndroid7.1.2/ROC-RK3328-CC_Android7.1.2_git_20171204/kernel/arch/arm64/mach-rockchipdts文件为板级设备描述文件,被编译后为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 // spENTRY(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 processorENDPROC(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 add x0, x0, x24 // 判断device tree的物理地址是否在kernel起始的512M内存空间内部 cmp x21, x0 b.ge 1f ret1: mov x21, #0 retENDPROC(__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_SIZE1: 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 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 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 sub x6, x6, #1 // inclusive range create_block_map x0, x7, x3, x5, x6 // 创建pud页表,x0是pud的基地址,x7是flag,x3是需要创建pud页表的内存地址 // 2MB block1: /* * 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.cphys_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 = ; #size-cells = ;这样的信息 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.carch_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;}///////////////////