Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index b40963c..9dab1f5 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -13,11 +13,13 @@
select ARM_AMBA
select ARM_GIC
select COMMON_CLK_SAMSUNG
+ select EXYNOS_CHIPID
select EXYNOS_THERMAL
select EXYNOS_PMU
select EXYNOS_SROM
select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS
select GPIOLIB
+ select HAVE_ARM_ARCH_TIMER if ARCH_EXYNOS5 && VIRTUALIZATION
select HAVE_ARM_SCU if SMP
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -49,6 +51,7 @@
config ARCH_EXYNOS3
bool "SAMSUNG EXYNOS3"
+ default y
select ARM_CPU_SUSPEND if PM
help
Samsung EXYNOS3 (Cortex-A7) SoC based systems
@@ -106,20 +109,18 @@
bool "SAMSUNG EXYNOS5420"
default y
depends on ARCH_EXYNOS5
+ select EXYNOS_MCPM if SMP
+ select ARM_CCI400_PORT_CTRL
+ select ARM_CPU_SUSPEND
config SOC_EXYNOS5800
bool "SAMSUNG EXYNOS5800"
default y
depends on SOC_EXYNOS5420
-config EXYNOS5420_MCPM
- bool "Exynos5420 Multi-Cluster PM support"
- depends on MCPM && SOC_EXYNOS5420
- select ARM_CCI400_PORT_CTRL
- select ARM_CPU_SUSPEND
- help
- This is needed to provide CPU and cluster power management
- on Exynos5420 implementing big.LITTLE.
+config EXYNOS_MCPM
+ bool
+ select MCPM
config EXYNOS_CPU_SUSPEND
bool
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index cd00c82..0fd3fcf 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -14,9 +14,5 @@
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
-plus_sec := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec)
-AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec)
-
-obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o
+obj-$(CONFIG_EXYNOS_MCPM) += mcpm-exynos.o
CFLAGS_mcpm-exynos.o += -march=armv7-a
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index dcd21bb..56411bb 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -91,6 +91,7 @@
extern void __iomem *sysram_ns_base_addr;
extern void __iomem *sysram_base_addr;
+extern phys_addr_t sysram_base_phys;
extern void __iomem *pmu_base_addr;
void exynos_sysram_init(void);
@@ -105,16 +106,15 @@
#define C2_STATE (1 << 3)
/*
* Magic values for bootloader indicating chosen low power mode.
- * See also Documentation/arm/Samsung/Bootloader-interface.txt
+ * See also Documentation/arm/samsung/bootloader-interface.rst
*/
#define EXYNOS_SLEEP_MAGIC 0x00000bad
#define EXYNOS_AFTR_MAGIC 0xfcba0d10
+bool __init exynos_secure_firmware_available(void);
void exynos_set_boot_flag(unsigned int cpu, unsigned int mode);
void exynos_clear_boot_flag(unsigned int cpu, unsigned int mode);
-extern u32 exynos_get_eint_wake_mask(void);
-
#ifdef CONFIG_PM_SLEEP
extern void __init exynos_pm_init(void);
#else
diff --git a/arch/arm/mach-exynos/exynos-smc.S b/arch/arm/mach-exynos/exynos-smc.S
index d259532..6da31e6 100644
--- a/arch/arm/mach-exynos/exynos-smc.S
+++ b/arch/arm/mach-exynos/exynos-smc.S
@@ -10,7 +10,8 @@
/*
* Function signature: void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3)
*/
-
+ .arch armv7-a
+ .arch_extension sec
ENTRY(exynos_smc)
stmfd sp!, {r4-r11, lr}
dsb
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index 865dcc4..9aa4833 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -33,6 +33,7 @@
};
void __iomem *sysram_base_addr __ro_after_init;
+phys_addr_t sysram_base_phys __ro_after_init;
void __iomem *sysram_ns_base_addr __ro_after_init;
void __init exynos_sysram_init(void)
@@ -43,6 +44,8 @@
if (!of_device_is_available(node))
continue;
sysram_base_addr = of_iomap(node, 0);
+ sysram_base_phys = of_translate_address(node,
+ of_get_address(node, 0, NULL, NULL));
break;
}
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index be1f20f..2eaf2db 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -185,7 +185,7 @@
exynos_smc(SMC_CMD_L2X0SETUP2, regs->pwr_ctrl, regs->aux_ctrl, 0);
}
-void __init exynos_firmware_init(void)
+bool __init exynos_secure_firmware_available(void)
{
struct device_node *nd;
const __be32 *addr;
@@ -193,14 +193,23 @@
nd = of_find_compatible_node(NULL, NULL,
"samsung,secure-firmware");
if (!nd)
- return;
+ return false;
addr = of_get_address(nd, 0, NULL, NULL);
+ of_node_put(nd);
if (!addr) {
pr_err("%s: No address specified.\n", __func__);
- return;
+ return false;
}
+ return true;
+}
+
+void __init exynos_firmware_init(void)
+{
+ if (!exynos_secure_firmware_available())
+ return;
+
pr_info("Running under secure firmware.\n");
register_firmware_ops(&exynos_firmware_ops);
diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S
index 005695c..0ac2cb9 100644
--- a/arch/arm/mach-exynos/headsmp.S
+++ b/arch/arm/mach-exynos/headsmp.S
@@ -36,4 +36,4 @@
.align 2
1: .long .
- .long pen_release
+ .long exynos_pen_release
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
index 72bc035..9a681b4 100644
--- a/arch/arm/mach-exynos/mcpm-exynos.c
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -75,14 +75,25 @@
*/
if (cluster &&
cluster == MPIDR_AFFINITY_LEVEL(cpu_logical_map(0), 1)) {
+ unsigned int timeout = 16;
+
/*
* Before we reset the Little cores, we should wait
* the SPARE2 register is set to 1 because the init
* codes of the iROM will set the register after
* initialization.
*/
- while (!pmu_raw_readl(S5P_PMU_SPARE2))
+ while (timeout && !pmu_raw_readl(S5P_PMU_SPARE2)) {
+ timeout--;
udelay(10);
+ }
+
+ if (timeout == 0) {
+ pr_err("cpu %u cluster %u powerup failed\n",
+ cpu, cluster);
+ exynos_cpu_power_down(cpunr);
+ return -ETIMEDOUT;
+ }
pmu_raw_writel(EXYNOS5420_KFC_CORE_RESET(cpu),
EXYNOS_SWRESET);
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 6a1e682..0cbbae8 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -28,6 +28,9 @@
extern void exynos4_secondary_startup(void);
+/* XXX exynos_pen_release is cargo culted code - DO NOT COPY XXX */
+volatile int exynos_pen_release = -1;
+
#ifdef CONFIG_HOTPLUG_CPU
static inline void cpu_leave_lowpower(u32 core_id)
{
@@ -57,7 +60,7 @@
wfi();
- if (pen_release == core_id) {
+ if (exynos_pen_release == core_id) {
/*
* OK, proper wakeup, we're done
*/
@@ -211,13 +214,20 @@
*/
void exynos_core_restart(u32 core_id)
{
+ unsigned int timeout = 16;
u32 val;
if (!of_machine_is_compatible("samsung,exynos3250"))
return;
- while (!pmu_raw_readl(S5P_PMU_SPARE2))
+ while (timeout && !pmu_raw_readl(S5P_PMU_SPARE2)) {
+ timeout--;
udelay(10);
+ }
+ if (timeout == 0) {
+ pr_err("cpu core %u restart failed\n", core_id);
+ return;
+ }
udelay(10);
val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id));
@@ -228,15 +238,17 @@
}
/*
- * Write pen_release in a way that is guaranteed to be visible to all
- * observers, irrespective of whether they're taking part in coherency
+ * XXX CARGO CULTED CODE - DO NOT COPY XXX
+ *
+ * Write exynos_pen_release in a way that is guaranteed to be visible to
+ * all observers, irrespective of whether they're taking part in coherency
* or not. This is necessary for the hotplug code to work reliably.
*/
-static void write_pen_release(int val)
+static void exynos_write_pen_release(int val)
{
- pen_release = val;
+ exynos_pen_release = val;
smp_wmb();
- sync_cache_w(&pen_release);
+ sync_cache_w(&exynos_pen_release);
}
static DEFINE_SPINLOCK(boot_lock);
@@ -247,7 +259,7 @@
* let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
- write_pen_release(-1);
+ exynos_write_pen_release(-1);
/*
* Synchronise with the boot thread.
@@ -322,12 +334,12 @@
/*
* The secondary processor is waiting to be released from
* the holding pen - release it, then wait for it to flag
- * that it has been released by resetting pen_release.
+ * that it has been released by resetting exynos_pen_release.
*
- * Note that "pen_release" is the hardware CPU core ID, whereas
+ * Note that "exynos_pen_release" is the hardware CPU core ID, whereas
* "cpu" is Linux's internal ID.
*/
- write_pen_release(core_id);
+ exynos_write_pen_release(core_id);
if (!exynos_cpu_power_state(core_id)) {
exynos_cpu_power_up(core_id);
@@ -336,9 +348,9 @@
/* wait max 10 ms until cpu1 is on */
while (exynos_cpu_power_state(core_id)
!= S5P_CORE_LOCAL_PWR_EN) {
- if (timeout-- == 0)
+ if (timeout == 0)
break;
-
+ timeout--;
mdelay(1);
}
@@ -376,13 +388,13 @@
else
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
- if (pen_release == -1)
+ if (exynos_pen_release == -1)
break;
udelay(10);
}
- if (pen_release != -1)
+ if (exynos_pen_release != -1)
ret = -ETIMEDOUT;
/*
@@ -392,43 +404,17 @@
fail:
spin_unlock(&boot_lock);
- return pen_release != -1 ? ret : 0;
+ return exynos_pen_release != -1 ? ret : 0;
}
static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
exynos_sysram_init();
exynos_set_delayed_reset_assertion(true);
if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
exynos_scu_enable();
-
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The boot monitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- *
- * Try using firmware operation first and fall back to
- * boot register if it fails.
- */
- for (i = 1; i < max_cpus; ++i) {
- unsigned long boot_addr;
- u32 mpidr;
- u32 core_id;
- int ret;
-
- mpidr = cpu_logical_map(i);
- core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- boot_addr = __pa_symbol(exynos4_secondary_startup);
-
- ret = exynos_set_boot_addr(core_id, boot_addr);
- if (ret)
- break;
- }
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S
index 2783c3a..ed93f91 100644
--- a/arch/arm/mach-exynos/sleep.S
+++ b/arch/arm/mach-exynos/sleep.S
@@ -44,7 +44,8 @@
ENDPROC(exynos_cpu_resume)
.align
-
+ .arch armv7-a
+ .arch_extension sec
ENTRY(exynos_cpu_resume_ns)
mrc p15, 0, r0, c0, c0, 0
ldr r1, =CPU_MASK
diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h
index f355185..98832e5 100644
--- a/arch/arm/mach-exynos/smc.h
+++ b/arch/arm/mach-exynos/smc.h
@@ -25,6 +25,13 @@
#define SMC_CMD_L2X0INVALL (-24)
#define SMC_CMD_L2X0DEBUG (-25)
+/* For Accessing CP15/SFR (General) */
+#define SMC_CMD_REG (-101)
+
+/* defines for SMC_CMD_REG */
+#define SMC_REG_CLASS_SFR_W (0x1 << 30)
+#define SMC_REG_ID_SFR_W(addr) (SMC_REG_CLASS_SFR_W | ((addr) >> 2))
+
#ifndef __ASSEMBLY__
extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
index 7ead3ac..6a0d344 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -30,9 +30,8 @@
#include <asm/smp_scu.h>
#include <asm/suspend.h>
-#include <plat/pm-common.h>
-
#include "common.h"
+#include "smc.h"
#define REG_TABLE_END (-1U)
@@ -59,10 +58,17 @@
int (*cpu_suspend)(unsigned long);
};
-static const struct exynos_pm_data *pm_data __ro_after_init;
+/* Used only on Exynos542x/5800 */
+struct exynos_pm_state {
+ int cpu_state;
+ unsigned int pmu_spare3;
+ void __iomem *sysram_base;
+ phys_addr_t sysram_phys;
+ bool secure_firmware;
+};
-static int exynos5420_cpu_state;
-static unsigned int exynos_pmu_spare3;
+static const struct exynos_pm_data *pm_data __ro_after_init;
+static struct exynos_pm_state pm_state;
/*
* GIC wake-up support
@@ -88,6 +94,11 @@
{ /* sentinel */ },
};
+static u32 exynos_read_eint_wakeup_mask(void)
+{
+ return pmu_raw_readl(EXYNOS_EINT_WAKEUP_MASK);
+}
+
static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
{
const struct exynos_wkup_irq *wkup_irq;
@@ -257,9 +268,7 @@
unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- writel_relaxed(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE);
-
- if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
+ if (IS_ENABLED(CONFIG_EXYNOS_MCPM)) {
mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
mcpm_cpu_suspend();
}
@@ -272,9 +281,11 @@
static void exynos_pm_set_wakeup_mask(void)
{
- /* Set wake-up mask registers */
- pmu_raw_writel(exynos_get_eint_wake_mask(), EXYNOS_EINT_WAKEUP_MASK);
- pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
+ /*
+ * Set wake-up mask registers
+ * EXYNOS_EINT_WAKEUP_MASK is set by pinctrl driver in late suspend.
+ */
+ pmu_raw_writel(exynos_irqwake_intmask & ~BIT(31), S5P_WAKEUP_MASK);
}
static void exynos_pm_enter_sleep_mode(void)
@@ -321,7 +332,7 @@
/* Set wake-up mask registers */
exynos_pm_set_wakeup_mask();
- exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3);
+ pm_state.pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3);
/*
* The cpu state needs to be saved and restored so that the
* secondary CPUs will enter low power start. Though the U-Boot
@@ -329,13 +340,18 @@
* needs to restore it back in case, the primary cpu fails to
* suspend for any reason.
*/
- exynos5420_cpu_state = readl_relaxed(sysram_base_addr +
- EXYNOS5420_CPU_STATE);
+ pm_state.cpu_state = readl_relaxed(pm_state.sysram_base +
+ EXYNOS5420_CPU_STATE);
+ writel_relaxed(0x0, pm_state.sysram_base + EXYNOS5420_CPU_STATE);
+ if (pm_state.secure_firmware)
+ exynos_smc(SMC_CMD_REG, SMC_REG_ID_SFR_W(pm_state.sysram_phys +
+ EXYNOS5420_CPU_STATE),
+ 0, 0);
exynos_pm_enter_sleep_mode();
/* ensure at least INFORM0 has the resume address */
- if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
+ if (IS_ENABLED(CONFIG_EXYNOS_MCPM))
pmu_raw_writel(__pa_symbol(mcpm_entry_point), S5P_INFORM0);
tmp = pmu_raw_readl(EXYNOS_L2_OPTION(0));
@@ -434,8 +450,27 @@
static void exynos5420_prepare_pm_resume(void)
{
- if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
+ unsigned int mpidr, cluster;
+
+ mpidr = read_cpuid_mpidr();
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+ if (IS_ENABLED(CONFIG_EXYNOS_MCPM))
WARN_ON(mcpm_cpu_powered_up());
+
+ if (IS_ENABLED(CONFIG_HW_PERF_EVENTS) && cluster != 0) {
+ /*
+ * When system is resumed on the LITTLE/KFC core (cluster 1),
+ * the DSCR is not properly updated until the power is turned
+ * on also for the cluster 0. Enable it for a while to
+ * propagate the SPNIDEN and SPIDEN signals from Secure JTAG
+ * block and avoid undefined instruction issue on CP14 reset.
+ */
+ pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN,
+ EXYNOS_COMMON_CONFIGURATION(0));
+ pmu_raw_writel(0,
+ EXYNOS_COMMON_CONFIGURATION(0));
+ }
}
static void exynos5420_pm_resume(void)
@@ -448,8 +483,13 @@
EXYNOS5_ARM_CORE0_SYS_PWR_REG);
/* Restore the sysram cpu state register */
- writel_relaxed(exynos5420_cpu_state,
- sysram_base_addr + EXYNOS5420_CPU_STATE);
+ writel_relaxed(pm_state.cpu_state,
+ pm_state.sysram_base + EXYNOS5420_CPU_STATE);
+ if (pm_state.secure_firmware)
+ exynos_smc(SMC_CMD_REG,
+ SMC_REG_ID_SFR_W(pm_state.sysram_phys +
+ EXYNOS5420_CPU_STATE),
+ EXYNOS_AFTR_MAGIC, 0);
pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
S5P_CENTRAL_SEQ_OPTION);
@@ -457,7 +497,7 @@
if (exynos_pm_central_resume())
goto early_wakeup;
- pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3);
+ pmu_raw_writel(pm_state.pmu_spare3, S5P_PMU_SPARE3);
early_wakeup:
@@ -483,27 +523,24 @@
static int exynos_suspend_enter(suspend_state_t state)
{
+ u32 eint_wakeup_mask = exynos_read_eint_wakeup_mask();
int ret;
- s3c_pm_debug_init();
+ pr_debug("%s: suspending the system...\n", __func__);
- S3C_PMDBG("%s: suspending the system...\n", __func__);
-
- S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__,
- exynos_irqwake_intmask, exynos_get_eint_wake_mask());
+ pr_debug("%s: wakeup masks: %08x,%08x\n", __func__,
+ exynos_irqwake_intmask, eint_wakeup_mask);
if (exynos_irqwake_intmask == -1U
- && exynos_get_eint_wake_mask() == -1U) {
+ && eint_wakeup_mask == EXYNOS_EINT_WAKEUP_MASK_DISABLED) {
pr_err("%s: No wake-up sources!\n", __func__);
pr_err("%s: Aborting sleep\n", __func__);
return -EINVAL;
}
- s3c_pm_save_uarts();
if (pm_data->pm_prepare)
pm_data->pm_prepare();
flush_cache_all();
- s3c_pm_check_store();
ret = call_firmware_op(suspend);
if (ret == -ENOSYS)
@@ -513,14 +550,11 @@
if (pm_data->pm_resume_prepare)
pm_data->pm_resume_prepare();
- s3c_pm_restore_uarts();
- S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
+ pr_debug("%s: wakeup stat: %08x\n", __func__,
pmu_raw_readl(S5P_WAKEUP_STAT));
- s3c_pm_check_restore();
-
- S3C_PMDBG("%s: resuming the system...\n", __func__);
+ pr_debug("%s: resuming the system...\n", __func__);
return 0;
}
@@ -543,8 +577,6 @@
return ret;
}
- s3c_pm_check_prepare();
-
return 0;
}
@@ -552,8 +584,6 @@
{
int ret;
- s3c_pm_check_cleanup();
-
ret = regulator_suspend_finish();
if (ret)
pr_warn("Failed to resume regulators from suspend (%d)\n", ret);
@@ -639,8 +669,10 @@
if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
+ of_node_put(np);
return;
}
+ of_node_put(np);
pm_data = (const struct exynos_pm_data *) match->data;
@@ -654,4 +686,16 @@
register_syscore_ops(&exynos_pm_syscore_ops);
suspend_set_ops(&exynos_suspend_ops);
+
+ /*
+ * Applicable as of now only to Exynos542x. If booted under secure
+ * firmware, the non-secure region of sysram should be used.
+ */
+ if (exynos_secure_firmware_available()) {
+ pm_state.sysram_phys = sysram_base_phys;
+ pm_state.sysram_base = sysram_ns_base_addr;
+ pm_state.secure_firmware = true;
+ } else {
+ pm_state.sysram_base = sysram_base_addr;
+ }
}