diff options
author | David P <megver83@openmailbox.org> | 2017-10-31 14:45:45 -0300 |
---|---|---|
committer | David P <megver83@openmailbox.org> | 2017-10-31 19:49:25 -0300 |
commit | 861cc5acaf28fbc7228f8f41aa194c03e27d4359 (patch) | |
tree | 3011ad0cdb7c28b82224ef3d4d8bc592d1eff593 /kernels/linux-libre-lts-knock | |
parent | 8e21be8d54c767339cba76c4280e7ce288fac07e (diff) | |
download | abslibre-861cc5acaf28fbc7228f8f41aa194c03e27d4359.tar.gz abslibre-861cc5acaf28fbc7228f8f41aa194c03e27d4359.tar.bz2 abslibre-861cc5acaf28fbc7228f8f41aa194c03e27d4359.zip |
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.patch | 35632 | ||||
-rw-r--r-- | kernels/linux-libre-lts-knock/tcp_stealth_4.9_1.diff | 642 |
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 = <®_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 = <®_usbh1_reset>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbh1>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_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 = <®_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 = <®_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 = <®_arm>; ++ soc-supply = <®_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 = <ðphy0>; ++ status = "okay"; ++}; ++ ++&fec2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet2>; ++ phy-mode = "rmii"; ++ phy-handle = <ðphy1>; ++ 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"; ++}; ++ ++®_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 = <®_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 = ðernet; + }; + + 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, ®); ++ 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, ®), ++ 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, ®_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); + |