DeviceTree updates for 4.11:
- Sync dtc to upstream commit 0931cea3ba20. This picks up overlay support in dtc. - Set dma_ops for reserved memory users. - Make references to IOMMU consistent in DT bindings. - Cleanup references to pm_power_off in bindings. - Move some display bindings that snuck into the old bindings/video/ path. - Fix some wrong documentation paths caused from binding restructuring. - Vendor prefixes for Faraday and Fujitsu. - Fix an of_node ref counting leak in of_find_node_opts_by_path - Introduce new graph helper of_graph_get_remote_node() which will be used by DRM drivers in 4.12. -----BEGIN PGP SIGNATURE----- iQItBAABCAAXBQJYrcjTEBxyb2JoQGtlcm5lbC5vcmcACgkQ+vtdtY28YcOPjg/8 CZgxb3humk7Kkt+I3IsZCxsXhgdk2+CPfCSHlK1bc5Jqg0TzepQvFt4ZkuRHkZy/ pQLUpRnUEUl64aaE8WxZY8ELYZggWazcTnWgCOzvoYpqSD4dAkAsqeti1Qh9PGKz fNLnPWREftojFZ7wVQ8btxC1dINc9eC9eEHsIsS8S8UIgLgv/aN6PeG1Ll/UUa9d u9orY3lxrz8JvdZslGtd1XLZqehIG0AAXqYRasyKl6Sc1NgjdwJTrqoeHEnCYaBM 0+JUOf8kjRa1QNYN4SpuQ1gpovS8tPUGuODrWF2FvaQIxYHTzF8MpLqTvjBzdsj6 b1owHzMXOLlPqqmmQ+jkHY5phisM4heJCIanNerzfM9+lHvb6kB3EuoTkAGvzsr/ HCJi/Wk8tVrw6MYdnav0NT6aLIgZmrVspeJKlS1IdIkpsxZ64DsgX/YS/qGn/fcx qMrDXh8gMFwJBENRCKmKYFu1kzJkBoVEXtGlIbRQDZwOIuHPJl/ed6naMSfyUmcL wEe1I3buyB38FVzUTM2y0K1LfFJSJqOFSWTy5WCcTyP4cbKUyEja8vzN1Cx8BDwf wYtGWQQcg1Pyo074De6ojXWPiiW8f64GLLjqPALjA+J6JtZY5PwAnGXV+1ZYgX+V hV+kXbS4UIjN1koxroJ7ahfouWdOignmpwdvomQPLG8= =D/BO -----END PGP SIGNATURE----- Merge tag 'devicetree-for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux Pull DeviceTree updates from Rob Herring: "Pretty standard stuff with dtc upstream sync being the biggest piece. - Sync dtc to upstream commit 0931cea3ba20. This picks up overlay support in dtc. - Set dma_ops for reserved memory users. - Make references to IOMMU consistent in DT bindings. - Cleanup references to pm_power_off in bindings. - Move some display bindings that snuck into the old bindings/video/ path. - Fix some wrong documentation paths caused from binding restructuring. - Vendor prefixes for Faraday and Fujitsu. - Fix an of_node ref counting leak in of_find_node_opts_by_path - Introduce new graph helper of_graph_get_remote_node() which will be used by DRM drivers in 4.12" * tag 'devicetree-for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (27 commits) DT: add Faraday Tec. as vendor of: introduce of_graph_get_remote_node of: Add missing space at end of pr_fmt(). of: make of_device_make_bus_id() static of: fix of_node leak caused in of_find_node_opts_by_path dt-bindings: net: remove reference to fixed link support dt-bindings: power: reset: qnap-poweroff: Drop reference to pm_power_off dt-bindings: power: reset: gpio-poweroff: Drop reference to pm_power_off dt-bindings: mfd: as3722: Drop reference to pm_power_off dt-bindings: display: move ANX7814 and SiI8620 bridge bindings of/unittest: Swap arguments of of_unittest_apply_overlay() Documentation: usb: fix wrong documentation paths serial: fsl-imx-uart.txt: Remove generic property devicetree: Add Fujitsu Ltd. vendor prefix Documentation: display: fix wrong documentation paths of: remove redundant memset in overlay bus:qcom : Fix typo in qcom,ebi2.txt dt-bindings: qman: Remove pool channel node Documentation: panel-dpi: fix path to display-timing.txt devicetree: bindings: clk: mvebu: fix description for sata1 on Armada XP ...
This commit is contained in:
commit
be5165a51d
|
@ -51,7 +51,7 @@ Required properties:
|
||||||
- compatible: should be one of:
|
- compatible: should be one of:
|
||||||
"qcom,msm8660-ebi2"
|
"qcom,msm8660-ebi2"
|
||||||
"qcom,apq8060-ebi2"
|
"qcom,apq8060-ebi2"
|
||||||
- #address-cells: shoule be <2>: the first cell is the chipselect,
|
- #address-cells: should be <2>: the first cell is the chipselect,
|
||||||
the second cell is the offset inside the memory range
|
the second cell is the offset inside the memory range
|
||||||
- #size-cells: should be <1>
|
- #size-cells: should be <1>
|
||||||
- ranges: should be set to:
|
- ranges: should be set to:
|
||||||
|
@ -64,7 +64,7 @@ Required properties:
|
||||||
- reg: two ranges of registers: EBI2 config and XMEM config areas
|
- reg: two ranges of registers: EBI2 config and XMEM config areas
|
||||||
- reg-names: should be "ebi2", "xmem"
|
- reg-names: should be "ebi2", "xmem"
|
||||||
- clocks: two clocks, EBI_2X and EBI
|
- clocks: two clocks, EBI_2X and EBI
|
||||||
- clock-names: shoule be "ebi2x", "ebi2"
|
- clock-names: should be "ebi2x", "ebi2"
|
||||||
|
|
||||||
Optional subnodes:
|
Optional subnodes:
|
||||||
- Nodes inside the EBI2 will be considered device nodes.
|
- Nodes inside the EBI2 will be considered device nodes.
|
||||||
|
@ -100,7 +100,7 @@ Optional properties arrays for FAST chip selects:
|
||||||
assertion, with respect to the cycle where ADV (address valid) is asserted.
|
assertion, with respect to the cycle where ADV (address valid) is asserted.
|
||||||
2 means 2 cycles between ADV and OE. Valid values 0, 1, 2 or 3.
|
2 means 2 cycles between ADV and OE. Valid values 0, 1, 2 or 3.
|
||||||
- qcom,xmem-read-hold-cycles: the length in cycles of the first segment of a
|
- qcom,xmem-read-hold-cycles: the length in cycles of the first segment of a
|
||||||
read transfer. For a single read trandfer this will be the time from CS
|
read transfer. For a single read transfer this will be the time from CS
|
||||||
assertion to OE assertion. Valid values 0 thru 15.
|
assertion to OE assertion. Valid values 0 thru 15.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ ID Clock Peripheral
|
||||||
25 tdm Time Division Mplx
|
25 tdm Time Division Mplx
|
||||||
28 xor1 XOR DMA 1
|
28 xor1 XOR DMA 1
|
||||||
29 sata1lnk
|
29 sata1lnk
|
||||||
30 sata1 SATA Host 0
|
30 sata1 SATA Host 1
|
||||||
|
|
||||||
The following is a list of provided IDs for Dove:
|
The following is a list of provided IDs for Dove:
|
||||||
ID Clock Peripheral
|
ID Clock Peripheral
|
||||||
|
|
|
@ -22,7 +22,7 @@ Required properties:
|
||||||
|
|
||||||
- clocks: contains phandle and clock specifier pairs for the entries
|
- clocks: contains phandle and clock specifier pairs for the entries
|
||||||
in the clock-names property. See
|
in the clock-names property. See
|
||||||
Documentation/devicetree/binding/clock/clock-bindings.txt
|
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ Optional properties for dp-controller:
|
||||||
in Documentation/devicetree/bindings/media/video-interfaces.txt,
|
in Documentation/devicetree/bindings/media/video-interfaces.txt,
|
||||||
please refer to the SoC specific binding document:
|
please refer to the SoC specific binding document:
|
||||||
* Documentation/devicetree/bindings/display/exynos/exynos_dp.txt
|
* Documentation/devicetree/bindings/display/exynos/exynos_dp.txt
|
||||||
* Documentation/devicetree/bindings/video/analogix_dp-rockchip.txt
|
* Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
|
||||||
|
|
||||||
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
|
@ -6,7 +6,7 @@ Required properties:
|
||||||
location and size of the framebuffer memory.
|
location and size of the framebuffer memory.
|
||||||
- clocks : phandle + clock specifier pair of the FB reference clock.
|
- clocks : phandle + clock specifier pair of the FB reference clock.
|
||||||
- display : phandle to a display node as described in
|
- display : phandle to a display node as described in
|
||||||
Documentation/devicetree/bindings/display/display-timing.txt.
|
Documentation/devicetree/bindings/display/panel/display-timing.txt.
|
||||||
Additionally, the display node has to define properties:
|
Additionally, the display node has to define properties:
|
||||||
- bits-per-pixel: Bits per pixel.
|
- bits-per-pixel: Bits per pixel.
|
||||||
- ac-prescale : LCD AC bias frequency. This frequency is the required
|
- ac-prescale : LCD AC bias frequency. This frequency is the required
|
||||||
|
|
|
@ -38,7 +38,7 @@ Optional Properties:
|
||||||
Can be used in case timings cannot be provided otherwise
|
Can be used in case timings cannot be provided otherwise
|
||||||
or to override timings provided by the panel.
|
or to override timings provided by the panel.
|
||||||
|
|
||||||
[1]: Documentation/devicetree/bindings/display/display-timing.txt
|
[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ in [2]. The following are properties specific to those nodes:
|
||||||
3 - for parallel output,
|
3 - for parallel output,
|
||||||
4 - for write-back interface
|
4 - for write-back interface
|
||||||
|
|
||||||
[1]: Documentation/devicetree/bindings/display/display-timing.txt
|
[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt
|
||||||
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
|
@ -9,7 +9,7 @@ Required properties:
|
||||||
|
|
||||||
Required nodes:
|
Required nodes:
|
||||||
- display: Phandle to a display node as described in
|
- display: Phandle to a display node as described in
|
||||||
Documentation/devicetree/bindings/display/display-timing.txt
|
Documentation/devicetree/bindings/display/panel/display-timing.txt
|
||||||
Additional, the display node has to define properties:
|
Additional, the display node has to define properties:
|
||||||
- bits-per-pixel: Bits per pixel
|
- bits-per-pixel: Bits per pixel
|
||||||
- fsl,pcr: LCDC PCR value
|
- fsl,pcr: LCDC PCR value
|
||||||
|
|
|
@ -64,7 +64,7 @@ Required properties:
|
||||||
Optional properties (required if display-timings are used):
|
Optional properties (required if display-timings are used):
|
||||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||||
- display-timings : A node that describes the display timings as defined in
|
- display-timings : A node that describes the display timings as defined in
|
||||||
Documentation/devicetree/bindings/display/display-timing.txt.
|
Documentation/devicetree/bindings/display/panel/display-timing.txt.
|
||||||
- fsl,data-mapping : should be "spwg" or "jeida"
|
- fsl,data-mapping : should be "spwg" or "jeida"
|
||||||
This describes how the color bits are laid out in the
|
This describes how the color bits are laid out in the
|
||||||
serialized LVDS signal.
|
serialized LVDS signal.
|
||||||
|
|
|
@ -55,7 +55,7 @@ Required properties (DMA function blocks):
|
||||||
"mediatek,<chip>-disp-rdma"
|
"mediatek,<chip>-disp-rdma"
|
||||||
"mediatek,<chip>-disp-wdma"
|
"mediatek,<chip>-disp-wdma"
|
||||||
- larb: Should contain a phandle pointing to the local arbiter device as defined
|
- larb: Should contain a phandle pointing to the local arbiter device as defined
|
||||||
in Documentation/devicetree/bindings/soc/mediatek/mediatek,smi-larb.txt
|
in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
|
||||||
- iommus: Should point to the respective IOMMU block with master port as
|
- iommus: Should point to the respective IOMMU block with master port as
|
||||||
argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
|
argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
|
||||||
for details.
|
for details.
|
||||||
|
|
|
@ -108,7 +108,7 @@ Optional properties:
|
||||||
- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
|
- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
|
||||||
regulator is wanted.
|
regulator is wanted.
|
||||||
|
|
||||||
[1] Documentation/devicetree/bindings/clocks/clock-bindings.txt
|
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||||
[2] Documentation/devicetree/bindings/graph.txt
|
[2] Documentation/devicetree/bindings/graph.txt
|
||||||
[3] Documentation/devicetree/bindings/media/video-interfaces.txt
|
[3] Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||||
[4] Documentation/devicetree/bindings/display/panel/
|
[4] Documentation/devicetree/bindings/display/panel/
|
||||||
|
|
|
@ -10,7 +10,7 @@ Required properties:
|
||||||
- interrupts: The interrupt signal from the eDP block.
|
- interrupts: The interrupt signal from the eDP block.
|
||||||
- power-domains: Should be <&mmcc MDSS_GDSC>.
|
- power-domains: Should be <&mmcc MDSS_GDSC>.
|
||||||
- clocks: device clocks
|
- clocks: device clocks
|
||||||
See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
|
See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
|
||||||
- clock-names: the following clocks are required:
|
- clock-names: the following clocks are required:
|
||||||
* "core_clk"
|
* "core_clk"
|
||||||
* "iface_clk"
|
* "iface_clk"
|
||||||
|
|
|
@ -49,7 +49,7 @@ Required properties:
|
||||||
* "hdmi_tx_l4"
|
* "hdmi_tx_l4"
|
||||||
- power-domains: Should be <&mmcc MDSS_GDSC>.
|
- power-domains: Should be <&mmcc MDSS_GDSC>.
|
||||||
- clocks: device clocks
|
- clocks: device clocks
|
||||||
See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
|
See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
|
||||||
- core-vdda-supply: phandle to vdda regulator device node
|
- core-vdda-supply: phandle to vdda regulator device node
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
|
@ -12,7 +12,7 @@ Optional properties:
|
||||||
|
|
||||||
Required nodes:
|
Required nodes:
|
||||||
- "panel-timing" containing video timings
|
- "panel-timing" containing video timings
|
||||||
(Documentation/devicetree/bindings/display/display-timing.txt)
|
(Documentation/devicetree/bindings/display/panel/display-timing.txt)
|
||||||
- Video port for DPI input
|
- Video port for DPI input
|
||||||
|
|
||||||
Example
|
Example
|
||||||
|
|
|
@ -20,7 +20,7 @@ The device node can contain one 'port' child node with one child
|
||||||
'endpoint' node, according to the bindings defined in [3]. This
|
'endpoint' node, according to the bindings defined in [3]. This
|
||||||
node should describe panel's video bus.
|
node should describe panel's video bus.
|
||||||
|
|
||||||
[1]: Documentation/devicetree/bindings/display/display-timing.txt
|
[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt
|
||||||
[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
|
[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||||
[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ The device node can contain one 'port' child node with one child
|
||||||
'endpoint' node, according to the bindings defined in [2]. This
|
'endpoint' node, according to the bindings defined in [2]. This
|
||||||
node should describe panel's video bus.
|
node should describe panel's video bus.
|
||||||
|
|
||||||
[1]: Documentation/devicetree/bindings/display/display-timing.txt
|
[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt
|
||||||
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
|
@ -35,7 +35,7 @@ Optional property for different chips:
|
||||||
Required elements: "grf"
|
Required elements: "grf"
|
||||||
|
|
||||||
For the below properties, please refer to Analogix DP binding document:
|
For the below properties, please refer to Analogix DP binding document:
|
||||||
* Documentation/devicetree/bindings/drm/bridge/analogix_dp.txt
|
* Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
|
||||||
- phys (required)
|
- phys (required)
|
||||||
- phy-names (required)
|
- phy-names (required)
|
||||||
- hpd-gpios (optional)
|
- hpd-gpios (optional)
|
||||||
|
|
|
@ -15,7 +15,7 @@ Required properties:
|
||||||
- display-timings: typical videomode of lcd panel. Multiple video modes
|
- display-timings: typical videomode of lcd panel. Multiple video modes
|
||||||
can be listed if the panel supports multiple timings, but the 'native-mode'
|
can be listed if the panel supports multiple timings, but the 'native-mode'
|
||||||
should be the preferred/default resolution. Refer to
|
should be the preferred/default resolution. Refer to
|
||||||
Documentation/devicetree/bindings/display/display-timing.txt for display
|
Documentation/devicetree/bindings/display/panel/display-timing.txt for display
|
||||||
timing binding details.
|
timing binding details.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|
|
@ -36,15 +36,15 @@ conditions.
|
||||||
combined interrupt, it must be listed multiple times.
|
combined interrupt, it must be listed multiple times.
|
||||||
|
|
||||||
- #iommu-cells : See Documentation/devicetree/bindings/iommu/iommu.txt
|
- #iommu-cells : See Documentation/devicetree/bindings/iommu/iommu.txt
|
||||||
for details. With a value of 1, each "iommus" entry
|
for details. With a value of 1, each IOMMU specifier
|
||||||
represents a distinct stream ID emitted by that device
|
represents a distinct stream ID emitted by that device
|
||||||
into the relevant SMMU.
|
into the relevant SMMU.
|
||||||
|
|
||||||
SMMUs with stream matching support and complex masters
|
SMMUs with stream matching support and complex masters
|
||||||
may use a value of 2, where the second cell represents
|
may use a value of 2, where the second cell of the
|
||||||
an SMR mask to combine with the ID in the first cell.
|
IOMMU specifier represents an SMR mask to combine with
|
||||||
Care must be taken to ensure the set of matched IDs
|
the ID in the first cell. Care must be taken to ensure
|
||||||
does not result in conflicts.
|
the set of matched IDs does not result in conflicts.
|
||||||
|
|
||||||
** System MMU optional properties:
|
** System MMU optional properties:
|
||||||
|
|
||||||
|
|
|
@ -122,8 +122,7 @@ Following are properties of regulator subnode.
|
||||||
|
|
||||||
Power-off:
|
Power-off:
|
||||||
=========
|
=========
|
||||||
AS3722 supports the system power off by turning off all its rail. This
|
AS3722 supports the system power off by turning off all its rails.
|
||||||
is provided through pm_power_off.
|
|
||||||
The device node should have the following properties to enable this
|
The device node should have the following properties to enable this
|
||||||
functionality
|
functionality
|
||||||
ams,system-power-controller: Boolean, to enable the power off functionality
|
ams,system-power-controller: Boolean, to enable the power off functionality
|
||||||
|
|
|
@ -64,8 +64,8 @@ Required properties if child node exists:
|
||||||
Properties for children:
|
Properties for children:
|
||||||
|
|
||||||
The OMAP HS USB Host subsystem contains EHCI and OHCI controllers.
|
The OMAP HS USB Host subsystem contains EHCI and OHCI controllers.
|
||||||
See Documentation/devicetree/bindings/usb/omap-ehci.txt and
|
See Documentation/devicetree/bindings/usb/ehci-omap.txt and
|
||||||
omap3-ohci.txt
|
Documentation/devicetree/bindings/usb/ohci-omap3.txt.
|
||||||
|
|
||||||
Example for OMAP4:
|
Example for OMAP4:
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,7 @@ Optional properties (port):
|
||||||
|
|
||||||
- marvell,loopback: port is loopback mode
|
- marvell,loopback: port is loopback mode
|
||||||
- phy: a phandle to a phy node defining the PHY address (as the reg
|
- phy: a phandle to a phy node defining the PHY address (as the reg
|
||||||
property, a single integer). Note: if this property isn't present,
|
property, a single integer).
|
||||||
then fixed link is assumed, and the 'fixed-link' property is
|
|
||||||
mandatory.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,17 @@ PCI root complex
|
||||||
Optional properties
|
Optional properties
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- iommu-map: Maps a Requester ID to an IOMMU and associated iommu-specifier
|
- iommu-map: Maps a Requester ID to an IOMMU and associated IOMMU specifier
|
||||||
data.
|
data.
|
||||||
|
|
||||||
The property is an arbitrary number of tuples of
|
The property is an arbitrary number of tuples of
|
||||||
(rid-base,iommu,iommu-base,length).
|
(rid-base,iommu,iommu-base,length).
|
||||||
|
|
||||||
Any RID r in the interval [rid-base, rid-base + length) is associated with
|
Any RID r in the interval [rid-base, rid-base + length) is associated with
|
||||||
the listed IOMMU, with the iommu-specifier (r - rid-base + iommu-base).
|
the listed IOMMU, with the IOMMU specifier (r - rid-base + iommu-base).
|
||||||
|
|
||||||
- iommu-map-mask: A mask to be applied to each Requester ID prior to being
|
- iommu-map-mask: A mask to be applied to each Requester ID prior to being
|
||||||
mapped to an iommu-specifier per the iommu-map property.
|
mapped to an IOMMU specifier per the iommu-map property.
|
||||||
|
|
||||||
|
|
||||||
Example (1)
|
Example (1)
|
||||||
|
|
|
@ -2,12 +2,12 @@ Driver a GPIO line that can be used to turn the power off.
|
||||||
|
|
||||||
The driver supports both level triggered and edge triggered power off.
|
The driver supports both level triggered and edge triggered power off.
|
||||||
At driver load time, the driver will request the given gpio line and
|
At driver load time, the driver will request the given gpio line and
|
||||||
install a pm_power_off handler. If the optional properties 'input' is
|
install a handler to power off the system. If the optional properties
|
||||||
not found, the GPIO line will be driven in the inactive
|
'input' is not found, the GPIO line will be driven in the inactive
|
||||||
state. Otherwise its configured as an input.
|
state. Otherwise its configured as an input.
|
||||||
|
|
||||||
When the pm_power_off is called, the gpio is configured as an output,
|
When the power-off handler is called, the gpio is configured as an
|
||||||
and drive active, so triggering a level triggered power off
|
output, and drive active, so triggering a level triggered power off
|
||||||
condition. This will also cause an inactive->active edge condition, so
|
condition. This will also cause an inactive->active edge condition, so
|
||||||
triggering positive edge triggered power off. After a delay of 100ms,
|
triggering positive edge triggered power off. After a delay of 100ms,
|
||||||
the GPIO is set to inactive, thus causing an active->inactive edge,
|
the GPIO is set to inactive, thus causing an active->inactive edge,
|
||||||
|
@ -24,7 +24,7 @@ Required properties:
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- input : Initially configure the GPIO line as an input. Only reconfigure
|
- input : Initially configure the GPIO line as an input. Only reconfigure
|
||||||
it to an output when the pm_power_off function is called. If this optional
|
it to an output when the power-off handler is called. If this optional
|
||||||
property is not specified, the GPIO is initialized as an output in its
|
property is not specified, the GPIO is initialized as an output in its
|
||||||
inactive state.
|
inactive state.
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
QNAP NAS devices have a microcontroller controlling the main power
|
QNAP NAS devices have a microcontroller controlling the main power
|
||||||
supply. This microcontroller is connected to UART1 of the Kirkwood and
|
supply. This microcontroller is connected to UART1 of the Kirkwood and
|
||||||
Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the
|
Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the
|
||||||
microcontroller to turn the power off. This driver adds a handler to
|
microcontroller to turn the power off.
|
||||||
pm_power_off which is called to turn the power off.
|
|
||||||
|
|
||||||
Synology NAS devices use a similar scheme, but a different baud rate,
|
Synology NAS devices use a similar scheme, but a different baud rate,
|
||||||
9600, and a different character, '1'.
|
9600, and a different character, '1'.
|
||||||
|
|
|
@ -6,11 +6,13 @@ Required properties:
|
||||||
- interrupts : Should contain uart interrupt
|
- interrupts : Should contain uart interrupt
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- uart-has-rtscts : Indicate the uart has rts and cts
|
|
||||||
- fsl,irda-mode : Indicate the uart supports irda mode
|
- fsl,irda-mode : Indicate the uart supports irda mode
|
||||||
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
|
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
|
||||||
in DCE mode by default.
|
in DCE mode by default.
|
||||||
|
|
||||||
|
Please check Documentation/devicetree/bindings/serial/serial.txt
|
||||||
|
for the complete list of generic properties.
|
||||||
|
|
||||||
Note: Each uart controller should have an alias correctly numbered
|
Note: Each uart controller should have an alias correctly numbered
|
||||||
in "aliases" node.
|
in "aliases" node.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ Copyright (C) 2008 - 2014 Freescale Semiconductor Inc.
|
||||||
CONTENTS
|
CONTENTS
|
||||||
|
|
||||||
- QMan Portal
|
- QMan Portal
|
||||||
- QMan Pool Channel
|
|
||||||
- Example
|
- Example
|
||||||
|
|
||||||
QMan Portal Node
|
QMan Portal Node
|
||||||
|
@ -82,25 +81,6 @@ These subnodes should have the following properties:
|
||||||
Definition: The phandle to the particular hardware device that this
|
Definition: The phandle to the particular hardware device that this
|
||||||
portal is connected to.
|
portal is connected to.
|
||||||
|
|
||||||
DPAA QMan Pool Channel Nodes
|
|
||||||
|
|
||||||
Pool Channels are defined with the following properties.
|
|
||||||
|
|
||||||
PROPERTIES
|
|
||||||
|
|
||||||
- compatible
|
|
||||||
Usage: Required
|
|
||||||
Value type: <stringlist>
|
|
||||||
Definition: Must include "fsl,qman-pool-channel"
|
|
||||||
May include "fsl,<SoC>-qman-pool-channel"
|
|
||||||
|
|
||||||
- fsl,qman-channel-id
|
|
||||||
Usage: Required
|
|
||||||
Value type: <u32>
|
|
||||||
Definition: The hardware index of the channel. This can also be
|
|
||||||
determined by dividing any of the channel's 8 work queue
|
|
||||||
IDs by 8
|
|
||||||
|
|
||||||
EXAMPLE
|
EXAMPLE
|
||||||
|
|
||||||
The example below shows a (P4080) QMan portals container/bus node with two portals
|
The example below shows a (P4080) QMan portals container/bus node with two portals
|
||||||
|
|
|
@ -29,4 +29,3 @@ usbhsehci: ehci@4a064c00 {
|
||||||
&usbhsehci {
|
&usbhsehci {
|
||||||
phys = <&hsusb1_phy 0 &hsusb3_phy>;
|
phys = <&hsusb1_phy 0 &hsusb3_phy>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -104,11 +104,13 @@ everest Everest Semiconductor Co. Ltd.
|
||||||
everspin Everspin Technologies, Inc.
|
everspin Everspin Technologies, Inc.
|
||||||
excito Excito
|
excito Excito
|
||||||
ezchip EZchip Semiconductor
|
ezchip EZchip Semiconductor
|
||||||
|
faraday Faraday Technology Corporation
|
||||||
fcs Fairchild Semiconductor
|
fcs Fairchild Semiconductor
|
||||||
firefly Firefly
|
firefly Firefly
|
||||||
focaltech FocalTech Systems Co.,Ltd
|
focaltech FocalTech Systems Co.,Ltd
|
||||||
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
|
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
|
||||||
fsl Freescale Semiconductor
|
fsl Freescale Semiconductor
|
||||||
|
fujitsu Fujitsu Ltd.
|
||||||
ge General Electric Company
|
ge General Electric Company
|
||||||
geekbuying GeekBuying
|
geekbuying GeekBuying
|
||||||
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||||
|
|
|
@ -843,8 +843,11 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
|
||||||
if (!np)
|
if (!np)
|
||||||
np = of_node_get(of_root);
|
np = of_node_get(of_root);
|
||||||
while (np && *path == '/') {
|
while (np && *path == '/') {
|
||||||
|
struct device_node *tmp = np;
|
||||||
|
|
||||||
path++; /* Increment past '/' delimiter */
|
path++; /* Increment past '/' delimiter */
|
||||||
np = __of_find_node_by_path(np, path);
|
np = __of_find_node_by_path(np, path);
|
||||||
|
of_node_put(tmp);
|
||||||
path = strchrnul(path, '/');
|
path = strchrnul(path, '/');
|
||||||
if (separator && separator < path)
|
if (separator && separator < path)
|
||||||
break;
|
break;
|
||||||
|
@ -2495,3 +2498,40 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node)
|
||||||
return of_get_next_parent(np);
|
return of_get_next_parent(np);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_graph_get_remote_port);
|
EXPORT_SYMBOL(of_graph_get_remote_port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
* version 2 as published by the Free Software Foundation.
|
* version 2 as published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) "OF: fdt:" fmt
|
#define pr_fmt(fmt) "OF: fdt: " fmt
|
||||||
|
|
||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
|
@ -104,7 +104,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||||
const __be32 *match_array = initial_match_array;
|
const __be32 *match_array = initial_match_array;
|
||||||
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
|
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
|
||||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||||
int imaplen, match, i;
|
int imaplen, match, i, rc = -EINVAL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
of_print_phandle_args("of_irq_parse_raw: ", out_irq);
|
of_print_phandle_args("of_irq_parse_raw: ", out_irq);
|
||||||
|
@ -134,7 +134,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||||
pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
|
pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
|
||||||
|
|
||||||
if (out_irq->args_count != intsize)
|
if (out_irq->args_count != intsize)
|
||||||
return -EINVAL;
|
goto fail;
|
||||||
|
|
||||||
/* Look for this #address-cells. We have to implement the old linux
|
/* Look for this #address-cells. We have to implement the old linux
|
||||||
* trick of looking for the parent here as some device-trees rely on it
|
* trick of looking for the parent here as some device-trees rely on it
|
||||||
|
@ -153,8 +153,10 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||||
pr_debug(" -> addrsize=%d\n", addrsize);
|
pr_debug(" -> addrsize=%d\n", addrsize);
|
||||||
|
|
||||||
/* Range check so that the temporary buffer doesn't overflow */
|
/* Range check so that the temporary buffer doesn't overflow */
|
||||||
if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
|
if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
|
||||||
|
rc = -EFAULT;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Precalculate the match array - this simplifies match loop */
|
/* Precalculate the match array - this simplifies match loop */
|
||||||
for (i = 0; i < addrsize; i++)
|
for (i = 0; i < addrsize; i++)
|
||||||
|
@ -240,10 +242,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||||
newintsize, newaddrsize);
|
newintsize, newaddrsize);
|
||||||
|
|
||||||
/* Check for malformed properties */
|
/* Check for malformed properties */
|
||||||
if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
|
if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
|
||||||
goto fail;
|
|| (imaplen < (newaddrsize + newintsize))) {
|
||||||
if (imaplen < (newaddrsize + newintsize))
|
rc = -EFAULT;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
imap += newaddrsize + newintsize;
|
imap += newaddrsize + newintsize;
|
||||||
imaplen -= newaddrsize + newintsize;
|
imaplen -= newaddrsize + newintsize;
|
||||||
|
@ -271,11 +274,13 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||||
ipar = newpar;
|
ipar = newpar;
|
||||||
newpar = NULL;
|
newpar = NULL;
|
||||||
}
|
}
|
||||||
|
rc = -ENOENT; /* No interrupt-map found */
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
of_node_put(ipar);
|
of_node_put(ipar);
|
||||||
of_node_put(newpar);
|
of_node_put(newpar);
|
||||||
|
|
||||||
return -EINVAL;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_irq_parse_raw);
|
EXPORT_SYMBOL_GPL(of_irq_parse_raw);
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,15 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
|
||||||
goto err;
|
goto err;
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
dev_err(&pdev->dev, "of_irq_parse_pci() failed with rc=%d\n", rc);
|
if (rc == -ENOENT) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"%s: no interrupt-map found, INTx interrupts not available\n",
|
||||||
|
__func__);
|
||||||
|
pr_warn_once("%s: possibly some PCI slots don't have level triggered interrupts capability\n",
|
||||||
|
__func__);
|
||||||
|
} else {
|
||||||
|
dev_err(&pdev->dev, "%s: failed with rc=%d\n", __func__, rc);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_irq_parse_pci);
|
EXPORT_SYMBOL_GPL(of_irq_parse_pci);
|
||||||
|
|
|
@ -354,6 +354,10 @@ int of_reserved_mem_device_init_by_idx(struct device *dev,
|
||||||
mutex_lock(&of_rmem_assigned_device_mutex);
|
mutex_lock(&of_rmem_assigned_device_mutex);
|
||||||
list_add(&rd->list, &of_rmem_assigned_device_list);
|
list_add(&rd->list, &of_rmem_assigned_device_list);
|
||||||
mutex_unlock(&of_rmem_assigned_device_mutex);
|
mutex_unlock(&of_rmem_assigned_device_mutex);
|
||||||
|
/* ensure that dma_ops is set for virtual devices
|
||||||
|
* using reserved memory
|
||||||
|
*/
|
||||||
|
of_dma_configure(dev, np);
|
||||||
|
|
||||||
dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
|
dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
|
@ -314,7 +313,6 @@ static int of_build_overlay_info(struct of_overlay *ov,
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
for_each_child_of_node(tree, node) {
|
for_each_child_of_node(tree, node) {
|
||||||
memset(&ovinfo[cnt], 0, sizeof(*ovinfo));
|
|
||||||
err = of_fill_overlay_info(ov, node, &ovinfo[cnt]);
|
err = of_fill_overlay_info(ov, node, &ovinfo[cnt]);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
|
@ -76,7 +76,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
|
||||||
* derive a unique name. If it cannot, then it will prepend names from
|
* derive a unique name. If it cannot, then it will prepend names from
|
||||||
* parent nodes until a unique name can be derived.
|
* parent nodes until a unique name can be derived.
|
||||||
*/
|
*/
|
||||||
void of_device_make_bus_id(struct device *dev)
|
static void of_device_make_bus_id(struct device *dev)
|
||||||
{
|
{
|
||||||
struct device_node *node = dev->of_node;
|
struct device_node *node = dev->of_node;
|
||||||
const __be32 *reg;
|
const __be32 *reg;
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
/* illegal phandle value (set when unresolved) */
|
/* illegal phandle value (set when unresolved) */
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/of_platform.h>
|
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/i2c-mux.h>
|
#include <linux/i2c-mux.h>
|
||||||
|
@ -1181,7 +1180,7 @@ static void of_unittest_destroy_tracked_overlays(void)
|
||||||
} while (defers > 0);
|
} while (defers > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr,
|
static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
|
||||||
int *overlay_id)
|
int *overlay_id)
|
||||||
{
|
{
|
||||||
struct device_node *np = NULL;
|
struct device_node *np = NULL;
|
||||||
|
@ -1840,7 +1839,7 @@ static void of_unittest_overlay_i2c_15(void)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* device should enable */
|
/* device should enable */
|
||||||
ret = of_unittest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY);
|
ret = of_unittest_apply_overlay_check(15, 15, 0, 1, I2C_OVERLAY);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ struct device;
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
extern const struct of_device_id *of_match_device(
|
extern const struct of_device_id *of_match_device(
|
||||||
const struct of_device_id *matches, const struct device *dev);
|
const struct of_device_id *matches, const struct device *dev);
|
||||||
extern void of_device_make_bus_id(struct device *dev);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* of_driver_match_device - Tell if a driver's of_match_table matches a device.
|
* of_driver_match_device - Tell if a driver's of_match_table matches a device.
|
||||||
|
|
|
@ -51,6 +51,8 @@ struct device_node *of_graph_get_endpoint_by_regs(
|
||||||
struct device_node *of_graph_get_remote_port_parent(
|
struct device_node *of_graph_get_remote_port_parent(
|
||||||
const struct device_node *node);
|
const struct device_node *node);
|
||||||
struct device_node *of_graph_get_remote_port(const struct device_node *node);
|
struct device_node *of_graph_get_remote_port(const struct device_node *node);
|
||||||
|
struct device_node *of_graph_get_remote_node(const struct device_node *node,
|
||||||
|
u32 port, u32 endpoint);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int of_graph_parse_endpoint(const struct device_node *node,
|
static inline int of_graph_parse_endpoint(const struct device_node *node,
|
||||||
|
@ -89,6 +91,12 @@ static inline struct device_node *of_graph_get_remote_port(
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
static inline struct device_node *of_graph_get_remote_node(
|
||||||
|
const struct device_node *node,
|
||||||
|
u32 port, u32 endpoint)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_OF */
|
#endif /* CONFIG_OF */
|
||||||
|
|
||||||
|
|
|
@ -40,16 +40,11 @@ enum checkstatus {
|
||||||
|
|
||||||
struct check;
|
struct check;
|
||||||
|
|
||||||
typedef void (*tree_check_fn)(struct check *c, struct node *dt);
|
typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node);
|
||||||
typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
|
|
||||||
typedef void (*prop_check_fn)(struct check *c, struct node *dt,
|
|
||||||
struct node *node, struct property *prop);
|
|
||||||
|
|
||||||
struct check {
|
struct check {
|
||||||
const char *name;
|
const char *name;
|
||||||
tree_check_fn tree_fn;
|
check_fn fn;
|
||||||
node_check_fn node_fn;
|
|
||||||
prop_check_fn prop_fn;
|
|
||||||
void *data;
|
void *data;
|
||||||
bool warn, error;
|
bool warn, error;
|
||||||
enum checkstatus status;
|
enum checkstatus status;
|
||||||
|
@ -58,45 +53,24 @@ struct check {
|
||||||
struct check **prereq;
|
struct check **prereq;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
|
#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \
|
||||||
static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
|
static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
|
||||||
static struct check nm = { \
|
static struct check _nm = { \
|
||||||
.name = #nm, \
|
.name = #_nm, \
|
||||||
.tree_fn = (tfn), \
|
.fn = (_fn), \
|
||||||
.node_fn = (nfn), \
|
.data = (_d), \
|
||||||
.prop_fn = (pfn), \
|
.warn = (_w), \
|
||||||
.data = (d), \
|
.error = (_e), \
|
||||||
.warn = (w), \
|
|
||||||
.error = (e), \
|
|
||||||
.status = UNCHECKED, \
|
.status = UNCHECKED, \
|
||||||
.num_prereqs = ARRAY_SIZE(nm##_prereqs), \
|
.num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
|
||||||
.prereq = nm##_prereqs, \
|
.prereq = _nm##_prereqs, \
|
||||||
};
|
};
|
||||||
#define WARNING(nm, tfn, nfn, pfn, d, ...) \
|
#define WARNING(_nm, _fn, _d, ...) \
|
||||||
CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
|
CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
|
||||||
#define ERROR(nm, tfn, nfn, pfn, d, ...) \
|
#define ERROR(_nm, _fn, _d, ...) \
|
||||||
CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
|
CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
|
||||||
#define CHECK(nm, tfn, nfn, pfn, d, ...) \
|
#define CHECK(_nm, _fn, _d, ...) \
|
||||||
CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__)
|
CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
|
||||||
|
|
||||||
#define TREE_WARNING(nm, d, ...) \
|
|
||||||
WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
|
||||||
#define TREE_ERROR(nm, d, ...) \
|
|
||||||
ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
|
||||||
#define TREE_CHECK(nm, d, ...) \
|
|
||||||
CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
|
||||||
#define NODE_WARNING(nm, d, ...) \
|
|
||||||
WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
|
||||||
#define NODE_ERROR(nm, d, ...) \
|
|
||||||
ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
|
||||||
#define NODE_CHECK(nm, d, ...) \
|
|
||||||
CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
|
||||||
#define PROP_WARNING(nm, d, ...) \
|
|
||||||
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
|
||||||
#define PROP_ERROR(nm, d, ...) \
|
|
||||||
ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
|
||||||
#define PROP_CHECK(nm, d, ...) \
|
|
||||||
CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
|
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
|
||||||
|
@ -123,27 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
|
||||||
check_msg((c), __VA_ARGS__); \
|
check_msg((c), __VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
|
static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
|
||||||
{
|
{
|
||||||
struct node *child;
|
struct node *child;
|
||||||
struct property *prop;
|
|
||||||
|
|
||||||
TRACE(c, "%s", node->fullpath);
|
TRACE(c, "%s", node->fullpath);
|
||||||
if (c->node_fn)
|
if (c->fn)
|
||||||
c->node_fn(c, dt, node);
|
c->fn(c, dti, node);
|
||||||
|
|
||||||
if (c->prop_fn)
|
|
||||||
for_each_property(node, prop) {
|
|
||||||
TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
|
|
||||||
c->prop_fn(c, dt, node, prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
for_each_child(node, child)
|
for_each_child(node, child)
|
||||||
check_nodes_props(c, dt, child);
|
check_nodes_props(c, dti, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool run_check(struct check *c, struct node *dt)
|
static bool run_check(struct check *c, struct dt_info *dti)
|
||||||
{
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -156,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt)
|
||||||
|
|
||||||
for (i = 0; i < c->num_prereqs; i++) {
|
for (i = 0; i < c->num_prereqs; i++) {
|
||||||
struct check *prq = c->prereq[i];
|
struct check *prq = c->prereq[i];
|
||||||
error = error || run_check(prq, dt);
|
error = error || run_check(prq, dti);
|
||||||
if (prq->status != PASSED) {
|
if (prq->status != PASSED) {
|
||||||
c->status = PREREQ;
|
c->status = PREREQ;
|
||||||
check_msg(c, "Failed prerequisite '%s'",
|
check_msg(c, "Failed prerequisite '%s'",
|
||||||
|
@ -167,11 +135,8 @@ static bool run_check(struct check *c, struct node *dt)
|
||||||
if (c->status != UNCHECKED)
|
if (c->status != UNCHECKED)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (c->node_fn || c->prop_fn)
|
check_nodes_props(c, dti, dt);
|
||||||
check_nodes_props(c, dt, dt);
|
|
||||||
|
|
||||||
if (c->tree_fn)
|
|
||||||
c->tree_fn(c, dt);
|
|
||||||
if (c->status == UNCHECKED)
|
if (c->status == UNCHECKED)
|
||||||
c->status = PASSED;
|
c->status = PASSED;
|
||||||
|
|
||||||
|
@ -189,13 +154,14 @@ out:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* A check which always fails, for testing purposes only */
|
/* A check which always fails, for testing purposes only */
|
||||||
static inline void check_always_fail(struct check *c, struct node *dt)
|
static inline void check_always_fail(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
{
|
{
|
||||||
FAIL(c, "always_fail check");
|
FAIL(c, "always_fail check");
|
||||||
}
|
}
|
||||||
TREE_CHECK(always_fail, NULL);
|
CHECK(always_fail, check_always_fail, NULL);
|
||||||
|
|
||||||
static void check_is_string(struct check *c, struct node *root,
|
static void check_is_string(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
@ -210,11 +176,11 @@ static void check_is_string(struct check *c, struct node *root,
|
||||||
propname, node->fullpath);
|
propname, node->fullpath);
|
||||||
}
|
}
|
||||||
#define WARNING_IF_NOT_STRING(nm, propname) \
|
#define WARNING_IF_NOT_STRING(nm, propname) \
|
||||||
WARNING(nm, NULL, check_is_string, NULL, (propname))
|
WARNING(nm, check_is_string, (propname))
|
||||||
#define ERROR_IF_NOT_STRING(nm, propname) \
|
#define ERROR_IF_NOT_STRING(nm, propname) \
|
||||||
ERROR(nm, NULL, check_is_string, NULL, (propname))
|
ERROR(nm, check_is_string, (propname))
|
||||||
|
|
||||||
static void check_is_cell(struct check *c, struct node *root,
|
static void check_is_cell(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
@ -229,15 +195,15 @@ static void check_is_cell(struct check *c, struct node *root,
|
||||||
propname, node->fullpath);
|
propname, node->fullpath);
|
||||||
}
|
}
|
||||||
#define WARNING_IF_NOT_CELL(nm, propname) \
|
#define WARNING_IF_NOT_CELL(nm, propname) \
|
||||||
WARNING(nm, NULL, check_is_cell, NULL, (propname))
|
WARNING(nm, check_is_cell, (propname))
|
||||||
#define ERROR_IF_NOT_CELL(nm, propname) \
|
#define ERROR_IF_NOT_CELL(nm, propname) \
|
||||||
ERROR(nm, NULL, check_is_cell, NULL, (propname))
|
ERROR(nm, check_is_cell, (propname))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structural check functions
|
* Structural check functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void check_duplicate_node_names(struct check *c, struct node *dt,
|
static void check_duplicate_node_names(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct node *child, *child2;
|
struct node *child, *child2;
|
||||||
|
@ -250,9 +216,9 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
|
||||||
FAIL(c, "Duplicate node name %s",
|
FAIL(c, "Duplicate node name %s",
|
||||||
child->fullpath);
|
child->fullpath);
|
||||||
}
|
}
|
||||||
NODE_ERROR(duplicate_node_names, NULL);
|
ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
|
||||||
|
|
||||||
static void check_duplicate_property_names(struct check *c, struct node *dt,
|
static void check_duplicate_property_names(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop, *prop2;
|
struct property *prop, *prop2;
|
||||||
|
@ -267,14 +233,14 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NODE_ERROR(duplicate_property_names, NULL);
|
ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
|
||||||
|
|
||||||
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
|
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
|
||||||
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
#define DIGITS "0123456789"
|
#define DIGITS "0123456789"
|
||||||
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
|
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
|
||||||
|
|
||||||
static void check_node_name_chars(struct check *c, struct node *dt,
|
static void check_node_name_chars(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
int n = strspn(node->name, c->data);
|
int n = strspn(node->name, c->data);
|
||||||
|
@ -283,19 +249,19 @@ static void check_node_name_chars(struct check *c, struct node *dt,
|
||||||
FAIL(c, "Bad character '%c' in node %s",
|
FAIL(c, "Bad character '%c' in node %s",
|
||||||
node->name[n], node->fullpath);
|
node->name[n], node->fullpath);
|
||||||
}
|
}
|
||||||
NODE_ERROR(node_name_chars, PROPNODECHARS "@");
|
ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
|
||||||
|
|
||||||
static void check_node_name_format(struct check *c, struct node *dt,
|
static void check_node_name_format(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
if (strchr(get_unitname(node), '@'))
|
if (strchr(get_unitname(node), '@'))
|
||||||
FAIL(c, "Node %s has multiple '@' characters in name",
|
FAIL(c, "Node %s has multiple '@' characters in name",
|
||||||
node->fullpath);
|
node->fullpath);
|
||||||
}
|
}
|
||||||
NODE_ERROR(node_name_format, NULL, &node_name_chars);
|
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
|
||||||
|
|
||||||
static void check_unit_address_vs_reg(struct check *c, struct node *dt,
|
static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
const char *unitname = get_unitname(node);
|
const char *unitname = get_unitname(node);
|
||||||
struct property *prop = get_property(node, "reg");
|
struct property *prop = get_property(node, "reg");
|
||||||
|
@ -316,18 +282,22 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt,
|
||||||
node->fullpath);
|
node->fullpath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NODE_WARNING(unit_address_vs_reg, NULL);
|
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
|
||||||
|
|
||||||
static void check_property_name_chars(struct check *c, struct node *dt,
|
static void check_property_name_chars(struct check *c, struct dt_info *dti,
|
||||||
struct node *node, struct property *prop)
|
struct node *node)
|
||||||
{
|
{
|
||||||
int n = strspn(prop->name, c->data);
|
struct property *prop;
|
||||||
|
|
||||||
if (n < strlen(prop->name))
|
for_each_property(node, prop) {
|
||||||
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
|
int n = strspn(prop->name, c->data);
|
||||||
prop->name[n], prop->name, node->fullpath);
|
|
||||||
|
if (n < strlen(prop->name))
|
||||||
|
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
|
||||||
|
prop->name[n], prop->name, node->fullpath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PROP_ERROR(property_name_chars, PROPNODECHARS);
|
ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
|
||||||
|
|
||||||
#define DESCLABEL_FMT "%s%s%s%s%s"
|
#define DESCLABEL_FMT "%s%s%s%s%s"
|
||||||
#define DESCLABEL_ARGS(node,prop,mark) \
|
#define DESCLABEL_ARGS(node,prop,mark) \
|
||||||
|
@ -336,10 +306,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS);
|
||||||
((prop) ? (prop)->name : ""), \
|
((prop) ? (prop)->name : ""), \
|
||||||
((prop) ? "' in " : ""), (node)->fullpath
|
((prop) ? "' in " : ""), (node)->fullpath
|
||||||
|
|
||||||
static void check_duplicate_label(struct check *c, struct node *dt,
|
static void check_duplicate_label(struct check *c, struct dt_info *dti,
|
||||||
const char *label, struct node *node,
|
const char *label, struct node *node,
|
||||||
struct property *prop, struct marker *mark)
|
struct property *prop, struct marker *mark)
|
||||||
{
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
struct node *othernode = NULL;
|
struct node *othernode = NULL;
|
||||||
struct property *otherprop = NULL;
|
struct property *otherprop = NULL;
|
||||||
struct marker *othermark = NULL;
|
struct marker *othermark = NULL;
|
||||||
|
@ -362,44 +333,43 @@ static void check_duplicate_label(struct check *c, struct node *dt,
|
||||||
DESCLABEL_ARGS(othernode, otherprop, othermark));
|
DESCLABEL_ARGS(othernode, otherprop, othermark));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_duplicate_label_node(struct check *c, struct node *dt,
|
static void check_duplicate_label_node(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct label *l;
|
struct label *l;
|
||||||
|
struct property *prop;
|
||||||
|
|
||||||
for_each_label(node->labels, l)
|
for_each_label(node->labels, l)
|
||||||
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
|
check_duplicate_label(c, dti, l->label, node, NULL, NULL);
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
struct marker *m = prop->val.markers;
|
||||||
|
|
||||||
|
for_each_label(prop->labels, l)
|
||||||
|
check_duplicate_label(c, dti, l->label, node, prop, NULL);
|
||||||
|
|
||||||
|
for_each_marker_of_type(m, LABEL)
|
||||||
|
check_duplicate_label(c, dti, m->ref, node, prop, m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void check_duplicate_label_prop(struct check *c, struct node *dt,
|
ERROR(duplicate_label, check_duplicate_label_node, NULL);
|
||||||
struct node *node, struct property *prop)
|
|
||||||
{
|
static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
|
||||||
struct marker *m = prop->val.markers;
|
struct node *node, const char *propname)
|
||||||
struct label *l;
|
|
||||||
|
|
||||||
for_each_label(prop->labels, l)
|
|
||||||
check_duplicate_label(c, dt, l->label, node, prop, NULL);
|
|
||||||
|
|
||||||
for_each_marker_of_type(m, LABEL)
|
|
||||||
check_duplicate_label(c, dt, m->ref, node, prop, m);
|
|
||||||
}
|
|
||||||
ERROR(duplicate_label, NULL, check_duplicate_label_node,
|
|
||||||
check_duplicate_label_prop, NULL);
|
|
||||||
|
|
||||||
static void check_explicit_phandles(struct check *c, struct node *root,
|
|
||||||
struct node *node, struct property *prop)
|
|
||||||
{
|
{
|
||||||
|
struct node *root = dti->dt;
|
||||||
|
struct property *prop;
|
||||||
struct marker *m;
|
struct marker *m;
|
||||||
struct node *other;
|
|
||||||
cell_t phandle;
|
cell_t phandle;
|
||||||
|
|
||||||
if (!streq(prop->name, "phandle")
|
prop = get_property(node, propname);
|
||||||
&& !streq(prop->name, "linux,phandle"))
|
if (!prop)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
if (prop->val.len != sizeof(cell_t)) {
|
if (prop->val.len != sizeof(cell_t)) {
|
||||||
FAIL(c, "%s has bad length (%d) %s property",
|
FAIL(c, "%s has bad length (%d) %s property",
|
||||||
node->fullpath, prop->val.len, prop->name);
|
node->fullpath, prop->val.len, prop->name);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m = prop->val.markers;
|
m = prop->val.markers;
|
||||||
|
@ -411,14 +381,13 @@ static void check_explicit_phandles(struct check *c, struct node *root,
|
||||||
* by construction. */ {
|
* by construction. */ {
|
||||||
FAIL(c, "%s in %s is a reference to another node",
|
FAIL(c, "%s in %s is a reference to another node",
|
||||||
prop->name, node->fullpath);
|
prop->name, node->fullpath);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
/* But setting this node's phandle equal to its own
|
/* But setting this node's phandle equal to its own
|
||||||
* phandle is allowed - that means allocate a unique
|
* phandle is allowed - that means allocate a unique
|
||||||
* phandle for this node, even if it's not otherwise
|
* phandle for this node, even if it's not otherwise
|
||||||
* referenced. The value will be filled in later, so
|
* referenced. The value will be filled in later, so
|
||||||
* no further checking for now. */
|
* we treat it as having no phandle data for now. */
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
phandle = propval_cell(prop);
|
phandle = propval_cell(prop);
|
||||||
|
@ -426,12 +395,36 @@ static void check_explicit_phandles(struct check *c, struct node *root,
|
||||||
if ((phandle == 0) || (phandle == -1)) {
|
if ((phandle == 0) || (phandle == -1)) {
|
||||||
FAIL(c, "%s has bad value (0x%x) in %s property",
|
FAIL(c, "%s has bad value (0x%x) in %s property",
|
||||||
node->fullpath, phandle, prop->name);
|
node->fullpath, phandle, prop->name);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->phandle && (node->phandle != phandle))
|
return phandle;
|
||||||
FAIL(c, "%s has %s property which replaces existing phandle information",
|
}
|
||||||
node->fullpath, prop->name);
|
|
||||||
|
static void check_explicit_phandles(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *root = dti->dt;
|
||||||
|
struct node *other;
|
||||||
|
cell_t phandle, linux_phandle;
|
||||||
|
|
||||||
|
/* Nothing should have assigned phandles yet */
|
||||||
|
assert(!node->phandle);
|
||||||
|
|
||||||
|
phandle = check_phandle_prop(c, dti, node, "phandle");
|
||||||
|
|
||||||
|
linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle");
|
||||||
|
|
||||||
|
if (!phandle && !linux_phandle)
|
||||||
|
/* No valid phandles; nothing further to check */
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (linux_phandle && phandle && (phandle != linux_phandle))
|
||||||
|
FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'"
|
||||||
|
" properties", node->fullpath);
|
||||||
|
|
||||||
|
if (linux_phandle && !phandle)
|
||||||
|
phandle = linux_phandle;
|
||||||
|
|
||||||
other = get_node_by_phandle(root, phandle);
|
other = get_node_by_phandle(root, phandle);
|
||||||
if (other && (other != node)) {
|
if (other && (other != node)) {
|
||||||
|
@ -442,9 +435,9 @@ static void check_explicit_phandles(struct check *c, struct node *root,
|
||||||
|
|
||||||
node->phandle = phandle;
|
node->phandle = phandle;
|
||||||
}
|
}
|
||||||
PROP_ERROR(explicit_phandles, NULL);
|
ERROR(explicit_phandles, check_explicit_phandles, NULL);
|
||||||
|
|
||||||
static void check_name_properties(struct check *c, struct node *root,
|
static void check_name_properties(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property **pp, *prop = NULL;
|
struct property **pp, *prop = NULL;
|
||||||
|
@ -472,60 +465,73 @@ static void check_name_properties(struct check *c, struct node *root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ERROR_IF_NOT_STRING(name_is_string, "name");
|
ERROR_IF_NOT_STRING(name_is_string, "name");
|
||||||
NODE_ERROR(name_properties, NULL, &name_is_string);
|
ERROR(name_properties, check_name_properties, NULL, &name_is_string);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference fixup functions
|
* Reference fixup functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void fixup_phandle_references(struct check *c, struct node *dt,
|
static void fixup_phandle_references(struct check *c, struct dt_info *dti,
|
||||||
struct node *node, struct property *prop)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct marker *m = prop->val.markers;
|
struct node *dt = dti->dt;
|
||||||
struct node *refnode;
|
struct property *prop;
|
||||||
cell_t phandle;
|
|
||||||
|
|
||||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
for_each_property(node, prop) {
|
||||||
assert(m->offset + sizeof(cell_t) <= prop->val.len);
|
struct marker *m = prop->val.markers;
|
||||||
|
struct node *refnode;
|
||||||
|
cell_t phandle;
|
||||||
|
|
||||||
refnode = get_node_by_ref(dt, m->ref);
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
if (! refnode) {
|
assert(m->offset + sizeof(cell_t) <= prop->val.len);
|
||||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
|
||||||
m->ref);
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
continue;
|
if (! refnode) {
|
||||||
|
if (!(dti->dtsflags & DTSF_PLUGIN))
|
||||||
|
FAIL(c, "Reference to non-existent node or "
|
||||||
|
"label \"%s\"\n", m->ref);
|
||||||
|
else /* mark the entry as unresolved */
|
||||||
|
*((cell_t *)(prop->val.val + m->offset)) =
|
||||||
|
cpu_to_fdt32(0xffffffff);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
phandle = get_node_phandle(dt, refnode);
|
||||||
|
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
phandle = get_node_phandle(dt, refnode);
|
|
||||||
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
|
ERROR(phandle_references, fixup_phandle_references, NULL,
|
||||||
&duplicate_node_names, &explicit_phandles);
|
&duplicate_node_names, &explicit_phandles);
|
||||||
|
|
||||||
static void fixup_path_references(struct check *c, struct node *dt,
|
static void fixup_path_references(struct check *c, struct dt_info *dti,
|
||||||
struct node *node, struct property *prop)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct marker *m = prop->val.markers;
|
struct node *dt = dti->dt;
|
||||||
struct node *refnode;
|
struct property *prop;
|
||||||
char *path;
|
|
||||||
|
|
||||||
for_each_marker_of_type(m, REF_PATH) {
|
for_each_property(node, prop) {
|
||||||
assert(m->offset <= prop->val.len);
|
struct marker *m = prop->val.markers;
|
||||||
|
struct node *refnode;
|
||||||
|
char *path;
|
||||||
|
|
||||||
refnode = get_node_by_ref(dt, m->ref);
|
for_each_marker_of_type(m, REF_PATH) {
|
||||||
if (!refnode) {
|
assert(m->offset <= prop->val.len);
|
||||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
|
||||||
m->ref);
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
continue;
|
if (!refnode) {
|
||||||
|
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||||||
|
m->ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = refnode->fullpath;
|
||||||
|
prop->val = data_insert_at_marker(prop->val, m, path,
|
||||||
|
strlen(path) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
path = refnode->fullpath;
|
|
||||||
prop->val = data_insert_at_marker(prop->val, m, path,
|
|
||||||
strlen(path) + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
|
ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
|
||||||
&duplicate_node_names);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Semantic checks
|
* Semantic checks
|
||||||
|
@ -538,7 +544,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
|
||||||
WARNING_IF_NOT_STRING(model_is_string, "model");
|
WARNING_IF_NOT_STRING(model_is_string, "model");
|
||||||
WARNING_IF_NOT_STRING(status_is_string, "status");
|
WARNING_IF_NOT_STRING(status_is_string, "status");
|
||||||
|
|
||||||
static void fixup_addr_size_cells(struct check *c, struct node *dt,
|
static void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
@ -554,7 +560,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt,
|
||||||
if (prop)
|
if (prop)
|
||||||
node->size_cells = propval_cell(prop);
|
node->size_cells = propval_cell(prop);
|
||||||
}
|
}
|
||||||
WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
|
WARNING(addr_size_cells, fixup_addr_size_cells, NULL,
|
||||||
&address_cells_is_cell, &size_cells_is_cell);
|
&address_cells_is_cell, &size_cells_is_cell);
|
||||||
|
|
||||||
#define node_addr_cells(n) \
|
#define node_addr_cells(n) \
|
||||||
|
@ -562,7 +568,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
|
||||||
#define node_size_cells(n) \
|
#define node_size_cells(n) \
|
||||||
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
|
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
|
||||||
|
|
||||||
static void check_reg_format(struct check *c, struct node *dt,
|
static void check_reg_format(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
@ -589,9 +595,9 @@ static void check_reg_format(struct check *c, struct node *dt,
|
||||||
"(#address-cells == %d, #size-cells == %d)",
|
"(#address-cells == %d, #size-cells == %d)",
|
||||||
node->fullpath, prop->val.len, addr_cells, size_cells);
|
node->fullpath, prop->val.len, addr_cells, size_cells);
|
||||||
}
|
}
|
||||||
NODE_WARNING(reg_format, NULL, &addr_size_cells);
|
WARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
|
||||||
|
|
||||||
static void check_ranges_format(struct check *c, struct node *dt,
|
static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
@ -630,12 +636,12 @@ static void check_ranges_format(struct check *c, struct node *dt,
|
||||||
p_addr_cells, c_addr_cells, c_size_cells);
|
p_addr_cells, c_addr_cells, c_size_cells);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NODE_WARNING(ranges_format, NULL, &addr_size_cells);
|
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Style checks
|
* Style checks
|
||||||
*/
|
*/
|
||||||
static void check_avoid_default_addr_size(struct check *c, struct node *dt,
|
static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *reg, *ranges;
|
struct property *reg, *ranges;
|
||||||
|
@ -657,14 +663,21 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt,
|
||||||
FAIL(c, "Relying on default #size-cells value for %s",
|
FAIL(c, "Relying on default #size-cells value for %s",
|
||||||
node->fullpath);
|
node->fullpath);
|
||||||
}
|
}
|
||||||
NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
|
WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
|
||||||
|
&addr_size_cells);
|
||||||
|
|
||||||
static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||||
struct node *dt)
|
struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
{
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
struct node *chosen;
|
struct node *chosen;
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
|
||||||
|
if (node != dt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
chosen = get_node_by_path(dt, "/chosen");
|
chosen = get_node_by_path(dt, "/chosen");
|
||||||
if (!chosen)
|
if (!chosen)
|
||||||
return;
|
return;
|
||||||
|
@ -674,7 +687,8 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||||
FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
|
FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
|
||||||
"property");
|
"property");
|
||||||
}
|
}
|
||||||
TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
|
WARNING(obsolete_chosen_interrupt_controller,
|
||||||
|
check_obsolete_chosen_interrupt_controller, NULL);
|
||||||
|
|
||||||
static struct check *check_table[] = {
|
static struct check *check_table[] = {
|
||||||
&duplicate_node_names, &duplicate_property_names,
|
&duplicate_node_names, &duplicate_property_names,
|
||||||
|
@ -760,9 +774,8 @@ void parse_checks_option(bool warn, bool error, const char *arg)
|
||||||
die("Unrecognized check name \"%s\"\n", name);
|
die("Unrecognized check name \"%s\"\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_checks(bool force, struct boot_info *bi)
|
void process_checks(bool force, struct dt_info *dti)
|
||||||
{
|
{
|
||||||
struct node *dt = bi->dt;
|
|
||||||
int i;
|
int i;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
|
@ -770,7 +783,7 @@ void process_checks(bool force, struct boot_info *bi)
|
||||||
struct check *c = check_table[i];
|
struct check *c = check_table[i];
|
||||||
|
|
||||||
if (c->warn || c->error)
|
if (c->warn || c->error)
|
||||||
error = error || run_check(c, dt);
|
error = error || run_check(c, dti);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
|
@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
|
||||||
return DT_V1;
|
return DT_V1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<*>"/plugin/" {
|
||||||
|
DPRINT("Keyword: /plugin/\n");
|
||||||
|
return DT_PLUGIN;
|
||||||
|
}
|
||||||
|
|
||||||
<*>"/memreserve/" {
|
<*>"/memreserve/" {
|
||||||
DPRINT("Keyword: /memreserve/\n");
|
DPRINT("Keyword: /memreserve/\n");
|
||||||
BEGIN_DEFAULT();
|
BEGIN_DEFAULT();
|
||||||
|
@ -184,16 +189,16 @@ static void lexical_error(const char *fmt, ...);
|
||||||
if (d.len == 1) {
|
if (d.len == 1) {
|
||||||
lexical_error("Empty character literal");
|
lexical_error("Empty character literal");
|
||||||
yylval.integer = 0;
|
yylval.integer = 0;
|
||||||
return DT_CHAR_LITERAL;
|
} else {
|
||||||
|
yylval.integer = (unsigned char)d.val[0];
|
||||||
|
|
||||||
|
if (d.len > 2)
|
||||||
|
lexical_error("Character literal has %d"
|
||||||
|
" characters instead of 1",
|
||||||
|
d.len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
yylval.integer = (unsigned char)d.val[0];
|
data_free(d);
|
||||||
|
|
||||||
if (d.len > 2)
|
|
||||||
lexical_error("Character literal has %d"
|
|
||||||
" characters instead of 1",
|
|
||||||
d.len - 1);
|
|
||||||
|
|
||||||
return DT_CHAR_LITERAL;
|
return DT_CHAR_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
||||||
/* A Bison parser, made by GNU Bison 3.0.2. */
|
/* A Bison parser, made by GNU Bison 3.0.4. */
|
||||||
|
|
||||||
/* Bison interface for Yacc-like parsers in C
|
/* Bison interface for Yacc-like parsers in C
|
||||||
|
|
||||||
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
|
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -46,35 +46,36 @@ extern int yydebug;
|
||||||
enum yytokentype
|
enum yytokentype
|
||||||
{
|
{
|
||||||
DT_V1 = 258,
|
DT_V1 = 258,
|
||||||
DT_MEMRESERVE = 259,
|
DT_PLUGIN = 259,
|
||||||
DT_LSHIFT = 260,
|
DT_MEMRESERVE = 260,
|
||||||
DT_RSHIFT = 261,
|
DT_LSHIFT = 261,
|
||||||
DT_LE = 262,
|
DT_RSHIFT = 262,
|
||||||
DT_GE = 263,
|
DT_LE = 263,
|
||||||
DT_EQ = 264,
|
DT_GE = 264,
|
||||||
DT_NE = 265,
|
DT_EQ = 265,
|
||||||
DT_AND = 266,
|
DT_NE = 266,
|
||||||
DT_OR = 267,
|
DT_AND = 267,
|
||||||
DT_BITS = 268,
|
DT_OR = 268,
|
||||||
DT_DEL_PROP = 269,
|
DT_BITS = 269,
|
||||||
DT_DEL_NODE = 270,
|
DT_DEL_PROP = 270,
|
||||||
DT_PROPNODENAME = 271,
|
DT_DEL_NODE = 271,
|
||||||
DT_LITERAL = 272,
|
DT_PROPNODENAME = 272,
|
||||||
DT_CHAR_LITERAL = 273,
|
DT_LITERAL = 273,
|
||||||
DT_BYTE = 274,
|
DT_CHAR_LITERAL = 274,
|
||||||
DT_STRING = 275,
|
DT_BYTE = 275,
|
||||||
DT_LABEL = 276,
|
DT_STRING = 276,
|
||||||
DT_REF = 277,
|
DT_LABEL = 277,
|
||||||
DT_INCBIN = 278
|
DT_REF = 278,
|
||||||
|
DT_INCBIN = 279
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Value type. */
|
/* Value type. */
|
||||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||||
typedef union YYSTYPE YYSTYPE;
|
|
||||||
union YYSTYPE
|
union YYSTYPE
|
||||||
{
|
{
|
||||||
#line 38 "dtc-parser.y" /* yacc.c:1909 */
|
#line 39 "dtc-parser.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
char *propnodename;
|
char *propnodename;
|
||||||
char *labelref;
|
char *labelref;
|
||||||
|
@ -92,9 +93,12 @@ union YYSTYPE
|
||||||
struct node *nodelist;
|
struct node *nodelist;
|
||||||
struct reserve_info *re;
|
struct reserve_info *re;
|
||||||
uint64_t integer;
|
uint64_t integer;
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */
|
#line 99 "dtc-parser.tab.h" /* yacc.c:1909 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef union YYSTYPE YYSTYPE;
|
||||||
# define YYSTYPE_IS_TRIVIAL 1
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
# define YYSTYPE_IS_DECLARED 1
|
# define YYSTYPE_IS_DECLARED 1
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
%{
|
%{
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "dtc.h"
|
#include "dtc.h"
|
||||||
#include "srcpos.h"
|
#include "srcpos.h"
|
||||||
|
@ -31,7 +32,7 @@ extern void yyerror(char const *s);
|
||||||
treesource_error = true; \
|
treesource_error = true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
extern struct boot_info *the_boot_info;
|
extern struct dt_info *parser_output;
|
||||||
extern bool treesource_error;
|
extern bool treesource_error;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -52,9 +53,11 @@ extern bool treesource_error;
|
||||||
struct node *nodelist;
|
struct node *nodelist;
|
||||||
struct reserve_info *re;
|
struct reserve_info *re;
|
||||||
uint64_t integer;
|
uint64_t integer;
|
||||||
|
unsigned int flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token DT_V1
|
%token DT_V1
|
||||||
|
%token DT_PLUGIN
|
||||||
%token DT_MEMRESERVE
|
%token DT_MEMRESERVE
|
||||||
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
|
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
|
||||||
%token DT_BITS
|
%token DT_BITS
|
||||||
|
@ -71,6 +74,8 @@ extern bool treesource_error;
|
||||||
|
|
||||||
%type <data> propdata
|
%type <data> propdata
|
||||||
%type <data> propdataprefix
|
%type <data> propdataprefix
|
||||||
|
%type <flags> header
|
||||||
|
%type <flags> headers
|
||||||
%type <re> memreserve
|
%type <re> memreserve
|
||||||
%type <re> memreserves
|
%type <re> memreserves
|
||||||
%type <array> arrayprefix
|
%type <array> arrayprefix
|
||||||
|
@ -101,10 +106,31 @@ extern bool treesource_error;
|
||||||
%%
|
%%
|
||||||
|
|
||||||
sourcefile:
|
sourcefile:
|
||||||
DT_V1 ';' memreserves devicetree
|
headers memreserves devicetree
|
||||||
{
|
{
|
||||||
the_boot_info = build_boot_info($3, $4,
|
parser_output = build_dt_info($1, $2, $3,
|
||||||
guess_boot_cpuid($4));
|
guess_boot_cpuid($3));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
header:
|
||||||
|
DT_V1 ';'
|
||||||
|
{
|
||||||
|
$$ = DTSF_V1;
|
||||||
|
}
|
||||||
|
| DT_V1 ';' DT_PLUGIN ';'
|
||||||
|
{
|
||||||
|
$$ = DTSF_V1 | DTSF_PLUGIN;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
headers:
|
||||||
|
header
|
||||||
|
| header headers
|
||||||
|
{
|
||||||
|
if ($2 != $1)
|
||||||
|
ERROR(&@2, "Header flags don't match earlier ones");
|
||||||
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,16 @@ int quiet; /* Level of quietness */
|
||||||
int reservenum; /* Number of memory reservation slots */
|
int reservenum; /* Number of memory reservation slots */
|
||||||
int minsize; /* Minimum blob size */
|
int minsize; /* Minimum blob size */
|
||||||
int padsize; /* Additional padding to blob */
|
int padsize; /* Additional padding to blob */
|
||||||
|
int alignsize; /* Additional padding to blob accroding to the alignsize */
|
||||||
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
|
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
|
||||||
|
int generate_symbols; /* enable symbols & fixup support */
|
||||||
|
int generate_fixups; /* suppress generation of fixups on symbol support */
|
||||||
|
int auto_label_aliases; /* auto generate labels -> aliases */
|
||||||
|
|
||||||
|
static int is_power_of_2(int x)
|
||||||
|
{
|
||||||
|
return (x > 0) && ((x & (x - 1)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void fill_fullpaths(struct node *tree, const char *prefix)
|
static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||||
{
|
{
|
||||||
|
@ -53,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||||
#define FDT_VERSION(version) _FDT_VERSION(version)
|
#define FDT_VERSION(version) _FDT_VERSION(version)
|
||||||
#define _FDT_VERSION(version) #version
|
#define _FDT_VERSION(version) #version
|
||||||
static const char usage_synopsis[] = "dtc [options] <input file>";
|
static const char usage_synopsis[] = "dtc [options] <input file>";
|
||||||
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
|
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
|
||||||
static struct option const usage_long_opts[] = {
|
static struct option const usage_long_opts[] = {
|
||||||
{"quiet", no_argument, NULL, 'q'},
|
{"quiet", no_argument, NULL, 'q'},
|
||||||
{"in-format", a_argument, NULL, 'I'},
|
{"in-format", a_argument, NULL, 'I'},
|
||||||
|
@ -64,6 +73,7 @@ static struct option const usage_long_opts[] = {
|
||||||
{"reserve", a_argument, NULL, 'R'},
|
{"reserve", a_argument, NULL, 'R'},
|
||||||
{"space", a_argument, NULL, 'S'},
|
{"space", a_argument, NULL, 'S'},
|
||||||
{"pad", a_argument, NULL, 'p'},
|
{"pad", a_argument, NULL, 'p'},
|
||||||
|
{"align", a_argument, NULL, 'a'},
|
||||||
{"boot-cpu", a_argument, NULL, 'b'},
|
{"boot-cpu", a_argument, NULL, 'b'},
|
||||||
{"force", no_argument, NULL, 'f'},
|
{"force", no_argument, NULL, 'f'},
|
||||||
{"include", a_argument, NULL, 'i'},
|
{"include", a_argument, NULL, 'i'},
|
||||||
|
@ -71,6 +81,8 @@ static struct option const usage_long_opts[] = {
|
||||||
{"phandle", a_argument, NULL, 'H'},
|
{"phandle", a_argument, NULL, 'H'},
|
||||||
{"warning", a_argument, NULL, 'W'},
|
{"warning", a_argument, NULL, 'W'},
|
||||||
{"error", a_argument, NULL, 'E'},
|
{"error", a_argument, NULL, 'E'},
|
||||||
|
{"symbols", no_argument, NULL, '@'},
|
||||||
|
{"auto-alias", no_argument, NULL, 'A'},
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{"version", no_argument, NULL, 'v'},
|
{"version", no_argument, NULL, 'v'},
|
||||||
{NULL, no_argument, NULL, 0x0},
|
{NULL, no_argument, NULL, 0x0},
|
||||||
|
@ -91,6 +103,7 @@ static const char * const usage_opts_help[] = {
|
||||||
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
|
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
|
||||||
"\n\tMake the blob at least <bytes> long (extra space)",
|
"\n\tMake the blob at least <bytes> long (extra space)",
|
||||||
"\n\tAdd padding to the blob of <bytes> long (extra space)",
|
"\n\tAdd padding to the blob of <bytes> long (extra space)",
|
||||||
|
"\n\tMake the blob align to the <bytes> (extra space)",
|
||||||
"\n\tSet the physical boot cpu",
|
"\n\tSet the physical boot cpu",
|
||||||
"\n\tTry to produce output even if the input tree has errors",
|
"\n\tTry to produce output even if the input tree has errors",
|
||||||
"\n\tAdd a path to search for include files",
|
"\n\tAdd a path to search for include files",
|
||||||
|
@ -101,6 +114,8 @@ static const char * const usage_opts_help[] = {
|
||||||
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
|
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
|
||||||
"\n\tEnable/disable warnings (prefix with \"no-\")",
|
"\n\tEnable/disable warnings (prefix with \"no-\")",
|
||||||
"\n\tEnable/disable errors (prefix with \"no-\")",
|
"\n\tEnable/disable errors (prefix with \"no-\")",
|
||||||
|
"\n\tEnable generation of symbols",
|
||||||
|
"\n\tEnable auto-alias of labels",
|
||||||
"\n\tPrint this help and exit",
|
"\n\tPrint this help and exit",
|
||||||
"\n\tPrint version and exit",
|
"\n\tPrint version and exit",
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -153,7 +168,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct boot_info *bi;
|
struct dt_info *dti;
|
||||||
const char *inform = NULL;
|
const char *inform = NULL;
|
||||||
const char *outform = NULL;
|
const char *outform = NULL;
|
||||||
const char *outname = "-";
|
const char *outname = "-";
|
||||||
|
@ -169,6 +184,7 @@ int main(int argc, char *argv[])
|
||||||
reservenum = 0;
|
reservenum = 0;
|
||||||
minsize = 0;
|
minsize = 0;
|
||||||
padsize = 0;
|
padsize = 0;
|
||||||
|
alignsize = 0;
|
||||||
|
|
||||||
while ((opt = util_getopt_long()) != EOF) {
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
@ -196,6 +212,12 @@ int main(int argc, char *argv[])
|
||||||
case 'p':
|
case 'p':
|
||||||
padsize = strtol(optarg, NULL, 0);
|
padsize = strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
alignsize = strtol(optarg, NULL, 0);
|
||||||
|
if (!is_power_of_2(alignsize))
|
||||||
|
die("Invalid argument \"%d\" to -a option\n",
|
||||||
|
optarg);
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
force = true;
|
force = true;
|
||||||
break;
|
break;
|
||||||
|
@ -234,6 +256,13 @@ int main(int argc, char *argv[])
|
||||||
parse_checks_option(false, true, optarg);
|
parse_checks_option(false, true, optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '@':
|
||||||
|
generate_symbols = 1;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
auto_label_aliases = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(NULL);
|
usage(NULL);
|
||||||
default:
|
default:
|
||||||
|
@ -272,11 +301,11 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (streq(inform, "dts"))
|
if (streq(inform, "dts"))
|
||||||
bi = dt_from_source(arg);
|
dti = dt_from_source(arg);
|
||||||
else if (streq(inform, "fs"))
|
else if (streq(inform, "fs"))
|
||||||
bi = dt_from_fs(arg);
|
dti = dt_from_fs(arg);
|
||||||
else if(streq(inform, "dtb"))
|
else if(streq(inform, "dtb"))
|
||||||
bi = dt_from_blob(arg);
|
dti = dt_from_blob(arg);
|
||||||
else
|
else
|
||||||
die("Unknown input format \"%s\"\n", inform);
|
die("Unknown input format \"%s\"\n", inform);
|
||||||
|
|
||||||
|
@ -286,13 +315,29 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdline_boot_cpuid != -1)
|
if (cmdline_boot_cpuid != -1)
|
||||||
bi->boot_cpuid_phys = cmdline_boot_cpuid;
|
dti->boot_cpuid_phys = cmdline_boot_cpuid;
|
||||||
|
|
||||||
fill_fullpaths(bi->dt, "");
|
fill_fullpaths(dti->dt, "");
|
||||||
process_checks(force, bi);
|
process_checks(force, dti);
|
||||||
|
|
||||||
|
/* on a plugin, generate by default */
|
||||||
|
if (dti->dtsflags & DTSF_PLUGIN) {
|
||||||
|
generate_fixups = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto_label_aliases)
|
||||||
|
generate_label_tree(dti, "aliases", false);
|
||||||
|
|
||||||
|
if (generate_symbols)
|
||||||
|
generate_label_tree(dti, "__symbols__", true);
|
||||||
|
|
||||||
|
if (generate_fixups) {
|
||||||
|
generate_fixups_tree(dti, "__fixups__");
|
||||||
|
generate_local_fixups_tree(dti, "__local_fixups__");
|
||||||
|
}
|
||||||
|
|
||||||
if (sort)
|
if (sort)
|
||||||
sort_tree(bi);
|
sort_tree(dti);
|
||||||
|
|
||||||
if (streq(outname, "-")) {
|
if (streq(outname, "-")) {
|
||||||
outf = stdout;
|
outf = stdout;
|
||||||
|
@ -304,11 +349,11 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(outform, "dts")) {
|
if (streq(outform, "dts")) {
|
||||||
dt_to_source(outf, bi);
|
dt_to_source(outf, dti);
|
||||||
} else if (streq(outform, "dtb")) {
|
} else if (streq(outform, "dtb")) {
|
||||||
dt_to_blob(outf, bi, outversion);
|
dt_to_blob(outf, dti, outversion);
|
||||||
} else if (streq(outform, "asm")) {
|
} else if (streq(outform, "asm")) {
|
||||||
dt_to_asm(outf, bi, outversion);
|
dt_to_asm(outf, dti, outversion);
|
||||||
} else if (streq(outform, "null")) {
|
} else if (streq(outform, "null")) {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -53,7 +53,11 @@ extern int quiet; /* Level of quietness */
|
||||||
extern int reservenum; /* Number of memory reservation slots */
|
extern int reservenum; /* Number of memory reservation slots */
|
||||||
extern int minsize; /* Minimum blob size */
|
extern int minsize; /* Minimum blob size */
|
||||||
extern int padsize; /* Additional padding to blob */
|
extern int padsize; /* Additional padding to blob */
|
||||||
|
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
|
||||||
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||||
|
extern int generate_symbols; /* generate symbols for nodes with labels */
|
||||||
|
extern int generate_fixups; /* generate fixups */
|
||||||
|
extern int auto_label_aliases; /* auto generate labels -> aliases */
|
||||||
|
|
||||||
#define PHANDLE_LEGACY 0x1
|
#define PHANDLE_LEGACY 0x1
|
||||||
#define PHANDLE_EPAPR 0x2
|
#define PHANDLE_EPAPR 0x2
|
||||||
|
@ -201,6 +205,8 @@ void delete_property(struct property *prop);
|
||||||
void add_child(struct node *parent, struct node *child);
|
void add_child(struct node *parent, struct node *child);
|
||||||
void delete_node_by_name(struct node *parent, char *name);
|
void delete_node_by_name(struct node *parent, char *name);
|
||||||
void delete_node(struct node *node);
|
void delete_node(struct node *node);
|
||||||
|
void append_to_property(struct node *node,
|
||||||
|
char *name, const void *data, int len);
|
||||||
|
|
||||||
const char *get_unitname(struct node *node);
|
const char *get_unitname(struct node *node);
|
||||||
struct property *get_property(struct node *node, const char *propname);
|
struct property *get_property(struct node *node, const char *propname);
|
||||||
|
@ -235,35 +241,44 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
|
||||||
struct reserve_info *new);
|
struct reserve_info *new);
|
||||||
|
|
||||||
|
|
||||||
struct boot_info {
|
struct dt_info {
|
||||||
|
unsigned int dtsflags;
|
||||||
struct reserve_info *reservelist;
|
struct reserve_info *reservelist;
|
||||||
struct node *dt; /* the device tree */
|
|
||||||
uint32_t boot_cpuid_phys;
|
uint32_t boot_cpuid_phys;
|
||||||
|
struct node *dt; /* the device tree */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct boot_info *build_boot_info(struct reserve_info *reservelist,
|
/* DTS version flags definitions */
|
||||||
struct node *tree, uint32_t boot_cpuid_phys);
|
#define DTSF_V1 0x0001 /* /dts-v1/ */
|
||||||
void sort_tree(struct boot_info *bi);
|
#define DTSF_PLUGIN 0x0002 /* /plugin/ */
|
||||||
|
|
||||||
|
struct dt_info *build_dt_info(unsigned int dtsflags,
|
||||||
|
struct reserve_info *reservelist,
|
||||||
|
struct node *tree, uint32_t boot_cpuid_phys);
|
||||||
|
void sort_tree(struct dt_info *dti);
|
||||||
|
void generate_label_tree(struct dt_info *dti, char *name, bool allocph);
|
||||||
|
void generate_fixups_tree(struct dt_info *dti, char *name);
|
||||||
|
void generate_local_fixups_tree(struct dt_info *dti, char *name);
|
||||||
|
|
||||||
/* Checks */
|
/* Checks */
|
||||||
|
|
||||||
void parse_checks_option(bool warn, bool error, const char *arg);
|
void parse_checks_option(bool warn, bool error, const char *arg);
|
||||||
void process_checks(bool force, struct boot_info *bi);
|
void process_checks(bool force, struct dt_info *dti);
|
||||||
|
|
||||||
/* Flattened trees */
|
/* Flattened trees */
|
||||||
|
|
||||||
void dt_to_blob(FILE *f, struct boot_info *bi, int version);
|
void dt_to_blob(FILE *f, struct dt_info *dti, int version);
|
||||||
void dt_to_asm(FILE *f, struct boot_info *bi, int version);
|
void dt_to_asm(FILE *f, struct dt_info *dti, int version);
|
||||||
|
|
||||||
struct boot_info *dt_from_blob(const char *fname);
|
struct dt_info *dt_from_blob(const char *fname);
|
||||||
|
|
||||||
/* Tree source */
|
/* Tree source */
|
||||||
|
|
||||||
void dt_to_source(FILE *f, struct boot_info *bi);
|
void dt_to_source(FILE *f, struct dt_info *dti);
|
||||||
struct boot_info *dt_from_source(const char *f);
|
struct dt_info *dt_from_source(const char *f);
|
||||||
|
|
||||||
/* FS trees */
|
/* FS trees */
|
||||||
|
|
||||||
struct boot_info *dt_from_fs(const char *dirname);
|
struct dt_info *dt_from_fs(const char *dirname);
|
||||||
|
|
||||||
#endif /* _DTC_H */
|
#endif /* _DTC_H */
|
||||||
|
|
|
@ -366,7 +366,7 @@ static void make_fdt_header(struct fdt_header *fdt,
|
||||||
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
|
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dt_to_blob(FILE *f, struct boot_info *bi, int version)
|
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
|
||||||
{
|
{
|
||||||
struct version_info *vi = NULL;
|
struct version_info *vi = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
@ -384,29 +384,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
|
||||||
if (!vi)
|
if (!vi)
|
||||||
die("Unknown device tree blob version %d\n", version);
|
die("Unknown device tree blob version %d\n", version);
|
||||||
|
|
||||||
flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
|
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
|
||||||
bin_emit_cell(&dtbuf, FDT_END);
|
bin_emit_cell(&dtbuf, FDT_END);
|
||||||
|
|
||||||
reservebuf = flatten_reserve_list(bi->reservelist, vi);
|
reservebuf = flatten_reserve_list(dti->reservelist, vi);
|
||||||
|
|
||||||
/* Make header */
|
/* Make header */
|
||||||
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
|
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
|
||||||
bi->boot_cpuid_phys);
|
dti->boot_cpuid_phys);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user asked for more space than is used, adjust the totalsize.
|
* If the user asked for more space than is used, adjust the totalsize.
|
||||||
*/
|
*/
|
||||||
if (minsize > 0) {
|
if (minsize > 0) {
|
||||||
padlen = minsize - fdt32_to_cpu(fdt.totalsize);
|
padlen = minsize - fdt32_to_cpu(fdt.totalsize);
|
||||||
if ((padlen < 0) && (quiet < 1))
|
if (padlen < 0) {
|
||||||
fprintf(stderr,
|
padlen = 0;
|
||||||
"Warning: blob size %d >= minimum size %d\n",
|
if (quiet < 1)
|
||||||
fdt32_to_cpu(fdt.totalsize), minsize);
|
fprintf(stderr,
|
||||||
|
"Warning: blob size %d >= minimum size %d\n",
|
||||||
|
fdt32_to_cpu(fdt.totalsize), minsize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (padsize > 0)
|
if (padsize > 0)
|
||||||
padlen = padsize;
|
padlen = padsize;
|
||||||
|
|
||||||
|
if (alignsize > 0)
|
||||||
|
padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
|
||||||
|
- fdt32_to_cpu(fdt.totalsize);
|
||||||
|
|
||||||
if (padlen > 0) {
|
if (padlen > 0) {
|
||||||
int tsize = fdt32_to_cpu(fdt.totalsize);
|
int tsize = fdt32_to_cpu(fdt.totalsize);
|
||||||
tsize += padlen;
|
tsize += padlen;
|
||||||
|
@ -460,7 +467,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
|
||||||
{
|
{
|
||||||
struct version_info *vi = NULL;
|
struct version_info *vi = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
@ -500,7 +507,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||||
|
|
||||||
if (vi->flags & FTF_BOOTCPUID) {
|
if (vi->flags & FTF_BOOTCPUID) {
|
||||||
fprintf(f, "\t/* boot_cpuid_phys */\n");
|
fprintf(f, "\t/* boot_cpuid_phys */\n");
|
||||||
asm_emit_cell(f, bi->boot_cpuid_phys);
|
asm_emit_cell(f, dti->boot_cpuid_phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vi->flags & FTF_STRTABSIZE) {
|
if (vi->flags & FTF_STRTABSIZE) {
|
||||||
|
@ -530,7 +537,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||||
* Use .long on high and low halfs of u64s to avoid .quad
|
* Use .long on high and low halfs of u64s to avoid .quad
|
||||||
* as it appears .quad isn't available in some assemblers.
|
* as it appears .quad isn't available in some assemblers.
|
||||||
*/
|
*/
|
||||||
for (re = bi->reservelist; re; re = re->next) {
|
for (re = dti->reservelist; re; re = re->next) {
|
||||||
struct label *l;
|
struct label *l;
|
||||||
|
|
||||||
for_each_label(re->labels, l) {
|
for_each_label(re->labels, l) {
|
||||||
|
@ -550,7 +557,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||||
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
|
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
|
||||||
|
|
||||||
emit_label(f, symprefix, "struct_start");
|
emit_label(f, symprefix, "struct_start");
|
||||||
flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
|
flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
|
||||||
|
|
||||||
fprintf(f, "\t/* FDT_END */\n");
|
fprintf(f, "\t/* FDT_END */\n");
|
||||||
asm_emit_cell(f, FDT_END);
|
asm_emit_cell(f, FDT_END);
|
||||||
|
@ -572,6 +579,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||||
if (padsize > 0) {
|
if (padsize > 0) {
|
||||||
fprintf(f, "\t.space\t%d, 0\n", padsize);
|
fprintf(f, "\t.space\t%d, 0\n", padsize);
|
||||||
}
|
}
|
||||||
|
if (alignsize > 0)
|
||||||
|
asm_emit_align(f, alignsize);
|
||||||
emit_label(f, symprefix, "blob_abs_end");
|
emit_label(f, symprefix, "blob_abs_end");
|
||||||
|
|
||||||
data_free(strbuf);
|
data_free(strbuf);
|
||||||
|
@ -797,11 +806,15 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
|
||||||
}
|
}
|
||||||
} while (val != FDT_END_NODE);
|
} while (val != FDT_END_NODE);
|
||||||
|
|
||||||
|
if (node->name != flatname) {
|
||||||
|
free(flatname);
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct boot_info *dt_from_blob(const char *fname)
|
struct dt_info *dt_from_blob(const char *fname)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
|
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
|
||||||
|
@ -929,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname)
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
return build_boot_info(reservelist, tree, boot_cpuid_phys);
|
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname)
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct boot_info *dt_from_fs(const char *dirname)
|
struct dt_info *dt_from_fs(const char *dirname)
|
||||||
{
|
{
|
||||||
struct node *tree;
|
struct node *tree;
|
||||||
|
|
||||||
tree = read_fstree(dirname);
|
tree = read_fstree(dirname);
|
||||||
tree = name_node(tree, "");
|
tree = name_node(tree, "");
|
||||||
|
|
||||||
return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
|
return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
|
||||||
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
|
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
|
||||||
LIBFDT_VERSION = version.lds
|
LIBFDT_VERSION = version.lds
|
||||||
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
|
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
|
||||||
fdt_addresses.c
|
fdt_addresses.c fdt_overlay.c
|
||||||
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
||||||
|
|
|
@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset,
|
||||||
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
|
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t fdt_get_max_phandle(const void *fdt)
|
||||||
|
{
|
||||||
|
uint32_t max_phandle = 0;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
for (offset = fdt_next_node(fdt, -1, NULL);;
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||||
|
uint32_t phandle;
|
||||||
|
|
||||||
|
if (offset == -FDT_ERR_NOTFOUND)
|
||||||
|
return max_phandle;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return (uint32_t)-1;
|
||||||
|
|
||||||
|
phandle = fdt_get_phandle(fdt, offset);
|
||||||
|
if (phandle == (uint32_t)-1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (phandle > max_phandle)
|
||||||
|
max_phandle = phandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||||
{
|
{
|
||||||
FDT_CHECK_HEADER(fdt);
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
@ -545,7 +571,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
|
||||||
|
|
||||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||||
if (!list)
|
if (!list)
|
||||||
return -length;
|
return length;
|
||||||
|
|
||||||
end = list + length;
|
end = list + length;
|
||||||
|
|
||||||
|
@ -571,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
||||||
|
|
||||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||||
if (!list)
|
if (!list)
|
||||||
return -length;
|
return length;
|
||||||
|
|
||||||
len = strlen(string) + 1;
|
len = strlen(string) + 1;
|
||||||
end = list + length;
|
end = list + length;
|
||||||
|
|
|
@ -191,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
|
||||||
int fdt_del_mem_rsv(void *fdt, int n)
|
int fdt_del_mem_rsv(void *fdt, int n)
|
||||||
{
|
{
|
||||||
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
|
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
|
||||||
int err;
|
|
||||||
|
|
||||||
FDT_RW_CHECK_HEADER(fdt);
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
if (n >= fdt_num_mem_rsv(fdt))
|
if (n >= fdt_num_mem_rsv(fdt))
|
||||||
return -FDT_ERR_NOTFOUND;
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
|
return _fdt_splice_mem_rsv(fdt, re, 1, 0);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
|
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
|
||||||
|
|
|
@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = {
|
||||||
|
|
||||||
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
|
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
|
||||||
FDT_ERRTABENT(FDT_ERR_BADPATH),
|
FDT_ERRTABENT(FDT_ERR_BADPATH),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
|
||||||
FDT_ERRTABENT(FDT_ERR_BADSTATE),
|
FDT_ERRTABENT(FDT_ERR_BADSTATE),
|
||||||
|
|
||||||
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
|
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
|
||||||
|
@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = {
|
||||||
FDT_ERRTABENT(FDT_ERR_BADVERSION),
|
FDT_ERRTABENT(FDT_ERR_BADVERSION),
|
||||||
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
|
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
|
||||||
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
|
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_INTERNAL),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADVALUE),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
||||||
};
|
};
|
||||||
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
||||||
|
|
||||||
|
|
|
@ -55,21 +55,42 @@
|
||||||
|
|
||||||
#include "libfdt_internal.h"
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||||
const void *val, int len)
|
const char *name, int namelen,
|
||||||
|
uint32_t idx, const void *val,
|
||||||
|
int len)
|
||||||
{
|
{
|
||||||
void *propval;
|
void *propval;
|
||||||
int proplen;
|
int proplen;
|
||||||
|
|
||||||
propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
|
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
|
||||||
|
&proplen);
|
||||||
|
if (!propval)
|
||||||
|
return proplen;
|
||||||
|
|
||||||
|
if (proplen < (len + idx))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
memcpy((char *)propval + idx, val, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||||
|
const void *val, int len)
|
||||||
|
{
|
||||||
|
const void *propval;
|
||||||
|
int proplen;
|
||||||
|
|
||||||
|
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
|
||||||
if (! propval)
|
if (! propval)
|
||||||
return proplen;
|
return proplen;
|
||||||
|
|
||||||
if (proplen != len)
|
if (proplen != len)
|
||||||
return -FDT_ERR_NOSPACE;
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
memcpy(propval, val, len);
|
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
|
||||||
return 0;
|
strlen(name), 0,
|
||||||
|
val, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _fdt_nop_region(void *start, int len)
|
static void _fdt_nop_region(void *start, int len)
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
#define FDT_ERR_NOTFOUND 1
|
#define FDT_ERR_NOTFOUND 1
|
||||||
/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
|
/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
|
||||||
#define FDT_ERR_EXISTS 2
|
#define FDT_ERR_EXISTS 2
|
||||||
/* FDT_ERR_EXISTS: Attemped to create a node or property which
|
/* FDT_ERR_EXISTS: Attempted to create a node or property which
|
||||||
* already exists */
|
* already exists */
|
||||||
#define FDT_ERR_NOSPACE 3
|
#define FDT_ERR_NOSPACE 3
|
||||||
/* FDT_ERR_NOSPACE: Operation needed to expand the device
|
/* FDT_ERR_NOSPACE: Operation needed to expand the device
|
||||||
|
@ -79,8 +79,10 @@
|
||||||
* (e.g. missing a leading / for a function which requires an
|
* (e.g. missing a leading / for a function which requires an
|
||||||
* absolute path) */
|
* absolute path) */
|
||||||
#define FDT_ERR_BADPHANDLE 6
|
#define FDT_ERR_BADPHANDLE 6
|
||||||
/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
|
/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
|
||||||
* value. phandle values of 0 and -1 are not permitted. */
|
* This can be caused either by an invalid phandle property
|
||||||
|
* length, or the phandle value was either 0 or -1, which are
|
||||||
|
* not permitted. */
|
||||||
#define FDT_ERR_BADSTATE 7
|
#define FDT_ERR_BADSTATE 7
|
||||||
/* FDT_ERR_BADSTATE: Function was passed an incomplete device
|
/* FDT_ERR_BADSTATE: Function was passed an incomplete device
|
||||||
* tree created by the sequential-write functions, which is
|
* tree created by the sequential-write functions, which is
|
||||||
|
@ -126,7 +128,16 @@
|
||||||
* value. For example: a property expected to contain a string list
|
* value. For example: a property expected to contain a string list
|
||||||
* is not NUL-terminated within the length of its value. */
|
* is not NUL-terminated within the length of its value. */
|
||||||
|
|
||||||
#define FDT_ERR_MAX 15
|
#define FDT_ERR_BADOVERLAY 16
|
||||||
|
/* FDT_ERR_BADOVERLAY: The device tree overlay, while
|
||||||
|
* correctly structured, cannot be applied due to some
|
||||||
|
* unexpected or missing value, property or node. */
|
||||||
|
|
||||||
|
#define FDT_ERR_NOPHANDLES 17
|
||||||
|
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
|
||||||
|
* phandle available anymore without causing an overflow */
|
||||||
|
|
||||||
|
#define FDT_ERR_MAX 17
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* Low-level functions (you probably don't need these) */
|
/* Low-level functions (you probably don't need these) */
|
||||||
|
@ -168,27 +179,55 @@ int fdt_first_subnode(const void *fdt, int offset);
|
||||||
*/
|
*/
|
||||||
int fdt_next_subnode(const void *fdt, int offset);
|
int fdt_next_subnode(const void *fdt, int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_for_each_subnode - iterate over all subnodes of a parent
|
||||||
|
*
|
||||||
|
* @node: child node (int, lvalue)
|
||||||
|
* @fdt: FDT blob (const void *)
|
||||||
|
* @parent: parent node (int)
|
||||||
|
*
|
||||||
|
* This is actually a wrapper around a for loop and would be used like so:
|
||||||
|
*
|
||||||
|
* fdt_for_each_subnode(node, fdt, parent) {
|
||||||
|
* Use node
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
|
||||||
|
* Error handling
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Note that this is implemented as a macro and @node is used as
|
||||||
|
* iterator in the loop. The parent variable be constant or even a
|
||||||
|
* literal.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define fdt_for_each_subnode(node, fdt, parent) \
|
||||||
|
for (node = fdt_first_subnode(fdt, parent); \
|
||||||
|
node >= 0; \
|
||||||
|
node = fdt_next_subnode(fdt, node))
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* General functions */
|
/* General functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
#define fdt_get_header(fdt, field) \
|
#define fdt_get_header(fdt, field) \
|
||||||
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
|
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
|
||||||
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
|
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
|
||||||
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
|
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
|
||||||
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
|
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
|
||||||
#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
|
#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
|
||||||
#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
|
#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
|
||||||
#define fdt_version(fdt) (fdt_get_header(fdt, version))
|
#define fdt_version(fdt) (fdt_get_header(fdt, version))
|
||||||
#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
|
#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
|
||||||
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
|
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
|
||||||
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
|
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
|
||||||
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
|
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
|
||||||
|
|
||||||
#define __fdt_set_hdr(name) \
|
#define __fdt_set_hdr(name) \
|
||||||
static inline void fdt_set_##name(void *fdt, uint32_t val) \
|
static inline void fdt_set_##name(void *fdt, uint32_t val) \
|
||||||
{ \
|
{ \
|
||||||
struct fdt_header *fdth = (struct fdt_header*)fdt; \
|
struct fdt_header *fdth = (struct fdt_header *)fdt; \
|
||||||
fdth->name = cpu_to_fdt32(val); \
|
fdth->name = cpu_to_fdt32(val); \
|
||||||
}
|
}
|
||||||
__fdt_set_hdr(magic);
|
__fdt_set_hdr(magic);
|
||||||
|
@ -258,6 +297,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
|
||||||
*/
|
*/
|
||||||
const char *fdt_string(const void *fdt, int stroffset);
|
const char *fdt_string(const void *fdt, int stroffset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_get_max_phandle - retrieves the highest phandle in a tree
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
*
|
||||||
|
* fdt_get_max_phandle retrieves the highest phandle in the given
|
||||||
|
* device tree. This will ignore badly formatted phandles, or phandles
|
||||||
|
* with a value of 0 or -1.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* the highest phandle on success
|
||||||
|
* 0, if no phandle was found in the device tree
|
||||||
|
* -1, if an error occurred
|
||||||
|
*/
|
||||||
|
uint32_t fdt_get_max_phandle(const void *fdt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
|
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
|
@ -318,8 +372,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
|
||||||
* returns:
|
* returns:
|
||||||
* structure block offset of the requested subnode (>=0), on success
|
* structure block offset of the requested subnode (>=0), on success
|
||||||
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
|
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
|
||||||
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
|
||||||
* -FDT_ERR_BADMAGIC,
|
* tag
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
* -FDT_ERR_BADSTRUCTURE,
|
* -FDT_ERR_BADSTRUCTURE,
|
||||||
|
@ -351,7 +406,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
|
||||||
* address).
|
* address).
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
* structure block offset of the node with the requested path (>=0), on success
|
* structure block offset of the node with the requested path (>=0), on
|
||||||
|
* success
|
||||||
* -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
|
* -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
|
||||||
* -FDT_ERR_NOTFOUND, if the requested node does not exist
|
* -FDT_ERR_NOTFOUND, if the requested node does not exist
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
@ -375,10 +431,12 @@ int fdt_path_offset(const void *fdt, const char *path);
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
* pointer to the node's name, on success
|
* pointer to the node's name, on success
|
||||||
* If lenp is non-NULL, *lenp contains the length of that name (>=0)
|
* If lenp is non-NULL, *lenp contains the length of that name
|
||||||
|
* (>=0)
|
||||||
* NULL, on error
|
* NULL, on error
|
||||||
* if lenp is non-NULL *lenp contains an error code (<0):
|
* if lenp is non-NULL *lenp contains an error code (<0):
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
|
||||||
|
* tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE, standard meanings
|
* -FDT_ERR_BADSTATE, standard meanings
|
||||||
|
@ -426,6 +484,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset);
|
||||||
*/
|
*/
|
||||||
int fdt_next_property_offset(const void *fdt, int offset);
|
int fdt_next_property_offset(const void *fdt, int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_for_each_property_offset - iterate over all properties of a node
|
||||||
|
*
|
||||||
|
* @property_offset: property offset (int, lvalue)
|
||||||
|
* @fdt: FDT blob (const void *)
|
||||||
|
* @node: node offset (int)
|
||||||
|
*
|
||||||
|
* This is actually a wrapper around a for loop and would be used like so:
|
||||||
|
*
|
||||||
|
* fdt_for_each_property_offset(property, fdt, node) {
|
||||||
|
* Use property
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
|
||||||
|
* Error handling
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Note that this is implemented as a macro and property is used as
|
||||||
|
* iterator in the loop. The node variable can be constant or even a
|
||||||
|
* literal.
|
||||||
|
*/
|
||||||
|
#define fdt_for_each_property_offset(property, fdt, node) \
|
||||||
|
for (property = fdt_first_property_offset(fdt, node); \
|
||||||
|
property >= 0; \
|
||||||
|
property = fdt_next_property_offset(fdt, property))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_get_property_by_offset - retrieve the property at a given offset
|
* fdt_get_property_by_offset - retrieve the property at a given offset
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
|
@ -490,7 +575,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||||
* NULL, on error
|
* NULL, on error
|
||||||
* if lenp is non-NULL, *lenp contains an error code (<0):
|
* if lenp is non-NULL, *lenp contains an error code (<0):
|
||||||
* -FDT_ERR_NOTFOUND, node does not have named property
|
* -FDT_ERR_NOTFOUND, node does not have named property
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
|
||||||
|
* tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -554,6 +640,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||||
*/
|
*/
|
||||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||||
const char *name, int namelen, int *lenp);
|
const char *name, int namelen, int *lenp);
|
||||||
|
static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
|
||||||
|
const char *name, int namelen,
|
||||||
|
int *lenp)
|
||||||
|
{
|
||||||
|
return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
|
||||||
|
namelen, lenp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_getprop - retrieve the value of a given property
|
* fdt_getprop - retrieve the value of a given property
|
||||||
|
@ -575,7 +668,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||||
* NULL, on error
|
* NULL, on error
|
||||||
* if lenp is non-NULL, *lenp contains an error code (<0):
|
* if lenp is non-NULL, *lenp contains an error code (<0):
|
||||||
* -FDT_ERR_NOTFOUND, node does not have named property
|
* -FDT_ERR_NOTFOUND, node does not have named property
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
|
||||||
|
* tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -617,7 +711,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
|
||||||
const char *name, int namelen);
|
const char *name, int namelen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_get_alias - retreive the path referenced by a given alias
|
* fdt_get_alias - retrieve the path referenced by a given alias
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
* @name: name of the alias th look up
|
* @name: name of the alias th look up
|
||||||
*
|
*
|
||||||
|
@ -647,7 +741,7 @@ const char *fdt_get_alias(const void *fdt, const char *name);
|
||||||
* 0, on success
|
* 0, on success
|
||||||
* buf contains the absolute path of the node at
|
* buf contains the absolute path of the node at
|
||||||
* nodeoffset, as a NUL-terminated string.
|
* nodeoffset, as a NUL-terminated string.
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
|
* -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
|
||||||
* characters and will not fit in the given buffer.
|
* characters and will not fit in the given buffer.
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
@ -677,11 +771,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
|
||||||
* structure from the start to nodeoffset.
|
* structure from the start to nodeoffset.
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
|
|
||||||
* structure block offset of the node at node offset's ancestor
|
* structure block offset of the node at node offset's ancestor
|
||||||
* of depth supernodedepth (>=0), on success
|
* of depth supernodedepth (>=0), on success
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
|
* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
|
||||||
|
* nodeoffset
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -703,7 +797,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
* depth of the node at nodeoffset (>=0), on success
|
* depth of the node at nodeoffset (>=0), on success
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -726,7 +820,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
|
||||||
* returns:
|
* returns:
|
||||||
* structure block offset of the parent of the node at nodeoffset
|
* structure block offset of the parent of the node at nodeoffset
|
||||||
* (>=0), on success
|
* (>=0), on success
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -766,7 +860,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset);
|
||||||
* on success
|
* on success
|
||||||
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
|
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
|
||||||
* tree after startoffset
|
* tree after startoffset
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -813,7 +907,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
|
||||||
* 1, if the node has a 'compatible' property, but it does not list
|
* 1, if the node has a 'compatible' property, but it does not list
|
||||||
* the given string
|
* the given string
|
||||||
* -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
|
* -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
|
||||||
* -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -850,7 +944,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
|
||||||
* on success
|
* on success
|
||||||
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
|
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
|
||||||
* tree after startoffset
|
* tree after startoffset
|
||||||
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -960,7 +1054,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
|
||||||
* returns:
|
* returns:
|
||||||
* 0 <= n < FDT_MAX_NCELLS, on success
|
* 0 <= n < FDT_MAX_NCELLS, on success
|
||||||
* 2, if the node has no #address-cells property
|
* 2, if the node has no #address-cells property
|
||||||
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property
|
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
|
||||||
|
* #address-cells property
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -980,7 +1075,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
|
||||||
* returns:
|
* returns:
|
||||||
* 0 <= n < FDT_MAX_NCELLS, on success
|
* 0 <= n < FDT_MAX_NCELLS, on success
|
||||||
* 2, if the node has no #address-cells property
|
* 2, if the node has no #address-cells property
|
||||||
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property
|
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
|
||||||
|
* #size-cells property
|
||||||
* -FDT_ERR_BADMAGIC,
|
* -FDT_ERR_BADMAGIC,
|
||||||
* -FDT_ERR_BADVERSION,
|
* -FDT_ERR_BADVERSION,
|
||||||
* -FDT_ERR_BADSTATE,
|
* -FDT_ERR_BADSTATE,
|
||||||
|
@ -994,6 +1090,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
|
||||||
/* Write-in-place functions */
|
/* Write-in-place functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_setprop_inplace_namelen_partial - change a property's value,
|
||||||
|
* but not its size
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @nodeoffset: offset of the node whose property to change
|
||||||
|
* @name: name of the property to change
|
||||||
|
* @namelen: number of characters of name to consider
|
||||||
|
* @idx: index of the property to change in the array
|
||||||
|
* @val: pointer to data to replace the property value with
|
||||||
|
* @len: length of the property value
|
||||||
|
*
|
||||||
|
* Identical to fdt_setprop_inplace(), but modifies the given property
|
||||||
|
* starting from the given index, and using only the first characters
|
||||||
|
* of the name. It is useful when you want to manipulate only one value of
|
||||||
|
* an array and you have a string that doesn't end with \0.
|
||||||
|
*/
|
||||||
|
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||||
|
const char *name, int namelen,
|
||||||
|
uint32_t idx, const void *val,
|
||||||
|
int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_setprop_inplace - change a property's value, but not its size
|
* fdt_setprop_inplace - change a property's value, but not its size
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
|
@ -1604,9 +1721,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||||
* change the offsets of some existing nodes.
|
* change the offsets of some existing nodes.
|
||||||
|
|
||||||
* returns:
|
* returns:
|
||||||
* structure block offset of the created nodeequested subnode (>=0), on success
|
* structure block offset of the created nodeequested subnode (>=0), on
|
||||||
|
* success
|
||||||
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
|
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
|
||||||
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
|
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
|
||||||
|
* tag
|
||||||
* -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
|
* -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
|
||||||
* the given name
|
* the given name
|
||||||
* -FDT_ERR_NOSPACE, if there is insufficient free space in the
|
* -FDT_ERR_NOSPACE, if there is insufficient free space in the
|
||||||
|
@ -1644,6 +1763,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
|
||||||
*/
|
*/
|
||||||
int fdt_del_node(void *fdt, int nodeoffset);
|
int fdt_del_node(void *fdt, int nodeoffset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_overlay_apply - Applies a DT overlay on a base DT
|
||||||
|
* @fdt: pointer to the base device tree blob
|
||||||
|
* @fdto: pointer to the device tree overlay blob
|
||||||
|
*
|
||||||
|
* fdt_overlay_apply() will apply the given device tree overlay on the
|
||||||
|
* given base device tree.
|
||||||
|
*
|
||||||
|
* Expect the base device tree to be modified, even if the function
|
||||||
|
* returns an error.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, there's not enough space in the base device tree
|
||||||
|
* -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
|
||||||
|
* properties in the base DT
|
||||||
|
* -FDT_ERR_BADPHANDLE,
|
||||||
|
* -FDT_ERR_BADOVERLAY,
|
||||||
|
* -FDT_ERR_NOPHANDLES,
|
||||||
|
* -FDT_ERR_INTERNAL,
|
||||||
|
* -FDT_ERR_BADLAYOUT,
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
* -FDT_ERR_BADOFFSET,
|
||||||
|
* -FDT_ERR_BADPATH,
|
||||||
|
* -FDT_ERR_BADVERSION,
|
||||||
|
* -FDT_ERR_BADSTRUCTURE,
|
||||||
|
* -FDT_ERR_BADSTATE,
|
||||||
|
* -FDT_ERR_TRUNCATED, standard meanings
|
||||||
|
*/
|
||||||
|
int fdt_overlay_apply(void *fdt, void *fdto);
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* Debugging / informational functions */
|
/* Debugging / informational functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef __CHECKER__
|
#ifdef __CHECKER__
|
||||||
|
|
|
@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if no collision occured, add child to the old node. */
|
/* if no collision occurred, add child to the old node. */
|
||||||
if (new_child)
|
if (new_child)
|
||||||
add_child(old_node, new_child);
|
add_child(old_node, new_child);
|
||||||
}
|
}
|
||||||
|
@ -296,6 +296,23 @@ void delete_node(struct node *node)
|
||||||
delete_labels(&node->labels);
|
delete_labels(&node->labels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void append_to_property(struct node *node,
|
||||||
|
char *name, const void *data, int len)
|
||||||
|
{
|
||||||
|
struct data d;
|
||||||
|
struct property *p;
|
||||||
|
|
||||||
|
p = get_property(node, name);
|
||||||
|
if (p) {
|
||||||
|
d = data_append_data(p->val, data, len);
|
||||||
|
p->val = d;
|
||||||
|
} else {
|
||||||
|
d = data_append_data(empty_data, data, len);
|
||||||
|
p = build_property(name, d);
|
||||||
|
add_property(node, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
||||||
{
|
{
|
||||||
struct reserve_info *new = xmalloc(sizeof(*new));
|
struct reserve_info *new = xmalloc(sizeof(*new));
|
||||||
|
@ -335,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct boot_info *build_boot_info(struct reserve_info *reservelist,
|
struct dt_info *build_dt_info(unsigned int dtsflags,
|
||||||
struct node *tree, uint32_t boot_cpuid_phys)
|
struct reserve_info *reservelist,
|
||||||
|
struct node *tree, uint32_t boot_cpuid_phys)
|
||||||
{
|
{
|
||||||
struct boot_info *bi;
|
struct dt_info *dti;
|
||||||
|
|
||||||
bi = xmalloc(sizeof(*bi));
|
dti = xmalloc(sizeof(*dti));
|
||||||
bi->reservelist = reservelist;
|
dti->dtsflags = dtsflags;
|
||||||
bi->dt = tree;
|
dti->reservelist = reservelist;
|
||||||
bi->boot_cpuid_phys = boot_cpuid_phys;
|
dti->dt = tree;
|
||||||
|
dti->boot_cpuid_phys = boot_cpuid_phys;
|
||||||
|
|
||||||
return bi;
|
return dti;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -592,12 +611,12 @@ static int cmp_reserve_info(const void *ax, const void *bx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sort_reserve_entries(struct boot_info *bi)
|
static void sort_reserve_entries(struct dt_info *dti)
|
||||||
{
|
{
|
||||||
struct reserve_info *ri, **tbl;
|
struct reserve_info *ri, **tbl;
|
||||||
int n = 0, i = 0;
|
int n = 0, i = 0;
|
||||||
|
|
||||||
for (ri = bi->reservelist;
|
for (ri = dti->reservelist;
|
||||||
ri;
|
ri;
|
||||||
ri = ri->next)
|
ri = ri->next)
|
||||||
n++;
|
n++;
|
||||||
|
@ -607,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi)
|
||||||
|
|
||||||
tbl = xmalloc(n * sizeof(*tbl));
|
tbl = xmalloc(n * sizeof(*tbl));
|
||||||
|
|
||||||
for (ri = bi->reservelist;
|
for (ri = dti->reservelist;
|
||||||
ri;
|
ri;
|
||||||
ri = ri->next)
|
ri = ri->next)
|
||||||
tbl[i++] = ri;
|
tbl[i++] = ri;
|
||||||
|
|
||||||
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
|
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
|
||||||
|
|
||||||
bi->reservelist = tbl[0];
|
dti->reservelist = tbl[0];
|
||||||
for (i = 0; i < (n-1); i++)
|
for (i = 0; i < (n-1); i++)
|
||||||
tbl[i]->next = tbl[i+1];
|
tbl[i]->next = tbl[i+1];
|
||||||
tbl[n-1]->next = NULL;
|
tbl[n-1]->next = NULL;
|
||||||
|
@ -704,8 +723,256 @@ static void sort_node(struct node *node)
|
||||||
sort_node(c);
|
sort_node(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sort_tree(struct boot_info *bi)
|
void sort_tree(struct dt_info *dti)
|
||||||
{
|
{
|
||||||
sort_reserve_entries(bi);
|
sort_reserve_entries(dti);
|
||||||
sort_node(bi->dt);
|
sort_node(dti->dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* utility helper to avoid code duplication */
|
||||||
|
static struct node *build_and_name_child_node(struct node *parent, char *name)
|
||||||
|
{
|
||||||
|
struct node *node;
|
||||||
|
|
||||||
|
node = build_node(NULL, NULL);
|
||||||
|
name_node(node, xstrdup(name));
|
||||||
|
add_child(parent, node);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct node *build_root_node(struct node *dt, char *name)
|
||||||
|
{
|
||||||
|
struct node *an;
|
||||||
|
|
||||||
|
an = get_subnode(dt, name);
|
||||||
|
if (!an)
|
||||||
|
an = build_and_name_child_node(dt, name);
|
||||||
|
|
||||||
|
if (!an)
|
||||||
|
die("Could not build root node /%s\n", name);
|
||||||
|
|
||||||
|
return an;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool any_label_tree(struct dt_info *dti, struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
|
||||||
|
if (node->labels)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
if (any_label_tree(dti, c))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_label_tree_internal(struct dt_info *dti,
|
||||||
|
struct node *an, struct node *node,
|
||||||
|
bool allocph)
|
||||||
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
|
struct node *c;
|
||||||
|
struct property *p;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
/* if there are labels */
|
||||||
|
if (node->labels) {
|
||||||
|
|
||||||
|
/* now add the label in the node */
|
||||||
|
for_each_label(node->labels, l) {
|
||||||
|
|
||||||
|
/* check whether the label already exists */
|
||||||
|
p = get_property(an, l->label);
|
||||||
|
if (p) {
|
||||||
|
fprintf(stderr, "WARNING: label %s already"
|
||||||
|
" exists in /%s", l->label,
|
||||||
|
an->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert it */
|
||||||
|
p = build_property(l->label,
|
||||||
|
data_copy_mem(node->fullpath,
|
||||||
|
strlen(node->fullpath) + 1));
|
||||||
|
add_property(an, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* force allocation of a phandle for this node */
|
||||||
|
if (allocph)
|
||||||
|
(void)get_node_phandle(dt, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
generate_label_tree_internal(dti, an, c, allocph);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool any_fixup_tree(struct dt_info *dti, struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
if (!get_node_by_ref(dti->dt, m->ref))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c) {
|
||||||
|
if (any_fixup_tree(dti, c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_fixup_entry(struct dt_info *dti, struct node *fn,
|
||||||
|
struct node *node, struct property *prop,
|
||||||
|
struct marker *m)
|
||||||
|
{
|
||||||
|
char *entry;
|
||||||
|
|
||||||
|
/* m->ref can only be a REF_PHANDLE, but check anyway */
|
||||||
|
assert(m->type == REF_PHANDLE);
|
||||||
|
|
||||||
|
/* there shouldn't be any ':' in the arguments */
|
||||||
|
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
|
||||||
|
die("arguments should not contain ':'\n");
|
||||||
|
|
||||||
|
xasprintf(&entry, "%s:%s:%u",
|
||||||
|
node->fullpath, prop->name, m->offset);
|
||||||
|
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_fixups_tree_internal(struct dt_info *dti,
|
||||||
|
struct node *fn,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
struct node *refnode;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
|
if (!refnode)
|
||||||
|
add_fixup_entry(dti, fn, node, prop, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
generate_fixups_tree_internal(dti, fn, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
if (get_node_by_ref(dti->dt, m->ref))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c) {
|
||||||
|
if (any_local_fixup_tree(dti, c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_local_fixup_entry(struct dt_info *dti,
|
||||||
|
struct node *lfn, struct node *node,
|
||||||
|
struct property *prop, struct marker *m,
|
||||||
|
struct node *refnode)
|
||||||
|
{
|
||||||
|
struct node *wn, *nwn; /* local fixup node, walk node, new */
|
||||||
|
uint32_t value_32;
|
||||||
|
char **compp;
|
||||||
|
int i, depth;
|
||||||
|
|
||||||
|
/* walk back retreiving depth */
|
||||||
|
depth = 0;
|
||||||
|
for (wn = node; wn; wn = wn->parent)
|
||||||
|
depth++;
|
||||||
|
|
||||||
|
/* allocate name array */
|
||||||
|
compp = xmalloc(sizeof(*compp) * depth);
|
||||||
|
|
||||||
|
/* store names in the array */
|
||||||
|
for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
|
||||||
|
compp[i] = wn->name;
|
||||||
|
|
||||||
|
/* walk the path components creating nodes if they don't exist */
|
||||||
|
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
|
||||||
|
/* if no node exists, create it */
|
||||||
|
nwn = get_subnode(wn, compp[i]);
|
||||||
|
if (!nwn)
|
||||||
|
nwn = build_and_name_child_node(wn, compp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(compp);
|
||||||
|
|
||||||
|
value_32 = cpu_to_fdt32(m->offset);
|
||||||
|
append_to_property(wn, prop->name, &value_32, sizeof(value_32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_local_fixups_tree_internal(struct dt_info *dti,
|
||||||
|
struct node *lfn,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
struct node *refnode;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
|
if (refnode)
|
||||||
|
add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
generate_local_fixups_tree_internal(dti, lfn, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
|
||||||
|
{
|
||||||
|
if (!any_label_tree(dti, dti->dt))
|
||||||
|
return;
|
||||||
|
generate_label_tree_internal(dti, build_root_node(dti->dt, name),
|
||||||
|
dti->dt, allocph);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_fixups_tree(struct dt_info *dti, char *name)
|
||||||
|
{
|
||||||
|
if (!any_fixup_tree(dti, dti->dt))
|
||||||
|
return;
|
||||||
|
generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
|
||||||
|
dti->dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_local_fixups_tree(struct dt_info *dti, char *name)
|
||||||
|
{
|
||||||
|
if (!any_local_fixup_tree(dti, dti->dt))
|
||||||
|
return;
|
||||||
|
generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
|
||||||
|
dti->dt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,46 +246,27 @@ srcpos_copy(struct srcpos *pos)
|
||||||
return pos_new;
|
return pos_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
srcpos_dump(struct srcpos *pos)
|
|
||||||
{
|
|
||||||
printf("file : \"%s\"\n",
|
|
||||||
pos->file ? (char *) pos->file : "<no file>");
|
|
||||||
printf("first_line : %d\n", pos->first_line);
|
|
||||||
printf("first_column: %d\n", pos->first_column);
|
|
||||||
printf("last_line : %d\n", pos->last_line);
|
|
||||||
printf("last_column : %d\n", pos->last_column);
|
|
||||||
printf("file : %s\n", pos->file->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
srcpos_string(struct srcpos *pos)
|
srcpos_string(struct srcpos *pos)
|
||||||
{
|
{
|
||||||
const char *fname = "<no-file>";
|
const char *fname = "<no-file>";
|
||||||
char *pos_str;
|
char *pos_str;
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (pos)
|
if (pos)
|
||||||
fname = pos->file->name;
|
fname = pos->file->name;
|
||||||
|
|
||||||
|
|
||||||
if (pos->first_line != pos->last_line)
|
if (pos->first_line != pos->last_line)
|
||||||
rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
|
xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
|
||||||
pos->first_line, pos->first_column,
|
pos->first_line, pos->first_column,
|
||||||
pos->last_line, pos->last_column);
|
pos->last_line, pos->last_column);
|
||||||
else if (pos->first_column != pos->last_column)
|
else if (pos->first_column != pos->last_column)
|
||||||
rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
|
xasprintf(&pos_str, "%s:%d.%d-%d", fname,
|
||||||
pos->first_line, pos->first_column,
|
pos->first_line, pos->first_column,
|
||||||
pos->last_column);
|
pos->last_column);
|
||||||
else
|
else
|
||||||
rc = asprintf(&pos_str, "%s:%d.%d", fname,
|
xasprintf(&pos_str, "%s:%d.%d", fname,
|
||||||
pos->first_line, pos->first_column);
|
pos->first_line, pos->first_column);
|
||||||
|
|
||||||
if (rc == -1)
|
|
||||||
die("Couldn't allocate in srcpos string");
|
|
||||||
|
|
||||||
return pos_str;
|
return pos_str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,6 @@ extern struct srcpos srcpos_empty;
|
||||||
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
|
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
|
||||||
extern struct srcpos *srcpos_copy(struct srcpos *pos);
|
extern struct srcpos *srcpos_copy(struct srcpos *pos);
|
||||||
extern char *srcpos_string(struct srcpos *pos);
|
extern char *srcpos_string(struct srcpos *pos);
|
||||||
extern void srcpos_dump(struct srcpos *pos);
|
|
||||||
|
|
||||||
extern void srcpos_verror(struct srcpos *pos, const char *prefix,
|
extern void srcpos_verror(struct srcpos *pos, const char *prefix,
|
||||||
const char *fmt, va_list va)
|
const char *fmt, va_list va)
|
||||||
|
|
|
@ -25,12 +25,12 @@ extern FILE *yyin;
|
||||||
extern int yyparse(void);
|
extern int yyparse(void);
|
||||||
extern YYLTYPE yylloc;
|
extern YYLTYPE yylloc;
|
||||||
|
|
||||||
struct boot_info *the_boot_info;
|
struct dt_info *parser_output;
|
||||||
bool treesource_error;
|
bool treesource_error;
|
||||||
|
|
||||||
struct boot_info *dt_from_source(const char *fname)
|
struct dt_info *dt_from_source(const char *fname)
|
||||||
{
|
{
|
||||||
the_boot_info = NULL;
|
parser_output = NULL;
|
||||||
treesource_error = false;
|
treesource_error = false;
|
||||||
|
|
||||||
srcfile_push(fname);
|
srcfile_push(fname);
|
||||||
|
@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname)
|
||||||
if (treesource_error)
|
if (treesource_error)
|
||||||
die("Syntax error parsing input tree\n");
|
die("Syntax error parsing input tree\n");
|
||||||
|
|
||||||
return the_boot_info;
|
return parser_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_prefix(FILE *f, int level)
|
static void write_prefix(FILE *f, int level)
|
||||||
|
@ -263,13 +263,13 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dt_to_source(FILE *f, struct boot_info *bi)
|
void dt_to_source(FILE *f, struct dt_info *dti)
|
||||||
{
|
{
|
||||||
struct reserve_info *re;
|
struct reserve_info *re;
|
||||||
|
|
||||||
fprintf(f, "/dts-v1/;\n\n");
|
fprintf(f, "/dts-v1/;\n\n");
|
||||||
|
|
||||||
for (re = bi->reservelist; re; re = re->next) {
|
for (re = dti->reservelist; re; re = re->next) {
|
||||||
struct label *l;
|
struct label *l;
|
||||||
|
|
||||||
for_each_label(re->labels, l)
|
for_each_label(re->labels, l)
|
||||||
|
@ -279,6 +279,6 @@ void dt_to_source(FILE *f, struct boot_info *bi)
|
||||||
(unsigned long long)re->re.size);
|
(unsigned long long)re->re.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_tree_source_node(f, bi->dt, 0);
|
write_tree_source_node(f, dti->dt, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,36 @@ char *xstrdup(const char *s)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* based in part from (3) vsnprintf */
|
||||||
|
int xasprintf(char **strp, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int n, size = 128; /* start with 128 bytes */
|
||||||
|
char *p;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* initial pointer is NULL making the fist realloc to be malloc */
|
||||||
|
p = NULL;
|
||||||
|
while (1) {
|
||||||
|
p = xrealloc(p, size);
|
||||||
|
|
||||||
|
/* Try to print in the allocated space. */
|
||||||
|
va_start(ap, fmt);
|
||||||
|
n = vsnprintf(p, size, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/* If that worked, return the string. */
|
||||||
|
if (n > -1 && n < size)
|
||||||
|
break;
|
||||||
|
/* Else try again with more space. */
|
||||||
|
if (n > -1) /* glibc 2.1 */
|
||||||
|
size = n + 1; /* precisely what is needed */
|
||||||
|
else /* glibc 2.0 */
|
||||||
|
size *= 2; /* twice the old size */
|
||||||
|
}
|
||||||
|
*strp = p;
|
||||||
|
return strlen(p);
|
||||||
|
}
|
||||||
|
|
||||||
char *join_path(const char *path, const char *name)
|
char *join_path(const char *path, const char *name)
|
||||||
{
|
{
|
||||||
int lenp = strlen(path);
|
int lenp = strlen(path);
|
||||||
|
|
|
@ -59,6 +59,7 @@ static inline void *xrealloc(void *p, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char *xstrdup(const char *s);
|
extern char *xstrdup(const char *s);
|
||||||
|
extern int xasprintf(char **strp, const char *fmt, ...);
|
||||||
extern char *join_path(const char *path, const char *name);
|
extern char *join_path(const char *path, const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define DTC_VERSION "DTC 1.4.1-g53bf130b"
|
#define DTC_VERSION "DTC 1.4.2-g0931cea3"
|
||||||
|
|
Loading…
Reference in New Issue