summaryrefslogtreecommitdiff
path: root/kernels/linux-libre-lts-knock
diff options
context:
space:
mode:
authorDavid P <megver83@openmailbox.org>2017-10-31 14:45:45 -0300
committerDavid P <megver83@openmailbox.org>2017-10-31 19:49:25 -0300
commit861cc5acaf28fbc7228f8f41aa194c03e27d4359 (patch)
tree3011ad0cdb7c28b82224ef3d4d8bc592d1eff593 /kernels/linux-libre-lts-knock
parent8e21be8d54c767339cba76c4280e7ce288fac07e (diff)
updpkgsums: kernels/linux-libre-lts-knock
Diffstat (limited to 'kernels/linux-libre-lts-knock')
-rw-r--r--kernels/linux-libre-lts-knock/rcn-libre-4.9.59-armv7-x5.patch35632
-rw-r--r--kernels/linux-libre-lts-knock/tcp_stealth_4.9_1.diff642
2 files changed, 36274 insertions, 0 deletions
diff --git a/kernels/linux-libre-lts-knock/rcn-libre-4.9.59-armv7-x5.patch b/kernels/linux-libre-lts-knock/rcn-libre-4.9.59-armv7-x5.patch
new file mode 100644
index 000000000..c54a3d888
--- /dev/null
+++ b/kernels/linux-libre-lts-knock/rcn-libre-4.9.59-armv7-x5.patch
@@ -0,0 +1,35632 @@
+diff --git a/.gitignore b/.gitignore
+index c2ed4ec..0544d50 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -114,3 +114,7 @@ all.config
+
+ # Kdevelop4
+ *.kdev4
++
++# dtb objects
++*.dtb
++*.dtbo
+diff --git b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
+new file mode 100644
+index 0000000..e2df613
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
+@@ -0,0 +1,63 @@
++What: /sys/devices/platform/bone_capemgr/slots
++Date: May 2015
++KernelVersion: 4.0
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ READ:
++ Describe the state of all the slots of the beaglebone capemgr.
++ Each line of the output describes a slot:
++ The slot format is as following:
++ <slot-id>: [P-][F-][O-][l-][L-][D-] \
++ <overlay-id> <board-name>,<version>,
++ <manufacturer>,<part-number>
++
++ Where the flags are:
++ P: Slot has been probed
++ F: Slot has failed probing (i.e. no EEPROM detected)
++ O: Slot has been overridden by the user
++ l: Slot is current loading
++ L: Slot has completed loading and is ready
++ D: Slot has been disabled
++
++ Example:
++ 0: P---L- -1 BeagleBone RS232 CAPE,00A1,Beagleboardtoys,BB-BONE-SERL-03
++ 1: PF---- -1
++ 2: PF---- -1
++ 3: PF---- -1
++
++ WRITE:
++ Writing a string of the form <part-number>[:version] issues a request to
++ load a firmware blob containing an overlay. The name of the firmware blob
++ is <part-number>-[version|00A0].dtbo. This act is defined as a slot override.
++
++ Writing a negative slot id removes the slot if it was an overridden one, or
++ unloads a slot that was probed.
++
++What: /sys/devices/platform/bone_capemgr/baseboard/<eeprom-field>
++Date: May 2015
++KernelVersion: 4.0
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description: Contains the probed base board EEPROM field; one of:
++ board-name - board-name as stored in cape EEPROM
++ dc-supplied - whether the cape draws or supplies DC
++ eeprom-format-revision - EEPROM format rev, only 00A0 supported
++ header - header; should be 'aa 55 33 ee'
++ manufacturer - manufacturer string
++ part-number - part-number of the cape
++ serial-number - serial number of the cape
++ version - version of the cape, i.e. 00A0
++ number-of-pins - displayed but ignored
++ pin-usage - displayed but ignored
++ sys-5v - displayed but ignored
++ vdd-3v3exp - displayed but ignored
++ vdd-5v - displayed but ignored
++What: /sys/devices/platform/bone_capemgr/slot-<n>/<eeprom-field>
++Date: May 2015
++KernelVersion: 4.0
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description: Contains the probed cape's EEPROM field; the field is one of:
++ board-name - baseboard name i.e. A335BNLT
++ header - header; should be 'aa 55 33 ee'
++ revision - baseboard revision
++ serial-number - baseboard serial number
++ config-option - displayed but ignored
+diff --git b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
+new file mode 100644
+index 0000000..88d1549
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
+@@ -0,0 +1,52 @@
++What: /sys/firmware/devicetree/overlays/
++Date: October 2015
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ This directory contains the applied device tree overlays of
++ the running system, as directories of the overlay id.
++
++What: /sys/firmware/devicetree/overlays/enable
++Date: October 2015
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ The master enable switch, by default is 1, and when
++ set to 0 it cannot be re-enabled for security reasons.
++
++ The discussion about this switch takes place in:
++ http://comments.gmane.org/gmane.linux.drivers.devicetree/101871
++
++ Kees Cook:
++ "Coming from the perspective of drawing a bright line between
++ kernel and the root user (which tends to start with disabling
++ kernel module loading), I would say that there at least needs
++ to be a high-level one-way "off" switch for the interface so
++ that systems that have this interface can choose to turn it off
++ during initial boot, etc."
++
++What: /sys/firmware/devicetree/overlays/<id>
++Date: October 2015
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ Each directory represents an applied overlay, containing
++ the following attribute files.
++
++What: /sys/firmware/devicetree/overlays/<id>/can_remove
++Date: October 2015
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ The attribute set to 1 means that the overlay can be removed,
++ while 0 means that the overlay is being overlapped therefore
++ removal is prohibited.
++
++What: /sys/firmware/devicetree/overlays/<id>/<fragment-name>/
++Date: October 2015
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ Each of these directories contain information about of the
++ particular overlay fragment.
++
++What: /sys/firmware/devicetree/overlays/<id>/<fragment-name>/target
++Date: October 2015
++Contact: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++Description:
++ The full-path of the target of the fragment
+diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
+index f53e2ee..29bc4fe 100644
+--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
++++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
+@@ -24,6 +24,8 @@ Optional properties:
+ - ti,no-reset-on-init: When present, the module should not be reset at init
+ - ti,no-idle-on-init: When present, the module should not be idled at init
+ - ti,no-idle: When present, the module is never allowed to idle.
++- ti,deassert-hard-reset: list of hwmod and hardware reset line name pairs
++ (ascii strings) to be deasserted upon device instantiation.
+
+ Example:
+
+diff --git b/Documentation/devicetree/bindings/cpufreq/ti-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/ti-cpufreq.txt
+new file mode 100644
+index 0000000..7a31864
+--- /dev/null
++++ b/Documentation/devicetree/bindings/cpufreq/ti-cpufreq.txt
+@@ -0,0 +1,132 @@
++TI CPUFreq and OPP bindings
++================================
++
++Certain TI SoCs, like those in the am335x, am437x, am57xx, and dra7xx
++families support different OPPs depending on the silicon variant in use.
++The ti_cpufreq driver can use revision and an efuse value from the SoC to
++provide the OPP framework with supported hardware information. This is
++used to determine which OPPs from the operating-points-v2 table get enabled
++when it is parsed by the OPP framework.
++
++Required properties:
++--------------------
++In 'cpus' nodes:
++- operating-points-v2: Phandle to the operating-points-v2 table to use.
++
++In 'operating-points-v2' table:
++- compatible: Should be
++ - 'operating-points-v2-ti' for am335x, am43xx, and dra7xx/am57xx SoCs
++- ti,syscon-efuse: Syscon phandle, offset to efuse register, efuse register
++ mask, and efuse register shift to get the relevant bits
++ that describe OPP availability.
++- ti,syscon-rev: Syscon and offset used to look up revision value on SoC.
++
++Optional properties:
++--------------------
++For each opp entry in 'operating-points-v2' table:
++- opp-supported-hw: Two bitfields indicating:
++ 1. Which revision of the SoC the OPP is supported by
++ 2. Which eFuse bits indicate this OPP is available
++
++ A bitwise AND is performed against these values and if any bit
++ matches, the OPP gets enabled. Not providing the property for an
++ entry indicates that an OPP is always supported.
++
++Example:
++--------
++
++/* From arch/arm/boot/dts/am33xx.dtsi */
++cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ cpu@0 {
++ compatible = "arm,cortex-a8";
++ device_type = "cpu";
++ reg = <0>;
++
++ operating-points-v2 = <&cpu0_opp_table>;
++
++ clocks = <&dpll_mpu_ck>;
++ clock-names = "cpu";
++
++ clock-latency = <300000>; /* From omap-cpufreq driver */
++ };
++};
++
++/*
++ * cpu0 has different OPPs depending on SoC revision and some on revisions
++ * 0x2 and 0x4 have eFuse bits that indicate if they are available or not
++ */
++cpu0_opp_table: opp_table0 {
++ compatible = "operating-points-v2-ti-am3352-cpu";
++ ti,syscon-efuse = <&scm_conf 0x7fc 0x1fff 0>;
++ ti,syscon-rev = <&scm_conf 0x600>;
++
++ /*
++ * The three following nodes are marked with opp-suspend
++ * because they can not be enabled simultaneously on a
++ * single SoC.
++ */
++ opp50@300000000 {
++ opp-hz = /bits/ 64 <300000000>;
++ opp-microvolt = <950000 931000 969000>;
++ opp-supported-hw = <0x06 0x0010>;
++ opp-suspend;
++ };
++
++ opp100@275000000 {
++ opp-hz = /bits/ 64 <275000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x01 0x00FF>;
++ opp-suspend;
++ };
++
++ opp100@300000000 {
++ opp-hz = /bits/ 64 <300000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x06 0x0020>;
++ opp-suspend;
++ };
++
++ opp100@500000000 {
++ opp-hz = /bits/ 64 <500000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x01 0xFFFF>;
++ };
++
++ opp100@600000000 {
++ opp-hz = /bits/ 64 <600000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x06 0x0040>;
++ };
++
++ opp120@600000000 {
++ opp-hz = /bits/ 64 <600000000>;
++ opp-microvolt = <1200000 1176000 1224000>;
++ opp-supported-hw = <0x01 0xFFFF>;
++ };
++
++ opp120@720000000 {
++ opp-hz = /bits/ 64 <720000000>;
++ opp-microvolt = <1200000 1176000 1224000>;
++ opp-supported-hw = <0x06 0x0080>;
++ };
++
++ oppturbo@720000000 {
++ opp-hz = /bits/ 64 <720000000>;
++ opp-microvolt = <1260000 1234800 1285200>;
++ opp-supported-hw = <0x01 0xFFFF>;
++ };
++
++ oppturbo@800000000 {
++ opp-hz = /bits/ 64 <800000000>;
++ opp-microvolt = <1260000 1234800 1285200>;
++ opp-supported-hw = <0x06 0x0100>;
++ };
++
++ oppnitro@1000000000 {
++ opp-hz = /bits/ 64 <1000000000>;
++ opp-microvolt = <1325000 1298500 1351500>;
++ opp-supported-hw = <0x04 0x0200>;
++ };
++};
+diff --git b/Documentation/devicetree/bindings/misc/bone_capemgr.txt b/Documentation/devicetree/bindings/misc/bone_capemgr.txt
+new file mode 100644
+index 0000000..7e4fbc9
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/bone_capemgr.txt
+@@ -0,0 +1,111 @@
++* Beaglebone cape manager driver
++
++Required properties:
++- compatible: "ti,bone-capemgr"
++- eeprom: phandle to the EEPROM baseboard.
++ The EEPROM framework interface is use to obtain the data.
++
++Required children nodes:
++
++- baseboardmaps: Contains nodes, which each of the them defines a mapping from
++ the baseboard EEPROM board-name ID to a DT friendly compatible
++ string.
++
++ - board-name: The baseboard EEPROM board name, i.e. A335BONE for the
++ original beaglebone white.
++ - compatible-name: The DT friendly compatible string to be used for matching
++ compatible capes, i.e. "ti,beaglebone"
++
++
++ - nvmem-cells: Defines the phandles of the nvmem cells of the baseboard and the
++ slots.
++ - nvmem-cells: Defines the names of the nvmem cells. Required to have at
++ least a baseboard cell name.
++
++ - #slots: Defines how many slots are there.
++
++- Example of a beaglebone cape-manager:
++
++bone_capemgr {
++ compatible = "ti,bone-capemgr";
++ status = "okay";
++
++ nvmem-cell = <&baseboard_data
++ &cape0_data &cape1_data &cape2_data &cape3_data>;
++ nvmem-cell-names = "baseboard", "slot0", "slot1", "slot2", "slot3";
++
++ #slots = <4>;
++
++ /* map board revisions to compatible definitions */
++ baseboardmaps {
++ baseboard_beaglebone: board@0 {
++ board-name = "A335BONE";
++ compatible-name = "ti,beaglebone";
++ };
++
++ baseboard_beaglebone_black: board@1 {
++ board-name = "A335BNLT";
++ compatible-name = "ti,beaglebone-black";
++ };
++ };
++};
++
++The format of the cape to be loaded is in a standard overlay format with
++the following root properties that are interpreted by the cape manager:
++
++Required properties:
++ - compatible: Should be compatible to the baseboard according to the
++ baseboard map value, i.e. "ti,beaglebone".
++ - part-numer: Should contain the part-number as stored in the EEPROM.
++ - version: Should contain a list of all the version that are supported
++ by the single cape dtbo, i.e. "00A1".
++
++Optional properties:
++ - exclusive-use: A string list which state the resources this cape requires.
++ No processing or matching to anything regarding the internal
++ kernel state is performed; it's purpose is to guard against
++ conflicts with other capes.
++ - priority: A priority to be assigned when loading a cape. A lower value
++ has higher priority. The purpose of the priority is to control
++ which cape is loaded first in case of a conflict.
++
++- Example of a serial cape:
++
++/dts-v1/;
++/plugin/;
++/ {
++ compatible = "ti,beaglebone", "ti,beaglebone-black";
++
++ /* identification */
++ part-number = "BB-BONE-SERL-03";
++ version = "00A1";
++
++ /* state the resources this cape uses */
++ exclusive-use =
++ /* the pin header uses */
++ "P9.21", /* uart2_txd */
++ "P9.22", /* uart2_rxd */
++ /* the hardware ip uses */
++ "uart2";
++
++ fragment@0 {
++ target = <&am33xx_pinmux>;
++ __overlay__ {
++ bb_uart2_pins: pinmux_bb_uart2_pins {
++ pinctrl-single,pins = <
++ 0x150 0x21 /* spi0_sclk.uart2_rxd | MODE1 */
++ 0x154 0x01 /* spi0_d0.uart2_txd | MODE1 */
++ >;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&uart2>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&bb_uart2_pins>;
++ };
++ };
++};
+diff --git b/Documentation/devicetree/bindings/net/allwinner,sun8i-emac.txt b/Documentation/devicetree/bindings/net/allwinner,sun8i-emac.txt
+new file mode 100644
+index 0000000..4bf4e53
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-emac.txt
+@@ -0,0 +1,65 @@
++* Allwinner sun8i EMAC ethernet controller
++
++Required properties:
++- compatible: "allwinner,sun8i-a83t-emac", "allwinner,sun8i-h3-emac",
++ or "allwinner,sun50i-a64-emac"
++- reg: address and length of the register sets for the device.
++- reg-names: should be "emac" and "syscon", matching the register sets
++- interrupts: interrupt for the device
++- clocks: A phandle to the reference clock for this device
++- clock-names: should be "ahb"
++- resets: A phandle to the reset control for this device
++- reset-names: should be "ahb"
++- phy-mode: See ethernet.txt
++- phy or phy-handle: See ethernet.txt
++- #address-cells: shall be 1
++- #size-cells: shall be 0
++
++"allwinner,sun8i-h3-emac" also requires:
++- clocks: an extra phandle to the reference clock for the EPHY
++- clock-names: an extra "ephy" entry matching the clocks property
++- resets: an extra phandle to the reset control for the EPHY
++- resets-names: an extra "ephy" entry matching the resets property
++
++See ethernet.txt in the same directory for generic bindings for ethernet
++controllers.
++
++The device node referenced by "phy" or "phy-handle" should be a child node
++of this node. See phy.txt for the generic PHY bindings.
++
++Optional properties:
++- phy-supply: phandle to a regulator if the PHY needs one
++- phy-io-supply: phandle to a regulator if the PHY needs a another one for I/O.
++ This is sometimes found with RGMII PHYs, which use a second
++ regulator for the lower I/O voltage.
++- allwinner,tx-delay: The setting of the TX clock delay chain
++- allwinner,rx-delay: The setting of the RX clock delay chain
++
++The TX/RX clock delay chain settings are board specific.
++
++Optional properties for "allwinner,sun8i-h3-emac":
++- allwinner,use-internal-phy: Use the H3 SoC's internal E(thernet) PHY
++- allwinner,leds-active-low: EPHY LEDs are active low
++
++When the internal PHY is requested, the implementation shall configure the
++internal PHY to use the address specified in the child PHY node.
++
++Example:
++
++emac: ethernet@01c0b000 {
++ compatible = "allwinner,sun8i-h3-emac";
++ reg = <0x01c0b000 0x104>, <0x01c00030 0x4>;
++ reg-names = "emac", "syscon";
++ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&bus_gates 17>, <&bus_gates 128>;
++ clock-names = "ahb", "ephy";
++ resets = <&ahb_rst 17>, <&ahb_rst 66>;
++ reset-names = "ahb", "ephy";
++ phy = <&phy1>;
++ allwinner,use-internal-phy;
++ allwinner,leds-active-low;
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++};
+diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt
+index ee91cbd..9f5ca44 100644
+--- a/Documentation/devicetree/bindings/opp/opp.txt
++++ b/Documentation/devicetree/bindings/opp/opp.txt
+@@ -86,8 +86,14 @@ Optional properties:
+ Single entry is for target voltage and three entries are for <target min max>
+ voltages.
+
+- Entries for multiple regulators must be present in the same order as
+- regulators are specified in device's DT node.
++ Entries for multiple regulators shall be provided in the same field separated
++ by angular brackets <>. The OPP binding doesn't provide any provisions to
++ relate the values to their power supplies or the order in which the supplies
++ need to be configured and that is left for the implementation specific
++ binding.
++
++ Entries for all regulators shall be of the same size, i.e. either all use a
++ single value or triplets.
+
+ - opp-microvolt-<name>: Named opp-microvolt property. This is exactly similar to
+ the above opp-microvolt property, but allows multiple voltage ranges to be
+@@ -104,10 +110,13 @@ Optional properties:
+
+ Should only be set if opp-microvolt is set for the OPP.
+
+- Entries for multiple regulators must be present in the same order as
+- regulators are specified in device's DT node. If this property isn't required
+- for few regulators, then this should be marked as zero for them. If it isn't
+- required for any regulator, then this property need not be present.
++ Entries for multiple regulators shall be provided in the same field separated
++ by angular brackets <>. If current values aren't required for a regulator,
++ then it shall be filled with 0. If current values aren't required for any of
++ the regulators, then this field is not required. The OPP binding doesn't
++ provide any provisions to relate the values to their power supplies or the
++ order in which the supplies need to be configured and that is left for the
++ implementation specific binding.
+
+ - opp-microamp-<name>: Named opp-microamp property. Similar to
+ opp-microvolt-<name> property, but for microamp instead.
+@@ -386,10 +395,12 @@ Example 4: Handling multiple regulators
+ / {
+ cpus {
+ cpu@0 {
+- compatible = "arm,cortex-a7";
++ compatible = "vendor,cpu-type";
+ ...
+
+- cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>;
++ vcc0-supply = <&cpu_supply0>;
++ vcc1-supply = <&cpu_supply1>;
++ vcc2-supply = <&cpu_supply2>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+diff --git b/Documentation/devicetree/bindings/pinctrl/ti,iodelay-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ti,iodelay-pinctrl.txt
+new file mode 100644
+index 0000000..e12f4e5
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pinctrl/ti,iodelay-pinctrl.txt
+@@ -0,0 +1,86 @@
++Texas Instruments I/O Delay module configuration pinctrl definition
++
++Used in conjunction with Documentation/devicetree/bindings/pinctrl/ti,omap-pinctrl.txt
++
++Required Properties:
++- compatible: Should be:
++ "ti,dra7-iodelay" - I/O delay configuration for DRA7
++- reg - must be the register address range of IODelay module
++- #address-cells = <1>;
++- #size-cells = <0>;
++
++Important note: Use of "ti,dra7-iodelay" compatible definition need to be
++carefully evaluated due to the expectation of glitch during configuration.
++
++Example:
++
++dra7_iodelay_core: padconf@4844a000 {
++ compatible = "ti,dra7-iodelay";
++ reg = <0x4844a000 0x0d1c>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++};
++
++Configuration definition follows similar model as the pinctrl-single:
++The groups of pin configuration are defined under "pinctrl-single,pins"
++
++&dra7_iodelay_core {
++ mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf {
++ pinctrl-single,pins = <
++ 0x18c (A_DELAY(0) | G_DELAY(120)) /* CFG_GPMC_A19_IN */
++ 0x1a4 (A_DELAY(265) | G_DELAY(360)) /* CFG_GPMC_A20_IN */
++ 0x1b0 (A_DELAY(0) | G_DELAY(120)) /* CFG_GPMC_A21_IN */
++ 0x1bc (A_DELAY(0) | G_DELAY(120)) /* CFG_GPMC_A22_IN */
++ 0x1c8 (A_DELAY(287) | G_DELAY(420)) /* CFG_GPMC_A23_IN */
++ 0x1d4 (A_DELAY(144) | G_DELAY(240)) /* CFG_GPMC_A24_IN */
++ 0x1e0 (A_DELAY(0) | G_DELAY(0)) /* CFG_GPMC_A25_IN */
++ 0x1ec (A_DELAY(120) | G_DELAY(0)) /* CFG_GPMC_A26_IN */
++ 0x1f8 (A_DELAY(120) | G_DELAY(180)) /* CFG_GPMC_A27_IN */
++ 0x360 (A_DELAY(0) | G_DELAY(0)) /* CFG_GPMC_CS1_IN */
++ >;
++ };
++};
++
++Usage in conjunction with pinctrl single:
++
++For a complete description of the pins both the regular muxing as well as the
++iodelay configuration is necessary. For example:
++
++&dra7_pmx_core {
++ mmc2_pins_default: mmc2_pins_default {
++ pinctrl-single,pins = <
++ 0x9c (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a23.mmc2_clk */
++ 0xb0 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
++ 0xa0 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
++ 0xa4 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
++ 0xa8 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
++ 0xac (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
++ 0x8c (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
++ 0x90 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
++ 0x94 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
++ 0x98 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
++ >;
++ };
++};
++
++&dra7_iodelay_core {
++ mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf {
++ pinctrl-single,pins = <
++ 0x18c (A_DELAY(0) | G_DELAY(120)) /* CFG_GPMC_A19_IN */
++ 0x1a4 (A_DELAY(265) | G_DELAY(360)) /* CFG_GPMC_A20_IN */
++ 0x1b0 (A_DELAY(0) | G_DELAY(120)) /* CFG_GPMC_A21_IN */
++ 0x1bc (A_DELAY(0) | G_DELAY(120)) /* CFG_GPMC_A22_IN */
++ 0x1c8 (A_DELAY(287) | G_DELAY(420)) /* CFG_GPMC_A23_IN */
++ 0x1d4 (A_DELAY(144) | G_DELAY(240)) /* CFG_GPMC_A24_IN */
++ 0x1e0 (A_DELAY(0) | G_DELAY(0)) /* CFG_GPMC_A25_IN */
++ 0x1ec (A_DELAY(120) | G_DELAY(0)) /* CFG_GPMC_A26_IN */
++ 0x1f8 (A_DELAY(120) | G_DELAY(180)) /* CFG_GPMC_A27_IN */
++ 0x360 (A_DELAY(0) | G_DELAY(0)) /* CFG_GPMC_CS1_IN */
++ >;
++ };
++};
++
++&mmc2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&mmc2_pins_default &mmc2_iodelay_3v3_conf>;
++};
+diff --git b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
+new file mode 100644
+index 0000000..ebf0d47
+--- /dev/null
++++ b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
+@@ -0,0 +1,48 @@
++The generic power sequence library
++
++Some hard-wired devices (eg USB/MMC) need to do power sequence before
++the device can be enumerated on the bus, the typical power sequence
++like: enable USB PHY clock, toggle reset pin, etc. But current
++Linux device driver lacks of such code to do it, it may cause some
++hard-wired devices works abnormal or can't be recognized by
++controller at all. The power sequence will be done before this device
++can be found at the bus.
++
++The power sequence properties is under the device node.
++
++Optional properties:
++- clocks: the input clocks for device.
++- reset-gpios: Should specify the GPIO for reset.
++- reset-duration-us: the duration in microsecond for assert reset signal.
++
++Below is the example of USB power sequence properties on USB device
++nodes which have two level USB hubs.
++
++&usbotg1 {
++ vbus-supply = <&reg_usb_otg1_vbus>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usb_otg1_id>;
++ status = "okay";
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ genesys: hub@1 {
++ compatible = "usb5e3,608";
++ reg = <1>;
++
++ clocks = <&clks IMX6SX_CLK_CKO>;
++ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
++ reset-duration-us = <10>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ asix: ethernet@1 {
++ compatible = "usbb95,1708";
++ reg = <1>;
++
++ clocks = <&clks IMX6SX_CLK_IPG>;
++ reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
++ reset-duration-us = <15>;
++ };
++ };
++};
+diff --git a/Documentation/devicetree/bindings/usb/usb-device.txt b/Documentation/devicetree/bindings/usb/usb-device.txt
+index 1c35e7b..3661dd2 100644
+--- a/Documentation/devicetree/bindings/usb/usb-device.txt
++++ b/Documentation/devicetree/bindings/usb/usb-device.txt
+@@ -13,6 +13,10 @@ Required properties:
+ - reg: the port number which this device is connecting to, the range
+ is 1-31.
+
++Optional properties:
++power sequence properties, see
++Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt for detail
++
+ Example:
+
+ &usb1 {
+@@ -21,8 +25,12 @@ Example:
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+- hub: genesys@1 {
++ genesys: hub@1 {
+ compatible = "usb5e3,608";
+ reg = <1>;
++
++ clocks = <&clks IMX6SX_CLK_CKO>;
++ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
++ reset-duration-us = <10>;
+ };
+ }
+diff --git b/Documentation/devicetree/configfs-overlays.txt b/Documentation/devicetree/configfs-overlays.txt
+new file mode 100644
+index 0000000..5fa43e0
+--- /dev/null
++++ b/Documentation/devicetree/configfs-overlays.txt
+@@ -0,0 +1,31 @@
++Howto use the configfs overlay interface.
++
++A device-tree configfs entry is created in /config/device-tree/overlays
++and and it is manipulated using standard file system I/O.
++Note that this is a debug level interface, for use by developers and
++not necessarily something accessed by normal users due to the
++security implications of having direct access to the kernel's device tree.
++
++* To create an overlay you mkdir the directory:
++
++ # mkdir /config/device-tree/overlays/foo
++
++* Either you echo the overlay firmware file to the path property file.
++
++ # echo foo.dtbo >/config/device-tree/overlays/foo/path
++
++* Or you cat the contents of the overlay to the dtbo file
++
++ # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
++
++The overlay file will be applied, and devices will be created/destroyed
++as required.
++
++To remove it simply rmdir the directory.
++
++ # rmdir /config/device-tree/overlays/foo
++
++The rationalle of the dual interface (firmware & direct copy) is that each is
++better suited to different use patterns. The firmware interface is what's
++intended to be used by hardware managers in the kernel, while the copy interface
++make sense for developers (since it avoids problems with namespaces).
+diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
+index d418a6c..3e8df30 100644
+--- a/Documentation/devicetree/overlay-notes.txt
++++ b/Documentation/devicetree/overlay-notes.txt
+@@ -100,6 +100,14 @@ Finally, if you need to remove all overlays in one-go, just call
+ of_overlay_destroy_all() which will remove every single one in the correct
+ order.
+
++If your board has multiple slots/places where a single overlay can work
++and each slot is defined by a node, you can use the
++of_overlay_create_target_index() method to select the target.
++
++For overlays on probeable busses, use the of_overlay_create_target_root() method
++in which you supply a device node as a target root, and which all target
++references in the overlay are performed relative to that node.
++
+ Overlay DTS Format
+ ------------------
+
+@@ -110,9 +118,11 @@ The DTS of an overlay should have the following format:
+
+ fragment@0 { /* first child node */
+
+- target=<phandle>; /* phandle target of the overlay */
++ /* phandle target of the overlay */
++ target=<phandle> [, <phandle>, ...];
+ or
+- target-path="/path"; /* target path of the overlay */
++ /* target path of the overlay */
++ target-path="/path" [ , "/path", ...];
+
+ __overlay__ {
+ property-a; /* add property-a to the target */
+@@ -131,3 +141,11 @@ Using the non-phandle based target method allows one to use a base DT which does
+ not contain a __symbols__ node, i.e. it was not compiled with the -@ option.
+ The __symbols__ node is only required for the target=<phandle> method, since it
+ contains the information required to map from a phandle to a tree location.
++
++Using a target index requires the use of a selector target on the call to
++of_overlay_create_target_index(). I.e. passing an index of 0 will select the
++target in the foo node, an index of 1 the bar node, etc.
++
++Note that when using the target root create method all target references must
++lie under the target root node. I.e. the overlay is not allowed to 'break' out
++of the root.
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 86a6746..b093a38 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -121,6 +121,7 @@ parameter is applicable:
+ NET Appropriate network support is enabled.
+ NUMA NUMA support is enabled.
+ NFS Appropriate NFS support is enabled.
++ OF Open Firmware support (device tree) is enabled.
+ OSS OSS sound support is enabled.
+ PV_OPS A paravirtualized kernel is enabled.
+ PARIDE The ParIDE (parallel port IDE) subsystem is enabled.
+@@ -2872,6 +2873,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ This can be set from sysctl after boot.
+ See Documentation/sysctl/vm.txt for details.
+
++ of_overlay_disable [OF] Disable device tree overlays at boot time.
++
+ ohci1394_dma=early [HW] enable debugging via the ohci1394 driver.
+ See Documentation/debugging-via-ohci1394.txt for more
+ info.
+diff --git b/Documentation/misc-devices/bone_capemgr.txt b/Documentation/misc-devices/bone_capemgr.txt
+new file mode 100644
+index 0000000..2a8c766
+--- /dev/null
++++ b/Documentation/misc-devices/bone_capemgr.txt
+@@ -0,0 +1,63 @@
++---------------------------
++ Beaglebone Cape-Manager
++---------------------------
++
++The beaglebone cape manager driver allows the automatic use of external
++peripheral capes to be automatically supported by Linux without any manual
++setup required by the user.
++
++Each beaglebone cape should contain an EEPROM that describes
++it in a fixed I2C address on the i2c2 bus of the baseboard.
++The format of the EEPROM is defined in the beaglebone reference
++manual at:
++http://beagleboard.org/static/beaglebone/latest/Docs/Hardware/BONE_SRM.pdf
++
++Reading the part number and revision information the manager
++requests a firmware file formatted as a device tree overlay blob.
++
++Applying the overlay the devices are instantiated and the cape is
++ready to be used.
++
++For instance if the part-number is BB-BONE-SERL-03 and the version is 00A1
++the firmware file requested will be BB-BONE-SERL-03-00A1-00A1.dtbo
++It will be located by the in-kernel firmware
++loader in the usual place, i.e. /lib/firmware/`uname -r`, /lib/firmware etc.
++
++The driver supports the following parameters (either as part of the kernel
++command line or supplied at module insertion time).
++
++disable_partno: A comma delimited list of PART-NUMBER[:REV] of
++ disabled capes.
++enable_partno: A comma delimited list of PART-NUMBER[:REV[:PRIO]] of
++ enabled capes.
++boot_scan_period: The boot scan period in ms. When the cape manager is built-in
++ the kernel image, the firmware loader cannot find the files
++ before the rootfs is mounted. This parameter controls the
++ period with which the boot state is checked in that case.
++
++There's a sysfs control interface which is defined at the ABI documentation
++area.
++
++Theory of operation:
++--------------------
++
++On driver probe the I2C EEPROM of the baseboard is read and information about
++the current baseboard is retrieved. This information includes the mapping from
++baseboard board name to DT friendly compatible string. I.e. the "A335BONE" board
++name from EEPROM is mapped to the "ti,beaglebone" compatible string which should
++be present in the dtbo to be loaded.
++
++Afterwards the EEPROMs declared in each slot are probed, and the EEPROMs found
++are decoded keeping track the cape part-number and version data.
++
++Using the part-number and version a firmware file is requested (the firmware
++file requested is <part-number>-<version>.dtbo).
++
++The dtbo is unflattend and the resulting device tree is matched against a
++compatible baseboard, and in case of multiple parallel loading capes the
++priorities defined are honored. That means that when there are multiple capes
++being loaded in parallel the ones with the lowest priority number are loaded
++first.
++
++Applying the device tree overlay makes the cape operational, as if it was part
++of the kernel's booting device tree.
+diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
+index 5962949..d1ba882 100644
+--- a/Documentation/printk-formats.txt
++++ b/Documentation/printk-formats.txt
+@@ -324,10 +324,49 @@ Network device features:
+
+ Passed by reference.
+
++Command from struct task_struct
++
++ %pT ls
++
++ For printing executable name excluding path from struct
++ task_struct.
++
++ Passed by reference.
++
++Device tree nodes:
++
++ %pO[fnpPcCFr]
++
++ For printing device tree nodes. The optional arguments are:
++ f device node full_name
++ n device node name
++ p device node phandle
++ P device node path spec (name + @unit)
++ F device node flags
++ c major compatible string
++ C full compatible string
++ r node reference count
++ Without any arguments prints full_name (same as %pOf)
++ The separator when using multiple arguments is '|'
++
++ Examples:
++
++ %pO /foo/bar@0 - Node full name
++ %pOf /foo/bar@0 - Same as above
++ %pOfp /foo/bar@0|10 - Node full name + phandle
++ %pOfcF /foo/bar@0|foo,device|--P- - Node full name +
++ major compatible string +
++ node flags
++ D - dynamic
++ d - detached
++ P - Populated
++ B - Populated bus
++
++ Passed by reference
++
+ If you add other %p extensions, please extend lib/test_printf.c with
+ one or more test cases, if at all feasible.
+
+-
+ Thank you for your cooperation and attention.
+
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 63cefa6..d49fd46 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -597,6 +597,12 @@ S: Maintained
+ F: Documentation/i2c/busses/i2c-ali1563
+ F: drivers/i2c/busses/i2c-ali1563.c
+
++ALLWINNER SUN8I-EMAC ETHERNET DRIVER
++M: Corentin Labbe <clabbe.montjoie@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/allwinner/sun8i-emac.c
++
+ ALLWINNER SECURITY SYSTEM
+ M: Corentin Labbe <clabbe.montjoie@gmail.com>
+ L: linux-crypto@vger.kernel.org
+@@ -2401,6 +2407,14 @@ W: https://linuxtv.org
+ S: Supported
+ F: drivers/media/platform/sti/bdisp
+
++BEAGLEBONE CAPEMANAGER
++M: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++S: Maintained
++F: drivers/misc/beaglebone-capemgr.c
++F: Documentation/misc-devices/bone_capemgr.txt
++F: Documentation/devicetree/bindings/misc/bone_capemgr.txt
++F: Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
++
+ BEFS FILE SYSTEM
+ M: Luis de Bethencourt <luisbg@osg.samsung.com>
+ M: Salah Triki <salah.triki@gmail.com>
+@@ -9635,6 +9649,15 @@ F: include/linux/pm_*
+ F: include/linux/powercap.h
+ F: drivers/powercap/
+
++POWER SEQUENCE LIBRARY
++M: Peter Chen <Peter.Chen@nxp.com>
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/power/pwrseq/
++F: drivers/power/pwrseq/
++F: include/linux/power/pwrseq.h/
++
+ POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
+ M: Sebastian Reichel <sre@kernel.org>
+ L: linux-pm@vger.kernel.org
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index b5d529f..ced2e08 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1496,8 +1496,7 @@ source kernel/Kconfig.preempt
+
+ config HZ_FIXED
+ int
+- default 200 if ARCH_EBSA110 || ARCH_S3C24XX || \
+- ARCH_S5PV210 || ARCH_EXYNOS4
++ default 200 if ARCH_EBSA110
+ default 128 if SOC_AT91RM9200
+ default 0
+
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 6be9ee1..6deeab7 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -13,7 +13,12 @@
+ # Ensure linker flags are correct
+ LDFLAGS :=
+
+-LDFLAGS_vmlinux :=-p --no-undefined -X --pic-veneer
++GCCVERSIONISGTE5 := $(shell expr `$(HOSTCC) -dumpversion | cut -f1 -d.` \>= 5)
++ifeq "$(GCCVERSIONISGTE5)" "1"
++LDFLAGS_vmlinux :=-p --no-undefined -X
++else
++LDFLAGS_vmlinux :=-p --no-undefined -X --pic-veneer
++endif
+ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+ LDFLAGS_vmlinux += --be8
+ LDFLAGS_MODULE += --be8
+diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
+index 50f8d1b..2c30c44 100644
+--- a/arch/arm/boot/Makefile
++++ b/arch/arm/boot/Makefile
+@@ -29,6 +29,10 @@ export ZRELADDR INITRD_PHYS PARAMS_PHYS
+
+ targets := Image zImage xipImage bootpImage uImage
+
++ifeq ($(CONFIG_OF_OVERLAY),y)
++DTC_FLAGS += -@
++endif
++
+ ifeq ($(CONFIG_XIP_KERNEL),y)
+
+ $(obj)/xipImage: vmlinux FORCE
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index 7037201..aabd736 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -1,11 +1,17 @@
+ ifeq ($(CONFIG_OF),y)
+
++ifeq ($(CONFIG_OF_OVERLAY),y)
++DTC_FLAGS += -@
++endif
++
+ dtb-$(CONFIG_ARCH_ALPINE) += \
+ alpine-db.dtb
+ dtb-$(CONFIG_MACH_ARTPEC6) += \
+ artpec6-devboard.dtb
++
+ dtb-$(CONFIG_MACH_ASM9260) += \
+ alphascale-asm9260-devkit.dtb
++
+ # Keep at91 dtb files sorted alphabetically for each SoC
+ dtb-$(CONFIG_SOC_AT91RM9200) += \
+ at91rm9200ek.dtb \
+@@ -155,6 +161,7 @@ dtb-$(CONFIG_ARCH_EXYNOS5) += \
+ exynos5420-arndale-octa.dtb \
+ exynos5420-peach-pit.dtb \
+ exynos5420-smdk5420.dtb \
++ exynos5422-artik10-eval.dtb \
+ exynos5422-odroidxu3.dtb \
+ exynos5422-odroidxu3-lite.dtb \
+ exynos5422-odroidxu4.dtb \
+@@ -366,6 +373,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
+ imx6q-b650v3.dtb \
+ imx6q-b850v3.dtb \
+ imx6q-cm-fx6.dtb \
++ imx6q-ccimx6sbc.dtb \
+ imx6q-cubox-i.dtb \
+ imx6q-dfi-fs700-m60.dtb \
+ imx6q-dmo-edmqmx6.dtb \
+@@ -419,6 +427,7 @@ dtb-$(CONFIG_SOC_IMX6SX) += \
+ imx6sx-sdb.dtb
+ dtb-$(CONFIG_SOC_IMX6UL) += \
+ imx6ul-14x14-evk.dtb \
++ imx6ul-14x14-evk-ism43362-b81-evb.dtb \
+ imx6ul-geam-kit.dtb \
+ imx6ul-pico-hobbit.dtb \
+ imx6ul-tx6ul-0010.dtb \
+@@ -548,6 +557,28 @@ dtb-$(CONFIG_SOC_AM33XX) += \
+ am335x-base0033.dtb \
+ am335x-bone.dtb \
+ am335x-boneblack.dtb \
++ am335x-boneblack-uboot.dtb \
++ am335x-sancloud-bbe.dtb \
++ am335x-boneblack-wireless-roboticscape.dtb \
++ am335x-boneblack-roboticscape.dtb \
++ am335x-boneblue.dtb \
++ am335x-boneblack-wireless-emmc-overlay.dtb \
++ am335x-boneblack-wireless.dtb \
++ am335x-bonegreen-wireless.dtb \
++ am335x-boneblack-audio.dtb \
++ am335x-boneblack-bbb-exp-r.dtb \
++ am335x-boneblack-bbb-exp-c.dtb \
++ am335x-boneblack-bbbmini.dtb \
++ am335x-boneblack-wl1835mod.dtb \
++ am335x-boneblack-cape-bone-argus.dtb \
++ am335x-bone-cape-bone-argus.dtb \
++ am335x-olimex-som.dtb \
++ am335x-abbbi.dtb \
++ am335x-bonegreen-overlay.dtb \
++ am335x-boneblack-overlay.dtb \
++ am335x-boneblack-nhdmi-overlay.dtb \
++ am335x-boneblack-hdmi-overlay.dtb \
++ am335x-boneblack-emmc-overlay.dtb \
+ am335x-bonegreen.dtb \
+ am335x-chiliboard.dtb \
+ am335x-cm-t335.dtb \
+@@ -567,6 +598,7 @@ dtb-$(CONFIG_ARCH_OMAP4) += \
+ omap4-panda.dtb \
+ omap4-panda-a4.dtb \
+ omap4-panda-es.dtb \
++ omap4-panda-es-b3.dtb \
+ omap4-sdp.dtb \
+ omap4-sdp-es23plus.dtb \
+ omap4-var-dvk-om44.dtb \
+diff --git b/arch/arm/boot/dts/am335x-abbbi.dts b/arch/arm/boot/dts/am335x-abbbi.dts
+new file mode 100644
+index 0000000..43efead
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-abbbi.dts
+@@ -0,0 +1,163 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ * Copyright 2015 Konsulko Group
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++
++
++/ {
++ model = "Arrow BeagleBone Black Industrial";
++ compatible = "arrow,am335x-abbbi", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&am33xx_pinmux {
++ adi_hdmi_bbbi_pins: adi_hdmi_bbbi_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++ adi_hdmi_bbbi_off_pins: adi_hdmi_bbbi_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++
++ mcasp0_pins: mcasp0_pins {
++ pinctrl-single,pins = <
++ 0x1ac (PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahclkx.mcasp0_ahclkx */
++ 0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2 */
++ 0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
++ 0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
++ 0x06c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
++ >;
++ };
++
++ mcasp0_pins_sleep: mcasp0_pins_sleep {
++ pinctrl-single,pins = <
++ 0x1ac (PIN_INPUT_PULLDOWN | MUX_MODE7) /* mcasp0_ahclkx.mcasp0_ahclkx */
++ 0x19c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* mcasp0_ahclkr.mcasp0_axr2 */
++ 0x194 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* mcasp0_fsx.mcasp0_fsx */
++ 0x190 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* mcasp0_aclkx.mcasp0_aclkx */
++ 0x06c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
++ >;
++ };
++};
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&i2c0 {
++ adv7511w {
++ compatible = "adi,adv7511w";
++ reg = <0x39>;
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&adi_hdmi_bbbi_pins>;
++ pinctrl-1 = <&adi_hdmi_bbbi_off_pins>;
++
++ port {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++};
++
++&mcasp0 {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&mcasp0_pins>;
++ pinctrl-1 = <&mcasp0_pins_sleep>;
++ status = "okay";
++ op-mode = <0>; /* MCASP_IIS_MODE */
++ tdm-slots = <2>;
++ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
++ 0 0 1 0
++ >;
++ tx-num-evt = <1>;
++ rx-num-evt = <1>;
++};
++
++/ {
++ clk_mcasp0_fixed: clk_mcasp0_fixed {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <24576000>;
++ };
++
++ clk_mcasp0: clk_mcasp0 {
++ #clock-cells = <0>;
++ compatible = "gpio-gate-clock";
++ clocks = <&clk_mcasp0_fixed>;
++ enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
++ };
++
++ hdmi_audio: hdmi_audio@0 {
++ compatible = "linux,hdmi-audio";
++ status = "okay";
++ };
++
++ sound {
++ compatible = "ti,beaglebone-black-audio";
++ ti,model = "TI BeagleBone Black";
++ ti,audio-codec = <&hdmi_audio>;
++ ti,mcasp-controller = <&mcasp0>;
++ ti,audio-routing =
++ "HDMI Out", "TX";
++ clocks = <&clk_mcasp0>;
++ clock-names = "mclk";
++ };
++};
++
++&rtc {
++ system-power-controller;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-argus.dtsi b/arch/arm/boot/dts/am335x-bone-argus.dtsi
+new file mode 100644
+index 0000000..21afad3
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-argus.dtsi
+@@ -0,0 +1,109 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++
++/ {
++ ocp {
++ P8_07_pinmux {
++ /* gpio2[2] */
++ status = "disabled";
++ };
++ P8_08_pinmux {
++ /* gpio2[3] */
++ status = "disabled";
++ };
++ P8_09_pinmux {
++ /* gpio2[5] */
++ status = "disabled";
++ };
++ P8_10_pinmux {
++ /* gpio2[4] */
++ status = "disabled";
++ };
++ P9_11_pinmux {
++ /* gpio0[30] */
++ status = "disabled";
++ };
++ P9_17_pinmux {
++ /* gpio0[5] */
++ status = "disabled";
++ };
++ P9_18_pinmux {
++ /* gpio0[4] */
++ status = "disabled";
++ };
++ P9_41_pinmux {
++ /* gpio0[20] */
++ status = "disabled";
++ };
++ P9_42_pinmux {
++ /* gpio0[7] */
++ status = "disabled";
++ };
++ };
++};
++
++/ {
++ argus-ups {
++ compatible = "argus-ups";
++ status = "okay";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&argus_ups_pins>; /* Refer to previous label */
++ /* This section communicates the gpio numbers to the driver module */
++ /* Note that gpio controllers appear to be numbered from 1-n here rather than 0-(n-1)????? */
++ gpios = <&gpio0 30 0>, /* Request */
++ <&gpio0 5 0>, /* Acknowledge */
++ <&gpio0 4 0>, /* Watchdog */
++ <&gpio2 2 0>, /* LED 1 Green */
++ <&gpio2 3 0>, /* LED 1 Red */
++ <&gpio2 5 0>, /* LED 2 Green */
++ <&gpio2 4 0>, /* LED 2 Red */
++ <&gpio0 20 0>, /* General Output #1 */
++ <&gpio0 7 0>; /* General Output #2 */
++ debug = <1>;
++ shutdown = <1>;
++ };
++};
++
++&am33xx_pinmux {
++ argus_ups_pins: pinmux_argus_ups_pins { /* Set up pinmux */
++ pinctrl-single,pins = <
++ 0x070 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_wait0.gpio0_30 */
++ 0x15c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* spi0_cs0.gpio0_5 */
++ 0x158 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* spi0_d1.gpio0_4 */
++ 0x090 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_advn_ale.gpio_2 */
++ 0x094 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_oen_ren.gpio2_3 */
++ 0x09c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_ben0_cle.gpio2_5 */
++ 0x098 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_gpmc_wen.gpio2_4 */
++ 0x1b4 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* xdma_event_intr1.gpio0_20 */
++ 0x164 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* ecap0_in_pwm0_out.gpio0_7 */
++ >;
++ };
++
++ i2c2_pins: pinmux_i2c2_pins {
++ pinctrl-single,pins = <
++ BONE_P9_20 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_ctsn.i2c2_sda */
++ BONE_P9_19 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_rtsn.i2c2_scl */
++ >;
++ };
++};
++
++&i2c2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c2_pins>;
++
++ status = "okay";
++ clock-frequency = <100000>;
++
++ rtc@68 {
++ compatible = "maxim,ds1307";
++ reg = <0x68>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-cape-bone-argus.dts b/arch/arm/boot/dts/am335x-bone-cape-bone-argus.dts
+new file mode 100644
+index 0000000..82218f5
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-cape-bone-argus.dts
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone";
++ compatible = "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&ldo3_reg>;
++};
++
++#include "am335x-bone-argus.dtsi"
+diff --git b/arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi b/arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi
+new file mode 100644
+index 0000000..56b9ccf
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi
+@@ -0,0 +1,362 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/mfd/tps65217.h>
++
++/ {
++ cpus {
++ cpu@0 {
++ cpu0-supply = <&dcdc2_reg>;
++ };
++ };
++
++ memory@80000000 {
++ device_type = "memory";
++ reg = <0x80000000 0x10000000>; /* 256 MB */
++ };
++
++ chosen {
++ stdout-path = &uart0;
++ };
++
++ leds {
++ pinctrl-names = "default";
++ pinctrl-0 = <&user_leds_s0>;
++
++ compatible = "gpio-leds";
++
++ led2 {
++ label = "beaglebone:green:usr0";
++ gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "heartbeat";
++ default-state = "off";
++ };
++
++ led3 {
++ label = "beaglebone:green:usr1";
++ gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "mmc0";
++ default-state = "off";
++ };
++
++ led4 {
++ label = "beaglebone:green:usr2";
++ gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "cpu0";
++ default-state = "off";
++ };
++
++ led5 {
++ label = "beaglebone:green:usr3";
++ gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "mmc1";
++ default-state = "off";
++ };
++ };
++
++ vmmcsd_fixed: fixedregulator0 {
++ compatible = "regulator-fixed";
++ regulator-name = "vmmcsd_fixed";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++};
++
++&am33xx_pinmux {
++ user_leds_s0: user_leds_s0 {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
++ AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
++ AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
++ AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
++ >;
++ };
++
++ i2c0_pins: pinmux_i2c0_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
++ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
++ >;
++ };
++
++ i2c2_pins: pinmux_i2c2_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_ctsn.i2c2_sda */
++ AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_rtsn.i2c2_scl */
++ >;
++ };
++
++ uart0_pins: pinmux_uart0_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
++ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
++ >;
++ };
++
++ cpsw_default: cpsw_default {
++ pinctrl-single,pins = <
++ /* Slave 1 */
++ 0x108 (PIN_INPUT | MUX_MODE0) /* mii1_col.mii1_col */
++ 0x10c (PIN_INPUT | MUX_MODE0) /* mii1_crs.mii1_crs */
++ AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
++ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
++ AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
++ AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
++ AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
++ AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
++ AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
++ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_txclk.mii1_txclk */
++ AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxclk.mii1_rxclk */
++ AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd3.mii1_rxd3 */
++ AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd2.mii1_rxd2 */
++ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd1.mii1_rxd1 */
++ AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd0.mii1_rxd0 */
++ >;
++ };
++
++ cpsw_sleep: cpsw_sleep {
++ pinctrl-single,pins = <
++ /* Slave 1 reset value */
++ 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ davinci_mdio_default: davinci_mdio_default {
++ pinctrl-single,pins = <
++ /* MDIO */
++ AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
++ AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
++ >;
++ };
++
++ davinci_mdio_sleep: davinci_mdio_sleep {
++ pinctrl-single,pins = <
++ /* MDIO reset value */
++ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ mmc1_pins: pinmux_mmc1_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* GPIO0_6 */
++ >;
++ };
++
++ emmc_pins: pinmux_emmc_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
++ AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
++ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
++ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
++ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
++ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
++ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
++ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
++ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
++ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
++ >;
++ };
++};
++
++&uart0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins>;
++
++ status = "okay";
++};
++
++&usb {
++ status = "okay";
++};
++
++&usb_ctrl_mod {
++ status = "okay";
++};
++
++&usb0_phy {
++ status = "okay";
++};
++
++&usb1_phy {
++ status = "okay";
++};
++
++&usb0 {
++ status = "okay";
++ dr_mode = "peripheral";
++};
++
++&usb1 {
++ status = "okay";
++ dr_mode = "host";
++};
++
++&cppi41dma {
++ status = "okay";
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++
++ status = "okay";
++ clock-frequency = <400000>;
++
++ tps: tps@24 {
++ reg = <0x24>;
++ };
++
++ baseboard_eeprom: baseboard_eeprom@50 {
++ compatible = "at,24c256";
++ reg = <0x50>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++ baseboard_data: baseboard_data@0 {
++ reg = <0 0x100>;
++ };
++ };
++};
++
++/include/ "tps65217.dtsi"
++
++&tps {
++ /*
++ * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
++ * mode") at poweroff. Most BeagleBone versions do not support RTC-only
++ * mode and risk hardware damage if this mode is entered.
++ *
++ * For details, see linux-omap mailing list May 2015 thread
++ * [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
++ * In particular, messages:
++ * http://www.spinics.net/lists/linux-omap/msg118585.html
++ * http://www.spinics.net/lists/linux-omap/msg118615.html
++ *
++ * You can override this later with
++ * &tps { /delete-property/ ti,pmic-shutdown-controller; }
++ * if you want to use RTC-only mode and made sure you are not affected
++ * by the hardware problems. (Tip: double-check by performing a current
++ * measurement after shutdown: it should be less than 1 mA.)
++ */
++
++ interrupts = <7>; /* NMI */
++ interrupt-parent = <&intc>;
++
++ ti,pmic-shutdown-controller;
++
++ charger {
++ interrupts = <TPS65217_IRQ_AC>, <TPS65217_IRQ_USB>;
++ interrupts-names = "AC", "USB";
++ status = "okay";
++ };
++
++ pwrbutton {
++ interrupts = <TPS65217_IRQ_PB>;
++ status = "okay";
++ };
++
++ regulators {
++ dcdc1_reg: regulator@0 {
++ regulator-name = "vdds_dpr";
++ regulator-always-on;
++ };
++
++ dcdc2_reg: regulator@1 {
++ /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
++ regulator-name = "vdd_mpu";
++ regulator-min-microvolt = <925000>;
++ regulator-max-microvolt = <1351500>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ dcdc3_reg: regulator@2 {
++ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
++ regulator-name = "vdd_core";
++ regulator-min-microvolt = <925000>;
++ regulator-max-microvolt = <1150000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo1_reg: regulator@3 {
++ regulator-name = "vio,vrtc,vdds";
++ regulator-always-on;
++ };
++
++ ldo2_reg: regulator@4 {
++ regulator-name = "vdd_3v3aux";
++ regulator-always-on;
++ };
++
++ ldo3_reg: regulator@5 {
++ regulator-name = "vdd_1v8";
++ regulator-always-on;
++ };
++
++ ldo4_reg: regulator@6 {
++ regulator-name = "vdd_3v3a";
++ regulator-always-on;
++ };
++ };
++};
++
++&cpsw_emac0 {
++ phy_id = <&davinci_mdio>, <0>;
++ phy-mode = "mii";
++};
++
++&mac {
++ slaves = <1>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&cpsw_default>;
++ pinctrl-1 = <&cpsw_sleep>;
++ status = "okay";
++};
++
++&davinci_mdio {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&davinci_mdio_default>;
++ pinctrl-1 = <&davinci_mdio_sleep>;
++ status = "okay";
++};
++
++&mmc1 {
++ status = "okay";
++ bus-width = <0x4>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&mmc1_pins>;
++ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
++};
++
++&aes {
++ status = "okay";
++};
++
++&sham {
++ status = "okay";
++};
++
++&rtc {
++ system-power-controller;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-common-universal-pins.dtsi b/arch/arm/boot/dts/am335x-bone-common-universal-pins.dtsi
+new file mode 100644
+index 0000000..e4d4971
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-common-universal-pins.dtsi
+@@ -0,0 +1,941 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&am33xx_pinmux {
++ /************************/
++ /* P8 Header */
++ /************************/
++
++ /* P8_01 GND */
++ /* P8_02 GND */
++ /* P8_03 (ZCZ ball R9 ) emmc */
++ /* P8_04 (ZCZ ball T9 ) emmc */
++ /* P8_05 (ZCZ ball R8 ) emmc */
++ /* P8_06 (ZCZ ball T8 ) emmc */
++
++ /* P8_07 (ZCZ ball R7 ) */
++ P8_07_default_pin: pinmux_P8_07_default_pin {
++ pinctrl-single,pins = <0x090 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_07_gpio_pin: pinmux_P8_07_gpio_pin {
++ pinctrl-single,pins = <0x090 0x2F>; }; /* Mode 7, RxActive */
++ P8_07_gpio_pu_pin: pinmux_P8_07_gpio_pu_pin {
++ pinctrl-single,pins = <0x090 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_07_gpio_pd_pin: pinmux_P8_07_gpio_pd_pin {
++ pinctrl-single,pins = <0x090 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_07_timer_pin: pinmux_P8_07_timer_pin {
++ pinctrl-single,pins = <0x090 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_08 (ZCZ ball T7 ) */
++ P8_08_default_pin: pinmux_P8_08_default_pin {
++ pinctrl-single,pins = <0x094 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_08_gpio_pin: pinmux_P8_08_gpio_pin {
++ pinctrl-single,pins = <0x094 0x2F>; }; /* Mode 7, RxActive */
++ P8_08_gpio_pu_pin: pinmux_P8_08_gpio_pu_pin {
++ pinctrl-single,pins = <0x094 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_08_gpio_pd_pin: pinmux_P8_08_gpio_pd_pin {
++ pinctrl-single,pins = <0x094 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_08_timer_pin: pinmux_P8_08_timer_pin {
++ pinctrl-single,pins = <0x094 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_09 (ZCZ ball T6 ) */
++ P8_09_default_pin: pinmux_P8_09_default_pin {
++ pinctrl-single,pins = <0x09c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_09_gpio_pin: pinmux_P8_09_gpio_pin {
++ pinctrl-single,pins = <0x09c 0x2F>; }; /* Mode 7, RxActive */
++ P8_09_gpio_pu_pin: pinmux_P8_09_gpio_pu_pin {
++ pinctrl-single,pins = <0x09c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_09_gpio_pd_pin: pinmux_P8_09_gpio_pd_pin {
++ pinctrl-single,pins = <0x09c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_09_timer_pin: pinmux_P8_09_timer_pin {
++ pinctrl-single,pins = <0x09c 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_10 (ZCZ ball U6 ) */
++ P8_10_default_pin: pinmux_P8_10_default_pin {
++ pinctrl-single,pins = <0x098 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_10_gpio_pin: pinmux_P8_10_gpio_pin {
++ pinctrl-single,pins = <0x098 0x2F>; }; /* Mode 7, RxActive */
++ P8_10_gpio_pu_pin: pinmux_P8_10_gpio_pu_pin {
++ pinctrl-single,pins = <0x098 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_10_gpio_pd_pin: pinmux_P8_10_gpio_pd_pin {
++ pinctrl-single,pins = <0x098 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_10_timer_pin: pinmux_P8_10_timer_pin {
++ pinctrl-single,pins = <0x098 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_11 (ZCZ ball R12) */
++ P8_11_default_pin: pinmux_P8_11_default_pin {
++ pinctrl-single,pins = <0x034 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_11_gpio_pin: pinmux_P8_11_gpio_pin {
++ pinctrl-single,pins = <0x034 0x2F>; }; /* Mode 7, RxActive */
++ P8_11_gpio_pu_pin: pinmux_P8_11_gpio_pu_pin {
++ pinctrl-single,pins = <0x034 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_11_gpio_pd_pin: pinmux_P8_11_gpio_pd_pin {
++ pinctrl-single,pins = <0x034 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_11_pruout_pin: pinmux_P8_11_pruout_pin {
++ pinctrl-single,pins = <0x034 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_11_qep_pin: pinmux_P8_11_qep_pin {
++ pinctrl-single,pins = <0x034 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_12 (ZCZ ball T12) */
++ P8_12_default_pin: pinmux_P8_12_default_pin {
++ pinctrl-single,pins = <0x030 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_12_gpio_pin: pinmux_P8_12_gpio_pin {
++ pinctrl-single,pins = <0x030 0x2F>; }; /* Mode 7, RxActive */
++ P8_12_gpio_pu_pin: pinmux_P8_12_gpio_pu_pin {
++ pinctrl-single,pins = <0x030 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_12_gpio_pd_pin: pinmux_P8_12_gpio_pd_pin {
++ pinctrl-single,pins = <0x030 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_12_pruout_pin: pinmux_P8_12_pruout_pin {
++ pinctrl-single,pins = <0x030 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_12_qep_pin: pinmux_P8_12_qep_pin {
++ pinctrl-single,pins = <0x030 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_13 (ZCZ ball T10) */
++ P8_13_default_pin: pinmux_P8_13_default_pin {
++ pinctrl-single,pins = <0x024 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_13_gpio_pin: pinmux_P8_13_gpio_pin {
++ pinctrl-single,pins = <0x024 0x2F>; }; /* Mode 7, RxActive */
++ P8_13_gpio_pu_pin: pinmux_P8_13_gpio_pu_pin {
++ pinctrl-single,pins = <0x024 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_13_gpio_pd_pin: pinmux_P8_13_gpio_pd_pin {
++ pinctrl-single,pins = <0x024 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_13_pwm_pin: pinmux_P8_13_pwm_pin {
++ pinctrl-single,pins = <0x024 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_14 (ZCZ ball T11) */
++ P8_14_default_pin: pinmux_P8_14_default_pin {
++ pinctrl-single,pins = <0x028 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_14_gpio_pin: pinmux_P8_14_gpio_pin {
++ pinctrl-single,pins = <0x028 0x2F>; }; /* Mode 7, RxActive */
++ P8_14_gpio_pu_pin: pinmux_P8_14_gpio_pu_pin {
++ pinctrl-single,pins = <0x028 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_14_gpio_pd_pin: pinmux_P8_14_gpio_pd_pin {
++ pinctrl-single,pins = <0x028 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_14_pwm_pin: pinmux_P8_14_pwm_pin {
++ pinctrl-single,pins = <0x028 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_15 (ZCZ ball U13) */
++ P8_15_default_pin: pinmux_P8_15_default_pin {
++ pinctrl-single,pins = <0x03c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_15_gpio_pin: pinmux_P8_15_gpio_pin {
++ pinctrl-single,pins = <0x03c 0x2F>; }; /* Mode 7, RxActive */
++ P8_15_gpio_pu_pin: pinmux_P8_15_gpio_pu_pin {
++ pinctrl-single,pins = <0x03c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_15_gpio_pd_pin: pinmux_P8_15_gpio_pd_pin {
++ pinctrl-single,pins = <0x03c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_15_pruin_pin: pinmux_P8_15_pruin_pin {
++ pinctrl-single,pins = <0x03c 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_15_qep_pin: pinmux_P8_15_qep_pin {
++ pinctrl-single,pins = <0x03c 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_16 (ZCZ ball V13) */
++ P8_16_default_pin: pinmux_P8_16_default_pin {
++ pinctrl-single,pins = <0x038 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_16_gpio_pin: pinmux_P8_16_gpio_pin {
++ pinctrl-single,pins = <0x038 0x2F>; }; /* Mode 7, RxActive */
++ P8_16_gpio_pu_pin: pinmux_P8_16_gpio_pu_pin {
++ pinctrl-single,pins = <0x038 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_16_gpio_pd_pin: pinmux_P8_16_gpio_pd_pin {
++ pinctrl-single,pins = <0x038 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_16_pruin_pin: pinmux_P8_16_pruin_pin {
++ pinctrl-single,pins = <0x038 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_16_qep_pin: pinmux_P8_16_qep_pin {
++ pinctrl-single,pins = <0x038 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_17 (ZCZ ball U12) */
++ P8_17_default_pin: pinmux_P8_17_default_pin {
++ pinctrl-single,pins = <0x02c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_17_gpio_pin: pinmux_P8_17_gpio_pin {
++ pinctrl-single,pins = <0x02c 0x2F>; }; /* Mode 7, RxActive */
++ P8_17_gpio_pu_pin: pinmux_P8_17_gpio_pu_pin {
++ pinctrl-single,pins = <0x02c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_17_gpio_pd_pin: pinmux_P8_17_gpio_pd_pin {
++ pinctrl-single,pins = <0x02c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_17_pwm_pin: pinmux_P8_17_pwm_pin {
++ pinctrl-single,pins = <0x02c 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_18 (ZCZ ball V12) */
++ P8_18_default_pin: pinmux_P8_18_default_pin {
++ pinctrl-single,pins = <0x08c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_18_gpio_pin: pinmux_P8_18_gpio_pin {
++ pinctrl-single,pins = <0x08c 0x2F>; }; /* Mode 7, RxActive */
++ P8_18_gpio_pu_pin: pinmux_P8_18_gpio_pu_pin {
++ pinctrl-single,pins = <0x08c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_18_gpio_pd_pin: pinmux_P8_18_gpio_pd_pin {
++ pinctrl-single,pins = <0x08c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++
++ /* P8_19 (ZCZ ball U10) */
++ P8_19_default_pin: pinmux_P8_19_default_pin {
++ pinctrl-single,pins = <0x020 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_19_gpio_pin: pinmux_P8_19_gpio_pin {
++ pinctrl-single,pins = <0x020 0x2F>; }; /* Mode 7, RxActive */
++ P8_19_gpio_pu_pin: pinmux_P8_19_gpio_pu_pin {
++ pinctrl-single,pins = <0x020 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_19_gpio_pd_pin: pinmux_P8_19_gpio_pd_pin {
++ pinctrl-single,pins = <0x020 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_19_pwm_pin: pinmux_P8_19_pwm_pin {
++ pinctrl-single,pins = <0x020 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_20 (ZCZ ball V9 ) emmc */
++ /* P8_21 (ZCZ ball U9 ) emmc */
++ /* P8_22 (ZCZ ball V8 ) emmc */
++ /* P8_23 (ZCZ ball U8 ) emmc */
++ /* P8_24 (ZCZ ball V7 ) emmc */
++ /* P8_25 (ZCZ ball U7 ) emmc */
++
++ /* P8_26 (ZCZ ball V6 ) */
++ P8_26_default_pin: pinmux_P8_26_default_pin {
++ pinctrl-single,pins = <0x07c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_26_gpio_pin: pinmux_P8_26_gpio_pin {
++ pinctrl-single,pins = <0x07c 0x2F>; }; /* Mode 7, RxActive */
++ P8_26_gpio_pu_pin: pinmux_P8_26_gpio_pu_pin {
++ pinctrl-single,pins = <0x07c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_26_gpio_pd_pin: pinmux_P8_26_gpio_pd_pin {
++ pinctrl-single,pins = <0x07c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++
++ /* P8_27 (ZCZ ball U5 ) hdmi */
++ P8_27_default_pin: pinmux_P8_27_default_pin {
++ pinctrl-single,pins = <0x0e0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_27_gpio_pin: pinmux_P8_27_gpio_pin {
++ pinctrl-single,pins = <0x0e0 0x2F>; }; /* Mode 7, RxActive */
++ P8_27_gpio_pu_pin: pinmux_P8_27_gpio_pu_pin {
++ pinctrl-single,pins = <0x0e0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_27_gpio_pd_pin: pinmux_P8_27_gpio_pd_pin {
++ pinctrl-single,pins = <0x0e0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_27_pruout_pin: pinmux_P8_27_pruout_pin {
++ pinctrl-single,pins = <0x0e0 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_27_pruin_pin: pinmux_P8_27_pruin_pin {
++ pinctrl-single,pins = <0x0e0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_27_hdmi_pin: pinmux_P8_27_hdmi_pin {
++ pinctrl-single,pins = <0x0e0 0x00>; }; /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_28 (ZCZ ball V5 ) hdmi */
++ P8_28_default_pin: pinmux_P8_28_default_pin {
++ pinctrl-single,pins = <0x0e8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_28_gpio_pin: pinmux_P8_28_gpio_pin {
++ pinctrl-single,pins = <0x0e8 0x2F>; }; /* Mode 7, RxActive */
++ P8_28_gpio_pu_pin: pinmux_P8_28_gpio_pu_pin {
++ pinctrl-single,pins = <0x0e8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_28_gpio_pd_pin: pinmux_P8_28_gpio_pd_pin {
++ pinctrl-single,pins = <0x0e8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_28_pruout_pin: pinmux_P8_28_pruout_pin {
++ pinctrl-single,pins = <0x0e8 0x05>; }; /* Mode 5, Pull-Down */
++ P8_28_pruin_pin: pinmux_P8_28_pruin_pin {
++ pinctrl-single,pins = <0x0e8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_28_hdmi_pin: pinmux_P8_28_hdmi_pin {
++ pinctrl-single,pins = <0x0e8 0x00>; }; /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_29 (ZCZ ball R5 ) hdmi */
++ P8_29_default_pin: pinmux_P8_29_default_pin {
++ pinctrl-single,pins = <0x0e4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_29_gpio_pin: pinmux_P8_29_gpio_pin {
++ pinctrl-single,pins = <0x0e4 0x2F>; }; /* Mode 7, RxActive */
++ P8_29_gpio_pu_pin: pinmux_P8_29_gpio_pu_pin {
++ pinctrl-single,pins = <0x0e4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_29_gpio_pd_pin: pinmux_P8_29_gpio_pd_pin {
++ pinctrl-single,pins = <0x0e4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_29_pruout_pin: pinmux_P8_29_pruout_pin {
++ pinctrl-single,pins = <0x0e4 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_29_pruin_pin: pinmux_P8_29_pruin_pin {
++ pinctrl-single,pins = <0x0e4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_29_hdmi_pin: pinmux_P8_29_hdmi_pin {
++ pinctrl-single,pins = <0x0e4 0x00>; }; /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_30 (ZCZ ball R6 ) hdmi */
++ P8_30_default_pin: pinmux_P8_30_default_pin {
++ pinctrl-single,pins = <0x0ec 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_30_gpio_pin: pinmux_P8_30_gpio_pin {
++ pinctrl-single,pins = <0x0ec 0x2F>; }; /* Mode 7, RxActive */
++ P8_30_gpio_pu_pin: pinmux_P8_30_gpio_pu_pin {
++ pinctrl-single,pins = <0x0ec 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_30_gpio_pd_pin: pinmux_P8_30_gpio_pd_pin {
++ pinctrl-single,pins = <0x0ec 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_30_pruout_pin: pinmux_P8_30_pruout_pin {
++ pinctrl-single,pins = <0x0ec 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_30_pruin_pin: pinmux_P8_30_pruin_pin {
++ pinctrl-single,pins = <0x0ec 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_30_hdmi_pin: pinmux_P8_30_hdmi_pin {
++ pinctrl-single,pins = <0x0ec 0x00>; }; /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_31 (ZCZ ball V4 ) hdmi */
++ P8_31_default_pin: pinmux_P8_31_default_pin {
++ pinctrl-single,pins = <0x0d8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_31_gpio_pin: pinmux_P8_31_gpio_pin {
++ pinctrl-single,pins = <0x0d8 0x2F>; }; /* Mode 7, RxActive */
++ P8_31_gpio_pu_pin: pinmux_P8_31_gpio_pu_pin {
++ pinctrl-single,pins = <0x0d8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_31_gpio_pd_pin: pinmux_P8_31_gpio_pd_pin {
++ pinctrl-single,pins = <0x0d8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_31_uart_pin: pinmux_P8_31_uart_pin {
++ pinctrl-single,pins = <0x0d8 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P8_31_hdmi_pin: pinmux_P8_31_hdmi_pin {
++ pinctrl-single,pins = <0x0d8 0x08>; }; /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_32 (ZCZ ball T5 ) hdmi */
++ P8_32_default_pin: pinmux_P8_32_default_pin {
++ pinctrl-single,pins = <0x0dc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_32_gpio_pin: pinmux_P8_32_gpio_pin {
++ pinctrl-single,pins = <0x0dc 0x2F>; }; /* Mode 7, RxActive */
++ P8_32_gpio_pu_pin: pinmux_P8_32_gpio_pu_pin {
++ pinctrl-single,pins = <0x0dc 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_32_gpio_pd_pin: pinmux_P8_32_gpio_pd_pin {
++ pinctrl-single,pins = <0x0dc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_32_uart_pin: pinmux_P8_32_uart_pin {
++ pinctrl-single,pins = <0x0dc 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_32_hdmi_pin: pinmux_P8_32_hdmi_pin {
++ pinctrl-single,pins = <0x0dc 0x08>; }; /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_33 (ZCZ ball V3 ) hdmi */
++ P8_33_default_pin: pinmux_P8_33_default_pin {
++ pinctrl-single,pins = <0x0d4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_33_gpio_pin: pinmux_P8_33_gpio_pin {
++ pinctrl-single,pins = <0x0d4 0x2F>; }; /* Mode 7, RxActive */
++ P8_33_gpio_pu_pin: pinmux_P8_33_gpio_pu_pin {
++ pinctrl-single,pins = <0x0d4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_33_gpio_pd_pin: pinmux_P8_33_gpio_pd_pin {
++ pinctrl-single,pins = <0x0d4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_33_hdmi_pin: pinmux_P8_33_hdmi_pin {
++ pinctrl-single,pins = <0x0d4 0x08>; }; /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++ P8_33_qep_pin: pinmux_P8_33_qep_pin {
++ pinctrl-single,pins = <0x0d4 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++
++ /* P8_34 (ZCZ ball U4 ) hdmi */
++ P8_34_default_pin: pinmux_P8_34_default_pin {
++ pinctrl-single,pins = <0x0cc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_34_gpio_pin: pinmux_P8_34_gpio_pin {
++ pinctrl-single,pins = <0x0cc 0x2F>; }; /* Mode 7, RxActive */
++ P8_34_gpio_pu_pin: pinmux_P8_34_gpio_pu_pin {
++ pinctrl-single,pins = <0x0cc 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_34_gpio_pd_pin: pinmux_P8_34_gpio_pd_pin {
++ pinctrl-single,pins = <0x0cc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_34_pwm_pin: pinmux_P8_34_pwm_pin {
++ pinctrl-single,pins = <0x0cc 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P8_34_hdmi_pin: pinmux_P8_34_hdmi_pin {
++ pinctrl-single,pins = <0x0cc 0x08>; }; /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_35 (ZCZ ball V2 ) hdmi */
++ P8_35_default_pin: pinmux_P8_35_default_pin {
++ pinctrl-single,pins = <0x0d0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_35_gpio_pin: pinmux_P8_35_gpio_pin {
++ pinctrl-single,pins = <0x0d0 0x2F>; }; /* Mode 7, RxActive */
++ P8_35_gpio_pu_pin: pinmux_P8_35_gpio_pu_pin {
++ pinctrl-single,pins = <0x0d0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_35_gpio_pd_pin: pinmux_P8_35_gpio_pd_pin {
++ pinctrl-single,pins = <0x0d0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_35_hdmi_pin: pinmux_P8_35_hdmi_pin {
++ pinctrl-single,pins = <0x0d0 0x08>; }; /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++ P8_35_qep_pin: pinmux_P8_35_qep_pin {
++ pinctrl-single,pins = <0x0d0 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++
++ /* P8_36 (ZCZ ball U3 ) hdmi */
++ P8_36_default_pin: pinmux_P8_36_default_pin {
++ pinctrl-single,pins = <0x0c8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_36_gpio_pin: pinmux_P8_36_gpio_pin {
++ pinctrl-single,pins = <0x0c8 0x2F>; }; /* Mode 7, RxActive */
++ P8_36_gpio_pu_pin: pinmux_P8_36_gpio_pu_pin {
++ pinctrl-single,pins = <0x0c8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_36_gpio_pd_pin: pinmux_P8_36_gpio_pd_pin {
++ pinctrl-single,pins = <0x0c8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_36_pwm_pin: pinmux_P8_36_pwm_pin {
++ pinctrl-single,pins = <0x0c8 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P8_36_hdmi_pin: pinmux_P8_36_hdmi_pin {
++ pinctrl-single,pins = <0x0c8 0x08>; }; /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_37 (ZCZ ball U1 ) hdmi */
++ P8_37_default_pin: pinmux_P8_37_default_pin {
++ pinctrl-single,pins = <0x0c0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_37_gpio_pin: pinmux_P8_37_gpio_pin {
++ pinctrl-single,pins = <0x0c0 0x2F>; }; /* Mode 7, RxActive */
++ P8_37_gpio_pu_pin: pinmux_P8_37_gpio_pu_pin {
++ pinctrl-single,pins = <0x0c0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_37_gpio_pd_pin: pinmux_P8_37_gpio_pd_pin {
++ pinctrl-single,pins = <0x0c0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_37_uart_pin: pinmux_P8_37_uart_pin {
++ pinctrl-single,pins = <0x0c0 0x04>; }; /* Mode 4, Pull-Down*/
++ P8_37_pwm_pin: pinmux_P8_37_pwm_pin {
++ pinctrl-single,pins = <0x0c0 0x02>; }; /* Mode 2, Pull-Down*/
++ P8_37_hdmi_pin: pinmux_P8_37_hdmi_pin {
++ pinctrl-single,pins = <0x0c0 0x08>; }; /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++
++ /* P8_38 (ZCZ ball U2 ) hdmi */
++ P8_38_default_pin: pinmux_P8_38_default_pin {
++ pinctrl-single,pins = <0x0c4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_38_gpio_pin: pinmux_P8_38_gpio_pin {
++ pinctrl-single,pins = <0x0c4 0x2F>; }; /* Mode 7, RxActive */
++ P8_38_gpio_pu_pin: pinmux_P8_38_gpio_pu_pin {
++ pinctrl-single,pins = <0x0c4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_38_gpio_pd_pin: pinmux_P8_38_gpio_pd_pin {
++ pinctrl-single,pins = <0x0c4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_38_uart_pin: pinmux_P8_38_uart_pin {
++ pinctrl-single,pins = <0x0c4 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P8_38_pwm_pin: pinmux_P8_38_pwm_pin {
++ pinctrl-single,pins = <0x0c4 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P8_38_hdmi_pin: pinmux_P8_38_hdmi_pin {
++ pinctrl-single,pins = <0x0c4 0x08>; }; /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++
++ /* P8_39 (ZCZ ball T3 ) hdmi */
++ P8_39_default_pin: pinmux_P8_39_default_pin {
++ pinctrl-single,pins = <0x0b8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_39_gpio_pin: pinmux_P8_39_gpio_pin {
++ pinctrl-single,pins = <0x0b8 0x2F>; }; /* Mode 7, RxActive */
++ P8_39_gpio_pu_pin: pinmux_P8_39_gpio_pu_pin {
++ pinctrl-single,pins = <0x0b8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_39_gpio_pd_pin: pinmux_P8_39_gpio_pd_pin {
++ pinctrl-single,pins = <0x0b8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_39_pruout_pin: pinmux_P8_39_pruout_pin {
++ pinctrl-single,pins = <0x0b8 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_39_pruin_pin: pinmux_P8_39_pruin_pin {
++ pinctrl-single,pins = <0x0b8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_39_hdmi_pin: pinmux_P8_39_hdmi_pin {
++ pinctrl-single,pins = <0x0b8 0x08>; }; /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_40 (ZCZ ball T4 ) hdmi */
++ P8_40_default_pin: pinmux_P8_40_default_pin {
++ pinctrl-single,pins = <0x0bc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_40_gpio_pin: pinmux_P8_40_gpio_pin {
++ pinctrl-single,pins = <0x0bc 0x2F>; }; /* Mode 7, RxActive */
++ P8_40_gpio_pu_pin: pinmux_P8_40_gpio_pu_pin {
++ pinctrl-single,pins = <0x0bc 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_40_gpio_pd_pin: pinmux_P8_40_gpio_pd_pin {
++ pinctrl-single,pins = <0x0bc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_40_pruout_pin: pinmux_P8_40_pruout_pin {
++ pinctrl-single,pins = <0x0bc 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_40_pruin_pin: pinmux_P8_40_pruin_pin {
++ pinctrl-single,pins = <0x0bc 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_40_hdmi_pin: pinmux_P8_40_hdmi_pin {
++ pinctrl-single,pins = <0x0bc 0x08>; }; /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_41 (ZCZ ball T1 ) hdmi */
++ P8_41_default_pin: pinmux_P8_41_default_pin {
++ pinctrl-single,pins = <0x0b0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_41_gpio_pin: pinmux_P8_41_gpio_pin {
++ pinctrl-single,pins = <0x0b0 0x2F>; }; /* Mode 7, RxActive */
++ P8_41_gpio_pu_pin: pinmux_P8_41_gpio_pu_pin {
++ pinctrl-single,pins = <0x0b0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_41_gpio_pd_pin: pinmux_P8_41_gpio_pd_pin {
++ pinctrl-single,pins = <0x0b0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_41_pruout_pin: pinmux_P8_41_pruout_pin {
++ pinctrl-single,pins = <0x0b0 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_41_pruin_pin: pinmux_P8_41_pruin_pin {
++ pinctrl-single,pins = <0x0b0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_41_hdmi_pin: pinmux_P8_41_hdmi_pin {
++ pinctrl-single,pins = <0x0b0 0x08>; }; /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_42 (ZCZ ball T2 ) hdmi */
++ P8_42_default_pin: pinmux_P8_42_default_pin {
++ pinctrl-single,pins = <0x0b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_42_gpio_pin: pinmux_P8_42_gpio_pin {
++ pinctrl-single,pins = <0x0b4 0x2F>; }; /* Mode 7, RxActive */
++ P8_42_gpio_pu_pin: pinmux_P8_42_gpio_pu_pin {
++ pinctrl-single,pins = <0x0b4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_42_gpio_pd_pin: pinmux_P8_42_gpio_pd_pin {
++ pinctrl-single,pins = <0x0b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_42_pruout_pin: pinmux_P8_42_pruout_pin {
++ pinctrl-single,pins = <0x0b4 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_42_pruin_pin: pinmux_P8_42_pruin_pin {
++ pinctrl-single,pins = <0x0b4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_42_hdmi_pin: pinmux_P8_42_hdmi_pin {
++ pinctrl-single,pins = <0x0b4 0x08>; }; /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_43 (ZCZ ball R3 ) hdmi */
++ P8_43_default_pin: pinmux_P8_43_default_pin {
++ pinctrl-single,pins = <0x0a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_43_gpio_pin: pinmux_P8_43_gpio_pin {
++ pinctrl-single,pins = <0x0a8 0x2F>; }; /* Mode 7, RxActive */
++ P8_43_gpio_pu_pin: pinmux_P8_43_gpio_pu_pin {
++ pinctrl-single,pins = <0x0a8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_43_gpio_pd_pin: pinmux_P8_43_gpio_pd_pin {
++ pinctrl-single,pins = <0x0a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_43_pruout_pin: pinmux_P8_43_pruout_pin {
++ pinctrl-single,pins = <0x0a8 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_43_pruin_pin: pinmux_P8_43_pruin_pin {
++ pinctrl-single,pins = <0x0a8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_43_pwm_pin: pinmux_P8_43_pwm_pin {
++ pinctrl-single,pins = <0x0a8 0x03>; }; /* Mode 3, Pull-Down */
++ P8_43_hdmi_pin: pinmux_P8_43_hdmi_pin {
++ pinctrl-single,pins = <0x0a8 0x08>; }; /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_44 (ZCZ ball R4 ) hdmi */
++ P8_44_default_pin: pinmux_P8_44_default_pin {
++ pinctrl-single,pins = <0x0ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_44_gpio_pin: pinmux_P8_44_gpio_pin {
++ pinctrl-single,pins = <0x0ac 0x2F>; }; /* Mode 7, RxActive */
++ P8_44_gpio_pu_pin: pinmux_P8_44_gpio_pu_pin {
++ pinctrl-single,pins = <0x0ac 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_44_gpio_pd_pin: pinmux_P8_44_gpio_pd_pin {
++ pinctrl-single,pins = <0x0ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_44_pruout_pin: pinmux_P8_44_pruout_pin {
++ pinctrl-single,pins = <0x0ac 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_44_pruin_pin: pinmux_P8_44_pruin_pin {
++ pinctrl-single,pins = <0x0ac 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_44_pwm_pin: pinmux_P8_44_pwm_pin {
++ pinctrl-single,pins = <0x0ac 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P8_44_hdmi_pin: pinmux_P8_44_hdmi_pin {
++ pinctrl-single,pins = <0x0ac 0x08>; }; /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_45 (ZCZ ball R1 ) hdmi */
++ P8_45_default_pin: pinmux_P8_45_default_pin {
++ pinctrl-single,pins = <0x0a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_45_gpio_pin: pinmux_P8_45_gpio_pin {
++ pinctrl-single,pins = <0x0a0 0x2F>; }; /* Mode 7, RxActive */
++ P8_45_gpio_pu_pin: pinmux_P8_45_gpio_pu_pin {
++ pinctrl-single,pins = <0x0a0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_45_gpio_pd_pin: pinmux_P8_45_gpio_pd_pin {
++ pinctrl-single,pins = <0x0a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_45_pruout_pin: pinmux_P8_45_pruout_pin {
++ pinctrl-single,pins = <0x0a0 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_45_pruin_pin: pinmux_P8_45_pruin_pin {
++ pinctrl-single,pins = <0x0a0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_45_pwm_pin: pinmux_P8_45_pwm_pin {
++ pinctrl-single,pins = <0x0a0 0x03>; }; /* Mode 3, Pull-Down*/
++ P8_45_hdmi_pin: pinmux_P8_45_hdmi_pin {
++ pinctrl-single,pins = <0x0a0 0x08>; }; /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_46 (ZCZ ball R2 ) hdmi */
++ P8_46_default_pin: pinmux_P8_46_default_pin {
++ pinctrl-single,pins = <0x0a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_46_gpio_pin: pinmux_P8_46_gpio_pin {
++ pinctrl-single,pins = <0x0a4 0x2F>; }; /* Mode 7, RxActive */
++ P8_46_gpio_pu_pin: pinmux_P8_46_gpio_pu_pin {
++ pinctrl-single,pins = <0x0a4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_46_gpio_pd_pin: pinmux_P8_46_gpio_pd_pin {
++ pinctrl-single,pins = <0x0a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_46_pruout_pin: pinmux_P8_46_pruout_pin {
++ pinctrl-single,pins = <0x0a4 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_46_pruin_pin: pinmux_P8_46_pruin_pin {
++ pinctrl-single,pins = <0x0a4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_46_pwm_pin: pinmux_P8_46_pwm_pin {
++ pinctrl-single,pins = <0x0a4 0x03>; }; /* Mode 3, Pull-Down*/
++ P8_46_hdmi_pin: pinmux_P8_46_hdmi_pin {
++ pinctrl-single,pins = <0x0a4 0x08>; }; /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /************************/
++ /* P9 Header */
++ /************************/
++
++ /* P9_01 GND */
++ /* P9_02 GND */
++ /* P9_03 3.3V */
++ /* P9_04 3.3V */
++ /* P9_05 VDD_5V */
++ /* P9_06 VDD_5V */
++ /* P9_07 SYS_5V */
++ /* P9_08 SYS_5V */
++ /* P9_09 PWR_BUT */
++ /* P9_10 (ZCZ ball A10) RESETn */
++
++ /* P9_11 (ZCZ ball T17) */
++ P9_11_default_pin: pinmux_P9_11_default_pin {
++ pinctrl-single,pins = <0x070 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_11_gpio_pin: pinmux_P9_11_gpio_pin {
++ pinctrl-single,pins = <0x070 0x2F>; }; /* Mode 7, RxActive */
++ P9_11_gpio_pu_pin: pinmux_P9_11_gpio_pu_pin {
++ pinctrl-single,pins = <0x070 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_11_gpio_pd_pin: pinmux_P9_11_gpio_pd_pin {
++ pinctrl-single,pins = <0x070 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_11_uart_pin: pinmux_P9_11_uart_pin {
++ pinctrl-single,pins = <0x070 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_12 (ZCZ ball U18) */
++ P9_12_default_pin: pinmux_P9_12_default_pin {
++ pinctrl-single,pins = <0x078 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_12_gpio_pin: pinmux_P9_12_gpio_pin {
++ pinctrl-single,pins = <0x078 0x2F>; }; /* Mode 7, RxActive */
++ P9_12_gpio_pu_pin: pinmux_P9_12_gpio_pu_pin {
++ pinctrl-single,pins = <0x078 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin {
++ pinctrl-single,pins = <0x078 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++
++ /* P9_13 (ZCZ ball U17) */
++ P9_13_default_pin: pinmux_P9_13_default_pin {
++ pinctrl-single,pins = <0x074 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_13_gpio_pin: pinmux_P9_13_gpio_pin {
++ pinctrl-single,pins = <0x074 0x2F>; }; /* Mode 7, RxActive */
++ P9_13_gpio_pu_pin: pinmux_P9_13_gpio_pu_pin {
++ pinctrl-single,pins = <0x074 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_13_gpio_pd_pin: pinmux_P9_13_gpio_pd_pin {
++ pinctrl-single,pins = <0x074 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_13_uart_pin: pinmux_P9_13_uart_pin {
++ pinctrl-single,pins = <0x074 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_14 (ZCZ ball U14) */
++ P9_14_default_pin: pinmux_P9_14_default_pin {
++ pinctrl-single,pins = <0x048 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_14_gpio_pin: pinmux_P9_14_gpio_pin {
++ pinctrl-single,pins = <0x048 0x2F>; }; /* Mode 7, RxActive */
++ P9_14_gpio_pu_pin: pinmux_P9_14_gpio_pu_pin {
++ pinctrl-single,pins = <0x048 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_14_gpio_pd_pin: pinmux_P9_14_gpio_pd_pin {
++ pinctrl-single,pins = <0x048 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_14_pwm_pin: pinmux_P9_14_pwm_pin {
++ pinctrl-single,pins = <0x048 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_15 (ZCZ ball R13) */
++ P9_15_default_pin: pinmux_P9_15_default_pin {
++ pinctrl-single,pins = <0x040 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_15_gpio_pin: pinmux_P9_15_gpio_pin {
++ pinctrl-single,pins = <0x040 0x2F>; }; /* Mode 7, RxActive */
++ P9_15_gpio_pu_pin: pinmux_P9_15_gpio_pu_pin {
++ pinctrl-single,pins = <0x040 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_15_gpio_pd_pin: pinmux_P9_15_gpio_pd_pin {
++ pinctrl-single,pins = <0x040 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_15_pwm_pin: pinmux_P9_15_pwm_pin {
++ pinctrl-single,pins = <0x040 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_16 (ZCZ ball T14) */
++ P9_16_default_pin: pinmux_P9_16_default_pin {
++ pinctrl-single,pins = <0x04c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_16_gpio_pin: pinmux_P9_16_gpio_pin {
++ pinctrl-single,pins = <0x04c 0x2F>; }; /* Mode 7, RxActive */
++ P9_16_gpio_pu_pin: pinmux_P9_16_gpio_pu_pin {
++ pinctrl-single,pins = <0x04c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_16_gpio_pd_pin: pinmux_P9_16_gpio_pd_pin {
++ pinctrl-single,pins = <0x04c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_16_pwm_pin: pinmux_P9_16_pwm_pin {
++ pinctrl-single,pins = <0x04c 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_17 (ZCZ ball A16) */
++ P9_17_default_pin: pinmux_P9_17_default_pin {
++ pinctrl-single,pins = <0x15c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_17_gpio_pin: pinmux_P9_17_gpio_pin {
++ pinctrl-single,pins = <0x15c 0x2F>; }; /* Mode 7, RxActive */
++ P9_17_gpio_pu_pin: pinmux_P9_17_gpio_pu_pin {
++ pinctrl-single,pins = <0x15c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_17_gpio_pd_pin: pinmux_P9_17_gpio_pd_pin {
++ pinctrl-single,pins = <0x15c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_17_spi_pin: pinmux_P9_17_spi_pin {
++ pinctrl-single,pins = <0x15c 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_17_i2c_pin: pinmux_P9_17_i2c_pin {
++ pinctrl-single,pins = <0x15c 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_17_pwm_pin: pinmux_P9_17_pwm_pin {
++ pinctrl-single,pins = <0x15c 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_18 (ZCZ ball B16) */
++ P9_18_default_pin: pinmux_P9_18_default_pin {
++ pinctrl-single,pins = <0x158 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_18_gpio_pin: pinmux_P9_18_gpio_pin {
++ pinctrl-single,pins = <0x158 0x2F>; }; /* Mode 7, RxActive */
++ P9_18_gpio_pu_pin: pinmux_P9_18_gpio_pu_pin {
++ pinctrl-single,pins = <0x158 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_18_gpio_pd_pin: pinmux_P9_18_gpio_pd_pin {
++ pinctrl-single,pins = <0x158 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_18_spi_pin: pinmux_P9_18_spi_pin {
++ pinctrl-single,pins = <0x158 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_18_i2c_pin: pinmux_P9_18_i2c_pin {
++ pinctrl-single,pins = <0x158 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_18_pwm_pin: pinmux_P9_18_pwm_pin {
++ pinctrl-single,pins = <0x158 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_19 (ZCZ ball D17) */
++ P9_19_default_pin: pinmux_P9_19_default_pin {
++ pinctrl-single,pins = <0x17c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_19_gpio_pin: pinmux_P9_19_gpio_pin {
++ pinctrl-single,pins = <0x17c 0x2F>; }; /* Mode 7, RxActive */
++ P9_19_gpio_pu_pin: pinmux_P9_19_gpio_pu_pin {
++ pinctrl-single,pins = <0x17c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_19_gpio_pd_pin: pinmux_P9_19_gpio_pd_pin {
++ pinctrl-single,pins = <0x17c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_19_can_pin: pinmux_P9_19_can_pin {
++ pinctrl-single,pins = <0x17c 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_19_i2c_pin: pinmux_P9_19_i2c_pin {
++ pinctrl-single,pins = <0x17c 0x73>; }; /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) */
++
++ /* P9_20 (ZCZ ball D18) */
++ P9_20_default_pin: pinmux_P9_20_default_pin {
++ pinctrl-single,pins = <0x178 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_20_gpio_pin: pinmux_P9_20_gpio_pin {
++ pinctrl-single,pins = <0x178 0x2F>; }; /* Mode 7, RxActive */
++ P9_20_gpio_pu_pin: pinmux_P9_20_gpio_pu_pin {
++ pinctrl-single,pins = <0x178 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_20_gpio_pd_pin: pinmux_P9_20_gpio_pd_pin {
++ pinctrl-single,pins = <0x178 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_20_can_pin: pinmux_P9_20_can_pin {
++ pinctrl-single,pins = <0x178 0x12>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_20_i2c_pin: pinmux_P9_20_i2c_pin {
++ pinctrl-single,pins = <0x178 0x73>; }; /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) */
++
++ /* P9_21 (ZCZ ball B17) */
++ P9_21_default_pin: pinmux_P9_21_default_pin {
++ pinctrl-single,pins = <0x154 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_21_gpio_pin: pinmux_P9_21_gpio_pin {
++ pinctrl-single,pins = <0x154 0x2F>; }; /* Mode 7, RxActive */
++ P9_21_gpio_pu_pin: pinmux_P9_21_gpio_pu_pin {
++ pinctrl-single,pins = <0x154 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_21_gpio_pd_pin: pinmux_P9_21_gpio_pd_pin {
++ pinctrl-single,pins = <0x154 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_21_spi_pin: pinmux_P9_21_spi_pin {
++ pinctrl-single,pins = <0x154 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_21_uart_pin: pinmux_P9_21_uart_pin {
++ pinctrl-single,pins = <0x154 0x31>; }; /* Mode 1, Pull-Up, RxActive */
++ P9_21_i2c_pin: pinmux_P9_21_i2c_pin {
++ pinctrl-single,pins = <0x154 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_21_pwm_pin: pinmux_P9_21_pwm_pin {
++ pinctrl-single,pins = <0x154 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_22 (ZCZ ball A17) */
++ P9_22_default_pin: pinmux_P9_22_default_pin {
++ pinctrl-single,pins = <0x150 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_22_gpio_pin: pinmux_P9_22_gpio_pin {
++ pinctrl-single,pins = <0x150 0x2F>; }; /* Mode 7, RxActive */
++ P9_22_gpio_pu_pin: pinmux_P9_22_gpio_pu_pin {
++ pinctrl-single,pins = <0x150 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_22_gpio_pd_pin: pinmux_P9_22_gpio_pd_pin {
++ pinctrl-single,pins = <0x150 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_22_spi_pin: pinmux_P9_22_spi_pin {
++ pinctrl-single,pins = <0x150 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_22_uart_pin: pinmux_P9_22_uart_pin {
++ pinctrl-single,pins = <0x150 0x31>; }; /* Mode 1, Pull-Up, RxActive */
++ P9_22_i2c_pin: pinmux_P9_22_i2c_pin {
++ pinctrl-single,pins = <0x150 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_22_pwm_pin: pinmux_P9_22_pwm_pin {
++ pinctrl-single,pins = <0x150 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_23 (ZCZ ball V14) */
++ P9_23_default_pin: pinmux_P9_23_default_pin {
++ pinctrl-single,pins = <0x044 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_23_gpio_pin: pinmux_P9_23_gpio_pin {
++ pinctrl-single,pins = <0x044 0x2F>; }; /* Mode 7, RxActive */
++ P9_23_gpio_pu_pin: pinmux_P9_23_gpio_pu_pin {
++ pinctrl-single,pins = <0x044 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_23_gpio_pd_pin: pinmux_P9_23_gpio_pd_pin {
++ pinctrl-single,pins = <0x044 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_23_pwm_pin: pinmux_P9_23_pwm_pin {
++ pinctrl-single,pins = <0x044 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_24 (ZCZ ball D15) */
++ P9_24_default_pin: pinmux_P9_24_default_pin {
++ pinctrl-single,pins = <0x184 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_24_gpio_pin: pinmux_P9_24_gpio_pin {
++ pinctrl-single,pins = <0x184 0x2F>; }; /* Mode 7, RxActive */
++ P9_24_gpio_pu_pin: pinmux_P9_24_gpio_pu_pin {
++ pinctrl-single,pins = <0x184 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_24_gpio_pd_pin: pinmux_P9_24_gpio_pd_pin {
++ pinctrl-single,pins = <0x184 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_24_uart_pin: pinmux_P9_24_uart_pin {
++ pinctrl-single,pins = <0x184 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_24_can_pin: pinmux_P9_24_can_pin {
++ pinctrl-single,pins = <0x184 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_24_i2c_pin: pinmux_P9_24_i2c_pin {
++ pinctrl-single,pins = <0x184 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++ P9_24_pruin_pin: pinmux_P9_24_pruin_pin {
++ pinctrl-single,pins = <0x184 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_25 (ZCZ ball A14) Audio */
++ P9_25_default_pin: pinmux_P9_25_default_pin {
++ pinctrl-single,pins = <0x1ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_25_gpio_pin: pinmux_P9_25_gpio_pin {
++ pinctrl-single,pins = <0x1ac 0x2F>; }; /* Mode 7, RxActive */
++ P9_25_gpio_pu_pin: pinmux_P9_25_gpio_pu_pin {
++ pinctrl-single,pins = <0x1ac 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_25_gpio_pd_pin: pinmux_P9_25_gpio_pd_pin {
++ pinctrl-single,pins = <0x1ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_25_qep_pin: pinmux_P9_25_qep_pin {
++ pinctrl-single,pins = <0x1ac 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_25_pruout_pin: pinmux_P9_25_pruout_pin {
++ pinctrl-single,pins = <0x1ac 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_25_pruin_pin: pinmux_P9_25_pruin_pin {
++ pinctrl-single,pins = <0x1ac 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_25_audio_pin: pinmux_P9_25_audio_pin {
++ pinctrl-single,pins = <0x1ac (PIN_INPUT_PULLUP | MUX_MODE0)>; }; /* mcasp0_ahclkx.mcasp0_ahclkx */
++
++ /* P9_26 (ZCZ ball D16) */
++ P9_26_default_pin: pinmux_P9_26_default_pin {
++ pinctrl-single,pins = <0x180 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_26_gpio_pin: pinmux_P9_26_gpio_pin {
++ pinctrl-single,pins = <0x180 0x2F>; }; /* Mode 7, RxActive */
++ P9_26_gpio_pu_pin: pinmux_P9_26_gpio_pu_pin {
++ pinctrl-single,pins = <0x180 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_26_gpio_pd_pin: pinmux_P9_26_gpio_pd_pin {
++ pinctrl-single,pins = <0x180 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_26_uart_pin: pinmux_P9_26_uart_pin {
++ pinctrl-single,pins = <0x180 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_26_can_pin: pinmux_P9_26_can_pin {
++ pinctrl-single,pins = <0x180 0x12>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_26_i2c_pin: pinmux_P9_26_i2c_pin {
++ pinctrl-single,pins = <0x180 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++ P9_26_pruin_pin: pinmux_P9_26_pruin_pin {
++ pinctrl-single,pins = <0x180 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_27 (ZCZ ball C13) */
++ P9_27_default_pin: pinmux_P9_27_default_pin {
++ pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_27_gpio_pin: pinmux_P9_27_gpio_pin {
++ pinctrl-single,pins = <0x1a4 0x2F>; }; /* Mode 7, RxActive */
++ P9_27_gpio_pu_pin: pinmux_P9_27_gpio_pu_pin {
++ pinctrl-single,pins = <0x1a4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_27_gpio_pd_pin: pinmux_P9_27_gpio_pd_pin {
++ pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_27_qep_pin: pinmux_P9_27_qep_pin {
++ pinctrl-single,pins = <0x1a4 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_27_pruout_pin: pinmux_P9_27_pruout_pin {
++ pinctrl-single,pins = <0x1a4 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_27_pruin_pin: pinmux_P9_27_pruin_pin {
++ pinctrl-single,pins = <0x1a4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_28 (ZCZ ball C12) Audio */
++ P9_28_default_pin: pinmux_P9_28_default_pin {
++ pinctrl-single,pins = <0x19c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_28_gpio_pin: pinmux_P9_28_gpio_pin {
++ pinctrl-single,pins = <0x19c 0x2F>; }; /* Mode 7, RxActive */
++ P9_28_gpio_pu_pin: pinmux_P9_28_gpio_pu_pin {
++ pinctrl-single,pins = <0x19c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_28_gpio_pd_pin: pinmux_P9_28_gpio_pd_pin {
++ pinctrl-single,pins = <0x19c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_28_pwm_pin: pinmux_P9_28_pwm_pin {
++ pinctrl-single,pins = <0x19c 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_28_spi_pin: pinmux_P9_28_spi_pin {
++ pinctrl-single,pins = <0x19c 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_28_pwm2_pin: pinmux_P9_28_pwm2_pin {
++ pinctrl-single,pins = <0x19c 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P9_28_pruout_pin: pinmux_P9_28_pruout_pin {
++ pinctrl-single,pins = <0x19c 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_28_pruin_pin: pinmux_P9_28_pruin_pin {
++ pinctrl-single,pins = <0x19c 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_28_audio_pin: pinmux_P9_28_audio_pin {
++ pinctrl-single,pins = <0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)>; }; /* mcasp0_ahclkr.mcasp0_axr2 */
++
++ /* P9_29 (ZCZ ball B13) Audio */
++ P9_29_default_pin: pinmux_P9_29_default_pin {
++ pinctrl-single,pins = <0x194 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_29_gpio_pin: pinmux_P9_29_gpio_pin {
++ pinctrl-single,pins = <0x194 0x2F>; }; /* Mode 7, RxActive */
++ P9_29_gpio_pu_pin: pinmux_P9_29_gpio_pu_pin {
++ pinctrl-single,pins = <0x194 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_29_gpio_pd_pin: pinmux_P9_29_gpio_pd_pin {
++ pinctrl-single,pins = <0x194 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_29_pwm_pin: pinmux_P9_29_pwm_pin {
++ pinctrl-single,pins = <0x194 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_29_spi_pin: pinmux_P9_29_spi_pin {
++ pinctrl-single,pins = <0x194 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_29_pruout_pin: pinmux_P9_29_pruout_pin {
++ pinctrl-single,pins = <0x194 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_29_pruin_pin: pinmux_P9_29_pruin_pin {
++ pinctrl-single,pins = <0x194 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_29_audio_pin: pinmux_P9_29_audio_pin {
++ pinctrl-single,pins = <0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0)>; }; /* mcasp0_fsx.mcasp0_fsx */
++
++ /* P9_30 (ZCZ ball D12) */
++ P9_30_default_pin: pinmux_P9_30_default_pin {
++ pinctrl-single,pins = <0x198 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_30_gpio_pin: pinmux_P9_30_gpio_pin {
++ pinctrl-single,pins = <0x198 0x2F>; }; /* Mode 7, RxActive */
++ P9_30_gpio_pu_pin: pinmux_P9_30_gpio_pu_pin {
++ pinctrl-single,pins = <0x198 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_30_gpio_pd_pin: pinmux_P9_30_gpio_pd_pin {
++ pinctrl-single,pins = <0x198 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_30_pwm_pin: pinmux_P9_30_pwm_pin {
++ pinctrl-single,pins = <0x198 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_30_spi_pin: pinmux_P9_30_spi_pin {
++ pinctrl-single,pins = <0x198 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_30_pruout_pin: pinmux_P9_30_pruout_pin {
++ pinctrl-single,pins = <0x198 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_30_pruin_pin: pinmux_P9_30_pruin_pin {
++ pinctrl-single,pins = <0x198 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_31 (ZCZ ball A13) Audio */
++ P9_31_default_pin: pinmux_P9_31_default_pin {
++ pinctrl-single,pins = <0x190 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_31_gpio_pin: pinmux_P9_31_gpio_pin {
++ pinctrl-single,pins = <0x190 0x2F>; }; /* Mode 7, RxActive */
++ P9_31_gpio_pu_pin: pinmux_P9_31_gpio_pu_pin {
++ pinctrl-single,pins = <0x190 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_31_gpio_pd_pin: pinmux_P9_31_gpio_pd_pin {
++ pinctrl-single,pins = <0x190 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_31_pwm_pin: pinmux_P9_31_pwm_pin {
++ pinctrl-single,pins = <0x190 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_31_spi_pin: pinmux_P9_31_spi_pin {
++ pinctrl-single,pins = <0x190 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_31_pruout_pin: pinmux_P9_31_pruout_pin {
++ pinctrl-single,pins = <0x190 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_31_pruin_pin: pinmux_P9_31_pruin_pin {
++ pinctrl-single,pins = <0x190 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_31_audio_pin: pinmux_P9_31_audio_pin {
++ pinctrl-single,pins = <0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)>; }; /* mcasp0_aclkx.mcasp0_aclkx */
++
++ /* P9_32 VADC */
++ /* P9_33 (ZCZ ball C8 ) AIN4 */
++ /* P9_34 AGND */
++ /* P9_35 (ZCZ ball A8 ) AIN6 */
++ /* P9_36 (ZCZ ball B8 ) AIN5 */
++ /* P9_37 (ZCZ ball B7 ) AIN2 */
++ /* P9_38 (ZCZ ball A7 ) AIN3 */
++ /* P9_39 (ZCZ ball B6 ) AIN0 */
++ /* P9_40 (ZCZ ball C7 ) AIN1 */
++
++ /* P9_41 (ZCZ ball D14) */
++ P9_41_default_pin: pinmux_P9_41_default_pin {
++ pinctrl-single,pins = <0x1b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_41_gpio_pin: pinmux_P9_41_gpio_pin {
++ pinctrl-single,pins = <0x1b4 0x2F>; }; /* Mode 7, RxActive */
++ P9_41_gpio_pu_pin: pinmux_P9_41_gpio_pu_pin {
++ pinctrl-single,pins = <0x1b4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_41_gpio_pd_pin: pinmux_P9_41_gpio_pd_pin {
++ pinctrl-single,pins = <0x1b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_41_timer_pin: pinmux_P9_41_timer_pin {
++ pinctrl-single,pins = <0x1b4 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P9_41_pruin_pin: pinmux_P9_41_pruin_pin {
++ pinctrl-single,pins = <0x1b4 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++
++ /* P9_41.1 */
++ /* P9_91 (ZCZ ball D13) */
++ P9_91_default_pin: pinmux_P9_91_default_pin {
++ pinctrl-single,pins = <0x1a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_91_gpio_pin: pinmux_P9_91_gpio_pin {
++ pinctrl-single,pins = <0x1a8 0x2F>; }; /* Mode 7, RxActive */
++ P9_91_gpio_pu_pin: pinmux_P9_91_gpio_pu_pin {
++ pinctrl-single,pins = <0x1a8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_91_gpio_pd_pin: pinmux_P9_91_gpio_pd_pin {
++ pinctrl-single,pins = <0x1a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_91_qep_pin: pinmux_P9_91_qep_pin {
++ pinctrl-single,pins = <0x1a8 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_91_pruout_pin: pinmux_P9_91_pruout_pin {
++ pinctrl-single,pins = <0x1a8 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_91_pruin_pin: pinmux_P9_91_pruin_pin {
++ pinctrl-single,pins = <0x1a8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_42 (ZCZ ball C18) */
++ P9_42_default_pin: pinmux_P9_42_default_pin {
++ pinctrl-single,pins = <0x164 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_42_gpio_pin: pinmux_P9_42_gpio_pin {
++ pinctrl-single,pins = <0x164 0x2F>; }; /* Mode 7, RxActive */
++ P9_42_gpio_pu_pin: pinmux_P9_42_gpio_pu_pin {
++ pinctrl-single,pins = <0x164 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_42_gpio_pd_pin: pinmux_P9_42_gpio_pd_pin {
++ pinctrl-single,pins = <0x164 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_42_pwm_pin: pinmux_P9_42_pwm_pin {
++ pinctrl-single,pins = <0x164 0x20>; }; /* Mode 0, Pull-Down, RxActive */
++ P9_42_uart_pin: pinmux_P9_42_uart_pin {
++ pinctrl-single,pins = <0x164 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_42_spics_pin: pinmux_P9_42_spics_pin {
++ pinctrl-single,pins = <0x164 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P9_42_spiclk_pin: pinmux_P9_42_spiclk_pin {
++ pinctrl-single,pins = <0x164 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P9_42.1 */
++ /* P9_92 (ZCZ ball B12) */
++ P9_92_default_pin: pinmux_P9_92_default_pin {
++ pinctrl-single,pins = <0x1a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_92_gpio_pin: pinmux_P9_92_gpio_pin {
++ pinctrl-single,pins = <0x1a0 0x2F>; }; /* Mode 7, RxActive */
++ P9_92_gpio_pu_pin: pinmux_P9_92_gpio_pu_pin {
++ pinctrl-single,pins = <0x1a0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_92_gpio_pd_pin: pinmux_P9_92_gpio_pd_pin {
++ pinctrl-single,pins = <0x1a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_92_qep_pin: pinmux_P9_92_qep_pin {
++ pinctrl-single,pins = <0x1a0 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_92_pruout_pin: pinmux_P9_92_pruout_pin {
++ pinctrl-single,pins = <0x1a0 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_92_pruin_pin: pinmux_P9_92_pruin_pin {
++ pinctrl-single,pins = <0x1a0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_43 GND */
++ /* P9_44 GND */
++ /* P9_45 GND */
++ /* P9_46 GND */
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-common-universal.dtsi b/arch/arm/boot/dts/am335x-bone-common-universal.dtsi
+new file mode 100644
+index 0000000..781e33f
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-common-universal.dtsi
+@@ -0,0 +1,2052 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&am33xx_pinmux {
++ /************************/
++ /* P8 Header */
++ /************************/
++
++ /* P8_01 GND */
++ /* P8_02 GND */
++ /* P8_03 (ZCZ ball R9 ) emmc */
++ /* P8_04 (ZCZ ball T9 ) emmc */
++ /* P8_05 (ZCZ ball R8 ) emmc */
++ /* P8_06 (ZCZ ball T8 ) emmc */
++
++ /* P8_07 (ZCZ ball R7 ) */
++ P8_07_default_pin: pinmux_P8_07_default_pin {
++ pinctrl-single,pins = <0x090 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_07_gpio_pin: pinmux_P8_07_gpio_pin {
++ pinctrl-single,pins = <0x090 0x2F>; }; /* Mode 7, RxActive */
++ P8_07_gpio_pu_pin: pinmux_P8_07_gpio_pu_pin {
++ pinctrl-single,pins = <0x090 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_07_gpio_pd_pin: pinmux_P8_07_gpio_pd_pin {
++ pinctrl-single,pins = <0x090 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_07_timer_pin: pinmux_P8_07_timer_pin {
++ pinctrl-single,pins = <0x090 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_08 (ZCZ ball T7 ) */
++ P8_08_default_pin: pinmux_P8_08_default_pin {
++ pinctrl-single,pins = <0x094 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_08_gpio_pin: pinmux_P8_08_gpio_pin {
++ pinctrl-single,pins = <0x094 0x2F>; }; /* Mode 7, RxActive */
++ P8_08_gpio_pu_pin: pinmux_P8_08_gpio_pu_pin {
++ pinctrl-single,pins = <0x094 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_08_gpio_pd_pin: pinmux_P8_08_gpio_pd_pin {
++ pinctrl-single,pins = <0x094 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_08_timer_pin: pinmux_P8_08_timer_pin {
++ pinctrl-single,pins = <0x094 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_09 (ZCZ ball T6 ) */
++ P8_09_default_pin: pinmux_P8_09_default_pin {
++ pinctrl-single,pins = <0x09c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_09_gpio_pin: pinmux_P8_09_gpio_pin {
++ pinctrl-single,pins = <0x09c 0x2F>; }; /* Mode 7, RxActive */
++ P8_09_gpio_pu_pin: pinmux_P8_09_gpio_pu_pin {
++ pinctrl-single,pins = <0x09c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_09_gpio_pd_pin: pinmux_P8_09_gpio_pd_pin {
++ pinctrl-single,pins = <0x09c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_09_timer_pin: pinmux_P8_09_timer_pin {
++ pinctrl-single,pins = <0x09c 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_10 (ZCZ ball U6 ) */
++ P8_10_default_pin: pinmux_P8_10_default_pin {
++ pinctrl-single,pins = <0x098 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_10_gpio_pin: pinmux_P8_10_gpio_pin {
++ pinctrl-single,pins = <0x098 0x2F>; }; /* Mode 7, RxActive */
++ P8_10_gpio_pu_pin: pinmux_P8_10_gpio_pu_pin {
++ pinctrl-single,pins = <0x098 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_10_gpio_pd_pin: pinmux_P8_10_gpio_pd_pin {
++ pinctrl-single,pins = <0x098 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_10_timer_pin: pinmux_P8_10_timer_pin {
++ pinctrl-single,pins = <0x098 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++
++ /* P8_11 (ZCZ ball R12) */
++ P8_11_default_pin: pinmux_P8_11_default_pin {
++ pinctrl-single,pins = <0x034 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_11_gpio_pin: pinmux_P8_11_gpio_pin {
++ pinctrl-single,pins = <0x034 0x2F>; }; /* Mode 7, RxActive */
++ P8_11_gpio_pu_pin: pinmux_P8_11_gpio_pu_pin {
++ pinctrl-single,pins = <0x034 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_11_gpio_pd_pin: pinmux_P8_11_gpio_pd_pin {
++ pinctrl-single,pins = <0x034 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_11_pruout_pin: pinmux_P8_11_pruout_pin {
++ pinctrl-single,pins = <0x034 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_11_qep_pin: pinmux_P8_11_qep_pin {
++ pinctrl-single,pins = <0x034 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_12 (ZCZ ball T12) */
++ P8_12_default_pin: pinmux_P8_12_default_pin {
++ pinctrl-single,pins = <0x030 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_12_gpio_pin: pinmux_P8_12_gpio_pin {
++ pinctrl-single,pins = <0x030 0x2F>; }; /* Mode 7, RxActive */
++ P8_12_gpio_pu_pin: pinmux_P8_12_gpio_pu_pin {
++ pinctrl-single,pins = <0x030 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_12_gpio_pd_pin: pinmux_P8_12_gpio_pd_pin {
++ pinctrl-single,pins = <0x030 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_12_pruout_pin: pinmux_P8_12_pruout_pin {
++ pinctrl-single,pins = <0x030 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_12_qep_pin: pinmux_P8_12_qep_pin {
++ pinctrl-single,pins = <0x030 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_13 (ZCZ ball T10) */
++ P8_13_default_pin: pinmux_P8_13_default_pin {
++ pinctrl-single,pins = <0x024 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_13_gpio_pin: pinmux_P8_13_gpio_pin {
++ pinctrl-single,pins = <0x024 0x2F>; }; /* Mode 7, RxActive */
++ P8_13_gpio_pu_pin: pinmux_P8_13_gpio_pu_pin {
++ pinctrl-single,pins = <0x024 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_13_gpio_pd_pin: pinmux_P8_13_gpio_pd_pin {
++ pinctrl-single,pins = <0x024 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_13_pwm_pin: pinmux_P8_13_pwm_pin {
++ pinctrl-single,pins = <0x024 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_14 (ZCZ ball T11) */
++ P8_14_default_pin: pinmux_P8_14_default_pin {
++ pinctrl-single,pins = <0x028 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_14_gpio_pin: pinmux_P8_14_gpio_pin {
++ pinctrl-single,pins = <0x028 0x2F>; }; /* Mode 7, RxActive */
++ P8_14_gpio_pu_pin: pinmux_P8_14_gpio_pu_pin {
++ pinctrl-single,pins = <0x028 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_14_gpio_pd_pin: pinmux_P8_14_gpio_pd_pin {
++ pinctrl-single,pins = <0x028 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_14_pwm_pin: pinmux_P8_14_pwm_pin {
++ pinctrl-single,pins = <0x028 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_15 (ZCZ ball U13) */
++ P8_15_default_pin: pinmux_P8_15_default_pin {
++ pinctrl-single,pins = <0x03c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_15_gpio_pin: pinmux_P8_15_gpio_pin {
++ pinctrl-single,pins = <0x03c 0x2F>; }; /* Mode 7, RxActive */
++ P8_15_gpio_pu_pin: pinmux_P8_15_gpio_pu_pin {
++ pinctrl-single,pins = <0x03c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_15_gpio_pd_pin: pinmux_P8_15_gpio_pd_pin {
++ pinctrl-single,pins = <0x03c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_15_pruin_pin: pinmux_P8_15_pruin_pin {
++ pinctrl-single,pins = <0x03c 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_15_qep_pin: pinmux_P8_15_qep_pin {
++ pinctrl-single,pins = <0x03c 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_16 (ZCZ ball V13) */
++ P8_16_default_pin: pinmux_P8_16_default_pin {
++ pinctrl-single,pins = <0x038 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_16_gpio_pin: pinmux_P8_16_gpio_pin {
++ pinctrl-single,pins = <0x038 0x2F>; }; /* Mode 7, RxActive */
++ P8_16_gpio_pu_pin: pinmux_P8_16_gpio_pu_pin {
++ pinctrl-single,pins = <0x038 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_16_gpio_pd_pin: pinmux_P8_16_gpio_pd_pin {
++ pinctrl-single,pins = <0x038 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_16_pruin_pin: pinmux_P8_16_pruin_pin {
++ pinctrl-single,pins = <0x038 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_16_qep_pin: pinmux_P8_16_qep_pin {
++ pinctrl-single,pins = <0x038 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_17 (ZCZ ball U12) */
++ P8_17_default_pin: pinmux_P8_17_default_pin {
++ pinctrl-single,pins = <0x02c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_17_gpio_pin: pinmux_P8_17_gpio_pin {
++ pinctrl-single,pins = <0x02c 0x2F>; }; /* Mode 7, RxActive */
++ P8_17_gpio_pu_pin: pinmux_P8_17_gpio_pu_pin {
++ pinctrl-single,pins = <0x02c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_17_gpio_pd_pin: pinmux_P8_17_gpio_pd_pin {
++ pinctrl-single,pins = <0x02c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_17_pwm_pin: pinmux_P8_17_pwm_pin {
++ pinctrl-single,pins = <0x02c 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_18 (ZCZ ball V12) */
++ P8_18_default_pin: pinmux_P8_18_default_pin {
++ pinctrl-single,pins = <0x08c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_18_gpio_pin: pinmux_P8_18_gpio_pin {
++ pinctrl-single,pins = <0x08c 0x2F>; }; /* Mode 7, RxActive */
++ P8_18_gpio_pu_pin: pinmux_P8_18_gpio_pu_pin {
++ pinctrl-single,pins = <0x08c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_18_gpio_pd_pin: pinmux_P8_18_gpio_pd_pin {
++ pinctrl-single,pins = <0x08c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++
++ /* P8_19 (ZCZ ball U10) */
++ P8_19_default_pin: pinmux_P8_19_default_pin {
++ pinctrl-single,pins = <0x020 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_19_gpio_pin: pinmux_P8_19_gpio_pin {
++ pinctrl-single,pins = <0x020 0x2F>; }; /* Mode 7, RxActive */
++ P8_19_gpio_pu_pin: pinmux_P8_19_gpio_pu_pin {
++ pinctrl-single,pins = <0x020 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_19_gpio_pd_pin: pinmux_P8_19_gpio_pd_pin {
++ pinctrl-single,pins = <0x020 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_19_pwm_pin: pinmux_P8_19_pwm_pin {
++ pinctrl-single,pins = <0x020 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P8_20 (ZCZ ball V9 ) emmc */
++ /* P8_21 (ZCZ ball U9 ) emmc */
++ /* P8_22 (ZCZ ball V8 ) emmc */
++ /* P8_23 (ZCZ ball U8 ) emmc */
++ /* P8_24 (ZCZ ball V7 ) emmc */
++ /* P8_25 (ZCZ ball U7 ) emmc */
++
++ /* P8_26 (ZCZ ball V6 ) */
++ P8_26_default_pin: pinmux_P8_26_default_pin {
++ pinctrl-single,pins = <0x07c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_26_gpio_pin: pinmux_P8_26_gpio_pin {
++ pinctrl-single,pins = <0x07c 0x2F>; }; /* Mode 7, RxActive */
++ P8_26_gpio_pu_pin: pinmux_P8_26_gpio_pu_pin {
++ pinctrl-single,pins = <0x07c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_26_gpio_pd_pin: pinmux_P8_26_gpio_pd_pin {
++ pinctrl-single,pins = <0x07c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++
++ /* P8_27 (ZCZ ball U5 ) hdmi */
++ P8_27_default_pin: pinmux_P8_27_default_pin {
++ pinctrl-single,pins = <0x0e0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_27_gpio_pin: pinmux_P8_27_gpio_pin {
++ pinctrl-single,pins = <0x0e0 0x2F>; }; /* Mode 7, RxActive */
++ P8_27_gpio_pu_pin: pinmux_P8_27_gpio_pu_pin {
++ pinctrl-single,pins = <0x0e0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_27_gpio_pd_pin: pinmux_P8_27_gpio_pd_pin {
++ pinctrl-single,pins = <0x0e0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_27_pruout_pin: pinmux_P8_27_pruout_pin {
++ pinctrl-single,pins = <0x0e0 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_27_pruin_pin: pinmux_P8_27_pruin_pin {
++ pinctrl-single,pins = <0x0e0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_27_hdmi_pin: pinmux_P8_27_hdmi_pin {
++ pinctrl-single,pins = <0x0e0 0x00>; }; /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_28 (ZCZ ball V5 ) hdmi */
++ P8_28_default_pin: pinmux_P8_28_default_pin {
++ pinctrl-single,pins = <0x0e8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_28_gpio_pin: pinmux_P8_28_gpio_pin {
++ pinctrl-single,pins = <0x0e8 0x2F>; }; /* Mode 7, RxActive */
++ P8_28_gpio_pu_pin: pinmux_P8_28_gpio_pu_pin {
++ pinctrl-single,pins = <0x0e8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_28_gpio_pd_pin: pinmux_P8_28_gpio_pd_pin {
++ pinctrl-single,pins = <0x0e8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_28_pruout_pin: pinmux_P8_28_pruout_pin {
++ pinctrl-single,pins = <0x0e8 0x05>; }; /* Mode 5, Pull-Down */
++ P8_28_pruin_pin: pinmux_P8_28_pruin_pin {
++ pinctrl-single,pins = <0x0e8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_28_hdmi_pin: pinmux_P8_28_hdmi_pin {
++ pinctrl-single,pins = <0x0e8 0x00>; }; /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_29 (ZCZ ball R5 ) hdmi */
++ P8_29_default_pin: pinmux_P8_29_default_pin {
++ pinctrl-single,pins = <0x0e4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_29_gpio_pin: pinmux_P8_29_gpio_pin {
++ pinctrl-single,pins = <0x0e4 0x2F>; }; /* Mode 7, RxActive */
++ P8_29_gpio_pu_pin: pinmux_P8_29_gpio_pu_pin {
++ pinctrl-single,pins = <0x0e4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_29_gpio_pd_pin: pinmux_P8_29_gpio_pd_pin {
++ pinctrl-single,pins = <0x0e4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_29_pruout_pin: pinmux_P8_29_pruout_pin {
++ pinctrl-single,pins = <0x0e4 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_29_pruin_pin: pinmux_P8_29_pruin_pin {
++ pinctrl-single,pins = <0x0e4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_29_hdmi_pin: pinmux_P8_29_hdmi_pin {
++ pinctrl-single,pins = <0x0e4 0x00>; }; /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_30 (ZCZ ball R6 ) hdmi */
++ P8_30_default_pin: pinmux_P8_30_default_pin {
++ pinctrl-single,pins = <0x0ec 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_30_gpio_pin: pinmux_P8_30_gpio_pin {
++ pinctrl-single,pins = <0x0ec 0x2F>; }; /* Mode 7, RxActive */
++ P8_30_gpio_pu_pin: pinmux_P8_30_gpio_pu_pin {
++ pinctrl-single,pins = <0x0ec 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_30_gpio_pd_pin: pinmux_P8_30_gpio_pd_pin {
++ pinctrl-single,pins = <0x0ec 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_30_pruout_pin: pinmux_P8_30_pruout_pin {
++ pinctrl-single,pins = <0x0ec 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_30_pruin_pin: pinmux_P8_30_pruin_pin {
++ pinctrl-single,pins = <0x0ec 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_30_hdmi_pin: pinmux_P8_30_hdmi_pin {
++ pinctrl-single,pins = <0x0ec 0x00>; }; /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
++
++ /* P8_31 (ZCZ ball V4 ) hdmi */
++ P8_31_default_pin: pinmux_P8_31_default_pin {
++ pinctrl-single,pins = <0x0d8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_31_gpio_pin: pinmux_P8_31_gpio_pin {
++ pinctrl-single,pins = <0x0d8 0x2F>; }; /* Mode 7, RxActive */
++ P8_31_gpio_pu_pin: pinmux_P8_31_gpio_pu_pin {
++ pinctrl-single,pins = <0x0d8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_31_gpio_pd_pin: pinmux_P8_31_gpio_pd_pin {
++ pinctrl-single,pins = <0x0d8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_31_uart_pin: pinmux_P8_31_uart_pin {
++ pinctrl-single,pins = <0x0d8 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P8_31_hdmi_pin: pinmux_P8_31_hdmi_pin {
++ pinctrl-single,pins = <0x0d8 0x08>; }; /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_32 (ZCZ ball T5 ) hdmi */
++ P8_32_default_pin: pinmux_P8_32_default_pin {
++ pinctrl-single,pins = <0x0dc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_32_gpio_pin: pinmux_P8_32_gpio_pin {
++ pinctrl-single,pins = <0x0dc 0x2F>; }; /* Mode 7, RxActive */
++ P8_32_gpio_pu_pin: pinmux_P8_32_gpio_pu_pin {
++ pinctrl-single,pins = <0x0dc 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_32_gpio_pd_pin: pinmux_P8_32_gpio_pd_pin {
++ pinctrl-single,pins = <0x0dc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_32_uart_pin: pinmux_P8_32_uart_pin {
++ pinctrl-single,pins = <0x0dc 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_32_hdmi_pin: pinmux_P8_32_hdmi_pin {
++ pinctrl-single,pins = <0x0dc 0x08>; }; /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_33 (ZCZ ball V3 ) hdmi */
++ P8_33_default_pin: pinmux_P8_33_default_pin {
++ pinctrl-single,pins = <0x0d4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_33_gpio_pin: pinmux_P8_33_gpio_pin {
++ pinctrl-single,pins = <0x0d4 0x2F>; }; /* Mode 7, RxActive */
++ P8_33_gpio_pu_pin: pinmux_P8_33_gpio_pu_pin {
++ pinctrl-single,pins = <0x0d4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_33_gpio_pd_pin: pinmux_P8_33_gpio_pd_pin {
++ pinctrl-single,pins = <0x0d4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_33_hdmi_pin: pinmux_P8_33_hdmi_pin {
++ pinctrl-single,pins = <0x0d4 0x08>; }; /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_34 (ZCZ ball U4 ) hdmi */
++ P8_34_default_pin: pinmux_P8_34_default_pin {
++ pinctrl-single,pins = <0x0cc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_34_gpio_pin: pinmux_P8_34_gpio_pin {
++ pinctrl-single,pins = <0x0cc 0x2F>; }; /* Mode 7, RxActive */
++ P8_34_gpio_pu_pin: pinmux_P8_34_gpio_pu_pin {
++ pinctrl-single,pins = <0x0cc 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_34_gpio_pd_pin: pinmux_P8_34_gpio_pd_pin {
++ pinctrl-single,pins = <0x0cc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_34_pwm_pin: pinmux_P8_34_pwm_pin {
++ pinctrl-single,pins = <0x0cc 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P8_34_hdmi_pin: pinmux_P8_34_hdmi_pin {
++ pinctrl-single,pins = <0x0cc 0x08>; }; /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_35 (ZCZ ball V2 ) hdmi */
++ P8_35_default_pin: pinmux_P8_35_default_pin {
++ pinctrl-single,pins = <0x0d0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_35_gpio_pin: pinmux_P8_35_gpio_pin {
++ pinctrl-single,pins = <0x0d0 0x2F>; }; /* Mode 7, RxActive */
++ P8_35_gpio_pu_pin: pinmux_P8_35_gpio_pu_pin {
++ pinctrl-single,pins = <0x0d0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_35_gpio_pd_pin: pinmux_P8_35_gpio_pd_pin {
++ pinctrl-single,pins = <0x0d0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_35_hdmi_pin: pinmux_P8_35_hdmi_pin {
++ pinctrl-single,pins = <0x0d0 0x08>; }; /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_36 (ZCZ ball U3 ) hdmi */
++ P8_36_default_pin: pinmux_P8_36_default_pin {
++ pinctrl-single,pins = <0x0c8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_36_gpio_pin: pinmux_P8_36_gpio_pin {
++ pinctrl-single,pins = <0x0c8 0x2F>; }; /* Mode 7, RxActive */
++ P8_36_gpio_pu_pin: pinmux_P8_36_gpio_pu_pin {
++ pinctrl-single,pins = <0x0c8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_36_gpio_pd_pin: pinmux_P8_36_gpio_pd_pin {
++ pinctrl-single,pins = <0x0c8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_36_pwm_pin: pinmux_P8_36_pwm_pin {
++ pinctrl-single,pins = <0x0c8 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P8_36_hdmi_pin: pinmux_P8_36_hdmi_pin {
++ pinctrl-single,pins = <0x0c8 0x08>; }; /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_37 (ZCZ ball U1 ) hdmi */
++ P8_37_default_pin: pinmux_P8_37_default_pin {
++ pinctrl-single,pins = <0x0c0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_37_gpio_pin: pinmux_P8_37_gpio_pin {
++ pinctrl-single,pins = <0x0c0 0x2F>; }; /* Mode 7, RxActive */
++ P8_37_gpio_pu_pin: pinmux_P8_37_gpio_pu_pin {
++ pinctrl-single,pins = <0x0c0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_37_gpio_pd_pin: pinmux_P8_37_gpio_pd_pin {
++ pinctrl-single,pins = <0x0c0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_37_uart_pin: pinmux_P8_37_uart_pin {
++ pinctrl-single,pins = <0x0c0 0x04>; }; /* Mode 4, Pull-Down*/
++ P8_37_pwm_pin: pinmux_P8_37_pwm_pin {
++ pinctrl-single,pins = <0x0c0 0x02>; }; /* Mode 2, Pull-Down*/
++ P8_37_hdmi_pin: pinmux_P8_37_hdmi_pin {
++ pinctrl-single,pins = <0x0c0 0x08>; }; /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++
++ /* P8_38 (ZCZ ball U2 ) hdmi */
++ P8_38_default_pin: pinmux_P8_38_default_pin {
++ pinctrl-single,pins = <0x0c4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_38_gpio_pin: pinmux_P8_38_gpio_pin {
++ pinctrl-single,pins = <0x0c4 0x2F>; }; /* Mode 7, RxActive */
++ P8_38_gpio_pu_pin: pinmux_P8_38_gpio_pu_pin {
++ pinctrl-single,pins = <0x0c4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_38_gpio_pd_pin: pinmux_P8_38_gpio_pd_pin {
++ pinctrl-single,pins = <0x0c4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_38_uart_pin: pinmux_P8_38_uart_pin {
++ pinctrl-single,pins = <0x0c4 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P8_38_pwm_pin: pinmux_P8_38_pwm_pin {
++ pinctrl-single,pins = <0x0c4 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P8_38_hdmi_pin: pinmux_P8_38_hdmi_pin {
++ pinctrl-single,pins = <0x0c4 0x08>; }; /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++
++ /* P8_39 (ZCZ ball T3 ) hdmi */
++ P8_39_default_pin: pinmux_P8_39_default_pin {
++ pinctrl-single,pins = <0x0b8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_39_gpio_pin: pinmux_P8_39_gpio_pin {
++ pinctrl-single,pins = <0x0b8 0x2F>; }; /* Mode 7, RxActive */
++ P8_39_gpio_pu_pin: pinmux_P8_39_gpio_pu_pin {
++ pinctrl-single,pins = <0x0b8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_39_gpio_pd_pin: pinmux_P8_39_gpio_pd_pin {
++ pinctrl-single,pins = <0x0b8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_39_pruout_pin: pinmux_P8_39_pruout_pin {
++ pinctrl-single,pins = <0x0b8 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_39_pruin_pin: pinmux_P8_39_pruin_pin {
++ pinctrl-single,pins = <0x0b8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_39_hdmi_pin: pinmux_P8_39_hdmi_pin {
++ pinctrl-single,pins = <0x0b8 0x08>; }; /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_40 (ZCZ ball T4 ) hdmi */
++ P8_40_default_pin: pinmux_P8_40_default_pin {
++ pinctrl-single,pins = <0x0bc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_40_gpio_pin: pinmux_P8_40_gpio_pin {
++ pinctrl-single,pins = <0x0bc 0x2F>; }; /* Mode 7, RxActive */
++ P8_40_gpio_pu_pin: pinmux_P8_40_gpio_pu_pin {
++ pinctrl-single,pins = <0x0bc 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_40_gpio_pd_pin: pinmux_P8_40_gpio_pd_pin {
++ pinctrl-single,pins = <0x0bc 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_40_pruout_pin: pinmux_P8_40_pruout_pin {
++ pinctrl-single,pins = <0x0bc 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_40_pruin_pin: pinmux_P8_40_pruin_pin {
++ pinctrl-single,pins = <0x0bc 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_40_hdmi_pin: pinmux_P8_40_hdmi_pin {
++ pinctrl-single,pins = <0x0bc 0x08>; }; /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_41 (ZCZ ball T1 ) hdmi */
++ P8_41_default_pin: pinmux_P8_41_default_pin {
++ pinctrl-single,pins = <0x0b0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_41_gpio_pin: pinmux_P8_41_gpio_pin {
++ pinctrl-single,pins = <0x0b0 0x2F>; }; /* Mode 7, RxActive */
++ P8_41_gpio_pu_pin: pinmux_P8_41_gpio_pu_pin {
++ pinctrl-single,pins = <0x0b0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_41_gpio_pd_pin: pinmux_P8_41_gpio_pd_pin {
++ pinctrl-single,pins = <0x0b0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_41_pruout_pin: pinmux_P8_41_pruout_pin {
++ pinctrl-single,pins = <0x0b0 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_41_pruin_pin: pinmux_P8_41_pruin_pin {
++ pinctrl-single,pins = <0x0b0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_41_hdmi_pin: pinmux_P8_41_hdmi_pin {
++ pinctrl-single,pins = <0x0b0 0x08>; }; /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_42 (ZCZ ball T2 ) hdmi */
++ P8_42_default_pin: pinmux_P8_42_default_pin {
++ pinctrl-single,pins = <0x0b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_42_gpio_pin: pinmux_P8_42_gpio_pin {
++ pinctrl-single,pins = <0x0b4 0x2F>; }; /* Mode 7, RxActive */
++ P8_42_gpio_pu_pin: pinmux_P8_42_gpio_pu_pin {
++ pinctrl-single,pins = <0x0b4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_42_gpio_pd_pin: pinmux_P8_42_gpio_pd_pin {
++ pinctrl-single,pins = <0x0b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_42_pruout_pin: pinmux_P8_42_pruout_pin {
++ pinctrl-single,pins = <0x0b4 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_42_pruin_pin: pinmux_P8_42_pruin_pin {
++ pinctrl-single,pins = <0x0b4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_42_hdmi_pin: pinmux_P8_42_hdmi_pin {
++ pinctrl-single,pins = <0x0b4 0x08>; }; /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_43 (ZCZ ball R3 ) hdmi */
++ P8_43_default_pin: pinmux_P8_43_default_pin {
++ pinctrl-single,pins = <0x0a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_43_gpio_pin: pinmux_P8_43_gpio_pin {
++ pinctrl-single,pins = <0x0a8 0x2F>; }; /* Mode 7, RxActive */
++ P8_43_gpio_pu_pin: pinmux_P8_43_gpio_pu_pin {
++ pinctrl-single,pins = <0x0a8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_43_gpio_pd_pin: pinmux_P8_43_gpio_pd_pin {
++ pinctrl-single,pins = <0x0a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_43_pruout_pin: pinmux_P8_43_pruout_pin {
++ pinctrl-single,pins = <0x0a8 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_43_pruin_pin: pinmux_P8_43_pruin_pin {
++ pinctrl-single,pins = <0x0a8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_43_pwm_pin: pinmux_P8_43_pwm_pin {
++ pinctrl-single,pins = <0x0a8 0x03>; }; /* Mode 3, Pull-Down */
++ P8_43_hdmi_pin: pinmux_P8_43_hdmi_pin {
++ pinctrl-single,pins = <0x0a8 0x08>; }; /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_44 (ZCZ ball R4 ) hdmi */
++ P8_44_default_pin: pinmux_P8_44_default_pin {
++ pinctrl-single,pins = <0x0ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_44_gpio_pin: pinmux_P8_44_gpio_pin {
++ pinctrl-single,pins = <0x0ac 0x2F>; }; /* Mode 7, RxActive */
++ P8_44_gpio_pu_pin: pinmux_P8_44_gpio_pu_pin {
++ pinctrl-single,pins = <0x0ac 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_44_gpio_pd_pin: pinmux_P8_44_gpio_pd_pin {
++ pinctrl-single,pins = <0x0ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_44_pruout_pin: pinmux_P8_44_pruout_pin {
++ pinctrl-single,pins = <0x0ac 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_44_pruin_pin: pinmux_P8_44_pruin_pin {
++ pinctrl-single,pins = <0x0ac 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_44_pwm_pin: pinmux_P8_44_pwm_pin {
++ pinctrl-single,pins = <0x0ac 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P8_44_hdmi_pin: pinmux_P8_44_hdmi_pin {
++ pinctrl-single,pins = <0x0ac 0x08>; }; /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_45 (ZCZ ball R1 ) hdmi */
++ P8_45_default_pin: pinmux_P8_45_default_pin {
++ pinctrl-single,pins = <0x0a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_45_gpio_pin: pinmux_P8_45_gpio_pin {
++ pinctrl-single,pins = <0x0a0 0x2F>; }; /* Mode 7, RxActive */
++ P8_45_gpio_pu_pin: pinmux_P8_45_gpio_pu_pin {
++ pinctrl-single,pins = <0x0a0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_45_gpio_pd_pin: pinmux_P8_45_gpio_pd_pin {
++ pinctrl-single,pins = <0x0a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_45_pruout_pin: pinmux_P8_45_pruout_pin {
++ pinctrl-single,pins = <0x0a0 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_45_pruin_pin: pinmux_P8_45_pruin_pin {
++ pinctrl-single,pins = <0x0a0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_45_pwm_pin: pinmux_P8_45_pwm_pin {
++ pinctrl-single,pins = <0x0a0 0x03>; }; /* Mode 3, Pull-Down*/
++ P8_45_hdmi_pin: pinmux_P8_45_hdmi_pin {
++ pinctrl-single,pins = <0x0a0 0x08>; }; /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /* P8_46 (ZCZ ball R2 ) hdmi */
++ P8_46_default_pin: pinmux_P8_46_default_pin {
++ pinctrl-single,pins = <0x0a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_46_gpio_pin: pinmux_P8_46_gpio_pin {
++ pinctrl-single,pins = <0x0a4 0x2F>; }; /* Mode 7, RxActive */
++ P8_46_gpio_pu_pin: pinmux_P8_46_gpio_pu_pin {
++ pinctrl-single,pins = <0x0a4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P8_46_gpio_pd_pin: pinmux_P8_46_gpio_pd_pin {
++ pinctrl-single,pins = <0x0a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P8_46_pruout_pin: pinmux_P8_46_pruout_pin {
++ pinctrl-single,pins = <0x0a4 0x05>; }; /* Mode 5, Pull-Down*/
++ P8_46_pruin_pin: pinmux_P8_46_pruin_pin {
++ pinctrl-single,pins = <0x0a4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P8_46_pwm_pin: pinmux_P8_46_pwm_pin {
++ pinctrl-single,pins = <0x0a4 0x03>; }; /* Mode 3, Pull-Down*/
++ P8_46_hdmi_pin: pinmux_P8_46_hdmi_pin {
++ pinctrl-single,pins = <0x0a4 0x08>; }; /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
++
++ /************************/
++ /* P9 Header */
++ /************************/
++
++ /* P9_01 GND */
++ /* P9_02 GND */
++ /* P9_03 3.3V */
++ /* P9_04 3.3V */
++ /* P9_05 VDD_5V */
++ /* P9_06 VDD_5V */
++ /* P9_07 SYS_5V */
++ /* P9_08 SYS_5V */
++ /* P9_09 PWR_BUT */
++ /* P9_10 (ZCZ ball A10) RESETn */
++
++ /* P9_11 (ZCZ ball T17) */
++ P9_11_default_pin: pinmux_P9_11_default_pin {
++ pinctrl-single,pins = <0x070 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_11_gpio_pin: pinmux_P9_11_gpio_pin {
++ pinctrl-single,pins = <0x070 0x2F>; }; /* Mode 7, RxActive */
++ P9_11_gpio_pu_pin: pinmux_P9_11_gpio_pu_pin {
++ pinctrl-single,pins = <0x070 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_11_gpio_pd_pin: pinmux_P9_11_gpio_pd_pin {
++ pinctrl-single,pins = <0x070 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_11_uart_pin: pinmux_P9_11_uart_pin {
++ pinctrl-single,pins = <0x070 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_12 (ZCZ ball U18) */
++ P9_12_default_pin: pinmux_P9_12_default_pin {
++ pinctrl-single,pins = <0x078 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_12_gpio_pin: pinmux_P9_12_gpio_pin {
++ pinctrl-single,pins = <0x078 0x2F>; }; /* Mode 7, RxActive */
++ P9_12_gpio_pu_pin: pinmux_P9_12_gpio_pu_pin {
++ pinctrl-single,pins = <0x078 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin {
++ pinctrl-single,pins = <0x078 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++
++ /* P9_13 (ZCZ ball U17) */
++ P9_13_default_pin: pinmux_P9_13_default_pin {
++ pinctrl-single,pins = <0x074 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_13_gpio_pin: pinmux_P9_13_gpio_pin {
++ pinctrl-single,pins = <0x074 0x2F>; }; /* Mode 7, RxActive */
++ P9_13_gpio_pu_pin: pinmux_P9_13_gpio_pu_pin {
++ pinctrl-single,pins = <0x074 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_13_gpio_pd_pin: pinmux_P9_13_gpio_pd_pin {
++ pinctrl-single,pins = <0x074 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_13_uart_pin: pinmux_P9_13_uart_pin {
++ pinctrl-single,pins = <0x074 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_14 (ZCZ ball U14) */
++ P9_14_default_pin: pinmux_P9_14_default_pin {
++ pinctrl-single,pins = <0x048 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_14_gpio_pin: pinmux_P9_14_gpio_pin {
++ pinctrl-single,pins = <0x048 0x2F>; }; /* Mode 7, RxActive */
++ P9_14_gpio_pu_pin: pinmux_P9_14_gpio_pu_pin {
++ pinctrl-single,pins = <0x048 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_14_gpio_pd_pin: pinmux_P9_14_gpio_pd_pin {
++ pinctrl-single,pins = <0x048 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_14_pwm_pin: pinmux_P9_14_pwm_pin {
++ pinctrl-single,pins = <0x048 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_15 (ZCZ ball R13) */
++ P9_15_default_pin: pinmux_P9_15_default_pin {
++ pinctrl-single,pins = <0x040 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_15_gpio_pin: pinmux_P9_15_gpio_pin {
++ pinctrl-single,pins = <0x040 0x2F>; }; /* Mode 7, RxActive */
++ P9_15_gpio_pu_pin: pinmux_P9_15_gpio_pu_pin {
++ pinctrl-single,pins = <0x040 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_15_gpio_pd_pin: pinmux_P9_15_gpio_pd_pin {
++ pinctrl-single,pins = <0x040 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_15_pwm_pin: pinmux_P9_15_pwm_pin {
++ pinctrl-single,pins = <0x040 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_16 (ZCZ ball T14) */
++ P9_16_default_pin: pinmux_P9_16_default_pin {
++ pinctrl-single,pins = <0x04c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_16_gpio_pin: pinmux_P9_16_gpio_pin {
++ pinctrl-single,pins = <0x04c 0x2F>; }; /* Mode 7, RxActive */
++ P9_16_gpio_pu_pin: pinmux_P9_16_gpio_pu_pin {
++ pinctrl-single,pins = <0x04c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_16_gpio_pd_pin: pinmux_P9_16_gpio_pd_pin {
++ pinctrl-single,pins = <0x04c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_16_pwm_pin: pinmux_P9_16_pwm_pin {
++ pinctrl-single,pins = <0x04c 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_17 (ZCZ ball A16) */
++ P9_17_default_pin: pinmux_P9_17_default_pin {
++ pinctrl-single,pins = <0x15c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_17_gpio_pin: pinmux_P9_17_gpio_pin {
++ pinctrl-single,pins = <0x15c 0x2F>; }; /* Mode 7, RxActive */
++ P9_17_gpio_pu_pin: pinmux_P9_17_gpio_pu_pin {
++ pinctrl-single,pins = <0x15c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_17_gpio_pd_pin: pinmux_P9_17_gpio_pd_pin {
++ pinctrl-single,pins = <0x15c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_17_spi_pin: pinmux_P9_17_spi_pin {
++ pinctrl-single,pins = <0x15c 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_17_i2c_pin: pinmux_P9_17_i2c_pin {
++ pinctrl-single,pins = <0x15c 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_17_pwm_pin: pinmux_P9_17_pwm_pin {
++ pinctrl-single,pins = <0x15c 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_18 (ZCZ ball B16) */
++ P9_18_default_pin: pinmux_P9_18_default_pin {
++ pinctrl-single,pins = <0x158 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_18_gpio_pin: pinmux_P9_18_gpio_pin {
++ pinctrl-single,pins = <0x158 0x2F>; }; /* Mode 7, RxActive */
++ P9_18_gpio_pu_pin: pinmux_P9_18_gpio_pu_pin {
++ pinctrl-single,pins = <0x158 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_18_gpio_pd_pin: pinmux_P9_18_gpio_pd_pin {
++ pinctrl-single,pins = <0x158 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_18_spi_pin: pinmux_P9_18_spi_pin {
++ pinctrl-single,pins = <0x158 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_18_i2c_pin: pinmux_P9_18_i2c_pin {
++ pinctrl-single,pins = <0x158 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_18_pwm_pin: pinmux_P9_18_pwm_pin {
++ pinctrl-single,pins = <0x158 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_19 (ZCZ ball D17) */
++ P9_19_default_pin: pinmux_P9_19_default_pin {
++ pinctrl-single,pins = <0x17c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_19_gpio_pin: pinmux_P9_19_gpio_pin {
++ pinctrl-single,pins = <0x17c 0x2F>; }; /* Mode 7, RxActive */
++ P9_19_gpio_pu_pin: pinmux_P9_19_gpio_pu_pin {
++ pinctrl-single,pins = <0x17c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_19_gpio_pd_pin: pinmux_P9_19_gpio_pd_pin {
++ pinctrl-single,pins = <0x17c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_19_can_pin: pinmux_P9_19_can_pin {
++ pinctrl-single,pins = <0x17c 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_19_i2c_pin: pinmux_P9_19_i2c_pin {
++ pinctrl-single,pins = <0x17c 0x73>; }; /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) */
++
++ /* P9_20 (ZCZ ball D18) */
++ P9_20_default_pin: pinmux_P9_20_default_pin {
++ pinctrl-single,pins = <0x178 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_20_gpio_pin: pinmux_P9_20_gpio_pin {
++ pinctrl-single,pins = <0x178 0x2F>; }; /* Mode 7, RxActive */
++ P9_20_gpio_pu_pin: pinmux_P9_20_gpio_pu_pin {
++ pinctrl-single,pins = <0x178 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_20_gpio_pd_pin: pinmux_P9_20_gpio_pd_pin {
++ pinctrl-single,pins = <0x178 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_20_can_pin: pinmux_P9_20_can_pin {
++ pinctrl-single,pins = <0x178 0x12>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_20_i2c_pin: pinmux_P9_20_i2c_pin {
++ pinctrl-single,pins = <0x178 0x73>; }; /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) */
++
++ /* P9_21 (ZCZ ball B17) */
++ P9_21_default_pin: pinmux_P9_21_default_pin {
++ pinctrl-single,pins = <0x154 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_21_gpio_pin: pinmux_P9_21_gpio_pin {
++ pinctrl-single,pins = <0x154 0x2F>; }; /* Mode 7, RxActive */
++ P9_21_gpio_pu_pin: pinmux_P9_21_gpio_pu_pin {
++ pinctrl-single,pins = <0x154 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_21_gpio_pd_pin: pinmux_P9_21_gpio_pd_pin {
++ pinctrl-single,pins = <0x154 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_21_spi_pin: pinmux_P9_21_spi_pin {
++ pinctrl-single,pins = <0x154 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_21_uart_pin: pinmux_P9_21_uart_pin {
++ pinctrl-single,pins = <0x154 0x31>; }; /* Mode 1, Pull-Up, RxActive */
++ P9_21_i2c_pin: pinmux_P9_21_i2c_pin {
++ pinctrl-single,pins = <0x154 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_21_pwm_pin: pinmux_P9_21_pwm_pin {
++ pinctrl-single,pins = <0x154 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_22 (ZCZ ball A17) */
++ P9_22_default_pin: pinmux_P9_22_default_pin {
++ pinctrl-single,pins = <0x150 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_22_gpio_pin: pinmux_P9_22_gpio_pin {
++ pinctrl-single,pins = <0x150 0x2F>; }; /* Mode 7, RxActive */
++ P9_22_gpio_pu_pin: pinmux_P9_22_gpio_pu_pin {
++ pinctrl-single,pins = <0x150 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_22_gpio_pd_pin: pinmux_P9_22_gpio_pd_pin {
++ pinctrl-single,pins = <0x150 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_22_spi_pin: pinmux_P9_22_spi_pin {
++ pinctrl-single,pins = <0x150 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_22_uart_pin: pinmux_P9_22_uart_pin {
++ pinctrl-single,pins = <0x150 0x31>; }; /* Mode 1, Pull-Up, RxActive */
++ P9_22_i2c_pin: pinmux_P9_22_i2c_pin {
++ pinctrl-single,pins = <0x150 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_22_pwm_pin: pinmux_P9_22_pwm_pin {
++ pinctrl-single,pins = <0x150 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++
++ /* P9_23 (ZCZ ball V14) */
++ P9_23_default_pin: pinmux_P9_23_default_pin {
++ pinctrl-single,pins = <0x044 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_23_gpio_pin: pinmux_P9_23_gpio_pin {
++ pinctrl-single,pins = <0x044 0x2F>; }; /* Mode 7, RxActive */
++ P9_23_gpio_pu_pin: pinmux_P9_23_gpio_pu_pin {
++ pinctrl-single,pins = <0x044 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_23_gpio_pd_pin: pinmux_P9_23_gpio_pd_pin {
++ pinctrl-single,pins = <0x044 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_23_pwm_pin: pinmux_P9_23_pwm_pin {
++ pinctrl-single,pins = <0x044 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_24 (ZCZ ball D15) */
++ P9_24_default_pin: pinmux_P9_24_default_pin {
++ pinctrl-single,pins = <0x184 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_24_gpio_pin: pinmux_P9_24_gpio_pin {
++ pinctrl-single,pins = <0x184 0x2F>; }; /* Mode 7, RxActive */
++ P9_24_gpio_pu_pin: pinmux_P9_24_gpio_pu_pin {
++ pinctrl-single,pins = <0x184 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_24_gpio_pd_pin: pinmux_P9_24_gpio_pd_pin {
++ pinctrl-single,pins = <0x184 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_24_uart_pin: pinmux_P9_24_uart_pin {
++ pinctrl-single,pins = <0x184 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_24_can_pin: pinmux_P9_24_can_pin {
++ pinctrl-single,pins = <0x184 0x32>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_24_i2c_pin: pinmux_P9_24_i2c_pin {
++ pinctrl-single,pins = <0x184 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++ P9_24_pruin_pin: pinmux_P9_24_pruin_pin {
++ pinctrl-single,pins = <0x184 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_25 (ZCZ ball A14) Audio */
++ P9_25_default_pin: pinmux_P9_25_default_pin {
++ pinctrl-single,pins = <0x1ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_25_gpio_pin: pinmux_P9_25_gpio_pin {
++ pinctrl-single,pins = <0x1ac 0x2F>; }; /* Mode 7, RxActive */
++ P9_25_gpio_pu_pin: pinmux_P9_25_gpio_pu_pin {
++ pinctrl-single,pins = <0x1ac 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_25_gpio_pd_pin: pinmux_P9_25_gpio_pd_pin {
++ pinctrl-single,pins = <0x1ac 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_25_qep_pin: pinmux_P9_25_qep_pin {
++ pinctrl-single,pins = <0x1ac 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_25_pruout_pin: pinmux_P9_25_pruout_pin {
++ pinctrl-single,pins = <0x1ac 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_25_pruin_pin: pinmux_P9_25_pruin_pin {
++ pinctrl-single,pins = <0x1ac 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_25_audio_pin: pinmux_P9_25_audio_pin {
++ pinctrl-single,pins = <0x1ac (PIN_INPUT_PULLUP | MUX_MODE0)>; }; /* mcasp0_ahclkx.mcasp0_ahclkx */
++
++ /* P9_26 (ZCZ ball D16) */
++ P9_26_default_pin: pinmux_P9_26_default_pin {
++ pinctrl-single,pins = <0x180 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_26_gpio_pin: pinmux_P9_26_gpio_pin {
++ pinctrl-single,pins = <0x180 0x2F>; }; /* Mode 7, RxActive */
++ P9_26_gpio_pu_pin: pinmux_P9_26_gpio_pu_pin {
++ pinctrl-single,pins = <0x180 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_26_gpio_pd_pin: pinmux_P9_26_gpio_pd_pin {
++ pinctrl-single,pins = <0x180 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_26_uart_pin: pinmux_P9_26_uart_pin {
++ pinctrl-single,pins = <0x180 0x30>; }; /* Mode 0, Pull-Up, RxActive */
++ P9_26_can_pin: pinmux_P9_26_can_pin {
++ pinctrl-single,pins = <0x180 0x12>; }; /* Mode 2, Pull-Up, RxActive */
++ P9_26_i2c_pin: pinmux_P9_26_i2c_pin {
++ pinctrl-single,pins = <0x180 0x33>; }; /* Mode 3, Pull-Up, RxActive */
++ P9_26_pruin_pin: pinmux_P9_26_pruin_pin {
++ pinctrl-single,pins = <0x180 0x36>; }; /* Mode 6, Pull-Up, RxActive */
++
++ /* P9_27 (ZCZ ball C13) */
++ P9_27_default_pin: pinmux_P9_27_default_pin {
++ pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_27_gpio_pin: pinmux_P9_27_gpio_pin {
++ pinctrl-single,pins = <0x1a4 0x2F>; }; /* Mode 7, RxActive */
++ P9_27_gpio_pu_pin: pinmux_P9_27_gpio_pu_pin {
++ pinctrl-single,pins = <0x1a4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_27_gpio_pd_pin: pinmux_P9_27_gpio_pd_pin {
++ pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_27_qep_pin: pinmux_P9_27_qep_pin {
++ pinctrl-single,pins = <0x1a4 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_27_pruout_pin: pinmux_P9_27_pruout_pin {
++ pinctrl-single,pins = <0x1a4 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_27_pruin_pin: pinmux_P9_27_pruin_pin {
++ pinctrl-single,pins = <0x1a4 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_28 (ZCZ ball C12) Audio */
++ P9_28_default_pin: pinmux_P9_28_default_pin {
++ pinctrl-single,pins = <0x19c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_28_gpio_pin: pinmux_P9_28_gpio_pin {
++ pinctrl-single,pins = <0x19c 0x2F>; }; /* Mode 7, RxActive */
++ P9_28_gpio_pu_pin: pinmux_P9_28_gpio_pu_pin {
++ pinctrl-single,pins = <0x19c 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_28_gpio_pd_pin: pinmux_P9_28_gpio_pd_pin {
++ pinctrl-single,pins = <0x19c 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_28_pwm_pin: pinmux_P9_28_pwm_pin {
++ pinctrl-single,pins = <0x19c 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_28_spi_pin: pinmux_P9_28_spi_pin {
++ pinctrl-single,pins = <0x19c 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_28_pwm2_pin: pinmux_P9_28_pwm2_pin {
++ pinctrl-single,pins = <0x19c 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P9_28_pruout_pin: pinmux_P9_28_pruout_pin {
++ pinctrl-single,pins = <0x19c 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_28_pruin_pin: pinmux_P9_28_pruin_pin {
++ pinctrl-single,pins = <0x19c 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_28_audio_pin: pinmux_P9_28_audio_pin {
++ pinctrl-single,pins = <0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)>; }; /* mcasp0_ahclkr.mcasp0_axr2 */
++
++ /* P9_29 (ZCZ ball B13) Audio */
++ P9_29_default_pin: pinmux_P9_29_default_pin {
++ pinctrl-single,pins = <0x194 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_29_gpio_pin: pinmux_P9_29_gpio_pin {
++ pinctrl-single,pins = <0x194 0x2F>; }; /* Mode 7, RxActive */
++ P9_29_gpio_pu_pin: pinmux_P9_29_gpio_pu_pin {
++ pinctrl-single,pins = <0x194 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_29_gpio_pd_pin: pinmux_P9_29_gpio_pd_pin {
++ pinctrl-single,pins = <0x194 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_29_pwm_pin: pinmux_P9_29_pwm_pin {
++ pinctrl-single,pins = <0x194 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_29_spi_pin: pinmux_P9_29_spi_pin {
++ pinctrl-single,pins = <0x194 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_29_pruout_pin: pinmux_P9_29_pruout_pin {
++ pinctrl-single,pins = <0x194 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_29_pruin_pin: pinmux_P9_29_pruin_pin {
++ pinctrl-single,pins = <0x194 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_29_audio_pin: pinmux_P9_29_audio_pin {
++ pinctrl-single,pins = <0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0)>; }; /* mcasp0_fsx.mcasp0_fsx */
++
++ /* P9_30 (ZCZ ball D12) */
++ P9_30_default_pin: pinmux_P9_30_default_pin {
++ pinctrl-single,pins = <0x198 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_30_gpio_pin: pinmux_P9_30_gpio_pin {
++ pinctrl-single,pins = <0x198 0x2F>; }; /* Mode 7, RxActive */
++ P9_30_gpio_pu_pin: pinmux_P9_30_gpio_pu_pin {
++ pinctrl-single,pins = <0x198 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_30_gpio_pd_pin: pinmux_P9_30_gpio_pd_pin {
++ pinctrl-single,pins = <0x198 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_30_pwm_pin: pinmux_P9_30_pwm_pin {
++ pinctrl-single,pins = <0x198 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_30_spi_pin: pinmux_P9_30_spi_pin {
++ pinctrl-single,pins = <0x198 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_30_pruout_pin: pinmux_P9_30_pruout_pin {
++ pinctrl-single,pins = <0x198 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_30_pruin_pin: pinmux_P9_30_pruin_pin {
++ pinctrl-single,pins = <0x198 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_31 (ZCZ ball A13) Audio */
++ P9_31_default_pin: pinmux_P9_31_default_pin {
++ pinctrl-single,pins = <0x190 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_31_gpio_pin: pinmux_P9_31_gpio_pin {
++ pinctrl-single,pins = <0x190 0x2F>; }; /* Mode 7, RxActive */
++ P9_31_gpio_pu_pin: pinmux_P9_31_gpio_pu_pin {
++ pinctrl-single,pins = <0x190 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_31_gpio_pd_pin: pinmux_P9_31_gpio_pd_pin {
++ pinctrl-single,pins = <0x190 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_31_pwm_pin: pinmux_P9_31_pwm_pin {
++ pinctrl-single,pins = <0x190 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_31_spi_pin: pinmux_P9_31_spi_pin {
++ pinctrl-single,pins = <0x190 0x23>; }; /* Mode 3, Pull-Down, RxActive */
++ P9_31_pruout_pin: pinmux_P9_31_pruout_pin {
++ pinctrl-single,pins = <0x190 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_31_pruin_pin: pinmux_P9_31_pruin_pin {
++ pinctrl-single,pins = <0x190 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++ P9_31_audio_pin: pinmux_P9_31_audio_pin {
++ pinctrl-single,pins = <0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)>; }; /* mcasp0_aclkx.mcasp0_aclkx */
++
++ /* P9_32 VADC */
++ /* P9_33 (ZCZ ball C8 ) AIN4 */
++ /* P9_34 AGND */
++ /* P9_35 (ZCZ ball A8 ) AIN6 */
++ /* P9_36 (ZCZ ball B8 ) AIN5 */
++ /* P9_37 (ZCZ ball B7 ) AIN2 */
++ /* P9_38 (ZCZ ball A7 ) AIN3 */
++ /* P9_39 (ZCZ ball B6 ) AIN0 */
++ /* P9_40 (ZCZ ball C7 ) AIN1 */
++
++ /* P9_41 (ZCZ ball D14) */
++ P9_41_default_pin: pinmux_P9_41_default_pin {
++ pinctrl-single,pins = <0x1b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_41_gpio_pin: pinmux_P9_41_gpio_pin {
++ pinctrl-single,pins = <0x1b4 0x2F>; }; /* Mode 7, RxActive */
++ P9_41_gpio_pu_pin: pinmux_P9_41_gpio_pu_pin {
++ pinctrl-single,pins = <0x1b4 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_41_gpio_pd_pin: pinmux_P9_41_gpio_pd_pin {
++ pinctrl-single,pins = <0x1b4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_41_timer_pin: pinmux_P9_41_timer_pin {
++ pinctrl-single,pins = <0x1b4 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++ P9_41_pruin_pin: pinmux_P9_41_pruin_pin {
++ pinctrl-single,pins = <0x1b4 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++
++ /* P9_41.1 */
++ /* P9_91 (ZCZ ball D13) */
++ P9_91_default_pin: pinmux_P9_91_default_pin {
++ pinctrl-single,pins = <0x1a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_91_gpio_pin: pinmux_P9_91_gpio_pin {
++ pinctrl-single,pins = <0x1a8 0x2F>; }; /* Mode 7, RxActive */
++ P9_91_gpio_pu_pin: pinmux_P9_91_gpio_pu_pin {
++ pinctrl-single,pins = <0x1a8 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_91_gpio_pd_pin: pinmux_P9_91_gpio_pd_pin {
++ pinctrl-single,pins = <0x1a8 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_91_qep_pin: pinmux_P9_91_qep_pin {
++ pinctrl-single,pins = <0x1a8 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_91_pruout_pin: pinmux_P9_91_pruout_pin {
++ pinctrl-single,pins = <0x1a8 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_91_pruin_pin: pinmux_P9_91_pruin_pin {
++ pinctrl-single,pins = <0x1a8 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_42 (ZCZ ball C18) */
++ P9_42_default_pin: pinmux_P9_42_default_pin {
++ pinctrl-single,pins = <0x164 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_42_gpio_pin: pinmux_P9_42_gpio_pin {
++ pinctrl-single,pins = <0x164 0x2F>; }; /* Mode 7, RxActive */
++ P9_42_gpio_pu_pin: pinmux_P9_42_gpio_pu_pin {
++ pinctrl-single,pins = <0x164 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_42_gpio_pd_pin: pinmux_P9_42_gpio_pd_pin {
++ pinctrl-single,pins = <0x164 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_42_pwm_pin: pinmux_P9_42_pwm_pin {
++ pinctrl-single,pins = <0x164 0x20>; }; /* Mode 0, Pull-Down, RxActive */
++ P9_42_uart_pin: pinmux_P9_42_uart_pin {
++ pinctrl-single,pins = <0x164 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_42_spics_pin: pinmux_P9_42_spics_pin {
++ pinctrl-single,pins = <0x164 0x22>; }; /* Mode 2, Pull-Down, RxActive */
++ P9_42_spiclk_pin: pinmux_P9_42_spiclk_pin {
++ pinctrl-single,pins = <0x164 0x24>; }; /* Mode 4, Pull-Down, RxActive */
++
++ /* P9_42.1 */
++ /* P9_92 (ZCZ ball B12) */
++ P9_92_default_pin: pinmux_P9_92_default_pin {
++ pinctrl-single,pins = <0x1a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_92_gpio_pin: pinmux_P9_92_gpio_pin {
++ pinctrl-single,pins = <0x1a0 0x2F>; }; /* Mode 7, RxActive */
++ P9_92_gpio_pu_pin: pinmux_P9_92_gpio_pu_pin {
++ pinctrl-single,pins = <0x1a0 0x37>; }; /* Mode 7, Pull-Up, RxActive */
++ P9_92_gpio_pd_pin: pinmux_P9_92_gpio_pd_pin {
++ pinctrl-single,pins = <0x1a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
++ P9_92_qep_pin: pinmux_P9_92_qep_pin {
++ pinctrl-single,pins = <0x1a0 0x21>; }; /* Mode 1, Pull-Down, RxActive */
++ P9_92_pruout_pin: pinmux_P9_92_pruout_pin {
++ pinctrl-single,pins = <0x1a0 0x25>; }; /* Mode 5, Pull-Down, RxActive */
++ P9_92_pruin_pin: pinmux_P9_92_pruin_pin {
++ pinctrl-single,pins = <0x1a0 0x26>; }; /* Mode 6, Pull-Down, RxActive */
++
++ /* P9_43 GND */
++ /* P9_44 GND */
++ /* P9_45 GND */
++ /* P9_46 GND */
++};
++
++/**********************************************************************/
++/* Pin Multiplex Helpers */
++/* */
++/* These provide userspace runtime pin configuration for the */
++/* BeagleBone cape expansion headers */
++/**********************************************************************/
++
++&ocp {
++ /************************/
++ /* P8 Header */
++ /************************/
++
++ P8_07_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
++ pinctrl-0 = <&P8_07_default_pin>;
++ pinctrl-1 = <&P8_07_gpio_pin>;
++ pinctrl-2 = <&P8_07_gpio_pu_pin>;
++ pinctrl-3 = <&P8_07_gpio_pd_pin>;
++ pinctrl-4 = <&P8_07_timer_pin>;
++ };
++
++ P8_08_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
++ pinctrl-0 = <&P8_08_default_pin>;
++ pinctrl-1 = <&P8_08_gpio_pin>;
++ pinctrl-2 = <&P8_08_gpio_pu_pin>;
++ pinctrl-3 = <&P8_08_gpio_pd_pin>;
++ pinctrl-4 = <&P8_08_timer_pin>;
++ };
++
++ P8_09_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
++ pinctrl-0 = <&P8_09_default_pin>;
++ pinctrl-1 = <&P8_09_gpio_pin>;
++ pinctrl-2 = <&P8_09_gpio_pu_pin>;
++ pinctrl-3 = <&P8_09_gpio_pd_pin>;
++ pinctrl-4 = <&P8_09_timer_pin>;
++ };
++
++ P8_10_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
++ pinctrl-0 = <&P8_10_default_pin>;
++ pinctrl-1 = <&P8_10_gpio_pin>;
++ pinctrl-2 = <&P8_10_gpio_pu_pin>;
++ pinctrl-3 = <&P8_10_gpio_pd_pin>;
++ pinctrl-4 = <&P8_10_timer_pin>;
++ };
++
++ P8_11_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "qep";
++ pinctrl-0 = <&P8_11_default_pin>;
++ pinctrl-1 = <&P8_11_gpio_pin>;
++ pinctrl-2 = <&P8_11_gpio_pu_pin>;
++ pinctrl-3 = <&P8_11_gpio_pd_pin>;
++ pinctrl-4 = <&P8_11_pruout_pin>;
++ pinctrl-5 = <&P8_11_qep_pin>;
++ };
++
++ P8_12_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "qep";
++ pinctrl-0 = <&P8_12_default_pin>;
++ pinctrl-1 = <&P8_12_gpio_pin>;
++ pinctrl-2 = <&P8_12_gpio_pu_pin>;
++ pinctrl-3 = <&P8_12_gpio_pd_pin>;
++ pinctrl-4 = <&P8_12_pruout_pin>;
++ pinctrl-5 = <&P8_12_qep_pin>;
++ };
++
++ P8_13_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P8_13_default_pin>;
++ pinctrl-1 = <&P8_13_gpio_pin>;
++ pinctrl-2 = <&P8_13_gpio_pu_pin>;
++ pinctrl-3 = <&P8_13_gpio_pd_pin>;
++ pinctrl-4 = <&P8_13_pwm_pin>;
++ };
++
++ P8_14_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P8_14_default_pin>;
++ pinctrl-1 = <&P8_14_gpio_pin>;
++ pinctrl-2 = <&P8_14_gpio_pu_pin>;
++ pinctrl-3 = <&P8_14_gpio_pd_pin>;
++ pinctrl-4 = <&P8_14_pwm_pin>;
++ };
++
++ P8_15_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruin", "qep";
++ pinctrl-0 = <&P8_15_default_pin>;
++ pinctrl-1 = <&P8_15_gpio_pin>;
++ pinctrl-2 = <&P8_15_gpio_pu_pin>;
++ pinctrl-3 = <&P8_15_gpio_pd_pin>;
++ pinctrl-4 = <&P8_15_pruin_pin>;
++ pinctrl-5 = <&P8_15_qep_pin>;
++ };
++
++ P8_16_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruin", "qep";
++ pinctrl-0 = <&P8_16_default_pin>;
++ pinctrl-1 = <&P8_16_gpio_pin>;
++ pinctrl-2 = <&P8_16_gpio_pu_pin>;
++ pinctrl-3 = <&P8_16_gpio_pd_pin>;
++ pinctrl-4 = <&P8_16_pruin_pin>;
++ pinctrl-5 = <&P8_16_qep_pin>;
++ };
++
++ P8_17_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P8_17_default_pin>;
++ pinctrl-1 = <&P8_17_gpio_pin>;
++ pinctrl-2 = <&P8_17_gpio_pu_pin>;
++ pinctrl-3 = <&P8_17_gpio_pd_pin>;
++ pinctrl-4 = <&P8_17_pwm_pin>;
++ };
++
++ P8_18_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio";
++ pinctrl-0 = <&P8_18_default_pin>;
++ pinctrl-1 = <&P8_18_gpio_pin>;
++ pinctrl-2 = <&P8_18_gpio_pu_pin>;
++ pinctrl-3 = <&P8_18_gpio_pd_pin>;
++ };
++
++ P8_19_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P8_19_default_pin>;
++ pinctrl-1 = <&P8_19_gpio_pin>;
++ pinctrl-2 = <&P8_19_gpio_pu_pin>;
++ pinctrl-3 = <&P8_19_gpio_pd_pin>;
++ pinctrl-4 = <&P8_19_pwm_pin>;
++ };
++
++ P8_26_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio";
++ pinctrl-0 = <&P8_26_default_pin>;
++ pinctrl-1 = <&P8_26_gpio_pin>;
++ pinctrl-2 = <&P8_26_gpio_pu_pin>;
++ pinctrl-3 = <&P8_26_gpio_pd_pin>;
++ };
++
++ P8_27_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_27_default_pin>;
++ pinctrl-1 = <&P8_27_gpio_pin>;
++ pinctrl-2 = <&P8_27_gpio_pu_pin>;
++ pinctrl-3 = <&P8_27_gpio_pd_pin>;
++ pinctrl-4 = <&P8_27_pruout_pin>;
++ pinctrl-5 = <&P8_27_pruin_pin>;
++ pinctrl-6 = <&P8_27_hdmi_pin>;
++ };
++
++ P8_28_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_28_default_pin>;
++ pinctrl-1 = <&P8_28_gpio_pin>;
++ pinctrl-2 = <&P8_28_gpio_pu_pin>;
++ pinctrl-3 = <&P8_28_gpio_pd_pin>;
++ pinctrl-4 = <&P8_28_pruout_pin>;
++ pinctrl-5 = <&P8_28_pruin_pin>;
++ pinctrl-6 = <&P8_28_hdmi_pin>;
++ };
++
++ P8_29_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_29_default_pin>;
++ pinctrl-1 = <&P8_29_gpio_pin>;
++ pinctrl-2 = <&P8_29_gpio_pu_pin>;
++ pinctrl-3 = <&P8_29_gpio_pd_pin>;
++ pinctrl-4 = <&P8_29_pruout_pin>;
++ pinctrl-5 = <&P8_29_pruin_pin>;
++ pinctrl-6 = <&P8_29_hdmi_pin>;
++ };
++
++ P8_30_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_30_default_pin>;
++ pinctrl-1 = <&P8_30_gpio_pin>;
++ pinctrl-2 = <&P8_30_gpio_pu_pin>;
++ pinctrl-3 = <&P8_30_gpio_pd_pin>;
++ pinctrl-4 = <&P8_30_pruout_pin>;
++ pinctrl-5 = <&P8_30_pruin_pin>;
++ pinctrl-6 = <&P8_30_hdmi_pin>;
++ };
++
++ P8_31_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","uart", "hdmi";
++ pinctrl-0 = <&P8_31_default_pin>;
++ pinctrl-1 = <&P8_31_gpio_pin>;
++ pinctrl-2 = <&P8_31_gpio_pu_pin>;
++ pinctrl-3 = <&P8_31_gpio_pd_pin>;
++ pinctrl-4 = <&P8_31_uart_pin>;
++ pinctrl-5 = <&P8_31_hdmi_pin>;
++ };
++
++ P8_32_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "hdmi";
++ pinctrl-0 = <&P8_32_default_pin>;
++ pinctrl-1 = <&P8_32_gpio_pin>;
++ pinctrl-2 = <&P8_32_gpio_pu_pin>;
++ pinctrl-3 = <&P8_32_gpio_pd_pin>;
++ pinctrl-4 = <&P8_32_hdmi_pin>;
++ };
++
++ P8_33_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "hdmi";
++ pinctrl-0 = <&P8_33_default_pin>;
++ pinctrl-1 = <&P8_33_gpio_pin>;
++ pinctrl-2 = <&P8_33_gpio_pu_pin>;
++ pinctrl-3 = <&P8_33_gpio_pd_pin>;
++ pinctrl-4 = <&P8_33_hdmi_pin>;
++ };
++
++ P8_34_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","pwm", "hdmi";
++ pinctrl-0 = <&P8_34_default_pin>;
++ pinctrl-1 = <&P8_34_gpio_pin>;
++ pinctrl-2 = <&P8_34_gpio_pu_pin>;
++ pinctrl-3 = <&P8_34_gpio_pd_pin>;
++ pinctrl-4 = <&P8_34_pwm_pin>;
++ pinctrl-5 = <&P8_34_hdmi_pin>;
++ };
++
++ P8_35_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "hdmi";
++ pinctrl-0 = <&P8_35_default_pin>;
++ pinctrl-1 = <&P8_35_gpio_pin>;
++ pinctrl-2 = <&P8_35_gpio_pu_pin>;
++ pinctrl-3 = <&P8_35_gpio_pd_pin>;
++ pinctrl-4 = <&P8_35_hdmi_pin>;
++ };
++
++ P8_36_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","pwm", "hdmi";
++ pinctrl-0 = <&P8_36_default_pin>;
++ pinctrl-1 = <&P8_36_gpio_pin>;
++ pinctrl-2 = <&P8_36_gpio_pu_pin>;
++ pinctrl-3 = <&P8_36_gpio_pd_pin>;
++ pinctrl-4 = <&P8_36_pwm_pin>;
++ pinctrl-5 = <&P8_36_hdmi_pin>;
++ };
++
++ P8_37_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","uart","pwm", "hdmi";
++ pinctrl-0 = <&P8_37_default_pin>;
++ pinctrl-1 = <&P8_37_gpio_pin>;
++ pinctrl-2 = <&P8_37_gpio_pu_pin>;
++ pinctrl-3 = <&P8_37_gpio_pd_pin>;
++ pinctrl-4 = <&P8_37_uart_pin>;
++ pinctrl-5 = <&P8_37_pwm_pin>;
++ pinctrl-6 = <&P8_37_hdmi_pin>;
++ };
++
++ P8_38_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","uart","pwm", "hdmi";
++ pinctrl-0 = <&P8_38_default_pin>;
++ pinctrl-1 = <&P8_38_gpio_pin>;
++ pinctrl-2 = <&P8_38_gpio_pu_pin>;
++ pinctrl-3 = <&P8_38_gpio_pd_pin>;
++ pinctrl-4 = <&P8_38_uart_pin>;
++ pinctrl-5 = <&P8_38_pwm_pin>;
++ pinctrl-6 = <&P8_38_hdmi_pin>;
++ };
++
++ P8_39_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_39_default_pin>;
++ pinctrl-1 = <&P8_39_gpio_pin>;
++ pinctrl-2 = <&P8_39_gpio_pu_pin>;
++ pinctrl-3 = <&P8_39_gpio_pd_pin>;
++ pinctrl-4 = <&P8_39_pruout_pin>;
++ pinctrl-5 = <&P8_39_pruin_pin>;
++ pinctrl-6 = <&P8_39_hdmi_pin>;
++ };
++
++ P8_40_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_40_default_pin>;
++ pinctrl-1 = <&P8_40_gpio_pin>;
++ pinctrl-2 = <&P8_40_gpio_pu_pin>;
++ pinctrl-3 = <&P8_40_gpio_pd_pin>;
++ pinctrl-4 = <&P8_40_pruout_pin>;
++ pinctrl-5 = <&P8_40_pruin_pin>;
++ pinctrl-6 = <&P8_40_hdmi_pin>;
++ };
++
++ P8_41_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_41_default_pin>;
++ pinctrl-1 = <&P8_41_gpio_pin>;
++ pinctrl-2 = <&P8_41_gpio_pu_pin>;
++ pinctrl-3 = <&P8_41_gpio_pd_pin>;
++ pinctrl-4 = <&P8_41_pruout_pin>;
++ pinctrl-5 = <&P8_41_pruin_pin>;
++ pinctrl-6 = <&P8_41_hdmi_pin>;
++ };
++
++ P8_42_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
++ pinctrl-0 = <&P8_42_default_pin>;
++ pinctrl-1 = <&P8_42_gpio_pin>;
++ pinctrl-2 = <&P8_42_gpio_pu_pin>;
++ pinctrl-3 = <&P8_42_gpio_pd_pin>;
++ pinctrl-4 = <&P8_42_pruout_pin>;
++ pinctrl-5 = <&P8_42_pruin_pin>;
++ pinctrl-6 = <&P8_42_hdmi_pin>;
++ };
++
++ P8_43_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
++ pinctrl-0 = <&P8_43_default_pin>;
++ pinctrl-1 = <&P8_43_gpio_pin>;
++ pinctrl-2 = <&P8_43_gpio_pu_pin>;
++ pinctrl-3 = <&P8_43_gpio_pd_pin>;
++ pinctrl-4 = <&P8_43_pruout_pin>;
++ pinctrl-5 = <&P8_43_pruin_pin>;
++ pinctrl-6 = <&P8_43_pwm_pin>;
++ pinctrl-7 = <&P8_43_hdmi_pin>;
++ };
++
++ P8_44_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
++ pinctrl-0 = <&P8_44_default_pin>;
++ pinctrl-1 = <&P8_44_gpio_pin>;
++ pinctrl-2 = <&P8_44_gpio_pu_pin>;
++ pinctrl-3 = <&P8_44_gpio_pd_pin>;
++ pinctrl-4 = <&P8_44_pruout_pin>;
++ pinctrl-5 = <&P8_44_pruin_pin>;
++ pinctrl-6 = <&P8_44_pwm_pin>;
++ pinctrl-7 = <&P8_44_hdmi_pin>;
++ };
++
++ P8_45_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
++ pinctrl-0 = <&P8_45_default_pin>;
++ pinctrl-1 = <&P8_45_gpio_pin>;
++ pinctrl-2 = <&P8_45_gpio_pu_pin>;
++ pinctrl-3 = <&P8_45_gpio_pd_pin>;
++ pinctrl-4 = <&P8_45_pruout_pin>;
++ pinctrl-5 = <&P8_45_pruin_pin>;
++ pinctrl-6 = <&P8_45_pwm_pin>;
++ pinctrl-7 = <&P8_45_hdmi_pin>;
++ };
++
++ P8_46_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
++ pinctrl-0 = <&P8_46_default_pin>;
++ pinctrl-1 = <&P8_46_gpio_pin>;
++ pinctrl-2 = <&P8_46_gpio_pu_pin>;
++ pinctrl-3 = <&P8_46_gpio_pd_pin>;
++ pinctrl-4 = <&P8_46_pruout_pin>;
++ pinctrl-5 = <&P8_46_pruin_pin>;
++ pinctrl-6 = <&P8_46_pwm_pin>;
++ pinctrl-7 = <&P8_46_hdmi_pin>;
++ };
++
++ /************************/
++ /* P9 Header */
++ /************************/
++
++ P9_11_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart";
++ pinctrl-0 = <&P9_11_default_pin>;
++ pinctrl-1 = <&P9_11_gpio_pin>;
++ pinctrl-2 = <&P9_11_gpio_pu_pin>;
++ pinctrl-3 = <&P9_11_gpio_pd_pin>;
++ pinctrl-4 = <&P9_11_uart_pin>;
++ };
++
++ P9_12_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio";
++ pinctrl-0 = <&P9_12_default_pin>;
++ pinctrl-1 = <&P9_12_gpio_pin>;
++ pinctrl-2 = <&P9_12_gpio_pu_pin>;
++ pinctrl-3 = <&P9_12_gpio_pd_pin>;
++ };
++
++ P9_13_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart";
++ pinctrl-0 = <&P9_13_default_pin>;
++ pinctrl-1 = <&P9_13_gpio_pin>;
++ pinctrl-2 = <&P9_13_gpio_pu_pin>;
++ pinctrl-3 = <&P9_13_gpio_pd_pin>;
++ pinctrl-4 = <&P9_13_uart_pin>;
++ };
++
++ P9_14_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P9_14_default_pin>;
++ pinctrl-1 = <&P9_14_gpio_pin>;
++ pinctrl-2 = <&P9_14_gpio_pu_pin>;
++ pinctrl-3 = <&P9_14_gpio_pd_pin>;
++ pinctrl-4 = <&P9_14_pwm_pin>;
++ };
++
++ P9_15_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P9_15_default_pin>;
++ pinctrl-1 = <&P9_15_gpio_pin>;
++ pinctrl-2 = <&P9_15_gpio_pu_pin>;
++ pinctrl-3 = <&P9_15_gpio_pd_pin>;
++ pinctrl-4 = <&P9_15_pwm_pin>;
++ };
++
++ P9_16_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P9_16_default_pin>;
++ pinctrl-1 = <&P9_16_gpio_pin>;
++ pinctrl-2 = <&P9_16_gpio_pu_pin>;
++ pinctrl-3 = <&P9_16_gpio_pd_pin>;
++ pinctrl-4 = <&P9_16_pwm_pin>;
++ };
++
++ P9_17_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "i2c", "pwm";
++ pinctrl-0 = <&P9_17_default_pin>;
++ pinctrl-1 = <&P9_17_gpio_pin>;
++ pinctrl-2 = <&P9_17_gpio_pu_pin>;
++ pinctrl-3 = <&P9_17_gpio_pd_pin>;
++ pinctrl-4 = <&P9_17_spi_pin>;
++ pinctrl-5 = <&P9_17_i2c_pin>;
++ pinctrl-6 = <&P9_17_pwm_pin>;
++ };
++
++ P9_18_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "i2c", "pwm";
++ pinctrl-0 = <&P9_18_default_pin>;
++ pinctrl-1 = <&P9_18_gpio_pin>;
++ pinctrl-2 = <&P9_18_gpio_pu_pin>;
++ pinctrl-3 = <&P9_18_gpio_pd_pin>;
++ pinctrl-4 = <&P9_18_spi_pin>;
++ pinctrl-5 = <&P9_18_i2c_pin>;
++ pinctrl-6 = <&P9_18_pwm_pin>;
++ };
++
++ P9_19_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "can", "i2c";
++ pinctrl-0 = <&P9_19_default_pin>;
++ pinctrl-1 = <&P9_19_gpio_pin>;
++ pinctrl-2 = <&P9_19_gpio_pu_pin>;
++ pinctrl-3 = <&P9_19_gpio_pd_pin>;
++ pinctrl-4 = <&P9_19_can_pin>;
++ pinctrl-5 = <&P9_19_i2c_pin>;
++ };
++
++ P9_20_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "can", "i2c";
++ pinctrl-0 = <&P9_20_default_pin>;
++ pinctrl-1 = <&P9_20_gpio_pin>;
++ pinctrl-2 = <&P9_20_gpio_pu_pin>;
++ pinctrl-3 = <&P9_20_gpio_pd_pin>;
++ pinctrl-4 = <&P9_20_can_pin>;
++ pinctrl-5 = <&P9_20_i2c_pin>;
++ };
++
++ P9_21_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
++ pinctrl-0 = <&P9_21_default_pin>;
++ pinctrl-1 = <&P9_21_gpio_pin>;
++ pinctrl-2 = <&P9_21_gpio_pu_pin>;
++ pinctrl-3 = <&P9_21_gpio_pd_pin>;
++ pinctrl-4 = <&P9_21_spi_pin>;
++ pinctrl-5 = <&P9_21_uart_pin>;
++ pinctrl-6 = <&P9_21_i2c_pin>;
++ pinctrl-7 = <&P9_21_pwm_pin>;
++ };
++
++ P9_22_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
++ pinctrl-0 = <&P9_22_default_pin>;
++ pinctrl-1 = <&P9_22_gpio_pin>;
++ pinctrl-2 = <&P9_22_gpio_pu_pin>;
++ pinctrl-3 = <&P9_22_gpio_pd_pin>;
++ pinctrl-4 = <&P9_22_spi_pin>;
++ pinctrl-5 = <&P9_22_uart_pin>;
++ pinctrl-6 = <&P9_22_i2c_pin>;
++ pinctrl-7 = <&P9_22_pwm_pin>;
++ };
++
++ P9_23_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P9_23_default_pin>;
++ pinctrl-1 = <&P9_23_gpio_pin>;
++ pinctrl-2 = <&P9_23_gpio_pu_pin>;
++ pinctrl-3 = <&P9_23_gpio_pd_pin>;
++ pinctrl-4 = <&P9_23_pwm_pin>;
++ };
++
++ P9_24_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
++ pinctrl-0 = <&P9_24_default_pin>;
++ pinctrl-1 = <&P9_24_gpio_pin>;
++ pinctrl-2 = <&P9_24_gpio_pu_pin>;
++ pinctrl-3 = <&P9_24_gpio_pd_pin>;
++ pinctrl-4 = <&P9_24_uart_pin>;
++ pinctrl-5 = <&P9_24_can_pin>;
++ pinctrl-6 = <&P9_24_i2c_pin>;
++ pinctrl-7 = <&P9_24_pruin_pin>;
++ };
++
++ P9_25_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin", "audio";
++ pinctrl-0 = <&P9_25_default_pin>;
++ pinctrl-1 = <&P9_25_gpio_pin>;
++ pinctrl-2 = <&P9_25_gpio_pu_pin>;
++ pinctrl-3 = <&P9_25_gpio_pd_pin>;
++ pinctrl-4 = <&P9_25_qep_pin>;
++ pinctrl-5 = <&P9_25_pruout_pin>;
++ pinctrl-6 = <&P9_25_pruin_pin>;
++ pinctrl-7 = <&P9_25_audio_pin>;
++ };
++
++ P9_26_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
++ pinctrl-0 = <&P9_26_default_pin>;
++ pinctrl-1 = <&P9_26_gpio_pin>;
++ pinctrl-2 = <&P9_26_gpio_pu_pin>;
++ pinctrl-3 = <&P9_26_gpio_pd_pin>;
++ pinctrl-4 = <&P9_26_uart_pin>;
++ pinctrl-5 = <&P9_26_can_pin>;
++ pinctrl-6 = <&P9_26_i2c_pin>;
++ pinctrl-7 = <&P9_26_pruin_pin>;
++ };
++
++ P9_27_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin";
++ pinctrl-0 = <&P9_27_default_pin>;
++ pinctrl-1 = <&P9_27_gpio_pin>;
++ pinctrl-2 = <&P9_27_gpio_pu_pin>;
++ pinctrl-3 = <&P9_27_gpio_pd_pin>;
++ pinctrl-4 = <&P9_27_qep_pin>;
++ pinctrl-5 = <&P9_27_pruout_pin>;
++ pinctrl-6 = <&P9_27_pruin_pin>;
++ };
++
++ P9_28_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pwm2", "pruout", "pruin", "audio";
++ pinctrl-0 = <&P9_28_default_pin>;
++ pinctrl-1 = <&P9_28_gpio_pin>;
++ pinctrl-2 = <&P9_28_gpio_pu_pin>;
++ pinctrl-3 = <&P9_28_gpio_pd_pin>;
++ pinctrl-4 = <&P9_28_pwm_pin>;
++ pinctrl-5 = <&P9_28_spi_pin>;
++ pinctrl-6 = <&P9_28_pwm2_pin>;
++ pinctrl-7 = <&P9_28_pruout_pin>;
++ pinctrl-8 = <&P9_28_pruin_pin>;
++ pinctrl-9 = <&P9_28_audio_pin>;
++ };
++
++ P9_29_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin", "audio";
++ pinctrl-0 = <&P9_29_default_pin>;
++ pinctrl-1 = <&P9_29_gpio_pin>;
++ pinctrl-2 = <&P9_29_gpio_pu_pin>;
++ pinctrl-3 = <&P9_29_gpio_pd_pin>;
++ pinctrl-4 = <&P9_29_pwm_pin>;
++ pinctrl-5 = <&P9_29_spi_pin>;
++ pinctrl-6 = <&P9_29_pruout_pin>;
++ pinctrl-7 = <&P9_29_pruin_pin>;
++ pinctrl-8 = <&P9_29_audio_pin>;
++ };
++
++ P9_30_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_30_default_pin>;
++ pinctrl-1 = <&P9_30_gpio_pin>;
++ pinctrl-2 = <&P9_30_gpio_pu_pin>;
++ pinctrl-3 = <&P9_30_gpio_pd_pin>;
++ pinctrl-4 = <&P9_30_pwm_pin>;
++ pinctrl-5 = <&P9_30_spi_pin>;
++ pinctrl-6 = <&P9_30_pruout_pin>;
++ pinctrl-7 = <&P9_30_pruin_pin>;
++ };
++
++ P9_31_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin", "audio";
++ pinctrl-0 = <&P9_31_default_pin>;
++ pinctrl-1 = <&P9_31_gpio_pin>;
++ pinctrl-2 = <&P9_31_gpio_pu_pin>;
++ pinctrl-3 = <&P9_31_gpio_pd_pin>;
++ pinctrl-4 = <&P9_31_pwm_pin>;
++ pinctrl-5 = <&P9_31_spi_pin>;
++ pinctrl-6 = <&P9_31_pruout_pin>;
++ pinctrl-7 = <&P9_31_pruin_pin>;
++ pinctrl-8 = <&P9_31_audio_pin>;
++ };
++
++ P9_41_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer", "pruin";
++ pinctrl-0 = <&P9_41_default_pin>;
++ pinctrl-1 = <&P9_41_gpio_pin>;
++ pinctrl-2 = <&P9_41_gpio_pu_pin>;
++ pinctrl-3 = <&P9_41_gpio_pd_pin>;
++ pinctrl-4 = <&P9_41_timer_pin>;
++ pinctrl-5 = <&P9_41_pruin_pin>;
++ };
++
++ P9_91_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin";
++ pinctrl-0 = <&P9_91_default_pin>;
++ pinctrl-1 = <&P9_91_gpio_pin>;
++ pinctrl-2 = <&P9_91_gpio_pu_pin>;
++ pinctrl-3 = <&P9_91_gpio_pd_pin>;
++ pinctrl-4 = <&P9_91_qep_pin>;
++ pinctrl-5 = <&P9_91_pruout_pin>;
++ pinctrl-6 = <&P9_91_pruin_pin>;
++ };
++
++ P9_42_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "uart", "spics", "spiclk";
++ pinctrl-0 = <&P9_42_default_pin>;
++ pinctrl-1 = <&P9_42_gpio_pin>;
++ pinctrl-2 = <&P9_42_gpio_pu_pin>;
++ pinctrl-3 = <&P9_42_gpio_pd_pin>;
++ pinctrl-4 = <&P9_42_pwm_pin>;
++ pinctrl-5 = <&P9_42_uart_pin>;
++ pinctrl-6 = <&P9_42_spics_pin>;
++ pinctrl-7 = <&P9_42_spiclk_pin>;
++ };
++
++ P9_92_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin";
++ pinctrl-0 = <&P9_92_default_pin>;
++ pinctrl-1 = <&P9_92_gpio_pin>;
++ pinctrl-2 = <&P9_92_gpio_pu_pin>;
++ pinctrl-3 = <&P9_92_gpio_pd_pin>;
++ pinctrl-4 = <&P9_92_qep_pin>;
++ pinctrl-5 = <&P9_92_pruout_pin>;
++ pinctrl-6 = <&P9_92_pruin_pin>;
++ };
++
++ cape-universal {
++ compatible = "gpio-of-helper";
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <>;
++
++ P8_07 {
++ gpio-name = "P8_07";
++ gpio = <&gpio2 2 0>;
++ input;
++ dir-changeable;
++ };
++ P8_08 {
++ gpio-name = "P8_08";
++ gpio = <&gpio2 3 0>;
++ input;
++ dir-changeable;
++ };
++ P8_09 {
++ gpio-name = "P8_09";
++ gpio = <&gpio2 5 0>;
++ input;
++ dir-changeable;
++ };
++ P8_10 {
++ gpio-name = "P8_10";
++ gpio = <&gpio2 4 0>;
++ input;
++ dir-changeable;
++ };
++ P8_11 {
++ gpio-name = "P8_11";
++ gpio = <&gpio1 13 0>;
++ input;
++ dir-changeable;
++ };
++ P8_12 {
++ gpio-name = "P8_12";
++ gpio = <&gpio1 12 0>;
++ input;
++ dir-changeable;
++ };
++ P8_13 {
++ gpio-name = "P8_13";
++ gpio = <&gpio0 23 0>;
++ input;
++ dir-changeable;
++ };
++ P8_14 {
++ gpio-name = "P8_14";
++ gpio = <&gpio0 26 0>;
++ input;
++ dir-changeable;
++ };
++ P8_15 {
++ gpio-name = "P8_15";
++ gpio = <&gpio1 15 0>;
++ input;
++ dir-changeable;
++ };
++ P8_16 {
++ gpio-name = "P8_16";
++ gpio = <&gpio1 14 0>;
++ input;
++ dir-changeable;
++ };
++ P8_17 {
++ gpio-name = "P8_17";
++ gpio = <&gpio0 27 0>;
++ input;
++ dir-changeable;
++ };
++ P8_18 {
++ gpio-name = "P8_18";
++ gpio = <&gpio2 1 0>;
++ input;
++ dir-changeable;
++ };
++ P8_19 {
++ gpio-name = "P8_19";
++ gpio = <&gpio0 22 0>;
++ input;
++ dir-changeable;
++ };
++
++ P8_26 {
++ gpio-name = "P8_26";
++ gpio = <&gpio1 29 0>;
++ input;
++ dir-changeable;
++ };
++ P8_27 {
++ gpio-name = "P8_27";
++ gpio = <&gpio2 22 0>;
++ input;
++ dir-changeable;
++ };
++ P8_28 {
++ gpio-name = "P8_28";
++ gpio = <&gpio2 24 0>;
++ input;
++ dir-changeable;
++ };
++ P8_29 {
++ gpio-name = "P8_29";
++ gpio = <&gpio2 23 0>;
++ input;
++ dir-changeable;
++ };
++ P8_30 {
++ gpio-name = "P8_30";
++ gpio = <&gpio2 25 0>;
++ input;
++ dir-changeable;
++ };
++ P8_31 {
++ gpio-name = "P8_31";
++ gpio = <&gpio0 10 0>;
++ input;
++ dir-changeable;
++ };
++ P8_32 {
++ gpio-name = "P8_32";
++ gpio = <&gpio0 11 0>;
++ input;
++ dir-changeable;
++ };
++ P8_33 {
++ gpio-name = "P8_33";
++ gpio = <&gpio0 9 0>;
++ input;
++ dir-changeable;
++ };
++ P8_34 {
++ gpio-name = "P8_34";
++ gpio = <&gpio2 17 0>;
++ input;
++ dir-changeable;
++ };
++ P8_35 {
++ gpio-name = "P8_35";
++ gpio = <&gpio0 8 0>;
++ input;
++ dir-changeable;
++ };
++ P8_36 {
++ gpio-name = "P8_36";
++ gpio = <&gpio2 16 0>;
++ input;
++ dir-changeable;
++ };
++ P8_37 {
++ gpio-name = "P8_37";
++ gpio = <&gpio2 14 0>;
++ input;
++ dir-changeable;
++ };
++ P8_38 {
++ gpio-name = "P8_38";
++ gpio = <&gpio2 15 0>;
++ input;
++ dir-changeable;
++ };
++ P8_39 {
++ gpio-name = "P8_39";
++ gpio = <&gpio2 12 0>;
++ input;
++ dir-changeable;
++ };
++ P8_40 {
++ gpio-name = "P8_40";
++ gpio = <&gpio2 13 0>;
++ input;
++ dir-changeable;
++ };
++ P8_41 {
++ gpio-name = "P8_41";
++ gpio = <&gpio2 10 0>;
++ input;
++ dir-changeable;
++ };
++ P8_42 {
++ gpio-name = "P8_42";
++ gpio = <&gpio2 11 0>;
++ input;
++ dir-changeable;
++ };
++ P8_43 {
++ gpio-name = "P8_43";
++ gpio = <&gpio2 8 0>;
++ input;
++ dir-changeable;
++ };
++ P8_44 {
++ gpio-name = "P8_44";
++ gpio = <&gpio2 9 0>;
++ input;
++ dir-changeable;
++ };
++ P8_45 {
++ gpio-name = "P8_45";
++ gpio = <&gpio2 6 0>;
++ input;
++ dir-changeable;
++ };
++ P8_46 {
++ gpio-name = "P8_46";
++ gpio = <&gpio2 7 0>;
++ input;
++ dir-changeable;
++ };
++
++
++ P9_11 {
++ gpio-name = "P9_11";
++ gpio = <&gpio0 30 0>;
++ input;
++ dir-changeable;
++ };
++ P9_12 {
++ gpio-name = "P9_12";
++ gpio = <&gpio1 28 0>;
++ input;
++ dir-changeable;
++ };
++ P9_13 {
++ gpio-name = "P9_13";
++ gpio = <&gpio0 31 0>;
++ input;
++ dir-changeable;
++ };
++ P9_14 {
++ gpio-name = "P9_14";
++ gpio = <&gpio1 18 0>;
++ input;
++ dir-changeable;
++ };
++ P9_15 {
++ gpio-name = "P9_15";
++ gpio = <&gpio1 16 0>;
++ input;
++ dir-changeable;
++ };
++ P9_16 {
++ gpio-name = "P9_16";
++ gpio = <&gpio1 19 0>;
++ input;
++ dir-changeable;
++ };
++ P9_17 {
++ gpio-name = "P9_17";
++ gpio = <&gpio0 5 0>;
++ input;
++ dir-changeable;
++ };
++ P9_18 {
++ gpio-name = "P9_18";
++ gpio = <&gpio0 4 0>;
++ input;
++ dir-changeable;
++ };
++ P9_19 {
++ gpio-name = "P9_19";
++ gpio = <&gpio0 13 0>;
++ input;
++ dir-changeable;
++ };
++ P9_20 {
++ gpio-name = "P9_20";
++ gpio = <&gpio0 12 0>;
++ input;
++ dir-changeable;
++ };
++ P9_21 {
++ gpio-name = "P9_21";
++ gpio = <&gpio0 3 0>;
++ input;
++ dir-changeable;
++ };
++ P9_22 {
++ gpio-name = "P9_22";
++ gpio = <&gpio0 2 0>;
++ input;
++ dir-changeable;
++ };
++ P9_23 {
++ gpio-name = "P9_23";
++ gpio = <&gpio1 17 0>;
++ input;
++ dir-changeable;
++ };
++ P9_24 {
++ gpio-name = "P9_24";
++ gpio = <&gpio0 15 0>;
++ input;
++ dir-changeable;
++ };
++ P9_25 {
++ gpio-name = "P9_25";
++ gpio = <&gpio3 21 0>;
++ input;
++ dir-changeable;
++ };
++ P9_26 {
++ gpio-name = "P9_26";
++ gpio = <&gpio0 14 0>;
++ input;
++ dir-changeable;
++ };
++ P9_27 {
++ gpio-name = "P9_27";
++ gpio = <&gpio3 19 0>;
++ input;
++ dir-changeable;
++ };
++ P9_28 {
++ gpio-name = "P9_28";
++ gpio = <&gpio3 17 0>;
++ input;
++ dir-changeable;
++ };
++ P9_29 {
++ gpio-name = "P9_29";
++ gpio = <&gpio3 15 0>;
++ input;
++ dir-changeable;
++ };
++ P9_30 {
++ gpio-name = "P9_30";
++ gpio = <&gpio3 16 0>;
++ input;
++ dir-changeable;
++ };
++ P9_31 {
++ gpio-name = "P9_31";
++ gpio = <&gpio3 14 0>;
++ input;
++ dir-changeable;
++ };
++ P9_41 {
++ gpio-name = "P9_41";
++ gpio = <&gpio0 20 0>;
++ input;
++ dir-changeable;
++ };
++ P9_91 {
++ gpio-name = "P9_91";
++ gpio = <&gpio3 20 0>;
++ input;
++ dir-changeable;
++ };
++ P9_42 {
++ gpio-name = "P9_42";
++ gpio = <&gpio0 7 0>;
++ input;
++ dir-changeable;
++ };
++ P9_92 {
++ gpio-name = "P9_92";
++ gpio = <&gpio3 18 0>;
++ input;
++ dir-changeable;
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
+index 007b5e5..54a3b8d 100644
+--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
++++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
+@@ -6,6 +6,8 @@
+ * published by the Free Software Foundation.
+ */
+
++#include <dt-bindings/mfd/tps65217.h>
++
+ / {
+ cpus {
+ cpu@0 {
+@@ -29,14 +31,14 @@
+ compatible = "gpio-leds";
+
+ led2 {
+- label = "beaglebone:green:heartbeat";
++ label = "beaglebone:green:usr0";
+ gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led3 {
+- label = "beaglebone:green:mmc0";
++ label = "beaglebone:green:usr1";
+ gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+@@ -66,9 +68,6 @@
+ };
+
+ &am33xx_pinmux {
+- pinctrl-names = "default";
+- pinctrl-0 = <&clkout2_pin>;
+-
+ user_leds_s0: user_leds_s0 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+@@ -99,15 +98,11 @@
+ >;
+ };
+
+- clkout2_pin: pinmux_clkout2_pin {
+- pinctrl-single,pins = <
+- AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+- >;
+- };
+-
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
++ 0x108 (PIN_INPUT | MUX_MODE0) /* mii1_col.mii1_col */
++ 0x10c (PIN_INPUT | MUX_MODE0) /* mii1_crs.mii1_crs */
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
+ AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
+@@ -127,6 +122,8 @@
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 reset value */
++ 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+@@ -310,8 +307,23 @@
+ * by the hardware problems. (Tip: double-check by performing a current
+ * measurement after shutdown: it should be less than 1 mA.)
+ */
++
++ interrupts = <7>; /* NMI */
++ interrupt-parent = <&intc>;
++
+ ti,pmic-shutdown-controller;
+
++ charger {
++ interrupts = <TPS65217_IRQ_AC>, <TPS65217_IRQ_USB>;
++ interrupts-names = "AC", "USB";
++ status = "okay";
++ };
++
++ pwrbutton {
++ interrupts = <TPS65217_IRQ_PB>;
++ status = "okay";
++ };
++
+ regulators {
+ dcdc1_reg: regulator@0 {
+ regulator-name = "vdds_dpr";
+@@ -393,3 +405,32 @@
+ &sham {
+ status = "okay";
+ };
++
++&rtc {
++ system-power-controller;
++};
++
++/* the cape manager */
++/ {
++ bone_capemgr {
++ compatible = "ti,bone-capemgr";
++ status = "okay";
++
++ nvmem-cells = <&baseboard_data &cape0_data &cape1_data &cape2_data &cape3_data>;
++ nvmem-cell-names = "baseboard", "slot0", "slot1", "slot2", "slot3";
++ #slots = <4>;
++
++ /* map board revisions to compatible definitions */
++ baseboardmaps {
++ baseboard_beaglebone: board@0 {
++ board-name = "A335BONE";
++ compatible-name = "ti,beaglebone";
++ };
++
++ baseboard_beaglebone_black: board@1 {
++ board-name = "A335BNLT";
++ compatible-name = "ti,beaglebone-black";
++ };
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-emmc-in-reset.dtsi b/arch/arm/boot/dts/am335x-bone-emmc-in-reset.dtsi
+new file mode 100644
+index 0000000..7d8f673
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-emmc-in-reset.dtsi
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* standard */
++
++&gpio1 {
++ emmc_rst {
++ gpio-hog;
++ gpios = <20 0>;
++ output-high;
++ line-name = "EMMC ResetN";
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-jtag.dtsi b/arch/arm/boot/dts/am335x-bone-jtag.dtsi
+new file mode 100644
+index 0000000..603ef0a
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-jtag.dtsi
+@@ -0,0 +1,20 @@
++/*
++ * Device Tree Source for bone jtag
++ *
++ * Copyright (C) 2015 Robert Nelson <robertcnelson@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&am33xx_pinmux {
++ pinctrl-names = "default";
++ pinctrl-0 = <&clkout2_pin>;
++
++ clkout2_pin: pinmux_clkout2_pin {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
++ >;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-can0.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-can0.dtsi
+new file mode 100644
+index 0000000..0961216
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-can0.dtsi
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-can0.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_19_pinmux {
++ * mode = "can";
++ * };
++ * P9_20_pinmux {
++ * mode = "can";
++ * };
++ *};
++ *
++ *&dcan0 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ dcan0_pins: pinmux_dcan0_pins {
++ pinctrl-single,pins = <
++ /* P9_20: uart1_ctsn.d_can0_tx */
++ BONE_P9_20 (PIN_OUTPUT_PULLUP | MUX_MODE2)
++ /* P9_19: uart1_rtsn.d_can0_rx */
++ BONE_P9_19 (PIN_INPUT_PULLUP | MUX_MODE2)
++ >;
++ };
++};
++
++&dcan0 {
++ pinctrl-0 = <&dcan0_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-can1.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-can1.dtsi
+new file mode 100644
+index 0000000..9e26413
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-can1.dtsi
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-can1.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_24_pinmux {
++ * mode = "can";
++ * };
++ * P9_26_pinmux {
++ * mode = "can";
++ * };
++ *};
++ *
++ *&dcan1 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ dcan1_pins: pinmux_dcan1_pins {
++ pinctrl-single,pins = <
++ /* P9_26: uart1_rxd.d_can1_tx */
++ BONE_P9_26 (PIN_OUTPUT_PULLUP | MUX_MODE2)
++ /* P9_24: uart1_txd.d_can1_rx */
++ BONE_P9_24 (PIN_INPUT_PULLUP | MUX_MODE2)
++ >;
++ };
++};
++
++&dcan1 {
++ pinctrl-0 = <&dcan1_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-emmc.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-emmc.dtsi
+new file mode 100644
+index 0000000..22cf462
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-emmc.dtsi
+@@ -0,0 +1,88 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Testing */
++/* lsblk */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-emmc.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P8_21_pinmux {
++ * state = "disabled";
++ * };
++ * P8_20_pinmux {
++ * state = "disabled";
++ * };
++ * P8_25_pinmux {
++ * state = "disabled";
++ * };
++ * P8_24_pinmux {
++ * state = "disabled";
++ * };
++ * P8_05_pinmux {
++ * state = "disabled";
++ * };
++ * P8_06_pinmux {
++ * state = "disabled";
++ * };
++ * P8_23_pinmux {
++ * state = "disabled";
++ * };
++ * P8_22_pinmux {
++ * state = "disabled";
++ * };
++ * P8_03_pinmux {
++ * state = "disabled";
++ * };
++ * P8_04_pinmux {
++ * state = "disabled";
++ * };
++ *};
++ *
++ *&mmc2 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ emmc_pins: pinmux_emmc_pins {
++ pinctrl-single,pins = <
++ /* P8_21: gpmc_csn1.mmc1_clk */
++ BONE_P8_21 (PIN_INPUT_PULLUP | MUX_MODE2)
++ /* P8_20: gpmc_csn2.mmc1_cmd */
++ BONE_P8_20 (PIN_INPUT_PULLUP | MUX_MODE2)
++ /* P8_25: gpmc_ad0.mmc1_dat0 */
++ BONE_P8_25 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_24: gpmc_ad1.mmc1_dat1 */
++ BONE_P8_24 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_05: gpmc_ad2.mmc1_dat2 */
++ BONE_P8_05 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_06: gpmc_ad3.mmc1_dat3 */
++ BONE_P8_06 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_23: gpmc_ad4.mmc1_dat4 */
++ BONE_P8_23 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_22: gpmc_ad5.mmc1_dat5 */
++ BONE_P8_22 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_03: gpmc_ad6.mmc1_dat6 */
++ BONE_P8_03 (PIN_INPUT_PULLUP | MUX_MODE1)
++ /* P8_04: gpmc_ad7.mmc1_dat7 */
++ BONE_P8_04 (PIN_INPUT_PULLUP | MUX_MODE1)
++ >;
++ };
++};
++
++&mmc2 {
++ pinctrl-0 = <&emmc_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-i2c2.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-i2c2.dtsi
+new file mode 100644
+index 0000000..abf3b57
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-i2c2.dtsi
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-i2c2.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_19_pinmux {
++ * mode = "i2c";
++ * };
++ * P9_20_pinmux {
++ * mode = "i2c";
++ * };
++ *};
++ *
++ *&dcan0 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ i2c2_pins: pinmux_i2c2_pins {
++ pinctrl-single,pins = <
++ /* P9_20: uart1_ctsn.i2c2_sda */
++ BONE_P9_20 (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3)
++ /* P9_19: uart1_rtsn.i2c2_scl */
++ BONE_P9_19 (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3)
++ >;
++ };
++};
++
++&i2c2 {
++ pinctrl-0 = <&i2c2_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-nxp-hdmi.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-nxp-hdmi.dtsi
+new file mode 100644
+index 0000000..5205fa0
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-nxp-hdmi.dtsi
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "am335x-peripheral-nxp-hdmi.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P8_27_pinmux {
++ * state = "disabled";
++ * };
++ * P8_28_pinmux {
++ * state = "disabled";
++ * };
++ * P8_29_pinmux {
++ * state = "disabled";
++ * };
++ * P8_30_pinmux {
++ * state = "disabled";
++ * };
++ * P8_31_pinmux {
++ * state = "disabled";
++ * };
++ * P8_32_pinmux {
++ * state = "disabled";
++ * };
++ * P8_33_pinmux {
++ * state = "disabled";
++ * };
++ * P8_34_pinmux {
++ * state = "disabled";
++ * };
++ * P8_35_pinmux {
++ * state = "disabled";
++ * };
++ * P8_36_pinmux {
++ * state = "disabled";
++ * };
++ * P8_37_pinmux {
++ * state = "disabled";
++ * };
++ * P8_38_pinmux {
++ * state = "disabled";
++ * };
++ * P8_39_pinmux {
++ * state = "disabled";
++ * };
++ * P8_40_pinmux {
++ * state = "disabled";
++ * };
++ * P8_41_pinmux {
++ * state = "disabled";
++ * };
++ * P8_42_pinmux {
++ * state = "disabled";
++ * };
++ * P8_43_pinmux {
++ * state = "disabled";
++ * };
++ * P8_44_pinmux {
++ * state = "disabled";
++ * };
++ * P8_45_pinmux {
++ * state = "disabled";
++ * };
++ * P8_46_pinmux {
++ * state = "disabled";
++ * };
++ *};
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ nxp_hdmi_pins: pinmux_nxp_hdmi_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++
++ nxp_hdmi_off_pins: nxp_hdmi_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++};
++
++&i2c0 {
++ tda19988 {
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
++ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-panel-1024x600-24bit.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-panel-1024x600-24bit.dtsi
+new file mode 100644
+index 0000000..65e5fbb
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-panel-1024x600-24bit.dtsi
+@@ -0,0 +1,151 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-panel-1024x600-24bit.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P8_27_pinmux {
++ * state = "disabled";
++ * };
++ * P8_28_pinmux {
++ * state = "disabled";
++ * };
++ * P8_29_pinmux {
++ * state = "disabled";
++ * };
++ * P8_30_pinmux {
++ * state = "disabled";
++ * };
++ * P8_31_pinmux {
++ * state = "disabled";
++ * };
++ * P8_32_pinmux {
++ * state = "disabled";
++ * };
++ * P8_33_pinmux {
++ * state = "disabled";
++ * };
++ * P8_34_pinmux {
++ * state = "disabled";
++ * };
++ * P8_35_pinmux {
++ * state = "disabled";
++ * };
++ * P8_36_pinmux {
++ * state = "disabled";
++ * };
++ * P8_37_pinmux {
++ * state = "disabled";
++ * };
++ * P8_38_pinmux {
++ * state = "disabled";
++ * };
++ * P8_39_pinmux {
++ * state = "disabled";
++ * };
++ * P8_40_pinmux {
++ * state = "disabled";
++ * };
++ * P8_41_pinmux {
++ * state = "disabled";
++ * };
++ * P8_42_pinmux {
++ * state = "disabled";
++ * };
++ * P8_43_pinmux {
++ * state = "disabled";
++ * };
++ * P8_44_pinmux {
++ * state = "disabled";
++ * };
++ * P8_45_pinmux {
++ * state = "disabled";
++ * };
++ * P8_46_pinmux {
++ * state = "disabled";
++ * };
++ *};
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ lcd_24bit_pins: pinmux_lcd_24bit_pins {
++ pinctrl-single,pins = <
++
++ /* P8_45: lcd_data0.lcd_data0 */
++ BONE_P8_45 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_46: lcd_data1.lcd_data1 */
++ BONE_P8_46 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_43: lcd_data2.lcd_data2 */
++ BONE_P8_43 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_44: lcd_data3.lcd_data3 */
++ BONE_P8_44 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_41: lcd_data4.lcd_data4 */
++ BONE_P8_41 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_42: lcd_data5.lcd_data5 */
++ BONE_P8_42 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_39: lcd_data6.lcd_data6 */
++ BONE_P8_39 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_40: lcd_data7.lcd_data7 */
++ BONE_P8_40 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_37: lcd_data8.lcd_data8 */
++ BONE_P8_37 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_38: lcd_data9.lcd_data9 */
++ BONE_P8_38 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_36: lcd_data10.lcd_data10 */
++ BONE_P8_36 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_34: lcd_data11.lcd_data11 */
++ BONE_P8_34 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_35: lcd_data12.lcd_data12 */
++ BONE_P8_35 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_33: lcd_data13.lcd_data13 */
++ BONE_P8_33 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_31: lcd_data14.lcd_data14 */
++ BONE_P8_31 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_32: lcd_data15.lcd_data15 */
++ BONE_P8_32 (PIN_OUTPUT | MUX_MODE0)
++
++ /* gpmc_ad15.lcd_data16 */
++ BONE_P8_15 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad14.lcd_data17 */
++ BONE_P8_16 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad13.lcd_data18 */
++ BONE_P8_11 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad12.lcd_data19 */
++ BONE_P8_12 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad11.lcd_data20 */
++ BONE_P8_17 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad10.lcd_data21 */
++ BONE_P8_14 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad9.lcd_data22 */
++ BONE_P8_13 (PIN_OUTPUT | MUX_MODE1)
++ /* gpmc_ad8.lcd_data23 */
++ BONE_P8_19 (PIN_OUTPUT | MUX_MODE1)
++
++ /* P8_27: lcd_vsync.lcd_vsync */
++ BONE_P8_27 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_29: lcd_hsync.lcd_hsync */
++ BONE_P8_29 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_28: lcd_pclk.lcd_pclk*/
++ BONE_P8_28 (PIN_OUTPUT | MUX_MODE0)
++ /* P8_30: lcd_ac_bias_en.lcd_ac_bias_en */
++ BONE_P8_30 (PIN_OUTPUT | MUX_MODE0)
++ >;
++ };
++};
++
++/ {
++ panel {
++ pinctrl-0 = <&lcd_24bit_pins>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-spi0.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-spi0.dtsi
+new file mode 100644
+index 0000000..354e66a
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-spi0.dtsi
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-spi0.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_17_pinmux {
++ * status = "disabled";
++ * };
++ * P9_18_pinmux {
++ * status = "disabled";
++ * };
++ * P9_21_pinmux {
++ * status = "disabled";
++ * };
++ * P9_22_pinmux {
++ * status = "disabled";
++ * };
++ *};
++ *
++ *&spi0 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ spi0_pins: pinmux_spi0_pins {
++ pinctrl-single,pins = <
++ 0x150 (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_sclk.spi0_sclk */
++ 0x154 (PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d0.spi0_d0 */
++ 0x158 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
++ 0x15c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
++ >;
++ };
++};
++
++&spi0 {
++ pinctrl-0 = <&spi0_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-spi1.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-spi1.dtsi
+new file mode 100644
+index 0000000..bff7f8d
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-spi1.dtsi
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-spi1.dtsi"
++
++/* standard */
++
++&am33xx_pinmux {
++ spi1_pins: pinmux_spi1_pins {
++ pinctrl-single,pins = <
++ 0x190 0x33 /* mcasp0_aclkx.spi1_sclk, INPUT_PULLUP | MODE3 */
++ 0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
++ 0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
++ 0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */
++ // 0x164 0x12 /* eCAP0_in_PWM0_out.spi1_cs1 OUTPUT_PULLUP | MODE2 */ >;
++ };
++};
++
++&spi1 {
++ pinctrl-0 = <&spi1_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-spi1a.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-spi1a.dtsi
+new file mode 100644
+index 0000000..62874c8
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-spi1a.dtsi
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-spi1.dtsi"
++
++/* standard */
++
++&am33xx_pinmux {
++ spi1a_pins: pinmux_spi1a_pins {
++ pinctrl-single,pins = <
++ 0x164 0x34 /* eCAP0_in_PWM0_out.spi1_sclk, INPUT_PULLUP | MODE4 */
++ /* NOTE: P9.42 is connected to two pads */
++ // 0x1A0 0x27 /* set the other pad to gpio input */
++ 0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
++ 0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
++ 0x178 0x14 /* uart1_ctsn.spi1_cs0, OUTPUT_PULLUP | MODE4 */ >;
++ };
++};
++
++&spi1 {
++ pinctrl-0 = <&spi1a_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS1.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS1.dtsi
+new file mode 100644
+index 0000000..ae5b813
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS1.dtsi
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Testing */
++/* sudo /sbin/getty -L ttyS1 115200 vt102 */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-ttyS1.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_24_pinmux {
++ * mode = "uart";
++ * };
++ * P9_26_pinmux {
++ * mode = "uart";
++ * };
++ *};
++ *
++ *&uart1 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ uart1_pins: pinmux_uart1_pins {
++ pinctrl-single,pins = <
++ /* P9_24: uart1_txd.uart1_txd */
++ BONE_P9_24 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)
++ /* P9_26: uart1_rxd.uart1_rxd */
++ BONE_P9_26 (PIN_INPUT_PULLUP | MUX_MODE0)
++ >;
++ };
++};
++
++&uart1 {
++ pinctrl-0 = <&uart1_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS2.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS2.dtsi
+new file mode 100644
+index 0000000..5fa593a
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS2.dtsi
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Testing */
++/* sudo /sbin/getty -L ttyS2 115200 vt102 */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-ttyS2.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_21_pinmux {
++ * mode = "uart";
++ * };
++ * P9_22_pinmux {
++ * mode = "uart";
++ * };
++ *};
++ *
++ *&uart2 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ uart2_pins: pinmux_uart2_pins {
++ pinctrl-single,pins = <
++ /* P9_21: spi0_d0.uart2_txd */
++ BONE_P9_21 (PIN_OUTPUT_PULLDOWN | MUX_MODE1)
++ /* P9_22: spi0_sclk.uart2_rxd */
++ BONE_P9_22 (PIN_INPUT_PULLUP | MUX_MODE1)
++ >;
++ };
++};
++
++&uart2 {
++ pinctrl-0 = <&uart2_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS4.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS4.dtsi
+new file mode 100644
+index 0000000..1d22a95
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS4.dtsi
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Testing */
++/* sudo /sbin/getty -L ttyS4 115200 vt102 */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-ttyS4.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P9_11_pinmux {
++ * mode = "uart";
++ * };
++ * P9_13_pinmux {
++ * mode = "uart";
++ * };
++ *};
++ *
++ *&uart4 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ uart4_pins: pinmux_uart4_pins {
++ pinctrl-single,pins = <
++ /* P9_11: gpmc_wait0.uart4_rxd_mux2 */
++ BONE_P9_11 (PIN_INPUT_PULLUP | MUX_MODE6)
++ /* P9_13: gpmc_wpn.uart4_txd_mux2 */
++ BONE_P9_13 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)
++ >;
++ };
++};
++
++&uart4 {
++ pinctrl-0 = <&uart4_pins>;
++};
+diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS5.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS5.dtsi
+new file mode 100644
+index 0000000..01d0aec
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS5.dtsi
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Testing */
++/* sudo /sbin/getty -L ttyS5 115200 vt102 */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include "am335x-peripheral-ttyS5.dtsi"
++
++/* cape universal */
++
++/*
++ *&ocp {
++ * P8_37_pinmux {
++ * mode = "uart";
++ * };
++ * P8_38_pinmux {
++ * mode = "uart";
++ * };
++ *};
++ *
++ *&uart5 {
++ * pinctrl-0 = <>;
++ *};
++ *
++ */
++
++/* standard */
++
++&am33xx_pinmux {
++ uart5_pins: pinmux_uart5_pins {
++ pinctrl-single,pins = <
++ /* P8_38: lcd_data9.uart5_rxd */
++ BONE_P8_38 (PIN_INPUT_PULLUP | MUX_MODE4)
++ /* P8_37: lcd_data8.uart5_txd */
++ BONE_P8_37 (PIN_OUTPUT_PULLDOWN | MUX_MODE4)
++ >;
++ };
++};
++
++&uart5 {
++ pinctrl-0 = <&uart5_pins>;
++};
+diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
+index 6b84937..3688fff 100644
+--- a/arch/arm/boot/dts/am335x-bone.dts
++++ b/arch/arm/boot/dts/am335x-bone.dts
+@@ -9,6 +9,7 @@
+
+ #include "am33xx.dtsi"
+ #include "am335x-bone-common.dtsi"
++/* #include "am335x-bone-jtag.dtsi" */
+
+ / {
+ model = "TI AM335x BeagleBone";
+diff --git b/arch/arm/boot/dts/am335x-boneblack-audio.dts b/arch/arm/boot/dts/am335x-boneblack-audio.dts
+new file mode 100644
+index 0000000..cac3626
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-audio.dts
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++
++ clk_mcasp0_fixed: clk_mcasp0_fixed {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <24576000>;
++ };
++
++ clk_mcasp0: clk_mcasp0 {
++ #clock-cells = <0>;
++ compatible = "gpio-gate-clock";
++ clocks = <&clk_mcasp0_fixed>;
++ enable-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>; /* BeagleBone Black Clk enable on GPIO1_27 */
++ };
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-c.dts b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-c.dts
+new file mode 100644
+index 0000000..8d795c0
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-c.dts
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++#include "am335x-cape-bbb-exp-c.dtsi"
+diff --git b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-r.dts b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-r.dts
+new file mode 100644
+index 0000000..5df881e
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-r.dts
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++#include "am335x-cape-bbb-exp-r.dtsi"
+diff --git b/arch/arm/boot/dts/am335x-boneblack-bbbmini.dts b/arch/arm/boot/dts/am335x-boneblack-bbbmini.dts
+new file mode 100644
+index 0000000..5ed89a2
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-bbbmini.dts
+@@ -0,0 +1,207 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ * Modified by Mirko Denecke <mirkix@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++#include <dt-bindings/pinctrl/am33xx.h>
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++&am33xx_pinmux {
++ dcan1_pins: pinmux_dcan1_pins {
++ pinctrl-single,pins = <
++ /* P9_26: uart1_rxd.d_can1_tx */
++ BONE_P9_26 (PIN_OUTPUT_PULLUP | MUX_MODE2)
++ /* P9_24: uart1_txd.d_can1_rx */
++ BONE_P9_24 (PIN_INPUT_PULLUP | MUX_MODE2)
++ >;
++ };
++
++ pru_pins: pinmux_pru_pins {
++ pinctrl-single,pins = <
++ 0x03c 0x35 /* ecap0_in_pwm0_out.pr1_ecap0_ecap_capin, MODE5 | INPUT_PULLUP | PRU, PPM-sum, SBUS, DSM */
++
++ 0x0e8 0x25 /* lcd_pclk.pr1_pru1_pru_r30_10, MODE5 | OUTPUT | PRU, CH_1 */
++ 0x0e0 0x25 /* lcd_vsync.pr1_pru1_pru_r30_8, MODE5 | OUTPUT | PRU, CH_2 */
++ 0x0ec 0x25 /* lcd_ac_bias_en.pr1_pru1_pru_r30_11, MODE5 | OUTPUT | PRU, CH_3 */
++ 0x0e4 0x25 /* lcd_hsync.pr1_pru1_pru_r30_9, MODE5 | OUTPUT | PRU, CH_4 */
++ 0x0bc 0x25 /* lcd_data7.pr1_pru1_pru_r30_7, MODE5 | OUTPUT | PRU, CH_5 */
++ 0x0b8 0x25 /* lcd_data6.pr1_pru1_pru_r30_6, MODE5 | OUTPUT | PRU, CH_6 */
++ 0x0b4 0x25 /* lcd_data5.pr1_pru1_pru_r30_5, MODE5 | OUTPUT | PRU, CH_7 */
++ 0x0b0 0x25 /* lcd_data4.pr1_pru1_pru_r30_4, MODE5 | OUTPUT | PRU, CH_8 */
++ 0x0ac 0x25 /* lcd_data3.pr1_pru1_pru_r30_3, MODE5 | OUTPUT | PRU, CH_9 */
++ 0x0a8 0x25 /* lcd_data2.pr1_pru1_pru_r30_2, MODE5 | OUTPUT | PRU, CH_10 */
++ 0x0a4 0x25 /* lcd_data1.pr1_pru1_pru_r30_1, MODE5 | OUTPUT | PRU, CH_11 */
++ 0x0a0 0x25 /* lcd_data0.pr1_pru1_pru_r30_0, MODE5 | OUTPUT | PRU, CH_12 */
++
++ BONE_P8_12 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* HC-SR04 TRIG */
++ BONE_P8_16 (PIN_INPUT_PULLDOWN | MUX_MODE6) /* HC-SR04 ECHO */
++
++ BONE_P9_25 (PIN_INPUT_PULLDOWN | MUX_MODE6) /* MPU9250 INT */
++ >;
++ };
++
++ spi0_pins: pinmux_spi0_pins {
++ pinctrl-single,pins = <
++ /* P9_22: spi0_sclk.spi0_sclk */
++ BONE_P9_22 (PIN_INPUT_PULLUP | MUX_MODE0)
++ /* P9_21: spi0_d0.spi0_d0 */
++ BONE_P9_21 (PIN_INPUT_PULLUP | MUX_MODE0)
++ /* P9_18: spi0_d1.spi0_d1 */
++ BONE_P9_18 (PIN_OUTPUT_PULLUP | MUX_MODE0)
++ /* P9_17: spi0_cs0.spi0_cs0 */
++ BONE_P9_17 (PIN_OUTPUT_PULLUP | MUX_MODE0)
++ >;
++ };
++
++ spi1_pins: pinmux_spi1_pins {
++ pinctrl-single,pins = <
++ /* P9_31: mcasp0_aclkx.spi1_sclk */
++ BONE_P9_31 (PIN_INPUT_PULLUP | MUX_MODE3)
++
++ /* P9_29: mcasp0_fsx.spi1_d0 */
++ BONE_P9_29 (PIN_INPUT_PULLUP | MUX_MODE3)
++
++ /* P9_30: mcasp0_axr0.spi1_d1 */
++ BONE_P9_30 (PIN_OUTPUT_PULLUP | MUX_MODE3)
++
++ /* P9_28: mcasp0_ahclkr.spi1_cs0 */
++ BONE_P9_28 (PIN_OUTPUT_PULLUP | MUX_MODE3)
++
++ /* P9_19: uart1_rtsn.spi1_cs1 */
++/* BONE_P9_19 (PIN_OUTPUT_PULLUP | MUX_MODE4)*/
++
++ /* P9_42: ecap0_in_pwm0_out.spi1_cs1 */
++ BONE_P9_42A (PIN_OUTPUT_PULLUP | MUX_MODE2)
++ >;
++ };
++
++ uart4_pins: pinmux_uart4_pins {
++ pinctrl-single,pins = <
++ /* P9_11: gpmc_wait0.uart4_rxd_mux2 */
++ BONE_P9_11 (PIN_INPUT_PULLUP | MUX_MODE6)
++ /* P9_13: gpmc_wpn.uart4_txd_mux2 */
++ BONE_P9_13 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)
++ >;
++ };
++
++ uart5_pins: pinmux_uart5_pins {
++ pinctrl-single,pins = <
++ /* P8_38: lcd_data9.uart5_rxd */
++ BONE_P8_38 (PIN_INPUT_PULLUP | MUX_MODE4)
++ /* P8_37: lcd_data8.uart5_txd */
++ BONE_P8_37 (PIN_OUTPUT_PULLDOWN | MUX_MODE4)
++ >;
++ };
++};
++
++&dcan1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&dcan1_pins>;
++ status = "okay";
++};
++
++&i2c2 {
++ clock-frequency = <400000>;
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins>;
++ status = "okay";
++
++ spi0_0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <24000000>;
++ reg = <0>;
++ compatible = "spidev";
++ };
++};
++
++&spi1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi1_pins>;
++ status = "okay";
++
++ spi1_0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ spi-max-frequency = <24000000>;
++ compatible = "spidev";
++ };
++
++ spi1_1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++ spi-max-frequency = <24000000>;
++ compatible = "spidev";
++ };
++};
++
++&tscadc {
++ adc {
++ ti,adc-channels = <0 1>;
++ };
++};
++
++&pruss {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pru_pins>;
++ status = "okay";
++};
++
++&uart4 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart4_pins>;
++ status = "okay";
++};
++
++&uart5 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart5_pins>;
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-cape-bone-argus.dts b/arch/arm/boot/dts/am335x-boneblack-cape-bone-argus.dts
+new file mode 100644
+index 0000000..c97c912
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-cape-bone-argus.dts
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++&am33xx_pinmux {
++ nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++ nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++};
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&i2c0 {
++ tda19988 {
++ compatible = "nxp,tda998x";
++ reg = <0x70>;
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
++ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
++
++ port {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++};
++
++#include "am335x-bone-argus.dtsi"
+diff --git b/arch/arm/boot/dts/am335x-boneblack-emmc-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-emmc-overlay.dts
+new file mode 100644
+index 0000000..ccd358e
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-emmc-overlay.dts
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++/* #include <dt-bindings/display/tda998x.h> */
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-hdmi-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-hdmi-overlay.dts
+new file mode 100644
+index 0000000..0582e57
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-hdmi-overlay.dts
+@@ -0,0 +1,169 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++#include <dt-bindings/display/tda998x.h>
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++/* EMMC in reset */
++&gpio1 {
++ emmc_rst {
++ gpio-hog;
++ gpios = <20 0>;
++ output-high;
++ line-name = "EMMC ResetN";
++ };
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++&am33xx_pinmux {
++ nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++ nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++
++ mcasp0_pins: mcasp0_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
++ AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
++ AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
++ AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
++ AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
++ >;
++ };
++};
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&i2c0 {
++ tda19988: tda19988 {
++ compatible = "nxp,tda998x";
++ reg = <0x70>;
++
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
++ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
++
++ #sound-dai-cells = <0>;
++ audio-ports = < TDA998x_I2S 0x03>;
++
++ ports {
++ port@0 {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++ };
++};
++
++&mcasp0 {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&mcasp0_pins>;
++ status = "okay";
++ op-mode = <0>; /* MCASP_IIS_MODE */
++ tdm-slots = <2>;
++ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
++ 0 0 1 0
++ >;
++ tx-num-evt = <32>;
++ rx-num-evt = <32>;
++};
++
++/ {
++ clk_mcasp0_fixed: clk_mcasp0_fixed {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <24576000>;
++ };
++
++ clk_mcasp0: clk_mcasp0 {
++ #clock-cells = <0>;
++ compatible = "gpio-gate-clock";
++ clocks = <&clk_mcasp0_fixed>;
++ enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
++ };
++
++ sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "TI BeagleBone Black";
++ simple-audio-card,format = "i2s";
++ simple-audio-card,bitclock-master = <&dailink0_master>;
++ simple-audio-card,frame-master = <&dailink0_master>;
++
++ dailink0_master: simple-audio-card,cpu {
++ sound-dai = <&mcasp0>;
++ clocks = <&clk_mcasp0>;
++ };
++
++ simple-audio-card,codec {
++ sound-dai = <&tda19988>;
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-nhdmi-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-nhdmi-overlay.dts
+new file mode 100644
+index 0000000..c166c90
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-nhdmi-overlay.dts
+@@ -0,0 +1,110 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++#include <dt-bindings/display/tda998x.h>
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++/* EMMC in reset */
++&gpio1 {
++ emmc_rst {
++ gpio-hog;
++ gpios = <20 0>;
++ output-high;
++ line-name = "EMMC ResetN";
++ };
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++&am33xx_pinmux {
++ nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++ nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++};
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&i2c0 {
++ tda19988: tda19988 {
++ compatible = "nxp,tda998x";
++ reg = <0x70>;
++
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
++ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
++
++ ports {
++ port@0 {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-overlay.dts
+new file mode 100644
+index 0000000..e9bbd93
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-overlay.dts
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++/* #include <dt-bindings/display/tda998x.h> */
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++/* EMMC in reset */
++&gpio1 {
++ emmc_rst {
++ gpio-hog;
++ gpios = <20 0>;
++ output-high;
++ line-name = "EMMC ResetN";
++ };
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-roboticscape.dts b/arch/arm/boot/dts/am335x-boneblack-roboticscape.dts
+new file mode 100644
+index 0000000..16e9376
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-roboticscape.dts
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++ /******************************************************************************
++ * This device tree serves to replace the need for an overlay when using
++ * the RoboticsCape. It is similar to the boneblue tree but preserves
++ * pin config for the black.
++ ******************************************************************************/
++
++
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++#include "am335x-bone-common-universal-pins.dtsi"
++/* #include "am33xx-pruss-rproc.dtsi" */
++#include "am335x-roboticscape.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-uboot.dts b/arch/arm/boot/dts/am335x-boneblack-uboot.dts
+new file mode 100644
+index 0000000..b2f6e36
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-uboot.dts
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-wireless-emmc-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-wireless-emmc-overlay.dts
+new file mode 100644
+index 0000000..78f63bf
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-wireless-emmc-overlay.dts
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++/* #include <dt-bindings/display/tda998x.h> */
++#include "am335x-boneblack-wl1835.dtsi"
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Black Wireless";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&mac {
++ status = "disabled";
++};
++
++&mmc3 {
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-wireless-roboticscape.dts b/arch/arm/boot/dts/am335x-boneblack-wireless-roboticscape.dts
+new file mode 100644
+index 0000000..4a72d56
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-wireless-roboticscape.dts
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++ /******************************************************************************
++ * This device tree serves to replace the need for an overlay when using
++ * the RoboticsCape. It is similar to the boneblue tree but preserves
++ * pin config for the black.
++ ******************************************************************************/
++
++
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++#include "am335x-bone-common-universal-pins.dtsi"
++/* #include "am33xx-pruss-rproc.dtsi" */
++#include "am335x-boneblack-wl1835.dtsi"
++#include "am335x-roboticscape.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black Wireless";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-wireless.dts b/arch/arm/boot/dts/am335x-boneblack-wireless.dts
+new file mode 100644
+index 0000000..9b39648
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-wireless.dts
+@@ -0,0 +1,165 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++#include <dt-bindings/display/tda998x.h>
++#include "am335x-boneblack-wl1835.dtsi"
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Black Wireless";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&mac {
++ status = "disabled";
++};
++
++&mmc3 {
++ status = "okay";
++};
++
++&am33xx_pinmux {
++ nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++ nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++
++ mcasp0_pins: mcasp0_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
++ AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
++ AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
++ AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
++ AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
++ >;
++ };
++};
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&i2c0 {
++ tda19988: tda19988 {
++ compatible = "nxp,tda998x";
++ reg = <0x70>;
++
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
++ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
++
++ #sound-dai-cells = <0>;
++ audio-ports = < TDA998x_I2S 0x03>;
++
++ ports {
++ port@0 {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++ };
++};
++
++&mcasp0 {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&mcasp0_pins>;
++ status = "okay";
++ op-mode = <0>; /* MCASP_IIS_MODE */
++ tdm-slots = <2>;
++ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
++ 0 0 1 0
++ >;
++ tx-num-evt = <32>;
++ rx-num-evt = <32>;
++};
++
++/ {
++ clk_mcasp0_fixed: clk_mcasp0_fixed {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <24576000>;
++ };
++
++ clk_mcasp0: clk_mcasp0 {
++ #clock-cells = <0>;
++ compatible = "gpio-gate-clock";
++ clocks = <&clk_mcasp0_fixed>;
++ enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
++ };
++
++ sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "TI BeagleBone Black";
++ simple-audio-card,format = "i2s";
++ simple-audio-card,bitclock-master = <&dailink0_master>;
++ simple-audio-card,frame-master = <&dailink0_master>;
++
++ dailink0_master: simple-audio-card,cpu {
++ sound-dai = <&mcasp0>;
++ clocks = <&clk_mcasp0>;
++ };
++
++ simple-audio-card,codec {
++ sound-dai = <&tda19988>;
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-wl1835.dtsi b/arch/arm/boot/dts/am335x-boneblack-wl1835.dtsi
+new file mode 100644
+index 0000000..ec6c0e4
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-wl1835.dtsi
+@@ -0,0 +1,143 @@
++
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/ {
++ wlan_en_reg: fixedregulator@2 {
++ compatible = "regulator-fixed";
++ regulator-name = "wlan-en-regulator";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ startup-delay-us= <70000>;
++
++ /* WL_EN */
++ gpio = <&gpio3 9 0>;
++ enable-active-high;
++ };
++
++ leds {
++ pinctrl-names = "default";
++ pinctrl-0 = <&wl18xx_pins>;
++ compatible = "gpio-leds";
++
++ wl18xx_bt_en {
++ label = "wl18xx_bt_en";
++ gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
++ default-state = "off";
++ };
++ };
++
++ btwilink {
++ compatible = "btwilink";
++ };
++};
++
++&am33xx_pinmux {
++ wl18xx_pins: pinmux_wl18xx_pins {
++ pinctrl-single,pins = <
++ 0x128 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* (K17) gmii1_txd0.gpio0[28] - BT_EN */
++ >;
++ };
++
++ wlbtbuf_pin: pinmux_wlbtbuf_pin {
++ pinctrl-single,pins = <
++ 0x130 ( PIN_OUTPUT_PULLUP | MUX_MODE7 ) /* (L18) gmii1_rxclk.gpio3[10] - LS_BUF_EN */
++ >;
++ };
++
++ mmc3_pins: pinmux_mmc3_pins {
++ pinctrl-single,pins = <
++ 0x13c ( PIN_INPUT_PULLUP | MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */
++ 0x114 ( PIN_INPUT_PULLUP | MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */
++ 0x118 ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */
++ 0x11c ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */
++ 0x120 ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */
++ 0x108 ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */
++ >;
++ };
++
++ mmc3_pins_sleep: pinmux_mmc3_pins_sleep {
++ pinctrl-single,pins = <
++ 0x13c ( PIN_INPUT_PULLDOWN | MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */
++ 0x114 ( PIN_INPUT_PULLDOWN | MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */
++ 0x118 ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */
++ 0x11c ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */
++ 0x120 ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */
++ 0x108 ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins: pinmux_wlan_pins {
++ pinctrl-single,pins = <
++ 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE7 ) /* (K18) gmii1_txclk.gpio3[9] - WL_EN */
++ 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7 ) /* (H18) rmii1_refclk.gpio0[29] - WL_IRQ */
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins_sleep: pinmux_wlan_pins_sleep {
++ pinctrl-single,pins = <
++ 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE7 ) /* (K18) gmii1_txclk.gpio3[9] - WL_EN */
++ 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7 ) /* (H18) rmii1_refclk.gpio0[29] - WL_IRQ */
++ >;
++ };
++
++ uart3_pins_default: pinmux_uart3_pins_default {
++ pinctrl-single,pins = <
++ 0x134 ( PIN_INPUT_PULLUP | MUX_MODE1 ) /* (L17) gmii1_rxd3.uart3_rxd */
++ 0x138 ( PIN_OUTPUT_PULLDOWN | MUX_MODE1 ) /* (L16) gmii1_rxd2.uart3_txd */
++ 0x148 ( PIN_INPUT | MUX_MODE3 ) /* (M17) mdio_data.uart3_ctsn */
++ 0x14c ( PIN_OUTPUT_PULLDOWN | MUX_MODE3 ) /* (M18) mdio_clk.uart3_rtsn */
++ >;
++ };
++
++ uart3_pins_sleep: pinmux_uart3_pins_sleep {
++ pinctrl-single,pins = <
++ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (L17) gmii1_rxd3.uart3_rxd */
++ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (L16) gmii1_rxd2.uart3_txd */
++ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M17) mdio_data.uart3_ctsn */
++ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M18) mdio_clk.uart3_rtsn */
++ >;
++ };
++};
++
++&mmc3 {
++ dmas = <&edma_xbar 12 0 1
++ &edma_xbar 13 0 2>;
++ dma-names = "tx", "rx";
++ status = "okay";
++ vmmc-supply = <&wlan_en_reg>;
++ bus-width = <4>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&mmc3_pins &wlan_pins &wlbtbuf_pin>;
++ pinctrl-1 = <&mmc3_pins_sleep &wlan_pins_sleep &wlbtbuf_pin>;
++ ti,non-removable;
++ ti,needs-special-hs-handling;
++ cap-power-off-card;
++ keep-power-in-suspend;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ wlcore: wlcore@0 {
++ compatible = "ti,wl1835";
++ reg = <2>;
++ interrupt-parent = <&gpio0>;
++ interrupts = <29 IRQ_TYPE_EDGE_RISING>;
++ };
++};
++
++&uart3 {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&uart3_pins_default>;
++ pinctrl-1 = <&uart3_pins_sleep>;
++ status = "okay";
++};
++
++&gpio3 {
++ ls_buf_en {
++ gpio-hog;
++ gpios = <10 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "LS_BUF_EN";
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-wl1835mod-cape.dtsi b/arch/arm/boot/dts/am335x-boneblack-wl1835mod-cape.dtsi
+new file mode 100644
+index 0000000..94caa22
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-wl1835mod-cape.dtsi
+@@ -0,0 +1,128 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/ {
++ wlan_en_reg: fixedregulator@2 {
++ compatible = "regulator-fixed";
++ regulator-name = "wlan-en-regulator";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++
++ /* WL_EN */
++ gpio = <&gpio0 26 0>;
++ enable-active-high;
++ };
++
++ kim {
++ compatible = "kim";
++ nshutdown_gpio = <44>; /* Bank1, pin12 */
++ dev_name = "/dev/ttyO4";
++ flow_cntrl = <1>;
++ baud_rate = <3000000>;
++ };
++
++ btwilink {
++ compatible = "btwilink";
++ };
++};
++
++&am33xx_pinmux {
++ bt_pins: pinmux_bt_pins {
++ pinctrl-single,pins = <
++ 0x30 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_ad12.gpio1_12 */
++ >;
++ };
++
++ mmc2_pins: pinmux_mmc2_pins {
++ pinctrl-single,pins = <
++ 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
++ 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
++ 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
++ 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
++ 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
++ 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
++ >;
++ };
++
++ mmc2_pins_sleep: pinmux_mmc2_pins_sleep {
++ pinctrl-single,pins = <
++ 0x80 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn1.mmc1_clk */
++ 0x84 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn2.mmc1_cmd */
++ 0x00 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad0.mmc1_dat0 */
++ 0x04 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad1.mmc1_dat1 */
++ 0x08 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad2.mmc1_dat2 */
++ 0x0c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad3.mmc1_dat3 */
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins: pinmux_wlan_pins {
++ pinctrl-single,pins = <
++ 0x28 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad10.gpio0_26 WL_EN*/
++ 0x2C (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_ad11.gpio0_27 WL_IRQ*/
++ 0x7C (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0.gpio1_29 BF_EN*/
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins_sleep: pinmux_wlan_pins_sleep {
++ pinctrl-single,pins = <
++ 0x28 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_ad10.gpio0_26 WL_EN*/
++ 0x2C (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_ad11.gpio0_27 WL_IRQ*/
++ 0x7C (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0.gpio1_29 BF_EN*/
++ >;
++ };
++
++ uart4_pins_default: pinmux_uart4_pins_default {
++ pinctrl-single,pins = <
++ 0xD0 (PIN_INPUT | MUX_MODE6) /* lcd_data12.uart4_cts */
++ 0xD4 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* lcd_data13.uart4_rts */
++ 0x70 (PIN_INPUT_PULLUP | MUX_MODE6) /* gpmc_wait0.uart4_rxd */
++ 0x74 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_wpn.uart4_txd */
++ >;
++ };
++
++ uart4_pins_sleep: pinmux_uart4_pins_sleep {
++ pinctrl-single,pins = <
++ 0xD0 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_data12.uart4_cts */
++ 0xD4 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_data13.uart4_rts */
++ 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_wait0.uart4_rxd */
++ 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_wpn.uart4_txd */
++ >;
++ };
++};
++
++&mmc2 {
++ status = "okay";
++ vmmc-supply = <&wlan_en_reg>;
++ bus-width = <4>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&mmc2_pins &wlan_pins>;
++ pinctrl-1 = <&mmc2_pins_sleep &wlan_pins_sleep>;
++ ti,non-removable;
++ ti,needs-special-hs-handling;
++ cap-power-off-card;
++ keep-power-in-suspend;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ wlcore: wlcore@0 {
++ compatible = "ti,wl1835";
++ reg = <2>;
++ interrupt-parent = <&gpio0>;
++ interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
++ };
++};
++
++&uart4 {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&uart4_pins_default>;
++ pinctrl-1 = <&uart4_pins_sleep>;
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblack-wl1835mod.dts b/arch/arm/boot/dts/am335x-boneblack-wl1835mod.dts
+new file mode 100644
+index 0000000..f35b64a
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblack-wl1835mod.dts
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Black";
++ compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++/* EMMC in reset */
++&gpio1 {
++ emmc_rst {
++ gpio-hog;
++ gpios = <20 0>;
++ output-high;
++ line-name = "EMMC ResetN";
++ };
++};
++
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
++#include "am335x-boneblack-wl1835mod-cape.dtsi"
+diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
+index 6bbb1fe..8f5d559 100644
+--- a/arch/arm/boot/dts/am335x-boneblack.dts
++++ b/arch/arm/boot/dts/am335x-boneblack.dts
+@@ -10,6 +10,7 @@
+ #include "am33xx.dtsi"
+ #include "am335x-bone-common.dtsi"
+ #include <dt-bindings/display/tda998x.h>
++/* #include "am335x-bone-jtag.dtsi" */
+
+ / {
+ model = "TI AM335x BeagleBone Black";
+@@ -34,6 +35,17 @@
+ status = "okay";
+ };
+
++&cpu0_opp_table {
++ /*
++ * All PG 2.0 silicon may not support 1GHz but some of the early
++ * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
++ * to support 1GHz OPP so enable it for PG 2.0 on this board.
++ */
++ oppnitro@1000000000 {
++ opp-supported-hw = <0x06 0x0100>;
++ };
++};
++
+ &am33xx_pinmux {
+ nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
+ pinctrl-single,pins = <
+@@ -108,10 +120,6 @@
+ };
+ };
+
+-&rtc {
+- system-power-controller;
+-};
+-
+ &mcasp0 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+diff --git b/arch/arm/boot/dts/am335x-boneblue-wl1835.dtsi b/arch/arm/boot/dts/am335x-boneblue-wl1835.dtsi
+new file mode 100644
+index 0000000..64731b0
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblue-wl1835.dtsi
+@@ -0,0 +1,143 @@
++
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/ {
++ wlan_en_reg: fixedregulator@2 {
++ compatible = "regulator-fixed";
++ regulator-name = "wlan-en-regulator";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ startup-delay-us= <70000>;
++
++ /* WL_EN */
++ gpio = <&gpio3 9 0>;
++ enable-active-high;
++ };
++
++ leds {
++ pinctrl-names = "default";
++ pinctrl-0 = <&wl18xx_pins>;
++ compatible = "gpio-leds";
++
++ wl18xx_bt_en {
++ label = "wl18xx_bt_en";
++ gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
++ default-state = "off";
++ };
++ };
++
++ btwilink {
++ compatible = "btwilink";
++ };
++};
++
++&am33xx_pinmux {
++ wl18xx_pins: pinmux_wl18xx_pins {
++ pinctrl-single,pins = <
++ 0x128 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* (K17) gmii1_txd0.gpio0[28] - BT_EN */
++ >;
++ };
++
++ wlbtbuf_pin: pinmux_wlbtbuf_pin {
++ pinctrl-single,pins = <
++ 0x130 ( PIN_OUTPUT_PULLUP | MUX_MODE7 ) /* (L18) gmii1_rxclk.gpio3[10] - LS_BUF_EN */
++ >;
++ };
++
++ mmc3_pins: pinmux_mmc3_pins {
++ pinctrl-single,pins = <
++ 0x13c ( PIN_INPUT_PULLUP | MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */
++ 0x114 ( PIN_INPUT_PULLUP | MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */
++ 0x118 ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */
++ 0x11c ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */
++ 0x120 ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */
++ 0x108 ( PIN_INPUT_PULLUP | MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */
++ >;
++ };
++
++ mmc3_pins_sleep: pinmux_mmc3_pins_sleep {
++ pinctrl-single,pins = <
++ 0x13c ( PIN_INPUT_PULLDOWN | MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */
++ 0x114 ( PIN_INPUT_PULLDOWN | MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */
++ 0x118 ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */
++ 0x11c ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */
++ 0x120 ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */
++ 0x108 ( PIN_INPUT_PULLDOWN | MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins: pinmux_wlan_pins {
++ pinctrl-single,pins = <
++ 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE7 ) /* (K18) gmii1_txclk.gpio3[9] - WL_EN */
++ 0x124 (PIN_INPUT_PULLUP | MUX_MODE7 ) /* (K16) gmii1_txd1.gpio0[21] - WL_IRQ */
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins_sleep: pinmux_wlan_pins_sleep {
++ pinctrl-single,pins = <
++ 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE7 ) /* (K18) gmii1_txclk.gpio3[9] - WL_EN */
++ 0x124 (PIN_INPUT_PULLUP | MUX_MODE7 ) /* (K16) gmii1_txd1.gpio0[21] - WL_IRQ */
++ >;
++ };
++
++ uart3_pins_default: pinmux_uart3_pins_default {
++ pinctrl-single,pins = <
++ 0x134 ( PIN_INPUT_PULLUP | MUX_MODE1 ) /* (L17) gmii1_rxd3.uart3_rxd */
++ 0x138 ( PIN_OUTPUT_PULLDOWN | MUX_MODE1 ) /* (L16) gmii1_rxd2.uart3_txd */
++ 0x148 ( PIN_INPUT | MUX_MODE3 ) /* (M17) mdio_data.uart3_ctsn */
++ 0x14c ( PIN_OUTPUT_PULLDOWN | MUX_MODE3 ) /* (M18) mdio_clk.uart3_rtsn */
++ >;
++ };
++
++ uart3_pins_sleep: pinmux_uart3_pins_sleep {
++ pinctrl-single,pins = <
++ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (L17) gmii1_rxd3.uart3_rxd */
++ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (L16) gmii1_rxd2.uart3_txd */
++ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M17) mdio_data.uart3_ctsn */
++ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M18) mdio_clk.uart3_rtsn */
++ >;
++ };
++};
++
++&mmc3 {
++ dmas = <&edma_xbar 12 0 1
++ &edma_xbar 13 0 2>;
++ dma-names = "tx", "rx";
++ status = "okay";
++ vmmc-supply = <&wlan_en_reg>;
++ bus-width = <4>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&mmc3_pins &wlan_pins &wlbtbuf_pin>;
++ pinctrl-1 = <&mmc3_pins_sleep &wlan_pins_sleep &wlbtbuf_pin>;
++ ti,non-removable;
++ ti,needs-special-hs-handling;
++ cap-power-off-card;
++ keep-power-in-suspend;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ wlcore: wlcore@0 {
++ compatible = "ti,wl1835";
++ reg = <2>;
++ interrupt-parent = <&gpio0>;
++ interrupts = <21 IRQ_TYPE_EDGE_RISING>;
++ };
++};
++
++&uart3 {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&uart3_pins_default>;
++ pinctrl-1 = <&uart3_pins_sleep>;
++ status = "okay";
++};
++
++&gpio3 {
++ ls_buf_en {
++ gpio-hog;
++ gpios = <10 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "LS_BUF_EN";
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-boneblue.dts b/arch/arm/boot/dts/am335x-boneblue.dts
+new file mode 100644
+index 0000000..e2a2fb5
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-boneblue.dts
+@@ -0,0 +1,569 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common-no-capemgr.dtsi"
++#include "am335x-bone-common-universal-pins.dtsi"
++#include "am335x-boneblue-wl1835.dtsi"
++/* #include "am33xx-pruss-rproc.dtsi" */
++
++#define BLUE_IO(x, y) AM33XX_IOPAD((x)*4+0x800, (y)) /* not used anymore */
++
++
++/ {
++ model = "TI AM335x BeagleBone Blue";
++ compatible = "ti,am335x-bone-blue", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&mac {
++ status = "disabled";
++};
++
++/*******************************************************************************
++* Pin Muxing
++*******************************************************************************/
++&am33xx_pinmux {
++
++ /***************************************************************************
++ * Static Pinmux
++ ***************************************************************************/
++ mux_helper_pins: pins {
++ pinctrl-single,pins = <
++
++ /* GPIO Inputs */
++ 0x09c 0x37 /*P8.9 Pause BUTTON, input pullup*/
++ 0x098 0x37 /*P8.10 MODE BUTTON input pullup*/
++ 0x1AC 0x37 /*P9.25 MPU-9150 INTERRUPT IN*/
++
++ /* LEDs GPIO Out*/
++ 0x090 0x0F /* P8.7 R7 LED_RED */
++ 0x094 0x0F /* P8.8 T7 LED_GREEN */
++ 0x02C 0x0F /* P8.17 U12 BATT_LED_1 */
++ 0x0DC 0x0F /* P8.32 T5 BATT_LED_2 diff from cape! */
++ 0x07c 0x0F /* P8.26 V6 BATT_LED_3 */
++ 0x028 0x0F /* P8.14 T11 BATT_LED_4 */
++
++ /* Motor Control GPIO Out*/
++ 0x0a8 0x0F /*P8.43 MDIR_3B*/
++ 0x0ac 0x0F /*P8.44 MDIR_3A*/
++ 0x0a0 0x0F /*P8.45 MDIR_4A*/
++ 0x0a4 0x0F /*P8.46 MDIR_4B*/
++ 0x074 0x0F /*P9.13 MDIR_1B*/
++ 0x040 0x0F /*P9.15 MDIR_2A*/
++ 0x1b4 0x0F /*P9.41 MOT_STBY*/
++ 0x088 0x0F /*T13 MDIR_1A different from cape! */
++ 0x0D8 0x0F /*P8.31 MDIR_2B different from cape! */
++
++ /* HRPWM 1 */
++ 0x048 0x6 /* P9_14 | MODE 6 */
++ 0x04c 0x6 /* P9_16 | MODE 6 */
++
++ /* HRPWM 2 */
++ 0x020 0x4 /* P8_19 | MODE 4 */
++ 0x024 0x4 /* P8_13 | MODE 4 */
++
++ /* EQEP */
++ 0x1A0 0x31 /* P9_42,EQEP0A, MODE1 */
++ 0x1A4 0x31 /* P9_27,EQEP0B, MODE1 */
++ 0x0D4 0x32 /* P8_33,EQEP1B, MODE2 */
++ 0x0D0 0x32 /* P8_35,EQEP1A, MODE2 */
++ 0x030 0x34 /* P8_12,EQEP2A, MODE4 */
++ 0x034 0x34 /* P8_11,EQEP2B, MODE4 */
++
++ /* PRU encoder input */
++ 0x03c 0x36 /* P8_15,PRU0_r31_15,MODE6 */
++ 0x038 0x36 /* P8_16,PRU0_r31_16,MODE6 */
++
++ /* PRU Servo output */
++ 0x0e0 0x05 /*pru1_pru_r30_8, MODE5*/
++ 0x0e8 0x05 /*pru1_pru_r30_10, MODE5 */
++ 0x0e4 0x05 /*pr1_pru1_pru_r30_9, MODE5 */
++ 0x0ec 0x05 /*pru1_pru_r30_11, MODE5 */
++ 0x0b8 0x05 /*pru1_pru_r30_6, MODE5 */
++ 0x0bc 0x05 /*pru1_pru_r30_7, MODE5 */
++ 0x0b0 0x05 /*pru1_pru_r30_4, MODE5 */
++ 0x0b4 0x05 /*pru1_pru_r30_5, MODE5 */
++ 0x0C8 0x0F /*P8.36, SERVO_PWR GPIO OUT*/
++
++ /* I2C1 */
++ 0x15C 0x32 /* P9.17,i2c1_scl,INPUT_PULLUP,MODE2 */
++ 0x158 0x32 /* P9.18,i2c1_sda,INPUT_PULLUP,MODE2 */
++
++ /* I2C2 */
++ 0x17c 0x73 /* P9.19, i2c2_sda, mode 3 */
++ 0x178 0x73 /* P9.20, i2c2_sda, mode 3 */
++
++ /* UART5 */
++ 0x0C4 0x34 /* P8.38,uart5_rxd,MODE4 */
++ 0x0C0 0x14 /* P8.37,uart5_txd,MODE4 */
++
++ /* WILINK 8 */
++ 0x08c 0x0F /*P8.18 V12 A2DP FSYNC */
++ 0x078 0x0F /*P9.12 A2DP_CLOCK*/
++
++ /* DCAN */
++ 0x16c ( PIN_INPUT | MUX_MODE2 ) /* (E17) uart0_rtsn.dcan1_rx */
++ 0x168 ( PIN_OUTPUT | MUX_MODE2 ) /* (E18) uart0_ctsn.dcan1_tx */
++ >;
++
++ /***********************************************************************
++ * New configurable pinmux modes for pins not on Black headers
++ ***********************************************************************/
++ /* H18 SPI1_SS1 */
++ H18_default_pin: pinmux_H18_default_pin {
++ pinctrl-single,pins = < 0x144 ( PIN_OUTPUT | MUX_MODE4 ) >; };
++ H18_gpio_pin: pinmux_H18_gpio_pin {
++ pinctrl-single,pins = < 0x144 ( PIN_OUTPUT | MUX_MODE7 ) >; };
++ H18_gpio_pu_pin: pinmux_H18_gpio_pu_pin {
++ pinctrl-single,pins = < 0x144 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ H18_gpio_pd_pin: pinmux_H18_gpio_pd_pin {
++ pinctrl-single,pins = < 0x144 ( PIN_INPUT_PULLDOWN | MUX_MODE7 ) >; };
++ H18_spi_pin: pinmux_H18_spi_pin {
++ pinctrl-single,pins = < 0x144 ( PIN_OUTPUT | MUX_MODE2 ) >; };
++
++ /* C18 SPI1_SS2 */
++ C18_default_pin: pinmux_C18_default_pin {
++ pinctrl-single,pins = < 0x164 ( PIN_OUTPUT | MUX_MODE4 ) >; };
++ C18_gpio_pin: pinmux_C18_gpio_pin {
++ pinctrl-single,pins = < 0x164 ( PIN_OUTPUT | MUX_MODE7 ) >; };
++ C18_gpio_pu_pin: pinmux_C18_gpio_pu_pin {
++ pinctrl-single,pins = < 0x164 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ C18_gpio_pd_pin: pinmux_C18_gpio_pd_pin {
++ pinctrl-single,pins = < 0x164 ( PIN_INPUT_PULLDOWN | MUX_MODE7 ) >; };
++ C18_spi_pin: pinmux_C18_spi_pin {
++ pinctrl-single,pins = < 0x164 ( PIN_OUTPUT | MUX_MODE2 ) >; };
++
++ /* U16 BLUE_GP0_PIN_3 gpio 1_25 */
++ U16_default_pin: pinmux_U16_default_pin {
++ pinctrl-single,pins = < 0x064 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ U16_gpio_pin: pinmux_U16_gpio_pin {
++ pinctrl-single,pins = < 0x064 ( PIN_OUTPUT | MUX_MODE7 ) >; };
++ U16_gpio_pu_pin: pinmux_U16_gpio_pu_pin {
++ pinctrl-single,pins = < 0x064 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ U16_gpio_pd_pin: pinmux_U16_gpio_pd_pin {
++ pinctrl-single,pins = < 0x064 ( PIN_INPUT_PULLDOWN | MUX_MODE7 ) >; };
++
++ /* D13 BLUE_GP0_PIN_5 gpio 3_20 */
++ D13_default_pin: pinmux_D13_default_pin {
++ pinctrl-single,pins = < 0x1A8 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ D13_gpio_pin: pinmux_D13_gpio_pin {
++ pinctrl-single,pins = < 0x1A8 ( PIN_OUTPUT | MUX_MODE7 ) >; };
++ D13_gpio_pu_pin: pinmux_D13_gpio_pu_pin {
++ pinctrl-single,pins = < 0x1A8 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ D13_gpio_pd_pin: pinmux_D13_gpio_pd_pin {
++ pinctrl-single,pins = < 0x1A8 ( PIN_INPUT_PULLDOWN | MUX_MODE7 ) >; };
++
++ /* J15 BLUE_GP1_PIN_3 gpio 3_2 */
++ J15_default_pin: pinmux_J15_default_pin {
++ pinctrl-single,pins = < 0x110 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ J15_gpio_pin: pinmux_J15_gpio_pin {
++ pinctrl-single,pins = < 0x110 ( PIN_OUTPUT | MUX_MODE7 ) >; };
++ J15_gpio_pu_pin: pinmux_J15_gpio_pu_pin {
++ pinctrl-single,pins = < 0x110 ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ J15_gpio_pd_pin: pinmux_J15_gpio_pd_pin {
++ pinctrl-single,pins = < 0x110 ( PIN_INPUT_PULLDOWN | MUX_MODE7 ) >; };
++
++ /* H17 BLUE_GP1_PIN_4 gpio 3_1 */
++ H17_default_pin: pinmux_H17_default_pin {
++ pinctrl-single,pins = < 0x10C ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ H17_gpio_pin: pinmux_H17_gpio_pin {
++ pinctrl-single,pins = < 0x10C ( PIN_OUTPUT | MUX_MODE7 ) >; };
++ H17_gpio_pu_pin: pinmux_H17_gpio_pu_pin {
++ pinctrl-single,pins = < 0x10C ( PIN_INPUT_PULLUP | MUX_MODE7 ) >; };
++ H17_gpio_pd_pin: pinmux_H17_gpio_pd_pin {
++ pinctrl-single,pins = < 0x10C ( PIN_INPUT_PULLDOWN | MUX_MODE7 ) >; };
++ };
++
++};
++
++
++/*******************************************************************************
++* apply static and dynamic pinmux modes listed above. Pins shared with the black
++* header pins get the modes from am335x-boneblack-common-universal-pins.dtsi
++*******************************************************************************/
++&ocp {
++ /* activate the static pinmux helper list of pin modes above */
++ test_helper: helper {
++ compatible = "bone-pinmux-helper";
++ pinctrl-names = "default";
++ pinctrl-0 = <&mux_helper_pins>;
++
++ status = "okay";
++ };
++
++ /* UART4 RX DSM */
++ P9_11_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart";
++ pinctrl-0 = <&P9_11_default_pin>;
++ pinctrl-1 = <&P9_11_gpio_pin>;
++ pinctrl-2 = <&P9_11_gpio_pu_pin>;
++ pinctrl-3 = <&P9_11_gpio_pd_pin>;
++ pinctrl-4 = <&P9_11_uart_pin>;
++ };
++
++ /* UART 2 TX GPS*/
++ P9_21_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
++ pinctrl-0 = <&P9_21_default_pin>;
++ pinctrl-1 = <&P9_21_gpio_pin>;
++ pinctrl-2 = <&P9_21_gpio_pu_pin>;
++ pinctrl-3 = <&P9_21_gpio_pd_pin>;
++ pinctrl-4 = <&P9_21_spi_pin>;
++ pinctrl-5 = <&P9_21_uart_pin>;
++ pinctrl-6 = <&P9_21_i2c_pin>;
++ pinctrl-7 = <&P9_21_pwm_pin>;
++ };
++
++ /* UART 2 RX GPS */
++ P9_22_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
++ pinctrl-0 = <&P9_22_default_pin>;
++ pinctrl-1 = <&P9_22_gpio_pin>;
++ pinctrl-2 = <&P9_22_gpio_pu_pin>;
++ pinctrl-3 = <&P9_22_gpio_pd_pin>;
++ pinctrl-4 = <&P9_22_spi_pin>;
++ pinctrl-5 = <&P9_22_uart_pin>;
++ pinctrl-6 = <&P9_22_i2c_pin>;
++ pinctrl-7 = <&P9_22_pwm_pin>;
++ };
++
++ /* SPI MISO */
++ P9_29_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_29_default_pin>;
++ pinctrl-1 = <&P9_29_gpio_pin>;
++ pinctrl-2 = <&P9_29_gpio_pu_pin>;
++ pinctrl-3 = <&P9_29_gpio_pd_pin>;
++ pinctrl-4 = <&P9_29_pwm_pin>;
++ pinctrl-5 = <&P9_29_spi_pin>;
++ pinctrl-6 = <&P9_29_pruout_pin>;
++ pinctrl-7 = <&P9_29_pruin_pin>;
++ };
++
++ /* SPI MOSI */
++ P9_30_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_30_default_pin>;
++ pinctrl-1 = <&P9_30_gpio_pin>;
++ pinctrl-2 = <&P9_30_gpio_pu_pin>;
++ pinctrl-3 = <&P9_30_gpio_pd_pin>;
++ pinctrl-4 = <&P9_30_pwm_pin>;
++ pinctrl-5 = <&P9_30_spi_pin>;
++ pinctrl-6 = <&P9_30_pruout_pin>;
++ pinctrl-7 = <&P9_30_pruin_pin>;
++ };
++
++ /* SPI SCK */
++ P9_31_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_31_default_pin>;
++ pinctrl-1 = <&P9_31_gpio_pin>;
++ pinctrl-2 = <&P9_31_gpio_pu_pin>;
++ pinctrl-3 = <&P9_31_gpio_pd_pin>;
++ pinctrl-4 = <&P9_31_pwm_pin>;
++ pinctrl-5 = <&P9_31_spi_pin>;
++ pinctrl-6 = <&P9_31_pruout_pin>;
++ pinctrl-7 = <&P9_31_pruin_pin>;
++ };
++
++ /* SPI SS1 */
++ H18_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi";
++ pinctrl-0 = <&H18_default_pin>;
++ pinctrl-1 = <&H18_gpio_pin>;
++ pinctrl-2 = <&H18_gpio_pu_pin>;
++ pinctrl-3 = <&H18_gpio_pd_pin>;
++ pinctrl-4 = <&H18_spi_pin>;
++ };
++
++ /* SPI SS2 */
++ C18_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi";
++ pinctrl-0 = <&C18_default_pin>;
++ pinctrl-1 = <&C18_gpio_pin>;
++ pinctrl-2 = <&C18_gpio_pu_pin>;
++ pinctrl-3 = <&C18_gpio_pd_pin>;
++ pinctrl-4 = <&C18_spi_pin>;
++ };
++
++ /* UART 1 TX */
++ P9_24_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
++ pinctrl-0 = <&P9_24_default_pin>;
++ pinctrl-1 = <&P9_24_gpio_pin>;
++ pinctrl-2 = <&P9_24_gpio_pu_pin>;
++ pinctrl-3 = <&P9_24_gpio_pd_pin>;
++ pinctrl-4 = <&P9_24_uart_pin>;
++ pinctrl-5 = <&P9_24_can_pin>;
++ pinctrl-6 = <&P9_24_i2c_pin>;
++ pinctrl-7 = <&P9_24_pruin_pin>;
++ };
++
++ /* UART 1 RX */
++ P9_26_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
++ pinctrl-0 = <&P9_26_default_pin>;
++ pinctrl-1 = <&P9_26_gpio_pin>;
++ pinctrl-2 = <&P9_26_gpio_pu_pin>;
++ pinctrl-3 = <&P9_26_gpio_pd_pin>;
++ pinctrl-4 = <&P9_26_uart_pin>;
++ pinctrl-5 = <&P9_26_can_pin>;
++ pinctrl-6 = <&P9_26_i2c_pin>;
++ pinctrl-7 = <&P9_26_pruin_pin>;
++ };
++
++ /* U16 BLUE_GP0_PIN_3 gpio 1_25*/
++ U16_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd";
++ pinctrl-0 = <&U16_default_pin>;
++ pinctrl-1 = <&U16_gpio_pin>;
++ pinctrl-2 = <&U16_gpio_pu_pin>;
++ pinctrl-3 = <&U16_gpio_pd_pin>;
++ };
++
++
++ /* BLUE_GP0_PIN_3 gpio1_17*/
++ P9_23_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P9_23_default_pin>;
++ pinctrl-1 = <&P9_23_gpio_pin>;
++ pinctrl-2 = <&P9_23_gpio_pu_pin>;
++ pinctrl-3 = <&P9_23_gpio_pd_pin>;
++ pinctrl-4 = <&P9_23_pwm_pin>;
++ };
++
++ /* BLUE_GP0_PIN_5 gpio3_20 */
++ D13_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd";
++ pinctrl-0 = <&D13_default_pin>;
++ pinctrl-1 = <&D13_gpio_pin>;
++ pinctrl-2 = <&D13_gpio_pu_pin>;
++ pinctrl-3 = <&D13_gpio_pd_pin>;
++ };
++
++ /* BLUE_GP0_PIN_6 gpio3_17 */
++ P9_28_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pwm2", "pruout", "pruin";
++ pinctrl-0 = <&P9_28_default_pin>;
++ pinctrl-1 = <&P9_28_gpio_pin>;
++ pinctrl-2 = <&P9_28_gpio_pu_pin>;
++ pinctrl-3 = <&P9_28_gpio_pd_pin>;
++ pinctrl-4 = <&P9_28_pwm_pin>;
++ pinctrl-5 = <&P9_28_spi_pin>;
++ pinctrl-6 = <&P9_28_pwm2_pin>;
++ pinctrl-7 = <&P9_28_pruout_pin>;
++ pinctrl-8 = <&P9_28_pruin_pin>;
++ };
++
++ /* BLUE_GP1_PIN_3 gpio3_2 */
++ J15_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd";
++ pinctrl-0 = <&J15_default_pin>;
++ pinctrl-1 = <&J15_gpio_pin>;
++ pinctrl-2 = <&J15_gpio_pu_pin>;
++ pinctrl-3 = <&J15_gpio_pd_pin>;
++ };
++
++ /* BLUE_GP1_PIN_4 gpio3_1 */
++ H17_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd";
++ pinctrl-0 = <&H17_default_pin>;
++ pinctrl-1 = <&H17_gpio_pin>;
++ pinctrl-2 = <&H17_gpio_pu_pin>;
++ pinctrl-3 = <&H17_gpio_pd_pin>;
++ };
++
++
++
++};
++
++
++/*******************************************************************************
++* PWMSS
++*******************************************************************************/
++&epwmss0 {
++ status = "okay";
++};
++
++&epwmss1 {
++ status = "okay";
++};
++
++&epwmss2 {
++ status = "okay";
++};
++
++&ehrpwm0 {
++ status = "okay";
++};
++
++&ehrpwm1 {
++ status = "okay";
++};
++
++&ehrpwm2 {
++ status = "okay";
++};
++
++
++/*******************************************************************************
++* EQEP
++*******************************************************************************/
++&eqep0 {
++ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
++ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
++ invert_qa = <1>; /* Should we invert the channel A input? */
++ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
++ invert_qi = <0>; /* Should we invert the index input? */
++ invert_qs = <0>; /* Should we invert the strobe input? */
++ status = "okay";
++};
++
++&eqep1 {
++ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
++ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
++ invert_qa = <1>; /* Should we invert the channel A input? */
++ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
++ invert_qi = <0>; /* Should we invert the index input? */
++ invert_qs = <0>; /* Should we invert the strobe input? */
++ status = "okay";
++};
++
++&eqep2 {
++ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
++ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
++ invert_qa = <1>; /* Should we invert the channel A input? */
++ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
++ invert_qi = <0>; /* Should we invert the index input? */
++ invert_qs = <0>; /* Should we invert the strobe input? */
++ status = "okay";
++};
++
++
++/*******************************************************************************
++ UART
++*******************************************************************************/
++
++&uart1 {
++ status = "okay";
++};
++
++&uart2 {
++ status = "okay";
++};
++
++&uart4 {
++ status = "okay";
++};
++
++&uart5 {
++ status = "okay";
++};
++
++
++/*******************************************************************************
++ PRU
++*******************************************************************************/
++&pruss {
++ status = "okay";
++};
++
++
++/*******************************************************************************
++ I2C
++*******************************************************************************/
++&i2c1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++ clock-frequency = <400000>;
++};
++
++&i2c2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++ clock-frequency = <400000>;
++};
++
++/*******************************************************************************
++ SPI
++*******************************************************************************/
++&spi1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ channel@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "spidev";
++ reg = <0>;
++ spi-max-frequency = <24000000>;
++ };
++
++ channel@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "spidev";
++ reg = <1>;
++ spi-max-frequency = <24000000>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bonegreen-overlay.dts b/arch/arm/boot/dts/am335x-bonegreen-overlay.dts
+new file mode 100644
+index 0000000..a703fcd
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bonegreen-overlay.dts
+@@ -0,0 +1,36 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++
++/ {
++ model = "TI AM335x BeagleBone Green";
++ compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++/* EMMC in reset */
++&gpio1 {
++ emmc_rst {
++ gpio-hog;
++ gpios = <20 0>;
++ output-high;
++ line-name = "EMMC ResetN";
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts
+new file mode 100644
+index 0000000..f37f39e
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++#include "am335x-bonegreen-wl1835.dtsi"
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "TI AM335x BeagleBone Green Wireless";
++ compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++};
++
++&uart3 {
++ status = "okay";
++};
++
++&mmc3 {
++ status = "okay";
++};
++
++&mac {
++ status = "disabled";
++};
+diff --git b/arch/arm/boot/dts/am335x-bonegreen-wl1835.dtsi b/arch/arm/boot/dts/am335x-bonegreen-wl1835.dtsi
+new file mode 100644
+index 0000000..0d4798d
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-bonegreen-wl1835.dtsi
+@@ -0,0 +1,147 @@
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/ {
++ wlan_en_reg: fixedregulator@2 {
++ compatible = "regulator-fixed";
++ regulator-name = "wlan-en-regulator";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ startup-delay-us= <70000>;
++
++ /* WL_EN */
++ gpio = <&gpio0 26 0>;
++ enable-active-high;
++ };
++
++ btwilink {
++ compatible = "btwilink";
++ };
++
++ wilink8_pcm: wilink8_pcm {
++ compatible = "ti,wilink8_bt";
++ status = "okay";
++ };
++
++ sound{
++ compatible = "ti,wilink8-bt-audio";
++ ti,model = "WILINK8_BT";
++ ti,audio-codec = <&wilink8_pcm>;
++ ti,mcasp-controller = <&mcasp0>;
++ ti,codec-clock-rate = <24000000>;
++ };
++};
++
++&am33xx_pinmux {
++ bt_pins: pinmux_bt_pins {
++ pinctrl-single,pins = <
++ 0x78 (PIN_OUTPUT | MUX_MODE7) /* gpmc_ad12.gpio1_28 BT_EN*/
++ >;
++ };
++
++ mmc3_pins: pinmux_mmc3_pins {
++ pinctrl-single,pins = <
++ 0x8c ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio2_1 gpmc_clk.mmc2_clk */
++ 0x88 ( PIN_INPUT_PULLUP | MUX_MODE3) /* gpio2_0 gpmc_csn3.mmc2_cmd */
++ 0x30 ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_12 gpmc_ad12.mmc2_dat0 */
++ 0x34 ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_13 gpmc_ad13.mmc2_dat1 */
++ 0x38 ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_14 gpmc_ad14.mmc2_dat2 */
++ 0x3c ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_15 gpmc_ad15.mmc2_dat3 */
++ >;
++ };
++
++ mmc3_pins_sleep: pinmux_mmc3_pins_sleep {
++ pinctrl-single,pins = <
++ 0x8c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio2_1 gpmc_clk.mmc2_clk */
++ 0x88 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio2_0 gpmc_csn3.mmc2_cmd */
++ 0x30 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_12 gpmc_ad12.mmc2_dat0 */
++ 0x34 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_13 gpmc_ad13.mmc2_dat1 */
++ 0x38 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_14 gpmc_ad14.mmc2_dat2 */
++ 0x3c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_15 gpmc_ad15.mmc2_dat3 */
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins: pinmux_wlan_pins {
++ pinctrl-single,pins = <
++ 0x28 (PIN_OUTPUT_PULLDOWN| MUX_MODE7) /* gpmc_ad10.gpio0_26 WL_EN*/
++ 0x2C (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad11.gpio0_27 WL_IRQ*/
++ 0x7C (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0.gpio1_29 Cape_Buffer_EN*/
++ >;
++ };
++
++ /* wl18xx card enable/irq GPIOs. */
++ wlan_pins_sleep: pinmux_wlan_pins_sleep {
++ pinctrl-single,pins = <
++ 0x28 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad10.gpio0_26 WL_EN*/
++ 0x2C (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad11.gpio0_27 WL_IRQ*/
++ 0x7C (PIN_OUTPUT_PULLUP | MUX_MODE0) /* gpmc_csn0.gpio1_29 Cape_Buffer_EN*/
++ >;
++ };
++
++ uart3_pins_default: pinmux_uart3_pins_default {
++ pinctrl-single,pins = <
++ 0x134 ( PIN_INPUT_PULLUP | MUX_MODE1 ) /* (L17) gmii1_rxd3.uart3_rxd */
++ 0x138 ( PIN_OUTPUT_PULLDOWN | MUX_MODE1 ) /* (L16) gmii1_rxd2.uart3_txd */
++ 0x148 ( PIN_INPUT | MUX_MODE3 ) /* (M17) mdio_data.uart3_ctsn */
++ 0x14c ( PIN_OUTPUT_PULLDOWN | MUX_MODE3 ) /* (M18) mdio_clk.uart3_rtsn */
++ >;
++ };
++
++ uart3_pins_sleep: pinmux_uart3_pins_sleep {
++ pinctrl-single,pins = <
++ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (L17) gmii1_rxd3.uart3_rxd */
++ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (L16) gmii1_rxd2.uart3_txd */
++ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M17) mdio_data.uart3_ctsn */
++ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M18) mdio_clk.uart3_rtsn */
++ >;
++ };
++};
++
++&mmc3 {
++ dmas = <&edma_xbar 12 0 1
++ &edma_xbar 13 0 2>;
++ dma-names = "tx", "rx";
++ status = "okay";
++ vmmc-supply = <&wlan_en_reg>;
++ bus-width = <4>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&mmc3_pins &wlan_pins>;
++ pinctrl-1 = <&mmc3_pins_sleep &wlan_pins_sleep>;
++ ti,non-removable;
++ ti,needs-special-hs-handling;
++ cap-power-off-card;
++ keep-power-in-suspend;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ wlcore: wlcore@0 {
++ compatible = "ti,wl1835";
++ reg = <2>;
++ interrupt-parent = <&gpio0>;
++ interrupts = <27 IRQ_TYPE_EDGE_RISING>;
++ };
++};
++
++&uart3 {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&uart3_pins_default &bt_pins>;
++ pinctrl-1 = <&uart3_pins_sleep &bt_pins>;
++ status = "okay";
++};
++
++/* BT_AUD_OUT from wl1835 has to be pulled low when WL_EN is activated. */
++/* in case it isn't, wilink8 ends up in one of the test modes that */
++/* intruces various issues (elp wkaeup timeouts etc.) */
++/* On the BBGW this pin is routed through the level shifter (U21) that */
++/* introduces a pullup on the line and wilink8 ends up in a bad state. */
++/* use a gpio hog to force this pin low. An alternative may be adding */
++/* an external pulldown on U21 pin 4. */
++
++&gpio3 {
++ bt_aud_in {
++ gpio-hog;
++ gpios = <16 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "MCASP0_AXR0";
++ };
++};
+diff --git a/arch/arm/boot/dts/am335x-bonegreen.dts b/arch/arm/boot/dts/am335x-bonegreen.dts
+index dce3c86..647d4bf 100644
+--- a/arch/arm/boot/dts/am335x-bonegreen.dts
++++ b/arch/arm/boot/dts/am335x-bonegreen.dts
+@@ -9,6 +9,7 @@
+
+ #include "am33xx.dtsi"
+ #include "am335x-bone-common.dtsi"
++/* #include "am335x-bone-jtag.dtsi" */
+
+ / {
+ model = "TI AM335x BeagleBone Green";
+@@ -32,22 +33,3 @@
+ bus-width = <8>;
+ status = "okay";
+ };
+-
+-&am33xx_pinmux {
+- uart2_pins: uart2_pins {
+- pinctrl-single,pins = <
+- AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd */
+- AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd */
+- >;
+- };
+-};
+-
+-&uart2 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart2_pins>;
+- status = "okay";
+-};
+-
+-&rtc {
+- system-power-controller;
+-};
+diff --git b/arch/arm/boot/dts/am335x-cape-bbb-exp-c.dtsi b/arch/arm/boot/dts/am335x-cape-bbb-exp-c.dtsi
+new file mode 100644
+index 0000000..01f9cde
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-cape-bbb-exp-c.dtsi
+@@ -0,0 +1,224 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++
++#include "am335x-peripheral-can0.dtsi"
++#include "am335x-bone-pinmux-can0.dtsi"
++
++#include "am335x-peripheral-ttyS1.dtsi"
++#include "am335x-bone-pinmux-ttyS1.dtsi"
++
++#include "am335x-peripheral-ttyS2.dtsi"
++#include "am335x-bone-pinmux-ttyS2.dtsi"
++
++#include "am335x-peripheral-ttyS4.dtsi"
++#include "am335x-bone-pinmux-ttyS4.dtsi"
++
++&am33xx_pinmux {
++ user_leds_s1: user_leds_s1 {
++ pinctrl-single,pins = <
++ 0x98 0x7 /* gpmc_wen.gpio2_4, OUTPUT | MODE7 */
++ 0x9c 0x7 /* gpmc_ben0_cle.gpio2_5, OUTPUT | MODE7 */
++ >;
++ };
++
++ bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins {
++ pinctrl-single,pins = <
++ BONE_P9_14 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_a2.ehrpwm1a */
++ >;
++ };
++
++ keymap3_pins: pinmux_keymap3_pins {
++ pinctrl-single,pins = <
++ 0x040 0x2f /* KEY_UP gpmc_a0.gpio1_16, INPUT | PULLDIS | MODE7 */
++ 0x04c 0x2f /* KEY_DOWN gpmc_a3.gpio1_19, INPUT | PULLDIS | MODE7 */
++ 0x078 0x2f /* KEY_RIGHT gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */
++ 0x164 0x2f /* KEY_LEFT ecap0_in_pwm0_out.gpio0_7, INPUT | PULLDIS | MODE7 */
++ 0x1a4 0x2f /* KEY_ENTER mcasp0_fxr.gpio3_19, INPUT | PULLDIS | MODE7 */
++ >;
++ };
++
++ edt_ft5306_ts_pins: pinmux_edt_ft5306_ts_pins {
++ pinctrl-single,pins = <
++ /* CAP_TSC gpmc_a1.gpio1_17, INPUT | MODE7 */
++ BONE_P9_23 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ i2c1_pins: pinmux_i2c1_pins {
++ pinctrl-single,pins = <
++ /* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
++ BONE_P9_18 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
++ /* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
++ BONE_P9_17 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
++ >;
++ };
++
++ mcasp0_pins: pinmux_mcasp0_pins {
++ pinctrl-single,pins = <
++ 0x190 0x20 /* mcasp0_aclkx.mcasp0_aclkx, INPUT | MODE0 */
++ 0x194 0x20 /* mcasp0_fsx.mcasp0_fsx, INPUT | MODE0 */
++ 0x198 0x20 /* mcasp0_axr0.mcasp0_axr0, INPUT | MODE0 */
++ 0x19c 0x22 /* mcasp0_ahclkr.mcasp0_axr2, INPUT | MODE2 */
++ >;
++ };
++};
++
++&epwmss1 {
++ status = "okay";
++};
++
++
++&ehrpwm1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&bb_lcd_pwm_backlight_pins>;
++ status = "okay";
++};
++
++&i2c1 {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <400000>;
++
++ edt-ft5306@38 {
++ status = "okay";
++ compatible = "edt,edt-ft5306", "edt,edt-ft5x06";
++ pinctrl-names = "default";
++ pinctrl-0 = <&edt_ft5306_ts_pins>;
++
++ reg = <0x38>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <17 0>;
++
++ touchscreen-size-x = <1024>;
++ touchscreen-size-y = <600>;
++ };
++
++ tlv320aic3x: tlv320aic3x@1b {
++ compatible = "ti,tlv320aic3x";
++ reg = <0x1b>;
++ status = "okay";
++ };
++};
++
++&mcasp0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&mcasp0_pins>;
++
++ status = "okay";
++
++ op-mode = <0>; /* MCASP_IIS_MODE */
++ tdm-slots = <2>;
++ num-serializer = <16>;
++ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
++ 1 0 2 0
++ 0 0 0 0
++ 0 0 0 0
++ 0 0 0 0
++ >;
++ tx-num-evt = <1>;
++ rx-num-evt = <1>;
++};
++
++/ {
++ backlight {
++ status = "okay";
++ compatible = "pwm-backlight";
++ pwms = <&ehrpwm1 0 50000 0>;
++ brightness-levels = <0 51 53 56 62 75 101 152 255>;
++ default-brightness-level = <8>;
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ pinctrl-names = "default";
++ pinctrl-0 = <&keymap3_pins>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ button@1 {
++ debounce_interval = <50>;
++ linux,code = <105>;
++ label = "left";
++ gpios = <&gpio0 7 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@2 {
++ debounce_interval = <50>;
++ linux,code = <106>;
++ label = "right";
++ gpios = <&gpio1 28 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@3 {
++ debounce_interval = <50>;
++ linux,code = <103>;
++ label = "up";
++ gpios = <&gpio1 16 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@4 {
++ debounce_interval = <50>;
++ linux,code = <108>;
++ label = "down";
++ gpios = <&gpio1 19 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@5 {
++ debounce_interval = <50>;
++ linux,code = <28>;
++ label = "enter";
++ gpios = <&gpio3 19 0x1>;
++ gpio-key,wakeup;
++ };
++ };
++
++ gpio-leds-cape-lcd {
++ compatible = "gpio-leds";
++ pinctrl-names = "default";
++
++ pinctrl-0 = <&user_leds_s1>;
++
++ lcd-led0 {
++ label = "lcd:green:usr0";
++ gpios = <&gpio2 4 0>;
++ linux,default-trigger = "heartbeat";
++ default-state = "off";
++ };
++
++ lcd-led1 {
++ label = "lcd:green:usr1";
++ gpios = <&gpio2 5 0>;
++ linux,default-trigger = "mmc0";
++ default-state = "off";
++ };
++ };
++
++ sound {
++ compatible = "ti,da830-evm-audio";
++ ti,model = "DA830 EVM";
++ ti,audio-codec = <&tlv320aic3x>;
++ ti,mcasp-controller = <&mcasp0>;
++ ti,codec-clock-rate = <12000000>;
++ ti,audio-routing =
++ "Headphone Jack", "HPLOUT",
++ "Headphone Jack", "HPROUT",
++ "MIC3L", "Mic Jack",
++ "MIC3R", "Mic Jack";
++ };
++};
++
++#include "am335x-peripheral-panel-1024x600-24bit.dtsi"
++#include "am335x-bone-pinmux-panel-1024x600-24bit.dtsi"
+diff --git b/arch/arm/boot/dts/am335x-cape-bbb-exp-r.dtsi b/arch/arm/boot/dts/am335x-cape-bbb-exp-r.dtsi
+new file mode 100644
+index 0000000..539409c
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-cape-bbb-exp-r.dtsi
+@@ -0,0 +1,217 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++
++#include "am335x-peripheral-can0.dtsi"
++#include "am335x-bone-pinmux-can0.dtsi"
++
++#include "am335x-peripheral-ttyS1.dtsi"
++#include "am335x-bone-pinmux-ttyS1.dtsi"
++
++#include "am335x-peripheral-ttyS2.dtsi"
++#include "am335x-bone-pinmux-ttyS2.dtsi"
++
++#include "am335x-peripheral-ttyS4.dtsi"
++#include "am335x-bone-pinmux-ttyS4.dtsi"
++
++&am33xx_pinmux {
++ user_leds_s1: user_leds_s1 {
++ pinctrl-single,pins = <
++ 0x98 0x7 /* gpmc_wen.gpio2_4, OUTPUT | MODE7 */
++ 0x9c 0x7 /* gpmc_ben0_cle.gpio2_5, OUTPUT | MODE7 */
++ >;
++ };
++
++ bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins {
++ pinctrl-single,pins = <
++ BONE_P9_14 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_a2.ehrpwm1a */
++ >;
++ };
++
++ keymap3_pins: pinmux_keymap3_pins {
++ pinctrl-single,pins = <
++ 0x040 0x2f /* KEY_UP gpmc_a0.gpio1_16, INPUT | PULLDIS | MODE7 */
++ 0x04c 0x2f /* KEY_DOWN gpmc_a3.gpio1_19, INPUT | PULLDIS | MODE7 */
++ 0x078 0x2f /* KEY_RIGHT gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */
++ 0x164 0x2f /* KEY_LEFT ecap0_in_pwm0_out.gpio0_7, INPUT | PULLDIS | MODE7 */
++ 0x1a4 0x2f /* KEY_ENTER mcasp0_fxr.gpio3_19, INPUT | PULLDIS | MODE7 */
++ >;
++ };
++
++ i2c1_pins: pinmux_i2c1_pins {
++ pinctrl-single,pins = <
++ /* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
++ BONE_P9_18 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
++ /* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
++ BONE_P9_17 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
++ >;
++ };
++
++ mcasp0_pins: pinmux_mcasp0_pins {
++ pinctrl-single,pins = <
++ 0x190 0x20 /* mcasp0_aclkx.mcasp0_aclkx, INPUT | MODE0 */
++ 0x194 0x20 /* mcasp0_fsx.mcasp0_fsx, INPUT | MODE0 */
++ 0x198 0x20 /* mcasp0_axr0.mcasp0_axr0, INPUT | MODE0 */
++ 0x19c 0x22 /* mcasp0_ahclkr.mcasp0_axr2, INPUT | MODE2 */
++ >;
++ };
++};
++
++&epwmss1 {
++ status = "okay";
++};
++
++
++&ehrpwm1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&bb_lcd_pwm_backlight_pins>;
++ status = "okay";
++};
++
++&i2c1 {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <400000>;
++
++ tlv320aic3x: tlv320aic3x@1b {
++ compatible = "ti,tlv320aic3x";
++ reg = <0x1b>;
++ status = "okay";
++ };
++};
++
++&mcasp0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&mcasp0_pins>;
++
++ status = "okay";
++
++ op-mode = <0>; /* MCASP_IIS_MODE */
++ tdm-slots = <2>;
++ num-serializer = <16>;
++ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
++ 1 0 2 0
++ 0 0 0 0
++ 0 0 0 0
++ 0 0 0 0
++ >;
++ tx-num-evt = <1>;
++ rx-num-evt = <1>;
++};
++
++&tscadc {
++ status = "okay";
++ tsc {
++ ti,wires = <4>;
++ ti,x-plate-resistance = <200>;
++ ti,coordinate-readouts = <5>;
++ ti,wire-config = <0x00 0x11 0x22 0x33>;
++ };
++
++ adc {
++ ti,adc-channels = <4 5 6 7>;
++ };
++};
++
++/ {
++ backlight {
++ status = "okay";
++ compatible = "pwm-backlight";
++ pwms = <&ehrpwm1 0 50000 0>;
++ brightness-levels = <0 51 53 56 62 75 101 152 255>;
++ default-brightness-level = <8>;
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ pinctrl-names = "default";
++ pinctrl-0 = <&keymap3_pins>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ button@1 {
++ debounce_interval = <50>;
++ linux,code = <105>;
++ label = "left";
++ gpios = <&gpio0 7 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@2 {
++ debounce_interval = <50>;
++ linux,code = <106>;
++ label = "right";
++ gpios = <&gpio1 28 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@3 {
++ debounce_interval = <50>;
++ linux,code = <103>;
++ label = "up";
++ gpios = <&gpio1 16 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@4 {
++ debounce_interval = <50>;
++ linux,code = <108>;
++ label = "down";
++ gpios = <&gpio1 19 0x1>;
++ gpio-key,wakeup;
++ autorepeat;
++ };
++ button@5 {
++ debounce_interval = <50>;
++ linux,code = <28>;
++ label = "enter";
++ gpios = <&gpio3 19 0x1>;
++ gpio-key,wakeup;
++ };
++ };
++
++ gpio-leds-cape-lcd {
++ compatible = "gpio-leds";
++ pinctrl-names = "default";
++
++ pinctrl-0 = <&user_leds_s1>;
++
++ lcd-led0 {
++ label = "lcd:green:usr0";
++ gpios = <&gpio2 4 0>;
++ linux,default-trigger = "heartbeat";
++ default-state = "off";
++ };
++
++ lcd-led1 {
++ label = "lcd:green:usr1";
++ gpios = <&gpio2 5 0>;
++ linux,default-trigger = "mmc0";
++ default-state = "off";
++ };
++ };
++
++ sound {
++ compatible = "ti,da830-evm-audio";
++ ti,model = "DA830 EVM";
++ ti,audio-codec = <&tlv320aic3x>;
++ ti,mcasp-controller = <&mcasp0>;
++ ti,codec-clock-rate = <12000000>;
++ ti,audio-routing =
++ "Headphone Jack", "HPLOUT",
++ "Headphone Jack", "HPROUT",
++ "MIC3L", "Mic Jack",
++ "MIC3R", "Mic Jack";
++ };
++};
++
++#include "am335x-peripheral-panel-1024x600-24bit.dtsi"
++#include "am335x-bone-pinmux-panel-1024x600-24bit.dtsi"
+diff --git b/arch/arm/boot/dts/am335x-cape-rtc-ds1307.dtsi b/arch/arm/boot/dts/am335x-cape-rtc-ds1307.dtsi
+new file mode 100644
+index 0000000..bce6ac5
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-cape-rtc-ds1307.dtsi
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <dt-bindings/board/am335x-bbw-bbb-base.h>
++
++&am33xx_pinmux {
++ i2c2_pins: pinmux_i2c2_pins {
++ pinctrl-single,pins = <
++ BONE_P9_20 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_ctsn.i2c2_sda */
++ BONE_P9_19 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_rtsn.i2c2_scl */
++ >;
++ };
++};
++
++&i2c2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c2_pins>;
++
++ status = "okay";
++ clock-frequency = <100000>;
++
++ rtc@68 {
++ compatible = "maxim,ds1307";
++ reg = <0x68>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-olimex-som.dts b/arch/arm/boot/dts/am335x-olimex-som.dts
+new file mode 100644
+index 0000000..2b00ad2
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-olimex-som.dts
+@@ -0,0 +1,189 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-som-common.dtsi"
++
++/ {
++ model = "Olimex AM335x SOM";
++ compatible = "olimex,am335x-olimex-som", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&am33xx_pinmux {
++ lcd_pins_default: lcd_pins_default {
++ pinctrl-single,pins = <
++ 0x20 0x01 /* gpmc_ad8.lcd_data16, OUTPUT | MODE1 */
++ 0x24 0x01 /* gpmc_ad9.lcd_data17, OUTPUT | MODE1 */
++ 0x28 0x01 /* gpmc_ad10.lcd_data18, OUTPUT | MODE1 */
++ 0x2c 0x01 /* gpmc_ad11.lcd_data19, OUTPUT | MODE1 */
++ 0x30 0x01 /* gpmc_ad12.lcd_data20, OUTPUT | MODE1 */
++ 0x34 0x01 /* gpmc_ad13.lcd_data21, OUTPUT | MODE1 */
++ 0x38 0x01 /* gpmc_ad14.lcd_data22, OUTPUT | MODE1 */
++ 0x3c 0x01 /* gpmc_ad15.lcd_data23, OUTPUT | MODE1 */
++ 0xa0 0x00 /* lcd_data0.lcd_data0, OUTPUT | MODE0 */
++ 0xa4 0x00 /* lcd_data1.lcd_data1, OUTPUT | MODE0 */
++ 0xa8 0x00 /* lcd_data2.lcd_data2, OUTPUT | MODE0 */
++ 0xac 0x00 /* lcd_data3.lcd_data3, OUTPUT | MODE0 */
++ 0xb0 0x00 /* lcd_data4.lcd_data4, OUTPUT | MODE0 */
++ 0xb4 0x00 /* lcd_data5.lcd_data5, OUTPUT | MODE0 */
++ 0xb8 0x00 /* lcd_data6.lcd_data6, OUTPUT | MODE0 */
++ 0xbc 0x00 /* lcd_data7.lcd_data7, OUTPUT | MODE0 */
++ 0xc0 0x00 /* lcd_data8.lcd_data8, OUTPUT | MODE0 */
++ 0xc4 0x00 /* lcd_data9.lcd_data9, OUTPUT | MODE0 */
++ 0xc8 0x00 /* lcd_data10.lcd_data10, OUTPUT | MODE0 */
++ 0xcc 0x00 /* lcd_data11.lcd_data11, OUTPUT | MODE0 */
++ 0xd0 0x00 /* lcd_data12.lcd_data12, OUTPUT | MODE0 */
++ 0xd4 0x00 /* lcd_data13.lcd_data13, OUTPUT | MODE0 */
++ 0xd8 0x00 /* lcd_data14.lcd_data14, OUTPUT | MODE0 */
++ 0xdc 0x00 /* lcd_data15.lcd_data15, OUTPUT | MODE0 */
++ 0xe0 0x00 /* lcd_vsync.lcd_vsync, OUTPUT | MODE0 */
++ 0xe4 0x00 /* lcd_hsync.lcd_hsync, OUTPUT | MODE0 */
++ 0xe8 0x00 /* lcd_pclk.lcd_pclk, OUTPUT | MODE0 */
++ 0xec 0x00 /* lcd_ac_bias_en.lcd_ac_bias_en, OUTPUT | MODE0 */
++ >;
++ };
++
++ lcd_pins_sleep: lcd_pins_sleep {
++ pinctrl-single,pins = <
++ 0x20 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad8.lcd_data16 */
++ 0x24 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad9.lcd_data17 */
++ 0x28 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad10.lcd_data18 */
++ 0x2c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad11.lcd_data19 */
++ 0x30 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad12.lcd_data20 */
++ 0x34 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad13.lcd_data21 */
++ 0x38 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad14.lcd_data22 */
++ 0x3c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad15.lcd_data23 */
++ 0xa0 (PULL_DISABLE | MUX_MODE7) /* lcd_data0.lcd_data0 */
++ 0xa4 (PULL_DISABLE | MUX_MODE7) /* lcd_data1.lcd_data1 */
++ 0xa8 (PULL_DISABLE | MUX_MODE7) /* lcd_data2.lcd_data2 */
++ 0xac (PULL_DISABLE | MUX_MODE7) /* lcd_data3.lcd_data3 */
++ 0xb0 (PULL_DISABLE | MUX_MODE7) /* lcd_data4.lcd_data4 */
++ 0xb4 (PULL_DISABLE | MUX_MODE7) /* lcd_data5.lcd_data5 */
++ 0xb8 (PULL_DISABLE | MUX_MODE7) /* lcd_data6.lcd_data6 */
++ 0xbc (PULL_DISABLE | MUX_MODE7) /* lcd_data7.lcd_data7 */
++ 0xc0 (PULL_DISABLE | MUX_MODE7) /* lcd_data8.lcd_data8 */
++ 0xc4 (PULL_DISABLE | MUX_MODE7) /* lcd_data9.lcd_data9 */
++ 0xc8 (PULL_DISABLE | MUX_MODE7) /* lcd_data10.lcd_data10 */
++ 0xcc (PULL_DISABLE | MUX_MODE7) /* lcd_data11.lcd_data11 */
++ 0xd0 (PULL_DISABLE | MUX_MODE7) /* lcd_data12.lcd_data12 */
++ 0xd4 (PULL_DISABLE | MUX_MODE7) /* lcd_data13.lcd_data13 */
++ 0xd8 (PULL_DISABLE | MUX_MODE7) /* lcd_data14.lcd_data14 */
++ 0xdc (PULL_DISABLE | MUX_MODE7) /* lcd_data15.lcd_data15 */
++ /* lcd_vsync.lcd_vsync,OUTPUT | MODE0 */
++ 0xe0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0xe4 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_hsync.lcd_hsync */
++ 0xe8 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_pclk.lcd_pclk */
++ /* lcd_ac_bias_en.lcd_ac_bias_en */
++ 0xec (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++};
++
++&lcdc {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&lcd_pins_default>;
++ pinctrl-1 = <&lcd_pins_sleep>;
++ status = "okay";
++ /* display-timings {
++ 480x272 {
++ hactive = <480>;
++ vactive = <272>;
++ hback-porch = <43>;
++ hfront-porch = <8>;
++ hsync-len = <4>;
++ vback-porch = <12>;
++ vfront-porch = <4>;
++ vsync-len = <10>;
++ clock-frequency = <9000000>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ };
++ };*/
++
++ display-timings {
++ native-mode = <&vga1024x768>;
++ lcd4: 480x272 {
++ clock-frequency = <9000000>;
++ hactive = <480>;
++ vactive = <272>;
++ hfront-porch = <3>;
++ hback-porch = <40>;
++ vback-porch = <8>;
++ vfront-porch = <7>;
++ hsync-len = <2>;
++ vsync-len = <1>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ };
++ lcd7: 800x480 {
++ clock-frequency = <33300000>;
++ hactive = <800>;
++ vactive = <480>;
++ hfront-porch = <210>;
++ hback-porch = <40>;
++ vback-porch = <23>;
++ vfront-porch = <20>;
++ hsync-len = <6>;
++ vsync-len = <2>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ };
++ lcd10: 1024x600 {
++ clock-frequency = <51200000>;
++ hactive = <1024>;
++ vactive = <600>;
++ hfront-porch = <160>;
++ hback-porch = <140>;
++ vback-porch = <20>;
++ vfront-porch = <12>;
++ hsync-len = <20>;
++ vsync-len = <3>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ };
++
++ vga800x600: 800x600 {
++ clock-frequency = <40000000>;
++ hactive = <800>;
++ vactive = <600>;
++ hfront-porch = <40>;
++ hback-porch = <88>;
++ vfront-porch = <1>;
++ vback-porch = <23>;
++ hsync-len = <128>;
++ vsync-len = <4>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ };
++ vga1024x768: 1024x768 {
++ clock-frequency = <65000000>;
++ hactive = <1024>;
++ hfront-porch = <24>;
++ hback-porch = <160>;
++ hsync-len = <136>;
++ vactive = <768>;
++ vfront-porch = <3>;
++ vback-porch = <29>;
++ vsync-len = <6>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-can0.dtsi b/arch/arm/boot/dts/am335x-peripheral-can0.dtsi
+new file mode 100644
+index 0000000..4335e39
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-can0.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&dcan0 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-can1.dtsi b/arch/arm/boot/dts/am335x-peripheral-can1.dtsi
+new file mode 100644
+index 0000000..02b5bd1
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-can1.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&dcan1 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-emmc.dtsi b/arch/arm/boot/dts/am335x-peripheral-emmc.dtsi
+new file mode 100644
+index 0000000..603f34e
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-emmc.dtsi
+@@ -0,0 +1,15 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++
++ bus-width = <8>;
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-i2c2.dtsi b/arch/arm/boot/dts/am335x-peripheral-i2c2.dtsi
+new file mode 100644
+index 0000000..ed9a0b5
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-i2c2.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&i2c2 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-nxp-hdmi.dtsi b/arch/arm/boot/dts/am335x-peripheral-nxp-hdmi.dtsi
+new file mode 100644
+index 0000000..1dfd26a
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-nxp-hdmi.dtsi
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&i2c0 {
++ tda19988 {
++ compatible = "nxp,tda998x";
++ reg = <0x70>;
++
++ port {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-panel-1024x600-24bit.dtsi b/arch/arm/boot/dts/am335x-peripheral-panel-1024x600-24bit.dtsi
+new file mode 100644
+index 0000000..74ddc12
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-panel-1024x600-24bit.dtsi
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&lcdc {
++ status = "okay";
++};
++
++/ {
++ panel {
++ status = "okay";
++ compatible = "ti,tilcdc,panel";
++ pinctrl-names = "default";
++
++ panel-info {
++ ac-bias = <255>;
++ ac-bias-intrpt = <0>;
++ dma-burst-sz = <16>;
++ bpp = <32>;
++ fdd = <0x80>;
++ sync-edge = <0>;
++ sync-ctrl = <0>;
++ raster-order = <1>;
++ fifo-th = <0>;
++ };
++ display-timings {
++ native-mode = <&timing0>;
++ timing0: 1024x600 {
++ clock-frequency = <36000000>;
++ hactive = <1024>;
++ vactive = <600>;
++ hfront-porch = <1>;
++ hback-porch = <45>;
++ hsync-len = <30>;
++ vback-porch = <22>;
++ vfront-porch = <12>;
++ vsync-len = <2>;
++ hsync-active = <1>;
++ vsync-active = <1>;
++ de-active = <1>;
++ pixelclk-active = <0>;
++ };
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-spi0.dtsi b/arch/arm/boot/dts/am335x-peripheral-spi0.dtsi
+new file mode 100644
+index 0000000..969e352
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-spi0.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&spi0 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-spi1.dtsi b/arch/arm/boot/dts/am335x-peripheral-spi1.dtsi
+new file mode 100644
+index 0000000..ac5fe97
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-spi1.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&spi1 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-spi1a.dtsi b/arch/arm/boot/dts/am335x-peripheral-spi1a.dtsi
+new file mode 100644
+index 0000000..ac5fe97
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-spi1a.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&spi1 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS1.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS1.dtsi
+new file mode 100644
+index 0000000..f59fa4c
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-ttyS1.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&uart1 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS2.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS2.dtsi
+new file mode 100644
+index 0000000..a25d6cf
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-ttyS2.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&uart2 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS4.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS4.dtsi
+new file mode 100644
+index 0000000..adc89f0
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-ttyS4.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&uart4 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS5.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS5.dtsi
+new file mode 100644
+index 0000000..8b42fb0
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-peripheral-ttyS5.dtsi
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++&uart5 {
++ pinctrl-names = "default";
++
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/am335x-roboticscape.dtsi b/arch/arm/boot/dts/am335x-roboticscape.dtsi
+new file mode 100644
+index 0000000..77d815a
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-roboticscape.dtsi
+@@ -0,0 +1,395 @@
++/*******************************************************************************
++* pinmux and modules used by roboticscape
++* included in:
++* am335x-boneblack-roboticscape.dts
++* am335x-boneblack-wireless-roboticscape.dts
++*******************************************************************************/
++
++
++
++/*******************************************************************************
++* Pin Muxing
++*******************************************************************************/
++&am33xx_pinmux {
++
++ /***************************************************************************
++ * Static Pinmux
++ ***************************************************************************/
++ mux_helper_pins: pins {
++ pinctrl-single,pins = <
++
++ /* GPIO Input Pullup */
++ 0x09c 0x37 /*P8.9 T6 PAUSE_BTN */
++ 0x098 0x37 /*P8.10 U6 MODE_BTN */
++ 0x1AC 0x37 /*P9.25 A14 IMU_INT */
++
++ /* LEDs GPIO Out*/
++ 0x090 0x0F /* P8.7 R7 LED_RED */
++ 0x094 0x0F /* P8.8 T7 LED_GREEN */
++ 0x028 0x0F /*P8.14 T11 BATT_LED_4 */
++ 0x02C 0x0F /*P8.17 U12 BATT_LED_1 */
++ 0x08c 0x0F /*P8.18 V12 BATT_LED_2 */
++ 0x07c 0x0F /*P8.26 V6 BATT_LED_3 */
++
++ /* Motor Control GPIO Out*/
++ 0x0cc 0x0F /*P8.34 MDIR_2B different from blue!!*/
++ 0x0a8 0x0F /*P8.43 MDIR_3B*/
++ 0x0ac 0x0F /*P8.44 MDIR_3A*/
++ 0x0a0 0x0F /*P8.45 MDIR_4A*/
++ 0x0a4 0x0F /*P8.46 MDIR_4B*/
++ 0x078 0x0F /*P9.12 MDIR_1A different from blue!!*/
++ 0x074 0x0F /*P9.13 MDIR_1B*/
++ 0x040 0x0F /*P9.15 MDIR_2A*/
++ 0x1b4 0x0F /*P9.41 MOT_STBY*/
++
++ /* HRPWM 1 */
++ 0x048 0x6 /* P9_14 | MODE 6 */
++ 0x04c 0x6 /* P9_16 | MODE 6 */
++
++ /* HRPWM 2 */
++ 0x020 0x4 /* P8_19 | MODE 4 */
++ 0x024 0x4 /* P8_13 | MODE 4 */
++
++ /* EQEP */
++ 0x1A0 0x31 /* P9_42,EQEP0A, MODE1 */
++ 0x1A4 0x31 /* P9_27,EQEP0B, MODE1 */
++ 0x0D4 0x32 /* P8_33,EQEP1B, MODE2 */
++ 0x0D0 0x32 /* P8_35,EQEP1A, MODE2 */
++ 0x030 0x34 /* P8_12,EQEP2A, MODE4 */
++ 0x034 0x34 /* P8_11,EQEP2B, MODE4 */
++
++ /* PRU encoder input */
++ 0x03c 0x36 /* P8_15,PRU0_r31_15,MODE6 */
++ 0x038 0x36 /* P8_16,PRU0_r31_16,MODE6 */
++
++ /* PRU Servo output */
++ 0x0e0 0x05 /*pru1_pru_r30_8, MODE5*/
++ 0x0e8 0x05 /*pru1_pru_r30_10, MODE5 */
++ 0x0e4 0x05 /*pr1_pru1_pru_r30_9, MODE5 */
++ 0x0ec 0x05 /*pru1_pru_r30_11, MODE5 */
++ 0x0b8 0x05 /*pru1_pru_r30_6, MODE5 */
++ 0x0bc 0x05 /*pru1_pru_r30_7, MODE5 */
++ 0x0b0 0x05 /*pru1_pru_r30_4, MODE5 */
++ 0x0b4 0x05 /*pru1_pru_r30_5, MODE5 */
++ 0x0C8 0x0F /*P8.36, SERVO_PWR GPIO OUT*/
++
++ /* I2C1 */
++ 0x15C 0x32 /* P9.17,i2c1_scl,INPUT_PULLUP,MODE2 */
++ 0x158 0x32 /* P9.18,i2c1_sda,INPUT_PULLUP,MODE2 */
++
++ /* I2C2 */
++ 0x17c 0x73 /* P9.19, i2c2_sda, mode 3 */
++ 0x178 0x73 /* P9.20, i2c2_sda, mode 3 */
++
++ /* UART5 */
++ 0x0C4 0x34 /* P8.38,uart5_rxd,MODE4 */
++ 0x0C0 0x14 /* P8.37,uart5_txd,MODE4 */
++
++ >;
++ };
++
++};
++
++
++/*******************************************************************************
++* apply static and dynamic pinmux modes listed above. Configurable pins get the
++* modes from am335x-boneblack-common-universal-pins.dtsi
++*******************************************************************************/
++&ocp {
++ /* activate the static pinmux helper list of pin modes above */
++ test_helper: helper {
++ compatible = "bone-pinmux-helper";
++ pinctrl-names = "default";
++ pinctrl-0 = <&mux_helper_pins>;
++
++ status = "okay";
++ };
++
++ /* UART4 RX DSM */
++ P9_11_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart";
++ pinctrl-0 = <&P9_11_default_pin>;
++ pinctrl-1 = <&P9_11_gpio_pin>;
++ pinctrl-2 = <&P9_11_gpio_pu_pin>;
++ pinctrl-3 = <&P9_11_gpio_pd_pin>;
++ pinctrl-4 = <&P9_11_uart_pin>;
++ };
++
++ /* UART 2 TX GPS*/
++ P9_21_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
++ pinctrl-0 = <&P9_21_default_pin>;
++ pinctrl-1 = <&P9_21_gpio_pin>;
++ pinctrl-2 = <&P9_21_gpio_pu_pin>;
++ pinctrl-3 = <&P9_21_gpio_pd_pin>;
++ pinctrl-4 = <&P9_21_spi_pin>;
++ pinctrl-5 = <&P9_21_uart_pin>;
++ pinctrl-6 = <&P9_21_i2c_pin>;
++ pinctrl-7 = <&P9_21_pwm_pin>;
++ };
++
++ /* UART 2 RX GPS */
++ P9_22_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
++ pinctrl-0 = <&P9_22_default_pin>;
++ pinctrl-1 = <&P9_22_gpio_pin>;
++ pinctrl-2 = <&P9_22_gpio_pu_pin>;
++ pinctrl-3 = <&P9_22_gpio_pd_pin>;
++ pinctrl-4 = <&P9_22_spi_pin>;
++ pinctrl-5 = <&P9_22_uart_pin>;
++ pinctrl-6 = <&P9_22_i2c_pin>;
++ pinctrl-7 = <&P9_22_pwm_pin>;
++ };
++
++ /* SPI MISO */
++ P9_29_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_29_default_pin>;
++ pinctrl-1 = <&P9_29_gpio_pin>;
++ pinctrl-2 = <&P9_29_gpio_pu_pin>;
++ pinctrl-3 = <&P9_29_gpio_pd_pin>;
++ pinctrl-4 = <&P9_29_pwm_pin>;
++ pinctrl-5 = <&P9_29_spi_pin>;
++ pinctrl-6 = <&P9_29_pruout_pin>;
++ pinctrl-7 = <&P9_29_pruin_pin>;
++ };
++
++ /* SPI MOSI */
++ P9_30_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_30_default_pin>;
++ pinctrl-1 = <&P9_30_gpio_pin>;
++ pinctrl-2 = <&P9_30_gpio_pu_pin>;
++ pinctrl-3 = <&P9_30_gpio_pd_pin>;
++ pinctrl-4 = <&P9_30_pwm_pin>;
++ pinctrl-5 = <&P9_30_spi_pin>;
++ pinctrl-6 = <&P9_30_pruout_pin>;
++ pinctrl-7 = <&P9_30_pruin_pin>;
++ };
++
++ /* SPI SCK */
++ P9_31_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
++ pinctrl-0 = <&P9_31_default_pin>;
++ pinctrl-1 = <&P9_31_gpio_pin>;
++ pinctrl-2 = <&P9_31_gpio_pu_pin>;
++ pinctrl-3 = <&P9_31_gpio_pd_pin>;
++ pinctrl-4 = <&P9_31_pwm_pin>;
++ pinctrl-5 = <&P9_31_spi_pin>;
++ pinctrl-6 = <&P9_31_pruout_pin>;
++ pinctrl-7 = <&P9_31_pruin_pin>;
++ };
++
++ /* SPI SS1 GPIO3_17*/
++ P9_28_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pwm2", "pruout", "pruin";
++ pinctrl-0 = <&P9_28_default_pin>;
++ pinctrl-1 = <&P9_28_gpio_pin>;
++ pinctrl-2 = <&P9_28_gpio_pu_pin>;
++ pinctrl-3 = <&P9_28_gpio_pd_pin>;
++ pinctrl-4 = <&P9_28_pwm_pin>;
++ pinctrl-5 = <&P9_28_spi_pin>;
++ pinctrl-6 = <&P9_28_pwm2_pin>;
++ pinctrl-7 = <&P9_28_pruout_pin>;
++ pinctrl-8 = <&P9_28_pruin_pin>;
++ };
++
++ /* SPI SS1 GPIO1_17*/
++ P9_23_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
++ pinctrl-0 = <&P9_23_default_pin>;
++ pinctrl-1 = <&P9_23_gpio_pin>;
++ pinctrl-2 = <&P9_23_gpio_pu_pin>;
++ pinctrl-3 = <&P9_23_gpio_pd_pin>;
++ pinctrl-4 = <&P9_23_pwm_pin>;
++ };
++
++ /* UART 1 TX */
++ P9_24_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
++ pinctrl-0 = <&P9_24_default_pin>;
++ pinctrl-1 = <&P9_24_gpio_pin>;
++ pinctrl-2 = <&P9_24_gpio_pu_pin>;
++ pinctrl-3 = <&P9_24_gpio_pd_pin>;
++ pinctrl-4 = <&P9_24_uart_pin>;
++ pinctrl-5 = <&P9_24_can_pin>;
++ pinctrl-6 = <&P9_24_i2c_pin>;
++ pinctrl-7 = <&P9_24_pruin_pin>;
++ };
++
++ /* UART 1 RX */
++ P9_26_pinmux {
++ compatible = "bone-pinmux-helper";
++ status = "okay";
++ pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
++ pinctrl-0 = <&P9_26_default_pin>;
++ pinctrl-1 = <&P9_26_gpio_pin>;
++ pinctrl-2 = <&P9_26_gpio_pu_pin>;
++ pinctrl-3 = <&P9_26_gpio_pd_pin>;
++ pinctrl-4 = <&P9_26_uart_pin>;
++ pinctrl-5 = <&P9_26_can_pin>;
++ pinctrl-6 = <&P9_26_i2c_pin>;
++ pinctrl-7 = <&P9_26_pruin_pin>;
++ };
++
++
++};
++
++
++/*******************************************************************************
++* PWMSS
++*******************************************************************************/
++&epwmss0 {
++ status = "okay";
++};
++
++&epwmss1 {
++ status = "okay";
++};
++
++&epwmss2 {
++ status = "okay";
++};
++
++&ehrpwm0 {
++ status = "okay";
++};
++
++&ehrpwm1 {
++ status = "okay";
++};
++
++&ehrpwm2 {
++ status = "okay";
++};
++
++/*******************************************************************************
++* EQEP
++*******************************************************************************/
++&eqep0 {
++ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
++ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
++ invert_qa = <1>; /* Should we invert the channel A input? */
++ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
++ invert_qi = <0>; /* Should we invert the index input? */
++ invert_qs = <0>; /* Should we invert the strobe input? */
++
++ status = "okay";
++};
++
++&eqep1 {
++ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
++ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
++ invert_qa = <1>; /* Should we invert the channel A input? */
++ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
++ invert_qi = <0>; /* Should we invert the index input? */
++ invert_qs = <0>; /* Should we invert the strobe input? */
++
++ status = "okay";
++};
++
++&eqep2 {
++ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
++ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
++ invert_qa = <1>; /* Should we invert the channel A input? */
++ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
++ invert_qi = <0>; /* Should we invert the index input? */
++ invert_qs = <0>; /* Should we invert the strobe input? */
++
++ status = "okay";
++};
++
++
++/*******************************************************************************
++* UART
++*******************************************************************************/
++&uart1 {
++ status = "okay";
++};
++
++&uart2 {
++ status = "okay";
++};
++
++&uart4 {
++ status = "okay";
++};
++
++&uart5 {
++ status = "okay";
++};
++
++
++/*******************************************************************************
++* PRU Encoder and Servos
++*******************************************************************************/
++&pruss {
++ status = "okay";
++};
++
++
++/*******************************************************************************
++* I2C
++*******************************************************************************/
++&i2c1 {
++ status = "okay";
++ clock-frequency = <400000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++};
++
++&i2c2 {
++ status = "okay";
++ clock-frequency = <400000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++};
++
++
++/*******************************************************************************
++* SPI
++*******************************************************************************/
++&spi1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ channel@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ compatible = "spidev";
++
++ reg = <0>;
++ spi-max-frequency = <16000000>;
++ spi-cpha;
++ };
++
++ channel@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ compatible = "spidev";
++
++ reg = <1>;
++ spi-max-frequency = <16000000>;
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-sancloud-bbe.dts b/arch/arm/boot/dts/am335x-sancloud-bbe.dts
+new file mode 100644
+index 0000000..a36b04b
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-sancloud-bbe.dts
+@@ -0,0 +1,264 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "am33xx.dtsi"
++#include "am335x-bone-common.dtsi"
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/display/tda998x.h>
++/* #include "am335x-bone-jtag.dtsi" */
++
++/ {
++ model = "SanCloud BeagleBone Enhanced";
++ compatible = "sancloud,am335x-boneenhanced", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
++};
++
++&ldo3_reg {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++};
++
++&mmc1 {
++ vmmc-supply = <&vmmcsd_fixed>;
++};
++
++&mmc2 {
++ vmmc-supply = <&vmmcsd_fixed>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_pins>;
++ bus-width = <8>;
++ status = "okay";
++ ti,vcc-aux-disable-is-sleep;
++};
++
++&am33xx_pinmux {
++ pinctrl-names = "default";
++ pinctrl-0 = <&usb_hub_ctrl>;
++
++ nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0.lcd_data0 */
++ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1.lcd_data1 */
++ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2.lcd_data2 */
++ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3.lcd_data3 */
++ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4.lcd_data4 */
++ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5.lcd_data5 */
++ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6.lcd_data6 */
++ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7.lcd_data7 */
++ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8.lcd_data8 */
++ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9.lcd_data9 */
++ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10.lcd_data10 */
++ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11.lcd_data11 */
++ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12.lcd_data12 */
++ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13.lcd_data13 */
++ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14.lcd_data14 */
++ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15.lcd_data15 */
++ AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_vsync.lcd_vsync */
++ AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_hsync.lcd_hsync */
++ AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_pclk.lcd_pclk */
++ AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* lcd_ac_bias_en.lcd_ac_bias_en */
++ >;
++ };
++ nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr0 */
++ >;
++ };
++
++ cpsw_default: cpsw_default {
++ pinctrl-single,pins = <
++ /* Slave 1 */
++ 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txen.rgmii1_tctl */
++ 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxdv.rgmii1_rctl */
++ 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd3.rgmii1_td3 */
++ 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd2.rgmii1_td2 */
++ 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd1.rgmii1_td1 */
++ 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txd0.rgmii1_td0 */
++ 0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_txclk.rgmii1_tclk */
++ 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxclk.rgmii1_rclk */
++ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd3.rgmii1_rd3 */
++ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd2.rgmii1_rd2 */
++ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd1.rgmii1_rd1 */
++ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2) /* mii1_rxd0.rgmii1_rd0 */
++ >;
++ };
++
++ cpsw_sleep: cpsw_sleep {
++ pinctrl-single,pins = <
++ /* Slave 1 reset value */
++ 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ davinci_mdio_default: davinci_mdio_default {
++ pinctrl-single,pins = <
++ /* MDIO */
++ 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
++ 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
++ >;
++ };
++
++ davinci_mdio_sleep: davinci_mdio_sleep {
++ pinctrl-single,pins = <
++ /* MDIO reset value */
++ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ usb_hub_ctrl: usb_hub_ctrl {
++ pinctrl-single,pins = <
++ 0x144 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* mcasp0_ahclkr.gpio3_17 */
++ >;
++ };
++
++ mpu6050_pins: pinmux_mpu6050_pins {
++ pinctrl-single,pins = <
++ 0x168 (PIN_INPUT | MUX_MODE7) /* spi0_sclk.gpio0_2 */
++ >;
++ };
++
++ lps3331ap_pins: pinmux_lps3331ap_pins {
++ pinctrl-single,pins = <
++ 0x6C (PIN_INPUT | MUX_MODE7) /* conf_gpmc_a11.gpio1_27 */
++ >;
++ };
++
++ mcasp0_pins: mcasp0_pins {
++ pinctrl-single,pins = <
++ AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
++ AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
++ AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
++ AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
++ AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
++ >;
++ };
++};
++
++&lcdc {
++ status = "okay";
++ port {
++ lcdc_0: endpoint@0 {
++ remote-endpoint = <&hdmi_0>;
++ };
++ };
++};
++
++&mac {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&cpsw_default>;
++ pinctrl-1 = <&cpsw_sleep>;
++};
++
++&davinci_mdio {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&davinci_mdio_default>;
++ pinctrl-1 = <&davinci_mdio_sleep>;
++};
++
++&cpsw_emac0 {
++ phy_id = <&davinci_mdio>, <0>;
++ phy-mode = "rgmii-txid";
++};
++
++&i2c0 {
++ tda19988: tda19988 {
++ compatible = "nxp,tda998x";
++ reg = <0x70>;
++
++ pinctrl-names = "default", "off";
++ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
++ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
++
++ #sound-dai-cells = <0>;
++ audio-ports = < TDA998x_I2S 0x03>;
++
++ ports {
++ port@0 {
++ hdmi_0: endpoint@0 {
++ remote-endpoint = <&lcdc_0>;
++ };
++ };
++ };
++ };
++
++ lps331ap: lps331ap@5C {
++ compatible = "st,lps331ap";
++ st,drdy-int-pin = <1>;
++ reg = <0x5C>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <27 IRQ_TYPE_EDGE_RISING>;
++ };
++
++ mpu6050: mpu6050@68 {
++ compatible = "invensense,mpu6050";
++ reg = <0x68>;
++ interrupt-parent = <&gpio0>;
++ interrupts = <2 IRQ_TYPE_EDGE_RISING>;
++ //orientation = <0xff 0 0 0 1 0 0 0 0xff>;
++ };
++};
++
++&mcasp0 {
++ #sound-dai-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&mcasp0_pins>;
++ status = "okay";
++ op-mode = <0>; /* MCASP_IIS_MODE */
++ tdm-slots = <2>;
++ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
++ 0 0 1 0
++ >;
++ tx-num-evt = <32>;
++ rx-num-evt = <32>;
++};
++
++/ {
++ clk_mcasp0_fixed: clk_mcasp0_fixed {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <24576000>;
++ };
++
++ clk_mcasp0: clk_mcasp0 {
++ #clock-cells = <0>;
++ compatible = "gpio-gate-clock";
++ clocks = <&clk_mcasp0_fixed>;
++ enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
++ };
++
++ sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "TI BeagleBone Black";
++ simple-audio-card,format = "i2s";
++ simple-audio-card,bitclock-master = <&dailink0_master>;
++ simple-audio-card,frame-master = <&dailink0_master>;
++
++ dailink0_master: simple-audio-card,cpu {
++ sound-dai = <&mcasp0>;
++ clocks = <&clk_mcasp0>;
++ };
++
++ simple-audio-card,codec {
++ sound-dai = <&tda19988>;
++ };
++ };
++};
+diff --git b/arch/arm/boot/dts/am335x-som-common.dtsi b/arch/arm/boot/dts/am335x-som-common.dtsi
+new file mode 100644
+index 0000000..fb4399b
+--- /dev/null
++++ b/arch/arm/boot/dts/am335x-som-common.dtsi
+@@ -0,0 +1,465 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/ {
++
++ cpus {
++ cpu@0 {
++ cpu0-supply = <&dcdc2_fixed>;
++ };
++ };
++
++ memory {
++ device_type = "memory";
++ reg = <0x80000000 0x20000000>; /* 512 MB */
++ };
++
++ ocp {
++ uart0: serial@44e09000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins>;
++
++ status = "okay";
++ };
++ uart1: serial@48022000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_pins>;
++ status = "okay";
++
++ };
++ uart4: serial@481a8000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart4_pins>;
++ status = "okay";
++ };
++
++ epwmss0: epwmss@48300000 {
++ status = "okay";
++
++ ecap0: ecap@48300100 {
++ status = "okay";
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&ecap0_pins_default>;
++ pinctrl-1 = <&ecap0_pins_sleep>;
++ };
++ };
++
++ musb: usb@47400000 {
++ status = "okay";
++
++ control@44e10000 {
++ status = "okay";
++ };
++
++ usb-phy@47401300 {
++ status = "okay";
++ };
++
++ usb-phy@47401b00 {
++ status = "okay";
++ };
++
++ usb@47401000 {
++ status = "okay";
++ dr_mode = "otg";
++ };
++
++ usb@47401800 {
++ status = "okay";
++ dr_mode = "host";
++ };
++
++ dma-controller@07402000 {
++ status = "okay";
++ };
++ };
++
++ i2c0: i2c@44e0b000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ status = "okay";
++ clock-frequency = <100000>;
++
++ tps: tps@24 {
++ reg = <0x24>;
++ };
++ };
++ };
++
++ vmmcsd_fixed: fixedregulator@0 {
++ compatible = "regulator-fixed";
++ regulator-name = "vmmcsd_fixed";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ dcdc2_fixed: fixedregulator@1 {
++ /* VDD_MPU voltage limits 0.95V - 1.325V with +/-4% tolerance */
++ compatible = "regulator-fixed";
++ regulator-name = "dcdc2_fixed";
++
++ regulator-min-microvolt = <1378000>;
++ regulator-max-microvolt = <1378000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ leds {
++ pinctrl-names = "default";
++ pinctrl-0 = <&user_leds_s0>;
++
++ compatible = "gpio-leds";
++
++ led@1 {
++ label = "led1:green:heartbeat";
++ gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "heartbeat";
++ };
++
++ led@2 {
++ label = "led2:red:heartbeat";
++ gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "heartbeat";
++ };
++
++ led@3 {
++ label = "led3:yello:heartbeat";
++ gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "heartbeat";
++ };
++
++ led@4 {
++ label = "bkl";
++ gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-on";
++ };
++ };
++
++ backlight {
++ compatible = "pwm-backlight";
++ pwms = <&ecap0 0 500000 1>;
++ brightness-levels = <
++ 0 1 2 3 4 5 6 7 8 9
++ 10 11 12 13 14 15 16 17 18 19
++ 20 21 22 23 24 25 26 27 28 29
++ 30 31 32 33 34 35 36 37 38 39
++ 40 41 42 43 44 45 46 47 48 49
++ 50 51 52 53 54 55 56 57 58 59
++ 60 61 62 63 64 65 66 67 68 69
++ 70 71 72 73 74 75 76 77 78 79
++ 80 81 82 83 84 85 86 87 88 89
++ 90 91 92 93 94 95 96 97 98 99
++ 100
++ >;
++ default-brightness-level = <50>;
++ };
++};
++
++&am33xx_pinmux {
++ pinctrl-names = "default";
++ pinctrl-0 = <&clkout2_pin>;
++
++ user_leds_s0: user_leds_s0 {
++ pinctrl-single,pins = <
++ 0x1b0 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* xdma_event_intr0.gpio0_19 */
++ 0x198 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mcasp0_axr0.gpio3_20 */
++ 0x1a8 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mcasp0_axr1.gpio3_21 */
++ 0x1a4 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mcasp0_fsr.gpio3[19], INPUT_PULLDOWN | MODE7 */
++ >;
++ };
++
++ i2c0_pins: pinmux_i2c0_pins {
++ pinctrl-single,pins = <
++ 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
++ 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
++ >;
++ };
++
++ uart0_pins: pinmux_uart0_pins {
++ pinctrl-single,pins = <
++ 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
++ 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
++ >;
++ };
++
++ uart1_pins: pinmux_uart1_pins {
++ pinctrl-single,pins = <
++ 0x168 (PIN_INPUT_PULLUP | MUX_MODE1)
++ 0x16c (PIN_OUTPUT_PULLDOWN | MUX_MODE1)
++ >;
++ };
++
++ uart4_pins: pinmux_uart4_pins {
++ pinctrl-single,pins = <
++ 0x180 (PIN_INPUT_PULLUP | MUX_MODE0)
++ 0x184 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)
++ >;
++ };
++
++
++
++ clkout2_pin: pinmux_clkout2_pin {
++ pinctrl-single,pins = <
++ 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* xdma_event_intr1.clkout2 */
++ >;
++ };
++
++ cpsw_default: cpsw_default {
++ pinctrl-single,pins = <
++ /* Slave 1 */
++ 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
++ 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
++ 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
++ 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
++ 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
++ 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
++ 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
++ 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_txclk.mii1_txclk */
++ 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxclk.mii1_rxclk */
++ 0x134 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd3.mii1_rxd3 */
++ 0x138 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd2.mii1_rxd2 */
++ 0x13c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd1.mii1_rxd1 */
++ 0x140 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd0.mii1_rxd0 */
++
++ 0x040 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a0.gmii2_txen, OUTPUT_PULLDOWN | MODE1 */
++ 0x044 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a1.gmii2_rxdv, INPUT_PULLDOWN | MODE1 */
++ 0x048 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a2.gmii2_txd3, OUTPUT_PULLDOWN | MODE1 */
++ 0x04c (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a3.gmii2_txd2, OUTPUT_PULLDOWN | MODE1 */
++ 0x050 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a4.gmii2_txd1, OUTPUT_PULLDOWN | MODE1 */
++ 0x054 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a5.gmii2_txd0, OUTPUT_PULLDOWN | MODE1 */
++ 0x058 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a6.gmii2_txclk, INPUT_PULLDOWN | MODE1 */
++ 0x05c (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a7.gmii2_rxclk, INPUT_PULLDOWN | MODE1 */
++ 0x060 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a8.gmii2_rxd3, INPUT_PULLDOWN | MODE1 */
++ 0x064 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a9.gmii2_rxd2, INPUT_PULLDOWN | MODE1 */
++ 0x068 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a10.gmii2_rxd1, INPUT_PULLDOWN | MODE1 */
++ 0x06c (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a11.gmii2_rxd0, INPUT_PULLDOWN | MODE1 */
++ 0x070 (PIN_INPUT_PULLUP | MUX_MODE1 ) /* gpmc_wait0.gmii2_crs, INPUT_PULLUP | MODE1 */
++ 0x074 (PIN_INPUT_PULLUP | MUX_MODE1 ) /* gpmc_wpn.gmii2_rxer, INPUT_PULLUP | MODE1 */
++ 0x078 (PIN_INPUT_PULLUP | MUX_MODE1 ) /* gpmc_ben1.gmii2_col, INPUT_PULLUP | MODE1 */
++ >;
++ };
++
++ cpsw_sleep: cpsw_sleep {
++ pinctrl-single,pins = <
++ /* Slave 1 reset value */
++ 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++
++ 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x58 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x5c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x60 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x070 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x074 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x078 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ davinci_mdio_default: davinci_mdio_default {
++ pinctrl-single,pins = <
++ /* MDIO */
++ 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
++ 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
++ >;
++ };
++
++ davinci_mdio_sleep: davinci_mdio_sleep {
++ pinctrl-single,pins = <
++ /* MDIO reset value */
++ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ mmc1_pins_default: pinmux_mmc1_pins {
++ pinctrl-single,pins = <
++ 0x0F0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
++ 0x0F4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
++ 0x0F8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
++ 0x0FC (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
++ 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
++ 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
++ 0x1A0 (PIN_INPUT_PULLUP | MUX_MODE7) /* mcasp0_aclkr.gpio3_18 */
++ 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
++ >;
++ };
++
++ mmc1_pins_sleep: pinmux_mmc1_pins_sleep {
++ pinctrl-single,pins = <
++ 0x0F0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x0F4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x0F8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x0FC (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x100 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x104 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x1A0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ 0x160 (PIN_INPUT_PULLDOWN | MUX_MODE7)
++ >;
++ };
++
++ emmc_pins: pinmux_emmc_pins {
++ pinctrl-single,pins = <
++ 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
++ 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
++ 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
++ 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
++ 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
++ 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
++ 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
++ 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
++ 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
++ 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
++ >;
++ };
++
++ ecap0_pins_default: backlight_pins {
++ pinctrl-single,pins = <
++ 0x164 0x0 /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
++ >;
++ };
++
++ ecap0_pins_sleep: ecap0_pins_sleep {
++ pinctrl-single,pins = <
++ 0x164 (PULL_DISABLE | MUX_MODE7) /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out */
++ >;
++ };
++ dcan0_default: dcan0_default_pins {
++ pinctrl-single,pins = <
++ 0x178 0x0a /* uart1_ctsn.dcan0_tx_mux2, OUTPUT | MODE2 */
++ 0x17c 0x2a /* uart1_rtsn.dcan0_rx_mux2, INPUT | MODE2 */
++ >;
++ };
++ };
++
++&tps {
++ compatible = "ti,tps65217";
++ regulators {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ dcdc1_reg: regulator@0 {
++ reg = <0>;
++ regulator-always-on;
++ };
++
++ dcdc2_reg: regulator@1 {
++ reg = <1>;
++ /* VDD_MPU voltage limits 0.95V - 1.325V with +/-4% tolerance */
++ regulator-name = "vdd_mpu";
++ regulator-min-microvolt = <925000>;
++ regulator-max-microvolt = <1378000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ dcdc3_reg: regulator@2 {
++ reg = <2>;
++ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
++ regulator-name = "vdd_core";
++ regulator-min-microvolt = <925000>;
++ regulator-max-microvolt = <1150000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo1_reg: regulator@3 {
++ reg = <3>;
++ regulator-always-on;
++ };
++
++ ldo2_reg: regulator@4 {
++ reg = <4>;
++ regulator-always-on;
++ };
++
++ ldo3_reg: regulator@5 {
++ reg = <5>;
++ regulator-always-on;
++ };
++
++ ldo4_reg: regulator@6 {
++ reg = <6>;
++ regulator-always-on;
++ };
++ };
++};
++
++&cpsw_emac0 {
++ phy_id = <&davinci_mdio>, <0>;
++ phy-mode = "mii";
++};
++
++&cpsw_emac1 {
++ phy_id = <&davinci_mdio>, <1>;
++ phy-mode = "mii";
++};
++
++&mac {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&cpsw_default>;
++ pinctrl-1 = <&cpsw_sleep>;
++ slaves = <2>;
++ dual_emac = <1>;
++ status = "okay";
++};
++
++&davinci_mdio {
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&davinci_mdio_default>;
++ pinctrl-1 = <&davinci_mdio_sleep>;
++ status = "okay";
++};
++
++&mmc1 {
++ status = "okay";
++ bus-width = <0x4>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&mmc1_pins_default>;
++ pinctrl-1 = <&mmc1_pins_sleep>;
++ cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
++ cd-inverted;
++};
++
++&dcan0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&dcan0_default>;
++ status = "okay";
++};
++
++&tscadc {
++ status = "okay";
++ tsc {
++ ti,wires = <4>;
++ ti,x-plate-resistance = <200>;
++ ti,coordinate-readouts = <5>;
++ ti,wire-config = <0x00 0x11 0x22 0x33>;
++ };
++
++ adc {
++ ti,adc-channels = <0 1 2 3>;
++ };
++};
+diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
+index f3d51f4..e051b96 100644
+--- a/arch/arm/boot/dts/am33xx.dtsi
++++ b/arch/arm/boot/dts/am33xx.dtsi
+@@ -36,6 +36,9 @@
+ phy1 = &usb1_phy;
+ ethernet0 = &cpsw_emac0;
+ ethernet1 = &cpsw_emac1;
++ mmc0 = &mmc1;
++ mmc1 = &mmc2;
++ mmc2 = &mmc3;
+ };
+
+ cpus {
+@@ -46,19 +49,7 @@
+ device_type = "cpu";
+ reg = <0>;
+
+- /*
+- * To consider voltage drop between PMIC and SoC,
+- * tolerance value is reduced to 2% from 4% and
+- * voltage value is increased as a precaution.
+- */
+- operating-points = <
+- /* kHz uV */
+- 720000 1285000
+- 600000 1225000
+- 500000 1125000
+- 275000 1125000
+- >;
+- voltage-tolerance = <2>; /* 2 percentage */
++ operating-points-v2 = <&cpu0_opp_table>;
+
+ clocks = <&dpll_mpu_ck>;
+ clock-names = "cpu";
+@@ -67,6 +58,80 @@
+ };
+ };
+
++ cpu0_opp_table: opp_table0 {
++ compatible = "operating-points-v2-ti-cpu";
++ ti,syscon-efuse = <&scm_conf 0x7fc 0x1fff 0>;
++ ti,syscon-rev = <&scm_conf 0x600>;
++
++ /*
++ * The three following nodes are marked with opp-suspend
++ * because the can not be enabled simultaneously on a
++ * single SoC.
++ */
++ opp50@300000000 {
++ opp-hz = /bits/ 64 <300000000>;
++ opp-microvolt = <950000 931000 969000>;
++ opp-supported-hw = <0x06 0x0010>;
++ opp-suspend;
++ };
++
++ opp100@275000000 {
++ opp-hz = /bits/ 64 <275000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x01 0x00FF>;
++ opp-suspend;
++ };
++
++ opp100@300000000 {
++ opp-hz = /bits/ 64 <300000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x06 0x0020>;
++ opp-suspend;
++ };
++
++ opp100@500000000 {
++ opp-hz = /bits/ 64 <500000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x01 0xFFFF>;
++ };
++
++ opp100@600000000 {
++ opp-hz = /bits/ 64 <600000000>;
++ opp-microvolt = <1100000 1078000 1122000>;
++ opp-supported-hw = <0x06 0x0040>;
++ };
++
++ opp120@600000000 {
++ opp-hz = /bits/ 64 <600000000>;
++ opp-microvolt = <1200000 1176000 1224000>;
++ opp-supported-hw = <0x01 0xFFFF>;
++ };
++
++ opp120@720000000 {
++ opp-hz = /bits/ 64 <720000000>;
++ opp-microvolt = <1200000 1176000 1224000>;
++ opp-supported-hw = <0x06 0x0080>;
++ };
++
++ oppturbo@720000000 {
++ opp-hz = /bits/ 64 <720000000>;
++ opp-microvolt = <1260000 1234800 1285200>;
++ opp-supported-hw = <0x01 0xFFFF>;
++ };
++
++ oppturbo@800000000 {
++ opp-hz = /bits/ 64 <800000000>;
++ opp-microvolt = <1260000 1234800 1285200>;
++ opp-supported-hw = <0x06 0x0100>;
++ };
++
++ oppnitro@1000000000 {
++ opp-hz = /bits/ 64 <1000000000>;
++ opp-microvolt = <1325000 1298500 1351500>;
++ opp-supported-hw = <0x04 0x0200>;
++ };
++ };
++
+ pmu {
+ compatible = "arm,cortex-a8-pmu";
+ interrupts = <3>;
+@@ -91,7 +156,7 @@
+ * for the moment, just use a fake OCP bus entry to represent
+ * the whole bus hierarchy.
+ */
+- ocp {
++ ocp: ocp {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+@@ -500,12 +565,25 @@
+ ti,timer-pwm;
+ };
+
++ pruss: pruss@4a300000 {
++ compatible = "ti,pruss-v2";
++ ti,hwmods = "pruss";
++ ti,deassert-hard-reset = "pruss", "pruss";
++ reg = <0x4a300000 0x080000>;
++ ti,pintc-offset = <0x20000>;
++ interrupt-parent = <&intc>;
++ status = "disabled";
++ interrupts = <20 21 22 23 24 25 26 27>;
++ };
++
+ rtc: rtc@44e3e000 {
+ compatible = "ti,am3352-rtc", "ti,da830-rtc";
+ reg = <0x44e3e000 0x1000>;
+ interrupts = <75
+ 76>;
+ ti,hwmods = "rtc";
++ ti,no-reset-on-init;
++ ti,no-idle-on-init;
+ };
+
+ spi0: spi@48030000 {
+@@ -691,6 +769,16 @@
+ status = "disabled";
+ };
+
++ eqep0: eqep@0x48300180 {
++ compatible = "ti,am33xx-eqep";
++ reg = <0x48300180 0x80>;
++ clocks = <&l4ls_gclk>;
++ clock-names = "fck";
++ interrupt-parent = <&intc>;
++ interrupts = <79>;
++ status = "disabled";
++ };
++
+ ehrpwm0: pwm@48300200 {
+ compatible = "ti,am3352-ehrpwm",
+ "ti,am33xx-ehrpwm";
+@@ -725,6 +813,17 @@
+ status = "disabled";
+ };
+
++
++ eqep1: eqep@0x48302180 {
++ compatible = "ti,am33xx-eqep";
++ reg = <0x48302180 0x80>;
++ clocks = <&l4ls_gclk>;
++ clock-names = "fck";
++ interrupt-parent = <&intc>;
++ interrupts = <88>;
++ status = "disabled";
++ };
++
+ ehrpwm1: pwm@48302200 {
+ compatible = "ti,am3352-ehrpwm",
+ "ti,am33xx-ehrpwm";
+@@ -759,6 +858,16 @@
+ status = "disabled";
+ };
+
++ eqep2: eqep@0x48304180 {
++ compatible = "ti,am33xx-eqep";
++ reg = <0x48304180 0x80>;
++ clocks = <&l4ls_gclk>;
++ clock-names = "fck";
++ interrupt-parent = <&intc>;
++ interrupts = <89>;
++ status = "disabled";
++ };
++
+ ehrpwm2: pwm@48304200 {
+ compatible = "ti,am3352-ehrpwm",
+ "ti,am33xx-ehrpwm";
+diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
+index 9435b6c..e2d77fd 100644
+--- a/arch/arm/boot/dts/am4372.dtsi
++++ b/arch/arm/boot/dts/am4372.dtsi
+@@ -50,15 +50,15 @@
+ clock-names = "cpu";
+
+ operating-points-v2 = <&cpu0_opp_table>;
+- ti,syscon-efuse = <&scm_conf 0x610 0x3f 0>;
+- ti,syscon-rev = <&scm_conf 0x600>;
+
+ clock-latency = <300000>; /* From omap-cpufreq driver */
+ };
+ };
+
+ cpu0_opp_table: opp_table0 {
+- compatible = "operating-points-v2";
++ compatible = "operating-points-v2-ti-cpu";
++ ti,syscon-efuse = <&scm_conf 0x610 0x3f 0>;
++ ti,syscon-rev = <&scm_conf 0x600>;
+
+ opp50@300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
+index 6df7829..a2e4c29 100644
+--- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
++++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
+@@ -190,6 +190,11 @@
+ >;
+ };
+ };
++
++&bb2d {
++ status = "okay";
++};
++
+ &i2c1 {
+ status = "okay";
+ clock-frequency = <400000>;
+diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
+index 064d84f..6e63e28 100644
+--- a/arch/arm/boot/dts/dra7.dtsi
++++ b/arch/arm/boot/dts/dra7.dtsi
+@@ -81,11 +81,7 @@
+ compatible = "arm,cortex-a15";
+ reg = <0>;
+
+- operating-points = <
+- /* kHz uV */
+- 1000000 1060000
+- 1176000 1160000
+- >;
++ operating-points-v2 = <&cpu0_opp_table>;
+
+ clocks = <&dpll_mpu_ck>;
+ clock-names = "cpu";
+@@ -99,6 +95,25 @@
+ };
+ };
+
++ cpu0_opp_table: opp_table0 {
++ compatible = "operating-points-v2-ti-cpu";
++ ti,syscon-efuse = <&scm_wkup 0x20c 0xf80000 19>;
++ ti,syscon-rev = <&scm_wkup 0x204>;
++
++ opp_nom@1000000000 {
++ opp-hz = /bits/ 64 <1000000000>;
++ opp-microvolt = <1060000 850000 1150000>;
++ opp-supported-hw = <0xFF 0x01>;
++ opp-suspend;
++ };
++
++ opp_od@1176000000 {
++ opp-hz = /bits/ 64 <1176000000>;
++ opp-microvolt = <1160000 885000 1160000>;
++ opp-supported-hw = <0xFF 0x02>;
++ };
++ };
++
+ /*
+ * The soc node represents the soc top level view. It is used for IPs
+ * that are not memory mapped in the MPU view or for the MPU itself.
+@@ -401,6 +416,13 @@
+ reg = <0x40d00000 0x100>;
+ };
+
++ dra7_iodelay_core: padconf@4844a000 {
++ compatible = "ti,dra7-iodelay";
++ reg = <0x4844a000 0x0d1c>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ sdma: dma-controller@4a056000 {
+ compatible = "ti,omap4430-sdma";
+ reg = <0x4a056000 0x1000>;
+@@ -959,6 +981,16 @@
+ ti,hwmods = "dmm";
+ };
+
++ bb2d: bb2d@59000000 {
++ compatible = "ti,dra7-bb2d","vivante,gc";
++ reg = <0x59000000 0x0700>;
++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
++ ti,hwmods = "bb2d";
++ clocks = <&dpll_core_h24x2_ck>;
++ clock-names = "fclk";
++ status = "disabled";
++ };
++
+ i2c1: i2c@48070000 {
+ compatible = "ti,omap4-i2c";
+ reg = <0x48070000 0x100>;
+@@ -1970,6 +2002,12 @@
+ };
+ };
+
++ gpu-subsystem {
++ compatible = "vivante,gc-gpu-subsystem";
++ cores = <&bb2d>;
++ status = "okay";
++ };
++
+ thermal_zones: thermal-zones {
+ #include "omap4-cpu-thermal.dtsi"
+ #include "omap5-gpu-thermal.dtsi"
+diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi
+index 0a78347..24e6746 100644
+--- a/arch/arm/boot/dts/dra74x.dtsi
++++ b/arch/arm/boot/dts/dra74x.dtsi
+@@ -17,6 +17,7 @@
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <1>;
++ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+
+@@ -79,6 +80,10 @@
+ };
+ };
+
++&cpu0_opp_table {
++ opp-shared;
++};
++
+ &dss {
+ reg = <0x58000000 0x80>,
+ <0x58004054 0x4>,
+diff --git b/arch/arm/boot/dts/exynos5422-artik10-eval.dts b/arch/arm/boot/dts/exynos5422-artik10-eval.dts
+new file mode 100644
+index 0000000..1001255
+--- /dev/null
++++ b/arch/arm/boot/dts/exynos5422-artik10-eval.dts
+@@ -0,0 +1,278 @@
++/*
++ * SAMSUNG ARTIK10 board device tree source
++ *
++ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
++ * http://www.samsung.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++*/
++
++/dts-v1/;
++
++#include <dt-bindings/clock/samsung,s2mps11.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/sound/samsung-i2s.h>
++#include "exynos5800.dtsi"
++#include "exynos5422-cpus.dtsi"
++#include "exynos-mfc-reserved-memory.dtsi"
++
++/ {
++ model = "Samsung ARTIK10 board based on EXYNOS5422";
++ compatible = "samsung,artik10", "samsung,exynos5422", "samsung,exynos5";
++
++ memory@40000000 {
++ device_type = "memory";
++ reg = <0x40000000 0x7EA00000>;
++ };
++
++ chosen {
++ stdout-path = "serial2:115200n8";
++ };
++
++ firmware@02073000 {
++ compatible = "samsung,secure-firmware";
++ reg = <0x02073000 0x1000>;
++ };
++
++ fixed-rate-clocks {
++ oscclk {
++ compatible = "samsung,exynos5420-oscclk";
++ clock-frequency = <24000000>;
++ };
++ };
++
++ rtc {
++ status = "okay";
++ };
++};
++
++&cpu0 {
++ cpu-supply = <&buck6_reg>;
++};
++
++&cpu4 {
++ cpu-supply = <&buck2_reg>;
++};
++
++&pinctrl_0 {
++ s2mps11_irq: s2mps11-irq {
++ samsung,pins = "gpx3-2";
++ samsung,pin-pud = <3>;
++ samsung,pin-drv = <3>;
++ };
++};
++
++&hsi2c_4 {
++ clock-frequency = <400000>;
++ status = "okay";
++
++ s2mps11_pmic@66 {
++ compatible = "samsung,s2mps11-pmic";
++ interrupt-parent = <&gpx3>;
++ interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
++ reg = <0x66>;
++
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&s2mps11_irq>;
++
++ s2mps11_osc: clocks {
++ #clock-cells = <1>;
++ clock-output-names = "s2mps11_ap",
++ "s2mps11_cp", "s2mps11_bt";
++ };
++
++ regulators {
++ ldo4_reg: LDO4 {
++ regulator-name = "vdd_adc";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ ldo6_reg: LDO6 {
++ regulator-name = "vdd_ldo6";
++ regulator-min-microvolt = <1000000>;
++ regulator-max-microvolt = <1000000>;
++ regulator-always-on;
++ };
++
++ ldo7_reg: LDO7 {
++ regulator-name = "vdd_ldo7";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ ldo13_reg: LDO13 {
++ regulator-name = "vqmmc";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ ldo17_reg: LDO17 {
++ regulator-name = "vdd_ldo17";
++ regulator-min-microvolt = <2800000>;
++ regulator-max-microvolt = <2800000>;
++ };
++
++ ldo18_reg: LDO18 {
++ regulator-name = "vdd_ldo18";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ ldo19_reg: LDO19 {
++ regulator-name = "vmmc";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ ldo20_reg: LDO20 {
++ regulator-name = "vdd_ldo20";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ ldo23_reg: LDO23 {
++ regulator-name = "vdd_mifs";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <1100000>;
++ regulator-always-on;
++ };
++
++ ldo24_reg: LDO24 {
++ regulator-name = "vdd_ldo24";
++ regulator-min-microvolt = <2400000>;
++ regulator-max-microvolt = <2400000>;
++ };
++
++ ldo25_reg: LDO25 {
++ regulator-name = "vdd_ldo25";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ };
++
++ ldo27_reg: LDO27 {
++ regulator-name = "vdd_g3ds";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <1100000>;
++ regulator-always-on;
++ };
++
++ ldo28_reg: LDO28 {
++ regulator-name = "vdd_ldo28";
++ regulator-min-microvolt = <2800000>;
++ regulator-max-microvolt = <2800000>;
++ };
++
++ ldo32_reg: LDO32 {
++ regulator-name = "vdd_lcd_1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ };
++
++ ldo38_reg: LDO38 {
++ regulator-name = "vdd_ldo38";
++ regulator-min-microvolt = <2800000>;
++ regulator-max-microvolt = <2800000>;
++ regulator-always-on;
++ };
++
++ buck1_reg: BUCK1 {
++ regulator-name = "vdd_mif";
++ regulator-min-microvolt = <700000>;
++ regulator-max-microvolt = <1300000>;
++ regulator-always-on;
++ };
++
++ buck2_reg: BUCK2 {
++ regulator-name = "vdd_eagle";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <1500000>;
++ regulator-always-on;
++ };
++
++ buck3_reg: BUCK3 {
++ regulator-name = "vdd_int";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <1400000>;
++ regulator-always-on;
++ };
++
++ buck4_reg: BUCK4 {
++ regulator-name = "vdd_g3d";
++ regulator-min-microvolt = <700000>;
++ regulator-max-microvolt = <1400000>;
++ regulator-always-on;
++ };
++
++ buck6_reg: BUCK6 {
++ regulator-name = "vdd_kfc";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <1500000>;
++ regulator-always-on;
++ };
++
++ buck10_reg: BUCK10 {
++ regulator-name = "vdd_cam_isp_1.0v";
++ regulator-min-microvolt = <750000>;
++ regulator-max-microvolt = <1500000>;
++ regulator-always-on;
++ };
++ };
++ };
++};
++
++&mmc_0 {
++ status = "okay";
++ broken-cd;
++ card-detect-delay = <200>;
++ samsung,dw-mshc-ciu-div = <3>;
++ samsung,dw-mshc-sdr-timing = <0 4>;
++ samsung,dw-mshc-ddr-timing = <0 2>;
++ samsung,dw-mshc-hs400-timing = <0 2>;
++ samsung,read-strobe-delay = <90>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8
++ &sd0_rclk>;
++ bus-width = <8>;
++ cap-mmc-highspeed;
++ keep-power-in-suspend;
++ non-removable;
++};
++
++&mmc_2 {
++ status = "okay";
++ card-detect-delay = <200>;
++ samsung,dw-mshc-ciu-div = <3>;
++ samsung,dw-mshc-sdr-timing = <2 3>;
++ samsung,dw-mshc-ddr-timing = <1 2>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
++ bus-width = <4>;
++ cap-sd-highspeed;
++ vmmc-supply = <&ldo28_reg>;
++};
++
++&nocp_mem0_0 {
++ status = "okay";
++};
++
++&nocp_mem0_1 {
++ status = "okay";
++};
++
++&nocp_mem1_0 {
++ status = "okay";
++};
++
++&nocp_mem1_1 {
++ status = "okay";
++};
+diff --git b/arch/arm/boot/dts/imx6q-ccimx6sbc.dts b/arch/arm/boot/dts/imx6q-ccimx6sbc.dts
+new file mode 100644
+index 0000000..d249240
+--- /dev/null
++++ b/arch/arm/boot/dts/imx6q-ccimx6sbc.dts
+@@ -0,0 +1,303 @@
++/*
++ * Copyright (C) 2015 Robert Nelson (robertcnelson@gmail.com)
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ * a) This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License.
++ *
++ * This file is distributed in the hope that it will be useful
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * Or, alternatively
++ *
++ * b) Permission is hereby granted, free of charge, to any person
++ * obtaining a copy of this software and associated documentation
++ * files (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use
++ * copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following
++ * conditions:
++ *
++ * The above copyright notice and this permission notice shall be
++ * included in all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
++ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ */
++/dts-v1/;
++
++#include "imx6q.dtsi"
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++ model = "Digi ConnectCore-i.MX6 SBC Board";
++ compatible = "digi,connectcore/q", "fsl,imx6q";
++
++ chosen {
++ stdout-path = &uart4;
++ };
++
++ memory {
++ reg = <0x10000000 0x40000000>;
++ };
++
++ regulators {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ reg_usbh1_reset: regulator@1 {
++ compatible = "regulator-fixed";
++ reg = <1>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usbh1>;
++ regulator-name = "usbh1_reset";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ gpio = <&gpio3 10 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ reg_usb_otg_vbus: regulator@2 {
++ compatible = "regulator-fixed";
++ reg = <2>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usbotg>;
++ regulator-name = "usb_otg_vbus";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++ };
++};
++
++&fec {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_enet>;
++ phy-mode = "rgmii";
++ phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
++ status = "okay";
++};
++
++&hdmi {
++ ddc-i2c-bus = <&i2c3>;
++ status = "okay";
++};
++
++&i2c2 {
++ clock-frequency = <400000>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c2>;
++ status = "okay";
++
++ pmic@58 {
++ compatible = "dlg,da9063";
++ reg = <0x58>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <17 0x8>; /* active-low GPIO0_17 */
++
++ regulators {
++ vdd_3v3_reg: bperi {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ ldo3_reg: ldo3 {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ ldo4_reg: ldo4 {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ ldo6_reg: ldo6 {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ ldo7_reg: ldo7 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++
++ ldo8_reg: ldo8 {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++ };
++ };
++};
++
++&i2c3 {
++ clock-frequency = <100000>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c3>;
++ status = "okay";
++};
++
++&iomuxc {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_hog>;
++
++ imx6qdl-ccimx6sbc {
++ pinctrl_hog: hoggrp {
++ fsl,pins = <
++ /* da9063*/
++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
++ >;
++ };
++
++ pinctrl_enet: enetgrp {
++ fsl,pins = <
++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
++ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
++ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
++ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
++ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
++ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
++ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
++ /* Phy reset */
++ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x000b0
++ >;
++ };
++
++ pinctrl_i2c2: i2c2grp {
++ fsl,pins = <
++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
++ >;
++ };
++
++ pinctrl_i2c3: i2c3grp {
++ fsl,pins = <
++ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
++ >;
++ };
++
++ pinctrl_uart4: uart4grp {
++ fsl,pins = <
++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
++ >;
++ };
++
++ pinctrl_usbh1: usbh1grp {
++ fsl,pins = <
++ /* need to force low for hub reset */
++ MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x10b0
++ >;
++ };
++
++ pinctrl_usbotg: usbotggrp {
++ fsl,pins = <
++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
++ MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0
++ /* power enable, high active */
++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x10b0
++ >;
++ };
++
++ pinctrl_usdhc2: usdhc2grp {
++ fsl,pins = <
++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
++ >;
++ };
++
++ pinctrl_usdhc4: usdhc4grp {
++ fsl,pins = <
++ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
++ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059
++ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
++ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
++ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
++ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
++ MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
++ MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
++ MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
++ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
++ >;
++ };
++ };
++};
++
++&sata {
++ status = "okay";
++};
++
++&ssi1 {
++ status = "okay";
++};
++
++&uart4 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart4>;
++ status = "okay";
++};
++
++&usbh1 {
++ vbus-supply = <&reg_usbh1_reset>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usbh1>;
++ status = "okay";
++};
++
++&usbotg {
++ vbus-supply = <&reg_usb_otg_vbus>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usbotg>;
++ status = "okay";
++};
++
++&usdhc2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usdhc2>;
++ bus-width = <4>;
++ broken-cd; /* cd & wp, is not wired up on this board */
++ status = "okay";
++};
++
++&usdhc4 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usdhc4>;
++ bus-width = <8>;
++ non-removable;
++ status = "okay";
++};
+diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
+index 6de21ff..3277a06 100644
+--- a/arch/arm/boot/dts/imx6q-evi.dts
++++ b/arch/arm/boot/dts/imx6q-evi.dts
+@@ -54,18 +54,6 @@
+ reg = <0x10000000 0x40000000>;
+ };
+
+- reg_usbh1_vbus: regulator-usbhubreset {
+- compatible = "regulator-fixed";
+- regulator-name = "usbh1_vbus";
+- regulator-min-microvolt = <5000000>;
+- regulator-max-microvolt = <5000000>;
+- enable-active-high;
+- startup-delay-us = <2>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_usbh1_hubreset>;
+- gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+- };
+-
+ reg_usb_otg_vbus: regulator-usbotgvbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_vbus";
+@@ -207,12 +195,18 @@
+ };
+
+ &usbh1 {
+- vbus-supply = <&reg_usbh1_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbh1>;
+ dr_mode = "host";
+ disable-over-current;
+ status = "okay";
++
++ usb2415host: hub@1 {
++ compatible = "usb424,2513";
++ reg = <1>;
++ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
++ reset-duration-us = <3000>;
++ };
+ };
+
+ &usbotg {
+@@ -471,11 +465,6 @@
+ MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0
+ /* usbh1_b OC */
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
+- >;
+- };
+-
+- pinctrl_usbh1_hubreset: usbh1hubresetgrp {
+- fsl,pins = <
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
+ >;
+ };
+diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+index c96c91d..a173de2 100644
+--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+@@ -9,6 +9,8 @@
+ *
+ */
+
++#include <dt-bindings/gpio/gpio.h>
++
+ / {
+ aliases {
+ backlight = &backlight;
+@@ -58,17 +60,6 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+- reg_usb_h1_vbus: regulator@0 {
+- compatible = "regulator-fixed";
+- reg = <0>;
+- regulator-name = "usb_h1_vbus";
+- regulator-min-microvolt = <5000000>;
+- regulator-max-microvolt = <5000000>;
+- enable-active-high;
+- startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
+- gpio = <&gpio7 12 0>;
+- };
+-
+ reg_panel: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+@@ -188,7 +179,7 @@
+
+ pinctrl_usbh: usbhgrp {
+ fsl,pins = <
+- MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
+ MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
+ >;
+ };
+@@ -259,9 +250,16 @@
+ &usbh1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbh>;
+- vbus-supply = <&reg_usb_h1_vbus>;
+- clocks = <&clks IMX6QDL_CLK_CKO>;
+ status = "okay";
++
++ usb2415: hub@1 {
++ compatible = "usb424,2514";
++ reg = <1>;
++
++ clocks = <&clks IMX6QDL_CLK_CKO>;
++ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
++ reset-duration-us = <3000>;
++ };
+ };
+
+ &usdhc3 {
+diff --git a/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi
+index ef7fa62..b5d0f58 100644
+--- a/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi
+@@ -11,6 +11,24 @@
+
+ #include "imx6qdl-wandboard.dtsi"
+
++/ {
++ rfkill {
++ compatible = "wand,imx6qdl-wandboard-rfkill";
++ pinctrl-names = "default";
++ pinctrl-0 = <>;
++
++ bluetooth-on = <&gpio3 13 0>;
++ bluetooth-wake = <&gpio3 14 0>;
++ bluetooth-host-wake = <&gpio3 15 0>;
++
++ wifi-ref-on = <&gpio2 29 0>;
++ wifi-rst-n = <&gpio5 2 0>;
++ wifi-reg-on = <&gpio1 26 0>;
++ wifi-host-wake = <&gpio1 29 0>;
++ wifi-wake = <&gpio1 30 0>;
++ };
++};
++
+ &iomuxc {
+ pinctrl-0 = <&pinctrl_hog>;
+
+@@ -37,6 +55,5 @@
+ &usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+- non-removable;
+ status = "okay";
+ };
+diff --git a/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi
+index 8d893a7..b2097ef 100644
+--- a/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi
+@@ -11,6 +11,24 @@
+
+ #include "imx6qdl-wandboard.dtsi"
+
++/ {
++ rfkill {
++ compatible = "wand,imx6qdl-wandboard-rfkill";
++ pinctrl-names = "default";
++ pinctrl-0 = <>;
++
++ bluetooth-on = <&gpio5 21 0>;
++ bluetooth-wake = <&gpio5 30 0>;
++ bluetooth-host-wake = <&gpio5 20 0>;
++
++ wifi-ref-on = <&gpio5 31 0>; /* Wifi Power Enable */
++ wifi-rst-n = <&gpio6 0 0>; /* WIFI_ON reset */
++ wifi-reg-on = <&gpio1 26 0>; /* WL_REG_ON */
++ wifi-host-wake = <&gpio1 29 0>; /* WL_HOST_WAKE */
++ wifi-wake = <&gpio1 30 0>; /* WL_WAKE */
++ };
++};
++
+ &iomuxc {
+ pinctrl-0 = <&pinctrl_hog>;
+
+diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
+index be2e747..b946245 100644
+--- a/arch/arm/boot/dts/imx6qdl.dtsi
++++ b/arch/arm/boot/dts/imx6qdl.dtsi
+@@ -935,6 +935,8 @@
+
+ usbh1: usb@02184200 {
+ compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ reg = <0x02184200 0x200>;
+ interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_USBOH3>;
+@@ -949,6 +951,8 @@
+
+ usbh2: usb@02184400 {
+ compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ reg = <0x02184400 0x200>;
+ interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_USBOH3>;
+@@ -962,6 +966,8 @@
+
+ usbh3: usb@02184600 {
+ compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ reg = <0x02184600 0x200>;
+ interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_USBOH3>;
+diff --git b/arch/arm/boot/dts/imx6ul-14x14-evk-ism43362-b81-evb.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-ism43362-b81-evb.dts
+new file mode 100644
+index 0000000..9ba86b8
+--- /dev/null
++++ b/arch/arm/boot/dts/imx6ul-14x14-evk-ism43362-b81-evb.dts
+@@ -0,0 +1,516 @@
++/*
++ * Copyright (C) 2015 Freescale Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/dts-v1/;
++
++#include "imx6ul.dtsi"
++
++/ {
++ model = "Freescale i.MX6 UltraLite 14x14 EVK Board";
++ compatible = "fsl,imx6ul-14x14-evk", "fsl,imx6ul";
++
++ chosen {
++ stdout-path = &uart1;
++ };
++
++ memory {
++ reg = <0x80000000 0x20000000>;
++ };
++
++ backlight {
++ compatible = "pwm-backlight";
++ pwms = <&pwm1 0 5000000>;
++ brightness-levels = <0 4 8 16 32 64 128 255>;
++ default-brightness-level = <6>;
++ status = "okay";
++ };
++
++ regulators {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ reg_sd1_vmmc: sd1_regulator {
++ compatible = "regulator-fixed";
++ regulator-name = "VSD_3V3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ wlreg_on: fixedregulator@100 {
++ compatible = "regulator-fixed";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ regulator-name = "wlreg_on";
++ gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;
++ startup-delay-us = <100>;
++ enable-active-high;
++ };
++ };
++
++ sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "mx6ul-wm8960";
++ simple-audio-card,format = "i2s";
++ simple-audio-card,bitclock-master = <&dailink_master>;
++ simple-audio-card,frame-master = <&dailink_master>;
++ simple-audio-card,widgets =
++ "Microphone", "Mic Jack",
++ "Line", "Line In",
++ "Line", "Line Out",
++ "Speaker", "Speaker",
++ "Headphone", "Headphone Jack";
++ simple-audio-card,routing =
++ "Headphone Jack", "HP_L",
++ "Headphone Jack", "HP_R",
++ "Speaker", "SPK_LP",
++ "Speaker", "SPK_LN",
++ "Speaker", "SPK_RP",
++ "Speaker", "SPK_RN",
++ "LINPUT1", "Mic Jack",
++ "LINPUT3", "Mic Jack",
++ "RINPUT1", "Mic Jack",
++ "RINPUT2", "Mic Jack";
++
++ simple-audio-card,cpu {
++ sound-dai = <&sai2>;
++ };
++
++ dailink_master: simple-audio-card,codec {
++ sound-dai = <&codec>;
++ clocks = <&clks IMX6UL_CLK_SAI2>;
++ };
++ };
++};
++
++&clks {
++ assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
++ assigned-clock-rates = <786432000>;
++};
++
++&cpu0 {
++ arm-supply = <&reg_arm>;
++ soc-supply = <&reg_soc>;
++};
++
++&i2c2 {
++ clock_frequency = <100000>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c2>;
++ status = "okay";
++
++ codec: wm8960@1a {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8960";
++ reg = <0x1a>;
++ wlf,shared-lrclk;
++ };
++};
++
++&fec1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_enet1>;
++ phy-mode = "rmii";
++ phy-handle = <&ethphy0>;
++ status = "okay";
++};
++
++&fec2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_enet2>;
++ phy-mode = "rmii";
++ phy-handle = <&ethphy1>;
++ status = "okay";
++
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ethphy0: ethernet-phy@2 {
++ reg = <2>;
++ };
++
++ ethphy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++ };
++};
++
++
++&lcdif {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_lcdif_dat
++ &pinctrl_lcdif_ctrl>;
++ display = <&display0>;
++ status = "okay";
++
++ display0: display {
++ bits-per-pixel = <16>;
++ bus-width = <24>;
++
++ display-timings {
++ native-mode = <&timing0>;
++
++ timing0: timing0 {
++ clock-frequency = <9200000>;
++ hactive = <480>;
++ vactive = <272>;
++ hfront-porch = <8>;
++ hback-porch = <4>;
++ hsync-len = <41>;
++ vback-porch = <2>;
++ vfront-porch = <4>;
++ vsync-len = <10>;
++ hsync-active = <0>;
++ vsync-active = <0>;
++ de-active = <1>;
++ pixelclk-active = <0>;
++ };
++ };
++ };
++};
++
++&pwm1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pwm1>;
++ status = "okay";
++};
++
++&qspi {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_qspi>;
++ status = "okay";
++
++ flash0: n25q256a@0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "micron,n25q256a";
++ spi-max-frequency = <29000000>;
++ reg = <0>;
++ };
++};
++
++&sai2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_sai2>;
++ assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
++ <&clks IMX6UL_CLK_SAI2>;
++ assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
++ assigned-clock-rates = <0>, <12288000>;
++ fsl,sai-mclk-direction-output;
++ status = "okay";
++};
++
++&snvs_poweroff {
++ status = "okay";
++};
++
++&tsc {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_tsc>;
++ xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
++ measure-delay-time = <0xffff>;
++ pre-charge-time = <0xfff>;
++ status = "okay";
++};
++
++&uart1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
++ status = "okay";
++};
++
++&uart2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart2>;
++ uart-has-rtscts;
++ status = "okay";
++};
++
++&usbotg1 {
++ dr_mode = "peripheral";
++ status = "okay";
++};
++
++&usbotg2 {
++ dr_mode = "host";
++ disable-over-current;
++ status = "okay";
++};
++
++&reg_sd1_vmmc {
++ regulator-always-on;
++};
++
++&usdhc1 {
++ pinctrl-names = "default", "state_100mhz", "state_200mhz";
++ pinctrl-0 = <&pinctrl_usdhc1>;
++ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
++ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
++ cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
++ no-1-8-v;
++ keep-power-in-suspend;
++ wakeup-source;
++ vmmc-supply = <&reg_sd1_vmmc>;
++ status = "okay";
++};
++
++&usdhc2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_usdhc2>;
++ no-1-8-v;
++ keep-power-in-suspend;
++ wakeup-source;
++ status = "okay";
++};
++
++&wdog1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_wdog>;
++ fsl,ext-reset-output;
++};
++
++&iomuxc {
++ pinctrl-names = "default";
++
++ pinctrl_csi1: csi1grp {
++ fsl,pins = <
++ MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
++ MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
++ MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088
++ MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088
++ MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088
++ MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088
++ MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088
++ MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088
++ MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088
++ MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088
++ MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088
++ MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088
++ >;
++ };
++
++ pinctrl_enet1: enet1grp {
++ fsl,pins = <
++ MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
++ MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
++ MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
++ MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
++ MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
++ MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
++ MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
++ MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
++ >;
++ };
++
++ pinctrl_enet2: enet2grp {
++ fsl,pins = <
++ MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
++ MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
++ MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
++ MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
++ MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
++ MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
++ MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
++ MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
++ MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
++ MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
++ MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x17059
++ >;
++ };
++
++ pinctrl_flexcan1: flexcan1grp{
++ fsl,pins = <
++ MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
++ MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
++ >;
++ };
++
++ pinctrl_flexcan2: flexcan2grp{
++ fsl,pins = <
++ MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020
++ MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020
++ >;
++ };
++
++ pinctrl_i2c1: i2c1grp {
++ fsl,pins = <
++ MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
++ MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
++ >;
++ };
++
++ pinctrl_i2c2: i2c2grp {
++ fsl,pins = <
++ MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
++ MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
++ >;
++ };
++
++ pinctrl_lcdif_dat: lcdifdatgrp {
++ fsl,pins = <
++ MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79
++ MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79
++ MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79
++ MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79
++ MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79
++ MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79
++ MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79
++ MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79
++ MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79
++ MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79
++ MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79
++ MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79
++ MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79
++ MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79
++ MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79
++ MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79
++ MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79
++ MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79
++ MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79
++ MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79
++ MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79
++ MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79
++ MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79
++ MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79
++ >;
++ };
++
++ pinctrl_lcdif_ctrl: lcdifctrlgrp {
++ fsl,pins = <
++ MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79
++ MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79
++ MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79
++ MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79
++ /* used for lcd reset */
++ MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79
++ >;
++ };
++
++ pinctrl_qspi: qspigrp {
++ fsl,pins = <
++ MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK 0x70a1
++ MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x70a1
++ MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01 0x70a1
++ MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02 0x70a1
++ MX6UL_PAD_NAND_CLE__QSPI_A_DATA03 0x70a1
++ MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B 0x70a1
++ >;
++ };
++
++ pinctrl_sai2: sai2grp {
++ fsl,pins = <
++ MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088
++ MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088
++ MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088
++ MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x11088
++ MX6UL_PAD_JTAG_TMS__SAI2_MCLK 0x17088
++ MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x17059
++ >;
++ };
++
++ pinctrl_pwm1: pwm1grp {
++ fsl,pins = <
++ MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0
++ >;
++ };
++
++ pinctrl_sim2: sim2grp {
++ fsl,pins = <
++ MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD 0xb808
++ MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK 0x31
++ MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B 0xb808
++ MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN 0xb808
++ MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD 0xb809
++ MX6UL_PAD_CSI_DATA02__GPIO4_IO23 0x3008
++ >;
++ };
++
++ pinctrl_tsc: tscgrp {
++ fsl,pins = <
++ MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
++ MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0
++ MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0
++ MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0
++ >;
++ };
++
++ pinctrl_uart1: uart1grp {
++ fsl,pins = <
++ MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
++ MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
++ >;
++ };
++
++ pinctrl_uart2: uart2grp {
++ fsl,pins = <
++ MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1
++ MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1
++ MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1
++ MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1
++ >;
++ };
++
++ pinctrl_usdhc1: usdhc1grp {
++ fsl,pins = <
++ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
++ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071
++ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
++ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
++ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
++ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
++ MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
++ MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
++ MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */
++ MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3029
++ >;
++ };
++
++ pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
++ fsl,pins = <
++ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9
++ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9
++ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
++ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
++ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
++ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
++ MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3029
++ >;
++ };
++
++ pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
++ fsl,pins = <
++ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9
++ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9
++ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
++ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
++ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
++ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
++ MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3029
++ >;
++ };
++
++ pinctrl_usdhc2: usdhc2grp {
++ fsl,pins = <
++ MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x17059
++ MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059
++ MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
++ MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
++ MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
++ MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
++ >;
++ };
++
++ pinctrl_wdog: wdoggrp {
++ fsl,pins = <
++ MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0
++ >;
++ };
++};
+diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
+index 85e297e..226b833 100644
+--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
++++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
+@@ -27,6 +27,7 @@
+ aliases {
+ display0 = &dvi0;
+ display1 = &tv0;
++ ethernet = &ethernet;
+ };
+
+ leds {
+@@ -146,6 +147,7 @@
+ };
+
+ etb@5401b000 {
++ status = "disabled";
+ compatible = "arm,coresight-etb10", "arm,primecell";
+ reg = <0x5401b000 0x1000>;
+
+@@ -160,6 +162,7 @@
+ };
+
+ etm@54010000 {
++ status = "disabled";
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x54010000 0x1000>;
+
+@@ -205,6 +208,25 @@
+ >;
+ };
+
++ spi3_pins: pinmux_spi3_pins {
++ pinctrl-single,pins = <
++ 0x128 (PIN_INPUT | MUX_MODE1) /* sdmmc2_clk.mcspi3_clk gpio_130 */
++ 0x12a (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_cmd.mcspi3_simo gpio_131 */
++ 0x12c (PIN_INPUT_PULLUP | MUX_MODE1) /* sdmmc2_dat0.mcspi3_somi gpio_132 */
++ 0x130 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat2.mcspi3_cs1 gpio_134 */
++ 0x132 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat3.mcspi3_cs0 gpio_135 */
++ >;
++ };
++
++ spi4_pins: pinmux_spi4_pins {
++ pinctrl-single,pins = <
++ 0x15c (PIN_INPUT | MUX_MODE1) /* mcbsp1_clkr.mcspi4_clk gpio_156 */
++ 0x160 (PIN_OUTPUT | MUX_MODE1) /* mcbsp1_dx.mcspi4_simo gpio_158 */
++ 0x162 (PIN_INPUT_PULLUP | MUX_MODE1) /* mcbsp1_dr.mcspi4_somi gpio_159 */
++ 0x166 (PIN_OUTPUT | MUX_MODE1) /* mcbsp1_fsx.mcspi4_cs0 gpio_161 */
++ >;
++ };
++
+ hsusb2_pins: pinmux_hsusb2_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21d4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi1_cs3.hsusb2_data2 */
+@@ -279,7 +301,7 @@
+ };
+
+ twl_power: power {
+- compatible = "ti,twl4030-power-beagleboard-xm", "ti,twl4030-power-idle-osc-off";
++ compatible = "ti,twl4030-power-reset";
+ ti,use_poweroff;
+ };
+ };
+@@ -310,6 +332,36 @@
+ status = "disabled";
+ };
+
++&mcspi3 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi3_pins>;
++ status = "okay";
++
++ spidev0: spi@0 {
++ compatible = "spidev";
++ reg = <0>;
++ spi-max-frequency = <48000000>;
++ };
++
++ spidev1: spi@1 {
++ compatible = "spidev";
++ reg = <1>;
++ spi-max-frequency = <48000000>;
++ };
++};
++
++&mcspi4 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi4_pins>;
++ status = "okay";
++
++ spidev2: spi@0 {
++ compatible = "spidev";
++ reg = <0>;
++ spi-max-frequency = <48000000>;
++ };
++};
++
+ &twl_gpio {
+ ti,use-leds;
+ /* pullups: BIT(1) */
+@@ -348,6 +400,21 @@
+
+ &usbhsehci {
+ phys = <0 &hsusb2_phy>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ hub@2 {
++ compatible = "usb424,9514";
++ reg = <2>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ethernet: usbether@1 {
++ compatible = "usb424,ec00";
++ reg = <1>;
++ };
++ };
+ };
+
+ &vaux2 {
+diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
+index 4be85ce..049b5e1 100644
+--- a/arch/arm/boot/dts/omap3-beagle.dts
++++ b/arch/arm/boot/dts/omap3-beagle.dts
+@@ -141,6 +141,7 @@
+ };
+
+ etb@540000000 {
++ status = "disabled";
+ compatible = "arm,coresight-etb10", "arm,primecell";
+ reg = <0x5401b000 0x1000>;
+
+@@ -155,6 +156,7 @@
+ };
+
+ etm@54010000 {
++ status = "disabled";
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x54010000 0x1000>;
+
+@@ -271,9 +273,18 @@
+ codec {
+ };
+ };
++
++ twl_power: power {
++ compatible = "ti,twl4030-power-reset";
++ ti,use_poweroff;
++ };
+ };
+ };
+
++&i2c2 {
++ clock-frequency = <400000>;
++};
++
+ #include "twl4030.dtsi"
+ #include "twl4030_omap3.dtsi"
+
+diff --git a/arch/arm/boot/dts/omap4-panda-a4.dts b/arch/arm/boot/dts/omap4-panda-a4.dts
+index 78d3631..67ee5b4 100644
+--- a/arch/arm/boot/dts/omap4-panda-a4.dts
++++ b/arch/arm/boot/dts/omap4-panda-a4.dts
+@@ -10,6 +10,18 @@
+ #include "omap443x.dtsi"
+ #include "omap4-panda-common.dtsi"
+
++&emif1 {
++ cs1-used;
++ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
++};
++
++&emif2 {
++ cs1-used;
++ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
++};
++
+ /* Pandaboard Rev A4+ have external pullups on SCL & SDA */
+ &dss_hdmi_pins {
+ pinctrl-single,pins = <
+diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
+index 1673689..c6b90f0 100644
+--- a/arch/arm/boot/dts/omap4-panda-common.dtsi
++++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
+@@ -463,16 +463,6 @@
+ };
+ };
+
+-&emif1 {
+- cs1-used;
+- device-handle = <&elpida_ECB240ABACN>;
+-};
+-
+-&emif2 {
+- cs1-used;
+- device-handle = <&elpida_ECB240ABACN>;
+-};
+-
+ &mcbsp1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcbsp1_pins>;
+diff --git b/arch/arm/boot/dts/omap4-panda-es-b3.dts b/arch/arm/boot/dts/omap4-panda-es-b3.dts
+new file mode 100644
+index 0000000..2f1dabc
+--- /dev/null
++++ b/arch/arm/boot/dts/omap4-panda-es-b3.dts
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++/dts-v1/;
++
++#include "omap4460.dtsi"
++#include "omap4-panda-common.dtsi"
++
++/ {
++ model = "TI OMAP4 PandaBoard-ES";
++ compatible = "ti,omap4-panda-es", "ti,omap4-panda", "ti,omap4460", "ti,omap4430", "ti,omap4";
++};
++
++/* Audio routing is differnet between PandaBoard4430 and PandaBoardES */
++&sound {
++ ti,model = "PandaBoardES";
++
++ /* Audio routing */
++ ti,audio-routing =
++ "Headset Stereophone", "HSOL",
++ "Headset Stereophone", "HSOR",
++ "Ext Spk", "HFL",
++ "Ext Spk", "HFR",
++ "Line Out", "AUXL",
++ "Line Out", "AUXR",
++ "AFML", "Line In",
++ "AFMR", "Line In";
++};
++
++/* PandaboardES has external pullups on SCL & SDA */
++&dss_hdmi_pins {
++ pinctrl-single,pins = <
++ 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
++ 0x5c (PIN_INPUT | MUX_MODE0) /* hdmi_scl.hdmi_scl */
++ 0x5e (PIN_INPUT | MUX_MODE0) /* hdmi_sda.hdmi_sda */
++ >;
++};
++
++&omap4_pmx_core {
++ led_gpio_pins: gpio_led_pmx {
++ pinctrl-single,pins = <
++ 0xb6 (PIN_OUTPUT | MUX_MODE3) /* gpio_110 */
++ >;
++ };
++};
++
++&led_wkgpio_pins {
++ pinctrl-single,pins = <
++ 0x1c (PIN_OUTPUT | MUX_MODE3) /* gpio_wk8 */
++ >;
++};
++
++&leds {
++ pinctrl-0 = <
++ &led_gpio_pins
++ &led_wkgpio_pins
++ >;
++
++ heartbeat {
++ gpios = <&gpio4 14 GPIO_ACTIVE_HIGH>;
++ };
++ mmc {
++ gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++&gpio1 {
++ ti,no-reset-on-init;
++};
+diff --git a/arch/arm/boot/dts/omap4-panda-es.dts b/arch/arm/boot/dts/omap4-panda-es.dts
+index 119f8e6..5c54ccf 100644
+--- a/arch/arm/boot/dts/omap4-panda-es.dts
++++ b/arch/arm/boot/dts/omap4-panda-es.dts
+@@ -15,6 +15,18 @@
+ compatible = "ti,omap4-panda-es", "ti,omap4-panda", "ti,omap4460", "ti,omap4430", "ti,omap4";
+ };
+
++&emif1 {
++ cs1-used;
++ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
++};
++
++&emif2 {
++ cs1-used;
++ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
++};
++
+ /* Audio routing is differnet between PandaBoard4430 and PandaBoardES */
+ &sound {
+ ti,model = "PandaBoardES";
+diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
+index a0e28b2..3ee41ef 100644
+--- a/arch/arm/boot/dts/omap4-panda.dts
++++ b/arch/arm/boot/dts/omap4-panda.dts
+@@ -14,3 +14,15 @@
+ model = "TI OMAP4 PandaBoard";
+ compatible = "ti,omap4-panda", "ti,omap4430", "ti,omap4";
+ };
++
++&emif1 {
++ cs1-used;
++ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
++};
++
++&emif2 {
++ cs1-used;
++ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
++};
+diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
+index d728ec9..fb2cda4 100644
+--- a/arch/arm/boot/dts/omap4-sdp.dts
++++ b/arch/arm/boot/dts/omap4-sdp.dts
+@@ -502,11 +502,13 @@
+ &emif1 {
+ cs1-used;
+ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
+ };
+
+ &emif2 {
+ cs1-used;
+ device-handle = <&elpida_ECB240ABACN>;
++ status = "ok";
+ };
+
+ &keypad {
+diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
+index 9c289dd..ea0b76b 100644
+--- a/arch/arm/boot/dts/omap4.dtsi
++++ b/arch/arm/boot/dts/omap4.dtsi
+@@ -696,6 +696,7 @@
+ hw-caps-read-idle-ctrl;
+ hw-caps-ll-interface;
+ hw-caps-temp-alert;
++ status = "disabled";
+ };
+
+ emif2: emif@4d000000 {
+@@ -708,6 +709,7 @@
+ hw-caps-read-idle-ctrl;
+ hw-caps-ll-interface;
+ hw-caps-temp-alert;
++ status = "disabled";
+ };
+
+ ocp2scp@4a0ad000 {
+diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+index 5c9b5bf..7c9335d 100644
+--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+@@ -94,6 +94,17 @@
+ status = "okay";
+ };
+
++&emac {
++ phy = <&phy1>;
++ phy-mode = "mii";
++ allwinner,use-internal-phy;
++ allwinner,leds-active-low;
++ status = "okay";
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++};
++
+ &mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+index 3ec9712..21acd8a 100644
+--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+@@ -183,3 +183,14 @@
+ /* USB VBUS is always on */
+ status = "okay";
+ };
++
++&emac {
++ phy = <&phy1>;
++ phy-mode = "mii";
++ allwinner,use-internal-phy;
++ allwinner,leds-active-low;
++ status = "okay";
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++};
+diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
+index f4ba088..43c4a5c 100644
+--- a/arch/arm/boot/dts/sun8i-h3.dtsi
++++ b/arch/arm/boot/dts/sun8i-h3.dtsi
+@@ -50,6 +50,10 @@
+ / {
+ interrupt-parent = <&gic>;
+
++ aliases {
++ ethernet0 = &emac;
++ };
++
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -530,6 +534,20 @@
+ #size-cells = <0>;
+ };
+
++ emac: ethernet@1c30000 {
++ compatible = "allwinner,sun8i-h3-emac";
++ reg = <0x01c30000 0x104>, <0x01c00030 0x4>;
++ reg-names = "emac", "syscon";
++ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
++ resets = <&ccu RST_BUS_EMAC>, <&ccu RST_BUS_EPHY>;
++ reset-names = "ahb", "ephy";
++ clocks = <&ccu CLK_BUS_EMAC>, <&ccu CLK_BUS_EPHY>;
++ clock-names = "ahb", "ephy";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ gic: interrupt-controller@01c81000 {
+ compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+ reg = <0x01c81000 0x1000>,
+diff --git a/arch/arm/boot/dts/tps65217.dtsi b/arch/arm/boot/dts/tps65217.dtsi
+index a632724..02de56b 100644
+--- a/arch/arm/boot/dts/tps65217.dtsi
++++ b/arch/arm/boot/dts/tps65217.dtsi
+@@ -13,6 +13,18 @@
+
+ &tps {
+ compatible = "ti,tps65217";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++
++ charger {
++ compatible = "ti,tps65217-charger";
++ status = "disabled";
++ };
++
++ pwrbutton {
++ compatible = "ti,tps65217-pwrbutton";
++ status = "disabled";
++ };
+
+ regulators {
+ #address-cells = <1>;
+diff --git a/arch/arm/mach-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig
+index 6ffe572..bb7bd88 100644
+--- a/arch/arm/mach-imx/devices/Kconfig
++++ b/arch/arm/mach-imx/devices/Kconfig
+@@ -68,3 +68,9 @@ config IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+
+ config IMX_HAVE_PLATFORM_SPI_IMX
+ bool
++
++config WAND_RFKILL
++ tristate "Wandboard RF Kill support"
++ depends on SOC_IMX6Q
++ default m
++ select RFKILL
+diff --git a/arch/arm/mach-imx/devices/Makefile b/arch/arm/mach-imx/devices/Makefile
+index aa6cee8..800ce9b 100644
+--- a/arch/arm/mach-imx/devices/Makefile
++++ b/arch/arm/mach-imx/devices/Makefile
+@@ -25,3 +25,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
+ obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
+ obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) += platform-spi_imx.o
+ obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_EMMA) += platform-mx2-emma.o
++obj-$(CONFIG_WAND_RFKILL) += wand-rfkill.o
+diff --git b/arch/arm/mach-imx/devices/wand-rfkill.c b/arch/arm/mach-imx/devices/wand-rfkill.c
+new file mode 100644
+index 0000000..da7ef9f
+--- /dev/null
++++ b/arch/arm/mach-imx/devices/wand-rfkill.c
+@@ -0,0 +1,290 @@
++/*
++ * arch/arm/mach-imx/devices/wand-rfkill.c
++ *
++ * Copyright (C) 2013 Vladimir Ermakov <vooon341@gmail.com>
++ *
++ * based on net/rfkill/rfkill-gpio.c
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/rfkill.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++
++struct wand_rfkill_data {
++ struct rfkill *rfkill_dev;
++ int shutdown_gpio;
++ const char *shutdown_name;
++};
++
++static int wand_rfkill_set_block(void *data, bool blocked)
++{
++ struct wand_rfkill_data *rfkill = data;
++
++ pr_debug("wandboard-rfkill: set block %d\n", blocked);
++
++ if (blocked) {
++ if (gpio_is_valid(rfkill->shutdown_gpio))
++ gpio_direction_output(rfkill->shutdown_gpio, 0);
++ } else {
++ if (gpio_is_valid(rfkill->shutdown_gpio))
++ gpio_direction_output(rfkill->shutdown_gpio, 1);
++ }
++
++ return 0;
++}
++
++static const struct rfkill_ops wand_rfkill_ops = {
++ .set_block = wand_rfkill_set_block,
++};
++
++static int wand_rfkill_wifi_probe(struct device *dev,
++ struct device_node *np,
++ struct wand_rfkill_data *rfkill)
++{
++ int ret;
++ int wl_ref_on, wl_rst_n, wl_reg_on, wl_wake, wl_host_wake;
++
++ wl_ref_on = of_get_named_gpio(np, "wifi-ref-on", 0);
++ wl_rst_n = of_get_named_gpio(np, "wifi-rst-n", 0);
++ wl_reg_on = of_get_named_gpio(np, "wifi-reg-on", 0);
++ wl_wake = of_get_named_gpio(np, "wifi-wake", 0);
++ wl_host_wake = of_get_named_gpio(np, "wifi-host-wake", 0);
++
++ if (!gpio_is_valid(wl_rst_n) || !gpio_is_valid(wl_ref_on) ||
++ !gpio_is_valid(wl_reg_on) || !gpio_is_valid(wl_wake) ||
++ !gpio_is_valid(wl_host_wake)) {
++
++ dev_err(dev, "incorrect wifi gpios (%d %d %d %d %d)\n",
++ wl_rst_n, wl_ref_on, wl_reg_on, wl_wake, wl_host_wake);
++ return -EINVAL;
++ }
++
++ dev_info(dev, "initialize wifi chip\n");
++
++ gpio_request(wl_rst_n, "wl_rst_n");
++ gpio_direction_output(wl_rst_n, 0);
++ msleep(11);
++ gpio_set_value(wl_rst_n, 1);
++
++ gpio_request(wl_ref_on, "wl_ref_on");
++ gpio_direction_output(wl_ref_on, 1);
++
++ gpio_request(wl_reg_on, "wl_reg_on");
++ gpio_direction_output(wl_reg_on, 1);
++
++ gpio_request(wl_wake, "wl_wake");
++ gpio_direction_output(wl_wake, 1);
++
++ gpio_request(wl_host_wake, "wl_host_wake");
++ gpio_direction_input(wl_host_wake);
++
++ rfkill->shutdown_name = "wifi_shutdown";
++ rfkill->shutdown_gpio = wl_wake;
++
++ rfkill->rfkill_dev = rfkill_alloc("wifi-rfkill", dev, RFKILL_TYPE_WLAN,
++ &wand_rfkill_ops, rfkill);
++ if (!rfkill->rfkill_dev) {
++ ret = -ENOMEM;
++ goto wifi_fail_free_gpio;
++ }
++
++ ret = rfkill_register(rfkill->rfkill_dev);
++ if (ret < 0)
++ goto wifi_fail_unregister;
++
++ dev_info(dev, "wifi-rfkill registered.\n");
++
++ return 0;
++
++wifi_fail_unregister:
++ rfkill_destroy(rfkill->rfkill_dev);
++wifi_fail_free_gpio:
++ if (gpio_is_valid(wl_rst_n)) gpio_free(wl_rst_n);
++ if (gpio_is_valid(wl_ref_on)) gpio_free(wl_ref_on);
++ if (gpio_is_valid(wl_reg_on)) gpio_free(wl_reg_on);
++ if (gpio_is_valid(wl_wake)) gpio_free(wl_wake);
++ if (gpio_is_valid(wl_host_wake)) gpio_free(wl_host_wake);
++
++ return ret;
++}
++
++static int wand_rfkill_bt_probe(struct device *dev,
++ struct device_node *np,
++ struct wand_rfkill_data *rfkill)
++{
++ int ret;
++ int bt_on, bt_wake, bt_host_wake;
++
++ bt_on = of_get_named_gpio(np, "bluetooth-on", 0);
++ bt_wake = of_get_named_gpio(np, "bluetooth-wake", 0);
++ bt_host_wake = of_get_named_gpio(np, "bluetooth-host-wake", 0);
++
++ if (!gpio_is_valid(bt_on) || !gpio_is_valid(bt_wake) ||
++ !gpio_is_valid(bt_host_wake)) {
++
++ dev_err(dev, "incorrect bt gpios (%d %d %d)\n",
++ bt_on, bt_wake, bt_host_wake);
++ return -EINVAL;
++ }
++
++ dev_info(dev, "initialize bluetooth chip\n");
++
++ gpio_request(bt_on, "bt_on");
++ gpio_direction_output(bt_on, 0);
++ msleep(11);
++ gpio_set_value(bt_on, 1);
++
++ gpio_request(bt_wake, "bt_wake");
++ gpio_direction_output(bt_wake, 1);
++
++ gpio_request(bt_host_wake, "bt_host_wake");
++ gpio_direction_input(bt_host_wake);
++
++ rfkill->shutdown_name = "bluetooth_shutdown";
++ rfkill->shutdown_gpio = bt_wake;
++
++ rfkill->rfkill_dev = rfkill_alloc("bluetooth-rfkill", dev, RFKILL_TYPE_BLUETOOTH,
++ &wand_rfkill_ops, rfkill);
++ if (!rfkill->rfkill_dev) {
++ ret = -ENOMEM;
++ goto bt_fail_free_gpio;
++ }
++
++ ret = rfkill_register(rfkill->rfkill_dev);
++ if (ret < 0)
++ goto bt_fail_unregister;
++
++ dev_info(dev, "bluetooth-rfkill registered.\n");
++
++ return 0;
++
++bt_fail_unregister:
++ rfkill_destroy(rfkill->rfkill_dev);
++bt_fail_free_gpio:
++ if (gpio_is_valid(bt_on)) gpio_free(bt_on);
++ if (gpio_is_valid(bt_wake)) gpio_free(bt_wake);
++ if (gpio_is_valid(bt_host_wake)) gpio_free(bt_host_wake);
++
++ return ret;
++}
++
++static int wand_rfkill_probe(struct platform_device *pdev)
++{
++ struct wand_rfkill_data *rfkill;
++ struct pinctrl *pinctrl;
++ int ret;
++
++ dev_info(&pdev->dev, "Wandboard rfkill initialization\n");
++
++ if (!pdev->dev.of_node) {
++ dev_err(&pdev->dev, "no device tree node\n");
++ return -ENODEV;
++ }
++
++ rfkill = kzalloc(sizeof(*rfkill) * 2, GFP_KERNEL);
++ if (!rfkill)
++ return -ENOMEM;
++
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ int ret = PTR_ERR(pinctrl);
++ dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
++ return ret;
++ }
++
++ /* setup WiFi */
++ ret = wand_rfkill_wifi_probe(&pdev->dev, pdev->dev.of_node, &rfkill[0]);
++ if (ret < 0)
++ goto fail_free_rfkill;
++
++ /* setup bluetooth */
++ ret = wand_rfkill_bt_probe(&pdev->dev, pdev->dev.of_node, &rfkill[1]);
++ if (ret < 0)
++ goto fail_unregister_wifi;
++
++ platform_set_drvdata(pdev, rfkill);
++
++ return 0;
++
++fail_unregister_wifi:
++ if (rfkill[1].rfkill_dev) {
++ rfkill_unregister(rfkill[1].rfkill_dev);
++ rfkill_destroy(rfkill[1].rfkill_dev);
++ }
++
++ /* TODO free gpio */
++
++fail_free_rfkill:
++ kfree(rfkill);
++
++ return ret;
++}
++
++static int wand_rfkill_remove(struct platform_device *pdev)
++{
++ struct wand_rfkill_data *rfkill = platform_get_drvdata(pdev);
++
++ dev_info(&pdev->dev, "Module unloading\n");
++
++ if (!rfkill)
++ return 0;
++
++ /* WiFi */
++ if (gpio_is_valid(rfkill[0].shutdown_gpio))
++ gpio_free(rfkill[0].shutdown_gpio);
++
++ rfkill_unregister(rfkill[0].rfkill_dev);
++ rfkill_destroy(rfkill[0].rfkill_dev);
++
++ /* Bt */
++ if (gpio_is_valid(rfkill[1].shutdown_gpio))
++ gpio_free(rfkill[1].shutdown_gpio);
++
++ rfkill_unregister(rfkill[1].rfkill_dev);
++ rfkill_destroy(rfkill[1].rfkill_dev);
++
++ kfree(rfkill);
++
++ return 0;
++}
++
++static struct of_device_id wand_rfkill_match[] = {
++ { .compatible = "wand,imx6q-wandboard-rfkill", },
++ { .compatible = "wand,imx6dl-wandboard-rfkill", },
++ { .compatible = "wand,imx6qdl-wandboard-rfkill", },
++ {}
++};
++
++static struct platform_driver wand_rfkill_driver = {
++ .driver = {
++ .name = "wandboard-rfkill",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(wand_rfkill_match),
++ },
++ .probe = wand_rfkill_probe,
++ .remove = wand_rfkill_remove
++};
++
++module_platform_driver(wand_rfkill_driver);
++
++MODULE_AUTHOR("Vladimir Ermakov <vooon341@gmail.com>");
++MODULE_DESCRIPTION("Wandboard rfkill driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
+index f989145..0679d78 100644
+--- a/arch/arm/mach-omap2/omap_device.c
++++ b/arch/arm/mach-omap2/omap_device.c
+@@ -138,8 +138,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ struct device_node *node = pdev->dev.of_node;
+- const char *oh_name;
+- int oh_cnt, i, ret = 0;
++ const char *oh_name, *rst_name;
++ int oh_cnt, dstr_cnt, i, ret = 0;
+ bool device_active = false;
+
+ oh_cnt = of_property_count_strings(node, "ti,hwmods");
+@@ -190,6 +190,26 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
+ omap_device_enable(pdev);
+ pm_runtime_set_active(&pdev->dev);
+ }
++ dstr_cnt =
++ of_property_count_strings(node, "ti,deassert-hard-reset");
++ if (dstr_cnt > 0) {
++ for (i = 0; i < dstr_cnt; i += 2) {
++ of_property_read_string_index(
++ node, "ti,deassert-hard-reset", i,
++ &oh_name);
++ of_property_read_string_index(
++ node, "ti,deassert-hard-reset", i+1,
++ &rst_name);
++ oh = omap_hwmod_lookup(oh_name);
++ if (!oh) {
++ dev_warn(&pdev->dev,
++ "Cannot parse deassert property for '%s'\n",
++ oh_name);
++ break;
++ }
++ omap_hwmod_deassert_hardreset(oh, rst_name);
++ }
++ }
+
+ odbfd_exit1:
+ kfree(hwmods);
+@@ -206,12 +226,21 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_device *od;
+- int err;
++ int i, err;
+
+ switch (event) {
+ case BUS_NOTIFY_REMOVED_DEVICE:
+- if (pdev->archdata.od)
+- omap_device_delete(pdev->archdata.od);
++ od = to_omap_device(pdev);
++ if (!od)
++ break;
++
++ for (i = 0; i < od->hwmods_cnt; i++) {
++ /* shutdown hwmods */
++ omap_hwmod_shutdown(od->hwmods[i]);
++ /* we don't remove clocks cause there's no API to do so */
++ /* no harm done, since they will not be created next time */
++ }
++ omap_device_delete(od);
+ break;
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ od = to_omap_device(pdev);
+@@ -793,6 +822,8 @@ int omap_device_idle(struct platform_device *pdev)
+ struct omap_device *od;
+
+ od = to_omap_device(pdev);
++ if (!od)
++ return 0;
+
+ if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+ dev_warn(&pdev->dev,
+diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
+index 6441dfd..f7a5fb4 100644
+--- a/drivers/base/power/opp/core.c
++++ b/drivers/base/power/opp/core.c
+@@ -93,6 +93,8 @@ struct opp_table *_find_opp_table(struct device *dev)
+ * Return: voltage in micro volt corresponding to the opp, else
+ * return 0
+ *
++ * This is useful only for devices with single power supply.
++ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. This means that opp which could have been fetched by
+ * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
+@@ -112,7 +114,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
+ if (IS_ERR_OR_NULL(tmp_opp))
+ pr_err("%s: Invalid parameters\n", __func__);
+ else
+- v = tmp_opp->u_volt;
++ v = tmp_opp->supplies[0].u_volt;
+
+ return v;
+ }
+@@ -210,6 +212,24 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
+ }
+ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
+
++static int _get_regulator_count(struct device *dev)
++{
++ struct opp_table *opp_table;
++ int count;
++
++ rcu_read_lock();
++
++ opp_table = _find_opp_table(dev);
++ if (!IS_ERR(opp_table))
++ count = opp_table->regulator_count;
++ else
++ count = 0;
++
++ rcu_read_unlock();
++
++ return count;
++}
++
+ /**
+ * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
+ * @dev: device for which we do this operation
+@@ -222,34 +242,51 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
+ {
+ struct opp_table *opp_table;
+ struct dev_pm_opp *opp;
+- struct regulator *reg;
++ struct regulator *reg, **regulators;
+ unsigned long latency_ns = 0;
+- unsigned long min_uV = ~0, max_uV = 0;
+- int ret;
++ int ret, i, count;
++ struct {
++ unsigned long min;
++ unsigned long max;
++ } *uV;
++
++ count = _get_regulator_count(dev);
++
++ /* Regulator may not be required for the device */
++ if (!count)
++ return 0;
++
++ regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL);
++ if (!regulators)
++ return 0;
++
++ uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
++ if (!uV)
++ goto free_regulators;
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ rcu_read_unlock();
+- return 0;
++ goto free_uV;
+ }
+
+- reg = opp_table->regulator;
+- if (IS_ERR(reg)) {
+- /* Regulator may not be required for device */
+- rcu_read_unlock();
+- return 0;
+- }
++ memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
+
+- list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+- if (!opp->available)
+- continue;
++ for (i = 0; i < count; i++) {
++ uV[i].min = ~0;
++ uV[i].max = 0;
+
+- if (opp->u_volt_min < min_uV)
+- min_uV = opp->u_volt_min;
+- if (opp->u_volt_max > max_uV)
+- max_uV = opp->u_volt_max;
++ list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
++ if (!opp->available)
++ continue;
++
++ if (opp->supplies[i].u_volt_min < uV[i].min)
++ uV[i].min = opp->supplies[i].u_volt_min;
++ if (opp->supplies[i].u_volt_max > uV[i].max)
++ uV[i].max = opp->supplies[i].u_volt_max;
++ }
+ }
+
+ rcu_read_unlock();
+@@ -258,9 +295,16 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
+ * The caller needs to ensure that opp_table (and hence the regulator)
+ * isn't freed, while we are executing this routine.
+ */
+- ret = regulator_set_voltage_time(reg, min_uV, max_uV);
+- if (ret > 0)
+- latency_ns = ret * 1000;
++ for (i = 0; reg = regulators[i], i < count; i++) {
++ ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
++ if (ret > 0)
++ latency_ns += ret * 1000;
++ }
++
++free_uV:
++ kfree(uV);
++free_regulators:
++ kfree(regulators);
+
+ return latency_ns;
+ }
+@@ -542,8 +586,7 @@ static struct clk *_get_opp_clk(struct device *dev)
+ }
+
+ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
+- unsigned long u_volt, unsigned long u_volt_min,
+- unsigned long u_volt_max)
++ struct dev_pm_opp_supply *supply)
+ {
+ int ret;
+
+@@ -554,14 +597,78 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
+ return 0;
+ }
+
+- dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, u_volt_min,
+- u_volt, u_volt_max);
++ dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__,
++ supply->u_volt_min, supply->u_volt, supply->u_volt_max);
+
+- ret = regulator_set_voltage_triplet(reg, u_volt_min, u_volt,
+- u_volt_max);
++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
++ supply->u_volt, supply->u_volt_max);
+ if (ret)
+ dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
+- __func__, u_volt_min, u_volt, u_volt_max, ret);
++ __func__, supply->u_volt_min, supply->u_volt,
++ supply->u_volt_max, ret);
++
++ return ret;
++}
++
++static inline int
++_generic_set_opp_clk_only(struct device *dev, struct clk *clk,
++ unsigned long old_freq, unsigned long freq)
++{
++ int ret;
++
++ ret = clk_set_rate(clk, freq);
++ if (ret) {
++ dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
++ ret);
++ }
++
++ return ret;
++}
++
++static int _generic_set_opp(struct dev_pm_set_opp_data *data)
++{
++ struct dev_pm_opp_supply *old_supply = data->old_opp.supplies;
++ struct dev_pm_opp_supply *new_supply = data->new_opp.supplies;
++ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
++ struct regulator *reg = data->regulators[0];
++ struct device *dev= data->dev;
++ int ret;
++
++ /* This function only supports single regulator per device */
++ if (WARN_ON(data->regulator_count > 1)) {
++ dev_err(dev, "multiple regulators are not supported\n");
++ return -EINVAL;
++ }
++
++ /* Scaling up? Scale voltage before frequency */
++ if (freq > old_freq) {
++ ret = _set_opp_voltage(dev, reg, new_supply);
++ if (ret)
++ goto restore_voltage;
++ }
++
++ /* Change frequency */
++ ret = _generic_set_opp_clk_only(dev, data->clk, old_freq, freq);
++ if (ret)
++ goto restore_voltage;
++
++ /* Scaling down? Scale voltage after frequency */
++ if (freq < old_freq) {
++ ret = _set_opp_voltage(dev, reg, new_supply);
++ if (ret)
++ goto restore_freq;
++ }
++
++ return 0;
++
++restore_freq:
++ if (_generic_set_opp_clk_only(dev, data->clk, freq, old_freq))
++ dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
++ __func__, old_freq);
++restore_voltage:
++ /* This shouldn't harm even if the voltages weren't updated earlier */
++ if (old_supply->u_volt)
++ _set_opp_voltage(dev, reg, old_supply);
+
+ return ret;
+ }
+@@ -579,13 +686,13 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
+ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
+ {
+ struct opp_table *opp_table;
++ unsigned long freq, old_freq;
++ int (*set_opp)(struct dev_pm_set_opp_data *data);
+ struct dev_pm_opp *old_opp, *opp;
+- struct regulator *reg;
++ struct regulator **regulators;
++ struct dev_pm_set_opp_data *data;
+ struct clk *clk;
+- unsigned long freq, old_freq;
+- unsigned long u_volt, u_volt_min, u_volt_max;
+- unsigned long old_u_volt, old_u_volt_min, old_u_volt_max;
+- int ret;
++ int ret, size;
+
+ if (unlikely(!target_freq)) {
+ dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
+@@ -634,64 +741,54 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
+ return ret;
+ }
+
+- if (IS_ERR(old_opp)) {
+- old_u_volt = 0;
+- } else {
+- old_u_volt = old_opp->u_volt;
+- old_u_volt_min = old_opp->u_volt_min;
+- old_u_volt_max = old_opp->u_volt_max;
+- }
+-
+- u_volt = opp->u_volt;
+- u_volt_min = opp->u_volt_min;
+- u_volt_max = opp->u_volt_max;
+-
+- reg = opp_table->regulator;
++ dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
++ old_freq, freq);
+
+- rcu_read_unlock();
++ regulators = opp_table->regulators;
+
+- /* Scaling up? Scale voltage before frequency */
+- if (freq > old_freq) {
+- ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
+- u_volt_max);
+- if (ret)
+- goto restore_voltage;
+- }
++ /* Only frequency scaling */
++ if (!regulators) {
++ unsigned long u_volt = opp->supplies[0].u_volt;
+
+- /* Change frequency */
++ rcu_read_unlock();
+
+- dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
+- __func__, old_freq, freq);
++ /*
++ * DT contained supply ratings? Consider platform failed to set
++ * regulators.
++ */
++ if (unlikely(u_volt)) {
++ dev_err(dev, "%s: Regulator not registered with OPP core\n",
++ __func__);
++ return -EINVAL;
++ }
+
+- ret = clk_set_rate(clk, freq);
+- if (ret) {
+- dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+- ret);
+- goto restore_voltage;
++ return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+ }
+
+- /* Scaling down? Scale voltage after frequency */
+- if (freq < old_freq) {
+- ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
+- u_volt_max);
+- if (ret)
+- goto restore_freq;
+- }
++ if (opp_table->set_opp)
++ set_opp = opp_table->set_opp;
++ else
++ set_opp = _generic_set_opp;
++
++ data = opp_table->set_opp_data;
++ data->regulators = regulators;
++ data->regulator_count = opp_table->regulator_count;
++ data->clk = clk;
++ data->dev = dev;
++
++ data->old_opp.rate = old_freq;
++ size = sizeof(*opp->supplies) * opp_table->regulator_count;
++ if (IS_ERR(old_opp))
++ memset(data->old_opp.supplies, 0, size);
++ else
++ memcpy(data->old_opp.supplies, old_opp->supplies, size);
+
+- return 0;
++ data->new_opp.rate = freq;
++ memcpy(data->new_opp.supplies, opp->supplies, size);
+
+-restore_freq:
+- if (clk_set_rate(clk, old_freq))
+- dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+- __func__, old_freq);
+-restore_voltage:
+- /* This shouldn't harm even if the voltages weren't updated earlier */
+- if (old_u_volt) {
+- _set_opp_voltage(dev, reg, old_u_volt, old_u_volt_min,
+- old_u_volt_max);
+- }
++ rcu_read_unlock();
+
+- return ret;
++ return set_opp(data);
+ }
+ EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
+
+@@ -774,9 +871,6 @@ static struct opp_table *_add_opp_table(struct device *dev)
+
+ _of_init_opp_table(opp_table, dev);
+
+- /* Set regulator to a non-NULL error value */
+- opp_table->regulator = ERR_PTR(-ENXIO);
+-
+ /* Find clk for the device */
+ opp_table->clk = clk_get(dev, NULL);
+ if (IS_ERR(opp_table->clk)) {
+@@ -825,7 +919,10 @@ static void _remove_opp_table(struct opp_table *opp_table)
+ if (opp_table->prop_name)
+ return;
+
+- if (!IS_ERR(opp_table->regulator))
++ if (opp_table->regulators)
++ return;
++
++ if (opp_table->set_opp)
+ return;
+
+ /* Release clk */
+@@ -934,34 +1031,50 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
+ struct opp_table **opp_table)
+ {
+ struct dev_pm_opp *opp;
++ int count, supply_size;
++ struct opp_table *table;
+
+- /* allocate new OPP node */
+- opp = kzalloc(sizeof(*opp), GFP_KERNEL);
+- if (!opp)
++ table = _add_opp_table(dev);
++ if (!table)
+ return NULL;
+
+- INIT_LIST_HEAD(&opp->node);
++ /* Allocate space for at least one supply */
++ count = table->regulator_count ? table->regulator_count : 1;
++ supply_size = sizeof(*opp->supplies) * count;
+
+- *opp_table = _add_opp_table(dev);
+- if (!*opp_table) {
+- kfree(opp);
++ /* allocate new OPP node and supplies structures */
++ opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
++ if (!opp) {
++ kfree(table);
+ return NULL;
+ }
+
++ /* Put the supplies at the end of the OPP structure as an empty array */
++ opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
++ INIT_LIST_HEAD(&opp->node);
++
++ *opp_table = table;
++
+ return opp;
+ }
+
+ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
+ struct opp_table *opp_table)
+ {
+- struct regulator *reg = opp_table->regulator;
+-
+- if (!IS_ERR(reg) &&
+- !regulator_is_supported_voltage(reg, opp->u_volt_min,
+- opp->u_volt_max)) {
+- pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
+- __func__, opp->u_volt_min, opp->u_volt_max);
+- return false;
++ struct regulator *reg;
++ int i;
++
++ for (i = 0; i < opp_table->regulator_count; i++) {
++ reg = opp_table->regulators[i];
++
++ if (!regulator_is_supported_voltage(reg,
++ opp->supplies[i].u_volt_min,
++ opp->supplies[i].u_volt_max)) {
++ pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
++ __func__, opp->supplies[i].u_volt_min,
++ opp->supplies[i].u_volt_max);
++ return false;
++ }
+ }
+
+ return true;
+@@ -993,11 +1106,13 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
+
+ /* Duplicate OPPs */
+ dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
+- __func__, opp->rate, opp->u_volt, opp->available,
+- new_opp->rate, new_opp->u_volt, new_opp->available);
++ __func__, opp->rate, opp->supplies[0].u_volt,
++ opp->available, new_opp->rate,
++ new_opp->supplies[0].u_volt, new_opp->available);
+
+- return opp->available && new_opp->u_volt == opp->u_volt ?
+- 0 : -EEXIST;
++ /* Should we compare voltages for all regulators here ? */
++ return opp->available &&
++ new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
+ }
+
+ new_opp->opp_table = opp_table;
+@@ -1064,9 +1179,9 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
+ /* populate the opp table */
+ new_opp->rate = freq;
+ tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
+- new_opp->u_volt = u_volt;
+- new_opp->u_volt_min = u_volt - tol;
+- new_opp->u_volt_max = u_volt + tol;
++ new_opp->supplies[0].u_volt = u_volt;
++ new_opp->supplies[0].u_volt_min = u_volt - tol;
++ new_opp->supplies[0].u_volt_max = u_volt + tol;
+ new_opp->available = true;
+ new_opp->dynamic = dynamic;
+
+@@ -1310,13 +1425,47 @@ void dev_pm_opp_put_prop_name(struct device *dev)
+ }
+ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
+
++static int _allocate_set_opp_data(struct opp_table *opp_table)
++{
++ struct dev_pm_set_opp_data *data;
++ int len, count = opp_table->regulator_count;
++
++ if (WARN_ON(!count))
++ return -EINVAL;
++
++ /* space for set_opp_data */
++ len = sizeof(*data);
++
++ /* space for old_opp.supplies and new_opp.supplies */
++ len += 2 * sizeof(struct dev_pm_opp_supply) * count;
++
++ data = kzalloc(len, GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ data->old_opp.supplies = (void *)(data + 1);
++ data->new_opp.supplies = data->old_opp.supplies + count;
++
++ opp_table->set_opp_data = data;
++
++ return 0;
++}
++
++static void _free_set_opp_data(struct opp_table *opp_table)
++{
++ kfree(opp_table->set_opp_data);
++ opp_table->set_opp_data = NULL;
++}
++
+ /**
+- * dev_pm_opp_set_regulator() - Set regulator name for the device
++ * dev_pm_opp_set_regulators() - Set regulator names for the device
+ * @dev: Device for which regulator name is being set.
+- * @name: Name of the regulator.
++ * @names: Array of pointers to the names of the regulator.
++ * @count: Number of regulators.
+ *
+ * In order to support OPP switching, OPP layer needs to know the name of the
+- * device's regulator, as the core would be required to switch voltages as well.
++ * device's regulators, as the core would be required to switch voltages as
++ * well.
+ *
+ * This must be called before any OPPs are initialized for the device.
+ *
+@@ -1326,11 +1475,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+-struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
++int dev_pm_opp_set_regulators(struct device *dev, const char * const names[],
++ unsigned int count)
+ {
+ struct opp_table *opp_table;
+ struct regulator *reg;
+- int ret;
++ int ret, i;
+
+ mutex_lock(&opp_table_lock);
+
+@@ -1346,38 +1496,62 @@ struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
+ goto err;
+ }
+
+- /* Already have a regulator set */
+- if (WARN_ON(!IS_ERR(opp_table->regulator))) {
++ /* Already have regulators set */
++ if (opp_table->regulators) {
+ ret = -EBUSY;
+ goto err;
+ }
+- /* Allocate the regulator */
+- reg = regulator_get_optional(dev, name);
+- if (IS_ERR(reg)) {
+- ret = PTR_ERR(reg);
+- if (ret != -EPROBE_DEFER)
+- dev_err(dev, "%s: no regulator (%s) found: %d\n",
+- __func__, name, ret);
++
++ opp_table->regulators = kmalloc_array(count,
++ sizeof(*opp_table->regulators),
++ GFP_KERNEL);
++ if (!opp_table->regulators) {
++ ret = -ENOMEM;
+ goto err;
+ }
+
+- opp_table->regulator = reg;
++ for (i = 0; i < count; i++) {
++ reg = regulator_get_optional(dev, names[i]);
++ if (IS_ERR(reg)) {
++ ret = PTR_ERR(reg);
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "%s: regulator (%s) not found: %d\n",
++ __func__, names[i], ret);
++ goto free_regulators;
++ }
++
++ opp_table->regulators[i] = reg;
++ }
++
++ opp_table->regulator_count = count;
++
++ /* Allocate block only once to pass to set_opp() routines */
++ ret = _allocate_set_opp_data(opp_table);
++ if (ret)
++ goto free_regulators;
+
+ mutex_unlock(&opp_table_lock);
+- return opp_table;
++ return 0;
+
++free_regulators:
++ while (i != 0)
++ regulator_put(opp_table->regulators[--i]);
++
++ kfree(opp_table->regulators);
++ opp_table->regulators = NULL;
++ opp_table->regulator_count = 0;
+ err:
+ _remove_opp_table(opp_table);
+ unlock:
+ mutex_unlock(&opp_table_lock);
+
+- return ERR_PTR(ret);
++ return ret;
+ }
+-EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
++EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
+
+ /**
+- * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
+- * @opp_table: OPP table returned from dev_pm_opp_set_regulator().
++ * dev_pm_opp_put_regulators() - Releases resources blocked for regulators
++ * @dev: Device for which regulators were set.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+@@ -1385,20 +1559,140 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+-void dev_pm_opp_put_regulator(struct opp_table *opp_table)
++void dev_pm_opp_put_regulators(struct device *dev)
+ {
++ struct opp_table *opp_table;
++ int i;
++
+ mutex_lock(&opp_table_lock);
+
+- if (IS_ERR(opp_table->regulator)) {
+- pr_err("%s: Doesn't have regulator set\n", __func__);
++ /* Check for existing table for 'dev' first */
++ opp_table = _find_opp_table(dev);
++ if (IS_ERR(opp_table)) {
++ dev_err(dev, "Failed to find opp_table: %ld\n",
++ PTR_ERR(opp_table));
++ goto unlock;
++ }
++
++ if (!opp_table->regulators) {
++ dev_err(dev, "%s: Doesn't have regulators set\n", __func__);
++ goto unlock;
++ }
++
++ /* Make sure there are no concurrent readers while updating opp_table */
++ WARN_ON(!list_empty(&opp_table->opp_list));
++
++ for (i = opp_table->regulator_count - 1; i >= 0; i--)
++ regulator_put(opp_table->regulators[i]);
++
++ _free_set_opp_data(opp_table);
++
++ kfree(opp_table->regulators);
++ opp_table->regulators = NULL;
++ opp_table->regulator_count = 0;
++
++ /* Try freeing opp_table if this was the last blocking resource */
++ _remove_opp_table(opp_table);
++
++unlock:
++ mutex_unlock(&opp_table_lock);
++}
++EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
++
++/**
++ * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
++ * @dev: Device for which the helper is getting registered.
++ * @set_opp: Custom set OPP helper.
++ *
++ * This is useful to support complex platforms (like platforms with multiple
++ * regulators per device), instead of the generic OPP set rate helper.
++ *
++ * This must be called before any OPPs are initialized for the device.
++ *
++ * Locking: The internal opp_table and opp structures are RCU protected.
++ * Hence this function internally uses RCU updater strategy with mutex locks
++ * to keep the integrity of the internal data structures. Callers should ensure
++ * that this function is *NOT* called under RCU protection or in contexts where
++ * mutex cannot be locked.
++ */
++int dev_pm_opp_register_set_opp_helper(struct device *dev,
++ int (*set_opp)(struct dev_pm_set_opp_data *data))
++{
++ struct opp_table *opp_table;
++ int ret;
++
++ if (!set_opp)
++ return -EINVAL;
++
++ mutex_lock(&opp_table_lock);
++
++ opp_table = _add_opp_table(dev);
++ if (!opp_table) {
++ ret = -ENOMEM;
++ goto unlock;
++ }
++
++ /* This should be called before OPPs are initialized */
++ if (WARN_ON(!list_empty(&opp_table->opp_list))) {
++ ret = -EBUSY;
++ goto err;
++ }
++
++ /* Already have custom set_opp helper */
++ if (WARN_ON(opp_table->set_opp)) {
++ ret = -EBUSY;
++ goto err;
++ }
++
++ opp_table->set_opp = set_opp;
++
++ mutex_unlock(&opp_table_lock);
++ return 0;
++
++err:
++ _remove_opp_table(opp_table);
++unlock:
++ mutex_unlock(&opp_table_lock);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
++
++/**
++ * dev_pm_opp_register_put_opp_helper() - Releases resources blocked for
++ * set_opp helper
++ * @dev: Device for which custom set_opp helper has to be cleared.
++ *
++ * Locking: The internal opp_table and opp structures are RCU protected.
++ * Hence this function internally uses RCU updater strategy with mutex locks
++ * to keep the integrity of the internal data structures. Callers should ensure
++ * that this function is *NOT* called under RCU protection or in contexts where
++ * mutex cannot be locked.
++ */
++void dev_pm_opp_register_put_opp_helper(struct device *dev)
++{
++ struct opp_table *opp_table;
++
++ mutex_lock(&opp_table_lock);
++
++ /* Check for existing table for 'dev' first */
++ opp_table = _find_opp_table(dev);
++ if (IS_ERR(opp_table)) {
++ dev_err(dev, "Failed to find opp_table: %ld\n",
++ PTR_ERR(opp_table));
++ goto unlock;
++ }
++
++ if (!opp_table->set_opp) {
++ dev_err(dev, "%s: Doesn't have custom set_opp helper set\n",
++ __func__);
+ goto unlock;
+ }
+
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
+
+- regulator_put(opp_table->regulator);
+- opp_table->regulator = ERR_PTR(-ENXIO);
++ opp_table->set_opp = NULL;
+
+ /* Try freeing opp_table if this was the last blocking resource */
+ _remove_opp_table(opp_table);
+@@ -1406,7 +1700,7 @@ void dev_pm_opp_put_regulator(struct opp_table *opp_table)
+ unlock:
+ mutex_unlock(&opp_table_lock);
+ }
+-EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
++EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);
+
+ /**
+ * dev_pm_opp_add() - Add an OPP table from a table definitions
+diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
+index ef1ae6b..95f433d 100644
+--- a/drivers/base/power/opp/debugfs.c
++++ b/drivers/base/power/opp/debugfs.c
+@@ -15,6 +15,7 @@
+ #include <linux/err.h>
+ #include <linux/init.h>
+ #include <linux/limits.h>
++#include <linux/slab.h>
+
+ #include "opp.h"
+
+@@ -34,6 +35,46 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
+ debugfs_remove_recursive(opp->dentry);
+ }
+
++static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
++ struct opp_table *opp_table,
++ struct dentry *pdentry)
++{
++ struct dentry *d;
++ int i = 0;
++ char *name;
++
++ /* Always create at least supply-0 directory */
++ do {
++ name = kasprintf(GFP_KERNEL, "supply-%d", i);
++
++ /* Create per-opp directory */
++ d = debugfs_create_dir(name, pdentry);
++
++ kfree(name);
++
++ if (!d)
++ return false;
++
++ if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d,
++ &opp->supplies[i].u_volt))
++ return false;
++
++ if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d,
++ &opp->supplies[i].u_volt_min))
++ return false;
++
++ if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d,
++ &opp->supplies[i].u_volt_max))
++ return false;
++
++ if (!debugfs_create_ulong("u_amp", S_IRUGO, d,
++ &opp->supplies[i].u_amp))
++ return false;
++ } while (++i < opp_table->regulator_count);
++
++ return true;
++}
++
+ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
+ {
+ struct dentry *pdentry = opp_table->dentry;
+@@ -63,16 +104,7 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
+ if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
+ return -ENOMEM;
+
+- if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->u_volt))
+- return -ENOMEM;
+-
+- if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->u_volt_min))
+- return -ENOMEM;
+-
+- if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->u_volt_max))
+- return -ENOMEM;
+-
+- if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->u_amp))
++ if (!opp_debug_create_supplies(opp, opp_table, d))
+ return -ENOMEM;
+
+ if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
+diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
+index 5552211..8c869aa 100644
+--- a/drivers/base/power/opp/of.c
++++ b/drivers/base/power/opp/of.c
+@@ -17,6 +17,7 @@
+ #include <linux/errno.h>
+ #include <linux/device.h>
+ #include <linux/of.h>
++#include <linux/slab.h>
+ #include <linux/export.h>
+
+ #include "opp.h"
+@@ -101,16 +102,16 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
+ return true;
+ }
+
+-/* TODO: Support multiple regulators */
+ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
+ struct opp_table *opp_table)
+ {
+- u32 microvolt[3] = {0};
+- u32 val;
+- int count, ret;
++ u32 *microvolt, *microamp = NULL;
++ int supplies, vcount, icount, ret, i, j;
+ struct property *prop = NULL;
+ char name[NAME_MAX];
+
++ supplies = opp_table->regulator_count ? opp_table->regulator_count : 1;
++
+ /* Search for "opp-microvolt-<name>" */
+ if (opp_table->prop_name) {
+ snprintf(name, sizeof(name), "opp-microvolt-%s",
+@@ -128,34 +129,29 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
+ return 0;
+ }
+
+- count = of_property_count_u32_elems(opp->np, name);
+- if (count < 0) {
++ vcount = of_property_count_u32_elems(opp->np, name);
++ if (vcount < 0) {
+ dev_err(dev, "%s: Invalid %s property (%d)\n",
+- __func__, name, count);
+- return count;
++ __func__, name, vcount);
++ return vcount;
+ }
+
+- /* There can be one or three elements here */
+- if (count != 1 && count != 3) {
+- dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n",
+- __func__, name, count);
++ /* There can be one or three elements per supply */
++ if (vcount != supplies && vcount != supplies * 3) {
++ dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
++ __func__, name, vcount, supplies);
+ return -EINVAL;
+ }
+
+- ret = of_property_read_u32_array(opp->np, name, microvolt, count);
++ microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
++ if (!microvolt)
++ return -ENOMEM;
++
++ ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
+ if (ret) {
+ dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
+- return -EINVAL;
+- }
+-
+- opp->u_volt = microvolt[0];
+-
+- if (count == 1) {
+- opp->u_volt_min = opp->u_volt;
+- opp->u_volt_max = opp->u_volt;
+- } else {
+- opp->u_volt_min = microvolt[1];
+- opp->u_volt_max = microvolt[2];
++ ret = -EINVAL;
++ goto free_microvolt;
+ }
+
+ /* Search for "opp-microamp-<name>" */
+@@ -172,10 +168,59 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
+ prop = of_find_property(opp->np, name, NULL);
+ }
+
+- if (prop && !of_property_read_u32(opp->np, name, &val))
+- opp->u_amp = val;
++ if (prop) {
++ icount = of_property_count_u32_elems(opp->np, name);
++ if (icount < 0) {
++ dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
++ name, icount);
++ ret = icount;
++ goto free_microvolt;
++ }
+
+- return 0;
++ if (icount != supplies) {
++ dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
++ __func__, name, icount, supplies);
++ ret = -EINVAL;
++ goto free_microvolt;
++ }
++
++ microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
++ if (!microamp) {
++ ret = -EINVAL;
++ goto free_microvolt;
++ }
++
++ ret = of_property_read_u32_array(opp->np, name, microamp,
++ icount);
++ if (ret) {
++ dev_err(dev, "%s: error parsing %s: %d\n", __func__,
++ name, ret);
++ ret = -EINVAL;
++ goto free_microamp;
++ }
++ }
++
++ for (i = 0, j = 0; i < supplies; i++) {
++ opp->supplies[i].u_volt = microvolt[j++];
++
++ if (vcount == supplies) {
++ opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
++ opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
++ } else {
++ opp->supplies[i].u_volt_min = microvolt[j++];
++ opp->supplies[i].u_volt_max = microvolt[j++];
++ }
++
++ if (microamp)
++ opp->supplies[i].u_amp = microamp[i];
++ }
++
++free_microamp:
++ kfree(microamp);
++free_microvolt:
++ kfree(microvolt);
++
++ return ret;
+ }
+
+ /**
+@@ -198,7 +243,7 @@ void dev_pm_opp_of_remove_table(struct device *dev)
+ EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
+
+ /* Returns opp descriptor node for a device, caller must do of_node_put() */
+-struct device_node *_of_get_opp_desc_node(struct device *dev)
++struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
+ {
+ /*
+ * TODO: Support for multiple OPP tables.
+@@ -209,6 +254,7 @@ struct device_node *_of_get_opp_desc_node(struct device *dev)
+
+ return of_parse_phandle(dev->of_node, "operating-points-v2", 0);
+ }
++EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
+
+ /**
+ * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
+@@ -303,9 +349,9 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
+ mutex_unlock(&opp_table_lock);
+
+ pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
+- __func__, new_opp->turbo, new_opp->rate, new_opp->u_volt,
+- new_opp->u_volt_min, new_opp->u_volt_max,
+- new_opp->clock_latency_ns);
++ __func__, new_opp->turbo, new_opp->rate,
++ new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
++ new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns);
+
+ /*
+ * Notify the changes in the availability of the operable
+@@ -450,7 +496,7 @@ int dev_pm_opp_of_add_table(struct device *dev)
+ * OPPs have two version of bindings now. The older one is deprecated,
+ * try for the new binding first.
+ */
+- opp_np = _of_get_opp_desc_node(dev);
++ opp_np = dev_pm_opp_of_get_opp_desc_node(dev);
+ if (!opp_np) {
+ /*
+ * Try old-deprecated bindings for backward compatibility with
+@@ -560,7 +606,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
+ int cpu, ret = 0;
+
+ /* Get OPP descriptor node */
+- np = _of_get_opp_desc_node(cpu_dev);
++ np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
+ if (!np) {
+ dev_dbg(cpu_dev, "%s: Couldn't find cpu_dev node.\n", __func__);
+ return -ENOENT;
+@@ -585,7 +631,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
+ }
+
+ /* Get OPP descriptor node */
+- tmp_np = _of_get_opp_desc_node(tcpu_dev);
++ tmp_np = dev_pm_opp_of_get_opp_desc_node(tcpu_dev);
+ if (!tmp_np) {
+ dev_err(tcpu_dev, "%s: Couldn't find tcpu_dev node.\n",
+ __func__);
+diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
+index fabd5ca..af9f2b8 100644
+--- a/drivers/base/power/opp/opp.h
++++ b/drivers/base/power/opp/opp.h
+@@ -61,10 +61,7 @@ extern struct list_head opp_tables;
+ * @turbo: true if turbo (boost) OPP
+ * @suspend: true if suspend OPP
+ * @rate: Frequency in hertz
+- * @u_volt: Target voltage in microvolts corresponding to this OPP
+- * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
+- * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
+- * @u_amp: Maximum current drawn by the device in microamperes
++ * @supplies: Power supplies voltage/current values
+ * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
+ * frequency from any other OPP's frequency.
+ * @opp_table: points back to the opp_table struct this opp belongs to
+@@ -83,10 +80,8 @@ struct dev_pm_opp {
+ bool suspend;
+ unsigned long rate;
+
+- unsigned long u_volt;
+- unsigned long u_volt_min;
+- unsigned long u_volt_max;
+- unsigned long u_amp;
++ struct dev_pm_opp_supply *supplies;
++
+ unsigned long clock_latency_ns;
+
+ struct opp_table *opp_table;
+@@ -144,7 +139,10 @@ enum opp_table_access {
+ * @supported_hw_count: Number of elements in supported_hw array.
+ * @prop_name: A name to postfix to many DT properties, while parsing them.
+ * @clk: Device's clock handle
+- * @regulator: Supply regulator
++ * @regulators: Supply regulators
++ * @regulator_count: Number of power supply regulators
++ * @set_opp: Platform specific set_opp callback
++ * @set_opp_data: Data to be passed to set_opp callback
+ * @dentry: debugfs dentry pointer of the real device directory (not links).
+ * @dentry_name: Name of the real dentry.
+ *
+@@ -179,7 +177,11 @@ struct opp_table {
+ unsigned int supported_hw_count;
+ const char *prop_name;
+ struct clk *clk;
+- struct regulator *regulator;
++ struct regulator **regulators;
++ unsigned int regulator_count;
++
++ int (*set_opp)(struct dev_pm_set_opp_data *data);
++ struct dev_pm_set_opp_data *set_opp_data;
+
+ #ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+@@ -190,7 +192,6 @@ struct opp_table {
+ /* Routines internal to opp core */
+ struct opp_table *_find_opp_table(struct device *dev);
+ struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
+-struct device_node *_of_get_opp_desc_node(struct device *dev);
+ void _dev_pm_opp_remove_table(struct device *dev, bool remove_all);
+ struct dev_pm_opp *_allocate_opp(struct device *dev, struct opp_table **opp_table);
+ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
+diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
+index 7875105..bbd5afd 100644
+--- a/drivers/bus/Kconfig
++++ b/drivers/bus/Kconfig
+@@ -120,7 +120,6 @@ config QCOM_EBI2
+ config SIMPLE_PM_BUS
+ bool "Simple Power-Managed Bus Driver"
+ depends on OF && PM
+- depends on ARCH_RENESAS || COMPILE_TEST
+ help
+ Driver for transparent busses that don't need a real driver, but
+ where the bus controller is part of a PM domain, or under the control
+diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
+index bc3917d..a7b3795 100644
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -234,6 +234,17 @@ config ARM_TEGRA124_CPUFREQ
+ help
+ This adds the CPUFreq driver support for Tegra124 SOCs.
+
++config ARM_TI_CPUFREQ
++ bool "Texas Instruments CPUFreq support"
++ depends on ARCH_OMAP2PLUS
++ help
++ This driver enables valid OPPs on the running platform based on
++ values contained within the SoC in use. Enable this in order to
++ use the cpufreq-dt driver on all Texas Instruments platforms that
++ provide dt based operating-points-v2 tables with opp-supported-hw
++ data provided. Required for cpufreq support on AM335x, AM437x,
++ DRA7x, and AM57x platforms.
++
+ config ARM_PXA2xx_CPUFREQ
+ tristate "Intel PXA2xx CPUfreq driver"
+ depends on PXA27x || PXA25x
+diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
+index 0a9b6a0..5b1b6ec 100644
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
+ obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o
+ obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
+ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
++obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o
+ obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
+ obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
+ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
+diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
+index 7126762..d2637e1 100644
+--- a/drivers/cpufreq/cpufreq-dt-platdev.c
++++ b/drivers/cpufreq/cpufreq-dt-platdev.c
+@@ -72,8 +72,6 @@ static const struct of_device_id machines[] __initconst = {
+
+ { .compatible = "sigma,tango4" },
+
+- { .compatible = "ti,am33xx", },
+- { .compatible = "ti,dra7", },
+ { .compatible = "ti,omap2", },
+ { .compatible = "ti,omap3", },
+ { .compatible = "ti,omap4", },
+diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
+index 4d3ec92..15cb261 100644
+--- a/drivers/cpufreq/cpufreq-dt.c
++++ b/drivers/cpufreq/cpufreq-dt.c
+@@ -28,7 +28,6 @@
+ #include "cpufreq-dt.h"
+
+ struct private_data {
+- struct opp_table *opp_table;
+ struct device *cpu_dev;
+ struct thermal_cooling_device *cdev;
+ const char *reg_name;
+@@ -144,7 +143,6 @@ static int resources_available(void)
+ static int cpufreq_init(struct cpufreq_policy *policy)
+ {
+ struct cpufreq_frequency_table *freq_table;
+- struct opp_table *opp_table = NULL;
+ struct private_data *priv;
+ struct device *cpu_dev;
+ struct clk *cpu_clk;
+@@ -188,9 +186,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)
+ */
+ name = find_supply_name(cpu_dev);
+ if (name) {
+- opp_table = dev_pm_opp_set_regulator(cpu_dev, name);
+- if (IS_ERR(opp_table)) {
+- ret = PTR_ERR(opp_table);
++ const char *names[] = {name};
++
++ ret = dev_pm_opp_set_regulators(cpu_dev, names,
++ ARRAY_SIZE(names));
++ if (ret) {
+ dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
+ policy->cpu, ret);
+ goto out_put_clk;
+@@ -240,7 +240,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
+ }
+
+ priv->reg_name = name;
+- priv->opp_table = opp_table;
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+@@ -289,7 +288,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
+ out_free_opp:
+ dev_pm_opp_of_cpumask_remove_table(policy->cpus);
+ if (name)
+- dev_pm_opp_put_regulator(opp_table);
++ dev_pm_opp_put_regulators(cpu_dev);
+ out_put_clk:
+ clk_put(cpu_clk);
+
+@@ -304,7 +303,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
+ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+ if (priv->reg_name)
+- dev_pm_opp_put_regulator(priv->opp_table);
++ dev_pm_opp_put_regulators(priv->cpu_dev);
+
+ clk_put(policy->clk);
+ kfree(priv);
+diff --git b/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
+new file mode 100644
+index 0000000..afbaef9
+--- /dev/null
++++ b/drivers/cpufreq/ti-cpufreq.c
+@@ -0,0 +1,288 @@
++/*
++ * TI CPUFreq/OPP hw-supported driver
++ *
++ * Copyright (C) 2016 Texas Instruments, Inc.
++ * Dave Gerlach <d-gerlach@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/cpu.h>
++#include <linux/io.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/pm_opp.h>
++#include <linux/regmap.h>
++#include <linux/slab.h>
++
++#define REVISION_MASK 0xF
++#define REVISION_SHIFT 28
++
++#define AM33XX_800M_ARM_MPU_MAX_FREQ 0x1E2F
++#define AM43XX_600M_ARM_MPU_MAX_FREQ 0xFFA
++
++#define DRA7_EFUSE_HAS_OD_MPU_OPP 11
++#define DRA7_EFUSE_HAS_HIGH_MPU_OPP 15
++#define DRA7_EFUSE_HAS_ALL_MPU_OPP 23
++
++#define DRA7_EFUSE_NOM_MPU_OPP BIT(0)
++#define DRA7_EFUSE_OD_MPU_OPP BIT(1)
++#define DRA7_EFUSE_HIGH_MPU_OPP BIT(2)
++
++#define VERSION_COUNT 2
++
++struct ti_cpufreq_data;
++
++struct ti_cpufreq_soc_data {
++ unsigned long (*efuse_xlate)(struct ti_cpufreq_data *opp_data,
++ unsigned long efuse);
++ unsigned long efuse_fallback;
++};
++
++struct ti_cpufreq_data {
++ struct device *cpu_dev;
++ struct device_node *opp_node;
++ struct regmap *opp_efuse;
++ struct regmap *revision;
++ const struct ti_cpufreq_soc_data *soc_data;
++};
++
++static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
++ unsigned long efuse)
++{
++ if (!efuse)
++ efuse = opp_data->soc_data->efuse_fallback;
++ /* AM335x and AM437x use "OPP disable" bits, so invert */
++ return ~efuse;
++}
++
++static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data,
++ unsigned long efuse)
++{
++ unsigned long calculated_efuse = DRA7_EFUSE_NOM_MPU_OPP;
++
++ /*
++ * The efuse on dra7 and am57 parts contains a specific
++ * value indicating the highest available OPP.
++ */
++
++ switch (efuse) {
++ case DRA7_EFUSE_HAS_ALL_MPU_OPP:
++ case DRA7_EFUSE_HAS_HIGH_MPU_OPP:
++ calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP;
++ case DRA7_EFUSE_HAS_OD_MPU_OPP:
++ calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP;
++ }
++
++ return calculated_efuse;
++}
++
++static struct ti_cpufreq_soc_data am3x_soc_data = {
++ .efuse_xlate = amx3_efuse_xlate,
++ .efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ,
++};
++
++static struct ti_cpufreq_soc_data am4x_soc_data = {
++ .efuse_xlate = amx3_efuse_xlate,
++ .efuse_fallback = AM43XX_600M_ARM_MPU_MAX_FREQ,
++};
++
++static struct ti_cpufreq_soc_data dra7_soc_data = {
++ .efuse_xlate = dra7_efuse_xlate,
++};
++
++/**
++ * ti_cpufreq_get_efuse() - Parse and return efuse value present on SoC
++ * @opp_data: pointer to ti_cpufreq_data context
++ * @efuse_value: Set to the value parsed from efuse
++ *
++ * Returns error code if efuse not read properly.
++ */
++static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data,
++ u32 *efuse_value)
++{
++ struct device *dev = opp_data->cpu_dev;
++ struct device_node *np = opp_data->opp_node;
++ unsigned int efuse_offset;
++ u32 efuse, efuse_mask, efuse_shift, vals[4];
++ int ret;
++
++ ret = of_property_read_u32_array(np, "ti,syscon-efuse", vals, 4);
++ if (ret) {
++ dev_err(dev, "ti,syscon-efuse cannot be read %s: %d\n",
++ np->full_name, ret);
++ return ret;
++ }
++
++ efuse_offset = vals[1];
++ efuse_mask = vals[2];
++ efuse_shift = vals[3];
++
++ ret = regmap_read(opp_data->opp_efuse, efuse_offset, &efuse);
++ if (ret) {
++ dev_err(dev,
++ "Failed to read the efuse value from syscon: %d\n",
++ ret);
++ return ret;
++ }
++
++ efuse = (efuse & efuse_mask) >> efuse_shift;
++
++ *efuse_value = opp_data->soc_data->efuse_xlate(opp_data, efuse);
++
++ return 0;
++}
++
++/**
++ * ti_cpufreq_get_rev() - Parse and return rev value present on SoC
++ * @opp_data: pointer to ti_cpufreq_data context
++ * @revision_value: Set to the value parsed from revision register
++ *
++ * Returns error code if revision not read properly.
++ */
++static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
++ u32 *revision_value)
++{
++ struct device *dev = opp_data->cpu_dev;
++ struct device_node *np = opp_data->opp_node;
++ unsigned int revision_offset;
++ u32 revision;
++ int ret;
++
++ ret = of_property_read_u32_index(np, "ti,syscon-rev",
++ 1, &revision_offset);
++ if (ret) {
++ dev_err(dev,
++ "No revision offset provided %s [%d]\n",
++ np->full_name, ret);
++ return ret;
++ }
++
++ ret = regmap_read(opp_data->revision, revision_offset, &revision);
++ if (ret) {
++ dev_err(dev,
++ "Failed to read the revision number from syscon: %d\n",
++ ret);
++ return ret;
++ }
++
++ *revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK);
++
++ return 0;
++}
++
++static int ti_cpufreq_setup_syscon_registers(struct ti_cpufreq_data *opp_data)
++{
++ struct device *dev = opp_data->cpu_dev;
++ struct device_node *np = opp_data->opp_node;
++
++ opp_data->opp_efuse = syscon_regmap_lookup_by_phandle(np,
++ "ti,syscon-efuse");
++ if (IS_ERR(opp_data->opp_efuse)) {
++ dev_err(dev,
++ "\"ti,syscon-efuse\" is missing, cannot use OPPv2 table.\n");
++ return PTR_ERR(opp_data->opp_efuse);
++ }
++
++ opp_data->revision = syscon_regmap_lookup_by_phandle(np,
++ "ti,syscon-rev");
++ if (IS_ERR(opp_data->revision)) {
++ dev_err(dev,
++ "\"ti,syscon-rev\" is missing, cannot use OPPv2 table.\n");
++ return PTR_ERR(opp_data->revision);
++ }
++
++ return 0;
++}
++
++static const struct of_device_id ti_cpufreq_of_match[] = {
++ { .compatible = "ti,am33xx", .data = &am3x_soc_data, },
++ { .compatible = "ti,am4372", .data = &am4x_soc_data, },
++ { .compatible = "ti,dra7", .data = &dra7_soc_data },
++ {},
++};
++
++static int ti_cpufreq_init(void)
++{
++ u32 version[VERSION_COUNT];
++ struct device_node *np;
++ const struct of_device_id *match;
++ struct ti_cpufreq_data *opp_data;
++ int ret;
++
++ np = of_find_node_by_path("/");
++ match = of_match_node(ti_cpufreq_of_match, np);
++ if (!match)
++ return -ENODEV;
++
++ opp_data = kzalloc(sizeof(*opp_data), GFP_KERNEL);
++ if (!opp_data)
++ return -ENOMEM;
++
++ opp_data->soc_data = match->data;
++
++ opp_data->cpu_dev = get_cpu_device(0);
++ if (!opp_data->cpu_dev) {
++ pr_err("%s: Failed to get device for CPU0\n", __func__);
++ return -ENODEV;
++ }
++
++ opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev);
++ if (!opp_data->opp_node) {
++ dev_info(opp_data->cpu_dev,
++ "OPP-v2 not supported, cpufreq-dt will attempt to use legacy tables.\n");
++ goto register_cpufreq_dt;
++ }
++
++ ret = ti_cpufreq_setup_syscon_registers(opp_data);
++ if (ret)
++ goto fail_put_node;
++
++ /*
++ * OPPs determine whether or not they are supported based on
++ * two metrics:
++ * 0 - SoC Revision
++ * 1 - eFuse value
++ */
++ ret = ti_cpufreq_get_rev(opp_data, &version[0]);
++ if (ret)
++ goto fail_put_node;
++
++ ret = ti_cpufreq_get_efuse(opp_data, &version[1]);
++ if (ret)
++ goto fail_put_node;
++
++ of_node_put(opp_data->opp_node);
++
++ ret = dev_pm_opp_set_supported_hw(opp_data->cpu_dev, version,
++ VERSION_COUNT);
++ if (ret) {
++ dev_err(opp_data->cpu_dev,
++ "Failed to set supported hardware\n");
++ goto fail_put_node;
++ }
++
++register_cpufreq_dt:
++ platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
++
++ return 0;
++
++fail_put_node:
++ of_node_put(opp_data->opp_node);
++
++ return ret;
++}
++module_init(ti_cpufreq_init);
++
++MODULE_DESCRIPTION("TI CPUFreq/OPP hw-supported driver");
++MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index ed37e59..a118ef6 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -61,6 +61,20 @@ config GPIO_SYSFS
+ Kernel drivers may also request that a particular GPIO be
+ exported to userspace; this can be useful when debugging.
+
++config GPIO_OF_HELPER
++ bool "GPIO OF helper device (EXPERIMENTAL)"
++ depends on OF_GPIO
++ help
++ Say Y here to add an GPIO OF helper driver
++
++ Allows you specify a GPIO helper based on OF
++ which allows simple export of GPIO functionality
++ in user-space.
++
++ Features include, value set/get, direction control,
++ interrupt/value change poll support, event counting
++ and others.
++
+ config GPIO_GENERIC
+ depends on HAS_IOMEM # Only for IOMEM drivers
+ tristate
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index d074c22..e4e13b8 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
+ obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+ obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
+ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
++obj-$(CONFIG_GPIO_OF_HELPER) += gpio-of-helper.o
+
+ # Device drivers. Generally keep list sorted alphabetically
+ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
+diff --git b/drivers/gpio/gpio-of-helper.c b/drivers/gpio/gpio-of-helper.c
+new file mode 100644
+index 0000000..83f362f
+--- /dev/null
++++ b/drivers/gpio/gpio-of-helper.c
+@@ -0,0 +1,435 @@
++/*
++ * GPIO OF based helper
++ *
++ * A simple DT based driver to provide access to GPIO functionality
++ * to user-space via sysfs.
++ *
++ * Copyright (C) 2013 Pantelis Antoniou <panto@antoniou-consulting.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/err.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/pinmux.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/atomic.h>
++#include <linux/clk.h>
++#include <linux/interrupt.h>
++#include <linux/math64.h>
++#include <linux/atomic.h>
++#include <linux/idr.h>
++
++/* fwd decl. */
++struct gpio_of_helper_info;
++
++enum gpio_type {
++ GPIO_TYPE_INPUT = 0,
++ GPIO_TYPE_OUTPUT = 1,
++};
++
++struct gpio_of_entry {
++ int id;
++ struct gpio_of_helper_info *info;
++ struct device_node *node;
++ enum gpio_type type;
++ int gpio;
++ int irq;
++ const char *name;
++ atomic64_t counter;
++ unsigned int count_flags;
++#define COUNT_RISING_EDGE (1 << 0)
++#define COUNT_FALLING_EDGE (1 << 1)
++};
++
++struct gpio_of_helper_info {
++ struct platform_device *pdev;
++ struct idr idr;
++};
++
++static const struct of_device_id gpio_of_helper_of_match[] = {
++ {
++ .compatible = "gpio-of-helper",
++ },
++ { },
++};
++MODULE_DEVICE_TABLE(of, gpio_of_helper_of_match);
++
++static ssize_t gpio_of_helper_show_status(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct gpio_of_helper_info *info = platform_get_drvdata(pdev);
++ struct gpio_of_entry *entry;
++ char *p, *e;
++ int id, n;
++
++ p = buf;
++ e = p + PAGE_SIZE;
++ n = 0;
++ idr_for_each_entry(&info->idr, entry, id) {
++ switch (entry->type) {
++ case GPIO_TYPE_INPUT:
++ n = snprintf(p, e - p, "%2d %-24s %3d %-3s %llu\n",
++ entry->id, entry->name, entry->gpio, "IN",
++ (unsigned long long)
++ atomic64_read(&entry->counter));
++ break;
++ case GPIO_TYPE_OUTPUT:
++ n = snprintf(p, e - p, "%2d %-24s %3d %-3s\n",
++ entry->id, entry->name, entry->gpio, "OUT");
++ break;
++ }
++ p += n;
++ }
++
++ return p - buf;
++}
++
++static DEVICE_ATTR(status, S_IRUGO,
++ gpio_of_helper_show_status, NULL);
++
++static irqreturn_t gpio_of_helper_handler(int irq, void *ptr)
++{
++ struct gpio_of_entry *entry = ptr;
++
++ /* caution - low speed interfaces only! */
++ atomic64_inc(&entry->counter);
++
++ return IRQ_HANDLED;
++}
++
++static struct gpio_of_entry *
++gpio_of_entry_create(struct gpio_of_helper_info *info,
++ struct device_node *node)
++{
++ struct platform_device *pdev = info->pdev;
++ struct device *dev = &pdev->dev;
++ struct gpio_of_entry *entry;
++ int err, gpio, irq;
++ unsigned int req_flags, count_flags, irq_flags;
++ enum gpio_type type;
++ enum of_gpio_flags gpio_flags;
++ const char *name;
++
++ /* get the type of the node first */
++ if (of_property_read_bool(node, "input"))
++ type = GPIO_TYPE_INPUT;
++ else if (of_property_read_bool(node, "output")
++ || of_property_read_bool(node, "init-low")
++ || of_property_read_bool(node, "init-high"))
++ type = GPIO_TYPE_OUTPUT;
++ else {
++ dev_err(dev, "Not valid gpio node type\n");
++ err = -EINVAL;
++ goto err_bad_node;
++ }
++
++ /* get the name */
++ if (of_property_read_string(node, "line-name", &name))
++ if (of_property_read_string(node, "gpio-name", &name))
++ name = node->name;
++
++ err = of_get_named_gpio_flags(node, "gpio", 0, &gpio_flags);
++ if (IS_ERR_VALUE(err)) {
++ dev_err(dev, "Failed to get gpio property of '%s'\n", name);
++ goto err_bad_node;
++ }
++ gpio = err;
++
++ req_flags = 0;
++ count_flags = 0;
++
++ /* set the request flags */
++ switch (type) {
++ case GPIO_TYPE_INPUT:
++ req_flags = GPIOF_DIR_IN | GPIOF_EXPORT;
++ if (of_property_read_bool(node, "count-falling-edge"))
++ count_flags |= COUNT_FALLING_EDGE;
++ if (of_property_read_bool(node, "count-rising-edge"))
++ count_flags |= COUNT_RISING_EDGE;
++ break;
++ case GPIO_TYPE_OUTPUT:
++ req_flags = GPIOF_DIR_OUT | GPIOF_EXPORT;
++ if (of_property_read_bool(node, "init-high"))
++ req_flags |= GPIOF_OUT_INIT_HIGH;
++ else if (of_property_read_bool(node, "init-low"))
++ req_flags |= GPIOF_OUT_INIT_LOW;
++ break;
++ }
++ if (of_property_read_bool(node, "dir-changeable"))
++ req_flags |= GPIOF_EXPORT_CHANGEABLE;
++ if (gpio_flags & OF_GPIO_ACTIVE_LOW)
++ req_flags |= GPIOF_ACTIVE_LOW;
++ if (gpio_flags & OF_GPIO_SINGLE_ENDED) {
++ if (gpio_flags & OF_GPIO_ACTIVE_LOW)
++ req_flags |= GPIOF_OPEN_DRAIN;
++ else
++ req_flags |= GPIOF_OPEN_SOURCE;
++ }
++
++ /* request the gpio */
++ err = devm_gpio_request_one(dev, gpio, req_flags, name);
++ if (err != 0) {
++ dev_err(dev, "Failed to request gpio '%s'\n", name);
++ goto err_bad_node;
++ }
++
++ irq = -1;
++ irq_flags = 0;
++
++ /* counter mode requested - need an interrupt */
++ if (count_flags != 0) {
++ irq = gpio_to_irq(gpio);
++ if (IS_ERR_VALUE(irq)) {
++ dev_err(dev, "Failed to request gpio '%s'\n", name);
++ goto err_bad_node;
++ }
++
++ if (count_flags & COUNT_RISING_EDGE)
++ irq_flags |= IRQF_TRIGGER_RISING;
++ if (count_flags & COUNT_FALLING_EDGE)
++ irq_flags |= IRQF_TRIGGER_FALLING;
++ }
++
++// if (!idr_pre_get(&info->idr, GFP_KERNEL)) {
++// dev_err(dev, "Failed on idr_pre_get of '%s'\n", name);
++// err = -ENOMEM;
++// goto err_no_mem;
++// }
++
++ idr_preload(GFP_KERNEL);
++
++ entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
++ if (entry == NULL) {
++ dev_err(dev, "Failed to allocate gpio entry of '%s'\n", name);
++ err = -ENOMEM;
++ goto err_no_mem;
++ }
++
++ entry->id = -1;
++ entry->info = info;
++ entry->node = of_node_get(node); /* get node reference */
++ entry->type = type;
++ entry->gpio = gpio;
++ entry->irq = irq;
++ entry->name = name;
++
++ /* interrupt enable is last thing done */
++ if (irq >= 0) {
++ atomic64_set(&entry->counter, 0);
++ entry->count_flags = count_flags;
++ err = devm_request_irq(dev, irq, gpio_of_helper_handler,
++ irq_flags, name, entry);
++ if (err != 0) {
++ dev_err(dev, "Failed to request irq of '%s'\n", name);
++ goto err_no_irq;
++ }
++ }
++
++ /* all done; insert */
++// err = idr_get_new(&info->idr, entry, &entry->id);
++// if (IS_ERR_VALUE(err)) {
++// dev_err(dev, "Failed to idr_get_new of '%s'\n", name);
++// goto err_fail_idr;
++// }
++
++ err = idr_alloc(&info->idr, entry, 0, 0, GFP_NOWAIT);
++ if (err >= 0)
++ entry->id = err;
++
++ idr_preload_end();
++
++ if (err < 0) {
++ dev_err(dev, "Failed to idr_get_new of '%s'\n", name);
++ goto err_fail_idr;
++ }
++
++ dev_dbg(dev, "Allocated GPIO id=%d name='%s'\n", entry->id, name);
++
++ return entry;
++
++err_fail_idr:
++ /* nothing to do */
++err_no_irq:
++ /* release node ref */
++ of_node_put(node);
++ /* nothing else needs to be done, devres handles it */
++err_no_mem:
++err_bad_node:
++ return ERR_PTR(err);
++}
++
++static int gpio_of_entry_destroy(struct gpio_of_entry *entry)
++{
++ struct gpio_of_helper_info *info = entry->info;
++ struct platform_device *pdev = info->pdev;
++ struct device *dev = &pdev->dev;
++
++ dev_dbg(dev, "Destroying GPIO id=%d\n", entry->id);
++
++ /* remove from the IDR */
++ idr_remove(&info->idr, entry->id);
++
++ /* remove node ref */
++ of_node_put(entry->node);
++
++ /* free gpio */
++ devm_gpio_free(dev, entry->gpio);
++
++ /* gree irq */
++ if (entry->irq >= 0)
++ devm_free_irq(dev, entry->irq, entry);
++
++ /* and free */
++ devm_kfree(dev, entry);
++
++ return 0;
++}
++
++static int gpio_of_helper_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct gpio_of_helper_info *info;
++ struct gpio_of_entry *entry;
++ struct device_node *pnode = pdev->dev.of_node;
++ struct device_node *cnode;
++ struct pinctrl *pinctrl;
++ int err;
++
++ /* we only support OF */
++ if (pnode == NULL) {
++ dev_err(&pdev->dev, "No platform of_node!\n");
++ return -ENODEV;
++ }
++
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ /* special handling for probe defer */
++ if (PTR_ERR(pinctrl) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++
++ dev_warn(&pdev->dev,
++ "pins are not configured from the driver\n");
++ }
++
++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++ if (info == NULL) {
++ dev_err(&pdev->dev, "Failed to allocate info\n");
++ err = -ENOMEM;
++ goto err_no_mem;
++ }
++ platform_set_drvdata(pdev, info);
++ info->pdev = pdev;
++
++ idr_init(&info->idr);
++
++ err = device_create_file(dev, &dev_attr_status);
++ if (err != 0) {
++ dev_err(dev, "Failed to create status sysfs attribute\n");
++ goto err_no_sysfs;
++ }
++
++ for_each_child_of_node(pnode, cnode) {
++
++ entry = gpio_of_entry_create(info, cnode);
++ if (IS_ERR_OR_NULL(entry)) {
++ dev_err(dev, "Failed to create gpio entry\n");
++ err = PTR_ERR(entry);
++ goto err_fail_entry;
++ }
++ }
++
++ dev_info(&pdev->dev, "ready\n");
++
++ return 0;
++err_fail_entry:
++ device_remove_file(&pdev->dev, &dev_attr_status);
++err_no_sysfs:
++err_no_mem:
++ return err;
++}
++
++static int gpio_of_helper_remove(struct platform_device *pdev)
++{
++ struct gpio_of_helper_info *info = platform_get_drvdata(pdev);
++ struct gpio_of_entry *entry;
++ int id;
++
++ dev_info(&pdev->dev, "removing\n");
++
++ device_remove_file(&pdev->dev, &dev_attr_status);
++
++ id = 0;
++ idr_for_each_entry(&info->idr, entry, id) {
++ /* destroy each and every one */
++ gpio_of_entry_destroy(entry);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++//#ifdef CONFIG_PM_RUNTIME
++static int gpio_of_helper_runtime_suspend(struct device *dev)
++{
++ /* place holder */
++ return 0;
++}
++
++static int gpio_of_helper_runtime_resume(struct device *dev)
++{
++ /* place holder */
++ return 0;
++}
++//#endif /* CONFIG_PM_RUNTIME */
++
++static struct dev_pm_ops gpio_of_helper_pm_ops = {
++ SET_RUNTIME_PM_OPS(gpio_of_helper_runtime_suspend,
++ gpio_of_helper_runtime_resume, NULL)
++};
++#define GPIO_OF_HELPER_PM_OPS (&gpio_of_helper_pm_ops)
++#else
++#define GPIO_OF_HELPER_PM_OPS NULL
++#endif /* CONFIG_PM */
++
++struct platform_driver gpio_of_helper_driver = {
++ .probe = gpio_of_helper_probe,
++ .remove = gpio_of_helper_remove,
++ .driver = {
++ .name = "gpio-of-helper",
++ .owner = THIS_MODULE,
++ .pm = GPIO_OF_HELPER_PM_OPS,
++ .of_match_table = gpio_of_helper_of_match,
++ },
++};
++
++module_platform_driver(gpio_of_helper_driver);
++
++MODULE_AUTHOR("Pantelis Antoniou <panto@antoniou-consulting.com>");
++MODULE_DESCRIPTION("GPIO OF Helper driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:gpio-of-helper");
+diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
+index 4b44dd9..9c6de28 100644
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -35,10 +35,10 @@ static DEFINE_MUTEX(sysfs_lock);
+ /*
+ * /sys/class/gpio/gpioN... only for GPIOs that are exported
+ * /direction
+- * * MAY BE OMITTED if kernel won't allow direction changes
+ * * is read/write as "in" or "out"
+ * * may also be written as "high" or "low", initializing
+ * output value as specified ("out" implies "low")
++ * * read-only if kernel won't allow direction changes
+ * /value
+ * * always readable, subject to hardware behavior
+ * * may be writable, as zero/nonzero
+@@ -51,6 +51,8 @@ static DEFINE_MUTEX(sysfs_lock);
+ * * is read/write as zero/nonzero
+ * * also affects existing and subsequent "falling" and "rising"
+ * /edge configuration
++ * /label
++ * * descriptor label
+ */
+
+ static ssize_t direction_show(struct device *dev,
+@@ -81,7 +83,9 @@ static ssize_t direction_store(struct device *dev,
+
+ mutex_lock(&data->mutex);
+
+- if (sysfs_streq(buf, "high"))
++ if (!data->direction_can_change)
++ status = -EPERM;
++ else if (sysfs_streq(buf, "high"))
+ status = gpiod_direction_output_raw(desc, 1);
+ else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
+ status = gpiod_direction_output_raw(desc, 0);
+@@ -350,6 +354,23 @@ static ssize_t active_low_store(struct device *dev,
+ }
+ static DEVICE_ATTR_RW(active_low);
+
++static ssize_t label_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct gpiod_data *data = dev_get_drvdata(dev);
++ struct gpio_desc *desc = data->desc;
++ ssize_t status;
++
++ mutex_lock(&data->mutex);
++
++ status = sprintf(buf, "%s\n", desc->label);
++
++ mutex_unlock(&data->mutex);
++
++ return status;
++}
++static DEVICE_ATTR_RO(label);
++
+ static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
+ int n)
+ {
+@@ -361,12 +382,15 @@ static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
+
+ if (attr == &dev_attr_direction.attr) {
+ if (!show_direction)
+- mode = 0;
++ mode &= 0444;
+ } else if (attr == &dev_attr_edge.attr) {
+ if (gpiod_to_irq(desc) < 0)
+ mode = 0;
+ if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
+ mode = 0;
++ } else if (attr == &dev_attr_value.attr) {
++ if (!show_direction && !test_bit(FLAG_IS_OUT, &desc->flags))
++ mode &= 0444;
+ }
+
+ return mode;
+@@ -377,6 +401,7 @@ static struct attribute *gpio_attrs[] = {
+ &dev_attr_edge.attr,
+ &dev_attr_value.attr,
+ &dev_attr_active_low.attr,
++ &dev_attr_label.attr,
+ NULL,
+ };
+
+@@ -390,6 +415,10 @@ static const struct attribute_group *gpio_groups[] = {
+ NULL
+ };
+
++/* bwlegh, a second device in the same file... get out of my namespace! */
++#define dev_attr_label dev_attr_chip_label
++#define label_show chip_label_show
++
+ /*
+ * /sys/class/gpio/gpiochipN/
+ * /base ... matching gpio_chip.base (N)
+diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig
+index 2cde7a5..b776f41 100644
+--- a/drivers/gpu/drm/etnaviv/Kconfig
++++ b/drivers/gpu/drm/etnaviv/Kconfig
+@@ -2,7 +2,7 @@
+ config DRM_ETNAVIV
+ tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
+ depends on DRM
+- depends on ARCH_MXC || ARCH_DOVE
++ depends on ARCH_MXC || ARCH_DOVE || ARCH_OMAP2PLUS
+ select SHMEM
+ select TMPFS
+ select IOMMU_API
+diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+index aa68766..20d20ca 100644
+--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
++++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+@@ -654,6 +654,7 @@ static int etnaviv_pdev_remove(struct platform_device *pdev)
+ static const struct of_device_id dt_match[] = {
+ { .compatible = "fsl,imx-gpu-subsystem" },
+ { .compatible = "marvell,dove-gpu-subsystem" },
++ { .compatible = "vivante,gc-gpu-subsystem"},
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, dt_match);
+diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
+index a6c92be..66ff8e3 100644
+--- a/drivers/gpu/drm/i2c/Kconfig
++++ b/drivers/gpu/drm/i2c/Kconfig
+@@ -1,6 +1,12 @@
+ menu "I2C encoder or helper chips"
+ depends on DRM && DRM_KMS_HELPER && I2C
+
++config DRM_I2C_ADIHDMI
++ tristate "ADI HDMI encoder"
++ default m if DRM_TILCDC
++ help
++ Support for ADI HDMI encoder.
++
+ config DRM_I2C_CH7006
+ tristate "Chrontel ch7006 TV encoder"
+ default m if DRM_NOUVEAU
+diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
+index 43aa33b..62a4eea 100644
+--- a/drivers/gpu/drm/i2c/Makefile
++++ b/drivers/gpu/drm/i2c/Makefile
+@@ -8,3 +8,6 @@ obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
+
+ tda998x-y := tda998x_drv.o
+ obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o
++
++adihdmi-y := adihdmi_drv.o
++obj-$(CONFIG_DRM_I2C_ADIHDMI) += adihdmi.o
+diff --git b/drivers/gpu/drm/i2c/adihdmi.h b/drivers/gpu/drm/i2c/adihdmi.h
+new file mode 100644
+index 0000000..58d9a2b
+--- /dev/null
++++ b/drivers/gpu/drm/i2c/adihdmi.h
+@@ -0,0 +1,289 @@
++/*
++ * Analog Devices ADIHDMI HDMI transmitter driver
++ *
++ * Copyright 2012 Analog Devices Inc.
++ *
++ * Licensed under the GPL-2.
++ */
++
++#ifndef __DRM_I2C_ADIHDMI_H__
++#define __DRM_I2C_ADIHDMI_H__
++
++#include <linux/hdmi.h>
++
++#define ADIHDMI_REG_CHIP_REVISION 0x00
++#define ADIHDMI_REG_N0 0x01
++#define ADIHDMI_REG_N1 0x02
++#define ADIHDMI_REG_N2 0x03
++#define ADIHDMI_REG_SPDIF_FREQ 0x04
++#define ADIHDMI_REG_CTS_AUTOMATIC1 0x05
++#define ADIHDMI_REG_CTS_AUTOMATIC2 0x06
++#define ADIHDMI_REG_CTS_MANUAL0 0x07
++#define ADIHDMI_REG_CTS_MANUAL1 0x08
++#define ADIHDMI_REG_CTS_MANUAL2 0x09
++#define ADIHDMI_REG_AUDIO_SOURCE 0x0a
++#define ADIHDMI_REG_AUDIO_CONFIG 0x0b
++#define ADIHDMI_REG_I2S_CONFIG 0x0c
++#define ADIHDMI_REG_I2S_WIDTH 0x0d
++#define ADIHDMI_REG_AUDIO_SUB_SRC0 0x0e
++#define ADIHDMI_REG_AUDIO_SUB_SRC1 0x0f
++#define ADIHDMI_REG_AUDIO_SUB_SRC2 0x10
++#define ADIHDMI_REG_AUDIO_SUB_SRC3 0x11
++#define ADIHDMI_REG_AUDIO_CFG1 0x12
++#define ADIHDMI_REG_AUDIO_CFG2 0x13
++#define ADIHDMI_REG_AUDIO_CFG3 0x14
++#define ADIHDMI_REG_I2C_FREQ_ID_CFG 0x15
++#define ADIHDMI_REG_VIDEO_INPUT_CFG1 0x16
++#define ADIHDMI_REG_CSC_UPPER(x) (0x18 + (x) * 2)
++#define ADIHDMI_REG_CSC_LOWER(x) (0x19 + (x) * 2)
++#define ADIHDMI_REG_SYNC_DECODER(x) (0x30 + (x))
++#define ADIHDMI_REG_DE_GENERATOR (0x35 + (x))
++#define ADIHDMI_REG_PIXEL_REPETITION 0x3b
++#define ADIHDMI_REG_VIC_MANUAL 0x3c
++#define ADIHDMI_REG_VIC_SEND 0x3d
++#define ADIHDMI_REG_VIC_DETECTED 0x3e
++#define ADIHDMI_REG_AUX_VIC_DETECTED 0x3f
++#define ADIHDMI_REG_PACKET_ENABLE0 0x40
++#define ADIHDMI_REG_POWER 0x41
++#define ADIHDMI_REG_STATUS 0x42
++#define ADIHDMI_REG_EDID_I2C_ADDR 0x43
++#define ADIHDMI_REG_PACKET_ENABLE1 0x44
++#define ADIHDMI_REG_PACKET_I2C_ADDR 0x45
++#define ADIHDMI_REG_DSD_ENABLE 0x46
++#define ADIHDMI_REG_VIDEO_INPUT_CFG2 0x48
++#define ADIHDMI_REG_INFOFRAME_UPDATE 0x4a
++#define ADIHDMI_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */
++#define ADIHDMI_REG_AVI_INFOFRAME_VERSION 0x52
++#define ADIHDMI_REG_AVI_INFOFRAME_LENGTH 0x53
++#define ADIHDMI_REG_AVI_INFOFRAME_CHECKSUM 0x54
++#define ADIHDMI_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */
++#define ADIHDMI_REG_AUDIO_INFOFRAME_VERSION 0x70
++#define ADIHDMI_REG_AUDIO_INFOFRAME_LENGTH 0x71
++#define ADIHDMI_REG_AUDIO_INFOFRAME_CHECKSUM 0x72
++#define ADIHDMI_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */
++#define ADIHDMI_REG_INT_ENABLE(x) (0x94 + (x))
++#define ADIHDMI_REG_INT(x) (0x96 + (x))
++#define ADIHDMI_REG_INPUT_CLK_DIV 0x9d
++#define ADIHDMI_REG_PLL_STATUS 0x9e
++#define ADIHDMI_REG_HDMI_POWER 0xa1
++#define ADIHDMI_REG_HDCP_HDMI_CFG 0xaf
++#define ADIHDMI_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */
++#define ADIHDMI_REG_HDCP_STATUS 0xb8
++#define ADIHDMI_REG_BCAPS 0xbe
++#define ADIHDMI_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */
++#define ADIHDMI_REG_EDID_SEGMENT 0xc4
++#define ADIHDMI_REG_DDC_STATUS 0xc8
++#define ADIHDMI_REG_EDID_READ_CTRL 0xc9
++#define ADIHDMI_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */
++#define ADIHDMI_REG_TIMING_GEN_SEQ 0xd0
++#define ADIHDMI_REG_POWER2 0xd6
++#define ADIHDMI_REG_HSYNC_PLACEMENT_MSB 0xfa
++
++#define ADIHDMI_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */
++#define ADIHDMI_REG_TMDS_CLOCK_INV 0xde
++#define ADIHDMI_REG_ARC_CTRL 0xdf
++#define ADIHDMI_REG_CEC_I2C_ADDR 0xe1
++#define ADIHDMI_REG_CEC_CTRL 0xe2
++#define ADIHDMI_REG_CHIP_ID_HIGH 0xf5
++#define ADIHDMI_REG_CHIP_ID_LOW 0xf6
++
++#define ADIHDMI_CSC_ENABLE BIT(7)
++#define ADIHDMI_CSC_UPDATE_MODE BIT(5)
++
++#define ADIHDMI_INT0_HDP BIT(7)
++#define ADIHDMI_INT0_VSYNC BIT(5)
++#define ADIHDMI_INT0_AUDIO_FIFO_FULL BIT(4)
++#define ADIHDMI_INT0_EDID_READY BIT(2)
++#define ADIHDMI_INT0_HDCP_AUTHENTICATED BIT(1)
++
++#define ADIHDMI_INT1_DDC_ERROR BIT(7)
++#define ADIHDMI_INT1_BKSV BIT(6)
++#define ADIHDMI_INT1_CEC_TX_READY BIT(5)
++#define ADIHDMI_INT1_CEC_TX_ARBIT_LOST BIT(4)
++#define ADIHDMI_INT1_CEC_TX_RETRY_TIMEOUT BIT(3)
++#define ADIHDMI_INT1_CEC_RX_READY3 BIT(2)
++#define ADIHDMI_INT1_CEC_RX_READY2 BIT(1)
++#define ADIHDMI_INT1_CEC_RX_READY1 BIT(0)
++
++#define ADIHDMI_ARC_CTRL_POWER_DOWN BIT(0)
++
++#define ADIHDMI_CEC_CTRL_POWER_DOWN BIT(0)
++
++#define ADIHDMI_POWER_POWER_DOWN BIT(6)
++
++#define ADIHDMI_HDMI_CFG_MODE_MASK 0x2
++#define ADIHDMI_HDMI_CFG_MODE_DVI 0x0
++#define ADIHDMI_HDMI_CFG_MODE_HDMI 0x2
++
++#define ADIHDMI_AUDIO_SELECT_I2C 0x0
++#define ADIHDMI_AUDIO_SELECT_SPDIF 0x1
++#define ADIHDMI_AUDIO_SELECT_DSD 0x2
++#define ADIHDMI_AUDIO_SELECT_HBR 0x3
++#define ADIHDMI_AUDIO_SELECT_DST 0x4
++
++#define ADIHDMI_I2S_SAMPLE_LEN_16 0x2
++#define ADIHDMI_I2S_SAMPLE_LEN_20 0x3
++#define ADIHDMI_I2S_SAMPLE_LEN_18 0x4
++#define ADIHDMI_I2S_SAMPLE_LEN_22 0x5
++#define ADIHDMI_I2S_SAMPLE_LEN_19 0x8
++#define ADIHDMI_I2S_SAMPLE_LEN_23 0x9
++#define ADIHDMI_I2S_SAMPLE_LEN_24 0xb
++#define ADIHDMI_I2S_SAMPLE_LEN_17 0xc
++#define ADIHDMI_I2S_SAMPLE_LEN_21 0xd
++
++#define ADIHDMI_SAMPLE_FREQ_44100 0x0
++#define ADIHDMI_SAMPLE_FREQ_48000 0x2
++#define ADIHDMI_SAMPLE_FREQ_32000 0x3
++#define ADIHDMI_SAMPLE_FREQ_88200 0x8
++#define ADIHDMI_SAMPLE_FREQ_96000 0xa
++#define ADIHDMI_SAMPLE_FREQ_176400 0xc
++#define ADIHDMI_SAMPLE_FREQ_192000 0xe
++
++#define ADIHDMI_STATUS_POWER_DOWN_POLARITY BIT(7)
++#define ADIHDMI_STATUS_HPD BIT(6)
++#define ADIHDMI_STATUS_MONITOR_SENSE BIT(5)
++#define ADIHDMI_STATUS_I2S_32BIT_MODE BIT(3)
++
++#define ADIHDMI_PACKET_ENABLE_N_CTS BIT(8+6)
++#define ADIHDMI_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5)
++#define ADIHDMI_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4)
++#define ADIHDMI_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3)
++#define ADIHDMI_PACKET_ENABLE_GC BIT(7)
++#define ADIHDMI_PACKET_ENABLE_SPD BIT(6)
++#define ADIHDMI_PACKET_ENABLE_MPEG BIT(5)
++#define ADIHDMI_PACKET_ENABLE_ACP BIT(4)
++#define ADIHDMI_PACKET_ENABLE_ISRC BIT(3)
++#define ADIHDMI_PACKET_ENABLE_GM BIT(2)
++#define ADIHDMI_PACKET_ENABLE_SPARE2 BIT(1)
++#define ADIHDMI_PACKET_ENABLE_SPARE1 BIT(0)
++
++#define ADIHDMI_REG_POWER2_HDP_SRC_MASK 0xc0
++#define ADIHDMI_REG_POWER2_HDP_SRC_BOTH 0x00
++#define ADIHDMI_REG_POWER2_HDP_SRC_HDP 0x40
++#define ADIHDMI_REG_POWER2_HDP_SRC_CEC 0x80
++#define ADIHDMI_REG_POWER2_HDP_SRC_NONE 0xc0
++#define ADIHDMI_REG_POWER2_TDMS_ENABLE BIT(4)
++#define ADIHDMI_REG_POWER2_GATE_INPUT_CLK BIT(0)
++
++#define ADIHDMI_LOW_REFRESH_RATE_NONE 0x0
++#define ADIHDMI_LOW_REFRESH_RATE_24HZ 0x1
++#define ADIHDMI_LOW_REFRESH_RATE_25HZ 0x2
++#define ADIHDMI_LOW_REFRESH_RATE_30HZ 0x3
++
++#define ADIHDMI_AUDIO_CFG3_LEN_MASK 0x0f
++#define ADIHDMI_I2C_FREQ_ID_CFG_RATE_MASK 0xf0
++
++#define ADIHDMI_AUDIO_SOURCE_I2S 0
++#define ADIHDMI_AUDIO_SOURCE_SPDIF 1
++
++#define ADIHDMI_I2S_FORMAT_I2S 0
++#define ADIHDMI_I2S_FORMAT_RIGHT_J 1
++#define ADIHDMI_I2S_FORMAT_LEFT_J 2
++
++#define ADIHDMI_PACKET(p, x) ((p) * 0x20 + (x))
++#define ADIHDMI_PACKET_SDP(x) ADIHDMI_PACKET(0, x)
++#define ADIHDMI_PACKET_MPEG(x) ADIHDMI_PACKET(1, x)
++#define ADIHDMI_PACKET_ACP(x) ADIHDMI_PACKET(2, x)
++#define ADIHDMI_PACKET_ISRC1(x) ADIHDMI_PACKET(3, x)
++#define ADIHDMI_PACKET_ISRC2(x) ADIHDMI_PACKET(4, x)
++#define ADIHDMI_PACKET_GM(x) ADIHDMI_PACKET(5, x)
++#define ADIHDMI_PACKET_SPARE(x) ADIHDMI_PACKET(6, x)
++
++enum adihdmi_input_clock {
++ ADIHDMI_INPUT_CLOCK_1X,
++ ADIHDMI_INPUT_CLOCK_2X,
++ ADIHDMI_INPUT_CLOCK_DDR,
++};
++
++enum adihdmi_input_justification {
++ ADIHDMI_INPUT_JUSTIFICATION_EVENLY = 0,
++ ADIHDMI_INPUT_JUSTIFICATION_RIGHT = 1,
++ ADIHDMI_INPUT_JUSTIFICATION_LEFT = 2,
++};
++
++enum adihdmi_input_sync_pulse {
++ ADIHDMI_INPUT_SYNC_PULSE_DE = 0,
++ ADIHDMI_INPUT_SYNC_PULSE_HSYNC = 1,
++ ADIHDMI_INPUT_SYNC_PULSE_VSYNC = 2,
++ ADIHDMI_INPUT_SYNC_PULSE_NONE = 3,
++};
++
++/**
++ * enum adihdmi_sync_polarity - Polarity for the input sync signals
++ * @ADIHDMI_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of
++ * the currently configured mode.
++ * @ADIHDMI_SYNC_POLARITY_LOW: Sync polarity is low
++ * @ADIHDMI_SYNC_POLARITY_HIGH: Sync polarity is high
++ *
++ * If the polarity is set to either LOW or HIGH the driver will configure the
++ * ADIHDMI to internally invert the sync signal if required to match the sync
++ * polarity setting for the currently selected output mode.
++ *
++ * If the polarity is set to PASSTHROUGH, the ADIHDMI will route the signal
++ * unchanged. This is used when the upstream graphics core already generates
++ * the sync signals with the correct polarity.
++ */
++enum adihdmi_sync_polarity {
++ ADIHDMI_SYNC_POLARITY_PASSTHROUGH,
++ ADIHDMI_SYNC_POLARITY_LOW,
++ ADIHDMI_SYNC_POLARITY_HIGH,
++};
++
++/**
++ * struct adihdmi_link_config - Describes adihdmi hardware configuration
++ * @input_color_depth: Number of bits per color component (8, 10 or 12)
++ * @input_colorspace: The input colorspace (RGB, YUV444, YUV422)
++ * @input_clock: The input video clock style (1x, 2x, DDR)
++ * @input_style: The input component arrangement variant
++ * @input_justification: Video input format bit justification
++ * @clock_delay: Clock delay for the input clock (in ps)
++ * @embedded_sync: Video input uses BT.656-style embedded sync
++ * @sync_pulse: Select the sync pulse
++ * @vsync_polarity: vsync input signal configuration
++ * @hsync_polarity: hsync input signal configuration
++ */
++struct adihdmi_link_config {
++ unsigned int input_color_depth;
++ enum hdmi_colorspace input_colorspace;
++ enum adihdmi_input_clock input_clock;
++ unsigned int input_style;
++ enum adihdmi_input_justification input_justification;
++
++ int clock_delay;
++
++ bool embedded_sync;
++ enum adihdmi_input_sync_pulse sync_pulse;
++ enum adihdmi_sync_polarity vsync_polarity;
++ enum adihdmi_sync_polarity hsync_polarity;
++};
++
++/**
++ * enum adihdmi_csc_scaling - Scaling factor for the ADIHDMI CSC
++ * @ADIHDMI_CSC_SCALING_1: CSC results are not scaled
++ * @ADIHDMI_CSC_SCALING_2: CSC results are scaled by a factor of two
++ * @ADIHDMI_CSC_SCALING_4: CSC results are scalled by a factor of four
++ */
++enum adihdmi_csc_scaling {
++ ADIHDMI_CSC_SCALING_1 = 0,
++ ADIHDMI_CSC_SCALING_2 = 1,
++ ADIHDMI_CSC_SCALING_4 = 2,
++};
++
++/**
++ * struct adihdmi_video_config - Describes adihdmi hardware configuration
++ * @csc_enable: Whether to enable color space conversion
++ * @csc_scaling_factor: Color space conversion scaling factor
++ * @csc_coefficents: Color space conversion coefficents
++ * @hdmi_mode: Whether to use HDMI or DVI output mode
++ * @avi_infoframe: HDMI infoframe
++ */
++struct adihdmi_video_config {
++ bool csc_enable;
++ enum adihdmi_csc_scaling csc_scaling_factor;
++ const uint16_t *csc_coefficents;
++
++ bool hdmi_mode;
++ struct hdmi_avi_infoframe avi_infoframe;
++};
++
++#endif /* __DRM_I2C_ADIHDMI_H__ */
+diff --git b/drivers/gpu/drm/i2c/adihdmi_drv.c b/drivers/gpu/drm/i2c/adihdmi_drv.c
+new file mode 100644
+index 0000000..6792224
+--- /dev/null
++++ b/drivers/gpu/drm/i2c/adihdmi_drv.c
+@@ -0,0 +1,1268 @@
++/*
++ * Analog Devices ADIHDMI HDMI transmitter driver
++ *
++ * Copyright 2012 Analog Devices Inc.
++ * Copyright 2015 Konsulko Group
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/component.h>
++#include <linux/device.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/regmap.h>
++#include <linux/slab.h>
++
++#include <drm/drmP.h>
++#include <drm/drm_crtc_helper.h>
++#include <drm/drm_edid.h>
++#include <drm/drm_encoder_slave.h>
++#include <drm_of.h>
++
++#include "adihdmi.h"
++
++#define ADIHDMI_INFOFRAME_PACKETS (0x7900)
++
++struct adihdmi {
++ struct i2c_client *i2c_main;
++ struct i2c_client *i2c_edid;
++
++ struct regmap *regmap;
++ struct regmap *packet_memory_regmap;
++ enum drm_connector_status status;
++ bool powered;
++
++ unsigned int f_tmds;
++
++ unsigned int current_edid_segment;
++ uint8_t edid_buf[256];
++ bool edid_read;
++
++ wait_queue_head_t wq;
++ struct drm_encoder *encoder;
++
++ bool embedded_sync;
++ enum adihdmi_sync_polarity vsync_polarity;
++ enum adihdmi_sync_polarity hsync_polarity;
++ bool rgb;
++
++ struct edid *edid;
++
++ struct gpio_desc *gpio_pd;
++};
++
++struct adihdmi2 {
++ struct adihdmi base;
++ struct drm_encoder encoder;
++ struct drm_connector connector;
++};
++
++/* ADI recommended values for proper operation. */
++static const struct reg_sequence adihdmi_fixed_registers[] = {
++ { 0x98, 0x03 },
++ { 0x9a, 0xe0 },
++ { 0x9c, 0x30 },
++ { 0x9d, 0x61 },
++ { 0xa2, 0xa4 },
++ { 0xa3, 0xa4 },
++ { 0xe0, 0xd0 },
++ { 0xf9, 0x00 },
++ { 0x55, 0x02 },
++};
++
++/* -----------------------------------------------------------------------------
++ * Register access
++ */
++
++static const uint8_t adihdmi_register_defaults[] = {
++ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */
++ 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13,
++ 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */
++ 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84,
++ 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */
++ 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */
++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
++ 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */
++ 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */
++ 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00,
++ 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */
++ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */
++ 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04,
++ 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01,
++ 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */
++ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++};
++
++static bool adihdmi_register_volatile(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case ADIHDMI_REG_CHIP_REVISION:
++ case ADIHDMI_REG_SPDIF_FREQ:
++ case ADIHDMI_REG_CTS_AUTOMATIC1:
++ case ADIHDMI_REG_CTS_AUTOMATIC2:
++ case ADIHDMI_REG_VIC_DETECTED:
++ case ADIHDMI_REG_VIC_SEND:
++ case ADIHDMI_REG_AUX_VIC_DETECTED:
++ case ADIHDMI_REG_STATUS:
++ case ADIHDMI_REG_GC(1):
++ case ADIHDMI_REG_INT(0):
++ case ADIHDMI_REG_INT(1):
++ case ADIHDMI_REG_PLL_STATUS:
++ case ADIHDMI_REG_AN(0):
++ case ADIHDMI_REG_AN(1):
++ case ADIHDMI_REG_AN(2):
++ case ADIHDMI_REG_AN(3):
++ case ADIHDMI_REG_AN(4):
++ case ADIHDMI_REG_AN(5):
++ case ADIHDMI_REG_AN(6):
++ case ADIHDMI_REG_AN(7):
++ case ADIHDMI_REG_HDCP_STATUS:
++ case ADIHDMI_REG_BCAPS:
++ case ADIHDMI_REG_BKSV(0):
++ case ADIHDMI_REG_BKSV(1):
++ case ADIHDMI_REG_BKSV(2):
++ case ADIHDMI_REG_BKSV(3):
++ case ADIHDMI_REG_BKSV(4):
++ case ADIHDMI_REG_DDC_STATUS:
++ case ADIHDMI_REG_BSTATUS(0):
++ case ADIHDMI_REG_BSTATUS(1):
++ case ADIHDMI_REG_CHIP_ID_HIGH:
++ case ADIHDMI_REG_CHIP_ID_LOW:
++ return true;
++ }
++
++ return false;
++}
++
++static const struct regmap_config adihdmi_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++
++ .max_register = 0xff,
++ .cache_type = REGCACHE_RBTREE,
++ .reg_defaults_raw = adihdmi_register_defaults,
++ .num_reg_defaults_raw = ARRAY_SIZE(adihdmi_register_defaults),
++
++ .volatile_reg = adihdmi_register_volatile,
++};
++
++/* -----------------------------------------------------------------------------
++ * Hardware configuration
++ */
++
++ static void adihdmi_audio_setup(struct adihdmi * adihdmi)
++{
++ /* Select I2S. */
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_AUDIO_SOURCE, 0x01);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_I2S_CONFIG, 0x84);
++
++ /* Setup clocks for 48KHz. */
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_N0, 0x00);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_N1, 0x18);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_N2, 0x00);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_I2C_FREQ_ID_CFG, 0xF0, 0x20);
++
++ /* Set audio word length to 24 bits. */
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_AUDIO_CFG3, 0x0F, 0x0B);
++
++ /* Update audio infoframe. */
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_INFOFRAME_UPDATE, 0x20, 0x20);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_AUDIO_INFOFRAME(0), 0x07, 0x01);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_AUDIO_INFOFRAME(3), 0x1F, 0x00);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_INFOFRAME_UPDATE, 0x20, 0x00);
++}
++
++static void adihdmi_set_colormap(struct adihdmi *adihdmi, bool enable,
++ const uint16_t *coeff,
++ unsigned int scaling_factor)
++{
++ unsigned int i;
++
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(1),
++ ADIHDMI_CSC_UPDATE_MODE, ADIHDMI_CSC_UPDATE_MODE);
++
++ if (enable) {
++ for (i = 0; i < 12; ++i) {
++ regmap_update_bits(adihdmi->regmap,
++ ADIHDMI_REG_CSC_UPPER(i),
++ 0x1f, coeff[i] >> 8);
++ regmap_write(adihdmi->regmap,
++ ADIHDMI_REG_CSC_LOWER(i),
++ coeff[i] & 0xff);
++ }
++ }
++
++ if (enable)
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(0),
++ 0xe0, 0x80 | (scaling_factor << 5));
++ else
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(0),
++ 0x80, 0x00);
++
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(1),
++ ADIHDMI_CSC_UPDATE_MODE, 0);
++}
++
++static int adihdmi_packet_enable(struct adihdmi *adihdmi, unsigned int packet)
++{
++ if (packet & 0xff)
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE0,
++ packet, 0xff);
++
++ if (packet & 0xff00) {
++ packet >>= 8;
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE1,
++ packet, 0xff);
++ }
++
++ return 0;
++}
++
++static int adihdmi_packet_disable(struct adihdmi *adihdmi, unsigned int packet)
++{
++ if (packet & 0xff)
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE0,
++ packet, 0x00);
++
++ if (packet & 0xff00) {
++ packet >>= 8;
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE1,
++ packet, 0x00);
++ }
++
++ return 0;
++}
++
++/* Coefficients for adihdmi color space conversion */
++static const uint16_t adihdmi_csc_ycbcr_to_rgb[] = {
++ 0x0734, 0x04ad, 0x0000, 0x1c1b,
++ 0x1ddc, 0x04ad, 0x1f24, 0x0135,
++ 0x0000, 0x04ad, 0x087c, 0x1b77,
++};
++
++static void adihdmi_set_config_csc(struct adihdmi *adihdmi,
++ struct drm_connector *connector,
++ bool rgb)
++{
++ struct adihdmi_video_config config;
++ bool output_format_422, output_format_ycbcr;
++ unsigned int mode;
++ uint8_t infoframe[17];
++
++ if (adihdmi->edid)
++ config.hdmi_mode = drm_detect_hdmi_monitor(adihdmi->edid);
++ else
++ config.hdmi_mode = false;
++
++ hdmi_avi_infoframe_init(&config.avi_infoframe);
++
++ config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
++
++ if (rgb) {
++ config.csc_enable = false;
++ config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
++ } else {
++ config.csc_scaling_factor = ADIHDMI_CSC_SCALING_4;
++ config.csc_coefficents = adihdmi_csc_ycbcr_to_rgb;
++
++ if ((connector->display_info.color_formats &
++ DRM_COLOR_FORMAT_YCRCB422) &&
++ config.hdmi_mode) {
++ config.csc_enable = false;
++ config.avi_infoframe.colorspace =
++ HDMI_COLORSPACE_YUV422;
++ } else {
++ config.csc_enable = true;
++ config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
++ }
++ }
++
++ if (config.hdmi_mode) {
++ mode = ADIHDMI_HDMI_CFG_MODE_HDMI;
++
++ switch (config.avi_infoframe.colorspace) {
++ case HDMI_COLORSPACE_YUV444:
++ output_format_422 = false;
++ output_format_ycbcr = true;
++ break;
++ case HDMI_COLORSPACE_YUV422:
++ output_format_422 = true;
++ output_format_ycbcr = true;
++ break;
++ default:
++ output_format_422 = false;
++ output_format_ycbcr = false;
++ break;
++ }
++ } else {
++ mode = ADIHDMI_HDMI_CFG_MODE_DVI;
++ output_format_422 = false;
++ output_format_ycbcr = false;
++ }
++
++ adihdmi_packet_disable(adihdmi, ADIHDMI_INFOFRAME_PACKETS);
++
++ adihdmi_set_colormap(adihdmi, config.csc_enable,
++ config.csc_coefficents,
++ config.csc_scaling_factor);
++
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_VIDEO_INPUT_CFG1, 0x81,
++ (output_format_422 << 7) | output_format_ycbcr);
++
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_HDCP_HDMI_CFG,
++ ADIHDMI_HDMI_CFG_MODE_MASK, mode);
++
++ hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe,
++ sizeof(infoframe));
++
++ /* The AVI infoframe id is not configurable */
++ regmap_bulk_write(adihdmi->regmap, ADIHDMI_REG_AVI_INFOFRAME_VERSION,
++ infoframe + 1, sizeof(infoframe) - 1);
++
++ adihdmi_packet_enable(adihdmi, ADIHDMI_INFOFRAME_PACKETS);
++}
++
++static void adihdmi_set_link_config(struct adihdmi *adihdmi,
++ const struct adihdmi_link_config *config)
++{
++ /*
++ * The input style values documented in the datasheet don't match the
++ * hardware register field values :-(
++ */
++ static const unsigned int input_styles[4] = { 0, 2, 1, 3 };
++
++ unsigned int clock_delay;
++ unsigned int color_depth;
++ unsigned int input_id;
++
++ clock_delay = (config->clock_delay + 1200) / 400;
++ color_depth = config->input_color_depth == 8 ? 3
++ : (config->input_color_depth == 10 ? 1 : 2);
++
++ /* TODO Support input ID 6 */
++ if (config->input_colorspace != HDMI_COLORSPACE_YUV422)
++ input_id = config->input_clock == ADIHDMI_INPUT_CLOCK_DDR
++ ? 5 : 0;
++ else if (config->input_clock == ADIHDMI_INPUT_CLOCK_DDR)
++ input_id = config->embedded_sync ? 8 : 7;
++ else if (config->input_clock == ADIHDMI_INPUT_CLOCK_2X)
++ input_id = config->embedded_sync ? 4 : 3;
++ else
++ input_id = config->embedded_sync ? 2 : 1;
++
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_I2C_FREQ_ID_CFG, 0xf,
++ input_id);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_VIDEO_INPUT_CFG1, 0x7e,
++ (color_depth << 4) |
++ (input_styles[config->input_style] << 2));
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_VIDEO_INPUT_CFG2,
++ config->input_justification << 3);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_TIMING_GEN_SEQ,
++ config->sync_pulse << 2);
++
++ regmap_write(adihdmi->regmap, 0xba, clock_delay << 5);
++
++ adihdmi->embedded_sync = config->embedded_sync;
++ adihdmi->hsync_polarity = config->hsync_polarity;
++ adihdmi->vsync_polarity = config->vsync_polarity;
++ adihdmi->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
++}
++
++static void adihdmi_power_on(struct adihdmi *adihdmi)
++{
++ adihdmi->current_edid_segment = -1;
++
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0),
++ ADIHDMI_INT0_EDID_READY);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(1),
++ ADIHDMI_INT1_DDC_ERROR);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
++ ADIHDMI_POWER_POWER_DOWN, 0);
++
++ /*
++ * Per spec it is allowed to pulse the HDP signal to indicate that the
++ * EDID information has changed. Some monitors do this when they wakeup
++ * from standby or are enabled. When the HDP goes low the adihdmi is
++ * reset and the outputs are disabled which might cause the monitor to
++ * go to standby again. To avoid this we ignore the HDP pin for the
++ * first few seconds after enabling the output.
++ */
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER2,
++ ADIHDMI_REG_POWER2_HDP_SRC_MASK,
++ ADIHDMI_REG_POWER2_HDP_SRC_NONE);
++
++ /*
++ * Most of the registers are reset during power down or when HPD is low.
++ */
++ regcache_sync(adihdmi->regmap);
++
++ adihdmi->powered = true;
++}
++
++static void adihdmi_power_off(struct adihdmi *adihdmi)
++{
++ /* TODO: setup additional power down modes */
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
++ ADIHDMI_POWER_POWER_DOWN,
++ ADIHDMI_POWER_POWER_DOWN);
++ regcache_mark_dirty(adihdmi->regmap);
++
++ adihdmi->powered = false;
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupt and hotplug detection
++ */
++
++static bool adihdmi_hpd(struct adihdmi *adihdmi)
++{
++ unsigned int irq0;
++ int ret;
++
++ ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_INT(0), &irq0);
++ if (ret < 0)
++ return false;
++
++ if (irq0 & ADIHDMI_INT0_HDP) {
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0),
++ ADIHDMI_INT0_HDP);
++ return true;
++ }
++
++ return false;
++}
++
++static int adihdmi_irq_process(struct adihdmi *adihdmi)
++{
++ unsigned int irq0, irq1;
++ int ret;
++
++ ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_INT(0), &irq0);
++ if (ret < 0)
++ return ret;
++
++ ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_INT(1), &irq1);
++ if (ret < 0)
++ return ret;
++
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0), irq0);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(1), irq1);
++
++ if (irq0 & ADIHDMI_INT0_HDP)
++ drm_helper_hpd_irq_event(adihdmi->encoder->dev);
++
++ if (irq0 & ADIHDMI_INT0_EDID_READY || irq1 & ADIHDMI_INT1_DDC_ERROR) {
++ adihdmi->edid_read = true;
++
++ if (adihdmi->i2c_main->irq)
++ wake_up_all(&adihdmi->wq);
++ }
++
++ return 0;
++}
++
++static irqreturn_t adihdmi_irq_handler(int irq, void *devid)
++{
++ struct adihdmi *adihdmi = devid;
++ int ret;
++
++ ret = adihdmi_irq_process(adihdmi);
++ return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
++}
++
++/* -----------------------------------------------------------------------------
++ * EDID retrieval
++ */
++
++static int adihdmi_wait_for_edid(struct adihdmi *adihdmi, int timeout)
++{
++ int ret;
++
++ if (adihdmi->i2c_main->irq) {
++ ret = wait_event_interruptible_timeout(adihdmi->wq,
++ adihdmi->edid_read, msecs_to_jiffies(timeout));
++ } else {
++ for (; timeout > 0; timeout -= 25) {
++ ret = adihdmi_irq_process(adihdmi);
++ if (ret < 0)
++ break;
++
++ if (adihdmi->edid_read)
++ break;
++
++ msleep(25);
++ }
++ }
++
++ return adihdmi->edid_read ? 0 : -EIO;
++}
++
++static int adihdmi_get_edid_block(void *data, u8 *buf, unsigned int block,
++ size_t len)
++{
++ struct adihdmi *adihdmi = data;
++ struct i2c_msg xfer[2];
++ uint8_t offset;
++ unsigned int i;
++ int ret;
++
++ if (len > 128)
++ return -EINVAL;
++
++ if (adihdmi->current_edid_segment != block / 2) {
++ unsigned int status;
++
++ ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_DDC_STATUS,
++ &status);
++ if (ret < 0)
++ return ret;
++
++ if (status != 2) {
++ adihdmi->edid_read = false;
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_EDID_SEGMENT,
++ block);
++ ret = adihdmi_wait_for_edid(adihdmi, 200);
++ if (ret < 0)
++ return ret;
++ }
++
++ /* Break this apart, hopefully more I2C controllers will
++ * support 64 byte transfers than 256 byte transfers
++ */
++
++ xfer[0].addr = adihdmi->i2c_edid->addr;
++ xfer[0].flags = 0;
++ xfer[0].len = 1;
++ xfer[0].buf = &offset;
++ xfer[1].addr = adihdmi->i2c_edid->addr;
++ xfer[1].flags = I2C_M_RD;
++ xfer[1].len = 64;
++ xfer[1].buf = adihdmi->edid_buf;
++
++ offset = 0;
++
++ for (i = 0; i < 4; ++i) {
++ ret = i2c_transfer(adihdmi->i2c_edid->adapter, xfer,
++ ARRAY_SIZE(xfer));
++ if (ret < 0)
++ return ret;
++ else if (ret != 2)
++ return -EIO;
++
++ xfer[1].buf += 64;
++ offset += 64;
++ }
++
++ adihdmi->current_edid_segment = block / 2;
++ }
++
++ if (block % 2 == 0)
++ memcpy(buf, adihdmi->edid_buf, len);
++ else
++ memcpy(buf, adihdmi->edid_buf + 128, len);
++
++ return 0;
++}
++
++static int adihdmi_mode_valid(struct drm_display_mode *mode)
++{
++ if (mode->clock > 165000)
++ return MODE_CLOCK_HIGH;
++
++ return MODE_OK;
++}
++
++/* -----------------------------------------------------------------------------
++ * DT and private structure operations
++ */
++
++#define conn_to_adihdmi2(x) \
++ container_of(x, struct adihdmi2, connector);
++
++#define enc_to_adihdmi2(x) \
++ container_of(x, struct adihdmi2, encoder);
++
++#define enc_to_adihdmi(x) \
++ (&(container_of(x, struct adihdmi2, encoder)->base))
++
++static int adihdmi_parse_dt(struct device_node *np,
++ struct adihdmi_link_config *config)
++{
++ memset(config, 0, sizeof(*config));
++
++ config->input_color_depth = 8;
++
++ config->input_colorspace = HDMI_COLORSPACE_RGB;
++ //config->input_colorspace = HDMI_COLORSPACE_YUV422;
++ //config->input_colorspace = HDMI_COLORSPACE_YUV444;
++
++ config->input_clock = ADIHDMI_INPUT_CLOCK_1X;
++ //config->input_clock = ADIHDMI_INPUT_CLOCK_2X;
++ //config->input_clock = ADIHDMI_INPUT_CLOCK_DDR;
++
++ if (config->input_colorspace == HDMI_COLORSPACE_YUV422 ||
++ config->input_clock != ADIHDMI_INPUT_CLOCK_1X) {
++
++ config->input_style = 1;
++ //config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_LEFT;
++ config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_EVENLY;
++ //config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_RIGHT;
++
++ } else {
++ config->input_style = 1;
++ config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_LEFT;
++ }
++
++ config->clock_delay = 0;
++ config->embedded_sync = 0;
++
++ /* Hardcode the sync pulse configurations for now. */
++ config->sync_pulse = ADIHDMI_INPUT_SYNC_PULSE_NONE;
++ config->vsync_polarity = ADIHDMI_SYNC_POLARITY_PASSTHROUGH;
++ config->hsync_polarity = ADIHDMI_SYNC_POLARITY_PASSTHROUGH;
++
++ return 0;
++}
++
++static const int edid_i2c_addr = 0x7e;
++static const int packet_i2c_addr = 0x70;
++static const int cec_i2c_addr = 0x78;
++
++static int adihdmi_create(struct i2c_client *i2c, struct adihdmi *adihdmi)
++{
++ struct adihdmi_link_config link_config;
++ struct device *dev = &i2c->dev;
++ unsigned int val;
++ int ret;
++
++ adihdmi->powered = false;
++ adihdmi->status = connector_status_disconnected;
++
++ ret = adihdmi_parse_dt(NULL, &link_config);
++ if (ret)
++ {
++ pr_err("%s - %d - Bad parse\n", __FUNCTION__, __LINE__);
++ return -EINVAL;
++ }
++
++ /*
++ * The power down GPIO is optional. If present, toggle it from active to
++ * inactive to wake up the encoder.
++ */
++ adihdmi->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
++ if (IS_ERR(adihdmi->gpio_pd))
++ {
++ pr_err("%s - %d - Bad PD GPIO\n", __FUNCTION__, __LINE__);
++ return PTR_ERR(adihdmi->gpio_pd);
++ }
++
++ if (adihdmi->gpio_pd) {
++ mdelay(5);
++ gpiod_set_value_cansleep(adihdmi->gpio_pd, 0);
++ }
++
++ adihdmi->regmap = devm_regmap_init_i2c(i2c, &adihdmi_regmap_config);
++ if (IS_ERR(adihdmi->regmap))
++ {
++ pr_err("%s - %d - Bad reg map init\n", __FUNCTION__, __LINE__);
++ return PTR_ERR(adihdmi->regmap);
++ }
++
++ ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_CHIP_REVISION, &val);
++ if (ret)
++ {
++ pr_err("%s - %d - Bad reg map read\n", __FUNCTION__, __LINE__);
++ return ret;
++ }
++ dev_dbg(dev, "Rev. %d\n", val);
++
++ ret = regmap_register_patch(adihdmi->regmap, adihdmi_fixed_registers,
++ ARRAY_SIZE(adihdmi_fixed_registers));
++ if (ret)
++ {
++ pr_err("%s - %d - Bad reg map patch\n", __FUNCTION__, __LINE__);
++ return ret;
++ }
++
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_EDID_I2C_ADDR, edid_i2c_addr);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_PACKET_I2C_ADDR,
++ packet_i2c_addr);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_CEC_I2C_ADDR, cec_i2c_addr);
++ adihdmi_packet_disable(adihdmi, 0xffff);
++
++ adihdmi->i2c_main = i2c;
++ adihdmi->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
++ if (!adihdmi->i2c_edid)
++ {
++ pr_err("%s - %d - No mem for EDID\n", __FUNCTION__, __LINE__);
++ return -ENOMEM;
++ }
++
++ if (i2c->irq) {
++ init_waitqueue_head(&adihdmi->wq);
++
++ ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
++ adihdmi_irq_handler,
++ IRQF_ONESHOT, dev_name(dev),
++ adihdmi);
++ if (ret)
++ {
++ pr_err("%s - %d - Bad IRQ thread request\n", __FUNCTION__, __LINE__);
++ goto err_i2c_unregister_device;
++ }
++ }
++
++ /* CEC is unused for now */
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_CEC_CTRL,
++ ADIHDMI_CEC_CTRL_POWER_DOWN);
++
++ adihdmi_power_off(adihdmi);
++
++ adihdmi_set_link_config(adihdmi, &link_config);
++
++ adihdmi_audio_setup(adihdmi);
++
++ return 0;
++
++err_i2c_unregister_device:
++ i2c_unregister_device(adihdmi->i2c_edid);
++
++ return ret;
++}
++
++static void adihdmi_destroy(struct adihdmi *priv)
++{
++ i2c_unregister_device(priv->i2c_edid);
++}
++
++/* -----------------------------------------------------------------------------
++ * Encoder operations
++ */
++
++static int adihdmi_encoder_get_modes(struct adihdmi *adihdmi,
++ struct drm_connector *connector)
++{
++ struct edid *edid;
++ unsigned int count;
++
++ /* Reading the EDID only works if the device is powered */
++ if (!adihdmi->powered) {
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0),
++ ADIHDMI_INT0_EDID_READY);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(1),
++ ADIHDMI_INT1_DDC_ERROR);
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
++ ADIHDMI_POWER_POWER_DOWN, 0);
++ adihdmi->current_edid_segment = -1;
++ }
++
++ edid = drm_do_get_edid(connector, adihdmi_get_edid_block, adihdmi);
++
++ if (!adihdmi->powered)
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
++ ADIHDMI_POWER_POWER_DOWN,
++ ADIHDMI_POWER_POWER_DOWN);
++
++ kfree(adihdmi->edid);
++ adihdmi->edid = edid;
++ if (!edid)
++ {
++ pr_err("%s - %d - No EDID\n", __FUNCTION__, __LINE__);
++ return 0;
++ }
++
++ drm_mode_connector_update_edid_property(connector, edid);
++ count = drm_add_edid_modes(connector, edid);
++
++ adihdmi_set_config_csc(adihdmi, connector, adihdmi->rgb);
++
++ return count;
++}
++
++static void adihdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
++{
++ struct adihdmi2 *priv2 = enc_to_adihdmi2(encoder);
++
++ if (mode == DRM_MODE_DPMS_ON)
++ adihdmi_power_on(&priv2->base);
++ else
++ adihdmi_power_off(&priv2->base);
++}
++
++ static enum drm_connector_status
++adihdmi_encoder_detect(struct adihdmi *adihdmi,
++ struct drm_connector *connector)
++{
++ enum drm_connector_status status;
++ unsigned int val;
++ bool hpd;
++ int ret;
++
++ ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_STATUS, &val);
++ if (ret < 0)
++ {
++ pr_err("%s - %d - Disconnected\n", __FUNCTION__, __LINE__);
++ return connector_status_disconnected;
++ }
++
++ if (val & ADIHDMI_STATUS_HPD)
++ status = connector_status_connected;
++ else
++ status = connector_status_disconnected;
++
++ hpd = adihdmi_hpd(adihdmi);
++
++ /* The chip resets itself when the cable is disconnected, so in case
++ * there is a pending HPD interrupt and the cable is connected there was
++ * at least one transition from disconnected to connected and the chip
++ * has to be reinitialized. */
++ if (status == connector_status_connected && hpd && adihdmi->powered) {
++ regcache_mark_dirty(adihdmi->regmap);
++ adihdmi_power_on(adihdmi);
++ adihdmi_encoder_get_modes(adihdmi, connector);
++ if (adihdmi->status == connector_status_connected)
++ status = connector_status_disconnected;
++ } else {
++ /* Renable HDP sensing */
++ regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER2,
++ ADIHDMI_REG_POWER2_HDP_SRC_MASK,
++ ADIHDMI_REG_POWER2_HDP_SRC_BOTH);
++ }
++
++ adihdmi->status = status;
++ return status;
++}
++
++static bool adihdmi_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
++{
++ return true;
++}
++
++static int adihdmi_encoder_mode_valid(struct drm_encoder *encoder, struct drm_display_mode *mode)
++{
++ return adihdmi_mode_valid(mode);
++}
++
++static void adihdmi_encoder_mode_set(struct drm_encoder *encoder,
++ struct drm_display_mode *mode,
++ struct drm_display_mode *adj_mode)
++{
++ unsigned int low_refresh_rate;
++ unsigned int hsync_polarity = 0;
++ unsigned int vsync_polarity = 0;
++ struct adihdmi *adihdmi = enc_to_adihdmi(encoder);
++
++ if (adihdmi->embedded_sync) {
++ unsigned int hsync_offset, hsync_len;
++ unsigned int vsync_offset, vsync_len;
++
++ hsync_offset = adj_mode->crtc_hsync_start -
++ adj_mode->crtc_hdisplay;
++ vsync_offset = adj_mode->crtc_vsync_start -
++ adj_mode->crtc_vdisplay;
++ hsync_len = adj_mode->crtc_hsync_end -
++ adj_mode->crtc_hsync_start;
++ vsync_len = adj_mode->crtc_vsync_end -
++ adj_mode->crtc_vsync_start;
++
++ /* The hardware vsync generator has a off-by-one bug */
++ vsync_offset += 1;
++
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_HSYNC_PLACEMENT_MSB,
++ ((hsync_offset >> 10) & 0x7) << 5);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(0),
++ (hsync_offset >> 2) & 0xff);
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(1),
++ ((hsync_offset & 0x3) << 6) |
++ ((hsync_len >> 4) & 0x3f));
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(2),
++ ((hsync_len & 0xf) << 4) |
++ ((vsync_offset >> 6) & 0xf));
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(3),
++ ((vsync_offset & 0x3f) << 2) |
++ ((vsync_len >> 8) & 0x3));
++ regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(4),
++ vsync_len & 0xff);
++
++ hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC);
++ vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC);
++ } else {
++ enum adihdmi_sync_polarity mode_hsync_polarity;
++ enum adihdmi_sync_polarity mode_vsync_polarity;
++
++ /**
++ * If the input signal is always low or always high we want to
++ * invert or let it passthrough depending on the polarity of the
++ * current mode.
++ **/
++ if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC)
++ mode_hsync_polarity = ADIHDMI_SYNC_POLARITY_LOW;
++ else
++ mode_hsync_polarity = ADIHDMI_SYNC_POLARITY_HIGH;
++
++ if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC)
++ mode_vsync_polarity = ADIHDMI_SYNC_POLARITY_LOW;
++ else
++ mode_vsync_polarity = ADIHDMI_SYNC_POLARITY_HIGH;
++
++ if (adihdmi->hsync_polarity != mode_hsync_polarity &&
++ adihdmi->hsync_polarity !=
++ ADIHDMI_SYNC_POLARITY_PASSTHROUGH)
++ hsync_polarity = 1;
++
++ if (adihdmi->vsync_polarity != mode_vsync_polarity &&
++ adihdmi->vsync_polarity !=
++ ADIHDMI_SYNC_POLARITY_PASSTHROUGH)
++ vsync_polarity = 1;
++ }
++
++ if (mode->vrefresh <= 24000)
++ low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_24HZ;
++ else if (mode->vrefresh <= 25000)
++ low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_25HZ;
++ else if (mode->vrefresh <= 30000)
++ low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_30HZ;
++ else
++ low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_NONE;
++
++ regmap_update_bits(adihdmi->regmap, 0xfb,
++ 0x6, low_refresh_rate << 1);
++ regmap_update_bits(adihdmi->regmap, 0x17,
++ 0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
++
++ /*
++ * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
++ * supposed to give better results.
++ */
++
++ adihdmi->f_tmds = mode->clock;
++}
++
++static void adihdmi_encoder_prepare(struct drm_encoder *encoder)
++{
++ adihdmi_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
++}
++
++static void adihdmi_encoder_commit(struct drm_encoder *encoder)
++{
++ adihdmi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
++}
++
++static struct drm_encoder_helper_funcs adihdmi_encoder_helper_funcs = {
++ .dpms = adihdmi_encoder_dpms,
++ .mode_fixup = adihdmi_encoder_mode_fixup,
++ .prepare = adihdmi_encoder_prepare,
++ .commit = adihdmi_encoder_commit,
++ .mode_set = adihdmi_encoder_mode_set,
++};
++
++static void adihdmi_encoder_destroy(struct drm_encoder *encoder)
++{
++ struct adihdmi2 *priv = enc_to_adihdmi2(encoder);
++
++ adihdmi_destroy(&priv->base);
++ drm_encoder_cleanup(encoder);
++}
++
++static const struct drm_encoder_funcs adihdmi_encoder_funcs = {
++ .destroy = adihdmi_encoder_destroy,
++};
++
++/* -----------------------------------------------------------------------------
++ * Slave operations
++ */
++
++static int adihdmi_encoder_slave_create_resources(struct drm_encoder *encoder, struct drm_connector *connector)
++{
++ pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
++ return 0;
++}
++
++static void adihdmi_encoder_slave_destroy(struct drm_encoder *encoder)
++{
++ pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
++}
++
++ static enum drm_connector_status
++adihdmi_encoder_slave_detect(struct drm_encoder *encoder,
++ struct drm_connector *connector)
++{
++ return adihdmi_encoder_detect(enc_to_adihdmi(encoder),
++ connector);
++}
++
++static int adihdmi_encoder_slave_get_modes(struct drm_encoder *encoder,
++ struct drm_connector *connector)
++{
++ return adihdmi_encoder_get_modes(enc_to_adihdmi(encoder),
++ connector);
++}
++
++
++static void adihdmi_encoder_slave_set_config(struct drm_encoder *encoder, void *params)
++{
++ pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
++}
++
++static int adihdmi_encoder_set_property(struct drm_encoder *encoder, struct drm_connector *connector, struct drm_property *property, uint64_t val)
++{
++ pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
++ return 0;
++}
++
++static struct drm_encoder_slave_funcs adihdmi_encoder_slave_funcs = {
++ .create_resources = adihdmi_encoder_slave_create_resources,
++ .destroy = adihdmi_encoder_slave_destroy,
++ .detect = adihdmi_encoder_slave_detect,
++ .dpms = adihdmi_encoder_dpms,
++ .get_modes = adihdmi_encoder_slave_get_modes,
++ .mode_fixup = adihdmi_encoder_mode_fixup,
++ .mode_set = adihdmi_encoder_mode_set,
++ .mode_valid = adihdmi_encoder_mode_valid,
++ .set_config = adihdmi_encoder_slave_set_config,
++ .set_property = adihdmi_encoder_set_property,
++};
++
++/* -----------------------------------------------------------------------------
++ * Connector operations
++ */
++
++static int adihdmi_connector_get_modes(struct drm_connector *connector)
++{
++ struct adihdmi2 *priv = conn_to_adihdmi2(connector);
++
++ return adihdmi_encoder_get_modes(&priv->base, connector);
++}
++
++static int adihdmi_connector_mode_valid(struct drm_connector *connector,
++ struct drm_display_mode *mode)
++{
++ return adihdmi_mode_valid(mode);
++}
++
++ static struct drm_encoder *
++adihdmi_connector_best_encoder(struct drm_connector *connector)
++{
++ struct adihdmi2 *priv = conn_to_adihdmi2(connector);
++
++ return &priv->encoder;
++}
++
++static struct drm_connector_helper_funcs adihdmi_connector_helper_funcs = {
++ .get_modes = adihdmi_connector_get_modes,
++ .mode_valid = adihdmi_connector_mode_valid,
++ .best_encoder = adihdmi_connector_best_encoder,
++};
++
++ static enum drm_connector_status
++adihdmi_connector_detect(struct drm_connector *connector, bool force)
++{
++ struct adihdmi2 *priv = conn_to_adihdmi2(connector);
++
++ return adihdmi_encoder_detect(&priv->base, connector);
++}
++
++static void adihdmi_connector_destroy(struct drm_connector *connector)
++{
++ drm_connector_unregister(connector);
++ drm_connector_cleanup(connector);
++}
++
++static struct drm_connector_funcs adihdmi_connector_funcs = {
++ .dpms = drm_helper_connector_dpms,
++ .fill_modes = drm_helper_probe_single_connector_modes,
++ .detect = adihdmi_connector_detect,
++ .destroy = adihdmi_connector_destroy,
++};
++
++/* -----------------------------------------------------------------------------
++ * Component operations
++ */
++
++static int adihdmi_bind(struct device *dev, struct device *master, void *data)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct drm_device *drm = data;
++ struct adihdmi2 *priv;
++ uint32_t crtcs = 0;
++ int ret;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ {
++ pr_err("%s - %d - No memory for ADIHDMI\n", __FUNCTION__, __LINE__);
++ return -ENOMEM;
++ }
++
++ dev_set_drvdata(dev, priv);
++
++ if (dev->of_node)
++ crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
++
++ /* If no CRTCs were found, fall back to our old behaviour */
++ if (crtcs == 0) {
++ dev_warn(dev, "Falling back to first CRTC\n");
++ crtcs = 1 << 0;
++ }
++
++ priv->base.encoder = &priv->encoder;
++ priv->connector.interlace_allowed = 1;
++ priv->encoder.possible_crtcs = crtcs;
++
++ ret = adihdmi_create(client, &priv->base);
++ if (ret)
++ return ret;
++
++ drm_encoder_helper_add(&priv->encoder, &adihdmi_encoder_helper_funcs);
++ ret = drm_encoder_init(drm, &priv->encoder, &adihdmi_encoder_funcs,
++ DRM_MODE_ENCODER_TMDS, NULL);
++ if (ret)
++ goto err_encoder;
++
++ drm_connector_helper_add(&priv->connector,
++ &adihdmi_connector_helper_funcs);
++ ret = drm_connector_init(drm, &priv->connector,
++ &adihdmi_connector_funcs,
++ DRM_MODE_CONNECTOR_HDMIA);
++ if (ret)
++ goto err_connector;
++
++ ret = drm_connector_register(&priv->connector);
++ if (ret)
++ goto err_sysfs;
++
++ priv->connector.encoder = &priv->encoder;
++ drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
++
++ return 0;
++
++err_sysfs:
++ drm_connector_cleanup(&priv->connector);
++err_connector:
++ drm_encoder_cleanup(&priv->encoder);
++err_encoder:
++ adihdmi_destroy(&priv->base);
++ return ret;
++
++
++}
++
++static void adihdmi_unbind(struct device *dev, struct device *master, void *data)
++{
++ struct adihdmi2 *priv = dev_get_drvdata(dev);
++
++ drm_connector_cleanup(&priv->connector);
++ drm_encoder_cleanup(&priv->encoder);
++ adihdmi_destroy(&priv->base);
++}
++
++static const struct component_ops adihdmi_ops =
++{
++ .bind = adihdmi_bind,
++ .unbind = adihdmi_unbind,
++};
++
++/* -----------------------------------------------------------------------------
++ * Init operations
++ */
++
++static int adihdmi_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
++{
++ return component_add(&i2c->dev, &adihdmi_ops);
++}
++
++static int adihdmi_remove(struct i2c_client *i2c)
++{
++ component_del(&i2c->dev, &adihdmi_ops);
++
++ return 0;
++}
++
++static int adihdmi_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
++ struct drm_encoder_slave *encoder_slave)
++{
++
++ struct adihdmi *adihdmi;
++ int ret;
++
++ adihdmi = kzalloc(sizeof(*adihdmi), GFP_KERNEL);
++ if (!adihdmi)
++ return -ENOMEM;
++
++ adihdmi->encoder = &encoder_slave->base;
++
++ ret = adihdmi_create(i2c, adihdmi);
++ if (ret) {
++ kfree(adihdmi);
++ return ret;
++ }
++
++ encoder_slave->slave_priv = adihdmi;
++ encoder_slave->slave_funcs = &adihdmi_encoder_slave_funcs;
++
++ return 0;
++}
++
++static const struct i2c_device_id adihdmi_i2c_ids[] = {
++ { "adv7511", 0 },
++ { "adv7511w", 0 },
++ { "adv7513", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, adihdmi_i2c_ids);
++
++static const struct of_device_id adihdmi_of_ids[] = {
++ { .compatible = "adi,adv7511", },
++ { .compatible = "adi,adv7511w", },
++ { .compatible = "adi,adv7513", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, adihdmi_of_ids);
++
++static struct drm_i2c_encoder_driver adihdmi_driver = {
++ .i2c_driver = {
++ .driver = {
++ .name = "adihdmi",
++ .of_match_table = adihdmi_of_ids,
++ },
++ .id_table = adihdmi_i2c_ids,
++ .probe = adihdmi_probe,
++ .remove = adihdmi_remove,
++ },
++
++ .encoder_init = adihdmi_encoder_init,
++};
++
++static int __init adihdmi_init(void)
++{
++ return drm_i2c_encoder_register(THIS_MODULE, &adihdmi_driver);
++}
++module_init(adihdmi_init);
++
++static void __exit adihdmi_exit(void)
++{
++ drm_i2c_encoder_unregister(&adihdmi_driver);
++}
++module_exit(adihdmi_exit);
++
++MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
++MODULE_DESCRIPTION("ADIHDMI HDMI transmitter driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
+index 46855c8..d189426 100644
+--- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
++++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
+@@ -234,25 +234,30 @@ static int tpd_probe(struct platform_device *pdev)
+ if (r)
+ return r;
+
+-
+ gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
+ GPIOD_OUT_LOW);
+- if (IS_ERR(gpio))
++ if (IS_ERR(gpio)) {
++ r = PTR_ERR(gpio);
+ goto err_gpio;
++ }
+
+ ddata->ct_cp_hpd_gpio = gpio;
+
+ gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
+ GPIOD_OUT_LOW);
+- if (IS_ERR(gpio))
++ if (IS_ERR(gpio)) {
++ r = PTR_ERR(gpio);
+ goto err_gpio;
++ }
+
+ ddata->ls_oe_gpio = gpio;
+
+ gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
+ GPIOD_IN);
+- if (IS_ERR(gpio))
++ if (IS_ERR(gpio)) {
++ r = PTR_ERR(gpio);
+ goto err_gpio;
++ }
+
+ ddata->hpd_gpio = gpio;
+
+diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c
+index 3273217..6f26022 100644
+--- a/drivers/input/misc/tps65218-pwrbutton.c
++++ b/drivers/input/misc/tps65218-pwrbutton.c
+@@ -36,7 +36,7 @@ struct tps6521x_data {
+ static const struct tps6521x_data tps65217_data = {
+ .reg_status = TPS65217_REG_STATUS,
+ .pb_mask = TPS65217_STATUS_PB,
+- .name = "tps65217_pwrbutton",
++ .name = "tps65217_pwr_but",
+ };
+
+ static const struct tps6521x_data tps65218_data = {
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 64971ba..0fbd1c5 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -766,6 +766,36 @@ config PANEL_BOOT_MESSAGE
+ An empty message will only clear the display at driver init time. Any other
+ printf()-formatted message is valid with newline and escape codes.
+
++config BONE_CAPEMGR
++ tristate "Beaglebone cape manager"
++ depends on ARCH_OMAP2PLUS && OF
++ select EEPROM
++ select OF_OVERLAY
++ help
++ Say Y here to include support for automatic loading of
++ beaglebone capes. Select M to build as a module which
++ will be named bone_capemgr.
++
++config DEV_OVERLAYMGR
++ tristate "Device overlay manager"
++ depends on OF
++ select OF_OVERLAY
++ default n
++ help
++ Say Y here to include support for the automagical dev
++ overlay manager.
++
++config TIEQEP
++ tristate "EQEP Hardware quadrature encoder controller"
++ depends on SOC_AM33XX
++ select PWM_TIPWMSS
++ help
++ Driver support for the EQEP quadrature encoder controller AM33XX
++ TI SOC
++
++ To compile this driver as a module, choose M here: the module
++ will be called tieqep.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+@@ -775,7 +805,9 @@ source "drivers/misc/altera-stapl/Kconfig"
+ source "drivers/misc/mei/Kconfig"
+ source "drivers/misc/vmw_vmci/Kconfig"
+ source "drivers/misc/mic/Kconfig"
++source "drivers/misc/cape_bone_argus/Kconfig"
+ source "drivers/misc/genwqe/Kconfig"
++source "drivers/misc/cape/Kconfig"
+ source "drivers/misc/echo/Kconfig"
+ source "drivers/misc/cxl/Kconfig"
+ endmenu
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 3198336..7fc8cfd 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -48,11 +48,16 @@ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
+ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
+ obj-$(CONFIG_SRAM) += sram.o
+ obj-y += mic/
++obj-y += cape_bone_argus/
+ obj-$(CONFIG_GENWQE) += genwqe/
++obj-y += cape/
+ obj-$(CONFIG_ECHO) += echo/
+ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
+ obj-$(CONFIG_CXL_BASE) += cxl/
+ obj-$(CONFIG_PANEL) += panel.o
++obj-$(CONFIG_TIEQEP) += tieqep.o
++obj-$(CONFIG_BONE_CAPEMGR) += bone_capemgr.o
++obj-$(CONFIG_DEV_OVERLAYMGR) += devovmgr.o
+
+ lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
+ lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
+diff --git b/drivers/misc/bone_capemgr.c b/drivers/misc/bone_capemgr.c
+new file mode 100644
+index 0000000..78c5f44
+--- /dev/null
++++ b/drivers/misc/bone_capemgr.c
+@@ -0,0 +1,1898 @@
++/*
++ * TI Beaglebone cape manager
++ *
++ * Copyright (C) 2012 Texas Instruments Inc.
++ * Copyright (C) 2012-2015 Konsulko Group.
++ * Author: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_fdt.h>
++#include <linux/slab.h>
++#include <linux/pm_runtime.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/firmware.h>
++#include <linux/err.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++#include <linux/memory.h>
++#include <linux/kthread.h>
++#include <linux/wait.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/nvmem-consumer.h>
++
++/* disabled capes */
++static char *disable_partno;
++module_param(disable_partno, charp, 0444);
++MODULE_PARM_DESC(disable_partno,
++ "Comma delimited list of PART-NUMBER[:REV] of disabled capes");
++
++/* enable capes */
++static char *enable_partno;
++module_param(enable_partno, charp, 0444);
++MODULE_PARM_DESC(enable_partno,
++ "Comma delimited list of PART-NUMBER[:REV] of enabled capes");
++
++/* delay to scan on boot until rootfs appears */
++static int boot_scan_period = 1000;
++module_param(boot_scan_period, int, 0444);
++MODULE_PARM_DESC(boot_scan_period,
++ "boot scan period until rootfs firmware is available");
++
++static int uboot_capemgr_enabled = 0;
++module_param(uboot_capemgr_enabled, int, 0444);
++MODULE_PARM_DESC(uboot_capemgr_enabled,
++ "U-Boot Cape Manager is enabled (0=Kernel Cape Manager [default], 1=Disable Kernel Cape Manager)");
++
++struct capemgr_info;
++
++struct slot_ee_attribute {
++ struct device_attribute devattr;
++ unsigned int field;
++ struct bone_cape_slot *slot; /* this is filled when instantiated */
++};
++#define to_slot_ee_attribute(x) \
++ container_of((x), struct slot_ee_attribute, devattr)
++
++struct bbrd_ee_attribute {
++ struct device_attribute devattr;
++ unsigned int field;
++};
++#define to_bbrd_ee_attribute(x) \
++ container_of((x), struct bbrd_ee_attribute, devattr)
++
++struct bone_cape_slot {
++ struct list_head node;
++ struct capemgr_info *info;
++ int slotno;
++ struct nvmem_cell *nvmem_cell;
++
++ char text_id[256];
++ char signature[256];
++ /* quick access */
++ char board_name[32+1];
++ char version[4+1];
++ char manufacturer[16+1];
++ char part_number[16+1];
++
++ /* attribute group */
++ char *ee_attr_name;
++ int ee_attrs_count;
++ struct slot_ee_attribute *ee_attrs;
++ struct attribute **ee_attrs_tab;
++ struct attribute_group attrgroup;
++
++ /* state flags */
++ unsigned int probed : 1;
++ unsigned int probe_failed : 1;
++ unsigned int override : 1;
++ unsigned int loading : 1;
++ unsigned int loaded : 1;
++ unsigned int retry_loading : 1;
++ unsigned int disabled : 1;
++
++ char *dtbo;
++ const struct firmware *fw;
++ struct device_node *overlay;
++ int overlay_id;
++
++ /* loader thread */
++ struct task_struct *loader_thread;
++
++ /* load priority */
++ int priority;
++};
++
++struct bone_baseboard {
++
++ /* from the matched boardmap node */
++ char *compatible_name;
++
++ /* filled in by reading the eeprom */
++ char signature[256];
++ char text_id[64+1];
++
++ /* quick access */
++ char board_name[8+1];
++ char revision[4+1];
++ char serial_number[12+1];
++
++ /* access to the eeprom */
++ struct nvmem_cell *nvmem_cell;
++};
++
++struct capemgr_info {
++ struct platform_device *pdev;
++
++ atomic_t next_slot_nr;
++ struct list_head slot_list;
++ struct mutex slots_list_mutex;
++
++ /* baseboard EEPROM data */
++ struct bone_baseboard baseboard;
++
++ /* wait queue for keeping the priorities straight */
++ wait_queue_head_t load_wq;
++};
++
++static int bone_slot_fill_override(struct bone_cape_slot *slot,
++ const char *part_number, const char *version);
++static struct bone_cape_slot *capemgr_add_slot(
++ struct capemgr_info *info, const char *slot_name,
++ const char *part_number, const char *version, int prio);
++static int capemgr_remove_slot_no_lock(struct bone_cape_slot *slot);
++static int capemgr_remove_slot(struct bone_cape_slot *slot);
++static int capemgr_load_slot(struct bone_cape_slot *slot);
++static int capemgr_unload_slot(struct bone_cape_slot *slot);
++
++/* baseboard EEPROM field definition */
++#define BBRD_EE_FIELD_HEADER 0
++#define BBRD_EE_FIELD_BOARD_NAME 1
++#define BBRD_EE_FIELD_REVISION 2
++#define BBRD_EE_FIELD_SERIAL_NUMBER 3
++#define BBRD_EE_FIELD_CONFIG_OPTION 4
++#define BBRD_EE_FILED_RSVD1 5
++#define BBRD_EE_FILED_RSVD2 6
++#define BBRD_EE_FILED_RSVD3 7
++
++/* cape EEPROM field definitions */
++#define CAPE_EE_FIELD_HEADER 0
++#define CAPE_EE_FIELD_EEPROM_REV 1
++#define CAPE_EE_FIELD_BOARD_NAME 2
++#define CAPE_EE_FIELD_VERSION 3
++#define CAPE_EE_FIELD_MANUFACTURER 4
++#define CAPE_EE_FIELD_PART_NUMBER 5
++#define CAPE_EE_FIELD_NUMBER_OF_PINS 6
++#define CAPE_EE_FIELD_SERIAL_NUMBER 7
++#define CAPE_EE_FIELD_PIN_USAGE 8
++#define CAPE_EE_FIELD_VDD_3V3EXP 9
++#define CAPE_EE_FIELD_VDD_5V 10
++#define CAPE_EE_FIELD_SYS_5V 11
++#define CAPE_EE_FIELD_DC_SUPPLIED 12
++#define CAPE_EE_FIELD_FIELDS_NR 13
++
++#define EE_FIELD_MAKE_HEADER(p) \
++ ({ \
++ const u8 *_p = (p); \
++ (((u32)_p[0] << 24) | ((u32)_p[1] << 16) | \
++ ((u32)_p[2] << 8) | (u32)_p[3]); \
++ })
++
++#define EE_FIELD_HEADER_VALID 0xaa5533ee
++
++struct ee_field {
++ const char *name;
++ int start;
++ int size;
++ unsigned int ascii : 1;
++ unsigned int strip_trailing_dots : 1;
++ const char *override;
++};
++
++/* baseboard EEPROM definitions */
++static const struct ee_field bbrd_sig_fields[] = {
++ [BBRD_EE_FIELD_HEADER] = {
++ .name = "header",
++ .start = 0,
++ .size = 4,
++ .ascii = 0,
++ .override = "\xaa\x55\x33\xee", /* AA 55 33 EE */
++ },
++ [BBRD_EE_FIELD_BOARD_NAME] = {
++ .name = "board-name",
++ .start = 4,
++ .size = 8,
++ .ascii = 1,
++ .strip_trailing_dots = 1,
++ .override = "Board Name",
++ },
++ [BBRD_EE_FIELD_REVISION] = {
++ .name = "revision",
++ .start = 12,
++ .size = 4,
++ .ascii = 1,
++ .override = "00A0",
++ },
++ [BBRD_EE_FIELD_SERIAL_NUMBER] = {
++ .name = "serial-number",
++ .start = 16,
++ .size = 12,
++ .ascii = 1,
++ .override = "0000000000",
++ },
++ [BBRD_EE_FIELD_CONFIG_OPTION] = {
++ .name = "config-option",
++ .start = 28,
++ .size = 32,
++ },
++};
++
++/* cape EEPROM definitions */
++static const struct ee_field cape_sig_fields[] = {
++ [CAPE_EE_FIELD_HEADER] = {
++ .name = "header",
++ .start = 0,
++ .size = 4,
++ .ascii = 0,
++ .override = "\xaa\x55\x33\xee", /* AA 55 33 EE */
++ },
++ [CAPE_EE_FIELD_EEPROM_REV] = {
++ .name = "eeprom-format-revision",
++ .start = 4,
++ .size = 2,
++ .ascii = 1,
++ .override = "A0",
++ },
++ [CAPE_EE_FIELD_BOARD_NAME] = {
++ .name = "board-name",
++ .start = 6,
++ .size = 32,
++ .ascii = 1,
++ .strip_trailing_dots = 1,
++ .override = "Override Board Name",
++ },
++ [CAPE_EE_FIELD_VERSION] = {
++ .name = "version",
++ .start = 38,
++ .size = 4,
++ .ascii = 1,
++ .override = "00A0",
++ },
++ [CAPE_EE_FIELD_MANUFACTURER] = {
++ .name = "manufacturer",
++ .start = 42,
++ .size = 16,
++ .ascii = 1,
++ .strip_trailing_dots = 1,
++ .override = "Override Manuf",
++ },
++ [CAPE_EE_FIELD_PART_NUMBER] = {
++ .name = "part-number",
++ .start = 58,
++ .size = 16,
++ .ascii = 1,
++ .strip_trailing_dots = 1,
++ .override = "Override Part#",
++ },
++ [CAPE_EE_FIELD_NUMBER_OF_PINS] = {
++ .name = "number-of-pins",
++ .start = 74,
++ .size = 2,
++ .ascii = 0,
++ .override = NULL,
++ },
++ [CAPE_EE_FIELD_SERIAL_NUMBER] = {
++ .name = "serial-number",
++ .start = 76,
++ .size = 12,
++ .ascii = 1,
++ .override = "0000000000",
++ },
++ [CAPE_EE_FIELD_PIN_USAGE] = {
++ .name = "pin-usage",
++ .start = 88,
++ .size = 140,
++ .ascii = 0,
++ .override = NULL,
++ },
++ [CAPE_EE_FIELD_VDD_3V3EXP] = {
++ .name = "vdd-3v3exp",
++ .start = 228,
++ .size = 2,
++ .ascii = 0,
++ .override = NULL,
++ },
++ [CAPE_EE_FIELD_VDD_5V] = {
++ .name = "vdd-5v",
++ .start = 230,
++ .size = 2,
++ .ascii = 0,
++ .override = NULL,
++ },
++ [CAPE_EE_FIELD_SYS_5V] = {
++ .name = "sys-5v",
++ .start = 232,
++ .size = 2,
++ .ascii = 0,
++ .override = NULL,
++ },
++ [CAPE_EE_FIELD_DC_SUPPLIED] = {
++ .name = "dc-supplied",
++ .start = 234,
++ .size = 2,
++ .ascii = 0,
++ .override = NULL,
++ },
++};
++
++static char *ee_field_get(const struct ee_field *sig_field,
++ const void *data, int field, char *buf, int bufsz)
++{
++ int len;
++
++ /* enough space? */
++ if (bufsz < sig_field->size + sig_field->ascii)
++ return NULL;
++
++ memcpy(buf, (char *)data + sig_field->start, sig_field->size);
++
++ /* terminate ascii field */
++ if (sig_field->ascii)
++ buf[sig_field->size] = '\0';
++
++ if (sig_field->strip_trailing_dots) {
++ len = strlen(buf);
++ while (len > 1 && buf[len - 1] == '.')
++ buf[--len] = '\0';
++ }
++
++ return buf;
++}
++
++char *bbrd_ee_field_get(const void *data,
++ int field, char *buf, int bufsz)
++{
++ if ((unsigned int)field >= ARRAY_SIZE(bbrd_sig_fields))
++ return NULL;
++
++ return ee_field_get(&bbrd_sig_fields[field], data, field, buf, bufsz);
++}
++
++char *cape_ee_field_get(const void *data,
++ int field, char *buf, int bufsz)
++{
++ if ((unsigned int)field >= ARRAY_SIZE(cape_sig_fields))
++ return NULL;
++
++ return ee_field_get(&cape_sig_fields[field], data, field, buf, bufsz);
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id capemgr_of_match[] = {
++ {
++ .compatible = "ti,bone-capemgr",
++ },
++ { },
++};
++MODULE_DEVICE_TABLE(of, capemgr_of_match);
++
++#endif
++
++static int bone_baseboard_scan(struct bone_baseboard *bbrd)
++{
++ struct capemgr_info *info = container_of(bbrd,
++ struct capemgr_info, baseboard);
++ const u8 *p;
++ int ret;
++ size_t len;
++
++ p = nvmem_cell_read(bbrd->nvmem_cell, &len);
++ if (IS_ERR(p)) {
++ ret = PTR_ERR(p);
++ dev_err(&info->pdev->dev,
++ "Cannot read cell (ret=%d)\n", ret);
++ return ret;
++ }
++ if (len < sizeof(bbrd->signature)) {
++ dev_info(&info->pdev->dev,
++ "Short read %d (should be >= %d bytes)\n",
++ len, sizeof(bbrd->signature));
++ return -EINVAL;
++ }
++ memcpy(bbrd->signature, p, sizeof(bbrd->signature));
++
++ p = bbrd->signature;
++ if (EE_FIELD_MAKE_HEADER(p) != EE_FIELD_HEADER_VALID) {
++ dev_err(&info->pdev->dev, "Invalid board signature '%08x'\n",
++ EE_FIELD_MAKE_HEADER(p));
++ return -ENODEV;
++ }
++
++ bbrd_ee_field_get(bbrd->signature,
++ BBRD_EE_FIELD_BOARD_NAME,
++ bbrd->board_name, sizeof(bbrd->board_name));
++ bbrd_ee_field_get(bbrd->signature,
++ BBRD_EE_FIELD_REVISION,
++ bbrd->revision, sizeof(bbrd->revision));
++ bbrd_ee_field_get(bbrd->signature,
++ BBRD_EE_FIELD_SERIAL_NUMBER,
++ bbrd->serial_number, sizeof(bbrd->serial_number));
++
++ /* board_name,version,manufacturer,part_number */
++ snprintf(bbrd->text_id, sizeof(bbrd->text_id) - 1,
++ "%s,%s,%s", bbrd->board_name, bbrd->revision,
++ bbrd->serial_number);
++
++ /* terminate always */
++ bbrd->text_id[sizeof(bbrd->text_id) - 1] = '\0';
++
++ return 0;
++}
++
++static int bone_slot_scan(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ const u8 *p;
++ int r;
++ ssize_t len;
++
++ /* need to read EEPROM? */
++ if (slot->probed)
++ goto slot_fail_check;
++
++ if (uboot_capemgr_enabled)
++ goto slot_fail_check;
++
++ slot->probed = 1;
++
++ if (!slot->override) {
++
++ p = nvmem_cell_read(slot->nvmem_cell, &len);
++ if (IS_ERR(p)) {
++ r = PTR_ERR(p);
++ slot->probe_failed = 1;
++
++ /* timeout is normal when no cape is present */
++ if (r != -ETIMEDOUT)
++ dev_err(&info->pdev->dev,
++ "Cannot read cell (ret=%d)\n", r);
++ return r;
++ }
++ if (len < sizeof(slot->signature)) {
++ dev_info(&info->pdev->dev,
++ "Short read %d (should be >= %d bytes)\n",
++ len, sizeof(slot->signature));
++ return -EINVAL;
++ }
++ memcpy(slot->signature, p, sizeof(slot->signature));
++
++ } else
++ dev_info(&info->pdev->dev,
++ "Using override eeprom data at slot %d\n",
++ slot->slotno);
++
++ p = slot->signature;
++ if (EE_FIELD_MAKE_HEADER(p) != EE_FIELD_HEADER_VALID) {
++ dev_err(&info->pdev->dev,
++ "Invalid signature '%08x' at slot %d\n",
++ EE_FIELD_MAKE_HEADER(p), slot->slotno);
++ slot->probe_failed = 1;
++ return -ENODEV;
++ }
++
++ cape_ee_field_get(slot->signature,
++ CAPE_EE_FIELD_BOARD_NAME,
++ slot->board_name, sizeof(slot->board_name));
++ cape_ee_field_get(slot->signature,
++ CAPE_EE_FIELD_VERSION,
++ slot->version, sizeof(slot->version));
++ cape_ee_field_get(slot->signature,
++ CAPE_EE_FIELD_MANUFACTURER,
++ slot->manufacturer, sizeof(slot->manufacturer));
++ cape_ee_field_get(slot->signature,
++ CAPE_EE_FIELD_PART_NUMBER,
++ slot->part_number, sizeof(slot->part_number));
++
++ /* board_name,version,manufacturer,part_number */
++ snprintf(slot->text_id, sizeof(slot->text_id) - 1,
++ "%s,%s,%s,%s", slot->board_name, slot->version,
++ slot->manufacturer, slot->part_number);
++
++ /* terminate always */
++ slot->text_id[sizeof(slot->text_id) - 1] = '\0';
++
++slot_fail_check:
++ /* slot has failed and we don't support hotpluging */
++ if (slot->probe_failed)
++ return -ENODEV;
++
++ return 0;
++}
++
++/* return 0 if not matched,, 1 if matched */
++static int bone_match_cape(const char *match,
++ const char *part_number, const char *version)
++{
++ char *tmp_part_number, *tmp_version;
++ char *buf, *s, *e, *sn;
++ int found;
++
++ if (match == NULL || part_number == NULL)
++ return 0;
++
++ /* copy the argument to work on it */
++ buf = kstrdup(match, GFP_KERNEL);
++
++ /* no memory, too bad... */
++ if (buf == NULL)
++ return 0;
++
++ found = 0;
++ s = buf;
++ e = s + strlen(s);
++ while (s < e) {
++ /* find comma separator */
++ sn = strchr(s, ',');
++ if (sn != NULL)
++ *sn++ = '\0';
++ else
++ sn = e;
++ tmp_part_number = s;
++ tmp_version = strchr(tmp_part_number, ':');
++ if (tmp_version != NULL)
++ *tmp_version++ = '\0';
++ s = sn;
++
++ /* the part names must match */
++ if (strcmp(tmp_part_number, part_number) != 0)
++ continue;
++
++ /* if there's no version, match any */
++ if (version == NULL || tmp_version == NULL ||
++ strcmp(version, tmp_version) == 0) {
++ found = 1;
++ break;
++ }
++ }
++
++ kfree(buf);
++
++ return found;
++}
++
++/* helper method */
++static int of_multi_prop_cmp(const struct property *prop, const char *value)
++{
++ const char *cp;
++ int cplen, vlen, l;
++
++ /* check if it's directly compatible */
++ cp = prop->value;
++ cplen = prop->length;
++ vlen = strlen(value);
++
++ while (cplen > 0) {
++ /* compatible? */
++ if (of_compat_cmp(cp, value, vlen) == 0)
++ return 0;
++ l = strlen(cp) + 1;
++ cp += l;
++ cplen -= l;
++ }
++ return -1;
++}
++
++static ssize_t slot_ee_attr_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct slot_ee_attribute *ee_attr = to_slot_ee_attribute(attr);
++ struct bone_cape_slot *slot = ee_attr->slot;
++ const struct ee_field *sig_field;
++ int i, len;
++ char *p, *s;
++ u16 val;
++
++ /* add newline for ascii fields */
++ sig_field = &cape_sig_fields[ee_attr->field];
++
++ len = sig_field->size + sig_field->ascii;
++ p = kmalloc(len, GFP_KERNEL);
++ if (p == NULL)
++ return -ENOMEM;
++
++ s = cape_ee_field_get(slot->signature, ee_attr->field, p, len);
++ if (s == NULL)
++ return -EINVAL;
++
++ /* add newline for ascii fields and return */
++ if (sig_field->ascii) {
++ len = sprintf(buf, "%s\n", s);
++ goto out;
++ }
++
++ /* case by case handling */
++ switch (ee_attr->field) {
++ case CAPE_EE_FIELD_HEADER:
++ len = sprintf(buf, "%02x %02x %02x %02x\n",
++ s[0], s[1], s[2], s[3]);
++ break;
++
++ /* 2 bytes */
++ case CAPE_EE_FIELD_NUMBER_OF_PINS:
++ case CAPE_EE_FIELD_VDD_3V3EXP:
++ case CAPE_EE_FIELD_VDD_5V:
++ case CAPE_EE_FIELD_SYS_5V:
++ case CAPE_EE_FIELD_DC_SUPPLIED:
++ /* the bone is LE */
++ val = s[0] & (s[1] << 8);
++ len = sprintf(buf, "%u\n", (unsigned int)val & 0xffff);
++ break;
++
++ case CAPE_EE_FIELD_PIN_USAGE:
++
++ len = 0;
++ for (i = 0; i < sig_field->size / 2; i++) {
++ /* the bone is LE */
++ val = s[0] & (s[1] << 8);
++ sprintf(buf, "%04x\n", val);
++ buf += 5;
++ len += 5;
++ s += 2;
++ }
++
++ break;
++
++ default:
++ *buf = '\0';
++ len = 0;
++ break;
++ }
++
++out:
++ kfree(p);
++
++ return len;
++}
++
++#define SLOT_EE_ATTR(_name, _field) \
++ { \
++ .devattr = __ATTR(_name, S_IRUGO, slot_ee_attr_show, NULL), \
++ .field = CAPE_EE_FIELD_##_field, \
++ .slot = NULL, \
++ }
++
++static const struct slot_ee_attribute slot_ee_attrs[] = {
++ SLOT_EE_ATTR(header, HEADER),
++ SLOT_EE_ATTR(eeprom-format-revision, EEPROM_REV),
++ SLOT_EE_ATTR(board-name, BOARD_NAME),
++ SLOT_EE_ATTR(version, VERSION),
++ SLOT_EE_ATTR(manufacturer, MANUFACTURER),
++ SLOT_EE_ATTR(part-number, PART_NUMBER),
++ SLOT_EE_ATTR(number-of-pins, NUMBER_OF_PINS),
++ SLOT_EE_ATTR(serial-number, SERIAL_NUMBER),
++ SLOT_EE_ATTR(pin-usage, PIN_USAGE),
++ SLOT_EE_ATTR(vdd-3v3exp, VDD_3V3EXP),
++ SLOT_EE_ATTR(vdd-5v, VDD_5V),
++ SLOT_EE_ATTR(sys-5v, SYS_5V),
++ SLOT_EE_ATTR(dc-supplied, DC_SUPPLIED),
++};
++
++static int bone_cape_slot_sysfs_register(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++ struct slot_ee_attribute *ee_attr;
++ struct attribute_group *attrgroup;
++ int i, err, sz;
++
++ slot->ee_attr_name = kasprintf(GFP_KERNEL, "slot-%d", slot->slotno);
++ if (slot->ee_attr_name == NULL) {
++ dev_err(dev, "slot #%d: Failed to allocate ee_attr_name\n",
++ slot->slotno);
++ err = -ENOMEM;
++ goto err_fail_no_ee_attr_name;
++ }
++
++ slot->ee_attrs_count = ARRAY_SIZE(slot_ee_attrs);
++
++ sz = slot->ee_attrs_count * sizeof(*slot->ee_attrs);
++ slot->ee_attrs = kmalloc(sz, GFP_KERNEL);
++ if (slot->ee_attrs == NULL) {
++ dev_err(dev, "slot #%d: Failed to allocate ee_attrs\n",
++ slot->slotno);
++ err = -ENOMEM;
++ goto err_fail_no_ee_attrs;
++ }
++
++ attrgroup = &slot->attrgroup;
++ memset(attrgroup, 0, sizeof(*attrgroup));
++ attrgroup->name = slot->ee_attr_name;
++
++ sz = sizeof(*slot->ee_attrs_tab) * (slot->ee_attrs_count + 1);
++ attrgroup->attrs = kmalloc(sz, GFP_KERNEL);
++ if (attrgroup->attrs == NULL) {
++ dev_err(dev, "slot #%d: Failed to allocate ee_attrs_tab\n",
++ slot->slotno);
++ err = -ENOMEM;
++ goto err_fail_no_ee_attrs_tab;
++ }
++ /* copy everything over */
++ memcpy(slot->ee_attrs, slot_ee_attrs, sizeof(slot_ee_attrs));
++
++ /* bind this attr to the slot */
++ for (i = 0; i < slot->ee_attrs_count; i++) {
++ ee_attr = &slot->ee_attrs[i];
++ ee_attr->slot = slot;
++ attrgroup->attrs[i] = &ee_attr->devattr.attr;
++ }
++ attrgroup->attrs[i] = NULL;
++
++ /* make lockdep happy */
++ for (i = 0; i < slot->ee_attrs_count; i++) {
++ ee_attr = &slot->ee_attrs[i];
++ sysfs_attr_init(&ee_attr->devattr.attr);
++ }
++
++ err = sysfs_create_group(&dev->kobj, attrgroup);
++ if (err != 0) {
++ dev_err(dev, "slot #%d: Failed to allocate ee_attrs_tab\n",
++ slot->slotno);
++ err = -ENOMEM;
++ goto err_fail_no_ee_attrs_group;
++ }
++
++ return 0;
++
++err_fail_no_ee_attrs_group:
++ kfree(slot->ee_attrs_tab);
++err_fail_no_ee_attrs_tab:
++ kfree(slot->ee_attrs);
++err_fail_no_ee_attrs:
++ kfree(slot->ee_attr_name);
++err_fail_no_ee_attr_name:
++ return err;
++}
++
++static void bone_cape_slot_sysfs_unregister(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++
++ sysfs_remove_group(&dev->kobj, &slot->attrgroup);
++ kfree(slot->ee_attrs_tab);
++ kfree(slot->ee_attrs);
++ kfree(slot->ee_attr_name);
++}
++
++static ssize_t bbrd_ee_attr_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct bbrd_ee_attribute *ee_attr = to_bbrd_ee_attribute(attr);
++ struct platform_device *pdev = to_platform_device(dev);
++ struct capemgr_info *info = platform_get_drvdata(pdev);
++ struct bone_baseboard *bbrd = &info->baseboard;
++ const struct ee_field *sig_field;
++ u16 val;
++ int i, len;
++ char *p, *s;
++
++ /* add newline for ascii fields */
++ sig_field = &bbrd_sig_fields[ee_attr->field];
++
++ len = sig_field->size + sig_field->ascii;
++ p = kmalloc(len, GFP_KERNEL);
++ if (p == NULL)
++ return -ENOMEM;
++
++ s = bbrd_ee_field_get(bbrd->signature, ee_attr->field, p, len);
++ if (s == NULL)
++ return -EINVAL;
++
++ /* add newline for ascii fields and return */
++ if (sig_field->ascii) {
++ len = sprintf(buf, "%s\n", s);
++ goto out;
++ }
++
++ /* case by case handling */
++ switch (ee_attr->field) {
++ case BBRD_EE_FIELD_HEADER:
++ len = sprintf(buf, "%02x %02x %02x %02x\n",
++ s[0], s[1], s[2], s[3]);
++ break;
++
++ case BBRD_EE_FIELD_CONFIG_OPTION:
++ len = 0;
++ for (i = 0; i < sig_field->size / 2; i++) {
++ /* the bone is LE */
++ val = s[0] & (s[1] << 8);
++ sprintf(buf, "%04x\n", val);
++ buf += 5;
++ len += 5;
++ s += 2;
++ }
++ break;
++
++ default:
++ *buf = '\0';
++ len = 0;
++ break;
++ }
++
++out:
++ kfree(p);
++
++ return len;
++}
++
++#define BBRD_EE_ATTR(_name, _field) \
++ { \
++ .devattr = __ATTR(_name, 0440, bbrd_ee_attr_show, NULL), \
++ .field = BBRD_EE_FIELD_##_field, \
++ }
++
++static struct bbrd_ee_attribute bbrd_ee_attrs[] = {
++ BBRD_EE_ATTR(header, HEADER),
++ BBRD_EE_ATTR(board-name, BOARD_NAME),
++ BBRD_EE_ATTR(revision, REVISION),
++ BBRD_EE_ATTR(serial-number, SERIAL_NUMBER),
++ BBRD_EE_ATTR(config-option, CONFIG_OPTION),
++};
++
++static struct attribute *bbrd_attrs_flat[] = {
++ &bbrd_ee_attrs[BBRD_EE_FIELD_HEADER].devattr.attr,
++ &bbrd_ee_attrs[BBRD_EE_FIELD_BOARD_NAME].devattr.attr,
++ &bbrd_ee_attrs[BBRD_EE_FIELD_REVISION].devattr.attr,
++ &bbrd_ee_attrs[BBRD_EE_FIELD_SERIAL_NUMBER].devattr.attr,
++ &bbrd_ee_attrs[BBRD_EE_FIELD_CONFIG_OPTION].devattr.attr,
++ NULL,
++};
++
++static const struct attribute_group bbrd_attr_group = {
++ .name = "baseboard",
++ .attrs = bbrd_attrs_flat,
++};
++
++static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
++ char *buf);
++static ssize_t slots_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count);
++
++static DEVICE_ATTR(slots, 0644, slots_show, slots_store);
++
++static struct attribute *root_attrs_flat[] = {
++ &dev_attr_slots.attr,
++ NULL,
++};
++
++static const struct attribute_group root_attr_group = {
++ .attrs = root_attrs_flat,
++};
++
++static const struct attribute_group *attr_groups[] = {
++ &root_attr_group,
++ &bbrd_attr_group,
++ NULL,
++};
++
++static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct capemgr_info *info = platform_get_drvdata(pdev);
++ struct bone_cape_slot *slot;
++ ssize_t len, sz;
++
++ mutex_lock(&info->slots_list_mutex);
++ sz = 0;
++ list_for_each_entry(slot, &info->slot_list, node) {
++
++ len = sprintf(buf, "%2d: %c%c%c%c%c%c %3d %s\n",
++ slot->slotno,
++ slot->probed ? 'P' : '-',
++ slot->probe_failed ? 'F' : '-',
++ slot->override ? 'O' : '-',
++ slot->loading ? 'l' : '-',
++ slot->loaded ? 'L' : '-',
++ slot->disabled ? 'D' : '-',
++ slot->overlay_id, slot->text_id);
++
++ buf += len;
++ sz += len;
++ }
++ mutex_unlock(&info->slots_list_mutex);
++
++ return sz;
++}
++
++static ssize_t slots_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct capemgr_info *info = platform_get_drvdata(pdev);
++ struct bone_cape_slot *slot;
++ struct device_node *pnode, *node;
++ char *s, *part_number, *version;
++ int ret;
++ int slotno;
++
++ /* check for remove slot */
++ if (strlen(buf) > 0 && buf[0] == '-') {
++ ret = kstrtoint(buf + 1, 10, &slotno);
++ if (ret != 0)
++ return ret;
++
++ /* now load each (take lock to be sure */
++ mutex_lock(&info->slots_list_mutex);
++ list_for_each_entry(slot, &info->slot_list, node) {
++ if (slotno == slot->slotno)
++ goto found;
++ }
++
++ mutex_unlock(&info->slots_list_mutex);
++ return -ENODEV;
++found:
++ /* the hardware slots just get unloaded */
++ if (!slot->override) {
++ ret = capemgr_unload_slot(slot);
++ if (ret == 0)
++ dev_info(&pdev->dev,
++ "Unloaded slot #%d\n", slotno);
++ else
++ dev_err(&pdev->dev,
++ "Failed to unload slot #%d\n", slotno);
++ } else {
++ ret = capemgr_remove_slot_no_lock(slot);
++ if (ret == 0)
++ dev_info(&pdev->dev,
++ "Removed slot #%d\n", slotno);
++ else
++ dev_err(&pdev->dev,
++ "Failed to remove slot #%d\n", slotno);
++ }
++ mutex_unlock(&info->slots_list_mutex);
++
++ return ret == 0 ? strlen(buf) : ret;
++ }
++
++ part_number = kstrdup(buf, GFP_KERNEL);
++ if (part_number == NULL)
++ return -ENOMEM;
++
++ /* remove trailing spaces dots and newlines */
++ s = part_number + strlen(part_number);
++ while (s > part_number &&
++ (isspace(s[-1]) || s[-1] == '\n' || s[-1] == '.'))
++ *--s = '\0';
++
++ version = strchr(part_number, ':');
++ if (version != NULL)
++ *version++ = '\0';
++
++ dev_info(&pdev->dev, "part_number '%s', version '%s'\n",
++ part_number, version ? version : "N/A");
++
++ pnode = pdev->dev.of_node;
++ node = NULL;
++ slot = NULL;
++ ret = 0;
++
++ /* no specific slot found, try immediate */
++ slot = capemgr_add_slot(info, NULL, part_number, version, 0);
++
++ if (IS_ERR_OR_NULL(slot)) {
++ dev_err(&pdev->dev, "Failed to add slot #%d\n",
++ atomic_read(&info->next_slot_nr) - 1);
++ ret = slot ? PTR_ERR(slot) : -ENODEV;
++ slot = NULL;
++ goto err_fail;
++ }
++
++ kfree(part_number);
++
++ ret = capemgr_load_slot(slot);
++ if (ret != 0)
++ capemgr_remove_slot(slot);
++
++ return ret == 0 ? strlen(buf) : ret;
++err_fail:
++ of_node_put(node);
++ kfree(part_number);
++ return ret;
++}
++
++/* verify the overlay */
++static int capemgr_verify_overlay(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++ struct bone_baseboard *bbrd = &info->baseboard;
++ struct device_node *node = slot->overlay;
++ struct property *prop;
++ struct bone_cape_slot *slotn;
++ int err, counta, countb, i, j;
++ const char *ra, *rb;
++
++ /* validate */
++ if (node == NULL) {
++ dev_err(dev, "slot #%d: No overlay for '%s'\n",
++ slot->slotno, slot->part_number);
++ return -EINVAL;
++ }
++
++ /* check if the slot is compatible with the board */
++ prop = of_find_property(node, "compatible", NULL);
++
++ /* no compatible property? */
++ if (prop == NULL) {
++ dev_err(dev, "slot #%d: No compatible property for '%s'\n",
++ slot->slotno, slot->part_number);
++ return -EINVAL;
++ }
++
++ /* verify that the cape is baseboard compatible */
++ if (of_multi_prop_cmp(prop, bbrd->compatible_name) != 0) {
++ dev_err(dev, "slot #%d: Incompatible with baseboard for '%s'\n",
++ slot->slotno, slot->part_number);
++ return -EINVAL;
++ }
++
++ /* count the strings */
++ counta = of_property_count_strings(node, "exclusive-use");
++ /* no valid property, or no resources; no matter, it's OK */
++ if (counta <= 0)
++ return 0;
++
++ /* and now check if there's a resource conflict */
++ err = 0;
++ mutex_lock(&info->slots_list_mutex);
++ for (i = 0; i < counta; i++) {
++
++ ra = NULL;
++ err = of_property_read_string_index(node, "exclusive-use",
++ i, &ra);
++ if (err != 0) {
++ dev_err(dev, "slot #%d: Could not read string #%d\n",
++ slot->slotno, i);
++ break;
++ }
++
++ list_for_each_entry(slotn, &info->slot_list, node) {
++
++ /* don't check against self */
++ if (slot == slotn)
++ continue;
++
++ /* only check against loaded or loading slots */
++ if (!slotn->loaded && !slotn->loading)
++ continue;
++
++ countb = of_property_count_strings(slotn->overlay,
++ "exclusive-use");
++ /* no valid property, or resources; it's OK */
++ if (countb <= 0)
++ continue;
++
++
++ for (j = 0; j < countb; j++) {
++
++ /* count the resources */
++ rb = NULL;
++ err = of_property_read_string_index(
++ slotn->overlay, "exclusive-use",
++ j, &rb);
++ if (err != 0) {
++ /* error, but we don't care */
++ err = 0;
++ break;
++ }
++
++ /* ignore case; just in case ;) */
++ if (strcasecmp(ra, rb) == 0) {
++
++ /* resource conflict */
++ err = -EEXIST;
++ dev_err(dev,
++ "slot #%d: %s conflict %s (#%d:%s)\n",
++ slot->slotno,
++ slot->part_number, ra,
++ slotn->slotno,
++ slotn->part_number);
++ goto out;
++ }
++ }
++ }
++ }
++out:
++ mutex_unlock(&info->slots_list_mutex);
++
++ return err;
++}
++
++static int capemgr_load_slot(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++ const char *dtbo;
++ int err;
++
++ if (slot->probe_failed) {
++ dev_err(dev, "slot #%d: probe failed for '%s'\n",
++ slot->slotno, slot->part_number);
++ return -ENODEV;
++ }
++
++ if (slot->loaded) {
++ dev_err(dev, "slot #%d: already loaded for '%s'\n",
++ slot->slotno, slot->part_number);
++ return -EAGAIN;
++ }
++
++ /* make sure we don't leak this on repeated calls */
++ kfree(slot->dtbo);
++ slot->dtbo = NULL;
++
++ dev_dbg(dev, "slot #%d: Requesting part number/version based '%s-%s.dtbo\n",
++ slot->slotno, slot->part_number, slot->version);
++
++ /* request the part number + .dtbo*/
++ slot->dtbo = kasprintf(GFP_KERNEL, "%s-%s.dtbo",
++ slot->part_number, slot->version);
++ if (slot->dtbo == NULL) {
++ dev_err(dev, "slot #%d: Failed to get dtbo '%s'\n",
++ slot->slotno, dtbo);
++ return -ENOMEM;
++ }
++
++ dev_dbg(dev, "slot #%d: Requesting firmware '%s' for board-name '%s', version '%s'%s\n",
++ slot->slotno,
++ slot->dtbo, slot->board_name, slot->version,
++ system_state == SYSTEM_BOOTING ? " - booting" : "");
++
++ err = request_firmware_direct(&slot->fw, slot->dtbo, dev);
++ if (err != 0) {
++ dev_dbg(dev, "failed to load firmware '%s'\n", slot->dtbo);
++ goto err_fail_no_fw;
++ }
++
++ dev_dbg(dev, "slot #%d: dtbo '%s' loaded; converting to live tree\n",
++ slot->slotno, slot->dtbo);
++
++ of_fdt_unflatten_tree((unsigned long *)slot->fw->data, NULL,
++ &slot->overlay);
++ if (slot->overlay == NULL) {
++ dev_err(dev, "slot #%d: Failed to unflatten\n",
++ slot->slotno);
++ err = -EINVAL;
++ goto err_fail;
++ }
++
++ /* mark it as detached */
++ of_node_set_flag(slot->overlay, OF_DETACHED);
++
++ /* perform resolution */
++ err = of_resolve_phandles(slot->overlay);
++ if (err != 0) {
++ dev_err(dev, "slot #%d: Failed to resolve tree\n",
++ slot->slotno);
++ goto err_fail;
++ }
++
++ err = capemgr_verify_overlay(slot);
++ if (err != 0) {
++ dev_err(dev, "slot #%d: Failed verification\n",
++ slot->slotno);
++ goto err_fail;
++ }
++
++ err = of_overlay_create(slot->overlay);
++ if (err < 0) {
++ dev_err(dev, "slot #%d: Failed to create overlay\n",
++ slot->slotno);
++ goto err_fail;
++ }
++ slot->overlay_id = err;
++
++ slot->loading = 0;
++ slot->loaded = 1;
++
++ dev_info(dev, "slot #%d: dtbo '%s' loaded; overlay id #%d\n",
++ slot->slotno, slot->dtbo, slot->overlay_id);
++
++ return 0;
++
++err_fail:
++
++ /* TODO: free the overlay, we can't right now cause
++ * the unflatten method does not track it */
++ slot->overlay = NULL;
++
++ release_firmware(slot->fw);
++ slot->fw = NULL;
++
++err_fail_no_fw:
++ slot->loading = 0;
++ return err;
++}
++
++static int capemgr_unload_slot(struct bone_cape_slot *slot)
++{
++ if (!slot->loaded || slot->overlay_id == -1)
++ return -EINVAL;
++
++ of_overlay_destroy(slot->overlay_id);
++ slot->overlay_id = -1;
++
++ slot->loaded = 0;
++
++ return 0;
++
++}
++
++/* slots_list_mutex must be taken */
++static int capemgr_remove_slot_no_lock(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++ int ret;
++
++ if (slot == NULL)
++ return 0;
++
++ if (slot->loaded && slot->overlay_id >= 0) {
++ /* unload just in case */
++ ret = capemgr_unload_slot(slot);
++ if (ret != 0) {
++ dev_err(dev, "Unable to unload slot #%d\n",
++ slot->slotno);
++ return ret;
++ }
++ }
++
++ /* if probed OK, remove the sysfs nodes */
++ if (slot->probed && !slot->probe_failed)
++ bone_cape_slot_sysfs_unregister(slot);
++
++ /* remove it from the list */
++ list_del(&slot->node);
++
++ if (slot->nvmem_cell)
++ nvmem_cell_put(slot->nvmem_cell);
++ devm_kfree(dev, slot);
++ return 0;
++}
++
++static int capemgr_remove_slot(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ int ret;
++
++ mutex_lock(&info->slots_list_mutex);
++ ret = capemgr_remove_slot_no_lock(slot);
++ mutex_unlock(&info->slots_list_mutex);
++
++ return ret;
++}
++
++static int bone_slot_fill_override(struct bone_cape_slot *slot,
++ const char *part_number, const char *version)
++{
++ const struct ee_field *sig_field;
++ int i, len, has_part_number;
++ char *p;
++
++ slot->probe_failed = 0;
++ slot->probed = 0;
++
++ /* zero out signature */
++ memset(slot->signature, 0,
++ sizeof(slot->signature));
++
++ /* first, fill in all with override defaults */
++ for (i = 0; i < ARRAY_SIZE(cape_sig_fields); i++) {
++
++ sig_field = &cape_sig_fields[i];
++
++ /* point to the entry */
++ p = slot->signature + sig_field->start;
++
++ if (sig_field->override)
++ memcpy(p, sig_field->override,
++ sig_field->size);
++ else
++ memset(p, 0, sig_field->size);
++ }
++
++ /* if a part_number is supplied use it */
++ len = part_number ? strlen(part_number) : 0;
++ if (len > 0) {
++ sig_field = &cape_sig_fields[CAPE_EE_FIELD_PART_NUMBER];
++
++ /* point to the entry */
++ p = slot->signature + sig_field->start;
++
++ /* copy and zero out any remainder */
++ if (len > sig_field->size)
++ len = sig_field->size;
++ memcpy(p, part_number, len);
++ if (len < sig_field->size)
++ memset(p + len, 0, sig_field->size - len);
++
++ has_part_number = 1;
++ }
++
++ /* if a version is supplied use it */
++ len = version ? strlen(version) : 0;
++ if (len > 0) {
++ sig_field = &cape_sig_fields[CAPE_EE_FIELD_VERSION];
++
++ /* point to the entry */
++ p = slot->signature + sig_field->start;
++
++ /* copy and zero out any remainder */
++ if (len > sig_field->size)
++ len = sig_field->size;
++ memcpy(p, version, len);
++ if (len < sig_field->size)
++ memset(p + len, 0, sig_field->size - len);
++ }
++
++ /* we must have a part number */
++ if (!has_part_number)
++ return -EINVAL;
++
++ slot->override = 1;
++
++ return 0;
++}
++
++static struct bone_cape_slot *
++capemgr_add_slot(struct capemgr_info *info, const char *slot_name,
++ const char *part_number, const char *version, int prio)
++{
++ struct bone_cape_slot *slot;
++ struct device *dev = &info->pdev->dev;
++ int slotno;
++ int ret;
++
++ slotno = atomic_inc_return(&info->next_slot_nr) - 1;
++
++ slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL);
++ if (slot == NULL)
++ return ERR_PTR(-ENOMEM);
++
++ slot->info = info;
++ slot->slotno = slotno;
++ slot->priority = prio;
++ slot->overlay_id = -1;
++
++ if (slot_name) {
++ slot->nvmem_cell = nvmem_cell_get(dev, slot_name);
++ if (IS_ERR(slot->nvmem_cell)) {
++ ret = PTR_ERR(slot->nvmem_cell);
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "Failed to get slot eeprom cell\n");
++ slot->nvmem_cell = NULL;
++ goto err_out;
++ }
++ } else {
++ dev_err(dev, "slot #%d: override\n", slotno);
++
++ /* fill in everything with defaults first */
++ ret = bone_slot_fill_override(slot, part_number, version);
++ if (ret != 0) {
++ dev_err(dev, "slot #%d: override failed\n", slotno);
++ goto err_out;
++ }
++ }
++
++ ret = bone_slot_scan(slot);
++ if (ret != 0) {
++
++ if (!slot->probe_failed) {
++ dev_err(dev, "slot #%d: scan failed\n",
++ slotno);
++ goto err_out;
++ }
++
++ dev_err(dev, "slot #%d: No cape found\n", slotno);
++ /* but all is fine */
++ } else {
++ if (uboot_capemgr_enabled == 0) {
++ dev_err(dev, "slot #%d: '%s'\n",
++ slotno, slot->text_id);
++
++ ret = bone_cape_slot_sysfs_register(slot);
++ if (ret != 0) {
++ dev_err(dev, "slot #%d: sysfs register failed\n",
++ slotno);
++ goto err_out;
++ }
++ } else {
++ dev_err(dev, "slot #%d: auto loading handled by U-Boot\n", slotno);
++ }
++ }
++
++ /* add to the slot list */
++ mutex_lock(&info->slots_list_mutex);
++ list_add_tail(&slot->node, &info->slot_list);
++ mutex_unlock(&info->slots_list_mutex);
++
++ return slot;
++
++err_out:
++ if (slot->nvmem_cell)
++ nvmem_cell_put(slot->nvmem_cell);
++ devm_kfree(dev, slot);
++ return ERR_PTR(ret);
++}
++
++/* return 1 if it makes sense to retry loading */
++static int retry_loading_condition(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++ struct bone_cape_slot *slotn;
++ int ret;
++
++ dev_dbg(dev, "loader: retry_loading slot-%d %s:%s (prio %d)\n",
++ slot->slotno, slot->part_number, slot->version,
++ slot->priority);
++
++ mutex_lock(&info->slots_list_mutex);
++ ret = 0;
++ list_for_each_entry(slotn, &info->slot_list, node) {
++ /* if same slot or not loading skip */
++ if (!slotn->loading || slotn->retry_loading)
++ continue;
++ /* at least one cape is still loading (without retrying) */
++ ret = 1;
++ }
++ mutex_unlock(&info->slots_list_mutex);
++ return ret;
++}
++
++/* return 1 if this slot is clear to try to load now */
++static int clear_to_load_condition(struct bone_cape_slot *slot)
++{
++ struct capemgr_info *info = slot->info;
++ int my_prio = slot->priority;
++ struct device *dev = &info->pdev->dev;
++ int ret;
++
++ dev_dbg(dev, "loader: check slot-%d %s:%s (prio %d)\n", slot->slotno,
++ slot->part_number, slot->version, slot->priority);
++
++ mutex_lock(&info->slots_list_mutex);
++ ret = 1;
++ list_for_each_entry(slot, &info->slot_list, node) {
++ /* if any slot is loading with lowest priority */
++ if (!slot->loading)
++ continue;
++ if (slot->priority < my_prio) {
++ ret = 0;
++ break;
++ }
++ }
++ mutex_unlock(&info->slots_list_mutex);
++ return ret;
++}
++
++static int capemgr_loader(void *data)
++{
++ struct bone_cape_slot *slot = data;
++ struct capemgr_info *info = slot->info;
++ struct device *dev = &info->pdev->dev;
++ int ret, done, other_loading, booting;
++
++ done = 0;
++
++ slot->retry_loading = 0;
++
++ dev_dbg(dev, "loader: before slot-%d %s:%s (prio %d)\n", slot->slotno,
++ slot->part_number, slot->version, slot->priority);
++
++ /*
++ * We have a basic priority based arbitration system
++ * Slots have priorities, so the lower priority ones
++ * should start loading first. So each time we end up
++ * here.
++ */
++ ret = wait_event_interruptible(info->load_wq,
++ clear_to_load_condition(slot));
++ if (ret < 0) {
++ dev_warn(dev, "loader, Signal pending\n");
++ return ret;
++ }
++
++ dev_dbg(dev, "loader: after slot-%d %s:%s (prio %d)\n", slot->slotno,
++ slot->part_number, slot->version, slot->priority);
++
++ /* using the return value */
++ ret = capemgr_load_slot(slot);
++
++ /* wake up all just in case */
++ wake_up_interruptible_all(&info->load_wq);
++
++ if (ret == 0)
++ goto done;
++
++ dev_dbg(dev, "loader: retrying slot-%d %s:%s (prio %d)\n", slot->slotno,
++ slot->part_number, slot->version, slot->priority);
++
++ /* first attempt has failed; now try each time there's any change */
++ slot->retry_loading = 1;
++
++ for (;;) {
++ booting = (system_state == SYSTEM_BOOTING);
++ other_loading = retry_loading_condition(slot);
++ if (!booting && !other_loading)
++ break;
++
++ /* simple wait for someone to kick us */
++ if (other_loading) {
++ DEFINE_WAIT(__wait);
++
++ prepare_to_wait(&info->load_wq, &__wait,
++ TASK_INTERRUPTIBLE);
++ finish_wait(&info->load_wq, &__wait);
++ } else {
++ /* always delay when booting */
++ msleep(boot_scan_period);
++ }
++
++ if (signal_pending(current)) {
++ dev_warn(dev, "loader, Signal pending\n");
++ ret = -ERESTARTSYS;
++ goto done;
++ }
++
++ /* using the return value */
++ ret = capemgr_load_slot(slot);
++ if (ret == 0)
++ goto done;
++
++ /* wake up all just in case */
++ wake_up_interruptible_all(&info->load_wq);
++ }
++
++done:
++ slot->loading = 0;
++ slot->retry_loading = 0;
++
++ if (ret == 0) {
++ dev_dbg(dev, "loader: done slot-%d %s:%s (prio %d)\n",
++ slot->slotno, slot->part_number, slot->version,
++ slot->priority);
++ } else {
++ dev_err(dev, "loader: failed to load slot-%d %s:%s (prio %d)\n",
++ slot->slotno, slot->part_number, slot->version,
++ slot->priority);
++
++ /* if it's a override slot remove it */
++ if (slot->override)
++ capemgr_remove_slot(slot);
++ }
++
++ return ret;
++}
++
++static int
++capemgr_probe(struct platform_device *pdev)
++{
++ struct capemgr_info *info;
++ struct bone_baseboard *bbrd;
++ struct bone_cape_slot *slot;
++ struct device_node *pnode = pdev->dev.of_node;
++ struct device_node *baseboardmaps_node;
++ struct device_node *node;
++ const char *part_number;
++ const char *version;
++ const char *board_name;
++ const char *compatible_name;
++ char slot_name[16];
++ u32 slots_nr;
++ int i, ret, len, prio;
++ long val;
++ char *wbuf, *s, *p, *e;
++
++ if (uboot_capemgr_enabled)
++ return 0;
++
++ /* we don't use platform_data at all; we require OF */
++ if (pnode == NULL)
++ return -ENOTSUPP;
++
++ info = devm_kzalloc(&pdev->dev,
++ sizeof(struct capemgr_info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ info->pdev = pdev;
++ platform_set_drvdata(pdev, info);
++
++ atomic_set(&info->next_slot_nr, 0);
++ INIT_LIST_HEAD(&info->slot_list);
++ mutex_init(&info->slots_list_mutex);
++
++ init_waitqueue_head(&info->load_wq);
++
++ baseboardmaps_node = NULL;
++
++ /* find the baseboard */
++ bbrd = &info->baseboard;
++
++ baseboardmaps_node = of_get_child_by_name(pnode, "baseboardmaps");
++ if (baseboardmaps_node == NULL) {
++ dev_err(&pdev->dev, "Failed to get baseboardmaps node");
++ ret = -ENODEV;
++ goto err_exit;
++ }
++
++ bbrd->nvmem_cell = nvmem_cell_get(&pdev->dev, "baseboard");
++ if (IS_ERR(bbrd->nvmem_cell)) {
++ ret = PTR_ERR(bbrd->nvmem_cell);
++ if (ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev, "Failed to get baseboard eeprom cell\n");
++ bbrd->nvmem_cell = NULL;
++ goto err_exit;
++ }
++
++ ret = bone_baseboard_scan(bbrd);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "Failed to scan baseboard eeprom\n");
++ goto err_exit;
++ }
++
++ dev_info(&pdev->dev, "Baseboard: '%s'\n", bbrd->text_id);
++
++ board_name = NULL;
++ compatible_name = NULL;
++ for_each_child_of_node(baseboardmaps_node, node) {
++ /* there must be board-name */
++ if (of_property_read_string(node, "board-name",
++ &board_name) != 0 ||
++ of_property_read_string(node, "compatible-name",
++ &compatible_name) != 0)
++ continue;
++
++ if (strcmp(bbrd->board_name, board_name) == 0)
++ break;
++ }
++ of_node_put(baseboardmaps_node);
++ baseboardmaps_node = NULL;
++
++ if (node == NULL) {
++ dev_err(&pdev->dev, "Failed to find compatible map for %s\n",
++ bbrd->board_name);
++ ret = -ENODEV;
++ goto err_exit;
++ }
++ bbrd->compatible_name = kstrdup(compatible_name, GFP_KERNEL);
++ if (bbrd->compatible_name == NULL) {
++ ret = -ENOMEM;
++ goto err_exit;
++ }
++ of_node_put(node);
++
++ /* get slot number */
++ ret = of_property_read_u32(pnode, "#slots", &slots_nr);
++ if (ret != 0)
++ slots_nr = 0;
++
++ dev_info(&pdev->dev, "compatible-baseboard=%s - #slots=%d\n",
++ bbrd->compatible_name, slots_nr);
++
++ for (i = 0; i < slots_nr; i++) {
++ snprintf(slot_name, sizeof(slot_name), "slot%d", i);
++ slot = capemgr_add_slot(info, slot_name, NULL, NULL, 0);
++ if (IS_ERR(slot)) {
++ dev_err(&pdev->dev, "Failed to add slot #%d\n",
++ atomic_read(&info->next_slot_nr));
++ ret = PTR_ERR(slot);
++ goto err_exit;
++ }
++ }
++
++ /* iterate over enable_partno (if there) */
++ if (enable_partno && strlen(enable_partno) > 0) {
++
++ /* allocate a temporary buffer */
++ wbuf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
++ if (wbuf == NULL) {
++ ret = -ENOMEM;
++ goto err_exit;
++ }
++
++ /* add any enable_partno capes */
++ s = enable_partno;
++ while (*s) {
++ /* form is PART[:REV[:PRIO]],PART.. */
++ p = strchr(s, ',');
++ if (p == NULL)
++ e = s + strlen(s);
++ else
++ e = p;
++
++ /* copy to temp buffer */
++ len = e - s;
++ if (len >= PAGE_SIZE - 1)
++ len = PAGE_SIZE - 1;
++ memcpy(wbuf, s, len);
++ wbuf[len] = '\0';
++
++ /* move to the next */
++ s = *e ? e + 1 : e;
++
++ part_number = wbuf;
++
++ /* default version is NULL & prio is 0 */
++ version = NULL;
++ prio = 0;
++
++ /* now split the rev & prio part */
++ p = strchr(wbuf, ':');
++ if (p != NULL) {
++ *p++ = '\0';
++ if (*p != ':')
++ version = p;
++ p = strchr(p, ':');
++ if (p != NULL) {
++ *p++ = '\0';
++ ret = kstrtol(p, 10, &val);
++ if (ret == 0)
++ prio = val;
++ }
++ }
++
++ dev_info(&pdev->dev,
++ "enabled_partno PARTNO '%s' VER '%s' PR '%d'\n",
++ part_number,
++ version ? version : "N/A", prio);
++
++ /* only immediate slots are allowed here */
++ slot = capemgr_add_slot(info, NULL,
++ part_number, version, prio);
++
++ /* we continue even in case of an error */
++ if (IS_ERR_OR_NULL(slot)) {
++ dev_warn(&pdev->dev, "Failed to add slot #%d\n",
++ atomic_read(&info->next_slot_nr) - 1);
++ }
++ }
++
++ devm_kfree(&pdev->dev, wbuf);
++ }
++
++ pm_runtime_enable(&pdev->dev);
++ ret = pm_runtime_get_sync(&pdev->dev);
++ if (IS_ERR_VALUE(ret)) {
++ dev_err(&pdev->dev, "Failed to pm_runtime_get_sync()\n");
++ goto err_exit;
++ }
++
++ pm_runtime_put(&pdev->dev);
++
++ /* it is safe to create the attribute groups */
++ ret = sysfs_create_groups(&pdev->dev.kobj, attr_groups);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "Failed to create sysfs attributes\n");
++ goto err_exit;
++ }
++ /* automatically cleared by driver core now */
++ pdev->dev.groups = attr_groups;
++
++ /* now load each (take lock to be sure */
++ mutex_lock(&info->slots_list_mutex);
++
++ list_for_each_entry(slot, &info->slot_list, node) {
++
++ /* if matches the disabled ones skip */
++ if (bone_match_cape(disable_partno, slot->part_number,
++ slot->version)) {
++ dev_info(&pdev->dev,
++ "Skipping loading of disabled cape with part# %s\n",
++ slot->part_number);
++ slot->disabled = 1;
++ continue;
++ }
++
++ if (!slot->probe_failed && !slot->loaded)
++ slot->loading = 1;
++ }
++
++ /* now start the loader thread(s) (all at once) */
++ list_for_each_entry(slot, &info->slot_list, node) {
++
++ if (!slot->loading)
++ continue;
++
++ slot->loader_thread = kthread_run(capemgr_loader,
++ slot, "capemgr-loader-%d",
++ slot->slotno);
++ if (IS_ERR(slot->loader_thread)) {
++ dev_warn(&pdev->dev, "slot #%d: Failed to start loader\n",
++ slot->slotno);
++ slot->loader_thread = NULL;
++ }
++ }
++ mutex_unlock(&info->slots_list_mutex);
++
++ dev_info(&pdev->dev, "initialized OK.\n");
++
++ return 0;
++
++err_exit:
++ if (bbrd->nvmem_cell)
++ nvmem_cell_put(bbrd->nvmem_cell);
++ of_node_put(baseboardmaps_node);
++ platform_set_drvdata(pdev, NULL);
++ devm_kfree(&pdev->dev, info);
++
++ return ret;
++}
++
++static int capemgr_remove(struct platform_device *pdev)
++{
++ struct capemgr_info *info = platform_get_drvdata(pdev);
++ struct bone_baseboard *bbrd = &info->baseboard;
++ struct bone_cape_slot *slot, *slotn;
++ int ret;
++
++ mutex_lock(&info->slots_list_mutex);
++ list_for_each_entry_safe(slot, slotn, &info->slot_list, node)
++ capemgr_remove_slot_no_lock(slot);
++ mutex_unlock(&info->slots_list_mutex);
++
++ platform_set_drvdata(pdev, NULL);
++
++ ret = pm_runtime_get_sync(&pdev->dev);
++ if (IS_ERR_VALUE(ret))
++ return ret;
++
++ pm_runtime_put(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++
++ if (bbrd->nvmem_cell)
++ nvmem_cell_put(bbrd->nvmem_cell);
++ devm_kfree(&pdev->dev, info);
++
++ return 0;
++}
++
++static struct platform_driver capemgr_driver = {
++ .probe = capemgr_probe,
++ .remove = capemgr_remove,
++ .driver = {
++ .name = "bone_capemgr",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(capemgr_of_match),
++ },
++};
++
++module_platform_driver(capemgr_driver);
++
++MODULE_AUTHOR("Pantelis Antoniou");
++MODULE_DESCRIPTION("Beaglebone cape manager");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:bone_capemgr");
+diff --git b/drivers/misc/cape/Kconfig b/drivers/misc/cape/Kconfig
+new file mode 100644
+index 0000000..a2ef85e
+--- /dev/null
++++ b/drivers/misc/cape/Kconfig
+@@ -0,0 +1,5 @@
++#
++# Capes
++#
++
++source "drivers/misc/cape/beaglebone/Kconfig"
+diff --git b/drivers/misc/cape/Makefile b/drivers/misc/cape/Makefile
+new file mode 100644
+index 0000000..7c4eb96
+--- /dev/null
++++ b/drivers/misc/cape/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for cape like devices
++#
++
++obj-y += beaglebone/
+diff --git b/drivers/misc/cape/beaglebone/Kconfig b/drivers/misc/cape/beaglebone/Kconfig
+new file mode 100644
+index 0000000..eeb6782
+--- /dev/null
++++ b/drivers/misc/cape/beaglebone/Kconfig
+@@ -0,0 +1,10 @@
++#
++# Beaglebone capes
++#
++
++config BEAGLEBONE_PINMUX_HELPER
++ tristate "Beaglebone Pinmux Helper"
++ depends on ARCH_OMAP2PLUS && OF
++ default n
++ help
++ Say Y here to include support for the pinmux helper
+diff --git b/drivers/misc/cape/beaglebone/Makefile b/drivers/misc/cape/beaglebone/Makefile
+new file mode 100644
+index 0000000..7f4617a
+--- /dev/null
++++ b/drivers/misc/cape/beaglebone/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for beaglebone capes
++#
++
++obj-$(CONFIG_BEAGLEBONE_PINMUX_HELPER) += bone-pinmux-helper.o
+diff --git b/drivers/misc/cape/beaglebone/bone-pinmux-helper.c b/drivers/misc/cape/beaglebone/bone-pinmux-helper.c
+new file mode 100644
+index 0000000..d81363a
+--- /dev/null
++++ b/drivers/misc/cape/beaglebone/bone-pinmux-helper.c
+@@ -0,0 +1,242 @@
++/*
++ * Pinmux helper driver
++ *
++ * Copyright (C) 2013 Pantelis Antoniou <panto@antoniou-consulting.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/slab.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/pinmux.h>
++#include <linux/pinctrl/consumer.h>
++
++static const struct of_device_id bone_pinmux_helper_of_match[] = {
++ {
++ .compatible = "bone-pinmux-helper",
++ },
++ { },
++};
++MODULE_DEVICE_TABLE(of, bone_pinmux_helper_of_match);
++
++struct pinmux_helper_data {
++ struct pinctrl *pinctrl;
++ char *selected_state_name;
++};
++
++static ssize_t pinmux_helper_show_state(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct pinmux_helper_data *data = platform_get_drvdata(pdev);
++ const char *name;
++
++ name = data->selected_state_name;
++ if (name == NULL || strlen(name) == 0)
++ name = "none";
++ return sprintf(buf, "%s\n", name);
++}
++
++static ssize_t pinmux_helper_store_state(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct pinmux_helper_data *data = platform_get_drvdata(pdev);
++ struct pinctrl_state *state;
++ char *state_name;
++ char *s;
++ int err;
++
++ /* duplicate (as a null terminated string) */
++ state_name = kmalloc(count + 1, GFP_KERNEL);
++ if (state_name == NULL)
++ return -ENOMEM;
++ memcpy(state_name, buf, count);
++ state_name[count] = '\0';
++
++ /* and chop off newline */
++ s = strchr(state_name, '\n');
++ if (s != NULL)
++ *s = '\0';
++
++ /* try to select default state at first (if it exists) */
++ state = pinctrl_lookup_state(data->pinctrl, state_name);
++ if (!IS_ERR(state)) {
++ err = pinctrl_select_state(data->pinctrl, state);
++ if (err != 0)
++ dev_err(dev, "Failed to select state %s\n",
++ state_name);
++ } else {
++ dev_err(dev, "Failed to find state %s\n", state_name);
++ err = PTR_RET(state);
++ }
++
++ if (err == 0) {
++ kfree(data->selected_state_name);
++ data->selected_state_name = state_name;
++ }
++
++ return err ? err : count;
++}
++
++static DEVICE_ATTR(state, S_IWUSR | S_IRUGO,
++ pinmux_helper_show_state, pinmux_helper_store_state);
++
++static struct attribute *pinmux_helper_attributes[] = {
++ &dev_attr_state.attr,
++ NULL
++};
++
++static const struct attribute_group pinmux_helper_attr_group = {
++ .attrs = pinmux_helper_attributes,
++};
++
++static int bone_pinmux_helper_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct pinmux_helper_data *data;
++ struct pinctrl_state *state;
++ char *state_name;
++ const char *mode_name;
++ int mode_len;
++ int err;
++
++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
++ if (data == NULL) {
++ dev_err(dev, "Failed to allocate data\n");
++ err = -ENOMEM;
++ goto err_no_mem;
++ }
++
++ state_name = kmalloc(strlen(PINCTRL_STATE_DEFAULT) + 1,
++ GFP_KERNEL);
++ if (state_name == NULL) {
++ dev_err(dev, "Failed to allocate state name\n");
++ err = -ENOMEM;
++ goto err_no_state_mem;
++ }
++ data->selected_state_name = state_name;
++ strcpy(data->selected_state_name, PINCTRL_STATE_DEFAULT);
++
++ platform_set_drvdata(pdev, data);
++
++ data->pinctrl = devm_pinctrl_get(dev);
++ if (IS_ERR(data->pinctrl)) {
++ dev_err(dev, "Failed to get pinctrl\n");
++ err = PTR_RET(data->pinctrl);
++ goto err_no_pinctrl;
++ }
++
++ /* See if an initial mode is specified in the device tree */
++ mode_name = of_get_property(dev->of_node, "mode", &mode_len);
++
++ err = -1;
++ if (mode_name != NULL ) {
++ state_name = kmalloc(mode_len + 1, GFP_KERNEL);
++ if (state_name == NULL) {
++ dev_err(dev, "Failed to allocate state name\n");
++ err = -ENOMEM;
++ goto err_no_mode_mem;
++ }
++ strncpy(state_name, mode_name, mode_len);
++
++ /* try to select requested mode */
++ state = pinctrl_lookup_state(data->pinctrl, state_name);
++ if (!IS_ERR(state)) {
++ err = pinctrl_select_state(data->pinctrl, state);
++ if (err != 0) {
++ dev_warn(dev, "Unable to select requested mode %s\n", state_name);
++ kfree(state_name);
++ } else {
++ kfree(data->selected_state_name);
++ data->selected_state_name = state_name;
++ dev_notice(dev, "Set initial pinmux mode to %s\n", state_name);
++ }
++ }
++ }
++
++ /* try to select default state if mode_name failed */
++ if ( err != 0) {
++ state = pinctrl_lookup_state(data->pinctrl,
++ data->selected_state_name);
++ if (!IS_ERR(state)) {
++ err = pinctrl_select_state(data->pinctrl, state);
++ if (err != 0) {
++ dev_err(dev, "Failed to select default state\n");
++ goto err_no_state;
++ }
++ } else {
++ data->selected_state_name = '\0';
++ }
++ }
++
++ /* Register sysfs hooks */
++ err = sysfs_create_group(&dev->kobj, &pinmux_helper_attr_group);
++ if (err) {
++ dev_err(dev, "Failed to create sysfs group\n");
++ goto err_no_sysfs;
++ }
++
++ return 0;
++
++err_no_sysfs:
++err_no_state:
++err_no_mode_mem:
++ devm_pinctrl_put(data->pinctrl);
++err_no_pinctrl:
++ devm_kfree(dev, data->selected_state_name);
++err_no_state_mem:
++ devm_kfree(dev, data);
++err_no_mem:
++ return err;
++}
++
++static int bone_pinmux_helper_remove(struct platform_device *pdev)
++{
++ struct pinmux_helper_data *data = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++
++ sysfs_remove_group(&dev->kobj, &pinmux_helper_attr_group);
++ kfree(data->selected_state_name);
++ devm_pinctrl_put(data->pinctrl);
++ devm_kfree(dev, data);
++
++ return 0;
++}
++
++struct platform_driver bone_pinmux_helper_driver = {
++ .probe = bone_pinmux_helper_probe,
++ .remove = bone_pinmux_helper_remove,
++ .driver = {
++ .name = "bone-pinmux-helper",
++ .owner = THIS_MODULE,
++ .of_match_table = bone_pinmux_helper_of_match,
++ },
++};
++
++module_platform_driver(bone_pinmux_helper_driver);
++
++MODULE_AUTHOR("Pantelis Antoniou");
++MODULE_DESCRIPTION("Beaglebone pinmux helper driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:bone-pinmux-helper");
+diff --git b/drivers/misc/cape_bone_argus/Kconfig b/drivers/misc/cape_bone_argus/Kconfig
+new file mode 100644
+index 0000000..1b39661
+--- /dev/null
++++ b/drivers/misc/cape_bone_argus/Kconfig
+@@ -0,0 +1,7 @@
++comment "Argus cape driver for beaglebone black"
++
++config CAPE_BONE_ARGUS
++ tristate "Argus Cape Driver"
++ default M
++ help
++ Argus Cape Driver
+diff --git b/drivers/misc/cape_bone_argus/Makefile b/drivers/misc/cape_bone_argus/Makefile
+new file mode 100644
+index 0000000..5482562
+--- /dev/null
++++ b/drivers/misc/cape_bone_argus/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for Argus cape
++#
++
++obj-$(CONFIG_CAPE_BONE_ARGUS) += cape_bone_argus.o
+diff --git b/drivers/misc/cape_bone_argus/cape_bone_argus.c b/drivers/misc/cape_bone_argus/cape_bone_argus.c
+new file mode 100644
+index 0000000..c434218
+--- /dev/null
++++ b/drivers/misc/cape_bone_argus/cape_bone_argus.c
+@@ -0,0 +1,415 @@
++/* -*- linux-c -*- */
++
++/* Linux Kernel Module for Breakaway Systems UPS control.
++ *
++ * PUBLIC DOMAIN
++ */
++
++#include <linux/syscalls.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/reboot.h>
++#include <linux/fs.h>
++#include <linux/uaccess.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/mount.h>
++#include <linux/workqueue.h>
++#include <linux/cdev.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/pinmux.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/of_gpio.h>
++
++/* Module to sync file systems leaving them mounted read-only,
++ * then signal the UPS that it is safe to remove
++ * power, and finally halt the processor.
++ * Also to allow kicking the watchdog from user mode.
++ */
++#undef DEBUG_ARGUS
++
++#define N_GPIOS 9 /* Total number of GPIOS used */
++
++#define REQ_GPIO_IDX 0 /* Indices got GPIOS */
++#define ACK_GPIO_IDX 1
++#define WDG_GPIO_IDX 2
++#define LED1_GREEN_IDX 3
++#define LED1_RED_IDX 4
++#define LED2_GREEN_IDX 5
++#define LED2_RED_IDX 6
++#define GEN_OUT1_IDX 7
++#define GEN_OUT2_IDX 8
++
++static struct argus_ups_info { /* As there is only one UPS device we can make this static */
++ struct fasync_struct *async_queue; /* asynchronous readers */
++ struct platform_device *pdev;
++ struct pwm_device *pwm_dev;
++ struct gpio gpios[N_GPIOS];
++} info = {NULL, NULL, NULL, /* Some fields filled in by device tree, probe, etc. */
++ {
++ {-1, GPIOF_IN, "Powerdown request"},
++ {-1, GPIOF_OUT_INIT_LOW, "Powerdown acknowledge" },
++ {-1, GPIOF_OUT_INIT_LOW, "Watchdog"},
++ {-1, GPIOF_OUT_INIT_LOW, "LED 1 Green"},
++ {-1, GPIOF_OUT_INIT_LOW, "LED 1 Red"},
++ {-1, GPIOF_OUT_INIT_LOW, "LED 2 Green"},
++ {-1, GPIOF_OUT_INIT_LOW, "LED 2 Red"},
++ {-1, GPIOF_OUT_INIT_LOW, "General Output #1"},
++ {-1, GPIOF_OUT_INIT_LOW, "General Output #2"}
++ },
++};
++
++
++static const struct of_device_id argus_ups_of_ids[] = {
++ { .compatible = "argus-ups" },
++ { }
++};
++
++static int argus_ups_major; /* Major device number */
++
++static struct class *argus_ups_class; /* /sys/class */
++
++dev_t argus_ups_dev; /* Device number */
++
++static struct cdev *argus_ups_cdev; /* Character device details */
++
++static void argus_ups_function(struct work_struct *ignored); /* Work function */
++
++static DECLARE_DELAYED_WORK(argus_ups_work, argus_ups_function); /* Kernel workqueue glue */
++
++static struct workqueue_struct *argus_ups_workqueue; /* Kernel workqueue */
++
++static int debug = 0;
++module_param(debug, int, S_IRUGO);
++MODULE_PARM_DESC(debug, "Debug flag");
++
++static int shutdown = 1;
++module_param(shutdown, int, S_IRUGO);
++MODULE_PARM_DESC(shutdown, "Shutdown flag");
++
++#ifdef DEBUG_ARGUS
++static char* fs_type_names[] = {"vfat", "ext4"}; /* File system names that may need syncing. */
++#endif
++
++/* Just kick watchdog */
++
++static ssize_t argus_ups_write(struct file *filp, const char __user *buf, size_t count,
++ loff_t *f_pos)
++{
++ int i;
++ if (debug >= 3) {
++ printk("Writing to watchdog - count:%d\n", count);
++ }
++ for (i = 0; i < count; i++) {
++ gpio_set_value(info.gpios[WDG_GPIO_IDX].gpio, 1); /* Set it */
++ msleep(10); /* Wait */
++ gpio_set_value(info.gpios[WDG_GPIO_IDX].gpio, 0); /* End clearing it */
++ msleep(10);
++ }
++ return count; /* Always returns what we sent, regardsless */
++}
++
++static long argus_ups_ioctl(struct file *file,
++ unsigned int ioctl,
++ unsigned long param)
++{
++ if (debug >= 4) {
++ printk(KERN_ERR "ioctl: %d, param: %ld\n", ioctl, param);
++ }
++ switch(ioctl) {
++ case 10001: {
++ debug = param;
++ printk("Debug set to %d\n", debug);
++ break;
++ }
++ case 10002: {
++ unsigned char value = param & 0x0F;
++ unsigned char mask = (param >> 4) & 0x0F;
++ int i; /* Loop iterator */
++ if (mask == 0) {
++ printk(KERN_ERR "Pointless mask of zero!\n");
++ }
++ for (i = 0; i < 4; i++) { /* For all four LEDS */
++ if (mask & (1 << i)) { /* Only masked values */
++ if (value & (1 << i)) { /* On - so gpio is hi */
++ if (debug >= 4) {
++ printk("Setting %d hi, ",
++ info.gpios[LED1_GREEN_IDX + i].gpio);
++ }
++ gpio_set_value(info.gpios[LED1_GREEN_IDX + i].gpio, 1);
++ }
++ else { /* Off - so gpio is lo */
++ if (debug >= 4) {
++ printk("Setting %d lo, ",
++ info.gpios[LED1_GREEN_IDX + i].gpio);
++ }
++ gpio_set_value(info.gpios[LED1_GREEN_IDX + i].gpio, 0);
++ }
++ }
++ }
++ if (debug >= 4) {
++ printk("\n");
++ }
++ break;
++ }
++ case 10003: {
++ gpio_set_value(info.gpios[GEN_OUT1_IDX].gpio, param & 1);
++ break;
++ }
++ case 10004: {
++ gpio_set_value(info.gpios[GEN_OUT2_IDX].gpio, param & 1);
++ break;
++ }
++ default:
++ {
++ printk(KERN_ERR "Invalid ioctl %d\n", ioctl);
++ return -1;
++ }
++ }
++ return 0;
++}
++
++static int argus_ups_fasync(int fd, struct file *filp, int mode)
++{
++ printk(KERN_ERR "In argus_ups_fasync() fd:%d, filp:%p, mode:%d\n", fd, filp, mode);
++ return fasync_helper(fd, filp, mode, &info.async_queue);
++}
++
++static struct file_operations argus_ups_fops = { /* Only file operation is to kick watchdog via a write */
++ .owner = THIS_MODULE,
++ .llseek = NULL,
++ .read = NULL,
++ .unlocked_ioctl = argus_ups_ioctl,
++ .write = argus_ups_write,
++ .open = NULL,
++ .release = NULL,
++ .fasync = argus_ups_fasync,
++};
++
++#ifdef DEBUG_ARGUS
++static void remount_sb(struct super_block *sb)
++{
++ int flags = MS_RDONLY;
++ int result = sb->s_op->remount_fs(sb, &flags, "");
++ if (debug) {
++ printk("Processing superblock %p\n", sb);
++ printk("Remount operation returned %d\n", result);
++ }
++}
++#endif
++
++static void argus_ups_function(struct work_struct *ignored)
++{
++ static int testdata = 0; /* Data for test */
++ int i; /* Iterator */
++ testdata++;
++ if (!gpio_get_value(info.gpios[REQ_GPIO_IDX].gpio)) {
++ queue_delayed_work(argus_ups_workqueue, &argus_ups_work, HZ/100); /* Re-queue in 10mS*/
++ return;
++ }
++ printk(KERN_ERR "Request received\n");
++ if (debug) {
++ printk("Shutdown request received from UPS\n");
++ }
++ if (!shutdown) {
++ printk("Shutdown request ignored\n");
++ return;
++ }
++
++ if (debug) {
++ printk("Sending async kill SIGIO to %p\n", info.async_queue);
++ }
++ if (info.async_queue) { /* Try and tell usermode to halt system */
++ kill_fasync(&info.async_queue, SIGIO, POLL_IN);
++ }
++ gpio_set_value(info.gpios[LED1_GREEN_IDX].gpio, 0); /* Turn off green LED1 */
++ for (i = 0; i < 300; i++) { /* Toggle acknowledge at 10 Hz for 15 seconds */
++ if (debug >= 2) {
++ printk("Waiting for first shutdown request:%d\n", i);
++ }
++ gpio_set_value(info.gpios[ACK_GPIO_IDX].gpio, i & 1); /* Toggle acknowledge */
++ gpio_set_value(info.gpios[LED1_RED_IDX].gpio, i & 1); /* and LED1 red */
++ msleep(50); /* Wait in 50ms increments */
++ }
++
++ {
++ char *argv[] = { "/sbin/halt", NULL };
++ static char *envp[] = {
++ "HOME=/",
++ "TERM=linux",
++ "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin", NULL };
++
++ call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
++ }
++ for (i = 0; i < 300; i++) { /* Toggle acknowledge at 10 Hz for 15 more seconds */
++ if (debug >= 2) {
++ printk("Waiting for second shutdown request:%d\n", i);
++ }
++ gpio_set_value(info.gpios[ACK_GPIO_IDX].gpio, i & 1); /* Toggle acknowledge */
++ gpio_set_value(info.gpios[LED1_RED_IDX].gpio, i & 1); /* and LED1 red */
++ msleep(50); /* Wait in 50ms increments */
++ }
++ printk(KERN_ERR "Usermode failed to halt system\n");
++ kernel_halt(); /* Last resort - may give some oopss */
++}
++
++
++static int argus_ups_probe(struct platform_device *pdev) /* Entry point */
++{
++ struct pinctrl *pinctrl;
++ struct device_node *pnode = pdev->dev.of_node;
++ int i;
++ int ret;
++ printk("Init UPS module - debug=%d, shutdown=%d\n",
++ debug, shutdown);
++ platform_set_drvdata(pdev, &info);
++ info.pdev = pdev;
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ dev_warn(&pdev->dev,
++ "pins are not configured from the driver\n");
++ return -1;
++ }
++ ret = of_property_read_u32(pnode, "debug", &debug);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "Unable to read debug parameter\n");
++ }
++ else {
++ printk("Debug parameter read from DT:%d\n", debug);
++ }
++
++ ret = of_property_read_u32(pnode, "shutdown", &shutdown);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "Unable to read shutdown parameter\n");
++ }
++ else {
++ printk("Shutdown parameter read from DT:%d\n", shutdown);
++ }
++
++ ret = of_gpio_count(pnode);
++
++ if (ret != N_GPIOS) {
++ printk(KERN_ERR "Wrong number of gpios");
++ return -1;
++ }
++
++ for (i = 0; i < of_gpio_count(pnode); i++) {
++ ret = of_get_gpio_flags(pnode, i, NULL);
++ if (debug) {
++ printk("GPIO#%d:%d\n", i, ret);
++ }
++ if (IS_ERR_VALUE(ret)) {
++ dev_err(&pdev->dev, "unable to get GPIO %d\n", i);
++ goto err_no_gpio;
++ }
++ info.gpios[i].gpio = ret;
++ }
++
++
++ ret = alloc_chrdev_region(&argus_ups_dev, 0, 2, "argus_ups");
++ argus_ups_major = MAJOR(argus_ups_dev);
++ if (ret) {
++ printk(KERN_ERR "Error %d adding argus_ups\n", ret);
++ return -1;
++ }
++ if (debug) {
++ printk("argus_ups major: %d\n", argus_ups_major);
++ }
++ argus_ups_cdev = cdev_alloc(); /* Make this a character device */
++ argus_ups_cdev->ops = &argus_ups_fops; /* File operations */
++ argus_ups_cdev->owner = THIS_MODULE; /* Top level device */
++ ret = cdev_add(argus_ups_cdev, argus_ups_dev, 1); /* Add it to the kernel */
++ if (ret) {
++ printk(KERN_ERR "cdev_add returned %d\n", ret);
++ unregister_chrdev_region(0, 1);
++ return -1;
++ }
++ ret = gpio_request_array(info.gpios, N_GPIOS);
++ if (ret) {
++ printk(KERN_ERR "Error %d requesting GPIOs\n", ret);
++ unregister_chrdev_region(0, 1);
++ return -1;
++ }
++
++ argus_ups_class = class_create(THIS_MODULE, "argus_ups"); /* /sys/class entry for udev */
++ if (IS_ERR(argus_ups_class)) {
++ printk(KERN_ERR "Error creating argus_ups_class\n");
++ unregister_chrdev_region(0, 1);
++ return -1;
++ }
++ device_create(argus_ups_class, NULL, MKDEV(argus_ups_major, 0), NULL, "argus_ups");
++ argus_ups_workqueue = create_singlethread_workqueue("argus_ups");
++ INIT_DELAYED_WORK(&argus_ups_work, argus_ups_function);
++ queue_delayed_work(argus_ups_workqueue, &argus_ups_work, 0); /* Start work immediately */
++
++ return 0;
++err_no_gpio:
++ return ret;
++
++}
++
++
++static void argus_ups_cleanup(void)
++{
++ printk("Module cleanup called\n");
++ while (cancel_delayed_work(&argus_ups_work) == 0) {
++ flush_workqueue(argus_ups_workqueue); /* Make sure all work is completed */
++ }
++ destroy_workqueue(argus_ups_workqueue);
++ gpio_free_array(info.gpios, N_GPIOS);
++ device_destroy(argus_ups_class, argus_ups_dev);
++ class_destroy(argus_ups_class);
++ unregister_chrdev_region(argus_ups_dev, 1);
++ cdev_del(argus_ups_cdev);
++}
++
++
++
++static int argus_ups_remove(struct platform_device *pdev)
++{
++ printk("In argus_ups_remove()\n");
++ argus_ups_cleanup();
++ printk("After cleanup\n");
++ return 0;
++}
++
++#define ARGUS_UPS_PM_OPS NULL
++
++struct platform_driver argus_ups_driver = {
++ .probe = argus_ups_probe,
++ .remove = argus_ups_remove,
++ .driver = {
++ .name = "argus-ups",
++ .owner = THIS_MODULE,
++ .pm = ARGUS_UPS_PM_OPS,
++ .of_match_table = argus_ups_of_ids,
++ },
++};
++
++
++static int __init argus_ups_init(void)
++{
++ return platform_driver_probe(&argus_ups_driver,
++ argus_ups_probe);
++}
++
++static void __exit argus_ups_exit(void)
++{
++ platform_driver_unregister(&argus_ups_driver);
++ printk("After driver unregister\n");
++}
++
++module_init(argus_ups_init);
++module_exit(argus_ups_exit);
++
++/*
++ * Get rid of taint message.
++ */
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("David Lambert"); /* Who wrote this module? */
++MODULE_DESCRIPTION("Argus UPS control"); /* What does this module do */
++MODULE_ALIAS("platform:argus-ups");
++MODULE_DEVICE_TABLE(of, argus_ups_of_ids);
+diff --git b/drivers/misc/devovmgr.c b/drivers/misc/devovmgr.c
+new file mode 100644
+index 0000000..d5c8d1d
+--- /dev/null
++++ b/drivers/misc/devovmgr.c
+@@ -0,0 +1,1306 @@
++/*
++ * Device overlay manager
++ *
++ * Copyright (C) 2015 Konsulko Group
++ * Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include <linux/ctype.h>
++#include <linux/cpu.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_fdt.h>
++#include <linux/spinlock.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/configfs.h>
++#include <linux/types.h>
++#include <linux/stat.h>
++#include <linux/limits.h>
++#include <linux/file.h>
++#include <linux/vmalloc.h>
++#include <linux/firmware.h>
++#include <linux/pci.h>
++#include <linux/usb.h>
++#include <linux/mod_devicetable.h>
++#include <linux/workqueue.h>
++#include <linux/firmware.h>
++
++enum dovmgr_type {
++ ITEM_PCI,
++ ITEM_USB
++};
++
++struct dovmgr_item;
++
++struct dovmgr_dev_item {
++ struct dovmgr_item *item;
++ struct list_head node;
++ struct device *dev;
++ const struct firmware *fw;
++ struct device_node *overlay;
++ int overlay_id;
++ struct work_struct work;
++};
++
++struct dovmgr_item {
++ struct config_item item;
++ char *path;
++ bool enable;
++ char *overlay_name;
++ struct mutex dev_item_mutex;
++ struct list_head dev_item_list;
++ enum dovmgr_type type;
++ union {
++ struct pci_device_id pci;
++ struct usb_device_id usb;
++ };
++};
++
++struct config_group dovmgr_pci_group;
++struct config_group dovmgr_usb_group;
++
++static inline struct dovmgr_item *to_dovmgr_item(struct config_item *cfsitem)
++{
++ if (!cfsitem)
++ return NULL;
++
++ return container_of(cfsitem, struct dovmgr_item, item);
++}
++
++static int dovmgr_notifier_action(struct config_group *group,
++ unsigned long action, struct device *dev,
++ int (*do_match)(struct dovmgr_item *item, struct device *dev),
++ int (*do_action)(struct dovmgr_item *item, unsigned long action,
++ struct device *dev))
++{
++ struct config_item *cfsitem;
++ struct dovmgr_item *item;
++ int ret;
++
++ /* only handle device notifiers */
++ if (action != BUS_NOTIFY_ADD_DEVICE &&
++ action != BUS_NOTIFY_DEL_DEVICE &&
++ action != BUS_NOTIFY_REMOVED_DEVICE)
++ return 0;
++
++ ret = 0;
++ list_for_each_entry(cfsitem, &group->cg_children, ci_entry) {
++ item = to_dovmgr_item(cfsitem);
++ if (!item->enable || !(*do_match)(item, dev))
++ continue;
++
++ ret = (*do_action)(item, action, dev);
++ if (ret != 0)
++ break;
++ }
++ return ret;
++}
++
++#if IS_ENABLED(CONFIG_PCI)
++/* copy of drivers/pci/pci.h */
++static inline const struct pci_device_id *
++pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
++{
++ if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
++ (id->device == PCI_ANY_ID || id->device == dev->device) &&
++ (id->subvendor == PCI_ANY_ID ||
++ id->subvendor == dev->subsystem_vendor) &&
++ (id->subdevice == PCI_ANY_ID ||
++ id->subdevice == dev->subsystem_device) &&
++ !((id->class ^ dev->class) & id->class_mask))
++ return id;
++ return NULL;
++}
++
++static int dovmgr_pci_item_match(struct dovmgr_item *item, struct device *dev)
++{
++ struct pci_dev *pdev;
++
++ BUG_ON(item->type != ITEM_PCI);
++ pdev = to_pci_dev(dev);
++
++ return pci_match_one_device(&item->pci, pdev) != NULL;
++}
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++/* in drivers/usb/core/driver.c */
++extern int usb_match_device(struct usb_device *dev,
++ const struct usb_device_id *id);
++
++static int dovmgr_usb_item_match(struct dovmgr_item *item, struct device *dev)
++{
++ struct usb_device *udev;
++
++ BUG_ON(item->type != ITEM_USB);
++ udev = to_usb_device(dev);
++
++ return usb_match_device(udev, &item->usb);
++}
++#endif
++
++static struct dovmgr_dev_item *dovmgr_lookup_dev_item(struct dovmgr_item *item,
++ struct device *dev)
++{
++ struct dovmgr_dev_item *ditem;
++
++ list_for_each_entry(ditem, &item->dev_item_list, node)
++ if (ditem->dev == dev)
++ return ditem;
++ return NULL;
++}
++
++static void dovmgr_item_work_func(struct work_struct *work)
++{
++ struct dovmgr_dev_item *ditem = container_of(work,
++ struct dovmgr_dev_item, work);
++ struct dovmgr_item *item = ditem->item;
++ struct device *dev;
++ struct device_node *np;
++ int err;
++
++ mutex_lock(&item->dev_item_mutex);
++
++ dev = ditem->dev;
++ np = dev->of_node;
++ if (!dev || !np || !item->overlay_name || ditem->overlay_id >= 0)
++ goto out_unlock;
++
++ pr_info("%s: %s %s\n", __func__,
++ kobject_name(&dev->kobj), of_node_full_name(np));
++
++ err = request_firmware_direct(&ditem->fw, item->overlay_name, dev);
++ if (err != 0) {
++ pr_err("%s: %s failed to load firmware '%s'\n", __func__,
++ kobject_name(&dev->kobj), item->overlay_name);
++ goto out_unlock;
++ }
++
++ of_fdt_unflatten_tree((void *)ditem->fw->data, &ditem->overlay);
++ if (ditem->overlay == NULL) {
++ pr_err("%s: %s failed to load firmware '%s'\n", __func__,
++ kobject_name(&dev->kobj), item->overlay_name);
++ goto out_release_fw;
++ }
++
++ /* mark it as detached */
++ of_node_set_flag(ditem->overlay, OF_DETACHED);
++
++ /* perform resolution */
++ err = of_resolve_phandles(ditem->overlay);
++ if (err != 0) {
++ pr_err("%s: %s failed to resolve tree\n", __func__,
++ kobject_name(&dev->kobj));
++ goto out_release_overlay;
++ }
++
++ err = of_overlay_create_target_root(ditem->overlay, np);
++ if (err < 0) {
++ pr_err("%s: %s failed to create overlay\n", __func__,
++ kobject_name(&dev->kobj));
++ goto out_release_overlay;
++ }
++ ditem->overlay_id = err;
++
++out_unlock:
++ mutex_unlock(&item->dev_item_mutex);
++ return;
++
++out_release_overlay:
++ /* TODO: free the overlay, we can't right now cause
++ * the unflatten method does not track it */
++ ditem->overlay = NULL;
++out_release_fw:
++ release_firmware(ditem->fw);
++ ditem->fw = NULL;
++ goto out_unlock;
++}
++
++/* dev item list mutex lock must be held */
++static int dovmgr_add_dev_item(struct dovmgr_item *item, struct device *dev)
++{
++ struct dovmgr_dev_item *ditem;
++
++ /* first make sure there's no duplicate */
++ if (dovmgr_lookup_dev_item(item, dev))
++ return -EEXIST;
++
++ /* add the device item */
++ ditem = kzalloc(sizeof(*ditem), GFP_KERNEL);
++ if (!ditem)
++ return -ENOMEM;
++ ditem->overlay_id = -1;
++ ditem->dev = get_device(dev);
++ INIT_WORK(&ditem->work, dovmgr_item_work_func);
++ ditem->item = item;
++
++ list_add_tail(&ditem->node, &item->dev_item_list);
++
++ pr_info("%s: added device %s from item's %s list\n", __func__,
++ kobject_name(&dev->kobj),
++ config_item_name(&item->item));
++
++ /* now schedule the overlay application */
++ if (item->overlay_name)
++ schedule_work(&ditem->work);
++
++ return 0;
++}
++
++static int dovmgr_remove_dev_item(struct dovmgr_item *item, struct device *dev)
++{
++ struct dovmgr_dev_item *ditem;
++
++ /* find it */
++ ditem = dovmgr_lookup_dev_item(item, dev);
++ if (!ditem)
++ return -ENODEV;
++
++ if (work_pending(&ditem->work))
++ cancel_work_sync(&ditem->work);
++
++ if (ditem->overlay_id >= 0) {
++ of_overlay_destroy(ditem->overlay_id);
++ ditem->overlay_id = -1;
++
++ }
++
++ if (ditem->overlay) {
++ /* TODO: free the overlay, we can't right now cause
++ * the unflatten method does not track it */
++ ditem->overlay = NULL;
++ }
++
++ if (ditem->fw) {
++ /* TODO release_firmware(ditem->fw); */
++ release_firmware(ditem->fw);
++ ditem->fw = NULL;
++ }
++
++ put_device(ditem->dev);
++ list_del(&ditem->node);
++
++ kfree(ditem);
++
++ pr_info("%s: removed device %s from item's %s list\n", __func__,
++ kobject_name(&dev->kobj),
++ config_item_name(&item->item));
++
++ return 0;
++}
++
++static int dovmgr_item_notify(struct dovmgr_item *item,
++ unsigned long action, struct device *dev)
++{
++ int ret;
++
++ ret = 0;
++ mutex_lock(&item->dev_item_mutex);
++
++ switch (action) {
++ case BUS_NOTIFY_ADD_DEVICE:
++ pr_info("%s: BUS_NOTIFY_ADD_DEVICE for %s\n", __func__,
++ kobject_name(&dev->kobj));
++
++ ret = dovmgr_add_dev_item(item, dev);
++ if (ret != 0)
++ goto out_unlock;
++
++ break;
++
++ case BUS_NOTIFY_DEL_DEVICE:
++ pr_info("%s: BUS_NOTIFY_DEL_DEVICE for %s\n", __func__,
++ kobject_name(&dev->kobj));
++ break;
++
++ case BUS_NOTIFY_REMOVED_DEVICE:
++ pr_info("%s: BUS_NOTIFY_REMOVE_DEVICE for %s\n", __func__,
++ kobject_name(&dev->kobj));
++
++ ret = dovmgr_remove_dev_item(item, dev);
++ if (ret != 0)
++ goto out_unlock;
++
++ break;
++ }
++
++out_unlock:
++ mutex_unlock(&item->dev_item_mutex);
++
++ return ret;
++}
++
++#if IS_ENABLED(CONFIG_PCI)
++static int dovmgr_pci_add_iterator(struct device *dev, void *data)
++{
++ struct dovmgr_item *item = data;
++
++ /* do add match */
++ if (!item->enable || !dovmgr_pci_item_match(item, dev))
++ return 0;
++
++ pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
++
++ return dovmgr_item_notify(item, BUS_NOTIFY_ADD_DEVICE, dev);
++}
++
++static int dovmgr_pci_removed_iterator(struct device *dev, void *data)
++{
++ struct dovmgr_item *item = data;
++
++ /* do add match */
++ if (item->enable || !dovmgr_pci_item_match(item, dev))
++ return 0;
++
++ pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
++
++ return dovmgr_item_notify(item, BUS_NOTIFY_REMOVED_DEVICE, dev);
++}
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static int dovmgr_usb_add_iterator(struct device *dev, void *data)
++{
++ struct dovmgr_item *item = data;
++
++ /* do add match */
++ if (item->enable || !dovmgr_usb_item_match(item, dev))
++ return 0;
++
++ pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
++
++ return dovmgr_item_notify(item, BUS_NOTIFY_ADD_DEVICE, dev);
++}
++
++static int dovmgr_usb_removed_iterator(struct device *dev, void *data)
++{
++ struct dovmgr_item *item = data;
++
++ /* do add match */
++ if (!item->enable || !dovmgr_usb_item_match(item, dev))
++ return 0;
++
++ pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
++
++ return dovmgr_item_notify(item, BUS_NOTIFY_REMOVED_DEVICE, dev);
++}
++#endif
++
++static int dovmgr_item_set_enable(struct dovmgr_item *item, bool new_enable)
++{
++ int ret;
++
++ if (new_enable == item->enable)
++ return 0;
++
++ item->enable = new_enable;
++ switch (item->type) {
++#if IS_ENABLED(CONFIG_PCI)
++ case ITEM_PCI:
++ ret = bus_for_each_dev(&pci_bus_type, NULL, item,
++ new_enable ? dovmgr_pci_add_iterator :
++ dovmgr_pci_removed_iterator);
++ if (ret != 0)
++ return ret;
++ break;
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ case ITEM_USB:
++ ret = bus_for_each_dev(&usb_bus_type, NULL, item,
++ new_enable ? dovmgr_usb_add_iterator :
++ dovmgr_usb_removed_iterator);
++ if (ret != 0)
++ return ret;
++ break;
++#endif
++ default:
++ break;
++ }
++ return 0;
++}
++
++
++static ssize_t dovmgr_item_str_show(struct dovmgr_item *item,
++ char *page, char **strp)
++{
++ return snprintf(page, PAGE_SIZE, "%s\n",
++ *strp ? *strp : "");
++}
++
++static ssize_t dovmgr_item_str_store(struct dovmgr_item *item,
++ const char *page, size_t count, char **strp)
++{
++ const char *s;
++ int len;
++
++ /* copy to path buffer (and make sure it's always zero terminated */
++ len = strnlen(page, PAGE_SIZE);
++ if (len >= PAGE_SIZE)
++ return -EINVAL;
++ s = page + len;
++ while (len > 0 && *--s == '\n')
++ len--;
++ if (len == 0)
++ return -EINVAL;
++
++ if (*strp)
++ kfree(*strp);
++ *strp = kmalloc(len + 1, GFP_KERNEL);
++ if (!*strp)
++ return -ENOMEM;
++ memcpy(*strp, page, len);
++ (*strp)[len + 1] = '\0';
++
++ return count;
++}
++
++static ssize_t dovmgr_item_path_show(struct config_item *citem, char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return dovmgr_item_str_show(item, page, &item->path);
++}
++
++static ssize_t dovmgr_item_path_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return dovmgr_item_str_store(item, page, count, &item->path);
++}
++
++static ssize_t dovmgr_item_enable_show(struct config_item *citem, char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "%u\n", !!item->enable);
++}
++
++static ssize_t dovmgr_item_enable_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++
++ ret = dovmgr_item_set_enable(item, !!val);
++ if (ret != 0)
++ return ret;
++
++ return count;
++}
++
++static ssize_t dovmgr_item_overlay_show(struct config_item *citem, char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ ssize_t ret;
++
++ mutex_lock(&item->dev_item_mutex);
++ ret = snprintf(page, PAGE_SIZE, "%s\n", item->overlay_name ?
++ item->overlay_name : "");
++ mutex_unlock(&item->dev_item_mutex);
++ return ret;
++};
++
++
++static ssize_t dovmgr_item_overlay_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ ssize_t ret;
++
++ mutex_lock(&item->dev_item_mutex);
++ kfree(item->overlay_name);
++ item->overlay_name = kstrndup(page, PAGE_SIZE, GFP_KERNEL);
++ if (!item->overlay_name)
++ ret = -ENOMEM;
++ else
++ ret = count;
++ mutex_unlock(&item->dev_item_mutex);
++ return ret;
++}
++
++static ssize_t dovmgr_item_status_show(struct config_item *citem, char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ struct dovmgr_dev_item *ditem;
++ char *p, *e;
++ int len;
++
++ p = page;
++ e = page + PAGE_SIZE;
++
++ mutex_lock(&item->dev_item_mutex);
++ list_for_each_entry(ditem, &item->dev_item_list, node) {
++ len = snprintf(p, e - p, "%s:%s:%d\n",
++ kobject_name(&ditem->dev->kobj),
++ of_node_full_name(ditem->dev->of_node),
++ ditem->overlay_id);
++ p += len;
++ if (p >= e - 1)
++ break;
++ }
++ mutex_unlock(&item->dev_item_mutex);
++
++ return p - page;
++}
++
++CONFIGFS_ATTR(dovmgr_item_, path);
++CONFIGFS_ATTR_RO(dovmgr_item_, status);
++CONFIGFS_ATTR(dovmgr_item_, enable);
++CONFIGFS_ATTR(dovmgr_item_, overlay);
++
++#if IS_ENABLED(CONFIG_PCI)
++static ssize_t dovmgr_item_pci_device_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.device);
++}
++
++static ssize_t dovmgr_item_pci_device_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->pci.device = val;
++ return count;
++}
++
++static ssize_t dovmgr_item_pci_vendor_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.vendor);
++}
++
++static ssize_t dovmgr_item_pci_vendor_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->pci.vendor = val;
++ return count;
++}
++
++static ssize_t dovmgr_item_pci_subdevice_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%08x\n", item->pci.subdevice);
++}
++
++static ssize_t dovmgr_item_pci_subdevice_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->pci.subdevice = val;
++ return count;
++}
++
++static ssize_t dovmgr_item_pci_subvendor_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%08x\n", item->pci.subvendor);
++}
++
++static ssize_t dovmgr_item_pci_subvendor_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->pci.subvendor = val;
++ return count;
++}
++
++static ssize_t dovmgr_item_pci_class_show(struct config_item *citem, char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.class);
++}
++
++static ssize_t dovmgr_item_pci_class_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->pci.class = val;
++ return count;
++}
++
++static ssize_t dovmgr_item_pci_class_mask_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.class_mask);
++}
++
++static ssize_t dovmgr_item_pci_class_mask_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->pci.class_mask = val;
++ return count;
++}
++
++CONFIGFS_ATTR(dovmgr_item_pci_, device);
++CONFIGFS_ATTR(dovmgr_item_pci_, vendor);
++CONFIGFS_ATTR(dovmgr_item_pci_, subdevice);
++CONFIGFS_ATTR(dovmgr_item_pci_, subvendor);
++CONFIGFS_ATTR(dovmgr_item_pci_, class);
++CONFIGFS_ATTR(dovmgr_item_pci_, class_mask);
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static ssize_t dovmgr_item_usb_idProduct_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%04x\n",
++ item->usb.idProduct);
++}
++
++static ssize_t dovmgr_item_usb_idProduct_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->usb.idProduct = val;
++ return count;
++}
++
++static ssize_t dovmgr_item_usb_idVendor_show(struct config_item *citem,
++ char *page)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ return snprintf(page, PAGE_SIZE, "0x%04x\n",
++ item->usb.idVendor);
++}
++
++static ssize_t dovmgr_item_usb_idVendor_store(struct config_item *citem,
++ const char *page, size_t count)
++{
++ struct dovmgr_item *item = to_dovmgr_item(citem);
++ int ret;
++ unsigned int val;
++
++ /* cannot modify when item is enabled */
++ if (item->enable)
++ return -EBUSY;
++
++ ret = kstrtouint(page, 0, &val);
++ if (ret != 0)
++ return ret;
++ item->usb.idVendor = val;
++ return count;
++}
++
++CONFIGFS_ATTR(dovmgr_item_usb_, idProduct);
++CONFIGFS_ATTR(dovmgr_item_usb_, idVendor);
++#endif
++
++#if IS_ENABLED(CONFIG_PCI)
++static struct configfs_attribute *dovmgr_pci_attrs[] = {
++ &dovmgr_item_attr_path,
++ &dovmgr_item_attr_status,
++ &dovmgr_item_attr_enable,
++ &dovmgr_item_attr_overlay,
++ &dovmgr_item_pci_attr_device,
++ &dovmgr_item_pci_attr_vendor,
++ &dovmgr_item_pci_attr_subdevice,
++ &dovmgr_item_pci_attr_subvendor,
++ &dovmgr_item_pci_attr_class,
++ &dovmgr_item_pci_attr_class_mask,
++ NULL,
++};
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static struct configfs_attribute *dovmgr_usb_attrs[] = {
++ &dovmgr_item_attr_path,
++ &dovmgr_item_attr_enable,
++ &dovmgr_item_attr_status,
++ &dovmgr_item_attr_overlay,
++ &dovmgr_item_usb_attr_idVendor,
++ &dovmgr_item_usb_attr_idProduct,
++ NULL,
++};
++#endif
++
++static void dovmgr_release(struct config_item *cfsitem)
++{
++ struct dovmgr_item *item = to_dovmgr_item(cfsitem);
++
++ /* disable item (this removes the overlay and all) */
++ dovmgr_item_set_enable(item, false);
++
++ kfree(item->path);
++ kfree(item);
++}
++
++static struct configfs_item_operations dovmgr_item_ops = {
++ .release = dovmgr_release,
++};
++
++#if IS_ENABLED(CONFIG_PCI)
++static struct config_item_type dovmgr_pci_item_type = {
++ .ct_item_ops = &dovmgr_item_ops,
++ .ct_attrs = dovmgr_pci_attrs,
++ .ct_owner = THIS_MODULE,
++};
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static struct config_item_type dovmgr_usb_item_type = {
++ .ct_item_ops = &dovmgr_item_ops,
++ .ct_attrs = dovmgr_usb_attrs,
++ .ct_owner = THIS_MODULE,
++};
++#endif
++
++static struct config_item *dovmgr_group_make_item(
++ struct config_group *group, const char *name,
++ enum dovmgr_type type)
++{
++ struct dovmgr_item *item;
++ struct config_item_type *item_type;
++
++ switch (type) {
++#if IS_ENABLED(CONFIG_PCI)
++ case ITEM_PCI:
++ item_type = &dovmgr_pci_item_type;
++ break;
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ case ITEM_USB:
++ item_type = &dovmgr_usb_item_type;
++ break;
++#endif
++ default:
++ return ERR_PTR(-EINVAL);
++ };
++
++ item = kzalloc(sizeof(*item), GFP_KERNEL);
++ if (!item)
++ return ERR_PTR(-ENOMEM);
++
++ item->type = type;
++ item->enable = false;
++ mutex_init(&item->dev_item_mutex);
++ INIT_LIST_HEAD(&item->dev_item_list);
++
++ switch (type) {
++#if IS_ENABLED(CONFIG_PCI)
++ case ITEM_PCI:
++ /* default for matching device/vendor */
++ item->pci.vendor = PCI_ANY_ID;
++ item->pci.device = PCI_ANY_ID;
++ item->pci.subvendor = PCI_ANY_ID;
++ item->pci.subdevice = PCI_ANY_ID;
++ item->pci.class = 0;
++ item->pci.class_mask = 0;
++ break;
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ case ITEM_USB:
++ /* default */
++ item->usb.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
++ break;
++#endif
++ default:
++ return ERR_PTR(-EINVAL);
++ };
++
++ config_item_init_type_name(&item->item, name, item_type);
++ return &item->item;
++}
++
++#if IS_ENABLED(CONFIG_PCI)
++static struct config_item *dovmgr_group_pci_make_item(
++ struct config_group *group, const char *name)
++{
++ return dovmgr_group_make_item(group, name, ITEM_PCI);
++}
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static struct config_item *dovmgr_group_usb_make_item(
++ struct config_group *group, const char *name)
++{
++ return dovmgr_group_make_item(group, name, ITEM_USB);
++}
++#endif
++
++static void dovmgr_group_drop_item(struct config_group *group,
++ struct config_item *cfsitem)
++{
++ struct dovmgr_item *item = to_dovmgr_item(cfsitem);
++
++ switch (item->type) {
++#if IS_ENABLED(CONFIG_PCI)
++ case ITEM_PCI:
++ break;
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ case ITEM_USB:
++ break;
++#endif
++ default:
++ break;
++ }
++ config_item_put(&item->item);
++}
++
++#if IS_ENABLED(CONFIG_PCI)
++static struct configfs_group_operations dovmgr_pci_group_ops = {
++ .make_item = dovmgr_group_pci_make_item,
++ .drop_item = dovmgr_group_drop_item,
++};
++
++static struct config_item_type dovmgr_pci_type = {
++ .ct_group_ops = &dovmgr_pci_group_ops,
++ .ct_owner = THIS_MODULE,
++};
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static struct configfs_group_operations dovmgr_usb_group_ops = {
++ .make_item = dovmgr_group_usb_make_item,
++ .drop_item = dovmgr_group_drop_item,
++};
++
++static struct config_item_type dovmgr_usb_type = {
++ .ct_group_ops = &dovmgr_usb_group_ops,
++ .ct_owner = THIS_MODULE,
++};
++#endif
++
++static struct configfs_group_operations dovmgr_ops = {
++ /* empty - we don't allow anything to be created */
++};
++
++static struct config_item_type dovmgr_type = {
++ .ct_group_ops = &dovmgr_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++struct config_group *dovmgr_def_groups[] = {
++#if IS_ENABLED(CONFIG_PCI)
++ &dovmgr_pci_group,
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ &dovmgr_usb_group,
++#endif
++ NULL
++};
++
++static struct configfs_subsystem dovmgr_subsys = {
++ .su_group = {
++ .cg_item = {
++ .ci_namebuf = "dovmgr",
++ .ci_type = &dovmgr_type,
++ },
++ .default_groups = dovmgr_def_groups,
++ },
++ .su_mutex = __MUTEX_INITIALIZER(dovmgr_subsys.su_mutex),
++};
++
++#if IS_ENABLED(CONFIG_PCI)
++static int pci_dev_instantiate(struct pci_dev *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device *bus_dev;
++ struct of_changeset cset;
++ struct device_node *np, *npb;
++ int ret;
++
++ npb = NULL;
++
++ /* already instantiated */
++ if (dev->of_node) {
++ pr_debug("%s: dev=%s of_node=%s\n", __func__,
++ kobject_name(&dev->kobj),
++ of_node_full_name(dev->of_node));
++ return 0;
++ }
++
++ bus_dev = &pdev->bus->dev;
++
++ pr_debug("%s: %s: %02x:%02x.%02x - node %s%s\n", __func__,
++ kobject_name(&dev->kobj),
++ pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
++ bus_dev->of_node ? of_node_full_name(bus_dev->of_node) : "<NULL>",
++ pci_is_bridge(pdev) ? " bridge" : "");
++
++ /* to create the node, the bus must be present */
++ if (!bus_dev->of_node) {
++ pr_err("%s: No node for %s because no bus device node\n",
++ __func__, kobject_name(&dev->kobj));
++ return 0;
++ }
++
++ of_changeset_init(&cset);
++
++ np = of_changeset_create_device_node(&cset, bus_dev->of_node,
++ "%s/pci-%04x-%02x-%02x.%d",
++ of_node_full_name(bus_dev->of_node),
++ pci_domain_nr(pdev->bus), pdev->bus->number,
++ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
++ if (IS_ERR(np)) {
++ ret = PTR_ERR(np);
++ goto out_cset_fail;
++ }
++
++ ret = of_changeset_add_property_stringf(&cset, np, "compatible",
++ "pciclass,%04x", (pdev->class >> 8) & 0xffffff);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_u32(&cset, np, "vendor",
++ pdev->vendor);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_u32(&cset, np, "device",
++ pdev->device);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_string(&cset, np, "status", "okay");
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_bool(&cset, np, "auto-generated");
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_attach_node(&cset, np);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ /* are we creating a bridge; swell */
++ npb = NULL;
++ if (pci_is_bridge(pdev) && !pdev->subordinate->dev.of_node) {
++
++ pr_debug("%s: %s: bus->dev=%s subordinate=%s\n", __func__,
++ kobject_name(&dev->kobj),
++ kobject_name(&pdev->bus->dev.kobj),
++ kobject_name(&pdev->subordinate->dev.kobj));
++
++ npb = of_changeset_create_device_node(&cset, bus_dev->of_node,
++ "%s/pci-%04x-%02x",
++ of_node_full_name(bus_dev->of_node),
++ pci_domain_nr(pdev->subordinate),
++ pdev->subordinate->number);
++ if (IS_ERR(npb)) {
++ ret = PTR_ERR(npb);
++ goto out_cset_fail;
++ }
++
++ ret = of_changeset_add_property_string(&cset, npb, "compatible", "generic,pci-bus");
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_string(&cset, npb, "device_type", "pci");
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_string(&cset, npb, "status", "okay");
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_add_property_bool(&cset, npb, "auto-generated");
++ if (ret != 0)
++ goto out_cset_fail;
++
++ ret = of_changeset_attach_node(&cset, npb);
++ if (ret != 0)
++ goto out_cset_fail;
++ }
++
++ ret = of_changeset_apply(&cset);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ /* permanently commit */
++ of_changeset_destroy(&cset);
++
++ /* bind the node to the device */
++ dev->of_node = np;
++ ret = sysfs_create_link(&dev->kobj, &dev->of_node->kobj,
++ "of_node");
++ if (ret)
++ pr_warn("%s: %s Error %d creating of_node link\n",
++ __func__, kobject_name(&dev->kobj), ret);
++
++ if (npb) {
++ pdev->subordinate->dev.of_node = npb;
++ ret = sysfs_create_link(&pdev->subordinate->dev.kobj, &npb->kobj,
++ "of_node");
++ if (ret)
++ pr_warn("%s: %s Error %d creating of_node link\n",
++ __func__, kobject_name(&dev->kobj), ret);
++ }
++
++
++ return 0;
++
++out_cset_fail:
++ pr_err("%s: %s Failed to apply changeset (err=%d)\n", __func__,
++ kobject_name(&dev->kobj), ret);
++ of_changeset_destroy(&cset);
++ return ret;
++}
++
++static int pci_dev_uninstantiate(struct pci_dev *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np, *npb;
++ struct of_changeset cset;
++ int ret;
++
++ /* device node must exist */
++ np = dev->of_node;
++ if (!np)
++ return 0;
++
++ /* and the auto-generated property */
++ if (!of_property_read_bool(np, "auto-generated"))
++ return 0;
++
++ of_changeset_init(&cset);
++
++ ret = of_changeset_detach_node(&cset, np);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ npb = NULL;
++ if (pci_is_bridge(pdev))
++ npb = pdev->subordinate->dev.of_node;
++
++ if (npb != NULL) {
++ ret = of_changeset_detach_node(&cset, npb);
++ if (ret != 0)
++ goto out_cset_fail;
++ }
++
++ ret = of_changeset_apply(&cset);
++ if (ret != 0)
++ goto out_cset_fail;
++
++ dev->of_node = NULL;
++ if (npb != NULL)
++ pdev->subordinate->dev.of_node = NULL;
++
++ pr_debug("%s: %s: %02x:%02x.%02x\n", __func__,
++ kobject_name(&dev->kobj),
++ pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
++
++ /* TODO iterate over the properties and free */
++
++ return 0;
++
++out_cset_fail:
++ of_changeset_destroy(&cset);
++
++ return ret;
++}
++
++static int dovmgr_pci_notify(struct notifier_block *nb,
++ unsigned long action, void *arg)
++{
++ int ret;
++
++ if (action == BUS_NOTIFY_ADD_DEVICE)
++ pci_dev_instantiate(to_pci_dev(arg));
++
++ ret = dovmgr_notifier_action(&dovmgr_pci_group, action, arg,
++ dovmgr_pci_item_match, dovmgr_item_notify);
++
++ if (action == BUS_NOTIFY_REMOVED_DEVICE)
++ pci_dev_uninstantiate(to_pci_dev(arg));
++
++ return ret;
++}
++
++static struct notifier_block dovmgr_pci_notifier = {
++ .notifier_call = dovmgr_pci_notify,
++};
++
++static int pci_instantiate_iterator(struct device *dev, void *data)
++{
++ return pci_dev_instantiate(to_pci_dev(dev));
++}
++
++static int dovmgr_pci_init(void)
++{
++ int ret;
++
++ config_group_init_type_name(&dovmgr_pci_group, "pci", &dovmgr_pci_type);
++ ret = bus_register_notifier(&pci_bus_type, &dovmgr_pci_notifier);
++ if (ret != 0) {
++ pr_err("%s: bus_register_notifier() failed\n", __func__);
++ return ret;
++ }
++
++ ret = bus_for_each_dev(&pci_bus_type, NULL, NULL,
++ pci_instantiate_iterator);
++ if (ret != 0) {
++ pr_err("%s: bus_for_each_dev() failed\n", __func__);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void dovmgr_pci_cleanup(void)
++{
++ bus_unregister_notifier(&pci_bus_type, &dovmgr_pci_notifier);
++}
++#endif
++
++#if IS_ENABLED(CONFIG_USB)
++static int dovmgr_usb_notify(struct notifier_block *nb,
++ unsigned long action, void *arg)
++{
++ return dovmgr_notifier_action(&dovmgr_usb_group, action, arg,
++ dovmgr_usb_item_match, dovmgr_item_notify);
++}
++
++static struct notifier_block dovmgr_usb_notifier = {
++ .notifier_call = dovmgr_usb_notify,
++};
++
++static int dovmgr_usb_init(void)
++{
++ int ret;
++
++ config_group_init_type_name(&dovmgr_usb_group, "usb", &dovmgr_usb_type);
++ ret = bus_register_notifier(&usb_bus_type, &dovmgr_usb_notifier);
++ if (ret != 0) {
++ pr_err("%s: bus_register_notifier() failed\n", __func__);
++ return ret;
++ }
++ return 0;
++}
++
++static void dovmgr_usb_cleanup(void)
++{
++ bus_unregister_notifier(&usb_bus_type, &dovmgr_usb_notifier);
++}
++#endif
++
++static int __init dovmgr_init(void)
++{
++ int ret;
++
++ config_group_init(&dovmgr_subsys.su_group);
++#if IS_ENABLED(CONFIG_PCI)
++ configfs_add_default_group(&dovmgr_pci_group,
++ &dovmgr_subsys.su_group);
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ configfs_add_default_group(&dovmgr_usb_group,
++ &dovmgr_subsys.su_group);
++#endif
++
++#if IS_ENABLED(CONFIG_PCI)
++ ret = dovmgr_pci_init();
++ if (ret != 0)
++ goto err_no_pci_init;
++#endif
++#if IS_ENABLED(CONFIG_USB)
++ ret = dovmgr_usb_init();
++ if (ret != 0)
++ goto err_no_usb_init;
++#endif
++
++ ret = configfs_register_subsystem(&dovmgr_subsys);
++ if (ret != 0) {
++ pr_err("%s: failed to register subsys\n", __func__);
++ goto err_no_configfs;
++ }
++ pr_info("%s: OK\n", __func__);
++ return 0;
++
++err_no_configfs:
++#if IS_ENABLED(CONFIG_USB)
++ dovmgr_usb_cleanup();
++err_no_usb_init:
++#endif
++#if IS_ENABLED(CONFIG_PCI)
++ dovmgr_pci_cleanup();
++err_no_pci_init:
++#endif
++ return ret;
++}
++late_initcall(dovmgr_init);
+diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
+index 051b147..3cdf8e1 100644
+--- a/drivers/misc/eeprom/at24.c
++++ b/drivers/misc/eeprom/at24.c
+@@ -593,7 +593,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ struct at24_data *at24;
+ int err;
+ unsigned i, num_addresses;
+- u8 test_byte;
+
+ if (client->dev.platform_data) {
+ chip = *(struct at24_platform_data *)client->dev.platform_data;
+@@ -744,18 +743,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ }
+ }
+
+- i2c_set_clientdata(client, at24);
+-
+- /*
+- * Perform a one-byte test read to verify that the
+- * chip is functional.
+- */
+- err = at24_read(at24, 0, &test_byte, 1);
+- if (err) {
+- err = -ENODEV;
+- goto err_clients;
+- }
+-
+ at24->nvmem_config.name = dev_name(&client->dev);
+ at24->nvmem_config.dev = &client->dev;
+ at24->nvmem_config.read_only = !writable;
+@@ -777,6 +764,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ goto err_clients;
+ }
+
++ i2c_set_clientdata(client, at24);
++
+ dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
+ chip.byte_len, client->name,
+ writable ? "writable" : "read-only", at24->write_max);
+diff --git b/drivers/misc/tieqep.c b/drivers/misc/tieqep.c
+new file mode 100644
+index 0000000..bb69ad4
+--- /dev/null
++++ b/drivers/misc/tieqep.c
+@@ -0,0 +1,754 @@
++/*
++ * TI eQEP driver for AM33xx devices
++ *
++ * Copyright (C) 2013 Nathaniel R. Lewis - http://teknoman117.wordpress.com/
++ * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * sysfs entries
++ * - position = absolute - current position; relative - last latched value
++ * - mode => 0 - absolute; 1 - relative
++ * - period => sampling period for the hardware
++ * - enable => 0 - eQEP disabled, 1 - eQEP enabled
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/pm_runtime.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/input.h>
++
++/* eQEP register offsets from its base IO address */
++#define QPOSCNT 0x0000
++#define QPOSINIT 0x0004
++#define QPOSMAX 0x0008
++#define QPOSCMP 0x000C
++#define QPOSILAT 0x0010
++#define QPOSSLAT 0x0014
++#define QPOSLAT 0x0018
++#define QUTMR 0x001C
++#define QUPRD 0x0020
++#define QWDTMR 0x0024
++#define QWDPRD 0x0026
++#define QDECCTL 0x0028
++#define QEPCTL 0x002A
++#define QCAPCTL 0x002C
++#define QPOSCTL 0x002E
++#define QEINT 0x0030
++#define QFLG 0x0032
++#define QCLR 0x0034
++#define QFRC 0x0036
++#define QEPSTS 0x0038
++#define QCTMR 0x003A
++#define QCPRD 0x003C
++#define QCTMRLAT 0x003E
++#define QCPRDLAT 0x0040
++#define QREVID 0x005C
++
++#if 0 /* if you wanted another way to modify IP registers... */
++typedef volatile u32 REG32;
++typedef volatile u16 REG16;
++struct EQEP_REGS {
++ REG32 q_poscnt; /* 0x00 position counter */
++ REG32 q_posinit; /* 0x04 position counter initialization */
++ REG32 q_posmax; /* 0x08 maximum position count */
++ REG32 q_poscmp; /* 0x0C position compare */
++ REG32 q_posilat; /* 0x10 index position latch */
++ REG32 q_posslat; /* 0x14 strobe position latch */
++ REG32 q_poslat; /* 0x18 position counter latch */
++ REG32 q_utmr; /* 0x1C unit timer */
++ REG32 q_uprd; /* 0x20 unit period */
++ REG16 q_wdtmr; /* 0x24 watchdog timer */
++ REG16 q_wdprd; /* 0x26 watchdog period */
++ REG16 q_decctl; /* 0x28 decoder control */
++ REG16 q_epctl; /* 0x2A control register */
++ REG16 q_capctl; /* 0x2C capture control */
++ REG16 q_posctl; /* 0x2E position compare control */
++ REG16 q_eint; /* 0x30 interrupt enable */
++ REG16 q_flg; /* 0x32 interrupt flag */
++ REG16 q_clr; /* 0x34 interrupt clear */
++ REG16 q_frc; /* 0x36 interrupt force */
++ REG16 q_epsts; /* 0x38 status */
++ REG16 q_ctmr; /* 0x3A capture timer */
++ REG16 q_cprd; /* 0x3C capture period */
++ REG16 q_ctmrlat; /* 0x3E capture timer latch */
++ REG16 q_prdlat; /* 0x40 capture period latch */
++ char q_fill1[0x5c-0x40];
++ REG32 q_revid; /* 0x5C revision id */
++};
++#endif
++
++
++/* Bits for the QDECTL register */
++#define QSRC1 (1 << 15)
++#define QSRC0 (1 << 14)
++#define SOEN (1 << 13)
++#define SPSEL (1 << 12)
++#define XCR (1 << 11)
++#define SWAP (1 << 10)
++#define IGATE (1 << 9)
++#define QAP (1 << 8)
++#define QBP (1 << 7)
++#define QIP (1 << 6)
++#define QSP (1 << 5)
++
++/* Bits for the QEPCTL register */
++#define FREESOFT1 (1 << 15)
++#define FREESOFT0 (1 << 14)
++#define PCRM1 (1 << 13)
++#define PCRM0 (1 << 12)
++#define SEI1 (1 << 11)
++#define SEI0 (1 << 10)
++#define IEI1 (1 << 9)
++#define IEI0 (1 << 8)
++#define SWI (1 << 7)
++#define SEL (1 << 6)
++#define IEL1 (1 << 5)
++#define IEL0 (1 << 4)
++#define PHEN (1 << 3)
++#define QCLM (1 << 2)
++#define UTE (1 << 1)
++#define WDE (1 << 0)
++
++/* Bits for the QCAPCTL register */
++#define CEN (1 << 15)
++#define CCPS2 (1 << 6)
++#define CCPS0 (1 << 5)
++#define CCPS1 (1 << 4)
++#define UPPS3 (1 << 3)
++#define UPPS2 (1 << 2)
++#define UPPS1 (1 << 1)
++#define UPPS0 (1 << 0)
++
++/* Bits for the QPOSCTL register */
++#define PCSHDW (1 << 15)
++#define PCLOAD (1 << 14)
++#define PCPOL (1 << 13)
++#define PCE (1 << 12)
++#define PCSPW11 (1 << 11)
++#define PCSPW10 (1 << 10)
++#define PCSPW9 (1 << 9)
++#define PCSPW8 (1 << 8)
++#define PCSPW7 (1 << 7)
++#define PCSPW6 (1 << 6)
++#define PCSPW5 (1 << 5)
++#define PCSPW4 (1 << 4)
++#define PCSPW3 (1 << 3)
++#define PCSPW2 (1 << 2)
++#define PCSPW1 (1 << 1)
++#define PCSPW0 (1 << 0)
++
++/* Bits for the interrupt registers */
++#define EQEP_INTERRUPT_MASK 0x0FFF
++#define UTOF (1 << 11)
++
++/* Bits to control the clock in the PWMSS subsystem */
++#define PWMSS_EQEPCLK_EN BIT(4)
++#define PWMSS_EQEPCLK_STOP_REQ BIT(5)
++#define PWMSS_EQEPCLK_EN_ACK BIT(4)
++
++/*
++ * Modes for the eQEP unit
++ * Absolute - the position entry represents the current position of the encoder.
++ * Poll this value and it will be notified every period nanoseconds
++ * Relative - the position entry represents the last latched position of the encoder
++ * This value is latched every period nanoseconds and the internal counter
++ * is subsequenty reset
++ */
++#define TIEQEP_MODE_ABSOLUTE 0
++#define TIEQEP_MODE_RELATIVE 1
++
++/* Structure defining the characteristics of the eQEP unit */
++struct eqep_chip
++{
++ /* Platform device for this eQEP unit */
++ struct platform_device *pdev;
++
++ /* Pointer to the base of the memory of the eQEP unit */
++ void __iomem *mmio_base;
++
++ /* SYSCLKOUT to the eQEP unit */
++ u32 clk_rate;
++
++ /* IRQ for the eQEP unit */
++ u16 irq;
++
++ /* Mode of the eQEP unit */
++ u8 op_mode;
++
++ /* work stuct for the notify userspace work */
++ struct work_struct notify_work;
++
++ /* Backup for driver suspension */
++ u16 prior_qepctl;
++ u16 prior_qeint;
++};
++
++/* Notify userspace work */
++static void notify_handler(struct work_struct *work)
++{
++ /* Get a reference to the eQEP driver */
++ struct eqep_chip *eqep = container_of(work, struct eqep_chip, notify_work);
++
++ /* Notify the userspace */
++ sysfs_notify(&eqep->pdev->dev.kobj, NULL, "position");
++}
++
++/* eQEP Interrupt handler */
++static irqreturn_t eqep_irq_handler(int irq, void *dev_id)
++{
++ /* Get the instance information */
++ struct platform_device *pdev = dev_id;
++ struct eqep_chip *eqep = platform_get_drvdata(pdev);
++
++ /* Get the interrupt flags */
++ u16 iflags = readw(eqep->mmio_base + QFLG) & EQEP_INTERRUPT_MASK;
++
++ /* Check the interrupt source(s) */
++ if (iflags & UTOF) {
++ /* Handle the unit timer overflow interrupt by notifying any potential pollers */
++ schedule_work(&eqep->notify_work);
++ }
++
++ /* Clear interrupt flags (write back triggered flags to the clear register) */
++ writew(iflags, eqep->mmio_base + QCLR);
++
++ /* Return that the IRQ was handled successfully */
++ return IRQ_HANDLED;
++}
++
++/* Function to read whether the eQEP unit is enabled or disabled */
++static ssize_t eqep_get_enabled(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ /* Get the instance structure */
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++ u16 enabled = 0;
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++
++ /* Read the qep control register and mask all but the enabled bit */
++ enabled = readw(eqep->mmio_base + QEPCTL) & PHEN;
++
++ /* Return the target in string format */
++ return sprintf(buf, "%u\n", (enabled) ? 1 : 0);
++}
++
++/* Function to set if the eQEP is enabled */
++static ssize_t eqep_set_enabled(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ /* Get the instance structure */
++ int rc;
++ u16 val;
++ u8 enabled;
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ /* Convert the input string to an 8 bit uint */
++ if ((rc = kstrtou8(buf, 0, &enabled)))
++ return rc;
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++ /* Get the existing state of QEPCTL */
++ val = readw(eqep->mmio_base + QEPCTL);
++
++ /* If we passed a number that is not 0, enable the eQEP */
++ if (enabled)
++ /* Enable the eQEP (Set PHEN in QEPCTL) */
++ val |= PHEN;
++ else
++ /* Disable the eQEP (Clear PHEN in QEPCTL) */
++ val &= ~PHEN;
++
++ /* Write flags back to control register */
++ writew(val, eqep->mmio_base + QEPCTL);
++
++ /* Return buffer length consumed (all) */
++ return count;
++}
++
++/* Function to read the current position of the eQEP */
++static ssize_t eqep_get_position(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ s32 position = 0;
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++
++ if (eqep->op_mode == TIEQEP_MODE_ABSOLUTE) {
++ position = readl(eqep->mmio_base + QPOSCNT);
++ } else if (eqep->op_mode == TIEQEP_MODE_RELATIVE) {
++ /* in relative mode, use the last latched value of the eQEP hardware */
++ position = readl(eqep->mmio_base + QPOSLAT);
++ dev_dbg(dev, "get_position:0x%08x\n", position);
++ }
++
++ return sprintf(buf, "%d\n", position);
++}
++
++/* Function to set the position of the eQEP hardware */
++static ssize_t eqep_set_position(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ int rc;
++ s32 position;
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ if ((rc = kstrtos32(buf, 0, &position)))
++ return rc;
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++ /*
++ * If we are in absolute mode, set the position of the encoder,
++ * discard relative mode because thats pointless
++ */
++ if (eqep->op_mode == TIEQEP_MODE_ABSOLUTE) {
++ /* If absolute mode, set the current value of the eQEP hardware */
++ writel(position, eqep->mmio_base + QPOSCNT);
++ }
++
++ /* Return buffer length consumed (all) */
++ return count;
++}
++
++/* Function to read the period of the unit time event timer */
++static ssize_t eqep_get_timer_period(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++ u64 period;
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++ /* Convert from counts per interrupt back into period_ns */
++ period = readl(eqep->mmio_base + QUPRD);
++ period = period * NSEC_PER_SEC;
++ do_div(period, eqep->clk_rate);
++
++ /* Otherwise write out the data */
++ return sprintf(buf, "%llu\n", period);
++}
++
++/* Function to set the unit timer period. 0 = off, greater than zero sets the period */
++static ssize_t eqep_set_timer_period(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ int rc;
++ u16 tmp;
++ u64 period;
++
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ if ((rc = kstrtou64(buf, 0, &period)))
++ return rc;
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++ /* Disable the unit timer before modifying its period register */
++ tmp = readw(eqep->mmio_base + QEPCTL);
++ tmp &= ~(UTE | QCLM);
++ writew(tmp, eqep->mmio_base + QEPCTL);
++
++ /* Zero the unit timer counter register */
++ writel(0, eqep->mmio_base + QUTMR);
++
++ /* If the timer is enabled (a non-zero period has been passed) */
++ if (period) {
++ /* update the period */
++ period = period * eqep->clk_rate;
++ do_div(period, NSEC_PER_SEC);
++
++ dev_dbg(dev, "eqep_set_timer_period:%llu\n", period);
++
++ writel(period, eqep->mmio_base + QUPRD);
++
++ /* Enable unit timer, and latch QPOSLAT to QPOSCNT on timer expiration */
++ tmp |= UTE | QCLM;
++ writew(tmp, eqep->mmio_base + QEPCTL);
++ }
++
++ return count;
++}
++
++/* Function to read the mode of the eQEP hardware */
++static ssize_t eqep_get_mode(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%u\n", eqep->op_mode);
++}
++
++/* Function to set the mode of the eQEP hardware */
++static ssize_t eqep_set_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ int rc;
++ u16 val;
++ u8 tmp_mode;
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ if ((rc = kstrtou8(buf, 0, &tmp_mode)))
++ return rc;
++
++ dev_dbg(dev, "eqep_set_mode:%d\n", tmp_mode);
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++ val = readw(eqep->mmio_base + QEPCTL);
++
++ if (tmp_mode == TIEQEP_MODE_ABSOLUTE) {
++ /*
++ * In absolute mode, don't reset the hardware based on time,
++ * so disable the unit timer position reset (Set PCRM[1:0] = 0)
++ */
++ val &= ~(PCRM1 | PCRM0);
++
++ eqep->op_mode = TIEQEP_MODE_ABSOLUTE;
++ } else if (tmp_mode == TIEQEP_MODE_RELATIVE) {
++ /*
++ * In relative mode, latch the value of the eQEP hardware on the
++ * overflow of the unit timer. So enable the unit timer position reset
++ * (Set PCRM[1:0] = 3)
++ */
++ val |= PCRM1 | PCRM0;
++
++ eqep->op_mode = TIEQEP_MODE_RELATIVE;
++ }
++
++ writew(val, eqep->mmio_base + QEPCTL);
++
++ return count;
++}
++
++/* Bind read/write functions to sysfs entries */
++static DEVICE_ATTR(enabled, 0644, eqep_get_enabled, eqep_set_enabled);
++static DEVICE_ATTR(position, 0644, eqep_get_position, eqep_set_position);
++static DEVICE_ATTR(period, 0644, eqep_get_timer_period, eqep_set_timer_period);
++static DEVICE_ATTR(mode, 0644, eqep_get_mode, eqep_set_mode);
++
++/* Array holding all of the sysfs entries */
++static const struct attribute *eqep_attrs[] = {
++ &dev_attr_enabled.attr,
++ &dev_attr_position.attr,
++ &dev_attr_period.attr,
++ &dev_attr_mode.attr,
++ NULL,
++};
++
++/* Driver function group */
++static const struct attribute_group eqep_device_attr_group = {
++ .attrs = (struct attribute **) eqep_attrs,
++};
++
++/* Driver compatibility list */
++static struct of_device_id eqep_of_match[] =
++{
++ { .compatible = "ti,am33xx-eqep" },
++ { }
++};
++
++/* Register our compatibilities for device trees */
++MODULE_DEVICE_TABLE(of, eqep_of_match);
++
++/* Create an instance of the eQEP driver */
++static int eqep_probe(struct platform_device *pdev)
++{
++ struct resource *r;
++ struct clk *clk;
++ struct eqep_chip *eqep;
++ struct pinctrl *pinctrl;
++
++ u64 period;
++ u16 status;
++ u32 value;
++
++ dev_info(&pdev->dev, "ver. 1.0\n");
++
++ /* Select pins provided through the device tree */
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl))
++ {
++ dev_warn(&pdev->dev, "unable to select pin group\n");
++ }
++
++ /* Allocate a eqep_driver object */
++ eqep = devm_kzalloc(&pdev->dev, sizeof(struct eqep_chip), GFP_KERNEL);
++ if (!eqep) {
++ dev_err(&pdev->dev, "failed to allocate memory\n");
++ return -ENOMEM;
++ }
++
++ /* Get a handle to the system clock object */
++ clk = devm_clk_get(pdev->dev.parent, "fck");
++ if (IS_ERR(clk)) {
++ dev_err(&pdev->dev, "failed to get clock\n");
++ return PTR_ERR(clk);
++ }
++
++ /* Get the frequency of the system clock */
++ eqep->clk_rate = clk_get_rate(clk);
++ if (!eqep->clk_rate) {
++ dev_err(&pdev->dev, "failed to get clock rate\n");
++ return -EINVAL;
++ }
++
++ /* Get a resource containing the IRQ for this eQEP controller */
++ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (unlikely(!r)) {
++ dev_err(&pdev->dev, "Invalid IRQ resource\n");
++ return -ENODEV;
++ }
++
++ /* Store the irq */
++ eqep->irq = r->start;
++
++ /* Get a resource containing the requested (from DT) memory address and range of eQEP controller */
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!r) {
++ dev_err(&pdev->dev, "no memory resource defined\n");
++ return -ENODEV;
++ }
++
++ /* Remap the eQEP controller memory into our own memory space */
++ eqep->mmio_base = devm_ioremap_resource(&pdev->dev, r);
++ if (IS_ERR(eqep->mmio_base))
++ return PTR_ERR(eqep->mmio_base);
++
++ /* Store the platform device in our eQEP data structure for later usage */
++ eqep->pdev = pdev;
++
++ /* Subscribe to the eQEP interrupt */
++ if (request_irq(eqep->irq, eqep_irq_handler, IRQF_IRQPOLL, "eqep_interrupt", pdev))
++ {
++ dev_err(&pdev->dev, "unable to request irq for eQEP\n");
++ return -ENODEV;
++ }
++
++ /* Register controls to sysfs */
++ if (sysfs_create_group(&pdev->dev.kobj, &eqep_device_attr_group))
++ {
++ dev_err(&pdev->dev, "sysfs creation failed\n");
++ return -EINVAL;
++ }
++
++ /* set QDECCTL */
++ status = 0; /* default to Quadrature count mode, QSRC1 & QSRC0 = 0 */
++
++ /* set QSRC1 & QSRC0 bits, one of 4 count_modes. */
++ if (!of_property_read_u32(pdev->dev.of_node, "count_mode", &value) && value <= 3) {
++ status |= value << 14;
++
++ /*
++ * in count up or count down mode, count on rising edge only
++ * not on both edges.
++ */
++ if (value >= 2)
++ status |= XCR;
++ }
++ dev_info(&pdev->dev, "count_mode:%d\n", value);
++
++ /* Should we invert the qa input */
++ if (!of_property_read_u32(pdev->dev.of_node, "invert_qa", &value))
++ status = value ? status | QAP : status & ~QAP;
++ dev_info(&pdev->dev, "invert_qa:%d\n", value);
++
++ /* Should we invert the qb input */
++ if (!of_property_read_u32(pdev->dev.of_node, "invert_qb", &value))
++ status = value ? status | QBP : status & ~QBP;
++ dev_info(&pdev->dev, "invert_qb:%d\n", value);
++
++ /* Should we invert the index input */
++ if (!of_property_read_u32(pdev->dev.of_node, "invert_qi", &value))
++ status = value ? status | QIP : status & ~QIP;
++ dev_info(&pdev->dev, "invert_qi:%d\n", value);
++
++ /* Should we invert the strobe input */
++ if (!of_property_read_u32(pdev->dev.of_node, "invert_qs", &value))
++ status = value ? status | QSP : status & ~QSP;
++ dev_info(&pdev->dev, "invert_qs:%d\n", value);
++
++ /* Should we swap the cha and chb inputs */
++ if (!of_property_read_u32(pdev->dev.of_node, "swap_inputs", &value))
++ status = value ? status | SWAP : status & ~SWAP;
++ dev_info(&pdev->dev, "swap_inputs:%d\n", value);
++
++ dev_info(&pdev->dev, "QDECCTL:0x%04x\n", status);
++
++ /* Write the decoder control settings back to the control register */
++ writew(status, eqep->mmio_base + QDECCTL);
++
++ writel( 0, eqep->mmio_base + QPOSINIT);
++ writel(~0, eqep->mmio_base + QPOSMAX);
++ writel( 0, eqep->mmio_base + QPOSCNT);
++
++ dev_info(&pdev->dev, "QPOSINIT:0x%08x\n", readl(eqep->mmio_base + QPOSINIT));
++ dev_info(&pdev->dev, "QPOSMAX:0x%08x\n", readl(eqep->mmio_base + QPOSMAX));
++ dev_info(&pdev->dev, "QPOSCNT:0x%08x\n", readl(eqep->mmio_base + QPOSCNT));
++
++ status = UTOF; /* Enable Unit Time Period interrupt. */
++ if (!of_property_read_u32(pdev->dev.of_node, "omit_interrupt", &value) && value) {
++ status = 0; /* no interrupt */
++ }
++ writew(status, eqep->mmio_base + QEINT);
++ dev_info(&pdev->dev, "omit_interrupt:%d\n", value);
++ dev_info(&pdev->dev, "QEINT:0x%04x\n", status);
++
++ /* Calculate the timer ticks per second */
++ period = 1000000000;
++ period = period * eqep->clk_rate;
++ do_div(period, NSEC_PER_SEC);
++
++ /* Set this period into the unit timer period register */
++ writel(period, eqep->mmio_base + QUPRD);
++ dev_info(&pdev->dev, "QUPRD:0x%08x\n", (u32) period);
++
++ /*
++ * Enable the eQEP with basic position counting turned on
++ * PHEN - Quadrature position counter enable bit
++ * UTE - unit timer enable
++ * QCLM - latch QPOSLAT to QPOSCNT upon unit timer overflow
++ * IEL0 - Latch QPOSILAT on index signal. Rising or falling, IEL[1:0] = 0 is reserved
++ * SWI - Software initialization of position count register, i.e. set QPOSCNT <= QPOSINIT,
++ * but this bit was not being reset by hardware as advertised in TRM,
++ * (so omit & clear QPOSCNT manually elsewhere?)
++ */
++ status = PHEN | UTE | QCLM | IEL0 | SWI;
++ writew(status, eqep->mmio_base + QEPCTL);
++ dev_info(&pdev->dev, "QEPCTL:0x%04x write\n", status);
++ dev_info(&pdev->dev, "QEPCTL:0x%04x read\n", readw(eqep->mmio_base + QEPCTL));
++
++ /* We default to absolute mode */
++ eqep->op_mode = TIEQEP_MODE_ABSOLUTE;
++
++ /* Enable the power management runtime */
++ pm_runtime_enable(&pdev->dev);
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(&pdev->dev);
++
++ /* Initialize the notify work struture */
++ INIT_WORK(&eqep->notify_work, notify_handler);
++
++ /* Decrement the device usage count (twice) and run pm_runtime_idle() if zero */
++ pm_runtime_put_sync(&pdev->dev);
++
++ /* Set the platform driver data to the data object we've been creating for the eQEP unit */
++ platform_set_drvdata(pdev, eqep);
++
++ /* Success! */
++ dev_info(&pdev->dev, "irq:%d, clk_rate:%u\n", eqep->irq, eqep->clk_rate);
++ return 0;
++}
++
++/* Remove an instance of the eQEP driver */
++static int eqep_remove(struct platform_device *pdev)
++{
++ /* Get the eQEP driver data from the platform device structure */
++ struct eqep_chip *eqep = platform_get_drvdata(pdev);
++
++ /* Cancel work */
++ cancel_work_sync(&eqep->notify_work);
++
++ /* Unmap from sysfs */
++ sysfs_remove_group(&pdev->dev.kobj, &eqep_device_attr_group);
++
++ /* Release important assets */
++ free_irq(eqep->irq, pdev);
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(&pdev->dev);
++
++ /* Decrement the device usage count (twice) and run pm_runtime_idle() if zero */
++ pm_runtime_put_sync(&pdev->dev);
++ pm_runtime_put_sync(&pdev->dev);
++
++ /* Disable the runtime power management of this device */
++ pm_runtime_disable(&pdev->dev);
++
++ /* Return success */
++ return 0;
++}
++
++/* Power management suspend device */
++static int eqep_suspend(struct device *dev)
++{
++ /* Get the eqep driver information */
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++ u16 tmp;
++
++ /* Shut down interrupts */
++ eqep->prior_qeint = readw(eqep->mmio_base + QEINT);
++ tmp = eqep->prior_qeint & ~UTOF;
++ writew(tmp, eqep->mmio_base + QEINT);
++
++ /* Get the existing state of QEPCTL */
++ eqep->prior_qepctl = readw(eqep->mmio_base + QEPCTL);
++
++ /* Disable eQEP controller */
++ writew(eqep->prior_qepctl & ~PHEN, eqep->mmio_base + QEPCTL);
++
++ /* Decrement the device usage count and run pm_runtime_idle() if zero */
++ pm_runtime_put_sync(dev);
++
++ /* Return success */
++ return 0;
++}
++
++/* Power management wake device back up */
++static int eqep_resume(struct device *dev)
++{
++ /* Get the eqep driver information */
++ struct eqep_chip *eqep = dev_get_drvdata(dev);
++
++ /* Restore interrupt enabled register */
++ writew(eqep->prior_qeint, eqep->mmio_base + QEINT);
++
++ /* Restore prior qep control register */
++ writew(eqep->prior_qepctl, eqep->mmio_base + QEPCTL);
++
++ /* Increment the device usage count and run pm_runtime_resume() */
++ pm_runtime_get_sync(dev);
++
++ /* Success */
++ return 0;
++}
++
++/* create pm functions object */
++static SIMPLE_DEV_PM_OPS(eqep_pm_ops, eqep_suspend, eqep_resume);
++
++/* Platform driver information */
++static struct platform_driver eqep_driver = {
++ .driver = {
++ .name = "eqep",
++ .owner = THIS_MODULE,
++ .pm = &eqep_pm_ops,
++ .of_match_table = eqep_of_match,
++ },
++ .probe = eqep_probe,
++ .remove = eqep_remove,
++};
++
++/* Register this platform driver */
++module_platform_driver(eqep_driver);
++
++/* Module information */
++MODULE_DESCRIPTION("TI eQEP driver");
++MODULE_AUTHOR("Nathaniel R. Lewis");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
+index 87a1337..eb57610 100644
+--- a/drivers/misc/tsl2550.c
++++ b/drivers/misc/tsl2550.c
+@@ -177,7 +177,7 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
+ } else
+ lux = 0;
+ else
+- return -EAGAIN;
++ return 0;
+
+ /* LUX range check */
+ return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 709a872..288cb38 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -36,6 +36,7 @@
+ #include <linux/compat.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/idr.h>
++#include <linux/of.h>
+
+ #include <linux/mmc/ioctl.h>
+ #include <linux/mmc/card.h>
+@@ -2219,13 +2220,20 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ {
+ struct mmc_blk_data *md;
+ int devidx, ret;
++ int mindynidx = max(0, of_alias_get_highest_id("mmc") + 1);
++ int reqidx = card->host->index;
+
+ again:
+ if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL))
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock(&mmc_blk_lock);
+- ret = ida_get_new(&mmc_blk_ida, &devidx);
++ ret = ida_get_new_above(&mmc_blk_ida, reqidx, &devidx);
++ if (!ret && devidx < mindynidx && devidx != reqidx) {
++ // requested index in use, fall back to dynamic
++ ida_remove(&mmc_blk_ida, devidx);
++ ret = ida_get_new_above(&mmc_blk_ida, mindynidx, &devidx);
++ }
+ spin_unlock(&mmc_blk_lock);
+
+ if (ret == -EAGAIN)
+diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
+index 848b345..2ae45ee 100644
+--- a/drivers/mmc/core/host.c
++++ b/drivers/mmc/core/host.c
+@@ -344,6 +344,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+ {
+ int err;
+ struct mmc_host *host;
++ int mindynidx = max(0, of_alias_get_highest_id("mmc") + 1);
++ int reqidx = dev->of_node ? of_alias_get_id(dev->of_node, "mmc") : -1;
+
+ host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+ if (!host)
+@@ -359,7 +361,16 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+ }
+
+ spin_lock(&mmc_host_lock);
+- err = ida_get_new(&mmc_host_ida, &host->index);
++ if (reqidx >= 0) {
++ err = ida_get_new_above(&mmc_host_ida, reqidx, &host->index);
++ if (!err && host->index != reqidx) {
++ // requested index in use, fall back to dynamic
++ ida_remove(&mmc_host_ida, host->index);
++ reqidx = -1;
++ }
++ }
++ if (reqidx < 0)
++ err = ida_get_new_above(&mmc_host_ida, mindynidx, &host->index);
+ spin_unlock(&mmc_host_lock);
+
+ if (err == -EAGAIN) {
+diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
+index 5f2f24a..c04d836 100644
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -2098,9 +2098,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
+ host->dbclk = NULL;
+ }
+
+- /* Since we do only SG emulation, we can have as many segs
+- * as we want. */
+- mmc->max_segs = 1024;
++ /* Set this to a value that allows allocating an entire descriptor
++ * list within a page (zero order allocation). */
++ mmc->max_segs = 64;
+
+ mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
+ mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
+diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig
+index 47da7e7..060569c 100644
+--- a/drivers/net/ethernet/allwinner/Kconfig
++++ b/drivers/net/ethernet/allwinner/Kconfig
+@@ -33,4 +33,17 @@ config SUN4I_EMAC
+ To compile this driver as a module, choose M here. The module
+ will be called sun4i-emac.
+
++config SUN8I_EMAC
++ tristate "Allwinner sun8i EMAC support"
++ depends on ARCH_SUNXI || COMPILE_TEST
++ depends on OF
++ select MII
++ select PHYLIB
++ ---help---
++ This driver support the sun8i EMAC ethernet driver present on
++ H3/A83T/A64 Allwinner SoCs.
++
++ To compile this driver as a module, choose M here. The module
++ will be called sun8i-emac.
++
+ endif # NET_VENDOR_ALLWINNER
+diff --git a/drivers/net/ethernet/allwinner/Makefile b/drivers/net/ethernet/allwinner/Makefile
+index 03129f7..8bd1693 100644
+--- a/drivers/net/ethernet/allwinner/Makefile
++++ b/drivers/net/ethernet/allwinner/Makefile
+@@ -3,3 +3,4 @@
+ #
+
+ obj-$(CONFIG_SUN4I_EMAC) += sun4i-emac.o
++obj-$(CONFIG_SUN8I_EMAC) += sun8i-emac.o
+diff --git b/drivers/net/ethernet/allwinner/sun8i-emac.c b/drivers/net/ethernet/allwinner/sun8i-emac.c
+new file mode 100644
+index 0000000..fc0c1dd
+--- /dev/null
++++ b/drivers/net/ethernet/allwinner/sun8i-emac.c
+@@ -0,0 +1,2129 @@
++/*
++ * sun8i-emac driver
++ *
++ * Copyright (C) 2015-2016 Corentin LABBE <clabbe.montjoie@gmail.com>
++ *
++ * This is the driver for Allwinner Ethernet MAC found in H3/A83T/A64 SoC
++ *
++ * TODO:
++ * - MAC filtering
++ * - Jumbo frame
++ * - features rx-all (NETIF_F_RXALL_BIT)
++ */
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/etherdevice.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/mii.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/of_device.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/phy.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/scatterlist.h>
++#include <linux/skbuff.h>
++
++#define SUN8I_EMAC_BASIC_CTL0 0x00
++#define SUN8I_EMAC_BASIC_CTL1 0x04
++#define SUN8I_EMAC_INT_STA 0x08
++#define SUN8I_EMAC_INT_EN 0x0C
++#define SUN8I_EMAC_TX_CTL0 0x10
++#define SUN8I_EMAC_TX_CTL1 0x14
++#define SUN8I_EMAC_TX_FLOW_CTL 0x1C
++#define SUN8I_EMAC_RX_CTL0 0x24
++#define SUN8I_EMAC_RX_CTL1 0x28
++#define SUN8I_EMAC_RX_FRM_FLT 0x38
++#define SUN8I_EMAC_MDIO_CMD 0x48
++#define SUN8I_EMAC_MDIO_DATA 0x4C
++#define SUN8I_EMAC_TX_DMA_STA 0xB0
++#define SUN8I_EMAC_TX_CUR_DESC 0xB4
++#define SUN8I_EMAC_TX_CUR_BUF 0xB8
++#define SUN8I_EMAC_RX_DMA_STA 0xC0
++
++#define MDIO_CMD_MII_BUSY BIT(0)
++#define MDIO_CMD_MII_WRITE BIT(1)
++#define MDIO_CMD_MII_PHY_REG_ADDR_MASK GENMASK(8, 4)
++#define MDIO_CMD_MII_PHY_REG_ADDR_SHIFT 4
++#define MDIO_CMD_MII_PHY_ADDR_MASK GENMASK(16, 12)
++#define MDIO_CMD_MII_PHY_ADDR_SHIFT 12
++
++#define SUN8I_EMAC_MACADDR_HI 0x50
++#define SUN8I_EMAC_MACADDR_LO 0x54
++
++#define SUN8I_EMAC_RX_DESC_LIST 0x34
++#define SUN8I_EMAC_TX_DESC_LIST 0x20
++
++#define SUN8I_EMAC_RX_DO_CRC BIT(27)
++#define SUN8I_EMAC_RX_STRIP_FCS BIT(28)
++
++#define SUN8I_COULD_BE_USED_BY_DMA BIT(31)
++
++/* Used in RX_CTL1*/
++#define RX_DMA_EN BIT(30)
++#define RX_DMA_START BIT(31)
++/* Used in TX_CTL1*/
++#define TX_DMA_EN BIT(30)
++#define TX_DMA_START BIT(31)
++
++/* Used in RX_CTL0 */
++#define RX_RECEIVER_EN BIT(31)
++/* Used in TX_CTL0 */
++#define TX_TRANSMITTER_EN BIT(31)
++
++/* Basic CTL0 */
++#define BCTL0_FD BIT(0)
++#define BCTL0_SPEED_10 2
++#define BCTL0_SPEED_100 3
++#define BCTL0_SPEED_MASK GENMASK(3, 2)
++#define BCTL0_SPEED_SHIFT 2
++
++#define FLOW_RX 1
++#define FLOW_TX 2
++
++#define RX_INT BIT(8)
++#define TX_INT BIT(0)
++
++/* Bits used in frame RX status */
++#define DSC_RX_FIRST BIT(9)
++#define DSC_RX_LAST BIT(8)
++
++/* Bits used in frame TX ctl */
++#define SUN8I_EMAC_MAGIC_TX_BIT BIT(24)
++#define SUN8I_EMAC_TX_DO_CRC (BIT(27) | BIT(28))
++#define DSC_TX_FIRST BIT(29)
++#define DSC_TX_LAST BIT(30)
++#define SUN8I_EMAC_WANT_INT BIT(31)
++
++enum emac_variant {
++ NONE_EMAC,/* for be sure that variant is non-0 if set */
++ A83T_EMAC,
++ H3_EMAC,
++ A64_EMAC,
++};
++
++static const char const estats_str[][ETH_GSTRING_LEN] = {
++ /* errors */
++ "rx_payload_error",
++ "rx_CRC_error",
++ "rx_phy_error",
++ "rx_length_error",
++ "rx_col_error",
++ "rx_header_error",
++ "rx_overflow_error",
++ "rx_saf_error",
++ "rx_daf_error",
++ "rx_buf_error",
++ /* misc infos */
++ "tx_stop_queue",
++ "rx_dma_ua",
++ "rx_dma_stop",
++ "tx_dma_ua",
++ "tx_dma_stop",
++ "rx_hw_csum",
++ "tx_hw_csum",
++ /* interrupts */
++ "rx_int",
++ "tx_int",
++ "rx_early_int",
++ "tx_early_int",
++ "tx_underflow_int",
++ /* debug */
++ "tx_used_desc",
++ "napi_schedule",
++ "napi_underflow",
++};
++
++struct sun8i_emac_stats {
++ u64 rx_payload_error;
++ u64 rx_crc_error;
++ u64 rx_phy_error;
++ u64 rx_length_error;
++ u64 rx_col_error;
++ u64 rx_header_error;
++ u64 rx_overflow_error;
++ u64 rx_saf_fail;
++ u64 rx_daf_fail;
++ u64 rx_buf_error;
++
++ u64 tx_stop_queue;
++ u64 rx_dma_ua;
++ u64 rx_dma_stop;
++ u64 tx_dma_ua;
++ u64 tx_dma_stop;
++ u64 rx_hw_csum;
++ u64 tx_hw_csum;
++
++ u64 rx_int;
++ u64 tx_int;
++ u64 rx_early_int;
++ u64 tx_early_int;
++ u64 tx_underflow_int;
++
++ u64 tx_used_desc;
++ u64 napi_schedule;
++ u64 napi_underflow;
++};
++
++/* The datasheet said that each descriptor can transfers up to 4096bytes
++ * But latter, a register documentation reduce that value to 2048
++ * Anyway using 2048 cause strange behaviours and even BSP driver use 2047
++ */
++#define DESC_BUF_MAX 2044
++#if (DESC_BUF_MAX < (ETH_FRAME_LEN + 4))
++#error "DESC_BUF_MAX must be set at minimum to ETH_FRAME_LEN + 4"
++#endif
++
++/* MAGIC value for knowing if a descriptor is available or not */
++#define DCLEAN (BIT(16) | BIT(14) | BIT(12) | BIT(10) | BIT(9))
++
++/* struct dma_desc - Structure of DMA descriptor used by the hardware
++ * @status: Status of the frame written by HW, so RO for the
++ * driver (except for BIT(31) which is R/W)
++ * @ctl: Information on the frame written by the driver (INT, len,...)
++ * @buf_addr: physical address of the frame data
++ * @next: physical address of next dma_desc
++ */
++struct dma_desc {
++ u32 status;
++ u32 ctl;
++ u32 buf_addr;
++ u32 next;
++};
++
++/* Describe how data from skb are DMA mapped (used in txinfo map member) */
++#define MAP_SINGLE 1
++#define MAP_PAGE 2
++
++/* Structure for storing information about data in TX ring buffer */
++struct txinfo {
++ struct sk_buff *skb;
++ int map;
++};
++
++struct sun8i_emac_priv {
++ void __iomem *base;
++ void __iomem *syscon;
++ int irq;
++ struct device *dev;
++ struct net_device *ndev;
++ struct mii_bus *mdio;
++ struct napi_struct napi;
++ spinlock_t tx_lock;/* control the access of transmit descriptors */
++ int duplex;
++ int speed;
++ int link;
++ int phy_interface;
++ enum emac_variant variant;
++ struct device_node *phy_node;
++ struct clk *ahb_clk;
++ struct clk *ephy_clk;
++ bool use_internal_phy;
++
++ struct reset_control *rst;
++ struct reset_control *rst_ephy;
++
++ struct dma_desc *dd_rx;
++ dma_addr_t dd_rx_phy;
++ struct dma_desc *dd_tx;
++ dma_addr_t dd_tx_phy;
++ struct sk_buff **rx_skb;
++ struct txinfo *txl;
++
++ int nbdesc_tx;
++ int nbdesc_rx;
++ int tx_slot;
++ int tx_dirty;
++ int rx_dirty;
++ struct sun8i_emac_stats estats;
++ u32 msg_enable;
++ int flow_ctrl;
++ int pause;
++};
++
++static irqreturn_t sun8i_emac_dma_interrupt(int irq, void *dev_id);
++
++static void rb_inc(int *p, const int max)
++{
++ (*p)++;
++ (*p) %= max;
++}
++
++/* Return the number of contiguous free descriptors
++ * starting from tx_slot
++ */
++static int rb_tx_numfreedesc(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ if (priv->tx_slot < priv->tx_dirty)
++ return priv->tx_dirty - priv->tx_slot;
++
++ return (priv->nbdesc_tx - priv->tx_slot) + priv->tx_dirty;
++}
++
++/* Allocate a skb in a DMA descriptor
++ *
++ * @i index of slot to fill
++*/
++static int sun8i_emac_rx_skb(struct net_device *ndev, int i)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct dma_desc *ddesc;
++ struct sk_buff *skb;
++
++ ddesc = priv->dd_rx + i;
++
++ ddesc->ctl = 0;
++
++ skb = netdev_alloc_skb_ip_align(ndev, DESC_BUF_MAX);
++ if (!skb)
++ return -ENOMEM;
++
++ /* should not happen */
++ if (unlikely(priv->rx_skb[i]))
++ dev_warn(priv->dev, "BUG: Leaking a skbuff\n");
++
++ priv->rx_skb[i] = skb;
++
++ ddesc->buf_addr = dma_map_single(priv->dev, skb->data,
++ DESC_BUF_MAX, DMA_FROM_DEVICE);
++ if (dma_mapping_error(priv->dev, ddesc->buf_addr)) {
++ dev_err(priv->dev, "ERROR: Cannot map RX buffer for DMA\n");
++ dev_kfree_skb(skb);
++ return -EFAULT;
++ }
++ ddesc->ctl |= DESC_BUF_MAX;
++ wmb();/* SUN8I_COULD_BE_USED_BY_DMA must be the last value written */
++ ddesc->status = SUN8I_COULD_BE_USED_BY_DMA;
++
++ return 0;
++}
++
++static void sun8i_emac_stop_tx(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v;
++
++ netif_stop_queue(ndev);
++
++ v = readl(priv->base + SUN8I_EMAC_TX_CTL0);
++ v &= ~TX_TRANSMITTER_EN;/*Disable transmitter after current reception*/
++ writel(v, priv->base + SUN8I_EMAC_TX_CTL0);
++ v = readl(priv->base + SUN8I_EMAC_TX_CTL1);
++ v &= ~TX_DMA_EN; /* Stop TX DMA */
++ writel(v, priv->base + SUN8I_EMAC_TX_CTL1);
++}
++
++static void sun8i_emac_stop_rx(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v;
++
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL0);
++ v &= ~RX_RECEIVER_EN; /* Disable receiver after current reception */
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL0);
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL1);
++ v &= ~RX_DMA_EN; /* Stop RX DMA */
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL1);
++}
++
++static void sun8i_emac_start_rx(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v;
++
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL0);
++ v |= RX_RECEIVER_EN;/* Enable receiver */
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL0);
++
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL1);
++ v |= RX_DMA_START;
++ v |= RX_DMA_EN;
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL1);
++}
++
++static void sun8i_emac_start_tx(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v;
++
++ v = readl(priv->base + SUN8I_EMAC_TX_CTL0);
++ v |= TX_TRANSMITTER_EN;
++ writel(v, priv->base + SUN8I_EMAC_TX_CTL0);
++
++ v = readl(priv->base + SUN8I_EMAC_TX_CTL1);
++ v |= TX_DMA_START;
++ v |= TX_DMA_EN;
++ writel(v, priv->base + SUN8I_EMAC_TX_CTL1);
++}
++
++/* Set MAC address for slot index
++ * @addr: the MAC address to set
++ * @index: The index of slot where to set address.
++ * The slot 0 is the main MACaddr
++ */
++static void sun8i_emac_set_macaddr(struct sun8i_emac_priv *priv,
++ const u8 *addr, int index)
++{
++ u32 v;
++
++ dev_info(priv->dev, "device MAC address slot %d %02x:%02x:%02x:%02x:%02x:%02x\n",
++ index, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
++
++ v = (addr[5] << 8) | addr[4];
++ writel(v, priv->base + SUN8I_EMAC_MACADDR_HI + index * 8);
++ v = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
++ writel(v, priv->base + SUN8I_EMAC_MACADDR_LO + index * 8);
++}
++
++static void sun8i_emac_set_link_mode(struct sun8i_emac_priv *priv)
++{
++ u32 v;
++
++ v = readl(priv->base + SUN8I_EMAC_BASIC_CTL0);
++
++ if (priv->duplex)
++ v |= BCTL0_FD;
++ else
++ v &= ~BCTL0_FD;
++
++ v &= ~BCTL0_SPEED_MASK;
++ switch (priv->speed) {
++ case 1000:
++ break;
++ case 100:
++ v |= BCTL0_SPEED_100 << BCTL0_SPEED_SHIFT;
++ break;
++ case 10:
++ v |= BCTL0_SPEED_10 << BCTL0_SPEED_SHIFT;
++ break;
++ }
++
++ writel(v, priv->base + SUN8I_EMAC_BASIC_CTL0);
++}
++
++static void sun8i_emac_flow_ctrl(struct sun8i_emac_priv *priv, int duplex,
++ int fc)
++{
++ u32 flow = 0;
++
++ netif_dbg(priv, link, priv->ndev, "%s %d %d\n", __func__,
++ duplex, fc);
++
++ flow = readl(priv->base + SUN8I_EMAC_RX_CTL0);
++ if (fc & FLOW_RX)
++ flow |= BIT(16);
++ else
++ flow &= ~BIT(16);
++ writel(flow, priv->base + SUN8I_EMAC_RX_CTL0);
++
++ flow = readl(priv->base + SUN8I_EMAC_TX_FLOW_CTL);
++ if (fc & FLOW_TX)
++ flow |= BIT(0);
++ else
++ flow &= ~BIT(0);
++ writel(flow, priv->base + SUN8I_EMAC_TX_FLOW_CTL);
++}
++
++/* Grab a frame into a skb from descriptor number i */
++static int sun8i_emac_rx_from_ddesc(struct net_device *ndev, int i)
++{
++ struct sk_buff *skb;
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct dma_desc *ddesc = priv->dd_rx + i;
++ int frame_len;
++ int rxcsum_done = 0;
++
++ if (ndev->features & NETIF_F_RXCSUM)
++ rxcsum_done = 1;
++
++ /* bit0/bit7 work only on IPv4/IPv6 TCP traffic,
++ * (not on ARP for example) so we dont raise rx_errors/discard frame
++ */
++ /* the checksum or length of received frame's payload is wrong*/
++ if (ddesc->status & BIT(0)) {
++ priv->estats.rx_payload_error++;
++ rxcsum_done = 0;
++ }
++ /* RX_CRC_ERR */
++ if (ddesc->status & BIT(1)) {
++ priv->ndev->stats.rx_errors++;
++ priv->ndev->stats.rx_crc_errors++;
++ priv->estats.rx_crc_error++;
++ goto discard_frame;
++ }
++ /* RX_PHY_ERR */
++ if ((ddesc->status & BIT(3))) {
++ priv->ndev->stats.rx_errors++;
++ priv->estats.rx_phy_error++;
++ goto discard_frame;
++ }
++ /* RX_LENGTH_ERR */
++ if ((ddesc->status & BIT(4))) {
++ priv->ndev->stats.rx_errors++;
++ priv->ndev->stats.rx_length_errors++;
++ priv->estats.rx_length_error++;
++ goto discard_frame;
++ }
++ /* RX_COL_ERR */
++ if ((ddesc->status & BIT(6))) {
++ priv->ndev->stats.rx_errors++;
++ priv->estats.rx_col_error++;
++ goto discard_frame;
++ }
++ /* RX_HEADER_ERR */
++ if ((ddesc->status & BIT(7))) {
++ priv->estats.rx_header_error++;
++ rxcsum_done = 0;
++ }
++ /* RX_OVERFLOW_ERR */
++ if ((ddesc->status & BIT(11))) {
++ priv->ndev->stats.rx_over_errors++;
++ priv->estats.rx_overflow_error++;
++ goto discard_frame;
++ }
++ /* RX_NO_ENOUGTH_BUF_ERR */
++ if ((ddesc->status & BIT(14))) {
++ priv->ndev->stats.rx_errors++;
++ priv->estats.rx_buf_error++;
++ goto discard_frame;
++ }
++
++ /* BIT(9) is for the first frame, not having it is bad since we do not
++ * handle Jumbo frame
++ */
++ if ((ddesc->status & DSC_RX_FIRST) == 0) {
++ dev_warn_ratelimited(priv->dev, "BUG: Non-first frame received. This should not happen\n");
++ goto discard_frame;
++ }
++ frame_len = (ddesc->status >> 16) & 0x3FFF;
++ if (!(ndev->features & NETIF_F_RXFCS))
++ frame_len -= ETH_FCS_LEN;
++
++ skb = priv->rx_skb[i];
++
++ netif_dbg(priv, rx_status, priv->ndev,
++ "%s from %02d %pad len=%d status=%x st=%x\n",
++ __func__, i, &ddesc, frame_len, ddesc->status, ddesc->ctl);
++
++ skb_put(skb, frame_len);
++
++ dma_unmap_single(priv->dev, ddesc->buf_addr, DESC_BUF_MAX,
++ DMA_FROM_DEVICE);
++ skb->protocol = eth_type_trans(skb, priv->ndev);
++ if (rxcsum_done) {
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ priv->estats.rx_hw_csum++;
++ } else {
++ skb->ip_summed = CHECKSUM_PARTIAL;
++ }
++
++ priv->ndev->stats.rx_packets++;
++ priv->ndev->stats.rx_bytes += frame_len;
++ priv->rx_skb[i] = NULL;
++
++ /* this frame is not the last */
++ if ((ddesc->status & DSC_RX_LAST) == 0) {
++ dev_warn(priv->dev, "Multi frame not implemented currlen=%d\n",
++ frame_len);
++ }
++
++ sun8i_emac_rx_skb(ndev, i);
++ napi_gro_receive(&priv->napi, skb);
++
++ return 0;
++ /* If the frame need to be dropped, we simply reuse the buffer */
++discard_frame:
++ ddesc->ctl = DESC_BUF_MAX;
++ wmb();/* SUN8I_COULD_BE_USED_BY_DMA must be the last value written */
++ ddesc->status = SUN8I_COULD_BE_USED_BY_DMA;
++ return 0;
++}
++
++/* iterate over dma_desc for finding completed xmit.
++ * Called from interrupt context, so no need to spinlock tx
++ *
++ * The problem is: how to know that a descriptor is sent and not just in
++ * preparation.
++ * Need to have status=0 and st set but this is the state of first frame just
++ * before setting the own-by-DMA bit.
++ * The solution is to used the artificial value DCLEAN.
++ */
++static int sun8i_emac_complete_xmit(struct net_device *ndev, int budget)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct dma_desc *ddesc;
++ int frame_len;
++ int work = 0;
++
++ spin_lock(&priv->tx_lock);
++ do {
++ ddesc = priv->dd_tx + priv->tx_dirty;
++
++ if (ddesc->status & SUN8I_COULD_BE_USED_BY_DMA)
++ goto xmit_end;
++
++ if (ddesc->status == DCLEAN)
++ goto xmit_end;
++
++ if (ddesc->status == 0 && !ddesc->ctl) {
++ dev_err(priv->dev, "BUG: reached the void %d %d\n",
++ priv->tx_dirty, priv->tx_slot);
++ goto xmit_end;
++ }
++
++ /* TX_UNDERFLOW_ERR */
++ if (ddesc->status & BIT(1))
++ priv->ndev->stats.tx_errors++;
++ /* TX_DEFER_ERR */
++ if (ddesc->status & BIT(2))
++ priv->ndev->stats.tx_errors++;
++ /* BIT 6:3 numbers of collisions */
++ if (ddesc->status & 0x78)
++ priv->ndev->stats.collisions +=
++ (ddesc->status & 0x78) >> 3;
++ /* TX_COL_ERR_1 */
++ if (ddesc->status & BIT(8))
++ priv->ndev->stats.tx_errors++;
++ /* TX_COL_ERR_0 */
++ if (ddesc->status & BIT(9))
++ priv->ndev->stats.tx_errors++;
++ /* TX_CRS_ERR */
++ if (ddesc->status & BIT(10))
++ priv->ndev->stats.tx_carrier_errors++;
++ /* TX_PAYLOAD_ERR */
++ if (ddesc->status & BIT(12))
++ priv->ndev->stats.tx_errors++;
++ /* TX_LENGTH_ERR */
++ if (ddesc->status & BIT(14))
++ priv->ndev->stats.tx_errors++;
++ /* TX_HEADER_ERR */
++ if (ddesc->status & BIT(16))
++ priv->ndev->stats.tx_errors++;
++ frame_len = ddesc->ctl & 0x3FFF;
++ if (priv->txl[priv->tx_dirty].map == MAP_SINGLE)
++ dma_unmap_single(priv->dev, ddesc->buf_addr,
++ frame_len, DMA_TO_DEVICE);
++ else
++ dma_unmap_page(priv->dev, ddesc->buf_addr,
++ frame_len, DMA_TO_DEVICE);
++ /* we can free skb only on last frame */
++ if (priv->txl[priv->tx_dirty].skb && (ddesc->ctl & DSC_TX_LAST))
++ dev_kfree_skb_irq(priv->txl[priv->tx_dirty].skb);
++
++ priv->txl[priv->tx_dirty].skb = NULL;
++ priv->txl[priv->tx_dirty].map = 0;
++ ddesc->ctl = 0;
++ wmb(); /* setting to DCLEAN is the last value to be set */
++ ddesc->status = DCLEAN;
++ work++;
++
++ rb_inc(&priv->tx_dirty, priv->nbdesc_tx);
++ ddesc = priv->dd_tx + priv->tx_dirty;
++ } while (ddesc->ctl && !(ddesc->status & SUN8I_COULD_BE_USED_BY_DMA));
++
++ if (netif_queue_stopped(ndev) &&
++ rb_tx_numfreedesc(ndev) > MAX_SKB_FRAGS + 1)
++ netif_wake_queue(ndev);
++xmit_end:
++ spin_unlock(&priv->tx_lock);
++ return work;
++}
++
++static int sun8i_emac_poll(struct napi_struct *napi, int budget)
++{
++ struct sun8i_emac_priv *priv =
++ container_of(napi, struct sun8i_emac_priv, napi);
++ struct net_device *ndev = priv->ndev;
++ int worked;
++ struct dma_desc *ddesc;
++
++ priv->estats.napi_schedule++;
++ worked = sun8i_emac_complete_xmit(ndev, budget);
++
++ ddesc = priv->dd_rx + priv->rx_dirty;
++ while (!(ddesc->status & SUN8I_COULD_BE_USED_BY_DMA) &&
++ worked < budget) {
++ sun8i_emac_rx_from_ddesc(ndev, priv->rx_dirty);
++ worked++;
++ rb_inc(&priv->rx_dirty, priv->nbdesc_rx);
++ ddesc = priv->dd_rx + priv->rx_dirty;
++ };
++ if (worked < budget) {
++ priv->estats.napi_underflow++;
++ napi_complete(&priv->napi);
++ writel(RX_INT | TX_INT, priv->base + SUN8I_EMAC_INT_EN);
++ }
++ return worked;
++}
++
++static int sun8i_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
++{
++ struct net_device *ndev = bus->priv;
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int err;
++ u32 reg;
++
++ err = readl_poll_timeout(priv->base + SUN8I_EMAC_MDIO_CMD, reg,
++ !(reg & MDIO_CMD_MII_BUSY), 100, 10000);
++ if (err) {
++ dev_err(priv->dev, "%s timeout %x\n", __func__, reg);
++ return err;
++ }
++
++ reg &= ~MDIO_CMD_MII_WRITE;
++ reg &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
++ reg |= (phy_reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
++ MDIO_CMD_MII_PHY_REG_ADDR_MASK;
++
++ reg &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
++
++ reg |= (phy_addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
++ MDIO_CMD_MII_PHY_ADDR_MASK;
++
++ reg |= MDIO_CMD_MII_BUSY;
++
++ writel(reg, priv->base + SUN8I_EMAC_MDIO_CMD);
++
++ err = readl_poll_timeout(priv->base + SUN8I_EMAC_MDIO_CMD, reg,
++ !(reg & MDIO_CMD_MII_BUSY), 100, 10000);
++
++ if (err) {
++ dev_err(priv->dev, "%s timeout %x\n", __func__, reg);
++ return err;
++ }
++
++ return readl(priv->base + SUN8I_EMAC_MDIO_DATA);
++}
++
++static int sun8i_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg,
++ u16 data)
++{
++ struct net_device *ndev = bus->priv;
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 reg;
++ int err;
++
++ err = readl_poll_timeout(priv->base + SUN8I_EMAC_MDIO_CMD, reg,
++ !(reg & MDIO_CMD_MII_BUSY), 100, 10000);
++ if (err) {
++ dev_err(priv->dev, "%s timeout %x\n", __func__, reg);
++ return err;
++ }
++
++ reg &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
++ reg |= (phy_reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
++ MDIO_CMD_MII_PHY_REG_ADDR_MASK;
++
++ reg &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
++ reg |= (phy_addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
++ MDIO_CMD_MII_PHY_ADDR_MASK;
++
++ reg |= MDIO_CMD_MII_WRITE;
++ reg |= MDIO_CMD_MII_BUSY;
++
++ writel(reg, priv->base + SUN8I_EMAC_MDIO_CMD);
++ writel(data, priv->base + SUN8I_EMAC_MDIO_DATA);
++ dev_dbg(priv->dev, "%s %d %d %x %x\n", __func__, phy_addr, phy_reg,
++ reg, data);
++
++ err = readl_poll_timeout(priv->base + SUN8I_EMAC_MDIO_CMD, reg,
++ !(reg & MDIO_CMD_MII_BUSY), 100, 10000);
++ if (err) {
++ dev_err(priv->dev, "%s timeout %x\n", __func__, reg);
++ return err;
++ }
++
++ return 0;
++}
++
++static int sun8i_emac_mdio_register(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct mii_bus *bus;
++ int ret;
++
++ bus = mdiobus_alloc();
++ if (!bus) {
++ netdev_err(ndev, "Failed to allocate a new mdio bus\n");
++ return -ENOMEM;
++ }
++
++ bus->name = dev_name(priv->dev);
++ bus->read = &sun8i_mdio_read;
++ bus->write = &sun8i_mdio_write;
++ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%x", bus->name, priv->dev->id);
++
++ bus->parent = priv->dev;
++ bus->priv = ndev;
++
++ ret = of_mdiobus_register(bus, priv->dev->of_node);
++ if (ret) {
++ netdev_err(ndev, "Could not register a MDIO bus: %d\n", ret);
++ mdiobus_free(bus);
++ return ret;
++ }
++
++ priv->mdio = bus;
++
++ return 0;
++}
++
++static void sun8i_emac_mdio_unregister(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ mdiobus_unregister(priv->mdio);
++ mdiobus_free(priv->mdio);
++}
++
++/* Run within phydev->lock */
++static void sun8i_emac_adjust_link(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct phy_device *phydev = ndev->phydev;
++ int new_state = 0;
++
++ netif_dbg(priv, link, priv->ndev,
++ "%s link=%x duplex=%x speed=%x\n", __func__,
++ phydev->link, phydev->duplex, phydev->speed);
++ if (!phydev)
++ return;
++
++ if (phydev->link) {
++ if (phydev->duplex != priv->duplex) {
++ new_state = 1;
++ priv->duplex = phydev->duplex;
++ }
++ if (phydev->pause)
++ sun8i_emac_flow_ctrl(priv, phydev->duplex,
++ priv->flow_ctrl);
++
++ if (phydev->speed != priv->speed) {
++ new_state = 1;
++ priv->speed = phydev->speed;
++ }
++
++ if (priv->link == 0) {
++ new_state = 1;
++ priv->link = phydev->link;
++ }
++
++ netif_dbg(priv, link, priv->ndev,
++ "%s new=%d link=%d pause=%d\n",
++ __func__, new_state, priv->link, phydev->pause);
++ if (new_state)
++ sun8i_emac_set_link_mode(priv);
++ } else if (priv->link != phydev->link) {
++ new_state = 1;
++ priv->link = 0;
++ priv->speed = 0;
++ priv->duplex = -1;
++ }
++
++ if (new_state)
++ phy_print_status(phydev);
++}
++
++/* H3 specific bits for EPHY */
++#define H3_EPHY_ADDR_SHIFT 20
++#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */
++#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
++#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
++#define H3_EPHY_DEFAULT_VALUE 0x58000
++#define H3_EPHY_DEFAULT_MASK GENMASK(31, 15)
++
++/* H3/A64 specific bits */
++#define SC_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */
++
++/* Generic system control EMAC_CLK bits */
++#define SC_ETXDC_MASK GENMASK(2, 0)
++#define SC_ETXDC_SHIFT 10
++#define SC_ERXDC_MASK GENMASK(4, 0)
++#define SC_ERXDC_SHIFT 5
++#define SC_EPIT BIT(2) /* 1: RGMII, 0: MII */
++#define SC_ETCS_MASK GENMASK(1, 0)
++#define SC_ETCS_MII 0x0
++#define SC_ETCS_EXT_GMII 0x1
++#define SC_ETCS_INT_GMII 0x2
++
++static int sun8i_emac_set_syscon_ephy(struct net_device *ndev, u32 *reg)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct device_node *node = priv->dev->of_node;
++ int ret;
++
++ *reg &= ~H3_EPHY_DEFAULT_MASK;
++ *reg |= H3_EPHY_DEFAULT_VALUE;
++
++ if (!priv->use_internal_phy) {
++ /* switch to external PHY interface */
++ *reg &= ~H3_EPHY_SELECT;
++ return 0;
++ }
++
++ if (priv->phy_interface != PHY_INTERFACE_MODE_MII) {
++ netdev_warn(ndev,
++ "Internal PHY requested, forcing MII mode.\n");
++ priv->phy_interface = PHY_INTERFACE_MODE_MII;
++ }
++
++ *reg |= H3_EPHY_SELECT;
++ *reg &= ~H3_EPHY_SHUTDOWN;
++
++ if (of_property_read_bool(node, "allwinner,leds-active-low"))
++ *reg |= H3_EPHY_LED_POL;
++
++ ret = of_mdio_parse_addr(priv->dev, priv->phy_node);
++ if (ret < 0) {
++ netdev_err(ndev, "Could not parse MDIO addr\n");
++ return ret;
++ }
++
++ /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
++ * address. No need to mask it again.
++ */
++ *reg |= ret << H3_EPHY_ADDR_SHIFT;
++
++ return 0;
++}
++
++static int sun8i_emac_set_syscon(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct device_node *node = priv->dev->of_node;
++ int ret;
++ u32 reg, val;
++
++ reg = readl(priv->syscon);
++
++ if (priv->variant == H3_EMAC) {
++ ret = sun8i_emac_set_syscon_ephy(ndev, &reg);
++ if (ret)
++ return ret;
++ }
++
++ if (!of_property_read_u32(node, "allwinner,tx-delay", &val)) {
++ if (val <= SC_ETXDC_MASK) {
++ reg &= ~(SC_ETXDC_MASK << SC_ETXDC_SHIFT);
++ reg |= (val << SC_ETXDC_SHIFT);
++ } else {
++ netdev_warn(ndev, "Invalid TX clock delay: %d\n", val);
++ }
++ }
++
++ if (!of_property_read_u32(node, "allwinner,rx-delay", &val)) {
++ if (val <= SC_ERXDC_MASK) {
++ reg &= ~(SC_ERXDC_MASK << SC_ERXDC_SHIFT);
++ reg |= (val << SC_ERXDC_SHIFT);
++ } else {
++ netdev_warn(ndev, "Invalid RX clock delay: %d\n", val);
++ }
++ }
++
++ /* Clear interface mode bits */
++ reg &= ~(SC_ETCS_MASK | SC_EPIT);
++ if (priv->variant == H3_EMAC || priv->variant == A64_EMAC)
++ reg &= ~SC_RMII_EN;
++
++ switch (priv->phy_interface) {
++ case PHY_INTERFACE_MODE_MII:
++ /* default */
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ reg |= SC_EPIT | SC_ETCS_INT_GMII;
++ break;
++ case PHY_INTERFACE_MODE_RMII:
++ if (priv->variant == H3_EMAC || priv->variant == A64_EMAC) {
++ reg |= SC_RMII_EN | SC_ETCS_EXT_GMII;
++ break;
++ }
++ /* RMII not supported on A83T */
++ default:
++ netdev_err(ndev, "Unsupported interface mode: %s",
++ phy_modes(priv->phy_interface));
++ return -EINVAL;
++ }
++
++ writel(reg, priv->syscon);
++
++ return 0;
++}
++
++static void sun8i_emac_unset_syscon(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 reg = 0;
++
++ if (priv->variant == H3_EMAC)
++ reg = H3_EPHY_DEFAULT_VALUE;
++
++ writel(reg, priv->syscon);
++}
++
++/* Set Management Data Clock, must be call after device reset */
++static void sun8i_emac_set_mdc(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ unsigned long rate;
++ u32 reg;
++
++ rate = clk_get_rate(priv->ahb_clk);
++ if (rate > 160000000)
++ reg = 0x3 << 20; /* AHB / 128 */
++ else if (rate > 80000000)
++ reg = 0x2 << 20; /* AHB / 64 */
++ else if (rate > 40000000)
++ reg = 0x1 << 20; /* AHB / 32 */
++ else
++ reg = 0x0 << 20; /* AHB / 16 */
++ netif_dbg(priv, link, ndev, "MDC auto : %x\n", reg);
++ writel(reg, priv->base + SUN8I_EMAC_MDIO_CMD);
++}
++
++/* "power" the device, by enabling clk/reset/regulators */
++static int sun8i_emac_power(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int ret;
++
++ ret = clk_prepare_enable(priv->ahb_clk);
++ if (ret) {
++ netdev_err(ndev, "Could not enable AHB clock\n");
++ return ret;
++ }
++
++ if (priv->rst) {
++ ret = reset_control_deassert(priv->rst);
++ if (ret) {
++ netdev_err(ndev, "Could not deassert reset\n");
++ goto err_reset;
++ }
++ }
++
++ if (priv->ephy_clk) {
++ ret = clk_prepare_enable(priv->ephy_clk);
++ if (ret) {
++ netdev_err(ndev, "Could not enable EPHY clock\n");
++ goto err_ephy_clk;
++ }
++ }
++
++ if (priv->rst_ephy) {
++ ret = reset_control_deassert(priv->rst_ephy);
++ if (ret) {
++ netdev_err(ndev, "Could not deassert EPHY reset\n");
++ goto err_ephy_reset;
++ }
++ }
++
++ return 0;
++
++err_ephy_reset:
++ if (priv->ephy_clk)
++ clk_disable_unprepare(priv->ephy_clk);
++err_ephy_clk:
++ if (priv->rst)
++ reset_control_assert(priv->rst);
++err_reset:
++ clk_disable_unprepare(priv->ahb_clk);
++ return ret;
++}
++
++/* "Unpower" the device, disabling clocks and regulators, asserting reset */
++static void sun8i_emac_unpower(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ if (priv->rst_ephy)
++ reset_control_assert(priv->rst_ephy);
++
++ if (priv->ephy_clk)
++ clk_disable_unprepare(priv->ephy_clk);
++
++ if (priv->rst)
++ reset_control_assert(priv->rst);
++
++ clk_disable_unprepare(priv->ahb_clk);
++}
++
++static int sun8i_emac_init(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct device_node *node = priv->dev->of_node;
++ const u8 *addr;
++
++ /* Try to get MAC address from DT, or assign a random one */
++ addr = of_get_mac_address(node);
++ if (addr)
++ ether_addr_copy(ndev->dev_addr, addr);
++ else
++ eth_hw_addr_random(ndev);
++
++ priv->phy_interface = of_get_phy_mode(node);
++ if (priv->phy_interface < 0) {
++ netdev_err(ndev, "PHY interface mode node unspecified\n");
++ return priv->phy_interface;
++ }
++
++ return sun8i_emac_power(ndev);
++}
++
++static void sun8i_emac_uninit(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ mdiobus_unregister(priv->mdio);
++
++ sun8i_emac_unpower(ndev);
++}
++
++static int sun8i_emac_mdio_probe(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct phy_device *phydev = NULL;
++
++ phydev = of_phy_connect(ndev, priv->phy_node, &sun8i_emac_adjust_link,
++ 0, priv->phy_interface);
++
++ if (!phydev) {
++ netdev_err(ndev, "Could not attach to PHY\n");
++ return -ENODEV;
++ }
++
++ phy_attached_info(phydev);
++
++ /* mask with MAC supported features */
++ phydev->supported &= PHY_GBIT_FEATURES;
++ phydev->advertising = phydev->supported;
++
++ priv->link = 0;
++ priv->speed = 0;
++ priv->duplex = -1;
++
++ return 0;
++}
++
++/* Allocate both RX and TX ring buffer and init them
++ * This function also write the startbase of thoses ring in the device.
++ * All structures that help managing thoses rings are also handled
++ * by this functions (rx_skb/txl)
++ */
++static int sun8i_emac_alloc_rings(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct dma_desc *ddesc;
++ int err, i;
++
++ priv->rx_skb = kcalloc(priv->nbdesc_rx, sizeof(struct sk_buff *),
++ GFP_KERNEL);
++ if (!priv->rx_skb) {
++ err = -ENOMEM;
++ goto rx_skb_error;
++ }
++ priv->txl = kcalloc(priv->nbdesc_tx, sizeof(struct txinfo), GFP_KERNEL);
++ if (!priv->txl) {
++ err = -ENOMEM;
++ goto tx_error;
++ }
++
++ /* allocate/init RX ring */
++ priv->dd_rx = dma_zalloc_coherent(priv->dev,
++ priv->nbdesc_rx * sizeof(struct dma_desc),
++ &priv->dd_rx_phy, GFP_KERNEL);
++ if (!priv->dd_rx) {
++ dev_err(priv->dev, "ERROR: cannot allocate DMA RX buffer");
++ err = -ENOMEM;
++ goto dma_rx_error;
++ }
++ ddesc = priv->dd_rx;
++ for (i = 0; i < priv->nbdesc_rx; i++) {
++ sun8i_emac_rx_skb(ndev, i);
++ ddesc->next = (u32)priv->dd_rx_phy + (i + 1)
++ * sizeof(struct dma_desc);
++ ddesc++;
++ }
++ /* last descriptor point back to first one */
++ ddesc--;
++ ddesc->next = (u32)priv->dd_rx_phy;
++
++ /* allocate/init TX ring */
++ priv->dd_tx = dma_zalloc_coherent(priv->dev,
++ priv->nbdesc_tx * sizeof(struct dma_desc),
++ &priv->dd_tx_phy, GFP_KERNEL);
++ if (!priv->dd_tx) {
++ dev_err(priv->dev, "ERROR: cannot allocate DMA TX buffer");
++ err = -ENOMEM;
++ goto dma_tx_error;
++ }
++ ddesc = priv->dd_tx;
++ for (i = 0; i < priv->nbdesc_tx; i++) {
++ ddesc->status = DCLEAN;
++ ddesc->ctl = 0;
++ ddesc->next = (u32)(priv->dd_tx_phy + (i + 1)
++ * sizeof(struct dma_desc));
++ ddesc++;
++ }
++ /* last descriptor point back to first one */
++ ddesc--;
++ ddesc->next = (u32)priv->dd_tx_phy;
++ i--;
++
++ priv->tx_slot = 0;
++ priv->tx_dirty = 0;
++ priv->rx_dirty = 0;
++
++ /* write start of RX ring descriptor */
++ writel(priv->dd_rx_phy, priv->base + SUN8I_EMAC_RX_DESC_LIST);
++ /* write start of TX ring descriptor */
++ writel(priv->dd_tx_phy, priv->base + SUN8I_EMAC_TX_DESC_LIST);
++
++ return 0;
++dma_tx_error:
++ dma_free_coherent(priv->dev, priv->nbdesc_rx * sizeof(struct dma_desc),
++ priv->dd_rx, priv->dd_rx_phy);
++dma_rx_error:
++ kfree(priv->txl);
++tx_error:
++ kfree(priv->rx_skb);
++rx_skb_error:
++ return err;
++}
++
++static int sun8i_emac_open(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int err;
++ u32 v;
++
++ err = request_irq(priv->irq, sun8i_emac_dma_interrupt, 0,
++ dev_name(priv->dev), ndev);
++ if (err) {
++ dev_err(priv->dev, "Cannot request IRQ: %d\n", err);
++ return err;
++ }
++
++ /* Set interface mode (and configure internal PHY on H3) */
++ err = sun8i_emac_set_syscon(ndev);
++ if (err)
++ goto err_irq;
++
++ /* Do SOFT RST */
++ v = readl(priv->base + SUN8I_EMAC_BASIC_CTL1);
++ writel(v | 0x01, priv->base + SUN8I_EMAC_BASIC_CTL1);
++
++ err = readl_poll_timeout(priv->base + SUN8I_EMAC_BASIC_CTL1, v,
++ !(v & 0x01), 100, 10000);
++ if (err) {
++ dev_err(priv->dev, "EMAC reset timeout\n");
++ err = -EFAULT;
++ goto err_syscon;
++ }
++
++ sun8i_emac_set_mdc(ndev);
++
++ err = sun8i_emac_mdio_register(ndev);
++ if (err)
++ goto err_syscon;
++
++ err = sun8i_emac_mdio_probe(ndev);
++ if (err)
++ goto err_syscon;
++
++ /* DMA */
++ v = (8 << 24);/* burst len */
++ writel(v, priv->base + SUN8I_EMAC_BASIC_CTL1);
++
++ writel(RX_INT | TX_INT, priv->base + SUN8I_EMAC_INT_EN);
++
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL0);
++ /* CHECK_CRC */
++ if (ndev->features & NETIF_F_RXCSUM)
++ v |= SUN8I_EMAC_RX_DO_CRC;
++ else
++ v &= ~SUN8I_EMAC_RX_DO_CRC;
++ /* STRIP_FCS */
++ if (ndev->features & NETIF_F_RXFCS)
++ v &= ~SUN8I_EMAC_RX_STRIP_FCS;
++ else
++ v |= SUN8I_EMAC_RX_STRIP_FCS;
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL0);
++
++ v = readl(priv->base + SUN8I_EMAC_TX_CTL1);
++ /* TX_MD Transmission starts after a full frame located in TX DMA FIFO*/
++ v |= BIT(1);
++ /* Undocumented bit (called TX_NEXT_FRM in BSP), the original comment is
++ * "Operating on second frame increase the performance
++ * especially when transmit store-and-forward is used."
++ */
++ v |= BIT(2);
++ writel(v, priv->base + SUN8I_EMAC_TX_CTL1);
++
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL1);
++ /* RX_MD RX DMA reads data from RX DMA FIFO to host memory after a
++ * complete frame has been written to RX DMA FIFO
++ */
++ v |= BIT(1);
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL1);
++
++ sun8i_emac_set_macaddr(priv, ndev->dev_addr, 0);
++
++ err = sun8i_emac_alloc_rings(ndev);
++ if (err) {
++ netdev_err(ndev, "Fail to allocate rings\n");
++ goto err_mdio;
++ }
++
++ phy_start(ndev->phydev);
++
++ sun8i_emac_start_rx(ndev);
++ sun8i_emac_start_tx(ndev);
++
++ netif_napi_add(ndev, &priv->napi, sun8i_emac_poll, 64);
++ napi_enable(&priv->napi);
++ netif_start_queue(ndev);
++
++ return 0;
++err_mdio:
++ phy_disconnect(ndev->phydev);
++err_syscon:
++ sun8i_emac_unset_syscon(ndev);
++err_irq:
++ free_irq(priv->irq, ndev);
++ return err;
++}
++
++/* Clean the TX ring of any accepted skb for xmit */
++static void sun8i_emac_tx_clean(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int i;
++ struct dma_desc *ddesc;
++ int frame_len;
++
++ spin_lock(&priv->tx_lock);
++
++ for (i = 0; i < priv->nbdesc_tx; i++) {
++ if (priv->txl[i].skb) {
++ ddesc = priv->dd_tx + i;
++ frame_len = ddesc->ctl & 0x3FFF;
++ switch (priv->txl[i].map) {
++ case MAP_SINGLE:
++ dma_unmap_single(priv->dev, ddesc->buf_addr,
++ frame_len, DMA_TO_DEVICE);
++ break;
++ case MAP_PAGE:
++ dma_unmap_page(priv->dev, ddesc->buf_addr,
++ frame_len, DMA_TO_DEVICE);
++ break;
++ default:
++ dev_err(priv->dev, "Trying to free an empty slot\n");
++ continue;
++ }
++ dev_kfree_skb_any(priv->txl[i].skb);
++ priv->txl[i].skb = NULL;
++ ddesc->ctl = 0;
++ ddesc->status = DCLEAN;
++ }
++ }
++ priv->tx_slot = 0;
++ priv->tx_dirty = 0;
++
++ spin_unlock(&priv->tx_lock);
++}
++
++/* Clean the RX ring */
++static void sun8i_emac_rx_clean(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int i;
++ struct dma_desc *ddesc;
++
++ /* clean RX ring */
++ for (i = 0; i < priv->nbdesc_rx; i++)
++ if (priv->rx_skb[i]) {
++ ddesc = priv->dd_rx + i;
++ dma_unmap_single(priv->dev, ddesc->buf_addr,
++ DESC_BUF_MAX, DMA_FROM_DEVICE);
++ dev_kfree_skb_any(priv->rx_skb[i]);
++ priv->rx_skb[i] = NULL;
++ }
++}
++
++static int sun8i_emac_stop(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ napi_disable(&priv->napi);
++
++ sun8i_emac_stop_tx(ndev);
++ sun8i_emac_stop_rx(ndev);
++
++ phy_stop(ndev->phydev);
++ phy_disconnect(ndev->phydev);
++
++ sun8i_emac_mdio_unregister(ndev);
++
++ sun8i_emac_unset_syscon(ndev);
++
++ free_irq(priv->irq, ndev);
++
++ sun8i_emac_rx_clean(ndev);
++ sun8i_emac_tx_clean(ndev);
++
++ kfree(priv->rx_skb);
++ kfree(priv->txl);
++
++ dma_free_coherent(priv->dev, priv->nbdesc_rx * sizeof(struct dma_desc),
++ priv->dd_rx, priv->dd_rx_phy);
++ dma_free_coherent(priv->dev, priv->nbdesc_tx * sizeof(struct dma_desc),
++ priv->dd_tx, priv->dd_tx_phy);
++
++ return 0;
++}
++
++static netdev_tx_t sun8i_emac_xmit(struct sk_buff *skb, struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct dma_desc *ddesc;
++ struct dma_desc *first;
++ int i = 0, rbd_first;
++ unsigned int len, fraglen, tlen;
++ u32 v;
++ int n;
++ int nf;
++ const skb_frag_t *frag;
++ int do_csum = 0;
++
++ if (skb_put_padto(skb, ETH_ZLEN))
++ return NETDEV_TX_OK;
++ len = skb_headlen(skb);
++
++ n = skb_shinfo(skb)->nr_frags;
++
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
++ do_csum = 1;
++ priv->estats.tx_hw_csum++;
++ }
++ netif_dbg(priv, tx_queued, ndev, "%s len=%u skblen=%u %x\n", __func__,
++ len, skb->len,
++ (skb->ip_summed == CHECKSUM_PARTIAL));
++
++ spin_lock(&priv->tx_lock);
++
++ /* check for contigous space
++ * We need at least 1(skb->data) + n(numfrags) + 1(one clean slot)
++ */
++ if (rb_tx_numfreedesc(ndev) < n + 2) {
++ dev_err_ratelimited(priv->dev, "BUG!: TX is full %d %d\n",
++ priv->tx_dirty, priv->tx_slot);
++ netif_stop_queue(ndev);
++ spin_unlock(&priv->tx_lock);
++ return NETDEV_TX_BUSY;
++ }
++ i = priv->tx_slot;
++
++ ddesc = priv->dd_tx + i;
++ first = priv->dd_tx + i;
++ rbd_first = i;
++
++ priv->tx_slot = (i + 1 + n) % priv->nbdesc_tx;
++
++ ddesc->buf_addr = dma_map_single(priv->dev, skb->data, len,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(priv->dev, ddesc->buf_addr)) {
++ dev_err(priv->dev, "ERROR: Cannot map buffer for DMA\n");
++ goto xmit_error;
++ }
++ priv->txl[i].map = MAP_SINGLE;
++ priv->txl[i].skb = skb;
++
++ tlen = len;
++ ddesc->ctl = len;
++ /* Undocumented bit that make it works
++ * Without it, packets never be sent on H3 SoC
++ */
++ ddesc->ctl |= SUN8I_EMAC_MAGIC_TX_BIT;
++ if (do_csum)
++ ddesc->ctl |= SUN8I_EMAC_TX_DO_CRC;
++
++ /* handle fragmented skb, one descriptor per fragment */
++ for (nf = 0; nf < n; nf++) {
++ frag = &skb_shinfo(skb)->frags[nf];
++ rb_inc(&i, priv->nbdesc_tx);
++ priv->txl[i].skb = skb;
++ ddesc = priv->dd_tx + i;
++ fraglen = skb_frag_size(frag);
++ ddesc->ctl = fraglen;
++ tlen += fraglen,
++ ddesc->ctl |= SUN8I_EMAC_MAGIC_TX_BIT;
++ if (do_csum)
++ ddesc->ctl |= SUN8I_EMAC_TX_DO_CRC;
++
++ ddesc->buf_addr = skb_frag_dma_map(priv->dev, frag, 0,
++ fraglen, DMA_TO_DEVICE);
++ if (dma_mapping_error(priv->dev, ddesc->buf_addr)) {
++ dev_err(priv->dev, "Cannot map buffer for DMA\n");
++ goto xmit_error;
++ }
++ priv->txl[i].map = MAP_PAGE;
++ ddesc->status = SUN8I_COULD_BE_USED_BY_DMA;
++ }
++
++ /* frame end */
++ ddesc->ctl |= DSC_TX_LAST;
++ /* We want an interrupt after transmission */
++ ddesc->ctl |= SUN8I_EMAC_WANT_INT;
++
++ rb_inc(&i, priv->nbdesc_tx);
++
++ /* frame begin */
++ first->ctl |= DSC_TX_FIRST;
++ wmb();/* SUN8I_COULD_BE_USED_BY_DMA must be the last value written */
++ first->status = SUN8I_COULD_BE_USED_BY_DMA;
++ priv->tx_slot = i;
++
++ /* Trying to optimize this (recording DMA start/stop) seems
++ * to lead to errors. So we always start DMA.
++ */
++ v = readl(priv->base + SUN8I_EMAC_TX_CTL1);
++ v |= TX_DMA_START;
++ v |= TX_DMA_EN;
++ writel(v, priv->base + SUN8I_EMAC_TX_CTL1);
++
++ if (rb_tx_numfreedesc(ndev) < MAX_SKB_FRAGS + 1) {
++ netif_stop_queue(ndev);
++ priv->estats.tx_stop_queue++;
++ }
++ priv->estats.tx_used_desc = rb_tx_numfreedesc(ndev);
++ priv->ndev->stats.tx_packets++;
++ priv->ndev->stats.tx_bytes += tlen;
++
++ spin_unlock(&priv->tx_lock);
++
++ return NETDEV_TX_OK;
++
++xmit_error:
++ /* destroy skb and return TX OK Documentation/DMA-API-HOWTO.txt */
++ /* clean descritors from rbd_first to i */
++ ddesc->ctl = 0;
++ wmb(); /* setting to DCLEAN is the last value to be set */
++ ddesc->status = DCLEAN;
++ do {
++ ddesc = priv->dd_tx + rbd_first;
++ ddesc->ctl = 0;
++ wmb(); /* setting to DCLEAN is the last value to be set */
++ ddesc->status = DCLEAN;
++ rb_inc(&rbd_first, priv->nbdesc_tx);
++ } while (rbd_first != i);
++ spin_unlock(&priv->tx_lock);
++ dev_kfree_skb_any(skb);
++ return NETDEV_TX_OK;
++}
++
++static int sun8i_emac_change_mtu(struct net_device *ndev, int new_mtu)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int max_mtu;
++
++ dev_info(priv->dev, "%s set MTU to %d\n", __func__, new_mtu);
++
++ if (netif_running(ndev)) {
++ dev_err(priv->dev, "%s: must be stopped to change its MTU\n",
++ ndev->name);
++ return -EBUSY;
++ }
++
++ max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
++
++ if ((new_mtu < 68) || (new_mtu > max_mtu)) {
++ dev_err(priv->dev, "%s: invalid MTU, max MTU is: %d\n",
++ ndev->name, max_mtu);
++ return -EINVAL;
++ }
++
++ ndev->mtu = new_mtu;
++ netdev_update_features(ndev);
++ return 0;
++}
++
++static netdev_features_t sun8i_emac_fix_features(struct net_device *ndev,
++ netdev_features_t features)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ netif_dbg(priv, drv, ndev, "%s %llx\n", __func__, features);
++ return features;
++}
++
++static int sun8i_emac_set_features(struct net_device *ndev,
++ netdev_features_t features)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v;
++
++ v = readl(priv->base + SUN8I_EMAC_BASIC_CTL0);
++ if (features & NETIF_F_LOOPBACK && netif_running(ndev)) {
++ netif_info(priv, hw, ndev, "Set loopback features");
++ v |= BIT(1);
++ } else {
++ netif_info(priv, hw, ndev, "Unset loopback features");
++ v &= ~BIT(1);
++ }
++ writel(v, priv->base + SUN8I_EMAC_BASIC_CTL0);
++
++ v = readl(priv->base + SUN8I_EMAC_RX_CTL0);
++ if (features & NETIF_F_RXCSUM) {
++ v |= SUN8I_EMAC_RX_DO_CRC;
++ netif_info(priv, hw, ndev, "Doing RX CRC check by hardware");
++ } else {
++ v &= ~SUN8I_EMAC_RX_DO_CRC;
++ netif_info(priv, hw, ndev, "No RX CRC check by hardware");
++ }
++ if (features & NETIF_F_RXFCS) {
++ v &= ~SUN8I_EMAC_RX_STRIP_FCS;
++ netif_info(priv, hw, ndev, "Keep FCS");
++ } else {
++ v |= SUN8I_EMAC_RX_STRIP_FCS;
++ netif_info(priv, hw, ndev, "Strip FCS");
++ }
++ writel(v, priv->base + SUN8I_EMAC_RX_CTL0);
++
++ netif_dbg(priv, drv, ndev, "%s %llx %x\n", __func__, features, v);
++
++ return 0;
++}
++
++static void sun8i_emac_set_rx_mode(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v = 0;
++ int i = 0;
++ struct netdev_hw_addr *ha;
++
++ /* Receive all multicast frames */
++ v |= BIT(16);
++ /* Receive all control frames */
++ v |= BIT(13);
++ if (ndev->flags & IFF_PROMISC)
++ v |= BIT(1);
++ if (netdev_uc_count(ndev) > 7) {
++ v |= BIT(1);
++ } else {
++ netdev_for_each_uc_addr(ha, ndev) {
++ i++;
++ sun8i_emac_set_macaddr(priv, ha->addr, i);
++ }
++ }
++ writel(v, priv->base + SUN8I_EMAC_RX_FRM_FLT);
++}
++
++static void sun8i_emac_tx_timeout(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ netdev_err(ndev, "%s\n", __func__);
++
++ sun8i_emac_stop_tx(ndev);
++
++ sun8i_emac_tx_clean(ndev);
++
++ /* write start of tx ring descriptor */
++ writel(priv->dd_tx_phy, priv->base + SUN8I_EMAC_TX_DESC_LIST);
++
++ sun8i_emac_start_tx(ndev);
++
++ netdev_reset_queue(ndev);
++
++ ndev->stats.tx_errors++;
++ netif_wake_queue(ndev);
++}
++
++static int sun8i_emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
++{
++ struct phy_device *phydev = ndev->phydev;
++
++ if (!netif_running(ndev))
++ return -EINVAL;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_mii_ioctl(phydev, rq, cmd);
++}
++
++static int sun8i_emac_check_if_running(struct net_device *ndev)
++{
++ if (!netif_running(ndev))
++ return -EINVAL;
++ return 0;
++}
++
++static int sun8i_emac_get_sset_count(struct net_device *ndev, int sset)
++{
++ switch (sset) {
++ case ETH_SS_STATS:
++ return ARRAY_SIZE(estats_str);
++ }
++ return -EOPNOTSUPP;
++}
++
++static int sun8i_emac_ethtool_get_settings(struct net_device *ndev,
++ struct ethtool_cmd *cmd)
++{
++ struct phy_device *phy = ndev->phydev;
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ if (!phy) {
++ netdev_err(ndev, "%s: %s: PHY is not registered\n",
++ __func__, ndev->name);
++ return -ENODEV;
++ }
++
++ if (!netif_running(ndev)) {
++ dev_err(priv->dev, "interface disabled: we cannot track link speed / duplex setting\n");
++ return -EBUSY;
++ }
++
++ return phy_ethtool_gset(phy, cmd);
++}
++
++static int sun8i_emac_ethtool_set_settings(struct net_device *ndev,
++ struct ethtool_cmd *cmd)
++{
++ struct phy_device *phy = ndev->phydev;
++
++ return phy_ethtool_sset(phy, cmd);
++}
++
++static void sun8i_emac_ethtool_getdrvinfo(struct net_device *ndev,
++ struct ethtool_drvinfo *info)
++{
++ strlcpy(info->driver, "sun8i_emac", sizeof(info->driver));
++ strcpy(info->version, "00");
++ info->fw_version[0] = '\0';
++}
++
++static void sun8i_emac_ethtool_stats(struct net_device *ndev,
++ struct ethtool_stats *dummy, u64 *data)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ memcpy(data, &priv->estats,
++ sun8i_emac_get_sset_count(ndev, ETH_SS_STATS) * sizeof(u64));
++}
++
++static void sun8i_emac_ethtool_strings(struct net_device *dev, u32 stringset,
++ u8 *buffer)
++{
++ switch (stringset) {
++ case ETH_SS_STATS:
++ memcpy(buffer, &estats_str, sizeof(estats_str));
++ break;
++ }
++}
++
++static u32 sun8i_emac_ethtool_getmsglevel(struct net_device *ndev)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ return priv->msg_enable;
++}
++
++static void sun8i_emac_ethtool_setmsglevel(struct net_device *ndev, u32 level)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ priv->msg_enable = level;
++}
++
++static void sun8i_emac_get_pauseparam(struct net_device *ndev,
++ struct ethtool_pauseparam *pause)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ pause->rx_pause = 0;
++ pause->tx_pause = 0;
++ pause->autoneg = ndev->phydev->autoneg;
++
++ if (priv->flow_ctrl & FLOW_RX)
++ pause->rx_pause = 1;
++ if (priv->flow_ctrl & FLOW_TX)
++ pause->tx_pause = 1;
++}
++
++static int sun8i_emac_set_pauseparam(struct net_device *ndev,
++ struct ethtool_pauseparam *pause)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ struct phy_device *phy = ndev->phydev;
++ int new_pause = 0;
++ int ret = 0;
++
++ if (pause->rx_pause)
++ new_pause |= FLOW_RX;
++ if (pause->tx_pause)
++ new_pause |= FLOW_TX;
++
++ priv->flow_ctrl = new_pause;
++ phy->autoneg = pause->autoneg;
++
++ if (phy->autoneg) {
++ if (netif_running(ndev))
++ ret = phy_start_aneg(phy);
++ } else {
++ sun8i_emac_flow_ctrl(priv, phy->duplex, priv->flow_ctrl);
++ }
++ return ret;
++}
++
++static void sun8i_emac_ethtool_get_ringparam(struct net_device *ndev,
++ struct ethtool_ringparam *ring)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++
++ ring->rx_pending = priv->nbdesc_rx;
++ ring->tx_pending = priv->nbdesc_tx;
++}
++
++static int sun8i_emac_ethtool_set_ringparam(struct net_device *ndev,
++ struct ethtool_ringparam *ring)
++{
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ int err;
++
++ if (ring->rx_max_pending || ring->rx_mini_max_pending ||
++ ring->rx_jumbo_max_pending || ring->rx_mini_pending ||
++ ring->rx_jumbo_pending || ring->tx_max_pending)
++ return -EINVAL;
++
++ if (ring->tx_pending < MAX_SKB_FRAGS + 1) {
++ netdev_err(ndev, "The number of TX descriptors is too low");
++ return -EINVAL;
++ }
++
++ sun8i_emac_stop_tx(ndev);
++ sun8i_emac_stop_rx(ndev);
++
++ sun8i_emac_rx_clean(ndev);
++ sun8i_emac_tx_clean(ndev);
++
++ kfree(priv->rx_skb);
++ kfree(priv->txl);
++
++ dma_free_coherent(priv->dev, priv->nbdesc_rx * sizeof(struct dma_desc),
++ priv->dd_rx, priv->dd_rx_phy);
++ dma_free_coherent(priv->dev, priv->nbdesc_tx * sizeof(struct dma_desc),
++ priv->dd_tx, priv->dd_tx_phy);
++
++ priv->nbdesc_rx = ring->rx_pending;
++ priv->nbdesc_tx = ring->tx_pending;
++ err = sun8i_emac_alloc_rings(ndev);
++ if (err) {
++ /* Fatal error, we cannot re start */
++ netdev_err(ndev, "Fail to allocate rings\n");
++ return -EFAULT;
++ }
++
++ sun8i_emac_start_rx(ndev);
++ sun8i_emac_start_tx(ndev);
++
++ netif_start_queue(ndev);
++
++ netdev_info(ndev, "Ring Param settings: rx: %d, tx %d\n",
++ ring->rx_pending, ring->tx_pending);
++ return 0;
++}
++
++static const struct ethtool_ops sun8i_emac_ethtool_ops = {
++ .begin = sun8i_emac_check_if_running,
++ .get_settings = sun8i_emac_ethtool_get_settings,
++ .set_settings = sun8i_emac_ethtool_set_settings,
++ .get_link = ethtool_op_get_link,
++ .get_pauseparam = sun8i_emac_get_pauseparam,
++ .set_pauseparam = sun8i_emac_set_pauseparam,
++ .get_ethtool_stats = sun8i_emac_ethtool_stats,
++ .get_strings = sun8i_emac_ethtool_strings,
++ .get_sset_count = sun8i_emac_get_sset_count,
++ .get_drvinfo = sun8i_emac_ethtool_getdrvinfo,
++ .get_msglevel = sun8i_emac_ethtool_getmsglevel,
++ .set_msglevel = sun8i_emac_ethtool_setmsglevel,
++ .get_ringparam = sun8i_emac_ethtool_get_ringparam,
++ .set_ringparam = sun8i_emac_ethtool_set_ringparam,
++};
++
++static const struct net_device_ops sun8i_emac_netdev_ops = {
++ .ndo_init = sun8i_emac_init,
++ .ndo_uninit = sun8i_emac_uninit,
++ .ndo_open = sun8i_emac_open,
++ .ndo_start_xmit = sun8i_emac_xmit,
++ .ndo_stop = sun8i_emac_stop,
++ .ndo_change_mtu = sun8i_emac_change_mtu,
++ .ndo_fix_features = sun8i_emac_fix_features,
++ .ndo_set_features = sun8i_emac_set_features,
++ .ndo_set_rx_mode = sun8i_emac_set_rx_mode,
++ .ndo_tx_timeout = sun8i_emac_tx_timeout,
++ .ndo_do_ioctl = sun8i_emac_ioctl,
++ .ndo_set_mac_address = eth_mac_addr,
++};
++
++static irqreturn_t sun8i_emac_dma_interrupt(int irq, void *dev_id)
++{
++ struct net_device *ndev = dev_id;
++ struct sun8i_emac_priv *priv = netdev_priv(ndev);
++ u32 v, u;
++
++ v = readl(priv->base + SUN8I_EMAC_INT_STA);
++
++ /* When this bit is asserted, a frame transmission is completed. */
++ if (v & BIT(0)) {
++ priv->estats.tx_int++;
++ writel(0, priv->base + SUN8I_EMAC_INT_EN);
++ napi_schedule(&priv->napi);
++ }
++
++ /* When this bit is asserted, the TX DMA FSM is stopped. */
++ if (v & BIT(1))
++ priv->estats.tx_dma_stop++;
++
++ /* When this asserted, the TX DMA can not acquire next TX descriptor
++ * and TX DMA FSM is suspended.
++ */
++ if (v & BIT(2))
++ priv->estats.tx_dma_ua++;
++
++ if (v & BIT(3))
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt TX TIMEOUT\n");
++
++ if (v & BIT(4)) {
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt TX underflow\n");
++ priv->estats.tx_underflow_int++;
++ }
++
++ /* When this bit asserted , the frame is transmitted to FIFO totally. */
++ if (v & BIT(5)) {
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt TX_EARLY_INT\n");
++ priv->estats.tx_early_int++;
++ }
++
++ /* When this bit is asserted, a frame reception is completed */
++ if (v & BIT(8)) {
++ priv->estats.rx_int++;
++ writel(0, priv->base + SUN8I_EMAC_INT_EN);
++ napi_schedule(&priv->napi);
++ }
++
++ /* When this asserted, the RX DMA can not acquire next TX descriptor
++ * and RX DMA FSM is suspended.
++ */
++ if (v & BIT(9)) {
++ u = readl(priv->base + SUN8I_EMAC_RX_CTL1);
++ netif_info(priv, intr, ndev, "Re-run RX DMA %x\n", u);
++ writel(u | RX_DMA_START, priv->base + SUN8I_EMAC_RX_CTL1);
++ priv->estats.rx_dma_ua++;
++ }
++
++ if (v & BIT(10)) {
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt RX_DMA_STOPPED_INT\n");
++ priv->estats.rx_dma_stop++;
++ }
++ if (v & BIT(11))
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt RX_TIMEOUT\n");
++ if (v & BIT(12))
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt RX OVERFLOW\n");
++ if (v & BIT(13)) {
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt RX EARLY\n");
++ priv->estats.rx_early_int++;
++ }
++ if (v & BIT(16))
++ netif_dbg(priv, intr, ndev, "Unhandled interrupt RGMII\n");
++
++ /* the datasheet state those register as read-only
++ * but nothing work(freeze) without writing to it
++ */
++ writel(v & 0x3FFF, priv->base + SUN8I_EMAC_INT_STA);
++
++ return IRQ_HANDLED;
++}
++
++static int sun8i_emac_probe(struct platform_device *pdev)
++{
++ struct device_node *node = pdev->dev.of_node;
++ struct sun8i_emac_priv *priv;
++ struct net_device *ndev;
++ struct resource *res;
++ int ret;
++
++ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
++ if (ret) {
++ dev_err(&pdev->dev, "No suitable DMA available\n");
++ return ret;
++ }
++
++ ndev = alloc_etherdev(sizeof(*priv));
++ if (!ndev)
++ return -ENOMEM;
++
++ SET_NETDEV_DEV(ndev, &pdev->dev);
++ priv = netdev_priv(ndev);
++ platform_set_drvdata(pdev, ndev);
++
++ priv->variant = (enum emac_variant)of_device_get_match_data(&pdev->dev);
++ if (!priv->variant) {
++ dev_err(&pdev->dev, "Missing sun8i-emac variant\n");
++ return -EINVAL;
++ }
++
++ priv->phy_node = of_parse_phandle(node, "phy", 0);
++ if (!priv->phy_node) {
++ netdev_err(ndev, "No associated PHY\n");
++ return -ENODEV;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(priv->base)) {
++ ret = PTR_ERR(priv->base);
++ dev_err(&pdev->dev, "Cannot request MMIO: %d\n", ret);
++ return ret;
++ }
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscon");
++ priv->syscon = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(priv->syscon)) {
++ ret = PTR_ERR(priv->syscon);
++ dev_err(&pdev->dev,
++ "Cannot map system control registers: %d\n", ret);
++ return ret;
++ }
++
++ priv->ahb_clk = devm_clk_get(&pdev->dev, "ahb");
++ if (IS_ERR(priv->ahb_clk)) {
++ ret = PTR_ERR(priv->ahb_clk);
++ dev_err(&pdev->dev, "Cannot get AHB clock err=%d\n", ret);
++ goto probe_err;
++ }
++
++ priv->rst = devm_reset_control_get_optional(&pdev->dev, "ahb");
++ if (IS_ERR(priv->rst)) {
++ ret = PTR_ERR(priv->rst);
++ if (ret == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ dev_info(&pdev->dev, "No MAC reset control found %d\n", ret);
++ priv->rst = NULL;
++ }
++
++ if (priv->variant == H3_EMAC)
++ priv->use_internal_phy = of_property_read_bool(node,
++ "allwinner,use-internal-phy");
++
++ if (priv->use_internal_phy) {
++ priv->ephy_clk = devm_clk_get(&pdev->dev, "ephy");
++ if (IS_ERR(priv->ephy_clk)) {
++ ret = PTR_ERR(priv->ephy_clk);
++ dev_err(&pdev->dev, "Cannot get EPHY clock err=%d\n",
++ ret);
++ goto probe_err;
++ }
++
++ priv->rst_ephy = devm_reset_control_get_optional(&pdev->dev,
++ "ephy");
++ if (IS_ERR(priv->rst_ephy)) {
++ ret = PTR_ERR(priv->rst_ephy);
++ if (ret == -EPROBE_DEFER)
++ goto probe_err;
++ dev_info(&pdev->dev,
++ "No EPHY reset control found %d\n", ret);
++ priv->rst_ephy = NULL;
++ }
++ }
++
++ priv->irq = platform_get_irq(pdev, 0);
++ if (priv->irq < 0) {
++ ret = priv->irq;
++ dev_err(&pdev->dev, "Cannot claim IRQ: %d\n", ret);
++ goto probe_err;
++ }
++
++ spin_lock_init(&priv->tx_lock);
++
++ ndev->netdev_ops = &sun8i_emac_netdev_ops;
++ ndev->ethtool_ops = &sun8i_emac_ethtool_ops;
++
++ priv->ndev = ndev;
++ priv->dev = &pdev->dev;
++
++ ndev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA;
++ ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++ NETIF_F_RXCSUM;
++ ndev->features |= ndev->hw_features;
++ ndev->hw_features |= NETIF_F_RXFCS;
++ ndev->hw_features |= NETIF_F_RXALL;
++ ndev->hw_features |= NETIF_F_LOOPBACK;
++ ndev->priv_flags |= IFF_UNICAST_FLT;
++
++ ndev->watchdog_timeo = msecs_to_jiffies(5000);
++ netif_carrier_off(ndev);
++
++ /* Benched on OPIPC with 100M, setting more than 256 does not give any
++ * perf boost
++ */
++ priv->nbdesc_rx = 128;
++ priv->nbdesc_tx = 256;
++
++ ret = register_netdev(ndev);
++ if (ret) {
++ dev_err(&pdev->dev, "ERROR: Register %s failed\n", ndev->name);
++ goto probe_err;
++ }
++
++ return 0;
++
++probe_err:
++ free_netdev(ndev);
++ return ret;
++}
++
++static int sun8i_emac_remove(struct platform_device *pdev)
++{
++ struct net_device *ndev = platform_get_drvdata(pdev);
++
++ unregister_netdev(ndev);
++ platform_set_drvdata(pdev, NULL);
++ free_netdev(ndev);
++
++ return 0;
++}
++
++static const struct of_device_id sun8i_emac_of_match_table[] = {
++ { .compatible = "allwinner,sun8i-a83t-emac",
++ .data = (void *)A83T_EMAC },
++ { .compatible = "allwinner,sun8i-h3-emac",
++ .data = (void *)H3_EMAC },
++ { .compatible = "allwinner,sun50i-a64-emac",
++ .data = (void *)A64_EMAC },
++ {}
++};
++MODULE_DEVICE_TABLE(of, sun8i_emac_of_match_table);
++
++static struct platform_driver sun8i_emac_driver = {
++ .probe = sun8i_emac_probe,
++ .remove = sun8i_emac_remove,
++ .driver = {
++ .name = "sun8i-emac",
++ .of_match_table = sun8i_emac_of_match_table,
++ },
++};
++
++module_platform_driver(sun8i_emac_driver);
++
++MODULE_DESCRIPTION("sun8i Ethernet driver");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("LABBE Corentin <clabbe.montjoie@gmail.com");
+diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
+index 33df340..425856f 100644
+--- a/drivers/net/ethernet/ti/davinci_mdio.c
++++ b/drivers/net/ethernet/ti/davinci_mdio.c
+@@ -106,6 +106,10 @@ struct davinci_mdio_data {
+ u32 clk_div;
+ };
+
++#if IS_ENABLED(CONFIG_OF)
++static void davinci_mdio_update_dt_from_phymask(u32 phy_mask);
++#endif
++
+ static void davinci_mdio_init_clk(struct davinci_mdio_data *data)
+ {
+ u32 mdio_in, div, mdio_out_khz, access_time;
+@@ -171,6 +175,12 @@ static int davinci_mdio_reset(struct mii_bus *bus)
+ /* restrict mdio bus to live phys only */
+ dev_info(data->dev, "detected phy mask %x\n", ~phy_mask);
+ phy_mask = ~phy_mask;
++
++ #if IS_ENABLED(CONFIG_OF)
++ if (of_machine_is_compatible("ti,am335x-bone"))
++ davinci_mdio_update_dt_from_phymask(phy_mask);
++ #endif
++
+ } else {
+ /* desperately scan all phys */
+ dev_warn(data->dev, "no live phy, scanning all\n");
+@@ -334,6 +344,93 @@ static int davinci_mdio_probe_dt(struct mdio_platform_data *data,
+
+ return 0;
+ }
++static void davinci_mdio_update_dt_from_phymask(u32 phy_mask)
++{
++ int i, len, skip;
++ u32 addr;
++ __be32 *old_phy_p, *phy_id_p;
++ struct property *phy_id_property = NULL;
++ struct device_node *node_p, *slave_p;
++
++ addr = 0;
++
++ for (i = 0; i < PHY_MAX_ADDR; i++) {
++ if ((phy_mask & (1 << i)) == 0) {
++ addr = (u32) i;
++ break;
++ }
++ }
++
++ for_each_compatible_node(node_p, NULL, "ti,cpsw") {
++ for_each_node_by_name(slave_p, "slave") {
++
++#if IS_ENABLED(CONFIG_OF_OVERLAY)
++ skip = 1;
++ // Hack, the overlay fixup "slave" doesn't have phy-mode...
++ old_phy_p = (__be32 *) of_get_property(slave_p, "phy-mode", &len);
++
++ if (len != (sizeof(__be32 *) * 1))
++ {
++ skip = 0;
++ }
++
++ if (skip) {
++#endif
++
++ old_phy_p = (__be32 *) of_get_property(slave_p, "phy_id", &len);
++
++ if (len != (sizeof(__be32 *) * 2))
++ goto err_out;
++
++ if (old_phy_p) {
++
++ phy_id_property = kzalloc(sizeof(*phy_id_property), GFP_KERNEL);
++
++ if (! phy_id_property)
++ goto err_out;
++
++ phy_id_property->length = len;
++ phy_id_property->name = kstrdup("phy_id", GFP_KERNEL);
++ phy_id_property->value = kzalloc(len, GFP_KERNEL);
++
++ if (! phy_id_property->name)
++ goto err_out;
++
++ if (! phy_id_property->value)
++ goto err_out;
++
++ memcpy(phy_id_property->value, old_phy_p, len);
++
++ phy_id_p = (__be32 *) phy_id_property->value + 1;
++
++ *phy_id_p = cpu_to_be32(addr);
++
++ of_update_property(slave_p, phy_id_property);
++ pr_info("davinci_mdio: dt: updated phy_id[%d] from phy_mask[%x]\n", addr, phy_mask);
++
++ ++addr;
++ }
++#if IS_ENABLED(CONFIG_OF_OVERLAY)
++ }
++#endif
++ }
++ }
++
++ return;
++
++err_out:
++
++ if (phy_id_property) {
++ if (phy_id_property->name)
++ kfree(phy_id_property->name);
++
++ if (phy_id_property->value)
++ kfree(phy_id_property->value);
++
++ if (phy_id_property)
++ kfree(phy_id_property);
++ }
++}
+ #endif
+
+ #if IS_ENABLED(CONFIG_OF)
+diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
+index ba7b034..7d4169e 100644
+--- a/drivers/of/Kconfig
++++ b/drivers/of/Kconfig
+@@ -112,4 +112,11 @@ config OF_OVERLAY
+ config OF_NUMA
+ bool
+
++config OF_CONFIGFS
++ bool "Device Tree Overlay ConfigFS interface"
++ select CONFIGFS_FS
++ depends on OF_OVERLAY
++ help
++ Enable a simple user-space driven DT overlay interface.
++
+ endif # OF
+diff --git a/drivers/of/Makefile b/drivers/of/Makefile
+index d7efd9d..aa5ef9d 100644
+--- a/drivers/of/Makefile
++++ b/drivers/of/Makefile
+@@ -1,4 +1,5 @@
+ obj-y = base.o device.o platform.o
++obj-$(CONFIG_OF_CONFIGFS) += configfs.o
+ obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
+ obj-$(CONFIG_OF_FLATTREE) += fdt.o
+ obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
+diff --git a/drivers/of/base.c b/drivers/of/base.c
+index a0bccb5..4e9df30 100644
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -30,6 +30,7 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/proc_fs.h>
++#include <linux/rhashtable.h>
+
+ #include "of_private.h"
+
+@@ -44,6 +45,18 @@ static const char *of_stdout_options;
+
+ struct kset *of_kset;
+
++const struct rhashtable_params of_phandle_ht_params = {
++ .key_offset = offsetof(struct device_node, phandle), /* base offset */
++ .key_len = sizeof(phandle),
++ .head_offset = offsetof(struct device_node, ht_node),
++ .automatic_shrinking = true,
++};
++
++struct rhashtable *of_phandle_ht;
++
++/* default is false */
++bool of_phandle_ht_is_disabled;
++
+ /*
+ * Used to protect the of_aliases, to hold off addition of nodes to sysfs.
+ * This mutex must be held whenever modifications are being made to the
+@@ -163,13 +176,19 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp)
+ return rc;
+ }
+
+-int __of_attach_node_sysfs(struct device_node *np)
++int __of_attach_node_post(struct device_node *np)
+ {
+ const char *name;
+ struct kobject *parent;
+ struct property *pp;
+ int rc;
+
++ if (of_phandle_ht_available()) {
++ rc = of_phandle_ht_insert(np);
++ WARN(rc, "insert to phandle hash fail @%s\n",
++ of_node_full_name(np));
++ }
++
+ if (!IS_ENABLED(CONFIG_SYSFS))
+ return 0;
+
+@@ -201,6 +220,18 @@ int __of_attach_node_sysfs(struct device_node *np)
+ void __init of_core_init(void)
+ {
+ struct device_node *np;
++ int ret;
++
++ of_phandle_ht = kzalloc(sizeof(*of_phandle_ht), GFP_KERNEL);
++ if (!of_phandle_ht) {
++ pr_warn("devicetree: Failed to allocate hashtable\n");
++ return;
++ }
++ ret = rhashtable_init(of_phandle_ht, &of_phandle_ht_params);
++ if (ret) {
++ pr_warn("devicetree: Failed to initialize hashtable\n");
++ return;
++ }
+
+ /* Create the kset, and register existing nodes */
+ mutex_lock(&of_mutex);
+@@ -211,12 +242,16 @@ void __init of_core_init(void)
+ return;
+ }
+ for_each_of_allnodes(np)
+- __of_attach_node_sysfs(np);
++ __of_attach_node_post(np);
+ mutex_unlock(&of_mutex);
+
+ /* Symlink in /proc as required by userspace ABI */
+ if (of_root)
+ proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
++
++ ret = of_overlay_init();
++ if (ret != 0)
++ pr_warn("of_init: of_overlay_init failed!\n");
+ }
+
+ static struct property *__of_find_property(const struct device_node *np,
+@@ -1100,9 +1135,14 @@ struct device_node *of_find_node_by_phandle(phandle handle)
+ return NULL;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+- for_each_of_allnodes(np)
+- if (np->phandle == handle)
+- break;
++ /* when we're ready use the hash table (and not disabled) */
++ if (of_phandle_ht_available() && !of_phandle_ht_is_disabled)
++ np = of_phandle_ht_lookup(handle);
++ else { /* fallback */
++ for_each_of_allnodes(np)
++ if (np->phandle == handle)
++ break;
++ }
+ of_node_get(np);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return np;
+diff --git b/drivers/of/configfs.c b/drivers/of/configfs.c
+new file mode 100644
+index 0000000..c7e999c
+--- /dev/null
++++ b/drivers/of/configfs.c
+@@ -0,0 +1,307 @@
++/*
++ * Configfs entries for device-tree
++ *
++ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include <linux/ctype.h>
++#include <linux/cpu.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_fdt.h>
++#include <linux/spinlock.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/configfs.h>
++#include <linux/types.h>
++#include <linux/stat.h>
++#include <linux/limits.h>
++#include <linux/file.h>
++#include <linux/vmalloc.h>
++#include <linux/firmware.h>
++
++#include "of_private.h"
++
++struct cfs_overlay_item {
++ struct config_item item;
++
++ char path[PATH_MAX];
++
++ const struct firmware *fw;
++ struct device_node *overlay;
++ int ov_id;
++
++ void *dtbo;
++ int dtbo_size;
++};
++
++static int create_overlay(struct cfs_overlay_item *overlay, void *blob)
++{
++ int err;
++
++ /* unflatten the tree */
++ of_fdt_unflatten_tree(blob, NULL, &overlay->overlay);
++ if (overlay->overlay == NULL) {
++ pr_err("%s: failed to unflatten tree\n", __func__);
++ err = -EINVAL;
++ goto out_err;
++ }
++ pr_debug("%s: unflattened OK\n", __func__);
++
++ /* mark it as detached */
++ of_node_set_flag(overlay->overlay, OF_DETACHED);
++
++ /* perform resolution */
++ err = of_resolve_phandles(overlay->overlay);
++ if (err != 0) {
++ pr_err("%s: Failed to resolve tree\n", __func__);
++ goto out_err;
++ }
++ pr_debug("%s: resolved OK\n", __func__);
++
++ err = of_overlay_create(overlay->overlay);
++ if (err < 0) {
++ pr_err("%s: Failed to create overlay (err=%d)\n",
++ __func__, err);
++ goto out_err;
++ }
++ overlay->ov_id = err;
++
++out_err:
++ return err;
++}
++
++static inline struct cfs_overlay_item *to_cfs_overlay_item(
++ struct config_item *item)
++{
++ return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
++}
++
++static ssize_t cfs_overlay_item_path_show(struct config_item *item, char *page)
++{
++ return sprintf(page, "%s\n", to_cfs_overlay_item(item)->path);
++}
++
++static ssize_t cfs_overlay_item_path_store(struct config_item *item,
++ const char *page, size_t count)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++ const char *p = page;
++ char *s;
++ int err;
++
++ /* if it's set do not allow changes */
++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
++ return -EPERM;
++
++ /* copy to path buffer (and make sure it's always zero terminated */
++ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
++ overlay->path[sizeof(overlay->path) - 1] = '\0';
++
++ /* strip trailing newlines */
++ s = overlay->path + strlen(overlay->path);
++ while (s > overlay->path && *--s == '\n')
++ *s = '\0';
++
++ pr_debug("%s: path is '%s'\n", __func__, overlay->path);
++
++ err = request_firmware(&overlay->fw, overlay->path, NULL);
++ if (err != 0)
++ goto out_err;
++
++ err = create_overlay(overlay, (void *)overlay->fw->data);
++ if (err < 0)
++ goto out_err;
++
++ return count;
++
++out_err:
++
++ release_firmware(overlay->fw);
++ overlay->fw = NULL;
++
++ overlay->path[0] = '\0';
++ return err;
++}
++
++static ssize_t cfs_overlay_item_status_show(struct config_item *item,
++ char *page)
++{
++ return sprintf(page, "%s\n", to_cfs_overlay_item(item)->ov_id >= 0 ?
++ "applied" : "unapplied");
++}
++
++CONFIGFS_ATTR(cfs_overlay_item_, path);
++CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
++
++static struct configfs_attribute *cfs_overlay_attrs[] = {
++ &cfs_overlay_item_attr_path,
++ &cfs_overlay_item_attr_status,
++ NULL,
++};
++
++ssize_t cfs_overlay_item_dtbo_read(struct config_item *item, void *buf,
++ size_t max_count)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ pr_debug("%s: buf=%p max_count=%u\n", __func__,
++ buf, max_count);
++
++ if (overlay->dtbo == NULL)
++ return 0;
++
++ /* copy if buffer provided */
++ if (buf != NULL) {
++ /* the buffer must be large enough */
++ if (overlay->dtbo_size > max_count)
++ return -ENOSPC;
++
++ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
++ }
++
++ return overlay->dtbo_size;
++}
++
++ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, const void *buf,
++ size_t count)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++ int err;
++
++ /* if it's set do not allow changes */
++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
++ return -EPERM;
++
++ /* copy the contents */
++ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
++ if (overlay->dtbo == NULL)
++ return -ENOMEM;
++
++ overlay->dtbo_size = count;
++
++ err = create_overlay(overlay, overlay->dtbo);
++ if (err < 0)
++ goto out_err;
++
++ return count;
++
++out_err:
++ kfree(overlay->dtbo);
++ overlay->dtbo = NULL;
++ overlay->dtbo_size = 0;
++
++ return err;
++}
++
++CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
++
++static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
++ &cfs_overlay_item_attr_dtbo,
++ NULL,
++};
++
++static void cfs_overlay_release(struct config_item *item)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ if (overlay->ov_id >= 0)
++ of_overlay_destroy(overlay->ov_id);
++ if (overlay->fw)
++ release_firmware(overlay->fw);
++ /* kfree with NULL is safe */
++ kfree(overlay->dtbo);
++ kfree(overlay);
++}
++
++static struct configfs_item_operations cfs_overlay_item_ops = {
++ .release = cfs_overlay_release,
++};
++
++static struct config_item_type cfs_overlay_type = {
++ .ct_item_ops = &cfs_overlay_item_ops,
++ .ct_attrs = cfs_overlay_attrs,
++ .ct_bin_attrs = cfs_overlay_bin_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item *cfs_overlay_group_make_item(
++ struct config_group *group, const char *name)
++{
++ struct cfs_overlay_item *overlay;
++
++ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
++ if (!overlay)
++ return ERR_PTR(-ENOMEM);
++ overlay->ov_id = -1;
++
++ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
++ return &overlay->item;
++}
++
++static void cfs_overlay_group_drop_item(struct config_group *group,
++ struct config_item *item)
++{
++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
++
++ config_item_put(&overlay->item);
++}
++
++static struct configfs_group_operations overlays_ops = {
++ .make_item = cfs_overlay_group_make_item,
++ .drop_item = cfs_overlay_group_drop_item,
++};
++
++static struct config_item_type overlays_type = {
++ .ct_group_ops = &overlays_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct configfs_group_operations of_cfs_ops = {
++ /* empty - we don't allow anything to be created */
++};
++
++static struct config_item_type of_cfs_type = {
++ .ct_group_ops = &of_cfs_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++struct config_group of_cfs_overlay_group;
++
++static struct configfs_subsystem of_cfs_subsys = {
++ .su_group = {
++ .cg_item = {
++ .ci_namebuf = "device-tree",
++ .ci_type = &of_cfs_type,
++ },
++ },
++ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
++};
++
++static int __init of_cfs_init(void)
++{
++ int ret;
++
++ pr_info("%s\n", __func__);
++
++ config_group_init(&of_cfs_subsys.su_group);
++ config_group_init_type_name(&of_cfs_overlay_group, "overlays",
++ &overlays_type);
++ configfs_add_default_group(&of_cfs_overlay_group,
++ &of_cfs_subsys.su_group);
++
++ ret = configfs_register_subsystem(&of_cfs_subsys);
++ if (ret != 0) {
++ pr_err("%s: failed to register subsys\n", __func__);
++ goto out;
++ }
++ pr_info("%s: OK\n", __func__);
++out:
++ return ret;
++}
++late_initcall(of_cfs_init);
+diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
+index 888fdbc..2a89b17 100644
+--- a/drivers/of/dynamic.c
++++ b/drivers/of/dynamic.c
+@@ -13,6 +13,7 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/proc_fs.h>
++#include <linux/rhashtable.h>
+
+ #include "of_private.h"
+
+@@ -43,9 +44,16 @@ void of_node_put(struct device_node *node)
+ }
+ EXPORT_SYMBOL(of_node_put);
+
+-void __of_detach_node_sysfs(struct device_node *np)
++void __of_detach_node_post(struct device_node *np)
+ {
+ struct property *pp;
++ int rc;
++
++ if (of_phandle_ht_available()) {
++ rc = of_phandle_ht_remove(np);
++ WARN(rc, "remove from phandle hash fail @%s\n",
++ of_node_full_name(np));
++ }
+
+ if (!IS_ENABLED(CONFIG_SYSFS))
+ return;
+@@ -253,7 +261,7 @@ int of_attach_node(struct device_node *np)
+ __of_attach_node(np);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+- __of_attach_node_sysfs(np);
++ __of_attach_node_post(np);
+ mutex_unlock(&of_mutex);
+
+ of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, &rd);
+@@ -306,7 +314,7 @@ int of_detach_node(struct device_node *np)
+ __of_detach_node(np);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+- __of_detach_node_sysfs(np);
++ __of_detach_node_post(np);
+ mutex_unlock(&of_mutex);
+
+ of_reconfig_notify(OF_RECONFIG_DETACH_NODE, &rd);
+@@ -397,8 +405,9 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
+ }
+
+ /**
+- * __of_node_dup() - Duplicate or create an empty device node dynamically.
+- * @fmt: Format string (plus vargs) for new full name of the device node
++ * __of_node_dupv() - Duplicate or create an empty device node dynamically.
++ * @fmt: Format string for new full name of the device node
++ * @vargs: va_list containing the arugments for the node full name
+ *
+ * Create an device tree node, either by duplicating an empty node or by allocating
+ * an empty one suitable for further modification. The node data are
+@@ -406,17 +415,15 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
+ * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of
+ * memory error.
+ */
+-struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...)
++struct device_node *__of_node_dupv(const struct device_node *np,
++ const char *fmt, va_list vargs)
+ {
+- va_list vargs;
+ struct device_node *node;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return NULL;
+- va_start(vargs, fmt);
+ node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs);
+- va_end(vargs);
+ if (!node->full_name) {
+ kfree(node);
+ return NULL;
+@@ -448,6 +455,24 @@ struct device_node *__of_node_dup(const struct device_node *np, const char *fmt,
+ return NULL;
+ }
+
++/**
++ * __of_node_dup() - Duplicate or create an empty device node dynamically.
++ * @fmt: Format string (plus vargs) for new full name of the device node
++ *
++ * See: __of_node_dupv()
++ */
++struct device_node *__of_node_dup(const struct device_node *np,
++ const char *fmt, ...)
++{
++ va_list vargs;
++ struct device_node *node;
++
++ va_start(vargs, fmt);
++ node = __of_node_dupv(np, fmt, vargs);
++ va_end(vargs);
++ return node;
++}
++
+ static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
+ {
+ of_node_put(ce->np);
+@@ -614,10 +639,10 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
+
+ switch (ce->action) {
+ case OF_RECONFIG_ATTACH_NODE:
+- __of_attach_node_sysfs(ce->np);
++ __of_attach_node_post(ce->np);
+ break;
+ case OF_RECONFIG_DETACH_NODE:
+- __of_detach_node_sysfs(ce->np);
++ __of_detach_node_post(ce->np);
+ break;
+ case OF_RECONFIG_ADD_PROPERTY:
+ /* ignore duplicate names */
+@@ -813,3 +838,295 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(of_changeset_action);
++
++/* changeset helpers */
++
++/**
++ * of_changeset_create_device_node - Create an empty device node
++ *
++ * @ocs: changeset pointer
++ * @parent: parent device node
++ * @fmt: format string for the node's full_name
++ * @args: argument list for the format string
++ *
++ * Create an empty device node, marking it as detached and allocated.
++ *
++ * Returns a device node on success, an error encoded pointer otherwise
++ */
++struct device_node *of_changeset_create_device_nodev(
++ struct of_changeset *ocs, struct device_node *parent,
++ const char *fmt, va_list vargs)
++{
++ struct device_node *node;
++
++ node = __of_node_dupv(NULL, fmt, vargs);
++ if (!node)
++ return ERR_PTR(-ENOMEM);
++
++ node->parent = parent;
++ return node;
++}
++EXPORT_SYMBOL_GPL(of_changeset_create_device_nodev);
++
++/**
++ * of_changeset_create_device_node - Create an empty device node
++ *
++ * @ocs: changeset pointer
++ * @parent: parent device node
++ * @fmt: Format string for the node's full_name
++ * ... Arguments
++ *
++ * Create an empty device node, marking it as detached and allocated.
++ *
++ * Returns a device node on success, an error encoded pointer otherwise
++ */
++__printf(3, 4) struct device_node *
++of_changeset_create_device_node(struct of_changeset *ocs,
++ struct device_node *parent, const char *fmt, ...)
++{
++ va_list vargs;
++ struct device_node *node;
++
++ va_start(vargs, fmt);
++ node = of_changeset_create_device_nodev(ocs, parent, fmt, vargs);
++ va_end(vargs);
++ return node;
++}
++EXPORT_SYMBOL_GPL(of_changeset_create_device_node);
++
++/**
++ * __of_changeset_add_property_copy - Create/update a new property copying
++ * name & value
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @value: pointer to the value data
++ * @length: length of the value in bytes
++ * @update: True on update operation
++ *
++ * Adds/updates a property to the changeset by making copies of the name & value
++ * entries. The @update parameter controls whether an add or update takes place.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++int __of_changeset_add_update_property_copy(struct of_changeset *ocs,
++ struct device_node *np, const char *name, const void *value,
++ int length, bool update)
++{
++ struct property *prop;
++ char *new_name;
++ void *new_value;
++ int ret = -ENOMEM;
++
++ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
++ if (!prop)
++ return -ENOMEM;
++
++ new_name = kstrdup(name, GFP_KERNEL);
++ if (!new_name)
++ goto out_err;
++
++ /*
++ * NOTE: There is no check for zero length value.
++ * In case of a boolean property, this will allocate a value
++ * of zero bytes. We do this to work around the use
++ * of of_get_property() calls on boolean values.
++ */
++ new_value = kmemdup(value, length, GFP_KERNEL);
++ if (!new_value)
++ goto out_err;
++
++ of_property_set_flag(prop, OF_DYNAMIC);
++
++ prop->name = new_name;
++ prop->value = new_value;
++ prop->length = length;
++
++ if (!update)
++ ret = of_changeset_add_property(ocs, np, prop);
++ else
++ ret = of_changeset_update_property(ocs, np, prop);
++
++ if (!ret)
++ return 0;
++
++out_err:
++ kfree(prop->value);
++ kfree(prop->name);
++ kfree(prop);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_copy);
++
++/**
++ * of_changeset_add_property_stringf - Create a new formatted string property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @fmt: format of string property
++ * ... arguments of the format string
++ *
++ * Adds a string property to the changeset by making copies of the name
++ * and the formatted value.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++__printf(4, 5) int of_changeset_add_property_stringf(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char *fmt, ...)
++{
++ va_list vargs;
++ int ret;
++
++ va_start(vargs, fmt);
++ ret = __of_changeset_add_update_property_stringv(ocs, np, name, fmt,
++ vargs, false);
++ va_end(vargs);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(of_changeset_add_property_stringf);
++
++/**
++ * of_changeset_update_property_stringf - Update formatted string property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @fmt: format of string property
++ * ... arguments of the format string
++ *
++ * Updates a string property to the changeset by making copies of the name
++ * and the formatted value.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++int of_changeset_update_property_stringf(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char *fmt, ...)
++{
++ va_list vargs;
++ int ret;
++
++ va_start(vargs, fmt);
++ ret = __of_changeset_add_update_property_stringv(ocs, np, name, fmt,
++ vargs, true);
++ va_end(vargs);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(of_changeset_update_property_stringf);
++
++/**
++ * __of_changeset_add_update_property_string_list - Create/update a string
++ * list property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @strs: pointer to the string list
++ * @count: string count
++ * @update: True on update operation
++ *
++ * Adds a string list property to the changeset.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++int __of_changeset_add_update_property_string_list(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char **strs, int count, bool update)
++{
++ int total = 0, i, ret;
++ char *value, *s;
++
++ for (i = 0; i < count; i++) {
++ /* check if it's NULL */
++ if (!strs[i])
++ return -EINVAL;
++ total += strlen(strs[i]) + 1;
++ }
++
++ value = kmalloc(total, GFP_KERNEL);
++ if (!value)
++ return -ENOMEM;
++
++ for (i = 0, s = value; i < count; i++) {
++ /* no need to check for NULL, check above */
++ strcpy(s, strs[i]);
++ s += strlen(strs[i]) + 1;
++ }
++
++ ret = __of_changeset_add_update_property_copy(ocs, np, name, value,
++ total, update);
++
++ kfree(value);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_string_list);
++
++static struct device_node *
++__of_changeset_node_move_one(struct of_changeset *ocs,
++ struct device_node *np, struct device_node *new_parent)
++{
++ struct device_node *np2;
++ const char *unitname;
++ int err;
++
++ err = of_changeset_detach_node(ocs, np);
++ if (err)
++ return ERR_PTR(err);
++
++ unitname = strrchr(np->full_name, '/');
++ if (!unitname)
++ unitname = np->full_name;
++
++ np2 = __of_node_dup(np, "%s/%s",
++ new_parent->full_name, unitname);
++ if (!np2)
++ return ERR_PTR(-ENOMEM);
++ np2->parent = new_parent;
++
++ err = of_changeset_attach_node(ocs, np2);
++ if (err)
++ return ERR_PTR(err);
++
++ return np2;
++}
++
++/**
++ * of_changeset_node_move_to - Moves a subtree to a new place in
++ * the tree
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer to be moved
++ * @to: device node of the new parent
++ *
++ * Moves a subtree to a new place in the tree.
++ * Note that a move is a safe operation because the phandles
++ * remain valid.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++int of_changeset_node_move(struct of_changeset *ocs,
++ struct device_node *np, struct device_node *new_parent)
++{
++ struct device_node *npc, *nppc;
++
++ /* move the root first */
++ nppc = __of_changeset_node_move_one(ocs, np, new_parent);
++ if (IS_ERR(nppc))
++ return PTR_ERR(nppc);
++
++ /* move the subtrees next */
++ for_each_child_of_node(np, npc) {
++ nppc = __of_changeset_node_move_one(ocs, npc, nppc);
++ if (IS_ERR(nppc)) {
++ of_node_put(npc);
++ return PTR_ERR(nppc);
++ }
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(of_changeset_node_move);
+diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
+index 18bbb45..2f906dd 100644
+--- a/drivers/of/of_private.h
++++ b/drivers/of/of_private.h
+@@ -79,9 +79,9 @@ extern void __of_update_property_sysfs(struct device_node *np,
+ struct property *newprop, struct property *oldprop);
+
+ extern void __of_attach_node(struct device_node *np);
+-extern int __of_attach_node_sysfs(struct device_node *np);
++extern int __of_attach_node_post(struct device_node *np);
+ extern void __of_detach_node(struct device_node *np);
+-extern void __of_detach_node_sysfs(struct device_node *np);
++extern void __of_detach_node_post(struct device_node *np);
+
+ extern void __of_sysfs_remove_bin_file(struct device_node *np,
+ struct property *prop);
+@@ -95,4 +95,46 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np,
+ #define for_each_transaction_entry_reverse(_oft, _te) \
+ list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
+
++#if defined(CONFIG_OF_OVERLAY)
++extern int of_overlay_init(void);
++#else
++static inline int of_overlay_init(void)
++{
++ return 0;
++}
++#endif
++
++extern const struct rhashtable_params of_phandle_ht_params;
++extern struct rhashtable *of_phandle_ht;
++
++/* for unittest use */
++extern bool of_phandle_ht_is_disabled;
++
++static inline bool of_phandle_ht_available(void)
++{
++ return of_phandle_ht != NULL;
++}
++
++static inline int of_phandle_ht_insert(struct device_node *np)
++{
++ if (!np || !np->phandle)
++ return 0;
++ return rhashtable_insert_fast(of_phandle_ht,
++ &np->ht_node, of_phandle_ht_params);
++}
++
++static inline int of_phandle_ht_remove(struct device_node *np)
++{
++ if (!np || !np->phandle)
++ return 0;
++ return rhashtable_remove_fast(of_phandle_ht,
++ &np->ht_node, of_phandle_ht_params);
++}
++
++static inline struct device_node *of_phandle_ht_lookup(phandle handle)
++{
++ return rhashtable_lookup_fast(of_phandle_ht,
++ &handle, of_phandle_ht_params);
++}
++
+ #endif /* _LINUX_OF_PRIVATE_H */
+diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
+index 318dbb5..27e5c21 100644
+--- a/drivers/of/overlay.c
++++ b/drivers/of/overlay.c
+@@ -22,11 +22,28 @@
+ #include <linux/slab.h>
+ #include <linux/err.h>
+ #include <linux/idr.h>
++#include <linux/sysfs.h>
++#include <linux/atomic.h>
+
+ #include "of_private.h"
+
++/* fwd. decl */
++struct of_overlay;
++struct of_overlay_info;
++
++/* an attribute for each fragment */
++struct fragment_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct kobject *kobj, struct fragment_attribute *fattr,
++ char *buf);
++ ssize_t (*store)(struct kobject *kobj, struct fragment_attribute *fattr,
++ const char *buf, size_t count);
++ struct of_overlay_info *ovinfo;
++};
++
+ /**
+ * struct of_overlay_info - Holds a single overlay info
++ * @info: info node that contains the target and overlay
+ * @target: target of the overlay operation
+ * @overlay: pointer to the overlay contents node
+ *
+@@ -34,8 +51,13 @@
+ * records.
+ */
+ struct of_overlay_info {
++ struct of_overlay *ov;
++ struct device_node *info;
+ struct device_node *target;
+ struct device_node *overlay;
++ struct attribute_group attr_group;
++ struct attribute *attrs[2];
++ struct fragment_attribute target_attr;
+ };
+
+ /**
+@@ -52,11 +74,26 @@ struct of_overlay {
+ struct list_head node;
+ int count;
+ struct of_overlay_info *ovinfo_tab;
++ const struct attribute_group **attr_groups;
+ struct of_changeset cset;
++ struct kobject kobj;
++ int target_index;
++ struct device_node *target_root;
+ };
+
++/* master enable switch; once set to 0 can't be re-enabled */
++static atomic_t ov_enable = ATOMIC_INIT(1);
++
++static int __init of_overlay_disable_setup(char *str __always_unused)
++{
++ atomic_set(&ov_enable, 0);
++ return 1;
++}
++__setup("of_overlay_disable", of_overlay_disable_setup);
++
+ static int of_overlay_apply_one(struct of_overlay *ov,
+ struct device_node *target, const struct device_node *overlay);
++static int overlay_removal_is_ok(struct of_overlay *ov);
+
+ static int of_overlay_apply_single_property(struct of_overlay *ov,
+ struct device_node *target, struct property *prop)
+@@ -187,30 +224,92 @@ static int of_overlay_apply(struct of_overlay *ov)
+
+ /*
+ * Find the target node using a number of different strategies
+- * in order of preference
++ * in order of preference. Respects the target index if available.
+ *
+ * "target" property containing the phandle of the target
+ * "target-path" property containing the path of the target
+ */
+-static struct device_node *find_target_node(struct device_node *info_node)
++static struct device_node *find_target_node(struct of_overlay *ov,
++ struct device_node *info_node, int index)
+ {
++ struct device_node *target = NULL, *np;
+ const char *path;
++ char *newpath;
+ u32 val;
+ int ret;
+
+ /* first try to go by using the target as a phandle */
+- ret = of_property_read_u32(info_node, "target", &val);
+- if (ret == 0)
+- return of_find_node_by_phandle(val);
++ ret = of_property_read_u32_index(info_node, "target", index, &val);
++ if (ret == 0) {
++ target = of_find_node_by_phandle(val);
++ if (!target) {
++ pr_err("%s: Could not find target phandle 0x%x\n",
++ __func__, val);
++ return NULL;
++ }
++ goto check_root;
++ }
+
+- /* now try to locate by path */
+- ret = of_property_read_string(info_node, "target-path", &path);
+- if (ret == 0)
+- return of_find_node_by_path(path);
++ /* failed, try to locate by path */
++ ret = of_property_read_string_index(info_node, "target-path", index,
++ &path);
++ if (ret == 0) {
++
++ if (!ov->target_root) {
++ target = of_find_node_by_path(path);
++ if (!target)
++ pr_err("%s: Could not find target path \"%s\"\n",
++ __func__, path);
++ return target;
++ }
++
++ /* remove preceding '/' from path; relative path */
++ if (*path == '/') {
++ while (*path == '/')
++ path++;
++
++ newpath = kasprintf(GFP_KERNEL, "%s%s%s",
++ of_node_full_name(ov->target_root),
++ *path ? "/" : "", path);
++ if (!newpath) {
++ pr_err("%s: Could not allocate \"%s%s%s\"\n",
++ __func__,
++ of_node_full_name(ov->target_root),
++ *path ? "/" : "", path);
++ return NULL;
++ }
++ target = of_find_node_by_path(newpath);
++ kfree(newpath);
+
+- pr_err("Failed to find target for node %p (%s)\n",
+- info_node, info_node->name);
++ return target;
+
++ }
++ /* target is an alias, need to check */
++ target = of_find_node_by_path(path);
++ if (!target) {
++ pr_err("%s: Could not find alias \"%s\"\n",
++ __func__, path);
++ return NULL;
++ }
++ goto check_root;
++ }
++
++ return NULL;
++
++check_root:
++ if (!ov->target_root)
++ return target;
++
++ /* got a target, but we have to check it's under target root */
++ for (np = target; np; np = np->parent) {
++ if (np == ov->target_root)
++ return target;
++ }
++ pr_err("%s: target \"%s\" not under target_root \"%s\"\n",
++ __func__, of_node_full_name(target),
++ of_node_full_name(ov->target_root));
++ /* target is not under target_root */
++ of_node_put(target);
+ return NULL;
+ }
+
+@@ -235,10 +334,12 @@ static int of_fill_overlay_info(struct of_overlay *ov,
+ if (ovinfo->overlay == NULL)
+ goto err_fail;
+
+- ovinfo->target = find_target_node(info_node);
++ ovinfo->target = find_target_node(ov, info_node, ov->target_index);
+ if (ovinfo->target == NULL)
+ goto err_fail;
+
++ ovinfo->info = of_node_get(info_node);
++
+ return 0;
+
+ err_fail:
+@@ -249,6 +350,17 @@ static int of_fill_overlay_info(struct of_overlay *ov,
+ return -EINVAL;
+ }
+
++static ssize_t target_show(struct kobject *kobj,
++ struct fragment_attribute *fattr, char *buf)
++{
++ struct of_overlay_info *ovinfo = fattr->ovinfo;
++
++ return snprintf(buf, PAGE_SIZE, "%s\n",
++ of_node_full_name(ovinfo->target));
++}
++
++static const struct fragment_attribute target_template_attr = __ATTR_RO(target);
++
+ /**
+ * of_build_overlay_info() - Build an overlay info array
+ * @ov Overlay to build
+@@ -266,7 +378,7 @@ static int of_build_overlay_info(struct of_overlay *ov,
+ {
+ struct device_node *node;
+ struct of_overlay_info *ovinfo;
+- int cnt, err;
++ int i, cnt, err;
+
+ /* worst case; every child is a node */
+ cnt = 0;
+@@ -287,14 +399,45 @@ static int of_build_overlay_info(struct of_overlay *ov,
+
+ /* if nothing filled, return error */
+ if (cnt == 0) {
+- kfree(ovinfo);
+- return -ENODEV;
++ err = -ENODEV;
++ goto err_free_ovinfo;
+ }
+
+ ov->count = cnt;
+ ov->ovinfo_tab = ovinfo;
+
++ ov->attr_groups = kcalloc(cnt + 1,
++ sizeof(struct attribute_group *), GFP_KERNEL);
++ if (ov->attr_groups == NULL) {
++ err = -ENOMEM;
++ goto err_free_ovinfo;
++ }
++
++ for (i = 0; i < cnt; i++) {
++ ovinfo = &ov->ovinfo_tab[i];
++
++ ov->attr_groups[i] = &ovinfo->attr_group;
++
++ ovinfo->target_attr = target_template_attr;
++ /* make lockdep happy */
++ sysfs_attr_init(&ovinfo->target_attr.attr);
++ ovinfo->target_attr.ovinfo = ovinfo;
++
++ ovinfo->attrs[0] = &ovinfo->target_attr.attr;
++ ovinfo->attrs[1] = NULL;
++
++ /* NOTE: direct reference to the full_name */
++ ovinfo->attr_group.name = kbasename(ovinfo->info->full_name);
++ ovinfo->attr_group.attrs = ovinfo->attrs;
++
++ }
++ ov->attr_groups[i] = NULL;
++
+ return 0;
++
++err_free_ovinfo:
++ kfree(ovinfo);
++ return err;
+ }
+
+ /**
+@@ -311,46 +454,201 @@ static int of_free_overlay_info(struct of_overlay *ov)
+ struct of_overlay_info *ovinfo;
+ int i;
+
++ /* free attribute groups space */
++ kfree(ov->attr_groups);
++
+ /* do it in reverse */
+ for (i = ov->count - 1; i >= 0; i--) {
+ ovinfo = &ov->ovinfo_tab[i];
+
+ of_node_put(ovinfo->target);
+ of_node_put(ovinfo->overlay);
++ of_node_put(ovinfo->info);
+ }
+ kfree(ov->ovinfo_tab);
+
+ return 0;
+ }
+
++static int of_overlay_add_symbols(
++ struct device_node *tree,
++ struct of_overlay *ov)
++{
++ struct of_overlay_info *ovinfo;
++ struct device_node *root_sym = NULL;
++ struct device_node *child = NULL;
++ struct property *prop;
++ const char *path, *s;
++ char *new_path;
++ int i, len, err;
++
++ /* both may fail (if no fixups are required) */
++ root_sym = of_find_node_by_path("/__symbols__");
++ child = of_get_child_by_name(tree, "__symbols__");
++
++ err = 0;
++ /* do nothing if either is NULL */
++ if (!root_sym || !child)
++ goto out;
++
++ for_each_property_of_node(child, prop) {
++
++ /* skip properties added automatically */
++ if (of_prop_cmp(prop->name, "name") == 0)
++ continue;
++
++ err = of_property_read_string(child,
++ prop->name, &path);
++ if (err != 0) {
++ pr_err("Could not find symbol '%s'\n", prop->name);
++ continue;
++ }
++
++ /* now find fragment index */
++ s = path;
++
++ /* compare paths to find fragment index */
++ for (i = 0, ovinfo = NULL, len = -1; i < ov->count; i++) {
++ ovinfo = &ov->ovinfo_tab[i];
++
++ pr_debug("#%d: overlay->name=%s target->name=%s\n",
++ i, ovinfo->overlay->full_name,
++ ovinfo->target->full_name);
++
++ len = strlen(ovinfo->overlay->full_name);
++ if (strncasecmp(path, ovinfo->overlay->full_name,
++ len) == 0 && path[len] == '/')
++ break;
++ }
++
++ if (i >= ov->count)
++ continue;
++
++ pr_debug("found target at #%d\n", i);
++ new_path = kasprintf(GFP_KERNEL, "%s%s",
++ ovinfo->target->full_name,
++ path + len);
++ if (!new_path) {
++ pr_err("Failed to allocate propname for \"%s\"\n",
++ prop->name);
++ err = -ENOMEM;
++ break;
++ }
++
++ err = of_changeset_add_property_string(&ov->cset, root_sym,
++ prop->name, new_path);
++
++ /* free always */
++ kfree(new_path);
++
++ if (err) {
++ pr_err("Failed to add property for \"%s\"\n",
++ prop->name);
++ break;
++ }
++ }
++
++out:
++ of_node_put(child);
++ of_node_put(root_sym);
++
++ return err;
++}
++
+ static LIST_HEAD(ov_list);
+ static DEFINE_IDR(ov_idr);
+
+-/**
+- * of_overlay_create() - Create and apply an overlay
+- * @tree: Device node containing all the overlays
+- *
+- * Creates and applies an overlay while also keeping track
+- * of the overlay in a list. This list can be used to prevent
+- * illegal overlay removals.
+- *
+- * Returns the id of the created overlay, or a negative error number
+- */
+-int of_overlay_create(struct device_node *tree)
++static inline struct of_overlay *kobj_to_overlay(struct kobject *kobj)
++{
++ return container_of(kobj, struct of_overlay, kobj);
++}
++
++void of_overlay_release(struct kobject *kobj)
++{
++ struct of_overlay *ov = kobj_to_overlay(kobj);
++
++ of_node_put(ov->target_root);
++ kfree(ov);
++}
++
++static ssize_t enable_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&ov_enable));
++}
++
++static ssize_t enable_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t count)
++{
++ int ret;
++ bool new_enable;
++
++ ret = strtobool(buf, &new_enable);
++ if (ret != 0)
++ return ret;
++ /* if we've disabled it, no going back */
++ if (atomic_read(&ov_enable) == 0)
++ return -EPERM;
++ atomic_set(&ov_enable, (int)new_enable);
++ return count;
++}
++
++static struct kobj_attribute enable_attr = __ATTR_RW(enable);
++
++static const struct attribute *overlay_global_attrs[] = {
++ &enable_attr.attr,
++ NULL
++};
++
++static ssize_t can_remove_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ struct of_overlay *ov = kobj_to_overlay(kobj);
++
++ return snprintf(buf, PAGE_SIZE, "%d\n", overlay_removal_is_ok(ov));
++}
++
++static struct kobj_attribute can_remove_attr = __ATTR_RO(can_remove);
++
++static struct attribute *overlay_attrs[] = {
++ &can_remove_attr.attr,
++ NULL
++};
++
++static struct kobj_type of_overlay_ktype = {
++ .release = of_overlay_release,
++ .sysfs_ops = &kobj_sysfs_ops, /* default kobj sysfs ops */
++ .default_attrs = overlay_attrs,
++};
++
++static struct kset *ov_kset;
++
++static int __of_overlay_create(struct device_node *tree,
++ int target_index, struct device_node *target_root)
+ {
+ struct of_overlay *ov;
+ int err, id;
+
++ /* administratively disabled */
++ if (!atomic_read(&ov_enable))
++ return -EPERM;
++
+ /* allocate the overlay structure */
+ ov = kzalloc(sizeof(*ov), GFP_KERNEL);
+ if (ov == NULL)
+ return -ENOMEM;
+ ov->id = -1;
+
++ ov->target_index = target_index;
++ ov->target_root = of_node_get(target_root);
++
+ INIT_LIST_HEAD(&ov->node);
+
+ of_changeset_init(&ov->cset);
+
++ /* initialize kobject */
++ kobject_init(&ov->kobj, &of_overlay_ktype);
++
+ mutex_lock(&of_mutex);
+
+ id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
+@@ -373,19 +671,44 @@ int of_overlay_create(struct device_node *tree)
+ if (err)
+ goto err_abort_trans;
+
++ err = of_overlay_add_symbols(tree, ov);
++ if (err) {
++ pr_err("%s: of_overlay_add_symbols() failed for tree@%s\n",
++ __func__, tree->full_name);
++ goto err_abort_trans;
++ }
++
+ /* apply the changeset */
+ err = __of_changeset_apply(&ov->cset);
+ if (err)
+ goto err_revert_overlay;
+
+
++ ov->kobj.kset = ov_kset;
++ err = kobject_add(&ov->kobj, NULL, "%d", id);
++ if (err != 0) {
++ pr_err("%s: kobject_add() failed for tree@%s\n",
++ __func__, tree->full_name);
++ goto err_cancel_overlay;
++ }
++
++ err = sysfs_create_groups(&ov->kobj, ov->attr_groups);
++ if (err != 0) {
++ pr_err("%s: sysfs_create_groups() failed for tree@%s\n",
++ __func__, tree->full_name);
++ goto err_remove_kobj;
++ }
++
+ /* add to the tail of the overlay list */
+ list_add_tail(&ov->node, &ov_list);
+
+ mutex_unlock(&of_mutex);
+
+ return id;
+-
++err_remove_kobj:
++ kobject_put(&ov->kobj);
++err_cancel_overlay:
++ of_changeset_revert(&ov->cset);
+ err_revert_overlay:
+ err_abort_trans:
+ of_free_overlay_info(ov);
+@@ -393,13 +716,66 @@ int of_overlay_create(struct device_node *tree)
+ idr_remove(&ov_idr, ov->id);
+ err_destroy_trans:
+ of_changeset_destroy(&ov->cset);
++ of_node_put(ov->target_root);
+ kfree(ov);
+ mutex_unlock(&of_mutex);
+
+ return err;
+ }
++
++/**
++ * of_overlay_create() - Create and apply an overlay
++ * @tree: Device node containing all the overlays
++ *
++ * Creates and applies an overlay while also keeping track
++ * of the overlay in a list. This list can be used to prevent
++ * illegal overlay removals.
++ *
++ * Returns the id of the created overlay, or a negative error number
++ */
++int of_overlay_create(struct device_node *tree)
++{
++ return __of_overlay_create(tree, 0, NULL);
++}
+ EXPORT_SYMBOL_GPL(of_overlay_create);
+
++/**
++ * of_overlay_create_target_index() - Create and apply an overlay
++ * @tree: Device node containing all the overlays
++ * @index: Index to use in the target properties
++ *
++ * Creates and applies an overlay while also keeping track
++ * of the overlay in a list. This list can be used to prevent
++ * illegal overlay removals.
++ *
++ * Returns the id of the created overlay, or a negative error number
++ */
++int of_overlay_create_target_index(struct device_node *tree, int index)
++{
++ return __of_overlay_create(tree, index, NULL);
++}
++EXPORT_SYMBOL_GPL(of_overlay_create_target_index);
++
++/**
++ * of_overlay_create_target_root() - Create and apply an overlay
++ * under which will be limited to target_root
++ * @tree: Device node containing all the overlays
++ * @target_root: Target root for the overlay.
++ *
++ * Creates and applies an overlay while also keeping track
++ * of the overlay in a list. This list can be used to prevent
++ * illegal overlay removals. The overlay is only allowed to
++ * target nodes under the target_root node.
++ *
++ * Returns the id of the created overlay, or an negative error number
++ */
++int of_overlay_create_target_root(struct device_node *tree,
++ struct device_node *target_root)
++{
++ return __of_overlay_create(tree, 0, target_root);
++}
++EXPORT_SYMBOL_GPL(of_overlay_create_target_root);
++
+ /* check whether the given node, lies under the given tree */
+ static int overlay_subtree_check(struct device_node *tree,
+ struct device_node *dn)
+@@ -500,11 +876,13 @@ int of_overlay_destroy(int id)
+
+
+ list_del(&ov->node);
++ sysfs_remove_groups(&ov->kobj, ov->attr_groups);
+ __of_changeset_revert(&ov->cset);
+ of_free_overlay_info(ov);
+ idr_remove(&ov_idr, id);
+ of_changeset_destroy(&ov->cset);
+- kfree(ov);
++
++ kobject_put(&ov->kobj);
+
+ err = 0;
+
+@@ -534,7 +912,7 @@ int of_overlay_destroy_all(void)
+ __of_changeset_revert(&ov->cset);
+ of_free_overlay_info(ov);
+ idr_remove(&ov_idr, ov->id);
+- kfree(ov);
++ kobject_put(&ov->kobj);
+ }
+
+ mutex_unlock(&of_mutex);
+@@ -542,3 +920,18 @@ int of_overlay_destroy_all(void)
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
++
++/* called from of_init() */
++int of_overlay_init(void)
++{
++ int rc;
++
++ ov_kset = kset_create_and_add("overlays", NULL, &of_kset->kobj);
++ if (!ov_kset)
++ return -ENOMEM;
++
++ rc = sysfs_create_files(&ov_kset->kobj, overlay_global_attrs);
++ WARN(rc, "%s: error adding global attributes\n", __func__);
++
++ return rc;
++}
+diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
+index 12f7c3d..a6ded1b 100644
+--- a/drivers/of/unittest-data/testcases.dts
++++ b/drivers/of/unittest-data/testcases.dts
+@@ -75,5 +75,15 @@
+ target = <0x00000000>;
+ };
+ };
++ overlay16 {
++ fragment@0 {
++ target = <0x00000000 0x00000004>;
++ };
++ };
++ overlay18 {
++ fragment@0 {
++ target = <0x00000000>;
++ };
++ };
+ };
+ }; };
+diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
+index 02ba56c..170b04d 100644
+--- a/drivers/of/unittest-data/tests-overlay.dtsi
++++ b/drivers/of/unittest-data/tests-overlay.dtsi
+@@ -110,6 +110,30 @@
+ };
+ };
+ };
++
++ unittest16: test-unittest16 {
++ compatible = "unittest";
++ status = "disabled";
++ reg = <16>;
++ };
++
++ unittest17: test-unittest17 {
++ compatible = "unittest";
++ status = "disabled";
++ reg = <17>;
++ };
++
++ unittest18: test-unittest18 {
++ compatible = "unittest";
++ status = "disabled";
++ reg = <18>;
++ };
++
++ unittest19: test-unittest19 {
++ compatible = "unittest";
++ status = "disabled";
++ reg = <19>;
++ };
+ };
+ };
+
+@@ -325,5 +349,44 @@
+ };
+ };
+
++ /* test enable using indirect functionality */
++ overlay16 {
++ fragment@0 {
++ target = <&unittest17>, <&unittest16>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++ };
++
++ /* test enable using target root (relative path) */
++ overlay17 {
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ status = "okay";
++ };
++ };
++ };
++
++ /* test enable using target phandle */
++ overlay18 {
++ fragment@0 {
++ target = <&unittest18>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++ };
++
++ /* test trying to enable out of root (should fail) */
++ overlay19 {
++ fragment@0 {
++ target = <&unittest19>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++ };
+ };
+ };
+diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
+index 53c83d6..b560ae7 100644
+--- a/drivers/of/unittest.c
++++ b/drivers/of/unittest.c
+@@ -24,6 +24,9 @@
+
+ #include <linux/bitops.h>
+
++#include <linux/timekeeping.h>
++#include <linux/random.h>
++
+ #include "of_private.h"
+
+ static struct unittest_results {
+@@ -542,6 +545,59 @@ static void __init of_unittest_changeset(void)
+ #endif
+ }
+
++static void __init of_unittest_changeset_helper(void)
++{
++#ifdef CONFIG_OF_DYNAMIC
++ struct device_node *n1, *n2, *n21, *parent, *np;
++ struct of_changeset chgset;
++
++ of_changeset_init(&chgset);
++
++ parent = of_find_node_by_path("/testcase-data/changeset");
++
++ unittest(parent, "testcase setup failure\n");
++ n1 = of_changeset_create_device_node(&chgset,
++ parent, "/testcase-data/changeset/n1");
++ unittest(n1, "testcase setup failure\n");
++ n2 = of_changeset_create_device_node(&chgset,
++ parent, "/testcase-data/changeset/n2");
++ unittest(n2, "testcase setup failure\n");
++ n21 = of_changeset_create_device_node(&chgset, n2, "%s/%s",
++ "/testcase-data/changeset/n2", "n21");
++ unittest(n21, "testcase setup failure\n");
++
++ unittest(!of_changeset_add_property_string(&chgset, parent,
++ "prop-add", "foo"), "fail add prop\n");
++
++ unittest(!of_changeset_attach_node(&chgset, n1), "fail n1 attach\n");
++ unittest(!of_changeset_attach_node(&chgset, n2), "fail n2 attach\n");
++ unittest(!of_changeset_attach_node(&chgset, n21), "fail n21 attach\n");
++
++ unittest(!of_changeset_apply(&chgset), "apply failed\n");
++
++ /* Make sure node names are constructed correctly */
++ np = of_find_node_by_path("/testcase-data/changeset/n1");
++ unittest(np, "'%s' not added\n", n1->full_name);
++ of_node_put(np);
++
++ /* Make sure node names are constructed correctly */
++ np = of_find_node_by_path("/testcase-data/changeset/n2");
++ unittest(np, "'%s' not added\n", n2->full_name);
++ of_node_put(np);
++
++ np = of_find_node_by_path("/testcase-data/changeset/n2/n21");
++ unittest(np, "'%s' not added\n", n21->full_name);
++ of_node_put(np);
++
++ unittest(!of_changeset_revert(&chgset), "revert failed\n");
++
++ of_changeset_destroy(&chgset);
++
++ of_node_put(parent);
++#endif
++}
++
++
+ static void __init of_unittest_parse_interrupts(void)
+ {
+ struct device_node *np;
+@@ -877,7 +933,7 @@ static int attach_node_and_children(struct device_node *np)
+ of_node_clear_flag(np, OF_DETACHED);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+- __of_attach_node_sysfs(np);
++ __of_attach_node_post(np);
+ mutex_unlock(&of_mutex);
+
+ while (child) {
+@@ -935,7 +991,7 @@ static int __init unittest_data_add(void)
+ if (!of_root) {
+ of_root = unittest_data_node;
+ for_each_of_allnodes(np)
+- __of_attach_node_sysfs(np);
++ __of_attach_node_post(np);
+ of_aliases = of_find_node_by_path("/aliases");
+ of_chosen = of_find_node_by_path("/chosen");
+ return 0;
+@@ -1854,6 +1910,273 @@ static inline void of_unittest_overlay_i2c_15(void) { }
+
+ #endif
+
++static void of_unittest_overlay_16(void)
++{
++ int ret;
++ int overlay_nr = 16;
++ int unittest_nr = 16;
++ enum overlay_type ovtype = PDEV_OVERLAY;
++ int before = 0;
++ int after = 1;
++ struct device_node *np = NULL;
++ int id = -1;
++
++ /* unittest device must not be in before state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
++ unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !before ? "enabled" : "disabled");
++ return;
++ }
++
++ np = of_find_node_by_path(overlay_path(overlay_nr));
++ if (np == NULL) {
++ unittest(0, "could not find overlay node @\"%s\"\n",
++ overlay_path(overlay_nr));
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /* unittest16 is at index #1 */
++ ret = of_overlay_create_target_index(np, 1);
++ if (ret < 0) {
++ unittest(0, "could not create overlay from \"%s\"\n",
++ overlay_path(overlay_nr));
++ goto out;
++ }
++ id = ret;
++ of_unittest_track_overlay(id);
++
++ ret = 0;
++
++out:
++ of_node_put(np);
++
++ if (ret)
++ return;
++
++ /* unittest device must be to set to after state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
++ unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !after ? "enabled" : "disabled");
++ return;
++ }
++
++ unittest(1, "overlay test %d passed\n", 16);
++}
++
++static void of_unittest_overlay_17(void)
++{
++ int ret;
++ int overlay_nr = 17;
++ int unittest_nr = 17;
++ enum overlay_type ovtype = PDEV_OVERLAY;
++ int before = 0;
++ int after = 1;
++ const char *root_path;
++ struct device_node *np = NULL, *target_root = NULL;
++ int id = -1;
++
++ /* unittest device must not be in before state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
++ unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !before ? "enabled" : "disabled");
++ return;
++ }
++
++ np = of_find_node_by_path(overlay_path(overlay_nr));
++ if (np == NULL) {
++ unittest(0, "could not find overlay node @\"%s\"\n",
++ overlay_path(overlay_nr));
++ ret = -EINVAL;
++ goto out;
++ }
++
++ root_path = "/testcase-data/overlay-node/test-bus/test-unittest17";
++ target_root = of_find_node_by_path(root_path);
++ if (!target_root) {
++ unittest(0, "could not find target_root node @\"%s\"\n",
++ root_path);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = of_overlay_create_target_root(np, target_root);
++ of_node_put(target_root);
++
++ if (ret < 0) {
++ unittest(0, "could not create overlay from \"%s\"\n",
++ overlay_path(overlay_nr));
++ goto out;
++ }
++ id = ret;
++ of_unittest_track_overlay(id);
++
++ ret = 0;
++
++out:
++ of_node_put(np);
++
++ if (ret)
++ return;
++
++ /* unittest device must be to set to after state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
++ unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !after ? "enabled" : "disabled");
++ return;
++ }
++
++ unittest(1, "overlay test %d passed\n", 17);
++}
++
++static void of_unittest_overlay_18(void)
++{
++ int ret;
++ int overlay_nr = 18;
++ int unittest_nr = 18;
++ enum overlay_type ovtype = PDEV_OVERLAY;
++ int before = 0;
++ int after = 1;
++ const char *root_path;
++ struct device_node *np = NULL, *target_root = NULL;
++ int id = -1;
++
++ /* unittest device must not be in before state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
++ unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !before ? "enabled" : "disabled");
++ return;
++ }
++
++ np = of_find_node_by_path(overlay_path(overlay_nr));
++ if (np == NULL) {
++ unittest(0, "could not find overlay node @\"%s\"\n",
++ overlay_path(overlay_nr));
++ ret = -EINVAL;
++ goto out;
++ }
++
++ root_path = "/testcase-data/overlay-node/test-bus/test-unittest18";
++ target_root = of_find_node_by_path(root_path);
++ if (!target_root) {
++ unittest(0, "could not find target_root node @\"%s\"\n",
++ root_path);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = of_overlay_create_target_root(np, target_root);
++ of_node_put(target_root);
++
++ if (ret < 0) {
++ unittest(0, "could not create overlay from \"%s\"\n",
++ overlay_path(overlay_nr));
++ goto out;
++ }
++ id = ret;
++ of_unittest_track_overlay(id);
++
++ ret = 0;
++
++out:
++ of_node_put(np);
++
++ if (ret)
++ return;
++
++ /* unittest device must be to set to after state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
++ unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !after ? "enabled" : "disabled");
++ return;
++ }
++
++ unittest(1, "overlay test %d passed\n", 18);
++}
++
++static void of_unittest_overlay_19(void)
++{
++ int ret;
++ int overlay_nr = 19;
++ int unittest_nr = 19;
++ enum overlay_type ovtype = PDEV_OVERLAY;
++ int before = 0;
++ int after = 0;
++ const char *root_path;
++ struct device_node *np = NULL, *target_root = NULL;
++ int id = -1;
++
++ /* unittest device must not be in before state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
++ unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !before ? "enabled" : "disabled");
++ return;
++ }
++
++ np = of_find_node_by_path(overlay_path(overlay_nr));
++ if (np == NULL) {
++ unittest(0, "could not find overlay node @\"%s\"\n",
++ overlay_path(overlay_nr));
++ ret = -EINVAL;
++ goto out;
++ }
++
++ root_path = "/testcase-data/overlay-node/test-bus/test-unittest19";
++ target_root = of_find_node_by_path(root_path);
++ if (!target_root) {
++ unittest(0, "could not find target_root node @\"%s\"\n",
++ root_path);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = of_overlay_create_target_root(np, target_root);
++ of_node_put(target_root);
++
++ if (ret >= 0) {
++ unittest(0, "created overlay from \"%s\" while we shouldn't\n",
++ overlay_path(overlay_nr));
++ id = ret;
++ of_unittest_track_overlay(id);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = 0;
++
++out:
++ of_node_put(np);
++
++ if (ret)
++ return;
++
++ /* unittest device must be to set to after state */
++ if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
++ unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
++ overlay_path(overlay_nr),
++ unittest_path(unittest_nr, ovtype),
++ !after ? "enabled" : "disabled");
++ return;
++ }
++
++ unittest(1, "overlay test %d passed\n", 16);
++}
++
++
+ static void __init of_unittest_overlay(void)
+ {
+ struct device_node *bus_np = NULL;
+@@ -1904,6 +2227,12 @@ static void __init of_unittest_overlay(void)
+ of_unittest_overlay_10();
+ of_unittest_overlay_11();
+
++ of_unittest_overlay_16();
++
++ of_unittest_overlay_17();
++ of_unittest_overlay_18();
++ of_unittest_overlay_19();
++
+ #if IS_BUILTIN(CONFIG_I2C)
+ if (unittest(of_unittest_overlay_i2c_init() == 0, "i2c init failed\n"))
+ goto out;
+@@ -1926,6 +2255,70 @@ static void __init of_unittest_overlay(void)
+ static inline void __init of_unittest_overlay(void) { }
+ #endif
+
++#define PHANDLE_LOOKUPS 1000
++
++static void __init of_unittest_phandle_hash(void)
++{
++ struct device_node *node;
++ phandle max_phandle;
++ u32 ph;
++ unsigned long flags;
++ int i, j, total;
++ ktime_t start, end;
++ s64 dur[2];
++ int dec, frac;
++
++ /* test only available when hashing is available */
++ if (!of_phandle_ht_available()) {
++ pr_warn("phandle hash test requires hash to be initialized\n");
++ return;
++ }
++
++ /* find the maximum phandle of the tree */
++ raw_spin_lock_irqsave(&devtree_lock, flags);
++ max_phandle = 0;
++ total = 0;
++ for_each_of_allnodes(node) {
++ if (node->phandle != (phandle)-1U &&
++ node->phandle > max_phandle)
++ max_phandle = node->phandle;
++ total++;
++ }
++ raw_spin_unlock_irqrestore(&devtree_lock, flags);
++ max_phandle++;
++
++ pr_debug("phandle: max-phandle #%u, #%d total nodes\n",
++ (u32)max_phandle, total);
++
++ /* perform random lookups using the hash */
++ for (j = 0; j < 2; j++) {
++
++ /* disabled for pass #0, enabled for pass #1 */
++ of_phandle_ht_is_disabled = j == 0;
++
++ start = ktime_get_raw();
++ for (i = 0; i < PHANDLE_LOOKUPS; i++) {
++ ph = prandom_u32() % max_phandle;
++ node = of_find_node_by_phandle(ph);
++ of_node_put(node);
++ }
++ end = ktime_get_raw();
++
++ dur[j] = ktime_to_us(end) - ktime_to_us(start);
++ pr_debug("#%d lookups in %lld us (%s)\n",
++ PHANDLE_LOOKUPS, dur[j],
++ j == 0 ? "original" : "hashed");
++ }
++
++ unittest(dur[0] > dur[1], "Non hashing phandles are faster!?");
++
++ dec = (int)div64_s64(dur[0] * 10 + 5, dur[1]);
++ frac = dec % 10;
++ dec /= 10;
++ pr_info("the hash method is %d.%d times faster than the original\n",
++ dec, frac);
++}
++
+ static int __init of_unittest(void)
+ {
+ struct device_node *np;
+@@ -1954,11 +2347,13 @@ static int __init of_unittest(void)
+ of_unittest_property_string();
+ of_unittest_property_copy();
+ of_unittest_changeset();
++ of_unittest_changeset_helper();
+ of_unittest_parse_interrupts();
+ of_unittest_parse_interrupts_extended();
+ of_unittest_match_node();
+ of_unittest_platform_populate();
+ of_unittest_overlay();
++ of_unittest_phandle_hash();
+
+ /* Double check linkage after removing testcase data */
+ of_unittest_check_tree_linkage();
+diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
+index 671610c..f90bed9 100644
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -180,6 +180,18 @@ config PINCTRL_ST
+ select PINCONF
+ select GPIOLIB_IRQCHIP
+
++config PINCTRL_TI_IODELAY
++ bool "TI IODelay Module pinconf driver"
++ depends on OF
++ select PINCONF
++ select GENERIC_PINCONF
++ select REGMAP_MMIO
++ help
++ Say Y here to support Texas Instruments' IODelay pinconf driver.
++ IODelay module is used for the DRA7 SoC family. This driver is in
++ addition to PINCTRL_SINGLE which controls the mux.
++
++
+ config PINCTRL_TZ1090
+ bool "Toumaz Xenif TZ1090 pin control driver"
+ depends on SOC_TZ1090
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 11bad37..23e118e 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -26,6 +26,7 @@ obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
+ obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
+ obj-$(CONFIG_PINCTRL_SIRF) += sirf/
+ obj-$(CONFIG_ARCH_TEGRA) += tegra/
++obj-$(CONFIG_PINCTRL_TI_IODELAY)+= pinctrl-ti-iodelay.o
+ obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o
+ obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o
+ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
+diff --git b/drivers/pinctrl/pinctrl-ti-iodelay.c b/drivers/pinctrl/pinctrl-ti-iodelay.c
+new file mode 100644
+index 0000000..8d33414
+--- /dev/null
++++ b/drivers/pinctrl/pinctrl-ti-iodelay.c
+@@ -0,0 +1,968 @@
++/*
++ * Support for configuration of IO Delay module found on Texas Instruments SoCs
++ * such as DRA7
++ *
++ * Copyright (C) 2015 Texas Instruments, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/of.h>
++#include <linux/pinctrl/pinconf-generic.h>
++#include <linux/pinctrl/pinconf.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/regmap.h>
++#include <linux/slab.h>
++
++#define IODELAY_REG_NAME_LEN ((sizeof(u32) * 2) + 3)
++#define DRIVER_NAME "ti-io-delay"
++/* Should I change this? Abuse? */
++#define IODELAY_MUX_PINS_NAME "pinctrl-single,pins"
++
++/* Device tree match, populated later */
++static const struct of_device_id ti_iodelay_of_match[];
++
++/**
++ * struct ti_iodelay_conf_vals - Description of each configuration parameters.
++ * @offset: Configuration register offset
++ * @a_delay: Agnostic Delay (in ps)
++ * @g_delay: Gnostic Delay (in ps)
++ */
++struct ti_iodelay_conf_vals {
++ u16 offset;
++ u16 a_delay;
++ u16 g_delay;
++};
++
++/**
++ * struct ti_iodelay_reg_data - Describes the registers for the IOdelay instance
++ * @signature_mask: Conf reg- mask for the signature bits
++ * @signature_value: Conf reg- signature value to be written (see TRM)
++ * @lock_mask: Conf reg- mask for the lock bits
++ * @lock_val: Conf reg- lock value for the lock bits (see TRM)
++ * @unlock_val: Conf reg- unlock value for the lock bits (see TRM)
++ * @binary_data_coarse_mask: Conf reg- coarse mask (see TRM)
++ * @binary_data_fine_mask: Conf reg- fine mask (see TRM)
++ * @reg_refclk_offset: Refclk register offset
++ * @refclk_period_mask: Refclk mask
++ * @reg_coarse_offset: Coarse register configuration offset
++ * @coarse_delay_count_mask: Coarse delay count mask
++ * @coarse_ref_count_mask: Coarse ref count mask
++ * @reg_fine_offset: Fine register configuration offset
++ * @fine_delay_count_mask: Fine delay count mask
++ * @fine_ref_count_mask: Fine ref count mask
++ * @reg_global_lock_offset: Global(for the IOdelay module) lock register offset
++ * @global_lock_mask: Lock mask
++ * @global_unlock_val: unlock value
++ * @global_lock_val: lock value
++ * @reg_start_offset: Where does the configuration registers start?
++ * @regmap_config: Regmap configuration for the IODelay region
++ */
++struct ti_iodelay_reg_data {
++ u32 signature_mask;
++ u32 signature_value;
++ u32 lock_mask;
++ u32 lock_val;
++ u32 unlock_val;
++ u32 binary_data_coarse_mask;
++ u32 binary_data_fine_mask;
++
++ u32 reg_refclk_offset;
++ u32 refclk_period_mask;
++
++ u32 reg_coarse_offset;
++ u32 coarse_delay_count_mask;
++ u32 coarse_ref_count_mask;
++
++ u32 reg_fine_offset;
++ u32 fine_delay_count_mask;
++ u32 fine_ref_count_mask;
++
++ u32 reg_global_lock_offset;
++ u32 global_lock_mask;
++ u32 global_unlock_val;
++ u32 global_lock_val;
++
++ u32 reg_start_offset;
++
++ struct regmap_config *regmap_config;
++};
++
++/**
++ * struct ti_iodelay_reg_values - Computed io_reg configuration values (see TRM)
++ * @coarse_ref_count: Coarse reference count
++ * @coarse_delay_count: Coarse delay count
++ * @fine_ref_count: Fine reference count
++ * @fine_delay_count: Fine Delay count
++ * @ref_clk_period: Reference Clock period
++ * @cdpe: Coarse delay parameter
++ * @fdpe: Fine delay parameter
++ */
++struct ti_iodelay_reg_values {
++ u16 coarse_ref_count;
++ u16 coarse_delay_count;
++
++ u16 fine_ref_count;
++ u16 fine_delay_count;
++
++ u16 ref_clk_period;
++
++ u32 cdpe;
++ u32 fdpe;
++};
++
++/**
++ * struct ti_iodelay_pin_name - name of the pins
++ * @name: name
++ */
++struct ti_iodelay_pin_name {
++ char name[IODELAY_REG_NAME_LEN];
++};
++
++/**
++ * struct ti_iodelay_pingroup - Structure that describes one group
++ * @np: Node pointer (device tree)
++ * @name: Name of the group
++ * @map: pinctrl map allocated for the group
++ * @vals: configuration values allocated for the group (from dt)
++ * @nvals: number of configuration values allocated
++ * @config: pinconf "Config" - currently a dummy value
++ * @node: list node to next group
++ */
++struct ti_iodelay_pingroup {
++ struct device_node *np;
++ const char *name;
++ struct pinctrl_map *map;
++ struct ti_iodelay_conf_vals *vals;
++ int nvals;
++ unsigned long config;
++ struct list_head node;
++};
++
++/**
++ * struct ti_iodelay_device - Represents information for a IOdelay instance
++ * @dev: device pointer
++ * @reg_base: Remapped virtual address
++ * @regmap: Regmap for this IOdelay instance
++ * @pctl: Pinctrl device
++ * @desc: pinctrl descriptor for pctl
++ * @pa: pinctrl pin wise description
++ * @names: names of the pins
++ * @groups: list of pinconf groups for iodelay instance
++ * @ngroups: number of groups in the list
++ * @mutex: mutex to protect group list modification
++ * @reg_data: Register definition data for the IODelay instance
++ * @reg_init_conf_values: Initial configuration values.
++ */
++struct ti_iodelay_device {
++ struct device *dev;
++ void __iomem *reg_base;
++ struct regmap *regmap;
++
++ struct pinctrl_dev *pctl;
++ struct pinctrl_desc desc;
++ struct pinctrl_pin_desc *pa;
++ struct ti_iodelay_pin_name *names;
++
++ struct list_head groups;
++ int ngroups;
++ struct mutex mutex; /* list protection */
++
++ const struct ti_iodelay_reg_data *reg_data;
++ struct ti_iodelay_reg_values reg_init_conf_values;
++};
++
++/*--- IOdelay configuration stuff ----*/
++
++/**
++ * ti_iodelay_extract() - extract bits for a field
++ * @val: register value
++ * @mask: Mask
++ *
++ * Return: extracted value which is appropriately shifted
++ */
++static inline u32 ti_iodelay_extract(u32 val, u32 mask)
++{
++ return (val & mask) >> __ffs(mask);
++}
++
++/**
++ * ti_iodelay_compute_dpe() - Compute equation for delay parameter
++ * @period: Period to use
++ * @ref: Reference Count
++ * @delay: Delay count
++ * @delay_m: Delay multiplier
++ *
++ * Return: Computed delay parameter
++ */
++static inline u32 ti_iodelay_compute_dpe(u16 period, u16 ref, u16 delay,
++ u16 delay_m)
++{
++ u64 m, d;
++
++ /* Handle overflow conditions */
++ m = 10 * (u64)period * (u64)ref;
++ d = 2 * (u64)delay * (u64)delay_m;
++
++ /* Truncate result back to 32 bits */
++ return div64_u64(m, d);
++}
++
++/**
++ * ti_iodelay_pinconf_set() - Configure the pin configuration
++ * @iod: IODelay device
++ * @val: Configuration value
++ *
++ * Update the configuration register as per TRM and lockup once done.
++ * *IMPORTANT NOTE* SoC TRM does recommend doing iodelay programmation only
++ * while in Isolation. But, then, isolation also implies that every pin
++ * on the SoC(including DDR) will be isolated out. The only benefit being
++ * a glitchless configuration, However, the intent of this driver is purely
++ * to support a "glitchy" configuration where applicable.
++ *
++ * Return: 0 in case of success, else appropriate error value
++ */
++static int ti_iodelay_pinconf_set(struct ti_iodelay_device *iod,
++ struct ti_iodelay_conf_vals *val)
++{
++ const struct ti_iodelay_reg_data *reg = iod->reg_data;
++ struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values;
++ struct device *dev = iod->dev;
++ u32 g_delay_coarse, g_delay_fine;
++ u32 a_delay_coarse, a_delay_fine;
++ u32 c_elements, f_elements;
++ u32 total_delay;
++ u32 reg_mask, reg_val, tmp_val;
++ int r;
++
++ /* NOTE: Truncation is expected in all division below */
++ g_delay_coarse = val->g_delay / 920;
++ g_delay_fine = ((val->g_delay % 920) * 10) / 60;
++
++ a_delay_coarse = val->a_delay / ival->cdpe;
++ a_delay_fine = ((val->a_delay % ival->cdpe) * 10) / ival->fdpe;
++
++ c_elements = g_delay_coarse + a_delay_coarse;
++ f_elements = (g_delay_fine + a_delay_fine) / 10;
++
++ if (f_elements > 22) {
++ total_delay = c_elements * ival->cdpe + f_elements * ival->fdpe;
++ c_elements = total_delay / ival->cdpe;
++ f_elements = (total_delay % ival->cdpe) / ival->fdpe;
++ }
++
++ reg_mask = reg->signature_mask;
++ reg_val = reg->signature_value << __ffs(reg->signature_mask);
++
++ reg_mask |= reg->binary_data_coarse_mask;
++ tmp_val = c_elements << __ffs(reg->binary_data_coarse_mask);
++ if (tmp_val & ~reg->binary_data_coarse_mask) {
++ dev_err(dev, "Masking overflow of coarse elements %08x\n",
++ tmp_val);
++ tmp_val &= reg->binary_data_coarse_mask;
++ }
++ reg_val |= tmp_val;
++
++ reg_mask |= reg->binary_data_fine_mask;
++ tmp_val = f_elements << __ffs(reg->binary_data_fine_mask);
++ if (tmp_val & ~reg->binary_data_fine_mask) {
++ dev_err(dev, "Masking overflow of fine elements %08x\n",
++ tmp_val);
++ tmp_val &= reg->binary_data_fine_mask;
++ }
++ reg_val |= tmp_val;
++
++ /*
++ * NOTE: we leave the iodelay values unlocked - this is to work around
++ * situations such as those found with mmc mode change.
++ * However, this leaves open any unwarranted changes to padconf register
++ * impacting iodelay configuration. Use with care!
++ */
++ reg_mask |= reg->lock_mask;
++ reg_val |= reg->unlock_val << __ffs(reg->lock_mask);
++ r = regmap_update_bits(iod->regmap, val->offset, reg_mask, reg_val);
++
++ dev_dbg(dev, "Set reg 0x%x Delay(a=%d g=%d), Elements(C=%d F=%d)0x%x\n",
++ val->offset, val->a_delay, val->g_delay, c_elements,
++ f_elements, reg_val);
++
++ return r;
++}
++
++/**
++ * ti_iodelay_pinconf_init_dev() - Initialize IODelay device
++ * @iod: IODelay device
++ *
++ * Unlocks the IODelay region, computes the common parameters
++ *
++ * Return: 0 in case of success, else appropriate error value
++ */
++static int ti_iodelay_pinconf_init_dev(struct ti_iodelay_device *iod)
++{
++ const struct ti_iodelay_reg_data *reg = iod->reg_data;
++ struct device *dev = iod->dev;
++ struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values;
++ u32 val;
++ int r;
++
++ /* unlock the IOdelay region */
++ r = regmap_update_bits(iod->regmap, reg->reg_global_lock_offset,
++ reg->global_lock_mask, reg->global_unlock_val);
++ if (r)
++ return r;
++
++ /* Read up Recalibration sequence done by bootloader */
++ r = regmap_read(iod->regmap, reg->reg_refclk_offset, &val);
++ if (r)
++ return r;
++ ival->ref_clk_period = ti_iodelay_extract(val, reg->refclk_period_mask);
++ dev_dbg(dev, "refclk_period=0x%04x\n", ival->ref_clk_period);
++
++ r = regmap_read(iod->regmap, reg->reg_coarse_offset, &val);
++ if (r)
++ return r;
++ ival->coarse_ref_count =
++ ti_iodelay_extract(val, reg->coarse_ref_count_mask);
++ ival->coarse_delay_count =
++ ti_iodelay_extract(val, reg->coarse_delay_count_mask);
++ if (!ival->coarse_delay_count) {
++ dev_err(dev, "Invalid Coarse delay count (0) (reg=0x%08x)\n",
++ val);
++ return -EINVAL;
++ }
++ ival->cdpe = ti_iodelay_compute_dpe(ival->ref_clk_period,
++ ival->coarse_ref_count,
++ ival->coarse_delay_count, 88);
++ if (!ival->cdpe) {
++ dev_err(dev, "Invalid cdpe computed params = %d %d %d\n",
++ ival->ref_clk_period, ival->coarse_ref_count,
++ ival->coarse_delay_count);
++ return -EINVAL;
++ }
++ dev_dbg(iod->dev, "coarse: ref=0x%04x delay=0x%04x cdpe=0x%08x\n",
++ ival->coarse_ref_count, ival->coarse_delay_count, ival->cdpe);
++
++ r = regmap_read(iod->regmap, reg->reg_fine_offset, &val);
++ if (r)
++ return r;
++ ival->fine_ref_count =
++ ti_iodelay_extract(val, reg->fine_ref_count_mask);
++ ival->fine_delay_count =
++ ti_iodelay_extract(val, reg->fine_delay_count_mask);
++ if (!ival->fine_delay_count) {
++ dev_err(dev, "Invalid Fine delay count (0) (reg=0x%08x)\n",
++ val);
++ return -EINVAL;
++ }
++ ival->fdpe = ti_iodelay_compute_dpe(ival->ref_clk_period,
++ ival->fine_ref_count,
++ ival->fine_delay_count, 264);
++ if (!ival->fdpe) {
++ dev_err(dev, "Invalid fdpe(0) computed params = %d %d %d\n",
++ ival->ref_clk_period, ival->fine_ref_count,
++ ival->fine_delay_count);
++ return -EINVAL;
++ }
++ dev_dbg(iod->dev, "fine: ref=0x%04x delay=0x%04x fdpe=0x%08x\n",
++ ival->fine_ref_count, ival->fine_delay_count, ival->fdpe);
++
++ return 0;
++}
++
++/**
++ * ti_iodelay_pinconf_deinit_dev() - deinit the IOdelay device
++ * @iod: IODelay device
++ *
++ * Deinitialize the IODelay device (basically just lock the region back up.
++ */
++static void ti_iodelay_pinconf_deinit_dev(struct ti_iodelay_device *iod)
++{
++ const struct ti_iodelay_reg_data *reg = iod->reg_data;
++
++ /* lock the IOdelay region back again */
++ regmap_update_bits(iod->regmap, reg->reg_global_lock_offset,
++ reg->global_lock_mask, reg->global_lock_val);
++}
++
++/*--- Pinctrl/pinconf framework stuff ----*/
++
++/**
++ * ti_iodelay_get_group() - Find the group mapped by a group selector
++ * @iod: IODelay device
++ * @gselector: Group Selector
++ *
++ * Return: Corresponding group representing group selector in list of groups
++ * managed in IOdelay device OR NULL if not found.
++ */
++static struct ti_iodelay_pingroup *ti_iodelay_get_group(struct ti_iodelay_device
++ *iod,
++ unsigned gselector)
++{
++ struct ti_iodelay_pingroup *group;
++ int gid = 0;
++
++ list_for_each_entry(group, &iod->groups, node) {
++ if (gid == gselector)
++ return group;
++ gid++;
++ }
++
++ dev_err(iod->dev, "%s could not find pingroup %i\n", __func__,
++ gselector);
++ return NULL;
++}
++
++/**
++ * ti_iodelay_dt_node_to_map() - Map a device tree node to appropriate group
++ * @pctldev: pinctrl device representing IODelay device
++ * @np: Node Pointer (device tree)
++ * @map: Pinctrl Map returned back to pinctrl framework
++ * @num_maps: Number of maps (1)
++ *
++ * Maps the device tree description into a group of configuration parameters
++ * for IOdelay block entry.
++ *
++ * Return: 0 in case of success, else appropriate error value
++ */
++static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev,
++ struct device_node *np,
++ struct pinctrl_map **map,
++ unsigned *num_maps)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++ /* const char **pgnames; */
++ int ret = 0;
++ const __be32 *mux;
++ struct ti_iodelay_conf_vals *vals;
++ struct ti_iodelay_pingroup *group;
++ int size, index, idx, rows;
++ u32 offset, val;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ if (!iod)
++ return -EINVAL;
++ dev = iod->dev;
++
++ *map = devm_kzalloc(dev, sizeof(**map), GFP_KERNEL);
++ if (!*map)
++ return -ENOMEM;
++ *num_maps = 0;
++
++ group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
++ if (!group) {
++ ret = -ENOMEM;
++ goto free_map;
++ }
++
++ mux = of_get_property(np, IODELAY_MUX_PINS_NAME, &size);
++ if ((!mux) || (size < sizeof(*mux) * 2)) {
++ dev_err(dev, "bad data for mux %s\n", np->name);
++ ret = -EINVAL;
++ goto free_group;
++ }
++
++ size /= sizeof(*mux); /* Number of elements in array */
++ rows = size / 2;
++
++ vals = devm_kzalloc(dev, sizeof(*vals) * rows, GFP_KERNEL);
++ if (!vals) {
++ ret = -ENOMEM;
++ goto free_group;
++ }
++
++ index = 0;
++ idx = 0;
++ while (index < size) {
++ offset = be32_to_cpup(mux + index++);
++ val = be32_to_cpup(mux + index++);
++ vals[idx].offset = offset;
++ vals[idx].a_delay = val & 0xFFFF;
++ vals[idx].g_delay = (val & 0xFFFF0000) >> 16;
++ if (offset > iod->reg_data->regmap_config->max_register) {
++ dev_err(dev, "Invalid offset for %s 0x%x\n",
++ np->name, offset);
++ break;
++ }
++ dev_dbg(dev, "%s offset=%x a_delay = %d g_delay = %d\n",
++ np->name, vals[idx].offset, vals[idx].a_delay,
++ vals[idx].g_delay);
++ idx++;
++ }
++
++ group->name = np->name;
++ group->np = np;
++ group->vals = vals;
++ group->nvals = idx;
++ group->config = PIN_CONFIG_END;
++ group->map = *map;
++
++ /* Add to group list */
++ mutex_lock(&iod->mutex);
++ list_add_tail(&group->node, &iod->groups);
++ iod->ngroups++;
++ mutex_unlock(&iod->mutex);
++
++ (*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP;
++ (*map)->data.configs.group_or_pin = np->name;
++ (*map)->data.configs.configs = &group->config;
++ (*map)->data.configs.num_configs = 1;
++ *num_maps = 1;
++
++ return 0;
++
++free_group:
++ devm_kfree(dev, group);
++free_map:
++ devm_kfree(dev, *map);
++ return ret;
++}
++
++/**
++ * ti_iodelay_dt_free_map() - Free map and resource alloted as per the map
++ * @pctldev: pinctrl device representing IODelay device
++ * @map: Map allocated by ti_iodelay_dt_node_to_map
++ * @num_maps: Num maps (1)
++ *
++ * Removes the group associated with the map and frees all resources allocated
++ * for the group.
++ */
++static void ti_iodelay_dt_free_map(struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++ struct ti_iodelay_pingroup *group;
++ bool found = false;
++
++ if (!map)
++ return;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ if (!iod)
++ return;
++ dev = iod->dev;
++
++ mutex_lock(&iod->mutex);
++ list_for_each_entry(group, &iod->groups, node) {
++ if (group->map == map) {
++ found = true;
++ list_del(&group->node);
++ iod->ngroups--;
++ break;
++ }
++ }
++ mutex_unlock(&iod->mutex);
++
++ /* If some freaky pinconf framework bug... */
++ if (!found)
++ return;
++
++ devm_kfree(dev, group->vals);
++ devm_kfree(dev, group);
++ devm_kfree(dev, map);
++}
++
++/**
++ * ti_iodelay_pinctrl_get_groups_count() - Get number of groups registered
++ * @pctldev: pinctrl device representing IODelay device
++ *
++ * Return: number of groups mapped on the IODelay
++ */
++static int ti_iodelay_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ dev = iod->dev;
++
++ return iod->ngroups;
++}
++
++/**
++ * ti_iodelay_pinctrl_get_group_name() - Get the group name
++ * @pctldev: pinctrl device representing IODelay device
++ * @gselector: group selector
++ *
++ * Return: name of the Group given a valid gselector, else NULL.
++ */
++static const char *ti_iodelay_pinctrl_get_group_name(struct pinctrl_dev
++ *pctldev,
++ unsigned gselector)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++ struct ti_iodelay_pingroup *group;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ dev = iod->dev;
++
++ group = ti_iodelay_get_group(iod, gselector);
++ if (!group)
++ return NULL;
++
++ return group->name;
++}
++
++/**
++ * ti_iodelay_pinctrl_get_group_pins() - get group pins
++ * @pctldev: pinctrl device representing IODelay device
++ * @gselector: Group selector
++ * @pins: pointer to the pins
++ * @npins: number of pins
++ *
++ * Dummy implementation since we do not track pins, we track configurations
++ * Forced by pinctrl's pinctrl_check_ops()
++ *
++ * Return: -EINVAL
++ */
++static int ti_iodelay_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
++ unsigned gselector,
++ const unsigned **pins,
++ unsigned *npins)
++{
++ /* Dummy implementation - we dont do pin mux */
++ return -EINVAL;
++}
++
++/**
++ * ti_iodelay_pinconf_group_get() - Get the group configuration
++ * @pctldev: pinctrl device representing IODelay device
++ * @gselector: Group selector
++ * @config: configuration returned
++ *
++ * Return: The configuration if the group is valid, else returns -EINVAL
++ */
++static int ti_iodelay_pinconf_group_get(struct pinctrl_dev *pctldev,
++ unsigned gselector,
++ unsigned long *config)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++ struct ti_iodelay_pingroup *group;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ dev = iod->dev;
++ group = ti_iodelay_get_group(iod, gselector);
++
++ if (!group)
++ return -EINVAL;
++
++ *config = group->config;
++ return 0;
++}
++
++/**
++ * ti_iodelay_pinconf_group_set() - Configure the groups of pins
++ * @pctldev: pinctrl device representing IODelay device
++ * @gselector: Group selector
++ * @configs: Configurations
++ * @num_configs: Number of configurations
++ *
++ * Return: 0 if all went fine, else appropriate error value.
++ */
++static int ti_iodelay_pinconf_group_set(struct pinctrl_dev *pctldev,
++ unsigned gselector,
++ unsigned long *configs,
++ unsigned num_configs)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++ struct ti_iodelay_pingroup *group;
++ int i;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ dev = iod->dev;
++ group = ti_iodelay_get_group(iod, gselector);
++
++ if (num_configs != 1) {
++ dev_err(dev, "Unsupported number of configurations %d\n",
++ num_configs);
++ return -EINVAL;
++ }
++
++ if (*configs != PIN_CONFIG_END) {
++ dev_err(dev, "Unsupported configuration\n");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < group->nvals; i++) {
++ if (ti_iodelay_pinconf_set(iod, &group->vals[i]))
++ return -ENOTSUPP;
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_DEBUG_FS
++/**
++ * ti_iodelay_pinconf_group_dbg_show() - show the group information
++ * @pctldev: Show the group information
++ * @s: Sequence file
++ * @gselector: group selector
++ *
++ * Provide the configuration information of the selected group
++ */
++static void ti_iodelay_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
++ struct seq_file *s,
++ unsigned gselector)
++{
++ struct ti_iodelay_device *iod;
++ struct device *dev;
++ struct ti_iodelay_pingroup *group;
++ int i;
++
++ iod = pinctrl_dev_get_drvdata(pctldev);
++ dev = iod->dev;
++ group = ti_iodelay_get_group(iod, gselector);
++ if (!group)
++ return;
++
++ for (i = 0; i < group->nvals; i++) {
++ struct ti_iodelay_conf_vals *val;
++ u32 reg = 0;
++
++ val = &group->vals[i];
++ regmap_read(iod->regmap, val->offset, &reg),
++ seq_printf(s, "\n\t0x%08x = 0x%08x (%3d, %3d)",
++ val->offset, reg, val->a_delay, val->g_delay);
++ }
++}
++#endif
++
++static struct pinctrl_ops ti_iodelay_pinctrl_ops = {
++ .dt_node_to_map = ti_iodelay_dt_node_to_map,
++ .dt_free_map = ti_iodelay_dt_free_map,
++ .get_groups_count = ti_iodelay_pinctrl_get_groups_count,
++ .get_group_name = ti_iodelay_pinctrl_get_group_name,
++ .get_group_pins = ti_iodelay_pinctrl_get_group_pins,
++};
++
++static struct pinconf_ops ti_iodelay_pinctrl_pinconf_ops = {
++ .pin_config_group_get = ti_iodelay_pinconf_group_get,
++ .pin_config_group_set = ti_iodelay_pinconf_group_set,
++#ifdef CONFIG_DEBUG_FS
++ .pin_config_group_dbg_show = ti_iodelay_pinconf_group_dbg_show,
++#endif
++};
++
++/**
++ * ti_iodelay_alloc_pins() - Allocate structures needed for pins for IOdelay
++ * @dev: device pointer
++ * @iod: IODelay device
++ * @base_phy: Base Physical Address
++ *
++ * Return: 0 if all went fine, else appropriate error value.
++ */
++static int ti_iodelay_alloc_pins(struct device *dev,
++ struct ti_iodelay_device *iod, u32 base_phy)
++{
++ const struct ti_iodelay_reg_data *r = iod->reg_data;
++ struct pinctrl_pin_desc *pin;
++ struct ti_iodelay_pin_name *pn;
++ u32 phy_reg;
++ int nr_pins, i;
++
++ nr_pins = (r->regmap_config->max_register - r->reg_start_offset) / 4;
++
++ dev_dbg(dev, "Allocating %i pins\n", nr_pins);
++
++ iod->pa = devm_kzalloc(dev, sizeof(*iod->pa) * nr_pins, GFP_KERNEL);
++ if (!iod->pa)
++ return -ENOMEM;
++
++ iod->names =
++ devm_kzalloc(dev, sizeof(struct ti_iodelay_pin_name) * nr_pins,
++ GFP_KERNEL);
++ if (!iod->names)
++ return -ENOMEM;
++
++ iod->desc.pins = iod->pa;
++ iod->desc.npins = nr_pins;
++
++ phy_reg = r->reg_start_offset + base_phy;
++ pn = iod->names;
++ for (i = 0; i < nr_pins; i++, pn++, phy_reg += 4) {
++ pin = &iod->pa[i];
++ sprintf(pn->name, "%x.%d", phy_reg, i);
++ pin->number = i;
++ pin->name = pn->name;
++ }
++
++ return 0;
++}
++
++/**
++ * ti_iodelay_probe() - Standard probe
++ * @pdev: platform device
++ *
++ * Return: 0 if all went fine, else appropriate error value.
++ */
++static int ti_iodelay_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = of_node_get(dev->of_node);
++ const struct of_device_id *match;
++ struct resource *res;
++ struct ti_iodelay_device *iod;
++ int ret = 0;
++
++ if (!np) {
++ ret = -EINVAL;
++ dev_err(dev, "No OF node\n");
++ goto exit_out;
++ }
++
++ match = of_match_device(ti_iodelay_of_match, dev);
++ if (!match) {
++ ret = -EINVAL;
++ dev_err(dev, "No DATA match\n");
++ goto exit_out;
++ }
++
++ iod = devm_kzalloc(dev, sizeof(*iod), GFP_KERNEL);
++ if (!iod) {
++ ret = -ENOMEM;
++ goto exit_out;
++ }
++ iod->dev = dev;
++ iod->reg_data = match->data;
++
++ /* So far We can assume there is only 1 bank of registers */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(dev, "Missing MEM resource\n");
++ ret = -ENODEV;
++ goto exit_out;
++ }
++
++ iod->reg_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(iod->reg_base)) {
++ ret = PTR_ERR(iod->reg_base);
++ goto exit_out;
++ }
++
++ iod->regmap = devm_regmap_init_mmio(dev, iod->reg_base,
++ iod->reg_data->regmap_config);
++ if (IS_ERR(iod->regmap)) {
++ dev_err(dev, "Regmap MMIO init failed.\n");
++ ret = PTR_ERR(iod->regmap);
++ goto exit_out;
++ }
++
++ if (ti_iodelay_pinconf_init_dev(iod))
++ goto exit_out;
++
++ ret = ti_iodelay_alloc_pins(dev, iod, res->start);
++ if (ret)
++ goto exit_out;
++
++ INIT_LIST_HEAD(&iod->groups);
++ mutex_init(&iod->mutex);
++
++ iod->desc.pctlops = &ti_iodelay_pinctrl_ops;
++ /* no pinmux ops - we are pinconf */
++ iod->desc.confops = &ti_iodelay_pinctrl_pinconf_ops;
++ iod->desc.name = dev_name(dev);
++ iod->desc.owner = THIS_MODULE;
++
++ iod->pctl = pinctrl_register(&iod->desc, dev, iod);
++ if (!iod->pctl) {
++ dev_err(dev, "Failed to register pinctrl\n");
++ ret = -ENODEV;
++ goto exit_out;
++ }
++
++ platform_set_drvdata(pdev, iod);
++
++exit_out:
++ of_node_put(np);
++ return ret;
++}
++
++/**
++ * ti_iodelay_remove() - standard remove
++ * @pdev: platform device
++ *
++ * Return: 0 if all went fine, else appropriate error value.
++ */
++static int ti_iodelay_remove(struct platform_device *pdev)
++{
++ struct ti_iodelay_device *iod = platform_get_drvdata(pdev);
++
++ if (!iod)
++ return 0;
++ if (iod->pctl)
++ pinctrl_unregister(iod->pctl);
++
++ ti_iodelay_pinconf_deinit_dev(iod);
++
++ /* Expect other allocations to be freed by devm */
++
++ return 0;
++}
++
++static struct regmap_config dra7_iodelay_regmap_config = {
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++ .max_register = 0xD1C,
++};
++
++static struct ti_iodelay_reg_data dra7_iodelay_data = {
++ .signature_mask = 0x0003F000,
++ .signature_value = 0x29,
++ .lock_mask = 0x00000400,
++ .lock_val = 1,
++ .unlock_val = 0,
++ .binary_data_coarse_mask = 0x000003E0,
++ .binary_data_fine_mask = 0x0000001F,
++
++ .reg_refclk_offset = 0x14,
++ .refclk_period_mask = 0xFFFF,
++
++ .reg_coarse_offset = 0x18,
++ .coarse_delay_count_mask = 0xFFFF0000,
++ .coarse_ref_count_mask = 0x0000FFFF,
++
++ .reg_fine_offset = 0x1C,
++ .fine_delay_count_mask = 0xFFFF0000,
++ .fine_ref_count_mask = 0x0000FFFF,
++
++ .reg_global_lock_offset = 0x2C,
++ .global_lock_mask = 0x0000FFFF,
++ .global_unlock_val = 0x0000AAAA,
++ .global_lock_val = 0x0000AAAB,
++
++ .reg_start_offset = 0x30,
++ .regmap_config = &dra7_iodelay_regmap_config,
++};
++
++static const struct of_device_id ti_iodelay_of_match[] = {
++ {.compatible = "ti,dra7-iodelay", .data = &dra7_iodelay_data},
++ { /* Hopefully no more.. */ },
++};
++MODULE_DEVICE_TABLE(of, ti_iodelay_of_match);
++
++static struct platform_driver ti_iodelay_driver = {
++ .probe = ti_iodelay_probe,
++ .remove = ti_iodelay_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = DRIVER_NAME,
++ .of_match_table = ti_iodelay_of_match,
++ },
++};
++module_platform_driver(ti_iodelay_driver);
++
++MODULE_AUTHOR("Texas Instruments, Inc.");
++MODULE_DESCRIPTION("Pinconf driver for TI's IO Delay module");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
+index 63454b5..c1bb046 100644
+--- a/drivers/power/Kconfig
++++ b/drivers/power/Kconfig
+@@ -1,3 +1,4 @@
+ source "drivers/power/avs/Kconfig"
+ source "drivers/power/reset/Kconfig"
+ source "drivers/power/supply/Kconfig"
++source "drivers/power/pwrseq/Kconfig"
+diff --git a/drivers/power/Makefile b/drivers/power/Makefile
+index ff35c71..7db8035 100644
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_POWER_AVS) += avs/
+ obj-$(CONFIG_POWER_RESET) += reset/
+ obj-$(CONFIG_POWER_SUPPLY) += supply/
++obj-$(CONFIG_POWER_SEQUENCE) += pwrseq/
+diff --git b/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig
+new file mode 100644
+index 0000000..3859a67
+--- /dev/null
++++ b/drivers/power/pwrseq/Kconfig
+@@ -0,0 +1,19 @@
++#
++# Power Sequence library
++#
++
++config POWER_SEQUENCE
++ bool
++
++menu "Power Sequence Support"
++
++config PWRSEQ_GENERIC
++ bool "Generic power sequence control"
++ depends on OF
++ select POWER_SEQUENCE
++ help
++ It is used for drivers which needs to do power sequence
++ (eg, turn on clock, toggle reset gpio) before the related
++ devices can be found by hardware. This generic one can be
++ used for common power sequence control.
++endmenu
+diff --git b/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile
+new file mode 100644
+index 0000000..ad82389
+--- /dev/null
++++ b/drivers/power/pwrseq/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_POWER_SEQUENCE) += core.o
++obj-$(CONFIG_PWRSEQ_GENERIC) += pwrseq_generic.o
+diff --git b/drivers/power/pwrseq/core.c b/drivers/power/pwrseq/core.c
+new file mode 100644
+index 0000000..9cb1223
+--- /dev/null
++++ b/drivers/power/pwrseq/core.c
+@@ -0,0 +1,191 @@
++/*
++ * core.c power sequence core file
++ *
++ * Copyright (C) 2016 Freescale Semiconductor, Inc.
++ * Author: Peter Chen <peter.chen@nxp.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 of
++ * the License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/power/pwrseq.h>
++
++static DEFINE_MUTEX(pwrseq_list_mutex);
++static LIST_HEAD(pwrseq_list);
++
++int pwrseq_get(struct device_node *np, struct pwrseq *p)
++{
++ if (p && p->get)
++ return p->get(np, p);
++
++ return -ENOTSUPP;
++}
++EXPORT_SYMBOL_GPL(pwrseq_get);
++
++int pwrseq_on(struct pwrseq *p)
++{
++ if (p && p->on)
++ return p->on(p);
++
++ return -ENOTSUPP;
++}
++EXPORT_SYMBOL_GPL(pwrseq_on);
++
++void pwrseq_off(struct pwrseq *p)
++{
++ if (p && p->off)
++ p->off(p);
++}
++EXPORT_SYMBOL_GPL(pwrseq_off);
++
++void pwrseq_put(struct pwrseq *p)
++{
++ if (p && p->put)
++ p->put(p);
++}
++EXPORT_SYMBOL_GPL(pwrseq_put);
++
++int pwrseq_suspend(struct pwrseq *p)
++{
++ if (p && p->suspend)
++ return p->suspend(p);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(pwrseq_suspend);
++
++int pwrseq_resume(struct pwrseq *p)
++{
++ if (p && p->resume)
++ return p->resume(p);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(pwrseq_resume);
++
++void pwrseq_register(struct pwrseq *pwrseq)
++{
++ mutex_lock(&pwrseq_list_mutex);
++ list_add(&pwrseq->node, &pwrseq_list);
++ mutex_unlock(&pwrseq_list_mutex);
++}
++EXPORT_SYMBOL_GPL(pwrseq_register);
++
++void pwrseq_unregister(struct pwrseq *pwrseq)
++{
++ mutex_lock(&pwrseq_list_mutex);
++ list_del(&pwrseq->node);
++ mutex_unlock(&pwrseq_list_mutex);
++}
++EXPORT_SYMBOL_GPL(pwrseq_unregister);
++
++static struct pwrseq *pwrseq_find_available_instance(struct device_node *np)
++{
++ struct pwrseq *pwrseq;
++
++ list_for_each_entry(pwrseq, &pwrseq_list, node) {
++ if (pwrseq->used)
++ continue;
++
++ /* compare compatible string for pwrseq node */
++ if (of_match_node(pwrseq->pwrseq_of_match_table, np)) {
++ pwrseq->used = true;
++ return pwrseq;
++ }
++
++ /* return generic pwrseq instance */
++ if (!strcmp(pwrseq->pwrseq_of_match_table->compatible,
++ "generic")) {
++ pr_debug("using generic pwrseq instance for %s\n",
++ np->full_name);
++ pwrseq->used = true;
++ return pwrseq;
++ }
++ }
++ pr_warn("Can't find any pwrseq instances for %s\n", np->full_name);
++
++ return NULL;
++}
++
++struct pwrseq *of_pwrseq_on(struct device_node *np)
++{
++ struct pwrseq *pwrseq;
++ int ret;
++
++ pwrseq = pwrseq_find_available_instance(np);
++ if (!pwrseq)
++ return ERR_PTR(-ENONET);
++
++ ret = pwrseq_get(np, pwrseq);
++ if (ret) {
++ /* Mark current pwrseq as unused */
++ pwrseq->used = false;
++ return ERR_PTR(ret);
++ }
++
++ ret = pwrseq_on(pwrseq);
++ if (ret)
++ goto pwr_put;
++
++ return pwrseq;
++
++pwr_put:
++ pwrseq_put(pwrseq);
++ return ERR_PTR(ret);
++}
++EXPORT_SYMBOL_GPL(of_pwrseq_on);
++
++void of_pwrseq_off(struct pwrseq *pwrseq)
++{
++ pwrseq_off(pwrseq);
++ pwrseq_put(pwrseq);
++}
++EXPORT_SYMBOL_GPL(of_pwrseq_off);
++
++int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
++{
++ struct pwrseq *pwrseq;
++ struct pwrseq_list_per_dev *pwrseq_list_node;
++
++ pwrseq = of_pwrseq_on(np);
++ if (IS_ERR(pwrseq))
++ return PTR_ERR(pwrseq);
++
++ pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL);
++ if (!pwrseq_list_node) {
++ of_pwrseq_off(pwrseq);
++ return -ENOMEM;
++ }
++ pwrseq_list_node->pwrseq = pwrseq;
++ list_add(&pwrseq_list_node->list, head);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(of_pwrseq_on_list);
++
++void of_pwrseq_off_list(struct list_head *head)
++{
++ struct pwrseq *pwrseq;
++ struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node;
++
++ list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) {
++ pwrseq = pwrseq_list_node->pwrseq;
++ of_pwrseq_off(pwrseq);
++ list_del(&pwrseq_list_node->list);
++ kfree(pwrseq_list_node);
++ }
++}
++EXPORT_SYMBOL_GPL(of_pwrseq_off_list);
+diff --git b/drivers/power/pwrseq/pwrseq_generic.c b/drivers/power/pwrseq/pwrseq_generic.c
+new file mode 100644
+index 0000000..d7a77f2
+--- /dev/null
++++ b/drivers/power/pwrseq/pwrseq_generic.c
+@@ -0,0 +1,183 @@
++/*
++ * pwrseq_generic.c Generic power sequence handling
++ *
++ * Copyright (C) 2016 Freescale Semiconductor, Inc.
++ * Author: Peter Chen <peter.chen@nxp.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 of
++ * the License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/slab.h>
++
++#include <linux/power/pwrseq.h>
++
++struct pwrseq_generic {
++ struct pwrseq pwrseq;
++ struct gpio_desc *gpiod_reset;
++ struct clk *clks[PWRSEQ_MAX_CLKS];
++ u32 duration_us;
++};
++
++#define to_generic_pwrseq(p) container_of(p, struct pwrseq_generic, pwrseq)
++
++static int pwrseq_generic_alloc_instance(void);
++static const struct of_device_id generic_id_table[] = {
++ { .compatible = "generic",},
++ { /* sentinel */ }
++};
++
++static void pwrseq_generic_put(struct pwrseq *pwrseq)
++{
++ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
++ int clk;
++
++ if (pwrseq_gen->gpiod_reset)
++ gpiod_put(pwrseq_gen->gpiod_reset);
++
++ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++)
++ clk_put(pwrseq_gen->clks[clk]);
++
++ pwrseq_unregister(&pwrseq_gen->pwrseq);
++ kfree(pwrseq_gen);
++}
++
++static void pwrseq_generic_off(struct pwrseq *pwrseq)
++{
++ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
++ int clk;
++
++ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
++ clk_disable_unprepare(pwrseq_gen->clks[clk]);
++}
++
++static int pwrseq_generic_on(struct pwrseq *pwrseq)
++{
++ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
++ int clk, ret = 0;
++ struct gpio_desc *gpiod_reset = pwrseq_gen->gpiod_reset;
++
++ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
++ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
++ if (ret) {
++ pr_err("Can't enable clock, ret=%d\n", ret);
++ goto err_disable_clks;
++ }
++ }
++
++ if (gpiod_reset) {
++ u32 duration_us = pwrseq_gen->duration_us;
++
++ if (duration_us <= 10)
++ udelay(10);
++ else
++ usleep_range(duration_us, duration_us + 100);
++ gpiod_set_value(gpiod_reset, 0);
++ }
++
++ return ret;
++
++err_disable_clks:
++ while (--clk >= 0)
++ clk_disable_unprepare(pwrseq_gen->clks[clk]);
++
++ return ret;
++}
++
++static int pwrseq_generic_get(struct device_node *np, struct pwrseq *pwrseq)
++{
++ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
++ enum of_gpio_flags flags;
++ int reset_gpio, clk, ret = 0;
++
++ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) {
++ pwrseq_gen->clks[clk] = of_clk_get(np, clk);
++ if (IS_ERR(pwrseq_gen->clks[clk])) {
++ ret = PTR_ERR(pwrseq_gen->clks[clk]);
++ if (ret != -ENOENT)
++ goto err_put_clks;
++ pwrseq_gen->clks[clk] = NULL;
++ break;
++ }
++ }
++
++ reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
++ if (gpio_is_valid(reset_gpio)) {
++ unsigned long gpio_flags;
++
++ if (flags & OF_GPIO_ACTIVE_LOW)
++ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
++ else
++ gpio_flags = GPIOF_OUT_INIT_HIGH;
++
++ ret = gpio_request_one(reset_gpio, gpio_flags,
++ "pwrseq-reset-gpios");
++ if (ret)
++ goto err_put_clks;
++
++ pwrseq_gen->gpiod_reset = gpio_to_desc(reset_gpio);
++ of_property_read_u32(np, "reset-duration-us",
++ &pwrseq_gen->duration_us);
++ } else if (reset_gpio == -ENOENT) {
++ ; /* no such gpio */
++ } else {
++ ret = reset_gpio;
++ pr_err("Failed to get reset gpio on %s, err = %d\n",
++ np->full_name, reset_gpio);
++ goto err_put_clks;
++ }
++
++ /* allocate new one for later pwrseq instance request */
++ ret = pwrseq_generic_alloc_instance();
++ if (ret)
++ goto err_put_gpio;
++
++ return 0;
++
++err_put_gpio:
++ if (pwrseq_gen->gpiod_reset)
++ gpiod_put(pwrseq_gen->gpiod_reset);
++err_put_clks:
++ while (--clk >= 0)
++ clk_put(pwrseq_gen->clks[clk]);
++ return ret;
++}
++
++static int pwrseq_generic_alloc_instance(void)
++{
++ struct pwrseq_generic *pwrseq_gen;
++
++ pwrseq_gen = kzalloc(sizeof(*pwrseq_gen), GFP_KERNEL);
++ if (!pwrseq_gen)
++ return -ENOMEM;
++
++ pwrseq_gen->pwrseq.pwrseq_of_match_table = generic_id_table;
++ pwrseq_gen->pwrseq.get = pwrseq_generic_get;
++ pwrseq_gen->pwrseq.on = pwrseq_generic_on;
++ pwrseq_gen->pwrseq.off = pwrseq_generic_off;
++ pwrseq_gen->pwrseq.put = pwrseq_generic_put;
++
++ pwrseq_register(&pwrseq_gen->pwrseq);
++ return 0;
++}
++
++static int __init pwrseq_generic_register(void)
++{
++ return pwrseq_generic_alloc_instance();
++}
++postcore_initcall(pwrseq_generic_register)
+diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
+index 2e05046..3c6dfad 100644
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -751,11 +751,11 @@ static int spidev_probe(struct spi_device *spi)
+ * compatible string, it is a Linux implementation thing
+ * rather than a description of the hardware.
+ */
+- if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
+- dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
+- WARN_ON(spi->dev.of_node &&
+- !of_match_device(spidev_dt_ids, &spi->dev));
+- }
++// if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
++// dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
++// WARN_ON(spi->dev.of_node &&
++// !of_match_device(spidev_dt_ids, &spi->dev));
++// }
+
+ spidev_probe_acpi(spi);
+
+diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
+index da31159..2c2d09c 100644
+--- a/drivers/tty/serial/8250/8250_omap.c
++++ b/drivers/tty/serial/8250/8250_omap.c
+@@ -1437,10 +1437,10 @@ static int __init omap8250_console_fixup(void)
+ }
+
+ add_preferred_console("ttyS", idx, options);
+- pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
++ pr_info("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
+ idx, idx);
+- pr_err("This ensures that you still see kernel messages. Please\n");
+- pr_err("update your kernel commandline.\n");
++ pr_info("This ensures that you still see kernel messages. Please\n");
++ pr_info("update your kernel commandline.\n");
+ return 0;
+ }
+ console_initcall(omap8250_console_fixup);
+diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
+index 44e5b5b..2914903 100644
+--- a/drivers/tty/serial/omap-serial.c
++++ b/drivers/tty/serial/omap-serial.c
+@@ -1595,6 +1595,31 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
+ return 0;
+ }
+
++static int serial_omap_of_get_port_line(struct device_node *np)
++{
++ unsigned long val;
++ const char *hwmod;
++ int ret;
++
++ /* first try the serial alias */
++ ret = of_alias_get_id(np, "serial");
++ if (ret >= 0)
++ return ret;
++
++ /* no? calculate it from hwmods */
++ ret = of_property_read_string(np, "ti,hwmods", &hwmod);
++ if (ret != 0 || strncmp(hwmod, "uart", 4) ||
++ kstrtoul(hwmod + 4, 10, &val))
++ return -ENODEV;
++
++ /* numbering of hwmods is +1 */
++ ret = (int)val - 1;
++ if (ret < 0)
++ return -ENODEV;
++
++ return ret;
++}
++
+ static int serial_omap_probe(struct platform_device *pdev)
+ {
+ struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
+@@ -1612,7 +1637,10 @@ static int serial_omap_probe(struct platform_device *pdev)
+ return -EPROBE_DEFER;
+ wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
+ omap_up_info = of_get_uart_port_info(&pdev->dev);
+- pdev->dev.platform_data = omap_up_info;
++ ret = platform_device_add_data(pdev, omap_up_info,
++ sizeof(*omap_up_info));
++ if (ret != 0)
++ return ret;
+ } else {
+ uartirq = platform_get_irq(pdev, 0);
+ if (uartirq < 0)
+@@ -1638,7 +1666,7 @@ static int serial_omap_probe(struct platform_device *pdev)
+ up->port.ops = &serial_omap_pops;
+
+ if (pdev->dev.of_node)
+- ret = of_alias_get_id(pdev->dev.of_node, "serial");
++ ret = serial_omap_of_get_port_line(pdev->dev.of_node);
+ else
+ ret = pdev->id;
+
+diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
+index 52c98ce..05400bc 100644
+--- a/drivers/uio/Kconfig
++++ b/drivers/uio/Kconfig
+@@ -129,7 +129,7 @@ config UIO_PRUSS
+ select GENERIC_ALLOCATOR
+ depends on HAS_IOMEM && HAS_DMA
+ help
+- PRUSS driver for OMAPL138/DA850/AM18XX devices
++ PRUSS driver for OMAPL138/DA850/AM18XX and AM33XX devices
+ PRUSS driver requires user space components, examples and user space
+ driver is available from below SVN repo - you may use anonymous login
+
+diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
+index ca9e2fa..6559752 100644
+--- a/drivers/uio/uio_pruss.c
++++ b/drivers/uio/uio_pruss.c
+@@ -19,6 +19,7 @@
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/platform_device.h>
++#include <linux/of_gpio.h>
+ #include <linux/uio_driver.h>
+ #include <linux/platform_data/uio_pruss.h>
+ #include <linux/io.h>
+@@ -27,6 +28,11 @@
+ #include <linux/sizes.h>
+ #include <linux/slab.h>
+ #include <linux/genalloc.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/err.h>
++#include <linux/pm_runtime.h>
+
+ #define DRV_NAME "pruss_uio"
+ #define DRV_VERSION "1.0"
+@@ -106,10 +112,12 @@ static void pruss_cleanup(struct device *dev, struct uio_pruss_dev *gdev)
+ dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr,
+ gdev->ddr_paddr);
+ }
++#ifdef CONFIG_ARCH_DAVINCI_DA850
+ if (gdev->sram_vaddr)
+ gen_pool_free(gdev->sram_pool,
+ gdev->sram_vaddr,
+ sram_pool_sz);
++#endif
+ kfree(gdev->info);
+ clk_put(gdev->pruss_clk);
+ kfree(gdev);
+@@ -120,9 +128,15 @@ static int pruss_probe(struct platform_device *pdev)
+ struct uio_info *p;
+ struct uio_pruss_dev *gdev;
+ struct resource *regs_prussio;
++ struct resource res;
+ struct device *dev = &pdev->dev;
+ int ret = -ENODEV, cnt = 0, len;
+ struct uio_pruss_pdata *pdata = dev_get_platdata(dev);
++ struct pinctrl *pinctrl;
++
++ int count;
++ struct device_node *child;
++ const char *pin_name;
+
+ gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
+ if (!gdev)
+@@ -133,7 +147,7 @@ static int pruss_probe(struct platform_device *pdev)
+ kfree(gdev);
+ return -ENOMEM;
+ }
+-
++#ifdef CONFIG_ARCH_DAVINCI_DA850
+ /* Power on PRU in case its not done as part of boot-loader */
+ gdev->pruss_clk = clk_get(dev, "pruss");
+ if (IS_ERR(gdev->pruss_clk)) {
+@@ -145,8 +159,25 @@ static int pruss_probe(struct platform_device *pdev)
+ } else {
+ clk_enable(gdev->pruss_clk);
+ }
++#endif
++
++ if (pdev->dev.of_node) {
++ pm_runtime_enable(&pdev->dev);
++ ret = pm_runtime_get_sync(&pdev->dev);
++ if (IS_ERR_VALUE(ret)) {
++ dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
++ return ret;
++ }
+
+- regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ret = of_address_to_resource(pdev->dev.of_node, 0, &res);
++ if (IS_ERR_VALUE(ret)) {
++ dev_err(&pdev->dev, "failed to parse DT reg\n");
++ return ret;
++ }
++ regs_prussio = &res;
++ }
++ else
++ regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs_prussio) {
+ dev_err(dev, "No PRUSS I/O resource specified\n");
+ goto out_free;
+@@ -157,7 +188,50 @@ static int pruss_probe(struct platform_device *pdev)
+ goto out_free;
+ }
+
+- if (pdata->sram_pool) {
++
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl))
++ dev_warn(&pdev->dev,
++ "pins are not configured from the driver\n");
++ else{
++ count = of_get_child_count(pdev->dev.of_node);
++ if (!count){
++ dev_info(&pdev->dev, "No children\n");
++ return -ENODEV;
++ }
++ // Run through all children. They have lables for easy reference.
++ for_each_child_of_node(pdev->dev.of_node, child){
++ enum of_gpio_flags flags;
++ unsigned gpio;
++
++ count = of_gpio_count(child);
++
++ ret = of_property_count_strings(child, "pin-names");
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Failed to get pin-names\n");
++ continue;
++ }
++ if(count != ret){
++ dev_err(&pdev->dev, "The number of gpios (%d) does not match"\
++ " the number of pin names (%d)\n", count, ret);
++ continue;
++ }
++
++ for(cnt=0; cnt<count; cnt++){
++ ret = of_property_read_string_index(child,
++ "pin-names", cnt, &pin_name);
++ if (ret != 0)
++ dev_err(&pdev->dev, "Error on pin-name #%d\n", cnt);
++ gpio = of_get_gpio_flags(child, cnt, &flags);
++ ret = devm_gpio_request_one(&pdev->dev, gpio, flags, pin_name);
++ if (ret < 0) {
++ dev_err(dev, "Failed to request GPIO %d (%s) flags: '%d', error %d\n",
++ gpio, pin_name, flags, ret);
++ }
++ }
++ }
++ }
++ if (pdata && pdata->sram_pool) {
+ gdev->sram_pool = pdata->sram_pool;
+ gdev->sram_vaddr =
+ (unsigned long)gen_pool_dma_alloc(gdev->sram_pool,
+@@ -182,7 +256,17 @@ static int pruss_probe(struct platform_device *pdev)
+ goto out_free;
+ }
+
+- gdev->pintc_base = pdata->pintc_base;
++ if (pdev->dev.of_node) {
++ ret = of_property_read_u32(pdev->dev.of_node,
++ "ti,pintc-offset",
++ &gdev->pintc_base);
++ if (ret < 0) {
++ dev_err(&pdev->dev,
++ "Can't parse ti,pintc-offset property\n");
++ goto out_free;
++ }
++ } else
++ gdev->pintc_base = pdata->pintc_base;
+ gdev->hostirq_start = platform_get_irq(pdev, 0);
+
+ for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) {
+@@ -190,6 +274,7 @@ static int pruss_probe(struct platform_device *pdev)
+ p->mem[0].size = resource_size(regs_prussio);
+ p->mem[0].memtype = UIO_MEM_PHYS;
+
++#ifdef CONFIG_ARCH_DAVINCI_DA850
+ p->mem[1].addr = gdev->sram_paddr;
+ p->mem[1].size = sram_pool_sz;
+ p->mem[1].memtype = UIO_MEM_PHYS;
+@@ -197,7 +282,11 @@ static int pruss_probe(struct platform_device *pdev)
+ p->mem[2].addr = gdev->ddr_paddr;
+ p->mem[2].size = extram_pool_sz;
+ p->mem[2].memtype = UIO_MEM_PHYS;
+-
++#else
++ p->mem[1].addr = gdev->ddr_paddr;
++ p->mem[1].size = extram_pool_sz;
++ p->mem[1].memtype = UIO_MEM_PHYS;
++#endif
+ p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
+ p->version = DRV_VERSION;
+
+@@ -227,11 +316,20 @@ static int pruss_remove(struct platform_device *dev)
+ return 0;
+ }
+
++static const struct of_device_id pruss_dt_ids[] = {
++ { .compatible = "ti,pruss-v1", .data = NULL, },
++ { .compatible = "ti,pruss-v2", .data = NULL, },
++ {},
++};
++MODULE_DEVICE_TABLE(of, pruss_dt_ids);
++
++
+ static struct platform_driver pruss_driver = {
+ .probe = pruss_probe,
+ .remove = pruss_remove,
+ .driver = {
+ .name = DRV_NAME,
++ .of_match_table = pruss_dt_ids,
+ },
+ };
+
+diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
+index 6e0d614..17e69cb 100644
+--- a/drivers/usb/chipidea/core.c
++++ b/drivers/usb/chipidea/core.c
+@@ -896,6 +896,16 @@ static int ci_hdrc_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ /*
++ * At device tree, we have no device node for chipidea core,
++ * the glue layer's node is the parent node for host and udc
++ * device. But in related driver, the parent device is chipidea
++ * core. So, in order to let the common driver get parent's node,
++ * we let the core's device node equals glue layer's node.
++ */
++ if (dev->parent && dev->parent->of_node)
++ dev->of_node = dev->parent->of_node;
++
+ if (ci->platdata->phy) {
+ ci->phy = ci->platdata->phy;
+ } else if (ci->platdata->usb_phy) {
+@@ -906,11 +916,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
+
+ /* if both generic PHY and USB PHY layers aren't enabled */
+ if (PTR_ERR(ci->phy) == -ENOSYS &&
+- PTR_ERR(ci->usb_phy) == -ENXIO)
+- return -ENXIO;
++ PTR_ERR(ci->usb_phy) == -ENXIO) {
++ ret = -ENXIO;
++ goto clear_of_node;
++ }
+
+- if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy))
+- return -EPROBE_DEFER;
++ if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) {
++ ret = -EPROBE_DEFER;
++ goto clear_of_node;
++ }
+
+ if (IS_ERR(ci->phy))
+ ci->phy = NULL;
+@@ -921,7 +935,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
+ ret = ci_usb_phy_init(ci);
+ if (ret) {
+ dev_err(dev, "unable to init phy: %d\n", ret);
+- return ret;
++ goto clear_of_node;
+ }
+
+ ci->hw_bank.phys = res->start;
+@@ -1027,6 +1041,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
+ ci_role_destroy(ci);
+ deinit_phy:
+ ci_usb_phy_exit(ci);
++clear_of_node:
++ dev->of_node = NULL;
+
+ return ret;
+ }
+@@ -1045,6 +1061,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
+ ci_extcon_unregister(ci);
+ ci_role_destroy(ci);
+ ci_hdrc_enter_lpm(ci, true);
++ ci->dev->of_node = NULL;
+ ci_usb_phy_exit(ci);
+
+ return 0;
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 706b3d6..6fe5665 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -26,6 +26,7 @@
+ #include <linux/mutex.h>
+ #include <linux/random.h>
+ #include <linux/pm_qos.h>
++#include <linux/power/pwrseq.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/byteorder.h>
+@@ -1632,6 +1633,7 @@ static void hub_disconnect(struct usb_interface *intf)
+ hub->error = 0;
+ hub_quiesce(hub, HUB_DISCONNECT);
+
++ of_pwrseq_off_list(&hub->pwrseq_on_list);
+ mutex_lock(&usb_port_peer_mutex);
+
+ /* Avoid races with recursively_mark_NOTATTACHED() */
+@@ -1659,12 +1661,41 @@ static void hub_disconnect(struct usb_interface *intf)
+ kref_put(&hub->kref, hub_release);
+ }
+
++#ifdef CONFIG_OF
++static int hub_of_pwrseq_on(struct usb_hub *hub)
++{
++ struct device *parent;
++ struct usb_device *hdev = hub->hdev;
++ struct device_node *np;
++ int ret;
++
++ if (hdev->parent)
++ parent = &hdev->dev;
++ else
++ parent = bus_to_hcd(hdev->bus)->self.controller;
++
++ for_each_child_of_node(parent->of_node, np) {
++ ret = of_pwrseq_on_list(np, &hub->pwrseq_on_list);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++#else
++static int hub_of_pwrseq_on(struct usb_hub *hub)
++{
++ return 0;
++}
++#endif
++
+ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ struct usb_host_interface *desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *hdev;
+ struct usb_hub *hub;
++ int ret = -ENODEV;
+
+ desc = intf->cur_altsetting;
+ hdev = interface_to_usbdev(intf);
+@@ -1769,6 +1800,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ INIT_DELAYED_WORK(&hub->leds, led_work);
+ INIT_DELAYED_WORK(&hub->init_work, NULL);
+ INIT_WORK(&hub->events, hub_event);
++ INIT_LIST_HEAD(&hub->pwrseq_on_list);
+ usb_get_intf(intf);
+ usb_get_dev(hdev);
+
+@@ -1782,11 +1814,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
+ hub->quirk_check_port_auto_suspend = 1;
+
+- if (hub_configure(hub, endpoint) >= 0)
+- return 0;
++ if (hub_configure(hub, endpoint) >= 0) {
++ ret = hub_of_pwrseq_on(hub);
++ if (!ret)
++ return 0;
++ }
+
+ hub_disconnect(intf);
+- return -ENODEV;
++ return ret;
+ }
+
+ static int
+diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
+index 34c1a7e..cd86f91 100644
+--- a/drivers/usb/core/hub.h
++++ b/drivers/usb/core/hub.h
+@@ -78,6 +78,7 @@ struct usb_hub {
+ struct delayed_work init_work;
+ struct work_struct events;
+ struct usb_port **ports;
++ struct list_head pwrseq_on_list; /* powered pwrseq node list */
+ };
+
+ /**
+diff --git a/firmware/am335x-bone-scale-data.bin b/firmware/am335x-bone-scale-data.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..1ce3c1c596d7a7f400b0cc89bda5a41eed2780c5
+GIT binary patch
+literal 73
+pcmd-HXHZUIU{c}EWl|AfLZWk+R0P|Ad@#)bSHb~R0-{lr003gr3L5|b
+
+literal 0
+HcmV?d00001
+
+diff --git a/firmware/am335x-evm-scale-data.bin b/firmware/am335x-evm-scale-data.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..a222389d233fa8f1c76ef35470b57284999c8df5
+GIT binary patch
+literal 17
+Ucmd-HXJAiZVA55UX8=>$024d{B>(^b
+
+literal 0
+HcmV?d00001
+
+diff --git a/firmware/am43x-evm-scale-data.bin b/firmware/am43x-evm-scale-data.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..2d71341089816be7989e6dc11b265d9194ac909e
+GIT binary patch
+literal 41
+hcmd-HXAn+dU{VptW>OLB0@CSBDpG9>aG{wnApnMi2I2q!
+
+literal 0
+HcmV?d00001
+
+diff --git b/include/dt-bindings/board/am335x-bbw-bbb-base.h b/include/dt-bindings/board/am335x-bbw-bbb-base.h
+new file mode 100644
+index 0000000..35f6d57
+--- /dev/null
++++ b/include/dt-bindings/board/am335x-bbw-bbb-base.h
+@@ -0,0 +1,103 @@
++/*
++ * This header provides constants for bbw/bbb pinctrl bindings.
++ *
++ * Copyright (C) 2014 Robert Nelson <robertcnelson@gmail.com>
++ *
++ * Numbers Based on: https://github.com/derekmolloy/boneDeviceTree/tree/master/docs
++ */
++
++#ifndef _DT_BINDINGS_BOARD_AM335X_BBW_BBB_BASE_H
++#define _DT_BINDINGS_BOARD_AM335X_BBW_BBB_BASE_H
++
++#define BONE_P8_03 0x018
++#define BONE_P8_04 0x01C
++
++#define BONE_P8_05 0x008
++#define BONE_P8_06 0x00C
++#define BONE_P8_07 0x090
++#define BONE_P8_08 0x094
++
++#define BONE_P8_09 0x09C
++#define BONE_P8_10 0x098
++#define BONE_P8_11 0x034
++#define BONE_P8_12 0x030
++
++#define BONE_P8_13 0x024
++#define BONE_P8_14 0x028
++#define BONE_P8_15 0x03C
++#define BONE_P8_16 0x038
++
++#define BONE_P8_17 0x02C
++#define BONE_P8_18 0x08C
++#define BONE_P8_19 0x020
++#define BONE_P8_20 0x084
++
++#define BONE_P8_21 0x080
++#define BONE_P8_22 0x014
++#define BONE_P8_23 0x010
++#define BONE_P8_24 0x004
++
++#define BONE_P8_25 0x000
++#define BONE_P8_26 0x07C
++#define BONE_P8_27 0x0E0
++#define BONE_P8_28 0x0E8
++
++#define BONE_P8_29 0x0E4
++#define BONE_P8_30 0x0EC
++#define BONE_P8_31 0x0D8
++#define BONE_P8_32 0x0DC
++
++#define BONE_P8_33 0x0D4
++#define BONE_P8_34 0x0CC
++#define BONE_P8_35 0x0D0
++#define BONE_P8_36 0x0C8
++
++#define BONE_P8_37 0x0C0
++#define BONE_P8_38 0x0C4
++#define BONE_P8_39 0x0B8
++#define BONE_P8_40 0x0BC
++
++#define BONE_P8_41 0x0B0
++#define BONE_P8_42 0x0B4
++#define BONE_P8_43 0x0A8
++#define BONE_P8_44 0x0AC
++
++#define BONE_P8_45 0x0A0
++#define BONE_P8_46 0x0A4
++
++#define BONE_P9_11 0x070
++#define BONE_P9_12 0x078
++
++#define BONE_P9_13 0x074
++#define BONE_P9_14 0x048
++#define BONE_P9_15 0x040
++#define BONE_P9_16 0x04C
++
++#define BONE_P9_17 0x15C
++#define BONE_P9_18 0x158
++#define BONE_P9_19 0x17C
++#define BONE_P9_20 0x178
++
++#define BONE_P9_21 0x154
++#define BONE_P9_22 0x150
++#define BONE_P9_23 0x044
++#define BONE_P9_24 0x184
++
++#define BONE_P9_25 0x1AC
++#define BONE_P9_26 0x180
++#define BONE_P9_27 0x1A4
++#define BONE_P9_28 0x19C
++
++#define BONE_P9_29 0x194
++#define BONE_P9_30 0x198
++#define BONE_P9_31 0x190
++
++/* Shared P21 of P11 */
++#define BONE_P9_41A 0x1B4
++#define BONE_P9_41B 0x1A8
++
++/* Shared P22 of P11 */
++#define BONE_P9_42A 0x164
++#define BONE_P9_42B 0x1A0
++
++#endif
+diff --git b/include/dt-bindings/mfd/tps65217.h b/include/dt-bindings/mfd/tps65217.h
+new file mode 100644
+index 0000000..cafb9e6
+--- /dev/null
++++ b/include/dt-bindings/mfd/tps65217.h
+@@ -0,0 +1,26 @@
++/*
++ * This header provides macros for TI TPS65217 DT bindings.
++ *
++ * Copyright (C) 2016 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __DT_BINDINGS_TPS65217_H__
++#define __DT_BINDINGS_TPS65217_H__
++
++#define TPS65217_IRQ_USB 0
++#define TPS65217_IRQ_AC 1
++#define TPS65217_IRQ_PB 2
++
++#endif
+diff --git a/include/dt-bindings/pinctrl/dra.h b/include/dt-bindings/pinctrl/dra.h
+index 5c75e80..5a60e3b 100644
+--- a/include/dt-bindings/pinctrl/dra.h
++++ b/include/dt-bindings/pinctrl/dra.h
+@@ -50,6 +50,8 @@
+
+ #define MODE_SELECT (1 << 8)
+
++#define MANUAL_MODE MODE_SELECT
++
+ #define PULL_ENA (0 << 16)
+ #define PULL_DIS (1 << 16)
+ #define PULL_UP (1 << 17)
+@@ -73,5 +75,9 @@
+ */
+ #define DRA7XX_CORE_IOPAD(pa, val) (((pa) & 0xffff) - 0x3400) (val)
+
++/* DRA7 IODELAY configuration parameters */
++#define A_DELAY(val) ((val) & 0xFFFF)
++#define G_DELAY(val) (((val) & 0xFFFF) << 16)
++
+ #endif
+
+diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
+index 4ccda89..3cbec4b 100644
+--- a/include/linux/mfd/tps65217.h
++++ b/include/linux/mfd/tps65217.h
+@@ -234,12 +234,11 @@ struct tps65217_bl_pdata {
+ int dft_brightness;
+ };
+
+-enum tps65217_irq_type {
+- TPS65217_IRQ_PB,
+- TPS65217_IRQ_AC,
+- TPS65217_IRQ_USB,
+- TPS65217_NUM_IRQ
+-};
++/* Interrupt numbers */
++#define TPS65217_IRQ_USB 0
++#define TPS65217_IRQ_AC 1
++#define TPS65217_IRQ_PB 2
++#define TPS65217_NUM_IRQ 3
+
+ /**
+ * struct tps65217_board - packages regulator init data
+diff --git a/include/linux/of.h b/include/linux/of.h
+index 299aeb1..725bd28 100644
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -23,8 +23,10 @@
+ #include <linux/spinlock.h>
+ #include <linux/topology.h>
+ #include <linux/notifier.h>
++#include <linux/slab.h>
+ #include <linux/property.h>
+ #include <linux/list.h>
++#include <linux/rhashtable.h>
+
+ #include <asm/byteorder.h>
+ #include <asm/errno.h>
+@@ -52,6 +54,7 @@ struct device_node {
+ phandle phandle;
+ const char *full_name;
+ struct fwnode_handle fwnode;
++ struct rhash_head ht_node;
+
+ struct property *properties;
+ struct property *deadprops; /* removed properties */
+@@ -1184,6 +1187,8 @@ enum of_reconfig_change {
+ };
+
+ #ifdef CONFIG_OF_DYNAMIC
++#include <linux/slab.h>
++
+ extern int of_reconfig_notifier_register(struct notifier_block *);
+ extern int of_reconfig_notifier_unregister(struct notifier_block *);
+ extern int of_reconfig_notify(unsigned long, struct of_reconfig_data *rd);
+@@ -1227,6 +1232,26 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
+ {
+ return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
+ }
++
++struct device_node *of_changeset_create_device_nodev(
++ struct of_changeset *ocs, struct device_node *parent,
++ const char *fmt, va_list vargs);
++
++__printf(3, 4) struct device_node *
++of_changeset_create_device_node(struct of_changeset *ocs,
++ struct device_node *parent, const char *fmt, ...);
++
++int __of_changeset_add_update_property_copy(struct of_changeset *ocs,
++ struct device_node *np, const char *name, const void *value,
++ int length, bool update);
++
++int __of_changeset_add_update_property_string_list(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char **strs, int count, bool update);
++
++int of_changeset_node_move(struct of_changeset *ocs,
++ struct device_node *np, struct device_node *new_parent);
++
+ #else /* CONFIG_OF_DYNAMIC */
+ static inline int of_reconfig_notifier_register(struct notifier_block *nb)
+ {
+@@ -1246,8 +1271,323 @@ static inline int of_reconfig_get_state_change(unsigned long action,
+ {
+ return -EINVAL;
+ }
++
++static inline struct device_node *of_changeset_create_device_nodev(
++ struct of_changeset *ocs, struct device_node *parent,
++ const char *fmt, va_list vargs)
++{
++ return ERR_PTR(-EINVAL);
++}
++
++static inline __printf(3, 4) struct device_node *
++of_changeset_create_device_node(struct of_changeset *ocs,
++ struct device_node *parent, const char *fmt, ...)
++{
++ return ERR_PTR(-EINVAL);
++}
++
++static inline int __of_changeset_add_update_property_copy(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const void *value, int length, bool update)
++{
++ return -EINVAL;
++}
++
++static inline __printf(4, 5) int of_changeset_add_property_stringf(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char *fmt, ...)
++{
++ return -EINVAL;
++}
++
++static inline int of_changeset_update_property_stringf(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char *fmt, ...)
++{
++ return -EINVAL;
++}
++
++static inline int __of_changeset_add_update_property_string_list(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char **strs, int count, bool update)
++{
++ return -EINVAL;
++}
++
++static inline int of_changeset_node_move(struct of_changeset *ocs,
++ struct device_node *np, struct device_node *new_parent)
++{
++ return -EINVAL;
++}
++
+ #endif /* CONFIG_OF_DYNAMIC */
+
++/**
++ * of_changeset_add_property_copy - Create a new property copying name & value
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @value: pointer to the value data
++ * @length: length of the value in bytes
++ *
++ * Adds a property to the changeset by making copies of the name & value
++ * entries.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_add_property_copy(struct of_changeset *ocs,
++ struct device_node *np, const char *name,
++ const void *value, int length)
++{
++ return __of_changeset_add_update_property_copy(ocs, np, name, value,
++ length, false);
++}
++
++/**
++ * of_changeset_update_property_copy - Update a property copying name & value
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @value: pointer to the value data
++ * @length: length of the value in bytes
++ *
++ * Update a property to the changeset by making copies of the name & value
++ * entries.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_update_property_copy(struct of_changeset *ocs,
++ struct device_node *np, const char *name,
++ const void *value, int length)
++{
++ return __of_changeset_add_update_property_copy(ocs, np, name, value,
++ length, true);
++}
++
++/**
++ * __of_changeset_add_update_property_string - Create/update a string property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @str: string property value
++ * @update: True on update operation
++ *
++ * Adds/updates a string property to the changeset by making copies of the name
++ * and the given value. The @update parameter controls whether an add or
++ * update takes place.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int __of_changeset_add_update_property_string(
++ struct of_changeset *ocs, struct device_node *np, const char *name,
++ const char *str, bool update)
++{
++ return __of_changeset_add_update_property_copy(ocs, np, name, str,
++ strlen(str) + 1, update);
++}
++
++/**
++ * __of_changeset_add_update_property_stringv - Create/update a formatted
++ * string property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @fmt: format of string property
++ * @vargs: arguments of the format string
++ * @update: True on update operation
++ *
++ * Adds/updates a string property to the changeset by making copies of the name
++ * and the formatted value. The @update parameter controls whether an add or
++ * update takes place.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int __of_changeset_add_update_property_stringv(
++ struct of_changeset *ocs, struct device_node *np, const char *name,
++ const char *fmt, va_list vargs, bool update)
++{
++ char *str;
++ int ret;
++
++ str = kvasprintf(GFP_KERNEL, fmt, vargs);
++ if (!str)
++ return -ENOMEM;
++ ret = __of_changeset_add_update_property_string(ocs, np, name, str,
++ update);
++ kfree(str);
++
++ return ret;
++}
++
++/**
++ * of_changeset_add_property_string_list - Create a new string list property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @strs: pointer to the string list
++ * @count: string count
++ *
++ * Adds a string list property to the changeset.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_add_property_string_list(
++ struct of_changeset *ocs, struct device_node *np, const char *name,
++ const char **strs, int count)
++{
++ return __of_changeset_add_update_property_string_list(ocs, np, name,
++ strs, count, false);
++}
++
++/**
++ * of_changeset_update_property_string_list - Update string list property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @strs: pointer to the string list
++ * @count: string count
++ *
++ * Updates a string list property to the changeset.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_update_property_string_list(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char **strs, int count)
++{
++ return __of_changeset_add_update_property_string_list(ocs, np, name,
++ strs, count, true);
++}
++
++/**
++ * of_changeset_add_property_string - Adds a string property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @str: string property
++ *
++ * Adds a string property to the changeset by making copies of the name
++ * and the string value.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_add_property_string(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char *str)
++{
++ return __of_changeset_add_update_property_string(ocs, np, name, str,
++ false);
++}
++
++/**
++ * of_changeset_update_property_string - Update a string property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @str: string property
++ *
++ * Updates a string property to the changeset by making copies of the name
++ * and the string value.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_update_property_string(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, const char *str)
++{
++ return __of_changeset_add_update_property_string(ocs, np, name, str,
++ true);
++}
++
++/**
++ * of_changeset_add_property_u32 - Create a new u32 property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @val: value in host endian format
++ *
++ * Adds a u32 property to the changeset.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_add_property_u32(struct of_changeset *ocs,
++ struct device_node *np, const char *name, u32 val)
++{
++ val = cpu_to_be32(val);
++ return __of_changeset_add_update_property_copy(ocs, np, name, &val,
++ sizeof(val), false);
++}
++
++/**
++ * of_changeset_update_property_u32 - Update u32 property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ * @val: value in host endian format
++ *
++ * Updates a u32 property to the changeset.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_update_property_u32(
++ struct of_changeset *ocs, struct device_node *np,
++ const char *name, u32 val)
++{
++ val = cpu_to_be32(val);
++ return __of_changeset_add_update_property_copy(ocs, np, name, &val,
++ sizeof(val), true);
++}
++
++/**
++ * of_changeset_add_property_bool - Create a new u32 property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ *
++ * Adds a bool property to the changeset. Note that there is
++ * no option to set the value to false, since the property
++ * existing sets it to true.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_add_property_bool(
++ struct of_changeset *ocs, struct device_node *np, const char *name)
++{
++ return __of_changeset_add_update_property_copy(ocs, np, name, "", 0,
++ false);
++}
++
++/**
++ * of_changeset_update_property_bool - Update a bool property
++ *
++ * @ocs: changeset pointer
++ * @np: device node pointer
++ * @name: name of the property
++ *
++ * Updates a property to the changeset. Note that there is
++ * no option to set the value to false, since the property
++ * existing sets it to true.
++ *
++ * Returns zero on success, a negative error value otherwise.
++ */
++static inline int of_changeset_update_property_bool(struct of_changeset *ocs,
++ struct device_node *np, const char *name)
++{
++ return __of_changeset_add_update_property_copy(ocs, np, name, "", 0,
++ true);
++}
++
+ /* CONFIG_OF_RESOLVE api */
+ extern int of_resolve_phandles(struct device_node *tree);
+
+@@ -1273,6 +1613,10 @@ int of_overlay_create(struct device_node *tree);
+ int of_overlay_destroy(int id);
+ int of_overlay_destroy_all(void);
+
++int of_overlay_create_target_index(struct device_node *tree, int index);
++int of_overlay_create_target_root(struct device_node *tree,
++ struct device_node *target_root);
++
+ #else
+
+ static inline int of_overlay_create(struct device_node *tree)
+@@ -1290,6 +1634,18 @@ static inline int of_overlay_destroy_all(void)
+ return -ENOTSUPP;
+ }
+
++static inline int of_overlay_create_target_index(struct device_node *tree,
++ int index)
++{
++ return -ENOTSUPP;
++}
++
++static inline int of_overlay_create_target_root(struct device_node *tree,
++ struct device_node *target_root)
++{
++ return -ENOTSUPP;
++}
++
+ #endif
+
+ #endif /* _LINUX_OF_H */
+diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
+index f6bc765..e9be0ec 100644
+--- a/include/linux/pm_opp.h
++++ b/include/linux/pm_opp.h
+@@ -17,14 +17,64 @@
+ #include <linux/err.h>
+ #include <linux/notifier.h>
+
++struct clk;
++struct regulator;
+ struct dev_pm_opp;
+ struct device;
+-struct opp_table;
+
+ enum dev_pm_opp_event {
+ OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
+ };
+
++/**
++ * struct dev_pm_opp_supply - Power supply voltage/current values
++ * @u_volt: Target voltage in microvolts corresponding to this OPP
++ * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
++ * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
++ * @u_amp: Maximum current drawn by the device in microamperes
++ *
++ * This structure stores the voltage/current values for a single power supply.
++ */
++struct dev_pm_opp_supply {
++ unsigned long u_volt;
++ unsigned long u_volt_min;
++ unsigned long u_volt_max;
++ unsigned long u_amp;
++};
++
++/**
++ * struct dev_pm_opp_info - OPP freq/voltage/current values
++ * @rate: Target clk rate in hz
++ * @supplies: Array of voltage/current values for all power supplies
++ *
++ * This structure stores the freq/voltage/current values for a single OPP.
++ */
++struct dev_pm_opp_info {
++ unsigned long rate;
++ struct dev_pm_opp_supply *supplies;
++};
++
++/**
++ * struct dev_pm_set_opp_data - Set OPP data
++ * @old_opp: Old OPP info
++ * @new_opp: New OPP info
++ * @regulators: Array of regulator pointers
++ * @regulator_count: Number of regulators
++ * @clk: Pointer to clk
++ * @dev: Pointer to the struct device
++ *
++ * This structure contains all information required for setting an OPP.
++ */
++struct dev_pm_set_opp_data {
++ struct dev_pm_opp_info old_opp;
++ struct dev_pm_opp_info new_opp;
++
++ struct regulator **regulators;
++ unsigned int regulator_count;
++ struct clk *clk;
++ struct device *dev;
++};
++
+ #if defined(CONFIG_PM_OPP)
+
+ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
+@@ -63,8 +113,10 @@ int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
+ void dev_pm_opp_put_supported_hw(struct device *dev);
+ int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
+ void dev_pm_opp_put_prop_name(struct device *dev);
+-struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name);
+-void dev_pm_opp_put_regulator(struct opp_table *opp_table);
++int dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
++void dev_pm_opp_put_regulators(struct device *dev);
++int dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
++void dev_pm_opp_register_put_opp_helper(struct device *dev);
+ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
+ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
+ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
+@@ -164,6 +216,14 @@ static inline int dev_pm_opp_set_supported_hw(struct device *dev,
+
+ static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
+
++static inline int dev_pm_opp_register_set_opp_helper(struct device *dev,
++ int (*set_opp)(struct dev_pm_set_opp_data *data))
++{
++ return -ENOTSUPP;
++}
++
++static inline void dev_pm_opp_register_put_opp_helper(struct device *dev) {}
++
+ static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+ {
+ return -ENOTSUPP;
+@@ -171,12 +231,12 @@ static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+
+ static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
+
+-static inline struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
++static inline int dev_pm_opp_set_regulators(struct device *dev, const char *names[], unsigned int count)
+ {
+- return ERR_PTR(-ENOTSUPP);
++ return -ENOTSUPP;
+ }
+
+-static inline void dev_pm_opp_put_regulator(struct opp_table *opp_table) {}
++static inline void dev_pm_opp_put_regulators(struct device *dev) {}
+
+ static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
+ {
+@@ -209,6 +269,7 @@ void dev_pm_opp_of_remove_table(struct device *dev);
+ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
+ void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask);
+ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
++struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev);
+ #else
+ static inline int dev_pm_opp_of_add_table(struct device *dev)
+ {
+@@ -232,6 +293,11 @@ static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct
+ {
+ return -ENOTSUPP;
+ }
++
++static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
++{
++ return NULL;
++}
+ #endif
+
+ #endif /* __LINUX_OPP_H__ */
+diff --git b/include/linux/power/pwrseq.h b/include/linux/power/pwrseq.h
+new file mode 100644
+index 0000000..4f37275
+--- /dev/null
++++ b/include/linux/power/pwrseq.h
+@@ -0,0 +1,72 @@
++#ifndef __LINUX_PWRSEQ_H
++#define __LINUX_PWRSEQ_H
++
++#include <linux/of.h>
++
++#define PWRSEQ_MAX_CLKS 3
++
++struct pwrseq {
++ const struct of_device_id *pwrseq_of_match_table;
++ struct list_head node;
++ int (*get)(struct device_node *np, struct pwrseq *p);
++ int (*on)(struct pwrseq *p);
++ void (*off)(struct pwrseq *p);
++ void (*put)(struct pwrseq *p);
++ int (*suspend)(struct pwrseq *p);
++ int (*resume)(struct pwrseq *p);
++ bool used;
++};
++
++/* used for power sequence instance list in one driver */
++struct pwrseq_list_per_dev {
++ struct pwrseq *pwrseq;
++ struct list_head list;
++};
++
++#if IS_ENABLED(CONFIG_POWER_SEQUENCE)
++int pwrseq_get(struct device_node *np, struct pwrseq *p);
++int pwrseq_on(struct pwrseq *p);
++void pwrseq_off(struct pwrseq *p);
++void pwrseq_put(struct pwrseq *p);
++int pwrseq_suspend(struct pwrseq *p);
++int pwrseq_resume(struct pwrseq *p);
++void pwrseq_register(struct pwrseq *pwrseq);
++void pwrseq_unregister(struct pwrseq *pwrseq);
++struct pwrseq *of_pwrseq_on(struct device_node *np);
++void of_pwrseq_off(struct pwrseq *pwrseq);
++int of_pwrseq_on_list(struct device_node *np, struct list_head *head);
++void of_pwrseq_off_list(struct list_head *head);
++#else
++static inline int pwrseq_get(struct device_node *np, struct pwrseq *p)
++{
++ return 0;
++}
++static inline int pwrseq_on(struct pwrseq *p)
++{
++ return 0;
++}
++static inline void pwrseq_off(struct pwrseq *p) {}
++static inline void pwrseq_put(struct pwrseq *p) {}
++static inline int pwrseq_suspend(struct pwrseq *p)
++{
++ return 0;
++}
++static inline int pwrseq_resume(struct pwrseq *p)
++{
++ return 0;
++}
++static inline void pwrseq_register(struct pwrseq *pwrseq) {}
++static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
++static inline struct pwrseq *of_pwrseq_on(struct device_node *np)
++{
++ return NULL;
++}
++void of_pwrseq_off(struct pwrseq *pwrseq) {}
++int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
++{
++ return 0;
++}
++void of_pwrseq_off_list(struct list_head *head) {}
++#endif /* CONFIG_POWER_SEQUENCE */
++
++#endif /* __LINUX_PWRSEQ_H */
+diff --git a/lib/vsprintf.c b/lib/vsprintf.c
+index 0967771..319e09d 100644
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -35,6 +35,7 @@
+ #ifdef CONFIG_BLOCK
+ #include <linux/blkdev.h>
+ #endif
++#include <linux/of.h>
+
+ #include "../mm/internal.h" /* For the trace_print_flags arrays */
+
+@@ -1470,6 +1471,141 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
+ return format_flags(buf, end, flags, names);
+ }
+
++/* helper method for calculating extends on first pass and filling in later */
++static noinline_for_stack
++void append_str(const char *str, int pass, int *lenp, char **bufp, char *end)
++{
++ int len;
++
++ len = strlen(str);
++ if (pass == 1)
++ *lenp += len;
++ else {
++ if (len > (end - *bufp))
++ len = end - *bufp;
++ memcpy(*bufp, str, len);
++ *bufp += len;
++ }
++}
++
++static noinline_for_stack
++char *device_node_string(char *buf, char *end, struct device_node *dn,
++ struct printf_spec spec, const char *fmt)
++{
++ char tbuf[sizeof("xxxxxxxxxx") + 1];
++ const char *fmtp, *p;
++ int len, ret, i, j, pass;
++ char c;
++
++ if (!IS_ENABLED(CONFIG_OF)) {
++ /* if OF is not enabled just print the pointer */
++ spec.flags |= SMALL;
++ if (spec.field_width == -1) {
++ spec.field_width = 2 * sizeof(void *);
++ spec.flags |= ZEROPAD;
++ }
++ spec.base = 16;
++ return number(buf, end, (unsigned long) dn, spec);
++ }
++
++ if ((unsigned long)dn < PAGE_SIZE)
++ return string(buf, end, "(null)", spec);
++
++ /* simple case without anything any more format specifiers */
++ if (fmt[1] == '\0' || isspace(fmt[1]))
++ fmt = "Of";
++
++ len = 0;
++
++ /* two passes; the first calculates length, the second fills in */
++ for (pass = 1; pass <= 2; pass++) {
++ if (pass == 2 && !(spec.flags & LEFT)) {
++ /* padding */
++ while (len < spec.field_width--) {
++ if (buf < end)
++ *buf = ' ';
++ ++buf;
++ }
++ }
++
++ for (fmtp = fmt + 1, j = 0; (c = *fmtp++) != '\0'; ) {
++
++ /* validate option */
++ if (c != 'f' && c != 'n' && c != 'p' && c != 'P' &&
++ c != 'F' && c != 'c' && c != 'C' && c != 'r')
++ continue;
++
++ /* handle separator */
++ if (j++ > 0)
++ append_str("|", pass, &len, &buf, end);
++
++ switch (c) {
++ case 'f': /* full_name */
++ append_str(of_node_full_name(dn), pass, &len,
++ &buf, end);
++ break;
++ case 'n': /* name */
++ append_str(dn->name, pass, &len, &buf, end);
++ break;
++ case 'p': /* phandle */
++ snprintf(tbuf, sizeof(tbuf), "%u",
++ (unsigned int)dn->phandle);
++ append_str(tbuf, pass, &len, &buf, end);
++ break;
++ case 'P': /* path-spec */
++ append_str(dn->name, pass, &len, &buf, end);
++ /* need to tack on the @ postfix */
++ p = strchr(of_node_full_name(dn), '@');
++ if (p)
++ append_str(p, pass, &len, &buf, end);
++ break;
++ case 'F': /* flags */
++ snprintf(tbuf, sizeof(tbuf), "%c%c%c%c",
++ of_node_check_flag(dn, OF_DYNAMIC) ?
++ 'D' : '-',
++ of_node_check_flag(dn, OF_DETACHED) ?
++ 'd' : '-',
++ of_node_check_flag(dn, OF_POPULATED) ?
++ 'P' : '-',
++ of_node_check_flag(dn,
++ OF_POPULATED_BUS) ? 'B' : '-');
++ append_str(tbuf, pass, &len, &buf, end);
++ break;
++ case 'c': /* major compatible string */
++ ret = of_property_read_string(dn, "compatible",
++ &p);
++ if (ret == 0)
++ append_str(p, pass, &len, &buf, end);
++ break;
++ case 'C': /* full compatible string */
++ i = 0;
++ while (of_property_read_string_index(dn,
++ "compatible", i, &p) == 0) {
++ append_str(i == 0 ? "\"" : "\",\"",
++ pass, &len, &buf, end);
++ append_str(p, pass, &len, &buf, end);
++ i++;
++ }
++ if (i > 0)
++ append_str("\"", pass, &len, &buf, end);
++ break;
++ case 'r': /* node reference count */
++ snprintf(tbuf, sizeof(tbuf), "%u",
++ atomic_read(&dn->kobj.kref.refcount));
++ append_str(tbuf, pass, &len, &buf, end);
++ break;
++ default:
++ break;
++ }
++ }
++ }
++ /* finish up */
++ while (buf < end && len < spec.field_width--)
++ *buf++ = ' ';
++
++ return buf;
++}
++
+ int kptr_restrict __read_mostly;
+
+ /*
+@@ -1563,6 +1699,16 @@ int kptr_restrict __read_mostly;
+ * p page flags (see struct page) given as pointer to unsigned long
+ * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
+ * v vma flags (VM_*) given as pointer to unsigned long
++ * - 'O[fnpPcCFr]' For an DT device node
++ * Without any optional arguments prints the full_name
++ * f device node full_name
++ * n device node name
++ * p device node phandle
++ * P device node path spec (name + @unit)
++ * F device node flags
++ * c major compatible string
++ * C full compatible string
++ * r node reference count
+ *
+ * ** Please update also Documentation/printk-formats.txt when making changes **
+ *
+@@ -1718,6 +1864,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
+
+ case 'G':
+ return flags_string(buf, end, ptr, fmt);
++
++ case 'O':
++ return device_node_string(buf, end, ptr, spec, fmt);
++
+ }
+ spec.flags |= SMALL;
+ if (spec.field_width == -1) {
+diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile
+index ae7ff6f..7659beb 100644
+--- a/samples/seccomp/Makefile
++++ b/samples/seccomp/Makefile
+@@ -20,6 +20,7 @@ bpf-direct-objs := bpf-direct.o
+ # Try to match the kernel target.
+ ifndef CROSS_COMPILE
+ ifndef CONFIG_64BIT
++ifndef CONFIG_ARM
+
+ # s390 has -m31 flag to build 31 bit binaries
+ ifndef CONFIG_S390
+@@ -46,3 +47,4 @@ ifndef CONFIG_MIPS
+ always := $(hostprogs-y)
+ endif
+ endif
++endif
+diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
+index 386f956..38f548e 100644
+--- a/scripts/dtc/checks.c
++++ b/scripts/dtc/checks.c
+@@ -40,16 +40,11 @@ enum checkstatus {
+
+ struct check;
+
+-typedef void (*tree_check_fn)(struct check *c, struct node *dt);
+-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);
++typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node);
+
+ struct check {
+ const char *name;
+- tree_check_fn tree_fn;
+- node_check_fn node_fn;
+- prop_check_fn prop_fn;
++ check_fn fn;
+ void *data;
+ bool warn, error;
+ enum checkstatus status;
+@@ -58,57 +53,35 @@ struct check {
+ struct check **prereq;
+ };
+
+-#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
+- static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
+- static struct check nm = { \
+- .name = #nm, \
+- .tree_fn = (tfn), \
+- .node_fn = (nfn), \
+- .prop_fn = (pfn), \
+- .data = (d), \
+- .warn = (w), \
+- .error = (e), \
++#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \
++ static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
++ static struct check _nm = { \
++ .name = #_nm, \
++ .fn = (_fn), \
++ .data = (_d), \
++ .warn = (_w), \
++ .error = (_e), \
+ .status = UNCHECKED, \
+- .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
+- .prereq = nm##_prereqs, \
++ .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
++ .prereq = _nm##_prereqs, \
+ };
+-#define WARNING(nm, tfn, nfn, pfn, d, ...) \
+- CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
+-#define ERROR(nm, tfn, nfn, pfn, d, ...) \
+- CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
+-#define CHECK(nm, tfn, nfn, pfn, d, ...) \
+- CHECK_ENTRY(nm, tfn, nfn, pfn, 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__
+-static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
+-#endif
+-static inline void check_msg(struct check *c, const char *fmt, ...)
++#define WARNING(_nm, _fn, _d, ...) \
++ CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
++#define ERROR(_nm, _fn, _d, ...) \
++ CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
++#define CHECK(_nm, _fn, _d, ...) \
++ CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
++
++static inline void PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti,
++ const char *fmt, ...)
+ {
+ va_list ap;
+ va_start(ap, fmt);
+
+ if ((c->warn && (quiet < 1))
+ || (c->error && (quiet < 2))) {
+- fprintf(stderr, "%s (%s): ",
++ fprintf(stderr, "%s: %s (%s): ",
++ strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
+ (c->error) ? "ERROR" : "Warning", c->name);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+@@ -116,34 +89,28 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
+ va_end(ap);
+ }
+
+-#define FAIL(c, ...) \
+- do { \
+- TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
+- (c)->status = FAILED; \
+- check_msg((c), __VA_ARGS__); \
++#define FAIL(c, dti, ...) \
++ do { \
++ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
++ (c)->status = FAILED; \
++ check_msg((c), dti, __VA_ARGS__); \
+ } 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 property *prop;
+
+ TRACE(c, "%s", node->fullpath);
+- if (c->node_fn)
+- c->node_fn(c, dt, 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);
+- }
++ if (c->fn)
++ c->fn(c, dti, node);
+
+ 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;
+ int i;
+
+@@ -156,10 +123,10 @@ static bool run_check(struct check *c, struct node *dt)
+
+ for (i = 0; i < c->num_prereqs; i++) {
+ struct check *prq = c->prereq[i];
+- error = error || run_check(prq, dt);
++ error = error || run_check(prq, dti);
+ if (prq->status != PASSED) {
+ c->status = PREREQ;
+- check_msg(c, "Failed prerequisite '%s'",
++ check_msg(c, dti, "Failed prerequisite '%s'",
+ c->prereq[i]->name);
+ }
+ }
+@@ -167,11 +134,8 @@ static bool run_check(struct check *c, struct node *dt)
+ if (c->status != UNCHECKED)
+ goto out;
+
+- if (c->node_fn || c->prop_fn)
+- check_nodes_props(c, dt, dt);
++ check_nodes_props(c, dti, dt);
+
+- if (c->tree_fn)
+- c->tree_fn(c, dt);
+ if (c->status == UNCHECKED)
+ c->status = PASSED;
+
+@@ -189,13 +153,14 @@ static bool run_check(struct check *c, struct node *dt)
+ */
+
+ /* 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, dti, "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 property *prop;
+@@ -206,15 +171,15 @@ static void check_is_string(struct check *c, struct node *root,
+ return; /* Not present, assumed ok */
+
+ if (!data_is_one_string(prop->val))
+- FAIL(c, "\"%s\" property in %s is not a string",
++ FAIL(c, dti, "\"%s\" property in %s is not a string",
+ propname, node->fullpath);
+ }
+ #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) \
+- 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 property *prop;
+@@ -225,19 +190,19 @@ static void check_is_cell(struct check *c, struct node *root,
+ return; /* Not present, assumed ok */
+
+ if (prop->val.len != sizeof(cell_t))
+- FAIL(c, "\"%s\" property in %s is not a single cell",
++ FAIL(c, dti, "\"%s\" property in %s is not a single cell",
+ propname, node->fullpath);
+ }
+ #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) \
+- ERROR(nm, NULL, check_is_cell, NULL, (propname))
++ ERROR(nm, check_is_cell, (propname))
+
+ /*
+ * 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 *child, *child2;
+@@ -247,12 +212,12 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
+ child2;
+ child2 = child2->next_sibling)
+ if (streq(child->name, child2->name))
+- FAIL(c, "Duplicate node name %s",
++ FAIL(c, dti, "Duplicate node name %s",
+ 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 property *prop, *prop2;
+@@ -262,40 +227,52 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
+ if (prop2->deleted)
+ continue;
+ if (streq(prop->name, prop2->name))
+- FAIL(c, "Duplicate property name %s in %s",
++ FAIL(c, dti, "Duplicate property name %s in %s",
+ prop->name, node->fullpath);
+ }
+ }
+ }
+-NODE_ERROR(duplicate_property_names, NULL);
++ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
+
+ #define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
+ #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ #define DIGITS "0123456789"
+ #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
++#define PROPNODECHARSSTRICT 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)
+ {
+ int n = strspn(node->name, c->data);
+
+ if (n < strlen(node->name))
+- FAIL(c, "Bad character '%c' in node %s",
++ FAIL(c, dti, "Bad character '%c' in node %s",
+ 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_chars_strict(struct check *c, struct dt_info *dti,
++ struct node *node)
++{
++ int n = strspn(node->name, c->data);
++
++ if (n < node->basenamelen)
++ FAIL(c, dti, "Character '%c' not recommended in node %s",
++ node->name[n], node->fullpath);
++}
++CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT);
++
++static void check_node_name_format(struct check *c, struct dt_info *dti,
+ struct node *node)
+ {
+ if (strchr(get_unitname(node), '@'))
+- FAIL(c, "Node %s has multiple '@' characters in name",
++ FAIL(c, dti, "Node %s has multiple '@' characters in name",
+ 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,
+- struct node *node)
++static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
++ struct node *node)
+ {
+ const char *unitname = get_unitname(node);
+ struct property *prop = get_property(node, "reg");
+@@ -308,26 +285,62 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt,
+
+ if (prop) {
+ if (!unitname[0])
+- FAIL(c, "Node %s has a reg or ranges property, but no unit name",
++ FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name",
+ node->fullpath);
+ } else {
+ if (unitname[0])
+- FAIL(c, "Node %s has a unit name, but no reg property",
++ FAIL(c, dti, "Node %s has a unit name, but no reg property",
+ 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 dt_info *dti,
++ struct node *node)
++{
++ struct property *prop;
++
++ for_each_property(node, prop) {
++ int n = strspn(prop->name, c->data);
++
++ if (n < strlen(prop->name))
++ FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s",
++ prop->name[n], prop->name, node->fullpath);
++ }
++}
++ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
+
+-static void check_property_name_chars(struct check *c, struct node *dt,
+- struct node *node, struct property *prop)
++static void check_property_name_chars_strict(struct check *c,
++ struct dt_info *dti,
++ struct node *node)
+ {
+- int n = strspn(prop->name, c->data);
++ struct property *prop;
++
++ for_each_property(node, prop) {
++ const char *name = prop->name;
++ int n = strspn(name, c->data);
++
++ if (n == strlen(prop->name))
++ continue;
++
++ /* Certain names are whitelisted */
++ if (streq(name, "device_type"))
++ continue;
+
+- if (n < strlen(prop->name))
+- FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
+- prop->name[n], prop->name, node->fullpath);
++ /*
++ * # is only allowed at the beginning of property names not counting
++ * the vendor prefix.
++ */
++ if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) {
++ name += n + 1;
++ n = strspn(name, c->data);
++ }
++ if (n < strlen(name))
++ FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s",
++ name[n], prop->name, node->fullpath);
++ }
+ }
+-PROP_ERROR(property_name_chars, PROPNODECHARS);
++CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT);
+
+ #define DESCLABEL_FMT "%s%s%s%s%s"
+ #define DESCLABEL_ARGS(node,prop,mark) \
+@@ -336,10 +349,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS);
+ ((prop) ? (prop)->name : ""), \
+ ((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,
+ struct property *prop, struct marker *mark)
+ {
++ struct node *dt = dti->dt;
+ struct node *othernode = NULL;
+ struct property *otherprop = NULL;
+ struct marker *othermark = NULL;
+@@ -356,50 +370,49 @@ static void check_duplicate_label(struct check *c, struct node *dt,
+ return;
+
+ if ((othernode != node) || (otherprop != prop) || (othermark != mark))
+- FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
++ FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT
+ " and " DESCLABEL_FMT,
+ label, DESCLABEL_ARGS(node, prop, mark),
+ 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 label *l;
++ struct property *prop;
+
+ for_each_label(node->labels, l)
+- check_duplicate_label(c, dt, l->label, node, NULL, NULL);
+-}
+-static void check_duplicate_label_prop(struct check *c, struct node *dt,
+- struct node *node, struct property *prop)
+-{
+- struct marker *m = prop->val.markers;
+- struct label *l;
++ check_duplicate_label(c, dti, l->label, node, NULL, NULL);
+
+- for_each_label(prop->labels, l)
+- check_duplicate_label(c, dt, l->label, node, prop, NULL);
++ for_each_property(node, prop) {
++ struct marker *m = prop->val.markers;
+
+- for_each_marker_of_type(m, LABEL)
+- check_duplicate_label(c, dt, m->ref, node, prop, m);
++ 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);
++ }
+ }
+-ERROR(duplicate_label, NULL, check_duplicate_label_node,
+- check_duplicate_label_prop, NULL);
++ERROR(duplicate_label, check_duplicate_label_node, NULL);
+
+-static void check_explicit_phandles(struct check *c, struct node *root,
+- struct node *node, struct property *prop)
++static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
++ struct node *node, const char *propname)
+ {
++ struct node *root = dti->dt;
++ struct property *prop;
+ struct marker *m;
+- struct node *other;
+ cell_t phandle;
+
+- if (!streq(prop->name, "phandle")
+- && !streq(prop->name, "linux,phandle"))
+- return;
++ prop = get_property(node, propname);
++ if (!prop)
++ return 0;
+
+ if (prop->val.len != sizeof(cell_t)) {
+- FAIL(c, "%s has bad length (%d) %s property",
++ FAIL(c, dti, "%s has bad length (%d) %s property",
+ node->fullpath, prop->val.len, prop->name);
+- return;
++ return 0;
+ }
+
+ m = prop->val.markers;
+@@ -409,42 +422,65 @@ static void check_explicit_phandles(struct check *c, struct node *root,
+ /* "Set this node's phandle equal to some
+ * other node's phandle". That's nonsensical
+ * by construction. */ {
+- FAIL(c, "%s in %s is a reference to another node",
++ FAIL(c, dti, "%s in %s is a reference to another node",
+ prop->name, node->fullpath);
+- return;
+ }
+ /* But setting this node's phandle equal to its own
+ * phandle is allowed - that means allocate a unique
+ * phandle for this node, even if it's not otherwise
+ * referenced. The value will be filled in later, so
+- * no further checking for now. */
+- return;
++ * we treat it as having no phandle data for now. */
++ return 0;
+ }
+
+ phandle = propval_cell(prop);
+
+ if ((phandle == 0) || (phandle == -1)) {
+- FAIL(c, "%s has bad value (0x%x) in %s property",
++ FAIL(c, dti, "%s has bad value (0x%x) in %s property",
+ node->fullpath, phandle, prop->name);
+- return;
++ return 0;
+ }
+
+- if (node->phandle && (node->phandle != phandle))
+- FAIL(c, "%s has %s property which replaces existing phandle information",
+- node->fullpath, prop->name);
++ return phandle;
++}
++
++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, dti, "%s has mismatching 'phandle' and 'linux,phandle'"
++ " properties", node->fullpath);
++
++ if (linux_phandle && !phandle)
++ phandle = linux_phandle;
+
+ other = get_node_by_phandle(root, phandle);
+ if (other && (other != node)) {
+- FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
++ FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)",
+ node->fullpath, phandle, other->fullpath);
+ return;
+ }
+
+ 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 property **pp, *prop = NULL;
+@@ -460,7 +496,7 @@ static void check_name_properties(struct check *c, struct node *root,
+
+ if ((prop->val.len != node->basenamelen+1)
+ || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
+- FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
++ FAIL(c, dti, "\"name\" property in %s is incorrect (\"%s\" instead"
+ " of base node name)", node->fullpath, prop->val.val);
+ } else {
+ /* The name property is correct, and therefore redundant.
+@@ -472,60 +508,73 @@ static void check_name_properties(struct check *c, struct node *root,
+ }
+ }
+ 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
+ */
+
+-static void fixup_phandle_references(struct check *c, struct node *dt,
+- struct node *node, struct property *prop)
++static void fixup_phandle_references(struct check *c, struct dt_info *dti,
++ struct node *node)
+ {
+- struct marker *m = prop->val.markers;
+- struct node *refnode;
+- cell_t phandle;
++ struct node *dt = dti->dt;
++ struct property *prop;
+
+- for_each_marker_of_type(m, REF_PHANDLE) {
+- assert(m->offset + sizeof(cell_t) <= prop->val.len);
++ for_each_property(node, prop) {
++ struct marker *m = prop->val.markers;
++ struct node *refnode;
++ cell_t phandle;
++
++ for_each_marker_of_type(m, REF_PHANDLE) {
++ assert(m->offset + sizeof(cell_t) <= prop->val.len);
++
++ refnode = get_node_by_ref(dt, m->ref);
++ if (! refnode) {
++ if (!(dti->dtsflags & DTSF_PLUGIN))
++ FAIL(c, dti, "Reference to non-existent node or "
++ "label \"%s\"\n", m->ref);
++ else /* mark the entry as unresolved */
++ *((fdt32_t *)(prop->val.val + m->offset)) =
++ cpu_to_fdt32(0xffffffff);
++ continue;
++ }
+
+- refnode = get_node_by_ref(dt, m->ref);
+- if (! refnode) {
+- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+- m->ref);
+- continue;
++ phandle = get_node_phandle(dt, refnode);
++ *((fdt32_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);
+
+-static void fixup_path_references(struct check *c, struct node *dt,
+- struct node *node, struct property *prop)
++static void fixup_path_references(struct check *c, struct dt_info *dti,
++ struct node *node)
+ {
+- struct marker *m = prop->val.markers;
+- struct node *refnode;
+- char *path;
++ struct node *dt = dti->dt;
++ struct property *prop;
++
++ for_each_property(node, prop) {
++ struct marker *m = prop->val.markers;
++ struct node *refnode;
++ char *path;
+
+- for_each_marker_of_type(m, REF_PATH) {
+- assert(m->offset <= prop->val.len);
++ for_each_marker_of_type(m, REF_PATH) {
++ assert(m->offset <= prop->val.len);
+
+- refnode = get_node_by_ref(dt, m->ref);
+- if (!refnode) {
+- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+- m->ref);
+- continue;
+- }
++ refnode = get_node_by_ref(dt, m->ref);
++ if (!refnode) {
++ FAIL(c, dti, "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,
+- &duplicate_node_names);
++ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
+
+ /*
+ * Semantic checks
+@@ -538,7 +587,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
+ WARNING_IF_NOT_STRING(model_is_string, "model");
+ 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 property *prop;
+@@ -554,7 +603,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt,
+ if (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);
+
+ #define node_addr_cells(n) \
+@@ -562,7 +611,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
+ #define node_size_cells(n) \
+ (((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 property *prop;
+@@ -573,25 +622,25 @@ static void check_reg_format(struct check *c, struct node *dt,
+ return; /* No "reg", that's fine */
+
+ if (!node->parent) {
+- FAIL(c, "Root node has a \"reg\" property");
++ FAIL(c, dti, "Root node has a \"reg\" property");
+ return;
+ }
+
+ if (prop->val.len == 0)
+- FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
++ FAIL(c, dti, "\"reg\" property in %s is empty", node->fullpath);
+
+ addr_cells = node_addr_cells(node->parent);
+ size_cells = node_size_cells(node->parent);
+ entrylen = (addr_cells + size_cells) * sizeof(cell_t);
+
+ if (!entrylen || (prop->val.len % entrylen) != 0)
+- FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
++ FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) "
+ "(#address-cells == %d, #size-cells == %d)",
+ 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 property *prop;
+@@ -602,7 +651,7 @@ static void check_ranges_format(struct check *c, struct node *dt,
+ return;
+
+ if (!node->parent) {
+- FAIL(c, "Root node has a \"ranges\" property");
++ FAIL(c, dti, "Root node has a \"ranges\" property");
+ return;
+ }
+
+@@ -614,28 +663,28 @@ static void check_ranges_format(struct check *c, struct node *dt,
+
+ if (prop->val.len == 0) {
+ if (p_addr_cells != c_addr_cells)
+- FAIL(c, "%s has empty \"ranges\" property but its "
++ FAIL(c, dti, "%s has empty \"ranges\" property but its "
+ "#address-cells (%d) differs from %s (%d)",
+ node->fullpath, c_addr_cells, node->parent->fullpath,
+ p_addr_cells);
+ if (p_size_cells != c_size_cells)
+- FAIL(c, "%s has empty \"ranges\" property but its "
++ FAIL(c, dti, "%s has empty \"ranges\" property but its "
+ "#size-cells (%d) differs from %s (%d)",
+ node->fullpath, c_size_cells, node->parent->fullpath,
+ p_size_cells);
+ } else if ((prop->val.len % entrylen) != 0) {
+- FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
++ FAIL(c, dti, "\"ranges\" property in %s has invalid length (%d bytes) "
+ "(parent #address-cells == %d, child #address-cells == %d, "
+ "#size-cells == %d)", node->fullpath, prop->val.len,
+ 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
+ */
+-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 property *reg, *ranges;
+@@ -650,31 +699,39 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt,
+ return;
+
+ if (node->parent->addr_cells == -1)
+- FAIL(c, "Relying on default #address-cells value for %s",
++ FAIL(c, dti, "Relying on default #address-cells value for %s",
+ node->fullpath);
+
+ if (node->parent->size_cells == -1)
+- FAIL(c, "Relying on default #size-cells value for %s",
++ FAIL(c, dti, "Relying on default #size-cells value for %s",
+ 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,
+- struct node *dt)
++ struct dt_info *dti,
++ struct node *node)
+ {
++ struct node *dt = dti->dt;
+ struct node *chosen;
+ struct property *prop;
+
++ if (node != dt)
++ return;
++
++
+ chosen = get_node_by_path(dt, "/chosen");
+ if (!chosen)
+ return;
+
+ prop = get_property(chosen, "interrupt-controller");
+ if (prop)
+- FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
++ FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" "
+ "property");
+ }
+-TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
++WARNING(obsolete_chosen_interrupt_controller,
++ check_obsolete_chosen_interrupt_controller, NULL);
+
+ static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+@@ -689,6 +746,9 @@ static struct check *check_table[] = {
+ &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
+ &device_type_is_string, &model_is_string, &status_is_string,
+
++ &property_name_chars_strict,
++ &node_name_chars_strict,
++
+ &addr_size_cells, &reg_format, &ranges_format,
+
+ &unit_address_vs_reg,
+@@ -760,9 +820,8 @@ void parse_checks_option(bool warn, bool error, const char *arg)
+ 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 error = 0;
+
+@@ -770,7 +829,7 @@ void process_checks(bool force, struct boot_info *bi)
+ struct check *c = check_table[i];
+
+ if (c->warn || c->error)
+- error = error || run_check(c, dt);
++ error = error || run_check(c, dti);
+ }
+
+ if (error) {
+diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
+index 8cae237..aa37a16 100644
+--- a/scripts/dtc/data.c
++++ b/scripts/dtc/data.c
+@@ -171,9 +171,9 @@ struct data data_merge(struct data d1, struct data d2)
+ struct data data_append_integer(struct data d, uint64_t value, int bits)
+ {
+ uint8_t value_8;
+- uint16_t value_16;
+- uint32_t value_32;
+- uint64_t value_64;
++ fdt16_t value_16;
++ fdt32_t value_32;
++ fdt64_t value_64;
+
+ switch (bits) {
+ case 8:
+@@ -197,14 +197,14 @@ struct data data_append_integer(struct data d, uint64_t value, int bits)
+ }
+ }
+
+-struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
++struct data data_append_re(struct data d, uint64_t address, uint64_t size)
+ {
+- struct fdt_reserve_entry bere;
++ struct fdt_reserve_entry re;
+
+- bere.address = cpu_to_fdt64(re->address);
+- bere.size = cpu_to_fdt64(re->size);
++ re.address = cpu_to_fdt64(address);
++ re.size = cpu_to_fdt64(size);
+
+- return data_append_data(d, &bere, sizeof(bere));
++ return data_append_data(d, &re, sizeof(re));
+ }
+
+ struct data data_append_cell(struct data d, cell_t word)
+diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
+index 790fbf6..fd825eb 100644
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -62,7 +62,8 @@ static int dts_version = 1;
+
+ static void push_input_file(const char *filename);
+ static bool pop_input_file(void);
+-static void lexical_error(const char *fmt, ...);
++static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
++
+ %}
+
+ %%
+@@ -121,6 +122,11 @@ static void lexical_error(const char *fmt, ...);
+ return DT_V1;
+ }
+
++<*>"/plugin/" {
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++
+ <*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+@@ -184,16 +190,16 @@ static void lexical_error(const char *fmt, ...);
+ if (d.len == 1) {
+ lexical_error("Empty character literal");
+ yylval.integer = 0;
+- return DT_CHAR_LITERAL;
+- }
+-
+- yylval.integer = (unsigned char)d.val[0];
++ } 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);
++ if (d.len > 2)
++ lexical_error("Character literal has %d"
++ " characters instead of 1",
++ d.len - 1);
++ }
+
++ data_free(d);
+ return DT_CHAR_LITERAL;
+ }
+
+diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped
+index ba525c2..c37d7ff 100644
+--- a/scripts/dtc/dtc-lexer.lex.c_shipped
++++ b/scripts/dtc/dtc-lexer.lex.c_shipped
+@@ -8,8 +8,8 @@
+
+ #define FLEX_SCANNER
+ #define YY_FLEX_MAJOR_VERSION 2
+-#define YY_FLEX_MINOR_VERSION 5
+-#define YY_FLEX_SUBMINOR_VERSION 39
++#define YY_FLEX_MINOR_VERSION 6
++#define YY_FLEX_SUBMINOR_VERSION 1
+ #if YY_FLEX_SUBMINOR_VERSION > 0
+ #define FLEX_BETA
+ #endif
+@@ -88,25 +88,13 @@ typedef unsigned int flex_uint32_t;
+
+ #endif /* ! FLEXINT_H */
+
+-#ifdef __cplusplus
+-
+-/* The "const" storage-class-modifier is valid. */
+-#define YY_USE_CONST
+-
+-#else /* ! __cplusplus */
+-
+-/* C99 requires __STDC__ to be defined as 1. */
+-#if defined (__STDC__)
+-
+-#define YY_USE_CONST
+-
+-#endif /* defined (__STDC__) */
+-#endif /* ! __cplusplus */
+-
+-#ifdef YY_USE_CONST
++/* TODO: this is always defined, so inline it */
+ #define yyconst const
++
++#if defined(__GNUC__) && __GNUC__ >= 3
++#define yynoreturn __attribute__((__noreturn__))
+ #else
+-#define yyconst
++#define yynoreturn
+ #endif
+
+ /* Returned upon end-of-file. */
+@@ -167,7 +155,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ typedef size_t yy_size_t;
+ #endif
+
+-extern yy_size_t yyleng;
++extern int yyleng;
+
+ extern FILE *yyin, *yyout;
+
+@@ -206,12 +194,12 @@ struct yy_buffer_state
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+- yy_size_t yy_buf_size;
++ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- yy_size_t yy_n_chars;
++ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -234,7 +222,7 @@ struct yy_buffer_state
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+-
++
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+@@ -262,7 +250,7 @@ struct yy_buffer_state
+ /* Stack of input buffers. */
+ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
++static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
+
+ /* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+@@ -281,11 +269,11 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+ /* yy_hold_char holds the character lost when yytext is formed. */
+ static char yy_hold_char;
+-static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+-yy_size_t yyleng;
++static int yy_n_chars; /* number of characters read into yy_ch_buf */
++int yyleng;
+
+ /* Points to current character in buffer. */
+-static char *yy_c_buf_p = (char *) 0;
++static char *yy_c_buf_p = NULL;
+ static int yy_init = 0; /* whether we need to initialize */
+ static int yy_start = 0; /* start state number */
+
+@@ -310,7 +298,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+ void *yyalloc (yy_size_t );
+ void *yyrealloc (void *,yy_size_t );
+@@ -342,12 +330,12 @@ void yyfree (void * );
+
+ /* Begin user sect3 */
+
+-#define yywrap() 1
++#define yywrap() (/*CONSTCOND*/1)
+ #define YY_SKIP_YYWRAP
+
+ typedef unsigned char YY_CHAR;
+
+-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
++FILE *yyin = NULL, *yyout = NULL;
+
+ typedef int yy_state_type;
+
+@@ -356,25 +344,28 @@ extern int yylineno;
+ int yylineno = 1;
+
+ extern char *yytext;
++#ifdef yytext_ptr
++#undef yytext_ptr
++#endif
+ #define yytext_ptr yytext
+
+ static yy_state_type yy_get_previous_state (void );
+ static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+ static int yy_get_next_buffer (void );
+-static void yy_fatal_error (yyconst char msg[] );
++static void yynoreturn yy_fatal_error (yyconst char* msg );
+
+ /* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+ #define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+- yyleng = (size_t) (yy_cp - yy_bp); \
++ yyleng = (int) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+-#define YY_NUM_RULES 30
+-#define YY_END_OF_BUFFER 31
++#define YY_NUM_RULES 31
++#define YY_END_OF_BUFFER 32
+ /* This struct is not used in this scanner,
+ but its presence is necessary. */
+ struct yy_trans_info
+@@ -382,28 +373,29 @@ struct yy_trans_info
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+-static yyconst flex_int16_t yy_accept[159] =
++static yyconst flex_int16_t yy_accept[166] =
+ { 0,
+- 0, 0, 0, 0, 0, 0, 0, 0, 31, 29,
+- 18, 18, 29, 29, 29, 29, 29, 29, 29, 29,
+- 29, 29, 29, 29, 29, 29, 15, 16, 16, 29,
+- 16, 10, 10, 18, 26, 0, 3, 0, 27, 12,
+- 0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
+- 21, 23, 25, 24, 22, 0, 9, 28, 0, 0,
+- 0, 14, 14, 16, 16, 16, 10, 10, 10, 0,
+- 12, 0, 11, 0, 0, 0, 20, 0, 0, 0,
+- 0, 0, 0, 0, 0, 16, 10, 10, 10, 0,
+- 13, 19, 0, 0, 0, 0, 0, 0, 0, 0,
+-
+- 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 16, 6, 0, 0, 0, 0, 0, 0, 2,
+- 0, 0, 0, 0, 0, 0, 0, 0, 4, 17,
+- 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+- 5, 8, 0, 0, 0, 0, 7, 0
++ 0, 0, 0, 0, 0, 0, 0, 0, 32, 30,
++ 19, 19, 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 16, 17, 17, 30,
++ 17, 11, 11, 19, 27, 0, 3, 0, 28, 13,
++ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
++ 0, 22, 24, 26, 25, 23, 0, 10, 29, 0,
++ 0, 0, 15, 15, 17, 17, 17, 11, 11, 11,
++ 0, 13, 0, 12, 0, 0, 0, 21, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 17, 11, 11,
++ 11, 0, 14, 20, 0, 0, 0, 0, 0, 0,
++
++ 0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 17, 7, 0, 0, 0,
++ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 4, 18, 0, 0, 5, 2,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 1, 0, 0, 0, 0, 6, 9, 0,
++ 0, 0, 0, 8, 0
+ } ;
+
+-static yyconst flex_int32_t yy_ec[256] =
++static yyconst YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 4, 4, 4, 1, 1, 1, 1, 1, 1, 1,
+@@ -416,9 +408,9 @@ static yyconst flex_int32_t yy_ec[256] =
+ 22, 22, 22, 22, 24, 22, 22, 25, 22, 22,
+ 1, 26, 27, 1, 22, 1, 21, 28, 29, 30,
+
+- 31, 21, 22, 22, 32, 22, 22, 33, 34, 35,
+- 36, 37, 22, 38, 39, 40, 41, 42, 22, 25,
+- 43, 22, 44, 45, 46, 1, 1, 1, 1, 1,
++ 31, 21, 32, 22, 33, 22, 22, 34, 35, 36,
++ 37, 38, 22, 39, 40, 41, 42, 43, 22, 25,
++ 44, 22, 45, 46, 47, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+@@ -435,163 +427,165 @@ static yyconst flex_int32_t yy_ec[256] =
+ 1, 1, 1, 1, 1
+ } ;
+
+-static yyconst flex_int32_t yy_meta[47] =
++static yyconst YY_CHAR yy_meta[48] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 2, 3, 1, 2,
+ 2, 2, 4, 5, 5, 5, 6, 1, 1, 1,
+ 7, 8, 8, 8, 8, 1, 1, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+- 8, 8, 8, 3, 1, 4
++ 8, 8, 8, 8, 3, 1, 4
+ } ;
+
+-static yyconst flex_int16_t yy_base[173] =
++static yyconst flex_uint16_t yy_base[180] =
+ { 0,
+- 0, 383, 34, 382, 65, 381, 37, 105, 387, 391,
+- 54, 111, 367, 110, 109, 109, 112, 41, 366, 104,
+- 367, 338, 124, 117, 0, 144, 391, 0, 121, 0,
+- 135, 155, 140, 179, 391, 160, 391, 379, 391, 0,
+- 368, 141, 391, 167, 370, 376, 346, 103, 342, 345,
+- 391, 391, 391, 391, 391, 358, 391, 391, 175, 342,
+- 338, 391, 355, 0, 185, 339, 184, 347, 346, 0,
+- 0, 322, 175, 357, 175, 363, 352, 324, 330, 323,
+- 332, 326, 201, 324, 329, 322, 391, 333, 181, 309,
+- 391, 341, 340, 313, 320, 338, 178, 311, 146, 317,
+-
+- 314, 315, 335, 331, 303, 300, 309, 299, 308, 188,
+- 336, 335, 391, 305, 320, 281, 283, 271, 203, 288,
+- 281, 271, 266, 264, 245, 242, 208, 104, 391, 391,
+- 244, 218, 204, 219, 206, 224, 201, 212, 204, 229,
+- 215, 208, 207, 200, 219, 391, 233, 221, 200, 181,
+- 391, 391, 149, 122, 86, 41, 391, 391, 245, 251,
+- 259, 263, 267, 273, 280, 284, 292, 300, 304, 310,
+- 318, 326
++ 0, 393, 35, 392, 66, 391, 38, 107, 397, 401,
++ 55, 113, 377, 112, 111, 111, 114, 42, 376, 106,
++ 377, 347, 126, 120, 0, 147, 401, 0, 124, 0,
++ 137, 158, 170, 163, 401, 153, 401, 389, 401, 0,
++ 378, 120, 401, 131, 380, 386, 355, 139, 351, 355,
++ 351, 401, 401, 401, 401, 401, 367, 401, 401, 185,
++ 350, 346, 401, 364, 0, 185, 347, 189, 356, 355,
++ 0, 0, 330, 180, 366, 141, 372, 361, 332, 338,
++ 331, 341, 334, 326, 205, 331, 337, 329, 401, 341,
++ 167, 316, 401, 349, 348, 320, 328, 346, 180, 318,
++
++ 324, 209, 324, 320, 322, 342, 338, 309, 306, 315,
++ 305, 315, 312, 192, 342, 341, 401, 293, 306, 282,
++ 268, 252, 255, 203, 285, 282, 272, 268, 252, 233,
++ 232, 239, 208, 107, 401, 401, 238, 211, 401, 211,
++ 212, 208, 228, 203, 215, 207, 233, 222, 212, 211,
++ 203, 227, 401, 237, 225, 204, 185, 401, 401, 149,
++ 128, 88, 42, 401, 401, 253, 259, 267, 271, 275,
++ 281, 288, 292, 300, 308, 312, 318, 326, 334
+ } ;
+
+-static yyconst flex_int16_t yy_def[173] =
++static yyconst flex_int16_t yy_def[180] =
+ { 0,
+- 158, 1, 1, 3, 158, 5, 1, 1, 158, 158,
+- 158, 158, 158, 159, 160, 161, 158, 158, 158, 158,
+- 162, 158, 158, 158, 163, 162, 158, 164, 165, 164,
+- 164, 158, 158, 158, 158, 159, 158, 159, 158, 166,
+- 158, 161, 158, 161, 167, 168, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 162, 158, 158, 158, 158,
+- 158, 158, 162, 164, 165, 164, 158, 158, 158, 169,
+- 166, 170, 161, 167, 167, 168, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 164, 158, 158, 169, 170,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+-
+- 158, 164, 158, 158, 158, 158, 158, 158, 158, 171,
+- 158, 164, 158, 158, 158, 158, 158, 158, 171, 158,
+- 171, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 172, 158, 158, 158, 172, 158, 172, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 0, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158
++ 165, 1, 1, 3, 165, 5, 1, 1, 165, 165,
++ 165, 165, 165, 166, 167, 168, 165, 165, 165, 165,
++ 169, 165, 165, 165, 170, 169, 165, 171, 172, 171,
++ 171, 165, 165, 165, 165, 166, 165, 166, 165, 173,
++ 165, 168, 165, 168, 174, 175, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 169, 165, 165, 165,
++ 165, 165, 165, 169, 171, 172, 171, 165, 165, 165,
++ 176, 173, 177, 168, 174, 174, 175, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 171, 165, 165,
++ 176, 177, 165, 165, 165, 165, 165, 165, 165, 165,
++
++ 165, 165, 165, 165, 171, 165, 165, 165, 165, 165,
++ 165, 165, 165, 178, 165, 171, 165, 165, 165, 165,
++ 165, 165, 165, 178, 165, 178, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 179, 165, 165,
++ 165, 179, 165, 179, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 0, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+-static yyconst flex_int16_t yy_nxt[438] =
++static yyconst flex_uint16_t yy_nxt[449] =
+ { 0,
+ 10, 11, 12, 11, 13, 14, 10, 15, 16, 10,
+ 10, 10, 17, 10, 10, 10, 10, 18, 19, 20,
+ 21, 21, 21, 21, 21, 10, 10, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+- 21, 21, 21, 10, 22, 10, 24, 25, 25, 25,
+- 32, 33, 33, 157, 26, 34, 34, 34, 51, 52,
+- 27, 26, 26, 26, 26, 10, 11, 12, 11, 13,
+- 14, 28, 15, 16, 28, 28, 28, 24, 28, 28,
+- 28, 10, 18, 19, 20, 29, 29, 29, 29, 29,
+- 30, 10, 29, 29, 29, 29, 29, 29, 29, 29,
+-
+- 29, 29, 29, 29, 29, 29, 29, 29, 10, 22,
+- 10, 23, 34, 34, 34, 37, 39, 43, 32, 33,
+- 33, 45, 54, 55, 46, 59, 45, 64, 156, 46,
+- 64, 64, 64, 79, 44, 38, 59, 57, 134, 47,
+- 135, 48, 80, 49, 47, 50, 48, 99, 61, 43,
+- 50, 110, 41, 67, 67, 67, 60, 63, 63, 63,
+- 57, 155, 68, 69, 63, 37, 44, 66, 67, 67,
+- 67, 63, 63, 63, 63, 73, 59, 68, 69, 70,
+- 34, 34, 34, 43, 75, 38, 154, 92, 83, 83,
+- 83, 64, 44, 120, 64, 64, 64, 67, 67, 67,
+-
+- 44, 57, 99, 68, 69, 107, 68, 69, 120, 127,
+- 108, 153, 152, 121, 83, 83, 83, 133, 133, 133,
+- 146, 133, 133, 133, 146, 140, 140, 140, 121, 141,
+- 140, 140, 140, 151, 141, 158, 150, 149, 148, 144,
+- 147, 143, 142, 139, 147, 36, 36, 36, 36, 36,
+- 36, 36, 36, 40, 138, 137, 136, 40, 40, 42,
+- 42, 42, 42, 42, 42, 42, 42, 56, 56, 56,
+- 56, 62, 132, 62, 64, 131, 130, 64, 129, 64,
+- 64, 65, 128, 158, 65, 65, 65, 65, 71, 127,
+- 71, 71, 74, 74, 74, 74, 74, 74, 74, 74,
+-
+- 76, 76, 76, 76, 76, 76, 76, 76, 89, 126,
+- 89, 90, 125, 90, 90, 124, 90, 90, 119, 119,
+- 119, 119, 119, 119, 119, 119, 145, 145, 145, 145,
+- 145, 145, 145, 145, 123, 122, 59, 59, 118, 117,
+- 116, 115, 114, 113, 45, 112, 108, 111, 109, 106,
+- 105, 104, 46, 103, 91, 87, 102, 101, 100, 98,
+- 97, 96, 95, 94, 93, 77, 75, 91, 88, 87,
+- 86, 57, 85, 84, 57, 82, 81, 78, 77, 75,
+- 72, 158, 58, 57, 53, 35, 158, 31, 23, 23,
+- 9, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+-
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158
++ 21, 21, 21, 21, 10, 22, 10, 24, 25, 25,
++ 25, 32, 33, 33, 164, 26, 34, 34, 34, 52,
++ 53, 27, 26, 26, 26, 26, 10, 11, 12, 11,
++ 13, 14, 28, 15, 16, 28, 28, 28, 24, 28,
++ 28, 28, 10, 18, 19, 20, 29, 29, 29, 29,
++ 29, 30, 10, 29, 29, 29, 29, 29, 29, 29,
++
++ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
++ 10, 22, 10, 23, 34, 34, 34, 37, 39, 43,
++ 32, 33, 33, 45, 55, 56, 46, 60, 43, 45,
++ 65, 163, 46, 65, 65, 65, 44, 38, 60, 74,
++ 58, 47, 141, 48, 142, 44, 49, 47, 50, 48,
++ 76, 51, 62, 94, 50, 41, 44, 51, 37, 61,
++ 64, 64, 64, 58, 34, 34, 34, 64, 162, 80,
++ 67, 68, 68, 68, 64, 64, 64, 64, 38, 81,
++ 69, 70, 71, 68, 68, 68, 60, 161, 43, 69,
++ 70, 65, 69, 70, 65, 65, 65, 125, 85, 85,
++
++ 85, 58, 68, 68, 68, 44, 102, 110, 125, 133,
++ 102, 69, 70, 111, 114, 160, 159, 126, 85, 85,
++ 85, 140, 140, 140, 140, 140, 140, 153, 126, 147,
++ 147, 147, 153, 148, 147, 147, 147, 158, 148, 165,
++ 157, 156, 155, 151, 150, 149, 146, 154, 145, 144,
++ 143, 139, 154, 36, 36, 36, 36, 36, 36, 36,
++ 36, 40, 138, 137, 136, 40, 40, 42, 42, 42,
++ 42, 42, 42, 42, 42, 57, 57, 57, 57, 63,
++ 135, 63, 65, 134, 165, 65, 133, 65, 65, 66,
++ 132, 131, 66, 66, 66, 66, 72, 130, 72, 72,
++
++ 75, 75, 75, 75, 75, 75, 75, 75, 77, 77,
++ 77, 77, 77, 77, 77, 77, 91, 129, 91, 92,
++ 128, 92, 92, 127, 92, 92, 124, 124, 124, 124,
++ 124, 124, 124, 124, 152, 152, 152, 152, 152, 152,
++ 152, 152, 60, 60, 123, 122, 121, 120, 119, 118,
++ 117, 45, 116, 111, 115, 113, 112, 109, 108, 107,
++ 46, 106, 93, 89, 105, 104, 103, 101, 100, 99,
++ 98, 97, 96, 95, 78, 76, 93, 90, 89, 88,
++ 58, 87, 86, 58, 84, 83, 82, 79, 78, 76,
++ 73, 165, 59, 58, 54, 35, 165, 31, 23, 23,
++
++ 9, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+-static yyconst flex_int16_t yy_chk[438] =
++static yyconst flex_int16_t yy_chk[449] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+- 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
+- 7, 7, 7, 156, 3, 11, 11, 11, 18, 18,
+- 3, 3, 3, 3, 3, 5, 5, 5, 5, 5,
++ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
++ 3, 7, 7, 7, 163, 3, 11, 11, 11, 18,
++ 18, 3, 3, 3, 3, 3, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+- 5, 8, 12, 12, 12, 14, 15, 16, 8, 8,
+- 8, 17, 20, 20, 17, 23, 24, 29, 155, 24,
+- 29, 29, 29, 48, 16, 14, 31, 29, 128, 17,
+- 128, 17, 48, 17, 24, 17, 24, 99, 24, 42,
+- 24, 99, 15, 33, 33, 33, 23, 26, 26, 26,
+- 26, 154, 33, 33, 26, 36, 42, 31, 32, 32,
+- 32, 26, 26, 26, 26, 44, 59, 32, 32, 32,
+- 34, 34, 34, 73, 75, 36, 153, 75, 59, 59,
+- 59, 65, 44, 110, 65, 65, 65, 67, 67, 67,
+-
+- 73, 65, 83, 89, 89, 97, 67, 67, 119, 127,
+- 97, 150, 149, 110, 83, 83, 83, 133, 133, 133,
+- 141, 127, 127, 127, 145, 136, 136, 136, 119, 136,
+- 140, 140, 140, 148, 140, 147, 144, 143, 142, 139,
+- 141, 138, 137, 135, 145, 159, 159, 159, 159, 159,
+- 159, 159, 159, 160, 134, 132, 131, 160, 160, 161,
+- 161, 161, 161, 161, 161, 161, 161, 162, 162, 162,
+- 162, 163, 126, 163, 164, 125, 124, 164, 123, 164,
+- 164, 165, 122, 121, 165, 165, 165, 165, 166, 120,
+- 166, 166, 167, 167, 167, 167, 167, 167, 167, 167,
+-
+- 168, 168, 168, 168, 168, 168, 168, 168, 169, 118,
+- 169, 170, 117, 170, 170, 116, 170, 170, 171, 171,
+- 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
+- 172, 172, 172, 172, 115, 114, 112, 111, 109, 108,
+- 107, 106, 105, 104, 103, 102, 101, 100, 98, 96,
+- 95, 94, 93, 92, 90, 88, 86, 85, 84, 82,
+- 81, 80, 79, 78, 77, 76, 74, 72, 69, 68,
+- 66, 63, 61, 60, 56, 50, 49, 47, 46, 45,
++ 5, 5, 5, 8, 12, 12, 12, 14, 15, 16,
++ 8, 8, 8, 17, 20, 20, 17, 23, 42, 24,
++ 29, 162, 24, 29, 29, 29, 16, 14, 31, 44,
++ 29, 17, 134, 17, 134, 42, 17, 24, 17, 24,
++ 76, 17, 24, 76, 24, 15, 44, 24, 36, 23,
++ 26, 26, 26, 26, 34, 34, 34, 26, 161, 48,
++ 31, 32, 32, 32, 26, 26, 26, 26, 36, 48,
++ 32, 32, 32, 33, 33, 33, 60, 160, 74, 91,
++ 91, 66, 33, 33, 66, 66, 66, 114, 60, 60,
++
++ 60, 66, 68, 68, 68, 74, 85, 99, 124, 133,
++ 102, 68, 68, 99, 102, 157, 156, 114, 85, 85,
++ 85, 133, 133, 133, 140, 140, 140, 148, 124, 143,
++ 143, 143, 152, 143, 147, 147, 147, 155, 147, 154,
++ 151, 150, 149, 146, 145, 144, 142, 148, 141, 138,
++ 137, 132, 152, 166, 166, 166, 166, 166, 166, 166,
++ 166, 167, 131, 130, 129, 167, 167, 168, 168, 168,
++ 168, 168, 168, 168, 168, 169, 169, 169, 169, 170,
++ 128, 170, 171, 127, 126, 171, 125, 171, 171, 172,
++ 123, 122, 172, 172, 172, 172, 173, 121, 173, 173,
++
++ 174, 174, 174, 174, 174, 174, 174, 174, 175, 175,
++ 175, 175, 175, 175, 175, 175, 176, 120, 176, 177,
++ 119, 177, 177, 118, 177, 177, 178, 178, 178, 178,
++ 178, 178, 178, 178, 179, 179, 179, 179, 179, 179,
++ 179, 179, 116, 115, 113, 112, 111, 110, 109, 108,
++ 107, 106, 105, 104, 103, 101, 100, 98, 97, 96,
++ 95, 94, 92, 90, 88, 87, 86, 84, 83, 82,
++ 81, 80, 79, 78, 77, 75, 73, 70, 69, 67,
++ 64, 62, 61, 57, 51, 50, 49, 47, 46, 45,
+ 41, 38, 22, 21, 19, 13, 9, 6, 4, 2,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
+- 158, 158, 158, 158, 158, 158, 158
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
++ 165, 165, 165, 165, 165, 165, 165, 165
+ } ;
+
+ static yy_state_type yy_last_accepting_state;
+@@ -661,8 +655,9 @@ static int dts_version = 1;
+
+ static void push_input_file(const char *filename);
+ static bool pop_input_file(void);
+-static void lexical_error(const char *fmt, ...);
+-#line 666 "dtc-lexer.lex.c"
++static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
++
++#line 661 "dtc-lexer.lex.c"
+
+ #define INITIAL 0
+ #define BYTESTRING 1
+@@ -698,19 +693,19 @@ void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+ FILE *yyget_in (void );
+
+-void yyset_in (FILE * in_str );
++void yyset_in (FILE * _in_str );
+
+ FILE *yyget_out (void );
+
+-void yyset_out (FILE * out_str );
++void yyset_out (FILE * _out_str );
+
+-yy_size_t yyget_leng (void );
++ int yyget_leng (void );
+
+ char *yyget_text (void );
+
+ int yyget_lineno (void );
+
+-void yyset_lineno (int line_number );
++void yyset_lineno (int _line_number );
+
+ /* Macros after this point can all be overridden by user definitions in
+ * section 1.
+@@ -724,6 +719,10 @@ extern int yywrap (void );
+ #endif
+ #endif
+
++#ifndef YY_NO_UNPUT
++
++#endif
++
+ #ifndef yytext_ptr
+ static void yy_flex_strncpy (char *,yyconst char *,int );
+ #endif
+@@ -757,7 +756,7 @@ static int input (void );
+ /* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
++#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+ #endif
+
+ /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+@@ -781,7 +780,7 @@ static int input (void );
+ else \
+ { \
+ errno=0; \
+- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
++ while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+@@ -836,7 +835,7 @@ extern int yylex (void);
+
+ /* Code executed at the end of each rule. */
+ #ifndef YY_BREAK
+-#define YY_BREAK break;
++#define YY_BREAK /*LINTED*/break;
+ #endif
+
+ #define YY_RULE_SETUP \
+@@ -849,9 +848,9 @@ extern int yylex (void);
+ */
+ YY_DECL
+ {
+- register yy_state_type yy_current_state;
+- register char *yy_cp, *yy_bp;
+- register int yy_act;
++ yy_state_type yy_current_state;
++ char *yy_cp, *yy_bp;
++ int yy_act;
+
+ if ( !(yy_init) )
+ {
+@@ -880,11 +879,11 @@ YY_DECL
+ }
+
+ {
+-#line 68 "dtc-lexer.l"
++#line 69 "dtc-lexer.l"
+
+-#line 886 "dtc-lexer.lex.c"
++#line 885 "dtc-lexer.lex.c"
+
+- while ( 1 ) /* loops until end-of-file is reached */
++ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+@@ -901,7 +900,7 @@ YY_DECL
+ yy_match:
+ do
+ {
+- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
++ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+@@ -910,13 +909,13 @@ yy_match:
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+ ++yy_cp;
+ }
+- while ( yy_current_state != 158 );
++ while ( yy_current_state != 165 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+@@ -939,7 +938,7 @@ do_action: /* This label is used only to access EOF actions. */
+ case 1:
+ /* rule 1 can match eol */
+ YY_RULE_SETUP
+-#line 69 "dtc-lexer.l"
++#line 70 "dtc-lexer.l"
+ {
+ char *name = strchr(yytext, '\"') + 1;
+ yytext[yyleng-1] = '\0';
+@@ -949,7 +948,7 @@ YY_RULE_SETUP
+ case 2:
+ /* rule 2 can match eol */
+ YY_RULE_SETUP
+-#line 75 "dtc-lexer.l"
++#line 76 "dtc-lexer.l"
+ {
+ char *line, *fnstart, *fnend;
+ struct data fn;
+@@ -983,7 +982,7 @@ case YY_STATE_EOF(INITIAL):
+ case YY_STATE_EOF(BYTESTRING):
+ case YY_STATE_EOF(PROPNODENAME):
+ case YY_STATE_EOF(V1):
+-#line 104 "dtc-lexer.l"
++#line 105 "dtc-lexer.l"
+ {
+ if (!pop_input_file()) {
+ yyterminate();
+@@ -993,7 +992,7 @@ case YY_STATE_EOF(V1):
+ case 3:
+ /* rule 3 can match eol */
+ YY_RULE_SETUP
+-#line 110 "dtc-lexer.l"
++#line 111 "dtc-lexer.l"
+ {
+ DPRINT("String: %s\n", yytext);
+ yylval.data = data_copy_escape_string(yytext+1,
+@@ -1003,7 +1002,7 @@ YY_RULE_SETUP
+ YY_BREAK
+ case 4:
+ YY_RULE_SETUP
+-#line 117 "dtc-lexer.l"
++#line 118 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /dts-v1/\n");
+ dts_version = 1;
+@@ -1013,25 +1012,33 @@ YY_RULE_SETUP
+ YY_BREAK
+ case 5:
+ YY_RULE_SETUP
+-#line 124 "dtc-lexer.l"
++#line 125 "dtc-lexer.l"
++{
++ DPRINT("Keyword: /plugin/\n");
++ return DT_PLUGIN;
++ }
++ YY_BREAK
++case 6:
++YY_RULE_SETUP
++#line 130 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+ return DT_MEMRESERVE;
+ }
+ YY_BREAK
+-case 6:
++case 7:
+ YY_RULE_SETUP
+-#line 130 "dtc-lexer.l"
++#line 136 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /bits/\n");
+ BEGIN_DEFAULT();
+ return DT_BITS;
+ }
+ YY_BREAK
+-case 7:
++case 8:
+ YY_RULE_SETUP
+-#line 136 "dtc-lexer.l"
++#line 142 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-property/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1039,9 +1046,9 @@ YY_RULE_SETUP
+ return DT_DEL_PROP;
+ }
+ YY_BREAK
+-case 8:
++case 9:
+ YY_RULE_SETUP
+-#line 143 "dtc-lexer.l"
++#line 149 "dtc-lexer.l"
+ {
+ DPRINT("Keyword: /delete-node/\n");
+ DPRINT("<PROPNODENAME>\n");
+@@ -1049,9 +1056,9 @@ YY_RULE_SETUP
+ return DT_DEL_NODE;
+ }
+ YY_BREAK
+-case 9:
++case 10:
+ YY_RULE_SETUP
+-#line 150 "dtc-lexer.l"
++#line 156 "dtc-lexer.l"
+ {
+ DPRINT("Label: %s\n", yytext);
+ yylval.labelref = xstrdup(yytext);
+@@ -1059,9 +1066,9 @@ YY_RULE_SETUP
+ return DT_LABEL;
+ }
+ YY_BREAK
+-case 10:
++case 11:
+ YY_RULE_SETUP
+-#line 157 "dtc-lexer.l"
++#line 163 "dtc-lexer.l"
+ {
+ char *e;
+ DPRINT("Integer Literal: '%s'\n", yytext);
+@@ -1084,10 +1091,10 @@ YY_RULE_SETUP
+ return DT_LITERAL;
+ }
+ YY_BREAK
+-case 11:
+-/* rule 11 can match eol */
++case 12:
++/* rule 12 can match eol */
+ YY_RULE_SETUP
+-#line 179 "dtc-lexer.l"
++#line 185 "dtc-lexer.l"
+ {
+ struct data d;
+ DPRINT("Character literal: %s\n", yytext);
+@@ -1096,31 +1103,31 @@ YY_RULE_SETUP
+ if (d.len == 1) {
+ lexical_error("Empty character literal");
+ yylval.integer = 0;
+- return DT_CHAR_LITERAL;
+- }
++ } else {
++ yylval.integer = (unsigned char)d.val[0];
+
+- yylval.integer = (unsigned char)d.val[0];
+-
+- if (d.len > 2)
+- lexical_error("Character literal has %d"
+- " characters instead of 1",
+- d.len - 1);
++ if (d.len > 2)
++ lexical_error("Character literal has %d"
++ " characters instead of 1",
++ d.len - 1);
++ }
+
++ data_free(d);
+ return DT_CHAR_LITERAL;
+ }
+ YY_BREAK
+-case 12:
++case 13:
+ YY_RULE_SETUP
+-#line 200 "dtc-lexer.l"
++#line 206 "dtc-lexer.l"
+ { /* label reference */
+ DPRINT("Ref: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_REF;
+ }
+ YY_BREAK
+-case 13:
++case 14:
+ YY_RULE_SETUP
+-#line 206 "dtc-lexer.l"
++#line 212 "dtc-lexer.l"
+ { /* new-style path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", yytext+2);
+@@ -1128,27 +1135,27 @@ YY_RULE_SETUP
+ return DT_REF;
+ }
+ YY_BREAK
+-case 14:
++case 15:
+ YY_RULE_SETUP
+-#line 213 "dtc-lexer.l"
++#line 219 "dtc-lexer.l"
+ {
+ yylval.byte = strtol(yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)yylval.byte);
+ return DT_BYTE;
+ }
+ YY_BREAK
+-case 15:
++case 16:
+ YY_RULE_SETUP
+-#line 219 "dtc-lexer.l"
++#line 225 "dtc-lexer.l"
+ {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+ YY_BREAK
+-case 16:
++case 17:
+ YY_RULE_SETUP
+-#line 225 "dtc-lexer.l"
++#line 231 "dtc-lexer.l"
+ {
+ DPRINT("PropNodeName: %s\n", yytext);
+ yylval.propnodename = xstrdup((yytext[0] == '\\') ?
+@@ -1157,75 +1164,75 @@ YY_RULE_SETUP
+ return DT_PROPNODENAME;
+ }
+ YY_BREAK
+-case 17:
++case 18:
+ YY_RULE_SETUP
+-#line 233 "dtc-lexer.l"
++#line 239 "dtc-lexer.l"
+ {
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+ YY_BREAK
+-case 18:
+-/* rule 18 can match eol */
+-YY_RULE_SETUP
+-#line 238 "dtc-lexer.l"
+-/* eat whitespace */
+- YY_BREAK
+ case 19:
+ /* rule 19 can match eol */
+ YY_RULE_SETUP
+-#line 239 "dtc-lexer.l"
+-/* eat C-style comments */
++#line 244 "dtc-lexer.l"
++/* eat whitespace */
+ YY_BREAK
+ case 20:
+ /* rule 20 can match eol */
+ YY_RULE_SETUP
+-#line 240 "dtc-lexer.l"
+-/* eat C++-style comments */
++#line 245 "dtc-lexer.l"
++/* eat C-style comments */
+ YY_BREAK
+ case 21:
++/* rule 21 can match eol */
+ YY_RULE_SETUP
+-#line 242 "dtc-lexer.l"
+-{ return DT_LSHIFT; };
++#line 246 "dtc-lexer.l"
++/* eat C++-style comments */
+ YY_BREAK
+ case 22:
+ YY_RULE_SETUP
+-#line 243 "dtc-lexer.l"
+-{ return DT_RSHIFT; };
++#line 248 "dtc-lexer.l"
++{ return DT_LSHIFT; };
+ YY_BREAK
+ case 23:
+ YY_RULE_SETUP
+-#line 244 "dtc-lexer.l"
+-{ return DT_LE; };
++#line 249 "dtc-lexer.l"
++{ return DT_RSHIFT; };
+ YY_BREAK
+ case 24:
+ YY_RULE_SETUP
+-#line 245 "dtc-lexer.l"
+-{ return DT_GE; };
++#line 250 "dtc-lexer.l"
++{ return DT_LE; };
+ YY_BREAK
+ case 25:
+ YY_RULE_SETUP
+-#line 246 "dtc-lexer.l"
+-{ return DT_EQ; };
++#line 251 "dtc-lexer.l"
++{ return DT_GE; };
+ YY_BREAK
+ case 26:
+ YY_RULE_SETUP
+-#line 247 "dtc-lexer.l"
+-{ return DT_NE; };
++#line 252 "dtc-lexer.l"
++{ return DT_EQ; };
+ YY_BREAK
+ case 27:
+ YY_RULE_SETUP
+-#line 248 "dtc-lexer.l"
+-{ return DT_AND; };
++#line 253 "dtc-lexer.l"
++{ return DT_NE; };
+ YY_BREAK
+ case 28:
+ YY_RULE_SETUP
+-#line 249 "dtc-lexer.l"
+-{ return DT_OR; };
++#line 254 "dtc-lexer.l"
++{ return DT_AND; };
+ YY_BREAK
+ case 29:
+ YY_RULE_SETUP
+-#line 251 "dtc-lexer.l"
++#line 255 "dtc-lexer.l"
++{ return DT_OR; };
++ YY_BREAK
++case 30:
++YY_RULE_SETUP
++#line 257 "dtc-lexer.l"
+ {
+ DPRINT("Char: %c (\\x%02x)\n", yytext[0],
+ (unsigned)yytext[0]);
+@@ -1241,12 +1248,12 @@ YY_RULE_SETUP
+ return yytext[0];
+ }
+ YY_BREAK
+-case 30:
++case 31:
+ YY_RULE_SETUP
+-#line 266 "dtc-lexer.l"
++#line 272 "dtc-lexer.l"
+ ECHO;
+ YY_BREAK
+-#line 1250 "dtc-lexer.lex.c"
++#line 1257 "dtc-lexer.lex.c"
+
+ case YY_END_OF_BUFFER:
+ {
+@@ -1388,9 +1395,9 @@ ECHO;
+ */
+ static int yy_get_next_buffer (void)
+ {
+- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+- register char *source = (yytext_ptr);
+- register int number_to_move, i;
++ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
++ char *source = (yytext_ptr);
++ int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+@@ -1419,7 +1426,7 @@ static int yy_get_next_buffer (void)
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
++ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+@@ -1432,7 +1439,7 @@ static int yy_get_next_buffer (void)
+
+ else
+ {
+- yy_size_t num_to_read =
++ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+@@ -1446,7 +1453,7 @@ static int yy_get_next_buffer (void)
+
+ if ( b->yy_is_our_buffer )
+ {
+- yy_size_t new_size = b->yy_buf_size * 2;
++ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -1459,7 +1466,7 @@ static int yy_get_next_buffer (void)
+ }
+ else
+ /* Can't grow it, we don't own it. */
+- b->yy_ch_buf = 0;
++ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+@@ -1501,9 +1508,9 @@ static int yy_get_next_buffer (void)
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+- if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
++ if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+- yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
++ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+@@ -1522,15 +1529,15 @@ static int yy_get_next_buffer (void)
+
+ static yy_state_type yy_get_previous_state (void)
+ {
+- register yy_state_type yy_current_state;
+- register char *yy_cp;
++ yy_state_type yy_current_state;
++ char *yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
++ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+@@ -1539,10 +1546,10 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+ }
+
+ return yy_current_state;
+@@ -1555,10 +1562,10 @@ static int yy_get_next_buffer (void)
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+ {
+- register int yy_is_jam;
+- register char *yy_cp = (yy_c_buf_p);
++ int yy_is_jam;
++ char *yy_cp = (yy_c_buf_p);
+
+- register YY_CHAR yy_c = 1;
++ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+@@ -1567,15 +1574,19 @@ static int yy_get_next_buffer (void)
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+- if ( yy_current_state >= 159 )
++ if ( yy_current_state >= 166 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+- yy_is_jam = (yy_current_state == 158);
++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
++ yy_is_jam = (yy_current_state == 165);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
++#ifndef YY_NO_UNPUT
++
++#endif
++
+ #ifndef YY_NO_INPUT
+ #ifdef __cplusplus
+ static int yyinput (void)
+@@ -1600,7 +1611,7 @@ static int yy_get_next_buffer (void)
+
+ else
+ { /* need more input */
+- yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
++ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+@@ -1624,7 +1635,7 @@ static int yy_get_next_buffer (void)
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+- return EOF;
++ return 0;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+@@ -1727,7 +1738,7 @@ static void yy_load_buffer_state (void)
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+- b->yy_buf_size = size;
++ b->yy_buf_size = (yy_size_t)size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+@@ -1874,7 +1885,7 @@ void yypop_buffer_state (void)
+ */
+ static void yyensure_buffer_stack (void)
+ {
+- yy_size_t num_to_alloc;
++ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+@@ -1882,15 +1893,15 @@ static void yyensure_buffer_stack (void)
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+- num_to_alloc = 1;
++ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+-
++
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+-
++
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+@@ -1899,7 +1910,7 @@ static void yyensure_buffer_stack (void)
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+- int grow_size = 8 /* arbitrary grow size */;
++ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+@@ -1919,7 +1930,7 @@ static void yyensure_buffer_stack (void)
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+- * @return the newly allocated buffer state object.
++ * @return the newly allocated buffer state object.
+ */
+ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+ {
+@@ -1929,7 +1940,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+- return 0;
++ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+@@ -1938,7 +1949,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+- b->yy_input_file = 0;
++ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+@@ -1961,7 +1972,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+ {
+
+- return yy_scan_bytes(yystr,strlen(yystr) );
++ return yy_scan_bytes(yystr,(int) strlen(yystr) );
+ }
+
+ /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+@@ -1971,15 +1982,15 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+ *
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+- yy_size_t i;
++ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+- n = _yybytes_len + 2;
++ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+@@ -2005,9 +2016,9 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len
+ #define YY_EXIT_FAILURE 2
+ #endif
+
+-static void yy_fatal_error (yyconst char* msg )
++static void yynoreturn yy_fatal_error (yyconst char* msg )
+ {
+- (void) fprintf( stderr, "%s\n", msg );
++ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+@@ -2035,7 +2046,7 @@ static void yy_fatal_error (yyconst char* msg )
+ */
+ int yyget_lineno (void)
+ {
+-
++
+ return yylineno;
+ }
+
+@@ -2058,7 +2069,7 @@ FILE *yyget_out (void)
+ /** Get the length of the current token.
+ *
+ */
+-yy_size_t yyget_leng (void)
++int yyget_leng (void)
+ {
+ return yyleng;
+ }
+@@ -2073,29 +2084,29 @@ char *yyget_text (void)
+ }
+
+ /** Set the current line number.
+- * @param line_number
++ * @param _line_number line number
+ *
+ */
+-void yyset_lineno (int line_number )
++void yyset_lineno (int _line_number )
+ {
+
+- yylineno = line_number;
++ yylineno = _line_number;
+ }
+
+ /** Set the input stream. This does not discard the current
+ * input buffer.
+- * @param in_str A readable stream.
++ * @param _in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+-void yyset_in (FILE * in_str )
++void yyset_in (FILE * _in_str )
+ {
+- yyin = in_str ;
++ yyin = _in_str ;
+ }
+
+-void yyset_out (FILE * out_str )
++void yyset_out (FILE * _out_str )
+ {
+- yyout = out_str ;
++ yyout = _out_str ;
+ }
+
+ int yyget_debug (void)
+@@ -2103,9 +2114,9 @@ int yyget_debug (void)
+ return yy_flex_debug;
+ }
+
+-void yyset_debug (int bdebug )
++void yyset_debug (int _bdebug )
+ {
+- yy_flex_debug = bdebug ;
++ yy_flex_debug = _bdebug ;
+ }
+
+ static int yy_init_globals (void)
+@@ -2114,10 +2125,10 @@ static int yy_init_globals (void)
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+- (yy_buffer_stack) = 0;
++ (yy_buffer_stack) = NULL;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+- (yy_c_buf_p) = (char *) 0;
++ (yy_c_buf_p) = NULL;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+@@ -2126,8 +2137,8 @@ static int yy_init_globals (void)
+ yyin = stdin;
+ yyout = stdout;
+ #else
+- yyin = (FILE *) 0;
+- yyout = (FILE *) 0;
++ yyin = NULL;
++ yyout = NULL;
+ #endif
+
+ /* For future reference: Set errno on error, since we are called by
+@@ -2165,7 +2176,8 @@ int yylex_destroy (void)
+ #ifndef yytext_ptr
+ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+ {
+- register int i;
++
++ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+@@ -2174,7 +2186,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+ #ifdef YY_NEED_STRLEN
+ static int yy_flex_strlen (yyconst char * s )
+ {
+- register int n;
++ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+@@ -2184,11 +2196,12 @@ static int yy_flex_strlen (yyconst char * s )
+
+ void *yyalloc (yy_size_t size )
+ {
+- return (void *) malloc( size );
++ return malloc(size);
+ }
+
+ void *yyrealloc (void * ptr, yy_size_t size )
+ {
++
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+@@ -2196,17 +2209,17 @@ void *yyrealloc (void * ptr, yy_size_t size )
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+- return (void *) realloc( (char *) ptr, size );
++ return realloc(ptr, size);
+ }
+
+ void yyfree (void * ptr )
+ {
+- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
++ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+ }
+
+ #define YYTABLES_NAME "yytables"
+
+-#line 265 "dtc-lexer.l"
++#line 272 "dtc-lexer.l"
+
+
+
+diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped
+index 31cec50..0a7a5ed 100644
+--- a/scripts/dtc/dtc-parser.tab.c_shipped
++++ b/scripts/dtc/dtc-parser.tab.c_shipped
+@@ -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 implementation 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
+ it under the terms of the GNU General Public License as published by
+@@ -44,7 +44,7 @@
+ #define YYBISON 1
+
+ /* Bison version. */
+-#define YYBISON_VERSION "3.0.2"
++#define YYBISON_VERSION "3.0.4"
+
+ /* Skeleton name. */
+ #define YYSKELETON_NAME "yacc.c"
+@@ -65,6 +65,7 @@
+ #line 20 "dtc-parser.y" /* yacc.c:339 */
+
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -77,10 +78,10 @@ extern void yyerror(char const *s);
+ treesource_error = true; \
+ } while (0)
+
+-extern struct boot_info *the_boot_info;
++extern struct dt_info *parser_output;
+ extern bool treesource_error;
+
+-#line 84 "dtc-parser.tab.c" /* yacc.c:339 */
++#line 85 "dtc-parser.tab.c" /* yacc.c:339 */
+
+ # ifndef YY_NULLPTR
+ # if defined __cplusplus && 201103L <= __cplusplus
+@@ -116,35 +117,36 @@ extern int yydebug;
+ enum yytokentype
+ {
+ DT_V1 = 258,
+- DT_MEMRESERVE = 259,
+- DT_LSHIFT = 260,
+- DT_RSHIFT = 261,
+- DT_LE = 262,
+- DT_GE = 263,
+- DT_EQ = 264,
+- DT_NE = 265,
+- DT_AND = 266,
+- DT_OR = 267,
+- DT_BITS = 268,
+- DT_DEL_PROP = 269,
+- DT_DEL_NODE = 270,
+- DT_PROPNODENAME = 271,
+- DT_LITERAL = 272,
+- DT_CHAR_LITERAL = 273,
+- DT_BYTE = 274,
+- DT_STRING = 275,
+- DT_LABEL = 276,
+- DT_REF = 277,
+- DT_INCBIN = 278
++ DT_PLUGIN = 259,
++ DT_MEMRESERVE = 260,
++ DT_LSHIFT = 261,
++ DT_RSHIFT = 262,
++ DT_LE = 263,
++ DT_GE = 264,
++ DT_EQ = 265,
++ DT_NE = 266,
++ DT_AND = 267,
++ DT_OR = 268,
++ DT_BITS = 269,
++ DT_DEL_PROP = 270,
++ DT_DEL_NODE = 271,
++ DT_PROPNODENAME = 272,
++ DT_LITERAL = 273,
++ DT_CHAR_LITERAL = 274,
++ DT_BYTE = 275,
++ DT_STRING = 276,
++ DT_LABEL = 277,
++ DT_REF = 278,
++ DT_INCBIN = 279
+ };
+ #endif
+
+ /* Value type. */
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+-typedef union YYSTYPE YYSTYPE;
++
+ union YYSTYPE
+ {
+-#line 38 "dtc-parser.y" /* yacc.c:355 */
++#line 39 "dtc-parser.y" /* yacc.c:355 */
+
+ char *propnodename;
+ char *labelref;
+@@ -162,9 +164,12 @@ union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ unsigned int flags;
+
+-#line 167 "dtc-parser.tab.c" /* yacc.c:355 */
++#line 170 "dtc-parser.tab.c" /* yacc.c:355 */
+ };
++
++typedef union YYSTYPE YYSTYPE;
+ # define YYSTYPE_IS_TRIVIAL 1
+ # define YYSTYPE_IS_DECLARED 1
+ #endif
+@@ -192,7 +197,7 @@ int yyparse (void);
+
+ /* Copy the second part of user declarations. */
+
+-#line 196 "dtc-parser.tab.c" /* yacc.c:358 */
++#line 201 "dtc-parser.tab.c" /* yacc.c:358 */
+
+ #ifdef short
+ # undef short
+@@ -434,23 +439,23 @@ union yyalloc
+ #endif /* !YYCOPY_NEEDED */
+
+ /* YYFINAL -- State number of the termination state. */
+-#define YYFINAL 4
++#define YYFINAL 6
+ /* YYLAST -- Last index in YYTABLE. */
+-#define YYLAST 136
++#define YYLAST 138
+
+ /* YYNTOKENS -- Number of terminals. */
+-#define YYNTOKENS 47
++#define YYNTOKENS 48
+ /* YYNNTS -- Number of nonterminals. */
+-#define YYNNTS 28
++#define YYNNTS 30
+ /* YYNRULES -- Number of rules. */
+-#define YYNRULES 80
++#define YYNRULES 84
+ /* YYNSTATES -- Number of states. */
+-#define YYNSTATES 144
++#define YYNSTATES 149
+
+ /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+ #define YYUNDEFTOK 2
+-#define YYMAXUTOK 278
++#define YYMAXUTOK 279
+
+ #define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+@@ -462,16 +467,16 @@ static const yytype_uint8 yytranslate[] =
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 46, 2, 2, 2, 44, 40, 2,
+- 32, 34, 43, 41, 33, 42, 2, 25, 2, 2,
+- 2, 2, 2, 2, 2, 2, 2, 2, 37, 24,
+- 35, 28, 29, 36, 2, 2, 2, 2, 2, 2,
++ 2, 2, 2, 47, 2, 2, 2, 45, 41, 2,
++ 33, 35, 44, 42, 34, 43, 2, 26, 2, 2,
++ 2, 2, 2, 2, 2, 2, 2, 2, 38, 25,
++ 36, 29, 30, 37, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 30, 2, 31, 39, 2, 2, 2, 2, 2,
++ 2, 31, 2, 32, 40, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 26, 38, 27, 45, 2, 2, 2,
++ 2, 2, 2, 27, 39, 28, 46, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+@@ -486,22 +491,22 @@ static const yytype_uint8 yytranslate[] =
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+- 15, 16, 17, 18, 19, 20, 21, 22, 23
++ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
+ };
+
+ #if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+ static const yytype_uint16 yyrline[] =
+ {
+- 0, 104, 104, 113, 116, 123, 127, 135, 139, 144,
+- 155, 165, 180, 188, 191, 198, 202, 206, 210, 218,
+- 222, 226, 230, 234, 250, 260, 268, 271, 275, 282,
+- 298, 303, 322, 336, 343, 344, 345, 352, 356, 357,
+- 361, 362, 366, 367, 371, 372, 376, 377, 381, 382,
+- 386, 387, 388, 392, 393, 394, 395, 396, 400, 401,
+- 402, 406, 407, 408, 412, 413, 422, 431, 435, 436,
+- 437, 438, 443, 446, 450, 458, 461, 465, 473, 477,
+- 481
++ 0, 109, 109, 117, 121, 128, 129, 139, 142, 149,
++ 153, 161, 165, 170, 181, 191, 206, 214, 217, 224,
++ 228, 232, 236, 244, 248, 252, 256, 260, 276, 286,
++ 294, 297, 301, 308, 324, 329, 348, 362, 369, 370,
++ 371, 378, 382, 383, 387, 388, 392, 393, 397, 398,
++ 402, 403, 407, 408, 412, 413, 414, 418, 419, 420,
++ 421, 422, 426, 427, 428, 432, 433, 434, 438, 439,
++ 448, 457, 461, 462, 463, 464, 469, 472, 476, 484,
++ 487, 491, 499, 503, 507
+ };
+ #endif
+
+@@ -510,19 +515,20 @@ static const yytype_uint16 yyrline[] =
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+ static const char *const yytname[] =
+ {
+- "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
+- "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
+- "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
+- "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
+- "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
+- "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
+- "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
+- "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
+- "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
+- "integer_expr", "integer_trinary", "integer_or", "integer_and",
+- "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
+- "integer_rela", "integer_shift", "integer_add", "integer_mul",
+- "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
++ "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
++ "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
++ "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
++ "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
++ "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
++ "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
++ "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
++ "header", "headers", "memreserves", "memreserve", "devicetree",
++ "nodedef", "proplist", "propdef", "propdata", "propdataprefix",
++ "arrayprefix", "integer_prim", "integer_expr", "integer_trinary",
++ "integer_or", "integer_and", "integer_bitor", "integer_bitxor",
++ "integer_bitand", "integer_eq", "integer_rela", "integer_shift",
++ "integer_add", "integer_mul", "integer_unary", "bytestring", "subnodes",
++ "subnode", YY_NULLPTR
+ };
+ #endif
+
+@@ -533,16 +539,16 @@ static const yytype_uint16 yytoknum[] =
+ {
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+- 275, 276, 277, 278, 59, 47, 123, 125, 61, 62,
+- 91, 93, 40, 44, 41, 60, 63, 58, 124, 94,
+- 38, 43, 45, 42, 37, 126, 33
++ 275, 276, 277, 278, 279, 59, 47, 123, 125, 61,
++ 62, 91, 93, 40, 44, 41, 60, 63, 58, 124,
++ 94, 38, 43, 45, 42, 37, 126, 33
+ };
+ # endif
+
+-#define YYPACT_NINF -81
++#define YYPACT_NINF -44
+
+ #define yypact_value_is_default(Yystate) \
+- (!!((Yystate) == (-81)))
++ (!!((Yystate) == (-44)))
+
+ #define YYTABLE_NINF -1
+
+@@ -553,21 +559,21 @@ static const yytype_uint16 yytoknum[] =
+ STATE-NUM. */
+ static const yytype_int8 yypact[] =
+ {
+- 16, -11, 21, 10, -81, 25, 10, 19, 10, -81,
+- -81, -9, 25, -81, 2, 51, -81, -9, -9, -9,
+- -81, 1, -81, -6, 50, 14, 28, 29, 36, 3,
+- 58, 44, -3, -81, 47, -81, -81, 65, 68, 2,
+- 2, -81, -81, -81, -81, -9, -9, -9, -9, -9,
+- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
+- -9, -9, -9, -9, -81, 63, 69, 2, -81, -81,
+- 50, 57, 14, 28, 29, 36, 3, 3, 58, 58,
+- 58, 58, 44, 44, -3, -3, -81, -81, -81, 79,
+- 80, -8, 63, -81, 72, 63, -81, -81, -9, 76,
+- 77, -81, -81, -81, -81, -81, 78, -81, -81, -81,
+- -81, -81, 35, 4, -81, -81, -81, -81, 86, -81,
+- -81, -81, 73, -81, -81, 33, 71, 84, 39, -81,
+- -81, -81, -81, -81, 41, -81, -81, -81, 25, -81,
+- 74, 25, 75, -81
++ 14, 27, 61, 14, 8, 18, -44, -44, 37, 8,
++ 40, 8, 64, -44, -44, -12, 37, -44, 50, 52,
++ -44, -44, -12, -12, -12, -44, 51, -44, -4, 78,
++ 53, 54, 55, 17, 2, 30, 38, -3, -44, 66,
++ -44, -44, 70, 72, 50, 50, -44, -44, -44, -44,
++ -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
++ -12, -12, -12, -12, -12, -12, -12, -12, -12, -44,
++ 3, 73, 50, -44, -44, 78, 59, 53, 54, 55,
++ 17, 2, 2, 30, 30, 30, 30, 38, 38, -3,
++ -3, -44, -44, -44, 82, 83, 44, 3, -44, 74,
++ 3, -44, -44, -12, 76, 79, -44, -44, -44, -44,
++ -44, 80, -44, -44, -44, -44, -44, -10, 36, -44,
++ -44, -44, -44, 85, -44, -44, -44, 75, -44, -44,
++ 21, 71, 88, -6, -44, -44, -44, -44, -44, 11,
++ -44, -44, -44, 37, -44, 77, 37, 81, -44
+ };
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+@@ -575,37 +581,37 @@ static const yytype_int8 yypact[] =
+ means the default is an error. */
+ static const yytype_uint8 yydefact[] =
+ {
+- 0, 0, 0, 3, 1, 0, 0, 0, 3, 34,
+- 35, 0, 0, 6, 0, 2, 4, 0, 0, 0,
+- 68, 0, 37, 38, 40, 42, 44, 46, 48, 50,
+- 53, 60, 63, 67, 0, 13, 7, 0, 0, 0,
+- 0, 69, 70, 71, 36, 0, 0, 0, 0, 0,
++ 0, 0, 0, 5, 7, 3, 1, 6, 0, 0,
++ 0, 7, 0, 38, 39, 0, 0, 10, 0, 2,
++ 8, 4, 0, 0, 0, 72, 0, 41, 42, 44,
++ 46, 48, 50, 52, 54, 57, 64, 67, 71, 0,
++ 17, 11, 0, 0, 0, 0, 73, 74, 75, 40,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 5, 75, 0, 0, 10, 8,
+- 41, 0, 43, 45, 47, 49, 51, 52, 56, 57,
+- 55, 54, 58, 59, 61, 62, 65, 64, 66, 0,
+- 0, 0, 0, 14, 0, 75, 11, 9, 0, 0,
+- 0, 16, 26, 78, 18, 80, 0, 77, 76, 39,
+- 17, 79, 0, 0, 12, 25, 15, 27, 0, 19,
+- 28, 22, 0, 72, 30, 0, 0, 0, 0, 33,
+- 32, 20, 31, 29, 0, 73, 74, 21, 0, 24,
+- 0, 0, 0, 23
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
++ 79, 0, 0, 14, 12, 45, 0, 47, 49, 51,
++ 53, 55, 56, 60, 61, 59, 58, 62, 63, 65,
++ 66, 69, 68, 70, 0, 0, 0, 0, 18, 0,
++ 79, 15, 13, 0, 0, 0, 20, 30, 82, 22,
++ 84, 0, 81, 80, 43, 21, 83, 0, 0, 16,
++ 29, 19, 31, 0, 23, 32, 26, 0, 76, 34,
++ 0, 0, 0, 0, 37, 36, 24, 35, 33, 0,
++ 77, 78, 25, 0, 28, 0, 0, 0, 27
+ };
+
+ /* YYPGOTO[NTERM-NUM]. */
+ static const yytype_int8 yypgoto[] =
+ {
+- -81, -81, 100, 104, -81, -38, -81, -80, -81, -81,
+- -81, -5, 66, 13, -81, 70, 67, 81, 64, 82,
+- 37, 27, 34, 38, -14, -81, 22, 24
++ -44, -44, -44, 103, 99, 104, -44, -43, -44, -21,
++ -44, -44, -44, -8, 63, 9, -44, 65, 67, 68,
++ 69, 62, 26, 4, 22, 23, -19, -44, 20, 28
+ };
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+ static const yytype_int16 yydefgoto[] =
+ {
+- -1, 2, 7, 8, 15, 36, 65, 93, 112, 113,
+- 125, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+- 29, 30, 31, 32, 33, 128, 94, 95
++ -1, 2, 3, 4, 10, 11, 19, 41, 70, 98,
++ 117, 118, 130, 25, 26, 27, 28, 29, 30, 31,
++ 32, 33, 34, 35, 36, 37, 38, 133, 99, 100
+ };
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+@@ -613,87 +619,87 @@ static const yytype_int16 yydefgoto[] =
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+ static const yytype_uint8 yytable[] =
+ {
+- 12, 68, 69, 41, 42, 43, 45, 34, 9, 10,
+- 53, 54, 104, 3, 5, 107, 101, 118, 35, 1,
+- 102, 4, 61, 11, 119, 120, 121, 122, 35, 97,
+- 46, 6, 55, 17, 123, 44, 18, 19, 56, 124,
+- 62, 63, 9, 10, 14, 51, 52, 86, 87, 88,
+- 9, 10, 48, 103, 129, 130, 115, 11, 135, 116,
+- 136, 47, 131, 57, 58, 11, 37, 49, 117, 50,
+- 137, 64, 38, 39, 138, 139, 40, 89, 90, 91,
+- 78, 79, 80, 81, 92, 59, 60, 66, 76, 77,
+- 67, 82, 83, 96, 98, 99, 100, 84, 85, 106,
+- 110, 111, 114, 126, 134, 127, 133, 141, 16, 143,
+- 13, 109, 71, 74, 72, 70, 105, 108, 0, 0,
+- 132, 0, 0, 0, 0, 0, 0, 0, 0, 73,
+- 0, 0, 75, 140, 0, 0, 142
++ 16, 73, 74, 46, 47, 48, 13, 14, 39, 50,
++ 58, 59, 120, 8, 140, 121, 141, 1, 94, 95,
++ 96, 15, 12, 66, 122, 97, 142, 56, 57, 102,
++ 9, 22, 60, 51, 23, 24, 62, 63, 61, 13,
++ 14, 67, 68, 134, 135, 143, 144, 91, 92, 93,
++ 123, 136, 5, 108, 15, 13, 14, 124, 125, 126,
++ 127, 6, 83, 84, 85, 86, 18, 128, 42, 106,
++ 15, 40, 129, 107, 43, 44, 109, 40, 45, 112,
++ 64, 65, 81, 82, 87, 88, 49, 89, 90, 21,
++ 52, 69, 53, 71, 54, 72, 55, 103, 101, 104,
++ 105, 115, 111, 131, 116, 119, 7, 138, 132, 139,
++ 20, 146, 114, 17, 76, 75, 148, 80, 0, 77,
++ 113, 78, 137, 79, 0, 110, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 145, 0, 0, 147
+ };
+
+ static const yytype_int16 yycheck[] =
+ {
+- 5, 39, 40, 17, 18, 19, 12, 12, 17, 18,
+- 7, 8, 92, 24, 4, 95, 24, 13, 26, 3,
+- 28, 0, 25, 32, 20, 21, 22, 23, 26, 67,
+- 36, 21, 29, 42, 30, 34, 45, 46, 35, 35,
+- 43, 44, 17, 18, 25, 9, 10, 61, 62, 63,
+- 17, 18, 38, 91, 21, 22, 21, 32, 19, 24,
+- 21, 11, 29, 5, 6, 32, 15, 39, 33, 40,
+- 31, 24, 21, 22, 33, 34, 25, 14, 15, 16,
+- 53, 54, 55, 56, 21, 41, 42, 22, 51, 52,
+- 22, 57, 58, 24, 37, 16, 16, 59, 60, 27,
+- 24, 24, 24, 17, 20, 32, 35, 33, 8, 34,
+- 6, 98, 46, 49, 47, 45, 92, 95, -1, -1,
+- 125, -1, -1, -1, -1, -1, -1, -1, -1, 48,
+- -1, -1, 50, 138, -1, -1, 141
++ 8, 44, 45, 22, 23, 24, 18, 19, 16, 13,
++ 8, 9, 22, 5, 20, 25, 22, 3, 15, 16,
++ 17, 33, 4, 26, 34, 22, 32, 10, 11, 72,
++ 22, 43, 30, 37, 46, 47, 6, 7, 36, 18,
++ 19, 44, 45, 22, 23, 34, 35, 66, 67, 68,
++ 14, 30, 25, 96, 33, 18, 19, 21, 22, 23,
++ 24, 0, 58, 59, 60, 61, 26, 31, 16, 25,
++ 33, 27, 36, 29, 22, 23, 97, 27, 26, 100,
++ 42, 43, 56, 57, 62, 63, 35, 64, 65, 25,
++ 12, 25, 39, 23, 40, 23, 41, 38, 25, 17,
++ 17, 25, 28, 18, 25, 25, 3, 36, 33, 21,
++ 11, 34, 103, 9, 51, 50, 35, 55, -1, 52,
++ 100, 53, 130, 54, -1, 97, -1, -1, -1, -1,
++ -1, -1, -1, -1, -1, 143, -1, -1, 146
+ };
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+ static const yytype_uint8 yystos[] =
+ {
+- 0, 3, 48, 24, 0, 4, 21, 49, 50, 17,
+- 18, 32, 58, 50, 25, 51, 49, 42, 45, 46,
+- 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+- 68, 69, 70, 71, 58, 26, 52, 15, 21, 22,
+- 25, 71, 71, 71, 34, 12, 36, 11, 38, 39,
+- 40, 9, 10, 7, 8, 29, 35, 5, 6, 41,
+- 42, 25, 43, 44, 24, 53, 22, 22, 52, 52,
+- 62, 59, 63, 64, 65, 66, 67, 67, 68, 68,
+- 68, 68, 69, 69, 70, 70, 71, 71, 71, 14,
+- 15, 16, 21, 54, 73, 74, 24, 52, 37, 16,
+- 16, 24, 28, 52, 54, 74, 27, 54, 73, 60,
+- 24, 24, 55, 56, 24, 21, 24, 33, 13, 20,
+- 21, 22, 23, 30, 35, 57, 17, 32, 72, 21,
+- 22, 29, 58, 35, 20, 19, 21, 31, 33, 34,
+- 58, 33, 58, 34
++ 0, 3, 49, 50, 51, 25, 0, 51, 5, 22,
++ 52, 53, 4, 18, 19, 33, 61, 53, 26, 54,
++ 52, 25, 43, 46, 47, 61, 62, 63, 64, 65,
++ 66, 67, 68, 69, 70, 71, 72, 73, 74, 61,
++ 27, 55, 16, 22, 23, 26, 74, 74, 74, 35,
++ 13, 37, 12, 39, 40, 41, 10, 11, 8, 9,
++ 30, 36, 6, 7, 42, 43, 26, 44, 45, 25,
++ 56, 23, 23, 55, 55, 65, 62, 66, 67, 68,
++ 69, 70, 70, 71, 71, 71, 71, 72, 72, 73,
++ 73, 74, 74, 74, 15, 16, 17, 22, 57, 76,
++ 77, 25, 55, 38, 17, 17, 25, 29, 55, 57,
++ 77, 28, 57, 76, 63, 25, 25, 58, 59, 25,
++ 22, 25, 34, 14, 21, 22, 23, 24, 31, 36,
++ 60, 18, 33, 75, 22, 23, 30, 61, 36, 21,
++ 20, 22, 32, 34, 35, 61, 34, 61, 35
+ };
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+ static const yytype_uint8 yyr1[] =
+ {
+- 0, 47, 48, 49, 49, 50, 50, 51, 51, 51,
+- 51, 51, 52, 53, 53, 54, 54, 54, 54, 55,
+- 55, 55, 55, 55, 55, 55, 56, 56, 56, 57,
+- 57, 57, 57, 57, 58, 58, 58, 59, 60, 60,
+- 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
+- 66, 66, 66, 67, 67, 67, 67, 67, 68, 68,
+- 68, 69, 69, 69, 70, 70, 70, 70, 71, 71,
+- 71, 71, 72, 72, 72, 73, 73, 73, 74, 74,
+- 74
++ 0, 48, 49, 50, 50, 51, 51, 52, 52, 53,
++ 53, 54, 54, 54, 54, 54, 55, 56, 56, 57,
++ 57, 57, 57, 58, 58, 58, 58, 58, 58, 58,
++ 59, 59, 59, 60, 60, 60, 60, 60, 61, 61,
++ 61, 62, 63, 63, 64, 64, 65, 65, 66, 66,
++ 67, 67, 68, 68, 69, 69, 69, 70, 70, 70,
++ 70, 70, 71, 71, 71, 72, 72, 72, 73, 73,
++ 73, 73, 74, 74, 74, 74, 75, 75, 75, 76,
++ 76, 76, 77, 77, 77
+ };
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+ static const yytype_uint8 yyr2[] =
+ {
+- 0, 2, 4, 0, 2, 4, 2, 2, 3, 4,
+- 3, 4, 5, 0, 2, 4, 2, 3, 2, 2,
+- 3, 4, 2, 9, 5, 2, 0, 2, 2, 3,
+- 1, 2, 2, 2, 1, 1, 3, 1, 1, 5,
+- 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+- 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
+- 1, 3, 3, 1, 3, 3, 3, 1, 1, 2,
+- 2, 2, 0, 2, 2, 0, 2, 2, 2, 3,
+- 2
++ 0, 2, 3, 2, 4, 1, 2, 0, 2, 4,
++ 2, 2, 3, 4, 3, 4, 5, 0, 2, 4,
++ 2, 3, 2, 2, 3, 4, 2, 9, 5, 2,
++ 0, 2, 2, 3, 1, 2, 2, 2, 1, 1,
++ 3, 1, 1, 5, 1, 3, 1, 3, 1, 3,
++ 1, 3, 1, 3, 1, 3, 3, 1, 3, 3,
++ 3, 3, 3, 3, 1, 3, 3, 1, 3, 3,
++ 3, 1, 1, 2, 2, 2, 0, 2, 2, 0,
++ 2, 2, 2, 3, 2
+ };
+
+
+@@ -1463,80 +1469,106 @@ yyreduce:
+ switch (yyn)
+ {
+ case 2:
+-#line 105 "dtc-parser.y" /* yacc.c:1646 */
++#line 110 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
+- guess_boot_cpuid((yyvsp[0].node)));
++ parser_output = build_dt_info((yyvsp[-2].flags), (yyvsp[-1].re), (yyvsp[0].node),
++ guess_boot_cpuid((yyvsp[0].node)));
+ }
+-#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1478 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 3:
+-#line 113 "dtc-parser.y" /* yacc.c:1646 */
++#line 118 "dtc-parser.y" /* yacc.c:1646 */
+ {
+- (yyval.re) = NULL;
++ (yyval.flags) = DTSF_V1;
+ }
+-#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1486 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+ case 4:
+-#line 117 "dtc-parser.y" /* yacc.c:1646 */
++#line 122 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ (yyval.flags) = DTSF_V1 | DTSF_PLUGIN;
++ }
++#line 1494 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
++
++ case 6:
++#line 130 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ if ((yyvsp[0].flags) != (yyvsp[-1].flags))
++ ERROR(&(yylsp[0]), "Header flags don't match earlier ones");
++ (yyval.flags) = (yyvsp[-1].flags);
++ }
++#line 1504 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
++
++ case 7:
++#line 139 "dtc-parser.y" /* yacc.c:1646 */
++ {
++ (yyval.re) = NULL;
++ }
++#line 1512 "dtc-parser.tab.c" /* yacc.c:1646 */
++ break;
++
++ case 8:
++#line 143 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
+ }
+-#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1520 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 5:
+-#line 124 "dtc-parser.y" /* yacc.c:1646 */
++ case 9:
++#line 150 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
+ }
+-#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1528 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 6:
+-#line 128 "dtc-parser.y" /* yacc.c:1646 */
++ case 10:
++#line 154 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
+ (yyval.re) = (yyvsp[0].re);
+ }
+-#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1537 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 7:
+-#line 136 "dtc-parser.y" /* yacc.c:1646 */
++ case 11:
++#line 162 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = name_node((yyvsp[0].node), "");
+ }
+-#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1545 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 8:
+-#line 140 "dtc-parser.y" /* yacc.c:1646 */
++ case 12:
++#line 166 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
+ }
+-#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1553 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 9:
+-#line 145 "dtc-parser.y" /* yacc.c:1646 */
++ case 13:
++#line 171 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
+
+- add_label(&target->labels, (yyvsp[-2].labelref));
+- if (target)
++ if (target) {
++ add_label(&target->labels, (yyvsp[-2].labelref));
+ merge_nodes(target, (yyvsp[0].node));
+- else
++ } else
+ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+ (yyval.node) = (yyvsp[-3].node);
+ }
+-#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1568 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 10:
+-#line 156 "dtc-parser.y" /* yacc.c:1646 */
++ case 14:
++#line 182 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
+
+@@ -1546,11 +1578,11 @@ yyreduce:
+ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
+ (yyval.node) = (yyvsp[-2].node);
+ }
+-#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 11:
+-#line 166 "dtc-parser.y" /* yacc.c:1646 */
++ case 15:
++#line 192 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
+
+@@ -1562,100 +1594,100 @@ yyreduce:
+
+ (yyval.node) = (yyvsp[-3].node);
+ }
+-#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 12:
+-#line 181 "dtc-parser.y" /* yacc.c:1646 */
++ case 16:
++#line 207 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
+ }
+-#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 13:
+-#line 188 "dtc-parser.y" /* yacc.c:1646 */
++ case 17:
++#line 214 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.proplist) = NULL;
+ }
+-#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 14:
+-#line 192 "dtc-parser.y" /* yacc.c:1646 */
++ case 18:
++#line 218 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
+ }
+-#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1622 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 15:
+-#line 199 "dtc-parser.y" /* yacc.c:1646 */
++ case 19:
++#line 225 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
+ }
+-#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1630 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 16:
+-#line 203 "dtc-parser.y" /* yacc.c:1646 */
++ case 20:
++#line 229 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
+ }
+-#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1638 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 17:
+-#line 207 "dtc-parser.y" /* yacc.c:1646 */
++ case 21:
++#line 233 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
+ }
+-#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1646 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 18:
+-#line 211 "dtc-parser.y" /* yacc.c:1646 */
++ case 22:
++#line 237 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
+ (yyval.prop) = (yyvsp[0].prop);
+ }
+-#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 19:
+-#line 219 "dtc-parser.y" /* yacc.c:1646 */
++ case 23:
++#line 245 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
+ }
+-#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1663 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 20:
+-#line 223 "dtc-parser.y" /* yacc.c:1646 */
++ case 24:
++#line 249 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
+ }
+-#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1671 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 21:
+-#line 227 "dtc-parser.y" /* yacc.c:1646 */
++ case 25:
++#line 253 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
+ }
+-#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1679 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 22:
+-#line 231 "dtc-parser.y" /* yacc.c:1646 */
++ case 26:
++#line 257 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
+ }
+-#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1687 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 23:
+-#line 235 "dtc-parser.y" /* yacc.c:1646 */
++ case 27:
++#line 261 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
+ struct data d;
+@@ -1671,11 +1703,11 @@ yyreduce:
+ (yyval.data) = data_merge((yyvsp[-8].data), d);
+ fclose(f);
+ }
+-#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1707 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 24:
+-#line 251 "dtc-parser.y" /* yacc.c:1646 */
++ case 28:
++#line 277 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
+ struct data d = empty_data;
+@@ -1685,43 +1717,43 @@ yyreduce:
+ (yyval.data) = data_merge((yyvsp[-4].data), d);
+ fclose(f);
+ }
+-#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 25:
+-#line 261 "dtc-parser.y" /* yacc.c:1646 */
++ case 29:
++#line 287 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
+-#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1729 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 26:
+-#line 268 "dtc-parser.y" /* yacc.c:1646 */
++ case 30:
++#line 294 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = empty_data;
+ }
+-#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1737 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 27:
+-#line 272 "dtc-parser.y" /* yacc.c:1646 */
++ case 31:
++#line 298 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = (yyvsp[-1].data);
+ }
+-#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1745 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 28:
+-#line 276 "dtc-parser.y" /* yacc.c:1646 */
++ case 32:
++#line 302 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
+-#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1753 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 29:
+-#line 283 "dtc-parser.y" /* yacc.c:1646 */
++ case 33:
++#line 309 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ unsigned long long bits;
+
+@@ -1737,20 +1769,20 @@ yyreduce:
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = bits;
+ }
+-#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 30:
+-#line 299 "dtc-parser.y" /* yacc.c:1646 */
++ case 34:
++#line 325 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.array).data = empty_data;
+ (yyval.array).bits = 32;
+ }
+-#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1782 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 31:
+-#line 304 "dtc-parser.y" /* yacc.c:1646 */
++ case 35:
++#line 330 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ if ((yyvsp[-1].array).bits < 64) {
+ uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
+@@ -1769,11 +1801,11 @@ yyreduce:
+
+ (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
+ }
+-#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1805 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 32:
+-#line 323 "dtc-parser.y" /* yacc.c:1646 */
++ case 36:
++#line 349 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
+
+@@ -1787,129 +1819,129 @@ yyreduce:
+
+ (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
+ }
+-#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1823 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 33:
+-#line 337 "dtc-parser.y" /* yacc.c:1646 */
++ case 37:
++#line 363 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
+ }
+-#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 36:
+-#line 346 "dtc-parser.y" /* yacc.c:1646 */
++ case 40:
++#line 372 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.integer) = (yyvsp[-1].integer);
+ }
+-#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1839 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 39:
+-#line 357 "dtc-parser.y" /* yacc.c:1646 */
++ case 43:
++#line 383 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
+-#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1845 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 41:
+-#line 362 "dtc-parser.y" /* yacc.c:1646 */
++ case 45:
++#line 388 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
+-#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1851 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 43:
+-#line 367 "dtc-parser.y" /* yacc.c:1646 */
++ case 47:
++#line 393 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
+-#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1857 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 45:
+-#line 372 "dtc-parser.y" /* yacc.c:1646 */
++ case 49:
++#line 398 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
+-#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1863 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 47:
+-#line 377 "dtc-parser.y" /* yacc.c:1646 */
++ case 51:
++#line 403 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
+-#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1869 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 49:
+-#line 382 "dtc-parser.y" /* yacc.c:1646 */
++ case 53:
++#line 408 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
+-#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1875 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 51:
+-#line 387 "dtc-parser.y" /* yacc.c:1646 */
++ case 55:
++#line 413 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
+-#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1881 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 52:
+-#line 388 "dtc-parser.y" /* yacc.c:1646 */
++ case 56:
++#line 414 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
+-#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1887 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 54:
+-#line 393 "dtc-parser.y" /* yacc.c:1646 */
++ case 58:
++#line 419 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
+-#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1893 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 55:
+-#line 394 "dtc-parser.y" /* yacc.c:1646 */
++ case 59:
++#line 420 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
+-#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1899 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 56:
+-#line 395 "dtc-parser.y" /* yacc.c:1646 */
++ case 60:
++#line 421 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
+-#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1905 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 57:
+-#line 396 "dtc-parser.y" /* yacc.c:1646 */
++ case 61:
++#line 422 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
+-#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1911 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 58:
+-#line 400 "dtc-parser.y" /* yacc.c:1646 */
++ case 62:
++#line 426 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
+-#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1917 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 59:
+-#line 401 "dtc-parser.y" /* yacc.c:1646 */
++ case 63:
++#line 427 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
+-#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1923 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 61:
+-#line 406 "dtc-parser.y" /* yacc.c:1646 */
++ case 65:
++#line 432 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
+-#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1929 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 62:
+-#line 407 "dtc-parser.y" /* yacc.c:1646 */
++ case 66:
++#line 433 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
+-#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 64:
+-#line 412 "dtc-parser.y" /* yacc.c:1646 */
++ case 68:
++#line 438 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
+-#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 65:
+-#line 414 "dtc-parser.y" /* yacc.c:1646 */
++ case 69:
++#line 440 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ if ((yyvsp[0].integer) != 0) {
+ (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer);
+@@ -1918,11 +1950,11 @@ yyreduce:
+ (yyval.integer) = 0;
+ }
+ }
+-#line 1922 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1954 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 66:
+-#line 423 "dtc-parser.y" /* yacc.c:1646 */
++ case 70:
++#line 449 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ if ((yyvsp[0].integer) != 0) {
+ (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer);
+@@ -1931,103 +1963,103 @@ yyreduce:
+ (yyval.integer) = 0;
+ }
+ }
+-#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1967 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 69:
+-#line 436 "dtc-parser.y" /* yacc.c:1646 */
++ case 73:
++#line 462 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = -(yyvsp[0].integer); }
+-#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1973 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 70:
+-#line 437 "dtc-parser.y" /* yacc.c:1646 */
++ case 74:
++#line 463 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = ~(yyvsp[0].integer); }
+-#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 71:
+-#line 438 "dtc-parser.y" /* yacc.c:1646 */
++ case 75:
++#line 464 "dtc-parser.y" /* yacc.c:1646 */
+ { (yyval.integer) = !(yyvsp[0].integer); }
+-#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 72:
+-#line 443 "dtc-parser.y" /* yacc.c:1646 */
++ case 76:
++#line 469 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = empty_data;
+ }
+-#line 1961 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 73:
+-#line 447 "dtc-parser.y" /* yacc.c:1646 */
++ case 77:
++#line 473 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
+ }
+-#line 1969 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2001 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 74:
+-#line 451 "dtc-parser.y" /* yacc.c:1646 */
++ case 78:
++#line 477 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
+ }
+-#line 1977 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2009 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 75:
+-#line 458 "dtc-parser.y" /* yacc.c:1646 */
++ case 79:
++#line 484 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.nodelist) = NULL;
+ }
+-#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 76:
+-#line 462 "dtc-parser.y" /* yacc.c:1646 */
++ case 80:
++#line 488 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
+ }
+-#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2025 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 77:
+-#line 466 "dtc-parser.y" /* yacc.c:1646 */
++ case 81:
++#line 492 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ ERROR(&(yylsp[0]), "Properties must precede subnodes");
+ YYERROR;
+ }
+-#line 2002 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2034 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 78:
+-#line 474 "dtc-parser.y" /* yacc.c:1646 */
++ case 82:
++#line 500 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
+ }
+-#line 2010 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2042 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 79:
+-#line 478 "dtc-parser.y" /* yacc.c:1646 */
++ case 83:
++#line 504 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
+ }
+-#line 2018 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2050 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+- case 80:
+-#line 482 "dtc-parser.y" /* yacc.c:1646 */
++ case 84:
++#line 508 "dtc-parser.y" /* yacc.c:1646 */
+ {
+ add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
+ (yyval.node) = (yyvsp[0].node);
+ }
+-#line 2027 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2059 "dtc-parser.tab.c" /* yacc.c:1646 */
+ break;
+
+
+-#line 2031 "dtc-parser.tab.c" /* yacc.c:1646 */
++#line 2063 "dtc-parser.tab.c" /* yacc.c:1646 */
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+@@ -2262,7 +2294,7 @@ yyreturn:
+ #endif
+ return yyresult;
+ }
+-#line 488 "dtc-parser.y" /* yacc.c:1906 */
++#line 514 "dtc-parser.y" /* yacc.c:1906 */
+
+
+ void yyerror(char const *s)
+diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped
+index 30867c6..6aa512c 100644
+--- a/scripts/dtc/dtc-parser.tab.h_shipped
++++ b/scripts/dtc/dtc-parser.tab.h_shipped
+@@ -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
+
+- 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
+ it under the terms of the GNU General Public License as published by
+@@ -46,35 +46,36 @@ extern int yydebug;
+ enum yytokentype
+ {
+ DT_V1 = 258,
+- DT_MEMRESERVE = 259,
+- DT_LSHIFT = 260,
+- DT_RSHIFT = 261,
+- DT_LE = 262,
+- DT_GE = 263,
+- DT_EQ = 264,
+- DT_NE = 265,
+- DT_AND = 266,
+- DT_OR = 267,
+- DT_BITS = 268,
+- DT_DEL_PROP = 269,
+- DT_DEL_NODE = 270,
+- DT_PROPNODENAME = 271,
+- DT_LITERAL = 272,
+- DT_CHAR_LITERAL = 273,
+- DT_BYTE = 274,
+- DT_STRING = 275,
+- DT_LABEL = 276,
+- DT_REF = 277,
+- DT_INCBIN = 278
++ DT_PLUGIN = 259,
++ DT_MEMRESERVE = 260,
++ DT_LSHIFT = 261,
++ DT_RSHIFT = 262,
++ DT_LE = 263,
++ DT_GE = 264,
++ DT_EQ = 265,
++ DT_NE = 266,
++ DT_AND = 267,
++ DT_OR = 268,
++ DT_BITS = 269,
++ DT_DEL_PROP = 270,
++ DT_DEL_NODE = 271,
++ DT_PROPNODENAME = 272,
++ DT_LITERAL = 273,
++ DT_CHAR_LITERAL = 274,
++ DT_BYTE = 275,
++ DT_STRING = 276,
++ DT_LABEL = 277,
++ DT_REF = 278,
++ DT_INCBIN = 279
+ };
+ #endif
+
+ /* Value type. */
+ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+-typedef union YYSTYPE YYSTYPE;
++
+ union YYSTYPE
+ {
+-#line 38 "dtc-parser.y" /* yacc.c:1909 */
++#line 39 "dtc-parser.y" /* yacc.c:1909 */
+
+ char *propnodename;
+ char *labelref;
+@@ -92,9 +93,12 @@ union YYSTYPE
+ struct node *nodelist;
+ struct reserve_info *re;
+ 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_DECLARED 1
+ #endif
+diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
+index 000873f..ca3f500 100644
+--- a/scripts/dtc/dtc-parser.y
++++ b/scripts/dtc/dtc-parser.y
+@@ -19,6 +19,7 @@
+ */
+ %{
+ #include <stdio.h>
++#include <inttypes.h>
+
+ #include "dtc.h"
+ #include "srcpos.h"
+@@ -31,7 +32,7 @@ extern void yyerror(char const *s);
+ treesource_error = true; \
+ } while (0)
+
+-extern struct boot_info *the_boot_info;
++extern struct dt_info *parser_output;
+ extern bool treesource_error;
+ %}
+
+@@ -52,9 +53,11 @@ extern bool treesource_error;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
++ unsigned int flags;
+ }
+
+ %token DT_V1
++%token DT_PLUGIN
+ %token DT_MEMRESERVE
+ %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
+ %token DT_BITS
+@@ -71,6 +74,8 @@ extern bool treesource_error;
+
+ %type <data> propdata
+ %type <data> propdataprefix
++%type <flags> header
++%type <flags> headers
+ %type <re> memreserve
+ %type <re> memreserves
+ %type <array> arrayprefix
+@@ -101,10 +106,31 @@ extern bool treesource_error;
+ %%
+
+ sourcefile:
+- DT_V1 ';' memreserves devicetree
++ headers memreserves devicetree
+ {
+- the_boot_info = build_boot_info($3, $4,
+- guess_boot_cpuid($4));
++ parser_output = build_dt_info($1, $2, $3,
++ 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;
+ }
+ ;
+
+@@ -145,10 +171,10 @@ devicetree:
+ {
+ struct node *target = get_node_by_ref($1, $3);
+
+- add_label(&target->labels, $2);
+- if (target)
++ if (target) {
++ add_label(&target->labels, $2);
+ merge_nodes(target, $4);
+- else
++ } else
+ ERROR(&@3, "Label or path %s not found", $3);
+ $$ = $1;
+ }
+diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
+index 5fa23c4..f5eed9d 100644
+--- a/scripts/dtc/dtc.c
++++ b/scripts/dtc/dtc.c
+@@ -30,7 +30,16 @@ int quiet; /* Level of quietness */
+ int reservenum; /* Number of memory reservation slots */
+ int minsize; /* Minimum blob size */
+ 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 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)
+ {
+@@ -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) #version
+ 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[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+@@ -64,6 +73,7 @@ static struct option const usage_long_opts[] = {
+ {"reserve", a_argument, NULL, 'R'},
+ {"space", a_argument, NULL, 'S'},
+ {"pad", a_argument, NULL, 'p'},
++ {"align", a_argument, NULL, 'a'},
+ {"boot-cpu", a_argument, NULL, 'b'},
+ {"force", no_argument, NULL, 'f'},
+ {"include", a_argument, NULL, 'i'},
+@@ -71,6 +81,8 @@ static struct option const usage_long_opts[] = {
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
++ {"symbols", no_argument, NULL, '@'},
++ {"auto-alias", no_argument, NULL, 'A'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {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 the blob at least <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\tTry to produce output even if the input tree has errors",
+ "\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",
+ "\n\tEnable/disable warnings (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 version and exit",
+ NULL,
+@@ -123,7 +138,7 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
+ static const char *guess_input_format(const char *fname, const char *fallback)
+ {
+ struct stat statbuf;
+- uint32_t magic;
++ fdt32_t magic;
+ FILE *f;
+
+ if (stat(fname, &statbuf) != 0)
+@@ -144,8 +159,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
+ }
+ fclose(f);
+
+- magic = fdt32_to_cpu(magic);
+- if (magic == FDT_MAGIC)
++ if (fdt32_to_cpu(magic) == FDT_MAGIC)
+ return "dtb";
+
+ return guess_type_by_name(fname, fallback);
+@@ -153,7 +167,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
+
+ int main(int argc, char *argv[])
+ {
+- struct boot_info *bi;
++ struct dt_info *dti;
+ const char *inform = NULL;
+ const char *outform = NULL;
+ const char *outname = "-";
+@@ -169,6 +183,7 @@ int main(int argc, char *argv[])
+ reservenum = 0;
+ minsize = 0;
+ padsize = 0;
++ alignsize = 0;
+
+ while ((opt = util_getopt_long()) != EOF) {
+ switch (opt) {
+@@ -196,6 +211,12 @@ int main(int argc, char *argv[])
+ case 'p':
+ padsize = strtol(optarg, NULL, 0);
+ break;
++ case 'a':
++ alignsize = strtol(optarg, NULL, 0);
++ if (!is_power_of_2(alignsize))
++ die("Invalid argument \"%d\" to -a option\n",
++ alignsize);
++ break;
+ case 'f':
+ force = true;
+ break;
+@@ -234,6 +255,13 @@ int main(int argc, char *argv[])
+ parse_checks_option(false, true, optarg);
+ break;
+
++ case '@':
++ generate_symbols = 1;
++ break;
++ case 'A':
++ auto_label_aliases = 1;
++ break;
++
+ case 'h':
+ usage(NULL);
+ default:
+@@ -272,27 +300,45 @@ int main(int argc, char *argv[])
+ }
+ }
+ if (streq(inform, "dts"))
+- bi = dt_from_source(arg);
++ dti = dt_from_source(arg);
+ else if (streq(inform, "fs"))
+- bi = dt_from_fs(arg);
++ dti = dt_from_fs(arg);
+ else if(streq(inform, "dtb"))
+- bi = dt_from_blob(arg);
++ dti = dt_from_blob(arg);
+ else
+ die("Unknown input format \"%s\"\n", inform);
+
++ dti->outname = outname;
++
+ if (depfile) {
+ fputc('\n', depfile);
+ fclose(depfile);
+ }
+
+ if (cmdline_boot_cpuid != -1)
+- bi->boot_cpuid_phys = cmdline_boot_cpuid;
++ dti->boot_cpuid_phys = cmdline_boot_cpuid;
++
++ fill_fullpaths(dti->dt, "");
++ process_checks(force, dti);
++
++ /* on a plugin, generate by default */
++ if (dti->dtsflags & DTSF_PLUGIN) {
++ generate_fixups = 1;
++ }
+
+- fill_fullpaths(bi->dt, "");
+- process_checks(force, bi);
++ 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)
+- sort_tree(bi);
++ sort_tree(dti);
+
+ if (streq(outname, "-")) {
+ outf = stdout;
+@@ -304,11 +350,11 @@ int main(int argc, char *argv[])
+ }
+
+ if (streq(outform, "dts")) {
+- dt_to_source(outf, bi);
++ dt_to_source(outf, dti);
+ } else if (streq(outform, "dtb")) {
+- dt_to_blob(outf, bi, outversion);
++ dt_to_blob(outf, dti, outversion);
+ } else if (streq(outform, "asm")) {
+- dt_to_asm(outf, bi, outversion);
++ dt_to_asm(outf, dti, outversion);
+ } else if (streq(outform, "null")) {
+ /* do nothing */
+ } else {
+diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
+index 56212c8..403b79d 100644
+--- a/scripts/dtc/dtc.h
++++ b/scripts/dtc/dtc.h
+@@ -43,7 +43,6 @@
+ #define debug(...)
+ #endif
+
+-
+ #define DEFAULT_FDT_VERSION 17
+
+ /*
+@@ -53,7 +52,11 @@ extern int quiet; /* Level of quietness */
+ extern int reservenum; /* Number of memory reservation slots */
+ extern int minsize; /* Minimum blob size */
+ 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 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_EPAPR 0x2
+@@ -110,7 +113,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
+ struct data data_merge(struct data d1, struct data d2);
+ struct data data_append_cell(struct data d, cell_t word);
+ struct data data_append_integer(struct data d, uint64_t word, int bits);
+-struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
++struct data data_append_re(struct data d, uint64_t address, uint64_t size);
+ struct data data_append_addr(struct data d, uint64_t addr);
+ struct data data_append_byte(struct data d, uint8_t byte);
+ struct data data_append_zeroes(struct data d, int len);
+@@ -201,6 +204,8 @@ void delete_property(struct property *prop);
+ void add_child(struct node *parent, struct node *child);
+ void delete_node_by_name(struct node *parent, char *name);
+ 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);
+ struct property *get_property(struct node *node, const char *propname);
+@@ -221,7 +226,7 @@ uint32_t guess_boot_cpuid(struct node *tree);
+ /* Boot info (tree plus memreserve information */
+
+ struct reserve_info {
+- struct fdt_reserve_entry re;
++ uint64_t address, size;
+
+ struct reserve_info *next;
+
+@@ -235,35 +240,45 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
+ struct reserve_info *new);
+
+
+-struct boot_info {
++struct dt_info {
++ unsigned int dtsflags;
+ struct reserve_info *reservelist;
+- struct node *dt; /* the device tree */
+ uint32_t boot_cpuid_phys;
++ struct node *dt; /* the device tree */
++ const char *outname; /* filename being written to, "-" for stdout */
+ };
+
+-struct boot_info *build_boot_info(struct reserve_info *reservelist,
+- struct node *tree, uint32_t boot_cpuid_phys);
+-void sort_tree(struct boot_info *bi);
++/* DTS version flags definitions */
++#define DTSF_V1 0x0001 /* /dts-v1/ */
++#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 */
+
+ 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 */
+
+-void dt_to_blob(FILE *f, struct boot_info *bi, int version);
+-void dt_to_asm(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 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 */
+
+-void dt_to_source(FILE *f, struct boot_info *bi);
+-struct boot_info *dt_from_source(const char *f);
++void dt_to_source(FILE *f, struct dt_info *dti);
++struct dt_info *dt_from_source(const char *f);
+
+ /* FS trees */
+
+-struct boot_info *dt_from_fs(const char *dirname);
++struct dt_info *dt_from_fs(const char *dirname);
+
+ #endif /* _DTC_H */
+diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
+index ec14954..fcf7154 100644
+--- a/scripts/dtc/flattree.c
++++ b/scripts/dtc/flattree.c
+@@ -49,7 +49,7 @@ static struct version_info {
+
+ struct emitter {
+ void (*cell)(void *, cell_t);
+- void (*string)(void *, char *, int);
++ void (*string)(void *, const char *, int);
+ void (*align)(void *, int);
+ void (*data)(void *, struct data);
+ void (*beginnode)(void *, struct label *labels);
+@@ -64,7 +64,7 @@ static void bin_emit_cell(void *e, cell_t val)
+ *dtbuf = data_append_cell(*dtbuf, val);
+ }
+
+-static void bin_emit_string(void *e, char *str, int len)
++static void bin_emit_string(void *e, const char *str, int len)
+ {
+ struct data *dtbuf = e;
+
+@@ -144,22 +144,14 @@ static void asm_emit_cell(void *e, cell_t val)
+ (val >> 8) & 0xff, val & 0xff);
+ }
+
+-static void asm_emit_string(void *e, char *str, int len)
++static void asm_emit_string(void *e, const char *str, int len)
+ {
+ FILE *f = e;
+- char c = 0;
+
+- if (len != 0) {
+- /* XXX: ewww */
+- c = str[len];
+- str[len] = '\0';
+- }
+-
+- fprintf(f, "\t.string\t\"%s\"\n", str);
+-
+- if (len != 0) {
+- str[len] = c;
+- }
++ if (len != 0)
++ fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
++ else
++ fprintf(f, "\t.string\t\"%s\"\n", str);
+ }
+
+ static void asm_emit_align(void *e, int a)
+@@ -179,7 +171,7 @@ static void asm_emit_data(void *e, struct data d)
+ emit_offset_label(f, m->ref, m->offset);
+
+ while ((d.len - off) >= sizeof(uint32_t)) {
+- asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
++ asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
+ off += sizeof(uint32_t);
+ }
+
+@@ -318,17 +310,16 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
+ {
+ struct reserve_info *re;
+ struct data d = empty_data;
+- static struct fdt_reserve_entry null_re = {0,0};
+ int j;
+
+ for (re = reservelist; re; re = re->next) {
+- d = data_append_re(d, &re->re);
++ d = data_append_re(d, re->address, re->size);
+ }
+ /*
+ * Add additional reserved slots if the user asked for them.
+ */
+ for (j = 0; j < reservenum; j++) {
+- d = data_append_re(d, &null_re);
++ d = data_append_re(d, 0, 0);
+ }
+
+ return d;
+@@ -366,7 +357,7 @@ static void make_fdt_header(struct fdt_header *fdt,
+ 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;
+ int i;
+@@ -384,29 +375,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
+ if (!vi)
+ 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);
+
+- reservebuf = flatten_reserve_list(bi->reservelist, vi);
++ reservebuf = flatten_reserve_list(dti->reservelist, vi);
+
+ /* Make header */
+ 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 (minsize > 0) {
+ padlen = minsize - fdt32_to_cpu(fdt.totalsize);
+- if ((padlen < 0) && (quiet < 1))
+- fprintf(stderr,
+- "Warning: blob size %d >= minimum size %d\n",
+- fdt32_to_cpu(fdt.totalsize), minsize);
++ if (padlen < 0) {
++ padlen = 0;
++ if (quiet < 1)
++ fprintf(stderr,
++ "Warning: blob size %d >= minimum size %d\n",
++ fdt32_to_cpu(fdt.totalsize), minsize);
++ }
+ }
+
+ if (padsize > 0)
+ padlen = padsize;
+
++ if (alignsize > 0)
++ padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
++ - fdt32_to_cpu(fdt.totalsize);
++
+ if (padlen > 0) {
+ int tsize = fdt32_to_cpu(fdt.totalsize);
+ tsize += padlen;
+@@ -460,7 +458,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;
+ int i;
+@@ -500,7 +498,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+
+ if (vi->flags & FTF_BOOTCPUID) {
+ 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) {
+@@ -530,18 +528,18 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+ * Use .long on high and low halfs of u64s to avoid .quad
+ * 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;
+
+ for_each_label(re->labels, l) {
+ fprintf(f, "\t.globl\t%s\n", l->label);
+ fprintf(f, "%s:\n", l->label);
+ }
+- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
++ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->address >> 32));
+ ASM_EMIT_BELONG(f, "0x%08x",
+- (unsigned int)(re->re.address & 0xffffffff));
+- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
+- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
++ (unsigned int)(re->address & 0xffffffff));
++ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32));
++ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff));
+ }
+ for (i = 0; i < reservenum; i++) {
+ fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
+@@ -550,7 +548,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");
+
+ 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");
+ asm_emit_cell(f, FDT_END);
+@@ -572,6 +570,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+ if (padsize > 0) {
+ fprintf(f, "\t.space\t%d, 0\n", padsize);
+ }
++ if (alignsize > 0)
++ asm_emit_align(f, alignsize);
+ emit_label(f, symprefix, "blob_abs_end");
+
+ data_free(strbuf);
+@@ -600,7 +600,7 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
+
+ static uint32_t flat_read_word(struct inbuf *inb)
+ {
+- uint32_t val;
++ fdt32_t val;
+
+ assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
+
+@@ -709,13 +709,15 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
+ * First pass, count entries.
+ */
+ while (1) {
++ uint64_t address, size;
++
+ flat_read_chunk(inb, &re, sizeof(re));
+- re.address = fdt64_to_cpu(re.address);
+- re.size = fdt64_to_cpu(re.size);
+- if (re.size == 0)
++ address = fdt64_to_cpu(re.address);
++ size = fdt64_to_cpu(re.size);
++ if (size == 0)
+ break;
+
+- new = build_reserve_entry(re.address, re.size);
++ new = build_reserve_entry(address, size);
+ reservelist = add_reserve_entry(reservelist, new);
+ }
+
+@@ -797,13 +799,18 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
+ }
+ } while (val != FDT_END_NODE);
+
++ if (node->name != flatname) {
++ free(flatname);
++ }
++
+ return node;
+ }
+
+
+-struct boot_info *dt_from_blob(const char *fname)
++struct dt_info *dt_from_blob(const char *fname)
+ {
+ FILE *f;
++ fdt32_t magic_buf, totalsize_buf;
+ uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
+ uint32_t off_dt, off_str, off_mem_rsvmap;
+ int rc;
+@@ -820,7 +827,7 @@ struct boot_info *dt_from_blob(const char *fname)
+
+ f = srcfile_relative_open(fname, NULL);
+
+- rc = fread(&magic, sizeof(magic), 1, f);
++ rc = fread(&magic_buf, sizeof(magic_buf), 1, f);
+ if (ferror(f))
+ die("Error reading DT blob magic number: %s\n",
+ strerror(errno));
+@@ -831,11 +838,11 @@ struct boot_info *dt_from_blob(const char *fname)
+ die("Mysterious short read reading magic number\n");
+ }
+
+- magic = fdt32_to_cpu(magic);
++ magic = fdt32_to_cpu(magic_buf);
+ if (magic != FDT_MAGIC)
+ die("Blob has incorrect magic number\n");
+
+- rc = fread(&totalsize, sizeof(totalsize), 1, f);
++ rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f);
+ if (ferror(f))
+ die("Error reading DT blob size: %s\n", strerror(errno));
+ if (rc < 1) {
+@@ -845,7 +852,7 @@ struct boot_info *dt_from_blob(const char *fname)
+ die("Mysterious short read reading blob size\n");
+ }
+
+- totalsize = fdt32_to_cpu(totalsize);
++ totalsize = fdt32_to_cpu(totalsize_buf);
+ if (totalsize < FDT_V1_SIZE)
+ die("DT blob size (%d) is too small\n", totalsize);
+
+@@ -929,5 +936,5 @@ struct boot_info *dt_from_blob(const char *fname)
+
+ fclose(f);
+
+- return build_boot_info(reservelist, tree, boot_cpuid_phys);
++ return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
+ }
+diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c
+index 6d1beec..ae7d06c 100644
+--- a/scripts/dtc/fstree.c
++++ b/scripts/dtc/fstree.c
+@@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname)
+ return tree;
+ }
+
+-struct boot_info *dt_from_fs(const char *dirname)
++struct dt_info *dt_from_fs(const char *dirname)
+ {
+ struct node *tree;
+
+ tree = read_fstree(dirname);
+ 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));
+ }
+-
+diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt
+index 09c322e..098b3f3 100644
+--- a/scripts/dtc/libfdt/Makefile.libfdt
++++ b/scripts/dtc/libfdt/Makefile.libfdt
+@@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
+ LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
+ 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 \
+- fdt_addresses.c
++ fdt_addresses.c fdt_overlay.c
+ LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
+index 50cce86..3d00d2e 100644
+--- a/scripts/dtc/libfdt/fdt_ro.c
++++ b/scripts/dtc/libfdt/fdt_ro.c
+@@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset,
+ 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)
+ {
+ 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);
+ if (!list)
+- return -length;
++ return 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);
+ if (!list)
+- return -length;
++ return length;
+
+ len = strlen(string) + 1;
+ end = list + length;
+diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
+index 8be02b1..3fd5847 100644
+--- a/scripts/dtc/libfdt/fdt_rw.c
++++ b/scripts/dtc/libfdt/fdt_rw.c
+@@ -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)
+ {
+ struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+- int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+- err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+- if (err)
+- return err;
+- return 0;
++ return _fdt_splice_mem_rsv(fdt, re, 1, 0);
+ }
+
+ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+@@ -287,7 +283,8 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ if (err)
+ return err;
+
+- memcpy(prop->data, val, len);
++ if (len)
++ memcpy(prop->data, val, len);
+ return 0;
+ }
+
+diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c
+index e6c3cee..9677a18 100644
+--- a/scripts/dtc/libfdt/fdt_strerror.c
++++ b/scripts/dtc/libfdt/fdt_strerror.c
+@@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = {
+
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
++ FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+@@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ 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]))
+
+diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c
+index c5bbb68..6aaab39 100644
+--- a/scripts/dtc/libfdt/fdt_wip.c
++++ b/scripts/dtc/libfdt/fdt_wip.c
+@@ -55,21 +55,42 @@
+
+ #include "libfdt_internal.h"
+
++int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
++ const char *name, int namelen,
++ uint32_t idx, const void *val,
++ int len)
++{
++ void *propval;
++ int 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)
+ {
+- void *propval;
++ const void *propval;
+ int proplen;
+
+- propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
++ propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+- memcpy(propval, val, len);
+- return 0;
++ return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
++ strlen(name), 0,
++ val, len);
+ }
+
+ static void _fdt_nop_region(void *start, int len)
+diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
+index 59ca339..9e71bb9 100644
+--- a/scripts/dtc/libfdt/libfdt.h
++++ b/scripts/dtc/libfdt/libfdt.h
+@@ -61,7 +61,7 @@
+ #define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+ #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 */
+ #define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+@@ -79,8 +79,10 @@
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+ #define FDT_ERR_BADPHANDLE 6
+- /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+- * value. phandle values of 0 and -1 are not permitted. */
++ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
++ * 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
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+@@ -126,7 +128,16 @@
+ * value. For example: a property expected to contain a string list
+ * 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) */
+@@ -168,27 +179,55 @@ int fdt_first_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 */
+ /**********************************************************************/
+
+ #define fdt_get_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_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_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+ #define fdt_version(fdt) (fdt_get_header(fdt, 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_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
++#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_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_set_hdr(name) \
+ 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); \
+ }
+ __fdt_set_hdr(magic);
+@@ -259,6 +298,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
+ 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: pointer to the device tree blob
+ *
+@@ -318,8 +372,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -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_BADMAGIC,
++ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
++ * tag
++ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+@@ -351,7 +406,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+ * address).
+ *
+ * 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_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+@@ -375,10 +431,12 @@ int fdt_path_offset(const void *fdt, const char *path);
+ *
+ * returns:
+ * 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
+ * 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_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+@@ -427,6 +485,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset);
+ 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: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+@@ -490,7 +575,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -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_BADVERSION,
+ * -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 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
+@@ -575,7 +668,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -617,7 +711,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
+ 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
+ * @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
+ * buf contains the absolute path of the node at
+ * 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)
+ * characters and will not fit in the given buffer.
+ * -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.
+ *
+ * returns:
+-
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+- * -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_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
++ * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
++ * nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -703,7 +797,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ *
+ * returns:
+ * 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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -726,7 +820,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
+ * returns:
+ * structure block offset of the parent 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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -766,7 +860,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset);
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * 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_BADVERSION,
+ * -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
+ * the given string
+ * -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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -850,7 +944,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * 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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -960,7 +1054,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+ * returns:
+ * 0 <= n < FDT_MAX_NCELLS, on success
+ * 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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -980,7 +1075,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
+ * returns:
+ * 0 <= n < FDT_MAX_NCELLS, on success
+ * 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_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+@@ -995,6 +1091,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
+ /**********************************************************************/
+
+ /**
++ * 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: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+@@ -1410,6 +1527,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ #define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
++
++/**
++ * fdt_setprop_empty - set a property to an empty value
++ * @fdt: pointer to the device tree blob
++ * @nodeoffset: offset of the node whose property to change
++ * @name: name of the property to change
++ *
++ * fdt_setprop_empty() sets the value of the named property in the
++ * given node to an empty (zero length) value, or creates a new empty
++ * property if it does not already exist.
++ *
++ * This function may insert or delete data from the blob, and will
++ * therefore change the offsets of some existing nodes.
++ *
++ * returns:
++ * 0, on success
++ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
++ * contain the new property value
++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
++ * -FDT_ERR_BADLAYOUT,
++ * -FDT_ERR_BADMAGIC,
++ * -FDT_ERR_BADVERSION,
++ * -FDT_ERR_BADSTATE,
++ * -FDT_ERR_BADSTRUCTURE,
++ * -FDT_ERR_BADLAYOUT,
++ * -FDT_ERR_TRUNCATED, standard meanings
++ */
++#define fdt_setprop_empty(fdt, nodeoffset, name) \
++ fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
++
+ /**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+@@ -1604,9 +1751,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ * change the offsets of some existing nodes.
+
+ * 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_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
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+@@ -1644,6 +1793,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+ */
+ 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 */
+ /**********************************************************************/
+diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h
+index 9dea97d..952056c 100644
+--- a/scripts/dtc/libfdt/libfdt_env.h
++++ b/scripts/dtc/libfdt/libfdt_env.h
+@@ -54,19 +54,20 @@
+
+ #include <stddef.h>
+ #include <stdint.h>
++#include <stdlib.h>
+ #include <string.h>
+
+ #ifdef __CHECKER__
+-#define __force __attribute__((force))
+-#define __bitwise __attribute__((bitwise))
++#define FDT_FORCE __attribute__((force))
++#define FDT_BITWISE __attribute__((bitwise))
+ #else
+-#define __force
+-#define __bitwise
++#define FDT_FORCE
++#define FDT_BITWISE
+ #endif
+
+-typedef uint16_t __bitwise fdt16_t;
+-typedef uint32_t __bitwise fdt32_t;
+-typedef uint64_t __bitwise fdt64_t;
++typedef uint16_t FDT_BITWISE fdt16_t;
++typedef uint32_t FDT_BITWISE fdt32_t;
++typedef uint64_t FDT_BITWISE fdt64_t;
+
+ #define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
+ #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+@@ -79,29 +80,29 @@ typedef uint64_t __bitwise fdt64_t;
+
+ static inline uint16_t fdt16_to_cpu(fdt16_t x)
+ {
+- return (__force uint16_t)CPU_TO_FDT16(x);
++ return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
+ }
+ static inline fdt16_t cpu_to_fdt16(uint16_t x)
+ {
+- return (__force fdt16_t)CPU_TO_FDT16(x);
++ return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
+ }
+
+ static inline uint32_t fdt32_to_cpu(fdt32_t x)
+ {
+- return (__force uint32_t)CPU_TO_FDT32(x);
++ return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
+ }
+ static inline fdt32_t cpu_to_fdt32(uint32_t x)
+ {
+- return (__force fdt32_t)CPU_TO_FDT32(x);
++ return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
+ }
+
+ static inline uint64_t fdt64_to_cpu(fdt64_t x)
+ {
+- return (__force uint64_t)CPU_TO_FDT64(x);
++ return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
+ }
+ static inline fdt64_t cpu_to_fdt64(uint64_t x)
+ {
+- return (__force fdt64_t)CPU_TO_FDT64(x);
++ return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
+ }
+ #undef CPU_TO_FDT64
+ #undef CPU_TO_FDT32
+diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
+index e229b84..3673de0 100644
+--- a/scripts/dtc/livetree.c
++++ b/scripts/dtc/livetree.c
+@@ -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)
+ add_child(old_node, new_child);
+ }
+@@ -242,7 +242,7 @@ void delete_property_by_name(struct node *node, char *name)
+ struct property *prop = node->proplist;
+
+ while (prop) {
+- if (!strcmp(prop->name, name)) {
++ if (streq(prop->name, name)) {
+ delete_property(prop);
+ return;
+ }
+@@ -275,7 +275,7 @@ void delete_node_by_name(struct node *parent, char *name)
+ struct node *node = parent->children;
+
+ while (node) {
+- if (!strcmp(node->name, name)) {
++ if (streq(node->name, name)) {
+ delete_node(node);
+ return;
+ }
+@@ -296,14 +296,31 @@ void delete_node(struct node *node)
+ 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 *new = xmalloc(sizeof(*new));
+
+ memset(new, 0, sizeof(*new));
+
+- new->re.address = address;
+- new->re.size = size;
++ new->address = address;
++ new->size = size;
+
+ return new;
+ }
+@@ -335,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
+ return list;
+ }
+
+-struct boot_info *build_boot_info(struct reserve_info *reservelist,
+- struct node *tree, uint32_t boot_cpuid_phys)
++struct dt_info *build_dt_info(unsigned int dtsflags,
++ struct reserve_info *reservelist,
++ struct node *tree, uint32_t boot_cpuid_phys)
+ {
+- struct boot_info *bi;
++ struct dt_info *dti;
+
+- bi = xmalloc(sizeof(*bi));
+- bi->reservelist = reservelist;
+- bi->dt = tree;
+- bi->boot_cpuid_phys = boot_cpuid_phys;
++ dti = xmalloc(sizeof(*dti));
++ dti->dtsflags = dtsflags;
++ dti->reservelist = reservelist;
++ dti->dt = tree;
++ dti->boot_cpuid_phys = boot_cpuid_phys;
+
+- return bi;
++ return dti;
+ }
+
+ /*
+@@ -374,7 +393,7 @@ struct property *get_property(struct node *node, const char *propname)
+ cell_t propval_cell(struct property *prop)
+ {
+ assert(prop->val.len == sizeof(cell_t));
+- return fdt32_to_cpu(*((cell_t *)prop->val.val));
++ return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
+ }
+
+ struct property *get_property_by_label(struct node *tree, const char *label,
+@@ -580,24 +599,24 @@ static int cmp_reserve_info(const void *ax, const void *bx)
+ a = *((const struct reserve_info * const *)ax);
+ b = *((const struct reserve_info * const *)bx);
+
+- if (a->re.address < b->re.address)
++ if (a->address < b->address)
+ return -1;
+- else if (a->re.address > b->re.address)
++ else if (a->address > b->address)
+ return 1;
+- else if (a->re.size < b->re.size)
++ else if (a->size < b->size)
+ return -1;
+- else if (a->re.size > b->re.size)
++ else if (a->size > b->size)
+ return 1;
+ else
+ 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;
+ int n = 0, i = 0;
+
+- for (ri = bi->reservelist;
++ for (ri = dti->reservelist;
+ ri;
+ ri = ri->next)
+ n++;
+@@ -607,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi)
+
+ tbl = xmalloc(n * sizeof(*tbl));
+
+- for (ri = bi->reservelist;
++ for (ri = dti->reservelist;
+ ri;
+ ri = ri->next)
+ tbl[i++] = ri;
+
+ qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
+
+- bi->reservelist = tbl[0];
++ dti->reservelist = tbl[0];
+ for (i = 0; i < (n-1); i++)
+ tbl[i]->next = tbl[i+1];
+ tbl[n-1]->next = NULL;
+@@ -704,8 +723,258 @@ static void sort_node(struct node *node)
+ sort_node(c);
+ }
+
+-void sort_tree(struct boot_info *bi)
++void sort_tree(struct dt_info *dti)
++{
++ sort_reserve_entries(dti);
++ 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)
+ {
+- sort_reserve_entries(bi);
+- sort_node(bi->dt);
++ 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);
++
++ free(entry);
++}
++
++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 */
++ fdt32_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);
+ }
+diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c
+index f534c22..9d38459 100644
+--- a/scripts/dtc/srcpos.c
++++ b/scripts/dtc/srcpos.c
+@@ -246,46 +246,27 @@ srcpos_copy(struct srcpos *pos)
+ 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 *
+ srcpos_string(struct srcpos *pos)
+ {
+ const char *fname = "<no-file>";
+ char *pos_str;
+- int rc;
+
+- if (pos)
++ if (pos->file && pos->file->name)
+ fname = pos->file->name;
+
+
+ if (pos->first_line != pos->last_line)
+- rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
+- pos->first_line, pos->first_column,
+- pos->last_line, pos->last_column);
++ xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
++ pos->first_line, pos->first_column,
++ pos->last_line, pos->last_column);
+ else if (pos->first_column != pos->last_column)
+- rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
+- pos->first_line, pos->first_column,
+- pos->last_column);
++ xasprintf(&pos_str, "%s:%d.%d-%d", fname,
++ pos->first_line, pos->first_column,
++ pos->last_column);
+ else
+- rc = asprintf(&pos_str, "%s:%d.%d", fname,
+- pos->first_line, pos->first_column);
+-
+- if (rc == -1)
+- die("Couldn't allocate in srcpos string");
++ xasprintf(&pos_str, "%s:%d.%d", fname,
++ pos->first_line, pos->first_column);
+
+ return pos_str;
+ }
+diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h
+index f81827b..7caca82 100644
+--- a/scripts/dtc/srcpos.h
++++ b/scripts/dtc/srcpos.h
+@@ -22,6 +22,7 @@
+
+ #include <stdio.h>
+ #include <stdbool.h>
++#include "util.h"
+
+ struct srcfile_state {
+ FILE *f;
+@@ -105,14 +106,11 @@ extern struct srcpos srcpos_empty;
+ extern void srcpos_update(struct srcpos *pos, const char *text, int len);
+ extern struct srcpos *srcpos_copy(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,
+- const char *fmt, va_list va)
+- __attribute__((format(printf, 3, 0)));
+-extern void srcpos_error(struct srcpos *pos, const char *prefix,
+- const char *fmt, ...)
+- __attribute__((format(printf, 3, 4)));
++
++extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
++ const char *fmt, va_list va);
++extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix,
++ const char *fmt, ...);
+
+ extern void srcpos_set_line(char *f, int l);
+
+diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
+index a55d1d1..2461a3d 100644
+--- a/scripts/dtc/treesource.c
++++ b/scripts/dtc/treesource.c
+@@ -25,12 +25,12 @@ extern FILE *yyin;
+ extern int yyparse(void);
+ extern YYLTYPE yylloc;
+
+-struct boot_info *the_boot_info;
++struct dt_info *parser_output;
+ 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;
+
+ srcfile_push(fname);
+@@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname)
+ if (treesource_error)
+ die("Syntax error parsing input tree\n");
+
+- return the_boot_info;
++ return parser_output;
+ }
+
+ static void write_prefix(FILE *f, int level)
+@@ -137,7 +137,7 @@ static void write_propval_string(FILE *f, struct data val)
+ static void write_propval_cells(FILE *f, struct data val)
+ {
+ void *propend = val.val + val.len;
+- cell_t *cp = (cell_t *)val.val;
++ fdt32_t *cp = (fdt32_t *)val.val;
+ struct marker *m = val.markers;
+
+ fprintf(f, "<");
+@@ -263,22 +263,22 @@ 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;
+
+ 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;
+
+ for_each_label(re->labels, l)
+ fprintf(f, "%s: ", l->label);
+ fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
+- (unsigned long long)re->re.address,
+- (unsigned long long)re->re.size);
++ (unsigned long long)re->address,
++ (unsigned long long)re->size);
+ }
+
+- write_tree_source_node(f, bi->dt, 0);
++ write_tree_source_node(f, dti->dt, 0);
+ }
+
+diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
+index fb124ee..9953c32 100644
+--- a/scripts/dtc/util.c
++++ b/scripts/dtc/util.c
+@@ -46,6 +46,36 @@ char *xstrdup(const char *s)
+ 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)
+ {
+ int lenp = strlen(path);
+@@ -366,7 +396,7 @@ void utilfdt_print_data(const char *data, int len)
+ } while (s < data + len);
+
+ } else if ((len % 4) == 0) {
+- const uint32_t *cell = (const uint32_t *)data;
++ const fdt32_t *cell = (const fdt32_t *)data;
+
+ printf(" = <");
+ for (i = 0, len /= 4; i < len; i++)
+@@ -382,15 +412,16 @@ void utilfdt_print_data(const char *data, int len)
+ }
+ }
+
+-void util_version(void)
++void NORETURN util_version(void)
+ {
+ printf("Version: %s\n", DTC_VERSION);
+ exit(0);
+ }
+
+-void util_usage(const char *errmsg, const char *synopsis,
+- const char *short_opts, struct option const long_opts[],
+- const char * const opts_help[])
++void NORETURN util_usage(const char *errmsg, const char *synopsis,
++ const char *short_opts,
++ struct option const long_opts[],
++ const char * const opts_help[])
+ {
+ FILE *fp = errmsg ? stderr : stdout;
+ const char a_arg[] = "<arg>";
+diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
+index f800b60..ad5f411 100644
+--- a/scripts/dtc/util.h
++++ b/scripts/dtc/util.h
+@@ -25,9 +25,17 @@
+ * USA
+ */
+
++#ifdef __GNUC__
++#define PRINTF(i, j) __attribute__((format (printf, i, j)))
++#define NORETURN __attribute__((noreturn))
++#else
++#define PRINTF(i, j)
++#define NORETURN
++#endif
++
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+-static inline void __attribute__((noreturn)) die(const char *str, ...)
++static inline void NORETURN PRINTF(1, 2) die(const char *str, ...)
+ {
+ va_list ap;
+
+@@ -53,12 +61,14 @@ static inline void *xrealloc(void *p, size_t len)
+ void *new = realloc(p, len);
+
+ if (!new)
+- die("realloc() failed (len=%d)\n", len);
++ die("realloc() failed (len=%zd)\n", len);
+
+ return new;
+ }
+
+ extern char *xstrdup(const char *s);
++
++extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
+ extern char *join_path(const char *path, const char *name);
+
+ /**
+@@ -187,7 +197,7 @@ void utilfdt_print_data(const char *data, int len);
+ /**
+ * Show source version and exit
+ */
+-void util_version(void) __attribute__((noreturn));
++void NORETURN util_version(void);
+
+ /**
+ * Show usage and exit
+@@ -201,9 +211,10 @@ void util_version(void) __attribute__((noreturn));
+ * @param long_opts The structure of long options
+ * @param opts_help An array of help strings (should align with long_opts)
+ */
+-void util_usage(const char *errmsg, const char *synopsis,
+- const char *short_opts, struct option const long_opts[],
+- const char * const opts_help[]) __attribute__((noreturn));
++void NORETURN util_usage(const char *errmsg, const char *synopsis,
++ const char *short_opts,
++ struct option const long_opts[],
++ const char * const opts_help[]);
+
+ /**
+ * Show usage and exit
+diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
+index ad9b05a..859564e 100644
+--- a/scripts/dtc/version_gen.h
++++ b/scripts/dtc/version_gen.h
+@@ -1 +1 @@
+-#define DTC_VERSION "DTC 1.4.1-g53bf130b"
++#define DTC_VERSION "DTC 1.4.4"
+diff --git a/scripts/package/builddeb b/scripts/package/builddeb
+index 3c575cd..172be74 100755
+--- a/scripts/package/builddeb
++++ b/scripts/package/builddeb
+@@ -69,7 +69,7 @@ set_debarch() {
+ echo "" >&2
+ echo "** ** ** WARNING ** ** **" >&2
+ echo "" >&2
+- echo "Your architecture doesn't have it's equivalent" >&2
++ echo "Your architecture doesn't have its equivalent" >&2
+ echo "Debian userspace architecture defined!" >&2
+ echo "Falling back to using your current userspace instead!" >&2
+ echo "Please add support for $UTS_MACHINE to ${0} ..." >&2
+@@ -151,9 +151,18 @@ else
+ fi
+
+ if grep -q "^CONFIG_OF=y" $KCONFIG_CONFIG ; then
++ mkdir -p "$tmpdir/boot/dtbs/$version"
+ # Only some architectures with OF support have this target
+ if grep -q dtbs_install "${srctree}/arch/$SRCARCH/Makefile"; then
+- $MAKE KBUILD_SRC= INSTALL_DTBS_PATH="$tmpdir/usr/lib/$packagename" dtbs_install
++ $MAKE KBUILD_SRC= INSTALL_DTBS_PATH="$tmpdir/boot/dtbs/$version" dtbs_install
++ else
++ $MAKE KBUILD_SRC= dtbs
++ find arch/arm/boot/ -iname "*.dtb" -exec cp -v '{}' "$tmpdir/boot/dtbs/$version" \;
++ fi
++
++ #make dtbs_install seems to add an .old directory
++ if [ -d "$tmpdir/boot/dtbs/$version.old" ] ; then
++ rm -rf "$tmpdir/boot/dtbs/$version.old"
+ fi
+ fi
+
+@@ -262,10 +271,10 @@ EOF
+ cat <<EOF > debian/copyright
+ This is a packacked upstream version of the Linux kernel.
+
+-The sources may be found at most Linux ftp sites, including:
+-ftp://ftp.kernel.org/pub/linux/kernel
++The sources may be found at most Linux archive sites, including:
++https://www.kernel.org/pub/linux/kernel
+
+-Copyright: 1991 - 2015 Linus Torvalds and others.
++Copyright: 1991 - 2017 Linus Torvalds and others.
+
+ The git repository for mainline kernel development is at:
+ git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+@@ -288,7 +297,6 @@ Section: kernel
+ Priority: optional
+ Maintainer: $maintainer
+ Build-Depends: $build_depends
+-Standards-Version: 3.8.4
+ Homepage: http://www.kernel.org/
+ EOF
+
+@@ -296,7 +304,6 @@ if [ "$ARCH" = "um" ]; then
+ cat <<EOF >> debian/control
+
+ Package: $packagename
+-Provides: linux-image, linux-image-2.6, linux-modules-$version
+ Architecture: any
+ Description: User Mode Linux kernel, version $version
+ User-mode Linux is a port of the Linux kernel to its own system call
+@@ -313,7 +320,6 @@ else
+ cat <<EOF >> debian/control
+
+ Package: $packagename
+-Provides: linux-image, linux-image-2.6, linux-modules-$version
+ Suggests: $fwpackagename
+ Architecture: any
+ Description: Linux kernel, version $version
+@@ -346,7 +352,6 @@ rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
+ cat <<EOF >> debian/control
+
+ Package: $kernel_headers_packagename
+-Provides: linux-headers, linux-headers-2.6
+ Architecture: any
+ Description: Linux kernel headers for $KERNELRELEASE on \${kernel:debarch}
+ This package provides kernel header files for $KERNELRELEASE on \${kernel:debarch}
+@@ -404,7 +409,6 @@ if [ -n "$BUILD_DEBUG" ] ; then
+
+ Package: $dbg_packagename
+ Section: debug
+-Provides: linux-debug, linux-debug-$version
+ Architecture: any
+ Description: Linux kernel debugging symbols for $version
+ This package will come in handy if you need to debug the kernel. It provides
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index c67667b..0f40b09 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -135,6 +135,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_TAS5086 if I2C
+ select SND_SOC_TAS571X if I2C
+ select SND_SOC_TAS5720 if I2C
++ select SND_SOC_TDM
+ select SND_SOC_TFA9879 if I2C
+ select SND_SOC_TLV320AIC23_I2C if I2C
+ select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
+@@ -812,6 +813,9 @@ config SND_SOC_TAS5720
+ Enable support for Texas Instruments TAS5720L/M high-efficiency mono
+ Class-D audio power amplifiers.
+
++config SND_SOC_TDM
++ tristate "Generic TDM codec"
++
+ config SND_SOC_TFA9879
+ tristate "NXP Semiconductors TFA9879 amplifier"
+ depends on I2C
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 958cd49..ea82c79 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -142,6 +142,7 @@ snd-soc-sti-sas-objs := sti-sas.o
+ snd-soc-tas5086-objs := tas5086.o
+ snd-soc-tas571x-objs := tas571x.o
+ snd-soc-tas5720-objs := tas5720.o
++snd-soc-tdm-objs := tdm.o
+ snd-soc-tfa9879-objs := tfa9879.o
+ snd-soc-tlv320aic23-objs := tlv320aic23.o
+ snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
+@@ -363,6 +364,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
+ obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
+ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
+ obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
++obj-$(CONFIG_SND_SOC_TDM) += snd-soc-tdm.o
+ obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
+ obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
+ obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
+diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
+index ee36753..b682f12 100644
+--- a/sound/soc/codecs/spdif_transmitter.c
++++ b/sound/soc/codecs/spdif_transmitter.c
+@@ -27,7 +27,9 @@
+ #define STUB_RATES SNDRV_PCM_RATE_8000_192000
+ #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+- SNDRV_PCM_FMTBIT_S24_LE)
++ SNDRV_PCM_FMTBIT_S24_3LE | \
++ SNDRV_PCM_FMTBIT_S24_LE | \
++ SNDRV_PCM_FMTBIT_S32_LE)
+
+ static const struct snd_soc_dapm_widget dit_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("spdif-out"),
+diff --git b/sound/soc/codecs/tdm.c b/sound/soc/codecs/tdm.c
+new file mode 100644
+index 0000000..b8fb3b8
+--- /dev/null
++++ b/sound/soc/codecs/tdm.c
+@@ -0,0 +1,112 @@
++/*
++ * ALSA SoC generic TDM codec driver
++ *
++ * Author: Matthijs van Duin <matthijsvanduin@gmail.com>
++ * Copyright: (C) 2016 Dutch & Dutch
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * TODO Allow customization via device tree.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/slab.h>
++#include <sound/soc.h>
++#include <sound/pcm.h>
++#include <sound/initval.h>
++#include <linux/of.h>
++
++#define DRV_NAME "tdm-audio"
++
++/* As far as I can tell the LE/3LE/BE/3BE suffix merely indicates how the data
++ * was represented in memory, so why would the codec care? On the other hand,
++ * how do you indicate the bit-endianness on wire? */
++
++#define TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
++ SNDRV_PCM_FMTBIT_U8 | \
++ SNDRV_PCM_FMTBIT_S16_LE | \
++ SNDRV_PCM_FMTBIT_U16_LE | \
++ SNDRV_PCM_FMTBIT_S20_3LE | \
++ SNDRV_PCM_FMTBIT_U20_3LE | \
++ SNDRV_PCM_FMTBIT_S24_3LE | \
++ SNDRV_PCM_FMTBIT_U24_3LE | \
++ SNDRV_PCM_FMTBIT_S24_LE | \
++ SNDRV_PCM_FMTBIT_U24_LE | \
++ SNDRV_PCM_FMTBIT_S32_LE | \
++ SNDRV_PCM_FMTBIT_U32_LE)
++
++static const struct snd_soc_dapm_widget tdm_audio_widgets[] = {
++ SND_SOC_DAPM_OUTPUT("Sink"),
++ SND_SOC_DAPM_INPUT("Source"),
++};
++
++static const struct snd_soc_dapm_route tdm_audio_routes[] = {
++ { "Sink", NULL, "Playback" },
++ { "Capture", NULL, "Source" },
++};
++
++static struct snd_soc_codec_driver soc_codec_tdm_audio = {
++ .component_driver = {
++ .dapm_widgets = tdm_audio_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(tdm_audio_widgets),
++ .dapm_routes = tdm_audio_routes,
++ .num_dapm_routes = ARRAY_SIZE(tdm_audio_routes),
++ },
++};
++
++static struct snd_soc_dai_driver tdm_audio_dai = {
++ .name = "tdm_audio",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 16,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .formats = TDM_FORMATS,
++ },
++ .capture = {
++ .stream_name = "Capture",
++ .channels_min = 1,
++ .channels_max = 16,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .formats = TDM_FORMATS,
++ },
++};
++
++static int tdm_audio_probe(struct platform_device *pdev)
++{
++ return snd_soc_register_codec(&pdev->dev, &soc_codec_tdm_audio,
++ &tdm_audio_dai, 1);
++}
++
++static int tdm_audio_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_codec(&pdev->dev);
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id tdm_audio_dt_ids[] = {
++ { .compatible = "linux,tdm-audio", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, tdm_audio_dt_ids);
++#endif
++
++static struct platform_driver tdm_audio_driver = {
++ .probe = tdm_audio_probe,
++ .remove = tdm_audio_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .of_match_table = of_match_ptr(tdm_audio_dt_ids),
++ },
++};
++
++module_platform_driver(tdm_audio_driver);
++
++MODULE_AUTHOR("Matthijs van Duin <matthijs@dutchdutch.com>");
++MODULE_DESCRIPTION("Generic TDM codec driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRV_NAME);
+diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
+index 3c5a980..35e441c 100644
+--- a/sound/soc/davinci/davinci-mcasp.c
++++ b/sound/soc/davinci/davinci-mcasp.c
+@@ -151,6 +151,8 @@ static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
+ mcasp_set_bits(mcasp, ctl_reg, val);
+
+ /* programming GBLCTL needs to read back from GBLCTL and verfiy */
++ ctl_reg = DAVINCI_MCASP_GBLCTL_REG;
++
+ /* loop count is to avoid the lock-up */
+ for (i = 0; i < 1000; i++) {
+ if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
+@@ -572,6 +574,12 @@ static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
+ * tdm_slot width by dividing the the ratio by the
+ * number of configured tdm slots.
+ */
++ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
++ if (div != 128)
++ dev_warn(mcasp->dev,
++ "%s(): BCLK/LRCLK %d requested, must be 128 for DIT mode", __func__, div);
++ break;
++ }
+ mcasp->slot_width = div / mcasp->tdm_slots;
+ if (div % mcasp->tdm_slots)
+ dev_warn(mcasp->dev,
+@@ -696,56 +704,59 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
+ }
+
+ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
+- int sample_width)
++ u32 sample_width)
+ {
+- u32 fmt;
+- u32 tx_rotate = (sample_width / 4) & 0x7;
+- u32 mask = (1ULL << sample_width) - 1;
+- u32 slot_width = sample_width;
++ u32 mask, tx_rotate, rx_rotate;
++ u32 slot_width, fmt;
+
+ /*
+- * For captured data we should not rotate, inversion and masking is
+- * enoguh to get the data to the right position:
+- * Format data from bus after reverse (XRBUF)
+- * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB|
+- * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB|
+- * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB|
+- * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB|
++ * Sample data is always right-justified. Apply mask and rotate right
++ * to left-justified. For receive the steps are in reverse order (but
++ * still rotates right).
+ */
+- u32 rx_rotate = 0;
++ mask = GENMASK(sample_width, 0);
++ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
++ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
++
++ tx_rotate = sample_width;
++ rx_rotate = -sample_width;
+
+ /*
+- * Setting the tdm slot width either with set_clkdiv() or
+- * set_tdm_slot() allows us to for example send 32 bits per
+- * channel to the codec, while only 16 of them carry audio
+- * payload.
++ * For big-endian formats (everything except DIT), McASP needs the slot
++ * data to be left-aligned for transmit, whereas received slot data is
++ * delivered right-aligned:
++ *
++ * +-----------------------------------------------+---------------+
++ * <--shift-out- slot data | |
++ * +-----------------------------------------------+---------------+
++ *
++ * +---------------+-----------------------------------------------+
++ * | | slot data <--shift-in--
++ * +---------------+-----------------------------------------------+
++ *
++ * For little-endian formats (DIT only) the reverse is true.
+ */
+- if (mcasp->slot_width) {
+- /*
+- * When we have more bclk then it is needed for the
+- * data, we need to use the rotation to move the
+- * received samples to have correct alignment.
+- */
+- slot_width = mcasp->slot_width;
+- rx_rotate = (slot_width - sample_width) / 4;
++ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
++ tx_rotate -= 24;
++ slot_width = 32;
++ fmt = 0; /* little endian */
++ } else {
++ slot_width = mcasp->slot_width ?: sample_width;
++ rx_rotate += slot_width;
++ fmt = TXORD; /* big endian */
+ }
+
+ /* mapping of the XSSZ bit-field as described in the datasheet */
+- fmt = (slot_width >> 1) - 1;
++ fmt |= TXSSZ((slot_width >> 1) - 1);
+
+- if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+- mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
+- RXSSZ(0x0F));
+- mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
+- TXSSZ(0x0F));
+- mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+- TXROT(7));
+- mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
+- RXROT(7));
+- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
+- }
++ tx_rotate = TXROT((tx_rotate & 31) >> 2);
++ rx_rotate = TXROT((rx_rotate & 31) >> 2);
+
+- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
++ if (!mcasp->dat_port)
++ fmt |= TXSEL;
++
++ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, fmt | tx_rotate, 0xffff);
++ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, fmt | rx_rotate, 0xffff);
+
+ return 0;
+ }
+@@ -866,7 +877,6 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
+ int total_slots;
+ int active_serializers;
+ u32 mask = 0;
+- u32 busel = 0;
+
+ total_slots = mcasp->tdm_slots;
+
+@@ -902,17 +912,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
+ }
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+
+- if (!mcasp->dat_port)
+- busel = TXSEL;
+-
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+ FSXMOD(total_slots), FSXMOD(0x1FF));
+ } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+ FSRMOD(total_slots), FSRMOD(0x1FF));
+ /*
+@@ -935,23 +940,13 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
+ u32 cs_value = 0;
+ u8 *cs_bytes = (u8*) &cs_value;
+
+- /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
+- and LSB first */
+- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
+-
+ /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
+
+ /* Set the TX tdm : for all the slots */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
+
+- /* Set the TX clock controls : div = 1 and internal */
+- mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
+-
+- mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
+-
+- /* Only 44100 and 48000 are valid, both have the same setting */
+- mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
++ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+
+ /* Enable the DIT */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+@@ -1049,6 +1044,15 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
+ return error_ppm;
+ }
+
++static uint mcasp_clocks_per_slot(struct davinci_mcasp *mcasp, uint width)
++{
++ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
++ return 64;
++ if (mcasp->slot_width)
++ return mcasp->slot_width;
++ return width;
++}
++
+ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+@@ -1068,12 +1072,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
+ * the machine driver, we need to calculate the ratio.
+ */
+ if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
+- int slots = mcasp->tdm_slots;
+- int rate = params_rate(params);
+- int sbits = params_width(params);
+-
+- if (mcasp->slot_width)
+- sbits = mcasp->slot_width;
++ uint slots = mcasp->tdm_slots;
++ uint rate = params_rate(params);
++ uint sbits = mcasp_clocks_per_slot(mcasp, params_width(params));
+
+ davinci_mcasp_calc_clk_div(mcasp, rate * sbits * slots, true);
+ }
+@@ -1103,11 +1104,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
+ word_length = 16;
+ break;
+
+- case SNDRV_PCM_FORMAT_U24_3LE:
+- case SNDRV_PCM_FORMAT_S24_3LE:
+- word_length = 24;
++ case SNDRV_PCM_FORMAT_U20_3LE:
++ case SNDRV_PCM_FORMAT_S20_3LE:
++ word_length = 20;
+ break;
+
++ case SNDRV_PCM_FORMAT_U24_3LE:
++ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ word_length = 24;
+@@ -1169,14 +1172,11 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct davinci_mcasp_ruledata *rd = rule->private;
+ struct snd_interval *ri =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+- int sbits = params_width(params);
+- int slots = rd->mcasp->tdm_slots;
++ uint sbits = mcasp_clocks_per_slot(rd->mcasp, params_width(params));
++ uint slots = rd->mcasp->tdm_slots;
+ struct snd_interval range;
+ int i;
+
+- if (rd->mcasp->slot_width)
+- sbits = rd->mcasp->slot_width;
+-
+ snd_interval_any(&range);
+ range.empty = 1;
+
+@@ -1223,8 +1223,7 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
+ uint sbits = snd_pcm_format_width(i);
+ int ppm;
+
+- if (rd->mcasp->slot_width)
+- sbits = rd->mcasp->slot_width;
++ sbits = mcasp_clocks_per_slot(rd->mcasp, sbits);
+
+ ppm = davinci_mcasp_calc_clk_div(rd->mcasp,
+ sbits * slots * rate,
+@@ -1834,7 +1833,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
+
+ mcasp->op_mode = pdata->op_mode;
+ /* sanity check for tdm slots parameter */
+- if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
++ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
++ mcasp->tdm_slots = 2;
++ } else {
+ if (pdata->tdm_slots < 2) {
+ dev_err(&pdev->dev, "invalid tdm slots: %d\n",
+ pdata->tdm_slots);
+diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
+index afddc80..ecc33cb 100644
+--- a/sound/soc/davinci/davinci-mcasp.h
++++ b/sound/soc/davinci/davinci-mcasp.h
+@@ -82,12 +82,12 @@
+ /* Serializer n Control Register */
+ #define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
+ #define DAVINCI_MCASP_XRSRCTL_REG(n) (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
+- (n << 2))
++ ((n) << 2))
+
+ /* Transmit Buffer for Serializer n */
+-#define DAVINCI_MCASP_TXBUF_REG(n) (0x200 + (n << 2))
++#define DAVINCI_MCASP_TXBUF_REG(n) (0x200 + ((n) << 2))
+ /* Receive Buffer for Serializer n */
+-#define DAVINCI_MCASP_RXBUF_REG(n) (0x280 + (n << 2))
++#define DAVINCI_MCASP_RXBUF_REG(n) (0x280 + ((n) << 2))
+
+ /* McASP FIFO Registers */
+ #define DAVINCI_MCASP_V2_AFIFO_BASE (0x1010)
+@@ -109,7 +109,7 @@
+ /*
+ * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
+ */
+-#define AXR(n) (1<<n)
++#define AXR(n) (1<<(n))
+ #define PFUNC_AMUTE BIT(25)
+ #define ACLKX BIT(26)
+ #define AHCLKX BIT(27)
+@@ -121,7 +121,7 @@
+ /*
+ * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ */
+-#define AXR(n) (1<<n)
++#define AXR(n) (1<<(n))
+ #define PDIR_AMUTE BIT(25)
+ #define ACLKX BIT(26)
+ #define AHCLKX BIT(27)
+@@ -142,22 +142,22 @@
+ */
+ #define TXROT(val) (val)
+ #define TXSEL BIT(3)
+-#define TXSSZ(val) (val<<4)
+-#define TXPBIT(val) (val<<8)
+-#define TXPAD(val) (val<<13)
++#define TXSSZ(val) ((val)<<4)
++#define TXPBIT(val) ((val)<<8)
++#define TXPAD(val) ((val)<<13)
+ #define TXORD BIT(15)
+-#define FSXDLY(val) (val<<16)
++#define FSXDLY(val) ((val)<<16)
+
+ /*
+ * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
+ */
+ #define RXROT(val) (val)
+ #define RXSEL BIT(3)
+-#define RXSSZ(val) (val<<4)
+-#define RXPBIT(val) (val<<8)
+-#define RXPAD(val) (val<<13)
++#define RXSSZ(val) ((val)<<4)
++#define RXPBIT(val) ((val)<<8)
++#define RXPAD(val) ((val)<<13)
+ #define RXORD BIT(15)
+-#define FSRDLY(val) (val<<16)
++#define FSRDLY(val) ((val)<<16)
+
+ /*
+ * DAVINCI_MCASP_TXFMCTL_REG - Transmit Frame Control Register Bits
+@@ -165,7 +165,7 @@
+ #define FSXPOL BIT(0)
+ #define AFSXE BIT(1)
+ #define FSXDUR BIT(4)
+-#define FSXMOD(val) (val<<7)
++#define FSXMOD(val) ((val)<<7)
+
+ /*
+ * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
+@@ -173,7 +173,7 @@
+ #define FSRPOL BIT(0)
+ #define AFSRE BIT(1)
+ #define FSRDUR BIT(4)
+-#define FSRMOD(val) (val<<7)
++#define FSRMOD(val) ((val)<<7)
+
+ /*
+ * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
+@@ -229,17 +229,17 @@
+ */
+ #define LBEN BIT(0)
+ #define LBORD BIT(1)
+-#define LBGENMODE(val) (val<<2)
++#define LBGENMODE(val) ((val)<<2)
+
+ /*
+ * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
+ */
+-#define TXTDMS(n) (1<<n)
++#define TXTDMS(n) (1<<(n))
+
+ /*
+ * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
+ */
+-#define RXTDMS(n) (1<<n)
++#define RXTDMS(n) (1<<(n))
+
+ /*
+ * DAVINCI_MCASP_GBLCTL_REG - Global Control Register Bits
diff --git a/kernels/linux-libre-lts-knock/tcp_stealth_4.9_1.diff b/kernels/linux-libre-lts-knock/tcp_stealth_4.9_1.diff
new file mode 100644
index 000000000..40ca22975
--- /dev/null
+++ b/kernels/linux-libre-lts-knock/tcp_stealth_4.9_1.diff
@@ -0,0 +1,642 @@
+diff --git a/include/linux/tcp.h b/include/linux/tcp.h
+index a17ae7b..e48e86f 100644
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -19,6 +19,7 @@
+
+
+ #include <linux/skbuff.h>
++#include <linux/cryptohash.h>
+ #include <linux/win_minmax.h>
+ #include <net/sock.h>
+ #include <net/inet_connection_sock.h>
+@@ -353,6 +354,21 @@ struct tcp_sock {
+ struct tcp_md5sig_info __rcu *md5sig_info;
+ #endif
+
++#ifdef CONFIG_TCP_STEALTH
++/* Stealth TCP socket configuration */
++ struct {
++ #define TCP_STEALTH_MODE_AUTH BIT(0)
++ #define TCP_STEALTH_MODE_INTEGRITY BIT(1)
++ #define TCP_STEALTH_MODE_INTEGRITY_LEN BIT(2)
++ u8 mode;
++ u8 secret[MD5_MESSAGE_BYTES];
++ u16 integrity_hash;
++ size_t integrity_len;
++ struct skb_mstamp mstamp;
++ bool saw_tsval;
++ } stealth;
++#endif
++
+ /* TCP fastopen related information */
+ struct tcp_fastopen_request *fastopen_req;
+ /* fastopen_rsk points to request_sock that resulted in this big
+diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
+index 3f36d45..ec392a1 100644
+--- a/include/net/secure_seq.h
++++ b/include/net/secure_seq.h
+@@ -14,5 +14,10 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport);
+ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+ __be16 sport, __be16 dport);
++#ifdef CONFIG_TCP_STEALTH
++u32 tcp_stealth_do_auth(struct sock *sk, struct sk_buff *skb);
++u32 tcp_stealth_sequence_number(struct sock *sk, __be32 *daddr,
++ u32 daddr_size, __be16 dport);
++#endif
+
+ #endif /* _NET_SECURE_SEQ */
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 123979f..f7a0d7c 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -429,6 +429,12 @@ void tcp_parse_options(const struct sk_buff *skb,
+ struct tcp_options_received *opt_rx,
+ int estab, struct tcp_fastopen_cookie *foc);
+ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
++#ifdef CONFIG_TCP_STEALTH
++const bool tcp_parse_tsval_option(u32 *tsval, const struct tcphdr *th);
++int tcp_stealth_integrity(u16 *hash, u8 *secret, u8 *payload, int len);
++#define be32_isn_to_be16_av(x) (((__be16 *)&x)[0])
++#define be32_isn_to_be16_ih(x) (((__be16 *)&x)[1])
++#endif
+
+ /*
+ * TCP v4 functions exported for the inet6 API
+diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
+index 73ac0db..d2a35e9 100644
+--- a/include/uapi/linux/tcp.h
++++ b/include/uapi/linux/tcp.h
+@@ -116,6 +116,9 @@ enum {
+ #define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */
+ #define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */
+ #define TCP_REPAIR_WINDOW 29 /* Get/set window parameters */
++#define TCP_STEALTH 30
++#define TCP_STEALTH_INTEGRITY 31
++#define TCP_STEALTH_INTEGRITY_LEN 32
+
+ struct tcp_repair_opt {
+ __u32 opt_code;
+diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
+index fd3ce46..2d49cee 100644
+--- a/net/core/secure_seq.c
++++ b/net/core/secure_seq.c
+@@ -8,7 +8,11 @@
+ #include <linux/ktime.h>
+ #include <linux/string.h>
+ #include <linux/net.h>
++#include <linux/socket.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
+
++#include <net/tcp.h>
+ #include <net/secure_seq.h>
+
+ #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
+@@ -39,6 +43,102 @@ static u32 seq_scale(u32 seq)
+ }
+ #endif
+
++#ifdef CONFIG_TCP_STEALTH
++u32 tcp_stealth_sequence_number(struct sock *sk, __be32 *daddr,
++ u32 daddr_size, __be16 dport)
++{
++ struct tcp_sock *tp = tcp_sk(sk);
++ struct tcp_md5sig_key *md5;
++
++ __u32 sec[MD5_MESSAGE_BYTES / sizeof(__u32)];
++ __u32 i;
++ __u32 tsval = 0;
++
++ __be32 iv[MD5_DIGEST_WORDS] = { 0 };
++ __be32 isn;
++
++ memcpy(iv, daddr, (daddr_size > sizeof(iv)) ? sizeof(iv) : daddr_size);
++
++#ifdef CONFIG_TCP_MD5SIG
++ md5 = tp->af_specific->md5_lookup(sk, sk);
++#else
++ md5 = NULL;
++#endif
++ if (likely(sysctl_tcp_timestamps && !md5) || tp->stealth.saw_tsval)
++ tsval = tp->stealth.mstamp.stamp_jiffies;
++
++ ((__be16 *)iv)[2] ^= cpu_to_be16(tp->stealth.integrity_hash);
++ iv[2] ^= cpu_to_be32(tsval);
++ ((__be16 *)iv)[6] ^= dport;
++
++ for (i = 0; i < MD5_DIGEST_WORDS; i++)
++ iv[i] = le32_to_cpu(iv[i]);
++ for (i = 0; i < MD5_MESSAGE_BYTES / sizeof(__le32); i++)
++ sec[i] = le32_to_cpu(((__le32 *)tp->stealth.secret)[i]);
++
++ md5_transform(iv, sec);
++
++ isn = cpu_to_be32(iv[0]) ^ cpu_to_be32(iv[1]) ^
++ cpu_to_be32(iv[2]) ^ cpu_to_be32(iv[3]);
++
++ if (tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY)
++ be32_isn_to_be16_ih(isn) =
++ cpu_to_be16(tp->stealth.integrity_hash);
++
++ return be32_to_cpu(isn);
++}
++EXPORT_SYMBOL(tcp_stealth_sequence_number);
++
++u32 tcp_stealth_do_auth(struct sock *sk, struct sk_buff *skb)
++{
++ struct tcp_sock *tp = tcp_sk(sk);
++ struct tcphdr *th = tcp_hdr(skb);
++ __be32 isn = th->seq;
++ __be32 hash;
++ __be32 *daddr;
++ u32 daddr_size;
++
++ tp->stealth.saw_tsval =
++ tcp_parse_tsval_option(&tp->stealth.mstamp.stamp_jiffies, th);
++
++ if (tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN)
++ tp->stealth.integrity_hash =
++ be16_to_cpu(be32_isn_to_be16_ih(isn));
++
++ switch (tp->inet_conn.icsk_inet.sk.sk_family) {
++#if IS_ENABLED(CONFIG_IPV6)
++ case PF_INET6:
++ daddr_size = sizeof(ipv6_hdr(skb)->daddr.s6_addr32);
++ daddr = ipv6_hdr(skb)->daddr.s6_addr32;
++ break;
++#endif
++ case PF_INET:
++ daddr_size = sizeof(ip_hdr(skb)->daddr);
++ daddr = &ip_hdr(skb)->daddr;
++ break;
++ default:
++ pr_err("TCP Stealth: Unknown network layer protocol, stop!\n");
++ return 1;
++ }
++
++ hash = tcp_stealth_sequence_number(sk, daddr, daddr_size, th->dest);
++ cpu_to_be32s(&hash);
++
++ if (tp->stealth.mode & TCP_STEALTH_MODE_AUTH &&
++ tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN &&
++ be32_isn_to_be16_av(isn) == be32_isn_to_be16_av(hash))
++ return 0;
++
++ if (tp->stealth.mode & TCP_STEALTH_MODE_AUTH &&
++ !(tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN) &&
++ isn == hash)
++ return 0;
++
++ return 1;
++}
++EXPORT_SYMBOL(tcp_stealth_do_auth);
++#endif
++
+ #if IS_ENABLED(CONFIG_IPV6)
+ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
+ __be16 sport, __be16 dport)
+diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
+index b54b3ca..9ec6794 100644
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -728,3 +728,13 @@ config TCP_MD5SIG
+ on the Internet.
+
+ If unsure, say N.
++
++config TCP_STEALTH
++ bool "TCP: Stealth TCP socket support"
++ default n
++ ---help---
++ This option enables support for stealth TCP sockets. If you do not
++ know what this means, you do not need it.
++
++ If unsure, say N.
++
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 814af89..c9f2ba5 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -269,6 +269,7 @@
+ #include <linux/err.h>
+ #include <linux/time.h>
+ #include <linux/slab.h>
++#include <linux/vmalloc.h>
+
+ #include <net/icmp.h>
+ #include <net/inet_common.h>
+@@ -2386,6 +2387,49 @@ static int tcp_repair_options_est(struct tcp_sock *tp,
+ return 0;
+ }
+
++#ifdef CONFIG_TCP_STEALTH
++int tcp_stealth_integrity(__be16 *hash, u8 *secret, u8 *payload, int len)
++{
++ struct scatterlist sg[2];
++ struct crypto_ahash *tfm;
++ struct ahash_request *req;
++ __be16 h[MD5_DIGEST_WORDS * 2];
++ int i;
++ int err = 0;
++
++ tfm = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ err = -PTR_ERR(tfm);
++ goto out;
++ }
++ req = ahash_request_alloc(tfm, GFP_ATOMIC);
++ if (!req)
++ err = -EFAULT;
++ goto out;
++
++ sg_init_table(sg, 2);
++ sg_set_buf(&sg[0], secret, MD5_MESSAGE_BYTES);
++ sg_set_buf(&sg[1], payload, len);
++
++ ahash_request_set_callback(req, 0, NULL, NULL);
++ ahash_request_set_crypt(req, sg, (u8 *)h, MD5_MESSAGE_BYTES + len);
++
++ if (crypto_ahash_digest(req)) {
++ err = -EFAULT;
++ goto out;
++ }
++
++ *hash = be16_to_cpu(h[0]);
++ for (i = 1; i < MD5_DIGEST_WORDS * 2; i++)
++ *hash ^= be16_to_cpu(h[i]);
++
++out:
++ ahash_request_free(req);
++ crypto_free_ahash(tfm);
++ return err;
++}
++#endif
++
+ /*
+ * Socket option code for TCP.
+ */
+@@ -2417,6 +2461,66 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
+ release_sock(sk);
+ return err;
+ }
++#ifdef CONFIG_TCP_STEALTH
++ case TCP_STEALTH: {
++ u8 secret[MD5_MESSAGE_BYTES] = { 0 };
++
++ val = copy_from_user(secret, optval,
++ min_t(unsigned int, optlen,
++ MD5_MESSAGE_BYTES));
++ if (val != 0)
++ return -EFAULT;
++
++ lock_sock(sk);
++ memcpy(tp->stealth.secret, secret, MD5_MESSAGE_BYTES);
++ tp->stealth.mode = TCP_STEALTH_MODE_AUTH;
++ tp->stealth.mstamp.v64 = 0;
++ tp->stealth.saw_tsval = false;
++ release_sock(sk);
++ return err;
++ }
++ case TCP_STEALTH_INTEGRITY: {
++ u8 *payload;
++
++ lock_sock(sk);
++
++ if (!(tp->stealth.mode & TCP_STEALTH_MODE_AUTH)) {
++ err = -EOPNOTSUPP;
++ goto stealth_integrity_out_1;
++ }
++
++ if (optlen < 1 || optlen > USHRT_MAX) {
++ err = -EINVAL;
++ goto stealth_integrity_out_1;
++ }
++
++ payload = vmalloc(optlen);
++ if (!payload) {
++ err = -ENOMEM;
++ goto stealth_integrity_out_1;
++ }
++
++ val = copy_from_user(payload, optval, optlen);
++ if (val != 0) {
++ err = -EFAULT;
++ goto stealth_integrity_out_2;
++ }
++
++ err = tcp_stealth_integrity(&tp->stealth.integrity_hash,
++ tp->stealth.secret, payload,
++ optlen);
++ if (err)
++ goto stealth_integrity_out_2;
++
++ tp->stealth.mode |= TCP_STEALTH_MODE_INTEGRITY;
++
++stealth_integrity_out_2:
++ vfree(payload);
++stealth_integrity_out_1:
++ release_sock(sk);
++ return err;
++ }
++#endif
+ default:
+ /* fallthru */
+ break;
+@@ -2671,6 +2775,18 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
+ tp->notsent_lowat = val;
+ sk->sk_write_space(sk);
+ break;
++#ifdef CONFIG_TCP_STEALTH
++ case TCP_STEALTH_INTEGRITY_LEN:
++ if (!(tp->stealth.mode & TCP_STEALTH_MODE_AUTH)) {
++ err = -EOPNOTSUPP;
++ } else if (val < 1 || val > USHRT_MAX) {
++ err = -EINVAL;
++ } else {
++ tp->stealth.integrity_len = val;
++ tp->stealth.mode |= TCP_STEALTH_MODE_INTEGRITY_LEN;
++ }
++ break;
++#endif
+ default:
+ err = -ENOPROTOOPT;
+ break;
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index c71d49c..24f6d73 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -77,6 +77,9 @@
+ #include <linux/errqueue.h>
+
+ int sysctl_tcp_timestamps __read_mostly = 1;
++#ifdef CONFIG_TCP_STEALTH
++EXPORT_SYMBOL(sysctl_tcp_timestamps);
++#endif
+ int sysctl_tcp_window_scaling __read_mostly = 1;
+ int sysctl_tcp_sack __read_mostly = 1;
+ int sysctl_tcp_fack __read_mostly = 1;
+@@ -3926,6 +3929,47 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb,
+ return true;
+ }
+
++#ifdef CONFIG_TCP_STEALTH
++/* Parse only the TSVal field of the TCP Timestamp option header.
++ */
++const bool tcp_parse_tsval_option(u32 *tsval, const struct tcphdr *th)
++{
++ int length = (th->doff << 2) - sizeof(*th);
++ const u8 *ptr = (const u8 *)(th + 1);
++
++ /* If the TCP option is too short, we can short cut */
++ if (length < TCPOLEN_TIMESTAMP)
++ return false;
++
++ while (length > 0) {
++ int opcode = *ptr++;
++ int opsize;
++
++ switch (opcode) {
++ case TCPOPT_EOL:
++ return false;
++ case TCPOPT_NOP:
++ length--;
++ continue;
++ case TCPOPT_TIMESTAMP:
++ opsize = *ptr++;
++ if (opsize != TCPOLEN_TIMESTAMP || opsize > length)
++ return false;
++ *tsval = get_unaligned_be32(ptr);
++ return true;
++ default:
++ opsize = *ptr++;
++ if (opsize < 2 || opsize > length)
++ return false;
++ }
++ ptr += opsize - 2;
++ length -= opsize;
++ }
++ return false;
++}
++EXPORT_SYMBOL(tcp_parse_tsval_option);
++#endif
++
+ #ifdef CONFIG_TCP_MD5SIG
+ /*
+ * Parse MD5 Signature option
+@@ -4631,6 +4675,31 @@ err:
+
+ }
+
++#ifdef CONFIG_TCP_STEALTH
++static int __tcp_stealth_integrity_check(struct sock *sk, struct sk_buff *skb)
++{
++ struct tcphdr *th = tcp_hdr(skb);
++ struct tcp_sock *tp = tcp_sk(sk);
++ u16 hash;
++ __be32 seq = cpu_to_be32(TCP_SKB_CB(skb)->seq - 1);
++ char *data = skb->data + th->doff * 4;
++ int len = skb->len - th->doff * 4;
++
++ if (len < tp->stealth.integrity_len)
++ return 1;
++
++ if (tcp_stealth_integrity(&hash, tp->stealth.secret, data,
++ tp->stealth.integrity_len))
++ return 1;
++
++ if (be32_isn_to_be16_ih(seq) != cpu_to_be16(hash))
++ return 1;
++
++ tp->stealth.mode &= ~TCP_STEALTH_MODE_INTEGRITY_LEN;
++ return 0;
++}
++#endif
++
+ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
+ {
+ struct tcp_sock *tp = tcp_sk(sk);
+@@ -4641,6 +4710,15 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
+ __kfree_skb(skb);
+ return;
+ }
++
++#ifdef CONFIG_TCP_STEALTH
++ if (unlikely(tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN) &&
++ __tcp_stealth_integrity_check(sk, skb)) {
++ tcp_reset(sk);
++ goto drop;
++ }
++#endif
++
+ skb_dst_drop(skb);
+ __skb_pull(skb, tcp_hdr(skb)->doff * 4);
+
+@@ -5456,6 +5534,15 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
+ int eaten = 0;
+ bool fragstolen = false;
+
++#ifdef CONFIG_TCP_STEALTH
++ if (unlikely(tp->stealth.mode &
++ TCP_STEALTH_MODE_INTEGRITY_LEN) &&
++ __tcp_stealth_integrity_check(sk, skb)) {
++ tcp_reset(sk);
++ goto discard;
++ }
++#endif
++
+ if (tp->ucopy.task == current &&
+ tp->copied_seq == tp->rcv_nxt &&
+ len - tcp_header_len <= tp->ucopy.len &&
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index 2259114..542da7a 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -74,6 +74,7 @@
+ #include <net/xfrm.h>
+ #include <net/secure_seq.h>
+ #include <net/busy_poll.h>
++#include <net/secure_seq.h>
+
+ #include <linux/inet.h>
+ #include <linux/ipv6.h>
+@@ -233,6 +234,21 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+ sk->sk_gso_type = SKB_GSO_TCPV4;
+ sk_setup_caps(sk, &rt->dst);
+
++#ifdef CONFIG_TCP_STEALTH
++ /* If CONFIG_TCP_STEALTH is defined, we need to know the timestamp as
++ * early as possible and thus move taking the snapshot of tcp_time_stamp
++ * here.
++ */
++ skb_mstamp_get(&tp->stealth.mstamp);
++
++ if (!tp->write_seq && likely(!tp->repair) &&
++ unlikely(tp->stealth.mode & TCP_STEALTH_MODE_AUTH))
++ tp->write_seq = tcp_stealth_sequence_number(sk,
++ &inet->inet_daddr,
++ sizeof(inet->inet_daddr),
++ usin->sin_port);
++#endif
++
+ if (!tp->write_seq && likely(!tp->repair))
+ tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
+ inet->inet_daddr,
+@@ -1382,6 +1398,8 @@ static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb)
+ */
+ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
+ {
++ struct tcp_sock *tp = tcp_sk(sk);
++ struct tcphdr *th = tcp_hdr(skb);
+ struct sock *rsk;
+
+ if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+@@ -1403,6 +1421,15 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
+ if (tcp_checksum_complete(skb))
+ goto csum_err;
+
++#ifdef CONFIG_TCP_STEALTH
++ if (sk->sk_state == TCP_LISTEN && th->syn && !th->fin &&
++ unlikely(tp->stealth.mode & TCP_STEALTH_MODE_AUTH) &&
++ tcp_stealth_do_auth(sk, skb)) {
++ rsk = sk;
++ goto reset;
++ }
++#endif
++
+ if (sk->sk_state == TCP_LISTEN) {
+ struct sock *nsk = tcp_v4_cookie_check(sk, skb);
+
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index 896e9df..7bf3142 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -939,6 +939,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
+ tcb = TCP_SKB_CB(skb);
+ memset(&opts, 0, sizeof(opts));
+
++#ifdef TCP_STEALTH
++ if (unlikely(tcb->tcp_flags & TCPHDR_SYN &&
++ tp->stealth.mode & TCP_STEALTH_MODE_AUTH)) {
++ skb->skb_mstamp = tp->stealth.mstamp;
++ }
++#endif
++
+ if (unlikely(tcb->tcp_flags & TCPHDR_SYN))
+ tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5);
+ else
+@@ -3349,7 +3356,15 @@ int tcp_connect(struct sock *sk)
+ return -ENOBUFS;
+
+ tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
++#ifdef CONFIG_TCP_STEALTH
++ /* The timetamp was already made at the time the ISN was generated
++ * as we need to know its value in the stealth_tcp_sequence_number()
++ * function.
++ */
++ tp->retrans_stamp = tp->stealth.mstamp.stamp_jiffies;
++#else
+ tp->retrans_stamp = tcp_time_stamp;
++#endif
+ tcp_connect_queue_skb(sk, buff);
+ tcp_ecn_send_syn(sk, buff);
+
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index b9f1fee..b301a49 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -62,6 +62,7 @@
+ #include <net/inet_common.h>
+ #include <net/secure_seq.h>
+ #include <net/busy_poll.h>
++#include <net/secure_seq.h>
+
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+@@ -278,6 +279,21 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+
+ sk_set_txhash(sk);
+
++#ifdef CONFIG_TCP_STEALTH
++ /* If CONFIG_TCP_STEALTH is defined, we need to know the timestamp as
++ * early as possible and thus move taking the snapshot of tcp_time_stamp
++ * here.
++ */
++ skb_mstamp_get(&tp->stealth.mstamp);
++
++ if (!tp->write_seq && likely(!tp->repair) &&
++ unlikely(tp->stealth.mode & TCP_STEALTH_MODE_AUTH))
++ tp->write_seq = tcp_stealth_sequence_number(sk,
++ sk->sk_v6_daddr.s6_addr32,
++ sizeof(sk->sk_v6_daddr),
++ inet->inet_dport);
++#endif
++
+ if (!tp->write_seq && likely(!tp->repair))
+ tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
+ sk->sk_v6_daddr.s6_addr32,
+@@ -1215,7 +1231,8 @@ static void tcp_v6_restore_cb(struct sk_buff *skb)
+ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
+ {
+ struct ipv6_pinfo *np = inet6_sk(sk);
+- struct tcp_sock *tp;
++ struct tcp_sock *tp = tcp_sk(sk);
++ struct tcphdr *th = tcp_hdr(skb);
+ struct sk_buff *opt_skb = NULL;
+
+ /* Imagine: socket is IPv6. IPv4 packet arrives,
+@@ -1275,6 +1292,13 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
+ if (tcp_checksum_complete(skb))
+ goto csum_err;
+
++#ifdef CONFIG_TCP_STEALTH
++ if (sk->sk_state == TCP_LISTEN && th->syn && !th->fin &&
++ tp->stealth.mode & TCP_STEALTH_MODE_AUTH &&
++ tcp_stealth_do_auth(sk, skb))
++ goto reset;
++#endif
++
+ if (sk->sk_state == TCP_LISTEN) {
+ struct sock *nsk = tcp_v6_cookie_check(sk, skb);
+