forked from Minki/linux
Exynos MCPM support for v3.16
- 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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJTeo2RAAoJEA0Cl+kVi2xqynAQAInNHE2zWbOj/h9VcOV4+Upt VTobcgMiwEKZ530vkW3dq0acs24M6BU/OEBDP9qCPKG5q9qdjQcmiIlwjmzWiPJM VBi05exFXAxcaOmj4SBl0rkFCHrpKu64B0YJrjKZz/zK9A1QN03kkYe8EYRnuwsH w3FN61JX/S+4MBvdgDL1KAvciHoZvNjhrsOFfY24+0vAMaQzWVhps49Tkg675MHO rZw9VV8nv0uJmOgFc8XnmlUe1DVTUHjBbCPC6Sy0H3H5DXzuMQOW1Y+qL0DLR9NJ bZDPYVaqpYK2cWvXqjqSNJz3sNpZhrWZi4BrVdnmWSlzuLSF8/DZom4gv+SNnd8+ DrvP/4wqGTzuhWq/gr+9T+/Lz2qzlyr8dGy86ohtBLwMocYwpufaEqU7iKIOxCrb IlpkM5EcstHKnSr8QinehVPGp8N1PqJDympYOgFb3hPDIDbKktNU2Wwgr4CDBN30 Qypd3+fHwU2SJtK34L5/+hDmxwQwB5gnpPbc//7Ir1Ld3ZTEXv9sn5Rtv0EXFK1E Xx/C4B+2COi3IGbELqyS1ax4twJr/t1EwxjZgQZO1LT2B9CtQeKKdrG/IpI+J6wL 9qjIRv4i0tICkGXyu/wwwhLAHqpDQ+FebWAqM3llpIcoTjBy3BOdjZ+C2R0mkS94 X2dRzKw0dswv8GpBTAYm =d5ZP -----END PGP SIGNATURE----- Merge tag 'exynos-mcpm' of http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/soc 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>
This commit is contained in:
commit
dca092f6d4
38
Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt
Normal file
38
Documentation/devicetree/bindings/arm/exynos/smp-sysram.txt
Normal file
@ -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>;
|
||||
};
|
||||
};
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -129,12 +129,10 @@
|
||||
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>;
|
||||
@ -371,6 +369,8 @@
|
||||
interrupts = <0 60 0>;
|
||||
clocks = <&clock CLK_I2C2>;
|
||||
clock-names = "i2c";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c2_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -382,6 +382,8 @@
|
||||
interrupts = <0 61 0>;
|
||||
clocks = <&clock CLK_I2C3>;
|
||||
clock-names = "i2c";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c3_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -393,6 +395,8 @@
|
||||
interrupts = <0 62 0>;
|
||||
clocks = <&clock CLK_I2C4>;
|
||||
clock-names = "i2c";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c4_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -404,6 +408,8 @@
|
||||
interrupts = <0 63 0>;
|
||||
clocks = <&clock CLK_I2C5>;
|
||||
clock-names = "i2c";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c5_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -415,6 +421,8 @@
|
||||
interrupts = <0 64 0>;
|
||||
clocks = <&clock CLK_I2C6>;
|
||||
clock-names = "i2c";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c6_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -426,6 +434,8 @@
|
||||
interrupts = <0 65 0>;
|
||||
clocks = <&clock CLK_I2C7>;
|
||||
clock-names = "i2c";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c7_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,21 @@
|
||||
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";
|
||||
};
|
||||
|
@ -31,6 +31,24 @@
|
||||
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>;
|
||||
|
@ -20,7 +20,7 @@
|
||||
compatible = "samsung,trats2", "samsung,exynos4412", "samsung,exynos4";
|
||||
|
||||
aliases {
|
||||
i2c8 = &i2c_ak8975;
|
||||
i2c9 = &i2c_ak8975;
|
||||
};
|
||||
|
||||
memory {
|
||||
@ -80,7 +80,24 @@
|
||||
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 {
|
||||
@ -140,6 +157,38 @@
|
||||
};
|
||||
};
|
||||
|
||||
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>;
|
||||
@ -586,8 +635,8 @@
|
||||
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";
|
||||
|
||||
@ -607,6 +656,23 @@
|
||||
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>;
|
||||
@ -647,10 +713,11 @@
|
||||
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>;
|
||||
|
||||
|
@ -37,6 +37,24 @@
|
||||
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>;
|
||||
|
@ -72,6 +72,24 @@
|
||||
};
|
||||
};
|
||||
|
||||
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>;
|
||||
|
147
arch/arm/boot/dts/exynos5420-peach-pit.dts
Normal file
147
arch/arm/boot/dts/exynos5420-peach-pit.dts
Normal file
@ -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>;
|
||||
};
|
@ -624,6 +624,34 @@
|
||||
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>;
|
||||
|
@ -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 {
|
||||
@ -100,6 +106,7 @@
|
||||
compatible = "arm,cortex-a7";
|
||||
reg = <0x102>;
|
||||
clock-frequency = <1000000000>;
|
||||
cci-control-port = <&cci_control0>;
|
||||
};
|
||||
|
||||
cpu7: cpu@103 {
|
||||
@ -107,6 +114,44 @@
|
||||
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>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -125,7 +170,7 @@
|
||||
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>;
|
||||
@ -169,7 +214,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mct@101C0000 {
|
||||
mct: mct@101C0000 {
|
||||
compatible = "samsung,exynos4210-mct";
|
||||
reg = <0x101C0000 0x800>;
|
||||
interrupt-controller;
|
||||
@ -270,7 +315,7 @@
|
||||
interrupts = <0 47 0>;
|
||||
};
|
||||
|
||||
rtc@101E0000 {
|
||||
rtc: rtc@101E0000 {
|
||||
clocks = <&clock CLK_RTC>;
|
||||
clock-names = "rtc";
|
||||
status = "disabled";
|
||||
@ -430,22 +475,22 @@
|
||||
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";
|
||||
};
|
||||
@ -465,14 +510,14 @@
|
||||
#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";
|
||||
@ -632,7 +677,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
hdmi@14530000 {
|
||||
hdmi: hdmi@14530000 {
|
||||
compatible = "samsung,exynos4212-hdmi";
|
||||
reg = <0x14530000 0x70000>;
|
||||
interrupts = <0 95 0>;
|
||||
@ -644,7 +689,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mixer@14450000 {
|
||||
mixer: mixer@14450000 {
|
||||
compatible = "samsung,exynos5420-mixer";
|
||||
reg = <0x14450000 0x10000>;
|
||||
interrupts = <0 94 0>;
|
||||
@ -715,7 +760,7 @@
|
||||
clock-names = "tmu_apbif", "tmu_triminfo_apbif";
|
||||
};
|
||||
|
||||
watchdog@101D0000 {
|
||||
watchdog: watchdog@101D0000 {
|
||||
compatible = "samsung,exynos5420-wdt";
|
||||
reg = <0x101D0000 0x100>;
|
||||
interrupts = <0 42 0>;
|
||||
@ -724,7 +769,7 @@
|
||||
samsung,syscon-phandle = <&pmu_system_controller>;
|
||||
};
|
||||
|
||||
sss@10830000 {
|
||||
sss: sss@10830000 {
|
||||
compatible = "samsung,exynos4210-secss";
|
||||
reg = <0x10830000 0x10000>;
|
||||
interrupts = <0 112 0>;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -23,13 +23,6 @@
|
||||
|
||||
#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
|
||||
|
351
arch/arm/mach-exynos/mcpm-exynos.c
Normal file
351
arch/arm/mach-exynos/mcpm-exynos.c
Normal file
@ -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);
|
@ -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>
|
||||
@ -33,11 +34,33 @@
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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)
|
||||
@ -105,8 +106,17 @@
|
||||
#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)
|
||||
@ -313,4 +323,6 @@
|
||||
|
||||
#define EXYNOS5_OPTION_USE_RETENTION (1 << 4)
|
||||
|
||||
#define EXYNOS5420_SWRESET_KFC_SEL 0x3
|
||||
|
||||
#endif /* __ASM_ARCH_REGS_PMU_H */
|
||||
|
Loading…
Reference in New Issue
Block a user