Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Apr 2015 16:08:39 +0000 (09:08 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Apr 2015 16:08:39 +0000 (09:08 -0700)
Pull ARM SoC platform updates from Olof Johansson:
 "Our SoC branch usually contains expanded support for new SoCs and
  other core platform code.  In this case, that includes:

   - support for the new Annapurna Labs "Alpine" platform

   - a rework greatly simplifying adding new platform support to the
     MCPM subsystem (Multi-cluster power management)

   - cpuidle and PM improvements for Exynos3250

   - misc updates for Renesas, OMAP, Meson, i.MX.  Some of these could
     have gone in other branches but ended up here for various reasons"

* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (53 commits)
  ARM: alpine: add support for generic pci
  ARM: Exynos: migrate DCSCB to the new MCPM backend abstraction
  ARM: vexpress: migrate DCSCB to the new MCPM backend abstraction
  ARM: vexpress: DCSCB: tighten CPU validity assertion
  ARM: vexpress: migrate TC2 to the new MCPM backend abstraction
  ARM: MCPM: move the algorithmic complexity to the core code
  ARM: EXYNOS: allow cpuidle driver usage on Exynos3250 SoC
  ARM: EXYNOS: add AFTR mode support for Exynos3250
  ARM: EXYNOS: add code for setting/clearing boot flag
  ARM: EXYNOS: fix CPU1 hotplug on Exynos3250
  ARM: S3C64XX: Use fixed IRQ bases to avoid conflicts on Cragganmore
  ARM: cygnus: fix const declaration bcm_cygnus_dt_compat
  ARM: DRA7: hwmod: Fix the hwmod class for GPTimer4
  ARM: DRA7: hwmod: Add data for GPTimers 13 through 16
  ARM: EXYNOS: Remove left over 'extra_save'
  ARM: EXYNOS: Constify exynos_pm_data array
  ARM: EXYNOS: use static in suspend.c
  ARM: EXYNOS: Use platform device name as power domain name
  ARM: EXYNOS: add support for async-bridge clocks for pm_domains
  ARM: omap-device: add missed callback for suspend-to-disk
  ...

60 files changed:
Documentation/arm/Marvell/README
Documentation/devicetree/bindings/arm/al,alpine.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/amlogic.txt
Documentation/devicetree/bindings/arm/armada-39x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp [new file with mode: 0644]
Documentation/devicetree/bindings/arm/cpus.txt
Documentation/devicetree/bindings/arm/geniatech.txt [deleted file]
Documentation/devicetree/bindings/power/fsl,imx-gpc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.txt
MAINTAINERS
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/common/mcpm_entry.c
arch/arm/include/asm/mcpm.h
arch/arm/mach-alpine/Kconfig [new file with mode: 0644]
arch/arm/mach-alpine/Makefile [new file with mode: 0644]
arch/arm/mach-alpine/alpine_cpu_pm.c [new file with mode: 0644]
arch/arm/mach-alpine/alpine_cpu_pm.h [new file with mode: 0644]
arch/arm/mach-alpine/alpine_cpu_resume.h [new file with mode: 0644]
arch/arm/mach-alpine/alpine_machine.c [new file with mode: 0644]
arch/arm/mach-alpine/platsmp.c [new file with mode: 0644]
arch/arm/mach-bcm/bcm_cygnus.c
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/exynos.c
arch/arm/mach-exynos/firmware.c
arch/arm/mach-exynos/mcpm-exynos.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-exynos/regs-pmu.h
arch/arm/mach-exynos/smc.h
arch/arm/mach-exynos/suspend.c
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/gpc.c
arch/arm/mach-meson/Kconfig
arch/arm/mach-mvebu/Kconfig
arch/arm/mach-mvebu/board-v7.c
arch/arm/mach-mvebu/platsmp-a9.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/omap_hwmod_43xx_data.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/prcm43xx.h
arch/arm/mach-rockchip/platsmp.c
arch/arm/mach-rockchip/pm.c
arch/arm/mach-rockchip/pm.h
arch/arm/mach-s3c64xx/crag6410.h
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c [new file with mode: 0644]
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-vexpress/dcscb.c
arch/arm/mach-vexpress/tc2_pm.c
drivers/bus/imx-weim.c
include/dt-bindings/clock/imx6qdl-clock.h
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h

index 17453794fca5d518be980b1350784a9e3a11ecd2..18a775d101723be46320bbf475f04c066b4c3ea2 100644 (file)
@@ -96,6 +96,11 @@ EBU Armada family
        88F6820
        88F6828
 
+  Armada 390/398 Flavors:
+       88F6920
+       88F6928
+    Product infos: http://www.marvell.com/embedded-processors/armada-39x/
+
   Armada XP Flavors:
         MV78230
         MV78260
diff --git a/Documentation/devicetree/bindings/arm/al,alpine.txt b/Documentation/devicetree/bindings/arm/al,alpine.txt
new file mode 100644 (file)
index 0000000..f404a4f
--- /dev/null
@@ -0,0 +1,88 @@
+Annapurna Labs Alpine Platform Device Tree Bindings
+---------------------------------------------------------------
+
+Boards in the Alpine family shall have the following properties:
+
+* Required root node properties:
+compatible: must contain "al,alpine"
+
+* Example:
+
+/ {
+       model = "Annapurna Labs Alpine Dev Board";
+       compatible = "al,alpine";
+
+       ...
+}
+
+* CPU node:
+
+The Alpine platform includes cortex-a15 cores.
+enable-method: must be "al,alpine-smp" to allow smp  [1]
+
+Example:
+
+cpus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       enable-method = "al,alpine-smp";
+
+       cpu@0 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <0>;
+       };
+
+       cpu@1 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <1>;
+       };
+
+       cpu@2 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <2>;
+       };
+
+       cpu@3 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <3>;
+       };
+};
+
+
+* Alpine CPU resume registers
+
+The CPU resume register are used to define required resume address after
+reset.
+
+Properties:
+- compatible : Should contain "al,alpine-cpu-resume".
+- reg : Offset and length of the register set for the device
+
+Example:
+
+cpu_resume {
+       compatible = "al,alpine-cpu-resume";
+       reg = <0xfbff5ed0 0x30>;
+};
+
+* Alpine System-Fabric Service Registers
+
+The System-Fabric Service Registers allow various operation on CPU and
+system fabric, like powering CPUs off.
+
+Properties:
+- compatible : Should contain "al,alpine-sysfabric-service" and "syscon".
+- reg : Offset and length of the register set for the device
+
+Example:
+
+nb_service {
+        compatible = "al,alpine-sysfabric-service", "syscon";
+        reg = <0xfb070000 0x10000>;
+};
+
+[1] arm/cpu-enable-method/al,alpine-smp
index 8fe815046140becdbc594545d6677b8800b6a541..973884a1bacff8b9619b07f708367bf664fe7673 100644 (file)
@@ -8,3 +8,7 @@ Boards with the Amlogic Meson6 SoC shall have the following properties:
 Boards with the Amlogic Meson8 SoC shall have the following properties:
   Required root node property:
     compatible: "amlogic,meson8";
+
+Board compatible values:
+  - "geniatech,atv1200"
+  - "minix,neo-x8"
diff --git a/Documentation/devicetree/bindings/arm/armada-39x.txt b/Documentation/devicetree/bindings/arm/armada-39x.txt
new file mode 100644 (file)
index 0000000..53d4ff9
--- /dev/null
@@ -0,0 +1,20 @@
+Marvell Armada 39x Platforms Device Tree Bindings
+-------------------------------------------------
+
+Boards with a SoC of the Marvell Armada 39x family shall have the
+following property:
+
+Required root node property:
+
+ - compatible: must contain "marvell,armada390"
+
+In addition, boards using the Marvell Armada 398 SoC shall have the
+following property before the previous one:
+
+Required root node property:
+
+compatible: must contain "marvell,armada398"
+
+Example:
+
+compatible = "marvell,a398-db", "marvell,armada398", "marvell,armada390";
diff --git a/Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp b/Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp
new file mode 100644 (file)
index 0000000..c2e0cc5
--- /dev/null
@@ -0,0 +1,52 @@
+========================================================
+Secondary CPU enable-method "al,alpine-smp" binding
+========================================================
+
+This document describes the "al,alpine-smp" method for
+enabling secondary CPUs. To apply to all CPUs, a single
+"al,alpine-smp" enable method should be defined in the
+"cpus" node.
+
+Enable method name:    "al,alpine-smp"
+Compatible machines:   "al,alpine"
+Compatible CPUs:       "arm,cortex-a15"
+Related properties:    (none)
+
+Note:
+This enable method requires valid nodes compatible with
+"al,alpine-cpu-resume" and "al,alpine-nb-service"[1].
+
+Example:
+
+cpus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       enable-method = "al,alpine-smp";
+
+       cpu@0 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <0>;
+       };
+
+       cpu@1 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <1>;
+       };
+
+       cpu@2 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <2>;
+       };
+
+       cpu@3 {
+               compatible = "arm,cortex-a15";
+               device_type = "cpu";
+               reg = <3>;
+       };
+};
+
+--
+[1] arm/al,alpine.txt
index 8b9e0a95de317e5369932d612ac131be8ac0a641..6aa331d11c5e3e042ff2e0ec495d39e26fe0681c 100644 (file)
@@ -192,6 +192,7 @@ nodes to be present and contain the properties described below.
                            "brcm,brahma-b15"
                            "marvell,armada-375-smp"
                            "marvell,armada-380-smp"
+                           "marvell,armada-390-smp"
                            "marvell,armada-xp-smp"
                            "qcom,gcc-msm8660"
                            "qcom,kpss-acc-v1"
diff --git a/Documentation/devicetree/bindings/arm/geniatech.txt b/Documentation/devicetree/bindings/arm/geniatech.txt
deleted file mode 100644 (file)
index 74ccba4..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Geniatech platforms device tree bindings
--------------------------------------------
-
-Geniatech ATV1200
-    - compatible = "geniatech,atv1200"
diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
new file mode 100644 (file)
index 0000000..65cc034
--- /dev/null
@@ -0,0 +1,59 @@
+Freescale i.MX General Power Controller
+=======================================
+
+The i.MX6Q General Power Control (GPC) block contains DVFS load tracking
+counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power
+domains.
+
+Required properties:
+- compatible: Should be "fsl,imx6q-gpc" or "fsl,imx6sl-gpc"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain GPC interrupt request 1
+- pu-supply: Link to the LDO regulator powering the PU power domain
+- clocks: Clock phandles to devices in the PU power domain that need
+         to be enabled during domain power-up for reset propagation.
+- #power-domain-cells: Should be 1, see below:
+
+The gpc node is a power-controller as documented by the generic power domain
+bindings in Documentation/devicetree/bindings/power/power_domain.txt.
+
+Example:
+
+       gpc: gpc@020dc000 {
+               compatible = "fsl,imx6q-gpc";
+               reg = <0x020dc000 0x4000>;
+               interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 90 IRQ_TYPE_LEVEL_HIGH>;
+               pu-supply = <&reg_pu>;
+               clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>,
+                        <&clks IMX6QDL_CLK_GPU3D_SHADER>,
+                        <&clks IMX6QDL_CLK_GPU2D_CORE>,
+                        <&clks IMX6QDL_CLK_GPU2D_AXI>,
+                        <&clks IMX6QDL_CLK_OPENVG_AXI>,
+                        <&clks IMX6QDL_CLK_VPU_AXI>;
+               #power-domain-cells = <1>;
+       };
+
+
+Specifying power domain for IP modules
+======================================
+
+IP cores belonging to a power domain should contain a 'power-domains' property
+that is a phandle pointing to the gpc device node and a DOMAIN_INDEX specifying
+the power domain the device belongs to.
+
+Example of a device that is part of the PU power domain:
+
+       vpu: vpu@02040000 {
+               reg = <0x02040000 0x3c000>;
+               /* ... */
+               power-domains = <&gpc 1>;
+               /* ... */
+       };
+
+The following DOMAIN_INDEX values are valid for i.MX6Q:
+ARM_DOMAIN     0
+PU_DOMAIN      1
+The following additional DOMAIN_INDEX value is valid for i.MX6SL:
+DISPLAY_DOMAIN 2
index aecec35594eea8c613f8c9777586d5b2d0811219..54c1d5790358adcd4ee6daaa16c231d86e4db0ea 100644 (file)
@@ -11,6 +11,7 @@ adapteva      Adapteva, Inc.
 adh    AD Holdings Plc.
 adi    Analog Devices, Inc.
 aeroflexgaisler        Aeroflex Gaisler AB
+al     Annapurna Labs
 allwinner      Allwinner Technology Co., Ltd.
 alphascale     AlphaScale Integrated Circuits Systems, Inc.
 altr   Altera Corp.
@@ -118,6 +119,7 @@ merrii      Merrii Technology Co., Ltd.
 micrel Micrel Inc.
 microchip      Microchip Technology Inc.
 micron Micron Technology Inc.
+minix  MINIX Technology Ltd.
 mitsubishi     Mitsubishi Electric Corporation
 mosaixtech     Mosaix Technologies, Inc.
 moxa   Moxa
index 9988e1a14f5045c21892bc0eb355b2f781b05899..e85dbd350c0cf6784ea4ad1323f27ed82bfc6366 100644 (file)
@@ -886,6 +886,11 @@ S: Maintained
 F:     drivers/media/rc/meson-ir.c
 N:     meson[x68]
 
+ARM/Annapurna Labs ALPINE ARCHITECTURE
+M:     Tsahee Zidenberg <tsahee@annapurnalabs.com>
+S:     Maintained
+F:     arch/arm/mach-alpine/
+
 ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
 M:     Andrew Victor <linux@maxim.org.za>
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
index c8baa96ed748d251686dd1ec774e88e16b44c25e..d74c9ea6eb064f48afcde2e9b9768a2953a4e584 100644 (file)
@@ -839,6 +839,8 @@ config ARCH_VIRT
 #
 source "arch/arm/mach-mvebu/Kconfig"
 
+source "arch/arm/mach-alpine/Kconfig"
+
 source "arch/arm/mach-asm9260/Kconfig"
 
 source "arch/arm/mach-at91/Kconfig"
index 4cfb4b8fc2dde3bf206f29843d40b7ebe4524163..771d5185a3977750ab291d45ea668aabf91fcfd4 100644 (file)
@@ -93,6 +93,14 @@ choice
        prompt "Kernel low-level debugging port"
        depends on DEBUG_LL
 
+       config DEBUG_ALPINE_UART0
+               bool "Kernel low-level debugging messages via Alpine UART0"
+               depends on ARCH_ALPINE
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Alpine based platforms.
+
        config DEBUG_ASM9260_UART
                bool "Kernel low-level debugging via asm9260 UART"
                depends on MACH_ASM9260
@@ -1397,6 +1405,7 @@ config DEBUG_UART_PHYS
        default 0xf8b00000 if DEBUG_HIX5HD2_UART
        default 0xf991e000 if DEBUG_QCOM_UARTDM
        default 0xfcb00000 if DEBUG_HI3620_UART
+       default 0xfd883000 if DEBUG_ALPINE_UART0
        default 0xfe800000 if ARCH_IOP32X
        default 0xff690000 if DEBUG_RK32_UART2
        default 0xffc02000 if DEBUG_SOCFPGA_UART
@@ -1462,6 +1471,7 @@ config DEBUG_UART_VIRT
        default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
        default 0xfd000000 if ARCH_SPEAR13XX
        default 0xfd012000 if ARCH_MV78XX0
+       default 0xfd883000 if DEBUG_ALPINE_UART0
        default 0xfde12000 if ARCH_DOVE
        default 0xfe012000 if ARCH_ORION5X
        default 0xf31004c0 if DEBUG_MESON_UARTAO
@@ -1522,7 +1532,7 @@ config DEBUG_UART_8250_WORD
        depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
        depends on DEBUG_UART_8250_SHIFT >= 2
        default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART || \
-               ARCH_KEYSTONE || \
+               ARCH_KEYSTONE || DEBUG_ALPINE_UART0 || \
                DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
                DEBUG_DAVINCI_DA8XX_UART2 || \
                DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \
index cced41d40ce237947002e7220cef02d8341abadf..985227cbbd1bd797546c36099dcd7cc17c0efc4f 100644 (file)
@@ -142,6 +142,7 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
 
 # Machine directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
+machine-$(CONFIG_ARCH_ALPINE)          += alpine
 machine-$(CONFIG_ARCH_AT91)            += at91
 machine-$(CONFIG_ARCH_AXXIA)           += axxia
 machine-$(CONFIG_ARCH_BCM)             += bcm
index 0c3b6783b72add5d05001c35f39d1da6e55f141b..2a0f895c48d0fcc5026a6d50546f358cb4bb4dba 100644 (file)
        pinctrl-0 = <&iic3_pins>;
        status = "okay";
 
+       pmic@58 {
+               compatible = "dlg,da9063";
+               reg = <0x58>;
+               interrupt-parent = <&irqc0>;
+               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+
+               rtc {
+                       compatible = "dlg,da9063-rtc";
+               };
+
+               wdt {
+                       compatible = "dlg,da9063-watchdog";
+               };
+       };
+
        vdd_dvfs: regulator@68 {
                compatible = "dlg,da9210";
                reg = <0x68>;
+               interrupt-parent = <&irqc0>;
+               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 
                regulator-min-microvolt = <1000000>;
                regulator-max-microvolt = <1000000>;
index a3c27807f6c516e8c28b75642cb2df3c1a259e5e..b2dcf640d5835b7a1fd6e699b22ba2428c5771e2 100644 (file)
        status = "okay";
        clock-frequency = <100000>;
 
+       pmic@58 {
+               compatible = "dlg,da9063";
+               reg = <0x58>;
+               interrupt-parent = <&irqc0>;
+               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+
+               rtc {
+                       compatible = "dlg,da9063-rtc";
+               };
+
+               wdt {
+                       compatible = "dlg,da9063-watchdog";
+               };
+       };
+
        vdd_dvfs: regulator@68 {
                compatible = "dlg,da9210";
                reg = <0x68>;
+               interrupt-parent = <&irqc0>;
+               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 
                regulator-min-microvolt = <1000000>;
                regulator-max-microvolt = <1000000>;
index 3c165fc2dce284593de47902637e1f7068e8798b..5f8a52ac7edf2c74ba6ba2547df969a6acfdbd87 100644 (file)
@@ -55,22 +55,81 @@ bool mcpm_is_available(void)
        return (platform_ops) ? true : false;
 }
 
+/*
+ * We can't use regular spinlocks. In the switcher case, it is possible
+ * for an outbound CPU to call power_down() after its inbound counterpart
+ * is already live using the same logical CPU number which trips lockdep
+ * debugging.
+ */
+static arch_spinlock_t mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+static int mcpm_cpu_use_count[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER];
+
+static inline bool mcpm_cluster_unused(unsigned int cluster)
+{
+       int i, cnt;
+       for (i = 0, cnt = 0; i < MAX_CPUS_PER_CLUSTER; i++)
+               cnt |= mcpm_cpu_use_count[cluster][i];
+       return !cnt;
+}
+
 int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster)
 {
+       bool cpu_is_down, cluster_is_down;
+       int ret = 0;
+
        if (!platform_ops)
                return -EUNATCH; /* try not to shadow power_up errors */
        might_sleep();
-       return platform_ops->power_up(cpu, cluster);
+
+       /* backward compatibility callback */
+       if (platform_ops->power_up)
+               return platform_ops->power_up(cpu, cluster);
+
+       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+
+       /*
+        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
+        * variant exists, we need to disable IRQs manually here.
+        */
+       local_irq_disable();
+       arch_spin_lock(&mcpm_lock);
+
+       cpu_is_down = !mcpm_cpu_use_count[cluster][cpu];
+       cluster_is_down = mcpm_cluster_unused(cluster);
+
+       mcpm_cpu_use_count[cluster][cpu]++;
+       /*
+        * The only possible values are:
+        * 0 = CPU down
+        * 1 = CPU (still) up
+        * 2 = CPU requested to be up before it had a chance
+        *     to actually make itself down.
+        * Any other value is a bug.
+        */
+       BUG_ON(mcpm_cpu_use_count[cluster][cpu] != 1 &&
+              mcpm_cpu_use_count[cluster][cpu] != 2);
+
+       if (cluster_is_down)
+               ret = platform_ops->cluster_powerup(cluster);
+       if (cpu_is_down && !ret)
+               ret = platform_ops->cpu_powerup(cpu, cluster);
+
+       arch_spin_unlock(&mcpm_lock);
+       local_irq_enable();
+       return ret;
 }
 
 typedef void (*phys_reset_t)(unsigned long);
 
 void mcpm_cpu_power_down(void)
 {
+       unsigned int mpidr, cpu, cluster;
+       bool cpu_going_down, last_man;
        phys_reset_t phys_reset;
 
-       if (WARN_ON_ONCE(!platform_ops || !platform_ops->power_down))
-               return;
+       if (WARN_ON_ONCE(!platform_ops))
+              return;
        BUG_ON(!irqs_disabled());
 
        /*
@@ -79,28 +138,65 @@ void mcpm_cpu_power_down(void)
         */
        setup_mm_for_reboot();
 
-       platform_ops->power_down();
+       /* backward compatibility callback */
+       if (platform_ops->power_down) {
+               platform_ops->power_down();
+               goto not_dead;
+       }
+
+       mpidr = read_cpuid_mpidr();
+       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+
+       __mcpm_cpu_going_down(cpu, cluster);
 
+       arch_spin_lock(&mcpm_lock);
+       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+
+       mcpm_cpu_use_count[cluster][cpu]--;
+       BUG_ON(mcpm_cpu_use_count[cluster][cpu] != 0 &&
+              mcpm_cpu_use_count[cluster][cpu] != 1);
+       cpu_going_down = !mcpm_cpu_use_count[cluster][cpu];
+       last_man = mcpm_cluster_unused(cluster);
+
+       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
+               platform_ops->cpu_powerdown_prepare(cpu, cluster);
+               platform_ops->cluster_powerdown_prepare(cluster);
+               arch_spin_unlock(&mcpm_lock);
+               platform_ops->cluster_cache_disable();
+               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
+       } else {
+               if (cpu_going_down)
+                       platform_ops->cpu_powerdown_prepare(cpu, cluster);
+               arch_spin_unlock(&mcpm_lock);
+               /*
+                * If cpu_going_down is false here, that means a power_up
+                * request raced ahead of us.  Even if we do not want to
+                * shut this CPU down, the caller still expects execution
+                * to return through the system resume entry path, like
+                * when the WFI is aborted due to a new IRQ or the like..
+                * So let's continue with cache cleaning in all cases.
+                */
+               platform_ops->cpu_cache_disable();
+       }
+
+       __mcpm_cpu_down(cpu, cluster);
+
+       /* Now we are prepared for power-down, do it: */
+       if (cpu_going_down)
+               wfi();
+
+not_dead:
        /*
         * It is possible for a power_up request to happen concurrently
         * with a power_down request for the same CPU. In this case the
-        * power_down method might not be able to actually enter a
-        * powered down state with the WFI instruction if the power_up
-        * method has removed the required reset condition.  The
-        * power_down method is then allowed to return. We must perform
-        * a re-entry in the kernel as if the power_up method just had
-        * deasserted reset on the CPU.
-        *
-        * To simplify race issues, the platform specific implementation
-        * must accommodate for the possibility of unordered calls to
-        * power_down and power_up with a usage count. Therefore, if a
-        * call to power_up is issued for a CPU that is not down, then
-        * the next call to power_down must not attempt a full shutdown
-        * but only do the minimum (normally disabling L1 cache and CPU
-        * coherency) and return just as if a concurrent power_up request
-        * had happened as described above.
+        * CPU might not be able to actually enter a powered down state
+        * with the WFI instruction if the power_up request has removed
+        * the required reset condition.  We must perform a re-entry in
+        * the kernel as if the power_up method just had deasserted reset
+        * on the CPU.
         */
-
        phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
        phys_reset(virt_to_phys(mcpm_entry_point));
 
@@ -125,26 +221,66 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster)
 
 void mcpm_cpu_suspend(u64 expected_residency)
 {
-       phys_reset_t phys_reset;
-
-       if (WARN_ON_ONCE(!platform_ops || !platform_ops->suspend))
+       if (WARN_ON_ONCE(!platform_ops))
                return;
-       BUG_ON(!irqs_disabled());
 
-       /* Very similar to mcpm_cpu_power_down() */
-       setup_mm_for_reboot();
-       platform_ops->suspend(expected_residency);
-       phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
-       phys_reset(virt_to_phys(mcpm_entry_point));
-       BUG();
+       /* backward compatibility callback */
+       if (platform_ops->suspend) {
+               phys_reset_t phys_reset;
+               BUG_ON(!irqs_disabled());
+               setup_mm_for_reboot();
+               platform_ops->suspend(expected_residency);
+               phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+               phys_reset(virt_to_phys(mcpm_entry_point));
+               BUG();
+       }
+
+       /* Some platforms might have to enable special resume modes, etc. */
+       if (platform_ops->cpu_suspend_prepare) {
+               unsigned int mpidr = read_cpuid_mpidr();
+               unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+               unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); 
+               arch_spin_lock(&mcpm_lock);
+               platform_ops->cpu_suspend_prepare(cpu, cluster);
+               arch_spin_unlock(&mcpm_lock);
+       }
+       mcpm_cpu_power_down();
 }
 
 int mcpm_cpu_powered_up(void)
 {
+       unsigned int mpidr, cpu, cluster;
+       bool cpu_was_down, first_man;
+       unsigned long flags;
+
        if (!platform_ops)
                return -EUNATCH;
-       if (platform_ops->powered_up)
+
+       /* backward compatibility callback */
+       if (platform_ops->powered_up) {
                platform_ops->powered_up();
+               return 0;
+       }
+
+       mpidr = read_cpuid_mpidr();
+       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+       local_irq_save(flags);
+       arch_spin_lock(&mcpm_lock);
+
+       cpu_was_down = !mcpm_cpu_use_count[cluster][cpu];
+       first_man = mcpm_cluster_unused(cluster);
+
+       if (first_man && platform_ops->cluster_is_up)
+               platform_ops->cluster_is_up(cluster);
+       if (cpu_was_down)
+               mcpm_cpu_use_count[cluster][cpu] = 1;
+       if (platform_ops->cpu_is_up)
+               platform_ops->cpu_is_up(cpu, cluster);
+
+       arch_spin_unlock(&mcpm_lock);
+       local_irq_restore(flags);
+
        return 0;
 }
 
@@ -334,8 +470,10 @@ int __init mcpm_sync_init(
        }
        mpidr = read_cpuid_mpidr();
        this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-       for_each_online_cpu(i)
+       for_each_online_cpu(i) {
+               mcpm_cpu_use_count[this_cluster][i] = 1;
                mcpm_sync.clusters[this_cluster].cpus[i].cpu = CPU_UP;
+       }
        mcpm_sync.clusters[this_cluster].cluster = CLUSTER_UP;
        sync_cache_w(&mcpm_sync);
 
index 3446f6a1d9fa6c982dbfc511aa34da8c8803da9e..50b378f59e086c45331a594060b1bafc3d627d48 100644 (file)
@@ -171,12 +171,73 @@ void mcpm_cpu_suspend(u64 expected_residency);
 int mcpm_cpu_powered_up(void);
 
 /*
- * Platform specific methods used in the implementation of the above API.
+ * Platform specific callbacks used in the implementation of the above API.
+ *
+ * cpu_powerup:
+ * Make given CPU runable. Called with MCPM lock held and IRQs disabled.
+ * The given cluster is assumed to be set up (cluster_powerup would have
+ * been called beforehand). Must return 0 for success or negative error code.
+ *
+ * cluster_powerup:
+ * Set up power for given cluster. Called with MCPM lock held and IRQs
+ * disabled. Called before first cpu_powerup when cluster is down. Must
+ * return 0 for success or negative error code.
+ *
+ * cpu_suspend_prepare:
+ * Special suspend configuration. Called on target CPU with MCPM lock held
+ * and IRQs disabled. This callback is optional. If provided, it is called
+ * before cpu_powerdown_prepare.
+ *
+ * cpu_powerdown_prepare:
+ * Configure given CPU for power down. Called on target CPU with MCPM lock
+ * held and IRQs disabled. Power down must be effective only at the next WFI instruction.
+ *
+ * cluster_powerdown_prepare:
+ * Configure given cluster for power down. Called on one CPU from target
+ * cluster with MCPM lock held and IRQs disabled. A cpu_powerdown_prepare
+ * for each CPU in the cluster has happened when this occurs.
+ *
+ * cpu_cache_disable:
+ * Clean and disable CPU level cache for the calling CPU. Called on with IRQs
+ * disabled only. The CPU is no longer cache coherent with the rest of the
+ * system when this returns.
+ *
+ * cluster_cache_disable:
+ * Clean and disable the cluster wide cache as well as the CPU level cache
+ * for the calling CPU. No call to cpu_cache_disable will happen for this
+ * CPU. Called with IRQs disabled and only when all the other CPUs are done
+ * with their own cpu_cache_disable. The cluster is no longer cache coherent
+ * with the rest of the system when this returns.
+ *
+ * cpu_is_up:
+ * Called on given CPU after it has been powered up or resumed. The MCPM lock
+ * is held and IRQs disabled. This callback is optional.
+ *
+ * cluster_is_up:
+ * Called by the first CPU to be powered up or resumed in given cluster.
+ * The MCPM lock is held and IRQs disabled. This callback is optional. If
+ * provided, it is called before cpu_is_up for that CPU.
+ *
+ * wait_for_powerdown:
+ * Wait until given CPU is powered down. This is called in sleeping context.
+ * Some reasonable timeout must be considered. Must return 0 for success or
+ * negative error code.
  */
 struct mcpm_platform_ops {
+       int (*cpu_powerup)(unsigned int cpu, unsigned int cluster);
+       int (*cluster_powerup)(unsigned int cluster);
+       void (*cpu_suspend_prepare)(unsigned int cpu, unsigned int cluster);
+       void (*cpu_powerdown_prepare)(unsigned int cpu, unsigned int cluster);
+       void (*cluster_powerdown_prepare)(unsigned int cluster);
+       void (*cpu_cache_disable)(void);
+       void (*cluster_cache_disable)(void);
+       void (*cpu_is_up)(unsigned int cpu, unsigned int cluster);
+       void (*cluster_is_up)(unsigned int cluster);
+       int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster);
+
+       /* deprecated callbacks */
        int (*power_up)(unsigned int cpu, unsigned int cluster);
        void (*power_down)(void);
-       int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster);
        void (*suspend)(u64);
        void (*powered_up)(void);
 };
diff --git a/arch/arm/mach-alpine/Kconfig b/arch/arm/mach-alpine/Kconfig
new file mode 100644 (file)
index 0000000..2c44b93
--- /dev/null
@@ -0,0 +1,12 @@
+config ARCH_ALPINE
+       bool "Annapurna Labs Alpine platform" if ARCH_MULTI_V7
+       select ARM_AMBA
+       select ARM_GIC
+       select GENERIC_IRQ_CHIP
+       select HAVE_ARM_ARCH_TIMER
+       select HAVE_SMP
+       select MFD_SYSCON
+       select PCI
+       select PCI_HOST_GENERIC
+       help
+         This enables support for the Annapurna Labs Alpine V1 boards.
diff --git a/arch/arm/mach-alpine/Makefile b/arch/arm/mach-alpine/Makefile
new file mode 100644 (file)
index 0000000..b667489
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y                          += alpine_machine.o
+obj-$(CONFIG_SMP)              += platsmp.o alpine_cpu_pm.o
diff --git a/arch/arm/mach-alpine/alpine_cpu_pm.c b/arch/arm/mach-alpine/alpine_cpu_pm.c
new file mode 100644 (file)
index 0000000..121c77c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Low-level power-management support for Alpine platform.
+ *
+ * Copyright (C) 2015 Annapurna Labs Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "alpine_cpu_pm.h"
+#include "alpine_cpu_resume.h"
+
+/* NB registers */
+#define AL_SYSFAB_POWER_CONTROL(cpu)   (0x2000 + (cpu)*0x100 + 0x20)
+
+static struct regmap *al_sysfabric;
+static struct al_cpu_resume_regs __iomem *al_cpu_resume_regs;
+static int wakeup_supported;
+
+int alpine_cpu_wakeup(unsigned int phys_cpu, uint32_t phys_resume_addr)
+{
+       if (!wakeup_supported)
+               return -ENOSYS;
+
+       /*
+        * Set CPU resume address -
+        * secure firmware running on boot will jump to this address
+        * after setting proper CPU mode, and initialiing e.g. secure
+        * regs (the same mode all CPUs are booted to - usually HYP)
+        */
+       writel(phys_resume_addr,
+              &al_cpu_resume_regs->per_cpu[phys_cpu].resume_addr);
+
+       /* Power-up the CPU */
+       regmap_write(al_sysfabric, AL_SYSFAB_POWER_CONTROL(phys_cpu), 0);
+
+       return 0;
+}
+
+void __init alpine_cpu_pm_init(void)
+{
+       struct device_node *np;
+       uint32_t watermark;
+
+       al_sysfabric = syscon_regmap_lookup_by_compatible("al,alpine-sysfabric-service");
+
+       np = of_find_compatible_node(NULL, NULL, "al,alpine-cpu-resume");
+       al_cpu_resume_regs = of_iomap(np, 0);
+
+       wakeup_supported = !IS_ERR(al_sysfabric) && al_cpu_resume_regs;
+
+       if (wakeup_supported) {
+               watermark = readl(&al_cpu_resume_regs->watermark);
+               wakeup_supported = (watermark & AL_CPU_RESUME_MAGIC_NUM_MASK)
+                                   == AL_CPU_RESUME_MAGIC_NUM;
+       }
+}
diff --git a/arch/arm/mach-alpine/alpine_cpu_pm.h b/arch/arm/mach-alpine/alpine_cpu_pm.h
new file mode 100644 (file)
index 0000000..5179e69
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Low-level power-management support for Alpine platform.
+ *
+ * Copyright (C) 2015 Annapurna Labs Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ALPINE_CPU_PM_H__
+#define __ALPINE_CPU_PM_H__
+
+/* Alpine CPU Power Management Services Initialization */
+void alpine_cpu_pm_init(void);
+
+/* Wake-up a CPU */
+int alpine_cpu_wakeup(unsigned int phys_cpu, uint32_t phys_resume_addr);
+
+#endif /* __ALPINE_CPU_PM_H__ */
diff --git a/arch/arm/mach-alpine/alpine_cpu_resume.h b/arch/arm/mach-alpine/alpine_cpu_resume.h
new file mode 100644 (file)
index 0000000..c80150c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Annapurna labs cpu-resume register structure.
+ *
+ * Copyright (C) 2015 Annapurna Labs Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ALPINE_CPU_RESUME_H_
+#define ALPINE_CPU_RESUME_H_
+
+/* Per-cpu regs */
+struct al_cpu_resume_regs_per_cpu {
+       uint32_t        flags;
+       uint32_t        resume_addr;
+};
+
+/* general regs */
+struct al_cpu_resume_regs {
+       /* Watermark for validating the CPU resume struct */
+       uint32_t watermark;
+       uint32_t flags;
+       struct al_cpu_resume_regs_per_cpu per_cpu[];
+};
+
+/* The expected magic number for validating the resume addresses */
+#define AL_CPU_RESUME_MAGIC_NUM                0xf0e1d200
+#define AL_CPU_RESUME_MAGIC_NUM_MASK   0xffffff00
+
+#endif /* ALPINE_CPU_RESUME_H_ */
diff --git a/arch/arm/mach-alpine/alpine_machine.c b/arch/arm/mach-alpine/alpine_machine.c
new file mode 100644 (file)
index 0000000..b8e2145
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Machine declaration for Alpine platforms.
+ *
+ * Copyright (C) 2015 Annapurna Labs Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_platform.h>
+
+#include <asm/mach/arch.h>
+
+static const char * const al_match[] __initconst = {
+       "al,alpine",
+       NULL,
+};
+
+DT_MACHINE_START(AL_DT, "Annapurna Labs Alpine")
+       .dt_compat      = al_match,
+MACHINE_END
diff --git a/arch/arm/mach-alpine/platsmp.c b/arch/arm/mach-alpine/platsmp.c
new file mode 100644 (file)
index 0000000..f78429f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SMP operations for Alpine platform.
+ *
+ * Copyright (C) 2015 Annapurna Labs Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/smp_plat.h>
+
+#include "alpine_cpu_pm.h"
+
+static int alpine_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       phys_addr_t addr;
+
+       addr = virt_to_phys(secondary_startup);
+
+       if (addr > (phys_addr_t)(uint32_t)(-1)) {
+               pr_err("FAIL: resume address over 32bit (%pa)", &addr);
+               return -EINVAL;
+       }
+
+       return alpine_cpu_wakeup(cpu_logical_map(cpu), (uint32_t)addr);
+}
+
+static void __init alpine_smp_prepare_cpus(unsigned int max_cpus)
+{
+       alpine_cpu_pm_init();
+}
+
+static struct smp_operations alpine_smp_ops __initdata = {
+       .smp_prepare_cpus       = alpine_smp_prepare_cpus,
+       .smp_boot_secondary     = alpine_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(alpine_smp, "al,alpine-smp", &alpine_smp_ops);
index 30dc58be51b8e70f49074ee47523e534d6676337..7ae894c7849b7cde3bc61b952868652b0fc29c22 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <asm/mach/arch.h>
 
-static const char const *bcm_cygnus_dt_compat[] = {
+static const char * const bcm_cygnus_dt_compat[] __initconst = {
        "brcm,cygnus",
        NULL,
 };
index f70eca7ee705fd26490d3ce7bbdc1988cbdf8752..acd5b560b72801c6e2e4b51baa5ca4c129f44b2d 100644 (file)
@@ -126,6 +126,12 @@ enum {
 
 void exynos_firmware_init(void);
 
+/* CPU BOOT mode flag for Exynos3250 SoC bootloader */
+#define C2_STATE       (1 << 3)
+
+void exynos_set_boot_flag(unsigned int cpu, unsigned int mode);
+void exynos_clear_boot_flag(unsigned int cpu, unsigned int mode);
+
 extern u32 exynos_get_eint_wake_mask(void);
 
 #ifdef CONFIG_PM_SLEEP
index 8576a9f734bd9aaf9dac0b83dd7e6744efcf86d2..bcde0dd668df950f1918a66179715a56ec9578fa 100644 (file)
@@ -214,6 +214,7 @@ static void __init exynos_dt_machine_init(void)
            of_machine_is_compatible("samsung,exynos4212") ||
            (of_machine_is_compatible("samsung,exynos4412") &&
             of_machine_is_compatible("samsung,trats2")) ||
+           of_machine_is_compatible("samsung,exynos3250") ||
            of_machine_is_compatible("samsung,exynos5250"))
                platform_device_register(&exynos_cpuidle);
 
index 4791a3cc00f9d40e71c474d6130c02697ebcd090..1bd35763f12ec04d712ace47f0f88bd2f9c95c89 100644 (file)
@@ -48,7 +48,13 @@ static int exynos_do_idle(unsigned long mode)
                __raw_writel(virt_to_phys(exynos_cpu_resume_ns),
                             sysram_ns_base_addr + 0x24);
                __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20);
-               exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0);
+               if (soc_is_exynos3250()) {
+                       exynos_smc(SMC_CMD_SAVE, OP_TYPE_CORE,
+                                  SMC_POWERSTATE_IDLE, 0);
+                       exynos_smc(SMC_CMD_SHUTDOWN, OP_TYPE_CLUSTER,
+                                  SMC_POWERSTATE_IDLE, 0);
+               } else
+                       exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0);
                break;
        case FW_DO_IDLE_SLEEP:
                exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
@@ -206,3 +212,28 @@ void __init exynos_firmware_init(void)
                outer_cache.configure = exynos_l2_configure;
        }
 }
+
+#define REG_CPU_STATE_ADDR     (sysram_ns_base_addr + 0x28)
+#define BOOT_MODE_MASK         0x1f
+
+void exynos_set_boot_flag(unsigned int cpu, unsigned int mode)
+{
+       unsigned int tmp;
+
+       tmp = __raw_readl(REG_CPU_STATE_ADDR + cpu * 4);
+
+       if (mode & BOOT_MODE_MASK)
+               tmp &= ~BOOT_MODE_MASK;
+
+       tmp |= mode;
+       __raw_writel(tmp, REG_CPU_STATE_ADDR + cpu * 4);
+}
+
+void exynos_clear_boot_flag(unsigned int cpu, unsigned int mode)
+{
+       unsigned int tmp;
+
+       tmp = __raw_readl(REG_CPU_STATE_ADDR + cpu * 4);
+       tmp &= ~mode;
+       __raw_writel(tmp, REG_CPU_STATE_ADDR + cpu * 4);
+}
index b0d3c2e876fbe9227d651b8c2bcc86de22fc0fc7..9bdf54795f05de26283881729a4427bd781ea2eb 100644 (file)
@@ -61,25 +61,7 @@ static void __iomem *ns_sram_base_addr;
        : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
          "r9", "r10", "lr", "memory")
 
-/*
- * We can't use regular spinlocks. In the switcher case, it is possible
- * for an outbound CPU to call power_down() after its inbound counterpart
- * is already live using the same logical CPU number which trips lockdep
- * debugging.
- */
-static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
-static int
-cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
-
-#define exynos_cluster_usecnt(cluster) \
-       (cpu_use_count[0][cluster] +   \
-        cpu_use_count[1][cluster] +   \
-        cpu_use_count[2][cluster] +   \
-        cpu_use_count[3][cluster])
-
-#define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster)
-
-static int exynos_power_up(unsigned int cpu, unsigned int cluster)
+static int exynos_cpu_powerup(unsigned int cpu, unsigned int cluster)
 {
        unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
 
@@ -88,127 +70,65 @@ static int exynos_power_up(unsigned int cpu, unsigned int cluster)
                cluster >= EXYNOS5420_NR_CLUSTERS)
                return -EINVAL;
 
-       /*
-        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
-        * variant exists, we need to disable IRQs manually here.
-        */
-       local_irq_disable();
-       arch_spin_lock(&exynos_mcpm_lock);
-
-       cpu_use_count[cpu][cluster]++;
-       if (cpu_use_count[cpu][cluster] == 1) {
-               bool was_cluster_down =
-                       (exynos_cluster_usecnt(cluster) == 1);
-
-               /*
-                * Turn on the cluster (L2/COMMON) and then power on the
-                * cores.
-                */
-               if (was_cluster_down)
-                       exynos_cluster_power_up(cluster);
-
-               exynos_cpu_power_up(cpunr);
-       } else if (cpu_use_count[cpu][cluster] != 2) {
-               /*
-                * The only possible values are:
-                * 0 = CPU down
-                * 1 = CPU (still) up
-                * 2 = CPU requested to be up before it had a chance
-                *     to actually make itself down.
-                * Any other value is a bug.
-                */
-               BUG();
-       }
+       exynos_cpu_power_up(cpunr);
+       return 0;
+}
 
-       arch_spin_unlock(&exynos_mcpm_lock);
-       local_irq_enable();
+static int exynos_cluster_powerup(unsigned int cluster)
+{
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       if (cluster >= EXYNOS5420_NR_CLUSTERS)
+               return -EINVAL;
 
+       exynos_cluster_power_up(cluster);
        return 0;
 }
 
-/*
- * NOTE: This function requires the stack data to be visible through power down
- * and can only be executed on processors like A15 and A7 that hit the cache
- * with the C bit clear in the SCTLR register.
- */
-static void exynos_power_down(void)
+static void exynos_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster)
 {
-       unsigned int mpidr, cpu, cluster;
-       bool last_man = false, skip_wfi = false;
-       unsigned int cpunr;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-       cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
 
        pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
        BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
                        cluster >= EXYNOS5420_NR_CLUSTERS);
+       exynos_cpu_power_down(cpunr);
+}
 
-       __mcpm_cpu_going_down(cpu, cluster);
-
-       arch_spin_lock(&exynos_mcpm_lock);
-       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
-       cpu_use_count[cpu][cluster]--;
-       if (cpu_use_count[cpu][cluster] == 0) {
-               exynos_cpu_power_down(cpunr);
-
-               if (exynos_cluster_unused(cluster)) {
-                       exynos_cluster_power_down(cluster);
-                       last_man = true;
-               }
-       } else if (cpu_use_count[cpu][cluster] == 1) {
-               /*
-                * A power_up request went ahead of us.
-                * Even if we do not want to shut this CPU down,
-                * the caller expects a certain state as if the WFI
-                * was aborted.  So let's continue with cache cleaning.
-                */
-               skip_wfi = true;
-       } else {
-               BUG();
-       }
-
-       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
-               arch_spin_unlock(&exynos_mcpm_lock);
-
-               if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
-                       /*
-                        * On the Cortex-A15 we need to disable
-                        * L2 prefetching before flushing the cache.
-                        */
-                       asm volatile(
-                       "mcr    p15, 1, %0, c15, c0, 3\n\t"
-                       "isb\n\t"
-                       "dsb"
-                       : : "r" (0x400));
-               }
+static void exynos_cluster_powerdown_prepare(unsigned int cluster)
+{
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       BUG_ON(cluster >= EXYNOS5420_NR_CLUSTERS);
+       exynos_cluster_power_down(cluster);
+}
 
-               /* Flush all cache levels for this cluster. */
-               exynos_v7_exit_coherency_flush(all);
+static void exynos_cpu_cache_disable(void)
+{
+       /* Disable and flush the local CPU cache. */
+       exynos_v7_exit_coherency_flush(louis);
+}
 
+static void exynos_cluster_cache_disable(void)
+{
+       if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
                /*
-                * Disable cluster-level coherency by masking
-                * incoming snoops and DVM messages:
+                * On the Cortex-A15 we need to disable
+                * L2 prefetching before flushing the cache.
                 */
-               cci_disable_port_by_cpu(mpidr);
-
-               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
-       } else {
-               arch_spin_unlock(&exynos_mcpm_lock);
-
-               /* Disable and flush the local CPU cache. */
-               exynos_v7_exit_coherency_flush(louis);
+               asm volatile(
+               "mcr    p15, 1, %0, c15, c0, 3\n\t"
+               "isb\n\t"
+               "dsb"
+               : : "r" (0x400));
        }
 
-       __mcpm_cpu_down(cpu, cluster);
-
-       /* Now we are prepared for power-down, do it: */
-       if (!skip_wfi)
-               wfi();
+       /* Flush all cache levels for this cluster. */
+       exynos_v7_exit_coherency_flush(all);
 
-       /* Not dead at this point?  Let our caller cope. */
+       /*
+        * Disable cluster-level coherency by masking
+        * incoming snoops and DVM messages:
+        */
+       cci_disable_port_by_cpu(read_cpuid_mpidr());
 }
 
 static int exynos_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
@@ -222,10 +142,8 @@ static int exynos_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
 
        /* Wait for the core state to be OFF */
        while (tries--) {
-               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
-                       if ((exynos_cpu_power_state(cpunr) == 0))
-                               return 0; /* success: the CPU is halted */
-               }
+               if ((exynos_cpu_power_state(cpunr) == 0))
+                       return 0; /* success: the CPU is halted */
 
                /* Otherwise, wait and retry: */
                msleep(1);
@@ -234,63 +152,23 @@ static int exynos_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
        return -ETIMEDOUT; /* timeout */
 }
 
-static void exynos_powered_up(void)
-{
-       unsigned int mpidr, cpu, cluster;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-
-       arch_spin_lock(&exynos_mcpm_lock);
-       if (cpu_use_count[cpu][cluster] == 0)
-               cpu_use_count[cpu][cluster] = 1;
-       arch_spin_unlock(&exynos_mcpm_lock);
-}
-
-static void exynos_suspend(u64 residency)
+static void exynos_cpu_is_up(unsigned int cpu, unsigned int cluster)
 {
-       unsigned int mpidr, cpunr;
-
-       exynos_power_down();
-
-       /*
-        * Execution reaches here only if cpu did not power down.
-        * Hence roll back the changes done in exynos_power_down function.
-        *
-        * CAUTION: "This function requires the stack data to be visible through
-        * power down and can only be executed on processors like A15 and A7
-        * that hit the cache with the C bit clear in the SCTLR register."
-       */
-       mpidr = read_cpuid_mpidr();
-       cpunr = exynos_pmu_cpunr(mpidr);
-
-       exynos_cpu_power_up(cpunr);
+       /* especially when resuming: make sure power control is set */
+       exynos_cpu_powerup(cpu, cluster);
 }
 
 static const struct mcpm_platform_ops exynos_power_ops = {
-       .power_up               = exynos_power_up,
-       .power_down             = exynos_power_down,
+       .cpu_powerup            = exynos_cpu_powerup,
+       .cluster_powerup        = exynos_cluster_powerup,
+       .cpu_powerdown_prepare  = exynos_cpu_powerdown_prepare,
+       .cluster_powerdown_prepare = exynos_cluster_powerdown_prepare,
+       .cpu_cache_disable      = exynos_cpu_cache_disable,
+       .cluster_cache_disable  = exynos_cluster_cache_disable,
        .wait_for_powerdown     = exynos_wait_for_powerdown,
-       .suspend                = exynos_suspend,
-       .powered_up             = exynos_powered_up,
+       .cpu_is_up              = exynos_cpu_is_up,
 };
 
-static void __init exynos_mcpm_usage_count_init(void)
-{
-       unsigned int mpidr, cpu, cluster;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-
-       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
-                       cluster >= EXYNOS5420_NR_CLUSTERS);
-
-       cpu_use_count[cpu][cluster] = 1;
-}
-
 /*
  * Enable cluster-level coherency, in preparation for turning on the MMU.
  */
@@ -302,19 +180,6 @@ static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
        "b      cci_enable_port_for_self");
 }
 
-static void __init exynos_cache_off(void)
-{
-       if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
-               /* disable L2 prefetching on the Cortex-A15 */
-               asm volatile(
-               "mcr    p15, 1, %0, c15, c0, 3\n\t"
-               "isb\n\t"
-               "dsb"
-               : : "r" (0x400));
-       }
-       exynos_v7_exit_coherency_flush(all);
-}
-
 static const struct of_device_id exynos_dt_mcpm_match[] = {
        { .compatible = "samsung,exynos5420" },
        { .compatible = "samsung,exynos5800" },
@@ -370,13 +235,11 @@ static int __init exynos_mcpm_init(void)
         */
        pmu_raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
 
-       exynos_mcpm_usage_count_init();
-
        ret = mcpm_platform_register(&exynos_power_ops);
        if (!ret)
                ret = mcpm_sync_init(exynos_pm_power_up_setup);
        if (!ret)
-               ret = mcpm_loopback(exynos_cache_off); /* turn on the CCI */
+               ret = mcpm_loopback(exynos_cluster_cache_disable); /* turn on the CCI */
        if (ret) {
                iounmap(ns_sram_base_addr);
                return ret;
index d2e9f12d12f187e1e2c40f11748f75bbe0a283f2..ebd135bb0995611517c1bce6d3b70deeeee37de4 100644 (file)
@@ -126,6 +126,8 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
  */
 void exynos_cpu_power_down(int cpu)
 {
+       u32 core_conf;
+
        if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) {
                /*
                 * Bypass power down for CPU0 during suspend. Check for
@@ -137,7 +139,10 @@ void exynos_cpu_power_down(int cpu)
                if (!(val & S5P_CORE_LOCAL_PWR_EN))
                        return;
        }
-       pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+
+       core_conf = pmu_raw_readl(EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+       core_conf &= ~S5P_CORE_LOCAL_PWR_EN;
+       pmu_raw_writel(core_conf, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
 }
 
 /**
@@ -148,7 +153,12 @@ void exynos_cpu_power_down(int cpu)
  */
 void exynos_cpu_power_up(int cpu)
 {
-       pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN,
+       u32 core_conf = S5P_CORE_LOCAL_PWR_EN;
+
+       if (soc_is_exynos3250())
+               core_conf |= S5P_CORE_AUTOWAKEUP_EN;
+
+       pmu_raw_writel(core_conf,
                        EXYNOS_ARM_CORE_CONFIGURATION(cpu));
 }
 
@@ -226,6 +236,10 @@ static void exynos_core_restart(u32 core_id)
        if (!of_machine_is_compatible("samsung,exynos3250"))
                return;
 
+       while (!pmu_raw_readl(S5P_PMU_SPARE2))
+               udelay(10);
+       udelay(10);
+
        val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id));
        val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG;
        pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id));
@@ -346,7 +360,10 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 
                call_firmware_op(cpu_boot, core_id);
 
-               arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+               if (soc_is_exynos3250())
+                       dsb_sev();
+               else
+                       arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 
                if (pen_release == -1)
                        break;
index 5685250693fdf8b5b547674ae845e06c8d6130fe..cc75ab448be3b4ce9b3c0fc2e626da4ed3d6e6ca 100644 (file)
@@ -127,6 +127,8 @@ int exynos_pm_central_resume(void)
 static void exynos_set_wakeupmask(long mask)
 {
        pmu_raw_writel(mask, S5P_WAKEUP_MASK);
+       if (soc_is_exynos3250())
+               pmu_raw_writel(0x0, S5P_WAKEUP_MASK2);
 }
 
 static void exynos_cpu_set_boot_vector(long flags)
@@ -140,7 +142,7 @@ static int exynos_aftr_finisher(unsigned long flags)
 {
        int ret;
 
-       exynos_set_wakeupmask(0x0000ff3e);
+       exynos_set_wakeupmask(soc_is_exynos3250() ? 0x40003ffe : 0x0000ff3e);
        /* Set value of power down register for aftr mode */
        exynos_sys_powerdown_conf(SYS_AFTR);
 
@@ -157,8 +159,13 @@ static int exynos_aftr_finisher(unsigned long flags)
 
 void exynos_enter_aftr(void)
 {
+       unsigned int cpuid = smp_processor_id();
+
        cpu_pm_enter();
 
+       if (soc_is_exynos3250())
+               exynos_set_boot_flag(cpuid, C2_STATE);
+
        exynos_pm_central_suspend();
 
        if (of_machine_is_compatible("samsung,exynos4212") ||
@@ -178,6 +185,9 @@ void exynos_enter_aftr(void)
 
        exynos_pm_central_resume();
 
+       if (soc_is_exynos3250())
+               exynos_clear_boot_flag(cpuid, C2_STATE);
+
        cpu_pm_exit();
 }
 
index 37266a8264372a9d8ab898aec6389476f707869f..cbe56b35aea000fe2ad5841851b5eb9a57a307d5 100644 (file)
@@ -37,6 +37,7 @@ struct exynos_pm_domain {
        struct clk *oscclk;
        struct clk *clk[MAX_CLK_PER_DOMAIN];
        struct clk *pclk[MAX_CLK_PER_DOMAIN];
+       struct clk *asb_clk[MAX_CLK_PER_DOMAIN];
 };
 
 static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
@@ -45,14 +46,19 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
        void __iomem *base;
        u32 timeout, pwr;
        char *op;
+       int i;
 
        pd = container_of(domain, struct exynos_pm_domain, pd);
        base = pd->base;
 
+       for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+               if (IS_ERR(pd->asb_clk[i]))
+                       break;
+               clk_prepare_enable(pd->asb_clk[i]);
+       }
+
        /* Set oscclk before powering off a domain*/
        if (!power_on) {
-               int i;
-
                for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
                        if (IS_ERR(pd->clk[i]))
                                break;
@@ -81,8 +87,6 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
 
        /* Restore clocks after powering on a domain*/
        if (power_on) {
-               int i;
-
                for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
                        if (IS_ERR(pd->clk[i]))
                                break;
@@ -92,6 +96,12 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
                }
        }
 
+       for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+               if (IS_ERR(pd->asb_clk[i]))
+                       break;
+               clk_disable_unprepare(pd->asb_clk[i]);
+       }
+
        return 0;
 }
 
@@ -125,12 +135,21 @@ static __init int exynos4_pm_init_power_domain(void)
                        return -ENOMEM;
                }
 
-               pd->pd.name = kstrdup(np->name, GFP_KERNEL);
+               pd->pd.name = kstrdup(dev_name(dev), GFP_KERNEL);
                pd->name = pd->pd.name;
                pd->base = of_iomap(np, 0);
                pd->pd.power_off = exynos_pd_power_off;
                pd->pd.power_on = exynos_pd_power_on;
 
+               for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+                       char clk_name[8];
+
+                       snprintf(clk_name, sizeof(clk_name), "asb%d", i);
+                       pd->asb_clk[i] = clk_get(dev, clk_name);
+                       if (IS_ERR(pd->asb_clk[i]))
+                               break;
+               }
+
                pd->oscclk = clk_get(dev, "oscclk");
                if (IS_ERR(pd->oscclk))
                        goto no_clk;
index eb461e1c325ad96952495dad756af1d6b9c8a049..b7614333d2968befa767109f693bf7947528db4a 100644 (file)
 #define S5P_WAKEUP_STAT                                0x0600
 #define S5P_EINT_WAKEUP_MASK                   0x0604
 #define S5P_WAKEUP_MASK                                0x0608
+#define S5P_WAKEUP_MASK2                               0x0614
 
 #define S5P_INFORM0                            0x0800
 #define S5P_INFORM1                            0x0804
 #define S5P_INFORM5                            0x0814
 #define S5P_INFORM6                            0x0818
 #define S5P_INFORM7                            0x081C
+#define S5P_PMU_SPARE2                         0x0908
 #define S5P_PMU_SPARE3                         0x090C
 
 #define EXYNOS_IROM_DATA2                      0x0988
 
 #define S5P_CORE_LOCAL_PWR_EN                  0x3
 #define S5P_CORE_WAKEUP_FROM_LOCAL_CFG         (0x3 << 8)
+#define S5P_CORE_AUTOWAKEUP_EN                 (1 << 31)
 
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR    0x1154
index f7b82f9c1e213053c53aaab321fb0e9f558b8b73..c2845717bc8fd9860d62ee14191556854a484d7d 100644 (file)
@@ -17,6 +17,8 @@
 #define SMC_CMD_SLEEP          (-3)
 #define SMC_CMD_CPU1BOOT       (-4)
 #define SMC_CMD_CPU0AFTR       (-5)
+#define SMC_CMD_SAVE           (-6)
+#define SMC_CMD_SHUTDOWN       (-7)
 /* For CP15 Access */
 #define SMC_CMD_C15RESUME      (-11)
 /* For L2 Cache Access */
@@ -32,4 +34,11 @@ extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
 
 #endif /* __ASSEMBLY__ */
 
+/* op type for SMC_CMD_SAVE and SMC_CMD_SHUTDOWN */
+#define OP_TYPE_CORE           0x0
+#define OP_TYPE_CLUSTER                0x1
+
+/* Power State required for SMC_CMD_SAVE and SMC_CMD_SHUTDOWN */
+#define SMC_POWERSTATE_IDLE    0x1
+
 #endif
index 2146d918aedd265623cd3a7cb1393e4437095f3b..3e6aea7f83af199d7c624372fb96549430504cc2 100644 (file)
@@ -65,8 +65,6 @@ static struct sleep_save exynos_core_save[] = {
 
 struct exynos_pm_data {
        const struct exynos_wkup_irq *wkup_irq;
-       struct sleep_save *extra_save;
-       int num_extra_save;
        unsigned int wake_disable_mask;
        unsigned int *release_ret_regs;
 
@@ -77,7 +75,7 @@ struct exynos_pm_data {
        int (*cpu_suspend)(unsigned long);
 };
 
-struct exynos_pm_data *pm_data;
+static const struct exynos_pm_data *pm_data;
 
 static int exynos5420_cpu_state;
 static unsigned int exynos_pmu_spare3;
@@ -106,7 +104,7 @@ static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
        { /* sentinel */ },
 };
 
-unsigned int exynos_release_ret_regs[] = {
+static unsigned int exynos_release_ret_regs[] = {
        S5P_PAD_RET_MAUDIO_OPTION,
        S5P_PAD_RET_GPIO_OPTION,
        S5P_PAD_RET_UART_OPTION,
@@ -117,7 +115,7 @@ unsigned int exynos_release_ret_regs[] = {
        REG_TABLE_END,
 };
 
-unsigned int exynos3250_release_ret_regs[] = {
+static unsigned int exynos3250_release_ret_regs[] = {
        S5P_PAD_RET_MAUDIO_OPTION,
        S5P_PAD_RET_GPIO_OPTION,
        S5P_PAD_RET_UART_OPTION,
@@ -130,7 +128,7 @@ unsigned int exynos3250_release_ret_regs[] = {
        REG_TABLE_END,
 };
 
-unsigned int exynos5420_release_ret_regs[] = {
+static unsigned int exynos5420_release_ret_regs[] = {
        EXYNOS_PAD_RET_DRAM_OPTION,
        EXYNOS_PAD_RET_MAUDIO_OPTION,
        EXYNOS_PAD_RET_JTAG_OPTION,
@@ -349,10 +347,6 @@ static void exynos_pm_prepare(void)
 
        s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 
-        if (pm_data->extra_save)
-               s3c_pm_do_save(pm_data->extra_save,
-                               pm_data->num_extra_save);
-
        exynos_pm_enter_sleep_mode();
 
        /* ensure at least INFORM0 has the resume address */
@@ -475,10 +469,6 @@ static void exynos_pm_resume(void)
        /* For release retention */
        exynos_pm_release_retention();
 
-       if (pm_data->extra_save)
-               s3c_pm_do_restore_core(pm_data->extra_save,
-                                       pm_data->num_extra_save);
-
        s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 
        if (cpuid == ARM_CPU_PART_CORTEX_A9)
@@ -685,7 +675,7 @@ static const struct exynos_pm_data exynos5250_pm_data = {
        .cpu_suspend    = exynos_cpu_suspend,
 };
 
-static struct exynos_pm_data exynos5420_pm_data = {
+static const struct exynos_pm_data exynos5420_pm_data = {
        .wkup_irq       = exynos5250_wkup_irq,
        .wake_disable_mask = (0x7F << 7) | (0x1F << 1),
        .release_ret_regs = exynos5420_release_ret_regs,
@@ -736,7 +726,7 @@ void __init exynos_pm_init(void)
        if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL)))
                pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
 
-       pm_data = (struct exynos_pm_data *) match->data;
+       pm_data = (const struct exynos_pm_data *) match->data;
 
        /* All wakeup disable */
        tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
index 0748747b2bc65abe6be98be2168e19d4d7888c63..3a3d3e9d7bfd6eb7f781bfa904df5caede06a33c 100644 (file)
@@ -21,6 +21,7 @@ config MXC_AVIC
 
 config MXC_DEBUG_BOARD
        bool "Enable MXC debug board(for 3-stack)"
+       depends on MACH_MX27_3DS || MACH_MX31_3DS || MACH_MX35_3DS
        help
          The debug board is an integral part of the MXC 3-stack(PDK)
          platforms, it can be attached or removed from the peripheral
@@ -50,6 +51,7 @@ config HAVE_IMX_ANATOP
 
 config HAVE_IMX_GPC
        bool
+       select PM_GENERIC_DOMAINS if PM
 
 config HAVE_IMX_MMDC
        bool
@@ -586,6 +588,7 @@ config SOC_VF610
        select ARM_GIC
        select PINCTRL_VF610
        select PL310_ERRATA_769419 if CACHE_L2X0
+       select SMP_ON_UP if SMP
 
        help
          This enables support for Freescale Vybrid VF610 processor.
index d04a430607b8af66ef71ba3f01ff8e151738eeb1..469a150bf98f98cbb5521343e81d531c7fc34e91 100644 (file)
@@ -119,6 +119,7 @@ static unsigned int share_count_asrc;
 static unsigned int share_count_ssi1;
 static unsigned int share_count_ssi2;
 static unsigned int share_count_ssi3;
+static unsigned int share_count_mipi_core_cfg;
 
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
@@ -246,6 +247,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[IMX6QDL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
        clk[IMX6QDL_CLK_TWD]       = imx_clk_fixed_factor("twd",       "arm",            1, 2);
        clk[IMX6QDL_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",    "osc",            1, 8);
+       clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
        if (cpu_is_imx6dl()) {
                clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
                clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
@@ -400,7 +402,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
        clk[IMX6QDL_CLK_GPU3D_CORE]   = imx_clk_gate2("gpu3d_core",    "gpu3d_core_podf",   base + 0x6c, 26);
        clk[IMX6QDL_CLK_HDMI_IAHB]    = imx_clk_gate2("hdmi_iahb",     "ahb",               base + 0x70, 0);
-       clk[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_gate2("hdmi_isfr",     "pll3_pfd1_540m",    base + 0x70, 4);
+       clk[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_gate2("hdmi_isfr",     "video_27m",         base + 0x70, 4);
        clk[IMX6QDL_CLK_I2C1]         = imx_clk_gate2("i2c1",          "ipg_per",           base + 0x70, 6);
        clk[IMX6QDL_CLK_I2C2]         = imx_clk_gate2("i2c2",          "ipg_per",           base + 0x70, 8);
        clk[IMX6QDL_CLK_I2C3]         = imx_clk_gate2("i2c3",          "ipg_per",           base + 0x70, 10);
@@ -415,7 +417,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[IMX6QDL_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_podf",      base + 0x74, 12);
        clk[IMX6QDL_CLK_LDB_DI1]      = imx_clk_gate2("ldb_di1",       "ldb_di1_podf",      base + 0x74, 14);
        clk[IMX6QDL_CLK_IPU2_DI1]     = imx_clk_gate2("ipu2_di1",      "ipu2_di1_sel",      base + 0x74, 10);
-       clk[IMX6QDL_CLK_HSI_TX]       = imx_clk_gate2("hsi_tx",        "hsi_tx_podf",       base + 0x74, 16);
+       clk[IMX6QDL_CLK_HSI_TX]       = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf",       base + 0x74, 16, &share_count_mipi_core_cfg);
+       clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
+       clk[IMX6QDL_CLK_MIPI_IPG]     = imx_clk_gate2_shared("mipi_ipg", "ipg",             base + 0x74, 16, &share_count_mipi_core_cfg);
        if (cpu_is_imx6dl())
                /*
                 * The multiplexer and divider of the imx6q clock gpu2d get
index 745caa18ab2c0bc0edcfa7388e1a44c1bdf6986a..029f59ce2712a00332b6cc0b969417b445aa80e0 100644 (file)
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regulator/consumer.h>
 #include <linux/irqchip/arm-gic.h>
 #include "common.h"
+#include "hardware.h"
 
+#define GPC_CNTR               0x000
 #define GPC_IMR1               0x008
+#define GPC_PGC_GPU_PDN                0x260
+#define GPC_PGC_GPU_PUPSCR     0x264
+#define GPC_PGC_GPU_PDNSCR     0x268
 #define GPC_PGC_CPU_PDN                0x2a0
 #define GPC_PGC_CPU_PUPSCR     0x2a4
 #define GPC_PGC_CPU_PDNSCR     0x2a8
 
 #define IMR_NUM                        4
 
+#define GPU_VPU_PUP_REQ                BIT(1)
+#define GPU_VPU_PDN_REQ                BIT(0)
+
+#define GPC_CLK_MAX            6
+
+struct pu_domain {
+       struct generic_pm_domain base;
+       struct regulator *reg;
+       struct clk *clk[GPC_CLK_MAX];
+       int num_clks;
+};
+
 static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
@@ -170,3 +192,194 @@ void __init imx_gpc_init(void)
        gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
        gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
 }
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+
+static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
+{
+       int iso, iso2sw;
+       u32 val;
+
+       /* Read ISO and ISO2SW power down delays */
+       val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
+       iso = val & 0x3f;
+       iso2sw = (val >> 8) & 0x3f;
+
+       /* Gate off PU domain when GPU/VPU when powered down */
+       writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
+
+       /* Request GPC to power down GPU/VPU */
+       val = readl_relaxed(gpc_base + GPC_CNTR);
+       val |= GPU_VPU_PDN_REQ;
+       writel_relaxed(val, gpc_base + GPC_CNTR);
+
+       /* Wait ISO + ISO2SW IPG clock cycles */
+       ndelay((iso + iso2sw) * 1000 / 66);
+}
+
+static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
+{
+       struct pu_domain *pu = container_of(genpd, struct pu_domain, base);
+
+       _imx6q_pm_pu_power_off(genpd);
+
+       if (pu->reg)
+               regulator_disable(pu->reg);
+
+       return 0;
+}
+
+static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
+{
+       struct pu_domain *pu = container_of(genpd, struct pu_domain, base);
+       int i, ret, sw, sw2iso;
+       u32 val;
+
+       if (pu->reg)
+               ret = regulator_enable(pu->reg);
+       if (pu->reg && ret) {
+               pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
+               return ret;
+       }
+
+       /* Enable reset clocks for all devices in the PU domain */
+       for (i = 0; i < pu->num_clks; i++)
+               clk_prepare_enable(pu->clk[i]);
+
+       /* Gate off PU domain when GPU/VPU when powered down */
+       writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
+
+       /* Read ISO and ISO2SW power down delays */
+       val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
+       sw = val & 0x3f;
+       sw2iso = (val >> 8) & 0x3f;
+
+       /* Request GPC to power up GPU/VPU */
+       val = readl_relaxed(gpc_base + GPC_CNTR);
+       val |= GPU_VPU_PUP_REQ;
+       writel_relaxed(val, gpc_base + GPC_CNTR);
+
+       /* Wait ISO + ISO2SW IPG clock cycles */
+       ndelay((sw + sw2iso) * 1000 / 66);
+
+       /* Disable reset clocks for all devices in the PU domain */
+       for (i = 0; i < pu->num_clks; i++)
+               clk_disable_unprepare(pu->clk[i]);
+
+       return 0;
+}
+
+static struct generic_pm_domain imx6q_arm_domain = {
+       .name = "ARM",
+};
+
+static struct pu_domain imx6q_pu_domain = {
+       .base = {
+               .name = "PU",
+               .power_off = imx6q_pm_pu_power_off,
+               .power_on = imx6q_pm_pu_power_on,
+               .power_off_latency_ns = 25000,
+               .power_on_latency_ns = 2000000,
+       },
+};
+
+static struct generic_pm_domain imx6sl_display_domain = {
+       .name = "DISPLAY",
+};
+
+static struct generic_pm_domain *imx_gpc_domains[] = {
+       &imx6q_arm_domain,
+       &imx6q_pu_domain.base,
+       &imx6sl_display_domain,
+};
+
+static struct genpd_onecell_data imx_gpc_onecell_data = {
+       .domains = imx_gpc_domains,
+       .num_domains = ARRAY_SIZE(imx_gpc_domains),
+};
+
+static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
+{
+       struct clk *clk;
+       bool is_off;
+       int i;
+
+       imx6q_pu_domain.reg = pu_reg;
+
+       for (i = 0; ; i++) {
+               clk = of_clk_get(dev->of_node, i);
+               if (IS_ERR(clk))
+                       break;
+               if (i >= GPC_CLK_MAX) {
+                       dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
+                       goto clk_err;
+               }
+               imx6q_pu_domain.clk[i] = clk;
+       }
+       imx6q_pu_domain.num_clks = i;
+
+       is_off = IS_ENABLED(CONFIG_PM);
+       if (is_off) {
+               _imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
+       } else {
+               /*
+                * Enable power if compiled without CONFIG_PM in case the
+                * bootloader disabled it.
+                */
+               imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
+       }
+
+       pm_genpd_init(&imx6q_pu_domain.base, NULL, is_off);
+       return of_genpd_add_provider_onecell(dev->of_node,
+                                            &imx_gpc_onecell_data);
+
+clk_err:
+       while (i--)
+               clk_put(imx6q_pu_domain.clk[i]);
+       return -EINVAL;
+}
+
+#else
+static inline int imx_gpc_genpd_init(struct device *dev, struct regulator *reg)
+{
+       return 0;
+}
+#endif /* CONFIG_PM_GENERIC_DOMAINS */
+
+static int imx_gpc_probe(struct platform_device *pdev)
+{
+       struct regulator *pu_reg;
+       int ret;
+
+       pu_reg = devm_regulator_get_optional(&pdev->dev, "pu");
+       if (PTR_ERR(pu_reg) == -ENODEV)
+               pu_reg = NULL;
+       if (IS_ERR(pu_reg)) {
+               ret = PTR_ERR(pu_reg);
+               dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
+               return ret;
+       }
+
+       return imx_gpc_genpd_init(&pdev->dev, pu_reg);
+}
+
+static const struct of_device_id imx_gpc_dt_ids[] = {
+       { .compatible = "fsl,imx6q-gpc" },
+       { .compatible = "fsl,imx6sl-gpc" },
+       { }
+};
+
+static struct platform_driver imx_gpc_driver = {
+       .driver = {
+               .name = "imx-gpc",
+               .owner = THIS_MODULE,
+               .of_match_table = imx_gpc_dt_ids,
+       },
+       .probe = imx_gpc_probe,
+};
+
+static int __init imx_pgc_init(void)
+{
+       return platform_driver_register(&imx_gpc_driver);
+}
+subsys_initcall(imx_pgc_init);
index 18301dc9d2e7c2459344b4096a2187f5ae03305d..0743e2059645d876af692026d9dfd74713ba2608 100644 (file)
@@ -1,8 +1,11 @@
 menuconfig ARCH_MESON
        bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
+       select ARCH_REQUIRE_GPIOLIB
        select GENERIC_IRQ_CHIP
        select ARM_GIC
        select CACHE_L2X0
+       select PINCTRL
+       select PINCTRL_MESON
 
 if ARCH_MESON
 
index c1e4567a5ab3ed8cfc10da7340beb624a7e0713c..97473168d6b65dfade5d92356a6ce73fe990c341 100644 (file)
@@ -64,6 +64,20 @@ config MACH_ARMADA_38X
          Say 'Y' here if you want your kernel to support boards based
          on the Marvell Armada 380/385 SoC with device tree.
 
+config MACH_ARMADA_39X
+       bool "Marvell Armada 39x boards" if ARCH_MULTI_V7
+       select ARM_GIC
+       select ARMADA_39X_CLK
+       select CACHE_L2X0
+       select HAVE_ARM_SCU
+       select HAVE_ARM_TWD if SMP
+       select HAVE_SMP
+       select MACH_MVEBU_V7
+       select PINCTRL_ARMADA_39X
+       help
+         Say 'Y' here if you want your kernel to support boards based
+         on the Marvell Armada 39x SoC with device tree.
+
 config MACH_ARMADA_XP
        bool "Marvell Armada XP boards" if ARCH_MULTI_V7
        select ARMADA_XP_CLK
index 31b66f26e029ab5155762cd3bb8d2fed4b0704cb..afee9083ad92bc6d16bb7b29ef5f86f811351847 100644 (file)
@@ -232,3 +232,17 @@ DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)")
        .restart        = mvebu_restart,
        .dt_compat      = armada_38x_dt_compat,
 MACHINE_END
+
+static const char * const armada_39x_dt_compat[] __initconst = {
+       "marvell,armada390",
+       "marvell,armada398",
+       NULL,
+};
+
+DT_MACHINE_START(ARMADA_39X_DT, "Marvell Armada 39x (Device Tree)")
+       .l2c_aux_val    = 0,
+       .l2c_aux_mask   = ~0,
+       .init_irq       = mvebu_init_irq,
+       .restart        = mvebu_restart,
+       .dt_compat      = armada_39x_dt_compat,
+MACHINE_END
index 2ec1a42b432152dafadd1bedf793b17f036037d2..df0a9cc5da59ad2ce7a95e7d13dc8e2a82937069 100644 (file)
@@ -110,3 +110,5 @@ CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
                      &mvebu_cortex_a9_smp_ops);
 CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
                      &armada_38x_smp_ops);
+CPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp",
+                     &armada_38x_smp_ops);
index be9541e1865096bb2c8b81659dfce952cbc98eeb..166b18f515a206ab3747d4eb51d4d1677c3879a2 100644 (file)
@@ -690,6 +690,9 @@ struct dev_pm_domain omap_device_pm_domain = {
                USE_PLATFORM_PM_SLEEP_OPS
                .suspend_noirq = _od_suspend_noirq,
                .resume_noirq = _od_resume_noirq,
+               .freeze_noirq = _od_suspend_noirq,
+               .thaw_noirq = _od_resume_noirq,
+               .restore_noirq = _od_resume_noirq,
        }
 };
 
index 8eb85925e44483c5840b83a79621a40f108cc752..e2223148ba4d37a0818fc65d19ddb00bdc49d56c 100644 (file)
@@ -20,6 +20,7 @@
 #include "omap_hwmod_33xx_43xx_common_data.h"
 #include "prcm43xx.h"
 #include "omap_hwmod_common_data.h"
+#include "hdq1w.h"
 
 
 /* IP blocks */
@@ -516,6 +517,33 @@ static struct omap_hwmod am43xx_dss_rfbi_hwmod = {
        .parent_hwmod   = &am43xx_dss_core_hwmod,
 };
 
+/* HDQ1W */
+static struct omap_hwmod_class_sysconfig am43xx_hdq1w_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0014,
+       .syss_offs      = 0x0018,
+       .sysc_flags     = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class am43xx_hdq1w_hwmod_class = {
+       .name   = "hdq1w",
+       .sysc   = &am43xx_hdq1w_sysc,
+       .reset  = &omap_hdq1w_reset,
+};
+
+static struct omap_hwmod am43xx_hdq1w_hwmod = {
+       .name           = "hdq1w",
+       .class          = &am43xx_hdq1w_hwmod_class,
+       .clkdm_name     = "l4ls_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
 /* Interfaces */
 static struct omap_hwmod_ocp_if am43xx_l3_main__l4_hs = {
        .master         = &am33xx_l3_main_hwmod,
@@ -790,6 +818,13 @@ static struct omap_hwmod_ocp_if am43xx_l4_ls__dss_rfbi = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_ocp_if am43xx_l4_ls__hdq1w = {
+       .master         = &am33xx_l4_ls_hwmod,
+       .slave          = &am43xx_hdq1w_hwmod,
+       .clk            = "l4ls_gclk",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l4_wkup__synctimer,
        &am43xx_l4_ls__timer8,
@@ -889,6 +924,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am43xx_l4_ls__dss,
        &am43xx_l4_ls__dss_dispc,
        &am43xx_l4_ls__dss_rfbi,
+       &am43xx_l4_ls__hdq1w,
        NULL,
 };
 
index 16fe7a1b7a3578069746371dc789e51308cc2134..0e64c2fac0b5fad2c92af76a2042a1080108fc04 100644 (file)
@@ -1726,21 +1726,6 @@ static struct omap_hwmod_class dra7xx_timer_1ms_hwmod_class = {
        .sysc   = &dra7xx_timer_1ms_sysc,
 };
 
-static struct omap_hwmod_class_sysconfig dra7xx_timer_secure_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class dra7xx_timer_secure_hwmod_class = {
-       .name   = "timer",
-       .sysc   = &dra7xx_timer_secure_sysc,
-};
-
 static struct omap_hwmod_class_sysconfig dra7xx_timer_sysc = {
        .rev_offs       = 0x0000,
        .sysc_offs      = 0x0010,
@@ -1804,7 +1789,7 @@ static struct omap_hwmod dra7xx_timer3_hwmod = {
 /* timer4 */
 static struct omap_hwmod dra7xx_timer4_hwmod = {
        .name           = "timer4",
-       .class          = &dra7xx_timer_secure_hwmod_class,
+       .class          = &dra7xx_timer_hwmod_class,
        .clkdm_name     = "l4per_clkdm",
        .main_clk       = "timer4_gfclk_mux",
        .prcm = {
@@ -1921,6 +1906,66 @@ static struct omap_hwmod dra7xx_timer11_hwmod = {
        },
 };
 
+/* timer13 */
+static struct omap_hwmod dra7xx_timer13_hwmod = {
+       .name           = "timer13",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per3_clkdm",
+       .main_clk       = "timer13_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER3_TIMER13_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER3_TIMER13_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer14 */
+static struct omap_hwmod dra7xx_timer14_hwmod = {
+       .name           = "timer14",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per3_clkdm",
+       .main_clk       = "timer14_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER3_TIMER14_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER3_TIMER14_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer15 */
+static struct omap_hwmod dra7xx_timer15_hwmod = {
+       .name           = "timer15",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per3_clkdm",
+       .main_clk       = "timer15_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER3_TIMER15_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER3_TIMER15_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer16 */
+static struct omap_hwmod dra7xx_timer16_hwmod = {
+       .name           = "timer16",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per3_clkdm",
+       .main_clk       = "timer16_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER3_TIMER16_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER3_TIMER16_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
 /*
  * 'uart' class
  *
@@ -3059,6 +3104,38 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer11 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* l4_per3 -> timer13 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer13 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer13_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer14 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer14 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer14_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer15 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer15 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer15_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer16 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer16 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer16_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* l4_per1 -> uart1 */
 static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart1 = {
        .master         = &dra7xx_l4_per1_hwmod,
@@ -3295,6 +3372,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_per1__timer9,
        &dra7xx_l4_per1__timer10,
        &dra7xx_l4_per1__timer11,
+       &dra7xx_l4_per3__timer13,
+       &dra7xx_l4_per3__timer14,
+       &dra7xx_l4_per3__timer15,
+       &dra7xx_l4_per3__timer16,
        &dra7xx_l4_per1__uart1,
        &dra7xx_l4_per1__uart2,
        &dra7xx_l4_per1__uart3,
index ad7b3e9977f8fa520b0281e3e9b876e98f7e98b3..48df3b55057e4d346076ada24e6e7404a13a117a 100644 (file)
 #define AM43XX_CM_PER_USB_OTG_SS1_CLKCTRL_OFFSET        0x0268
 #define AM43XX_CM_PER_USBPHYOCP2SCP1_CLKCTRL_OFFSET    0x05C0
 #define AM43XX_CM_PER_DSS_CLKCTRL_OFFSET               0x0a20
+#define AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET             0x04a0
 
 #endif
index f26fcdca2445e96e5cbac6731791485e9f904e7e..5b4ca3c3c8797d2560c4addaad6773b974ebb2d0 100644 (file)
@@ -55,7 +55,7 @@ static int pmu_power_domain_is_on(int pd)
        return !(val & BIT(pd));
 }
 
-struct reset_control *rockchip_get_core_reset(int cpu)
+static struct reset_control *rockchip_get_core_reset(int cpu)
 {
        struct device *dev = get_cpu_device(cpu);
        struct device_node *np;
@@ -201,7 +201,7 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
        return 0;
 }
 
-static struct regmap_config rockchip_pmu_regmap_config = {
+static const struct regmap_config rockchip_pmu_regmap_config = {
        .reg_bits = 32,
        .val_bits = 32,
        .reg_stride = 4,
index 50cb781aaa36c97f9b2f905a0e1e3076421b5654..b07d8860207323e302a86234f9bf7cbbeac827a4 100644 (file)
@@ -75,9 +75,13 @@ static void rk3288_slp_mode_set(int level)
        regmap_read(pmu_regmap, RK3288_PMU_PWRMODE_CON,
                    &rk3288_pmu_pwr_mode_con);
 
-       /* set bit 8 so that system will resume to FAST_BOOT_ADDR */
+       /*
+        * SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR
+        * PCLK_WDT_GATE - disable WDT during suspend.
+        */
        regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
-                    SGRF_FAST_BOOT_EN | SGRF_FAST_BOOT_EN_WRITE);
+                    SGRF_PCLK_WDT_GATE | SGRF_FAST_BOOT_EN
+                    | SGRF_PCLK_WDT_GATE_WRITE | SGRF_FAST_BOOT_EN_WRITE);
 
        /* booting address of resuming system is from this register value */
        regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
@@ -122,7 +126,8 @@ static void rk3288_slp_mode_set_resume(void)
                     rk3288_pmu_pwr_mode_con);
 
        regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
-                    rk3288_sgrf_soc_con0 | SGRF_FAST_BOOT_EN_WRITE);
+                    rk3288_sgrf_soc_con0 | SGRF_PCLK_WDT_GATE_WRITE
+                    | SGRF_FAST_BOOT_EN_WRITE);
 }
 
 static int rockchip_lpmode_enter(unsigned long arg)
@@ -209,6 +214,9 @@ static int rk3288_suspend_init(struct device_node *np)
        memcpy(rk3288_bootram_base, rockchip_slp_cpu_resume,
               rk3288_bootram_sz);
 
+       regmap_write(pmu_regmap, RK3288_PMU_OSC_CNT, OSC_STABL_CNT_THRESH);
+       regmap_write(pmu_regmap, RK3288_PMU_STABL_CNT, PMU_STABL_CNT_THRESH);
+
        return 0;
 }
 
index 7c889c04604b5ec0d9faaec30d0b612275c4cda4..03ff31d8282d07bd4fcd54dcde67b6ee7d7069ef 100644 (file)
@@ -50,6 +50,8 @@ static inline void rockchip_suspend_init(void)
 
 #define RK3288_SGRF_SOC_CON0           (0x0000)
 #define RK3288_SGRF_FAST_BOOT_ADDR     (0x0120)
+#define SGRF_PCLK_WDT_GATE             BIT(6)
+#define SGRF_PCLK_WDT_GATE_WRITE       BIT(22)
 #define SGRF_FAST_BOOT_EN              BIT(8)
 #define SGRF_FAST_BOOT_EN_WRITE                BIT(24)
 
@@ -63,6 +65,10 @@ static inline void rockchip_suspend_init(void)
 /* PMU_WAKEUP_CFG1 bits */
 #define PMU_ARMINT_WAKEUP_EN           BIT(0)
 
+/* wait 30ms for OSC stable and 30ms for pmic stable */
+#define OSC_STABL_CNT_THRESH   (32 * 30)
+#define PMU_STABL_CNT_THRESH   (32 * 30)
+
 enum rk3288_pwr_mode_con {
        PMU_PWR_MODE_EN = 0,
        PMU_CLK_CORE_SRC_GATE_EN,
index 7bc66682687efa4f240a5557618278d38c39e4b1..dcbe17f5e5f8054ee7fd1e796197eb88d78e97a8 100644 (file)
@@ -14,6 +14,7 @@
 #include <mach/gpio-samsung.h>
 
 #define GLENFARCLAS_PMIC_IRQ_BASE      IRQ_BOARD_START
+#define BANFF_PMIC_IRQ_BASE            (IRQ_BOARD_START + 64)
 
 #define PCA935X_GPIO_BASE              GPIO_BOARD_START
 #define CODEC_GPIO_BASE                        (GPIO_BOARD_START + 8)
index 10b913baab2883562acb916ecef103d96b35b761..65c426bc45f72eb530df0736493d4e4a373904cd 100644 (file)
@@ -554,6 +554,7 @@ static struct wm831x_touch_pdata touch_pdata = {
 
 static struct wm831x_pdata crag_pmic_pdata = {
        .wm831x_num = 1,
+       .irq_base = BANFF_PMIC_IRQ_BASE,
        .gpio_base = BANFF_PMIC_GPIO_BASE,
        .soft_shutdown = true,
 
index 2f36c85eec4b201e4ab1016a2c9501a433758e65..347b6a58fc3e033138c6e5ba98088902cd24723f 100644 (file)
@@ -69,10 +69,12 @@ config ARCH_R8A7779
 config ARCH_R8A7790
        bool "R-Car H2 (R8A77900)"
        select ARCH_RCAR_GEN2
+       select I2C
 
 config ARCH_R8A7791
        bool "R-Car M2-W (R8A77910)"
        select ARCH_RCAR_GEN2
+       select I2C
 
 config ARCH_R8A7794
        bool "R-Car E2 (R8A77940)"
index 03794b0de64b5cfc1714ccd8d82cca9af6ffd213..3631d8b6fc5e6deb767bc2615f45776f2cefde99 100644 (file)
@@ -35,6 +35,8 @@ cpu-y                         := platsmp.o headsmp.o
 # Shared SoC family objects
 obj-$(CONFIG_ARCH_RCAR_GEN2)   += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y)
 CFLAGS_setup-rcar-gen2.o       += -march=armv7-a
+obj-$(CONFIG_ARCH_R8A7790)     += regulator-quirk-rcar-gen2.o
+obj-$(CONFIG_ARCH_R8A7791)     += regulator-quirk-rcar-gen2.o
 
 # SMP objects
 smp-y                          := $(cpu-y)
diff --git a/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c b/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
new file mode 100644 (file)
index 0000000..384e6e9
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * R-Car Generation 2 da9063/da9210 regulator quirk
+ *
+ * The r8a7790/lager and r8a7791/koelsch development boards have da9063 and
+ * da9210 regulators.  Both regulators have their interrupt request lines tied
+ * to the same interrupt pin (IRQ2) on the SoC.
+ *
+ * After cold boot or da9063-induced restart, both the da9063 and da9210 seem
+ * to assert their interrupt request lines.  Hence as soon as one driver
+ * requests this irq, it gets stuck in an interrupt storm, as it only manages
+ * to deassert its own interrupt request line, and the other driver hasn't
+ * installed an interrupt handler yet.
+ *
+ * To handle this, install a quirk that masks the interrupts in both the
+ * da9063 and da9210.  This quirk has to run after the i2c master driver has
+ * been initialized, but before the i2c slave drivers are initialized.
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/mfd/da9063/registers.h>
+
+
+#define IRQC_BASE              0xe61c0000
+#define IRQC_MONITOR           0x104   /* IRQn Signal Level Monitor Register */
+
+#define REGULATOR_IRQ_MASK     BIT(2)  /* IRQ2, active low */
+
+static void __iomem *irqc;
+
+static const u8 da9063_mask_regs[] = {
+       DA9063_REG_IRQ_MASK_A,
+       DA9063_REG_IRQ_MASK_B,
+       DA9063_REG_IRQ_MASK_C,
+       DA9063_REG_IRQ_MASK_D,
+};
+
+/* DA9210 System Control and Event Registers */
+#define DA9210_REG_MASK_A              0x54
+#define DA9210_REG_MASK_B              0x55
+
+static const u8 da9210_mask_regs[] = {
+       DA9210_REG_MASK_A,
+       DA9210_REG_MASK_B,
+};
+
+static void da9xxx_mask_irqs(struct i2c_client *client, const u8 regs[],
+                            unsigned int nregs)
+{
+       unsigned int i;
+
+       dev_info(&client->dev, "Masking %s interrupt sources\n", client->name);
+
+       for (i = 0; i < nregs; i++) {
+               int error = i2c_smbus_write_byte_data(client, regs[i], ~0);
+               if (error) {
+                       dev_err(&client->dev, "i2c error %d\n", error);
+                       return;
+               }
+       }
+}
+
+static int regulator_quirk_notify(struct notifier_block *nb,
+                                 unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct i2c_client *client;
+       u32 mon;
+
+       mon = ioread32(irqc + IRQC_MONITOR);
+       dev_dbg(dev, "%s: %ld, IRQC_MONITOR = 0x%x\n", __func__, action, mon);
+       if (mon & REGULATOR_IRQ_MASK)
+               goto remove;
+
+       if (action != BUS_NOTIFY_ADD_DEVICE || dev->type == &i2c_adapter_type)
+               return 0;
+
+       client = to_i2c_client(dev);
+       dev_dbg(dev, "Detected %s\n", client->name);
+
+       if ((client->addr == 0x58 && !strcmp(client->name, "da9063")))
+               da9xxx_mask_irqs(client, da9063_mask_regs,
+                                ARRAY_SIZE(da9063_mask_regs));
+       else if (client->addr == 0x68 && !strcmp(client->name, "da9210"))
+               da9xxx_mask_irqs(client, da9210_mask_regs,
+                                ARRAY_SIZE(da9210_mask_regs));
+
+       mon = ioread32(irqc + IRQC_MONITOR);
+       if (mon & REGULATOR_IRQ_MASK)
+               goto remove;
+
+       return 0;
+
+remove:
+       dev_info(dev, "IRQ2 is not asserted, removing quirk\n");
+
+       bus_unregister_notifier(&i2c_bus_type, nb);
+       iounmap(irqc);
+       return 0;
+}
+
+static struct notifier_block regulator_quirk_nb = {
+       .notifier_call = regulator_quirk_notify
+};
+
+static int __init rcar_gen2_regulator_quirk(void)
+{
+       u32 mon;
+
+       if (!of_machine_is_compatible("renesas,koelsch") &&
+           !of_machine_is_compatible("renesas,lager"))
+               return -ENODEV;
+
+       irqc = ioremap(IRQC_BASE, PAGE_SIZE);
+       if (!irqc)
+               return -ENOMEM;
+
+       mon = ioread32(irqc + IRQC_MONITOR);
+       if (mon & REGULATOR_IRQ_MASK) {
+               pr_debug("%s: IRQ2 is not asserted, not installing quirk\n",
+                        __func__);
+               iounmap(irqc);
+               return 0;
+       }
+
+       pr_info("IRQ2 is asserted, installing da9063/da9210 regulator quirk\n");
+
+       bus_register_notifier(&i2c_bus_type, &regulator_quirk_nb);
+       return 0;
+}
+
+arch_initcall(rcar_gen2_regulator_quirk);
index 51464cc6d65baaf7241551e65364a788cdb2dfed..5d13595aa027447dc9b933f4a5132c6d9f75407c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/dma-contiguous.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/memblock.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <asm/mach/arch.h>
@@ -195,7 +196,7 @@ void __init rcar_gen2_reserve(void)
 
        of_scan_flat_dt(rcar_gen2_scan_mem, &mrc);
 #ifdef CONFIG_DMA_CMA
-       if (mrc.size)
+       if (mrc.size && memblock_is_region_memory(mrc.base, mrc.size))
                dma_contiguous_reserve_area(mrc.size, mrc.base, 0,
                                            &rcar_gen2_dma_contiguous, true);
 #endif
index 30b993399ed7758062f1f458b05d3fee2c9cd7b8..5cedcf572104bcdf82b1b75ab61f89f4cdf19651 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/of_address.h>
 #include <linux/vexpress.h>
 #define KFC_CFG_W      0x2c
 #define DCS_CFG_R      0x30
 
-/*
- * We can't use regular spinlocks. In the switcher case, it is possible
- * for an outbound CPU to call power_down() while its inbound counterpart
- * is already live using the same logical CPU number which trips lockdep
- * debugging.
- */
-static arch_spinlock_t dcscb_lock = __ARCH_SPIN_LOCK_UNLOCKED;
-
 static void __iomem *dcscb_base;
-static int dcscb_use_count[4][2];
 static int dcscb_allcpus_mask[2];
 
-static int dcscb_power_up(unsigned int cpu, unsigned int cluster)
+static int dcscb_cpu_powerup(unsigned int cpu, unsigned int cluster)
 {
        unsigned int rst_hold, cpumask = (1 << cpu);
-       unsigned int all_mask;
 
        pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-       if (cpu >= 4 || cluster >= 2)
+       if (cluster >= 2 || !(cpumask & dcscb_allcpus_mask[cluster]))
                return -EINVAL;
 
-       all_mask = dcscb_allcpus_mask[cluster];
+       rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
+       rst_hold &= ~(cpumask | (cpumask << 4));
+       writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
+       return 0;
+}
 
-       /*
-        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
-        * variant exists, we need to disable IRQs manually here.
-        */
-       local_irq_disable();
-       arch_spin_lock(&dcscb_lock);
-
-       dcscb_use_count[cpu][cluster]++;
-       if (dcscb_use_count[cpu][cluster] == 1) {
-               rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
-               if (rst_hold & (1 << 8)) {
-                       /* remove cluster reset and add individual CPU's reset */
-                       rst_hold &= ~(1 << 8);
-                       rst_hold |= all_mask;
-               }
-               rst_hold &= ~(cpumask | (cpumask << 4));
-               writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
-       } else if (dcscb_use_count[cpu][cluster] != 2) {
-               /*
-                * The only possible values are:
-                * 0 = CPU down
-                * 1 = CPU (still) up
-                * 2 = CPU requested to be up before it had a chance
-                *     to actually make itself down.
-                * Any other value is a bug.
-                */
-               BUG();
-       }
+static int dcscb_cluster_powerup(unsigned int cluster)
+{
+       unsigned int rst_hold;
 
-       arch_spin_unlock(&dcscb_lock);
-       local_irq_enable();
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       if (cluster >= 2)
+               return -EINVAL;
 
+       /* remove cluster reset and add individual CPU's reset */
+       rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
+       rst_hold &= ~(1 << 8);
+       rst_hold |= dcscb_allcpus_mask[cluster];
+       writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
        return 0;
 }
 
-static void dcscb_power_down(void)
+static void dcscb_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster)
 {
-       unsigned int mpidr, cpu, cluster, rst_hold, cpumask, all_mask;
-       bool last_man = false, skip_wfi = false;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-       cpumask = (1 << cpu);
+       unsigned int rst_hold;
 
        pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-       BUG_ON(cpu >= 4 || cluster >= 2);
-
-       all_mask = dcscb_allcpus_mask[cluster];
-
-       __mcpm_cpu_going_down(cpu, cluster);
-
-       arch_spin_lock(&dcscb_lock);
-       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
-       dcscb_use_count[cpu][cluster]--;
-       if (dcscb_use_count[cpu][cluster] == 0) {
-               rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
-               rst_hold |= cpumask;
-               if (((rst_hold | (rst_hold >> 4)) & all_mask) == all_mask) {
-                       rst_hold |= (1 << 8);
-                       last_man = true;
-               }
-               writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
-       } else if (dcscb_use_count[cpu][cluster] == 1) {
-               /*
-                * A power_up request went ahead of us.
-                * Even if we do not want to shut this CPU down,
-                * the caller expects a certain state as if the WFI
-                * was aborted.  So let's continue with cache cleaning.
-                */
-               skip_wfi = true;
-       } else
-               BUG();
-
-       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
-               arch_spin_unlock(&dcscb_lock);
-
-               /* Flush all cache levels for this cluster. */
-               v7_exit_coherency_flush(all);
-
-               /*
-                * A full outer cache flush could be needed at this point
-                * on platforms with such a cache, depending on where the
-                * outer cache sits. In some cases the notion of a "last
-                * cluster standing" would need to be implemented if the
-                * outer cache is shared across clusters. In any case, when
-                * the outer cache needs flushing, there is no concurrent
-                * access to the cache controller to worry about and no
-                * special locking besides what is already provided by the
-                * MCPM state machinery is needed.
-                */
-
-               /*
-                * Disable cluster-level coherency by masking
-                * incoming snoops and DVM messages:
-                */
-               cci_disable_port_by_cpu(mpidr);
-
-               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
-       } else {
-               arch_spin_unlock(&dcscb_lock);
-
-               /* Disable and flush the local CPU cache. */
-               v7_exit_coherency_flush(louis);
-       }
+       BUG_ON(cluster >= 2 || !((1 << cpu) & dcscb_allcpus_mask[cluster]));
 
-       __mcpm_cpu_down(cpu, cluster);
+       rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
+       rst_hold |= (1 << cpu);
+       writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
+}
 
-       /* Now we are prepared for power-down, do it: */
-       dsb();
-       if (!skip_wfi)
-               wfi();
+static void dcscb_cluster_powerdown_prepare(unsigned int cluster)
+{
+       unsigned int rst_hold;
 
-       /* Not dead at this point?  Let our caller cope. */
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       BUG_ON(cluster >= 2);
+
+       rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
+       rst_hold |= (1 << 8);
+       writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
 }
 
-static const struct mcpm_platform_ops dcscb_power_ops = {
-       .power_up       = dcscb_power_up,
-       .power_down     = dcscb_power_down,
-};
+static void dcscb_cpu_cache_disable(void)
+{
+       /* Disable and flush the local CPU cache. */
+       v7_exit_coherency_flush(louis);
+}
 
-static void __init dcscb_usage_count_init(void)
+static void dcscb_cluster_cache_disable(void)
 {
-       unsigned int mpidr, cpu, cluster;
+       /* Flush all cache levels for this cluster. */
+       v7_exit_coherency_flush(all);
 
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+       /*
+        * A full outer cache flush could be needed at this point
+        * on platforms with such a cache, depending on where the
+        * outer cache sits. In some cases the notion of a "last
+        * cluster standing" would need to be implemented if the
+        * outer cache is shared across clusters. In any case, when
+        * the outer cache needs flushing, there is no concurrent
+        * access to the cache controller to worry about and no
+        * special locking besides what is already provided by the
+        * MCPM state machinery is needed.
+        */
 
-       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-       BUG_ON(cpu >= 4 || cluster >= 2);
-       dcscb_use_count[cpu][cluster] = 1;
+       /*
+        * Disable cluster-level coherency by masking
+        * incoming snoops and DVM messages:
+        */
+       cci_disable_port_by_cpu(read_cpuid_mpidr());
 }
 
+static const struct mcpm_platform_ops dcscb_power_ops = {
+       .cpu_powerup            = dcscb_cpu_powerup,
+       .cluster_powerup        = dcscb_cluster_powerup,
+       .cpu_powerdown_prepare  = dcscb_cpu_powerdown_prepare,
+       .cluster_powerdown_prepare = dcscb_cluster_powerdown_prepare,
+       .cpu_cache_disable      = dcscb_cpu_cache_disable,
+       .cluster_cache_disable  = dcscb_cluster_cache_disable,
+};
+
 extern void dcscb_power_up_setup(unsigned int affinity_level);
 
 static int __init dcscb_init(void)
@@ -213,7 +151,6 @@ static int __init dcscb_init(void)
        cfg = readl_relaxed(dcscb_base + DCS_CFG_R);
        dcscb_allcpus_mask[0] = (1 << (((cfg >> 16) >> (0 << 2)) & 0xf)) - 1;
        dcscb_allcpus_mask[1] = (1 << (((cfg >> 16) >> (1 << 2)) & 0xf)) - 1;
-       dcscb_usage_count_init();
 
        ret = mcpm_platform_register(&dcscb_power_ops);
        if (!ret)
index 2fb78b4648cba73620516a7cd52fcf95d45e40a8..b3328cd46c332b61d3981ed008947dbe45f8a1b2 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/irqchip/arm-gic.h>
 
 
 static void __iomem *scc;
 
-/*
- * We can't use regular spinlocks. In the switcher case, it is possible
- * for an outbound CPU to call power_down() after its inbound counterpart
- * is already live using the same logical CPU number which trips lockdep
- * debugging.
- */
-static arch_spinlock_t tc2_pm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
-
 #define TC2_CLUSTERS                   2
 #define TC2_MAX_CPUS_PER_CLUSTER       3
 
 static unsigned int tc2_nr_cpus[TC2_CLUSTERS];
 
-/* Keep per-cpu usage count to cope with unordered up/down requests */
-static int tc2_pm_use_count[TC2_MAX_CPUS_PER_CLUSTER][TC2_CLUSTERS];
-
-#define tc2_cluster_unused(cluster) \
-       (!tc2_pm_use_count[0][cluster] && \
-        !tc2_pm_use_count[1][cluster] && \
-        !tc2_pm_use_count[2][cluster])
-
-static int tc2_pm_power_up(unsigned int cpu, unsigned int cluster)
+static int tc2_pm_cpu_powerup(unsigned int cpu, unsigned int cluster)
 {
        pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
        if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster])
                return -EINVAL;
-
-       /*
-        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
-        * variant exists, we need to disable IRQs manually here.
-        */
-       local_irq_disable();
-       arch_spin_lock(&tc2_pm_lock);
-
-       if (tc2_cluster_unused(cluster))
-               ve_spc_powerdown(cluster, false);
-
-       tc2_pm_use_count[cpu][cluster]++;
-       if (tc2_pm_use_count[cpu][cluster] == 1) {
-               ve_spc_set_resume_addr(cluster, cpu,
-                                      virt_to_phys(mcpm_entry_point));
-               ve_spc_cpu_wakeup_irq(cluster, cpu, true);
-       } else if (tc2_pm_use_count[cpu][cluster] != 2) {
-               /*
-                * The only possible values are:
-                * 0 = CPU down
-                * 1 = CPU (still) up
-                * 2 = CPU requested to be up before it had a chance
-                *     to actually make itself down.
-                * Any other value is a bug.
-                */
-               BUG();
-       }
-
-       arch_spin_unlock(&tc2_pm_lock);
-       local_irq_enable();
-
+       ve_spc_set_resume_addr(cluster, cpu,
+                              virt_to_phys(mcpm_entry_point));
+       ve_spc_cpu_wakeup_irq(cluster, cpu, true);
        return 0;
 }
 
-static void tc2_pm_down(u64 residency)
+static int tc2_pm_cluster_powerup(unsigned int cluster)
 {
-       unsigned int mpidr, cpu, cluster;
-       bool last_man = false, skip_wfi = false;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       if (cluster >= TC2_CLUSTERS)
+               return -EINVAL;
+       ve_spc_powerdown(cluster, false);
+       return 0;
+}
 
+static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster)
+{
        pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
        BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER);
-
-       __mcpm_cpu_going_down(cpu, cluster);
-
-       arch_spin_lock(&tc2_pm_lock);
-       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
-       tc2_pm_use_count[cpu][cluster]--;
-       if (tc2_pm_use_count[cpu][cluster] == 0) {
-               ve_spc_cpu_wakeup_irq(cluster, cpu, true);
-               if (tc2_cluster_unused(cluster)) {
-                       ve_spc_powerdown(cluster, true);
-                       ve_spc_global_wakeup_irq(true);
-                       last_man = true;
-               }
-       } else if (tc2_pm_use_count[cpu][cluster] == 1) {
-               /*
-                * A power_up request went ahead of us.
-                * Even if we do not want to shut this CPU down,
-                * the caller expects a certain state as if the WFI
-                * was aborted.  So let's continue with cache cleaning.
-                */
-               skip_wfi = true;
-       } else
-               BUG();
-
+       ve_spc_cpu_wakeup_irq(cluster, cpu, true);
        /*
         * If the CPU is committed to power down, make sure
         * the power controller will be in charge of waking it
@@ -146,55 +80,38 @@ static void tc2_pm_down(u64 residency)
         * to the CPU by disabling the GIC CPU IF to prevent wfi
         * from completing execution behind power controller back
         */
-       if (!skip_wfi)
-               gic_cpu_if_down();
-
-       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
-               arch_spin_unlock(&tc2_pm_lock);
-
-               if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
-                       /*
-                        * On the Cortex-A15 we need to disable
-                        * L2 prefetching before flushing the cache.
-                        */
-                       asm volatile(
-                       "mcr    p15, 1, %0, c15, c0, 3 \n\t"
-                       "isb    \n\t"
-                       "dsb    "
-                       : : "r" (0x400) );
-               }
-
-               v7_exit_coherency_flush(all);
-
-               cci_disable_port_by_cpu(mpidr);
-
-               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
-       } else {
-               /*
-                * If last man then undo any setup done previously.
-                */
-               if (last_man) {
-                       ve_spc_powerdown(cluster, false);
-                       ve_spc_global_wakeup_irq(false);
-               }
-
-               arch_spin_unlock(&tc2_pm_lock);
-
-               v7_exit_coherency_flush(louis);
-       }
-
-       __mcpm_cpu_down(cpu, cluster);
+       gic_cpu_if_down();
+}
 
-       /* Now we are prepared for power-down, do it: */
-       if (!skip_wfi)
-               wfi();
+static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster)
+{
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       BUG_ON(cluster >= TC2_CLUSTERS);
+       ve_spc_powerdown(cluster, true);
+       ve_spc_global_wakeup_irq(true);
+}
 
-       /* Not dead at this point?  Let our caller cope. */
+static void tc2_pm_cpu_cache_disable(void)
+{
+       v7_exit_coherency_flush(louis);
 }
 
-static void tc2_pm_power_down(void)
+static void tc2_pm_cluster_cache_disable(void)
 {
-       tc2_pm_down(0);
+       if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
+               /*
+                * On the Cortex-A15 we need to disable
+                * L2 prefetching before flushing the cache.
+                */
+               asm volatile(
+               "mcr    p15, 1, %0, c15, c0, 3 \n\t"
+               "isb    \n\t"
+               "dsb    "
+               : : "r" (0x400) );
+       }
+
+       v7_exit_coherency_flush(all);
+       cci_disable_port_by_cpu(read_cpuid_mpidr());
 }
 
 static int tc2_core_in_reset(unsigned int cpu, unsigned int cluster)
@@ -217,27 +134,21 @@ static int tc2_pm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
        BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER);
 
        for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; ++tries) {
+               pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n",
+                        __func__, cpu, cluster,
+                        readl_relaxed(scc + RESET_CTRL));
+
                /*
-                * Only examine the hardware state if the target CPU has
-                * caught up at least as far as tc2_pm_down():
+                * We need the CPU to reach WFI, but the power
+                * controller may put the cluster in reset and
+                * power it off as soon as that happens, before
+                * we have a chance to see STANDBYWFI.
+                *
+                * So we need to check for both conditions:
                 */
-               if (ACCESS_ONCE(tc2_pm_use_count[cpu][cluster]) == 0) {
-                       pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n",
-                                __func__, cpu, cluster,
-                                readl_relaxed(scc + RESET_CTRL));
-
-                       /*
-                        * We need the CPU to reach WFI, but the power
-                        * controller may put the cluster in reset and
-                        * power it off as soon as that happens, before
-                        * we have a chance to see STANDBYWFI.
-                        *
-                        * So we need to check for both conditions:
-                        */
-                       if (tc2_core_in_reset(cpu, cluster) ||
-                           ve_spc_cpu_in_wfi(cpu, cluster))
-                               return 0; /* success: the CPU is halted */
-               }
+               if (tc2_core_in_reset(cpu, cluster) ||
+                   ve_spc_cpu_in_wfi(cpu, cluster))
+                       return 0; /* success: the CPU is halted */
 
                /* Otherwise, wait and retry: */
                msleep(POLL_MSEC);
@@ -246,72 +157,40 @@ static int tc2_pm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
        return -ETIMEDOUT; /* timeout */
 }
 
-static void tc2_pm_suspend(u64 residency)
+static void tc2_pm_cpu_suspend_prepare(unsigned int cpu, unsigned int cluster)
 {
-       unsigned int mpidr, cpu, cluster;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
        ve_spc_set_resume_addr(cluster, cpu, virt_to_phys(mcpm_entry_point));
-       tc2_pm_down(residency);
 }
 
-static void tc2_pm_powered_up(void)
+static void tc2_pm_cpu_is_up(unsigned int cpu, unsigned int cluster)
 {
-       unsigned int mpidr, cpu, cluster;
-       unsigned long flags;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-
        pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
        BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER);
-
-       local_irq_save(flags);
-       arch_spin_lock(&tc2_pm_lock);
-
-       if (tc2_cluster_unused(cluster)) {
-               ve_spc_powerdown(cluster, false);
-               ve_spc_global_wakeup_irq(false);
-       }
-
-       if (!tc2_pm_use_count[cpu][cluster])
-               tc2_pm_use_count[cpu][cluster] = 1;
-
        ve_spc_cpu_wakeup_irq(cluster, cpu, false);
        ve_spc_set_resume_addr(cluster, cpu, 0);
+}
 
-       arch_spin_unlock(&tc2_pm_lock);
-       local_irq_restore(flags);
+static void tc2_pm_cluster_is_up(unsigned int cluster)
+{
+       pr_debug("%s: cluster %u\n", __func__, cluster);
+       BUG_ON(cluster >= TC2_CLUSTERS);
+       ve_spc_powerdown(cluster, false);
+       ve_spc_global_wakeup_irq(false);
 }
 
 static const struct mcpm_platform_ops tc2_pm_power_ops = {
-       .power_up               = tc2_pm_power_up,
-       .power_down             = tc2_pm_power_down,
+       .cpu_powerup            = tc2_pm_cpu_powerup,
+       .cluster_powerup        = tc2_pm_cluster_powerup,
+       .cpu_suspend_prepare    = tc2_pm_cpu_suspend_prepare,
+       .cpu_powerdown_prepare  = tc2_pm_cpu_powerdown_prepare,
+       .cluster_powerdown_prepare = tc2_pm_cluster_powerdown_prepare,
+       .cpu_cache_disable      = tc2_pm_cpu_cache_disable,
+       .cluster_cache_disable  = tc2_pm_cluster_cache_disable,
        .wait_for_powerdown     = tc2_pm_wait_for_powerdown,
-       .suspend                = tc2_pm_suspend,
-       .powered_up             = tc2_pm_powered_up,
+       .cpu_is_up              = tc2_pm_cpu_is_up,
+       .cluster_is_up          = tc2_pm_cluster_is_up,
 };
 
-static bool __init tc2_pm_usage_count_init(void)
-{
-       unsigned int mpidr, cpu, cluster;
-
-       mpidr = read_cpuid_mpidr();
-       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-
-       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-       if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) {
-               pr_err("%s: boot CPU is out of bound!\n", __func__);
-               return false;
-       }
-       tc2_pm_use_count[cpu][cluster] = 1;
-       return true;
-}
-
 /*
  * Enable cluster-level coherency, in preparation for turning on the MMU.
  */
@@ -323,23 +202,9 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level)
 "      b       cci_enable_port_for_self ");
 }
 
-static void __init tc2_cache_off(void)
-{
-       pr_info("TC2: disabling cache during MCPM loopback test\n");
-       if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
-               /* disable L2 prefetching on the Cortex-A15 */
-               asm volatile(
-               "mcr    p15, 1, %0, c15, c0, 3 \n\t"
-               "isb    \n\t"
-               "dsb    "
-               : : "r" (0x400) );
-       }
-       v7_exit_coherency_flush(all);
-       cci_disable_port_by_cpu(read_cpuid_mpidr());
-}
-
 static int __init tc2_pm_init(void)
 {
+       unsigned int mpidr, cpu, cluster;
        int ret, irq;
        u32 a15_cluster_id, a7_cluster_id, sys_info;
        struct device_node *np;
@@ -379,14 +244,20 @@ static int __init tc2_pm_init(void)
        if (!cci_probed())
                return -ENODEV;
 
-       if (!tc2_pm_usage_count_init())
+       mpidr = read_cpuid_mpidr();
+       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+       if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) {
+               pr_err("%s: boot CPU is out of bound!\n", __func__);
                return -EINVAL;
+       }
 
        ret = mcpm_platform_register(&tc2_pm_power_ops);
        if (!ret) {
                mcpm_sync_init(tc2_pm_power_up_setup);
                /* test if we can (re)enable the CCI on our own */
-               BUG_ON(mcpm_loopback(tc2_cache_off) != 0);
+               BUG_ON(mcpm_loopback(tc2_pm_cluster_cache_disable) != 0);
                pr_info("TC2 power management initialized\n");
        }
        return ret;
index 0958b6981773c19527973916c65b3e703c5633f8..e98d15eaa7994c7349d1db8df4dd19f684b85ba6 100644 (file)
@@ -142,7 +142,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
                                                           &pdev->dev);
        const struct imx_weim_devtype *devtype = of_id->data;
        struct device_node *child;
-       int ret;
+       int ret, have_child = 0;
 
        if (devtype == &imx50_weim_devtype) {
                ret = imx_weim_gpr_setup(pdev);
@@ -155,14 +155,15 @@ static int __init weim_parse_dt(struct platform_device *pdev,
                        continue;
 
                ret = weim_timing_setup(child, base, devtype);
-               if (ret) {
-                       dev_err(&pdev->dev, "%s set timing failed.\n",
+               if (ret)
+                       dev_warn(&pdev->dev, "%s set timing failed.\n",
                                child->full_name);
-                       return ret;
-               }
+               else
+                       have_child = 1;
        }
 
-       ret = of_platform_populate(pdev->dev.of_node,
+       if (have_child)
+               ret = of_platform_populate(pdev->dev.of_node,
                                   of_default_bus_match_table,
                                   NULL, &pdev->dev);
        if (ret)
index b690cdba163b85b7c81a60cb1ac0cea8253dcc5c..8780868458a09e9b35d7fdee97f732663da0a61c 100644 (file)
 #define IMX6QDL_PLL6_BYPASS                    235
 #define IMX6QDL_PLL7_BYPASS                    236
 #define IMX6QDL_CLK_GPT_3M                     237
-#define IMX6QDL_CLK_END                                238
+#define IMX6QDL_CLK_VIDEO_27M                  238
+#define IMX6QDL_CLK_MIPI_CORE_CFG              239
+#define IMX6QDL_CLK_MIPI_IPG                   240
+#define IMX6QDL_CLK_END                                241
 
 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
index c877cad61a132586086c6c51ef327a2877d393d2..d16f4c82c568f13ad6e025d28951cb8978e4c3e2 100644 (file)
 #define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1      (0x1 << 6)
 #define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0      (0x2 << 6)
 #define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1      (0x3 << 6)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_SHIFT          4
 #define IMX6Q_GPR3_MIPI_MUX_CTL_MASK           (0x3 << 4)
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0       (0x0 << 4)
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1       (0x1 << 4)