forked from Minki/linux
DeviceTree for 4.13:
- vsprintf format specifier %pOF for device_node's. This will enable us to stop storing the full node names. Conversion of users will happen next cycle. - Update documentation to point to DT specification instead of ePAPR. - Split out graph and property functions to a separate file. - New of-graph functions for ALSA - Add vendor prefixes for RISC-V, Linksys, iWave Systems, Roofull, Itead, and BananaPi. - Improve dtx_diff utility filename printing. -----BEGIN PGP SIGNATURE----- iQItBAABCAAXBQJZXpNsEBxyb2JoQGtlcm5lbC5vcmcACgkQ+vtdtY28YcO2gg// VxhXDs6+oTkBCUzVtEHue/yv44q8Sa7M3jY3/VqVSLa3Eopp/4dmDgBAtWYYX2ou KfUl0+yD4cSKhw6oxycwsaS61zf8JkM4sbXYQTphty/5lwxq0/i3OGj98Uk9w9JH kM+b1Wi7Z6GBzqh1GuS4E+ADSktMadxd0LugXZvDEMVQZusv/nzWxzq/bdMUqW19 0nvBL9ABRAPirhBuMSWpYlEEkwQn7JF3LO3i8IBDhhFzMsvbfR7cTp+ydt6I2pk8 h8DxlsaPIOWH5KePNEmzsd1VlV/HcNl7/vZb0ev0Eb94TLHJRJ7V0ZMQxc5vxHgN x6aMlBLHGzG6LI5CV30pWAD/qrrtXNbqmlj1Qjd+FXen6NuQSngSfo5aXzXrM6X5 ZUD7ou9KzYObraOarU6w2qSICok85bGQHOiBQDVTmE4E/4AVscnc1VQi/rTHrt2O Yt3AV8iwaum8q2PVOVKdy8tu7x/7BzBdSObYtjjMIuWcrInnlIyUkmehtCl38kqV fd6OIVEOhTJTr0CYDiXEbKtG81j7JhoREdVZvzcEhWFGt/98Rjc9tkTihhFzky4m D6lpzpf8mvemrBiMegyQbhVcfHyo0fJe+6giV7cssf2Xhe1QkC15UXywbccO7xFJ nf3yqCl8YVEPG0l1MrR+YEHHcnr4ZIEZpejOv+SzZeg= =DNwf -----END PGP SIGNATURE----- Merge tag 'devicetree-for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux Pull DeviceTree updates from Rob Herring: - vsprintf format specifier %pOF for device_node's. This will enable us to stop storing the full node names. Conversion of users will happen next cycle. - Update documentation to point to DT specification instead of ePAPR. - Split out graph and property functions to a separate file. - New of-graph functions for ALSA - Add vendor prefixes for RISC-V, Linksys, iWave Systems, Roofull, Itead, and BananaPi. - Improve dtx_diff utility filename printing. * tag 'devicetree-for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (32 commits) of: document /sys/firmware/fdt dt-bindings: Add RISC-V vendor prefix vsprintf: Add %p extension "%pOF" for device tree of: find_node_by_full_name rewrite to compare each level of: use kbasename instead of open coding dt-bindings: thermal: add file extension to brcm,ns-thermal of: update ePAPR references to point to Devicetree Specification scripts/dtc: dtx_diff - Show real file names in diff header of: detect invalid phandle in overlay of: be consistent in form of file mode of: make __of_attach_node() static of: address.c header comment typo of: fdt.c header comment typo of: make of_fdt_is_compatible() static dt-bindings: display-timing.txt convert non-ascii characters to ascii Documentation: remove overlay-notes reference to non-existent file dt-bindings: usb: exynos-usb: Add missing required VDD properties dt-bindings: Add vendor prefix for Linksys MAINTAINERS: add device tree ABI documentation file of: Add vendor prefix for iWave Systems Technologies Pvt. Ltd ...
This commit is contained in:
commit
dd6ec12f3b
@ -1,6 +1,6 @@
|
||||
What: /sys/firmware/devicetree/*
|
||||
Date: November 2013
|
||||
Contact: Grant Likely <grant.likely@linaro.org>
|
||||
Contact: Grant Likely <grant.likely@arm.com>, devicetree@vger.kernel.org
|
||||
Description:
|
||||
When using OpenFirmware or a Flattened Device Tree to enumerate
|
||||
hardware, the device tree structure will be exposed in this
|
||||
@ -26,3 +26,27 @@ Description:
|
||||
name plus address). Properties are represented as files
|
||||
in the directory. The contents of each file is the exact
|
||||
binary data from the device tree.
|
||||
|
||||
What: /sys/firmware/fdt
|
||||
Date: February 2015
|
||||
KernelVersion: 3.19
|
||||
Contact: Frank Rowand <frowand.list@gmail.com>, devicetree@vger.kernel.org
|
||||
Description:
|
||||
Exports the FDT blob that was passed to the kernel by
|
||||
the bootloader. This allows userland applications such
|
||||
as kexec to access the raw binary. This blob is also
|
||||
useful when debugging since it contains any changes
|
||||
made to the blob by the bootloader.
|
||||
|
||||
The fact that this node does not reside under
|
||||
/sys/firmware/device-tree is deliberate: FDT is also used
|
||||
on arm64 UEFI/ACPI systems to communicate just the UEFI
|
||||
and ACPI entry points, but the FDT is never unflattened
|
||||
and used to configure the system.
|
||||
|
||||
A CRC32 checksum is calculated over the entire FDT
|
||||
blob, and verified at late_initcall time. The sysfs
|
||||
entry is instantiated only if the checksum is valid,
|
||||
i.e., if the FDT blob has not been modified in the mean
|
||||
time. Otherwise, a warning is printed.
|
||||
Users: kexec, debugging
|
||||
|
@ -11,13 +11,6 @@ clusters, through memory mapped interface, with a global control register
|
||||
space and multiple sets of interface control registers, one per slave
|
||||
interface.
|
||||
|
||||
Bindings for the CCI node follow the ePAPR standard, available from:
|
||||
|
||||
www.power.org/documentation/epapr-version-1-1/
|
||||
|
||||
with the addition of the bindings described in this document which are
|
||||
specific to ARM.
|
||||
|
||||
* CCI interconnect node
|
||||
|
||||
Description: Describes a CCI cache coherent Interconnect component
|
||||
@ -50,10 +43,10 @@ specific to ARM.
|
||||
as a tuple of cells, containing child address,
|
||||
parent address and the size of the region in the
|
||||
child address space.
|
||||
Definition: A standard property. Follow rules in the ePAPR for
|
||||
hierarchical bus addressing. CCI interfaces
|
||||
addresses refer to the parent node addressing
|
||||
scheme to declare their register bases.
|
||||
Definition: A standard property. Follow rules in the Devicetree
|
||||
Specification for hierarchical bus addressing. CCI
|
||||
interfaces addresses refer to the parent node
|
||||
addressing scheme to declare their register bases.
|
||||
|
||||
CCI interconnect node can define the following child nodes:
|
||||
|
||||
|
@ -6,9 +6,9 @@ The device tree allows to describe the layout of CPUs in a system through
|
||||
the "cpus" node, which in turn contains a number of subnodes (ie "cpu")
|
||||
defining properties for every cpu.
|
||||
|
||||
Bindings for CPU nodes follow the ePAPR v1.1 standard, available from:
|
||||
Bindings for CPU nodes follow the Devicetree Specification, available from:
|
||||
|
||||
https://www.power.org/documentation/epapr-version-1-1/
|
||||
https://www.devicetree.org/specifications/
|
||||
|
||||
with updates for 32-bit and 64-bit ARM systems provided in this document.
|
||||
|
||||
@ -16,8 +16,8 @@ with updates for 32-bit and 64-bit ARM systems provided in this document.
|
||||
Convention used in this document
|
||||
================================
|
||||
|
||||
This document follows the conventions described in the ePAPR v1.1, with
|
||||
the addition:
|
||||
This document follows the conventions described in the Devicetree
|
||||
Specification, with the addition:
|
||||
|
||||
- square brackets define bitfields, eg reg[7:0] value of the bitfield in
|
||||
the reg property contained in bits 7 down to 0
|
||||
@ -26,8 +26,9 @@ the addition:
|
||||
cpus and cpu node bindings definition
|
||||
=====================================
|
||||
|
||||
The ARM architecture, in accordance with the ePAPR, requires the cpus and cpu
|
||||
nodes to be present and contain the properties described below.
|
||||
The ARM architecture, in accordance with the Devicetree Specification,
|
||||
requires the cpus and cpu nodes to be present and contain the properties
|
||||
described below.
|
||||
|
||||
- cpus node
|
||||
|
||||
|
@ -695,5 +695,5 @@ cpus {
|
||||
[4] ARM Architecture Reference Manuals
|
||||
http://infocenter.arm.com/help/index.jsp
|
||||
|
||||
[5] ePAPR standard
|
||||
https://www.power.org/documentation/epapr-version-1-1/
|
||||
[5] Devicetree Specification
|
||||
https://www.devicetree.org/specifications/
|
||||
|
@ -4,8 +4,8 @@ ARM cores often have a separate L2C210/L2C220/L2C310 (also known as PL210/PL220/
|
||||
PL310 and variants) based level 2 cache controller. All these various implementations
|
||||
of the L2 cache controller have compatible programming models (Note 1).
|
||||
Some of the properties that are just prefixed "cache-*" are taken from section
|
||||
3.7.3 of the ePAPR v1.1 specification which can be found at:
|
||||
https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf
|
||||
3.7.3 of the Devicetree Specification which can be found at:
|
||||
https://www.devicetree.org/specifications/
|
||||
|
||||
The ARM L2 cache representation in the device tree should be done as follows:
|
||||
|
||||
|
@ -29,9 +29,9 @@ corresponding to the system hierarchy; syntactically they are defined as device
|
||||
tree nodes.
|
||||
|
||||
The remainder of this document provides the topology bindings for ARM, based
|
||||
on the ePAPR standard, available from:
|
||||
on the Devicetree Specification, available from:
|
||||
|
||||
http://www.power.org/documentation/epapr-version-1-1/
|
||||
https://www.devicetree.org/specifications/
|
||||
|
||||
If not stated otherwise, whenever a reference to a cpu node phandle is made its
|
||||
value must point to a cpu node compliant with the cpu node bindings as
|
||||
|
@ -10,7 +10,7 @@ enabled for child devices connected to the bus (either on-SoC or externally)
|
||||
to function.
|
||||
|
||||
While "simple-pm-bus" follows the "simple-bus" set of properties, as specified
|
||||
in ePAPR, it is not an extension of "simple-bus".
|
||||
in the Devicetree Specification, it is not an extension of "simple-bus".
|
||||
|
||||
|
||||
Required properties:
|
||||
|
@ -10,7 +10,8 @@ stdout-path property
|
||||
--------------------
|
||||
|
||||
Device trees may specify the device to be used for boot console output
|
||||
with a stdout-path property under /chosen, as described in ePAPR, e.g.
|
||||
with a stdout-path property under /chosen, as described in the Devicetree
|
||||
Specification, e.g.
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
|
@ -1,6 +1,6 @@
|
||||
Common properties
|
||||
|
||||
The ePAPR specification does not define any properties related to hardware
|
||||
The Devicetree Specification does not define any properties related to hardware
|
||||
byteswapping, but endianness issues show up frequently in porting Linux to
|
||||
different machine types. This document attempts to provide a consistent
|
||||
way of handling byteswapping across drivers.
|
||||
|
@ -118,8 +118,8 @@ PROPERTIES
|
||||
Definition: A list of clock name strings in the same order as the
|
||||
clocks property.
|
||||
|
||||
Note: All other standard properties (see the ePAPR) are allowed
|
||||
but are optional.
|
||||
Note: All other standard properties (see the Devicetree Specification)
|
||||
are allowed but are optional.
|
||||
|
||||
|
||||
EXAMPLE
|
||||
|
@ -55,8 +55,8 @@ PROPERTIES
|
||||
triplet that includes the child address, parent address, &
|
||||
length.
|
||||
|
||||
Note: All other standard properties (see the ePAPR) are allowed
|
||||
but are optional.
|
||||
Note: All other standard properties (see the Devicetree Specification)
|
||||
are allowed but are optional.
|
||||
|
||||
EXAMPLE
|
||||
crypto@a0000 {
|
||||
|
@ -57,11 +57,11 @@ can be specified.
|
||||
The parameters are defined as:
|
||||
|
||||
+----------+-------------------------------------+----------+-------+
|
||||
| | ↑ | | |
|
||||
| | ^ | | |
|
||||
| | |vback_porch | | |
|
||||
| | ↓ | | |
|
||||
| | v | | |
|
||||
+----------#######################################----------+-------+
|
||||
| # ↑ # | |
|
||||
| # ^ # | |
|
||||
| # | # | |
|
||||
| hback # | # hfront | hsync |
|
||||
| porch # | hactive # porch | len |
|
||||
@ -69,15 +69,15 @@ The parameters are defined as:
|
||||
| # | # | |
|
||||
| # |vactive # | |
|
||||
| # | # | |
|
||||
| # ↓ # | |
|
||||
| # v # | |
|
||||
+----------#######################################----------+-------+
|
||||
| | ↑ | | |
|
||||
| | ^ | | |
|
||||
| | |vfront_porch | | |
|
||||
| | ↓ | | |
|
||||
| | v | | |
|
||||
+----------+-------------------------------------+----------+-------+
|
||||
| | ↑ | | |
|
||||
| | ^ | | |
|
||||
| | |vsync_len | | |
|
||||
| | ↓ | | |
|
||||
| | v | | |
|
||||
+----------+-------------------------------------+----------+-------+
|
||||
|
||||
Example:
|
||||
|
@ -34,7 +34,7 @@ remote device, an 'endpoint' child node must be provided for each link.
|
||||
If more than one port is present in a device node or there is more than one
|
||||
endpoint at a port, or a port node needs to be associated with a selected
|
||||
hardware interface, a common scheme using '#address-cells', '#size-cells'
|
||||
and 'reg' properties is used number the nodes.
|
||||
and 'reg' properties is used to number the nodes.
|
||||
|
||||
device {
|
||||
...
|
||||
@ -89,9 +89,9 @@ Links between endpoints
|
||||
|
||||
Each endpoint should contain a 'remote-endpoint' phandle property that points
|
||||
to the corresponding endpoint in the port of the remote device. In turn, the
|
||||
remote endpoint should contain a 'remote-endpoint' property. If it has one,
|
||||
it must not point to another than the local endpoint. Two endpoints with their
|
||||
'remote-endpoint' phandles pointing at each other form a link between the
|
||||
remote endpoint should contain a 'remote-endpoint' property. If it has one, it
|
||||
must not point to anything other than the local endpoint. Two endpoints with
|
||||
their 'remote-endpoint' phandles pointing at each other form a link between the
|
||||
containing ports.
|
||||
|
||||
device-1 {
|
||||
@ -110,13 +110,12 @@ device-2 {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
|
||||
If there is more than one 'port' or more than one 'endpoint' node or 'reg'
|
||||
property is present in port and/or endpoint nodes the following properties
|
||||
are required in a relevant parent node:
|
||||
property present in the port and/or endpoint nodes then the following
|
||||
properties are required in a relevant parent node:
|
||||
|
||||
- #address-cells : number of cells required to define port/endpoint
|
||||
identifier, should be 1.
|
||||
|
@ -3,6 +3,7 @@ Austrian Microsystems AS3935 Franklin lightning sensor device driver
|
||||
Required properties:
|
||||
- compatible: must be "ams,as3935"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-max-frequency: specifies maximum SPI clock frequency
|
||||
- spi-cpha: SPI Mode 1. Refer to spi/spi-bus.txt for generic SPI
|
||||
slave node bindings.
|
||||
- interrupt-parent : should be the phandle for the interrupt controller
|
||||
@ -21,6 +22,7 @@ Example:
|
||||
as3935@0 {
|
||||
compatible = "ams,as3935";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <400000>;
|
||||
spi-cpha;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 1>;
|
||||
|
@ -92,7 +92,6 @@ Example 2:
|
||||
|
||||
* References
|
||||
|
||||
[1] Power.org (TM) Standard for Embedded Power Architecture (TM) Platform
|
||||
Requirements (ePAPR), Version 1.0, July 2008.
|
||||
(http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf)
|
||||
[1] Devicetree Specification
|
||||
(https://www.devicetree.org/specifications/)
|
||||
|
||||
|
@ -8,7 +8,8 @@ The following properties are common to the Ethernet controllers:
|
||||
property;
|
||||
- max-speed: number, specifies maximum speed in Mbit/s supported by the device;
|
||||
- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
|
||||
the maximum frame size (there's contradiction in ePAPR).
|
||||
the maximum frame size (there's contradiction in the Devicetree
|
||||
Specification).
|
||||
- phy-mode: string, operation mode of the PHY interface. This is now a de-facto
|
||||
standard property; supported values are:
|
||||
* "internal"
|
||||
@ -35,9 +36,11 @@ The following properties are common to the Ethernet controllers:
|
||||
* "rxaui"
|
||||
* "xaui"
|
||||
* "10gbase-kr" (10GBASE-KR, XFI, SFI)
|
||||
- phy-connection-type: the same as "phy-mode" property but described in ePAPR;
|
||||
- phy-connection-type: the same as "phy-mode" property but described in the
|
||||
Devicetree Specification;
|
||||
- phy-handle: phandle, specifies a reference to a node representing a PHY
|
||||
device; this property is described in ePAPR and so preferred;
|
||||
device; this property is described in the Devicetree Specification and so
|
||||
preferred;
|
||||
- phy: the same as "phy-handle" property, not recommended for new bindings.
|
||||
- phy-device: the same as "phy-handle" property, not recommended for new
|
||||
bindings.
|
||||
|
@ -31,7 +31,7 @@ mmc3: mmc@01c12000 {
|
||||
non-removable;
|
||||
status = "okay";
|
||||
|
||||
brcmf: bcrmf@1 {
|
||||
brcmf: wifi@1 {
|
||||
reg = <1>;
|
||||
compatible = "brcm,bcm4329-fmac";
|
||||
interrupt-parent = <&pio>;
|
||||
|
@ -3,10 +3,10 @@ Power Architecture CPU Binding
|
||||
Copyright 2013 Freescale Semiconductor Inc.
|
||||
|
||||
Power Architecture CPUs in Freescale SOCs are represented in device trees as
|
||||
per the definition in ePAPR.
|
||||
per the definition in the Devicetree Specification.
|
||||
|
||||
In addition to the ePAPR definitions, the properties defined below may be
|
||||
present on CPU nodes.
|
||||
In addition to the the Devicetree Specification definitions, the properties
|
||||
defined below may be present on CPU nodes.
|
||||
|
||||
PROPERTIES
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
Freescale L2 Cache Controller
|
||||
|
||||
L2 cache is present in Freescale's QorIQ and QorIQ Qonverge platforms.
|
||||
The cache bindings explained below are ePAPR compliant
|
||||
The cache bindings explained below are Devicetree Specification compliant
|
||||
|
||||
Required Properties:
|
||||
|
||||
|
@ -124,8 +124,8 @@ Port-Write Unit:
|
||||
A single IRQ that handles port-write conditions is
|
||||
specified by this property. (Typically shared with error).
|
||||
|
||||
Note: All other standard properties (see the ePAPR) are allowed
|
||||
but are optional.
|
||||
Note: All other standard properties (see the Devicetree Specification)
|
||||
are allowed but are optional.
|
||||
|
||||
Example:
|
||||
rmu: rmu@d3000 {
|
||||
|
@ -72,7 +72,8 @@ the following properties:
|
||||
represents the LIODN associated with maintenance transactions
|
||||
for the port.
|
||||
|
||||
Note: All other standard properties (see ePAPR) are allowed but are optional.
|
||||
Note: All other standard properties (see the Devicetree Specification)
|
||||
are allowed but are optional.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -92,6 +92,8 @@ Required properties:
|
||||
parent's address space
|
||||
- clocks: Clock IDs array as required by the controller.
|
||||
- clock-names: names of clocks correseponding to IDs in the clock property
|
||||
- vdd10-supply: 1.0V powr supply
|
||||
- vdd33-supply: 3.0V/3.3V power supply
|
||||
|
||||
Sub-nodes:
|
||||
The dwc3 core should be added as subnode to Exynos dwc3 glue.
|
||||
@ -107,6 +109,8 @@ Example:
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
vdd10-supply = <&ldo11_reg>;
|
||||
vdd33-supply = <&ldo9_reg>;
|
||||
|
||||
dwc3 {
|
||||
compatible = "synopsys,dwc3";
|
||||
|
@ -45,6 +45,7 @@ avia avia semiconductor
|
||||
avic Shanghai AVIC Optoelectronics Co., Ltd.
|
||||
axentia Axentia Technologies AB
|
||||
axis Axis Communications AB
|
||||
bananapi BIPAI KEJI LIMITED
|
||||
boe BOE Technology Group Co., Ltd.
|
||||
bosch Bosch Sensortec GmbH
|
||||
boundary Boundary Devices Inc.
|
||||
@ -159,6 +160,8 @@ iom Iomega Corporation
|
||||
isee ISEE 2007 S.L.
|
||||
isil Intersil
|
||||
issi Integrated Silicon Solutions Inc.
|
||||
itead ITEAD Intelligent Systems Co.Ltd
|
||||
iwave iWave Systems Technologies Pvt. Ltd.
|
||||
jdi Japan Display Inc.
|
||||
jedec JEDEC Solid State Technology Association
|
||||
karo Ka-Ro electronics GmbH
|
||||
@ -177,6 +180,7 @@ lg LG Corporation
|
||||
libretech Shenzhen Libre Technology Co., Ltd
|
||||
licheepi Lichee Pi
|
||||
linaro Linaro Limited
|
||||
linksys Belkin International, Inc. (Linksys)
|
||||
linux Linux-specific binding
|
||||
lltc Linear Technology Corporation
|
||||
lsi LSI Corp. (LSI Logic)
|
||||
@ -269,8 +273,10 @@ renesas Renesas Electronics Corporation
|
||||
richtek Richtek Technology Corporation
|
||||
ricoh Ricoh Co. Ltd.
|
||||
rikomagic Rikomagic Tech Corp. Ltd
|
||||
riscv RISC-V Foundation
|
||||
rockchip Fuzhou Rockchip Electronics Co., Ltd
|
||||
rohm ROHM Semiconductor Co., Ltd
|
||||
roofull Shenzhen Roofull Technology Co, Ltd
|
||||
samsung Samsung Semiconductor
|
||||
samtec Samtec/Softing company
|
||||
sandisk Sandisk Corporation
|
||||
|
@ -1413,7 +1413,7 @@ Optional property:
|
||||
from DMA operations originating from the bus. It provides a means of
|
||||
defining a mapping or translation between the physical address space of
|
||||
the bus and the physical address space of the parent of the bus.
|
||||
(for more information see ePAPR specification)
|
||||
(for more information see the Devicetree Specification)
|
||||
|
||||
* DMA Bus child
|
||||
Optional property:
|
||||
|
@ -3,8 +3,7 @@ Device Tree Overlay Notes
|
||||
|
||||
This document describes the implementation of the in-kernel
|
||||
device tree overlay functionality residing in drivers/of/overlay.c and is a
|
||||
companion document to Documentation/devicetree/dt-object-internal.txt[1] &
|
||||
Documentation/devicetree/dynamic-resolution-notes.txt[2]
|
||||
companion document to Documentation/devicetree/dynamic-resolution-notes.txt[1]
|
||||
|
||||
How overlays work
|
||||
-----------------
|
||||
@ -16,8 +15,7 @@ Since the kernel mainly deals with devices, any new device node that result
|
||||
in an active device should have it created while if the device node is either
|
||||
disabled or removed all together, the affected device should be deregistered.
|
||||
|
||||
Lets take an example where we have a foo board with the following base tree
|
||||
which is taken from [1].
|
||||
Lets take an example where we have a foo board with the following base tree:
|
||||
|
||||
---- foo.dts -----------------------------------------------------------------
|
||||
/* FOO platform */
|
||||
@ -36,7 +34,7 @@ which is taken from [1].
|
||||
};
|
||||
---- foo.dts -----------------------------------------------------------------
|
||||
|
||||
The overlay bar.dts, when loaded (and resolved as described in [2]) should
|
||||
The overlay bar.dts, when loaded (and resolved as described in [1]) should
|
||||
|
||||
---- bar.dts -----------------------------------------------------------------
|
||||
/plugin/; /* allow undefined label references and record them */
|
||||
|
@ -387,7 +387,7 @@ static void __init harmony_init_machine(void)
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
"simple-bus" is defined in the ePAPR 1.0 specification as a property
|
||||
"simple-bus" is defined in the Devicetree Specification as a property
|
||||
meaning a simple memory mapped bus, so the of_platform_populate() code
|
||||
could be written to just assume simple-bus compatible nodes will
|
||||
always be traversed. However, we pass it in as an argument so that
|
||||
|
@ -275,6 +275,42 @@ struct va_format:
|
||||
|
||||
Passed by reference.
|
||||
|
||||
kobjects:
|
||||
%pO
|
||||
|
||||
Base specifier for kobject based structs. Must be followed with
|
||||
character for specific type of kobject as listed below:
|
||||
|
||||
Device tree nodes:
|
||||
|
||||
%pOF[fnpPcCF]
|
||||
|
||||
For printing device tree nodes. The optional arguments are:
|
||||
f device node full_name
|
||||
n device node name
|
||||
p device node phandle
|
||||
P device node path spec (name + @unit)
|
||||
F device node flags
|
||||
c major compatible string
|
||||
C full compatible string
|
||||
Without any arguments prints full_name (same as %pOFf)
|
||||
The separator when using multiple arguments is ':'
|
||||
|
||||
Examples:
|
||||
|
||||
%pOF /foo/bar@0 - Node full name
|
||||
%pOFf /foo/bar@0 - Same as above
|
||||
%pOFfp /foo/bar@0:10 - Node full name + phandle
|
||||
%pOFfcF /foo/bar@0:foo,device:--P- - Node full name +
|
||||
major compatible string +
|
||||
node flags
|
||||
D - dynamic
|
||||
d - detached
|
||||
P - Populated
|
||||
B - Populated bus
|
||||
|
||||
Passed by reference.
|
||||
|
||||
struct clk:
|
||||
|
||||
%pC pll1
|
||||
|
@ -41,9 +41,9 @@ The scheme below assumes that the kernel is loaded below 0x40000000.
|
||||
00..1F -> 00 -> 00 -> 00
|
||||
|
||||
The default location of IO peripherals is above 0xf0000000. This may be changed
|
||||
using a "ranges" property in a device tree simple-bus node. See ePAPR 1.1, §6.5
|
||||
for details on the syntax and semantic of simple-bus nodes. The following
|
||||
limitations apply:
|
||||
using a "ranges" property in a device tree simple-bus node. See the Devicetree
|
||||
Specification, section 4.5 for details on the syntax and semantics of
|
||||
simple-bus nodes. The following limitations apply:
|
||||
|
||||
1. Only top level simple-bus nodes are considered
|
||||
|
||||
|
@ -9664,6 +9664,7 @@ S: Maintained
|
||||
F: drivers/of/
|
||||
F: include/linux/of*.h
|
||||
F: scripts/dtc/
|
||||
F: Documentation/ABI/testing/sysfs-firmware-ofw
|
||||
|
||||
OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
|
||||
M: Rob Herring <robh+dt@kernel.org>
|
||||
|
@ -1,4 +1,4 @@
|
||||
obj-y = base.o device.o platform.o
|
||||
obj-y = base.o device.o platform.o property.o
|
||||
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
|
||||
obj-$(CONFIG_OF_FLATTREE) += fdt.o
|
||||
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
||||
|
@ -710,7 +710,7 @@ static int __of_address_to_resource(struct device_node *dev,
|
||||
*
|
||||
* Note that if your address is a PIO address, the conversion will fail if
|
||||
* the physical address can't be internally converted to an IO token with
|
||||
* pci_address_to_pio(), that is because it's either called to early or it
|
||||
* pci_address_to_pio(), that is because it's either called too early or it
|
||||
* can't be matched to any host bridge IO space
|
||||
*/
|
||||
int of_address_to_resource(struct device_node *dev, int index,
|
||||
|
@ -155,7 +155,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp)
|
||||
|
||||
sysfs_bin_attr_init(&pp->attr);
|
||||
pp->attr.attr.name = safe_name(&np->kobj, pp->name);
|
||||
pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
|
||||
pp->attr.attr.mode = secure ? 0400 : 0444;
|
||||
pp->attr.size = secure ? 0 : pp->length;
|
||||
pp->attr.read = of_node_property_read;
|
||||
|
||||
@ -773,16 +773,31 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
|
||||
return NULL;
|
||||
|
||||
__for_each_child_of_node(parent, child) {
|
||||
const char *name = strrchr(child->full_name, '/');
|
||||
if (WARN(!name, "malformed device_node %s\n", child->full_name))
|
||||
continue;
|
||||
name++;
|
||||
const char *name = kbasename(child->full_name);
|
||||
if (strncmp(path, name, len) == 0 && (strlen(name) == len))
|
||||
return child;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct device_node *__of_find_node_by_full_path(struct device_node *node,
|
||||
const char *path)
|
||||
{
|
||||
const char *separator = strchr(path, ':');
|
||||
|
||||
while (node && *path == '/') {
|
||||
struct device_node *tmp = node;
|
||||
|
||||
path++; /* Increment past '/' delimiter */
|
||||
node = __of_find_node_by_path(node, path);
|
||||
of_node_put(tmp);
|
||||
path = strchrnul(path, '/');
|
||||
if (separator && separator < path)
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_find_node_opts_by_path - Find a node matching a full OF path
|
||||
* @path: Either the full path to match, or if the path does not
|
||||
@ -842,16 +857,7 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
|
||||
raw_spin_lock_irqsave(&devtree_lock, flags);
|
||||
if (!np)
|
||||
np = of_node_get(of_root);
|
||||
while (np && *path == '/') {
|
||||
struct device_node *tmp = np;
|
||||
|
||||
path++; /* Increment past '/' delimiter */
|
||||
np = __of_find_node_by_path(np, path);
|
||||
of_node_put(tmp);
|
||||
path = strchrnul(path, '/');
|
||||
if (separator && separator < path)
|
||||
break;
|
||||
}
|
||||
np = __of_find_node_by_full_path(np, path);
|
||||
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
||||
return np;
|
||||
}
|
||||
@ -1113,458 +1119,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
|
||||
}
|
||||
EXPORT_SYMBOL(of_find_node_by_phandle);
|
||||
|
||||
/**
|
||||
* of_property_count_elems_of_size - Count the number of elements in a property
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @elem_size: size of the individual element
|
||||
*
|
||||
* Search for a property in a device node and count the number of elements of
|
||||
* size elem_size in it. Returns number of elements on sucess, -EINVAL if the
|
||||
* property does not exist or its length does not match a multiple of elem_size
|
||||
* and -ENODATA if the property does not have a value.
|
||||
*/
|
||||
int of_property_count_elems_of_size(const struct device_node *np,
|
||||
const char *propname, int elem_size)
|
||||
{
|
||||
struct property *prop = of_find_property(np, propname, NULL);
|
||||
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
|
||||
if (prop->length % elem_size != 0) {
|
||||
pr_err("size of %s in node %s is not a multiple of %d\n",
|
||||
propname, np->full_name, elem_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return prop->length / elem_size;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
|
||||
|
||||
/**
|
||||
* of_find_property_value_of_size
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @min: minimum allowed length of property value
|
||||
* @max: maximum allowed length of property value (0 means unlimited)
|
||||
* @len: if !=NULL, actual length is written to here
|
||||
*
|
||||
* Search for a property in a device node and valid the requested size.
|
||||
* Returns the property value on success, -EINVAL if the property does not
|
||||
* exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data is too small or too large.
|
||||
*
|
||||
*/
|
||||
static void *of_find_property_value_of_size(const struct device_node *np,
|
||||
const char *propname, u32 min, u32 max, size_t *len)
|
||||
{
|
||||
struct property *prop = of_find_property(np, propname, NULL);
|
||||
|
||||
if (!prop)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (!prop->value)
|
||||
return ERR_PTR(-ENODATA);
|
||||
if (prop->length < min)
|
||||
return ERR_PTR(-EOVERFLOW);
|
||||
if (max && prop->length > max)
|
||||
return ERR_PTR(-EOVERFLOW);
|
||||
|
||||
if (len)
|
||||
*len = prop->length;
|
||||
|
||||
return prop->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_property_read_u32_index - Find and read a u32 from a multi-value property.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @index: index of the u32 in the list of values
|
||||
* @out_value: pointer to return value, modified only if no error.
|
||||
*
|
||||
* Search for a property in a device node and read nth 32-bit value from
|
||||
* it. Returns 0 on success, -EINVAL if the property does not exist,
|
||||
* -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data isn't large enough.
|
||||
*
|
||||
* The out_value is modified only if a valid u32 value can be decoded.
|
||||
*/
|
||||
int of_property_read_u32_index(const struct device_node *np,
|
||||
const char *propname,
|
||||
u32 index, u32 *out_value)
|
||||
{
|
||||
const u32 *val = of_find_property_value_of_size(np, propname,
|
||||
((index + 1) * sizeof(*out_value)),
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
*out_value = be32_to_cpup(((__be32 *)val) + index);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_u32_index);
|
||||
|
||||
/**
|
||||
* of_property_read_u64_index - Find and read a u64 from a multi-value property.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @index: index of the u64 in the list of values
|
||||
* @out_value: pointer to return value, modified only if no error.
|
||||
*
|
||||
* Search for a property in a device node and read nth 64-bit value from
|
||||
* it. Returns 0 on success, -EINVAL if the property does not exist,
|
||||
* -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data isn't large enough.
|
||||
*
|
||||
* The out_value is modified only if a valid u64 value can be decoded.
|
||||
*/
|
||||
int of_property_read_u64_index(const struct device_node *np,
|
||||
const char *propname,
|
||||
u32 index, u64 *out_value)
|
||||
{
|
||||
const u64 *val = of_find_property_value_of_size(np, propname,
|
||||
((index + 1) * sizeof(*out_value)),
|
||||
0, NULL);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
*out_value = be64_to_cpup(((__be64 *)val) + index);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_u64_index);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u8_array - Find and read an array of u8 from a
|
||||
* property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 8-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* dts entry of array should be like:
|
||||
* property = /bits/ 8 <0x50 0x60 0x70>;
|
||||
*
|
||||
* The out_values is modified only if a valid u8 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u8_array(const struct device_node *np,
|
||||
const char *propname, u8 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const u8 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--)
|
||||
*out_values++ = *val++;
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u16_array - Find and read an array of u16 from a
|
||||
* property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 16-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* dts entry of array should be like:
|
||||
* property = /bits/ 16 <0x5000 0x6000 0x7000>;
|
||||
*
|
||||
* The out_values is modified only if a valid u16 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u16_array(const struct device_node *np,
|
||||
const char *propname, u16 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const __be16 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--)
|
||||
*out_values++ = be16_to_cpup(val++);
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u32_array - Find and read an array of 32 bit
|
||||
* integers from a property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 32-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* The out_values is modified only if a valid u32 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u32_array(const struct device_node *np,
|
||||
const char *propname, u32 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const __be32 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--)
|
||||
*out_values++ = be32_to_cpup(val++);
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
|
||||
|
||||
/**
|
||||
* of_property_read_u64 - Find and read a 64 bit integer from a property
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_value: pointer to return value, modified only if return value is 0.
|
||||
*
|
||||
* Search for a property in a device node and read a 64-bit value from
|
||||
* it. Returns 0 on success, -EINVAL if the property does not exist,
|
||||
* -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data isn't large enough.
|
||||
*
|
||||
* The out_value is modified only if a valid u64 value can be decoded.
|
||||
*/
|
||||
int of_property_read_u64(const struct device_node *np, const char *propname,
|
||||
u64 *out_value)
|
||||
{
|
||||
const __be32 *val = of_find_property_value_of_size(np, propname,
|
||||
sizeof(*out_value),
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
*out_value = of_read_number(val, 2);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_u64);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u64_array - Find and read an array of 64 bit
|
||||
* integers from a property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 64-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* The out_values is modified only if a valid u64 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u64_array(const struct device_node *np,
|
||||
const char *propname, u64 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const __be32 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--) {
|
||||
*out_values++ = of_read_number(val, 2);
|
||||
val += 2;
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
|
||||
|
||||
/**
|
||||
* of_property_read_string - Find and read a string from a property
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_string: pointer to null terminated return string, modified only if
|
||||
* return value is 0.
|
||||
*
|
||||
* Search for a property in a device tree node and retrieve a null
|
||||
* terminated string value (pointer to data, not a copy). Returns 0 on
|
||||
* success, -EINVAL if the property does not exist, -ENODATA if property
|
||||
* does not have a value, and -EILSEQ if the string is not null-terminated
|
||||
* within the length of the property data.
|
||||
*
|
||||
* The out_string pointer is modified only if a valid string can be decoded.
|
||||
*/
|
||||
int of_property_read_string(const struct device_node *np, const char *propname,
|
||||
const char **out_string)
|
||||
{
|
||||
const struct property *prop = of_find_property(np, propname, NULL);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
if (strnlen(prop->value, prop->length) >= prop->length)
|
||||
return -EILSEQ;
|
||||
*out_string = prop->value;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_string);
|
||||
|
||||
/**
|
||||
* of_property_match_string() - Find string in a list and return index
|
||||
* @np: pointer to node containing string list property
|
||||
* @propname: string list property name
|
||||
* @string: pointer to string to search for in string list
|
||||
*
|
||||
* This function searches a string list property and returns the index
|
||||
* of a specific string value.
|
||||
*/
|
||||
int of_property_match_string(const struct device_node *np, const char *propname,
|
||||
const char *string)
|
||||
{
|
||||
const struct property *prop = of_find_property(np, propname, NULL);
|
||||
size_t l;
|
||||
int i;
|
||||
const char *p, *end;
|
||||
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
|
||||
p = prop->value;
|
||||
end = p + prop->length;
|
||||
|
||||
for (i = 0; p < end; i++, p += l) {
|
||||
l = strnlen(p, end - p) + 1;
|
||||
if (p + l > end)
|
||||
return -EILSEQ;
|
||||
pr_debug("comparing %s with %s\n", string, p);
|
||||
if (strcmp(string, p) == 0)
|
||||
return i; /* Found it; return index */
|
||||
}
|
||||
return -ENODATA;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_match_string);
|
||||
|
||||
/**
|
||||
* of_property_read_string_helper() - Utility helper for parsing string properties
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_strs: output array of string pointers.
|
||||
* @sz: number of array elements to read.
|
||||
* @skip: Number of strings to skip over at beginning of list.
|
||||
*
|
||||
* Don't call this function directly. It is a utility helper for the
|
||||
* of_property_read_string*() family of functions.
|
||||
*/
|
||||
int of_property_read_string_helper(const struct device_node *np,
|
||||
const char *propname, const char **out_strs,
|
||||
size_t sz, int skip)
|
||||
{
|
||||
const struct property *prop = of_find_property(np, propname, NULL);
|
||||
int l = 0, i = 0;
|
||||
const char *p, *end;
|
||||
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
p = prop->value;
|
||||
end = p + prop->length;
|
||||
|
||||
for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
|
||||
l = strnlen(p, end - p) + 1;
|
||||
if (p + l > end)
|
||||
return -EILSEQ;
|
||||
if (out_strs && i >= skip)
|
||||
*out_strs++ = p;
|
||||
}
|
||||
i -= skip;
|
||||
return i <= 0 ? -ENODATA : i;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_string_helper);
|
||||
|
||||
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
|
||||
{
|
||||
int i;
|
||||
@ -2213,47 +1767,6 @@ int of_alias_get_highest_id(const char *stem)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
|
||||
|
||||
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
|
||||
u32 *pu)
|
||||
{
|
||||
const void *curv = cur;
|
||||
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (!cur) {
|
||||
curv = prop->value;
|
||||
goto out_val;
|
||||
}
|
||||
|
||||
curv += sizeof(*cur);
|
||||
if (curv >= prop->value + prop->length)
|
||||
return NULL;
|
||||
|
||||
out_val:
|
||||
*pu = be32_to_cpup(curv);
|
||||
return curv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_prop_next_u32);
|
||||
|
||||
const char *of_prop_next_string(struct property *prop, const char *cur)
|
||||
{
|
||||
const void *curv = cur;
|
||||
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (!cur)
|
||||
return prop->value;
|
||||
|
||||
curv += strlen(cur) + 1;
|
||||
if (curv >= prop->value + prop->length)
|
||||
return NULL;
|
||||
|
||||
return curv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_prop_next_string);
|
||||
|
||||
/**
|
||||
* of_console_check() - Test and setup console for DT setup
|
||||
* @dn - Pointer to device node
|
||||
@ -2327,283 +1840,3 @@ int of_find_last_cache_level(unsigned int cpu)
|
||||
|
||||
return cache_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_graph_parse_endpoint() - parse common endpoint node properties
|
||||
* @node: pointer to endpoint device_node
|
||||
* @endpoint: pointer to the OF endpoint data structure
|
||||
*
|
||||
* The caller should hold a reference to @node.
|
||||
*/
|
||||
int of_graph_parse_endpoint(const struct device_node *node,
|
||||
struct of_endpoint *endpoint)
|
||||
{
|
||||
struct device_node *port_node = of_get_parent(node);
|
||||
|
||||
WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
|
||||
__func__, node->full_name);
|
||||
|
||||
memset(endpoint, 0, sizeof(*endpoint));
|
||||
|
||||
endpoint->local_node = node;
|
||||
/*
|
||||
* It doesn't matter whether the two calls below succeed.
|
||||
* If they don't then the default value 0 is used.
|
||||
*/
|
||||
of_property_read_u32(port_node, "reg", &endpoint->port);
|
||||
of_property_read_u32(node, "reg", &endpoint->id);
|
||||
|
||||
of_node_put(port_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_parse_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_port_by_id() - get the port matching a given id
|
||||
* @parent: pointer to the parent device node
|
||||
* @id: id of the port
|
||||
*
|
||||
* Return: A 'port' node pointer with refcount incremented. The caller
|
||||
* has to use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
|
||||
{
|
||||
struct device_node *node, *port;
|
||||
|
||||
node = of_get_child_by_name(parent, "ports");
|
||||
if (node)
|
||||
parent = node;
|
||||
|
||||
for_each_child_of_node(parent, port) {
|
||||
u32 port_id = 0;
|
||||
|
||||
if (of_node_cmp(port->name, "port") != 0)
|
||||
continue;
|
||||
of_property_read_u32(port, "reg", &port_id);
|
||||
if (id == port_id)
|
||||
break;
|
||||
}
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
return port;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_port_by_id);
|
||||
|
||||
/**
|
||||
* of_graph_get_next_endpoint() - get next endpoint node
|
||||
* @parent: pointer to the parent device node
|
||||
* @prev: previous endpoint node, or NULL to get first
|
||||
*
|
||||
* Return: An 'endpoint' node pointer with refcount incremented. Refcount
|
||||
* of the passed @prev node is decremented.
|
||||
*/
|
||||
struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *endpoint;
|
||||
struct device_node *port;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Start by locating the port node. If no previous endpoint is specified
|
||||
* search for the first port node, otherwise get the previous endpoint
|
||||
* parent port node.
|
||||
*/
|
||||
if (!prev) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_get_child_by_name(parent, "ports");
|
||||
if (node)
|
||||
parent = node;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
of_node_put(node);
|
||||
|
||||
if (!port) {
|
||||
pr_err("graph: no port node found in %s\n",
|
||||
parent->full_name);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
port = of_get_parent(prev);
|
||||
if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
|
||||
__func__, prev->full_name))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Now that we have a port node, get the next endpoint by
|
||||
* getting the next child. If the previous endpoint is NULL this
|
||||
* will return the first child.
|
||||
*/
|
||||
endpoint = of_get_next_child(port, prev);
|
||||
if (endpoint) {
|
||||
of_node_put(port);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/* No more endpoints under this port, try the next one. */
|
||||
prev = NULL;
|
||||
|
||||
do {
|
||||
port = of_get_next_child(parent, port);
|
||||
if (!port)
|
||||
return NULL;
|
||||
} while (of_node_cmp(port->name, "port"));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_next_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
|
||||
* @parent: pointer to the parent device node
|
||||
* @port_reg: identifier (value of reg property) of the parent port node
|
||||
* @reg: identifier (value of reg property) of the endpoint node
|
||||
*
|
||||
* Return: An 'endpoint' node pointer which is identified by reg and at the same
|
||||
* is the child of a port node identified by port_reg. reg and port_reg are
|
||||
* ignored when they are -1.
|
||||
*/
|
||||
struct device_node *of_graph_get_endpoint_by_regs(
|
||||
const struct device_node *parent, int port_reg, int reg)
|
||||
{
|
||||
struct of_endpoint endpoint;
|
||||
struct device_node *node = NULL;
|
||||
|
||||
for_each_endpoint_of_node(parent, node) {
|
||||
of_graph_parse_endpoint(node, &endpoint);
|
||||
if (((port_reg == -1) || (endpoint.port == port_reg)) &&
|
||||
((reg == -1) || (endpoint.id == reg)))
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_endpoint() - get remote endpoint node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote endpoint node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_endpoint(const struct device_node *node)
|
||||
{
|
||||
/* Get remote endpoint node. */
|
||||
return of_parse_phandle(node, "remote-endpoint", 0);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_port_parent() - get port's parent node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: device node associated with endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_port_parent(struct device_node *node)
|
||||
{
|
||||
unsigned int depth;
|
||||
|
||||
/* Walk 3 levels up only if there is 'ports' node. */
|
||||
for (depth = 3; depth && node; depth--) {
|
||||
node = of_get_next_parent(node);
|
||||
if (depth == 2 && of_node_cmp(node->name, "ports"))
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_port_parent);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_port_parent() - get remote port's parent node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote device node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_port_parent(
|
||||
const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_graph_get_remote_endpoint(node);
|
||||
|
||||
return of_graph_get_port_parent(np);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_port_parent);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_port() - get remote port node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote port node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_port(const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_graph_get_remote_endpoint(node);
|
||||
if (!np)
|
||||
return NULL;
|
||||
return of_get_next_parent(np);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_port);
|
||||
|
||||
int of_graph_get_endpoint_count(const struct device_node *np)
|
||||
{
|
||||
struct device_node *endpoint;
|
||||
int num = 0;
|
||||
|
||||
for_each_endpoint_of_node(np, endpoint)
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_endpoint_count);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
|
||||
* @node: pointer to parent device_node containing graph port/endpoint
|
||||
* @port: identifier (value of reg property) of the parent port node
|
||||
* @endpoint: identifier (value of reg property) of the endpoint node
|
||||
*
|
||||
* Return: Remote device node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_node(const struct device_node *node,
|
||||
u32 port, u32 endpoint)
|
||||
{
|
||||
struct device_node *endpoint_node, *remote;
|
||||
|
||||
endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
|
||||
if (!endpoint_node) {
|
||||
pr_debug("no valid endpoint (%d, %d) for node %s\n",
|
||||
port, endpoint, node->full_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
remote = of_graph_get_remote_port_parent(endpoint_node);
|
||||
of_node_put(endpoint_node);
|
||||
if (!remote) {
|
||||
pr_debug("no valid remote node\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(remote)) {
|
||||
pr_debug("not available for remote node\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return remote;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_node);
|
||||
|
@ -216,7 +216,7 @@ int of_property_notify(int action, struct device_node *np,
|
||||
return of_reconfig_notify(action, &pr);
|
||||
}
|
||||
|
||||
void __of_attach_node(struct device_node *np)
|
||||
static void __of_attach_node(struct device_node *np)
|
||||
{
|
||||
const __be32 *phandle;
|
||||
int sz;
|
||||
|
@ -91,7 +91,7 @@ void of_fdt_limit_memory(int limit)
|
||||
* On match, returns a non-zero value with smaller values returned for more
|
||||
* specific compatible values.
|
||||
*/
|
||||
int of_fdt_is_compatible(const void *blob,
|
||||
static int of_fdt_is_compatible(const void *blob,
|
||||
unsigned long node, const char *compat)
|
||||
{
|
||||
const char *cp;
|
||||
@ -1053,7 +1053,7 @@ u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
|
||||
}
|
||||
|
||||
/**
|
||||
* early_init_dt_scan_memory - Look for an parse memory nodes
|
||||
* early_init_dt_scan_memory - Look for and parse memory nodes
|
||||
*/
|
||||
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
|
||||
int depth, void *data)
|
||||
|
@ -369,7 +369,10 @@ EXPORT_SYMBOL_GPL(of_irq_parse_one);
|
||||
*/
|
||||
int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
|
||||
{
|
||||
int irq = irq_of_parse_and_map(dev, index);
|
||||
int irq = of_irq_get(dev, index);
|
||||
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
/* Only dereference the resource if both the
|
||||
* resource and the irq are valid. */
|
||||
|
@ -77,6 +77,9 @@ extern void *__unflatten_device_tree(const void *blob,
|
||||
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
|
||||
__printf(2, 3) struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...);
|
||||
|
||||
struct device_node *__of_find_node_by_full_path(struct device_node *node,
|
||||
const char *path);
|
||||
|
||||
extern const void *__of_get_property(const struct device_node *np,
|
||||
const char *name, int *lenp);
|
||||
extern int __of_add_property(struct device_node *np, struct property *prop);
|
||||
@ -90,7 +93,6 @@ extern int __of_update_property(struct device_node *np,
|
||||
extern void __of_update_property_sysfs(struct device_node *np,
|
||||
struct property *newprop, struct property *oldprop);
|
||||
|
||||
extern void __of_attach_node(struct device_node *np);
|
||||
extern int __of_attach_node_sysfs(struct device_node *np);
|
||||
extern void __of_detach_node(struct device_node *np);
|
||||
extern void __of_detach_node_sysfs(struct device_node *np);
|
||||
|
@ -132,6 +132,10 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
|
||||
/* NOTE: Multiple mods of created nodes not supported */
|
||||
tchild = of_get_child_by_name(target, cname);
|
||||
if (tchild != NULL) {
|
||||
/* new overlay phandle value conflicts with existing value */
|
||||
if (child->phandle)
|
||||
return -EINVAL;
|
||||
|
||||
/* apply overlay recursively */
|
||||
ret = of_overlay_apply_one(ov, tchild, child);
|
||||
of_node_put(tchild);
|
||||
|
@ -99,7 +99,7 @@ static void of_device_make_bus_id(struct device *dev)
|
||||
|
||||
/* format arguments only used if dev_name() resolves to NULL */
|
||||
dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
|
||||
strrchr(node->full_name, '/') + 1, dev_name(dev));
|
||||
kbasename(node->full_name), dev_name(dev));
|
||||
node = node->parent;
|
||||
}
|
||||
}
|
||||
|
806
drivers/of/property.c
Normal file
806
drivers/of/property.c
Normal file
@ -0,0 +1,806 @@
|
||||
/*
|
||||
* drivers/of/property.c - Procedures for accessing and interpreting
|
||||
* Devicetree properties and graphs.
|
||||
*
|
||||
* Initially created by copying procedures from drivers/of/base.c. This
|
||||
* file contains the OF property as well as the OF graph interface
|
||||
* functions.
|
||||
*
|
||||
* Paul Mackerras August 1996.
|
||||
* Copyright (C) 1996-2005 Paul Mackerras.
|
||||
*
|
||||
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
|
||||
* {engebret|bergner}@us.ibm.com
|
||||
*
|
||||
* Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
|
||||
*
|
||||
* Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
|
||||
* Grant Likely.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "OF: " fmt
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "of_private.h"
|
||||
|
||||
/**
|
||||
* of_property_count_elems_of_size - Count the number of elements in a property
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @elem_size: size of the individual element
|
||||
*
|
||||
* Search for a property in a device node and count the number of elements of
|
||||
* size elem_size in it. Returns number of elements on sucess, -EINVAL if the
|
||||
* property does not exist or its length does not match a multiple of elem_size
|
||||
* and -ENODATA if the property does not have a value.
|
||||
*/
|
||||
int of_property_count_elems_of_size(const struct device_node *np,
|
||||
const char *propname, int elem_size)
|
||||
{
|
||||
struct property *prop = of_find_property(np, propname, NULL);
|
||||
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
|
||||
if (prop->length % elem_size != 0) {
|
||||
pr_err("size of %s in node %s is not a multiple of %d\n",
|
||||
propname, np->full_name, elem_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return prop->length / elem_size;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
|
||||
|
||||
/**
|
||||
* of_find_property_value_of_size
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @min: minimum allowed length of property value
|
||||
* @max: maximum allowed length of property value (0 means unlimited)
|
||||
* @len: if !=NULL, actual length is written to here
|
||||
*
|
||||
* Search for a property in a device node and valid the requested size.
|
||||
* Returns the property value on success, -EINVAL if the property does not
|
||||
* exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data is too small or too large.
|
||||
*
|
||||
*/
|
||||
static void *of_find_property_value_of_size(const struct device_node *np,
|
||||
const char *propname, u32 min, u32 max, size_t *len)
|
||||
{
|
||||
struct property *prop = of_find_property(np, propname, NULL);
|
||||
|
||||
if (!prop)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (!prop->value)
|
||||
return ERR_PTR(-ENODATA);
|
||||
if (prop->length < min)
|
||||
return ERR_PTR(-EOVERFLOW);
|
||||
if (max && prop->length > max)
|
||||
return ERR_PTR(-EOVERFLOW);
|
||||
|
||||
if (len)
|
||||
*len = prop->length;
|
||||
|
||||
return prop->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_property_read_u32_index - Find and read a u32 from a multi-value property.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @index: index of the u32 in the list of values
|
||||
* @out_value: pointer to return value, modified only if no error.
|
||||
*
|
||||
* Search for a property in a device node and read nth 32-bit value from
|
||||
* it. Returns 0 on success, -EINVAL if the property does not exist,
|
||||
* -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data isn't large enough.
|
||||
*
|
||||
* The out_value is modified only if a valid u32 value can be decoded.
|
||||
*/
|
||||
int of_property_read_u32_index(const struct device_node *np,
|
||||
const char *propname,
|
||||
u32 index, u32 *out_value)
|
||||
{
|
||||
const u32 *val = of_find_property_value_of_size(np, propname,
|
||||
((index + 1) * sizeof(*out_value)),
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
*out_value = be32_to_cpup(((__be32 *)val) + index);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_u32_index);
|
||||
|
||||
/**
|
||||
* of_property_read_u64_index - Find and read a u64 from a multi-value property.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @index: index of the u64 in the list of values
|
||||
* @out_value: pointer to return value, modified only if no error.
|
||||
*
|
||||
* Search for a property in a device node and read nth 64-bit value from
|
||||
* it. Returns 0 on success, -EINVAL if the property does not exist,
|
||||
* -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data isn't large enough.
|
||||
*
|
||||
* The out_value is modified only if a valid u64 value can be decoded.
|
||||
*/
|
||||
int of_property_read_u64_index(const struct device_node *np,
|
||||
const char *propname,
|
||||
u32 index, u64 *out_value)
|
||||
{
|
||||
const u64 *val = of_find_property_value_of_size(np, propname,
|
||||
((index + 1) * sizeof(*out_value)),
|
||||
0, NULL);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
*out_value = be64_to_cpup(((__be64 *)val) + index);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_u64_index);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u8_array - Find and read an array of u8 from a
|
||||
* property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 8-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* dts entry of array should be like:
|
||||
* property = /bits/ 8 <0x50 0x60 0x70>;
|
||||
*
|
||||
* The out_values is modified only if a valid u8 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u8_array(const struct device_node *np,
|
||||
const char *propname, u8 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const u8 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--)
|
||||
*out_values++ = *val++;
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u16_array - Find and read an array of u16 from a
|
||||
* property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 16-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* dts entry of array should be like:
|
||||
* property = /bits/ 16 <0x5000 0x6000 0x7000>;
|
||||
*
|
||||
* The out_values is modified only if a valid u16 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u16_array(const struct device_node *np,
|
||||
const char *propname, u16 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const __be16 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--)
|
||||
*out_values++ = be16_to_cpup(val++);
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u32_array - Find and read an array of 32 bit
|
||||
* integers from a property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 32-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* The out_values is modified only if a valid u32 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u32_array(const struct device_node *np,
|
||||
const char *propname, u32 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const __be32 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--)
|
||||
*out_values++ = be32_to_cpup(val++);
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
|
||||
|
||||
/**
|
||||
* of_property_read_u64 - Find and read a 64 bit integer from a property
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_value: pointer to return value, modified only if return value is 0.
|
||||
*
|
||||
* Search for a property in a device node and read a 64-bit value from
|
||||
* it. Returns 0 on success, -EINVAL if the property does not exist,
|
||||
* -ENODATA if property does not have a value, and -EOVERFLOW if the
|
||||
* property data isn't large enough.
|
||||
*
|
||||
* The out_value is modified only if a valid u64 value can be decoded.
|
||||
*/
|
||||
int of_property_read_u64(const struct device_node *np, const char *propname,
|
||||
u64 *out_value)
|
||||
{
|
||||
const __be32 *val = of_find_property_value_of_size(np, propname,
|
||||
sizeof(*out_value),
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
*out_value = of_read_number(val, 2);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_u64);
|
||||
|
||||
/**
|
||||
* of_property_read_variable_u64_array - Find and read an array of 64 bit
|
||||
* integers from a property, with bounds on the minimum and maximum array size.
|
||||
*
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_values: pointer to return value, modified only if return value is 0.
|
||||
* @sz_min: minimum number of array elements to read
|
||||
* @sz_max: maximum number of array elements to read, if zero there is no
|
||||
* upper limit on the number of elements in the dts entry but only
|
||||
* sz_min will be read.
|
||||
*
|
||||
* Search for a property in a device node and read 64-bit value(s) from
|
||||
* it. Returns number of elements read on success, -EINVAL if the property
|
||||
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
|
||||
* if the property data is smaller than sz_min or longer than sz_max.
|
||||
*
|
||||
* The out_values is modified only if a valid u64 value can be decoded.
|
||||
*/
|
||||
int of_property_read_variable_u64_array(const struct device_node *np,
|
||||
const char *propname, u64 *out_values,
|
||||
size_t sz_min, size_t sz_max)
|
||||
{
|
||||
size_t sz, count;
|
||||
const __be32 *val = of_find_property_value_of_size(np, propname,
|
||||
(sz_min * sizeof(*out_values)),
|
||||
(sz_max * sizeof(*out_values)),
|
||||
&sz);
|
||||
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
if (!sz_max)
|
||||
sz = sz_min;
|
||||
else
|
||||
sz /= sizeof(*out_values);
|
||||
|
||||
count = sz;
|
||||
while (count--) {
|
||||
*out_values++ = of_read_number(val, 2);
|
||||
val += 2;
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
|
||||
|
||||
/**
|
||||
* of_property_read_string - Find and read a string from a property
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_string: pointer to null terminated return string, modified only if
|
||||
* return value is 0.
|
||||
*
|
||||
* Search for a property in a device tree node and retrieve a null
|
||||
* terminated string value (pointer to data, not a copy). Returns 0 on
|
||||
* success, -EINVAL if the property does not exist, -ENODATA if property
|
||||
* does not have a value, and -EILSEQ if the string is not null-terminated
|
||||
* within the length of the property data.
|
||||
*
|
||||
* The out_string pointer is modified only if a valid string can be decoded.
|
||||
*/
|
||||
int of_property_read_string(const struct device_node *np, const char *propname,
|
||||
const char **out_string)
|
||||
{
|
||||
const struct property *prop = of_find_property(np, propname, NULL);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
if (strnlen(prop->value, prop->length) >= prop->length)
|
||||
return -EILSEQ;
|
||||
*out_string = prop->value;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_string);
|
||||
|
||||
/**
|
||||
* of_property_match_string() - Find string in a list and return index
|
||||
* @np: pointer to node containing string list property
|
||||
* @propname: string list property name
|
||||
* @string: pointer to string to search for in string list
|
||||
*
|
||||
* This function searches a string list property and returns the index
|
||||
* of a specific string value.
|
||||
*/
|
||||
int of_property_match_string(const struct device_node *np, const char *propname,
|
||||
const char *string)
|
||||
{
|
||||
const struct property *prop = of_find_property(np, propname, NULL);
|
||||
size_t l;
|
||||
int i;
|
||||
const char *p, *end;
|
||||
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
|
||||
p = prop->value;
|
||||
end = p + prop->length;
|
||||
|
||||
for (i = 0; p < end; i++, p += l) {
|
||||
l = strnlen(p, end - p) + 1;
|
||||
if (p + l > end)
|
||||
return -EILSEQ;
|
||||
pr_debug("comparing %s with %s\n", string, p);
|
||||
if (strcmp(string, p) == 0)
|
||||
return i; /* Found it; return index */
|
||||
}
|
||||
return -ENODATA;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_match_string);
|
||||
|
||||
/**
|
||||
* of_property_read_string_helper() - Utility helper for parsing string properties
|
||||
* @np: device node from which the property value is to be read.
|
||||
* @propname: name of the property to be searched.
|
||||
* @out_strs: output array of string pointers.
|
||||
* @sz: number of array elements to read.
|
||||
* @skip: Number of strings to skip over at beginning of list.
|
||||
*
|
||||
* Don't call this function directly. It is a utility helper for the
|
||||
* of_property_read_string*() family of functions.
|
||||
*/
|
||||
int of_property_read_string_helper(const struct device_node *np,
|
||||
const char *propname, const char **out_strs,
|
||||
size_t sz, int skip)
|
||||
{
|
||||
const struct property *prop = of_find_property(np, propname, NULL);
|
||||
int l = 0, i = 0;
|
||||
const char *p, *end;
|
||||
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
p = prop->value;
|
||||
end = p + prop->length;
|
||||
|
||||
for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
|
||||
l = strnlen(p, end - p) + 1;
|
||||
if (p + l > end)
|
||||
return -EILSEQ;
|
||||
if (out_strs && i >= skip)
|
||||
*out_strs++ = p;
|
||||
}
|
||||
i -= skip;
|
||||
return i <= 0 ? -ENODATA : i;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_property_read_string_helper);
|
||||
|
||||
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
|
||||
u32 *pu)
|
||||
{
|
||||
const void *curv = cur;
|
||||
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (!cur) {
|
||||
curv = prop->value;
|
||||
goto out_val;
|
||||
}
|
||||
|
||||
curv += sizeof(*cur);
|
||||
if (curv >= prop->value + prop->length)
|
||||
return NULL;
|
||||
|
||||
out_val:
|
||||
*pu = be32_to_cpup(curv);
|
||||
return curv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_prop_next_u32);
|
||||
|
||||
const char *of_prop_next_string(struct property *prop, const char *cur)
|
||||
{
|
||||
const void *curv = cur;
|
||||
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (!cur)
|
||||
return prop->value;
|
||||
|
||||
curv += strlen(cur) + 1;
|
||||
if (curv >= prop->value + prop->length)
|
||||
return NULL;
|
||||
|
||||
return curv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_prop_next_string);
|
||||
|
||||
/**
|
||||
* of_graph_parse_endpoint() - parse common endpoint node properties
|
||||
* @node: pointer to endpoint device_node
|
||||
* @endpoint: pointer to the OF endpoint data structure
|
||||
*
|
||||
* The caller should hold a reference to @node.
|
||||
*/
|
||||
int of_graph_parse_endpoint(const struct device_node *node,
|
||||
struct of_endpoint *endpoint)
|
||||
{
|
||||
struct device_node *port_node = of_get_parent(node);
|
||||
|
||||
WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
|
||||
__func__, node->full_name);
|
||||
|
||||
memset(endpoint, 0, sizeof(*endpoint));
|
||||
|
||||
endpoint->local_node = node;
|
||||
/*
|
||||
* It doesn't matter whether the two calls below succeed.
|
||||
* If they don't then the default value 0 is used.
|
||||
*/
|
||||
of_property_read_u32(port_node, "reg", &endpoint->port);
|
||||
of_property_read_u32(node, "reg", &endpoint->id);
|
||||
|
||||
of_node_put(port_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_parse_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_port_by_id() - get the port matching a given id
|
||||
* @parent: pointer to the parent device node
|
||||
* @id: id of the port
|
||||
*
|
||||
* Return: A 'port' node pointer with refcount incremented. The caller
|
||||
* has to use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
|
||||
{
|
||||
struct device_node *node, *port;
|
||||
|
||||
node = of_get_child_by_name(parent, "ports");
|
||||
if (node)
|
||||
parent = node;
|
||||
|
||||
for_each_child_of_node(parent, port) {
|
||||
u32 port_id = 0;
|
||||
|
||||
if (of_node_cmp(port->name, "port") != 0)
|
||||
continue;
|
||||
of_property_read_u32(port, "reg", &port_id);
|
||||
if (id == port_id)
|
||||
break;
|
||||
}
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
return port;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_port_by_id);
|
||||
|
||||
/**
|
||||
* of_graph_get_next_endpoint() - get next endpoint node
|
||||
* @parent: pointer to the parent device node
|
||||
* @prev: previous endpoint node, or NULL to get first
|
||||
*
|
||||
* Return: An 'endpoint' node pointer with refcount incremented. Refcount
|
||||
* of the passed @prev node is decremented.
|
||||
*/
|
||||
struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *endpoint;
|
||||
struct device_node *port;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Start by locating the port node. If no previous endpoint is specified
|
||||
* search for the first port node, otherwise get the previous endpoint
|
||||
* parent port node.
|
||||
*/
|
||||
if (!prev) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_get_child_by_name(parent, "ports");
|
||||
if (node)
|
||||
parent = node;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
of_node_put(node);
|
||||
|
||||
if (!port) {
|
||||
pr_err("graph: no port node found in %s\n",
|
||||
parent->full_name);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
port = of_get_parent(prev);
|
||||
if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
|
||||
__func__, prev->full_name))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Now that we have a port node, get the next endpoint by
|
||||
* getting the next child. If the previous endpoint is NULL this
|
||||
* will return the first child.
|
||||
*/
|
||||
endpoint = of_get_next_child(port, prev);
|
||||
if (endpoint) {
|
||||
of_node_put(port);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/* No more endpoints under this port, try the next one. */
|
||||
prev = NULL;
|
||||
|
||||
do {
|
||||
port = of_get_next_child(parent, port);
|
||||
if (!port)
|
||||
return NULL;
|
||||
} while (of_node_cmp(port->name, "port"));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_next_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
|
||||
* @parent: pointer to the parent device node
|
||||
* @port_reg: identifier (value of reg property) of the parent port node
|
||||
* @reg: identifier (value of reg property) of the endpoint node
|
||||
*
|
||||
* Return: An 'endpoint' node pointer which is identified by reg and at the same
|
||||
* is the child of a port node identified by port_reg. reg and port_reg are
|
||||
* ignored when they are -1.
|
||||
*/
|
||||
struct device_node *of_graph_get_endpoint_by_regs(
|
||||
const struct device_node *parent, int port_reg, int reg)
|
||||
{
|
||||
struct of_endpoint endpoint;
|
||||
struct device_node *node = NULL;
|
||||
|
||||
for_each_endpoint_of_node(parent, node) {
|
||||
of_graph_parse_endpoint(node, &endpoint);
|
||||
if (((port_reg == -1) || (endpoint.port == port_reg)) &&
|
||||
((reg == -1) || (endpoint.id == reg)))
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_endpoint() - get remote endpoint node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote endpoint node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_endpoint(const struct device_node *node)
|
||||
{
|
||||
/* Get remote endpoint node. */
|
||||
return of_parse_phandle(node, "remote-endpoint", 0);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_port_parent() - get port's parent node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: device node associated with endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_port_parent(struct device_node *node)
|
||||
{
|
||||
unsigned int depth;
|
||||
|
||||
/* Walk 3 levels up only if there is 'ports' node. */
|
||||
for (depth = 3; depth && node; depth--) {
|
||||
node = of_get_next_parent(node);
|
||||
if (depth == 2 && of_node_cmp(node->name, "ports"))
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_port_parent);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_port_parent() - get remote port's parent node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote device node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_port_parent(
|
||||
const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_graph_get_remote_endpoint(node);
|
||||
|
||||
return of_graph_get_port_parent(np);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_port_parent);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_port() - get remote port node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote port node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_port(const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_graph_get_remote_endpoint(node);
|
||||
if (!np)
|
||||
return NULL;
|
||||
return of_get_next_parent(np);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_port);
|
||||
|
||||
int of_graph_get_endpoint_count(const struct device_node *np)
|
||||
{
|
||||
struct device_node *endpoint;
|
||||
int num = 0;
|
||||
|
||||
for_each_endpoint_of_node(np, endpoint)
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_endpoint_count);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
|
||||
* @node: pointer to parent device_node containing graph port/endpoint
|
||||
* @port: identifier (value of reg property) of the parent port node
|
||||
* @endpoint: identifier (value of reg property) of the endpoint node
|
||||
*
|
||||
* Return: Remote device node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_node(const struct device_node *node,
|
||||
u32 port, u32 endpoint)
|
||||
{
|
||||
struct device_node *endpoint_node, *remote;
|
||||
|
||||
endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
|
||||
if (!endpoint_node) {
|
||||
pr_debug("no valid endpoint (%d, %d) for node %s\n",
|
||||
port, endpoint, node->full_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
remote = of_graph_get_remote_port_parent(endpoint_node);
|
||||
of_node_put(endpoint_node);
|
||||
if (!remote) {
|
||||
pr_debug("no valid remote node\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(remote)) {
|
||||
pr_debug("not available for remote node\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return remote;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_node);
|
@ -20,35 +20,11 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "of_private.h"
|
||||
|
||||
/* illegal phandle value (set when unresolved) */
|
||||
#define OF_PHANDLE_ILLEGAL 0xdeadbeef
|
||||
|
||||
/**
|
||||
* Find a node with the give full name by recursively following any of
|
||||
* the child node links.
|
||||
*/
|
||||
static struct device_node *find_node_by_full_name(struct device_node *node,
|
||||
const char *full_name)
|
||||
{
|
||||
struct device_node *child, *found;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
if (!of_node_cmp(node->full_name, full_name))
|
||||
return of_node_get(node);
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
found = find_node_by_full_name(child, full_name);
|
||||
if (found != NULL) {
|
||||
of_node_put(child);
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static phandle live_tree_max_phandle(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
@ -138,7 +114,7 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay,
|
||||
if (err)
|
||||
goto err_fail;
|
||||
|
||||
refnode = find_node_by_full_name(overlay, node_path);
|
||||
refnode = __of_find_node_by_full_path(of_node_get(overlay), node_path);
|
||||
if (!refnode)
|
||||
continue;
|
||||
|
||||
@ -165,8 +141,8 @@ err_fail:
|
||||
static int node_name_cmp(const struct device_node *dn1,
|
||||
const struct device_node *dn2)
|
||||
{
|
||||
const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
|
||||
const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
|
||||
const char *n1 = kbasename(dn1->full_name);
|
||||
const char *n2 = kbasename(dn2->full_name);
|
||||
|
||||
return of_node_cmp(n1, n2);
|
||||
}
|
||||
|
@ -26,7 +26,9 @@
|
||||
#size-cells = <0>;
|
||||
|
||||
dev@100 {
|
||||
compatible = "test-sub-device";
|
||||
compatible = "test-sub-device",
|
||||
"test-compat2",
|
||||
"test-compat3";
|
||||
reg = <0x100>;
|
||||
};
|
||||
};
|
||||
|
@ -239,6 +239,63 @@ static void __init of_unittest_check_tree_linkage(void)
|
||||
pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
|
||||
}
|
||||
|
||||
static void __init of_unittest_printf_one(struct device_node *np, const char *fmt,
|
||||
const char *expected)
|
||||
{
|
||||
unsigned char buf[strlen(expected)+10];
|
||||
int size, i;
|
||||
|
||||
/* Baseline; check conversion with a large size limit */
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
size = snprintf(buf, sizeof(buf) - 2, fmt, np);
|
||||
|
||||
/* use strcmp() instead of strncmp() here to be absolutely sure strings match */
|
||||
unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff),
|
||||
"sprintf failed; fmt='%s' expected='%s' rslt='%s'\n",
|
||||
fmt, expected, buf);
|
||||
|
||||
/* Make sure length limits work */
|
||||
size++;
|
||||
for (i = 0; i < 2; i++, size--) {
|
||||
/* Clear the buffer, and make sure it works correctly still */
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
snprintf(buf, size+1, fmt, np);
|
||||
unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff),
|
||||
"snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n",
|
||||
size, fmt, expected, buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init of_unittest_printf(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
const char *full_name = "/testcase-data/platform-tests/test-device@1/dev@100";
|
||||
char phandle_str[16] = "";
|
||||
|
||||
np = of_find_node_by_path(full_name);
|
||||
if (!np) {
|
||||
unittest(np, "testcase data missing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
num_to_str(phandle_str, sizeof(phandle_str), np->phandle);
|
||||
|
||||
of_unittest_printf_one(np, "%pOF", full_name);
|
||||
of_unittest_printf_one(np, "%pOFf", full_name);
|
||||
of_unittest_printf_one(np, "%pOFp", phandle_str);
|
||||
of_unittest_printf_one(np, "%pOFP", "dev@100");
|
||||
of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC");
|
||||
of_unittest_printf_one(np, "%10pOFP", " dev@100");
|
||||
of_unittest_printf_one(np, "%-10pOFP", "dev@100 ");
|
||||
of_unittest_printf_one(of_root, "%pOFP", "/");
|
||||
of_unittest_printf_one(np, "%pOFF", "----");
|
||||
of_unittest_printf_one(np, "%pOFPF", "dev@100:----");
|
||||
of_unittest_printf_one(np, "%pOFPFPc", "dev@100:----:dev@100:test-sub-device");
|
||||
of_unittest_printf_one(np, "%pOFc", "test-sub-device");
|
||||
of_unittest_printf_one(np, "%pOFC",
|
||||
"\"test-sub-device\",\"test-compat2\",\"test-compat3\"");
|
||||
}
|
||||
|
||||
struct node_hash {
|
||||
struct hlist_node node;
|
||||
struct device_node *np;
|
||||
@ -2269,6 +2326,7 @@ static int __init of_unittest(void)
|
||||
of_unittest_find_node_by_name();
|
||||
of_unittest_dynamic();
|
||||
of_unittest_parse_phandle_with_args();
|
||||
of_unittest_printf();
|
||||
of_unittest_property_string();
|
||||
of_unittest_property_copy();
|
||||
of_unittest_changeset();
|
||||
|
@ -148,18 +148,28 @@ extern raw_spinlock_t devtree_lock;
|
||||
#ifdef CONFIG_OF
|
||||
void of_core_init(void);
|
||||
|
||||
static inline bool is_of_node(struct fwnode_handle *fwnode)
|
||||
static inline bool is_of_node(const struct fwnode_handle *fwnode)
|
||||
{
|
||||
return !IS_ERR_OR_NULL(fwnode) && fwnode->type == FWNODE_OF;
|
||||
}
|
||||
|
||||
static inline struct device_node *to_of_node(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return is_of_node(fwnode) ?
|
||||
container_of(fwnode, struct device_node, fwnode) : NULL;
|
||||
}
|
||||
#define to_of_node(__fwnode) \
|
||||
({ \
|
||||
typeof(__fwnode) __to_of_node_fwnode = (__fwnode); \
|
||||
\
|
||||
is_of_node(__to_of_node_fwnode) ? \
|
||||
container_of(__to_of_node_fwnode, \
|
||||
struct device_node, fwnode) : \
|
||||
NULL; \
|
||||
})
|
||||
|
||||
#define of_fwnode_handle(node) (&(node)->fwnode)
|
||||
#define of_fwnode_handle(node) \
|
||||
({ \
|
||||
typeof(node) __of_fwnode_handle_node = (node); \
|
||||
\
|
||||
__of_fwnode_handle_node ? \
|
||||
&__of_fwnode_handle_node->fwnode : NULL; \
|
||||
})
|
||||
|
||||
static inline bool of_have_populated_dt(void)
|
||||
{
|
||||
@ -533,12 +543,12 @@ static inline void of_core_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool is_of_node(struct fwnode_handle *fwnode)
|
||||
static inline bool is_of_node(const struct fwnode_handle *fwnode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct device_node *to_of_node(struct fwnode_handle *fwnode)
|
||||
static inline struct device_node *to_of_node(const struct fwnode_handle *fwnode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -627,6 +637,12 @@ static inline int of_device_is_compatible(const struct device_node *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int of_device_compatible_match(struct device_node *device,
|
||||
const char *const *compat)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool of_device_is_available(const struct device_node *device)
|
||||
{
|
||||
return false;
|
||||
|
@ -31,9 +31,6 @@ extern void *of_fdt_get_property(const void *blob,
|
||||
unsigned long node,
|
||||
const char *name,
|
||||
int *size);
|
||||
extern int of_fdt_is_compatible(const void *blob,
|
||||
unsigned long node,
|
||||
const char *compat);
|
||||
extern bool of_fdt_is_big_endian(const void *blob,
|
||||
unsigned long node);
|
||||
extern int of_fdt_match(const void *blob, unsigned long node,
|
||||
|
136
lib/vsprintf.c
136
lib/vsprintf.c
@ -31,6 +31,7 @@
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/of.h>
|
||||
#include <net/addrconf.h>
|
||||
#ifdef CONFIG_BLOCK
|
||||
#include <linux/blkdev.h>
|
||||
@ -1470,6 +1471,126 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
|
||||
return format_flags(buf, end, flags, names);
|
||||
}
|
||||
|
||||
static const char *device_node_name_for_depth(const struct device_node *np, int depth)
|
||||
{
|
||||
for ( ; np && depth; depth--)
|
||||
np = np->parent;
|
||||
|
||||
return kbasename(np->full_name);
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)
|
||||
{
|
||||
int depth;
|
||||
const struct device_node *parent = np->parent;
|
||||
static const struct printf_spec strspec = {
|
||||
.field_width = -1,
|
||||
.precision = -1,
|
||||
};
|
||||
|
||||
/* special case for root node */
|
||||
if (!parent)
|
||||
return string(buf, end, "/", strspec);
|
||||
|
||||
for (depth = 0; parent->parent; depth++)
|
||||
parent = parent->parent;
|
||||
|
||||
for ( ; depth >= 0; depth--) {
|
||||
buf = string(buf, end, "/", strspec);
|
||||
buf = string(buf, end, device_node_name_for_depth(np, depth),
|
||||
strspec);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
char *device_node_string(char *buf, char *end, struct device_node *dn,
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
char tbuf[sizeof("xxxx") + 1];
|
||||
const char *p;
|
||||
int ret;
|
||||
char *buf_start = buf;
|
||||
struct property *prop;
|
||||
bool has_mult, pass;
|
||||
static const struct printf_spec num_spec = {
|
||||
.flags = SMALL,
|
||||
.field_width = -1,
|
||||
.precision = -1,
|
||||
.base = 10,
|
||||
};
|
||||
|
||||
struct printf_spec str_spec = spec;
|
||||
str_spec.field_width = -1;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF))
|
||||
return string(buf, end, "(!OF)", spec);
|
||||
|
||||
if ((unsigned long)dn < PAGE_SIZE)
|
||||
return string(buf, end, "(null)", spec);
|
||||
|
||||
/* simple case without anything any more format specifiers */
|
||||
fmt++;
|
||||
if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0)
|
||||
fmt = "f";
|
||||
|
||||
for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) {
|
||||
if (pass) {
|
||||
if (buf < end)
|
||||
*buf = ':';
|
||||
buf++;
|
||||
}
|
||||
|
||||
switch (*fmt) {
|
||||
case 'f': /* full_name */
|
||||
buf = device_node_gen_full_name(dn, buf, end);
|
||||
break;
|
||||
case 'n': /* name */
|
||||
buf = string(buf, end, dn->name, str_spec);
|
||||
break;
|
||||
case 'p': /* phandle */
|
||||
buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
|
||||
break;
|
||||
case 'P': /* path-spec */
|
||||
p = kbasename(of_node_full_name(dn));
|
||||
if (!p[1])
|
||||
p = "/";
|
||||
buf = string(buf, end, p, str_spec);
|
||||
break;
|
||||
case 'F': /* flags */
|
||||
tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-';
|
||||
tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-';
|
||||
tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-';
|
||||
tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-';
|
||||
tbuf[4] = 0;
|
||||
buf = string(buf, end, tbuf, str_spec);
|
||||
break;
|
||||
case 'c': /* major compatible string */
|
||||
ret = of_property_read_string(dn, "compatible", &p);
|
||||
if (!ret)
|
||||
buf = string(buf, end, p, str_spec);
|
||||
break;
|
||||
case 'C': /* full compatible string */
|
||||
has_mult = false;
|
||||
of_property_for_each_string(dn, "compatible", prop, p) {
|
||||
if (has_mult)
|
||||
buf = string(buf, end, ",", str_spec);
|
||||
buf = string(buf, end, "\"", str_spec);
|
||||
buf = string(buf, end, p, str_spec);
|
||||
buf = string(buf, end, "\"", str_spec);
|
||||
|
||||
has_mult = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return widen_string(buf, buf - buf_start, end, spec);
|
||||
}
|
||||
|
||||
int kptr_restrict __read_mostly;
|
||||
|
||||
/*
|
||||
@ -1566,6 +1687,16 @@ int kptr_restrict __read_mostly;
|
||||
* p page flags (see struct page) given as pointer to unsigned long
|
||||
* g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
|
||||
* v vma flags (VM_*) given as pointer to unsigned long
|
||||
* - 'O' For a kobject based struct. Must be one of the following:
|
||||
* - 'OF[fnpPcCF]' For a device tree object
|
||||
* Without any optional arguments prints the full_name
|
||||
* f device node full_name
|
||||
* n device node name
|
||||
* p device node phandle
|
||||
* P device node path spec (name + @unit)
|
||||
* F device node flags
|
||||
* c major compatible string
|
||||
* C full compatible string
|
||||
*
|
||||
* ** Please update also Documentation/printk-formats.txt when making changes **
|
||||
*
|
||||
@ -1721,6 +1852,11 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||
|
||||
case 'G':
|
||||
return flags_string(buf, end, ptr, fmt);
|
||||
case 'O':
|
||||
switch (fmt[1]) {
|
||||
case 'F':
|
||||
return device_node_string(buf, end, ptr, spec, fmt + 1);
|
||||
}
|
||||
}
|
||||
spec.flags |= SMALL;
|
||||
if (spec.field_width == -1) {
|
||||
|
@ -5692,7 +5692,7 @@ sub process {
|
||||
for (my $count = $linenr; $count <= $lc; $count++) {
|
||||
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
|
||||
$fmt =~ s/%%//g;
|
||||
if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGN]).)/) {
|
||||
if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
|
||||
$bad_extension = $1;
|
||||
last;
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ DTC="${DTC} ${dtc_flags} -O dts -qq -f ${dtc_sort} -o -"
|
||||
|
||||
if (( ${cmd_diff} )) ; then
|
||||
|
||||
diff ${diff_flags} \
|
||||
diff ${diff_flags} --label "${dtx_file_1}" --label "${dtx_file_2}" \
|
||||
<(compile_to_dts "${dtx_file_1}") \
|
||||
<(compile_to_dts "${dtx_file_2}")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user