aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2015-07-24 00:17:24 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2015-08-03 01:33:05 -0400
commit3d87b02281a2ec977108ad90ce502e721b447301 (patch)
tree676ba7bea3a11550f0d664ff7aa585aa0f4eadbd
parent9b0a18626288ecd62ad09a9c36a5ba318ea30087 (diff)
PM / devfreq: exynos-ppmu: Add the support of PPMUv2 for Exynos5433
This patch adds the support for PPMU (Platform Performance Monitoring Unit) version 2.0 for Exynos5433 SoC. Exynos5433 SoC must need PPMUv2 which is quite different from PPMUv1.1. The exynos-ppmu.c driver supports both PPMUv1.1 and PPMUv2. Cc: MyungJoo Ham <myungjoo.ham@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--drivers/devfreq/event/exynos-ppmu.c170
-rw-r--r--drivers/devfreq/event/exynos-ppmu.h70
2 files changed, 233 insertions, 7 deletions
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c
index 7d99d13bacd8..f9901f52a225 100644
--- a/drivers/devfreq/event/exynos-ppmu.c
+++ b/drivers/devfreq/event/exynos-ppmu.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support 2 * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support
3 * 3 *
4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. 4 * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
5 * Author : Chanwoo Choi <cw00.choi@samsung.com> 5 * Author : Chanwoo Choi <cw00.choi@samsung.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -82,6 +82,15 @@ struct __exynos_ppmu_events {
82 PPMU_EVENT(mscl), 82 PPMU_EVENT(mscl),
83 PPMU_EVENT(fimd0x), 83 PPMU_EVENT(fimd0x),
84 PPMU_EVENT(fimd1x), 84 PPMU_EVENT(fimd1x),
85
86 /* Only for Exynos5433 SoCs */
87 PPMU_EVENT(d0-cpu),
88 PPMU_EVENT(d0-general),
89 PPMU_EVENT(d0-rt),
90 PPMU_EVENT(d1-cpu),
91 PPMU_EVENT(d1-general),
92 PPMU_EVENT(d1-rt),
93
85 { /* sentinel */ }, 94 { /* sentinel */ },
86}; 95};
87 96
@@ -96,6 +105,9 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
96 return -EINVAL; 105 return -EINVAL;
97} 106}
98 107
108/*
109 * The devfreq-event ops structure for PPMU v1.1
110 */
99static int exynos_ppmu_disable(struct devfreq_event_dev *edev) 111static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
100{ 112{
101 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 113 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
@@ -200,10 +212,158 @@ static const struct devfreq_event_ops exynos_ppmu_ops = {
200 .get_event = exynos_ppmu_get_event, 212 .get_event = exynos_ppmu_get_event,
201}; 213};
202 214
215/*
216 * The devfreq-event ops structure for PPMU v2.0
217 */
218static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
219{
220 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
221 u32 pmnc, clear;
222
223 /* Disable all counters */
224 clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK
225 | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK);
226
227 __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG);
228 __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC);
229 __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC);
230 __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET);
231
232 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0);
233 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1);
234 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2);
235 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT);
236 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO);
237 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE);
238 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE);
239 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE);
240 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE);
241 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V);
242 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A);
243 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V);
244 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A);
245 __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET);
246
247 /* Disable PPMU */
248 pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
249 pmnc &= ~PPMU_PMNC_ENABLE_MASK;
250 __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
251
252 return 0;
253}
254
255static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
256{
257 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
258 int id = exynos_ppmu_find_ppmu_id(edev);
259 u32 pmnc, cntens;
260
261 /* Enable all counters */
262 cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS);
263 cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
264 __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS);
265
266 /* Set the event of Read/Write data count */
267 switch (id) {
268 case PPMU_PMNCNT0:
269 case PPMU_PMNCNT1:
270 case PPMU_PMNCNT2:
271 __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT,
272 info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id));
273 break;
274 case PPMU_PMNCNT3:
275 __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT,
276 info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id));
277 break;
278 }
279
280 /* Reset cycle counter/performance counter and enable PPMU */
281 pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
282 pmnc &= ~(PPMU_PMNC_ENABLE_MASK
283 | PPMU_PMNC_COUNTER_RESET_MASK
284 | PPMU_PMNC_CC_RESET_MASK
285 | PPMU_PMNC_CC_DIVIDER_MASK
286 | PPMU_V2_PMNC_START_MODE_MASK);
287 pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
288 pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
289 pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
290 pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT);
291 __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
292
293 return 0;
294}
295
296static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev,
297 struct devfreq_event_data *edata)
298{
299 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
300 int id = exynos_ppmu_find_ppmu_id(edev);
301 u32 pmnc, cntenc;
302 u32 pmcnt_high, pmcnt_low;
303 u64 load_count = 0;
304
305 /* Disable PPMU */
306 pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
307 pmnc &= ~PPMU_PMNC_ENABLE_MASK;
308 __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
309
310 /* Read cycle count and performance count */
311 edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT);
312
313 switch (id) {
314 case PPMU_PMNCNT0:
315 case PPMU_PMNCNT1:
316 case PPMU_PMNCNT2:
317 load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id));
318 break;
319 case PPMU_PMNCNT3:
320 pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH);
321 pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW);
322 load_count = (u64)((pmcnt_high & 0xff) << 32) + (u64)pmcnt_low;
323 break;
324 }
325 edata->load_count = load_count;
326
327 /* Disable all counters */
328 cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC);
329 cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
330 __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC);
331
332 dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name,
333 edata->load_count, edata->total_count);
334 return 0;
335}
336
337static const struct devfreq_event_ops exynos_ppmu_v2_ops = {
338 .disable = exynos_ppmu_v2_disable,
339 .set_event = exynos_ppmu_v2_set_event,
340 .get_event = exynos_ppmu_v2_get_event,
341};
342
343static const struct of_device_id exynos_ppmu_id_match[] = {
344 {
345 .compatible = "samsung,exynos-ppmu",
346 .data = (void *)&exynos_ppmu_ops,
347 }, {
348 .compatible = "samsung,exynos-ppmu-v2",
349 .data = (void *)&exynos_ppmu_v2_ops,
350 },
351 { /* sentinel */ },
352};
353
354static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np)
355{
356 const struct of_device_id *match;
357
358 match = of_match_node(exynos_ppmu_id_match, np);
359 return (struct devfreq_event_ops *)match->data;
360}
361
203static int of_get_devfreq_events(struct device_node *np, 362static int of_get_devfreq_events(struct device_node *np,
204 struct exynos_ppmu *info) 363 struct exynos_ppmu *info)
205{ 364{
206 struct devfreq_event_desc *desc; 365 struct devfreq_event_desc *desc;
366 struct devfreq_event_ops *event_ops;
207 struct device *dev = info->dev; 367 struct device *dev = info->dev;
208 struct device_node *events_np, *node; 368 struct device_node *events_np, *node;
209 int i, j, count; 369 int i, j, count;
@@ -214,6 +374,7 @@ static int of_get_devfreq_events(struct device_node *np,
214 "failed to get child node of devfreq-event devices\n"); 374 "failed to get child node of devfreq-event devices\n");
215 return -EINVAL; 375 return -EINVAL;
216 } 376 }
377 event_ops = exynos_bus_get_ops(np);
217 378
218 count = of_get_child_count(events_np); 379 count = of_get_child_count(events_np);
219 desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); 380 desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL);
@@ -238,7 +399,7 @@ static int of_get_devfreq_events(struct device_node *np,
238 continue; 399 continue;
239 } 400 }
240 401
241 desc[j].ops = &exynos_ppmu_ops; 402 desc[j].ops = event_ops;
242 desc[j].driver_data = info; 403 desc[j].driver_data = info;
243 404
244 of_property_read_string(node, "event-name", &desc[j].name); 405 of_property_read_string(node, "event-name", &desc[j].name);
@@ -354,11 +515,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev)
354 return 0; 515 return 0;
355} 516}
356 517
357static struct of_device_id exynos_ppmu_id_match[] = {
358 { .compatible = "samsung,exynos-ppmu", },
359 { /* sentinel */ },
360};
361
362static struct platform_driver exynos_ppmu_driver = { 518static struct platform_driver exynos_ppmu_driver = {
363 .probe = exynos_ppmu_probe, 519 .probe = exynos_ppmu_probe,
364 .remove = exynos_ppmu_remove, 520 .remove = exynos_ppmu_remove,
diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h
index 4e831d48c138..05774c449137 100644
--- a/drivers/devfreq/event/exynos-ppmu.h
+++ b/drivers/devfreq/event/exynos-ppmu.h
@@ -26,6 +26,9 @@ enum ppmu_counter {
26 PPMU_PMNCNT_MAX, 26 PPMU_PMNCNT_MAX,
27}; 27};
28 28
29/***
30 * PPMUv1.1 Definitions
31 */
29enum ppmu_event_type { 32enum ppmu_event_type {
30 PPMU_RO_BUSY_CYCLE_CNT = 0x0, 33 PPMU_RO_BUSY_CYCLE_CNT = 0x0,
31 PPMU_WO_BUSY_CYCLE_CNT = 0x1, 34 PPMU_WO_BUSY_CYCLE_CNT = 0x1,
@@ -90,4 +93,71 @@ enum ppmu_reg {
90#define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x)) 93#define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x))
91#define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x)) 94#define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x))
92 95
96/***
97 * PPMU_V2.0 definitions
98 */
99enum ppmu_v2_mode {
100 PPMU_V2_MODE_MANUAL = 0,
101 PPMU_V2_MODE_AUTO = 1,
102 PPMU_V2_MODE_CIG = 2, /* CIG (Conditional Interrupt Generation) */
103};
104
105enum ppmu_v2_event_type {
106 PPMU_V2_RO_DATA_CNT = 0x4,
107 PPMU_V2_WO_DATA_CNT = 0x5,
108
109 PPMU_V2_EVT3_RW_DATA_CNT = 0x22, /* Only for Event3 */
110};
111
112enum ppmu_V2_reg {
113 /* PPC control register */
114 PPMU_V2_PMNC = 0x04,
115 PPMU_V2_CNTENS = 0x08,
116 PPMU_V2_CNTENC = 0x0c,
117 PPMU_V2_INTENS = 0x10,
118 PPMU_V2_INTENC = 0x14,
119 PPMU_V2_FLAG = 0x18,
120
121 /* Cycle Counter and Performance Event Counter Register */
122 PPMU_V2_CCNT = 0x48,
123 PPMU_V2_PMCNT0 = 0x34,
124 PPMU_V2_PMCNT1 = 0x38,
125 PPMU_V2_PMCNT2 = 0x3c,
126 PPMU_V2_PMCNT3_LOW = 0x40,
127 PPMU_V2_PMCNT3_HIGH = 0x44,
128
129 /* Bus Event Generator */
130 PPMU_V2_CIG_CFG0 = 0x1c,
131 PPMU_V2_CIG_CFG1 = 0x20,
132 PPMU_V2_CIG_CFG2 = 0x24,
133 PPMU_V2_CIG_RESULT = 0x28,
134 PPMU_V2_CNT_RESET = 0x2c,
135 PPMU_V2_CNT_AUTO = 0x30,
136 PPMU_V2_CH_EV0_TYPE = 0x200,
137 PPMU_V2_CH_EV1_TYPE = 0x204,
138 PPMU_V2_CH_EV2_TYPE = 0x208,
139 PPMU_V2_CH_EV3_TYPE = 0x20c,
140 PPMU_V2_SM_ID_V = 0x220,
141 PPMU_V2_SM_ID_A = 0x224,
142 PPMU_V2_SM_OTHERS_V = 0x228,
143 PPMU_V2_SM_OTHERS_A = 0x22c,
144 PPMU_V2_INTERRUPT_RESET = 0x260,
145};
146
147/* PMNC register */
148#define PPMU_V2_PMNC_START_MODE_SHIFT 20
149#define PPMU_V2_PMNC_START_MODE_MASK (0x3 << PPMU_V2_PMNC_START_MODE_SHIFT)
150
151#define PPMU_PMNC_CC_RESET_SHIFT 2
152#define PPMU_PMNC_COUNTER_RESET_SHIFT 1
153#define PPMU_PMNC_ENABLE_SHIFT 0
154#define PPMU_PMNC_START_MODE_MASK BIT(16)
155#define PPMU_PMNC_CC_DIVIDER_MASK BIT(3)
156#define PPMU_PMNC_CC_RESET_MASK BIT(2)
157#define PPMU_PMNC_COUNTER_RESET_MASK BIT(1)
158#define PPMU_PMNC_ENABLE_MASK BIT(0)
159
160#define PPMU_V2_PMNCT(x) (PPMU_V2_PMCNT0 + (0x4 * x))
161#define PPMU_V2_CH_EVx_TYPE(x) (PPMU_V2_CH_EV0_TYPE + (0x4 * x))
162
93#endif /* __EXYNOS_PPMU_H__ */ 163#endif /* __EXYNOS_PPMU_H__ */