root/drivers/soc/tegra/flowctrl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flowctrl_update
  2. flowctrl_read_cpu_csr
  3. flowctrl_write_cpu_csr
  4. flowctrl_write_cpu_halt
  5. flowctrl_cpu_suspend_enter
  6. flowctrl_cpu_suspend_exit
  7. tegra_flowctrl_probe
  8. tegra_flowctrl_init

   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 
  22 static 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 
  29 static 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 
  36 static void __iomem *tegra_flowctrl_base;
  37 
  38 static 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 
  51 u32 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 
  62 void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
  63 {
  64         return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
  65 }
  66 
  67 void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
  68 {
  69         return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
  70 }
  71 
  72 void 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 
 113 void 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 
 141 static 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 
 156 static 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 
 165 static 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 };
 173 builtin_platform_driver(tegra_flowctrl_driver);
 174 
 175 static 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 }
 213 early_initcall(tegra_flowctrl_init);

/* [<][>][^][v][top][bottom][index][help] */