linux/drivers/soc/tegra/flowctrl.c
<<
>>
Prefs
   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                /* pwr gating on wfi */
  95                reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
  96                break;
  97        }
  98        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr flag */
  99        reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event flag */
 100        reg |= FLOW_CTRL_CSR_ENABLE;                    /* pwr gating */
 101        flowctrl_write_cpu_csr(cpuid, reg);
 102
 103        for (i = 0; i < num_possible_cpus(); i++) {
 104                if (i == cpuid)
 105                        continue;
 106                reg = flowctrl_read_cpu_csr(i);
 107                reg |= FLOW_CTRL_CSR_EVENT_FLAG;
 108                reg |= FLOW_CTRL_CSR_INTR_FLAG;
 109                flowctrl_write_cpu_csr(i, reg);
 110        }
 111}
 112
 113void flowctrl_cpu_suspend_exit(unsigned int cpuid)
 114{
 115        unsigned int reg;
 116
 117        /* Disable powergating via flow controller for CPU0 */
 118        reg = flowctrl_read_cpu_csr(cpuid);
 119        switch (tegra_get_chip_id()) {
 120        case TEGRA20:
 121                /* clear wfe bitmap */
 122                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
 123                /* clear wfi bitmap */
 124                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
 125                break;
 126        case TEGRA30:
 127        case TEGRA114:
 128        case TEGRA124:
 129                /* clear wfe bitmap */
 130                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
 131                /* clear wfi bitmap */
 132                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
 133                break;
 134        }
 135        reg &= ~FLOW_CTRL_CSR_ENABLE;                   /* clear enable */
 136        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr */
 137        reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event */
 138        flowctrl_write_cpu_csr(cpuid, reg);
 139}
 140
 141static int tegra_flowctrl_probe(struct platform_device *pdev)
 142{
 143        void __iomem *base = tegra_flowctrl_base;
 144        struct resource *res;
 145
 146        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 147        tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
 148        if (IS_ERR(tegra_flowctrl_base))
 149                return PTR_ERR(tegra_flowctrl_base);
 150
 151        iounmap(base);
 152
 153        return 0;
 154}
 155
 156static const struct of_device_id tegra_flowctrl_match[] = {
 157        { .compatible = "nvidia,tegra210-flowctrl" },
 158        { .compatible = "nvidia,tegra124-flowctrl" },
 159        { .compatible = "nvidia,tegra114-flowctrl" },
 160        { .compatible = "nvidia,tegra30-flowctrl" },
 161        { .compatible = "nvidia,tegra20-flowctrl" },
 162        { }
 163};
 164
 165static struct platform_driver tegra_flowctrl_driver = {
 166        .driver = {
 167                .name = "tegra-flowctrl",
 168                .suppress_bind_attrs = true,
 169                .of_match_table = tegra_flowctrl_match,
 170        },
 171        .probe = tegra_flowctrl_probe,
 172};
 173builtin_platform_driver(tegra_flowctrl_driver);
 174
 175static int __init tegra_flowctrl_init(void)
 176{
 177        struct resource res;
 178        struct device_node *np;
 179
 180        if (!soc_is_tegra())
 181                return 0;
 182
 183        np = of_find_matching_node(NULL, tegra_flowctrl_match);
 184        if (np) {
 185                if (of_address_to_resource(np, 0, &res) < 0) {
 186                        pr_err("failed to get flowctrl register\n");
 187                        return -ENXIO;
 188                }
 189                of_node_put(np);
 190        } else if (IS_ENABLED(CONFIG_ARM)) {
 191                /*
 192                 * Hardcoded fallback for 32-bit Tegra
 193                 * devices if device tree node is missing.
 194                 */
 195                res.start = 0x60007000;
 196                res.end = 0x60007fff;
 197                res.flags = IORESOURCE_MEM;
 198        } else {
 199                /*
 200                 * At this point we're running on a Tegra,
 201                 * that doesn't support the flow controller
 202                 * (eg. Tegra186), so just return.
 203                 */
 204                return 0;
 205        }
 206
 207        tegra_flowctrl_base = ioremap_nocache(res.start, resource_size(&res));
 208        if (!tegra_flowctrl_base)
 209                return -ENXIO;
 210
 211        return 0;
 212}
 213early_initcall(tegra_flowctrl_init);
 214