linux/arch/arm/mach-tegra/flowctrl.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-tegra/flowctrl.c
   3 *
   4 * functions and macros to control the flowcontroller
   5 *
   6 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms and conditions of the GNU General Public License,
  10 * version 2, as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include <linux/cpumask.h>
  22#include <linux/init.h>
  23#include <linux/io.h>
  24#include <linux/kernel.h>
  25#include <linux/of.h>
  26#include <linux/of_address.h>
  27
  28#include <soc/tegra/fuse.h>
  29
  30#include "flowctrl.h"
  31
  32static u8 flowctrl_offset_halt_cpu[] = {
  33        FLOW_CTRL_HALT_CPU0_EVENTS,
  34        FLOW_CTRL_HALT_CPU1_EVENTS,
  35        FLOW_CTRL_HALT_CPU1_EVENTS + 8,
  36        FLOW_CTRL_HALT_CPU1_EVENTS + 16,
  37};
  38
  39static u8 flowctrl_offset_cpu_csr[] = {
  40        FLOW_CTRL_CPU0_CSR,
  41        FLOW_CTRL_CPU1_CSR,
  42        FLOW_CTRL_CPU1_CSR + 8,
  43        FLOW_CTRL_CPU1_CSR + 16,
  44};
  45
  46static void __iomem *tegra_flowctrl_base;
  47
  48static void flowctrl_update(u8 offset, u32 value)
  49{
  50        writel(value, tegra_flowctrl_base + offset);
  51
  52        /* ensure the update has reached the flow controller */
  53        wmb();
  54        readl_relaxed(tegra_flowctrl_base + offset);
  55}
  56
  57u32 flowctrl_read_cpu_csr(unsigned int cpuid)
  58{
  59        u8 offset = flowctrl_offset_cpu_csr[cpuid];
  60
  61        return readl(tegra_flowctrl_base + offset);
  62}
  63
  64void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
  65{
  66        return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
  67}
  68
  69void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
  70{
  71        return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
  72}
  73
  74void flowctrl_cpu_suspend_enter(unsigned int cpuid)
  75{
  76        unsigned int reg;
  77        int i;
  78
  79        reg = flowctrl_read_cpu_csr(cpuid);
  80        switch (tegra_get_chip_id()) {
  81        case TEGRA20:
  82                /* clear wfe bitmap */
  83                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
  84                /* clear wfi bitmap */
  85                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
  86                /* pwr gating on wfe */
  87                reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
  88                break;
  89        case TEGRA30:
  90        case TEGRA114:
  91        case TEGRA124:
  92                /* clear wfe bitmap */
  93                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
  94                /* clear wfi bitmap */
  95                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
  96                /* pwr gating on wfi */
  97                reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
  98                break;
  99        }
 100        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr flag */
 101        reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event flag */
 102        reg |= FLOW_CTRL_CSR_ENABLE;                    /* pwr gating */
 103        flowctrl_write_cpu_csr(cpuid, reg);
 104
 105        for (i = 0; i < num_possible_cpus(); i++) {
 106                if (i == cpuid)
 107                        continue;
 108                reg = flowctrl_read_cpu_csr(i);
 109                reg |= FLOW_CTRL_CSR_EVENT_FLAG;
 110                reg |= FLOW_CTRL_CSR_INTR_FLAG;
 111                flowctrl_write_cpu_csr(i, reg);
 112        }
 113}
 114
 115void flowctrl_cpu_suspend_exit(unsigned int cpuid)
 116{
 117        unsigned int reg;
 118
 119        /* Disable powergating via flow controller for CPU0 */
 120        reg = flowctrl_read_cpu_csr(cpuid);
 121        switch (tegra_get_chip_id()) {
 122        case TEGRA20:
 123                /* clear wfe bitmap */
 124                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
 125                /* clear wfi bitmap */
 126                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
 127                break;
 128        case TEGRA30:
 129        case TEGRA114:
 130        case TEGRA124:
 131                /* clear wfe bitmap */
 132                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
 133                /* clear wfi bitmap */
 134                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
 135                break;
 136        }
 137        reg &= ~FLOW_CTRL_CSR_ENABLE;                   /* clear enable */
 138        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr */
 139        reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event */
 140        flowctrl_write_cpu_csr(cpuid, reg);
 141}
 142
 143static const struct of_device_id matches[] __initconst = {
 144        { .compatible = "nvidia,tegra124-flowctrl" },
 145        { .compatible = "nvidia,tegra114-flowctrl" },
 146        { .compatible = "nvidia,tegra30-flowctrl" },
 147        { .compatible = "nvidia,tegra20-flowctrl" },
 148        { }
 149};
 150
 151void __init tegra_flowctrl_init(void)
 152{
 153        /* hardcoded fallback if device tree node is missing */
 154        unsigned long base = 0x60007000;
 155        unsigned long size = SZ_4K;
 156        struct device_node *np;
 157
 158        np = of_find_matching_node(NULL, matches);
 159        if (np) {
 160                struct resource res;
 161
 162                if (of_address_to_resource(np, 0, &res) == 0) {
 163                        size = resource_size(&res);
 164                        base = res.start;
 165                }
 166
 167                of_node_put(np);
 168        }
 169
 170        tegra_flowctrl_base = ioremap_nocache(base, size);
 171}
 172