aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/ppmu.c
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2012-09-28 13:46:28 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2012-09-28 14:50:15 -0400
commitdaa22703f14c007e93b464c45fa60019a36f546d (patch)
treea1a130b6e128dc9d57c35c026977e1b4953105e1 /arch/arm/mach-exynos/ppmu.c
parent5aa287dcf1b5879aa0150b0511833c52885f5b4c (diff)
Apply k4412 kernel from HardKernel for ODROID-X.
Diffstat (limited to 'arch/arm/mach-exynos/ppmu.c')
-rw-r--r--arch/arm/mach-exynos/ppmu.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/ppmu.c b/arch/arm/mach-exynos/ppmu.c
new file mode 100644
index 00000000000..a46421798c2
--- /dev/null
+++ b/arch/arm/mach-exynos/ppmu.c
@@ -0,0 +1,190 @@
1/* linux/arch/arm/mach-exynos/ppmu.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * EXYNOS4 - CPU PPMU support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/list.h>
18#include <linux/math64.h>
19
20#include <plat/cpu.h>
21
22#include <mach/map.h>
23#include <mach/regs-clock.h>
24#include <mach/ppmu.h>
25
26static LIST_HEAD(ppmu_list);
27
28unsigned long long ppmu_load[PPMU_END];
29
30void exynos4_ppmu_reset(struct exynos4_ppmu_hw *ppmu)
31{
32 void __iomem *ppmu_base = ppmu->hw_base;
33 int i;
34
35 __raw_writel(0x3 << 1, ppmu_base);
36 __raw_writel(0x8000000f, ppmu_base + PPMU_CNTENS);
37
38 if (soc_is_exynos4210())
39 for (i = 0; i < NUMBER_OF_COUNTER; i++) {
40 __raw_writel(0x0, ppmu_base + DEVT0_ID + (i * DEVT_ID_OFFSET));
41 __raw_writel(0x0, ppmu_base + DEVT0_IDMSK + (i * DEVT_ID_OFFSET));
42 }
43}
44
45void exynos4_ppmu_setevent(struct exynos4_ppmu_hw *ppmu,
46 unsigned int evt_num)
47{
48 void __iomem *ppmu_base = ppmu->hw_base;
49 __raw_writel(ppmu->event[evt_num], ppmu_base + PPMU_BEVT0SEL + (evt_num * PPMU_BEVTSEL_OFFSET));
50}
51
52void exynos4_ppmu_start(struct exynos4_ppmu_hw *ppmu)
53{
54 void __iomem *ppmu_base = ppmu->hw_base;
55 __raw_writel(0x1, ppmu_base);
56}
57
58void exynos4_ppmu_stop(struct exynos4_ppmu_hw *ppmu)
59{
60 void __iomem *ppmu_base = ppmu->hw_base;
61 __raw_writel(0x0, ppmu_base);
62}
63
64unsigned long long exynos4_ppmu_update(struct exynos4_ppmu_hw *ppmu, int ch)
65{
66 void __iomem *ppmu_base = ppmu->hw_base;
67 unsigned long long total = 0;
68
69 ppmu->ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
70
71 if (ppmu->ccnt == 0)
72 ppmu->ccnt = MAX_CCNT;
73
74 if (ch >= NUMBER_OF_COUNTER || ppmu->event[ch] == 0)
75 return 0;
76
77 if (ch == 3 && !soc_is_exynos4210())
78 total = (((u64)__raw_readl(ppmu_base + PMCNT_OFFSET(ch)) << 8) |
79 __raw_readl(ppmu_base + PMCNT_OFFSET(ch + 1)));
80 else
81 total = __raw_readl(ppmu_base + PMCNT_OFFSET(ch));
82
83 if (total > ppmu->ccnt)
84 total = ppmu->ccnt;
85
86 return div64_u64((total * ppmu->weight * 100), ppmu->ccnt);
87}
88
89void ppmu_start(struct device *dev)
90{
91 struct exynos4_ppmu_hw *ppmu;
92
93 list_for_each_entry(ppmu, &ppmu_list, node)
94 if (ppmu->dev == dev)
95 exynos4_ppmu_start(ppmu);
96}
97
98void ppmu_update(struct device *dev, int ch)
99{
100 struct exynos4_ppmu_hw *ppmu;
101
102 list_for_each_entry(ppmu, &ppmu_list, node)
103 if (ppmu->dev == dev) {
104 exynos4_ppmu_stop(ppmu);
105 ppmu_load[ppmu->id] = exynos4_ppmu_update(ppmu, ch);
106 exynos4_ppmu_reset(ppmu);
107 }
108}
109
110void ppmu_reset(struct device *dev)
111{
112 struct exynos4_ppmu_hw *ppmu;
113 int i;
114
115 list_for_each_entry(ppmu, &ppmu_list, node) {
116 if (ppmu->dev == dev) {
117 exynos4_ppmu_stop(ppmu);
118 for (i = 0; i < NUMBER_OF_COUNTER; i++)
119 if (ppmu->event[i] != 0)
120 exynos4_ppmu_setevent(ppmu, i);
121 exynos4_ppmu_reset(ppmu);
122 }
123 }
124}
125
126void ppmu_init(struct exynos4_ppmu_hw *ppmu, struct device *dev)
127{
128 void __iomem *ppmu_base = ppmu->hw_base;
129 int i;
130
131 ppmu->dev = dev;
132 list_add(&ppmu->node, &ppmu_list);
133
134 if (soc_is_exynos4210())
135 for (i = 0; i < NUMBER_OF_COUNTER; i++) {
136 __raw_writel(0x0, ppmu_base + DEVT0_ID + (i * DEVT_ID_OFFSET));
137 __raw_writel(0x0, ppmu_base + DEVT0_IDMSK + (i * DEVT_ID_OFFSET));
138 }
139
140 for (i = 0; i < NUMBER_OF_COUNTER; i++)
141 if (ppmu->event[i] != 0)
142 exynos4_ppmu_setevent(ppmu, i);
143}
144
145struct exynos4_ppmu_hw exynos_ppmu[] = {
146 [PPMU_DMC0] = {
147 .id = PPMU_DMC0,
148 .hw_base = S5P_VA_PPMU_DMC0,
149 .event[3] = RDWR_DATA_COUNT,
150 .weight = DEFAULT_WEIGHT,
151 },
152 [PPMU_DMC1] = {
153 .id = PPMU_DMC1,
154 .hw_base = S5P_VA_PPMU_DMC1,
155 .event[3] = RDWR_DATA_COUNT,
156 .weight = DEFAULT_WEIGHT,
157 },
158 [PPMU_CPU] = {
159 .id = PPMU_CPU,
160 .hw_base = S5P_VA_PPMU_CPU,
161 .event[3] = RDWR_DATA_COUNT,
162 .weight = DEFAULT_WEIGHT,
163 },
164#ifdef CONFIG_ARCH_EXYNOS5
165 [PPMU_DDR_C] = {
166 .id = PPMU_DDR_C,
167 .hw_base = S5P_VA_PPMU_DDR_C,
168 .event[3] = RDWR_DATA_COUNT,
169 .weight = DEFAULT_WEIGHT,
170 },
171 [PPMU_DDR_R1] = {
172 .id = PPMU_DDR_R1,
173 .hw_base = S5P_VA_PPMU_DDR_R1,
174 .event[3] = RDWR_DATA_COUNT,
175 .weight = DEFAULT_WEIGHT,
176 },
177 [PPMU_DDR_L] = {
178 .id = PPMU_DDR_L,
179 .hw_base = S5P_VA_PPMU_DDR_L,
180 .event[3] = RDWR_DATA_COUNT,
181 .weight = DEFAULT_WEIGHT,
182 },
183 [PPMU_RIGHT0_BUS] = {
184 .id = PPMU_RIGHT0_BUS,
185 .hw_base = S5P_VA_PPMU_RIGHT0_BUS,
186 .event[3] = RDWR_DATA_COUNT,
187 .weight = DEFAULT_WEIGHT,
188 },
189#endif
190};