Merge tag 'exynos-mcpm' of http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux...
authorOlof Johansson <olof@lixom.net>
Thu, 29 May 2014 16:48:55 +0000 (09:48 -0700)
committerOlof Johansson <olof@lixom.net>
Thu, 29 May 2014 16:48:55 +0000 (09:48 -0700)
Merge "Exynos MCPM support for v3.16" from Kukjin Kim:

- adding MCPM backend support for SMP secondary boot and core switching
on Samsung's Exynos5420.

Tested on exynos5420-smdk5420 and exynos5420 based chromebook (peach-pit)
using the "/dev/b.L_switcher" user interface. Secondary core boot-up has
also been tested on both the boards.

* tag 'exynos-mcpm' of http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
  ARM: EXYNOS: Add MCPM call-back functions
  ARM: dts: add CCI node for exynos5420
  ARM: EXYNOS: Add generic cluster power control functions
  ARM: EXYNOS: use generic exynos cpu power control functions
  ARM: EXYNOS: Add generic cpu power control functions for exynos SoCs

Signed-off-by: Olof Johansson <olof@lixom.net>
23 files changed:
Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt [new file with mode: 0644]
arch/arm/Kconfig
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/exynos4412-trats2.dts
arch/arm/boot/dts/exynos4x12.dtsi
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5420-peach-pit.dts [new file with mode: 0644]
arch/arm/boot/dts/exynos5420-pinctrl.dtsi
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/Makefile
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/exynos.c
arch/arm/mach-exynos/firmware.c
arch/arm/mach-exynos/hotplug.c
arch/arm/mach-exynos/include/mach/map.h
arch/arm/mach-exynos/mcpm-exynos.c [new file with mode: 0644]
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm.c
arch/arm/mach-exynos/regs-pmu.h

diff --git a/Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt b/Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt
new file mode 100644 (file)
index 0000000..4a0a4f7
--- /dev/null
@@ -0,0 +1,38 @@
+Samsung Exynos SYSRAM for SMP bringup:
+------------------------------------
+
+Samsung SMP-capable Exynos SoCs use part of the SYSRAM for the bringup
+of the secondary cores. Once the core gets powered up it executes the
+code that is residing at some specific location of the SYSRAM.
+
+Therefore reserved section sub-nodes have to be added to the mmio-sram
+declaration. These nodes are of two types depending upon secure or
+non-secure execution environment.
+
+Required sub-node properties:
+- compatible : depending upon boot mode, should be
+               "samsung,exynos4210-sysram" : for Secure SYSRAM
+               "samsung,exynos4210-sysram-ns" : for Non-secure SYSRAM
+
+The rest of the properties should follow the generic mmio-sram discription
+found in ../../misc/sysram.txt
+
+Example:
+
+       sysram@02020000 {
+               compatible = "mmio-sram";
+               reg = <0x02020000 0x54000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x02020000 0x54000>;
+
+               smp-sysram@0 {
+                       compatible = "samsung,exynos4210-sysram";
+                       reg = <0x0 0x1000>;
+               };
+
+               smp-sysram@53000 {
+                       compatible = "samsung,exynos4210-sysram-ns";
+                       reg = <0x53000 0x1000>;
+               };
+       };
index f849690eb8887f26484d2d76a21acd9c593f6cb9..3bf70415542e8eb5cafc51bec30a5fcab29441ec 100644 (file)
@@ -843,6 +843,7 @@ config ARCH_EXYNOS
        select HAVE_S3C_RTC if RTC_CLASS
        select NEED_MACH_MEMORY_H
        select SPARSE_IRQ
+       select SRAM
        select USE_OF
        help
          Support for SAMSUNG's EXYNOS SoCs (EXYNOS4/5)
index 7ec6ec076417523c1977cd6ebc9e2004e68f9949..ff7a04b68d88f7cba7b53469781258b2b9aa8706 100644 (file)
@@ -74,6 +74,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
        exynos5250-smdk5250.dtb \
        exynos5250-snow.dtb \
        exynos5420-arndale-octa.dtb \
+       exynos5420-peach-pit.dtb \
        exynos5420-smdk5420.dtb \
        exynos5440-sd5v1.dtb \
        exynos5440-ssdk5440.dtb
index 2f8bcd068d171644dd5bcd5266b34d64aa315de9..58ff8e28c74f3c01564cb6cf344a76e45f99a1b4 100644 (file)
                status = "disabled";
                #address-cells = <1>;
                #size-cells = <1>;
+               #clock-cells = <1>;
+               clock-output-names = "cam_a_clkout", "cam_b_clkout";
                ranges;
 
-               clock_cam: clock-controller {
-                        #clock-cells = <1>;
-               };
-
                fimc_0: fimc@11800000 {
                        compatible = "samsung,exynos4210-fimc";
                        reg = <0x11800000 0x1000>;
                interrupts = <0 60 0>;
                clocks = <&clock CLK_I2C2>;
                clock-names = "i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_bus>;
                status = "disabled";
        };
 
                interrupts = <0 61 0>;
                clocks = <&clock CLK_I2C3>;
                clock-names = "i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c3_bus>;
                status = "disabled";
        };
 
                interrupts = <0 62 0>;
                clocks = <&clock CLK_I2C4>;
                clock-names = "i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c4_bus>;
                status = "disabled";
        };
 
                interrupts = <0 63 0>;
                clocks = <&clock CLK_I2C5>;
                clock-names = "i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c5_bus>;
                status = "disabled";
        };
 
                interrupts = <0 64 0>;
                clocks = <&clock CLK_I2C6>;
                clock-names = "i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c6_bus>;
                status = "disabled";
        };
 
                interrupts = <0 65 0>;
                clocks = <&clock CLK_I2C7>;
                clock-names = "i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c7_bus>;
                status = "disabled";
        };
 
index 63e34b24b04f7fbf35b4f78e7e17ee8b4a314d05..9296dee10e264035e774c6a21b0a5d782eb4c52b 100644 (file)
                bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1";
        };
 
+       sysram@02020000 {
+               smp-sysram@0 {
+                       status = "disabled";
+               };
+
+               smp-sysram@5000 {
+                       compatible = "samsung,exynos4210-sysram";
+                       reg = <0x5000 0x1000>;
+               };
+
+               smp-sysram@1f000 {
+                       status = "disabled";
+               };
+       };
+
        mct@10050000 {
                compatible = "none";
        };
index cacf6140dd2f58be5351f797d889d8b0563e461c..ee3001f38821a7d9ad32b93be4ad414a4f3070e6 100644 (file)
                pinctrl2 = &pinctrl_2;
        };
 
+       sysram@02020000 {
+               compatible = "mmio-sram";
+               reg = <0x02020000 0x20000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x02020000 0x20000>;
+
+               smp-sysram@0 {
+                       compatible = "samsung,exynos4210-sysram";
+                       reg = <0x0 0x1000>;
+               };
+
+               smp-sysram@1f000 {
+                       compatible = "samsung,exynos4210-sysram-ns";
+                       reg = <0x1f000 0x1000>;
+               };
+       };
+
        pd_lcd1: lcd1-power-domain@10023CA0 {
                compatible = "samsung,exynos4210-pd";
                reg = <0x10023CA0 0x20>;
index 9583563dd0ef7a3f0d4cd89765a20bb243b10117..f621fd976815cfcd93bd0d636a16ba34c1e1a0de 100644 (file)
@@ -20,7 +20,7 @@
        compatible = "samsung,trats2", "samsung,exynos4412", "samsung,exynos4";
 
        aliases {
-               i2c8 = &i2c_ak8975;
+               i2c9 = &i2c_ak8975;
        };
 
        memory {
                        enable-active-high;
                };
 
-               /* More to come */
+               cam_af_reg: voltage-regulator-3 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "CAM_AF";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       gpio = <&gpm0 4 0>;
+                       enable-active-high;
+               };
+
+               cam_isp_core_reg: voltage-regulator-4 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "CAM_ISP_CORE_1.2V_EN";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       gpio = <&gpm0 3 0>;
+                       enable-active-high;
+                       regulator-always-on;
+               };
        };
 
        gpio-keys {
                };
        };
 
+       i2c_0: i2c@13860000 {
+               samsung,i2c-sda-delay = <100>;
+               samsung,i2c-slave-addr = <0x10>;
+               samsung,i2c-max-bus-freq = <400000>;
+               pinctrl-0 = <&i2c0_bus>;
+               pinctrl-names = "default";
+               status = "okay";
+
+               s5c73m3@3c {
+                       compatible = "samsung,s5c73m3";
+                       reg = <0x3c>;
+                       standby-gpios = <&gpm0 1 1>;   /* ISP_STANDBY */
+                       xshutdown-gpios = <&gpf1 3 1>; /* ISP_RESET */
+                       vdd-int-supply = <&buck9_reg>;
+                       vddio-cis-supply = <&ldo9_reg>;
+                       vdda-supply = <&ldo17_reg>;
+                       vddio-host-supply = <&ldo18_reg>;
+                       vdd-af-supply = <&cam_af_reg>;
+                       vdd-reg-supply = <&cam_io_reg>;
+                       clock-frequency = <24000000>;
+                       /* CAM_A_CLKOUT */
+                       clocks = <&camera 0>;
+                       clock-names = "cis_extclk";
+                       port {
+                               s5c73m3_ep: endpoint {
+                                       remote-endpoint = <&csis0_ep>;
+                                       data-lanes = <1 2 3 4>;
+                               };
+                       };
+               };
+       };
+
        i2c@138D0000 {
                samsung,i2c-sda-delay = <100>;
                samsung,i2c-slave-addr = <0x10>;
                status = "okay";
        };
 
-       camera {
-               pinctrl-0 = <&cam_port_b_clk_active>;
+       camera: camera {
+               pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>;
                pinctrl-names = "default";
                status = "okay";
 
                        status = "okay";
                };
 
+               csis_0: csis@11880000 {
+                       status = "okay";
+                       vddcore-supply = <&ldo8_reg>;
+                       vddio-supply = <&ldo10_reg>;
+                       clock-frequency = <176000000>;
+
+                       /* Camera C (3) MIPI CSI-2 (CSIS0) */
+                       port@3 {
+                               reg = <3>;
+                               csis0_ep: endpoint {
+                                       remote-endpoint = <&s5c73m3_ep>;
+                                       data-lanes = <1 2 3 4>;
+                                       samsung,csis-hs-settle = <12>;
+                               };
+                       };
+               };
+
                csis_1: csis@11890000 {
                        vddcore-supply = <&ldo8_reg>;
                        vddio-supply = <&ldo10_reg>;
                                        reg = <0x10>;
                                        svdda-supply = <&cam_io_reg>;
                                        svddio-supply = <&ldo19_reg>;
+                                       afvdd-supply = <&ldo19_reg>;
                                        clock-frequency = <24000000>;
                                        /* CAM_B_CLKOUT */
-                                       clocks = <&clock_cam 1>;
-                                       clock-names = "mclk";
+                                       clocks = <&camera 1>;
+                                       clock-names = "extclk";
                                        samsung,camclk-out = <1>;
                                        gpios = <&gpm1 6 0>;
 
index c4a9306f8529ab84ce3836781d1795b83c735e15..70e3765b51eee263bd921f35c57dafcb1936ca9f 100644 (file)
                interrupts = <2 2>, <3 2>, <18 2>, <19 2>;
        };
 
+       sysram@02020000 {
+               compatible = "mmio-sram";
+               reg = <0x02020000 0x40000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x02020000 0x40000>;
+
+               smp-sysram@0 {
+                       compatible = "samsung,exynos4210-sysram";
+                       reg = <0x0 0x1000>;
+               };
+
+               smp-sysram@2f000 {
+                       compatible = "samsung,exynos4210-sysram-ns";
+                       reg = <0x2f000 0x1000>;
+               };
+       };
+
        pd_isp: isp-power-domain@10023CA0 {
                compatible = "samsung,exynos4210-pd";
                reg = <0x10023CA0 0x20>;
index 37423314a02826a66670776c03109f1526449bc7..e44693e2cfdaa9ae7a79e5b6f5e2476e6570a8d7 100644 (file)
                };
        };
 
+       sysram@02020000 {
+               compatible = "mmio-sram";
+               reg = <0x02020000 0x30000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x02020000 0x30000>;
+
+               smp-sysram@0 {
+                       compatible = "samsung,exynos4210-sysram";
+                       reg = <0x0 0x1000>;
+               };
+
+               smp-sysram@2f000 {
+                       compatible = "samsung,exynos4210-sysram-ns";
+                       reg = <0x2f000 0x1000>;
+               };
+       };
+
        pd_gsc: gsc-power-domain@10044000 {
                compatible = "samsung,exynos4210-pd";
                reg = <0x10044000 0x20>;
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
new file mode 100644 (file)
index 0000000..fae33dd
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Google Peach Pit Rev 6+ board device tree source
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "exynos5420.dtsi"
+
+/ {
+       model = "Google Peach Pit Rev 6+";
+
+       compatible = "google,pit-rev16",
+               "google,pit-rev15", "google,pit-rev14",
+               "google,pit-rev13", "google,pit-rev12",
+               "google,pit-rev11", "google,pit-rev10",
+               "google,pit-rev9", "google,pit-rev8",
+               "google,pit-rev7", "google,pit-rev6",
+               "google,pit", "google,peach","samsung,exynos5420",
+               "samsung,exynos5";
+
+       memory {
+               reg = <0x20000000 0x80000000>;
+       };
+
+       fixed-rate-clocks {
+               oscclk {
+                       compatible = "samsung,exynos5420-oscclk";
+                       clock-frequency = <24000000>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&power_key_irq>;
+
+               power {
+                       label = "Power";
+                       gpios = <&gpx1 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+                       gpio-key,wakeup;
+               };
+       };
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 0 1000000 0>;
+               brightness-levels = <0 100 500 1000 1500 2000 2500 2800>;
+               default-brightness-level = <7>;
+               pinctrl-0 = <&pwm0_out>;
+               pinctrl-names = "default";
+       };
+};
+
+&pinctrl_0 {
+       tpm_irq: tpm-irq {
+               samsung,pins = "gpx1-0";
+               samsung,pin-function = <0>;
+               samsung,pin-pud = <0>;
+               samsung,pin-drv = <0>;
+       };
+
+       power_key_irq: power-key-irq {
+               samsung,pins = "gpx1-2";
+               samsung,pin-function = <0>;
+               samsung,pin-pud = <0>;
+               samsung,pin-drv = <0>;
+       };
+};
+
+&rtc {
+       status = "okay";
+};
+
+&uart_3 {
+       status = "okay";
+};
+
+&mmc_0 {
+       status = "okay";
+       num-slots = <1>;
+       broken-cd;
+       caps2-mmc-hs200-1_8v;
+       supports-highspeed;
+       non-removable;
+       card-detect-delay = <200>;
+       clock-frequency = <400000000>;
+       samsung,dw-mshc-ciu-div = <3>;
+       samsung,dw-mshc-sdr-timing = <0 4>;
+       samsung,dw-mshc-ddr-timing = <0 2>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+
+       slot@0 {
+               reg = <0>;
+               bus-width = <8>;
+       };
+};
+
+&mmc_2 {
+       status = "okay";
+       num-slots = <1>;
+       supports-highspeed;
+       card-detect-delay = <200>;
+       clock-frequency = <400000000>;
+       samsung,dw-mshc-ciu-div = <3>;
+       samsung,dw-mshc-sdr-timing = <2 3>;
+       samsung,dw-mshc-ddr-timing = <1 2>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+
+       slot@0 {
+               reg = <0>;
+               bus-width = <4>;
+       };
+};
+
+&hsi2c_9 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       tpm@20 {
+               compatible = "infineon,slb9645tt";
+               reg = <0x20>;
+
+               /* Unused irq; but still need to configure the pins */
+               pinctrl-names = "default";
+               pinctrl-0 = <&tpm_irq>;
+       };
+};
+
+/*
+ * Use longest HW watchdog in SoC (32 seconds) since the hardware
+ * watchdog provides no debugging information (compared to soft/hard
+ * lockup detectors) and so should be last resort.
+ */
+&watchdog {
+       timeout-sec = <32>;
+};
index e62c8eb57438988c0c5493cfb2a88c2471e624e3..ba686e40eac7965942555a1f5eca9a81bb57ef39 100644 (file)
                        samsung,pin-drv = <0>;
                };
 
+               pwm0_out: pwm0-out {
+                       samsung,pins = "gpb2-0";
+                       samsung,pin-function = <2>;
+                       samsung,pin-pud = <0>;
+                       samsung,pin-drv = <0>;
+               };
+
+               pwm1_out: pwm1-out {
+                       samsung,pins = "gpb2-1";
+                       samsung,pin-function = <2>;
+                       samsung,pin-pud = <0>;
+                       samsung,pin-drv = <0>;
+               };
+
+               pwm2_out: pwm2-out {
+                       samsung,pins = "gpb2-2";
+                       samsung,pin-function = <2>;
+                       samsung,pin-pud = <0>;
+                       samsung,pin-drv = <0>;
+               };
+
+               pwm3_out: pwm3-out {
+                       samsung,pins = "gpb2-3";
+                       samsung,pin-function = <2>;
+                       samsung,pin-pud = <0>;
+                       samsung,pin-drv = <0>;
+               };
+
                i2c7_hs_bus: i2c7-hs-bus {
                        samsung,pins = "gpb2-2", "gpb2-3";
                        samsung,pin-function = <3>;
index c3a9a66c57678f9a5dddd75e11e55be913e3c3c0..00d541a1a3d49192316bdc8ee3bb993585677a73 100644 (file)
@@ -58,6 +58,7 @@
                        compatible = "arm,cortex-a15";
                        reg = <0x0>;
                        clock-frequency = <1800000000>;
+                       cci-control-port = <&cci_control1>;
                };
 
                cpu1: cpu@1 {
@@ -65,6 +66,7 @@
                        compatible = "arm,cortex-a15";
                        reg = <0x1>;
                        clock-frequency = <1800000000>;
+                       cci-control-port = <&cci_control1>;
                };
 
                cpu2: cpu@2 {
@@ -72,6 +74,7 @@
                        compatible = "arm,cortex-a15";
                        reg = <0x2>;
                        clock-frequency = <1800000000>;
+                       cci-control-port = <&cci_control1>;
                };
 
                cpu3: cpu@3 {
@@ -79,6 +82,7 @@
                        compatible = "arm,cortex-a15";
                        reg = <0x3>;
                        clock-frequency = <1800000000>;
+                       cci-control-port = <&cci_control1>;
                };
 
                cpu4: cpu@100 {
@@ -86,6 +90,7 @@
                        compatible = "arm,cortex-a7";
                        reg = <0x100>;
                        clock-frequency = <1000000000>;
+                       cci-control-port = <&cci_control0>;
                };
 
                cpu5: cpu@101 {
@@ -93,6 +98,7 @@
                        compatible = "arm,cortex-a7";
                        reg = <0x101>;
                        clock-frequency = <1000000000>;
+                       cci-control-port = <&cci_control0>;
                };
 
                cpu6: cpu@102 {
                        compatible = "arm,cortex-a7";
                        reg = <0x102>;
                        clock-frequency = <1000000000>;
+                       cci-control-port = <&cci_control0>;
                };
 
                cpu7: cpu@103 {
                        compatible = "arm,cortex-a7";
                        reg = <0x103>;
                        clock-frequency = <1000000000>;
+                       cci-control-port = <&cci_control0>;
+               };
+       };
+
+       cci@10d20000 {
+               compatible = "arm,cci-400";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0x10d20000 0x1000>;
+               ranges = <0x0 0x10d20000 0x6000>;
+
+               cci_control0: slave-if@4000 {
+                       compatible = "arm,cci-400-ctrl-if";
+                       interface-type = "ace";
+                       reg = <0x4000 0x1000>;
+               };
+               cci_control1: slave-if@5000 {
+                       compatible = "arm,cci-400-ctrl-if";
+                       interface-type = "ace";
+                       reg = <0x5000 0x1000>;
+               };
+       };
+
+       sysram@02020000 {
+               compatible = "mmio-sram";
+               reg = <0x02020000 0x54000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x02020000 0x54000>;
+
+               smp-sysram@0 {
+                       compatible = "samsung,exynos4210-sysram";
+                       reg = <0x0 0x1000>;
+               };
+
+               smp-sysram@53000 {
+                       compatible = "samsung,exynos4210-sysram-ns";
+                       reg = <0x53000 0x1000>;
                };
        };
 
                clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in";
        };
 
-       codec@11000000 {
+       mfc: codec@11000000 {
                compatible = "samsung,mfc-v7";
                reg = <0x11000000 0x10000>;
                interrupts = <0 96 0>;
                status = "disabled";
        };
 
-       mct@101C0000 {
+       mct: mct@101C0000 {
                compatible = "samsung,exynos4210-mct";
                reg = <0x101C0000 0x800>;
                interrupt-controller;
                interrupts = <0 47 0>;
        };
 
-       rtc@101E0000 {
+       rtc: rtc@101E0000 {
                clocks = <&clock CLK_RTC>;
                clock-names = "rtc";
                status = "disabled";
                status = "disabled";
        };
 
-       serial@12C00000 {
+       uart_0: serial@12C00000 {
                clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
                clock-names = "uart", "clk_uart_baud0";
        };
 
-       serial@12C10000 {
+       uart_1: serial@12C10000 {
                clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
                clock-names = "uart", "clk_uart_baud0";
        };
 
-       serial@12C20000 {
+       uart_2: serial@12C20000 {
                clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
                clock-names = "uart", "clk_uart_baud0";
        };
 
-       serial@12C30000 {
+       uart_3: serial@12C30000 {
                clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
                clock-names = "uart", "clk_uart_baud0";
        };
                #phy-cells = <0>;
        };
 
-       dp-controller@145B0000 {
+       dp: dp-controller@145B0000 {
                clocks = <&clock CLK_DP1>;
                clock-names = "dp";
                phys = <&dp_phy>;
                phy-names = "dp";
        };
 
-       fimd@14400000 {
+       fimd: fimd@14400000 {
                samsung,power-domain = <&disp_pd>;
                clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
                clock-names = "sclk_fimd", "fimd";
                status = "disabled";
        };
 
-       hdmi@14530000 {
+       hdmi: hdmi@14530000 {
                compatible = "samsung,exynos4212-hdmi";
                reg = <0x14530000 0x70000>;
                interrupts = <0 95 0>;
                status = "disabled";
        };
 
-       mixer@14450000 {
+       mixer: mixer@14450000 {
                compatible = "samsung,exynos5420-mixer";
                reg = <0x14450000 0x10000>;
                interrupts = <0 94 0>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
        };
 
-        watchdog@101D0000 {
+        watchdog: watchdog@101D0000 {
                compatible = "samsung,exynos5420-wdt";
                reg = <0x101D0000 0x100>;
                interrupts = <0 42 0>;
                samsung,syscon-phandle = <&pmu_system_controller>;
         };
 
-       sss@10830000 {
+       sss: sss@10830000 {
                compatible = "samsung,exynos4210-secss";
                reg = <0x10830000 0x10000>;
                interrupts = <0 112 0>;
index fc8bf18e222ddbd855e407547936e85dcc751499..1602abce6ec043ae40b5e97bd3d296901503750c 100644 (file)
@@ -110,4 +110,12 @@ config SOC_EXYNOS5440
 
 endmenu
 
+config EXYNOS5420_MCPM
+       bool "Exynos5420 Multi-Cluster PM support"
+       depends on MCPM && SOC_EXYNOS5420
+       select ARM_CCI
+       help
+         This is needed to provide CPU and cluster power management
+         on Exynos5420 implementing big.LITTLE.
+
 endif
index a656dbe3b78c877e94ac88e34fab3eb1814ef3e3..01bc9b94a032de5a62e572f7b4848dbeb6a9149b 100644 (file)
@@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)     += firmware.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_exynos-smc.o            :=-Wa,-march=armv7-a$(plus_sec)
+
+obj-$(CONFIG_EXYNOS5420_MCPM)  += mcpm-exynos.o
index 9ef3f83efaffa642c9bbe26d68aa71750072c28e..7876ed04b7a5e35e323deca22f478d9701f6aae9 100644 (file)
@@ -18,6 +18,7 @@
 void mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1);
 
 struct map_desc;
+extern void __iomem *sysram_ns_base_addr;
 void exynos_init_io(void);
 void exynos_restart(enum reboot_mode mode, const char *cmd);
 void exynos_cpuidle_init(void);
@@ -62,5 +63,11 @@ struct exynos_pmu_conf {
 };
 
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+extern void exynos_cpu_power_down(int cpu);
+extern void exynos_cpu_power_up(int cpu);
+extern int  exynos_cpu_power_state(int cpu);
+extern void exynos_cluster_power_down(int cluster);
+extern void exynos_cluster_power_up(int cluster);
+extern int  exynos_cluster_power_state(int cluster);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
index b32a907d021d4a2b5a809a22899cb237464d0d57..e973ff5de7b394fdb11e5dd7962992c32485827c 100644 (file)
@@ -114,51 +114,6 @@ static struct map_desc exynos4_iodesc[] __initdata = {
        },
 };
 
-static struct map_desc exynos4_iodesc0[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_SYSRAM0),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc exynos4_iodesc1[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_SYSRAM1),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc exynos4210_iodesc[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM_NS,
-               .pfn            = __phys_to_pfn(EXYNOS4210_PA_SYSRAM_NS),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc exynos4x12_iodesc[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM_NS,
-               .pfn            = __phys_to_pfn(EXYNOS4x12_PA_SYSRAM_NS),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc exynos5250_iodesc[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM_NS,
-               .pfn            = __phys_to_pfn(EXYNOS5250_PA_SYSRAM_NS),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       },
-};
-
 static struct map_desc exynos5_iodesc[] __initdata = {
        {
                .virtual        = (unsigned long)S3C_VA_SYS,
@@ -180,11 +135,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(EXYNOS5_PA_SROMC),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM,
-               .pfn            = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5P_VA_CMU,
                .pfn            = __phys_to_pfn(EXYNOS5_PA_CMU),
@@ -280,20 +230,6 @@ static void __init exynos_map_io(void)
 
        if (soc_is_exynos5())
                iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
-
-       if (soc_is_exynos4210()) {
-               if (samsung_rev() == EXYNOS4210_REV_0)
-                       iotable_init(exynos4_iodesc0,
-                                               ARRAY_SIZE(exynos4_iodesc0));
-               else
-                       iotable_init(exynos4_iodesc1,
-                                               ARRAY_SIZE(exynos4_iodesc1));
-               iotable_init(exynos4210_iodesc, ARRAY_SIZE(exynos4210_iodesc));
-       }
-       if (soc_is_exynos4212() || soc_is_exynos4412())
-               iotable_init(exynos4x12_iodesc, ARRAY_SIZE(exynos4x12_iodesc));
-       if (soc_is_exynos5250())
-               iotable_init(exynos5250_iodesc, ARRAY_SIZE(exynos5250_iodesc));
 }
 
 void __init exynos_init_io(void)
index 932129ef26c66054a2bdeecaef9c0af1a9bba788..483dfcd690650c54674584169b99ef00967964d0 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <mach/map.h>
 
+#include "common.h"
 #include "smc.h"
 
 static int exynos_do_idle(void)
@@ -34,7 +35,12 @@ static int exynos_cpu_boot(int cpu)
 
 static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
 {
-       void __iomem *boot_reg = S5P_VA_SYSRAM_NS + 0x1c + 4*cpu;
+       void __iomem *boot_reg;
+
+       if (!sysram_ns_base_addr)
+               return -ENODEV;
+
+       boot_reg = sysram_ns_base_addr + 0x1c + 4*cpu;
 
        __raw_writel(boot_addr, boot_reg);
        return 0;
index 5eead530c6f8fa57ab8444911b19b684ef1e84fc..609c99ca59c44f7a5814a1696ceebe5982fa5837 100644 (file)
@@ -96,7 +96,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
 
                /* make cpu1 to be turned off at next WFI command */
                if (cpu == 1)
-                       __raw_writel(0, S5P_ARM_CORE1_CONFIGURATION);
+                       exynos_cpu_power_down(cpu);
 
                /*
                 * here's the WFI
index 7b046b59d9ecc8829a98699ed84a6ffcbad4a8f5..548269a606340aad4bd275684b4b9d98fc5e7f68 100644 (file)
 
 #include <plat/map-s5p.h>
 
-#define EXYNOS4_PA_SYSRAM0             0x02025000
-#define EXYNOS4_PA_SYSRAM1             0x02020000
-#define EXYNOS5_PA_SYSRAM              0x02020000
-#define EXYNOS4210_PA_SYSRAM_NS                0x0203F000
-#define EXYNOS4x12_PA_SYSRAM_NS                0x0204F000
-#define EXYNOS5250_PA_SYSRAM_NS                0x0204F000
-
 #define EXYNOS_PA_CHIPID               0x10000000
 
 #define EXYNOS4_PA_SYSCON              0x10010000
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
new file mode 100644 (file)
index 0000000..1ac618c
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * arch/arm/mach-exynos/mcpm-exynos.c
+ *
+ * Based on arch/arm/mach-vexpress/dcscb.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/arm-cci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+#include <asm/mcpm.h>
+
+#include "regs-pmu.h"
+#include "common.h"
+
+#define EXYNOS5420_CPUS_PER_CLUSTER    4
+#define EXYNOS5420_NR_CLUSTERS         2
+#define MCPM_BOOT_ADDR_OFFSET          0x1c
+
+/*
+ * The common v7_exit_coherency_flush API could not be used because of the
+ * Erratum 799270 workaround. This macro is the same as the common one (in
+ * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
+ */
+#define exynos_v7_exit_coherency_flush(level) \
+       asm volatile( \
+       "stmfd  sp!, {fp, ip}\n\t"\
+       "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
+       "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
+       "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
+       "isb\n\t"\
+       "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
+       "clrex\n\t"\
+       "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
+       "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
+       /* Dummy Load of a device register to avoid Erratum 799270 */ \
+       "ldr    r4, [%0]\n\t" \
+       "and    r4, r4, #0\n\t" \
+       "orr    r0, r0, r4\n\t" \
+       "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
+       "isb\n\t" \
+       "dsb\n\t" \
+       "ldmfd  sp!, {fp, ip}" \
+       : \
+       : "Ir" (S5P_INFORM0) \
+       : "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_cluster_power_control(unsigned int cluster, int enable)
+{
+       unsigned int tries = 100;
+       unsigned int val;
+
+       if (enable) {
+               exynos_cluster_power_up(cluster);
+               val = S5P_CORE_LOCAL_PWR_EN;
+       } else {
+               exynos_cluster_power_down(cluster);
+               val = 0;
+       }
+
+       /* Wait until cluster power control is applied */
+       while (tries--) {
+               if (exynos_cluster_power_state(cluster) == val)
+                       return 0;
+
+               cpu_relax();
+       }
+       pr_debug("timed out waiting for cluster %u to power %s\n", cluster,
+               enable ? "on" : "off");
+
+       return -ETIMEDOUT;
+}
+
+static int exynos_power_up(unsigned int cpu, unsigned int cluster)
+{
+       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+       int err = 0;
+
+       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+       if (cpu >= EXYNOS5420_CPUS_PER_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)
+                       err = exynos_cluster_power_control(cluster, 1);
+
+               if (!err)
+                       exynos_cpu_power_up(cpunr);
+               else
+                       exynos_cluster_power_control(cluster, 0);
+       } 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();
+       }
+
+       arch_spin_unlock(&exynos_mcpm_lock);
+       local_irq_enable();
+
+       return err;
+}
+
+/*
+ * 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)
+{
+       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);
+
+       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+                       cluster >= EXYNOS5420_NR_CLUSTERS);
+
+       __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))
+                       /* TODO: Turn off the cluster here to save power. */
+                       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_number() == 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));
+               }
+
+               /* Flush all cache levels for this cluster. */
+               exynos_v7_exit_coherency_flush(all);
+
+               /*
+                * 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(&exynos_mcpm_lock);
+
+               /* Disable and flush the local CPU cache. */
+               exynos_v7_exit_coherency_flush(louis);
+       }
+
+       __mcpm_cpu_down(cpu, cluster);
+
+       /* Now we are prepared for power-down, do it: */
+       if (!skip_wfi)
+               wfi();
+
+       /* Not dead at this point?  Let our caller cope. */
+}
+
+static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
+{
+       unsigned int tries = 100;
+       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);
+
+       /* 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 */
+               }
+
+               /* Otherwise, wait and retry: */
+               msleep(1);
+       }
+
+       return -ETIMEDOUT; /* timeout */
+}
+
+static const struct mcpm_platform_ops exynos_power_ops = {
+       .power_up               = exynos_power_up,
+       .power_down             = exynos_power_down,
+       .power_down_finish      = exynos_power_down_finish,
+};
+
+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.
+ */
+static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
+{
+       asm volatile ("\n"
+       "cmp    r0, #1\n"
+       "bxne   lr\n"
+       "b      cci_enable_port_for_self");
+}
+
+static int __init exynos_mcpm_init(void)
+{
+       struct device_node *node;
+       void __iomem *ns_sram_base_addr;
+       int ret;
+
+       node = of_find_compatible_node(NULL, NULL, "samsung,exynos5420");
+       if (!node)
+               return -ENODEV;
+       of_node_put(node);
+
+       if (!cci_probed())
+               return -ENODEV;
+
+       node = of_find_compatible_node(NULL, NULL,
+                       "samsung,exynos4210-sysram-ns");
+       if (!node)
+               return -ENODEV;
+
+       ns_sram_base_addr = of_iomap(node, 0);
+       of_node_put(node);
+       if (!ns_sram_base_addr) {
+               pr_err("failed to map non-secure iRAM base address\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * To increase the stability of KFC reset we need to program
+        * the PMU SPARE3 register
+        */
+       __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) {
+               iounmap(ns_sram_base_addr);
+               return ret;
+       }
+
+       mcpm_smp_set_ops();
+
+       pr_info("Exynos MCPM support installed\n");
+
+       /*
+        * Future entries into the kernel can now go
+        * through the cluster entry vectors.
+        */
+       __raw_writel(virt_to_phys(mcpm_entry_point),
+                       ns_sram_base_addr + MCPM_BOOT_ADDR_OFFSET);
+
+       iounmap(ns_sram_base_addr);
+
+       return ret;
+}
+
+early_initcall(exynos_mcpm_init);
index 03e5e9f9470536c01180963261dabf0c0c0eca08..78002c7344b349510e3bcd7cb36c1b1bd5a81d0c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/jiffies.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <linux/of_address.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
 
 extern void exynos4_secondary_startup(void);
 
+static void __iomem *sysram_base_addr;
+void __iomem *sysram_ns_base_addr;
+
+static void __init exynos_smp_prepare_sysram(void)
+{
+       struct device_node *node;
+
+       for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram") {
+               if (!of_device_is_available(node))
+                       continue;
+               sysram_base_addr = of_iomap(node, 0);
+               break;
+       }
+
+       for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram-ns") {
+               if (!of_device_is_available(node))
+                       continue;
+               sysram_ns_base_addr = of_iomap(node, 0);
+               break;
+       }
+}
+
 static inline void __iomem *cpu_boot_reg_base(void)
 {
        if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1)
                return S5P_INFORM5;
-       return S5P_VA_SYSRAM;
+       return sysram_base_addr;
 }
 
 static inline void __iomem *cpu_boot_reg(int cpu)
@@ -45,6 +68,8 @@ static inline void __iomem *cpu_boot_reg(int cpu)
        void __iomem *boot_reg;
 
        boot_reg = cpu_boot_reg_base();
+       if (!boot_reg)
+               return ERR_PTR(-ENODEV);
        if (soc_is_exynos4412())
                boot_reg += 4*cpu;
        else if (soc_is_exynos5420())
@@ -90,6 +115,7 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
        unsigned long timeout;
        unsigned long phys_cpu = cpu_logical_map(cpu);
+       int ret = -ENOSYS;
 
        /*
         * Set synchronisation state between this boot processor
@@ -107,15 +133,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
         */
        write_pen_release(phys_cpu);
 
-       if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
-               __raw_writel(S5P_CORE_LOCAL_PWR_EN,
-                            S5P_ARM_CORE1_CONFIGURATION);
-
+       if (!exynos_cpu_power_state(cpu)) {
+               exynos_cpu_power_up(cpu);
                timeout = 10;
 
                /* wait max 10 ms until cpu1 is on */
-               while ((__raw_readl(S5P_ARM_CORE1_STATUS)
-                       & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
+               while (exynos_cpu_power_state(cpu) != S5P_CORE_LOCAL_PWR_EN) {
                        if (timeout-- == 0)
                                break;
 
@@ -146,8 +169,18 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
                 * Try to set boot address using firmware first
                 * and fall back to boot register if it fails.
                 */
-               if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr))
+               ret = call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr);
+               if (ret && ret != -ENOSYS)
+                       goto fail;
+               if (ret == -ENOSYS) {
+                       void __iomem *boot_reg = cpu_boot_reg(phys_cpu);
+
+                       if (IS_ERR(boot_reg)) {
+                               ret = PTR_ERR(boot_reg);
+                               goto fail;
+                       }
                        __raw_writel(boot_addr, cpu_boot_reg(phys_cpu));
+               }
 
                call_firmware_op(cpu_boot, phys_cpu);
 
@@ -163,9 +196,10 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
         * now the secondary core is starting up let it run its
         * calibrations, then wait for it to finish
         */
+fail:
        spin_unlock(&boot_lock);
 
-       return pen_release != -1 ? -ENOSYS : 0;
+       return pen_release != -1 ? ret : 0;
 }
 
 /*
@@ -205,6 +239,8 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
        if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9)
                scu_enable(scu_base_addr());
 
+       exynos_smp_prepare_sysram();
+
        /*
         * Write the address of secondary startup into the
         * system-wide flags register. The boot monitor waits
@@ -217,12 +253,21 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
        for (i = 1; i < max_cpus; ++i) {
                unsigned long phys_cpu;
                unsigned long boot_addr;
+               int ret;
 
                phys_cpu = cpu_logical_map(i);
                boot_addr = virt_to_phys(exynos4_secondary_startup);
 
-               if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr))
+               ret = call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr);
+               if (ret && ret != -ENOSYS)
+                       break;
+               if (ret == -ENOSYS) {
+                       void __iomem *boot_reg = cpu_boot_reg(phys_cpu);
+
+                       if (IS_ERR(boot_reg))
+                               break;
                        __raw_writel(boot_addr, cpu_boot_reg(phys_cpu));
+               }
        }
 }
 
index 15af0ceb0a66a063d0c2ed948ca4a28a1109c777..3f2ae864582ec3c742f3ceabf5a0066549a52ceb 100644 (file)
@@ -100,6 +100,72 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
        return -ENOENT;
 }
 
+/**
+ * exynos_core_power_down : power down the specified cpu
+ * @cpu : the cpu to power down
+ *
+ * Power down the specified cpu. The sequence must be finished by a
+ * call to cpu_do_idle()
+ *
+ */
+void exynos_cpu_power_down(int cpu)
+{
+       __raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+}
+
+/**
+ * exynos_cpu_power_up : power up the specified cpu
+ * @cpu : the cpu to power up
+ *
+ * Power up the specified cpu
+ */
+void exynos_cpu_power_up(int cpu)
+{
+       __raw_writel(S5P_CORE_LOCAL_PWR_EN,
+                    EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+}
+
+/**
+ * exynos_cpu_power_state : returns the power state of the cpu
+ * @cpu : the cpu to retrieve the power state from
+ *
+ */
+int exynos_cpu_power_state(int cpu)
+{
+       return (__raw_readl(EXYNOS_ARM_CORE_STATUS(cpu)) &
+                       S5P_CORE_LOCAL_PWR_EN);
+}
+
+/**
+ * exynos_cluster_power_down : power down the specified cluster
+ * @cluster : the cluster to power down
+ */
+void exynos_cluster_power_down(int cluster)
+{
+       __raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_power_up : power up the specified cluster
+ * @cluster : the cluster to power up
+ */
+void exynos_cluster_power_up(int cluster)
+{
+       __raw_writel(S5P_CORE_LOCAL_PWR_EN,
+                    EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_power_state : returns the power state of the cluster
+ * @cluster : the cluster to retrieve the power state from
+ *
+ */
+int exynos_cluster_power_state(int cluster)
+{
+       return (__raw_readl(EXYNOS_COMMON_STATUS(cluster)) &
+                       S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
index 4f6a2560d0220e0244eb35d55f1ebc55e66cc734..4179f6a6d59520111a6743d7dfb3bf5bfd82ed9a 100644 (file)
@@ -38,6 +38,7 @@
 #define S5P_INFORM5                            S5P_PMUREG(0x0814)
 #define S5P_INFORM6                            S5P_PMUREG(0x0818)
 #define S5P_INFORM7                            S5P_PMUREG(0x081C)
+#define S5P_PMU_SPARE3                         S5P_PMUREG(0x090C)
 
 #define S5P_ARM_CORE0_LOWPWR                   S5P_PMUREG(0x1000)
 #define S5P_DIS_IRQ_CORE0                      S5P_PMUREG(0x1004)
 #define S5P_GPS_LOWPWR                         S5P_PMUREG(0x139C)
 #define S5P_GPS_ALIVE_LOWPWR                   S5P_PMUREG(0x13A0)
 
-#define S5P_ARM_CORE1_CONFIGURATION            S5P_PMUREG(0x2080)
-#define S5P_ARM_CORE1_STATUS                   S5P_PMUREG(0x2084)
+#define EXYNOS_ARM_CORE0_CONFIGURATION         S5P_PMUREG(0x2000)
+#define EXYNOS_ARM_CORE_CONFIGURATION(_nr)     \
+                       (EXYNOS_ARM_CORE0_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_ARM_CORE_STATUS(_nr)            \
+                       (EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
+
+#define EXYNOS_ARM_COMMON_CONFIGURATION                S5P_PMUREG(0x2500)
+#define EXYNOS_COMMON_CONFIGURATION(_nr)       \
+                       (EXYNOS_ARM_COMMON_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_COMMON_STATUS(_nr)              \
+                       (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x4)
 
 #define S5P_PAD_RET_MAUDIO_OPTION              S5P_PMUREG(0x3028)
 #define S5P_PAD_RET_GPIO_OPTION                        S5P_PMUREG(0x3108)
 
 #define EXYNOS5_OPTION_USE_RETENTION                           (1 << 4)
 
+#define EXYNOS5420_SWRESET_KFC_SEL                             0x3
+
 #endif /* __ASM_ARCH_REGS_PMU_H */