3, the processing core of the device tree


Section 01 _ _ kernel from source analysis head.S simple handling of the dtb

When bootloader launch kernel, is set r0, r1, r2 three registers,
r0 of generally set to 0;
R1 is generally set to machine id (this parameter is not used when using the device tree); which indicates the use of the board
ships provided ATAGS r2 the start address or DTB

There are two methods when the kernel parameters passed to the bootloader:
ATAGS or DTB

For ATAGS parameter passing methods, we can refer to the "graduating class video - write their own bootloader"

 

a __lookup_processor_type:. assembler instruction reads the CPU ID, find the corresponding proc_info_list structure according to this ID (which contains such initialization functions of the CPU, information)
B __vet_atags:. determining whether there is an available ATAGS or DTB (The DTB file format or file format ATAGS r2 is located to determine the kind of)
C __create_page_tables:. creates the page table, i.e. the mapping between virtual addresses and physical addresses
d __enable_mmu:. the MMU is enabled, after the necessary virtual address,
e. __mmap_switched: the above function will be called in __mmap_switched
f r2 passed the bootloader parameters, save it to a variable __atags_pointer in.
G call C functions start_kernel.

head.S / head-common.S:
the bootloader came r1 value assigned to the variable C: __machine_arch_type
the bootloader came r2 values assigned to the variable C: __atags_pointer // dtb first address

Section 02 _ handling of the device tree platform information (Select machine_desc)
A. Compatible device attribute root node lists a series of strings,
indicating that it is compatible with the board name,
from "most compatible" to second place

b. a plurality machine_desc kernel,
which dt_compat members, which points to a string array, which indicates which board supports the machine_desc

. c value using compatile property,
with
each machine_desc.dt_compat
comparison,
the results for the "consistent position compatile attribute value",

the lower the score the more matches, the corresponding machine_desc will be selected


function call:
start_kernel // the init / main .c
  setup_arch (& command_line); // Arch / ARM / Kernel / setup.c
    mdesc = setup_machine_fdt (__ atags_pointer); // Arch / ARM / Kernel / devtree.c
      early_init_dt_verify (phys_to_virt (dt_phys) // determines whether a valid dtb, Drivers / of / ftd.c
          initial_boot_params = the params;
      mdesc = of_flat_dt_match_machine (mdesc_best, arch_get_next_mach); // find the best match machine_desc, Drivers / of / ftd.c
      the while ((Data = get_next_compat (& compat))) {
Score = of_flat_dt_match (dt_root, compat);
IF (Score> 0 && Score <BEST_SCORE) {
best_data = data;
best_score = score;
}
}

machine_desc = mdesc;



Processing information in Section 03 _ configured to run when the device tree

函数调用过程:
start_kernel // init/main.c
setup_arch(&command_line); // arch/arm/kernel/setup.c
mdesc = setup_machine_fdt(__atags_pointer); // arch/arm/kernel/devtree.c
early_init_dt_scan_nodes(); // drivers/of/ftd.c
/* 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);

. a value / chosen node bootargs attributes stored in global variables: boot_command_line
B determines two values of the root attribute:. # address-cells, # size-cells
stored in global variables: dt_root_addr_cells, dt_root_size_cells
. Analytical C / reg in the attribute memory, extract "base, size", the final call memblock_add (base, size);


section 04 is converted to _dtb device_node (unflatten)

函数调用过程:
start_kernel // init/main.c
setup_arch(&command_line); // arch/arm/kernel/setup.c
arm_memblock_init(mdesc); // arch/arm/kernel/setup.c
early_init_fdt_reserve_self();
/* Reserve the dtb region */
// 把DTB所占区域保留下来, 即调用: memblock_reserve
early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
fdt_totalsize(initial_boot_params),
0);
early_init_fdt_scan_reserved_mem(); // 根据dtb中的memreserve信息, 调用memblock_reserve

unflatten_device_tree(); // arch/arm/kernel/setup.c
__unflatten_device_tree(initial_boot_params, NULL, &of_root,
early_init_dt_alloc_memory_arch, false); // drivers/of/fdt.c

/* First pass, scan for size */
size = unflatten_dt_nodes(blob, NULL, dad, NULL);

/* Allocate memory for the expanded device tree */
mem = dt_alloc(size + 4, __alignof__(struct device_node));

/* Second pass, do actual unflattening */
unflatten_dt_nodes(blob, mem, dad, mynodes);
populate_node
np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node));

np->full_name = fn = ((char *)np) + sizeof(*np);

populate_properties
pp = unflatten_dt_alloc(mem, sizeof(struct property),
__alignof__(struct property));

pp->name = (char *)pname;
pp->length = sz;
pp->value = (__be32 *)val;

a. In DTB file,
each node in a TAG (FDT_BEGIN_NODE, 0x00000001) starts, nodes can be nested inside the other nodes,
each attribute begins with TAG (FDT_PROP, 0x00000003)

. b each node device_node converted to a structure:
struct {device_node
const char * name; // name attribute from the node, if the attribute is not, then set to "NULL"
const char * type; // node from the device_type property without the property, set to "NULL"
pHandle pHandle;
const char * FULL_NAME; // node name, the node-name [@ Unit-address]
struct fwnode_handle fwnode;

struct property * properties; // attribute node
struct Property * deadprops; / * removed the Properties * /
struct device_node * parent; // node father
struct device_node * child; children (child node) // node
struct device_node * sibling; // sibling node (peer node)
#if defined (CONFIG_OF_KOBJ)
struct the kobject Kobj;
#endif
unsigned Long _flags;
void * Data;
#if defined (CONFIG_SPARC)
const char * path_component_name;
unsigned int UNIQUE_ID;
struct of_irq_controller * irq_trans;
#endif
};

. c device_node structure has Properties, indicates the attribute of the node to
each of a property corresponding to a property of the structure:
struct property {
char * name; // attribute name, the file pointer to the string dtb
int length; // Properties length value
void * value; // attribute value, point value dtb location where file data is still stored in big endian
struct * property Next;
#if defined (CONFIG_OF_DYNAMIC) || defined (CONFIG_SPARC)
unsigned Long _flags;
#endif
# defined IF (CONFIG_OF_PROMTREE)
unsigned int UNIQUE_ID;
#endif
#if defined (CONFIG_OF_KOBJ)
struct bin_attribute attr;
#endif
};

D device_node these constitute a tree, the root node is: of_root.

 

Section 05 _device_node converted to platform_device

dts -> dtb -> device_node -> platform_device

Two issues:
A device_node which can be converted to platform_device.?
Child node of the root node containing attributes compatile
( "simple-bus", " simple-mfd", "isa" If a node attribute compatile containing these particular values , "arm, amba-bus" ) one, then its child nodes (including compatile required attributes) may also be converted to platform_device
subnodes under I2C, SPI, etc. bus node, a bus driver to be processed corresponding to they should not be converted into platform_device

. b how conversion?
platform_device resource contains an array, it comes from device_node the reg, interrupts property;
platform_device.dev.of_node point device_node, other properties can be obtained by it

This section summarizes:

. a kernel function of_platform_default_populate_init, device_node tree traversal generates platform_device
B device_node not all are converted to platform_device.
Only converted device_node following:
B.1 node must contain the compatible attribute
child node b.2 root (node must contain compatible property)
child node b.3 node contains special properties compatible (child node must contain compatible property):
these special compatilbe property: "simple-bus", " simple-mfd", "isa", "arm, amba-bus "

b.4 Example:
such as the node,
/ mytest will be converted to platform_device,
because it is compatible with "simple-bus", its child nodes / mytest / mytest @ 0 will be converted to platform_device

/ i2c i2c generally designated node controller, it will be converted to platform_device, a corresponding kernel platform_driver;
/ i2c / AT24C02 nodes not be converted to platform_device, how it is processed entirely determined by the parent node platform_driver generally It was created as a i2c_client.

Similar has / spi nodes, which are generally used to indicate SPI controller, it is converted to platform_device, a corresponding kernel platform_driver;
/ spi / @ Flash not be converted to node 0 platform_device, how it is processed platform_driver entirely determined by the parent node generally is created as a spi_device.

/ {
Mytest {
compatile = "mytest", "Simple-Bus";
mytest @ 0 {
compatile = "mytest_0";
};
};

I2C {
compatile = "Samsung, I2C";
AT24C02 {
compatile = "AT24C02";
};
};

spi {
compatile = "samsung,spi";
flash@0 {
compatible = "winbond,w25q32dw";
spi-max-frequency = <25000000>;
reg = <0>;
};
};
};


Function call:
. A of_platform_default_populate_init (Drivers / of / platform.c) to the called procedure:
the start_kernel // the init / main.c
rest_init ();
PID = kernel_thread (kernel_init, NULL, CLONE_FS);
kernel_init
kernel_init_freeable ();
to do_basic_setup ();
do_initcalls ();
for (Level = 0; Level <ARRAY_SIZE (initcall_levels) -. 1; Level ++)
do_initcall_level (Level); // such do_initcall_level (. 3)
for (Fn = initcall_levels [. 3]; Fn <initcall_levels [. 3 +1]; the Fn ++)
do_one_initcall (initcall_from_entry (the Fn)); // is calling "arch_initcall_sync (fn)" fn function defined in

. b of_platform_default_populate_init (drivers / of / platform.c) platform_device generation process:
of_platform_default_populate_init
of_platform_default_populate (NULL, NULL, NULL);
of_platform_populate (NULL, of_default_bus_match_table, NULL, NULL)
for_each_child_of_node (the root, Child) {
RC = of_platform_bus_create (Child, matches, lookup, parent, true) ; // call procedure see below
dev = of_device_alloc (np, bus_id, parent); // set according to the attribute device_node platform_device the resource node
IF (RC) {
of_node_put (Child);
BREAK;
}
}

. C of_platform_bus_create (bus, the matches, ...) of the calling process (process bus node generates platform_devie, and decide whether to take its child nodes):
dev = of_platform_device_create_pdata (bus, bus_id, platform_data, parent); // generated bus platform_device node structure
if (! dev || of_match_node (matches , bus)!) // If compatile attribute does not match the bus node matches into tables, it does not deal with child nodes
return 0;

for_each_child_of_node (bus, child) {// each child node extracted
pr_debug ( "Create Child: POF% \ n-", Child);
RC = of_platform_bus_create (Child, The matches, Lookup, & the dev-> dev, strict); // process its child nodes, of_platform_bus_create is a recursive call
IF (RC) {
of_node_put (child);
BREAK;
}
}

D I2C bus node process:.
/ i2c i2c generally designated node controller, it will be converted to platform_device, in a corresponding kernel platform_driver;
Probe will call the function platform_driver i2c_add_numbered_adapter:

i2c_add_numbered_adapter // Drivers / I2C / I2C-core-base.c
__i2c_add_numbered_adapter
i2c_register_adapter
of_i2c_register_devices (ADAP); // Drivers / I2C / I2C-core-of.c
for_each_available_child_of_node (Bus, Node) {
Client = of_i2c_register_device (ADAP, Node);
client = i2c_new_device (adap, & info ); // i2c device tree child node is converted to i2c_client
}

. e SPI bus processing node:
/ spi spi generally designated node controller, it will be converted to platform_device, the kernel in a corresponding platform_driver;
Probe will call the function platform_driver spi_register_master, i.e. spi_register_controller:

spi_register_controller // Drivers / SPI / spi.c
of_register_spi_devices // Drivers / SPI / spi.c
for_each_available_child_of_node (ctlr-> dev.of_node, NC) {
spi = of_register_spi_device (ctlr, nc) ; spi // child node device in the tree is converted into spi_device
SPI = spi_alloc_device (ctlr);
RC = of_spi_parse_dt (ctlr, SPI, NC);
RC = spi_add_device (SPI);
}


Section 06 _platform_device match with platform_driver

drivers/base/platform.c

. a registration process of platform_driver:
platform_driver_register
__platform_driver_register
Drv-> driver.probe = platform_drv_probe;
driver_register
bus_add_driver
klist_add_tail (& priv-> knode_bus, & BUS-> p-> klist_drivers); // put the driver list platform_bus_type platform_driver in
driver_attach
bus_for_each_dev ( drv-> bus, NULL, drv, __driver_attach); // for each device under plarform_bus_type, call __driver_attach
__driver_attach
RET = driver_match_device (drv, dev); // dev and determining whether the match is successful drv
return drv-> bus- > match drv-> bus-> match ( dev, drv):? 1; // call platform_bus_type.match
driver_probe_device (drv, dev);
really_probe
Drv-> // platform_drv_probe the Probe
platform_drv_probe
struct platform_driver *drv = to_platform_driver(_dev->driver);
drv->probe

b. 注册 platform_device 的过程:
platform_device_register
platform_device_add
device_add
bus_add_device
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); // 把 platform_device 放入 platform_bus_type的device链表中
bus_probe_device(dev);
device_initial_probe
__device_attach
ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); // // 对于plarform_bus_type下的每一个driver, 调用 __device_attach_driver
__device_attach_driver
ret = driver_match_device(drv, dev);
return drv->bus->match ? drv->bus->match(dev, drv) : 1; // 调用platform_bus_type.match
driver_probe_device

Matching function is platform_bus_type.match, i.e. platform_match,
the matching process are listed below in order of priority:
. A comparison platform_dev.driver_override and platform_driver.drv-> name
. Platform_dev.dev.of_node B comparison of the compatible and platform_driver.drv-> of_match_table
C Comparative platform_dev.name and platform_driver.id_table
D Comparative platform_dev.name and platform_driver.drv-> name
there is a successful, i.e., the matching is successful


Yesterday, participants proposed increase recorded following section 2, very grateful for their advice,
if you have suggestions, please let me know.
I'm not worried about the increased workload, the recording quality is my goal.
"Herself to make, in order pleasing "If I were not satisfied with my product, how can you be satisfied?

Function operation section 07 in the device tree kernel _

There are a lot of headers at the beginning of the include / linux / directory:

dtb -> device_node -> platform_device
A process DTB.
correlation function operation of_fdt.h // dtb document, we generally less than, as in the kernel dtb file has been converted to device_node tree (which is easier to use)

b. Processing device_node
of.h // providing device tree general processing functions, such as of_property_read_u32 (u32 reading a property value), of_get_child_count (acquisition sub-nodes of a device_node)
of_address.h // address related functions such of_get_address (reg properties obtained addr, size value)
of_match_device (removed with a best matches the current device from the array matches)
of_dma.h // DMA device tree attributes related functions
of_gpio.h // GPIO related function
of_graph.h // function GPU used in the relevant drive, GPU obtain information from the device tree
of_iommu.h // rarely used
of_irq.h // interrupt related functions
of_mdio.h // MDIO (Ethernet PHY ) API
of_net.h // oF helpers for Network Devices.
of_pci.h // PCI-correlation function
of_pdt.h // rarely used
correlation function of of_reserved_mem.h // reserved_mem

c. Disposal platform_device
of_platform.h // function used when the conversion platform_device device_node,
// such of_device_alloc (device_node provided platform_device The assignment),
// of_find_device_by_node (find platform_device according device_node),
// of_platform_bus_probe (device_node and Processing its child nodes)
of_device.h // function associated equipment, such as of_match_device

 

Section 08 _ viewing device tree root file system (useful for debugging)

a. / sys / firmware / fdt // original file dtb

hexdump -C /sys/firmware/fdt

b. / sys / firmware / devicetree // current path to the directory structure of the files dtb, base directory corresponding to the root node, each node corresponds to a directory, a file corresponding to each property

c. / sys / devices / platform // All platform_device system, there is a tree from the device, but also to have a .c file registered
for platform_device from the device tree,
you can enter the / sys / devices / platform / <device name > / of_node device tree view its properties

d. / proc / devicetree is linked files, point / sys / firmware / devicetree / base

 

Guess you like

Origin www.cnblogs.com/liusiluandzhangkun/p/11784597.html