代码平台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;
}
///////////////////
阅读(1697) | 评论(0) | 转发(0) |