Commit dca092f6 authored by Olof Johansson's avatar Olof Johansson

Merge tag 'exynos-mcpm' of...

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: default avatarOlof Johansson <olof@lixom.net>
parents 4fd09120 ccf55117
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,11 +129,9 @@ camera {
status = "disabled";
#address-cells = <1>;
#size-cells = <1>;
ranges;
clock_cam: clock-controller {
#clock-cells = <1>;
};
clock-output-names = "cam_a_clkout", "cam_b_clkout";
ranges;
fimc_0: fimc@11800000 {
compatible = "samsung,exynos4210-fimc";
......@@ -371,6 +369,8 @@ i2c_2: i2c@13880000 {
interrupts = <0 60 0>;
clocks = <&clock CLK_I2C2>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c2_bus>;
status = "disabled";
};
......@@ -382,6 +382,8 @@ i2c_3: i2c@13890000 {
interrupts = <0 61 0>;
clocks = <&clock CLK_I2C3>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c3_bus>;
status = "disabled";
};
......@@ -393,6 +395,8 @@ i2c_4: i2c@138A0000 {
interrupts = <0 62 0>;
clocks = <&clock CLK_I2C4>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c4_bus>;
status = "disabled";
};
......@@ -404,6 +408,8 @@ i2c_5: i2c@138B0000 {
interrupts = <0 63 0>;
clocks = <&clock CLK_I2C5>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c5_bus>;
status = "disabled";
};
......@@ -415,6 +421,8 @@ i2c_6: i2c@138C0000 {
interrupts = <0 64 0>;
clocks = <&clock CLK_I2C6>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c6_bus>;
status = "disabled";
};
......@@ -426,6 +434,8 @@ i2c_7: i2c@138D0000 {
interrupts = <0 65 0>;
clocks = <&clock CLK_I2C7>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c7_bus>;
status = "disabled";
};
......
......@@ -28,6 +28,21 @@ chosen {
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 @@ aliases {
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 @@ lcd_vdd3_reg: voltage-regulator-2 {
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 @@ mms114-touchscreen@48 {
};
};
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 @@ fimd@11c00000 {
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 @@ fimc_3: fimc@11830000 {
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 @@ s5k6a3@10 {
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 @@ pmu {
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 @@ cpu@1 {
};
};
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>;
......
/*
* 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 @@ i2c6_hs_bus: i2c6-hs-bus {
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 @@ cpu0: cpu@0 {
compatible = "arm,cortex-a15";
reg = <0x0>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
cpu1: cpu@1 {
......@@ -65,6 +66,7 @@ cpu1: cpu@1 {
compatible = "arm,cortex-a15";
reg = <0x1>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
cpu2: cpu@2 {
......@@ -72,6 +74,7 @@ cpu2: cpu@2 {
compatible = "arm,cortex-a15";
reg = <0x2>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
cpu3: cpu@3 {
......@@ -79,6 +82,7 @@ cpu3: cpu@3 {
compatible = "arm,cortex-a15";
reg = <0x3>;
clock-frequency = <1800000000>;
cci-control-port = <&cci_control1>;
};
cpu4: cpu@100 {
......@@ -86,6 +90,7 @@ cpu4: cpu@100 {
compatible = "arm,cortex-a7";
reg = <0x100>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
cpu5: cpu@101 {
......@@ -93,6 +98,7 @@ cpu5: cpu@101 {
compatible = "arm,cortex-a7";
reg = <0x101>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
cpu6: cpu@102 {
......@@ -100,6 +106,7 @@ cpu6: cpu@102 {
compatible = "arm,cortex-a7";
reg = <0x102>;
clock-frequency = <1000000000>;
cci-control-port = <&cci_control0>;
};
cpu7: cpu@103 {
......@@ -107,6 +114,44 @@ 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>;
};
};
......@@ -125,7 +170,7 @@ clock_audss: audss-clock-controller@3810000 {
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 @@ mmc_2: mmc@12220000 {
status = "disabled";
};
mct@101C0000 {
mct: mct@101C0000 {
compatible = "samsung,exynos4210-mct";
reg = <0x101C0000 0x800>;
interrupt-controller;
......@@ -270,7 +315,7 @@ pinctrl_4: pinctrl@03860000 {
interrupts = <0 47 0>;
};
rtc@101E0000 {
rtc: rtc@101E0000 {
clocks = <&clock CLK_RTC>;
clock-names = "rtc";
status = "disabled";
......@@ -430,22 +475,22 @@ spi_2: spi@12d40000 {
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 @@ dp_phy: video-phy@10040728 {
#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 @@ hsi2c_10: i2c@12E20000 {
status = "disabled";
};
hdmi@14530000 {
hdmi: hdmi@14530000 {
compatible = "samsung,exynos4212-hdmi";
reg = <0x14530000 0x70000>;
interrupts = <0 95 0>;
......@@ -644,7 +689,7 @@ hdmi@14530000 {
status = "disabled";
};
mixer@14450000 {
mixer: mixer@14450000 {
compatible = "samsung,exynos5420-mixer";
reg = <0x14450000 0x10000>;
interrupts = <0 94 0>;
......@@ -715,7 +760,7 @@ tmu_gpu: tmu@100a0000 {
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 @@ watchdog@101D0000 {
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
......
/*
* 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,13 +253,22 @@ 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));
}
}
}
struct smp_operations exynos_smp_ops __initdata = {
......
......@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment