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

flowctrl.c (5806B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/soc/tegra/flowctrl.c
      4 *
      5 * Functions and macros to control the flowcontroller
      6 *
      7 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
      8 */
      9
     10#include <linux/cpumask.h>
     11#include <linux/init.h>
     12#include <linux/io.h>
     13#include <linux/kernel.h>
     14#include <linux/of.h>
     15#include <linux/of_address.h>
     16#include <linux/platform_device.h>
     17
     18#include <soc/tegra/common.h>
     19#include <soc/tegra/flowctrl.h>
     20#include <soc/tegra/fuse.h>
     21
     22static u8 flowctrl_offset_halt_cpu[] = {
     23	FLOW_CTRL_HALT_CPU0_EVENTS,
     24	FLOW_CTRL_HALT_CPU1_EVENTS,
     25	FLOW_CTRL_HALT_CPU1_EVENTS + 8,
     26	FLOW_CTRL_HALT_CPU1_EVENTS + 16,
     27};
     28
     29static u8 flowctrl_offset_cpu_csr[] = {
     30	FLOW_CTRL_CPU0_CSR,
     31	FLOW_CTRL_CPU1_CSR,
     32	FLOW_CTRL_CPU1_CSR + 8,
     33	FLOW_CTRL_CPU1_CSR + 16,
     34};
     35
     36static void __iomem *tegra_flowctrl_base;
     37
     38static void flowctrl_update(u8 offset, u32 value)
     39{
     40	if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
     41		      "Tegra flowctrl not initialised!\n"))
     42		return;
     43
     44	writel(value, tegra_flowctrl_base + offset);
     45
     46	/* ensure the update has reached the flow controller */
     47	wmb();
     48	readl_relaxed(tegra_flowctrl_base + offset);
     49}
     50
     51u32 flowctrl_read_cpu_csr(unsigned int cpuid)
     52{
     53	u8 offset = flowctrl_offset_cpu_csr[cpuid];
     54
     55	if (WARN_ONCE(IS_ERR_OR_NULL(tegra_flowctrl_base),
     56		      "Tegra flowctrl not initialised!\n"))
     57		return 0;
     58
     59	return readl(tegra_flowctrl_base + offset);
     60}
     61
     62void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
     63{
     64	return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
     65}
     66
     67void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
     68{
     69	return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
     70}
     71
     72void flowctrl_cpu_suspend_enter(unsigned int cpuid)
     73{
     74	unsigned int reg;
     75	int i;
     76
     77	reg = flowctrl_read_cpu_csr(cpuid);
     78	switch (tegra_get_chip_id()) {
     79	case TEGRA20:
     80		/* clear wfe bitmap */
     81		reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
     82		/* clear wfi bitmap */
     83		reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
     84		/* pwr gating on wfe */
     85		reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
     86		break;
     87	case TEGRA30:
     88	case TEGRA114:
     89	case TEGRA124:
     90		/* clear wfe bitmap */
     91		reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
     92		/* clear wfi bitmap */
     93		reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
     94
     95		if (tegra_get_chip_id() == TEGRA30) {
     96			/*
     97			 * The wfi doesn't work well on Tegra30 because
     98			 * CPU hangs under some odd circumstances after
     99			 * power-gating (like memory running off PLLP),
    100			 * hence use wfe that is working perfectly fine.
    101			 * Note that Tegra30 TRM doc clearly stands that
    102			 * wfi should be used for the "Cluster Switching",
    103			 * while wfe for the power-gating, just like it
    104			 * is done on Tegra20.
    105			 */
    106			reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
    107		} else {
    108			/* pwr gating on wfi */
    109			reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
    110		}
    111		break;
    112	}
    113	reg |= FLOW_CTRL_CSR_INTR_FLAG;			/* clear intr flag */
    114	reg |= FLOW_CTRL_CSR_EVENT_FLAG;		/* clear event flag */
    115	reg |= FLOW_CTRL_CSR_ENABLE;			/* pwr gating */
    116	flowctrl_write_cpu_csr(cpuid, reg);
    117
    118	for (i = 0; i < num_possible_cpus(); i++) {
    119		if (i == cpuid)
    120			continue;
    121		reg = flowctrl_read_cpu_csr(i);
    122		reg |= FLOW_CTRL_CSR_EVENT_FLAG;
    123		reg |= FLOW_CTRL_CSR_INTR_FLAG;
    124		flowctrl_write_cpu_csr(i, reg);
    125	}
    126}
    127
    128void flowctrl_cpu_suspend_exit(unsigned int cpuid)
    129{
    130	unsigned int reg;
    131
    132	/* Disable powergating via flow controller for CPU0 */
    133	reg = flowctrl_read_cpu_csr(cpuid);
    134	switch (tegra_get_chip_id()) {
    135	case TEGRA20:
    136		/* clear wfe bitmap */
    137		reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
    138		/* clear wfi bitmap */
    139		reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
    140		break;
    141	case TEGRA30:
    142	case TEGRA114:
    143	case TEGRA124:
    144		/* clear wfe bitmap */
    145		reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
    146		/* clear wfi bitmap */
    147		reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
    148		break;
    149	}
    150	reg &= ~FLOW_CTRL_CSR_ENABLE;			/* clear enable */
    151	reg |= FLOW_CTRL_CSR_INTR_FLAG;			/* clear intr */
    152	reg |= FLOW_CTRL_CSR_EVENT_FLAG;		/* clear event */
    153	flowctrl_write_cpu_csr(cpuid, reg);
    154}
    155
    156static int tegra_flowctrl_probe(struct platform_device *pdev)
    157{
    158	void __iomem *base = tegra_flowctrl_base;
    159	struct resource *res;
    160
    161	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    162	tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
    163	if (IS_ERR(tegra_flowctrl_base))
    164		return PTR_ERR(tegra_flowctrl_base);
    165
    166	iounmap(base);
    167
    168	return 0;
    169}
    170
    171static const struct of_device_id tegra_flowctrl_match[] = {
    172	{ .compatible = "nvidia,tegra210-flowctrl" },
    173	{ .compatible = "nvidia,tegra124-flowctrl" },
    174	{ .compatible = "nvidia,tegra114-flowctrl" },
    175	{ .compatible = "nvidia,tegra30-flowctrl" },
    176	{ .compatible = "nvidia,tegra20-flowctrl" },
    177	{ }
    178};
    179
    180static struct platform_driver tegra_flowctrl_driver = {
    181	.driver = {
    182		.name = "tegra-flowctrl",
    183		.suppress_bind_attrs = true,
    184		.of_match_table = tegra_flowctrl_match,
    185	},
    186	.probe = tegra_flowctrl_probe,
    187};
    188builtin_platform_driver(tegra_flowctrl_driver);
    189
    190static int __init tegra_flowctrl_init(void)
    191{
    192	struct resource res;
    193	struct device_node *np;
    194
    195	if (!soc_is_tegra())
    196		return 0;
    197
    198	np = of_find_matching_node(NULL, tegra_flowctrl_match);
    199	if (np) {
    200		if (of_address_to_resource(np, 0, &res) < 0) {
    201			pr_err("failed to get flowctrl register\n");
    202			return -ENXIO;
    203		}
    204		of_node_put(np);
    205	} else if (IS_ENABLED(CONFIG_ARM)) {
    206		/*
    207		 * Hardcoded fallback for 32-bit Tegra
    208		 * devices if device tree node is missing.
    209		 */
    210		res.start = 0x60007000;
    211		res.end = 0x60007fff;
    212		res.flags = IORESOURCE_MEM;
    213	} else {
    214		/*
    215		 * At this point we're running on a Tegra,
    216		 * that doesn't support the flow controller
    217		 * (eg. Tegra186), so just return.
    218		 */
    219		return 0;
    220	}
    221
    222	tegra_flowctrl_base = ioremap(res.start, resource_size(&res));
    223	if (!tegra_flowctrl_base)
    224		return -ENXIO;
    225
    226	return 0;
    227}
    228early_initcall(tegra_flowctrl_init);