以前的习惯是,当我要了解一个知识点的时候,会去找相关的网络文章;但现在想了解开源软件的时候,
一般会去阅读它的README或者Documents。开源软件的开发者写的这些东西,通常都是直达本质毫无
保留,这也从另外一个角度深刻的说明,这些开发者们的屌丝本质!
当然,也是因为开源世界的教程类的东东很少,还是老老实实的读README或者Documents吧!
==================================================================
III) - Required content of the device tree
WARNING: All "linux,*" properties defined in this documents apply only to a
flattened device-tree. If your platform uses a real implementation of Open
Firmware or an implementation compatible with the Open Firmware client
interface, those properties will be created by the trampoline code in the
kernel's prom_init() file. For example, that's where you'll have to add code
to detect your board model and set the platform number. However, when using
the flattened device-tree entry point, there is no prom_init() pass, and thus
you have to provide those properties yourself.
***********************************************************
练习:什么是Open Firmware?
答:Open Firmware, or OpenBoot in Sun Microsystems parlance, is a
standard defining the interfaces of a computer firmware system,
formerly endorsed by the Institute of Electrical and Electronics
Engineers (IEEE). It originated at Sun, and has been used by Sun,
Apple, IBM, and most other non-x86 PCI chipset verdors. Open Firmware
allows the system to load platform-independent drivers directly from
the PCI card, improving compatibility.
--from http://en.wikipedia.org/wiki/Open_Firmware
当然,我用的AM335x平台没有使用Open Firmware,实际上AM335x都不支持PCI协议。所以
这个flattened device-tree里面,不能使用Open Firmware定义的硬件啦,我需要自己
添加像board model或者platform number这样的参数进去。
***********************************************************
1) Note about cells and address representation
The general rule is documented in the various Open Firmware documentations. If
you choose to describe a bus with the device-tree and there exist an OF bus
binding, then you should follow the specification. However, the kernel does
not require every single device or bus to be described by the device tree.
In general, the format of an address for a device is defined by the parent bus
type, based on the #address-cells and #size-cells properties. Note that the
parent's parent definitions of #address-cells and #size-cells are not
inherited so every node with children must specify them. The kernel requires
the root node to have those properties defining addressed format for devices
directly mapped on the processor bus.
Those 2 properties define 'cells' for representing an address and a size. A
'cell' is a 32-bit number. For example, if both contain 2 like the example
tree given above, then an address and a size are both composed of 2 cells,
and each is a 64-bit number (cells are concatenated and expected to be in big
endian format). Another example is the way Apple firmware defines them, with 2
cells for an address and one cell for a size. Most 32-bit implementation
should define #address-cells and #size-cells to 1, which represents a 32-bit
value. Some 32-bit processors allow for physical addresses greater than 32
bits; these processors should define #address-cells as 2.
***********************************************************
练习:观察am33xx.dtsi的#address-cells和#size-cells。
***********************************************************
"reg" properties are always a tuple of the type "address size" where the
number of cells of address and size is specified by the bus #address-cells
and #size-cells. When a bus supports various address spaces and other flags
relative to a given address allocation (like prefetchable, etc) those flags
are usually added to the top level bits of the physical address. For example,
a PCI physical address is made of 3 cells, the bottom two containing the
actual address itself while the top cell contains address space indication,
flags, and pci bus & device numbers.
***********************************************************
练习:找一找各种各样的#address-cells和#size-cells定义。
***********************************************************
For buses that support dynamic allocation, it's the accepted practice to then
not provide the address in "reg" (keep it 0) though while providing a flag
indicating the address is dynamically allocated, and then, to provide a
separate "assigned-addressed" property that contains the fully allocated
addresses. See the PCI OF binding for details.
***********************************************************
练习:如果动态申请reg应该怎么办?
(这块的含义有些难以理解,待研究。)
***********************************************************
2) Note about "compatible" properties
These properties are optional, but recommended in devices and the root node.
The format of a "compatible" property is a list of concatenated zero
terminated strings. They allow a device to express its compatibility with a
family of similar devices, in some cases, allowing a single driver to match
against several devices regardless of their actual names.
3) Note about "name" properties
While earlier users of Open Firmware like Oldworld macintoshes tended to use
the actual device name for the "name" property, it's nowadays considered a
good practice to use a name that is closer to the device class (often equal
to device_type). For example, nowadays, Ethernet controllers are named
"ethernet", an additional "model" property defining precisely the chip
type/model, and "compatible" property defining the family in case a single
driver can driver more than one of these chips. However, the kernel doesn't
generally put any restriction on the "name" property; it is simply considered
good practice to follow the standard and its evolutions as closely as possible.
Note also that the new format version 16 makes the "name" property optional.
If it's absent for a node, then the node's unit name is then used to
reconstruct the name. That is, the part of the unit name before the "@" sign
is used (or the entire unit name if no "@" sign is present).
4) Note about node and property names and character set
While Open Firmware provides more flexible usage of 8859-1, this specification
enforces more strict rules. Nodes and properties should be comprised only of
ASCII characters 'a' to 'z', '0' to '9', ',', '.', '_', '+', '#', '?', and '-'.
Node names additionally allow uppercase characters 'A' to 'Z' (property names
should be lowercase. The fact that vendors like Apple don't respect this rule
is irrelevant here). Additionally, node and property names should always begin
with a character in the range 'a' to 'z' (or 'A' to 'Z' for node names).
The maximum number of characters for both nodes and property names is 31. In
the case of node names, this is only the leftmost part of a unit name (the pure
"name" property), it doesn't include the unit address which can extend beyond
that limit.
***********************************************************
练习:尝试一下不同的node或者property names。
实际上即使在name或者property names里面使用大写字母也不会报错,即使超过
了31个字符也不会报错。Anyway,遵守语法规则总是没错的^_^!
***********************************************************
5) Required nodes and properties
These are all that are currently required. However, it is strongly recommended
that you expose PCI host bridges as documented in the PCI binding to Open
Firmware, and your interrupt tree as documented in OF interrupt tree
specification.
a) The root node
The root node requires some properties to be present:
- model: This is your board name/model
- #address-cells: address representation for "root" devices
- #size-cells: the size representation for "root" devices
- compatible: the board "family" generally finds its way here, for example,
if you have 2 board models with a similar layout, that typically get
driven by the same platform code in the kernel, you would specify the
exact board model in the compatible property followed by an entry that
represents the SoC model.
The root node is also generally where you add additional properties specific
to your board like the serial number if any, that sort of thing. It is
recommended that if you add any "custom" property whose name may clash with
standard ones, you prefix them with your vendor name and a comma.
***********************************************************
练习:观察一下AM335x的root节点。
/ {
model = "TI AM335x maria_am335x";
compatible = "ti,maria_am335x", "ti,am33xx";
};
/ {
compatible = "ti,am33xx";
interrupt-parent = <&intc>;
};
/ {
#address-cells = <1>;
#size-cells = <1>;
chosen { };
aliases { };
memory { device_type = "memory"; reg = <0 0>; };
};
这三条root节点分别来自:
maria_am335x-common.dtsi
am33xx.dtsi
skeleton.dtsi
它们被maria_am335x.dts以各种不同的层次include。参考本系列的第一篇中关于include
的规则,当最顶层定义了从未定义过的property时,则把这项添加进入;当最顶层定义了底层定
义过的property时,则更新成最顶层的定义。所以,将上面的root节点整理一下就是下面这个
样子:
/ {
model = "TI AM335x maria_am335x";
compatible = "ti,maria_am335x", "ti,am33xx";
interrupt-parent = <&intc>;
#address-cells = <1>;
#size-cells = <1>;
chosen { };
aliases {
i2c0 = &i2c0;
/* ... */
};
memory {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
};
这样,root节点就和文档里面对应起来了!
***********************************************************
b) The /cpus node
This node is the parent of all individual CPU nodes. It doesn't have any
specific requirements, though it's generally good practice to have at least:
#address-cells = <00000001>
#size-cells = <00000000>
This defines that the "address" for a CPU is a single cell, and has no
meaningful size. This is not necessary but the kernel will assume that format
when reading the "reg" properties of a CPU node, see below
c) The /cpus/* nodes
So under /cpus, you are supposed to create a node for every CPU on the machine.
There is no specific restriction on the name of the CPU, though it's common to
call it <architeture>,<core>. For example, Apple uses PowerPC,G5 while IBM
users PowerPC,970FX. However, the Generic Names convention suggests that is
would be better to simply use 'cpu' for each node and use the compatible
property to identify the specific cpu core.
Required properties"
- device_type: has to be "cpu"
- reg: This is the physical CPU number, it's a single 32-bit cell and is also
used as-is as the unit number for constructing the unit name in the full
path. For example, with 2 CPUs, you would have the full path:
/cpus/PowerPC,970FX@0
/cpus/PowerPC,970FX@1
(unit addresses do not require leading zeroes)
- d-cache-block-size: one cell, L1 data cache block size in bytes (*)
- i-cache-block-size: one cell, L1 instruction cache block size in bytes
- d-cache-size: one cell, size of L1 data cache in bytes
- i-cache-size: one cell, size of L1 intruction cache in bytes
(*) The cache "block" size is the size on which the cache management
instructions operate. Historically, this document used the cache "line" size
here which is incorrect. The kernel will prefer the cache block size and will
fallback to line size for backward compatibility.
Recommended properties:
- timebase-frequency: a cell indicating the frequency of the timebase in Hz.
This is not directly used by the generic code, but you are welcome to
copy/paste the pSeries code for setting the kernel timebase/decrementer
calibration based on this value.
- clock-frequency: a cell indicating the CPU core clock frequency in Hz. A
new property will be defined for 64-bit values, but if your frequency is
< 4GHz, one cell is enough. Here as well as for the above, the common code
doesn't use that property, but you are welcome to re-use the pSeries or
Maple one. A future kernel version might provide a common function for
this.
- d-cache-line-size: one cell, L1 data cache line size in bytes if different
from the block size
- i-cache-line-size: one cell, L1 instruction cache line size in bytes if
different from the block size
You are welcome to add any property you find relevant to your board, like some
information about the mechanism used to soft-reset the CPUs. For example,
Apple puts the GPIO number for CPU soft reset lines in there as a "soft-reset"
property since they start secondary CPUs by soft-resetting them.
***********************************************************
练习:观察一下AM335x的cpus节点。
直接上整理好的结果:
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
cpu0-supply = <&dcdc2_reg>;
campatible = "arm,cortex-a8";
device_type = "cpu";
reg = <0>;
operation-points = <
/* kHz uV*/
720000 1285000
600000 1225000
500000 1125000
275000 1125000
>;
voltage-tolerance = <2>;
clocks = <&dpll_mpu_ck>;
clock-names = "cpu";
clock-latency = <300000>;
};
};
***********************************************************
d) the /memory node(s)
To define the physical memory layout of your board, you should create one
or more memory node(s). You can either create a single node with all memory
ranges in its reg property, or you can create several nodes, as you wish.
The unit address (@ part) used for the full path is the address of the first
range of memory defined by a given node. If you use a single memory node, this
will typically be @0.
- device_type: has to be "memory"
- reg: This property contains all the physical memory ranges of your board.
It's a list of addresses/sizes concatenated together, with the number of
cells of each defined by the #address-cells and #size-cells of the root
node. For example, with both of these properties being 2 like in the
example given earlier, a 970 based machine with 6Gb of RAM could typically
have a "reg" property here that looks like:
00000000 00000000 00000000 80000000
00000001 00000000 00000001 00000000
That is a range starting at 0 of 0x80000000 bytes and a range starting at
0x10000000 and of 0x10000000 bytes. You can see that there is no memory
covering the IO hole between 2Gb and 4Gb. Some vendors prefer splitting
those ranges into smaller segments, but the kernel doesn't care.
***********************************************************
练习:观察一下memory节点。
直接上整理好的结果:
memory {
device-type = "memory";
reg = <0x80000000 0x20000000>;
};
***********************************************************
e) The /chosen node
f) the /soc<SOCname> node
This node is used to represent a system-on-chip (SoC) and must be present if
the processor is SoC. The top-level soc node contains information that is
global to all devices on the SoC. The node name should contain a unit address
for the SoC, which is the base address of the memory-mapped register set for
the SoC. The name of an SoC node should start with "soc", and the remainder
of the name should represent the part number for the soc. For example, the
MPC8540's soc node would be called "soc8540".
***********************************************************
练习:观察一下soc节点。
直接上整理好的结果:
soc {
compatible = "ti,omap-infra";
mpu {
compatible = "ti,omap3-mpu";
ti,hwmods = "mpu";
};
};
***********************************************************
文章评论(0条评论)
登录后参与讨论