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

src.c (5964B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2011 Freescale Semiconductor, Inc.
      4 * Copyright 2011 Linaro Ltd.
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/io.h>
      9#include <linux/iopoll.h>
     10#include <linux/of.h>
     11#include <linux/of_address.h>
     12#include <linux/platform_device.h>
     13#include <linux/reset-controller.h>
     14#include <linux/smp.h>
     15#include <asm/smp_plat.h>
     16#include "common.h"
     17#include "hardware.h"
     18
     19#define SRC_SCR				0x000
     20#define SRC_GPR1_V1			0x020
     21#define SRC_GPR1_V2			0x074
     22#define SRC_GPR1(gpr_v2)		((gpr_v2) ? SRC_GPR1_V2 : SRC_GPR1_V1)
     23#define BP_SRC_SCR_WARM_RESET_ENABLE	0
     24#define BP_SRC_SCR_SW_GPU_RST		1
     25#define BP_SRC_SCR_SW_VPU_RST		2
     26#define BP_SRC_SCR_SW_IPU1_RST		3
     27#define BP_SRC_SCR_SW_OPEN_VG_RST	4
     28#define BP_SRC_SCR_SW_IPU2_RST		12
     29#define BP_SRC_SCR_CORE1_RST		14
     30#define BP_SRC_SCR_CORE1_ENABLE		22
     31/* below is for i.MX7D */
     32#define SRC_A7RCR1			0x008
     33#define BP_SRC_A7RCR1_A7_CORE1_ENABLE	1
     34#define GPC_CPU_PGC_SW_PUP_REQ		0xf0
     35#define GPC_CPU_PGC_SW_PDN_REQ		0xfc
     36#define GPC_PGC_C1			0x840
     37#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7	0x2
     38
     39static void __iomem *src_base;
     40static DEFINE_SPINLOCK(scr_lock);
     41static bool gpr_v2;
     42static void __iomem *gpc_base;
     43
     44static const int sw_reset_bits[5] = {
     45	BP_SRC_SCR_SW_GPU_RST,
     46	BP_SRC_SCR_SW_VPU_RST,
     47	BP_SRC_SCR_SW_IPU1_RST,
     48	BP_SRC_SCR_SW_OPEN_VG_RST,
     49	BP_SRC_SCR_SW_IPU2_RST
     50};
     51
     52static int imx_src_reset_module(struct reset_controller_dev *rcdev,
     53		unsigned long sw_reset_idx)
     54{
     55	unsigned long timeout;
     56	unsigned long flags;
     57	int bit;
     58	u32 val;
     59
     60	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
     61		return -EINVAL;
     62
     63	bit = 1 << sw_reset_bits[sw_reset_idx];
     64
     65	spin_lock_irqsave(&scr_lock, flags);
     66	val = readl_relaxed(src_base + SRC_SCR);
     67	val |= bit;
     68	writel_relaxed(val, src_base + SRC_SCR);
     69	spin_unlock_irqrestore(&scr_lock, flags);
     70
     71	timeout = jiffies + msecs_to_jiffies(1000);
     72	while (readl(src_base + SRC_SCR) & bit) {
     73		if (time_after(jiffies, timeout))
     74			return -ETIME;
     75		cpu_relax();
     76	}
     77
     78	return 0;
     79}
     80
     81static const struct reset_control_ops imx_src_ops = {
     82	.reset = imx_src_reset_module,
     83};
     84
     85static void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset)
     86{
     87	writel_relaxed(enable, gpc_base + offset);
     88}
     89
     90/*
     91 * The motivation for bringing up the second i.MX7D core inside the kernel
     92 * is that legacy vendor bootloaders usually do not implement PSCI support.
     93 * This is a significant blocker for systems in the field that are running old
     94 * bootloader versions to upgrade to a modern mainline kernel version, as only
     95 * one CPU of the i.MX7D would be brought up.
     96 * Bring up the second i.MX7D core inside the kernel to make the migration
     97 * path to mainline kernel easier for the existing iMX7D users.
     98 */
     99void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn)
    100{
    101	u32 reg = pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ;
    102	u32 val, pup;
    103	int ret;
    104
    105	imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
    106	val = readl_relaxed(gpc_base + reg);
    107	val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
    108	writel_relaxed(val, gpc_base + reg);
    109
    110	ret = readl_relaxed_poll_timeout_atomic(gpc_base + reg, pup,
    111				!(pup & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7),
    112				5, 1000000);
    113	if (ret < 0) {
    114		pr_err("i.MX7D: CORE1_A7 power up timeout\n");
    115		val &= ~BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
    116		writel_relaxed(val, gpc_base + reg);
    117	}
    118
    119	imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
    120}
    121
    122void imx_enable_cpu(int cpu, bool enable)
    123{
    124	u32 mask, val;
    125
    126	cpu = cpu_logical_map(cpu);
    127	spin_lock(&scr_lock);
    128	if (gpr_v2) {
    129		if (enable)
    130			imx_gpcv2_set_core1_pdn_pup_by_software(false);
    131
    132		mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1);
    133		val = readl_relaxed(src_base + SRC_A7RCR1);
    134		val = enable ? val | mask : val & ~mask;
    135		writel_relaxed(val, src_base + SRC_A7RCR1);
    136	} else {
    137		mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
    138		val = readl_relaxed(src_base + SRC_SCR);
    139		val = enable ? val | mask : val & ~mask;
    140		val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1);
    141		writel_relaxed(val, src_base + SRC_SCR);
    142	}
    143	spin_unlock(&scr_lock);
    144}
    145
    146void imx_set_cpu_jump(int cpu, void *jump_addr)
    147{
    148	cpu = cpu_logical_map(cpu);
    149	writel_relaxed(__pa_symbol(jump_addr),
    150		       src_base + SRC_GPR1(gpr_v2) + cpu * 8);
    151}
    152
    153u32 imx_get_cpu_arg(int cpu)
    154{
    155	cpu = cpu_logical_map(cpu);
    156	return readl_relaxed(src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4);
    157}
    158
    159void imx_set_cpu_arg(int cpu, u32 arg)
    160{
    161	cpu = cpu_logical_map(cpu);
    162	writel_relaxed(arg, src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4);
    163}
    164
    165void __init imx_src_init(void)
    166{
    167	struct device_node *np;
    168	u32 val;
    169
    170	np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src");
    171	if (!np)
    172		return;
    173	src_base = of_iomap(np, 0);
    174	WARN_ON(!src_base);
    175
    176	/*
    177	 * force warm reset sources to generate cold reset
    178	 * for a more reliable restart
    179	 */
    180	spin_lock(&scr_lock);
    181	val = readl_relaxed(src_base + SRC_SCR);
    182	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
    183	writel_relaxed(val, src_base + SRC_SCR);
    184	spin_unlock(&scr_lock);
    185}
    186
    187void __init imx7_src_init(void)
    188{
    189	struct device_node *np;
    190
    191	gpr_v2 = true;
    192
    193	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src");
    194	if (!np)
    195		return;
    196
    197	src_base = of_iomap(np, 0);
    198	if (!src_base)
    199		return;
    200
    201	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc");
    202	if (!np)
    203		return;
    204
    205	gpc_base = of_iomap(np, 0);
    206	if (!gpc_base)
    207		return;
    208}
    209
    210static const struct of_device_id imx_src_dt_ids[] = {
    211	{ .compatible = "fsl,imx51-src" },
    212	{ /* sentinel */ }
    213};
    214
    215static int imx_src_probe(struct platform_device *pdev)
    216{
    217	struct reset_controller_dev *rcdev;
    218
    219	rcdev = devm_kzalloc(&pdev->dev, sizeof(*rcdev), GFP_KERNEL);
    220	if (!rcdev)
    221		return -ENOMEM;
    222
    223	rcdev->ops = &imx_src_ops;
    224	rcdev->dev = &pdev->dev;
    225	rcdev->of_node = pdev->dev.of_node;
    226	rcdev->nr_resets = ARRAY_SIZE(sw_reset_bits);
    227
    228	return devm_reset_controller_register(&pdev->dev, rcdev);
    229}
    230
    231static struct platform_driver imx_src_driver = {
    232	.driver = {
    233		.name = "imx-src",
    234		.of_match_table = imx_src_dt_ids,
    235	},
    236	.probe = imx_src_probe,
    237};
    238builtin_platform_driver(imx_src_driver);