arm linux启动流程带dts
arm linux启动流程
初始化
start_kernel()
init/main.c
asmlinkage void __init start_kernel(void)
{
…
setup_arch(&command_line);
…
rest_init();
}
setup_arch()
arch/arm64/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
…
setup_machine_fdt(__fdt_pointer);
…
parse_early_param();
…
unflatten_device_tree();
…
ifdef CONFIG_SMP
smp_init_cpus();
endif
...
}
rest_init()
init/main.c
static noinline void __init_refok rest_init(void)
{
…
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
…
}
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
}
static noinline void __init kernel_init_freeable(void)
{
smp_prepare_cpus(setup_max_cpus);
}
void __init smp_prepare_cpus(unsigned int max_cpus)
{
int err;
unsigned int cpu, ncores = num_possible_cpus();
init_cpu_topology();
setup_machine_fdt()
arch/arm64/kernel/setup.c
static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) {
while (true)
cpu_relax();
}
machine_name = of_flat_dt_get_machine_name();
}
setup_machine_fdt()调用了两个函数:
1.early_init_dt_scan()
2.of_flat_dt_get_machine_name()
of_flat_dt_get_machine_name用于获取如下属性:
model
compatible
如果model没有设置,就用compatible来设置machine_name.
early_init_dt_scan()
drivers/of/fdt.c
bool __init early_init_dt_scan(void *params)
{
if (!params)
return false;
/* Setup flat device-tree pointer */
initial_boot_params = params;
/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* Initialize {size,address}-cells info */
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);
return true;
}
early_init_dt_scan()做了三件事,分别解析如下相关属性:
1、early_init_dt_scan_chosen()
chosen
bootargs
2、early_init_dt_scan_root()
size-cells
address-cells
3、early_init_dt_scan_memory()
device_type
linux,usable-memory
drivers/of/fdt.c
early_init_dt_scan_memory()参阅后面关于memory节点的说明。
unflatten_device_tree
start_kernel->setup_arch->unflatten_device_tree->
drivers/of/fdt.c
void __init unflatten_device_tree(void)
{
__unflatten_device_tree(initial_boot_params, &of_allnodes,
early_init_dt_alloc_memory_arch);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
of_alias_scan(early_init_dt_alloc_memory_arch);
}
arm64_device_init
arch/arm64/kernel/setup.c
static int __init arm64_device_init(void)
{
of_clk_init(NULL);
of_platform_populate(NULL[参数为NULL,则用根节点], of_default_bus_match_table, NULL, NULL);
return 0;
}
arch_initcall_sync启动加载级别;
drivers/of/platform.c
const struct of_device_id of_default_bus_match_table[] = {
{ .compatible = “simple-bus”, },
ifdef CONFIG_ARM_AMBA
{ .compatible = "arm,amba-bus", },
endif /* CONFIG_ARM_AMBA */
{} /* Empty terminated list */
};
of_platform_populate
drivers/of/platform.c
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path("/");[如果root参数为NULL,则用根节点]
if (!root)
return -EINVAL;
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}
of_node_put(root);
return rc;
}
实际调用:
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, of_default_bus_match_table, NULL, NULL, true);
}
}
of_platform_bus_create
of_platform_populate实际调用:
of_platform_bus_create(child, of_default_bus_match_table, NULL, NULL, true);
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
if (strict && (!of_get_property(bus, “compatible”, NULL))) {
pr_err(“%s() - skipping %s, no compatible prop\n”,
func, bus->full_name);
return 0;
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return [到这里就直接返回了。]0;
for_each_child_of_node(bus, child) {
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc) {
of_node_put(child);
break;
}
}
return rc;[这一段代码没有执行。]
}
关于参数true:
drivers/of/platform.c
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
…
/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, “compatible”, NULL))) {
pr_debug(“%s() - skipping %s, no compatible prop\n”,
func, bus->full_name);
return 0;
}
…
}
也就是说dts配置的节点必须有compatible属性。
节点
定义
[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
}
1、[]可选;
2、lable用于在dts中引用;
3、@后面是地址;
4、如果没有@unit-address,则node-name必须唯一;
5、如果有@unit-address,则node-name可以相同;
例1
gic: interrupt-controller@2c001000 {
compatible = “arm,cortex-a15-gic”, “arm,cortex-a9-gic”;
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
reg = <0x0 0xc4301000 0 0x1000>,
<0x0 0xc4302000 0 0x0100>;
interrupts = ;
};
编译后的dtb是:
interrupt-controller@2c001000 {
compatible = “arm,cortex-a15-gic”, “arm,cortex-a9-gic”;
#interrupt-cells = <0x00000003>;
#address-cells = <0x00000000>;
interrupt-controller;
reg = <0x00000000 0xc4301000 0x00000000 0x00001000 0x00000000 0xc4302000 0x00000000 0x00000100>;
interrupts = <0x00000001 0x00000009 0x00000f04>;
linux,phandle = <0x00000001>;
phandle = <0x00000001>;
};
例2:
gpio: banks@c11080b0 {
reg = <0x0 0xc88344b0 0x0 0x2c>,
<0x0 0xc88344e8 0x0 0x14>,
<0x0 0xc8834520 0x0 0x14>,
<0x0 0xc8834430 0x0 0x3c>;
reg-names = “mux”, “pull”, “pull-enable”, “gpio”;
gpio-controller;
#gpio-cells = <2>;
};
memory
例1:
memory@00000000 {
device_type = “memory”;
linux,usable-memory = <0x0 0x1000000 0x0 0x3f000000>;
};
这里linux,usable-memory和reg属性一样。建议统一使用reg。
前面两个数是64位的起始地址,后面两个数是64位的大小。
该节点是由early_init_dt_scan_memory()来解析。
drivers/of/fdt.c
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data)
{
const char *type = of_get_flat_dt_prop(node, “device_type”, NULL);
const __be32 *reg, *endp;
int l;
/* We are scanning "memory" nodes only */
if (type == NULL) {
/*
* The longtrail doesn't have a device_type on the
* /memory node, so look for the node called /memory@0.
*/
if (depth != 1 || strcmp(uname, "memory@0") != 0)
return 0;
} else if (strcmp(type, "memory") != 0)
return 0;
reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
if (reg == NULL)
reg = of_get_flat_dt_prop(node, "reg", &l);
if (reg == NULL)
return 0;
}
解释:
1、如果没有有device_type属性,则必须在根节点(depth=1)下这么写dts:
memory@0 {
linux,usable-memory = <0x0 0x1000000 0x0 0x3f000000>;
};
2、如果device_type属性的值不是memory,则该函数不继续解析。
3、优先使用linux,usable-memory,如果没有,则使用reg来解析memory。
cpus
例1:
cpus:cpus {
#address-cells = <2>;
#size-cells = <0>;
#cooling-cells = <2>; /* min followed by max */
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53","arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
};
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53","arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
};
cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a53","arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
};
cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a53","arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
};
};
arch/arm64/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
…
setup_machine_fdt(__fdt_pointer);
…
parse_early_param();
…
unflatten_device_tree();
…
ifdef CONFIG_SMP
smp_init_cpus();
endif
...
}
解析过程:
第一阶段:
start_kernel()->setup_arch()->smp_init_cpus()
第二阶段:
start_kernel()->rest_init()
->kernel_init(kernel_thread)->…->smp_prepare_cpus()
smp_init_cpus()
start_kernel()->setup_arch()->smp_init_cpus()
arch/arm64/kernel/smp.c
void __init smp_init_cpus(void)
{
struct device_node *dn = NULL;
unsigned int i, cpu = 1;
bool bootcpu_valid = false;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
cell = of_get_property(dn, "reg", NULL);
hwid = of_read_number(cell, of_n_addr_cells(dn));
if (cpu_read_ops(dn, cpu) != 0)
goto next;
if (cpu_ops[cpu]->cpu_init(dn, cpu))
goto next;
cpu_logical_map(cpu) = hwid;
cpu++;
}
for (i = 0; i < NR_CPUS; i++)
if (cpu_logical_map(i) != INVALID_HWID)
set_cpu_possible(i, true);
}
smp_prepare_cpus
start_kernel()->rest_init()
->kernel_init(kernel_thread)->kernel_init_freeable()->
smp_prepare_cpus()
do_pre_smp_initcalls()
smp_init()
sched_init_smp()
init/main.c
static noinline void __init kernel_init_freeable(void)
{
cad_pid = task_pid(current);
smp_prepare_cpus(setup_max_cpus);
do_pre_smp_initcalls();
lockup_detector_init();
smp_init();
sched_init_smp();
do_basic_setup();
}
smp_prepare_cpus()->init_cpu_topology()->
parse_dt_topology()
parse_dt_cpu_power
arch/arm64/kernel/topology.c
void __init init_cpu_topology(void)
{
reset_cpu_topology();
/*
* Discard anything that was parsed if we hit an error so we
* don't use partial information.
*/
if (parse_dt_topology())
reset_cpu_topology();
reset_cpu_power();
parse_dt_cpu_power();
}
static int __init parse_dt_topology(void)
{
cn = of_find_node_by_path(“/cpus”);
map = of_get_child_by_name(cn, "cpu-map");
if (!map)
goto out;
out:
of_node_put(cn);
return ret;
}
static void __init parse_dt_cpu_power(void)
{
for_each_possible_cpu(cpu) {
cn = of_get_cpu_node(cpu, NULL);
for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
if (of_device_is_compatible(cn, cpu_eff->compatible))
break;
rate = of_get_property(cn, "clock-frequency", &len);
if (!rate || len != 4) {
pr_err("%s: Missing clock-frequency property\n",
cn->full_name);
continue;
}
capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
cpu_capacity(cpu) = capacity;
}
}
enable-method
cpu@0 {
device_type = “cpu”;
compatible = “arm,cortex-a53”,”arm,armv8”;
reg = <0x0 0x0>;
enable-method = “psci”;
};
arch/arm64/kernel/cpu_ops.c
int __init cpu_read_ops(struct device_node *dn, int cpu)
{
const char *enable_method = of_get_property(dn, “enable-method”, NULL);
cpu_ops[cpu] = cpu_get_ops(enable_method);
return 0;
}
static const struct cpu_operations * __init cpu_get_ops(const char *name)
{
const struct cpu_operations **ops = supported_cpu_ops;
while (*ops) {
if (!strcmp(name, (*ops)->name))
return *ops;
ops++;
}
return NULL;
}
static const struct cpu_operations *supported_cpu_ops[] __initconst = {
ifdef CONFIG_SMP
&smp_spin_table_ops,
&cpu_psci_ops,
endif
NULL,
};
const struct cpu_operations cpu_psci_ops = {
.name = “psci”,
.cpu_init = cpu_psci_cpu_init,
.cpu_prepare = cpu_psci_cpu_prepare,
.cpu_boot = cpu_psci_cpu_boot,
.cpu_suspend = cpu_psci_cpu_suspend,
ifdef CONFIG_HOTPLUG_CPU
.cpu_disable = cpu_psci_cpu_disable,
.cpu_die = cpu_psci_cpu_die,
endif
};
reserved-memory
exmaple
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
/* global autoconfigured region for contiguous allocations */
secmon_reserved:linux,secmon {
compatible = “amlogic, aml_secmon_memory”;
reg = <0x0 0x10000000 0x0 0x200000>;
no-map;
};
pstore:aml_pstore {
compatible = “amlogic, pstore”;
reg = <0x0 0x07300000 0x0 0x100000>;
no-map;
};
di_reserved:linux,di {
compatible = “amlogic, di-mem”;
size = <0x0 0x3300000>; //51M for support nr10bit
multi-use;
};
…
};
sequence
start_kernel()->setup_arch()->arm64_memblock_init()->
early_init_fdt_scan_reserved_mem()->
of_scan_flat_dt(__fdt_scan_reserved_mem)
fdt_init_reserved_mem()
early_init_fdt_scan_reserved_mem()
arch/arm64/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
…
setup_machine_fdt(__fdt_pointer);
…
parse_early_param();
arm64_memblock_init();
…
unflatten_device_tree();
…
ifdef CONFIG_SMP
smp_init_cpus();
endif
...
}
arch/arm64/mm/init.c
void __init arm64_memblock_init(void)
{
…
early_init_fdt_scan_reserved_mem();
…
}
drivers/of/fdt.c
void __init early_init_fdt_scan_reserved_mem(void)
{
if (!initial_boot_params)
return;
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
}
__fdt_scan_reserved_mem()
drivers/of/fdt.c
static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
int depth, void *data)
{
if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
if (__reserved_mem_check_root(node) != 0) {
pr_err("Reserved memory: unsupported node format, ignoring\n");
/* break scan */
return 1;
}
found = 1;
/* scan next node */
return 0;
} else if (!found) {
/* scan next node */
return 0;
} else if (found && depth < 2) {
/* scanning of /reserved-memory has been finished */
return 1;
}
status = of_get_flat_dt_prop(node, "status[如果没有status,则默认status =okay]", NULL);
if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
return 0;
err = __reserved_mem_reserve_reg(node, uname);
if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
fdt_reserved_mem_save_node(node, uname, 0, 0);
/* scan next node */
return 0;
}
__reserved_mem_check_root()
static int __init __reserved_mem_check_root(unsigned long node)
{
const __be32 *prop;
prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "ranges", NULL);
if (!prop)
return -EINVAL;
return 0;
}
必须提供以下三个属性:
size-cells
address-cells
ranges
而且#size-cells和#address-cells的值必须和根节点的值(由dt_root_size_cells和dt_root_addr_cells保存)相同。
reserved_mem[]
drivers/of/of_reserved_mem.c
define MAX_RESERVED_REGIONS 16
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
从上面代码看,reserved memory最多只能有16个。
属性
property[=value]
1、单个字符串
2、字符串列表
3、单个无符号整型数
4、无符号整型数列表
5、无参数值属性
address-cells
drivers/of/base.c
int of_n_addr_cells(struct device_node *np)
{
const __be32 *ip;
do {
if (np->parent)
np = np->parent;
ip = of_get_property(np, "#address-cells", NULL);
if (ip)
return be32_to_cpup(ip);
} while (np->parent);
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
const __be32 *ip;
do {
if (np->parent)
np = np->parent;
ip = of_get_property(np, "#size-cells", NULL);
if (ip)
return be32_to_cpup(ip);
} while (np->parent);
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_size_cells);
size-cells
描述子节点的reg属性。#address-cells表示地址域占用几个cell,#size-cells表示地址长度占用几个cell。
针对reg格式:
reg =
address-cells 表示address1/2 包含几个cell。
size-cells表示length1/2包含几个cell
例1:
/ {
#address-cells = <2>;
#size-cells = <2>;
sd {
reg = <0x0 0xd0072000 0x0 0x2000>;
}
}
例1的sd节点的reg属性,address是0x0 0xd0072000,length是0x0 0x2000。这个例子的地址实际都是64bit地址。
例2:
/ {
#address-cells = <2>;
#size-cells = <2>;
i2c {
address-cells = <1>;
size-cells = <0>;
at24 {
reg = <0x50>;
}
}
}
reg
格式:
reg =
address-cells
size-cells
也就是说节点的reg属性,需要使用父节点的#address-cells、#size-cells的值来解析。
例子
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
/* global autoconfigured region for contiguous allocations */
secmon_reserved:linux,secmon {
compatible = “amlogic, aml_secmon_memory”;
reg = <0x0 0x10000000 0x0 0x200000>;
no-map;
};
model
const char * __init of_flat_dt_get_machine_name(void)
{
const char *name;
unsigned long dt_root = of_get_flat_dt_root();
name = of_get_flat_dt_prop(dt_root, "model", NULL);
if (!name)
name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
return name;
}
从代码看,如果定义了model,就用model来设置machine_name,否则就是用compatible.
有两处使用:
of_flat_dt_match_machine()
pr_info(“Machine model: %s\n”, of_flat_dt_get_machine_name());
start_kernel->setup_arch->setup_machine_fdt->
machine_name = of_flat_dt_get_machine_name();
compatible
格式:
[manufacturer], [model]
例1:
compatible = “amlogic, gxtvbb”;
interrupt-parent
例子
interrupt-parent = <&gic>;
gic: interrupt-controller@2c001000 {
compatible = “arm,cortex-a15-gic”, “arm,cortex-a9-gic”;
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
reg = <0x0 0xc4301000 0 0x1000>,
<0x0 0xc4302000 0 0x0100>;
interrupts = ;
};
1、定义interrupt-parent属性是定义在root节点,这样其他有中断的节点就不需要再定义了,直接继承。
系统在启动时,按照如下过程,分解irq dts:
of_irq_find_parent+0x68/0x6c
of_irq_init+0xb0/0x2c4
irqchip_init+0x10/0x1c
init_IRQ+0x8/0x2c arch/arm64/kernel/irq.c:80: irqchip_init();
start_kernel+0x1ec/0x354
分解
drivers/of/irq.c
device_name
drivers/of/platform.c
void of_device_make_bus_id(struct device *dev)
{
name = of_get_property(node, "device_name", NULL);
if (name) {
dev_set_name(dev, "%s", name);
return;
}
reg = of_get_property(node, "reg", NULL);
if (reg) {
if (of_can_translate_address(node)) {
addr = of_translate_address(node, reg);
} else {
addrp = of_get_address(node, 0, NULL, NULL);
if (addrp)
addr = of_read_number(addrp, 1);
else
addr = OF_BAD_ADDR;
}
if (addr != OF_BAD_ADDR) {
dev_set_name(dev, "%llx.%s",
(unsigned long long)addr, node->name);
return;
}
}
/*
* No BusID, use the node name and add a globally incremented
* counter (and pray...)
*/
magic = atomic_add_return(1, &bus_no_reg_magic);
dev_set_name(dev, "%s.%d", node->name, magic - 1);
}
优先使用device_name属性作为设备名。
例1:
aml_sensor0: aml-sensor@0 {
compatible = “amlogic, aml-thermal”;
device_name = “thermal”;
#thermal-sensor-cells = <1>;
cpu_dyn_coeff = <140>;
/* cpu_freq gpu_freq cpu_core gpu_core */
min_state = <1000000 400 1 1>;
};
platform->dev->name:thermal
node->full_name:/aml-sensor@0
如果没有device_name,则使用reg参数作为设备名。
例2:
gpu_clk:gpu_clk@c883c00 {
compatible = “meson, gpu-clkgen-1.00.a”;
#clock-cells = <0>;
reg = <0 0xc883c000 0 0x00100>;
platform->dev->name:c883c000.gpu_clk
node->full_name: /gpu_clk@c883c00
如果没有reg,则动态分配(atomic)一个整数。
例3:
timer {
compatible = “arm,armv8-timer”;
interrupts = ,
,
,
;
};
platform->dev->name:/timer
node->full_name: timer.0
static atomic_t bus_no_reg_magic;
magic = atomic_add_return(1, &bus_no_reg_magic);
dev_set_name(dev, “%s.%d”, node->name, magic - 1);
第一个返回的值是0,依次是1, 2, 3, 4, …
格式是:节点的短名.编号
timer.0 timer.1 timer2 tmier.3
结构体
of_device_id
函数
of_get_flat_dt_root()
例1:
unsigned long root = of_get_flat_dt_root();
drivers/of/fdt.c
unsigned long __init of_get_flat_dt_root(void)
{
return 0;
}
of_flat_dt_is_compatible()
drivers/of/fdt.c
int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
{
return of_fdt_is_compatible(initial_boot_params, node, compat);
}
of_scan_flat_dt()
drivers/of/fdt.c
int __init of_scan_flat_dt(int (*it)(unsigned long node,
const char *uname, int depth,
void *data),
void *data)
{
const void *blob = initial_boot_params;
const char *pathp;
int offset, rc = 0, depth = -1;
for (offset = fdt_next_node(blob, -1, &depth);
offset >= 0 && depth >= 0 && !rc;
offset = fdt_next_node(blob, offset, &depth)) {
pathp = fdt_get_name(blob, offset, NULL);
if (*pathp == '/')
pathp = kbasename(pathp);
rc = it(offset, pathp, depth, data);
}
return rc;
}
每一个节点,包括其子节点,都会扫描一遍。
如果一旦回调函数返回非零值,则不再继续。
有如下几处调用:
drivers/of/fdt.c
void __init early_init_fdt_scan_reserved_mem(void)
{
if (!initial_boot_params)
return;
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
}
bool __init early_init_dt_scan(void *params)
{
if (!params)
return false;
/* Setup flat device-tree pointer */
initial_boot_params = params;
/* check device tree validity */
if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
initial_boot_params = NULL;
return false;
}
/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* Initialize {size,address}-cells info */
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);
return true;
}
of_flat_dt_is_compatible()
drivers/of/of_reserved_mem.c
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
extern const struct of_device_id __reservedmem_of_table[];
const struct of_device_id *i;
int ret = 0;
for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
reservedmem_of_init_fn initfn = i->data;
const char *compat = i->compatible;
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
/*
* scan whole table to set up all initfn, if one memory region
* is used by multi-users.
*/
if (initfn(rmem) == 0) {
pr_debug("Reserved memory: initialized node %s, compatible id %s\n",
rmem->name, compat);
} else
ret--;
}
return ret;
}
of_find_node_by_path()
例1:
struct device_node *root = of_find_node_by_path(“/”)
例2:
struct device_node *memory;
memory = of_find_node_by_path(“/memory”);
of_find_node_by_name()
如果第一个参数为NULL,则是在全局中查找结点。
例1:
np = of_find_node_by_name(NULL, “thermal-zones”)
of_device_is_compatible
of_get_property
of_property_read_u32_index
of_property_read_u32_array
of_property_read_u64
of_property_read_string
of_property_read_string_index
of_property_count_strings
of_iomap
of_irq_get
irq_of_parse_and_map
of_irq_to_resource
of_irq_count
gpiolib-of
drivers/gpio/gpiolib-of.c
更多推荐
所有评论(0)