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/init.h>
  22#include <linux/kernel.h>
  23#include <linux/io.h>
  24#include <linux/cpumask.h>
  25
  26#include "flowctrl.h"
  27#include "iomap.h"
  28#include "fuse.h"
  29
  30static u8 flowctrl_offset_halt_cpu[] = {
  31        FLOW_CTRL_HALT_CPU0_EVENTS,
  32        FLOW_CTRL_HALT_CPU1_EVENTS,
  33        FLOW_CTRL_HALT_CPU1_EVENTS + 8,
  34        FLOW_CTRL_HALT_CPU1_EVENTS + 16,
  35};
  36
  37static u8 flowctrl_offset_cpu_csr[] = {
  38        FLOW_CTRL_CPU0_CSR,
  39        FLOW_CTRL_CPU1_CSR,
  40        FLOW_CTRL_CPU1_CSR + 8,
  41        FLOW_CTRL_CPU1_CSR + 16,
  42};
  43
  44static void flowctrl_update(u8 offset, u32 value)
  45{
  46        void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset;
  47
  48        writel(value, addr);
  49
  50        /* ensure the update has reached the flow controller */
  51        wmb();
  52        readl_relaxed(addr);
  53}
  54
  55u32 flowctrl_read_cpu_csr(unsigned int cpuid)
  56{
  57        u8 offset = flowctrl_offset_cpu_csr[cpuid];
  58        void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset;
  59
  60        return readl(addr);
  61}
  62
  63void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
  64{
  65        return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
  66}
  67
  68void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
  69{
  70        return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
  71}
  72
  73void flowctrl_cpu_suspend_enter(unsigned int cpuid)
  74{
  75        unsigned int reg;
  76        int i;
  77
  78        reg = flowctrl_read_cpu_csr(cpuid);
  79        switch (tegra_chip_id) {
  80        case TEGRA20:
  81                /* clear wfe bitmap */
  82                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
  83                /* clear wfi bitmap */
  84                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
  85                /* pwr gating on wfe */
  86                reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
  87                break;
  88        case TEGRA30:
  89                /* clear wfe bitmap */
  90                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
  91                /* clear wfi bitmap */
  92                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
  93                /* pwr gating on wfi */
  94                reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
  95                break;
  96        }
  97        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr flag */
  98        reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event flag */
  99        reg |= FLOW_CTRL_CSR_ENABLE;                    /* pwr gating */
 100        flowctrl_write_cpu_csr(cpuid, reg);
 101
 102        for (i = 0; i < num_possible_cpus(); i++) {
 103                if (i == cpuid)
 104                        continue;
 105                reg = flowctrl_read_cpu_csr(i);
 106                reg |= FLOW_CTRL_CSR_EVENT_FLAG;
 107                reg |= FLOW_CTRL_CSR_INTR_FLAG;
 108                flowctrl_write_cpu_csr(i, reg);
 109        }
 110}
 111
 112void flowctrl_cpu_suspend_exit(unsigned int cpuid)
 113{
 114        unsigned int reg;
 115
 116        /* Disable powergating via flow controller for CPU0 */
 117        reg = flowctrl_read_cpu_csr(cpuid);
 118        switch (tegra_chip_id) {
 119        case TEGRA20:
 120                /* clear wfe bitmap */
 121                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
 122                /* clear wfi bitmap */
 123                reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
 124                break;
 125        case TEGRA30:
 126                /* clear wfe bitmap */
 127                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
 128                /* clear wfi bitmap */
 129                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
 130                break;
 131        }
 132        reg &= ~FLOW_CTRL_CSR_ENABLE;                   /* clear enable */
 133        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr */
 134        reg |= FLOW_CTRL_CSR_EVENT_FLAG;                /* clear event */
 135        flowctrl_write_cpu_csr(cpuid, reg);
 136}
 137