blob: c80d1e57d2f73a0a345365f16091c23e0617f181 [file] [log] [blame]
Olav Haugan7a2f99c2013-02-04 14:43:26 -08001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/**
14 * This file contains the part of the IOMMUv0 PMU driver that actually touches
15 * IOMMU PMU registers.
16 */
17
18#include <linux/io.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <mach/iommu_hw-v0.h>
23#include <mach/iommu_perfmon.h>
24
25#define PM_RESET_MASK (0xF)
26#define PM_RESET_SHIFT (0x8)
27#define PM_RESET (PM_RESET_MASK << PM_RESET_SHIFT)
28
29#define PM_ENABLE_MASK (0x1)
30#define PM_ENABLE_SHIFT (0x0)
31#define PM_ENABLE (PM_ENABLE_MASK << PM_ENABLE_SHIFT)
32
33#define PM_OVFL_FLAG_MASK (0xF)
34#define PM_OVFL_FLAG_SHIFT (0x0)
35#define PM_OVFL_FLAG (PM_OVFL_FLAG_MASK << PM_OVFL_FLAG_SHIFT)
36
37#define PM_EVENT_TYPE_MASK (0x1F)
38#define PM_EVENT_TYPE_SHIFT (0x2)
39#define PM_EVENT_TYPE (PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT)
40
41#define PM_INT_EN_MASK (0x1)
42#define PM_INT_EN_SHIFT (0x0)
43#define PM_INT_EN (PM_INT_EN_MASK << PM_INT_EN_SHIFT)
44
45#define PM_INT_POL_MASK (0x1)
46#define PM_INT_POL_SHIFT (0x2)
47#define PM_INT_ACTIVE_HIGH (0x1)
48
49#define PMEVCNTR_(n) (EMC_N + n*4)
50#define PMEVTYPER_(n) (EMCC_N + n*4)
51
52/**
53 * Translate between SMMUv0 event classes and standard ARM SMMU event classes
54 */
55static int iommu_pm_event_class_translation_table[] = {
56 MSM_IOMMU_PMU_NO_EVENT_CLASS,
57 MSM_IOMMU_PMU_NO_EVENT_CLASS,
58 MSM_IOMMU_PMU_NO_EVENT_CLASS,
59 0x8,
60 0x9,
61 MSM_IOMMU_PMU_NO_EVENT_CLASS,
62 0x80,
63 MSM_IOMMU_PMU_NO_EVENT_CLASS,
64 0x12,
65 MSM_IOMMU_PMU_NO_EVENT_CLASS,
66 MSM_IOMMU_PMU_NO_EVENT_CLASS,
67 MSM_IOMMU_PMU_NO_EVENT_CLASS,
68 MSM_IOMMU_PMU_NO_EVENT_CLASS,
69 MSM_IOMMU_PMU_NO_EVENT_CLASS,
70 MSM_IOMMU_PMU_NO_EVENT_CLASS,
71 0x10,
72};
73
74static int iommu_pm_translate_event_class(int event_class)
75{
76 const unsigned int TBL_LEN =
77 ARRAY_SIZE(iommu_pm_event_class_translation_table);
78 unsigned int i;
79
80 if (event_class < 0)
81 return event_class;
82
83 for (i = 0; i < TBL_LEN; ++i) {
84 if (iommu_pm_event_class_translation_table[i] == event_class)
85 return i;
86 }
87 return MSM_IOMMU_PMU_NO_EVENT_CLASS;
88}
89
90static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
91{
92 /*
93 * IOMMUv0 is in always ON domain so we don't care whether we are
94 * attached or not. We only care whether the PMU is enabled or
95 * not meaning clocks are turned on.
96 */
97 return pmon->enabled;
98}
99
100static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
101{
102 /* No group concept in v0. */
103}
104
105static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
106{
107 /* No group concept in v0. */
108}
109
110static void iommu_pm_set_int_active_high(const struct iommu_info *iommu)
111{
112 unsigned int emmc;
113 emmc = readl_relaxed(iommu->base + EMMC);
114 emmc |= (PM_INT_ACTIVE_HIGH & PM_INT_POL_MASK) << PM_INT_POL_SHIFT;
115 writel_relaxed(emmc, iommu->base + EMMC);
116}
117
118static void iommu_pm_enable(struct iommu_info *iommu)
119{
120 unsigned int emmc;
121 emmc = readl_relaxed(iommu->base + EMMC);
122 emmc |= PM_ENABLE;
123 writel_relaxed(emmc, iommu->base + EMMC);
124}
125
126static void iommu_pm_disable(struct iommu_info *iommu)
127{
128 unsigned int emmc;
129 emmc = readl_relaxed(iommu->base + EMMC);
130 emmc &= ~PM_ENABLE;
131 writel_relaxed(emmc, iommu->base + EMMC);
132}
133
134static void iommu_pm_reset_counters(const struct iommu_info *iommu)
135{
136 unsigned int emmc;
137 emmc = readl_relaxed(iommu->base + EMMC);
138 emmc |= PM_RESET;
139 writel_relaxed(emmc, iommu->base + EMMC);
140}
141
142static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
143{
144 struct iommu_pmon_counter *counter;
145 struct iommu_info *iommu = &pmon->iommu;
146 unsigned int reg_value;
147 unsigned int j;
148 struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[0];
149
150 reg_value = readl_relaxed(iommu->base + EMCS);
151 reg_value &= PM_OVFL_FLAG;
152
153 for (j = 0; j < cnt_grp->num_counters; ++j) {
154 counter = &cnt_grp->counters[j];
155
156 if (counter->enabled) {
157 if (reg_value & (1 << counter->absolute_counter_no))
158 counter->overflow_count++;
159 }
160 }
161
162 /* Clear overflow */
163 writel_relaxed(reg_value, iommu->base + EMCS);
164}
165
166static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
167{
168 struct iommu_pmon *pmon = dev_id;
169 struct iommu_info *iommu = &pmon->iommu;
170
171 mutex_lock(&pmon->lock);
172
173 if (!iommu_pm_is_hw_access_OK(pmon)) {
174 mutex_unlock(&pmon->lock);
175 goto out;
176 }
177
178 iommu->ops->iommu_lock_acquire();
179 iommu_pm_check_for_overflow(pmon);
180 iommu->ops->iommu_lock_release();
181
182 mutex_unlock(&pmon->lock);
183
184out:
185 return IRQ_HANDLED;
186}
187
188static void iommu_pm_counter_enable(struct iommu_info *iommu,
189 struct iommu_pmon_counter *counter)
190{
191 unsigned int bit_no = counter->absolute_counter_no;
192 unsigned int reg_value;
193
194 /* Clear overflow of counter */
195 reg_value = readl_relaxed(iommu->base + EMCS);
196 reg_value &= (1 << bit_no);
197 writel_relaxed(reg_value, iommu->base + EMCS);
198
199 /* Enable counter */
200 counter->enabled = 1;
201}
202
203static void iommu_pm_counter_disable(struct iommu_info *iommu,
204 struct iommu_pmon_counter *counter)
205{
206 unsigned int bit_no = counter->absolute_counter_no;
207 unsigned int reg_value;
208
209 /* Disable counter */
210 counter->enabled = 0;
211
212 /* Clear overflow of counter */
213 reg_value = readl_relaxed(iommu->base + EMCS);
214 reg_value &= (1 << bit_no);
215 writel_relaxed(reg_value, iommu->base + EMCS);
216}
217
218/*
219 * Must be called after iommu_start_access() is called
220 */
221static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
222 const struct iommu_pmon_counter *counter)
223{
224 unsigned int reg_no = counter->absolute_counter_no;
225 unsigned int reg_value;
226
227 /* Enable overflow interrupt for counter */
228 reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
229 reg_value |= PM_INT_EN;
230 writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
231}
232
233/*
234 * Must be called after iommu_start_access() is called
235 */
236static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
237 const struct iommu_pmon_counter *counter)
238{
239 unsigned int reg_no = counter->absolute_counter_no;
240 unsigned int reg_value;
241
242 /* Disable overflow interrupt for counter */
243 reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
244 reg_value &= ~PM_INT_EN;
245 writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
246}
247
248static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
249 unsigned int count_no,
250 unsigned int event_class)
251{
252 unsigned int reg_no = count_no;
253 unsigned int reg_value;
254 int event = iommu_pm_translate_event_class(event_class);
255
256 if (event == MSM_IOMMU_PMU_NO_EVENT_CLASS)
257 event = 0;
258
259 reg_value = readl_relaxed(pmon->iommu.base + PMEVTYPER_(reg_no));
260 reg_value &= ~(PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT);
261 reg_value |= (event & PM_EVENT_TYPE_MASK) << PM_EVENT_TYPE_SHIFT;
262 writel_relaxed(reg_value, pmon->iommu.base + PMEVTYPER_(reg_no));
263}
264
265static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
266{
267 struct iommu_pmon *pmon = counter->cnt_group->pmon;
268 struct iommu_info *info = &pmon->iommu;
269 unsigned int cnt_no = counter->absolute_counter_no;
270 return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
271}
272
273static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
274{
275 const struct iommu_info *iommu = &pmon->iommu;
276 struct msm_iommu_drvdata *iommu_drvdata =
277 dev_get_drvdata(iommu->iommu_dev);
278
279 /* This is called during bootup device initialization so no need
280 * for locking here.
281 */
282 iommu->ops->iommu_power_on(iommu_drvdata);
283 iommu_pm_set_int_active_high(iommu);
284 iommu->ops->iommu_power_off(iommu_drvdata);
285}
286
287static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
288 .initialize_hw = iommu_pm_initialize_hw,
289 .is_hw_access_OK = iommu_pm_is_hw_access_OK,
290 .grp_enable = iommu_pm_grp_enable,
291 .grp_disable = iommu_pm_grp_disable,
292 .enable_pm = iommu_pm_enable,
293 .disable_pm = iommu_pm_disable,
294 .reset_counters = iommu_pm_reset_counters,
295 .check_for_overflow = iommu_pm_check_for_overflow,
296 .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
297 .counter_enable = iommu_pm_counter_enable,
298 .counter_disable = iommu_pm_counter_disable,
299 .ovfl_int_enable = iommu_pm_ovfl_int_enable,
300 .ovfl_int_disable = iommu_pm_ovfl_int_disable,
301 .set_event_class = iommu_pm_set_event_class,
302 .read_counter = iommu_pm_read_counter,
303};
304
305struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
306{
307 return &iommu_pm_hw_ops;
308}
309EXPORT_SYMBOL(iommu_pm_get_hw_ops_v0);
310