summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Chauvet <kwizart@gmail.com>2013-07-23 00:23:59 +0200
committerNicolas Chauvet <kwizart@gmail.com>2013-10-12 14:20:36 +0200
commite792c5bf24d99b2dadbb74e59704f8fce02963f3 (patch)
treeeb96bfef4fcd8bd3b3a768e62a033fa68125ca69
parentbcc447331c08bcd58847294e33388f4b4ea271d6 (diff)
downloadkernel-e792c5bf24d99b2dadbb74e59704f8fce02963f3.tar.gz
kernel-e792c5bf24d99b2dadbb74e59704f8fce02963f3.tar.xz
kernel-e792c5bf24d99b2dadbb74e59704f8fce02963f3.zip
Add patches from marvin24s tree linux-3.10-ac100
git clone git://gitorious.org/~marvin24/ac100/marvin24s-kernel.git origin/linux-ac100-3.10
-rw-r--r--marvin24s-ac100-3.10.patch4044
1 files changed, 4044 insertions, 0 deletions
diff --git a/marvin24s-ac100-3.10.patch b/marvin24s-ac100-3.10.patch
new file mode 100644
index 00000000..125ef4b5
--- /dev/null
+++ b/marvin24s-ac100-3.10.patch
@@ -0,0 +1,4044 @@
+diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
+index b4fa934..9c65e8e 100644
+--- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
++++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
+@@ -67,6 +67,7 @@ of the following host1x client modules:
+ - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+ - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+ - nvidia,edid: supplies a binary EDID blob
++ - nvidia,panel: phandle of a display entity connected to this output
+
+ - hdmi: High Definition Multimedia Interface
+
+@@ -81,6 +82,7 @@ of the following host1x client modules:
+ - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+ - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+ - nvidia,edid: supplies a binary EDID blob
++ - nvidia,panel: phandle of a display entity connected to this output
+
+ - tvo: TV encoder output
+
+diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
+index 05ffecb..208fd3b 100644
+--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
++++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
+@@ -29,7 +29,6 @@ Required properties:
+ * MIC1_N
+ * MIC2_P
+ * MIC2_N
+- * MICBIAS1
+ * DMICDAT
+
+ Board connectors:
+@@ -53,7 +52,6 @@ sound {
+ nvidia,audio-routing =
+ "Int Spk", "SPK_OUTP",
+ "Int Spk", "SPK_OUTN",
+- "Headset Mic","MICBIAS1",
+ "MIC1_N", "Headset Mic",
+ "MIC1_P", "Headset Mic",
+ "Headset Stereophone", "HP_OUT_R",
+diff --git a/Documentation/devicetree/bindings/video/display/chunghwa,claa101wa01a.txt b/Documentation/devicetree/bindings/video/display/chunghwa,claa101wa01a.txt
+new file mode 100644
+index 0000000..cfdc7fd
+--- /dev/null
++++ b/Documentation/devicetree/bindings/video/display/chunghwa,claa101wa01a.txt
+@@ -0,0 +1,8 @@
++Chunghwa CLAA101WA01A Display Panel
++
++Required properties:
++- compatible: "chunghwa,claa101wa01a"
++- pnl-supply: regulator controlling power supply to the panel
++- bl-supply: regulator controlling power supply to the backlight
++- pnl-enable-gpios: GPIO that enables the panel
++- bl-enable-gpios: GPIO that enables the backlight
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 48c7480..74abed3 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2697,12 +2697,13 @@ F: include/drm/exynos*
+ F: include/uapi/drm/exynos*
+
+ DRM DRIVERS FOR NVIDIA TEGRA
+-M: Thierry Reding <thierry.reding@avionic-design.de>
++M: Thierry Reding <thierry.reding@gmail.com>
++M: Terje Bergström <tbergstrom@nvidia.com>
+ L: dri-devel@lists.freedesktop.org
+ L: linux-tegra@vger.kernel.org
+-T: git git://gitorious.org/thierryreding/linux.git
++T: git git://anongit.freedesktop.org/tegra/linux.git
+ S: Maintained
+-F: drivers/gpu/drm/tegra/
++F: drivers/gpu/host1x/
+ F: Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
+
+ DSBR100 USB FM RADIO DRIVER
+diff --git a/arch/arm/boot/dts/tegra20-colibri-512.dtsi b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
+index a573b94..0d7665e 100644
+--- a/arch/arm/boot/dts/tegra20-colibri-512.dtsi
++++ b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
+@@ -362,7 +362,7 @@
+ };
+
+ pmc {
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <5000>;
+ nvidia,cpu-pwr-off-time = <5000>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
+index e7d5de4..f0129c6 100644
+--- a/arch/arm/boot/dts/tegra20-harmony.dts
++++ b/arch/arm/boot/dts/tegra20-harmony.dts
+@@ -416,7 +416,7 @@
+
+ pmc {
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <5000>;
+ nvidia,cpu-pwr-off-time = <5000>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
+index e3e0c99..994f0b8 100644
+--- a/arch/arm/boot/dts/tegra20-paz00.dts
++++ b/arch/arm/boot/dts/tegra20-paz00.dts
+@@ -11,6 +11,14 @@
+ };
+
+ host1x {
++ dc@54200000 {
++ rgb {
++ status = "okay";
++ nvidia,ddc-i2c-bus = <&lvds_ddc>;
++ nvidia,panel = <&panel>;
++ };
++ };
++
+ hdmi {
+ status = "okay";
+
+@@ -250,7 +258,7 @@
+ status = "okay";
+ };
+
+- i2c@7000c000 {
++ lvds_ddc: i2c@7000c000 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+@@ -415,7 +423,7 @@
+
+ pmc {
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <2000>;
+ nvidia,cpu-pwr-off-time = <0>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+@@ -488,6 +496,30 @@
+ };
+ };
+
++ pwm: pwm {
++ status = "okay";
++ };
++
++ backlight: backlight {
++ compatible = "pwm-backlight";
++ pwms = <&pwm 2 5000000>;
++
++ brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>;
++ default-brightness-level = <10>;
++ };
++
++ panel: panel {
++ compatible = "chunghwa,claa101wa01a";
++
++ pnl-supply = <&vdd_panel_reg>;
++ pnl-enable-gpios = <&gpio 102 0>;
++
++ bl-supply = <&bl_panel_reg>;
++ bl-enable-gpios = <&gpio 164 0>;
++
++ backlight = <&backlight>;
++ };
++
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+@@ -501,6 +533,25 @@
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
++
++ vdd_panel_reg: regulator@1 {
++ compatible = "regulator-fixed";
++ reg = <1>;
++ regulator-name = "+3VS,vdd_pnl";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio 4 0>; /* gpio PA4 */
++ enable-active-high;
++ };
++
++ bl_panel_reg: regulator@2 {
++ compatible = "regulator-fixed";
++ reg = <2>;
++ regulator-name = "dummy blacklight regulator";
++ regulator-min-microvolt = <3000000>;
++ regulator-max-microvolt = <3000000>;
++ regulator-always-on;
++ };
+ };
+
+ sound {
+@@ -512,7 +563,6 @@
+ nvidia,audio-routing =
+ "Int Spk", "SPKOUT",
+ "Int Spk", "SPKOUTN",
+- "Headset Mic", "MICBIAS1",
+ "MIC1", "Headset Mic",
+ "Headset Stereophone", "HPR",
+ "Headset Stereophone", "HPL",
+diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
+index cee4c34..e22ef5f 100644
+--- a/arch/arm/boot/dts/tegra20-seaboard.dts
++++ b/arch/arm/boot/dts/tegra20-seaboard.dts
+@@ -517,7 +517,7 @@
+
+ pmc {
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <5000>;
+ nvidia,cpu-pwr-off-time = <5000>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi
+index 50b3ec1..4b396865 100644
+--- a/arch/arm/boot/dts/tegra20-tamonten.dtsi
++++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi
+@@ -458,7 +458,7 @@
+
+ pmc {
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <5000>;
+ nvidia,cpu-pwr-off-time = <5000>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
+index 9cc78a1..c7e568d 100644
+--- a/arch/arm/boot/dts/tegra20-trimslice.dts
++++ b/arch/arm/boot/dts/tegra20-trimslice.dts
+@@ -301,7 +301,7 @@
+ };
+
+ pmc {
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <5000>;
+ nvidia,cpu-pwr-off-time = <5000>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
+index dd38f1f..32cddf2 100644
+--- a/arch/arm/boot/dts/tegra20-ventana.dts
++++ b/arch/arm/boot/dts/tegra20-ventana.dts
+@@ -493,7 +493,7 @@
+
+ pmc {
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <2000>;
+ nvidia,cpu-pwr-off-time = <100>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
+index d2567f8..954b4a3 100644
+--- a/arch/arm/boot/dts/tegra20-whistler.dts
++++ b/arch/arm/boot/dts/tegra20-whistler.dts
+@@ -496,7 +496,7 @@
+
+ pmc {
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <2000>;
+ nvidia,cpu-pwr-off-time = <1000>;
+ nvidia,core-pwr-good-time = <0 3845>;
+diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts
+index b732f7c..22cfc03 100644
+--- a/arch/arm/boot/dts/tegra30-beaver.dts
++++ b/arch/arm/boot/dts/tegra30-beaver.dts
+@@ -253,7 +253,7 @@
+ pmc {
+ status = "okay";
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <2000>;
+ nvidia,cpu-pwr-off-time = <200>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
+index 01b4c26..4dc3e9b 100644
+--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
++++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
+@@ -307,7 +307,7 @@
+ pmc {
+ status = "okay";
+ nvidia,invert-interrupt;
+- nvidia,suspend-mode = <2>;
++ nvidia,suspend-mode = <1>;
+ nvidia,cpu-pwr-good-time = <2000>;
+ nvidia,cpu-pwr-off-time = <200>;
+ nvidia,core-pwr-good-time = <3845 3845>;
+diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
+index f7ba3161..594ceed 100644
+--- a/arch/arm/configs/tegra_defconfig
++++ b/arch/arm/configs/tegra_defconfig
+@@ -1,3 +1,4 @@
++CONFIG_SYSVIPC=y
+ CONFIG_NO_HZ=y
+ CONFIG_HIGH_RES_TIMERS=y
+ CONFIG_IKCONFIG=y
+@@ -21,8 +22,8 @@ CONFIG_MODULE_FORCE_UNLOAD=y
+ CONFIG_PARTITION_ADVANCED=y
+ # CONFIG_IOSCHED_DEADLINE is not set
+ # CONFIG_IOSCHED_CFQ is not set
+-CONFIG_ARCH_TEGRA=y
+ 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
+@@ -35,8 +36,9 @@ CONFIG_AEABI=y
+ CONFIG_HIGHMEM=y
+ CONFIG_ZBOOT_ROM_TEXT=0x0
+ CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_ARM_APPENDED_DTB=y
++CONFIG_ARM_ATAG_DTB_COMPAT=y
+ CONFIG_KEXEC=y
+-CONFIG_AUTO_ZRELADDR=y
+ CONFIG_CPU_FREQ=y
+ CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+ CONFIG_CPU_IDLE=y
+@@ -81,7 +83,6 @@ CONFIG_DEVTMPFS_MOUNT=y
+ # CONFIG_FIRMWARE_IN_KERNEL is not set
+ CONFIG_CMA=y
+ CONFIG_MTD=y
+-CONFIG_MTD_CHAR=y
+ CONFIG_MTD_M25P80=y
+ CONFIG_PROC_DEVICETREE=y
+ CONFIG_BLK_DEV_LOOP=y
+@@ -105,8 +106,9 @@ CONFIG_BRCMFMAC=m
+ CONFIG_RT2X00=y
+ CONFIG_RT2800USB=m
+ CONFIG_INPUT_EVDEV=y
+-CONFIG_KEYBOARD_TEGRA=y
+ CONFIG_KEYBOARD_GPIO=y
++CONFIG_KEYBOARD_TEGRA=y
++CONFIG_MOUSE_PS2_ELANTECH=y
+ CONFIG_INPUT_MISC=y
+ CONFIG_INPUT_MPU3050=y
+ # CONFIG_LEGACY_PTYS is not set
+@@ -132,12 +134,13 @@ CONFIG_BATTERY_SBS=y
+ CONFIG_POWER_RESET=y
+ CONFIG_POWER_RESET_GPIO=y
+ CONFIG_SENSORS_LM90=y
+-CONFIG_MFD_TPS6586X=y
+-CONFIG_MFD_TPS65910=y
+ CONFIG_MFD_MAX8907=y
+-CONFIG_MFD_TPS65090=y
+ CONFIG_MFD_PALMAS=y
++CONFIG_MFD_TPS65090=y
++CONFIG_MFD_TPS6586X=y
++CONFIG_MFD_TPS65910=y
+ CONFIG_REGULATOR=y
++CONFIG_REGULATOR_DUMMY=y
+ CONFIG_REGULATOR_FIXED_VOLTAGE=y
+ CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+ CONFIG_REGULATOR_GPIO=y
+@@ -155,13 +158,14 @@ CONFIG_USB_VIDEO_CLASS=m
+ CONFIG_DRM=y
+ CONFIG_TEGRA_HOST1X=y
+ CONFIG_DRM_TEGRA=y
++CONFIG_DRM_TEGRA_STAGING=y
+ CONFIG_BACKLIGHT_LCD_SUPPORT=y
+ # CONFIG_LCD_CLASS_DEVICE is not set
+ CONFIG_BACKLIGHT_CLASS_DEVICE=y
+ # CONFIG_BACKLIGHT_GENERIC is not set
+-CONFIG_BACKLIGHT_PWM=y
++CONFIG_DISPLAY_CORE=y
++CONFIG_DISPLAY_PANEL_CLAA101WA01A=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+-CONFIG_LOGO=y
+ CONFIG_SOUND=y
+ CONFIG_SND=y
+ # CONFIG_SND_SUPPORT_OLD_API is not set
+@@ -182,6 +186,7 @@ CONFIG_USB_ACM=y
+ CONFIG_USB_WDM=y
+ CONFIG_USB_STORAGE=y
+ CONFIG_MMC=y
++CONFIG_MMC_UNSAFE_RESUME=y
+ CONFIG_MMC_BLOCK_MINORS=16
+ CONFIG_MMC_SDHCI=y
+ CONFIG_MMC_SDHCI_PLTFM=y
+@@ -192,6 +197,7 @@ CONFIG_LEDS_GPIO=y
+ CONFIG_LEDS_TRIGGERS=y
+ CONFIG_LEDS_TRIGGER_GPIO=y
+ CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc1"
+ CONFIG_RTC_DRV_MAX8907=y
+ CONFIG_RTC_DRV_PALMAS=y
+ CONFIG_RTC_DRV_TPS6586X=y
+@@ -203,7 +209,6 @@ CONFIG_TEGRA20_APB_DMA=y
+ CONFIG_STAGING=y
+ CONFIG_SENSORS_ISL29018=y
+ CONFIG_SENSORS_ISL29028=y
+-CONFIG_AK8975=y
+ CONFIG_MFD_NVEC=y
+ CONFIG_KEYBOARD_NVEC=y
+ CONFIG_SERIO_NVEC_PS2=y
+@@ -213,6 +218,7 @@ CONFIG_TEGRA_IOMMU_GART=y
+ CONFIG_TEGRA_IOMMU_SMMU=y
+ CONFIG_MEMORY=y
+ CONFIG_IIO=y
++CONFIG_AK8975=y
+ CONFIG_PWM=y
+ CONFIG_PWM_TEGRA=y
+ CONFIG_EXT2_FS=y
+diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
+index d011f0a..0412f85 100644
+--- a/arch/arm/mach-tegra/Makefile
++++ b/arch/arm/mach-tegra/Makefile
+@@ -17,11 +17,13 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
+ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
+ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o
++obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o
+ ifeq ($(CONFIG_CPU_IDLE),y)
+ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o
+ endif
+ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o
+ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o
++obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o
+ ifeq ($(CONFIG_CPU_IDLE),y)
+ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
+ endif
+diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
+index 0cdba8d..706aa42 100644
+--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
++++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
+@@ -177,7 +177,6 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+ {
+- u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
+ bool entered_lp2 = false;
+
+ if (tegra_pending_sgi())
+@@ -193,16 +192,16 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
+
+ local_fiq_disable();
+
+- tegra_set_cpu_in_lp2(cpu);
++ tegra_set_cpu_in_lp2();
+ cpu_pm_enter();
+
+- if (cpu == 0)
++ if (dev->cpu == 0)
+ entered_lp2 = tegra20_cpu_cluster_power_down(dev, drv, index);
+ else
+ entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index);
+
+ cpu_pm_exit();
+- tegra_clear_cpu_in_lp2(cpu);
++ tegra_clear_cpu_in_lp2();
+
+ local_fiq_enable();
+
+@@ -214,8 +213,5 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
+
+ int __init tegra20_cpuidle_init(void)
+ {
+-#ifdef CONFIG_PM_SLEEP
+- tegra_tear_down_cpu = tegra20_tear_down_cpu;
+-#endif
+ return cpuidle_register(&tegra_idle_driver, cpu_possible_mask);
+ }
+diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
+index 3cf9aca..ed2a2a7 100644
+--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
++++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
+@@ -114,16 +114,15 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+ {
+- u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
+ bool entered_lp2 = false;
+ bool last_cpu;
+
+ local_fiq_disable();
+
+- last_cpu = tegra_set_cpu_in_lp2(cpu);
++ last_cpu = tegra_set_cpu_in_lp2();
+ cpu_pm_enter();
+
+- if (cpu == 0) {
++ if (dev->cpu == 0) {
+ if (last_cpu)
+ entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv,
+ index);
+@@ -134,7 +133,7 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
+ }
+
+ cpu_pm_exit();
+- tegra_clear_cpu_in_lp2(cpu);
++ tegra_clear_cpu_in_lp2();
+
+ local_fiq_enable();
+
+@@ -146,8 +145,5 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
+
+ int __init tegra30_cpuidle_init(void)
+ {
+-#ifdef CONFIG_PM_SLEEP
+- tegra_tear_down_cpu = tegra30_tear_down_cpu;
+-#endif
+ return cpuidle_register(&tegra_idle_driver, NULL);
+ }
+diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
+index aacc00d..def7968 100644
+--- a/arch/arm/mach-tegra/fuse.h
++++ b/arch/arm/mach-tegra/fuse.h
+@@ -19,16 +19,6 @@
+ #ifndef __MACH_TEGRA_FUSE_H
+ #define __MACH_TEGRA_FUSE_H
+
+-enum tegra_revision {
+- TEGRA_REVISION_UNKNOWN = 0,
+- TEGRA_REVISION_A01,
+- TEGRA_REVISION_A02,
+- TEGRA_REVISION_A03,
+- TEGRA_REVISION_A03p,
+- TEGRA_REVISION_A04,
+- TEGRA_REVISION_MAX,
+-};
+-
+ #define SKU_ID_T20 8
+ #define SKU_ID_T25SE 20
+ #define SKU_ID_AP25 23
+@@ -40,6 +30,17 @@ enum tegra_revision {
+ #define TEGRA30 0x30
+ #define TEGRA114 0x35
+
++#ifndef __ASSEMBLY__
++enum tegra_revision {
++ TEGRA_REVISION_UNKNOWN = 0,
++ TEGRA_REVISION_A01,
++ TEGRA_REVISION_A02,
++ TEGRA_REVISION_A03,
++ TEGRA_REVISION_A03p,
++ TEGRA_REVISION_A04,
++ TEGRA_REVISION_MAX,
++};
++
+ extern int tegra_sku_id;
+ extern int tegra_cpu_process_id;
+ extern int tegra_core_process_id;
+@@ -72,5 +73,6 @@ void tegra114_init_speedo_data(void);
+ #else
+ static inline void tegra114_init_speedo_data(void) {}
+ #endif
++#endif /* __ASSEMBLY__ */
+
+ #endif
+diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
+index 184914a..5eedebd 100644
+--- a/arch/arm/mach-tegra/hotplug.c
++++ b/arch/arm/mach-tegra/hotplug.c
+@@ -37,7 +37,7 @@ int tegra_cpu_kill(unsigned cpu)
+ void __ref tegra_cpu_die(unsigned int cpu)
+ {
+ /* Clean L1 data cache */
+- tegra_disable_clean_inv_dcache();
++ tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS);
+
+ /* Shut down the current CPU. */
+ tegra_hotplug_shutdown();
+diff --git a/arch/arm/mach-tegra/pm-tegra20.c b/arch/arm/mach-tegra/pm-tegra20.c
+new file mode 100644
+index 0000000..47bc40b
+--- /dev/null
++++ b/arch/arm/mach-tegra/pm-tegra20.c
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (c) 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 "pm.h"
++
++#ifdef CONFIG_PM_SLEEP
++static struct tegra_lp1_iram tegra20_lp1_iram;
++extern u32 tegra20_iram_start, tegra20_iram_end;
++extern void tegra20_sleep_core_finish(unsigned long);
++
++void tegra20_lp1_iram_hook(void)
++{
++ tegra20_lp1_iram.start_addr = &tegra20_iram_start;
++ tegra20_lp1_iram.end_addr = &tegra20_iram_end;
++
++ tegra_lp1_iram = &tegra20_lp1_iram;
++}
++
++void tegra20_sleep_core_init(void)
++{
++ tegra_sleep_core_finish = tegra20_sleep_core_finish;
++}
++#endif
+diff --git a/arch/arm/mach-tegra/pm-tegra30.c b/arch/arm/mach-tegra/pm-tegra30.c
+new file mode 100644
+index 0000000..6786955
+--- /dev/null
++++ b/arch/arm/mach-tegra/pm-tegra30.c
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (c) 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 "pm.h"
++
++#ifdef CONFIG_PM_SLEEP
++static struct tegra_lp1_iram tegra30_lp1_iram;
++extern u32 tegra30_iram_start, tegra30_iram_end;
++extern void tegra30_sleep_core_finish(unsigned long);
++
++void tegra30_lp1_iram_hook(void)
++{
++ tegra30_lp1_iram.start_addr = &tegra30_iram_start;
++ tegra30_lp1_iram.end_addr = &tegra30_iram_end;
++
++ tegra_lp1_iram = &tegra30_lp1_iram;
++}
++
++void tegra30_sleep_core_init(void)
++{
++ tegra_sleep_core_finish = tegra30_sleep_core_finish;
++}
++#endif
+diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
+index 45cf52c..d2b8d56 100644
+--- a/arch/arm/mach-tegra/pm.c
++++ b/arch/arm/mach-tegra/pm.c
+@@ -37,12 +37,34 @@
+ #include "reset.h"
+ #include "flowctrl.h"
+ #include "fuse.h"
++#include "pm.h"
+ #include "pmc.h"
+ #include "sleep.h"
+
+ #ifdef CONFIG_PM_SLEEP
+ static DEFINE_SPINLOCK(tegra_lp2_lock);
++static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
++static u32 iram_save_size;
++static void *iram_save_addr;
++struct tegra_lp1_iram *tegra_lp1_iram;
+ void (*tegra_tear_down_cpu)(void);
++void (*tegra_sleep_core_finish)(unsigned long v2p);
++
++static void tegra_tear_down_cpu_init(void)
++{
++ switch (tegra_chip_id) {
++ case TEGRA20:
++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
++ tegra_tear_down_cpu = tegra20_tear_down_cpu;
++ break;
++ case TEGRA30:
++ case TEGRA114:
++ if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) ||
++ IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC))
++ tegra_tear_down_cpu = tegra30_tear_down_cpu;
++ break;
++ }
++}
+
+ /*
+ * restore_cpu_complex
+@@ -91,8 +113,9 @@ static void suspend_cpu_complex(void)
+ flowctrl_cpu_suspend_enter(cpu);
+ }
+
+-void tegra_clear_cpu_in_lp2(int phy_cpu_id)
++void tegra_clear_cpu_in_lp2(void)
+ {
++ int phy_cpu_id = cpu_logical_map(smp_processor_id());
+ u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
+
+ spin_lock(&tegra_lp2_lock);
+@@ -103,8 +126,9 @@ void tegra_clear_cpu_in_lp2(int phy_cpu_id)
+ spin_unlock(&tegra_lp2_lock);
+ }
+
+-bool tegra_set_cpu_in_lp2(int phy_cpu_id)
++bool tegra_set_cpu_in_lp2(void)
+ {
++ int phy_cpu_id = cpu_logical_map(smp_processor_id());
+ bool last_cpu = false;
+ cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
+ u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
+@@ -160,14 +184,97 @@ enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
+ return TEGRA_SUSPEND_NONE;
+
+ /*
+- * The Tegra devices only support suspending to LP2 currently.
++ * The Tegra devices only support suspending to LP1 currently.
+ */
+- if (mode > TEGRA_SUSPEND_LP2)
+- return TEGRA_SUSPEND_LP2;
++ if (mode > TEGRA_SUSPEND_LP1)
++ return TEGRA_SUSPEND_LP1;
+
+ return mode;
+ }
+
++static int tegra_sleep_core(unsigned long v2p)
++{
++ setup_mm_for_reboot();
++ tegra_sleep_core_finish(v2p);
++
++ /* should never here */
++ BUG();
++
++ return 0;
++}
++
++/*
++ * tegra_lp1_iram_hook
++ *
++ * Hooking the address of LP1 reset vector and SDRAM self-refresh code in
++ * SDRAM. These codes not be copied to IRAM in this fuction. We need to
++ * copy these code to IRAM before LP0/LP1 suspend and restore the content
++ * of IRAM after resume.
++ */
++static bool tegra_lp1_iram_hook(void)
++{
++ switch (tegra_chip_id) {
++ case TEGRA30:
++ tegra30_lp1_iram_hook();
++ break;
++ case TEGRA20:
++ tegra20_lp1_iram_hook();
++ break;
++ default:
++ break;
++ }
++
++ if (!tegra_lp1_iram)
++ return false;
++
++ iram_save_size = tegra_lp1_iram->end_addr - tegra_lp1_iram->start_addr;
++ iram_save_addr = kmalloc(iram_save_size, GFP_KERNEL);
++ if (!iram_save_addr)
++ return false;
++
++ return true;
++}
++
++static bool tegra_sleep_core_init(void)
++{
++ switch (tegra_chip_id) {
++ case TEGRA30:
++ tegra30_sleep_core_init();
++ break;
++ case TEGRA20:
++ tegra20_sleep_core_init();
++ break;
++ default:
++ break;
++ }
++
++ if (!tegra_sleep_core_finish)
++ return false;
++
++ return true;
++}
++
++static void tegra_suspend_enter_lp1(void)
++{
++ tegra_pmc_suspend();
++
++ /* copy the reset vector & SDRAM shutdown code into IRAM */
++ memcpy(iram_save_addr, iram_code, iram_save_size);
++ memcpy(iram_code, tegra_lp1_iram->start_addr, iram_save_size);
++
++ *((u32 *)tegra_cpu_lp1_mask) = 1;
++}
++
++static void tegra_suspend_exit_lp1(void)
++{
++ tegra_pmc_resume();
++
++ /* restore IRAM */
++ memcpy(iram_code, iram_save_addr, iram_save_size);
++
++ *(u32 *)tegra_cpu_lp1_mask = 0;
++}
++
+ static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
+ [TEGRA_SUSPEND_NONE] = "none",
+ [TEGRA_SUSPEND_LP2] = "LP2",
+@@ -191,18 +298,27 @@ static int __cpuinit tegra_suspend_enter(suspend_state_t state)
+
+ suspend_cpu_complex();
+ switch (mode) {
++ case TEGRA_SUSPEND_LP1:
++ tegra_suspend_enter_lp1();
++ break;
+ case TEGRA_SUSPEND_LP2:
+- tegra_set_cpu_in_lp2(0);
++ tegra_set_cpu_in_lp2();
+ break;
+ default:
+ break;
+ }
+
+- cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
++ if (mode == TEGRA_SUSPEND_LP2)
++ cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
++ else
++ cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_core);
+
+ switch (mode) {
++ case TEGRA_SUSPEND_LP1:
++ tegra_suspend_exit_lp1();
++ break;
+ case TEGRA_SUSPEND_LP2:
+- tegra_clear_cpu_in_lp2(0);
++ tegra_clear_cpu_in_lp2();
+ break;
+ default:
+ break;
+@@ -221,11 +337,23 @@ static const struct platform_suspend_ops tegra_suspend_ops = {
+
+ void __init tegra_init_suspend(void)
+ {
+- if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
++ enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
++
++ if (mode == TEGRA_SUSPEND_NONE)
+ return;
+
++ tegra_tear_down_cpu_init();
+ tegra_pmc_suspend_init();
+
++ if (mode >= TEGRA_SUSPEND_LP1) {
++ if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) {
++ pr_err("%s: unable to allocate memory for SDRAM"
++ "self-refresh -- LP0/LP1 unavailable\n",
++ __func__);
++ tegra_pmc_set_suspend_mode(TEGRA_SUSPEND_LP2);
++ }
++ }
++
+ suspend_set_ops(&tegra_suspend_ops);
+ }
+ #endif
+diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
+index 778a4aa..ff68746 100644
+--- a/arch/arm/mach-tegra/pm.h
++++ b/arch/arm/mach-tegra/pm.h
+@@ -23,13 +23,36 @@
+
+ #include "pmc.h"
+
++struct tegra_lp1_iram {
++ void *start_addr;
++ void *end_addr;
++};
++extern struct tegra_lp1_iram *tegra_lp1_iram;
++extern void (*tegra_sleep_core_finish)(unsigned long v2p);
++
++#ifdef CONFIG_ARCH_TEGRA_3x_SOC
++void tegra30_lp1_iram_hook(void);
++void tegra30_sleep_core_init(void);
++#else
++static inline void tegra30_lp1_iram_hook(void) {}
++static inline void void tegra30_sleep_core_init(void) {}
++#endif
++
++#ifdef CONFIG_ARCH_TEGRA_2x_SOC
++void tegra20_lp1_iram_hook(void);
++void tegra20_sleep_core_init(void);
++#else
++static inline void tegra20_lp1_iram_hook(void) {}
++static inline void void tegra20_sleep_core_init(void) {}
++#endif
++
+ extern unsigned long l2x0_saved_regs_addr;
+
+ void save_cpu_arch_register(void);
+ void restore_cpu_arch_register(void);
+
+-void tegra_clear_cpu_in_lp2(int phy_cpu_id);
+-bool tegra_set_cpu_in_lp2(int phy_cpu_id);
++void tegra_clear_cpu_in_lp2(void);
++bool tegra_set_cpu_in_lp2(void);
+
+ void tegra_idle_lp2_last(void);
+ extern void (*tegra_tear_down_cpu)(void);
+diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
+index 32360e5..617de14 100644
+--- a/arch/arm/mach-tegra/pmc.c
++++ b/arch/arm/mach-tegra/pmc.c
+@@ -26,6 +26,8 @@
+ #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 */
+@@ -193,10 +195,28 @@ 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;
+- unsigned long rate = 0;
++ unsigned long rate = 32768;
+
+ reg = tegra_pmc_readl(PMC_CTRL);
+ reg |= TEGRA_POWER_CPU_PWRREQ_OE;
+@@ -224,6 +244,20 @@ void tegra_pmc_suspend_init(void)
+ 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 inverts 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
+
+diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
+index e1c2df2..549f8c7 100644
+--- a/arch/arm/mach-tegra/pmc.h
++++ b/arch/arm/mach-tegra/pmc.h
+@@ -28,6 +28,9 @@ enum tegra_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
+diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
+index e6de88a..3ecf3b1 100644
+--- a/arch/arm/mach-tegra/reset-handler.S
++++ b/arch/arm/mach-tegra/reset-handler.S
+@@ -22,11 +22,11 @@
+ #include <asm/hardware/cache-l2x0.h>
+
+ #include "flowctrl.h"
++#include "fuse.h"
+ #include "iomap.h"
+ #include "reset.h"
+ #include "sleep.h"
+
+-#define APB_MISC_GP_HIDREV 0x804
+ #define PMC_SCRATCH41 0x140
+
+ #define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
+@@ -49,10 +49,8 @@ ENTRY(tegra_resume)
+
+ #ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ /* Are we on Tegra20? */
+- mov32 r6, TEGRA_APB_MISC_BASE
+- ldr r0, [r6, #APB_MISC_GP_HIDREV]
+- and r0, r0, #0xff00
+- cmp r0, #(0x20 << 8)
++ tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
++ cmp r6, #TEGRA20
+ beq 1f @ Yes
+ /* Clear the flow controller flags for this CPU. */
+ mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
+@@ -98,7 +96,7 @@ ENTRY(__tegra_cpu_reset_handler_start)
+ * Register usage within the reset handler:
+ *
+ * Others: scratch
+- * R6 = SoC ID << 8
++ * R6 = SoC ID
+ * R7 = CPU present (to the OS) mask
+ * R8 = CPU in LP1 state mask
+ * R9 = CPU in LP2 state mask
+@@ -115,12 +113,10 @@ ENTRY(__tegra_cpu_reset_handler)
+
+ cpsid aif, 0x13 @ SVC mode, interrupts disabled
+
+- mov32 r6, TEGRA_APB_MISC_BASE
+- ldr r6, [r6, #APB_MISC_GP_HIDREV]
+- and r6, r6, #0xff00
++ tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
+ #ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ t20_check:
+- cmp r6, #(0x20 << 8)
++ cmp r6, #TEGRA20
+ bne after_t20_check
+ t20_errata:
+ # Tegra20 is a Cortex-A9 r1p1
+@@ -136,7 +132,7 @@ after_t20_check:
+ #endif
+ #ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ t30_check:
+- cmp r6, #(0x30 << 8)
++ cmp r6, #TEGRA30
+ bne after_t30_check
+ t30_errata:
+ # Tegra30 is a Cortex-A9 r2p9
+@@ -163,7 +159,7 @@ after_errata:
+
+ #ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ /* Are we on Tegra20? */
+- cmp r6, #(0x20 << 8)
++ cmp r6, #TEGRA20
+ bne 1f
+ /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
+ mov32 r5, TEGRA_PMC_BASE
+@@ -173,6 +169,19 @@ after_errata:
+ 1:
+ #endif
+
++ /* Waking up from LP1? */
++ ldr r8, [r12, #RESET_DATA(MASK_LP1)]
++ tst r8, r11 @ if in_lp1
++ beq __is_not_lp1
++ cmp r10, #0
++ bne __die @ only CPU0 can be here
++ ldr lr, [r12, #RESET_DATA(STARTUP_LP1)]
++ THUMB( add lr, lr, #1 ) @ switch to Thumb mode
++ cmp lr, #0
++ bleq __die @ no LP1 startup handler
++ bx lr
++__is_not_lp1:
++
+ /* Waking up from LP2? */
+ ldr r9, [r12, #RESET_DATA(MASK_LP2)]
+ tst r9, r11 @ if in_lp2
+@@ -210,10 +219,7 @@ __die:
+ mov32 r7, TEGRA_CLK_RESET_BASE
+
+ /* Are we on Tegra20? */
+- mov32 r6, TEGRA_APB_MISC_BASE
+- ldr r0, [r6, #APB_MISC_GP_HIDREV]
+- and r0, r0, #0xff00
+- cmp r0, #(0x20 << 8)
++ cmp r6, #TEGRA20
+ bne 1f
+
+ #ifdef CONFIG_ARCH_TEGRA_2x_SOC
+diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
+index 1ac434e..fd0bbf8 100644
+--- a/arch/arm/mach-tegra/reset.c
++++ b/arch/arm/mach-tegra/reset.c
+@@ -81,6 +81,8 @@ void __init tegra_cpu_reset_handler_init(void)
+ #endif
+
+ #ifdef CONFIG_PM_SLEEP
++ __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP1] =
++ TEGRA_IRAM_CODE_AREA;
+ __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] =
+ virt_to_phys((void *)tegra_resume);
+ #endif
+diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
+index c90d8e9..76a9343 100644
+--- a/arch/arm/mach-tegra/reset.h
++++ b/arch/arm/mach-tegra/reset.h
+@@ -39,6 +39,10 @@ void __tegra_cpu_reset_handler_end(void);
+ void tegra_secondary_startup(void);
+
+ #ifdef CONFIG_PM_SLEEP
++#define tegra_cpu_lp1_mask \
++ (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
++ ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP1] - \
++ (u32)__tegra_cpu_reset_handler_start)))
+ #define tegra_cpu_lp2_mask \
+ (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
+ ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
+diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S
+index e3f2417..8972a8e 100644
+--- a/arch/arm/mach-tegra/sleep-tegra20.S
++++ b/arch/arm/mach-tegra/sleep-tegra20.S
+@@ -23,10 +23,49 @@
+ #include <asm/assembler.h>
+ #include <asm/proc-fns.h>
+ #include <asm/cp15.h>
++#include <asm/cache.h>
+
+ #include "sleep.h"
+ #include "flowctrl.h"
+
++#define EMC_CFG 0xc
++#define EMC_ADR_CFG 0x10
++#define EMC_REFRESH 0x70
++#define EMC_NOP 0xdc
++#define EMC_SELF_REF 0xe0
++#define EMC_REQ_CTRL 0x2b0
++#define EMC_EMC_STATUS 0x2b4
++
++#define CLK_RESET_CCLK_BURST 0x20
++#define CLK_RESET_CCLK_DIVIDER 0x24
++#define CLK_RESET_SCLK_BURST 0x28
++#define CLK_RESET_SCLK_DIVIDER 0x2c
++#define CLK_RESET_PLLC_BASE 0x80
++#define CLK_RESET_PLLM_BASE 0x90
++#define CLK_RESET_PLLP_BASE 0xa0
++
++#define APB_MISC_XM2CFGCPADCTRL 0x8c8
++#define APB_MISC_XM2CFGDPADCTRL 0x8cc
++#define APB_MISC_XM2CLKCFGPADCTRL 0x8d0
++#define APB_MISC_XM2COMPPADCTRL 0x8d4
++#define APB_MISC_XM2VTTGENPADCTRL 0x8d8
++#define APB_MISC_XM2CFGCPADCTRL2 0x8e4
++#define APB_MISC_XM2CFGDPADCTRL2 0x8e8
++
++.macro pll_enable, rd, r_car_base, pll_base
++ ldr \rd, [\r_car_base, #\pll_base]
++ tst \rd, #(1 << 30)
++ orreq \rd, \rd, #(1 << 30)
++ streq \rd, [\r_car_base, #\pll_base]
++.endm
++
++.macro emc_device_mask, rd, base
++ ldr \rd, [\base, #EMC_ADR_CFG]
++ tst \rd, #(0x3 << 24)
++ moveq \rd, #(0x1 << 8) @ just 1 device
++ movne \rd, #(0x3 << 8) @ 2 devices
++.endm
++
+ #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
+ /*
+ * tegra20_hotplug_shutdown(void)
+@@ -181,6 +220,28 @@ ENTRY(tegra20_cpu_is_resettable_soon)
+ ENDPROC(tegra20_cpu_is_resettable_soon)
+
+ /*
++ * tegra20_sleep_core_finish(unsigned long v2p)
++ *
++ * Enters suspend in LP0 or LP1 by turning off the mmu and jumping to
++ * tegra20_tear_down_core in IRAM
++ */
++ENTRY(tegra20_sleep_core_finish)
++ /* Flush, disable the L1 data cache and exit SMP */
++ bl tegra_disable_clean_inv_dcache
++
++ mov32 r3, tegra_shut_off_mmu
++ add r3, r3, r0
++
++ mov32 r0, tegra20_tear_down_core
++ mov32 r1, tegra20_iram_start
++ sub r0, r0, r1
++ mov32 r1, TEGRA_IRAM_CODE_AREA
++ add r0, r0, r1
++
++ mov pc, r3
++ENDPROC(tegra20_sleep_core_finish)
++
++/*
+ * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
+ *
+ * Enters WFI on secondary CPU by exiting coherency.
+@@ -191,6 +252,7 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
+ mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency
+
+ /* Flush and disable the L1 data cache */
++ mov r0, #TEGRA_FLUSH_CACHE_LOUIS
+ bl tegra_disable_clean_inv_dcache
+
+ mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
+@@ -250,6 +312,150 @@ ENTRY(tegra20_tear_down_cpu)
+ b tegra20_enter_sleep
+ ENDPROC(tegra20_tear_down_cpu)
+
++/* START OF ROUTINES COPIED TO IRAM */
++ .align L1_CACHE_SHIFT
++ .globl tegra20_iram_start
++tegra20_iram_start:
++
++/*
++ * tegra20_lp1_reset
++ *
++ * reset vector for LP1 restore; copied into IRAM during suspend.
++ * Brings the system back up to a safe staring point (SDRAM out of
++ * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP,
++ * system clock running on the same PLL that it suspended at), and
++ * jumps to tegra_resume to restore virtual addressing and PLLX.
++ * The physical address of tegra_resume expected to be stored in
++ * PMC_SCRATCH41.
++ *
++ * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA AND MUST BE FIRST.
++ */
++ENTRY(tegra20_lp1_reset)
++ /*
++ * The CPU and system bus are running at 32KHz and executing from
++ * IRAM when this code is executed; immediately switch to CLKM and
++ * enable PLLM, PLLP, PLLC.
++ */
++ mov32 r0, TEGRA_CLK_RESET_BASE
++
++ mov r1, #(1 << 28)
++ str r1, [r0, #CLK_RESET_SCLK_BURST]
++ str r1, [r0, #CLK_RESET_CCLK_BURST]
++ mov r1, #0
++ str r1, [r0, #CLK_RESET_CCLK_DIVIDER]
++ str r1, [r0, #CLK_RESET_SCLK_DIVIDER]
++
++ pll_enable r1, r0, CLK_RESET_PLLM_BASE
++ pll_enable r1, r0, CLK_RESET_PLLP_BASE
++ pll_enable r1, r0, CLK_RESET_PLLC_BASE
++
++ adr r2, tegra20_sdram_pad_address
++ adr r4, tegra20_sdram_pad_save
++ mov r5, #0
++
++ ldr r6, tegra20_sdram_pad_size
++padload:
++ ldr r7, [r2, r5] @ r7 is the addr in the pad_address
++
++ ldr r1, [r4, r5]
++ str r1, [r7] @ restore the value in pad_save
++
++ add r5, r5, #4
++ cmp r6, r5
++ bne padload
++
++padload_done:
++ /* 255uS delay for PLL stabilization */
++ mov32 r7, TEGRA_TMRUS_BASE
++ wait_for_us r1, r7, r9
++ add r1, r1, #0xfe
++ wait_until r1, r7, r9
++
++ adr r4, tegra20_sclk_save
++ ldr r4, [r4]
++ str r4, [r0, #CLK_RESET_SCLK_BURST]
++ mov32 r4, ((1 << 28) | (4)) @ burst policy is PLLP
++ str r4, [r0, #CLK_RESET_CCLK_BURST]
++
++ mov32 r0, TEGRA_EMC_BASE
++ ldr r1, [r0, #EMC_CFG]
++ bic r1, r1, #(1 << 31) @ disable DRAM_CLK_STOP
++ str r1, [r0, #EMC_CFG]
++
++ mov r1, #0
++ str r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh
++ mov r1, #1
++ str r1, [r0, #EMC_NOP]
++ str r1, [r0, #EMC_NOP]
++ str r1, [r0, #EMC_REFRESH]
++
++ emc_device_mask r1, r0
++
++exit_selfrefresh_loop:
++ ldr r2, [r0, #EMC_EMC_STATUS]
++ ands r2, r2, r1
++ bne exit_selfrefresh_loop
++
++ mov r1, #0 @ unstall all transactions
++ str r1, [r0, #EMC_REQ_CTRL]
++
++ mov32 r0, TEGRA_PMC_BASE
++ ldr r0, [r0, #PMC_SCRATCH41]
++ mov pc, r0 @ jump to tegra_resume
++ENDPROC(tegra20_lp1_reset)
++
++/*
++ * tegra20_tear_down_core
++ *
++ * copied into and executed from IRAM
++ * puts memory in self-refresh for LP0 and LP1
++ */
++tegra20_tear_down_core:
++ bl tegra20_sdram_self_refresh
++ bl tegra20_switch_cpu_to_clk32k
++ b tegra20_enter_sleep
++
++/*
++ * tegra20_switch_cpu_to_clk32k
++ *
++ * In LP0 and LP1 all PLLs will be turned off. Switch the CPU and system clock
++ * to the 32KHz clock.
++ */
++tegra20_switch_cpu_to_clk32k:
++ /*
++ * start by jumping to CLKM to safely disable PLLs, then jump to
++ * CLKS.
++ */
++ mov r0, #(1 << 28)
++ str r0, [r5, #CLK_RESET_SCLK_BURST]
++ str r0, [r5, #CLK_RESET_CCLK_BURST]
++ mov r0, #0
++ str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
++ str r0, [r5, #CLK_RESET_SCLK_DIVIDER]
++
++ /* 2uS delay delay between changing SCLK and disabling PLLs */
++ mov32 r7, TEGRA_TMRUS_BASE
++ wait_for_us r1, r7, r9
++ add r1, r1, #2
++ wait_until r1, r7, r9
++
++ /* switch to CLKS */
++ mov r0, #0 /* brust policy = 32KHz */
++ str r0, [r5, #CLK_RESET_SCLK_BURST]
++
++ /* disable PLLM, PLLP and PLLC */
++ ldr r0, [r5, #CLK_RESET_PLLM_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLM_BASE]
++ ldr r0, [r5, #CLK_RESET_PLLP_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLP_BASE]
++ ldr r0, [r5, #CLK_RESET_PLLC_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLC_BASE]
++
++ mov pc, lr
++
+ /*
+ * tegra20_enter_sleep
+ *
+@@ -274,4 +480,99 @@ halted:
+ isb
+ b halted
+
++/*
++ * tegra20_sdram_self_refresh
++ *
++ * called with MMU off and caches disabled
++ * puts sdram in self refresh
++ * must be executed from IRAM
++ */
++tegra20_sdram_self_refresh:
++ mov32 r1, TEGRA_EMC_BASE @ r1 reserved for emc base addr
++
++ mov r2, #3
++ str r2, [r1, #EMC_REQ_CTRL] @ stall incoming DRAM requests
++
++emcidle:
++ ldr r2, [r1, #EMC_EMC_STATUS]
++ tst r2, #4
++ beq emcidle
++
++ mov r2, #1
++ str r2, [r1, #EMC_SELF_REF]
++
++ emc_device_mask r2, r1
++
++emcself:
++ ldr r3, [r1, #EMC_EMC_STATUS]
++ and r3, r3, r2
++ cmp r3, r2
++ bne emcself @ loop until DDR in self-refresh
++
++ adr r2, tegra20_sdram_pad_address
++ adr r3, tegra20_sdram_pad_safe
++ adr r4, tegra20_sdram_pad_save
++ mov r5, #0
++
++ ldr r6, tegra20_sdram_pad_size
++padsave:
++ ldr r0, [r2, r5] @ r0 is the addr in the pad_address
++
++ ldr r1, [r0]
++ str r1, [r4, r5] @ save the content of the addr
++
++ ldr r1, [r3, r5]
++ str r1, [r0] @ set the save val to the addr
++
++ add r5, r5, #4
++ cmp r6, r5
++ bne padsave
++padsave_done:
++
++ mov32 r5, TEGRA_CLK_RESET_BASE
++ ldr r0, [r5, #CLK_RESET_SCLK_BURST]
++ adr r2, tegra20_sclk_save
++ str r0, [r2]
++ dsb
++ mov pc, lr
++
++tegra20_sdram_pad_address:
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CLKCFGPADCTRL
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2COMPPADCTRL
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2VTTGENPADCTRL
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL2
++ .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL2
++
++tegra20_sdram_pad_size:
++ .word tegra20_sdram_pad_size - tegra20_sdram_pad_address
++
++tegra20_sdram_pad_safe:
++ .word 0x8
++ .word 0x8
++ .word 0x0
++ .word 0x8
++ .word 0x5500
++ .word 0x08080040
++ .word 0x0
++
++tegra20_sclk_save:
++ .word 0x0
++
++tegra20_sdram_pad_save:
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++
++ .ltorg
++/* dummy symbol for end of IRAM */
++ .align L1_CACHE_SHIFT
++ .globl tegra20_iram_end
++tegra20_iram_end:
++ b .
+ #endif
+diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S
+index d29dfcc..7eb21f4 100644
+--- a/arch/arm/mach-tegra/sleep-tegra30.S
++++ b/arch/arm/mach-tegra/sleep-tegra30.S
+@@ -18,12 +18,95 @@
+
+ #include <asm/assembler.h>
+ #include <asm/asm-offsets.h>
++#include <asm/cache.h>
+
+ #include "sleep.h"
+ #include "flowctrl.h"
+
++#define EMC_CFG 0xc
++#define EMC_ADR_CFG 0x10
++#define EMC_TIMING_CONTROL 0x28
++#define EMC_REFRESH 0x70
++#define EMC_NOP 0xdc
++#define EMC_SELF_REF 0xe0
++#define EMC_MRW 0xe8
++#define EMC_FBIO_CFG5 0x104
++#define EMC_AUTO_CAL_CONFIG 0x2a4
++#define EMC_AUTO_CAL_INTERVAL 0x2a8
++#define EMC_AUTO_CAL_STATUS 0x2ac
++#define EMC_REQ_CTRL 0x2b0
++#define EMC_CFG_DIG_DLL 0x2bc
++#define EMC_EMC_STATUS 0x2b4
++#define EMC_ZCAL_INTERVAL 0x2e0
++#define EMC_ZQ_CAL 0x2ec
++#define EMC_XM2VTTGENPADCTRL 0x310
++#define EMC_XM2VTTGENPADCTRL2 0x314
++
++#define PMC_CTRL 0x0
++#define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */
++
++#define PMC_PLLP_WB0_OVERRIDE 0xf8
++#define PMC_IO_DPD_REQ 0x1b8
++#define PMC_IO_DPD_STATUS 0x1bc
++
++#define CLK_RESET_CCLK_BURST 0x20
++#define CLK_RESET_CCLK_DIVIDER 0x24
++#define CLK_RESET_SCLK_BURST 0x28
++#define CLK_RESET_SCLK_DIVIDER 0x2c
++
++#define CLK_RESET_PLLC_BASE 0x80
++#define CLK_RESET_PLLC_MISC 0x8c
++#define CLK_RESET_PLLM_BASE 0x90
++#define CLK_RESET_PLLM_MISC 0x9c
++#define CLK_RESET_PLLP_BASE 0xa0
++#define CLK_RESET_PLLP_MISC 0xac
++#define CLK_RESET_PLLA_BASE 0xb0
++#define CLK_RESET_PLLA_MISC 0xbc
++#define CLK_RESET_PLLX_BASE 0xe0
++#define CLK_RESET_PLLX_MISC 0xe4
++
++#define CLK_RESET_CLK_SOURCE_MSELECT 0x3b4
++
++#define MSELECT_CLKM (0x3 << 30)
++
++#define LOCK_DELAY 50 /* safety delay after lock is detected */
++
+ #define TEGRA30_POWER_HOTPLUG_SHUTDOWN (1 << 27) /* Hotplug shutdown */
+
++.macro emc_device_mask, rd, base
++ ldr \rd, [\base, #EMC_ADR_CFG]
++ tst \rd, #0x1
++ moveq \rd, #(0x1 << 8) @ just 1 device
++ movne \rd, #(0x3 << 8) @ 2 devices
++.endm
++
++.macro emc_timing_update, rd, base
++ mov \rd, #1
++ str \rd, [\base, #EMC_TIMING_CONTROL]
++1001:
++ ldr \rd, [\base, #EMC_EMC_STATUS]
++ tst \rd, #(0x1<<23) @ wait EMC_STATUS_TIMING_UPDATE_STALLED is clear
++ bne 1001b
++.endm
++
++.macro pll_enable, rd, r_car_base, pll_base, pll_misc
++ ldr \rd, [\r_car_base, #\pll_base]
++ tst \rd, #(1 << 30)
++ orreq \rd, \rd, #(1 << 30)
++ streq \rd, [\r_car_base, #\pll_base]
++ /* Enable lock detector */
++ ldr \rd, [\r_car_base, #\pll_misc]
++ orr \rd, \rd, #(1 << 18)
++ str \rd, [\r_car_base, #\pll_misc]
++.endm
++
++.macro pll_locked, rd, r_car_base, pll_base
++1:
++ ldr \rd, [\r_car_base, #\pll_base]
++ tst \rd, #(1 << 27)
++ beq 1b
++.endm
++
+ #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
+ /*
+ * tegra30_hotplug_shutdown(void)
+@@ -107,6 +190,41 @@ ENDPROC(tegra30_cpu_shutdown)
+
+ #ifdef CONFIG_PM_SLEEP
+ /*
++ * tegra30_sleep_core_finish(unsigned long v2p)
++ *
++ * Enters suspend in LP0 or LP1 by turning off the MMU and jumping to
++ * tegra30_tear_down_core in IRAM
++ */
++ENTRY(tegra30_sleep_core_finish)
++ /* Flush, disable the L1 data cache and exit SMP */
++ bl tegra_disable_clean_inv_dcache
++
++ /*
++ * Preload all the address literals that are needed for the
++ * CPU power-gating process, to avoid loading from SDRAM which
++ * are not supported once SDRAM is put into self-refresh.
++ * LP0 / LP1 use physical address, since the MMU needs to be
++ * disalbed before putting SDRAM into self-refresh to avoid
++ * memory access due to page table walks.
++ */
++ mov32 r4, TEGRA_PMC_BASE
++ mov32 r5, TEGRA_CLK_RESET_BASE
++ mov32 r6, TEGRA_FLOW_CTRL_BASE
++ mov32 r7, TEGRA_TMRUS_BASE
++
++ mov32 r3, tegra_shut_off_mmu
++ add r3, r3, r0
++
++ mov32 r0, tegra30_tear_down_core
++ mov32 r1, tegra30_iram_start
++ sub r0, r0, r1
++ mov32 r1, TEGRA_IRAM_CODE_AREA
++ add r0, r0, r1
++
++ mov pc, r3
++ENDPROC(tegra30_sleep_core_finish)
++
++/*
+ * tegra30_sleep_cpu_secondary_finish(unsigned long v2p)
+ *
+ * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU.
+@@ -115,6 +233,7 @@ ENTRY(tegra30_sleep_cpu_secondary_finish)
+ mov r7, lr
+
+ /* Flush and disable the L1 data cache */
++ mov r0, #TEGRA_FLUSH_CACHE_LOUIS
+ bl tegra_disable_clean_inv_dcache
+
+ /* Powergate this CPU. */
+@@ -135,6 +254,278 @@ ENTRY(tegra30_tear_down_cpu)
+ b tegra30_enter_sleep
+ ENDPROC(tegra30_tear_down_cpu)
+
++/* START OF ROUTINES COPIED TO IRAM */
++ .align L1_CACHE_SHIFT
++ .globl tegra30_iram_start
++tegra30_iram_start:
++
++/*
++ * tegra30_lp1_reset
++ *
++ * reset vector for LP1 restore; copied into IRAM during suspend.
++ * Brings the system back up to a safe staring point (SDRAM out of
++ * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLX,
++ * system clock running on the same PLL that it suspended at), and
++ * jumps to tegra_resume to restore virtual addressing.
++ * The physical address of tegra_resume expected to be stored in
++ * PMC_SCRATCH41.
++ *
++ * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA AND MUST BE FIRST.
++ */
++ENTRY(tegra30_lp1_reset)
++ /*
++ * The CPU and system bus are running at 32KHz and executing from
++ * IRAM when this code is executed; immediately switch to CLKM and
++ * enable PLLP, PLLM, PLLC, PLLA and PLLX.
++ */
++ mov32 r0, TEGRA_CLK_RESET_BASE
++
++ mov r1, #(1 << 28)
++ str r1, [r0, #CLK_RESET_SCLK_BURST]
++ str r1, [r0, #CLK_RESET_CCLK_BURST]
++ mov r1, #0
++ str r1, [r0, #CLK_RESET_CCLK_DIVIDER]
++ str r1, [r0, #CLK_RESET_SCLK_DIVIDER]
++
++ /* enable PLLM via PMC */
++ mov32 r2, TEGRA_PMC_BASE
++ ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
++ orr r1, r1, #(1 << 12)
++ str r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
++
++ pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC
++ pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC
++ pll_enable r1, r0, CLK_RESET_PLLA_BASE, CLK_RESET_PLLA_MISC
++ pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC
++ pll_enable r1, r0, CLK_RESET_PLLX_BASE, CLK_RESET_PLLX_MISC
++
++ pll_locked r1, r0, CLK_RESET_PLLM_BASE
++ pll_locked r1, r0, CLK_RESET_PLLP_BASE
++ pll_locked r1, r0, CLK_RESET_PLLA_BASE
++ pll_locked r1, r0, CLK_RESET_PLLC_BASE
++ pll_locked r1, r0, CLK_RESET_PLLX_BASE
++
++ mov32 r7, TEGRA_TMRUS_BASE
++ ldr r1, [r7]
++ add r1, r1, #LOCK_DELAY
++ wait_until r1, r7, r3
++
++ adr r5, tegra30_sdram_pad_save
++
++ ldr r4, [r5, #0x18] @ restore CLK_SOURCE_MSELECT
++ str r4, [r0, #CLK_RESET_CLK_SOURCE_MSELECT]
++
++ ldr r4, [r5, #0x1C] @ restore SCLK_BURST
++ str r4, [r0, #CLK_RESET_SCLK_BURST]
++
++ mov32 r4, ((1 << 28) | (0x8)) @ burst policy is PLLX
++ str r4, [r0, #CLK_RESET_CCLK_BURST]
++
++ /* Restore pad power state to normal */
++ ldr r1, [r5, #0x14] @ PMC_IO_DPD_STATUS
++ mvn r1, r1
++ bic r1, r1, #(1 << 31)
++ orr r1, r1, #(1 << 30)
++ str r1, [r2, #PMC_IO_DPD_REQ] @ DPD_OFF
++
++ mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base
++
++ ldr r1, [r5, #0xC] @ restore EMC_XM2VTTGENPADCTRL
++ str r1, [r0, #EMC_XM2VTTGENPADCTRL]
++ ldr r1, [r5, #0x10] @ restore EMC_XM2VTTGENPADCTRL2
++ str r1, [r0, #EMC_XM2VTTGENPADCTRL2]
++ ldr r1, [r5, #0x8] @ restore EMC_AUTO_CAL_INTERVAL
++ str r1, [r0, #EMC_AUTO_CAL_INTERVAL]
++
++ /* Relock DLL */
++ ldr r1, [r0, #EMC_CFG_DIG_DLL]
++ orr r1, r1, #(1 << 30) @ set DLL_RESET
++ str r1, [r0, #EMC_CFG_DIG_DLL]
++
++ emc_timing_update r1, r0
++
++ ldr r1, [r0, #EMC_AUTO_CAL_CONFIG]
++ orr r1, r1, #(1 << 31) @ set AUTO_CAL_ACTIVE
++ str r1, [r0, #EMC_AUTO_CAL_CONFIG]
++
++emc_wait_auto_cal_onetime:
++ ldr r1, [r0, #EMC_AUTO_CAL_STATUS]
++ tst r1, #(1 << 31) @ wait until AUTO_CAL_ACTIVE is cleared
++ bne emc_wait_auto_cal_onetime
++
++ ldr r1, [r0, #EMC_CFG]
++ bic r1, r1, #(1 << 31) @ disable DRAM_CLK_STOP_PD
++ str r1, [r0, #EMC_CFG]
++
++ mov r1, #0
++ str r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh
++ mov r1, #1
++ str r1, [r0, #EMC_NOP]
++ str r1, [r0, #EMC_NOP]
++ str r1, [r0, #EMC_REFRESH]
++
++ emc_device_mask r1, r0
++
++exit_selfrefresh_loop:
++ ldr r2, [r0, #EMC_EMC_STATUS]
++ ands r2, r2, r1
++ bne exit_selfrefresh_loop
++
++ lsr r1, r1, #8 @ devSel, bit0:dev0, bit1:dev1
++
++ mov32 r7, TEGRA_TMRUS_BASE
++ ldr r2, [r0, #EMC_FBIO_CFG5]
++
++ and r2, r2, #3 @ check DRAM_TYPE
++ cmp r2, #2
++ beq emc_lpddr2
++
++ /* Issue a ZQ_CAL for dev0 - DDR3 */
++ mov32 r2, 0x80000011 @ DEV_SELECTION=2, LENGTH=LONG, CMD=1
++ str r2, [r0, #EMC_ZQ_CAL]
++ ldr r2, [r7]
++ add r2, r2, #10
++ wait_until r2, r7, r3
++
++ tst r1, #2
++ beq zcal_done
++
++ /* Issue a ZQ_CAL for dev1 - DDR3 */
++ mov32 r2, 0x40000011 @ DEV_SELECTION=1, LENGTH=LONG, CMD=1
++ str r2, [r0, #EMC_ZQ_CAL]
++ ldr r2, [r7]
++ add r2, r2, #10
++ wait_until r2, r7, r3
++ b zcal_done
++
++emc_lpddr2:
++ /* Issue a ZQ_CAL for dev0 - LPDDR2 */
++ mov32 r2, 0x800A00AB @ DEV_SELECTION=2, MA=10, OP=0xAB
++ str r2, [r0, #EMC_MRW]
++ ldr r2, [r7]
++ add r2, r2, #1
++ wait_until r2, r7, r3
++
++ tst r1, #2
++ beq zcal_done
++
++ /* Issue a ZQ_CAL for dev0 - LPDDR2 */
++ mov32 r2, 0x400A00AB @ DEV_SELECTION=1, MA=10, OP=0xAB
++ str r2, [r0, #EMC_MRW]
++ ldr r2, [r7]
++ add r2, r2, #1
++ wait_until r2, r7, r3
++
++zcal_done:
++ mov r1, #0 @ unstall all transactions
++ str r1, [r0, #EMC_REQ_CTRL]
++ ldr r1, [r5, #0x4] @ restore EMC_ZCAL_INTERVAL
++ str r1, [r0, #EMC_ZCAL_INTERVAL]
++ ldr r1, [r5, #0x0] @ restore EMC_CFG
++ str r1, [r0, #EMC_CFG]
++
++ mov32 r0, TEGRA_PMC_BASE
++ ldr r0, [r0, #PMC_SCRATCH41]
++ mov pc, r0 @ jump to tegra_resume
++ENDPROC(tegra30_lp1_reset)
++
++ .align L1_CACHE_SHIFT
++ .type tegra30_sdram_pad_save, %object
++tegra30_sdram_pad_save:
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++ .word 0
++
++tegra30_sdram_pad_address:
++ .word TEGRA_EMC_BASE + EMC_CFG @0x0
++ .word TEGRA_EMC_BASE + EMC_ZCAL_INTERVAL @0x4
++ .word TEGRA_EMC_BASE + EMC_AUTO_CAL_INTERVAL @0x8
++ .word TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL @0xc
++ .word TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL2 @0x10
++ .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14
++ .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18
++ .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c
++
++tegra30_sdram_pad_size:
++ .word tegra30_sdram_pad_address - tegra30_sdram_pad_save
++
++/*
++ * tegra30_tear_down_core
++ *
++ * copied into and executed from IRAM
++ * puts memory in self-refresh for LP0 and LP1
++ */
++tegra30_tear_down_core:
++ bl tegra30_sdram_self_refresh
++ bl tegra30_switch_cpu_to_clk32k
++ b tegra30_enter_sleep
++
++/*
++ * tegra30_switch_cpu_to_clk32k
++ *
++ * In LP0 and LP1 all PLLs will be turned off. Switching the CPU and System CLK
++ * to the 32KHz clock.
++ * r4 = TEGRA_PMC_BASE
++ * r5 = TEGRA_CLK_RESET_BASE
++ * r6 = TEGRA_FLOW_CTRL_BASE
++ * r7 = TEGRA_TMRUS_BASE
++ */
++tegra30_switch_cpu_to_clk32k:
++ /*
++ * start by jumping to CLKM to safely disable PLLs, then jump to
++ * CLKS.
++ */
++ mov r0, #(1 << 28)
++ str r0, [r5, #CLK_RESET_SCLK_BURST]
++ /* 2uS delay delay between changing SCLK and CCLK */
++ wait_for_us r1, r7, r9
++ add r1, r1, #2
++ wait_until r1, r7, r9
++ str r0, [r5, #CLK_RESET_CCLK_BURST]
++ mov r0, #0
++ str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
++ str r0, [r5, #CLK_RESET_SCLK_DIVIDER]
++
++ /* switch the clock source of mselect to be CLK_M */
++ ldr r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT]
++ orr r0, r0, #MSELECT_CLKM
++ str r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT]
++
++ /* 2uS delay delay between changing SCLK and disabling PLLs */
++ wait_for_us r1, r7, r9
++ add r1, r1, #2
++ wait_until r1, r7, r9
++
++ /* disable PLLM via PMC in LP1 */
++ ldr r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
++ bic r0, r0, #(1 << 12)
++ str r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
++
++ /* disable PLLP, PLLA, PLLC and PLLX */
++ ldr r0, [r5, #CLK_RESET_PLLP_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLP_BASE]
++ ldr r0, [r5, #CLK_RESET_PLLA_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLA_BASE]
++ ldr r0, [r5, #CLK_RESET_PLLC_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLC_BASE]
++ ldr r0, [r5, #CLK_RESET_PLLX_BASE]
++ bic r0, r0, #(1 << 30)
++ str r0, [r5, #CLK_RESET_PLLX_BASE]
++
++ /* switch to CLKS */
++ mov r0, #0 /* brust policy = 32KHz */
++ str r0, [r5, #CLK_RESET_SCLK_BURST]
++
++ mov pc, lr
++
+ /*
+ * tegra30_enter_sleep
+ *
+@@ -167,4 +558,105 @@ halted:
+ /* !!!FIXME!!! Implement halt failure handler */
+ b halted
+
++/*
++ * tegra30_sdram_self_refresh
++ *
++ * called with MMU off and caches disabled
++ * must be executed from IRAM
++ * r4 = TEGRA_PMC_BASE
++ * r5 = TEGRA_CLK_RESET_BASE
++ * r6 = TEGRA_FLOW_CTRL_BASE
++ * r7 = TEGRA_TMRUS_BASE
++ */
++tegra30_sdram_self_refresh:
++
++ adr r2, tegra30_sdram_pad_address
++ adr r8, tegra30_sdram_pad_save
++ mov r9, #0
++
++ ldr r3, tegra30_sdram_pad_size
++padsave:
++ ldr r0, [r2, r9] @ r0 is the addr in the pad_address
++
++ ldr r1, [r0]
++ str r1, [r8, r9] @ save the content of the addr
++
++ add r9, r9, #4
++ cmp r3, r9
++ bne padsave
++padsave_done:
++
++ dsb
++
++ mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base addr
++
++ mov r1, #0
++ str r1, [r0, #EMC_ZCAL_INTERVAL]
++ str r1, [r0, #EMC_AUTO_CAL_INTERVAL]
++ ldr r1, [r0, #EMC_CFG]
++ bic r1, r1, #(1 << 28)
++ str r1, [r0, #EMC_CFG] @ disable DYN_SELF_REF
++
++ emc_timing_update r1, r0
++
++ ldr r1, [r7]
++ add r1, r1, #5
++ wait_until r1, r7, r2
++
++emc_wait_auto_cal:
++ ldr r1, [r0, #EMC_AUTO_CAL_STATUS]
++ tst r1, #(1 << 31) @ wait until AUTO_CAL_ACTIVE is cleared
++ bne emc_wait_auto_cal
++
++ mov r1, #3
++ str r1, [r0, #EMC_REQ_CTRL] @ stall incoming DRAM requests
++
++emcidle:
++ ldr r1, [r0, #EMC_EMC_STATUS]
++ tst r1, #4
++ beq emcidle
++
++ mov r1, #1
++ str r1, [r0, #EMC_SELF_REF]
++
++ emc_device_mask r1, r0
++
++emcself:
++ ldr r2, [r0, #EMC_EMC_STATUS]
++ and r2, r2, r1
++ cmp r2, r1
++ bne emcself @ loop until DDR in self-refresh
++
++ /* Put VTTGEN in the lowest power mode */
++ ldr r1, [r0, #EMC_XM2VTTGENPADCTRL]
++ mov32 r2, 0xF8F8FFFF @ clear XM2VTTGEN_DRVUP and XM2VTTGEN_DRVDN
++ and r1, r1, r2
++ str r1, [r0, #EMC_XM2VTTGENPADCTRL]
++ ldr r1, [r0, #EMC_XM2VTTGENPADCTRL2]
++ orr r1, r1, #7 @ set E_NO_VTTGEN
++ str r1, [r0, #EMC_XM2VTTGENPADCTRL2]
++
++ emc_timing_update r1, r0
++
++ ldr r1, [r4, #PMC_CTRL]
++ tst r1, #PMC_CTRL_SIDE_EFFECT_LP0
++ bne pmc_io_dpd_skip
++ /*
++ * Put DDR_DATA, DISC_ADDR_CMD, DDR_ADDR_CMD, POP_ADDR_CMD, POP_CLK
++ * and COMP in the lowest power mode when LP1.
++ */
++ mov32 r1, 0x8EC00000
++ str r1, [r4, #PMC_IO_DPD_REQ]
++pmc_io_dpd_skip:
++
++ dsb
++
++ mov pc, lr
++
++ .ltorg
++/* dummy symbol for end of IRAM */
++ .align L1_CACHE_SHIFT
++ .global tegra30_iram_end
++tegra30_iram_end:
++ b .
+ #endif
+diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
+index 364d845..193ed7d 100644
+--- a/arch/arm/mach-tegra/sleep.S
++++ b/arch/arm/mach-tegra/sleep.S
+@@ -56,7 +56,9 @@ ENTRY(tegra_disable_clean_inv_dcache)
+ isb
+
+ /* Flush the D-cache */
+- bl v7_flush_dcache_louis
++ cmp r0, #TEGRA_FLUSH_CACHE_ALL
++ blne v7_flush_dcache_louis
++ bleq v7_flush_dcache_all
+
+ /* Trun off coherency */
+ exit_smp r4, r5
+@@ -73,9 +75,12 @@ ENDPROC(tegra_disable_clean_inv_dcache)
+ * tegra?_tear_down_cpu
+ */
+ ENTRY(tegra_sleep_cpu_finish)
++ mov r4, r0
+ /* Flush and disable the L1 data cache */
++ mov r0, #TEGRA_FLUSH_CACHE_ALL
+ bl tegra_disable_clean_inv_dcache
+
++ mov r0, r4
+ mov32 r6, tegra_tear_down_cpu
+ ldr r1, [r6]
+ add r1, r1, r0
+@@ -106,9 +111,11 @@ ENTRY(tegra_shut_off_mmu)
+ isb
+ #ifdef CONFIG_CACHE_L2X0
+ /* Disable L2 cache */
+- mov32 r4, TEGRA_ARM_PERIF_BASE + 0x3000
+- mov r5, #0
+- str r5, [r4, #L2X0_CTRL]
++ check_cpu_part_num 0xc09, r9, r10
++ movweq r2, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000)
++ movteq r2, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000)
++ moveq r3, #0
++ streq r3, [r2, #L2X0_CTRL]
+ #endif
+ mov pc, r0
+ ENDPROC(tegra_shut_off_mmu)
+diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
+index 2080fb1..13b076d 100644
+--- a/arch/arm/mach-tegra/sleep.h
++++ b/arch/arm/mach-tegra/sleep.h
+@@ -27,6 +27,8 @@
+ + IO_PPSB_VIRT)
+ #define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
+
++#define TEGRA_IRAM_CODE_AREA (TEGRA_IRAM_BASE + SZ_4K)
++
+ /* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
+ #define PMC_SCRATCH37 0x130
+ #define PMC_SCRATCH38 0x134
+@@ -39,7 +41,27 @@
+ #define CPU_NOT_RESETTABLE 0
+ #endif
+
++/* flag of tegra_disable_clean_inv_dcache to do LoUIS or all */
++#define TEGRA_FLUSH_CACHE_LOUIS 0
++#define TEGRA_FLUSH_CACHE_ALL 1
++
+ #ifdef __ASSEMBLY__
++/* waits until the microsecond counter (base) ticks, for exact timing loops */
++.macro wait_for_us, rd, base, tmp
++ ldr \rd, [\base]
++1001: ldr \tmp, [\base]
++ cmp \rd, \tmp
++ beq 1001b
++.endm
++
++/* waits until the microsecond counter (base) is > rn */
++.macro wait_until, rn, base, tmp
++ add \rn, \rn, #1
++1002: ldr \tmp, [\base]
++ cmp \tmp, \rn
++ bmi 1002b
++.endm
++
+ /* returns the offset of the flow controller halt register for a cpu */
+ .macro cpu_to_halt_reg rd, rcpu
+ cmp \rcpu, #0
+@@ -70,19 +92,40 @@
+ movt \reg, #:upper16:\val
+ .endm
+
++/* Marco to check CPU part num */
++.macro check_cpu_part_num part_num, tmp1, tmp2
++ mrc p15, 0, \tmp1, c0, c0, 0
++ ubfx \tmp1, \tmp1, #4, #12
++ mov32 \tmp2, \part_num
++ cmp \tmp1, \tmp2
++.endm
++
+ /* Macro to exit SMP coherency. */
+ .macro exit_smp, tmp1, tmp2
+ mrc p15, 0, \tmp1, c1, c0, 1 @ ACTLR
+ bic \tmp1, \tmp1, #(1<<6) | (1<<0) @ clear ACTLR.SMP | ACTLR.FW
+ mcr p15, 0, \tmp1, c1, c0, 1 @ ACTLR
+ isb
+- cpu_id \tmp1
+- mov \tmp1, \tmp1, lsl #2
+- mov \tmp2, #0xf
+- mov \tmp2, \tmp2, lsl \tmp1
+- mov32 \tmp1, TEGRA_ARM_PERIF_VIRT + 0xC
+- str \tmp2, [\tmp1] @ invalidate SCU tags for CPU
++#ifdef CONFIG_HAVE_ARM_SCU
++ check_cpu_part_num 0xc09, \tmp1, \tmp2
++ mrceq p15, 0, \tmp1, c0, c0, 5
++ andeq \tmp1, \tmp1, #0xF
++ moveq \tmp1, \tmp1, lsl #2
++ moveq \tmp2, #0xf
++ moveq \tmp2, \tmp2, lsl \tmp1
++ ldreq \tmp1, =(TEGRA_ARM_PERIF_VIRT + 0xC)
++ streq \tmp2, [\tmp1] @ invalidate SCU tags for CPU
+ dsb
++#endif
++.endm
++
++/* Macro to check Tegra revision */
++#define APB_MISC_GP_HIDREV 0x804
++.macro tegra_get_soc_id base, tmp1
++ mov32 \tmp1, \base
++ ldr \tmp1, [\tmp1, #APB_MISC_GP_HIDREV]
++ and \tmp1, \tmp1, #0xff00
++ mov \tmp1, \tmp1, lsr #8
+ .endm
+
+ /* Macro to resume & re-enable L2 cache */
+@@ -121,7 +164,7 @@ void tegra_pen_lock(void);
+ void tegra_pen_unlock(void);
+ void tegra_resume(void);
+ int tegra_sleep_cpu_finish(unsigned long);
+-void tegra_disable_clean_inv_dcache(void);
++void tegra_disable_clean_inv_dcache(u32 flag);
+
+ #ifdef CONFIG_HOTPLUG_CPU
+ void tegra20_hotplug_shutdown(void);
+diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
+index a1607d6..790ddf1 100644
+--- a/drivers/gpu/host1x/dev.h
++++ b/drivers/gpu/host1x/dev.h
+@@ -73,7 +73,7 @@ struct host1x_syncpt_ops {
+ void (*restore_wait_base)(struct host1x_syncpt *syncpt);
+ void (*load_wait_base)(struct host1x_syncpt *syncpt);
+ u32 (*load)(struct host1x_syncpt *syncpt);
+- void (*cpu_incr)(struct host1x_syncpt *syncpt);
++ int (*cpu_incr)(struct host1x_syncpt *syncpt);
+ int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr);
+ };
+
+@@ -157,10 +157,10 @@ static inline u32 host1x_hw_syncpt_load(struct host1x *host,
+ return host->syncpt_op->load(sp);
+ }
+
+-static inline void host1x_hw_syncpt_cpu_incr(struct host1x *host,
+- struct host1x_syncpt *sp)
++static inline int host1x_hw_syncpt_cpu_incr(struct host1x *host,
++ struct host1x_syncpt *sp)
+ {
+- host->syncpt_op->cpu_incr(sp);
++ return host->syncpt_op->cpu_incr(sp);
+ }
+
+ static inline int host1x_hw_syncpt_patch_wait(struct host1x *host,
+diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
+index 8c04943..5360e5a 100644
+--- a/drivers/gpu/host1x/drm/dc.c
++++ b/drivers/gpu/host1x/drm/dc.c
+@@ -79,6 +79,9 @@ static int tegra_plane_disable(struct drm_plane *plane)
+ struct tegra_plane *p = to_tegra_plane(plane);
+ unsigned long value;
+
++ if (!plane->crtc)
++ return 0;
++
+ value = WINDOW_A_SELECT << p->index;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+
+@@ -140,6 +143,7 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
+ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
+ struct drm_framebuffer *fb)
+ {
++ unsigned int format = tegra_dc_format(fb->pixel_format);
+ struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
+ unsigned long value;
+
+@@ -150,6 +154,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
+
+ tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
+ tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
++ tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
+
+ value = GENERAL_UPDATE | WIN_A_UPDATE;
+ tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
+diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c
+index 2b561c9..e184b00 100644
+--- a/drivers/gpu/host1x/drm/drm.c
++++ b/drivers/gpu/host1x/drm/drm.c
+@@ -148,6 +148,7 @@ int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm)
+ dev_err(host1x->dev,
+ "DRM setup failed for %s: %d\n",
+ dev_name(client->dev), err);
++ mutex_unlock(&host1x->clients_lock);
+ return err;
+ }
+ }
+@@ -175,6 +176,7 @@ int host1x_drm_exit(struct host1x_drm *host1x)
+ dev_err(host1x->dev,
+ "DRM cleanup failed for %s: %d\n",
+ dev_name(client->dev), err);
++ mutex_unlock(&host1x->clients_lock);
+ return err;
+ }
+ }
+@@ -257,6 +259,13 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
+ if (err < 0)
+ return err;
+
++ /*
++ * We don't use the drm_irq_install() helpers provided by the DRM
++ * core, so we need to set this manually in order to allow the
++ * DRM_IOCTL_WAIT_VBLANK to operate correctly.
++ */
++ drm->irq_enabled = 1;
++
+ err = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (err < 0)
+ return err;
+@@ -378,8 +387,7 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data,
+ if (!sp)
+ return -EINVAL;
+
+- host1x_syncpt_incr(sp);
+- return 0;
++ return host1x_syncpt_incr(sp);
+ }
+
+ static int tegra_syncpt_wait(struct drm_device *drm, void *data,
+@@ -605,7 +613,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor)
+ #endif
+
+ struct drm_driver tegra_drm_driver = {
+- .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM,
++ .driver_features = DRIVER_MODESET | DRIVER_GEM,
+ .load = tegra_drm_load,
+ .unload = tegra_drm_unload,
+ .open = tegra_drm_open,
+diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h
+index 02ce020..755943e 100644
+--- a/drivers/gpu/host1x/drm/drm.h
++++ b/drivers/gpu/host1x/drm/drm.h
+@@ -16,6 +16,7 @@
+ #include <drm/drm_fb_helper.h>
+ #include <drm/drm_fixed.h>
+ #include <uapi/drm/tegra_drm.h>
++#include <video/display.h>
+
+ #include "host1x.h"
+
+@@ -202,6 +203,9 @@ struct tegra_output {
+
+ struct drm_encoder encoder;
+ struct drm_connector connector;
++ struct display_entity stream;
++ struct display_entity *panel;
++ struct display_entity_notifier display_notifier;
+ };
+
+ static inline struct tegra_output *encoder_to_output(struct drm_encoder *e)
+@@ -214,6 +218,18 @@ static inline struct tegra_output *connector_to_output(struct drm_connector *c)
+ return container_of(c, struct tegra_output, connector);
+ }
+
++static inline
++struct tegra_output *display_entity_to_output(struct display_entity *e)
++{
++ return container_of(e, struct tegra_output, stream);
++}
++
++static inline struct tegra_output *
++display_notifier_to_output(struct display_entity_notifier *n)
++{
++ return container_of(n, struct tegra_output, display_notifier);
++}
++
+ static inline int tegra_output_enable(struct tegra_output *output)
+ {
+ if (output && output->ops && output->ops->enable)
+diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c
+index 6a45ae0..27ffcf1 100644
+--- a/drivers/gpu/host1x/drm/gr2d.c
++++ b/drivers/gpu/host1x/drm/gr2d.c
+@@ -84,7 +84,7 @@ static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm,
+
+ gem = drm_gem_object_lookup(drm, file, handle);
+ if (!gem)
+- return 0;
++ return NULL;
+
+ mutex_lock(&drm->struct_mutex);
+ drm_gem_object_unreference(gem);
+@@ -135,8 +135,10 @@ static int gr2d_submit(struct host1x_drm_context *context,
+ goto fail;
+
+ bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
+- if (!bo)
++ if (!bo) {
++ err = -ENOENT;
+ goto fail;
++ }
+
+ host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
+ num_cmdbufs--;
+@@ -158,8 +160,10 @@ static int gr2d_submit(struct host1x_drm_context *context,
+ reloc->cmdbuf = cmdbuf;
+ reloc->target = target;
+
+- if (!reloc->target || !reloc->cmdbuf)
++ if (!reloc->target || !reloc->cmdbuf) {
++ err = -ENOENT;
+ goto fail;
++ }
+ }
+
+ err = copy_from_user(job->waitchk, waitchks,
+@@ -281,7 +285,7 @@ static int gr2d_probe(struct platform_device *pdev)
+ if (!gr2d->channel)
+ return -ENOMEM;
+
+- *syncpts = host1x_syncpt_request(dev, 0);
++ *syncpts = host1x_syncpt_request(dev, false);
+ if (!(*syncpts)) {
+ host1x_channel_free(gr2d->channel);
+ return -ENOMEM;
+diff --git a/drivers/gpu/host1x/drm/output.c b/drivers/gpu/host1x/drm/output.c
+index 8140fc6..7bd7a37 100644
+--- a/drivers/gpu/host1x/drm/output.c
++++ b/drivers/gpu/host1x/drm/output.c
+@@ -105,6 +105,29 @@ static const struct drm_encoder_funcs encoder_funcs = {
+
+ static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
+ {
++ struct tegra_output *output = encoder_to_output(encoder);
++ enum display_entity_state state;
++
++ if (!output->panel)
++ return;
++
++ switch (mode) {
++ case DRM_MODE_DPMS_ON:
++ state = DISPLAY_ENTITY_STATE_ON;
++ break;
++ case DRM_MODE_DPMS_STANDBY:
++ state = DISPLAY_ENTITY_STATE_STANDBY;
++ break;
++ case DRM_MODE_DPMS_SUSPEND:
++ case DRM_MODE_DPMS_OFF:
++ state = DISPLAY_ENTITY_STATE_OFF;
++ break;
++ default:
++ dev_warn(output->dev, "unknown DPMS state, ignoring\n");
++ return;
++ }
++
++ display_entity_set_state(output->panel, state);
+ }
+
+ static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder,
+@@ -129,9 +152,14 @@ static void tegra_encoder_mode_set(struct drm_encoder *encoder,
+ struct tegra_output *output = encoder_to_output(encoder);
+ int err;
+
+- err = tegra_output_enable(output);
++ if (output->panel)
++ err = display_entity_set_state(output->panel,
++ DISPLAY_ENTITY_STATE_ON);
++ else
++ err = tegra_output_enable(output);
++
+ if (err < 0)
+- dev_err(encoder->dev->dev, "tegra_output_enable(): %d\n", err);
++ dev_err(encoder->dev->dev, "cannot enable output: %d\n", err);
+ }
+
+ static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+@@ -185,6 +213,71 @@ int tegra_output_parse_dt(struct tegra_output *output)
+ return 0;
+ }
+
++static int display_notify_callback(struct display_entity_notifier *notifier,
++ struct display_entity *entity, int event)
++{
++ struct tegra_output *output = display_notifier_to_output(notifier);
++ struct device_node *pnode;
++
++ switch (event) {
++ case DISPLAY_ENTITY_NOTIFIER_CONNECT:
++ if (output->panel)
++ break;
++
++ pnode = of_parse_phandle(output->of_node, "nvidia,panel", 0);
++ if (!pnode)
++ break;
++
++ if (entity->dev && entity->dev->of_node == pnode) {
++ dev_dbg(output->dev, "connecting panel\n");
++ output->panel = display_entity_get(entity);
++ display_entity_connect(&output->stream, output->panel);
++ /* TODO set state of panel according to current DPMS
++ * state? */
++ }
++ of_node_put(pnode);
++
++ break;
++
++ case DISPLAY_ENTITY_NOTIFIER_DISCONNECT:
++ if (!output->panel || output->panel != entity)
++ break;
++
++ dev_dbg(output->dev, "disconnecting panel\n");
++ display_entity_disconnect(&output->stream, output->panel);
++ output->panel = NULL;
++ display_entity_put(output->panel);
++
++ break;
++
++ default:
++ dev_dbg(output->dev, "unhandled display event\n");
++ break;
++ }
++
++ return 0;
++}
++
++static int tegra_output_set_stream(struct display_entity *entity,
++ enum display_entity_stream_state state)
++{
++ struct tegra_output *output = display_entity_to_output(entity);
++
++ switch (state) {
++ case DISPLAY_ENTITY_STATE_OFF:
++ case DISPLAY_ENTITY_STATE_STANDBY:
++ return output->ops->disable(output);
++ case DISPLAY_ENTITY_STATE_ON:
++ return output->ops->enable(output);
++ }
++
++ return 0;
++}
++
++static struct display_entity_video_ops tegra_output_video_ops = {
++ .set_stream = tegra_output_set_stream,
++};
++
+ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
+ {
+ int connector, encoder, err;
+@@ -250,6 +343,23 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
+
+ output->encoder.possible_crtcs = 0x3;
+
++ /* register display entity */
++ memset(&output->stream, 0, sizeof(output->stream));
++ output->stream.dev = output->dev;
++ output->stream.ops.video = &tegra_output_video_ops;
++ err = display_entity_register(&output->stream);
++ if (err) {
++ dev_err(output->dev, "cannot register display entity\n");
++ return err;
++ }
++
++ /* register display notifier */
++ output->display_notifier.dev = NULL;
++ output->display_notifier.notify = display_notify_callback;
++ err = display_entity_register_notifier(&output->display_notifier);
++ if (err)
++ return err;
++
+ return 0;
+
+ free_hpd:
+@@ -260,6 +370,12 @@ free_hpd:
+
+ int tegra_output_exit(struct tegra_output *output)
+ {
++ if (output->panel)
++ display_entity_put(output->panel);
++
++ display_entity_unregister_notifier(&output->display_notifier);
++ display_entity_unregister(&output->stream);
++
+ if (gpio_is_valid(output->hpd_gpio)) {
+ free_irq(output->hpd_irq, output);
+ gpio_free(output->hpd_gpio);
+diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c
+index 590b69d..2ee4ad5 100644
+--- a/drivers/gpu/host1x/hw/cdma_hw.c
++++ b/drivers/gpu/host1x/hw/cdma_hw.c
+@@ -44,7 +44,7 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
+ u32 i;
+
+ for (i = 0; i < syncpt_incrs; i++)
+- host1x_syncpt_cpu_incr(cdma->timeout.syncpt);
++ host1x_syncpt_incr(cdma->timeout.syncpt);
+
+ /* after CPU incr, ensure shadow is up to date */
+ host1x_syncpt_load(cdma->timeout.syncpt);
+diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c
+index 6117499..0cf6095 100644
+--- a/drivers/gpu/host1x/hw/syncpt_hw.c
++++ b/drivers/gpu/host1x/hw/syncpt_hw.c
+@@ -77,21 +77,19 @@ static u32 syncpt_load(struct host1x_syncpt *sp)
+ * Write a cpu syncpoint increment to the hardware, without touching
+ * the cache.
+ */
+-static void syncpt_cpu_incr(struct host1x_syncpt *sp)
++static int syncpt_cpu_incr(struct host1x_syncpt *sp)
+ {
+ struct host1x *host = sp->host;
+ u32 reg_offset = sp->id / 32;
+
+ if (!host1x_syncpt_client_managed(sp) &&
+- host1x_syncpt_idle(sp)) {
+- dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n",
+- sp->id);
+- host1x_debug_dump(sp->host);
+- return;
+- }
++ host1x_syncpt_idle(sp))
++ return -EINVAL;
+ host1x_sync_writel(host, BIT_MASK(sp->id),
+ HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset));
+ wmb();
++
++ return 0;
+ }
+
+ /* remove a wait pointed to by patch_addr */
+diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
+index f665d67..cc80766 100644
+--- a/drivers/gpu/host1x/job.c
++++ b/drivers/gpu/host1x/job.c
+@@ -228,17 +228,15 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
+ void *cmdbuf_page_addr = NULL;
+
+ /* pin & patch the relocs for one gather */
+- while (i < job->num_relocs) {
++ for (i = 0; i < job->num_relocs; i++) {
+ struct host1x_reloc *reloc = &job->relocarray[i];
+ u32 reloc_addr = (job->reloc_addr_phys[i] +
+ reloc->target_offset) >> reloc->shift;
+ u32 *target;
+
+ /* skip all other gathers */
+- if (!(reloc->cmdbuf && cmdbuf == reloc->cmdbuf)) {
+- i++;
++ if (cmdbuf != reloc->cmdbuf)
+ continue;
+- }
+
+ if (last_page != reloc->cmdbuf_offset >> PAGE_SHIFT) {
+ if (cmdbuf_page_addr)
+@@ -257,9 +255,6 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
+
+ target = cmdbuf_page_addr + (reloc->cmdbuf_offset & ~PAGE_MASK);
+ *target = reloc_addr;
+-
+- /* mark this gather as handled */
+- reloc->cmdbuf = 0;
+ }
+
+ if (cmdbuf_page_addr)
+@@ -268,15 +263,15 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
+ return 0;
+ }
+
+-static int check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
++static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
+ unsigned int offset)
+ {
+ offset *= sizeof(u32);
+
+ if (reloc->cmdbuf != cmdbuf || reloc->cmdbuf_offset != offset)
+- return -EINVAL;
++ return false;
+
+- return 0;
++ return true;
+ }
+
+ struct host1x_firewall {
+@@ -307,10 +302,10 @@ static int check_mask(struct host1x_firewall *fw)
+
+ if (mask & 1) {
+ if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) {
+- bool bad_reloc = check_reloc(fw->reloc,
+- fw->cmdbuf_id,
+- fw->offset);
+- if (!fw->num_relocs || bad_reloc)
++ if (!fw->num_relocs)
++ return -EINVAL;
++ if (!check_reloc(fw->reloc, fw->cmdbuf_id,
++ fw->offset))
+ return -EINVAL;
+ fw->reloc++;
+ fw->num_relocs--;
+@@ -330,14 +325,14 @@ static int check_incr(struct host1x_firewall *fw)
+ u32 count = fw->count;
+ u32 reg = fw->reg;
+
+- while (fw) {
++ while (count) {
+ if (fw->words == 0)
+ return -EINVAL;
+
+ if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) {
+- bool bad_reloc = check_reloc(fw->reloc, fw->cmdbuf_id,
+- fw->offset);
+- if (!fw->num_relocs || bad_reloc)
++ if (!fw->num_relocs)
++ return -EINVAL;
++ if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset))
+ return -EINVAL;
+ fw->reloc++;
+ fw->num_relocs--;
+@@ -361,9 +356,9 @@ static int check_nonincr(struct host1x_firewall *fw)
+ return -EINVAL;
+
+ if (is_addr_reg) {
+- bool bad_reloc = check_reloc(fw->reloc, fw->cmdbuf_id,
+- fw->offset);
+- if (!fw->num_relocs || bad_reloc)
++ if (!fw->num_relocs)
++ return -EINVAL;
++ if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset))
+ return -EINVAL;
+ fw->reloc++;
+ fw->num_relocs--;
+@@ -376,69 +371,58 @@ static int check_nonincr(struct host1x_firewall *fw)
+ return 0;
+ }
+
+-static int validate(struct host1x_job *job, struct device *dev,
+- struct host1x_job_gather *g)
++static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
+ {
+- u32 *cmdbuf_base;
++ u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped +
++ (g->offset / sizeof(u32));
+ int err = 0;
+- struct host1x_firewall fw;
+
+- fw.job = job;
+- fw.dev = dev;
+- fw.reloc = job->relocarray;
+- fw.num_relocs = job->num_relocs;
+- fw.cmdbuf_id = g->bo;
+-
+- fw.offset = 0;
+- fw.class = 0;
+-
+- if (!job->is_addr_reg)
++ if (!fw->job->is_addr_reg)
+ return 0;
+
+- cmdbuf_base = host1x_bo_mmap(g->bo);
+- if (!cmdbuf_base)
+- return -ENOMEM;
++ fw->words = g->words;
++ fw->cmdbuf_id = g->bo;
++ fw->offset = 0;
+
+- fw.words = g->words;
+- while (fw.words && !err) {
+- u32 word = cmdbuf_base[fw.offset];
++ while (fw->words && !err) {
++ u32 word = cmdbuf_base[fw->offset];
+ u32 opcode = (word & 0xf0000000) >> 28;
+
+- fw.mask = 0;
+- fw.reg = 0;
+- fw.count = 0;
+- fw.words--;
+- fw.offset++;
++ fw->mask = 0;
++ fw->reg = 0;
++ fw->count = 0;
++ fw->words--;
++ fw->offset++;
+
+ switch (opcode) {
+ case 0:
+- fw.class = word >> 6 & 0x3ff;
+- fw.mask = word & 0x3f;
+- fw.reg = word >> 16 & 0xfff;
+- err = check_mask(&fw);
++ fw->class = word >> 6 & 0x3ff;
++ fw->mask = word & 0x3f;
++ fw->reg = word >> 16 & 0xfff;
++ err = check_mask(fw);
+ if (err)
+ goto out;
+ break;
+ case 1:
+- fw.reg = word >> 16 & 0xfff;
+- fw.count = word & 0xffff;
+- err = check_incr(&fw);
++ fw->reg = word >> 16 & 0xfff;
++ fw->count = word & 0xffff;
++ err = check_incr(fw);
+ if (err)
+ goto out;
+ break;
+
+ case 2:
+- fw.reg = word >> 16 & 0xfff;
+- fw.count = word & 0xffff;
+- err = check_nonincr(&fw);
++ fw->reg = word >> 16 & 0xfff;
++ fw->count = word & 0xffff;
++ err = check_nonincr(fw);
+ if (err)
+ goto out;
+ break;
+
+ case 3:
+- fw.mask = word & 0xffff;
+- fw.reg = word >> 16 & 0xfff;
+- err = check_mask(&fw);
++ fw->mask = word & 0xffff;
++ fw->reg = word >> 16 & 0xfff;
++ err = check_mask(fw);
+ if (err)
+ goto out;
+ break;
+@@ -453,21 +437,26 @@ static int validate(struct host1x_job *job, struct device *dev,
+ }
+
+ /* No relocs should remain at this point */
+- if (fw.num_relocs)
++ if (fw->num_relocs)
+ err = -EINVAL;
+
+ out:
+- host1x_bo_munmap(g->bo, cmdbuf_base);
+-
+ return err;
+ }
+
+ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
+ {
++ struct host1x_firewall fw;
+ size_t size = 0;
+ size_t offset = 0;
+ int i;
+
++ fw.job = job;
++ fw.dev = dev;
++ fw.reloc = job->relocarray;
++ fw.num_relocs = job->num_relocs;
++ fw.class = 0;
++
+ for (i = 0; i < job->num_gathers; i++) {
+ struct host1x_job_gather *g = &job->gathers[i];
+ size += g->words * sizeof(u32);
+@@ -488,14 +477,19 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
+ struct host1x_job_gather *g = &job->gathers[i];
+ void *gather;
+
++ /* Copy the gather */
+ gather = host1x_bo_mmap(g->bo);
+ memcpy(job->gather_copy_mapped + offset, gather + g->offset,
+ g->words * sizeof(u32));
+ host1x_bo_munmap(g->bo, gather);
+
++ /* Store the location in the buffer */
+ g->base = job->gather_copy;
+ g->offset = offset;
+- g->bo = NULL;
++
++ /* Validate the job */
++ if (validate(&fw, g))
++ return -EINVAL;
+
+ offset += g->words * sizeof(u32);
+ }
+@@ -540,20 +534,11 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
+ if (job->gathers[j].bo == g->bo)
+ job->gathers[j].handled = true;
+
+- err = 0;
+-
+- if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
+- err = validate(job, dev, g);
+-
++ err = do_relocs(job, g->bo);
+ if (err)
+- dev_err(dev, "Job invalid (err=%d)\n", err);
+-
+- if (!err)
+- err = do_relocs(job, g->bo);
+-
+- if (!err)
+- err = do_waitchks(job, host, g->bo);
++ break;
+
++ err = do_waitchks(job, host, g->bo);
+ if (err)
+ break;
+ }
+diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
+index 4b49345..409745b 100644
+--- a/drivers/gpu/host1x/syncpt.c
++++ b/drivers/gpu/host1x/syncpt.c
+@@ -32,7 +32,7 @@
+
+ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
+ struct device *dev,
+- int client_managed)
++ bool client_managed)
+ {
+ int i;
+ struct host1x_syncpt *sp = host->syncpt;
+@@ -40,7 +40,8 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
+
+ for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
+ ;
+- if (sp->dev)
++
++ if (i >= host->info->nb_pts)
+ return NULL;
+
+ name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
+@@ -128,22 +129,11 @@ u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
+ }
+
+ /*
+- * Write a cpu syncpoint increment to the hardware, without touching
+- * the cache. Caller is responsible for host being powered.
+- */
+-void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp)
+-{
+- host1x_hw_syncpt_cpu_incr(sp->host, sp);
+-}
+-
+-/*
+ * Increment syncpoint value from cpu, updating cache
+ */
+-void host1x_syncpt_incr(struct host1x_syncpt *sp)
++int host1x_syncpt_incr(struct host1x_syncpt *sp)
+ {
+- if (host1x_syncpt_client_managed(sp))
+- host1x_syncpt_incr_max(sp, 1);
+- host1x_syncpt_cpu_incr(sp);
++ return host1x_hw_syncpt_cpu_incr(sp->host, sp);
+ }
+
+ /*
+@@ -331,7 +321,7 @@ int host1x_syncpt_init(struct host1x *host)
+ host1x_syncpt_restore(host);
+
+ /* Allocate sync point to use for clearing waits for expired fences */
+- host->nop_sp = _host1x_syncpt_alloc(host, NULL, 0);
++ host->nop_sp = _host1x_syncpt_alloc(host, NULL, false);
+ if (!host->nop_sp)
+ return -ENOMEM;
+
+@@ -339,7 +329,7 @@ int host1x_syncpt_init(struct host1x *host)
+ }
+
+ struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
+- int client_managed)
++ bool client_managed)
+ {
+ struct host1x *host = dev_get_drvdata(dev->parent);
+ return _host1x_syncpt_alloc(host, dev, client_managed);
+@@ -353,7 +343,7 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
+ kfree(sp->name);
+ sp->dev = NULL;
+ sp->name = NULL;
+- sp->client_managed = 0;
++ sp->client_managed = false;
+ }
+
+ void host1x_syncpt_deinit(struct host1x *host)
+diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h
+index c998061..267c0b9 100644
+--- a/drivers/gpu/host1x/syncpt.h
++++ b/drivers/gpu/host1x/syncpt.h
+@@ -36,7 +36,7 @@ struct host1x_syncpt {
+ atomic_t max_val;
+ u32 base_val;
+ const char *name;
+- int client_managed;
++ bool client_managed;
+ struct host1x *host;
+ struct device *dev;
+
+@@ -94,7 +94,7 @@ static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real)
+ }
+
+ /* Return true if sync point is client managed. */
+-static inline int host1x_syncpt_client_managed(struct host1x_syncpt *sp)
++static inline bool host1x_syncpt_client_managed(struct host1x_syncpt *sp)
+ {
+ return sp->client_managed;
+ }
+@@ -115,9 +115,6 @@ static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp)
+ /* Return pointer to struct denoting sync point id. */
+ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
+
+-/* Request incrementing a sync point. */
+-void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp);
+-
+ /* Load current value from hardware to the shadow register. */
+ u32 host1x_syncpt_load(struct host1x_syncpt *sp);
+
+@@ -133,8 +130,8 @@ void host1x_syncpt_restore(struct host1x *host);
+ /* Read current wait base value into shadow register and return it. */
+ u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp);
+
+-/* Increment sync point and its max. */
+-void host1x_syncpt_incr(struct host1x_syncpt *sp);
++/* Request incrementing a sync point. */
++int host1x_syncpt_incr(struct host1x_syncpt *sp);
+
+ /* Indicate future operations by incrementing the sync point max. */
+ u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
+@@ -157,7 +154,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp);
+
+ /* Allocate a sync point for a device. */
+ struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
+- int client_managed);
++ bool client_managed);
+
+ /* Free a sync point. */
+ void host1x_syncpt_free(struct host1x_syncpt *sp);
+diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
+index 197c393..5a5c639 100644
+--- a/drivers/staging/nvec/nvec.c
++++ b/drivers/staging/nvec/nvec.c
+@@ -33,7 +33,6 @@
+ #include <linux/mfd/core.h>
+ #include <linux/mutex.h>
+ #include <linux/notifier.h>
+-#include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <linux/spinlock.h>
+ #include <linux/workqueue.h>
+@@ -751,8 +750,6 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
+ writel(0, nvec->base + I2C_SL_ADDR2);
+
+ enable_irq(nvec->irq);
+-
+- clk_disable_unprepare(nvec->i2c_clk);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+@@ -772,11 +769,31 @@ static void nvec_power_off(void)
+ nvec_write_async(nvec_power_handle, ap_pwr_down, 2);
+ }
+
++/*
++ * Parse common device tree data
++ */
++static int nvec_i2c_parse_dt_pdata(struct nvec_chip *nvec)
++{
++ nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0);
++
++ if (nvec->gpio < 0) {
++ dev_err(nvec->dev, "no gpio specified");
++ return -ENODEV;
++ }
++
++ if (of_property_read_u32(nvec->dev->of_node, "slave-addr",
++ &nvec->i2c_addr)) {
++ dev_err(nvec->dev, "no i2c address specified");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
+ static int tegra_nvec_probe(struct platform_device *pdev)
+ {
+ int err, ret;
+ struct clk *i2c_clk;
+- struct nvec_platform_data *pdata = pdev->dev.platform_data;
+ struct nvec_chip *nvec;
+ struct nvec_msg *msg;
+ struct resource *res;
+@@ -785,6 +802,11 @@ static int tegra_nvec_probe(struct platform_device *pdev)
+ unmute_speakers[] = { NVEC_OEM0, 0x10, 0x59, 0x95 },
+ enable_event[7] = { NVEC_SYS, CNF_EVENT_REPORTING, true };
+
++ if(!pdev->dev.of_node) {
++ dev_err(&pdev->dev, "must be instantiated using device tree\n");
++ return -ENODEV;
++ }
++
+ nvec = devm_kzalloc(&pdev->dev, sizeof(struct nvec_chip), GFP_KERNEL);
+ if (nvec == NULL) {
+ dev_err(&pdev->dev, "failed to reserve memory\n");
+@@ -793,25 +815,9 @@ static int tegra_nvec_probe(struct platform_device *pdev)
+ platform_set_drvdata(pdev, nvec);
+ nvec->dev = &pdev->dev;
+
+- if (pdata) {
+- nvec->gpio = pdata->gpio;
+- nvec->i2c_addr = pdata->i2c_addr;
+- } else if (nvec->dev->of_node) {
+- nvec->gpio = of_get_named_gpio(nvec->dev->of_node,
+- "request-gpios", 0);
+- if (nvec->gpio < 0) {
+- dev_err(&pdev->dev, "no gpio specified");
+- return -ENODEV;
+- }
+- if (of_property_read_u32(nvec->dev->of_node,
+- "slave-addr", &nvec->i2c_addr)) {
+- dev_err(&pdev->dev, "no i2c address specified");
+- return -ENODEV;
+- }
+- } else {
+- dev_err(&pdev->dev, "no platform data\n");
+- return -ENODEV;
+- }
++ err = nvec_i2c_parse_dt_pdata(nvec);
++ if (err < 0)
++ return err;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+@@ -864,9 +870,6 @@ static int tegra_nvec_probe(struct platform_device *pdev)
+
+ tegra_init_i2c_slave(nvec);
+
+- clk_prepare_enable(i2c_clk);
+-
+-
+ /* enable event reporting */
+ nvec_toggle_global_events(nvec, true);
+
+diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
+index 2b1316d..e880518 100644
+--- a/drivers/staging/nvec/nvec.h
++++ b/drivers/staging/nvec/nvec.h
+@@ -103,31 +103,6 @@ struct nvec_msg {
+ };
+
+ /**
+- * struct nvec_subdev - A subdevice of nvec, such as nvec_kbd
+- * @name: The name of the sub device
+- * @platform_data: Platform data
+- * @id: Identifier of the sub device
+- */
+-struct nvec_subdev {
+- const char *name;
+- void *platform_data;
+- int id;
+-};
+-
+-/**
+- * struct nvec_platform_data - platform data for a tegra slave controller
+- * @i2c_addr: number of i2c slave adapter the ec is connected to
+- * @gpio: gpio number for the ec request line
+- *
+- * Platform data, to be used in board definitions. For an example, take a
+- * look at the paz00 board in arch/arm/mach-tegra/board-paz00.c
+- */
+-struct nvec_platform_data {
+- int i2c_addr;
+- int gpio;
+-};
+-
+-/**
+ * struct nvec_chip - A single connection to an NVIDIA Embedded controller
+ * @dev: The device
+ * @gpio: The same as for &struct nvec_platform_data
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 2e937bd..6d9788d 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -2475,6 +2475,7 @@ source "drivers/video/omap2/Kconfig"
+ source "drivers/video/exynos/Kconfig"
+ source "drivers/video/mmp/Kconfig"
+ source "drivers/video/backlight/Kconfig"
++source "drivers/video/display/Kconfig"
+
+ if VT
+ source "drivers/video/console/Kconfig"
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index e8bae8d..d7fd4a2 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -15,6 +15,7 @@ fb-objs := $(fb-y)
+ obj-$(CONFIG_VT) += console/
+ obj-$(CONFIG_LOGO) += logo/
+ obj-y += backlight/
++obj-y += display/
+
+ obj-$(CONFIG_EXYNOS_VIDEO) += exynos/
+
+diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
+new file mode 100644
+index 0000000..165776f
+--- /dev/null
++++ b/drivers/video/display/Kconfig
+@@ -0,0 +1,16 @@
++menuconfig DISPLAY_CORE
++ tristate "Display Core"
++ ---help---
++ Support common display framework for graphics devices.
++
++if DISPLAY_CORE
++
++config DISPLAY_PANEL_CLAA101WA01A
++ tristate "Chunghwa CLAA101WA01A Display Panel"
++ select BACKLIGHT_PWM
++ ---help---
++ Support for the Chunghwa CLAA101WA01A Display Panel.
++
++ If you are in doubt, say N.
++
++endif # DISPLAY_CORE
+diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
+new file mode 100644
+index 0000000..2e6cf49
+--- /dev/null
++++ b/drivers/video/display/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_DISPLAY_CORE) += display-core.o
++obj-$(CONFIG_DISPLAY_PANEL_CLAA101WA01A) += panel-claa101wa01a.o
+diff --git a/drivers/video/display/display-core.c b/drivers/video/display/display-core.c
+new file mode 100644
+index 0000000..46295fb
+--- /dev/null
++++ b/drivers/video/display/display-core.c
+@@ -0,0 +1,361 @@
++/*
++ * Display Core
++ *
++ * Copyright (C) 2012 Renesas Solutions Corp.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <video/videomode.h>
++#include <video/display.h>
++
++static LIST_HEAD(display_entity_list);
++static LIST_HEAD(display_entity_notifiers);
++static DEFINE_MUTEX(display_entity_mutex);
++
++/* -----------------------------------------------------------------------------
++ * Control operations
++ */
++
++/**
++ * display_entity_set_state - Set the display entity operation state
++ * @entity: The display entity
++ * @state: Display entity operation state
++ *
++ * See &enum display_entity_state for information regarding the entity states.
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++int display_entity_set_state(struct display_entity *entity,
++ enum display_entity_state state)
++{
++ int ret;
++
++ if (entity->state == state)
++ return 0;
++
++ if (!entity->ops.ctrl || !entity->ops.ctrl->set_state)
++ return 0;
++
++ ret = entity->ops.ctrl->set_state(entity, state);
++ if (ret < 0)
++ return ret;
++
++ entity->state = state;
++ return 0;
++}
++EXPORT_SYMBOL_GPL(display_entity_set_state);
++
++/**
++ * display_entity_update - Update the display
++ * @entity: The display entity
++ *
++ * Make the display entity ready to receive pixel data and start frame transfer.
++ * This operation can only be called if the display entity is in STANDBY or ON
++ * state.
++ *
++ * The display entity will call the upstream entity in the video chain to start
++ * the video stream.
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++int display_entity_update(struct display_entity *entity)
++{
++ if (!entity->ops.ctrl || !entity->ops.ctrl->update)
++ return 0;
++
++ return entity->ops.ctrl->update(entity);
++}
++EXPORT_SYMBOL_GPL(display_entity_update);
++
++/**
++ * display_entity_get_modes - Get video modes supported by the display entity
++ * @entity The display entity
++ * @modes: Pointer to an array of modes
++ *
++ * Fill the modes argument with a pointer to an array of video modes. The array
++ * is owned by the display entity.
++ *
++ * Return the number of supported modes on success (including 0 if no mode is
++ * supported) or a negative error code otherwise.
++ */
++int display_entity_get_modes(struct display_entity *entity,
++ const struct videomode **modes)
++{
++ if (!entity->ops.ctrl || !entity->ops.ctrl->get_modes)
++ return 0;
++
++ return entity->ops.ctrl->get_modes(entity, modes);
++}
++EXPORT_SYMBOL_GPL(display_entity_get_modes);
++
++/**
++ * display_entity_get_size - Get display entity physical size
++ * @entity: The display entity
++ * @width: Physical width in millimeters
++ * @height: Physical height in millimeters
++ *
++ * When applicable, for instance for display panels, retrieve the display
++ * physical size in millimeters.
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++int display_entity_get_size(struct display_entity *entity,
++ unsigned int *width, unsigned int *height)
++{
++ if (!entity->ops.ctrl || !entity->ops.ctrl->get_size)
++ return -EOPNOTSUPP;
++
++ return entity->ops.ctrl->get_size(entity, width, height);
++}
++EXPORT_SYMBOL_GPL(display_entity_get_size);
++
++/**
++ * display_entity_get_params - Get display entity interface parameters
++ * @entity: The display entity
++ * @params: Pointer to interface parameters
++ *
++ * Fill the parameters structure pointed to by the params argument with display
++ * entity interface parameters.
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++int display_entity_get_params(struct display_entity *entity,
++ struct display_entity_interface_params *params)
++{
++ if (!entity->ops.ctrl || !entity->ops.ctrl->get_modes)
++ return -EOPNOTSUPP;
++
++ return entity->ops.ctrl->get_params(entity, params);
++}
++EXPORT_SYMBOL_GPL(display_entity_get_params);
++
++/* -----------------------------------------------------------------------------
++ * Video operations
++ */
++
++/**
++ * display_entity_set_stream - Control the video stream state
++ * @entity: The display entity
++ * @state: Display video stream state
++ *
++ * Control the video stream state at the entity video output.
++ *
++ * See &enum display_entity_stream_state for information regarding the stream
++ * states.
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++int display_entity_set_stream(struct display_entity *entity,
++ enum display_entity_stream_state state)
++{
++ if (!entity->ops.video || !entity->ops.video->set_stream)
++ return 0;
++
++ return entity->ops.video->set_stream(entity, state);
++}
++EXPORT_SYMBOL_GPL(display_entity_set_stream);
++
++/* -----------------------------------------------------------------------------
++ * Connections
++ */
++
++/**
++ * display_entity_connect - Connect two entities through a video stream
++ * @source: The video stream source
++ * @sink: The video stream sink
++ *
++ * Set the sink entity source field to the source entity.
++ */
++
++/**
++ * display_entity_disconnect - Disconnect two previously connected entities
++ * @source: The video stream source
++ * @sink: The video stream sink
++ *
++ * Break a connection between two previously connected entities. The source
++ * entity source field is reset to NULL.
++ */
++
++/* -----------------------------------------------------------------------------
++ * Registration and notification
++ */
++
++static void display_entity_release(struct kref *ref)
++{
++ struct display_entity *entity =
++ container_of(ref, struct display_entity, ref);
++
++ if (entity->release)
++ entity->release(entity);
++}
++
++/**
++ * display_entity_get - get a reference to a display entity
++ * @display_entity: the display entity
++ *
++ * Return the display entity pointer.
++ */
++struct display_entity *display_entity_get(struct display_entity *entity)
++{
++ if (entity == NULL)
++ return NULL;
++
++ kref_get(&entity->ref);
++ return entity;
++}
++EXPORT_SYMBOL_GPL(display_entity_get);
++
++/**
++ * display_entity_put - release a reference to a display entity
++ * @display_entity: the display entity
++ *
++ * Releasing the last reference to a display entity releases the display entity
++ * itself.
++ */
++void display_entity_put(struct display_entity *entity)
++{
++ kref_put(&entity->ref, display_entity_release);
++}
++EXPORT_SYMBOL_GPL(display_entity_put);
++
++static int display_entity_notifier_match(struct display_entity *entity,
++ struct display_entity_notifier *notifier)
++{
++ return notifier->dev == NULL || notifier->dev == entity->dev;
++}
++
++/**
++ * display_entity_register_notifier - register a display entity notifier
++ * @notifier: display entity notifier structure we want to register
++ *
++ * Display entity notifiers are called to notify drivers of display
++ * entity-related events for matching display_entitys.
++ *
++ * Notifiers and display_entitys are matched through the device they correspond
++ * to. If the notifier dev field is equal to the display entity dev field the
++ * notifier will be called when an event is reported. Notifiers with a NULL dev
++ * field act as catch-all and will be called for all display_entitys.
++ *
++ * Supported events are
++ *
++ * - DISPLAY_ENTITY_NOTIFIER_CONNECT reports display entity connection and is
++ * sent at display entity or notifier registration time
++ * - DISPLAY_ENTITY_NOTIFIER_DISCONNECT reports display entity disconnection and
++ * is sent at display entity unregistration time
++ *
++ * Registering a notifier sends DISPLAY_ENTITY_NOTIFIER_CONNECT events for all
++ * previously registered display_entitys that match the notifiers.
++ *
++ * Return 0 on success.
++ */
++int display_entity_register_notifier(struct display_entity_notifier *notifier)
++{
++ struct display_entity *entity;
++
++ mutex_lock(&display_entity_mutex);
++ list_add_tail(&notifier->list, &display_entity_notifiers);
++
++ list_for_each_entry(entity, &display_entity_list, list) {
++ if (!display_entity_notifier_match(entity, notifier))
++ continue;
++
++ if (notifier->notify(notifier, entity,
++ DISPLAY_ENTITY_NOTIFIER_CONNECT))
++ break;
++ }
++ mutex_unlock(&display_entity_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(display_entity_register_notifier);
++
++/**
++ * display_entity_unregister_notifier - unregister a display entity notifier
++ * @notifier: display entity notifier to be unregistered
++ *
++ * Unregistration guarantees that the notifier will never be called upon return
++ * of this function.
++ */
++void display_entity_unregister_notifier(struct display_entity_notifier *notifier)
++{
++ mutex_lock(&display_entity_mutex);
++ list_del(&notifier->list);
++ mutex_unlock(&display_entity_mutex);
++}
++EXPORT_SYMBOL_GPL(display_entity_unregister_notifier);
++
++/**
++ * display_entity_register - register a display entity
++ * @display_entity: display entity to be registered
++ *
++ * Register the display entity and send the DISPLAY_ENTITY_NOTIFIER_CONNECT
++ * event to all matching registered notifiers.
++ *
++ * Return 0 on success.
++ */
++int __must_check __display_entity_register(struct display_entity *entity,
++ struct module *owner)
++{
++ struct display_entity_notifier *notifier;
++
++ kref_init(&entity->ref);
++ entity->owner = owner;
++ entity->state = DISPLAY_ENTITY_STATE_OFF;
++
++ mutex_lock(&display_entity_mutex);
++ list_add(&entity->list, &display_entity_list);
++
++ list_for_each_entry(notifier, &display_entity_notifiers, list) {
++ if (!display_entity_notifier_match(entity, notifier))
++ continue;
++
++ if (notifier->notify(notifier, entity,
++ DISPLAY_ENTITY_NOTIFIER_CONNECT))
++ break;
++ }
++ mutex_unlock(&display_entity_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(__display_entity_register);
++
++/**
++ * display_entity_unregister - unregister a display entity
++ * @display_entity: display entity to be unregistered
++ *
++ * Unregister the display entity and send the DISPLAY_ENTITY_NOTIFIER_DISCONNECT
++ * event to all matching registered notifiers.
++ */
++void display_entity_unregister(struct display_entity *entity)
++{
++ struct display_entity_notifier *notifier;
++
++ mutex_lock(&display_entity_mutex);
++ list_for_each_entry(notifier, &display_entity_notifiers, list) {
++ if (!display_entity_notifier_match(entity, notifier))
++ continue;
++
++ notifier->notify(notifier, entity,
++ DISPLAY_ENTITY_NOTIFIER_DISCONNECT);
++ }
++
++ list_del(&entity->list);
++ mutex_unlock(&display_entity_mutex);
++
++ display_entity_put(entity);
++}
++EXPORT_SYMBOL_GPL(display_entity_unregister);
++
++MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
++MODULE_DESCRIPTION("Display Core");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/display/panel-claa101wa01a.c b/drivers/video/display/panel-claa101wa01a.c
+new file mode 100644
+index 0000000..b76ebe0
+--- /dev/null
++++ b/drivers/video/display/panel-claa101wa01a.c
+@@ -0,0 +1,263 @@
++/*
++ * CLAA101WA01A Display Panel
++ *
++ * Copyright (C) 2013 NVIDIA CORPORATION. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/regulator/consumer.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/backlight.h>
++
++#include <video/display.h>
++
++#define CLAA101WA01A_WIDTH 223
++#define CLAA101WA01A_HEIGHT 125
++
++struct panel_claa101 {
++ struct display_entity entity;
++ struct backlight_device *backlight;
++ struct regulator *vdd_pnl;
++ struct regulator *vdd_bl;
++ /* Enable GPIOs */
++ int pnl_enable;
++ int bl_enable;
++};
++
++#define to_panel_claa101(p) container_of(p, struct panel_claa101, entity)
++
++static int panel_claa101_off(struct panel_claa101 *panel)
++{
++ /* TODO error checking? */
++ if (panel->backlight) {
++ panel->backlight->props.state |= BL_CORE_FBBLANK;
++ backlight_update_status(panel->backlight);
++ }
++
++ gpio_set_value_cansleep(panel->bl_enable, 0);
++ usleep_range(10000, 10000);
++ regulator_disable(panel->vdd_bl);
++ usleep_range(200000, 200000);
++ gpio_set_value_cansleep(panel->pnl_enable, 0);
++ regulator_disable(panel->vdd_pnl);
++
++ if (panel->entity.source)
++ display_entity_set_stream(panel->entity.source,
++ DISPLAY_ENTITY_STREAM_STOPPED);
++
++ return 0;
++}
++
++static int panel_claa101_on(struct panel_claa101 *panel)
++{
++ /* TODO error checking? */
++ if (panel->entity.source)
++ display_entity_set_stream(panel->entity.source,
++ DISPLAY_ENTITY_STREAM_CONTINUOUS);
++
++ regulator_enable(panel->vdd_pnl);
++ gpio_set_value_cansleep(panel->pnl_enable, 1);
++ usleep_range(200000, 200000);
++ regulator_enable(panel->vdd_bl);
++ usleep_range(10000, 10000);
++ gpio_set_value_cansleep(panel->bl_enable, 1);
++
++ if (panel->backlight) {
++ panel->backlight->props.state &= ~BL_CORE_FBBLANK;
++ backlight_update_status(panel->backlight);
++ }
++
++ return 0;
++}
++
++static int panel_claa101_set_state(struct display_entity *entity,
++ enum display_entity_state state)
++{
++ struct panel_claa101 *panel = to_panel_claa101(entity);
++
++ switch (state) {
++ case DISPLAY_ENTITY_STATE_OFF:
++ case DISPLAY_ENTITY_STATE_STANDBY:
++ /* OFF and STANDBY are the same to us. Avoid unbalanced calls to
++ * off() when we are switching between these two states. */
++ if (entity->state == DISPLAY_ENTITY_STATE_OFF ||
++ entity->state == DISPLAY_ENTITY_STATE_STANDBY)
++ return 0;
++
++ return panel_claa101_off(panel);
++
++ case DISPLAY_ENTITY_STATE_ON:
++ return panel_claa101_on(panel);
++ }
++
++ return 0;
++}
++
++static int panel_claa101_get_modes(struct display_entity *entity,
++ const struct videomode **modes)
++{
++ /* TODO get modes from EDID? */
++ return 0;
++}
++
++static int panel_claa101_get_size(struct display_entity *entity,
++ unsigned int *width, unsigned int *height)
++{
++ *width = CLAA101WA01A_WIDTH;
++ *height = CLAA101WA01A_HEIGHT;
++
++ return 0;
++}
++
++static int panel_claa101_get_params(struct display_entity *entity,
++ struct display_entity_interface_params *params)
++{
++ return 0;
++}
++
++static const struct display_entity_control_ops panel_claa101_control_ops = {
++ .set_state = panel_claa101_set_state,
++ .get_modes = panel_claa101_get_modes,
++ .get_size = panel_claa101_get_size,
++ .get_params = panel_claa101_get_params,
++};
++
++static int __init panel_claa101_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct panel_claa101 *panel;
++ struct device_node *node;
++ int err;
++
++ panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
++ if (!panel)
++ return -ENOMEM;
++
++ panel->vdd_pnl = devm_regulator_get(dev, "pnl");
++ if (IS_ERR(panel->vdd_pnl)) {
++ dev_err(dev, "cannot get vdd regulator\n");
++ return PTR_ERR(panel->vdd_pnl);
++ }
++
++ panel->vdd_bl = devm_regulator_get(dev, "bl");
++ if (IS_ERR(panel->vdd_bl)) {
++ dev_err(dev, "cannot get bl regulator\n");
++ return PTR_ERR(panel->vdd_bl);
++ }
++
++ err = of_get_named_gpio(dev->of_node, "pnl-enable-gpios", 0);
++ if (err < 0) {
++ dev_err(dev, "cannot find panel enable GPIO!\n");
++ return err;
++ }
++ panel->pnl_enable = err;
++ err = devm_gpio_request_one(dev, panel->pnl_enable,
++ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "panel");
++ if (err < 0) {
++ dev_err(dev, "cannot acquire panel enable GPIO!\n");
++ return err;
++ }
++
++ err = of_get_named_gpio(dev->of_node, "bl-enable-gpios", 0);
++ if (err < 0) {
++ dev_err(dev, "cannot find backlight enable GPIO!\n");
++ return err;
++ }
++ panel->bl_enable = err;
++ err = devm_gpio_request_one(dev, panel->bl_enable,
++ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "backlight");
++ if (err < 0) {
++ dev_err(dev, "cannot acquire backlight enable GPIO!\n");
++ return err;
++ }
++
++ node = of_parse_phandle(dev->of_node, "backlight", 0);
++ if (node) {
++ panel->backlight = of_find_backlight_by_node(node);
++ if (!panel->backlight)
++ return -EPROBE_DEFER;
++ }
++
++ panel->entity.dev = dev;
++ panel->entity.ops.ctrl = &panel_claa101_control_ops;
++ err = display_entity_register(&panel->entity);
++ if (err < 0) {
++ if (panel->backlight)
++ put_device(&panel->backlight->dev);
++ return err;
++ }
++
++ platform_set_drvdata(pdev, panel);
++
++ return 0;
++}
++
++static int __exit panel_claa101_remove(struct platform_device *pdev)
++{
++ struct panel_claa101 *panel = platform_get_drvdata(pdev);
++
++ display_entity_unregister(&panel->entity);
++ if (panel->backlight)
++ put_device(&panel->backlight->dev);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int panel_claa101_suspend(struct device *dev)
++{
++ struct panel_claa101 *panel = dev_get_drvdata(dev);
++ return panel_claa101_off(panel);
++}
++
++static int panel_claa101_resume(struct device *dev)
++{
++ struct panel_claa101 *panel = dev_get_drvdata(dev);
++ return panel_claa101_on(panel);
++}
++#endif
++
++#ifdef CONFIG_OF
++static struct of_device_id panel_claa101_of_match[] = {
++ { .compatible = "chunghwa,claa101wa01a", },
++ { },
++};
++MODULE_DEVICE_TABLE(of, panel_claa101_of_match);
++#else
++#endif
++
++static const struct dev_pm_ops panel_claa101_dev_pm_ops = {
++ .suspend = panel_claa101_suspend,
++ .resume = panel_claa101_resume,
++};
++
++static struct platform_driver panel_claa101_driver = {
++ .probe = panel_claa101_probe,
++ .remove = panel_claa101_remove,
++ .driver = {
++ .name = "panel_claa101wa01a",
++ .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++ .pm = &panel_claa101_dev_pm_ops,
++#endif
++#ifdef CONFIG_OF
++ .of_match_table = of_match_ptr(panel_claa101_of_match),
++#endif
++ },
++};
++
++module_platform_driver(panel_claa101_driver);
++
++MODULE_AUTHOR("Alexandre Courbot <acourbot@nvidia.com>");
++MODULE_DESCRIPTION("Chunghwa CLAA101WA01A Display Panel");
++MODULE_LICENSE("GPL");
+diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h
+index 642789b..46da5cd 100644
+--- a/include/linux/clk/tegra.h
++++ b/include/linux/clk/tegra.h
+@@ -120,8 +120,13 @@ static inline void tegra_cpu_clock_resume(void)
+ }
+ #endif
+
++#ifdef CONFIG_ARCH_TEGRA
+ void tegra_periph_reset_deassert(struct clk *c);
+ void tegra_periph_reset_assert(struct clk *c);
++#else
++static inline void tegra_periph_reset_deassert(struct clk *c) {}
++static inline void tegra_periph_reset_assert(struct clk *c) {}
++#endif
+ void tegra_clocks_init(void);
+ void tegra_clocks_apply_init_table(void);
+
+diff --git a/include/uapi/drm/tegra_drm.h b/include/uapi/drm/tegra_drm.h
+index 6e132a2..73bde4e 100644
+--- a/include/uapi/drm/tegra_drm.h
++++ b/include/uapi/drm/tegra_drm.h
+@@ -17,6 +17,8 @@
+ #ifndef _UAPI_TEGRA_DRM_H_
+ #define _UAPI_TEGRA_DRM_H_
+
++#include <drm/drm.h>
++
+ struct drm_tegra_gem_create {
+ __u64 size;
+ __u32 flags;
+diff --git a/include/video/display.h b/include/video/display.h
+new file mode 100644
+index 0000000..90d18ca
+--- /dev/null
++++ b/include/video/display.h
+@@ -0,0 +1,150 @@
++/*
++ * Display Core
++ *
++ * Copyright (C) 2012 Renesas Solutions Corp.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __DISPLAY_H__
++#define __DISPLAY_H__
++
++#include <linux/kref.h>
++#include <linux/list.h>
++#include <linux/module.h>
++
++/* -----------------------------------------------------------------------------
++ * Display Entity
++ */
++
++struct display_entity;
++struct videomode;
++
++#define DISPLAY_ENTITY_NOTIFIER_CONNECT 1
++#define DISPLAY_ENTITY_NOTIFIER_DISCONNECT 2
++
++struct display_entity_notifier {
++ int (*notify)(struct display_entity_notifier *, struct display_entity *,
++ int);
++ struct device *dev;
++ struct list_head list;
++};
++
++/**
++ * enum display_entity_state - State of a display entity
++ * @DISPLAY_ENTITY_STATE_OFF: The entity is turned off completely, possibly
++ * including its power supplies. Communication with a display entity in
++ * that state is not possible.
++ * @DISPLAY_ENTITY_STATE_STANDBY: The entity is in a low-power state. Full
++ * communication with the display entity is supported, including pixel data
++ * transfer, but the output is kept blanked.
++ * @DISPLAY_ENTITY_STATE_ON: The entity is fully operational.
++ */
++enum display_entity_state {
++ DISPLAY_ENTITY_STATE_OFF,
++ DISPLAY_ENTITY_STATE_STANDBY,
++ DISPLAY_ENTITY_STATE_ON,
++};
++
++/**
++ * enum display_entity_stream_state - State of a video stream
++ * @DISPLAY_ENTITY_STREAM_STOPPED: The video stream is stopped, no frames are
++ * transferred.
++ * @DISPLAY_ENTITY_STREAM_SINGLE_SHOT: The video stream has been started for
++ * single shot operation. The source entity will transfer a single frame
++ * and then stop.
++ * @DISPLAY_ENTITY_STREAM_CONTINUOUS: The video stream is running, frames are
++ * transferred continuously by the source entity.
++ */
++enum display_entity_stream_state {
++ DISPLAY_ENTITY_STREAM_STOPPED,
++ DISPLAY_ENTITY_STREAM_SINGLE_SHOT,
++ DISPLAY_ENTITY_STREAM_CONTINUOUS,
++};
++
++enum display_entity_interface_type {
++ DISPLAY_ENTITY_INTERFACE_DPI,
++};
++
++struct display_entity_interface_params {
++ enum display_entity_interface_type type;
++};
++
++struct display_entity_control_ops {
++ int (*set_state)(struct display_entity *ent,
++ enum display_entity_state state);
++ int (*update)(struct display_entity *ent);
++ int (*get_modes)(struct display_entity *ent,
++ const struct videomode **modes);
++ int (*get_params)(struct display_entity *ent,
++ struct display_entity_interface_params *params);
++ int (*get_size)(struct display_entity *ent,
++ unsigned int *width, unsigned int *height);
++};
++
++struct display_entity_video_ops {
++ int (*set_stream)(struct display_entity *ent,
++ enum display_entity_stream_state state);
++};
++
++struct display_entity {
++ struct list_head list;
++ struct device *dev;
++ struct module *owner;
++ struct kref ref;
++
++ struct display_entity *source;
++
++ struct {
++ const struct display_entity_control_ops *ctrl;
++ const struct display_entity_video_ops *video;
++ } ops;
++
++ void(*release)(struct display_entity *ent);
++
++ enum display_entity_state state;
++};
++
++int display_entity_set_state(struct display_entity *entity,
++ enum display_entity_state state);
++int display_entity_update(struct display_entity *entity);
++int display_entity_get_modes(struct display_entity *entity,
++ const struct videomode **modes);
++int display_entity_get_params(struct display_entity *entity,
++ struct display_entity_interface_params *params);
++int display_entity_get_size(struct display_entity *entity,
++ unsigned int *width, unsigned int *height);
++
++int display_entity_set_stream(struct display_entity *entity,
++ enum display_entity_stream_state state);
++
++static inline void display_entity_connect(struct display_entity *source,
++ struct display_entity *sink)
++{
++ sink->source = source;
++}
++
++static inline void display_entity_disconnect(struct display_entity *source,
++ struct display_entity *sink)
++{
++ sink->source = NULL;
++}
++
++struct display_entity *display_entity_get(struct display_entity *entity);
++void display_entity_put(struct display_entity *entity);
++
++int __must_check __display_entity_register(struct display_entity *entity,
++ struct module *owner);
++void display_entity_unregister(struct display_entity *entity);
++
++int display_entity_register_notifier(struct display_entity_notifier *notifier);
++void display_entity_unregister_notifier(struct display_entity_notifier *notifier);
++
++#define display_entity_register(display_entity) \
++ __display_entity_register(display_entity, THIS_MODULE)
++
++#endif /* __DISPLAY_H__ */
+diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
+index f2e62e4..6bda3aa 100644
+--- a/sound/soc/codecs/alc5632.c
++++ b/sound/soc/codecs/alc5632.c
+@@ -551,8 +551,10 @@ static const struct snd_soc_dapm_route alc5632_dapm_routes[] = {
+ {"Left LineIn", NULL, "LINEINL"},
+ {"Right LineIn", NULL, "LINEINR"},
+ {"Phone", NULL, "PHONEP"},
+- {"MIC1 Pre Amp", NULL, "MIC1"},
+- {"MIC2 Pre Amp", NULL, "MIC2"},
++ {"MICBIAS1", NULL, "MIC1"},
++ {"MIC1 Pre Amp", NULL, "MICBIAS1"},
++ {"MICBIAS2", NULL, "MIC2"},
++ {"MIC2 Pre Amp", NULL, "MICBIAS2"},
+ {"MIC1 PGA", NULL, "MIC1 Pre Amp"},
+ {"MIC2 PGA", NULL, "MIC2 Pre Amp"},
+
+diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
+index 48d05d9..1b1e775 100644
+--- a/sound/soc/tegra/tegra_alc5632.c
++++ b/sound/soc/tegra/tegra_alc5632.c
+@@ -36,6 +36,7 @@
+ struct tegra_alc5632 {
+ struct tegra_asoc_utils_data util_data;
+ int gpio_hp_det;
++ int gpio_spkr_en;
+ };
+
+ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream,
+@@ -91,8 +92,24 @@ static struct snd_soc_jack_gpio tegra_alc5632_hp_jack_gpio = {
+ .debounce_time = 150,
+ };
+
++static int tegra_alc5632_event_int_spk(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *k, int event)
++{
++ struct snd_soc_dapm_context *dapm = w->dapm;
++ struct snd_soc_card *card = dapm->card;
++ struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
++
++ if (!gpio_is_valid(machine->gpio_spkr_en))
++ return 0;
++
++ gpio_set_value_cansleep(machine->gpio_spkr_en,
++ SND_SOC_DAPM_EVENT_ON(event));
++
++ return 0;
++}
++
+ static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = {
+- SND_SOC_DAPM_SPK("Int Spk", NULL),
++ SND_SOC_DAPM_SPK("Int Spk", tegra_alc5632_event_int_spk),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic", NULL),
+@@ -172,6 +189,11 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
+ if (alc5632->gpio_hp_det == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
++ alc5632->gpio_spkr_en = of_get_named_gpio(pdev->dev.of_node,
++ "nvidia,spkr-en-gpios", 0);
++ if (alc5632->gpio_spkr_en == -ENODEV)
++ return -EPROBE_DEFER;
++
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+ goto err;
+@@ -201,6 +223,16 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
+
+ tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node;
+
++ if (gpio_is_valid(alc5632->gpio_spkr_en)) {
++
++ ret = devm_gpio_request(&pdev->dev, alc5632->gpio_spkr_en,
++ "spkr_en");
++ if (ret) {
++ dev_err(card->dev, "cannot get spkr_en gpio\n");
++ return ret;
++ }
++ }
++
+ ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
+ if (ret)
+ goto err;