aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/tegra3_actmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_actmon.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_actmon.c847
1 files changed, 847 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra3_actmon.c b/arch/arm/mach-tegra/tegra3_actmon.c
new file mode 100644
index 00000000000..43130f960ec
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra3_actmon.c
@@ -0,0 +1,847 @@
1/*
2 * Copyright (c) 2011, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 */
17
18#include <linux/kernel.h>
19#include <linux/spinlock.h>
20#include <linux/err.h>
21#include <linux/io.h>
22#include <linux/clk.h>
23#include <linux/interrupt.h>
24#include <linux/suspend.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
27#include <linux/uaccess.h>
28
29#include <mach/iomap.h>
30#include <mach/irqs.h>
31#include <mach/clk.h>
32
33#include "clock.h"
34
35#define ACTMON_GLB_STATUS 0x00
36#define ACTMON_GLB_PERIOD_CTRL 0x04
37
38#define ACTMON_DEV_CTRL 0x00
39#define ACTMON_DEV_CTRL_ENB (0x1 << 31)
40#define ACTMON_DEV_CTRL_UP_WMARK_ENB (0x1 << 30)
41#define ACTMON_DEV_CTRL_DOWN_WMARK_ENB (0x1 << 29)
42#define ACTMON_DEV_CTRL_UP_WMARK_NUM_SHIFT 26
43#define ACTMON_DEV_CTRL_UP_WMARK_NUM_MASK (0x7 << 26)
44#define ACTMON_DEV_CTRL_DOWN_WMARK_NUM_SHIFT 23
45#define ACTMON_DEV_CTRL_DOWN_WMARK_NUM_MASK (0x7 << 23)
46#define ACTMON_DEV_CTRL_AVG_UP_WMARK_ENB (0x1 << 21)
47#define ACTMON_DEV_CTRL_AVG_DOWN_WMARK_ENB (0x1 << 20)
48#define ACTMON_DEV_CTRL_PERIODIC_ENB (0x1 << 18)
49#define ACTMON_DEV_CTRL_K_VAL_SHIFT 10
50#define ACTMON_DEV_CTRL_K_VAL_MASK (0x7 << 10)
51
52#define ACTMON_DEV_UP_WMARK 0x04
53#define ACTMON_DEV_DOWN_WMARK 0x08
54#define ACTMON_DEV_INIT_AVG 0x0c
55#define ACTMON_DEV_AVG_UP_WMARK 0x10
56#define ACTMON_DEV_AVG_DOWN_WMARK 0x14
57
58#define ACTMON_DEV_COUNT_WEGHT 0x18
59#define ACTMON_DEV_COUNT 0x1c
60#define ACTMON_DEV_AVG_COUNT 0x20
61
62#define ACTMON_DEV_INTR_STATUS 0x24
63#define ACTMON_DEV_INTR_UP_WMARK (0x1 << 31)
64#define ACTMON_DEV_INTR_DOWN_WMARK (0x1 << 30)
65#define ACTMON_DEV_INTR_AVG_DOWN_WMARK (0x1 << 25)
66#define ACTMON_DEV_INTR_AVG_UP_WMARK (0x1 << 24)
67
68#define ACTMON_DEFAULT_AVG_WINDOW_LOG2 6
69#define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */
70
71enum actmon_type {
72 ACTMON_LOAD_SAMPLER,
73 ACTMON_FREQ_SAMPLER,
74};
75
76enum actmon_state {
77 ACTMON_UNINITIALIZED = -1,
78 ACTMON_OFF = 0,
79 ACTMON_ON = 1,
80 ACTMON_SUSPENDED = 2,
81};
82
83#define ACTMON_DEFAULT_SAMPLING_PERIOD 12
84static u8 actmon_sampling_period;
85
86static unsigned long actmon_clk_freq;
87
88
89/* Units:
90 * - frequency in kHz
91 * - coefficients, and thresholds in %
92 * - sampling period in ms
93 * - window in sample periods (value = setting + 1)
94 */
95struct actmon_dev {
96 u32 reg;
97 u32 glb_status_irq_mask;
98 const char *dev_id;
99 const char *con_id;
100 struct clk *clk;
101
102 unsigned long max_freq;
103 unsigned long target_freq;
104 unsigned long cur_freq;
105
106 unsigned long avg_actv_freq;
107 unsigned long avg_band_freq;
108 unsigned int avg_sustain_coef;
109 u32 avg_count;
110
111 unsigned long boost_freq;
112 unsigned long boost_freq_step;
113 unsigned int boost_up_coef;
114 unsigned int boost_down_coef;
115 unsigned int boost_up_threshold;
116 unsigned int boost_down_threshold;
117
118 u8 up_wmark_window;
119 u8 down_wmark_window;
120 u8 avg_window_log2;
121 u32 count_weight;
122
123 enum actmon_type type;
124 enum actmon_state state;
125 enum actmon_state saved_state;
126
127 spinlock_t lock;
128
129 struct notifier_block rate_change_nb;
130};
131
132static void __iomem *actmon_base = IO_ADDRESS(TEGRA_ACTMON_BASE);
133
134static inline u32 actmon_readl(u32 offset)
135{
136 return __raw_readl((u32)actmon_base + offset);
137}
138static inline void actmon_writel(u32 val, u32 offset)
139{
140 __raw_writel(val, (u32)actmon_base + offset);
141}
142static inline void actmon_wmb(void)
143{
144 wmb();
145 actmon_readl(ACTMON_GLB_STATUS);
146}
147
148#define offs(x) (dev->reg + x)
149
150static inline unsigned long do_percent(unsigned long val, unsigned int pct)
151{
152 return val * pct / 100;
153}
154
155static inline void actmon_dev_up_wmark_set(struct actmon_dev *dev)
156{
157 u32 val;
158 unsigned long freq = (dev->type == ACTMON_FREQ_SAMPLER) ?
159 dev->cur_freq : actmon_clk_freq;
160
161 val = freq * actmon_sampling_period;
162 actmon_writel(do_percent(val, dev->boost_up_threshold),
163 offs(ACTMON_DEV_UP_WMARK));
164}
165
166static inline void actmon_dev_down_wmark_set(struct actmon_dev *dev)
167{
168 u32 val;
169 unsigned long freq = (dev->type == ACTMON_FREQ_SAMPLER) ?
170 dev->cur_freq : actmon_clk_freq;
171
172 val = freq * actmon_sampling_period;
173 actmon_writel(do_percent(val, dev->boost_down_threshold),
174 offs(ACTMON_DEV_DOWN_WMARK));
175}
176
177static inline void actmon_dev_wmark_set(struct actmon_dev *dev)
178{
179 u32 val;
180 unsigned long freq = (dev->type == ACTMON_FREQ_SAMPLER) ?
181 dev->cur_freq : actmon_clk_freq;
182
183 val = freq * actmon_sampling_period;
184 actmon_writel(do_percent(val, dev->boost_up_threshold),
185 offs(ACTMON_DEV_UP_WMARK));
186 actmon_writel(do_percent(val, dev->boost_down_threshold),
187 offs(ACTMON_DEV_DOWN_WMARK));
188}
189
190static inline void actmon_dev_avg_wmark_set(struct actmon_dev *dev)
191{
192 u32 avg = dev->avg_count;
193 u32 band = dev->avg_band_freq * actmon_sampling_period;
194
195 actmon_writel(avg + band, offs(ACTMON_DEV_AVG_UP_WMARK));
196 avg = max(avg, band);
197 actmon_writel(avg - band, offs(ACTMON_DEV_AVG_DOWN_WMARK));
198}
199
200static unsigned long actmon_dev_avg_freq_get(struct actmon_dev *dev)
201{
202 u64 val;
203
204 if (dev->type == ACTMON_FREQ_SAMPLER)
205 return dev->avg_count / actmon_sampling_period;
206
207 val = (u64)dev->avg_count * dev->cur_freq;
208 do_div(val, actmon_clk_freq * actmon_sampling_period);
209 return (u32)val;
210}
211
212/* Activity monitor sampling operations */
213irqreturn_t actmon_dev_isr(int irq, void *dev_id)