diff options
author | Nicolas Chauvet <kwizart@gmail.com> | 2014-07-15 21:21:38 +0200 |
---|---|---|
committer | Nicolas Chauvet <kwizart@gmail.com> | 2014-08-09 22:11:38 +0200 |
commit | 186a708bb62ba479c094d3f2ba5dd5199ebfb657 (patch) | |
tree | f59e1ddfb97d7a2eb4dea955891277fed16f0f5a | |
parent | 81a6ef5279efc4fdb7f37eed27bbebde1ddad376 (diff) | |
download | kernel-186a708bb62ba479c094d3f2ba5dd5199ebfb657.tar.gz kernel-186a708bb62ba479c094d3f2ba5dd5199ebfb657.tar.xz kernel-186a708bb62ba479c094d3f2ba5dd5199ebfb657.zip |
Resync with tegra-next 20140715
-rw-r--r-- | tegra-bp-next-3.17.patch | 4941 |
1 files changed, 4407 insertions, 534 deletions
diff --git a/tegra-bp-next-3.17.patch b/tegra-bp-next-3.17.patch index 946f8707..05f1dd20 100644 --- a/tegra-bp-next-3.17.patch +++ b/tegra-bp-next-3.17.patch @@ -74,6 +74,55 @@ index 0000000..d8c98c7 + }; + + +diff --git a/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt b/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt +new file mode 100644 +index 0000000..23bfe8e +--- /dev/null ++++ b/Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt +@@ -0,0 +1,43 @@ ++NVIDIA GK20A Graphics Processing Unit ++ ++Required properties: ++- compatible: "nvidia,<chip>-<gpu>" ++ Currently recognized values: ++ - nvidia,tegra124-gk20a ++- reg: Physical base address and length of the controller's registers. ++ Must contain two entries: ++ - first entry for bar0 ++ - second entry for bar1 ++- interrupts: Must contain an entry for each entry in interrupt-names. ++ See ../interrupt-controller/interrupts.txt for details. ++- interrupt-names: Must include the following entries: ++ - stall ++ - nonstall ++- vdd-supply: regulator for supply voltage. ++- clocks: Must contain an entry for each entry in clock-names. ++ See ../clocks/clock-bindings.txt for details. ++- clock-names: Must include the following entries: ++ - gpu ++ - pwr ++- resets: Must contain an entry for each entry in reset-names. ++ See ../reset/reset.txt for details. ++- reset-names: Must include the following entries: ++ - gpu ++ ++Example: ++ ++ gpu@0,57000000 { ++ compatible = "nvidia,gk20a"; ++ reg = <0x0 0x57000000 0x0 0x01000000>, ++ <0x0 0x58000000 0x0 0x01000000>; ++ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "stall", "nonstall"; ++ vdd-supply = <&vdd_gpu>; ++ clocks = <&tegra_car TEGRA124_CLK_GPU>, ++ <&tegra_car TEGRA124_CLK_PLL_P_OUT5>; ++ clock-names = "gpu", "pwr"; ++ resets = <&tegra_car 184>; ++ reset-names = "gpu"; ++ status = "disabled"; ++ }; diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt new file mode 100644 index 0000000..b97b8be @@ -141,6 +190,139 @@ index c300391..0823362 100644 Root ports are defined as subnodes of the PCIe controller node. Required properties: +diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt +new file mode 100644 +index 0000000..2f9c0bd +--- /dev/null ++++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt +@@ -0,0 +1,127 @@ ++Device tree binding for NVIDIA Tegra XUSB pad controller ++======================================================== ++ ++The Tegra XUSB pad controller manages a set of lanes, each of which can be ++assigned to one out of a set of different pads. Some of these pads have an ++associated PHY that must be powered up before the pad can be used. ++ ++This document defines the device-specific binding for the XUSB pad controller. ++ ++Refer to pinctrl-bindings.txt in this directory for generic information about ++pin controller device tree bindings and ../phy/phy-bindings.txt for details on ++how to describe and reference PHYs in device trees. ++ ++Required properties: ++-------------------- ++- compatible: should be "nvidia,tegra124-xusb-padctl" ++- reg: Physical base address and length of the controller's registers. ++- resets: Must contain an entry for each entry in reset-names. ++ See ../reset/reset.txt for details. ++- reset-names: Must include the following entries: ++ - padctl ++- #phy-cells: Should be 1. The specifier is the index of the PHY to reference. ++ See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values. ++ ++Lane muxing: ++------------ ++ ++Child nodes contain the pinmux configurations following the conventions from ++the pinctrl-bindings.txt document. Typically a single, static configuration is ++given and applied at boot time. ++ ++Each subnode describes groups of lanes along with parameters and pads that ++they should be assigned to. The name of these subnodes is not important. All ++subnodes should be parsed solely based on their content. ++ ++Each subnode only applies the parameters that are explicitly listed. In other ++words, if a subnode that lists a function but no pin configuration parameters ++implies no information about any pin configuration parameters. Similarly, a ++subnode that describes only an IDDQ parameter implies no information about ++what function the pins are assigned to. For this reason even seemingly boolean ++values are actually tristates in this binding: unspecified, off or on. ++Unspecified is represented as an absent property, and off/on are represented ++as integer values 0 and 1. ++ ++Required properties: ++- nvidia,lanes: An array of strings. Each string is the name of a lane. ++ ++Optional properties: ++- nvidia,function: A string that is the name of the function (pad) that the ++ pin or group should be assigned to. Valid values for function names are ++ listed below. ++- nvidia,iddq: Enables IDDQ mode of the lane. (0: no, 1: yes) ++ ++Note that not all of these properties are valid for all lanes. Lanes can be ++divided into three groups: ++ ++ - otg-0, otg-1, otg-2: ++ ++ Valid functions for this group are: "snps", "xusb", "uart", "rsvd". ++ ++ The nvidia,iddq property does not apply to this group. ++ ++ - ulpi-0, hsic-0, hsic-1: ++ ++ Valid functions for this group are: "snps", "xusb". ++ ++ The nvidia,iddq property does not apply to this group. ++ ++ - pcie-0, pcie-1, pcie-2, pcie-3, pcie-4, sata-0: ++ ++ Valid functions for this group are: "pcie", "usb3", "sata", "rsvd". ++ ++ ++Example: ++======== ++ ++SoC file extract: ++----------------- ++ ++ padctl@0,7009f000 { ++ compatible = "nvidia,tegra124-xusb-padctl"; ++ reg = <0x0 0x7009f000 0x0 0x1000>; ++ resets = <&tegra_car 142>; ++ reset-names = "padctl"; ++ ++ #phy-cells = <1>; ++ }; ++ ++Board file extract: ++------------------- ++ ++ pcie-controller@0,01003000 { ++ ... ++ ++ phys = <&padctl 0>; ++ phy-names = "pcie"; ++ ++ ... ++ }; ++ ++ ... ++ ++ padctl: padctl@0,7009f000 { ++ pinctrl-0 = <&padctl_default>; ++ pinctrl-names = "default"; ++ ++ padctl_default: pinmux { ++ usb3 { ++ nvidia,lanes = "pcie-0", "pcie-1"; ++ nvidia,function = "usb3"; ++ nvidia,iddq = <0>; ++ }; ++ ++ pcie { ++ nvidia,lanes = "pcie-2", "pcie-3", ++ "pcie-4"; ++ nvidia,function = "pcie"; ++ nvidia,iddq = <0>; ++ }; ++ ++ sata { ++ nvidia,lanes = "sata-0"; ++ nvidia,function = "sata"; ++ nvidia,iddq = <0>; ++ }; ++ }; ++ }; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5986ff6..906fb67 100644 --- a/arch/arm/boot/dts/Makefile @@ -379,6 +561,119 @@ index 079fdf9..7bd2df1 100644 }; + +#include "cros-ec-keyboard.dtsi" +diff --git a/arch/arm/boot/dts/tegra114-roth.dts b/arch/arm/boot/dts/tegra114-roth.dts +index 0b0e8e0..c7c6825 100644 +--- a/arch/arm/boot/dts/tegra114-roth.dts ++++ b/arch/arm/boot/dts/tegra114-roth.dts +@@ -28,6 +28,22 @@ + reg = <0x80000000 0x79600000>; + }; + ++ host1x@50000000 { ++ dsi@54300000 { ++ status = "okay"; ++ ++ vdd-supply = <&vdd_1v2_ap>; ++ ++ panel@0 { ++ compatible = "lg,lh500wx1-sd03"; ++ reg = <0>; ++ ++ power-supply = <&vdd_lcd>; ++ backlight = <&backlight>; ++ }; ++ }; ++ }; ++ + pinmux@70000868 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; +@@ -244,7 +260,7 @@ + nvidia,function = "sdmmc1"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; +- nvidia,enable-input = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + sdmmc1_cmd_pz1 { + nvidia,pins = "sdmmc1_cmd_pz1", +@@ -262,7 +278,7 @@ + nvidia,function = "sdmmc3"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; +- nvidia,enable-input = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + sdmmc3_cmd_pa7 { + nvidia,pins = "sdmmc3_cmd_pa7", +@@ -290,7 +306,7 @@ + nvidia,function = "sdmmc4"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; +- nvidia,enable-input = <TEGRA_PIN_DISABLE>; ++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + sdmmc4_cmd_pt7 { + nvidia,pins = "sdmmc4_cmd_pt7", +@@ -730,7 +746,6 @@ + nvidia,pins = "drive_sdio1"; + nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; + nvidia,schmitt = <TEGRA_PIN_DISABLE>; +- nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; + nvidia,pull-down-strength = <36>; + nvidia,pull-up-strength = <20>; + nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_SLOW>; +@@ -740,7 +755,6 @@ + nvidia,pins = "drive_sdio3"; + nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; + nvidia,schmitt = <TEGRA_PIN_DISABLE>; +- nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; + nvidia,pull-down-strength = <36>; + nvidia,pull-up-strength = <20>; + nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; +@@ -750,12 +764,10 @@ + nvidia,pins = "drive_gma"; + nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; + nvidia,schmitt = <TEGRA_PIN_DISABLE>; +- nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; + nvidia,pull-down-strength = <2>; + nvidia,pull-up-strength = <2>; + nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; + nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>; +- nvidia,drive-type = <1>; + }; + }; + }; +@@ -815,7 +827,6 @@ + regulator-name = "vdd-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +- regulator-always-on; + regulator-boot-on; + }; + +@@ -862,10 +873,11 @@ + regulator-name = "vdd-2v8-display"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; ++ regulator-always-on; + regulator-boot-on; + }; + +- ldo3 { ++ vdd_1v2_ap: ldo3 { + regulator-name = "avdd-1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; +@@ -1052,7 +1064,7 @@ + regulator-boot-on; + }; + +- regulator@1 { ++ vdd_lcd: regulator@1 { + compatible = "regulator-fixed"; + reg = <1>; + regulator-name = "vdd_lcd_1v8"; diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index fdc559a..335a1d8 100644 --- a/arch/arm/boot/dts/tegra114.dtsi @@ -413,10 +708,70 @@ index fdc559a..335a1d8 100644 compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu"; reg = <0x70019010 0x02c diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts -index e31fb61..16082c0 100644 +index e31fb61..624b0fb 100644 --- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts -@@ -1633,6 +1633,7 @@ +@@ -1461,7 +1461,7 @@ + regulator-max-microamp = <3500000>; + regulator-always-on; + regulator-boot-on; +- ams,external-control = <2>; ++ ams,ext-control = <2>; + }; + + sd1 { +@@ -1472,7 +1472,7 @@ + regulator-max-microamp = <2500000>; + regulator-always-on; + regulator-boot-on; +- ams,external-control = <1>; ++ ams,ext-control = <1>; + }; + + vdd_1v35_lp0: sd2 { +@@ -1521,7 +1521,7 @@ + regulator-max-microvolt = <1050000>; + regulator-boot-on; + regulator-always-on; +- ams,external-control = <1>; ++ ams,ext-control = <1>; + }; + + ldo1 { +@@ -1619,6 +1619,32 @@ + nvidia,sys-clock-req-active-high; + }; + ++ padctl@0,7009f000 { ++ pinctrl-0 = <&padctl_default>; ++ pinctrl-names = "default"; ++ ++ padctl_default: pinmux { ++ usb3 { ++ nvidia,lanes = "pcie-0", "pcie-1"; ++ nvidia,function = "usb3"; ++ nvidia,iddq = <0>; ++ }; ++ ++ pcie { ++ nvidia,lanes = "pcie-2", "pcie-3", ++ "pcie-4"; ++ nvidia,function = "pcie"; ++ nvidia,iddq = <0>; ++ }; ++ ++ sata { ++ nvidia,lanes = "sata-0"; ++ nvidia,function = "sata"; ++ nvidia,iddq = <0>; ++ }; ++ }; ++ }; ++ + /* SD card */ + sdhci@0,700b0400 { + status = "okay"; +@@ -1633,6 +1659,7 @@ sdhci@0,700b0600 { status = "okay"; bus-width = <8>; @@ -425,9 +780,36 @@ index e31fb61..16082c0 100644 ahub@0,70300000 { diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts -index f0bb842..f1a5bac 100644 +index f0bb842..70ad91d 100644 --- a/arch/arm/boot/dts/tegra124-venice2.dts +++ b/arch/arm/boot/dts/tegra124-venice2.dts +@@ -682,7 +682,7 @@ + regulator-max-microamp = <3500000>; + regulator-always-on; + regulator-boot-on; +- ams,external-control = <2>; ++ ams,ext-control = <2>; + }; + + sd1 { +@@ -693,7 +693,7 @@ + regulator-max-microamp = <2500000>; + regulator-always-on; + regulator-boot-on; +- ams,external-control = <1>; ++ ams,ext-control = <1>; + }; + + vdd_1v35_lp0: sd2 { +@@ -742,7 +742,7 @@ + regulator-max-microvolt = <1050000>; + regulator-boot-on; + regulator-always-on; +- ams,external-control = <1>; ++ ams,ext-control = <1>; + }; + + ldo1 { @@ -816,7 +816,7 @@ spi@0,7000d400 { status = "okay"; @@ -576,10 +958,40 @@ index f0bb842..f1a5bac 100644 + +#include "cros-ec-keyboard.dtsi" diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi -index 6e6bc4e..d675186 100644 +index 6e6bc4e..3af46d3 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi -@@ -179,6 +179,12 @@ +@@ -1,6 +1,7 @@ + #include <dt-bindings/clock/tegra124-car.h> + #include <dt-bindings/gpio/tegra-gpio.h> + #include <dt-bindings/pinctrl/pinctrl-tegra.h> ++#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + #include "skeleton.dtsi" +@@ -102,6 +103,21 @@ + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + ++ gpu@0,57000000 { ++ compatible = "nvidia,gk20a"; ++ reg = <0x0 0x57000000 0x0 0x01000000>, ++ <0x0 0x58000000 0x0 0x01000000>; ++ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, ++ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "stall", "nonstall"; ++ clocks = <&tegra_car TEGRA124_CLK_GPU>, ++ <&tegra_car TEGRA124_CLK_PLL_P_OUT5>; ++ clock-names = "gpu", "pwr"; ++ resets = <&tegra_car 184>; ++ reset-names = "gpu"; ++ status = "disabled"; ++ }; ++ + timer@0,60005000 { + compatible = "nvidia,tegra124-timer", "nvidia,tegra20-timer"; + reg = <0x0 0x60005000 0x0 0x400>; +@@ -179,6 +195,12 @@ #dma-cells = <1>; }; @@ -592,7 +1004,7 @@ index 6e6bc4e..d675186 100644 pinmux: pinmux@0,70000868 { compatible = "nvidia,tegra124-pinmux"; reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */ -@@ -449,6 +455,30 @@ +@@ -449,6 +471,39 @@ clock-names = "pclk", "clk32k_in"; }; @@ -620,6 +1032,15 @@ index 6e6bc4e..d675186 100644 + status = "disabled"; + }; + ++ padctl: padctl@0,7009f000 { ++ compatible = "nvidia,tegra124-xusb-padctl"; ++ reg = <0x0 0x7009f000 0x0 0x1000>; ++ resets = <&tegra_car 142>; ++ reset-names = "padctl"; ++ ++ #phy-cells = <1>; ++ }; ++ sdhci@0,700b0000 { compatible = "nvidia,tegra124-sdhci"; reg = <0x0 0x700b0000 0x0 0x200>; @@ -1958,10 +2379,43 @@ index dec4fc8..0b1ede9 100644 compatible = "nvidia,tegra30-ahub"; reg = <0x70080000 0x200 diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig -index 157a4f1..285c433 100644 +index fb25e29..285c433 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig -@@ -104,6 +104,7 @@ CONFIG_SCSI_MULTI_LUN=y +@@ -23,14 +23,11 @@ CONFIG_MODULE_FORCE_UNLOAD=y + CONFIG_PARTITION_ADVANCED=y + # CONFIG_IOSCHED_DEADLINE is not set + # CONFIG_IOSCHED_CFQ is not set +-CONFIG_GPIO_PCA953X=y + CONFIG_ARCH_TEGRA=y + CONFIG_ARCH_TEGRA_2x_SOC=y + CONFIG_ARCH_TEGRA_3x_SOC=y + CONFIG_ARCH_TEGRA_114_SOC=y + CONFIG_ARCH_TEGRA_124_SOC=y +-CONFIG_TEGRA_EMC_SCALING_ENABLE=y +-CONFIG_TRUSTED_FOUNDATIONS=y + CONFIG_PCI=y + CONFIG_PCI_MSI=y + CONFIG_PCI_TEGRA=y +@@ -74,9 +71,6 @@ CONFIG_IPV6_MIP6=y + CONFIG_IPV6_TUNNEL=y + CONFIG_IPV6_MULTIPLE_TABLES=y + CONFIG_CAN=y +-CONFIG_CAN_RAW=y +-CONFIG_CAN_BCM=y +-CONFIG_CAN_DEV=y + CONFIG_CAN_MCP251X=y + CONFIG_BT=y + CONFIG_BT_RFCOMM=y +@@ -96,7 +90,6 @@ CONFIG_CMA_SIZE_MBYTES=64 + CONFIG_MTD=y + CONFIG_MTD_M25P80=y + CONFIG_MTD_SPI_NOR=y +-CONFIG_PROC_DEVICETREE=y + CONFIG_BLK_DEV_LOOP=y + CONFIG_AD525X_DPOT=y + CONFIG_AD525X_DPOT_I2C=y +@@ -111,6 +104,7 @@ CONFIG_SCSI_MULTI_LUN=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y @@ -1969,7 +2423,7 @@ index 157a4f1..285c433 100644 CONFIG_R8169=y CONFIG_USB_PEGASUS=y CONFIG_USB_USBNET=y -@@ -118,6 +119,8 @@ CONFIG_KEYBOARD_GPIO=y +@@ -125,6 +119,8 @@ CONFIG_KEYBOARD_GPIO=y CONFIG_KEYBOARD_TEGRA=y CONFIG_KEYBOARD_CROS_EC=y CONFIG_MOUSE_PS2_ELANTECH=y @@ -1978,7 +2432,7 @@ index 157a4f1..285c433 100644 CONFIG_INPUT_MISC=y CONFIG_INPUT_MPU3050=y # CONFIG_LEGACY_PTYS is not set -@@ -128,6 +131,7 @@ CONFIG_SERIAL_TEGRA=y +@@ -135,6 +131,7 @@ CONFIG_SERIAL_TEGRA=y CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_I2C_COMPAT is not set @@ -1986,7 +2440,15 @@ index 157a4f1..285c433 100644 CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_MUX_PINCTRL=y CONFIG_I2C_TEGRA=y -@@ -149,10 +153,12 @@ CONFIG_POWER_RESET=y +@@ -144,6 +141,7 @@ CONFIG_SPI_TEGRA20_SFLASH=y + CONFIG_SPI_TEGRA20_SLINK=y + CONFIG_PINCTRL_AS3722=y + CONFIG_PINCTRL_PALMAS=y ++CONFIG_GPIO_PCA953X=y + CONFIG_GPIO_PCA953X_IRQ=y + CONFIG_GPIO_PALMAS=y + CONFIG_GPIO_TPS6586X=y +@@ -155,10 +153,12 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_AS3722=y CONFIG_POWER_RESET_GPIO=y CONFIG_SENSORS_LM90=y @@ -1999,7 +2461,7 @@ index 157a4f1..285c433 100644 CONFIG_MFD_PALMAS=y CONFIG_MFD_TPS65090=y CONFIG_MFD_TPS6586X=y -@@ -215,6 +221,7 @@ CONFIG_MMC_SDHCI_TEGRA=y +@@ -221,6 +221,7 @@ CONFIG_MMC_SDHCI_TEGRA=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y @@ -2007,6 +2469,12 @@ index 157a4f1..285c433 100644 CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y +@@ -291,5 +292,4 @@ CONFIG_DEBUG_LL=y + CONFIG_EARLY_PRINTK=y + CONFIG_CRYPTO_TWOFISH=y + # CONFIG_CRYPTO_ANSI_CPRNG is not set +-CONFIG_CRYPTO_DEV_TEGRA_AES=y + CONFIG_CRC_CCITT=y diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c index 5306de3..312d43e 100644 --- a/arch/arm/lib/delay.c @@ -2078,23 +2546,24 @@ index 5306de3..312d43e 100644 + delay_calibrated = true; +} diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile -index 6fbfbb7..c303b55 100644 +index 6fbfbb7..34c05b7 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile -@@ -2,24 +2,20 @@ asflags-y += -march=armv7-a +@@ -2,24 +2,19 @@ asflags-y += -march=armv7-a obj-y += io.o obj-y += irq.o -obj-y += fuse.o - obj-y += pmc.o +-obj-y += pmc.o obj-y += flowctrl.o - obj-y += powergate.o +-obj-y += powergate.o -obj-y += apbio.o obj-y += pm.o obj-y += reset.o obj-y += reset-handler.o obj-y += sleep.o obj-y += tegra.o ++obj-y += tegra-pmc.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o @@ -2106,7 +2575,7 @@ index 6fbfbb7..c303b55 100644 obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) -@@ -28,7 +24,6 @@ endif +@@ -28,7 +23,6 @@ endif obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o @@ -2354,11 +2823,134 @@ index f05d71c..0000000 -u32 tegra_apb_readl(unsigned long offset); -void tegra_apb_writel(u32 value, unsigned long offset); -#endif +diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c +index 9c6029b..bb4782a 100644 +--- a/arch/arm/mach-tegra/board-paz00.c ++++ b/arch/arm/mach-tegra/board-paz00.c +@@ -17,9 +17,10 @@ + * + */ + +-#include <linux/platform_device.h> + #include <linux/gpio/driver.h> ++#include <linux/platform_device.h> + #include <linux/rfkill-gpio.h> ++ + #include "board.h" + + static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = { +diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h +index bcf5dbf..da90c89 100644 +--- a/arch/arm/mach-tegra/board.h ++++ b/arch/arm/mach-tegra/board.h +@@ -28,13 +28,6 @@ + void __init tegra_map_common_io(void); + void __init tegra_init_irq(void); + +-int __init tegra_powergate_init(void); +-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) && defined(CONFIG_DEBUG_FS) +-int __init tegra_powergate_debugfs_init(void); +-#else +-static inline int tegra_powergate_debugfs_init(void) { return 0; } +-#endif +- + void __init tegra_paz00_wifikill_init(void); + + #endif +diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c +index b5fb7c1..e3ebdce 100644 +--- a/arch/arm/mach-tegra/cpuidle-tegra114.c ++++ b/arch/arm/mach-tegra/cpuidle-tegra114.c +@@ -14,16 +14,16 @@ + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +-#include <linux/kernel.h> +-#include <linux/module.h> ++#include <asm/firmware.h> ++#include <linux/clockchips.h> + #include <linux/cpuidle.h> + #include <linux/cpu_pm.h> +-#include <linux/clockchips.h> +-#include <asm/firmware.h> ++#include <linux/kernel.h> ++#include <linux/module.h> + + #include <asm/cpuidle.h> +-#include <asm/suspend.h> + #include <asm/smp_plat.h> ++#include <asm/suspend.h> + + #include "pm.h" + #include "sleep.h" +diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c +index b82dcae..b30bf5c 100644 +--- a/arch/arm/mach-tegra/cpuidle-tegra20.c ++++ b/arch/arm/mach-tegra/cpuidle-tegra20.c +@@ -19,23 +19,23 @@ + * more details. + */ + +-#include <linux/kernel.h> +-#include <linux/module.h> ++#include <linux/clk/tegra.h> ++#include <linux/clockchips.h> + #include <linux/cpuidle.h> + #include <linux/cpu_pm.h> +-#include <linux/clockchips.h> +-#include <linux/clk/tegra.h> ++#include <linux/kernel.h> ++#include <linux/module.h> + + #include <asm/cpuidle.h> + #include <asm/proc-fns.h> +-#include <asm/suspend.h> + #include <asm/smp_plat.h> ++#include <asm/suspend.h> + +-#include "pm.h" +-#include "sleep.h" ++#include "flowctrl.h" + #include "iomap.h" + #include "irq.h" +-#include "flowctrl.h" ++#include "pm.h" ++#include "sleep.h" + + #ifdef CONFIG_PM_SLEEP + static bool abort_flag; +diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c +index ed2a2a7..3556127 100644 +--- a/arch/arm/mach-tegra/cpuidle-tegra30.c ++++ b/arch/arm/mach-tegra/cpuidle-tegra30.c +@@ -19,17 +19,17 @@ + * more details. + */ + +-#include <linux/kernel.h> +-#include <linux/module.h> ++#include <linux/clk/tegra.h> ++#include <linux/clockchips.h> + #include <linux/cpuidle.h> + #include <linux/cpu_pm.h> +-#include <linux/clockchips.h> +-#include <linux/clk/tegra.h> ++#include <linux/kernel.h> ++#include <linux/module.h> + + #include <asm/cpuidle.h> + #include <asm/proc-fns.h> +-#include <asm/suspend.h> + #include <asm/smp_plat.h> ++#include <asm/suspend.h> + + #include "pm.h" + #include "sleep.h" diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c -index 7bc5d8d..ff0a10b 100644 +index 7bc5d8d..b27330c 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c -@@ -23,8 +23,8 @@ +@@ -23,13 +23,13 @@ #include <linux/kernel.h> #include <linux/module.h> @@ -2368,14 +2960,35 @@ index 7bc5d8d..ff0a10b 100644 #include "cpuidle.h" void __init tegra_cpuidle_init(void) + { +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra20_cpuidle_init(); +@@ -49,7 +49,7 @@ void __init tegra_cpuidle_init(void) + + void tegra_cpuidle_pcie_irqs_in_use(void) + { +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra20_cpuidle_pcie_irqs_in_use(); diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c -index ce8ab8a..4b31091 100644 +index ce8ab8a..2106b3d 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c -@@ -22,10 +22,10 @@ - #include <linux/kernel.h> +@@ -18,14 +18,14 @@ + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + ++#include <linux/cpumask.h> + #include <linux/init.h> +-#include <linux/kernel.h> #include <linux/io.h> - #include <linux/cpumask.h> +-#include <linux/cpumask.h> ++#include <linux/kernel.h> +#include <linux/tegra-soc.h> #include "flowctrl.h" @@ -2384,6 +2997,24 @@ index ce8ab8a..4b31091 100644 static u8 flowctrl_offset_halt_cpu[] = { FLOW_CTRL_HALT_CPU0_EVENTS, +@@ -76,7 +76,7 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid) + int i; + + reg = flowctrl_read_cpu_csr(cpuid); +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + /* clear wfe bitmap */ + reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; +@@ -117,7 +117,7 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid) + + /* Disable powergating via flow controller for CPU0 */ + reg = flowctrl_read_cpu_csr(cpuid); +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + /* clear wfe bitmap */ + reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c deleted file mode 100644 index c9ac23b..0000000 @@ -2728,13 +3359,18 @@ index c01d047..0000000 - -#endif diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c -index ff26af2..38c5170 100644 +index ff26af2..e2ea4aa 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c -@@ -10,10 +10,10 @@ +@@ -7,13 +7,14 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ ++ ++#include <linux/clk/tegra.h> #include <linux/kernel.h> #include <linux/smp.h> - #include <linux/clk/tegra.h> +-#include <linux/clk/tegra.h> +#include <linux/tegra-soc.h> #include <asm/smp_plat.h> @@ -2743,79 +3379,444 @@ index ff26af2..38c5170 100644 #include "sleep.h" static void (*tegra_hotplug_shutdown)(void); +@@ -36,6 +37,11 @@ int tegra_cpu_kill(unsigned cpu) + */ + void __ref tegra_cpu_die(unsigned int cpu) + { ++ if (!tegra_hotplug_shutdown) { ++ WARN(1, "hotplug is not yet initialized\n"); ++ return; ++ } ++ + /* Clean L1 data cache */ + tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS); + +@@ -46,17 +52,20 @@ void __ref tegra_cpu_die(unsigned int cpu) + BUG(); + } + +-void __init tegra_hotplug_init(void) ++static int __init tegra_hotplug_init(void) + { + if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) +- return; ++ return 0; + +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) + tegra_hotplug_shutdown = tegra20_hotplug_shutdown; +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; ++ ++ return 0; + } ++pure_initcall(tegra_hotplug_init); +diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c +index bb9c9c2..352de15 100644 +--- a/arch/arm/mach-tegra/io.c ++++ b/arch/arm/mach-tegra/io.c +@@ -18,14 +18,14 @@ + * + */ + +-#include <linux/kernel.h> +-#include <linux/module.h> + #include <linux/init.h> +-#include <linux/mm.h> + #include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/module.h> + +-#include <asm/page.h> + #include <asm/mach/map.h> ++#include <asm/page.h> + + #include "board.h" + #include "iomap.h" +diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c +index 1a74d56..da7be13 100644 +--- a/arch/arm/mach-tegra/irq.c ++++ b/arch/arm/mach-tegra/irq.c +@@ -17,14 +17,14 @@ + * + */ + +-#include <linux/kernel.h> + #include <linux/cpu_pm.h> + #include <linux/interrupt.h> +-#include <linux/irq.h> + #include <linux/io.h> +-#include <linux/of.h> +-#include <linux/of_address.h> + #include <linux/irqchip/arm-gic.h> ++#include <linux/irq.h> ++#include <linux/kernel.h> ++#include <linux/of_address.h> ++#include <linux/of.h> + #include <linux/syscore_ops.h> + + #include "board.h" diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c -index 929d104..d9878ac 100644 +index 929d104..53e8442 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c -@@ -19,13 +19,13 @@ +@@ -11,27 +11,26 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +-#include <linux/init.h> +-#include <linux/errno.h> ++ ++#include <linux/clk/tegra.h> + #include <linux/delay.h> + #include <linux/device.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/io.h> + #include <linux/jiffies.h> #include <linux/smp.h> - #include <linux/io.h> - #include <linux/clk/tegra.h> +-#include <linux/io.h> +-#include <linux/clk/tegra.h> +#include <linux/tegra-soc.h> #include <asm/cacheflush.h> #include <asm/mach-types.h> - #include <asm/smp_scu.h> +-#include <asm/smp_scu.h> #include <asm/smp_plat.h> - +- -#include "fuse.h" - #include "flowctrl.h" - #include "reset.h" - #include "pmc.h" +-#include "flowctrl.h" +-#include "reset.h" +-#include "pmc.h" ++#include <asm/smp_scu.h> + + #include "common.h" ++#include "flowctrl.h" + #include "iomap.h" ++#include "reset.h" + + static cpumask_t tegra_cpu_init_mask; + +@@ -170,13 +169,13 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle) + static int tegra_boot_secondary(unsigned int cpu, + struct task_struct *idle) + { +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) + return tegra20_boot_secondary(cpu, idle); +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) + return tegra30_boot_secondary(cpu, idle); +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) + return tegra114_boot_secondary(cpu, idle); +- if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124) ++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) + return tegra114_boot_secondary(cpu, idle); + + return -EINVAL; +diff --git a/arch/arm/mach-tegra/pm-tegra20.c b/arch/arm/mach-tegra/pm-tegra20.c +index d65e1d7..39ac2b7 100644 +--- a/arch/arm/mach-tegra/pm-tegra20.c ++++ b/arch/arm/mach-tegra/pm-tegra20.c +@@ -13,6 +13,7 @@ + * 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/kernel.h> + + #include "pm.h" +diff --git a/arch/arm/mach-tegra/pm-tegra30.c b/arch/arm/mach-tegra/pm-tegra30.c +index 8fa326d..46cc19d 100644 +--- a/arch/arm/mach-tegra/pm-tegra30.c ++++ b/arch/arm/mach-tegra/pm-tegra30.c +@@ -13,6 +13,7 @@ + * 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/kernel.h> + + #include "pm.h" diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c -index f55b05a..d7e6370 100644 +index f55b05a..d9637d8 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c -@@ -26,6 +26,7 @@ +@@ -16,30 +16,29 @@ + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +-#include <linux/kernel.h> +-#include <linux/spinlock.h> +-#include <linux/io.h> ++#include <linux/clk/tegra.h> + #include <linux/cpumask.h> +-#include <linux/delay.h> + #include <linux/cpu_pm.h> +-#include <linux/suspend.h> ++#include <linux/delay.h> #include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> #include <linux/slab.h> - #include <linux/clk/tegra.h> +-#include <linux/clk/tegra.h> ++#include <linux/spinlock.h> ++#include <linux/suspend.h> +#include <linux/tegra-soc.h> - #include <asm/smp_plat.h> +-#include <asm/smp_plat.h> #include <asm/cacheflush.h> -@@ -37,7 +38,6 @@ - #include "iomap.h" - #include "reset.h" +-#include <asm/suspend.h> + #include <asm/idmap.h> + #include <asm/proc-fns.h> ++#include <asm/smp_plat.h> ++#include <asm/suspend.h> + #include <asm/tlbflush.h> + +-#include "iomap.h" +-#include "reset.h" #include "flowctrl.h" -#include "fuse.h" ++#include "iomap.h" #include "pm.h" - #include "pmc.h" +-#include "pmc.h" ++#include "reset.h" #include "sleep.h" -diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c -index 7c7123e..e1677c0 100644 ---- a/arch/arm/mach-tegra/pmc.c -+++ b/arch/arm/mach-tegra/pmc.c -@@ -17,13 +17,12 @@ - #include <linux/kernel.h> - #include <linux/clk.h> --#include <linux/io.h> - #include <linux/of.h> - #include <linux/of_address.h> - #include <linux/tegra-powergate.h> -+#include <linux/tegra-soc.h> + #ifdef CONFIG_PM_SLEEP +@@ -53,7 +52,7 @@ static int (*tegra_sleep_func)(unsigned long v2p); - #include "flowctrl.h" --#include "fuse.h" - #include "pm.h" - #include "pmc.h" - #include "sleep.h" -@@ -60,9 +59,9 @@ static u8 tegra_cpu_domains[] = { - }; - static DEFINE_SPINLOCK(tegra_powergate_lock); + static void tegra_tear_down_cpu_init(void) + { +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra_tear_down_cpu = tegra20_tear_down_cpu; +@@ -143,7 +142,7 @@ bool tegra_set_cpu_in_lp2(void) + + if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask)) + last_cpu = true; +- else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1) ++ else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1) + tegra20_cpu_set_resettable_soon(); + + spin_unlock(&tegra_lp2_lock); +@@ -166,9 +165,29 @@ static int tegra_sleep_cpu(unsigned long v2p) + return 0; + } --static void __iomem *tegra_pmc_base; - static bool tegra_pmc_invert_interrupt; - static struct clk *tegra_pclk; -+void __iomem *tegra_pmc_base; ++static void tegra_pm_set(enum tegra_suspend_mode mode) ++{ ++ u32 value; ++ ++ switch (tegra_get_chip_id()) { ++ case TEGRA20: ++ case TEGRA30: ++ break; ++ default: ++ /* Turn off CRAIL */ ++ value = flowctrl_read_cpu_csr(0); ++ value &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK; ++ value |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL; ++ flowctrl_write_cpu_csr(0, value); ++ break; ++ } ++ ++ tegra_pmc_enter_suspend_mode(mode); ++} ++ + void tegra_idle_lp2_last(void) + { +- tegra_pmc_pm_set(TEGRA_SUSPEND_LP2); ++ tegra_pm_set(TEGRA_SUSPEND_LP2); - struct pmc_pm_data { - u32 cpu_good_time; /* CPU power good time in uS */ -@@ -80,16 +79,6 @@ struct pmc_pm_data { + cpu_cluster_pm_enter(); + suspend_cpu_complex(); +@@ -212,7 +231,7 @@ static int tegra_sleep_core(unsigned long v2p) + */ + static bool tegra_lp1_iram_hook(void) + { +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra20_lp1_iram_hook(); +@@ -242,7 +261,7 @@ static bool tegra_lp1_iram_hook(void) + + static bool tegra_sleep_core_init(void) + { +- switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA20: + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra20_sleep_core_init(); +@@ -267,8 +286,6 @@ static bool tegra_sleep_core_init(void) + + static void tegra_suspend_enter_lp1(void) + { +- tegra_pmc_suspend(); +- + /* copy the reset vector & SDRAM shutdown code into IRAM */ + memcpy(iram_save_addr, IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), + iram_save_size); +@@ -280,8 +297,6 @@ static void tegra_suspend_enter_lp1(void) + + static void tegra_suspend_exit_lp1(void) + { +- tegra_pmc_resume(); +- + /* restore IRAM */ + memcpy(IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), iram_save_addr, + iram_save_size); +@@ -306,7 +321,7 @@ static int tegra_suspend_enter(suspend_state_t state) + + pr_info("Entering suspend state %s\n", lp_state[mode]); + +- tegra_pmc_pm_set(mode); ++ tegra_pm_set(mode); + + local_fiq_disable(); + +@@ -354,7 +369,6 @@ void __init tegra_init_suspend(void) + return; + + tegra_tear_down_cpu_init(); +- tegra_pmc_suspend_init(); + + if (mode >= TEGRA_SUSPEND_LP1) { + if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) { +diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h +index f4a8969..83bc875 100644 +--- a/arch/arm/mach-tegra/pm.h ++++ b/arch/arm/mach-tegra/pm.h +@@ -21,12 +21,11 @@ + #ifndef _MACH_TEGRA_PM_H_ + #define _MACH_TEGRA_PM_H_ + +-#include "pmc.h" +- + struct tegra_lp1_iram { + void *start_addr; + void *end_addr; }; - static struct pmc_pm_data pmc_pm_data; ++ + extern struct tegra_lp1_iram tegra_lp1_iram; + extern void (*tegra_sleep_core_finish)(unsigned long v2p); + +@@ -42,15 +41,8 @@ void tegra_idle_lp2_last(void); + extern void (*tegra_tear_down_cpu)(void); + #ifdef CONFIG_PM_SLEEP +-enum tegra_suspend_mode tegra_pm_validate_suspend_mode( +- enum tegra_suspend_mode mode); + void tegra_init_suspend(void); + #else +-static inline enum tegra_suspend_mode tegra_pm_validate_suspend_mode( +- enum tegra_suspend_mode mode) +-{ +- return TEGRA_SUSPEND_NONE; +-} + static inline void tegra_init_suspend(void) {} + #endif + +diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c +deleted file mode 100644 +index 7c7123e..0000000 +--- a/arch/arm/mach-tegra/pmc.c ++++ /dev/null +@@ -1,413 +0,0 @@ +-/* +- * Copyright (C) 2012,2013 NVIDIA CORPORATION. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope 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/kernel.h> +-#include <linux/clk.h> +-#include <linux/io.h> +-#include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/tegra-powergate.h> +- +-#include "flowctrl.h" +-#include "fuse.h" +-#include "pm.h" +-#include "pmc.h" +-#include "sleep.h" +- +-#define TEGRA_POWER_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */ +-#define TEGRA_POWER_SYSCLK_OE (1 << 11) /* system clock enable */ +-#define TEGRA_POWER_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ +-#define TEGRA_POWER_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ +-#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ +- +-#define PMC_CTRL 0x0 +-#define PMC_CTRL_INTR_LOW (1 << 17) +-#define PMC_PWRGATE_TOGGLE 0x30 +-#define PMC_PWRGATE_TOGGLE_START (1 << 8) +-#define PMC_REMOVE_CLAMPING 0x34 +-#define PMC_PWRGATE_STATUS 0x38 +- +-#define PMC_SCRATCH0 0x50 +-#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) +-#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) +-#define PMC_SCRATCH0_MODE_RCM (1 << 1) +-#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ +- PMC_SCRATCH0_MODE_BOOTLOADER | \ +- PMC_SCRATCH0_MODE_RCM) +- +-#define PMC_CPUPWRGOOD_TIMER 0xc8 +-#define PMC_CPUPWROFF_TIMER 0xcc +- +-static u8 tegra_cpu_domains[] = { +- 0xFF, /* not available for CPU0 */ +- TEGRA_POWERGATE_CPU1, +- TEGRA_POWERGATE_CPU2, +- TEGRA_POWERGATE_CPU3, +-}; +-static DEFINE_SPINLOCK(tegra_powergate_lock); +- +-static void __iomem *tegra_pmc_base; +-static bool tegra_pmc_invert_interrupt; +-static struct clk *tegra_pclk; +- +-struct pmc_pm_data { +- u32 cpu_good_time; /* CPU power good time in uS */ +- u32 cpu_off_time; /* CPU power off time in uS */ +- u32 core_osc_time; /* Core power good osc time in uS */ +- u32 core_pmu_time; /* Core power good pmu time in uS */ +- u32 core_off_time; /* Core power off time in uS */ +- bool corereq_high; /* Core power request active-high */ +- bool sysclkreq_high; /* System clock request active-high */ +- bool combined_req; /* Combined pwr req for CPU & Core */ +- bool cpu_pwr_good_en; /* CPU power good signal is enabled */ +- u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */ +- u32 lp0_vec_size; /* The size of LP0 warm boot code */ +- enum tegra_suspend_mode suspend_mode; +-}; +-static struct pmc_pm_data pmc_pm_data; +- -static inline u32 tegra_pmc_readl(u32 reg) -{ - return readl(tegra_pmc_base + reg); @@ -2826,60 +3827,475 @@ index 7c7123e..e1677c0 100644 - writel(val, tegra_pmc_base + reg); -} - - static int tegra_pmc_get_cpu_powerdomain_id(int cpuid) - { - if (cpuid <= 0 || cpuid >= num_possible_cpus()) +-static int tegra_pmc_get_cpu_powerdomain_id(int cpuid) +-{ +- if (cpuid <= 0 || cpuid >= num_possible_cpus()) +- return -EINVAL; +- return tegra_cpu_domains[cpuid]; +-} +- +-static bool tegra_pmc_powergate_is_powered(int id) +-{ +- return (tegra_pmc_readl(PMC_PWRGATE_STATUS) >> id) & 1; +-} +- +-static int tegra_pmc_powergate_set(int id, bool new_state) +-{ +- bool old_state; +- unsigned long flags; +- +- spin_lock_irqsave(&tegra_powergate_lock, flags); +- +- old_state = tegra_pmc_powergate_is_powered(id); +- WARN_ON(old_state == new_state); +- +- tegra_pmc_writel(PMC_PWRGATE_TOGGLE_START | id, PMC_PWRGATE_TOGGLE); +- +- spin_unlock_irqrestore(&tegra_powergate_lock, flags); +- +- return 0; +-} +- +-static int tegra_pmc_powergate_remove_clamping(int id) +-{ +- u32 mask; +- +- /* +- * Tegra has a bug where PCIE and VDE clamping masks are +- * swapped relatively to the partition ids. +- */ +- if (id == TEGRA_POWERGATE_VDEC) +- mask = (1 << TEGRA_POWERGATE_PCIE); +- else if (id == TEGRA_POWERGATE_PCIE) +- mask = (1 << TEGRA_POWERGATE_VDEC); +- else +- mask = (1 << id); +- +- tegra_pmc_writel(mask, PMC_REMOVE_CLAMPING); +- +- return 0; +-} +- +-bool tegra_pmc_cpu_is_powered(int cpuid) +-{ +- int id; +- +- id = tegra_pmc_get_cpu_powerdomain_id(cpuid); +- if (id < 0) +- return false; +- return tegra_pmc_powergate_is_powered(id); +-} +- +-int tegra_pmc_cpu_power_on(int cpuid) +-{ +- int id; +- +- id = tegra_pmc_get_cpu_powerdomain_id(cpuid); +- if (id < 0) +- return id; +- return tegra_pmc_powergate_set(id, true); +-} +- +-int tegra_pmc_cpu_remove_clamping(int cpuid) +-{ +- int id; +- +- id = tegra_pmc_get_cpu_powerdomain_id(cpuid); +- if (id < 0) +- return id; +- return tegra_pmc_powergate_remove_clamping(id); +-} +- +-void tegra_pmc_restart(enum reboot_mode mode, const char *cmd) +-{ +- u32 val; +- +- val = tegra_pmc_readl(PMC_SCRATCH0); +- val &= ~PMC_SCRATCH0_MODE_MASK; +- +- if (cmd) { +- if (strcmp(cmd, "recovery") == 0) +- val |= PMC_SCRATCH0_MODE_RECOVERY; +- +- if (strcmp(cmd, "bootloader") == 0) +- val |= PMC_SCRATCH0_MODE_BOOTLOADER; +- +- if (strcmp(cmd, "forced-recovery") == 0) +- val |= PMC_SCRATCH0_MODE_RCM; +- } +- +- tegra_pmc_writel(val, PMC_SCRATCH0); +- +- val = tegra_pmc_readl(0); +- val |= 0x10; +- tegra_pmc_writel(val, 0); +-} +- +-#ifdef CONFIG_PM_SLEEP +-static void set_power_timers(u32 us_on, u32 us_off, unsigned long rate) +-{ +- unsigned long long ticks; +- unsigned long long pclk; +- static unsigned long tegra_last_pclk; +- +- if (WARN_ON_ONCE(rate <= 0)) +- pclk = 100000000; +- else +- pclk = rate; +- +- if ((rate != tegra_last_pclk)) { +- ticks = (us_on * pclk) + 999999ull; +- do_div(ticks, 1000000); +- tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWRGOOD_TIMER); +- +- ticks = (us_off * pclk) + 999999ull; +- do_div(ticks, 1000000); +- tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWROFF_TIMER); +- wmb(); +- } +- tegra_last_pclk = pclk; +-} +- +-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) +-{ +- return pmc_pm_data.suspend_mode; +-} +- +-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode) +-{ +- if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE) +- return; +- +- pmc_pm_data.suspend_mode = mode; +-} +- +-void tegra_pmc_suspend(void) +-{ +- tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41); +-} +- +-void tegra_pmc_resume(void) +-{ +- tegra_pmc_writel(0x0, PMC_SCRATCH41); +-} +- +-void tegra_pmc_pm_set(enum tegra_suspend_mode mode) +-{ +- u32 reg, csr_reg; +- unsigned long rate = 0; +- +- reg = tegra_pmc_readl(PMC_CTRL); +- reg |= TEGRA_POWER_CPU_PWRREQ_OE; +- reg &= ~TEGRA_POWER_EFFECT_LP0; +- +- switch (tegra_chip_id) { +- case TEGRA20: +- case TEGRA30: +- break; +- default: +- /* Turn off CRAIL */ +- csr_reg = flowctrl_read_cpu_csr(0); +- csr_reg &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK; +- csr_reg |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL; +- flowctrl_write_cpu_csr(0, csr_reg); +- break; +- } +- +- switch (mode) { +- case TEGRA_SUSPEND_LP1: +- rate = 32768; +- break; +- case TEGRA_SUSPEND_LP2: +- rate = clk_get_rate(tegra_pclk); +- break; +- default: +- break; +- } +- +- set_power_timers(pmc_pm_data.cpu_good_time, pmc_pm_data.cpu_off_time, +- rate); +- +- tegra_pmc_writel(reg, PMC_CTRL); +-} +- +-void tegra_pmc_suspend_init(void) +-{ +- u32 reg; +- +- /* Always enable CPU power request */ +- reg = tegra_pmc_readl(PMC_CTRL); +- reg |= TEGRA_POWER_CPU_PWRREQ_OE; +- tegra_pmc_writel(reg, PMC_CTRL); +- +- reg = tegra_pmc_readl(PMC_CTRL); +- +- if (!pmc_pm_data.sysclkreq_high) +- reg |= TEGRA_POWER_SYSCLK_POLARITY; +- else +- reg &= ~TEGRA_POWER_SYSCLK_POLARITY; +- +- /* configure the output polarity while the request is tristated */ +- tegra_pmc_writel(reg, PMC_CTRL); +- +- /* now enable the request */ +- reg |= TEGRA_POWER_SYSCLK_OE; +- tegra_pmc_writel(reg, PMC_CTRL); +-} +-#endif +- +-static const struct of_device_id matches[] __initconst = { +- { .compatible = "nvidia,tegra124-pmc" }, +- { .compatible = "nvidia,tegra114-pmc" }, +- { .compatible = "nvidia,tegra30-pmc" }, +- { .compatible = "nvidia,tegra20-pmc" }, +- { } +-}; +- +-void __init tegra_pmc_init_irq(void) +-{ +- struct device_node *np; +- u32 val; +- +- np = of_find_matching_node(NULL, matches); +- BUG_ON(!np); +- +- tegra_pmc_base = of_iomap(np, 0); +- +- tegra_pmc_invert_interrupt = of_property_read_bool(np, +- "nvidia,invert-interrupt"); +- +- val = tegra_pmc_readl(PMC_CTRL); +- if (tegra_pmc_invert_interrupt) +- val |= PMC_CTRL_INTR_LOW; +- else +- val &= ~PMC_CTRL_INTR_LOW; +- tegra_pmc_writel(val, PMC_CTRL); +-} +- +-void __init tegra_pmc_init(void) +-{ +- struct device_node *np; +- u32 prop; +- enum tegra_suspend_mode suspend_mode; +- u32 core_good_time[2] = {0, 0}; +- u32 lp0_vec[2] = {0, 0}; +- +- np = of_find_matching_node(NULL, matches); +- BUG_ON(!np); +- +- tegra_pclk = of_clk_get_by_name(np, "pclk"); +- WARN_ON(IS_ERR(tegra_pclk)); +- +- /* Grabbing the power management configurations */ +- if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) { +- suspend_mode = TEGRA_SUSPEND_NONE; +- } else { +- switch (prop) { +- case 0: +- suspend_mode = TEGRA_SUSPEND_LP0; +- break; +- case 1: +- suspend_mode = TEGRA_SUSPEND_LP1; +- break; +- case 2: +- suspend_mode = TEGRA_SUSPEND_LP2; +- break; +- default: +- suspend_mode = TEGRA_SUSPEND_NONE; +- break; +- } +- } +- suspend_mode = tegra_pm_validate_suspend_mode(suspend_mode); +- +- if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop)) +- suspend_mode = TEGRA_SUSPEND_NONE; +- pmc_pm_data.cpu_good_time = prop; +- +- if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop)) +- suspend_mode = TEGRA_SUSPEND_NONE; +- pmc_pm_data.cpu_off_time = prop; +- +- if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", +- core_good_time, ARRAY_SIZE(core_good_time))) +- suspend_mode = TEGRA_SUSPEND_NONE; +- pmc_pm_data.core_osc_time = core_good_time[0]; +- pmc_pm_data.core_pmu_time = core_good_time[1]; +- +- if (of_property_read_u32(np, "nvidia,core-pwr-off-time", +- &prop)) +- suspend_mode = TEGRA_SUSPEND_NONE; +- pmc_pm_data.core_off_time = prop; +- +- pmc_pm_data.corereq_high = of_property_read_bool(np, +- "nvidia,core-power-req-active-high"); +- +- pmc_pm_data.sysclkreq_high = of_property_read_bool(np, +- "nvidia,sys-clock-req-active-high"); +- +- pmc_pm_data.combined_req = of_property_read_bool(np, +- "nvidia,combined-power-req"); +- +- pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np, +- "nvidia,cpu-pwr-good-en"); +- +- if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec, +- ARRAY_SIZE(lp0_vec))) +- if (suspend_mode == TEGRA_SUSPEND_LP0) +- suspend_mode = TEGRA_SUSPEND_LP1; +- +- pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0]; +- pmc_pm_data.lp0_vec_size = lp0_vec[1]; +- +- pmc_pm_data.suspend_mode = suspend_mode; +-} diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h -index 59e19c34..139a3086 100644 +deleted file mode 100644 +index 59e19c34..0000000 --- a/arch/arm/mach-tegra/pmc.h -+++ b/arch/arm/mach-tegra/pmc.h -@@ -18,6 +18,7 @@ - #ifndef __MACH_TEGRA_PMC_H - #define __MACH_TEGRA_PMC_H - -+#include <linux/io.h> - #include <linux/reboot.h> - - enum tegra_suspend_mode { -@@ -37,6 +38,18 @@ void tegra_pmc_pm_set(enum tegra_suspend_mode mode); - void tegra_pmc_suspend_init(void); - #endif - -+extern void __iomem *tegra_pmc_base; -+ -+static inline u32 tegra_pmc_readl(u32 reg) -+{ -+ return readl(tegra_pmc_base + reg); -+} -+ -+static inline void tegra_pmc_writel(u32 val, u32 reg) -+{ -+ writel(val, tegra_pmc_base + reg); -+} -+ - bool tegra_pmc_cpu_is_powered(int cpuid); - int tegra_pmc_cpu_power_on(int cpuid); - int tegra_pmc_cpu_remove_clamping(int cpuid); ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* +- * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope 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 __MACH_TEGRA_PMC_H +-#define __MACH_TEGRA_PMC_H +- +-#include <linux/reboot.h> +- +-enum tegra_suspend_mode { +- TEGRA_SUSPEND_NONE = 0, +- TEGRA_SUSPEND_LP2, /* CPU voltage off */ +- TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */ +- TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */ +- TEGRA_MAX_SUSPEND_MODE, +-}; +- +-#ifdef CONFIG_PM_SLEEP +-enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void); +-void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode); +-void tegra_pmc_suspend(void); +-void tegra_pmc_resume(void); +-void tegra_pmc_pm_set(enum tegra_suspend_mode mode); +-void tegra_pmc_suspend_init(void); +-#endif +- +-bool tegra_pmc_cpu_is_powered(int cpuid); +-int tegra_pmc_cpu_power_on(int cpuid); +-int tegra_pmc_cpu_remove_clamping(int cpuid); +- +-void tegra_pmc_restart(enum reboot_mode mode, const char *cmd); +- +-void tegra_pmc_init_irq(void); +-void tegra_pmc_init(void); +- +-#endif diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c -index 4cefc5c..c90f303 100644 +deleted file mode 100644 +index 4cefc5c..0000000 --- a/arch/arm/mach-tegra/powergate.c -+++ b/arch/arm/mach-tegra/powergate.c -@@ -30,9 +30,9 @@ - #include <linux/spinlock.h> - #include <linux/clk/tegra.h> - #include <linux/tegra-powergate.h> -+#include <linux/tegra-soc.h> - ++++ /dev/null +@@ -1,515 +0,0 @@ +-/* +- * drivers/powergate/tegra-powergate.c +- * +- * Copyright (c) 2010 Google, Inc +- * +- * Author: +- * Colin Cross <ccross@google.com> +- * +- * 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/kernel.h> +-#include <linux/clk.h> +-#include <linux/debugfs.h> +-#include <linux/delay.h> +-#include <linux/err.h> +-#include <linux/export.h> +-#include <linux/init.h> +-#include <linux/io.h> +-#include <linux/reset.h> +-#include <linux/seq_file.h> +-#include <linux/spinlock.h> +-#include <linux/clk/tegra.h> +-#include <linux/tegra-powergate.h> +- -#include "fuse.h" -#include "iomap.h" -+#include "pmc.h" - - #define DPD_SAMPLE 0x020 - #define DPD_SAMPLE_ENABLE (1 << 0) -@@ -85,18 +85,6 @@ static const u8 tegra124_cpu_domains[] = { - - static DEFINE_SPINLOCK(tegra_powergate_lock); - +- +-#define DPD_SAMPLE 0x020 +-#define DPD_SAMPLE_ENABLE (1 << 0) +-#define DPD_SAMPLE_DISABLE (0 << 0) +- +-#define PWRGATE_TOGGLE 0x30 +-#define PWRGATE_TOGGLE_START (1 << 8) +- +-#define REMOVE_CLAMPING 0x34 +- +-#define PWRGATE_STATUS 0x38 +- +-#define IO_DPD_REQ 0x1b8 +-#define IO_DPD_REQ_CODE_IDLE (0 << 30) +-#define IO_DPD_REQ_CODE_OFF (1 << 30) +-#define IO_DPD_REQ_CODE_ON (2 << 30) +-#define IO_DPD_REQ_CODE_MASK (3 << 30) +- +-#define IO_DPD_STATUS 0x1bc +-#define IO_DPD2_REQ 0x1c0 +-#define IO_DPD2_STATUS 0x1c4 +-#define SEL_DPD_TIM 0x1c8 +- +-#define GPU_RG_CNTRL 0x2d4 +- +-static int tegra_num_powerdomains; +-static int tegra_num_cpu_domains; +-static const u8 *tegra_cpu_domains; +- +-static const u8 tegra30_cpu_domains[] = { +- TEGRA_POWERGATE_CPU, +- TEGRA_POWERGATE_CPU1, +- TEGRA_POWERGATE_CPU2, +- TEGRA_POWERGATE_CPU3, +-}; +- +-static const u8 tegra114_cpu_domains[] = { +- TEGRA_POWERGATE_CPU0, +- TEGRA_POWERGATE_CPU1, +- TEGRA_POWERGATE_CPU2, +- TEGRA_POWERGATE_CPU3, +-}; +- +-static const u8 tegra124_cpu_domains[] = { +- TEGRA_POWERGATE_CPU0, +- TEGRA_POWERGATE_CPU1, +- TEGRA_POWERGATE_CPU2, +- TEGRA_POWERGATE_CPU3, +-}; +- +-static DEFINE_SPINLOCK(tegra_powergate_lock); +- -static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); - -static u32 pmc_read(unsigned long reg) @@ -2892,138 +4308,464 @@ index 4cefc5c..c90f303 100644 - writel(val, pmc + reg); -} - - static int tegra_powergate_set(int id, bool new_state) - { - bool status; -@@ -104,14 +92,14 @@ static int tegra_powergate_set(int id, bool new_state) - - spin_lock_irqsave(&tegra_powergate_lock, flags); - +-static int tegra_powergate_set(int id, bool new_state) +-{ +- bool status; +- unsigned long flags; +- +- spin_lock_irqsave(&tegra_powergate_lock, flags); +- - status = pmc_read(PWRGATE_STATUS) & (1 << id); -+ status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); - - if (status == new_state) { - spin_unlock_irqrestore(&tegra_powergate_lock, flags); - return 0; - } - +- +- if (status == new_state) { +- spin_unlock_irqrestore(&tegra_powergate_lock, flags); +- return 0; +- } +- - pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); -+ tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); - - spin_unlock_irqrestore(&tegra_powergate_lock, flags); - -@@ -142,7 +130,7 @@ int tegra_powergate_is_powered(int id) - if (id < 0 || id >= tegra_num_powerdomains) - return -EINVAL; - +- +- spin_unlock_irqrestore(&tegra_powergate_lock, flags); +- +- return 0; +-} +- +-int tegra_powergate_power_on(int id) +-{ +- if (id < 0 || id >= tegra_num_powerdomains) +- return -EINVAL; +- +- return tegra_powergate_set(id, true); +-} +- +-int tegra_powergate_power_off(int id) +-{ +- if (id < 0 || id >= tegra_num_powerdomains) +- return -EINVAL; +- +- return tegra_powergate_set(id, false); +-} +-EXPORT_SYMBOL(tegra_powergate_power_off); +- +-int tegra_powergate_is_powered(int id) +-{ +- u32 status; +- +- if (id < 0 || id >= tegra_num_powerdomains) +- return -EINVAL; +- - status = pmc_read(PWRGATE_STATUS) & (1 << id); -+ status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); - return !!status; - } - -@@ -159,7 +147,7 @@ int tegra_powergate_remove_clamping(int id) - */ - if (tegra_chip_id == TEGRA124) { - if (id == TEGRA_POWERGATE_3D) { +- return !!status; +-} +- +-int tegra_powergate_remove_clamping(int id) +-{ +- u32 mask; +- +- if (id < 0 || id >= tegra_num_powerdomains) +- return -EINVAL; +- +- /* +- * The Tegra124 GPU has a separate register (with different semantics) +- * to remove clamps. +- */ +- if (tegra_chip_id == TEGRA124) { +- if (id == TEGRA_POWERGATE_3D) { - pmc_write(0, GPU_RG_CNTRL); -+ tegra_pmc_writel(0, GPU_RG_CNTRL); - return 0; - } - } -@@ -175,7 +163,7 @@ int tegra_powergate_remove_clamping(int id) - else - mask = (1 << id); - +- return 0; +- } +- } +- +- /* +- * Tegra 2 has a bug where PCIE and VDE clamping masks are +- * swapped relatively to the partition ids +- */ +- if (id == TEGRA_POWERGATE_VDEC) +- mask = (1 << TEGRA_POWERGATE_PCIE); +- else if (id == TEGRA_POWERGATE_PCIE) +- mask = (1 << TEGRA_POWERGATE_VDEC); +- else +- mask = (1 << id); +- - pmc_write(mask, REMOVE_CLAMPING); -+ tegra_pmc_writel(mask, REMOVE_CLAMPING); - - return 0; - } -@@ -425,12 +413,12 @@ static int tegra_io_rail_prepare(int id, unsigned long *request, - rate = clk_get_rate(clk); - clk_put(clk); - +- +- return 0; +-} +-EXPORT_SYMBOL(tegra_powergate_remove_clamping); +- +-/* Must be called with clk disabled, and returns with clk enabled */ +-int tegra_powergate_sequence_power_up(int id, struct clk *clk, +- struct reset_control *rst) +-{ +- int ret; +- +- reset_control_assert(rst); +- +- ret = tegra_powergate_power_on(id); +- if (ret) +- goto err_power; +- +- ret = clk_prepare_enable(clk); +- if (ret) +- goto err_clk; +- +- udelay(10); +- +- ret = tegra_powergate_remove_clamping(id); +- if (ret) +- goto err_clamp; +- +- udelay(10); +- reset_control_deassert(rst); +- +- return 0; +- +-err_clamp: +- clk_disable_unprepare(clk); +-err_clk: +- tegra_powergate_power_off(id); +-err_power: +- return ret; +-} +-EXPORT_SYMBOL(tegra_powergate_sequence_power_up); +- +-int tegra_cpu_powergate_id(int cpuid) +-{ +- if (cpuid > 0 && cpuid < tegra_num_cpu_domains) +- return tegra_cpu_domains[cpuid]; +- +- return -EINVAL; +-} +- +-int __init tegra_powergate_init(void) +-{ +- switch (tegra_chip_id) { +- case TEGRA20: +- tegra_num_powerdomains = 7; +- break; +- case TEGRA30: +- tegra_num_powerdomains = 14; +- tegra_num_cpu_domains = 4; +- tegra_cpu_domains = tegra30_cpu_domains; +- break; +- case TEGRA114: +- tegra_num_powerdomains = 23; +- tegra_num_cpu_domains = 4; +- tegra_cpu_domains = tegra114_cpu_domains; +- break; +- case TEGRA124: +- tegra_num_powerdomains = 25; +- tegra_num_cpu_domains = 4; +- tegra_cpu_domains = tegra124_cpu_domains; +- break; +- default: +- /* Unknown Tegra variant. Disable powergating */ +- tegra_num_powerdomains = 0; +- break; +- } +- +- return 0; +-} +- +-#ifdef CONFIG_DEBUG_FS +- +-static const char * const *powergate_name; +- +-static const char * const powergate_name_t20[] = { +- [TEGRA_POWERGATE_CPU] = "cpu", +- [TEGRA_POWERGATE_3D] = "3d", +- [TEGRA_POWERGATE_VENC] = "venc", +- [TEGRA_POWERGATE_VDEC] = "vdec", +- [TEGRA_POWERGATE_PCIE] = "pcie", +- [TEGRA_POWERGATE_L2] = "l2", +- [TEGRA_POWERGATE_MPE] = "mpe", +-}; +- +-static const char * const powergate_name_t30[] = { +- [TEGRA_POWERGATE_CPU] = "cpu0", +- [TEGRA_POWERGATE_3D] = "3d0", +- [TEGRA_POWERGATE_VENC] = "venc", +- [TEGRA_POWERGATE_VDEC] = "vdec", +- [TEGRA_POWERGATE_PCIE] = "pcie", +- [TEGRA_POWERGATE_L2] = "l2", +- [TEGRA_POWERGATE_MPE] = "mpe", +- [TEGRA_POWERGATE_HEG] = "heg", +- [TEGRA_POWERGATE_SATA] = "sata", +- [TEGRA_POWERGATE_CPU1] = "cpu1", +- [TEGRA_POWERGATE_CPU2] = "cpu2", +- [TEGRA_POWERGATE_CPU3] = "cpu3", +- [TEGRA_POWERGATE_CELP] = "celp", +- [TEGRA_POWERGATE_3D1] = "3d1", +-}; +- +-static const char * const powergate_name_t114[] = { +- [TEGRA_POWERGATE_CPU] = "crail", +- [TEGRA_POWERGATE_3D] = "3d", +- [TEGRA_POWERGATE_VENC] = "venc", +- [TEGRA_POWERGATE_VDEC] = "vdec", +- [TEGRA_POWERGATE_MPE] = "mpe", +- [TEGRA_POWERGATE_HEG] = "heg", +- [TEGRA_POWERGATE_CPU1] = "cpu1", +- [TEGRA_POWERGATE_CPU2] = "cpu2", +- [TEGRA_POWERGATE_CPU3] = "cpu3", +- [TEGRA_POWERGATE_CELP] = "celp", +- [TEGRA_POWERGATE_CPU0] = "cpu0", +- [TEGRA_POWERGATE_C0NC] = "c0nc", +- [TEGRA_POWERGATE_C1NC] = "c1nc", +- [TEGRA_POWERGATE_DIS] = "dis", +- [TEGRA_POWERGATE_DISB] = "disb", +- [TEGRA_POWERGATE_XUSBA] = "xusba", +- [TEGRA_POWERGATE_XUSBB] = "xusbb", +- [TEGRA_POWERGATE_XUSBC] = "xusbc", +-}; +- +-static const char * const powergate_name_t124[] = { +- [TEGRA_POWERGATE_CPU] = "crail", +- [TEGRA_POWERGATE_3D] = "3d", +- [TEGRA_POWERGATE_VENC] = "venc", +- [TEGRA_POWERGATE_PCIE] = "pcie", +- [TEGRA_POWERGATE_VDEC] = "vdec", +- [TEGRA_POWERGATE_L2] = "l2", +- [TEGRA_POWERGATE_MPE] = "mpe", +- [TEGRA_POWERGATE_HEG] = "heg", +- [TEGRA_POWERGATE_SATA] = "sata", +- [TEGRA_POWERGATE_CPU1] = "cpu1", +- [TEGRA_POWERGATE_CPU2] = "cpu2", +- [TEGRA_POWERGATE_CPU3] = "cpu3", +- [TEGRA_POWERGATE_CELP] = "celp", +- [TEGRA_POWERGATE_CPU0] = "cpu0", +- [TEGRA_POWERGATE_C0NC] = "c0nc", +- [TEGRA_POWERGATE_C1NC] = "c1nc", +- [TEGRA_POWERGATE_SOR] = "sor", +- [TEGRA_POWERGATE_DIS] = "dis", +- [TEGRA_POWERGATE_DISB] = "disb", +- [TEGRA_POWERGATE_XUSBA] = "xusba", +- [TEGRA_POWERGATE_XUSBB] = "xusbb", +- [TEGRA_POWERGATE_XUSBC] = "xusbc", +- [TEGRA_POWERGATE_VIC] = "vic", +- [TEGRA_POWERGATE_IRAM] = "iram", +-}; +- +-static int powergate_show(struct seq_file *s, void *data) +-{ +- int i; +- +- seq_printf(s, " powergate powered\n"); +- seq_printf(s, "------------------\n"); +- +- for (i = 0; i < tegra_num_powerdomains; i++) { +- if (!powergate_name[i]) +- continue; +- +- seq_printf(s, " %9s %7s\n", powergate_name[i], +- tegra_powergate_is_powered(i) ? "yes" : "no"); +- } +- +- return 0; +-} +- +-static int powergate_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, powergate_show, inode->i_private); +-} +- +-static const struct file_operations powergate_fops = { +- .open = powergate_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; +- +-int __init tegra_powergate_debugfs_init(void) +-{ +- struct dentry *d; +- +- switch (tegra_chip_id) { +- case TEGRA20: +- powergate_name = powergate_name_t20; +- break; +- case TEGRA30: +- powergate_name = powergate_name_t30; +- break; +- case TEGRA114: +- powergate_name = powergate_name_t114; +- break; +- case TEGRA124: +- powergate_name = powergate_name_t124; +- break; +- } +- +- if (powergate_name) { +- d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, +- &powergate_fops); +- if (!d) +- return -ENOMEM; +- } +- +- return 0; +-} +- +-#endif +- +-static int tegra_io_rail_prepare(int id, unsigned long *request, +- unsigned long *status, unsigned int *bit) +-{ +- unsigned long rate, value; +- struct clk *clk; +- +- *bit = id % 32; +- +- /* +- * There are two sets of 30 bits to select IO rails, but bits 30 and +- * 31 are control bits rather than IO rail selection bits. +- */ +- if (id > 63 || *bit == 30 || *bit == 31) +- return -EINVAL; +- +- if (id < 32) { +- *status = IO_DPD_STATUS; +- *request = IO_DPD_REQ; +- } else { +- *status = IO_DPD2_STATUS; +- *request = IO_DPD2_REQ; +- } +- +- clk = clk_get_sys(NULL, "pclk"); +- if (IS_ERR(clk)) +- return PTR_ERR(clk); +- +- rate = clk_get_rate(clk); +- clk_put(clk); +- - pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE); -+ tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); - - /* must be at least 200 ns, in APB (PCLK) clock cycles */ - value = DIV_ROUND_UP(1000000000, rate); - value = DIV_ROUND_UP(200, value); +- +- /* must be at least 200 ns, in APB (PCLK) clock cycles */ +- value = DIV_ROUND_UP(1000000000, rate); +- value = DIV_ROUND_UP(200, value); - pmc_write(value, SEL_DPD_TIM); -+ tegra_pmc_writel(value, SEL_DPD_TIM); - - return 0; - } -@@ -443,7 +431,7 @@ static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, - timeout = jiffies + msecs_to_jiffies(timeout); - - while (time_after(timeout, jiffies)) { +- +- return 0; +-} +- +-static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, +- unsigned long val, unsigned long timeout) +-{ +- unsigned long value; +- +- timeout = jiffies + msecs_to_jiffies(timeout); +- +- while (time_after(timeout, jiffies)) { - value = pmc_read(offset); -+ value = tegra_pmc_readl(offset); - if ((value & mask) == val) - return 0; - -@@ -455,7 +443,7 @@ static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, - - static void tegra_io_rail_unprepare(void) - { +- if ((value & mask) == val) +- return 0; +- +- usleep_range(250, 1000); +- } +- +- return -ETIMEDOUT; +-} +- +-static void tegra_io_rail_unprepare(void) +-{ - pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE); -+ tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); - } - - int tegra_io_rail_power_on(int id) -@@ -470,11 +458,11 @@ int tegra_io_rail_power_on(int id) - - mask = 1 << bit; - +-} +- +-int tegra_io_rail_power_on(int id) +-{ +- unsigned long request, status, value; +- unsigned int bit, mask; +- int err; +- +- err = tegra_io_rail_prepare(id, &request, &status, &bit); +- if (err < 0) +- return err; +- +- mask = 1 << bit; +- - value = pmc_read(request); -+ value = tegra_pmc_readl(request); - value |= mask; - value &= ~IO_DPD_REQ_CODE_MASK; - value |= IO_DPD_REQ_CODE_OFF; +- value |= mask; +- value &= ~IO_DPD_REQ_CODE_MASK; +- value |= IO_DPD_REQ_CODE_OFF; - pmc_write(value, request); -+ tegra_pmc_writel(value, request); - - err = tegra_io_rail_poll(status, mask, 0, 250); - if (err < 0) -@@ -498,11 +486,11 @@ int tegra_io_rail_power_off(int id) - - mask = 1 << bit; - +- +- err = tegra_io_rail_poll(status, mask, 0, 250); +- if (err < 0) +- return err; +- +- tegra_io_rail_unprepare(); +- +- return 0; +-} +-EXPORT_SYMBOL(tegra_io_rail_power_on); +- +-int tegra_io_rail_power_off(int id) +-{ +- unsigned long request, status, value; +- unsigned int bit, mask; +- int err; +- +- err = tegra_io_rail_prepare(id, &request, &status, &bit); +- if (err < 0) +- return err; +- +- mask = 1 << bit; +- - value = pmc_read(request); -+ value = tegra_pmc_readl(request); - value |= mask; - value &= ~IO_DPD_REQ_CODE_MASK; - value |= IO_DPD_REQ_CODE_ON; +- value |= mask; +- value &= ~IO_DPD_REQ_CODE_MASK; +- value |= IO_DPD_REQ_CODE_ON; - pmc_write(value, request); -+ tegra_pmc_writel(value, request); - - err = tegra_io_rail_poll(status, mask, mask, 250); - if (err < 0) +- +- err = tegra_io_rail_poll(status, mask, mask, 250); +- if (err < 0) +- return err; +- +- tegra_io_rail_unprepare(); +- +- return 0; +-} +-EXPORT_SYMBOL(tegra_io_rail_power_off); diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S -index 578d4d1..b9ff929 100644 +index 578d4d1..be2eaa8 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S -@@ -19,9 +19,9 @@ +@@ -14,14 +14,14 @@ + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ - #include <asm/cache.h> - #include <asm/asm-offsets.h> +-#include <linux/linkage.h> + #include <linux/init.h> ++#include <linux/linkage.h> +#include <linux/tegra-soc.h> +-#include <asm/cache.h> + #include <asm/asm-offsets.h> ++#include <asm/cache.h> + #include "flowctrl.h" -#include "fuse.h" #include "iomap.h" #include "reset.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c -index 146fe8e..203bac5 100644 +index 146fe8e..96cafc4 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c -@@ -22,12 +22,12 @@ +@@ -14,20 +14,20 @@ + * + */ + ++#include <linux/bitops.h> ++#include <linux/cpumask.h> + #include <linux/init.h> + #include <linux/io.h> +-#include <linux/cpumask.h> +-#include <linux/bitops.h> ++#include <linux/tegra-soc.h> + #include <asm/cacheflush.h> - #include <asm/hardware/cache-l2x0.h> +-#include <asm/hardware/cache-l2x0.h> #include <asm/firmware.h> -+#include <linux/tegra-soc.h> ++#include <asm/hardware/cache-l2x0.h> #include "iomap.h" #include "irammap.h" @@ -3033,38 +4775,1055 @@ index 146fe8e..203bac5 100644 #define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \ TEGRA_IRAM_RESET_HANDLER_OFFSET) +@@ -53,12 +53,10 @@ static void __init tegra_cpu_reset_handler_set(const u32 reset_address) + * Prevent further modifications to the physical reset vector. + * NOTE: Has no effect on chips prior to Tegra30. + */ +- if (tegra_chip_id != TEGRA20) { +- reg = readl(sb_ctrl); +- reg |= 2; +- writel(reg, sb_ctrl); +- wmb(); +- } ++ reg = readl(sb_ctrl); ++ reg |= 2; ++ writel(reg, sb_ctrl); ++ wmb(); + } + + static void __init tegra_cpu_reset_handler_enable(void) diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S -index b16d4a57..f808c2c 100644 +index b16d4a57..3700fe9 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S -@@ -15,13 +15,13 @@ +@@ -15,15 +15,15 @@ */ #include <linux/linkage.h> +#include <linux/tegra-soc.h> - #include <asm/assembler.h> +-#include <asm/assembler.h> #include <asm/asm-offsets.h> ++#include <asm/assembler.h> #include <asm/cache.h> ++#include "flowctrl.h" #include "irammap.h" -#include "fuse.h" #include "sleep.h" - #include "flowctrl.h" +-#include "flowctrl.h" + + #define EMC_CFG 0xc + #define EMC_ADR_CFG 0x10 +diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h +index 339fe42..92d46ec 100644 +--- a/arch/arm/mach-tegra/sleep.h ++++ b/arch/arm/mach-tegra/sleep.h +@@ -130,9 +130,6 @@ void tegra_disable_clean_inv_dcache(u32 flag); + #ifdef CONFIG_HOTPLUG_CPU + void tegra20_hotplug_shutdown(void); + void tegra30_hotplug_shutdown(void); +-void tegra_hotplug_init(void); +-#else +-static inline void tegra_hotplug_init(void) {} + #endif + void tegra20_cpu_shutdown(int cpu); +diff --git a/arch/arm/mach-tegra/tegra-pmc.c b/arch/arm/mach-tegra/tegra-pmc.c +new file mode 100644 +index 0000000..b6bc758 +--- /dev/null ++++ b/arch/arm/mach-tegra/tegra-pmc.c +@@ -0,0 +1,948 @@ ++/* ++ * drivers/soc/tegra/pmc.c ++ * ++ * Copyright (c) 2010 Google, Inc ++ * ++ * Author: ++ * Colin Cross <ccross@google.com> ++ * ++ * 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/kernel.h> ++#include <linux/clk.h> ++#include <linux/clk/tegra.h> ++#include <linux/debugfs.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/export.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/reboot.h> ++#include <linux/reset.h> ++#include <linux/seq_file.h> ++#include <linux/spinlock.h> ++#include <linux/tegra-powergate.h> ++#include <linux/tegra-soc.h> ++ ++#define PMC_CNTRL 0x0 ++#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */ ++#define PMC_CNTRL_SYSCLK_OE (1 << 11) /* system clock enable */ ++#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ ++#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ ++#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ ++#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ ++ ++#define DPD_SAMPLE 0x020 ++#define DPD_SAMPLE_ENABLE (1 << 0) ++#define DPD_SAMPLE_DISABLE (0 << 0) ++ ++#define PWRGATE_TOGGLE 0x30 ++#define PWRGATE_TOGGLE_START (1 << 8) ++ ++#define REMOVE_CLAMPING 0x34 ++ ++#define PWRGATE_STATUS 0x38 ++ ++#define PMC_SCRATCH0 0x50 ++#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) ++#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) ++#define PMC_SCRATCH0_MODE_RCM (1 << 1) ++#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ ++ PMC_SCRATCH0_MODE_BOOTLOADER | \ ++ PMC_SCRATCH0_MODE_RCM) ++ ++#define PMC_CPUPWRGOOD_TIMER 0xc8 ++#define PMC_CPUPWROFF_TIMER 0xcc ++ ++#define PMC_SCRATCH41 0x140 ++ ++#define IO_DPD_REQ 0x1b8 ++#define IO_DPD_REQ_CODE_IDLE (0 << 30) ++#define IO_DPD_REQ_CODE_OFF (1 << 30) ++#define IO_DPD_REQ_CODE_ON (2 << 30) ++#define IO_DPD_REQ_CODE_MASK (3 << 30) ++ ++#define IO_DPD_STATUS 0x1bc ++#define IO_DPD2_REQ 0x1c0 ++#define IO_DPD2_STATUS 0x1c4 ++#define SEL_DPD_TIM 0x1c8 ++ ++#define GPU_RG_CNTRL 0x2d4 ++ ++struct tegra_pmc_soc { ++ unsigned int num_powergates; ++ const char *const *powergates; ++ unsigned int num_cpu_powergates; ++ const u8 *cpu_powergates; ++}; ++ ++/** ++ * struct tegra_pmc - NVIDIA Tegra PMC ++ * @base: pointer to I/O remapped register region ++ * @clk: pointer to pclk clock ++ * @rate: currently configured rate of pclk ++ * @suspend_mode: lowest suspend mode available ++ * @cpu_good_time: CPU power good time (in microseconds) ++ * @cpu_off_time: CPU power off time (in microsecends) ++ * @core_osc_time: core power good OSC time (in microseconds) ++ * @core_pmu_time: core power good PMU time (in microseconds) ++ * @core_off_time: core power off time (in microseconds) ++ * @corereq_high: core power request is active-high ++ * @sysclkreq_high: system clock request is active-high ++ * @combined_req: combined power request for CPU & core ++ * @cpu_pwr_good_en: CPU power good signal is enabled ++ * @lp0_vec_phys: physical base address of the LP0 warm boot code ++ * @lp0_vec_size: size of the LP0 warm boot code ++ * @powergates_lock: mutex for power gate register access ++ */ ++struct tegra_pmc { ++ void __iomem *base; ++ struct clk *clk; ++ ++ const struct tegra_pmc_soc *soc; ++ ++ unsigned long rate; ++ ++ enum tegra_suspend_mode suspend_mode; ++ u32 cpu_good_time; ++ u32 cpu_off_time; ++ u32 core_osc_time; ++ u32 core_pmu_time; ++ u32 core_off_time; ++ bool corereq_high; ++ bool sysclkreq_high; ++ bool combined_req; ++ bool cpu_pwr_good_en; ++ u32 lp0_vec_phys; ++ u32 lp0_vec_size; ++ ++ struct mutex powergates_lock; ++}; ++ ++static struct tegra_pmc *pmc = &(struct tegra_pmc) { ++ .base = NULL, ++ .suspend_mode = TEGRA_SUSPEND_NONE, ++}; ++ ++static u32 tegra_pmc_readl(unsigned long offset) ++{ ++ return readl(pmc->base + offset); ++} ++ ++static void tegra_pmc_writel(u32 value, unsigned long offset) ++{ ++ writel(value, pmc->base + offset); ++} ++ ++/** ++ * tegra_powergate_set() - set the state of a partition ++ * @id: partition ID ++ * @new_state: new state of the partition ++ */ ++static int tegra_powergate_set(int id, bool new_state) ++{ ++ bool status; ++ ++ mutex_lock(&pmc->powergates_lock); ++ ++ status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); ++ ++ if (status == new_state) { ++ mutex_unlock(&pmc->powergates_lock); ++ return 0; ++ } ++ ++ tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); ++ ++ mutex_unlock(&pmc->powergates_lock); ++ ++ return 0; ++} ++ ++/** ++ * tegra_powergate_power_on() - power on partition ++ * @id: partition ID ++ */ ++int tegra_powergate_power_on(int id) ++{ ++ if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) ++ return -EINVAL; ++ ++ return tegra_powergate_set(id, true); ++} ++ ++/** ++ * tegra_powergate_power_off() - power off partition ++ * @id: partition ID ++ */ ++int tegra_powergate_power_off(int id) ++{ ++ if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) ++ return -EINVAL; ++ ++ return tegra_powergate_set(id, false); ++} ++EXPORT_SYMBOL(tegra_powergate_power_off); ++ ++/** ++ * tegra_powergate_is_powered() - check if partition is powered ++ * @id: partition ID ++ */ ++int tegra_powergate_is_powered(int id) ++{ ++ u32 status; ++ ++ if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) ++ return -EINVAL; ++ ++ status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); ++ return !!status; ++} ++ ++/** ++ * tegra_powergate_remove_clamping() - remove power clamps for partition ++ * @id: partition ID ++ */ ++int tegra_powergate_remove_clamping(int id) ++{ ++ u32 mask; ++ ++ if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) ++ return -EINVAL; ++ ++ /* ++ * The Tegra124 GPU has a separate register (with different semantics) ++ * to remove clamps. ++ */ ++ if (tegra_get_chip_id() == TEGRA124) { ++ if (id == TEGRA_POWERGATE_3D) { ++ tegra_pmc_writel(0, GPU_RG_CNTRL); ++ return 0; ++ } ++ } ++ ++ /* ++ * Tegra 2 has a bug where PCIE and VDE clamping masks are ++ * swapped relatively to the partition ids ++ */ ++ if (id == TEGRA_POWERGATE_VDEC) ++ mask = (1 << TEGRA_POWERGATE_PCIE); ++ else if (id == TEGRA_POWERGATE_PCIE) ++ mask = (1 << TEGRA_POWERGATE_VDEC); ++ else ++ mask = (1 << id); ++ ++ tegra_pmc_writel(mask, REMOVE_CLAMPING); ++ ++ return 0; ++} ++EXPORT_SYMBOL(tegra_powergate_remove_clamping); ++ ++/** ++ * tegra_powergate_sequence_power_up() - power up partition ++ * @id: partition ID ++ * @clk: clock for partition ++ * @rst: reset for partition ++ * ++ * Must be called with clk disabled, and returns with clk enabled. ++ */ ++int tegra_powergate_sequence_power_up(int id, struct clk *clk, ++ struct reset_control *rst) ++{ ++ int ret; ++ ++ reset_control_assert(rst); ++ ++ ret = tegra_powergate_power_on(id); ++ if (ret) ++ goto err_power; ++ ++ ret = clk_prepare_enable(clk); ++ if (ret) ++ goto err_clk; ++ ++ usleep_range(10, 20); ++ ++ ret = tegra_powergate_remove_clamping(id); ++ if (ret) ++ goto err_clamp; ++ ++ usleep_range(10, 20); ++ reset_control_deassert(rst); ++ ++ return 0; ++ ++err_clamp: ++ clk_disable_unprepare(clk); ++err_clk: ++ tegra_powergate_power_off(id); ++err_power: ++ return ret; ++} ++EXPORT_SYMBOL(tegra_powergate_sequence_power_up); ++ ++/** ++ * tegra_get_cpu_powergate_id() - convert from CPU ID to partition ID ++ * @cpuid: CPU partition ID ++ * ++ * Returns the partition ID corresponding to the CPU partition ID or a ++ * negative error code on failure. ++ */ ++static int tegra_get_cpu_powergate_id(int cpuid) ++{ ++ if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates) ++ return pmc->soc->cpu_powergates[cpuid]; ++ ++ return -EINVAL; ++} ++ ++/** ++ * tegra_pmc_cpu_is_powered() - check if CPU partition is powered ++ * @cpuid: CPU partition ID ++ */ ++bool tegra_pmc_cpu_is_powered(int cpuid) ++{ ++ int id; ++ ++ id = tegra_get_cpu_powergate_id(cpuid); ++ if (id < 0) ++ return false; ++ ++ return tegra_powergate_is_powered(id); ++} ++ ++/** ++ * tegra_pmc_cpu_power_on() - power on CPU partition ++ * @cpuid: CPU partition ID ++ */ ++int tegra_pmc_cpu_power_on(int cpuid) ++{ ++ int id; ++ ++ id = tegra_get_cpu_powergate_id(cpuid); ++ if (id < 0) ++ return id; ++ ++ return tegra_powergate_set(id, true); ++} ++ ++/** ++ * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition ++ * @cpuid: CPU partition ID ++ */ ++int tegra_pmc_cpu_remove_clamping(int cpuid) ++{ ++ int id; ++ ++ id = tegra_get_cpu_powergate_id(cpuid); ++ if (id < 0) ++ return id; ++ ++ return tegra_powergate_remove_clamping(id); ++} ++ ++/** ++ * tegra_pmc_restart() - reboot the system ++ * @mode: which mode to reboot in ++ * @cmd: reboot command ++ */ ++void tegra_pmc_restart(enum reboot_mode mode, const char *cmd) ++{ ++ u32 value; ++ ++ value = tegra_pmc_readl(PMC_SCRATCH0); ++ value &= ~PMC_SCRATCH0_MODE_MASK; ++ ++ if (cmd) { ++ if (strcmp(cmd, "recovery") == 0) ++ value |= PMC_SCRATCH0_MODE_RECOVERY; ++ ++ if (strcmp(cmd, "bootloader") == 0) ++ value |= PMC_SCRATCH0_MODE_BOOTLOADER; ++ ++ if (strcmp(cmd, "forced-recovery") == 0) ++ value |= PMC_SCRATCH0_MODE_RCM; ++ } ++ ++ tegra_pmc_writel(value, PMC_SCRATCH0); ++ ++ value = tegra_pmc_readl(0); ++ value |= 0x10; ++ tegra_pmc_writel(value, 0); ++} ++ ++static int powergate_show(struct seq_file *s, void *data) ++{ ++ unsigned int i; ++ ++ seq_printf(s, " powergate powered\n"); ++ seq_printf(s, "------------------\n"); ++ ++ for (i = 0; i < pmc->soc->num_powergates; i++) { ++ if (!pmc->soc->powergates[i]) ++ continue; ++ ++ seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], ++ tegra_powergate_is_powered(i) ? "yes" : "no"); ++ } ++ ++ return 0; ++} ++ ++static int powergate_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, powergate_show, inode->i_private); ++} ++ ++static const struct file_operations powergate_fops = { ++ .open = powergate_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int tegra_powergate_debugfs_init(void) ++{ ++ struct dentry *d; ++ ++ d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, ++ &powergate_fops); ++ if (!d) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static int tegra_io_rail_prepare(int id, unsigned long *request, ++ unsigned long *status, unsigned int *bit) ++{ ++ unsigned long rate, value; ++ struct clk *clk; ++ ++ *bit = id % 32; ++ ++ /* ++ * There are two sets of 30 bits to select IO rails, but bits 30 and ++ * 31 are control bits rather than IO rail selection bits. ++ */ ++ if (id > 63 || *bit == 30 || *bit == 31) ++ return -EINVAL; ++ ++ if (id < 32) { ++ *status = IO_DPD_STATUS; ++ *request = IO_DPD_REQ; ++ } else { ++ *status = IO_DPD2_STATUS; ++ *request = IO_DPD2_REQ; ++ } ++ ++ clk = clk_get_sys(NULL, "pclk"); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ rate = clk_get_rate(clk); ++ clk_put(clk); ++ ++ tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); ++ ++ /* must be at least 200 ns, in APB (PCLK) clock cycles */ ++ value = DIV_ROUND_UP(1000000000, rate); ++ value = DIV_ROUND_UP(200, value); ++ tegra_pmc_writel(value, SEL_DPD_TIM); ++ ++ return 0; ++} ++ ++static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, ++ unsigned long val, unsigned long timeout) ++{ ++ unsigned long value; ++ ++ timeout = jiffies + msecs_to_jiffies(timeout); ++ ++ while (time_after(timeout, jiffies)) { ++ value = tegra_pmc_readl(offset); ++ if ((value & mask) == val) ++ return 0; ++ ++ usleep_range(250, 1000); ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++static void tegra_io_rail_unprepare(void) ++{ ++ tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); ++} ++ ++int tegra_io_rail_power_on(int id) ++{ ++ unsigned long request, status, value; ++ unsigned int bit, mask; ++ int err; ++ ++ err = tegra_io_rail_prepare(id, &request, &status, &bit); ++ if (err < 0) ++ return err; ++ ++ mask = 1 << bit; ++ ++ value = tegra_pmc_readl(request); ++ value |= mask; ++ value &= ~IO_DPD_REQ_CODE_MASK; ++ value |= IO_DPD_REQ_CODE_OFF; ++ tegra_pmc_writel(value, request); ++ ++ err = tegra_io_rail_poll(status, mask, 0, 250); ++ if (err < 0) ++ return err; ++ ++ tegra_io_rail_unprepare(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(tegra_io_rail_power_on); ++ ++int tegra_io_rail_power_off(int id) ++{ ++ unsigned long request, status, value; ++ unsigned int bit, mask; ++ int err; ++ ++ err = tegra_io_rail_prepare(id, &request, &status, &bit); ++ if (err < 0) ++ return err; ++ ++ mask = 1 << bit; ++ ++ value = tegra_pmc_readl(request); ++ value |= mask; ++ value &= ~IO_DPD_REQ_CODE_MASK; ++ value |= IO_DPD_REQ_CODE_ON; ++ tegra_pmc_writel(value, request); ++ ++ err = tegra_io_rail_poll(status, mask, mask, 250); ++ if (err < 0) ++ return err; ++ ++ tegra_io_rail_unprepare(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(tegra_io_rail_power_off); ++ ++enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) ++{ ++ return pmc->suspend_mode; ++} ++ ++void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode) ++{ ++ if (mode < TEGRA_SUSPEND_NONE || mode >= TEGRA_MAX_SUSPEND_MODE) ++ return; ++ ++ pmc->suspend_mode = mode; ++} ++ ++void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) ++{ ++ unsigned long long rate = 0; ++ u32 value; ++ ++ switch (mode) { ++ case TEGRA_SUSPEND_LP1: ++ rate = 32768; ++ break; ++ ++ case TEGRA_SUSPEND_LP2: ++ rate = clk_get_rate(pmc->clk); ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (WARN_ON_ONCE(rate == 0)) ++ rate = 100000000; ++ ++ if (rate != pmc->rate) { ++ u64 ticks; ++ ++ ticks = pmc->cpu_good_time * rate + USEC_PER_SEC - 1; ++ do_div(ticks, USEC_PER_SEC); ++ tegra_pmc_writel(ticks, PMC_CPUPWRGOOD_TIMER); ++ ++ ticks = pmc->cpu_off_time * rate + USEC_PER_SEC - 1; ++ do_div(ticks, USEC_PER_SEC); ++ tegra_pmc_writel(ticks, PMC_CPUPWROFF_TIMER); ++ ++ wmb(); ++ ++ pmc->rate = rate; ++ } ++ ++ value = tegra_pmc_readl(PMC_CNTRL); ++ value &= ~PMC_CNTRL_SIDE_EFFECT_LP0; ++ value |= PMC_CNTRL_CPU_PWRREQ_OE; ++ tegra_pmc_writel(value, PMC_CNTRL); ++} ++ ++static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np) ++{ ++ u32 value, values[2]; ++ ++ if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) { ++ } else { ++ switch (value) { ++ case 0: ++ pmc->suspend_mode = TEGRA_SUSPEND_LP0; ++ break; ++ ++ case 1: ++ pmc->suspend_mode = TEGRA_SUSPEND_LP1; ++ break; ++ ++ case 2: ++ pmc->suspend_mode = TEGRA_SUSPEND_LP2; ++ break; ++ ++ default: ++ pmc->suspend_mode = TEGRA_SUSPEND_NONE; ++ break; ++ } ++ } ++ ++ pmc->suspend_mode = tegra_pm_validate_suspend_mode(pmc->suspend_mode); ++ ++ if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &value)) ++ pmc->suspend_mode = TEGRA_SUSPEND_NONE; ++ ++ pmc->cpu_good_time = value; ++ ++ if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &value)) ++ pmc->suspend_mode = TEGRA_SUSPEND_NONE; ++ ++ pmc->cpu_off_time = value; ++ ++ if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", ++ values, ARRAY_SIZE(values))) ++ pmc->suspend_mode = TEGRA_SUSPEND_NONE; ++ ++ pmc->core_osc_time = values[0]; ++ pmc->core_pmu_time = values[1]; ++ ++ if (of_property_read_u32(np, "nvidia,core-pwr-off-time", &value)) ++ pmc->suspend_mode = TEGRA_SUSPEND_NONE; ++ ++ pmc->core_off_time = value; ++ ++ pmc->corereq_high = of_property_read_bool(np, ++ "nvidia,core-power-req-active-high"); ++ ++ pmc->sysclkreq_high = of_property_read_bool(np, ++ "nvidia,sys-clock-req-active-high"); ++ ++ pmc->combined_req = of_property_read_bool(np, ++ "nvidia,combined-power-req"); ++ ++ pmc->cpu_pwr_good_en = of_property_read_bool(np, ++ "nvidia,cpu-pwr-good-en"); ++ ++ if (of_property_read_u32_array(np, "nvidia,lp0-vec", values, ++ ARRAY_SIZE(values))) ++ if (pmc->suspend_mode == TEGRA_SUSPEND_LP0) ++ pmc->suspend_mode = TEGRA_SUSPEND_LP1; ++ ++ pmc->lp0_vec_phys = values[0]; ++ pmc->lp0_vec_size = values[1]; ++ ++ return 0; ++} ++ ++static void tegra_pmc_init(struct tegra_pmc *pmc) ++{ ++ u32 value; ++ ++ /* Always enable CPU power request */ ++ value = tegra_pmc_readl(PMC_CNTRL); ++ value |= PMC_CNTRL_CPU_PWRREQ_OE; ++ tegra_pmc_writel(value, PMC_CNTRL); ++ ++ value = tegra_pmc_readl(PMC_CNTRL); ++ ++ if (pmc->sysclkreq_high) ++ value &= ~PMC_CNTRL_SYSCLK_POLARITY; ++ else ++ value |= PMC_CNTRL_SYSCLK_POLARITY; ++ ++ /* configure the output polarity while the request is tristated */ ++ tegra_pmc_writel(value, PMC_CNTRL); ++ ++ /* now enable the request */ ++ value = tegra_pmc_readl(PMC_CNTRL); ++ value |= PMC_CNTRL_SYSCLK_OE; ++ tegra_pmc_writel(value, PMC_CNTRL); ++} ++ ++static int tegra_pmc_probe(struct platform_device *pdev) ++{ ++ void __iomem *base = pmc->base; ++ struct resource *res; ++ int err; ++ ++ err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node); ++ if (err < 0) ++ return err; ++ ++ /* take over the memory region from the early initialization */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pmc->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(pmc->base)) ++ return PTR_ERR(pmc->base); ++ ++ iounmap(base); ++ ++ pmc->clk = devm_clk_get(&pdev->dev, "pclk"); ++ if (IS_ERR(pmc->clk)) { ++ err = PTR_ERR(pmc->clk); ++ dev_err(&pdev->dev, "failed to get pclk: %d\n", err); ++ return err; ++ } ++ ++ tegra_pmc_init(pmc); ++ ++ if (IS_ENABLED(CONFIG_DEBUG_FS)) { ++ err = tegra_powergate_debugfs_init(); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int tegra_pmc_suspend(struct device *dev) ++{ ++ tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41); ++ ++ return 0; ++} ++ ++static int tegra_pmc_resume(struct device *dev) ++{ ++ tegra_pmc_writel(0x0, PMC_SCRATCH41); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); ++ ++static const char * const tegra20_powergates[] = { ++ [TEGRA_POWERGATE_CPU] = "cpu", ++ [TEGRA_POWERGATE_3D] = "3d", ++ [TEGRA_POWERGATE_VENC] = "venc", ++ [TEGRA_POWERGATE_VDEC] = "vdec", ++ [TEGRA_POWERGATE_PCIE] = "pcie", ++ [TEGRA_POWERGATE_L2] = "l2", ++ [TEGRA_POWERGATE_MPE] = "mpe", ++}; ++ ++static const struct tegra_pmc_soc tegra20_pmc_soc = { ++ .num_powergates = ARRAY_SIZE(tegra20_powergates), ++ .powergates = tegra20_powergates, ++ .num_cpu_powergates = 0, ++ .cpu_powergates = NULL, ++}; ++ ++static const char * const tegra30_powergates[] = { ++ [TEGRA_POWERGATE_CPU] = "cpu0", ++ [TEGRA_POWERGATE_3D] = "3d0", ++ [TEGRA_POWERGATE_VENC] = "venc", ++ [TEGRA_POWERGATE_VDEC] = "vdec", ++ [TEGRA_POWERGATE_PCIE] = "pcie", ++ [TEGRA_POWERGATE_L2] = "l2", ++ [TEGRA_POWERGATE_MPE] = "mpe", ++ [TEGRA_POWERGATE_HEG] = "heg", ++ [TEGRA_POWERGATE_SATA] = "sata", ++ [TEGRA_POWERGATE_CPU1] = "cpu1", ++ [TEGRA_POWERGATE_CPU2] = "cpu2", ++ [TEGRA_POWERGATE_CPU3] = "cpu3", ++ [TEGRA_POWERGATE_CELP] = "celp", ++ [TEGRA_POWERGATE_3D1] = "3d1", ++}; ++ ++static const u8 tegra30_cpu_powergates[] = { ++ TEGRA_POWERGATE_CPU, ++ TEGRA_POWERGATE_CPU1, ++ TEGRA_POWERGATE_CPU2, ++ TEGRA_POWERGATE_CPU3, ++}; ++ ++static const struct tegra_pmc_soc tegra30_pmc_soc = { ++ .num_powergates = ARRAY_SIZE(tegra30_powergates), ++ .powergates = tegra30_powergates, ++ .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), ++ .cpu_powergates = tegra30_cpu_powergates, ++}; ++ ++static const char * const tegra114_powergates[] = { ++ [TEGRA_POWERGATE_CPU] = "crail", ++ [TEGRA_POWERGATE_3D] = "3d", ++ [TEGRA_POWERGATE_VENC] = "venc", ++ [TEGRA_POWERGATE_VDEC] = "vdec", ++ [TEGRA_POWERGATE_MPE] = "mpe", ++ [TEGRA_POWERGATE_HEG] = "heg", ++ [TEGRA_POWERGATE_CPU1] = "cpu1", ++ [TEGRA_POWERGATE_CPU2] = "cpu2", ++ [TEGRA_POWERGATE_CPU3] = "cpu3", ++ [TEGRA_POWERGATE_CELP] = "celp", ++ [TEGRA_POWERGATE_CPU0] = "cpu0", ++ [TEGRA_POWERGATE_C0NC] = "c0nc", ++ [TEGRA_POWERGATE_C1NC] = "c1nc", ++ [TEGRA_POWERGATE_DIS] = "dis", ++ [TEGRA_POWERGATE_DISB] = "disb", ++ [TEGRA_POWERGATE_XUSBA] = "xusba", ++ [TEGRA_POWERGATE_XUSBB] = "xusbb", ++ [TEGRA_POWERGATE_XUSBC] = "xusbc", ++}; ++ ++static const u8 tegra114_cpu_powergates[] = { ++ TEGRA_POWERGATE_CPU0, ++ TEGRA_POWERGATE_CPU1, ++ TEGRA_POWERGATE_CPU2, ++ TEGRA_POWERGATE_CPU3, ++}; ++ ++static const struct tegra_pmc_soc tegra114_pmc_soc = { ++ .num_powergates = ARRAY_SIZE(tegra114_powergates), ++ .powergates = tegra114_powergates, ++ .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), ++ .cpu_powergates = tegra114_cpu_powergates, ++}; ++ ++static const char * const tegra124_powergates[] = { ++ [TEGRA_POWERGATE_CPU] = "crail", ++ [TEGRA_POWERGATE_3D] = "3d", ++ [TEGRA_POWERGATE_VENC] = "venc", ++ [TEGRA_POWERGATE_PCIE] = "pcie", ++ [TEGRA_POWERGATE_VDEC] = "vdec", ++ [TEGRA_POWERGATE_L2] = "l2", ++ [TEGRA_POWERGATE_MPE] = "mpe", ++ [TEGRA_POWERGATE_HEG] = "heg", ++ [TEGRA_POWERGATE_SATA] = "sata", ++ [TEGRA_POWERGATE_CPU1] = "cpu1", ++ [TEGRA_POWERGATE_CPU2] = "cpu2", ++ [TEGRA_POWERGATE_CPU3] = "cpu3", ++ [TEGRA_POWERGATE_CELP] = "celp", ++ [TEGRA_POWERGATE_CPU0] = "cpu0", ++ [TEGRA_POWERGATE_C0NC] = "c0nc", ++ [TEGRA_POWERGATE_C1NC] = "c1nc", ++ [TEGRA_POWERGATE_SOR] = "sor", ++ [TEGRA_POWERGATE_DIS] = "dis", ++ [TEGRA_POWERGATE_DISB] = "disb", ++ [TEGRA_POWERGATE_XUSBA] = "xusba", ++ [TEGRA_POWERGATE_XUSBB] = "xusbb", ++ [TEGRA_POWERGATE_XUSBC] = "xusbc", ++ [TEGRA_POWERGATE_VIC] = "vic", ++ [TEGRA_POWERGATE_IRAM] = "iram", ++}; ++ ++static const u8 tegra124_cpu_powergates[] = { ++ TEGRA_POWERGATE_CPU0, ++ TEGRA_POWERGATE_CPU1, ++ TEGRA_POWERGATE_CPU2, ++ TEGRA_POWERGATE_CPU3, ++}; ++ ++static const struct tegra_pmc_soc tegra124_pmc_soc = { ++ .num_powergates = ARRAY_SIZE(tegra124_powergates), ++ .powergates = tegra124_powergates, ++ .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), ++ .cpu_powergates = tegra124_cpu_powergates, ++}; ++ ++static const struct of_device_id tegra_pmc_match[] = { ++ { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc }, ++ { .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc }, ++ { .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc }, ++ { .compatible = "nvidia,tegra20-pmc", .data = &tegra20_pmc_soc }, ++ { } ++}; ++ ++static struct platform_driver tegra_pmc_driver = { ++ .driver = { ++ .name = "tegra-pmc", ++ .suppress_bind_attrs = true, ++ .of_match_table = tegra_pmc_match, ++ .pm = &tegra_pmc_pm_ops, ++ }, ++ .probe = tegra_pmc_probe, ++}; ++module_platform_driver(tegra_pmc_driver); ++ ++/* ++ * Early initialization to allow access to registers in the very early boot ++ * process. ++ */ ++static int __init tegra_pmc_early_init(void) ++{ ++ const struct of_device_id *match; ++ struct device_node *np; ++ struct resource regs; ++ bool invert; ++ u32 value; ++ ++ np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match); ++ if (!np) { ++ pr_warn("PMC device node not found, disabling powergating\n"); ++ ++ regs.start = 0x7000e400; ++ regs.end = 0x7000e7ff; ++ regs.flags = IORESOURCE_MEM; ++ ++ pr_warn("Using memory region %pR\n", ®s); ++ } else { ++ pmc->soc = match->data; ++ } ++ ++ if (of_address_to_resource(np, 0, ®s) < 0) { ++ pr_err("failed to get PMC registers\n"); ++ return -ENXIO; ++ } ++ ++ pmc->base = ioremap_nocache(regs.start, resource_size(®s)); ++ if (!pmc->base) { ++ pr_err("failed to map PMC registers\n"); ++ return -ENXIO; ++ } ++ ++ mutex_init(&pmc->powergates_lock); ++ ++ invert = of_property_read_bool(np, "nvidia,invert-interrupt"); ++ ++ value = tegra_pmc_readl(PMC_CNTRL); ++ ++ if (invert) ++ value |= PMC_CNTRL_INTR_POLARITY; ++ else ++ value &= ~PMC_CNTRL_INTR_POLARITY; ++ ++ tegra_pmc_writel(value, PMC_CNTRL); ++ ++ return 0; ++} ++early_initcall(tegra_pmc_early_init); diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c -index 15ac9fc..cf6a7ac 100644 +index 15ac9fc..4482ad8 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c -@@ -34,6 +34,7 @@ - #include <linux/usb/tegra_usb_phy.h> - #include <linux/clk/tegra.h> - #include <linux/irqchip.h> +@@ -16,40 +16,38 @@ + * + */ + +-#include <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/platform_device.h> +-#include <linux/serial_8250.h> + #include <linux/clk.h> ++#include <linux/clk/tegra.h> + #include <linux/dma-mapping.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/irqchip.h> + #include <linux/irqdomain.h> +-#include <linux/of.h> ++#include <linux/kernel.h> + #include <linux/of_address.h> + #include <linux/of_fdt.h> ++#include <linux/of.h> + #include <linux/of_platform.h> + #include <linux/pda_power.h> +-#include <linux/io.h> ++#include <linux/platform_device.h> ++#include <linux/serial_8250.h> + #include <linux/slab.h> + #include <linux/sys_soc.h> +#include <linux/tegra-soc.h> + #include <linux/usb/tegra_usb_phy.h> +-#include <linux/clk/tegra.h> +-#include <linux/irqchip.h> #include <asm/hardware/cache-l2x0.h> - #include <asm/mach-types.h> -@@ -42,11 +43,9 @@ +-#include <asm/mach-types.h> + #include <asm/mach/arch.h> + #include <asm/mach/time.h> ++#include <asm/mach-types.h> #include <asm/setup.h> #include <asm/trusted_foundations.h> @@ -3075,25 +5834,56 @@ index 15ac9fc..cf6a7ac 100644 -#include "fuse.h" #include "iomap.h" #include "irq.h" - #include "pmc.h" -@@ -73,7 +72,6 @@ u32 tegra_uart_config[3] = { +-#include "pmc.h" + #include "pm.h" + #include "reset.h" + #include "sleep.h" +@@ -73,16 +71,11 @@ u32 tegra_uart_config[3] = { static void __init tegra_init_early(void) { of_register_trusted_foundations(); - tegra_apb_io_init(); - tegra_init_fuse(); +- tegra_init_fuse(); tegra_cpu_reset_handler_init(); - tegra_powergate_init(); -@@ -103,7 +101,8 @@ static void __init tegra_dt_init(void) +- tegra_powergate_init(); +- tegra_hotplug_init(); + } + + static void __init tegra_dt_init_irq(void) + { +- tegra_pmc_init_irq(); + tegra_init_irq(); + irqchip_init(); + tegra_legacy_irq_syscore_init(); +@@ -94,8 +87,6 @@ static void __init tegra_dt_init(void) + struct soc_device *soc_dev; + struct device *parent = NULL; + +- tegra_pmc_init(); +- + tegra_clocks_apply_init_table(); + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); +@@ -103,8 +94,9 @@ static void __init tegra_dt_init(void) goto out; soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); +- soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", -+ tegra_sku_info.revision); - soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id); ++ tegra_sku_info.revision); ++ soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id()); soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { +@@ -144,7 +136,6 @@ static void __init tegra_dt_init_late(void) + + tegra_init_suspend(); + tegra_cpuidle_init(); +- tegra_powergate_debugfs_init(); + + for (i = 0; i < ARRAY_SIZE(board_init_funcs); i++) { + if (of_machine_is_compatible(board_init_funcs[i].machine)) { diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c deleted file mode 100644 index 5218d48..0000000 @@ -3662,15 +6452,6 @@ index d1869f0..d2616ef 100644 ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); if (ret) { pr_err("Failed to register timer IRQ: %d\n", ret); -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index d59ce12..f4ac83b 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -56,3 +56,4 @@ obj-y += mic/ - obj-$(CONFIG_GENWQE) += genwqe/ - obj-$(CONFIG_ECHO) += echo/ - obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o -+obj-y += fuse/ diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile new file mode 100644 index 0000000..0679c4f @@ -3678,11 +6459,1273 @@ index 0000000..0679c4f +++ b/drivers/misc/fuse/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ -diff --git a/drivers/misc/fuse/tegra/Makefile b/drivers/misc/fuse/tegra/Makefile +diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c +index 083cf37..7df5aaf 100644 +--- a/drivers/pci/host/pci-tegra.c ++++ b/drivers/pci/host/pci-tegra.c +@@ -233,7 +233,6 @@ struct tegra_pcie_soc_data { + bool has_pex_clkreq_en; + bool has_pex_bias_ctrl; + bool has_intr_prsnt_sense; +- bool has_avdd_supply; + bool has_cml_clk; + }; + +@@ -272,9 +271,8 @@ struct tegra_pcie { + unsigned int num_ports; + u32 xbar_config; + +- struct regulator *pex_clk_supply; +- struct regulator *vdd_supply; +- struct regulator *avdd_supply; ++ struct regulator_bulk_data *supplies; ++ unsigned int num_supplies; + + const struct tegra_pcie_soc_data *soc_data; + }; +@@ -894,7 +892,6 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) + + static void tegra_pcie_power_off(struct tegra_pcie *pcie) + { +- const struct tegra_pcie_soc_data *soc = pcie->soc_data; + int err; + + /* TODO: disable and unprepare clocks? */ +@@ -905,23 +902,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) + + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + +- if (soc->has_avdd_supply) { +- err = regulator_disable(pcie->avdd_supply); +- if (err < 0) +- dev_warn(pcie->dev, +- "failed to disable AVDD regulator: %d\n", +- err); +- } +- +- err = regulator_disable(pcie->pex_clk_supply); ++ err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); + if (err < 0) +- dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n", +- err); +- +- err = regulator_disable(pcie->vdd_supply); +- if (err < 0) +- dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n", +- err); ++ dev_warn(pcie->dev, "failed to disable regulators: %d\n", err); + } + + static int tegra_pcie_power_on(struct tegra_pcie *pcie) +@@ -936,28 +919,9 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + + /* enable regulators */ +- err = regulator_enable(pcie->vdd_supply); +- if (err < 0) { +- dev_err(pcie->dev, "failed to enable VDD regulator: %d\n", err); +- return err; +- } +- +- err = regulator_enable(pcie->pex_clk_supply); +- if (err < 0) { +- dev_err(pcie->dev, "failed to enable pex-clk regulator: %d\n", +- err); +- return err; +- } +- +- if (soc->has_avdd_supply) { +- err = regulator_enable(pcie->avdd_supply); +- if (err < 0) { +- dev_err(pcie->dev, +- "failed to enable AVDD regulator: %d\n", +- err); +- return err; +- } +- } ++ err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); ++ if (err < 0) ++ dev_err(pcie->dev, "failed to enable regulators: %d\n", err); + + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, + pcie->pex_clk, +@@ -1394,14 +1358,83 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, + return -EINVAL; + } + ++/* ++ * Obtains the list of regulators required for a particular generation of the ++ * IP block. ++ * ++ * This would've been nice to do simply by providing static tables for use ++ * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky ++ * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB) ++ * and either seems to be optional depending on which ports are being used. ++ */ ++static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) ++{ ++ struct device_node *np = pcie->dev->of_node; ++ unsigned int i = 0; ++ ++ if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { ++ bool need_pexa = false, need_pexb = false; ++ ++ /* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */ ++ if (lane_mask & 0x0f) ++ need_pexa = true; ++ ++ /* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */ ++ if (lane_mask & 0x30) ++ need_pexb = true; ++ ++ pcie->num_supplies = 4 + (need_pexa ? 2 : 0) + ++ (need_pexb ? 2 : 0); ++ ++ pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, ++ sizeof(*pcie->supplies), ++ GFP_KERNEL); ++ if (!pcie->supplies) ++ return -ENOMEM; ++ ++ pcie->supplies[i++].supply = "avdd-pex-pll"; ++ pcie->supplies[i++].supply = "hvdd-pex"; ++ pcie->supplies[i++].supply = "vddio-pex-ctl"; ++ pcie->supplies[i++].supply = "avdd-plle"; ++ ++ if (need_pexa) { ++ pcie->supplies[i++].supply = "avdd-pexa"; ++ pcie->supplies[i++].supply = "vdd-pexa"; ++ } ++ ++ if (need_pexb) { ++ pcie->supplies[i++].supply = "avdd-pexb"; ++ pcie->supplies[i++].supply = "vdd-pexb"; ++ } ++ } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { ++ pcie->num_supplies = 5; ++ ++ pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, ++ sizeof(*pcie->supplies), ++ GFP_KERNEL); ++ if (!pcie->supplies) ++ return -ENOMEM; ++ ++ pcie->supplies[0].supply = "avdd-pex"; ++ pcie->supplies[1].supply = "vdd-pex"; ++ pcie->supplies[2].supply = "avdd-pex-pll"; ++ pcie->supplies[3].supply = "avdd-plle"; ++ pcie->supplies[4].supply = "vddio-pex-clk"; ++ } ++ ++ return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, ++ pcie->supplies); ++} ++ + static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + { + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + struct device_node *np = pcie->dev->of_node, *port; + struct of_pci_range_parser parser; + struct of_pci_range range; ++ u32 lanes = 0, mask = 0; ++ unsigned int lane = 0; + struct resource res; +- u32 lanes = 0; + int err; + + if (of_pci_range_parser_init(&parser, np)) { +@@ -1409,20 +1442,6 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + return -EINVAL; + } + +- pcie->vdd_supply = devm_regulator_get(pcie->dev, "vdd"); +- if (IS_ERR(pcie->vdd_supply)) +- return PTR_ERR(pcie->vdd_supply); +- +- pcie->pex_clk_supply = devm_regulator_get(pcie->dev, "pex-clk"); +- if (IS_ERR(pcie->pex_clk_supply)) +- return PTR_ERR(pcie->pex_clk_supply); +- +- if (soc->has_avdd_supply) { +- pcie->avdd_supply = devm_regulator_get(pcie->dev, "avdd"); +- if (IS_ERR(pcie->avdd_supply)) +- return PTR_ERR(pcie->avdd_supply); +- } +- + for_each_of_pci_range(&parser, &range) { + of_pci_range_to_resource(&range, np, &res); + +@@ -1490,8 +1509,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + + lanes |= value << (index << 3); + +- if (!of_device_is_available(port)) ++ if (!of_device_is_available(port)) { ++ lane += value; + continue; ++ } ++ ++ mask |= ((1 << value) - 1) << lane; ++ lane += value; + + rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL); + if (!rp) +@@ -1522,6 +1546,10 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + return err; + } + ++ err = tegra_pcie_get_regulators(pcie, mask); ++ if (err < 0) ++ return err; ++ + return 0; + } + +@@ -1615,7 +1643,6 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = { + .has_pex_clkreq_en = false, + .has_pex_bias_ctrl = false, + .has_intr_prsnt_sense = false, +- .has_avdd_supply = false, + .has_cml_clk = false, + }; + +@@ -1627,7 +1654,6 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = { + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_intr_prsnt_sense = true, +- .has_avdd_supply = true, + .has_cml_clk = true, + }; + +diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig +index 0042ccb..0fa42be 100644 +--- a/drivers/pinctrl/Kconfig ++++ b/drivers/pinctrl/Kconfig +@@ -328,6 +328,12 @@ config PINCTRL_TEGRA124 + bool + select PINCTRL_TEGRA + ++config PINCTRL_TEGRA_XUSB ++ def_bool y if ARCH_TEGRA ++ select GENERIC_PHY ++ select PINCONF ++ select PINMUX ++ + 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 c4b5d40..df88788 100644 +--- a/drivers/pinctrl/Makefile ++++ b/drivers/pinctrl/Makefile +@@ -55,6 +55,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o + obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o + obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o + obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o ++obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.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 a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c +new file mode 100644 +index 0000000..4a7daf5 +--- /dev/null ++++ b/drivers/pinctrl/pinctrl-tegra-xusb.c +@@ -0,0 +1,973 @@ ++/* ++ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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/delay.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/phy/phy.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/platform_device.h> ++#include <linux/reset.h> ++ ++#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> ++ ++#include "core.h" ++#include "pinctrl-utils.h" ++ ++#define XUSB_PADCTL_ELPG_PROGRAM 0x01c ++#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) ++#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) ++#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) ++ ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12) ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) ++ ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) ++#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) ++ ++#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 ++#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) ++#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) ++#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) ++#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1) ++#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) ++ ++#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 ++#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) ++#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) ++ ++struct tegra_xusb_padctl_function { ++ const char *name; ++ const char * const *groups; ++ unsigned int num_groups; ++}; ++ ++struct tegra_xusb_padctl_group { ++ const unsigned int *funcs; ++ unsigned int num_funcs; ++}; ++ ++struct tegra_xusb_padctl_soc { ++ const struct pinctrl_pin_desc *pins; ++ unsigned int num_pins; ++ ++ const struct tegra_xusb_padctl_function *functions; ++ unsigned int num_functions; ++ ++ const struct tegra_xusb_padctl_lane *lanes; ++ unsigned int num_lanes; ++}; ++ ++struct tegra_xusb_padctl_lane { ++ const char *name; ++ ++ unsigned int offset; ++ unsigned int shift; ++ unsigned int mask; ++ unsigned int iddq; ++ ++ const unsigned int *funcs; ++ unsigned int num_funcs; ++}; ++ ++struct tegra_xusb_padctl { ++ struct device *dev; ++ void __iomem *regs; ++ struct mutex lock; ++ struct reset_control *rst; ++ ++ const struct tegra_xusb_padctl_soc *soc; ++ struct pinctrl_dev *pinctrl; ++ struct pinctrl_desc desc; ++ ++ struct phy_provider *provider; ++ struct phy *phys[2]; ++ ++ unsigned int enable; ++}; ++ ++static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, ++ unsigned long offset) ++{ ++ writel(value, padctl->regs + offset); ++} ++ ++static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl, ++ unsigned long offset) ++{ ++ return readl(padctl->regs + offset); ++} ++ ++static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ ++ return padctl->soc->num_pins; ++} ++ ++static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl, ++ unsigned int group) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ ++ return padctl->soc->pins[group].name; ++} ++ ++enum tegra_xusb_padctl_param { ++ TEGRA_XUSB_PADCTL_IDDQ, ++}; ++ ++static const struct tegra_xusb_padctl_property { ++ const char *name; ++ enum tegra_xusb_padctl_param param; ++} properties[] = { ++ { "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ }, ++}; ++ ++#define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value)) ++#define TEGRA_XUSB_PADCTL_UNPACK_PARAM(config) ((config) >> 16) ++#define TEGRA_XUSB_PADCTL_UNPACK_VALUE(config) ((config) & 0xffff) ++ ++static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl, ++ struct device_node *np, ++ struct pinctrl_map **maps, ++ unsigned int *reserved_maps, ++ unsigned int *num_maps) ++{ ++ unsigned int i, reserve = 0, num_configs = 0; ++ unsigned long config, *configs = NULL; ++ const char *function, *group; ++ struct property *prop; ++ int err = 0; ++ u32 value; ++ ++ err = of_property_read_string(np, "nvidia,function", &function); ++ if (err < 0) { ++ if (err != -EINVAL) ++ return err; ++ ++ function = NULL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(properties); i++) { ++ err = of_property_read_u32(np, properties[i].name, &value); ++ if (err < 0) { ++ if (err == -EINVAL) ++ continue; ++ ++ return err; ++ } ++ ++ config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, value); ++ ++ err = pinctrl_utils_add_config(padctl->pinctrl, &configs, ++ &num_configs, config); ++ if (err < 0) ++ return err; ++ } ++ ++ if (function) ++ reserve++; ++ ++ if (num_configs) ++ reserve++; ++ ++ err = of_property_count_strings(np, "nvidia,lanes"); ++ if (err < 0) ++ return err; ++ ++ reserve *= err; ++ ++ err = pinctrl_utils_reserve_map(padctl->pinctrl, maps, reserved_maps, ++ num_maps, reserve); ++ if (err < 0) ++ return err; ++ ++ of_property_for_each_string(np, "nvidia,lanes", prop, group) { ++ if (function) { ++ err = pinctrl_utils_add_map_mux(padctl->pinctrl, maps, ++ reserved_maps, num_maps, group, ++ function); ++ if (err < 0) ++ return err; ++ } ++ ++ if (num_configs) { ++ err = pinctrl_utils_add_map_configs(padctl->pinctrl, ++ maps, reserved_maps, num_maps, group, ++ configs, num_configs, ++ PIN_MAP_TYPE_CONFIGS_GROUP); ++ if (err < 0) ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl, ++ struct device_node *parent, ++ struct pinctrl_map **maps, ++ unsigned int *num_maps) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ unsigned int reserved_maps = 0; ++ struct device_node *np; ++ int err; ++ ++ *num_maps = 0; ++ *maps = NULL; ++ ++ for_each_child_of_node(parent, np) { ++ err = tegra_xusb_padctl_parse_subnode(padctl, np, maps, ++ &reserved_maps, ++ num_maps); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static const struct pinctrl_ops tegra_xusb_padctl_pinctrl_ops = { ++ .get_groups_count = tegra_xusb_padctl_get_groups_count, ++ .get_group_name = tegra_xusb_padctl_get_group_name, ++ .dt_node_to_map = tegra_xusb_padctl_dt_node_to_map, ++ .dt_free_map = pinctrl_utils_dt_free_map, ++}; ++ ++static int tegra_xusb_padctl_get_functions_count(struct pinctrl_dev *pinctrl) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ ++ return padctl->soc->num_functions; ++} ++ ++static const char * ++tegra_xusb_padctl_get_function_name(struct pinctrl_dev *pinctrl, ++ unsigned int function) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ ++ return padctl->soc->functions[function].name; ++} ++ ++static int tegra_xusb_padctl_get_function_groups(struct pinctrl_dev *pinctrl, ++ unsigned int function, ++ const char * const **groups, ++ unsigned * const num_groups) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ ++ *num_groups = padctl->soc->functions[function].num_groups; ++ *groups = padctl->soc->functions[function].groups; ++ ++ return 0; ++} ++ ++static int tegra_xusb_padctl_pinmux_enable(struct pinctrl_dev *pinctrl, ++ unsigned int function, ++ unsigned int group) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ const struct tegra_xusb_padctl_lane *lane; ++ unsigned int i; ++ u32 value; ++ ++ lane = &padctl->soc->lanes[group]; ++ ++ for (i = 0; i < lane->num_funcs; i++) ++ if (lane->funcs[i] == function) ++ break; ++ ++ if (i >= lane->num_funcs) ++ return -EINVAL; ++ ++ value = padctl_readl(padctl, lane->offset); ++ value &= ~(lane->mask << lane->shift); ++ value |= i << lane->shift; ++ padctl_writel(padctl, value, lane->offset); ++ ++ return 0; ++} ++ ++static const struct pinmux_ops tegra_xusb_padctl_pinmux_ops = { ++ .get_functions_count = tegra_xusb_padctl_get_functions_count, ++ .get_function_name = tegra_xusb_padctl_get_function_name, ++ .get_function_groups = tegra_xusb_padctl_get_function_groups, ++ .enable = tegra_xusb_padctl_pinmux_enable, ++}; ++ ++static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl, ++ unsigned int group, ++ unsigned long *config) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ const struct tegra_xusb_padctl_lane *lane; ++ enum tegra_xusb_padctl_param param; ++ u32 value; ++ ++ param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config); ++ lane = &padctl->soc->lanes[group]; ++ ++ switch (param) { ++ case TEGRA_XUSB_PADCTL_IDDQ: ++ /* lanes with iddq == 0 don't support this parameter */ ++ if (lane->iddq == 0) ++ return -EINVAL; ++ ++ value = padctl_readl(padctl, lane->offset); ++ ++ if (value & BIT(lane->iddq)) ++ value = 0; ++ else ++ value = 1; ++ ++ *config = TEGRA_XUSB_PADCTL_PACK(param, value); ++ break; ++ ++ default: ++ dev_err(padctl->dev, "invalid configuration parameter: %04x\n", ++ param); ++ return -ENOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl, ++ unsigned int group, ++ unsigned long *configs, ++ unsigned int num_configs) ++{ ++ struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); ++ const struct tegra_xusb_padctl_lane *lane; ++ enum tegra_xusb_padctl_param param; ++ unsigned long value; ++ unsigned int i; ++ u32 regval; ++ ++ lane = &padctl->soc->lanes[group]; ++ ++ for (i = 0; i < num_configs; i++) { ++ param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(configs[i]); ++ value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(configs[i]); ++ ++ switch (param) { ++ case TEGRA_XUSB_PADCTL_IDDQ: ++ /* lanes with iddq == 0 don't support this parameter */ ++ if (lane->iddq == 0) ++ return -EINVAL; ++ ++ regval = padctl_readl(padctl, lane->offset); ++ ++ if (value) ++ regval &= ~BIT(lane->iddq); ++ else ++ regval |= BIT(lane->iddq); ++ ++ padctl_writel(padctl, regval, lane->offset); ++ break; ++ ++ default: ++ dev_err(padctl->dev, ++ "invalid configuration parameter: %04x\n", ++ param); ++ return -ENOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static const char *strip_prefix(const char *s) ++{ ++ const char *comma = strchr(s, ','); ++ if (!comma) ++ return s; ++ ++ return comma + 1; ++} ++ ++static void ++tegra_xusb_padctl_pinconf_group_dbg_show(struct pinctrl_dev *pinctrl, ++ struct seq_file *s, ++ unsigned int group) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(properties); i++) { ++ unsigned long config, value; ++ int err; ++ ++ config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, 0); ++ ++ err = tegra_xusb_padctl_pinconf_group_get(pinctrl, group, ++ &config); ++ if (err < 0) ++ continue; ++ ++ value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config); ++ ++ seq_printf(s, "\n\t%s=%lu\n", strip_prefix(properties[i].name), ++ value); ++ } ++} ++ ++static void ++tegra_xusb_padctl_pinconf_config_dbg_show(struct pinctrl_dev *pinctrl, ++ struct seq_file *s, ++ unsigned long config) ++{ ++ enum tegra_xusb_padctl_param param; ++ const char *name = "unknown"; ++ unsigned long value; ++ unsigned int i; ++ ++ param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(config); ++ value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config); ++ ++ for (i = 0; i < ARRAY_SIZE(properties); i++) { ++ if (properties[i].param == param) { ++ name = properties[i].name; ++ break; ++ } ++ } ++ ++ seq_printf(s, "%s=%lu", strip_prefix(name), value); ++} ++#endif ++ ++static const struct pinconf_ops tegra_xusb_padctl_pinconf_ops = { ++ .pin_config_group_get = tegra_xusb_padctl_pinconf_group_get, ++ .pin_config_group_set = tegra_xusb_padctl_pinconf_group_set, ++#ifdef CONFIG_DEBUG_FS ++ .pin_config_group_dbg_show = tegra_xusb_padctl_pinconf_group_dbg_show, ++ .pin_config_config_dbg_show = tegra_xusb_padctl_pinconf_config_dbg_show, ++#endif ++}; ++ ++static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) ++{ ++ u32 value; ++ ++ mutex_lock(&padctl->lock); ++ ++ if (padctl->enable++ > 0) ++ goto out; ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); ++ value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; ++ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); ++ ++ usleep_range(100, 200); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); ++ value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; ++ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); ++ ++ usleep_range(100, 200); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); ++ value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; ++ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); ++ ++out: ++ mutex_unlock(&padctl->lock); ++ return 0; ++} ++ ++static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) ++{ ++ u32 value; ++ ++ mutex_lock(&padctl->lock); ++ ++ if (WARN_ON(padctl->enable == 0)) ++ goto out; ++ ++ if (--padctl->enable > 0) ++ goto out; ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); ++ value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; ++ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); ++ ++ usleep_range(100, 200); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); ++ value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; ++ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); ++ ++ usleep_range(100, 200); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); ++ value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; ++ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); ++ ++out: ++ mutex_unlock(&padctl->lock); ++ return 0; ++} ++ ++static int tegra_xusb_phy_init(struct phy *phy) ++{ ++ struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); ++ ++ return tegra_xusb_padctl_enable(padctl); ++} ++ ++static int tegra_xusb_phy_exit(struct phy *phy) ++{ ++ struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); ++ ++ return tegra_xusb_padctl_disable(padctl); ++} ++ ++static int pcie_phy_power_on(struct phy *phy) ++{ ++ struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); ++ unsigned long timeout; ++ int err = -ETIMEDOUT; ++ u32 value; ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); ++ value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN | ++ XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN | ++ XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ ++ timeout = jiffies + msecs_to_jiffies(50); ++ ++ while (time_before(jiffies, timeout)) { ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) { ++ err = 0; ++ break; ++ } ++ ++ usleep_range(100, 200); ++ } ++ ++ return err; ++} ++ ++static int pcie_phy_power_off(struct phy *phy) ++{ ++ struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); ++ u32 value; ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); ++ ++ return 0; ++} ++ ++static const struct phy_ops pcie_phy_ops = { ++ .init = tegra_xusb_phy_init, ++ .exit = tegra_xusb_phy_exit, ++ .power_on = pcie_phy_power_on, ++ .power_off = pcie_phy_power_off, ++ .owner = THIS_MODULE, ++}; ++ ++static int sata_phy_power_on(struct phy *phy) ++{ ++ struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); ++ unsigned long timeout; ++ int err = -ETIMEDOUT; ++ u32 value; ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); ++ value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; ++ value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; ++ value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ ++ timeout = jiffies + msecs_to_jiffies(50); ++ ++ while (time_before(jiffies, timeout)) { ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) { ++ err = 0; ++ break; ++ } ++ ++ usleep_range(100, 200); ++ } ++ ++ return err; ++} ++ ++static int sata_phy_power_off(struct phy *phy) ++{ ++ struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); ++ u32 value; ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; ++ value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); ++ ++ value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); ++ value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; ++ value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; ++ padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); ++ ++ return 0; ++} ++ ++static const struct phy_ops sata_phy_ops = { ++ .init = tegra_xusb_phy_init, ++ .exit = tegra_xusb_phy_exit, ++ .power_on = sata_phy_power_on, ++ .power_off = sata_phy_power_off, ++ .owner = THIS_MODULE, ++}; ++ ++static struct phy *tegra_xusb_padctl_xlate(struct device *dev, ++ struct of_phandle_args *args) ++{ ++ struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev); ++ unsigned int index = args->args[0]; ++ ++ if (args->args_count <= 0) ++ return ERR_PTR(-EINVAL); ++ ++ if (index > ARRAY_SIZE(padctl->phys)) ++ return ERR_PTR(-EINVAL); ++ ++ return padctl->phys[index]; ++} ++ ++#define PIN_OTG_0 0 ++#define PIN_OTG_1 1 ++#define PIN_OTG_2 2 ++#define PIN_ULPI_0 3 ++#define PIN_HSIC_0 4 ++#define PIN_HSIC_1 5 ++#define PIN_PCIE_0 6 ++#define PIN_PCIE_1 7 ++#define PIN_PCIE_2 8 ++#define PIN_PCIE_3 9 ++#define PIN_PCIE_4 10 ++#define PIN_SATA_0 11 ++ ++static const struct pinctrl_pin_desc tegra124_pins[] = { ++ PINCTRL_PIN(PIN_OTG_0, "otg-0"), ++ PINCTRL_PIN(PIN_OTG_1, "otg-1"), ++ PINCTRL_PIN(PIN_OTG_2, "otg-2"), ++ PINCTRL_PIN(PIN_ULPI_0, "ulpi-0"), ++ PINCTRL_PIN(PIN_HSIC_0, "hsic-0"), ++ PINCTRL_PIN(PIN_HSIC_1, "hsic-1"), ++ PINCTRL_PIN(PIN_PCIE_0, "pcie-0"), ++ PINCTRL_PIN(PIN_PCIE_1, "pcie-1"), ++ PINCTRL_PIN(PIN_PCIE_2, "pcie-2"), ++ PINCTRL_PIN(PIN_PCIE_3, "pcie-3"), ++ PINCTRL_PIN(PIN_PCIE_4, "pcie-4"), ++ PINCTRL_PIN(PIN_SATA_0, "sata-0"), ++}; ++ ++static const char * const tegra124_snps_groups[] = { ++ "otg-0", ++ "otg-1", ++ "otg-2", ++ "ulpi-0", ++ "hsic-0", ++ "hsic-1", ++}; ++ ++static const char * const tegra124_xusb_groups[] = { ++ "otg-0", ++ "otg-1", ++ "otg-2", ++ "ulpi-0", ++ "hsic-0", ++ "hsic-1", ++}; ++ ++static const char * const tegra124_uart_groups[] = { ++ "otg-0", ++ "otg-1", ++ "otg-2", ++}; ++ ++static const char * const tegra124_pcie_groups[] = { ++ "pcie-0", ++ "pcie-1", ++ "pcie-2", ++ "pcie-3", ++ "pcie-4", ++ "sata-0", ++}; ++ ++static const char * const tegra124_usb3_groups[] = { ++ "pcie-0", ++ "pcie-1", ++ "pcie-2", ++ "pcie-3", ++ "pcie-4", ++ "sata-0", ++}; ++ ++static const char * const tegra124_sata_groups[] = { ++ "pcie-0", ++ "pcie-1", ++ "pcie-2", ++ "pcie-3", ++ "pcie-4", ++ "sata-0", ++}; ++ ++static const char * const tegra124_rsvd_groups[] = { ++ "otg-0", ++ "otg-1", ++ "otg-2", ++ "pcie-0", ++ "pcie-1", ++ "pcie-2", ++ "pcie-3", ++ "pcie-4", ++ "sata-0", ++}; ++ ++#define TEGRA124_FUNCTION(_name) \ ++ { \ ++ .name = #_name, \ ++ .num_groups = ARRAY_SIZE(tegra124_##_name##_groups), \ ++ .groups = tegra124_##_name##_groups, \ ++ } ++ ++static struct tegra_xusb_padctl_function tegra124_functions[] = { ++ TEGRA124_FUNCTION(snps), ++ TEGRA124_FUNCTION(xusb), ++ TEGRA124_FUNCTION(uart), ++ TEGRA124_FUNCTION(pcie), ++ TEGRA124_FUNCTION(usb3), ++ TEGRA124_FUNCTION(sata), ++ TEGRA124_FUNCTION(rsvd), ++}; ++ ++enum tegra124_function { ++ TEGRA124_FUNC_SNPS, ++ TEGRA124_FUNC_XUSB, ++ TEGRA124_FUNC_UART, ++ TEGRA124_FUNC_PCIE, ++ TEGRA124_FUNC_USB3, ++ TEGRA124_FUNC_SATA, ++ TEGRA124_FUNC_RSVD, ++}; ++ ++static const unsigned int tegra124_otg_functions[] = { ++ TEGRA124_FUNC_SNPS, ++ TEGRA124_FUNC_XUSB, ++ TEGRA124_FUNC_UART, ++ TEGRA124_FUNC_RSVD, ++}; ++ ++static const unsigned int tegra124_usb_functions[] = { ++ TEGRA124_FUNC_SNPS, ++ TEGRA124_FUNC_XUSB, ++}; ++ ++static const unsigned int tegra124_pci_functions[] = { ++ TEGRA124_FUNC_PCIE, ++ TEGRA124_FUNC_USB3, ++ TEGRA124_FUNC_SATA, ++ TEGRA124_FUNC_RSVD, ++}; ++ ++#define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs) \ ++ { \ ++ .name = _name, \ ++ .offset = _offset, \ ++ .shift = _shift, \ ++ .mask = _mask, \ ++ .iddq = _iddq, \ ++ .num_funcs = ARRAY_SIZE(tegra124_##_funcs##_functions), \ ++ .funcs = tegra124_##_funcs##_functions, \ ++ } ++ ++static const struct tegra_xusb_padctl_lane tegra124_lanes[] = { ++ TEGRA124_LANE("otg-0", 0x004, 0, 0x3, 0, otg), ++ TEGRA124_LANE("otg-1", 0x004, 2, 0x3, 0, otg), ++ TEGRA124_LANE("otg-2", 0x004, 4, 0x3, 0, otg), ++ TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb), ++ TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb), ++ TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb), ++ TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci), ++ TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci), ++ TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci), ++ TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci), ++ TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci), ++ TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci), ++}; ++ ++static const struct tegra_xusb_padctl_soc tegra124_soc = { ++ .num_pins = ARRAY_SIZE(tegra124_pins), ++ .pins = tegra124_pins, ++ .num_functions = ARRAY_SIZE(tegra124_functions), ++ .functions = tegra124_functions, ++ .num_lanes = ARRAY_SIZE(tegra124_lanes), ++ .lanes = tegra124_lanes, ++}; ++ ++static const struct of_device_id tegra_xusb_padctl_of_match[] = { ++ { .compatible = "nvidia,tegra124-xusb-padctl", .data = &tegra124_soc }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); ++ ++static int tegra_xusb_padctl_probe(struct platform_device *pdev) ++{ ++ struct tegra_xusb_padctl *padctl; ++ const struct of_device_id *match; ++ struct resource *res; ++ struct phy *phy; ++ int err; ++ ++ padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL); ++ if (!padctl) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, padctl); ++ mutex_init(&padctl->lock); ++ padctl->dev = &pdev->dev; ++ ++ match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node); ++ padctl->soc = match->data; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ padctl->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(padctl->regs)) ++ return PTR_ERR(padctl->regs); ++ ++ padctl->rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(padctl->rst)) ++ return PTR_ERR(padctl->rst); ++ ++ err = reset_control_deassert(padctl->rst); ++ if (err < 0) ++ return err; ++ ++ memset(&padctl->desc, 0, sizeof(padctl->desc)); ++ padctl->desc.name = dev_name(padctl->dev); ++ padctl->desc.pctlops = &tegra_xusb_padctl_pinctrl_ops; ++ padctl->desc.pmxops = &tegra_xusb_padctl_pinmux_ops; ++ padctl->desc.confops = &tegra_xusb_padctl_pinconf_ops; ++ padctl->desc.owner = THIS_MODULE; ++ ++ padctl->pinctrl = pinctrl_register(&padctl->desc, &pdev->dev, padctl); ++ if (!padctl->pinctrl) { ++ dev_err(&pdev->dev, "failed to register pincontrol\n"); ++ err = -ENODEV; ++ goto reset; ++ } ++ ++ phy = devm_phy_create(&pdev->dev, &pcie_phy_ops, NULL); ++ if (IS_ERR(phy)) { ++ err = PTR_ERR(phy); ++ goto unregister; ++ } ++ ++ padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; ++ phy_set_drvdata(phy, padctl); ++ ++ phy = devm_phy_create(&pdev->dev, &sata_phy_ops, NULL); ++ if (IS_ERR(phy)) { ++ err = PTR_ERR(phy); ++ goto unregister; ++ } ++ ++ padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy; ++ phy_set_drvdata(phy, padctl); ++ ++ padctl->provider = devm_of_phy_provider_register(&pdev->dev, ++ tegra_xusb_padctl_xlate); ++ if (err < 0) { ++ dev_err(&pdev->dev, "failed to register PHYs: %d\n", err); ++ goto unregister; ++ } ++ ++ return 0; ++ ++unregister: ++ pinctrl_unregister(padctl->pinctrl); ++reset: ++ reset_control_assert(padctl->rst); ++ return err; ++} ++ ++static int tegra_xusb_padctl_remove(struct platform_device *pdev) ++{ ++ struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); ++ int err; ++ ++ pinctrl_unregister(padctl->pinctrl); ++ ++ err = reset_control_assert(padctl->rst); ++ if (err < 0) ++ dev_err(&pdev->dev, "failed to assert reset: %d\n", err); ++ ++ return err; ++} ++ ++static struct platform_driver tegra_xusb_padctl_driver = { ++ .driver = { ++ .name = "tegra-xusb-padctl", ++ .of_match_table = tegra_xusb_padctl_of_match, ++ }, ++ .probe = tegra_xusb_padctl_probe, ++ .remove = tegra_xusb_padctl_remove, ++}; ++module_platform_driver(tegra_xusb_padctl_driver); ++ ++MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); ++MODULE_DESCRIPTION("Tegra 124 XUSB Pad Control driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile +index 0f7c447..3b1b95d 100644 +--- a/drivers/soc/Makefile ++++ b/drivers/soc/Makefile +@@ -3,3 +3,4 @@ + # + + obj-$(CONFIG_ARCH_QCOM) += qcom/ ++obj-$(CONFIG_ARCH_TEGRA) += tegra/ +diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile +new file mode 100644 +index 0000000..236600f +--- /dev/null ++++ b/drivers/soc/tegra/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_ARCH_TEGRA) += fuse/ +diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile new file mode 100644 index 0000000..3af357d --- /dev/null -+++ b/drivers/misc/fuse/tegra/Makefile ++++ b/drivers/soc/tegra/fuse/Makefile @@ -0,0 +1,8 @@ +obj-y += fuse-tegra.o +obj-y += fuse-tegra30.o @@ -3692,12 +7735,12 @@ index 0000000..3af357d +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o -diff --git a/drivers/misc/fuse/tegra/fuse-tegra.c b/drivers/misc/fuse/tegra/fuse-tegra.c +diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c new file mode 100644 -index 0000000..934073e +index 0000000..7cf83dd --- /dev/null -+++ b/drivers/misc/fuse/tegra/fuse-tegra.c -@@ -0,0 +1,154 @@ ++++ b/drivers/soc/tegra/fuse/fuse-tegra.c +@@ -0,0 +1,158 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * @@ -3798,15 +7841,16 @@ index 0000000..934073e + writel(reg, base + 0x14); +} + -+int tegra_fuse_readl(u32 offset, u32 *val) ++int tegra_fuse_readl(unsigned long offset, u32 *value) +{ + if (!fuse_readl) + return -EPROBE_DEFER; + -+ *val = fuse_readl(offset); ++ *value = fuse_readl(offset); + + return 0; +} ++EXPORT_SYMBOL(tegra_fuse_readl); + +int tegra_fuse_create_sysfs(struct device *dev, int size, + u32 (*readl)(const unsigned int offset)) @@ -3823,7 +7867,7 @@ index 0000000..934073e + return device_create_bin_file(dev, &fuse_bin_attr); +} + -+void __init tegra_init_fuse(void) ++static int __init tegra_init_fuse(void) +{ + struct device_node *np; + void __iomem *car_base; @@ -3837,10 +7881,10 @@ index 0000000..934073e + iounmap(car_base); + } else { + pr_err("Could not enable fuse clk. ioremap tegra car failed.\n"); -+ return; ++ return -ENXIO; + } + -+ if (tegra_chip_id == TEGRA20) ++ if (tegra_get_chip_id() == TEGRA20) + tegra20_init_fuse_early(); + else + tegra30_init_fuse_early(); @@ -3851,12 +7895,15 @@ index 0000000..934073e + tegra_sku_info.core_process_id); + pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", + tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); ++ ++ return 0; +} -diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c ++early_initcall(tegra_init_fuse); +diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c new file mode 100644 index 0000000..c3dcf11 --- /dev/null -+++ b/drivers/misc/fuse/tegra/fuse-tegra20.c ++++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. @@ -4072,11 +8119,11 @@ index 0000000..c3dcf11 + + iounmap(fuse_base); +} -diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c +diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c new file mode 100644 -index 0000000..8aef5d0 +index 0000000..a4cfb11 --- /dev/null -+++ b/drivers/misc/fuse/tegra/fuse-tegra30.c ++++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. @@ -4254,7 +8301,7 @@ index 0000000..8aef5d0 + +static void __init legacy_fuse_init(void) +{ -+ switch (tegra_chip_id) { ++ switch (tegra_get_chip_id()) { + case TEGRA30: + fuse_info = &tegra30_info; + break; @@ -4293,7 +8340,7 @@ index 0000000..8aef5d0 + + if (!fuse_base) { + pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n", -+ tegra_chip_id); ++ tegra_get_chip_id()); + return; + } + @@ -4301,11 +8348,11 @@ index 0000000..8aef5d0 + speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info); + tegra30_fuse_add_randomness(); +} -diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h +diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h new file mode 100644 index 0000000..3a398bf3 --- /dev/null -+++ b/drivers/misc/fuse/tegra/fuse.h ++++ b/drivers/soc/tegra/fuse/fuse.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Google, Inc. @@ -4378,11 +8425,11 @@ index 0000000..3a398bf3 +#endif + +#endif -diff --git a/drivers/misc/fuse/tegra/speedo-tegra114.c b/drivers/misc/fuse/tegra/speedo-tegra114.c +diff --git a/drivers/soc/tegra/fuse/speedo-tegra114.c b/drivers/soc/tegra/fuse/speedo-tegra114.c new file mode 100644 index 0000000..98d6cde --- /dev/null -+++ b/drivers/misc/fuse/tegra/speedo-tegra114.c ++++ b/drivers/soc/tegra/fuse/speedo-tegra114.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. @@ -4493,11 +8540,11 @@ index 0000000..98d6cde + break; + sku_info->core_process_id = i; +} -diff --git a/drivers/misc/fuse/tegra/speedo-tegra124.c b/drivers/misc/fuse/tegra/speedo-tegra124.c +diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c new file mode 100644 index 0000000..a15dd53 --- /dev/null -+++ b/drivers/misc/fuse/tegra/speedo-tegra124.c ++++ b/drivers/soc/tegra/fuse/speedo-tegra124.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. @@ -4666,11 +8713,11 @@ index 0000000..a15dd53 + pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", + sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); +} -diff --git a/drivers/misc/fuse/tegra/speedo-tegra20.c b/drivers/misc/fuse/tegra/speedo-tegra20.c +diff --git a/drivers/soc/tegra/fuse/speedo-tegra20.c b/drivers/soc/tegra/fuse/speedo-tegra20.c new file mode 100644 index 0000000..c951fa4 --- /dev/null -+++ b/drivers/misc/fuse/tegra/speedo-tegra20.c ++++ b/drivers/soc/tegra/fuse/speedo-tegra20.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. @@ -4781,11 +8828,11 @@ index 0000000..c951fa4 + } + sku_info->core_process_id = i; +} -diff --git a/drivers/misc/fuse/tegra/speedo-tegra30.c b/drivers/misc/fuse/tegra/speedo-tegra30.c +diff --git a/drivers/soc/tegra/fuse/speedo-tegra30.c b/drivers/soc/tegra/fuse/speedo-tegra30.c new file mode 100644 index 0000000..1a85ad8 --- /dev/null -+++ b/drivers/misc/fuse/tegra/speedo-tegra30.c ++++ b/drivers/soc/tegra/fuse/speedo-tegra30.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. @@ -5074,12 +9121,12 @@ index 0000000..1a85ad8 + sku_info->soc_speedo_id = 1; + } +} -diff --git a/drivers/misc/fuse/tegra/tegra-apbmisc.c b/drivers/misc/fuse/tegra/tegra-apbmisc.c +diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c new file mode 100644 -index 0000000..43e5bd5 +index 0000000..30126e6 --- /dev/null -+++ b/drivers/misc/fuse/tegra/tegra-apbmisc.c -@@ -0,0 +1,110 @@ ++++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c +@@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * @@ -5109,8 +9156,6 @@ index 0000000..43e5bd5 +#define APBMISC_SIZE 0x64 +#define FUSE_SKU_INFO 0x10 + -+int tegra_chip_id; -+ +static void __iomem *apbmisc_base; +static void __iomem *strapping_base; + @@ -5119,6 +9164,16 @@ index 0000000..43e5bd5 + return readl_relaxed(apbmisc_base + 4); +} + ++u8 tegra_get_chip_id(void) ++{ ++ if (!apbmisc_base) { ++ WARN(1, "Tegra Chip ID not yet available\n"); ++ return 0; ++ } ++ ++ return (tegra_read_chipid() >> 8) & 0xff; ++} ++ +u32 tegra_read_straps(void) +{ + if (strapping_base) @@ -5134,10 +9189,11 @@ index 0000000..43e5bd5 + +void __init tegra_init_revision(void) +{ -+ u32 id, minor_rev; ++ u32 id, chip_id, minor_rev; + int rev; + + id = tegra_read_chipid(); ++ chip_id = (id >> 8) & 0xff; + minor_rev = (id >> 16) & 0xf; + + switch (minor_rev) { @@ -5148,9 +9204,8 @@ index 0000000..43e5bd5 + rev = TEGRA_REVISION_A02; + break; + case 3: -+ if (tegra_chip_id == TEGRA20 && -+ (tegra20_spare_fuse_early(18) || -+ tegra20_spare_fuse_early(19))) ++ if (chip_id == TEGRA20 && (tegra20_spare_fuse_early(18) || ++ tegra20_spare_fuse_early(19))) + rev = TEGRA_REVISION_A03p; + else + rev = TEGRA_REVISION_A03; @@ -5164,7 +9219,7 @@ index 0000000..43e5bd5 + + tegra_sku_info.revision = rev; + -+ if (tegra_chip_id == TEGRA20) ++ if (chip_id == TEGRA20) + tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO); + else + tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO); @@ -5173,7 +9228,6 @@ index 0000000..43e5bd5 +void __init tegra_init_apbmisc(void) +{ + struct device_node *np; -+ u32 id; + + np = of_find_matching_node(NULL, apbmisc_match); + apbmisc_base = of_iomap(np, 0); @@ -5183,256 +9237,28 @@ index 0000000..43e5bd5 + apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE); + } + -+ id = tegra_read_chipid(); -+ tegra_chip_id = (id >> 8) & 0xff; -+ + strapping_base = of_iomap(np, 1); + if (!strapping_base) + pr_err("ioremap tegra strapping_base failed\n"); +} -diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c -index 083cf37..7df5aaf 100644 ---- a/drivers/pci/host/pci-tegra.c -+++ b/drivers/pci/host/pci-tegra.c -@@ -233,7 +233,6 @@ struct tegra_pcie_soc_data { - bool has_pex_clkreq_en; - bool has_pex_bias_ctrl; - bool has_intr_prsnt_sense; -- bool has_avdd_supply; - bool has_cml_clk; - }; - -@@ -272,9 +271,8 @@ struct tegra_pcie { - unsigned int num_ports; - u32 xbar_config; - -- struct regulator *pex_clk_supply; -- struct regulator *vdd_supply; -- struct regulator *avdd_supply; -+ struct regulator_bulk_data *supplies; -+ unsigned int num_supplies; - - const struct tegra_pcie_soc_data *soc_data; - }; -@@ -894,7 +892,6 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) - - static void tegra_pcie_power_off(struct tegra_pcie *pcie) - { -- const struct tegra_pcie_soc_data *soc = pcie->soc_data; - int err; - - /* TODO: disable and unprepare clocks? */ -@@ -905,23 +902,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) - - tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); - -- if (soc->has_avdd_supply) { -- err = regulator_disable(pcie->avdd_supply); -- if (err < 0) -- dev_warn(pcie->dev, -- "failed to disable AVDD regulator: %d\n", -- err); -- } -- -- err = regulator_disable(pcie->pex_clk_supply); -+ err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); - if (err < 0) -- dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n", -- err); -- -- err = regulator_disable(pcie->vdd_supply); -- if (err < 0) -- dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n", -- err); -+ dev_warn(pcie->dev, "failed to disable regulators: %d\n", err); - } - - static int tegra_pcie_power_on(struct tegra_pcie *pcie) -@@ -936,28 +919,9 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) - tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); - - /* enable regulators */ -- err = regulator_enable(pcie->vdd_supply); -- if (err < 0) { -- dev_err(pcie->dev, "failed to enable VDD regulator: %d\n", err); -- return err; -- } -- -- err = regulator_enable(pcie->pex_clk_supply); -- if (err < 0) { -- dev_err(pcie->dev, "failed to enable pex-clk regulator: %d\n", -- err); -- return err; -- } -- -- if (soc->has_avdd_supply) { -- err = regulator_enable(pcie->avdd_supply); -- if (err < 0) { -- dev_err(pcie->dev, -- "failed to enable AVDD regulator: %d\n", -- err); -- return err; -- } -- } -+ err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); -+ if (err < 0) -+ dev_err(pcie->dev, "failed to enable regulators: %d\n", err); - - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, - pcie->pex_clk, -@@ -1394,14 +1358,83 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, - return -EINVAL; - } - -+/* -+ * Obtains the list of regulators required for a particular generation of the -+ * IP block. -+ * -+ * This would've been nice to do simply by providing static tables for use -+ * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky -+ * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB) -+ * and either seems to be optional depending on which ports are being used. -+ */ -+static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) -+{ -+ struct device_node *np = pcie->dev->of_node; -+ unsigned int i = 0; -+ -+ if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { -+ bool need_pexa = false, need_pexb = false; -+ -+ /* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */ -+ if (lane_mask & 0x0f) -+ need_pexa = true; -+ -+ /* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */ -+ if (lane_mask & 0x30) -+ need_pexb = true; -+ -+ pcie->num_supplies = 4 + (need_pexa ? 2 : 0) + -+ (need_pexb ? 2 : 0); -+ -+ pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, -+ sizeof(*pcie->supplies), -+ GFP_KERNEL); -+ if (!pcie->supplies) -+ return -ENOMEM; -+ -+ pcie->supplies[i++].supply = "avdd-pex-pll"; -+ pcie->supplies[i++].supply = "hvdd-pex"; -+ pcie->supplies[i++].supply = "vddio-pex-ctl"; -+ pcie->supplies[i++].supply = "avdd-plle"; -+ -+ if (need_pexa) { -+ pcie->supplies[i++].supply = "avdd-pexa"; -+ pcie->supplies[i++].supply = "vdd-pexa"; -+ } -+ -+ if (need_pexb) { -+ pcie->supplies[i++].supply = "avdd-pexb"; -+ pcie->supplies[i++].supply = "vdd-pexb"; -+ } -+ } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { -+ pcie->num_supplies = 5; -+ -+ pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, -+ sizeof(*pcie->supplies), -+ GFP_KERNEL); -+ if (!pcie->supplies) -+ return -ENOMEM; -+ -+ pcie->supplies[0].supply = "avdd-pex"; -+ pcie->supplies[1].supply = "vdd-pex"; -+ pcie->supplies[2].supply = "avdd-pex-pll"; -+ pcie->supplies[3].supply = "avdd-plle"; -+ pcie->supplies[4].supply = "vddio-pex-clk"; -+ } -+ -+ return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, -+ pcie->supplies); -+} -+ - static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) - { - const struct tegra_pcie_soc_data *soc = pcie->soc_data; - struct device_node *np = pcie->dev->of_node, *port; - struct of_pci_range_parser parser; - struct of_pci_range range; -+ u32 lanes = 0, mask = 0; -+ unsigned int lane = 0; - struct resource res; -- u32 lanes = 0; - int err; - - if (of_pci_range_parser_init(&parser, np)) { -@@ -1409,20 +1442,6 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) - return -EINVAL; - } - -- pcie->vdd_supply = devm_regulator_get(pcie->dev, "vdd"); -- if (IS_ERR(pcie->vdd_supply)) -- return PTR_ERR(pcie->vdd_supply); -- -- pcie->pex_clk_supply = devm_regulator_get(pcie->dev, "pex-clk"); -- if (IS_ERR(pcie->pex_clk_supply)) -- return PTR_ERR(pcie->pex_clk_supply); -- -- if (soc->has_avdd_supply) { -- pcie->avdd_supply = devm_regulator_get(pcie->dev, "avdd"); -- if (IS_ERR(pcie->avdd_supply)) -- return PTR_ERR(pcie->avdd_supply); -- } -- - for_each_of_pci_range(&parser, &range) { - of_pci_range_to_resource(&range, np, &res); - -@@ -1490,8 +1509,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) - - lanes |= value << (index << 3); - -- if (!of_device_is_available(port)) -+ if (!of_device_is_available(port)) { -+ lane += value; - continue; -+ } +diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h b/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h +new file mode 100644 +index 0000000..914d56d +--- /dev/null ++++ b/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h +@@ -0,0 +1,7 @@ ++#ifndef _DT_BINDINGS_PINCTRL_TEGRA_XUSB_H ++#define _DT_BINDINGS_PINCTRL_TEGRA_XUSB_H 1 + -+ mask |= ((1 << value) - 1) << lane; -+ lane += value; - - rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL); - if (!rp) -@@ -1522,6 +1546,10 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) - return err; - } - -+ err = tegra_pcie_get_regulators(pcie, mask); -+ if (err < 0) -+ return err; ++#define TEGRA_XUSB_PADCTL_PCIE 0 ++#define TEGRA_XUSB_PADCTL_SATA 1 + - return 0; - } - -@@ -1615,7 +1643,6 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = { - .has_pex_clkreq_en = false, - .has_pex_bias_ctrl = false, - .has_intr_prsnt_sense = false, -- .has_avdd_supply = false, - .has_cml_clk = false, - }; - -@@ -1627,7 +1654,6 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = { - .has_pex_clkreq_en = true, - .has_pex_bias_ctrl = true, - .has_intr_prsnt_sense = true, -- .has_avdd_supply = true, - .has_cml_clk = true, - }; - ++#endif /* _DT_BINDINGS_PINCTRL_TEGRA_XUSB_H */ diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h -index 95f611d..fcf65ec 100644 +index 95f611d..70a6124 100644 --- a/include/linux/tegra-soc.h +++ b/include/linux/tegra-soc.h -@@ -17,6 +17,48 @@ +@@ -17,6 +17,95 @@ #ifndef __LINUX_TEGRA_SOC_H_ #define __LINUX_TEGRA_SOC_H_ @@ -5446,6 +9272,11 @@ index 95f611d..fcf65ec 100644 + +#ifndef __ASSEMBLY__ + ++#include <linux/reboot.h> ++ + u32 tegra_read_chipid(void); ++u8 tegra_get_chip_id(void); ++ +enum tegra_revision { + TEGRA_REVISION_UNKNOWN = 0, + TEGRA_REVISION_A01, @@ -5471,13 +9302,55 @@ index 95f611d..fcf65ec 100644 +}; + +u32 tegra_read_straps(void); - u32 tegra_read_chipid(void); -+void tegra_init_fuse(void); -+int tegra_fuse_readl(u32 offset, u32 *val); ++u32 tegra_read_chipid(void); ++int tegra_fuse_readl(unsigned long offset, u32 *value); + -+extern int tegra_chip_id; +extern struct tegra_sku_info tegra_sku_info; + ++/* ++ * PMC ++ */ ++enum tegra_suspend_mode { ++ TEGRA_SUSPEND_NONE = 0, ++ TEGRA_SUSPEND_LP2, /* CPU voltage off */ ++ TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */ ++ TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */ ++ TEGRA_MAX_SUSPEND_MODE, ++}; ++ ++#ifdef CONFIG_PM_SLEEP ++enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void); ++void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode); ++void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode); ++ ++bool tegra_pmc_cpu_is_powered(int cpuid); ++int tegra_pmc_cpu_power_on(int cpuid); ++int tegra_pmc_cpu_remove_clamping(int cpuid); ++ ++void tegra_pmc_restart(enum reboot_mode mode, const char *cmd); ++#endif ++ ++/* ++ * PM ++ */ ++#ifdef CONFIG_PM_SLEEP ++enum tegra_suspend_mode ++tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode); ++ ++/* low-level resume entry point */ ++void tegra_resume(void); ++#else ++static inline enum tegra_suspend_mode ++tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode) ++{ ++ return TEGRA_SUSPEND_NONE; ++} ++ ++static inline void tegra_resume(void) ++{ ++} ++#endif /* CONFIG_PM_SLEEP */ ++ +#endif /* __ASSEMBLY__ */ #endif /* __LINUX_TEGRA_SOC_H_ */ |