cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

platsmp.c (9883B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2015 Carlo Caione <carlo@endlessm.com>
      4 * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
      5 */
      6
      7#include <linux/delay.h>
      8#include <linux/init.h>
      9#include <linux/io.h>
     10#include <linux/of.h>
     11#include <linux/of_address.h>
     12#include <linux/regmap.h>
     13#include <linux/reset.h>
     14#include <linux/smp.h>
     15#include <linux/mfd/syscon.h>
     16
     17#include <asm/cacheflush.h>
     18#include <asm/cp15.h>
     19#include <asm/smp_scu.h>
     20#include <asm/smp_plat.h>
     21
     22#define MESON_SMP_SRAM_CPU_CTRL_REG		(0x00)
     23#define MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(c)	(0x04 + ((c - 1) << 2))
     24
     25#define MESON_CPU_AO_RTI_PWR_A9_CNTL0		(0x00)
     26#define MESON_CPU_AO_RTI_PWR_A9_CNTL1		(0x04)
     27#define MESON_CPU_AO_RTI_PWR_A9_MEM_PD0		(0x14)
     28
     29#define MESON_CPU_PWR_A9_CNTL0_M(c)		(0x03 << ((c * 2) + 16))
     30#define MESON_CPU_PWR_A9_CNTL1_M(c)		(0x03 << ((c + 1) << 1))
     31#define MESON_CPU_PWR_A9_MEM_PD0_M(c)		(0x0f << (32 - (c * 4)))
     32#define MESON_CPU_PWR_A9_CNTL1_ST(c)		(0x01 << (c + 16))
     33
     34static void __iomem *sram_base;
     35static void __iomem *scu_base;
     36static struct regmap *pmu;
     37
     38static struct reset_control *meson_smp_get_core_reset(int cpu)
     39{
     40	struct device_node *np = of_get_cpu_node(cpu, 0);
     41
     42	return of_reset_control_get_exclusive(np, NULL);
     43}
     44
     45static void meson_smp_set_cpu_ctrl(int cpu, bool on_off)
     46{
     47	u32 val = readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
     48
     49	if (on_off)
     50		val |= BIT(cpu);
     51	else
     52		val &= ~BIT(cpu);
     53
     54	/* keep bit 0 always enabled */
     55	val |= BIT(0);
     56
     57	writel(val, sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
     58}
     59
     60static void __init meson_smp_prepare_cpus(const char *scu_compatible,
     61					  const char *pmu_compatible,
     62					  const char *sram_compatible)
     63{
     64	static struct device_node *node;
     65
     66	/* SMP SRAM */
     67	node = of_find_compatible_node(NULL, NULL, sram_compatible);
     68	if (!node) {
     69		pr_err("Missing SRAM node\n");
     70		return;
     71	}
     72
     73	sram_base = of_iomap(node, 0);
     74	of_node_put(node);
     75	if (!sram_base) {
     76		pr_err("Couldn't map SRAM registers\n");
     77		return;
     78	}
     79
     80	/* PMU */
     81	pmu = syscon_regmap_lookup_by_compatible(pmu_compatible);
     82	if (IS_ERR(pmu)) {
     83		pr_err("Couldn't map PMU registers\n");
     84		return;
     85	}
     86
     87	/* SCU */
     88	node = of_find_compatible_node(NULL, NULL, scu_compatible);
     89	if (!node) {
     90		pr_err("Missing SCU node\n");
     91		return;
     92	}
     93
     94	scu_base = of_iomap(node, 0);
     95	of_node_put(node);
     96	if (!scu_base) {
     97		pr_err("Couldn't map SCU registers\n");
     98		return;
     99	}
    100
    101	scu_enable(scu_base);
    102}
    103
    104static void __init meson8b_smp_prepare_cpus(unsigned int max_cpus)
    105{
    106	meson_smp_prepare_cpus("arm,cortex-a5-scu", "amlogic,meson8b-pmu",
    107			       "amlogic,meson8b-smp-sram");
    108}
    109
    110static void __init meson8_smp_prepare_cpus(unsigned int max_cpus)
    111{
    112	meson_smp_prepare_cpus("arm,cortex-a9-scu", "amlogic,meson8-pmu",
    113			       "amlogic,meson8-smp-sram");
    114}
    115
    116static void meson_smp_begin_secondary_boot(unsigned int cpu)
    117{
    118	/*
    119	 * Set the entry point before powering on the CPU through the SCU. This
    120	 * is needed if the CPU is in "warm" state (= after rebooting the
    121	 * system without power-cycling, or when taking the CPU offline and
    122	 * then taking it online again.
    123	 */
    124	writel(__pa_symbol(secondary_startup),
    125	       sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
    126
    127	/*
    128	 * SCU Power on CPU (needs to be done before starting the CPU,
    129	 * otherwise the secondary CPU will not start).
    130	 */
    131	scu_cpu_power_enable(scu_base, cpu);
    132}
    133
    134static int meson_smp_finalize_secondary_boot(unsigned int cpu)
    135{
    136	unsigned long timeout;
    137
    138	timeout = jiffies + (10 * HZ);
    139	while (readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu))) {
    140		if (!time_before(jiffies, timeout)) {
    141			pr_err("Timeout while waiting for CPU%d status\n",
    142			       cpu);
    143			return -ETIMEDOUT;
    144		}
    145	}
    146
    147	writel(__pa_symbol(secondary_startup),
    148	       sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
    149
    150	meson_smp_set_cpu_ctrl(cpu, true);
    151
    152	return 0;
    153}
    154
    155static int meson8_smp_boot_secondary(unsigned int cpu,
    156				     struct task_struct *idle)
    157{
    158	struct reset_control *rstc;
    159	int ret;
    160
    161	rstc = meson_smp_get_core_reset(cpu);
    162	if (IS_ERR(rstc)) {
    163		pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
    164		return PTR_ERR(rstc);
    165	}
    166
    167	meson_smp_begin_secondary_boot(cpu);
    168
    169	/* Reset enable */
    170	ret = reset_control_assert(rstc);
    171	if (ret) {
    172		pr_err("Failed to assert CPU%d reset\n", cpu);
    173		goto out;
    174	}
    175
    176	/* CPU power ON */
    177	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
    178				 MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
    179	if (ret < 0) {
    180		pr_err("Couldn't wake up CPU%d\n", cpu);
    181		goto out;
    182	}
    183
    184	udelay(10);
    185
    186	/* Isolation disable */
    187	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
    188				 0);
    189	if (ret < 0) {
    190		pr_err("Error when disabling isolation of CPU%d\n", cpu);
    191		goto out;
    192	}
    193
    194	/* Reset disable */
    195	ret = reset_control_deassert(rstc);
    196	if (ret) {
    197		pr_err("Failed to de-assert CPU%d reset\n", cpu);
    198		goto out;
    199	}
    200
    201	ret = meson_smp_finalize_secondary_boot(cpu);
    202	if (ret)
    203		goto out;
    204
    205out:
    206	reset_control_put(rstc);
    207
    208	return 0;
    209}
    210
    211static int meson8b_smp_boot_secondary(unsigned int cpu,
    212				     struct task_struct *idle)
    213{
    214	struct reset_control *rstc;
    215	int ret;
    216	u32 val;
    217
    218	rstc = meson_smp_get_core_reset(cpu);
    219	if (IS_ERR(rstc)) {
    220		pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
    221		return PTR_ERR(rstc);
    222	}
    223
    224	meson_smp_begin_secondary_boot(cpu);
    225
    226	/* CPU power UP */
    227	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
    228				 MESON_CPU_PWR_A9_CNTL0_M(cpu), 0);
    229	if (ret < 0) {
    230		pr_err("Couldn't power up CPU%d\n", cpu);
    231		goto out;
    232	}
    233
    234	udelay(5);
    235
    236	/* Reset enable */
    237	ret = reset_control_assert(rstc);
    238	if (ret) {
    239		pr_err("Failed to assert CPU%d reset\n", cpu);
    240		goto out;
    241	}
    242
    243	/* Memory power UP */
    244	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
    245				 MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0);
    246	if (ret < 0) {
    247		pr_err("Couldn't power up the memory for CPU%d\n", cpu);
    248		goto out;
    249	}
    250
    251	/* Wake up CPU */
    252	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
    253				 MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
    254	if (ret < 0) {
    255		pr_err("Couldn't wake up CPU%d\n", cpu);
    256		goto out;
    257	}
    258
    259	udelay(10);
    260
    261	ret = regmap_read_poll_timeout(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1, val,
    262				       val & MESON_CPU_PWR_A9_CNTL1_ST(cpu),
    263				       10, 10000);
    264	if (ret) {
    265		pr_err("Timeout while polling PMU for CPU%d status\n", cpu);
    266		goto out;
    267	}
    268
    269	/* Isolation disable */
    270	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
    271				 0);
    272	if (ret < 0) {
    273		pr_err("Error when disabling isolation of CPU%d\n", cpu);
    274		goto out;
    275	}
    276
    277	/* Reset disable */
    278	ret = reset_control_deassert(rstc);
    279	if (ret) {
    280		pr_err("Failed to de-assert CPU%d reset\n", cpu);
    281		goto out;
    282	}
    283
    284	ret = meson_smp_finalize_secondary_boot(cpu);
    285	if (ret)
    286		goto out;
    287
    288out:
    289	reset_control_put(rstc);
    290
    291	return 0;
    292}
    293
    294#ifdef CONFIG_HOTPLUG_CPU
    295static void meson8_smp_cpu_die(unsigned int cpu)
    296{
    297	meson_smp_set_cpu_ctrl(cpu, false);
    298
    299	v7_exit_coherency_flush(louis);
    300
    301	scu_power_mode(scu_base, SCU_PM_POWEROFF);
    302
    303	dsb();
    304	wfi();
    305
    306	/* we should never get here */
    307	WARN_ON(1);
    308}
    309
    310static int meson8_smp_cpu_kill(unsigned int cpu)
    311{
    312	int ret, power_mode;
    313	unsigned long timeout;
    314
    315	timeout = jiffies + (50 * HZ);
    316	do {
    317		power_mode = scu_get_cpu_power_mode(scu_base, cpu);
    318
    319		if (power_mode == SCU_PM_POWEROFF)
    320			break;
    321
    322		usleep_range(10000, 15000);
    323	} while (time_before(jiffies, timeout));
    324
    325	if (power_mode != SCU_PM_POWEROFF) {
    326		pr_err("Error while waiting for SCU power-off on CPU%d\n",
    327		       cpu);
    328		return -ETIMEDOUT;
    329	}
    330
    331	msleep(30);
    332
    333	/* Isolation enable */
    334	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
    335				 0x3);
    336	if (ret < 0) {
    337		pr_err("Error when enabling isolation for CPU%d\n", cpu);
    338		return ret;
    339	}
    340
    341	udelay(10);
    342
    343	/* CPU power OFF */
    344	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
    345				 MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
    346	if (ret < 0) {
    347		pr_err("Couldn't change sleep status of CPU%d\n", cpu);
    348		return ret;
    349	}
    350
    351	return 1;
    352}
    353
    354static int meson8b_smp_cpu_kill(unsigned int cpu)
    355{
    356	int ret, power_mode, count = 5000;
    357
    358	do {
    359		power_mode = scu_get_cpu_power_mode(scu_base, cpu);
    360
    361		if (power_mode == SCU_PM_POWEROFF)
    362			break;
    363
    364		udelay(10);
    365	} while (++count);
    366
    367	if (power_mode != SCU_PM_POWEROFF) {
    368		pr_err("Error while waiting for SCU power-off on CPU%d\n",
    369		       cpu);
    370		return -ETIMEDOUT;
    371	}
    372
    373	udelay(10);
    374
    375	/* CPU power DOWN */
    376	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
    377				 MESON_CPU_PWR_A9_CNTL0_M(cpu), 0x3);
    378	if (ret < 0) {
    379		pr_err("Couldn't power down CPU%d\n", cpu);
    380		return ret;
    381	}
    382
    383	/* Isolation enable */
    384	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
    385				 0x3);
    386	if (ret < 0) {
    387		pr_err("Error when enabling isolation for CPU%d\n", cpu);
    388		return ret;
    389	}
    390
    391	udelay(10);
    392
    393	/* Sleep status */
    394	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
    395				 MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
    396	if (ret < 0) {
    397		pr_err("Couldn't change sleep status of CPU%d\n", cpu);
    398		return ret;
    399	}
    400
    401	/* Memory power DOWN */
    402	ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
    403				 MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0xf);
    404	if (ret < 0) {
    405		pr_err("Couldn't power down the memory of CPU%d\n", cpu);
    406		return ret;
    407	}
    408
    409	return 1;
    410}
    411#endif
    412
    413static struct smp_operations meson8_smp_ops __initdata = {
    414	.smp_prepare_cpus	= meson8_smp_prepare_cpus,
    415	.smp_boot_secondary	= meson8_smp_boot_secondary,
    416#ifdef CONFIG_HOTPLUG_CPU
    417	.cpu_die		= meson8_smp_cpu_die,
    418	.cpu_kill		= meson8_smp_cpu_kill,
    419#endif
    420};
    421
    422static struct smp_operations meson8b_smp_ops __initdata = {
    423	.smp_prepare_cpus	= meson8b_smp_prepare_cpus,
    424	.smp_boot_secondary	= meson8b_smp_boot_secondary,
    425#ifdef CONFIG_HOTPLUG_CPU
    426	.cpu_die		= meson8_smp_cpu_die,
    427	.cpu_kill		= meson8b_smp_cpu_kill,
    428#endif
    429};
    430
    431CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,meson8-smp", &meson8_smp_ops);
    432CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,meson8b-smp", &meson8b_smp_ops);