gator: ARM DS-5.4 Streamline gator driver
[android-sdk/arm-ds5-gator.git] / gator_events_armv6.c
1 /**
2  * Copyright (C) ARM Limited 2010-2011. All rights reserved.
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 version 2 as
6  * published by the Free Software Foundation.
7  */
9 #include "gator.h"
11 #if defined(__arm__)
13 #define ARM1136         0xb36
14 #define ARM1156         0xb56
15 #define ARM1176         0xb76
17 static const char *pmnc_name;
19 extern u32 gator_cpuid(void);
21 /*
22  * Per-CPU PMCR
23  */
24 #define PMCR_E                  (1 << 0)        /* Enable */
25 #define PMCR_P                  (1 << 1)        /* Count reset */
26 #define PMCR_C                  (1 << 2)        /* Cycle counter reset */
27 #define PMCR_OFL_PMN0   (1 << 8)        /* Count reg 0 overflow */
28 #define PMCR_OFL_PMN1   (1 << 9)        /* Count reg 1 overflow */
29 #define PMCR_OFL_CCNT   (1 << 10)       /* Cycle counter overflow */
31 #define PMN0 0
32 #define PMN1 1
33 #define CCNT 2
34 #define CNTMAX  (CCNT+1)
36 static int pmnc_count = 0;
37 static unsigned long pmnc_enabled[CNTMAX];
38 static unsigned long pmnc_event[CNTMAX];
39 static unsigned long pmnc_key[CNTMAX];
41 static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
42 static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
44 static inline void armv6_pmnc_write(u32 val)
45 {
46         /* upper 4bits and 7, 11 are write-as-0 */
47         val &= 0x0ffff77f;
48         asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
49 }
51 static inline u32 armv6_pmnc_read(void)
52 {
53         u32 val;
54         asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
55         return val;
56 }
58 static void armv6_pmnc_reset_counter(unsigned int cnt)
59 {
60         u32 val = 0;
61         switch (cnt) {
62         case CCNT:
63                 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
64                 break;
65         case PMN0:
66                 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
67                 break;
68         case PMN1:
69                 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
70                 break;
71         }
72 }
74 int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
75 {
76         struct dentry *dir;
77         int i;
79         pmnc_count = 3;
81         for (i = PMN0; i <= CCNT; i++) {
82                 char buf[40];
83                 if (i == CCNT) {
84                         snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
85                 } else {
86                         snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
87                 }
88                 dir = gatorfs_mkdir(sb, root, buf);
89                 if (!dir) {
90                         return -1;
91                 }
92                 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
93                 if (i != CCNT) {
94                         gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
95                 }
96                 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
97         }
99         return 0;
102 static int gator_events_armv6_init(int *key)
104         unsigned int cnt;
106         for (cnt = PMN0; cnt <= CCNT; cnt++) {
107                 pmnc_enabled[cnt] = 0;
108                 pmnc_event[cnt] = 0;
109                 pmnc_key[cnt] = *key;
110                 *key = *key + 1;
111         }
113         return 0;
116 static void gator_events_armv6_online(void)
118         unsigned int cnt;
119         u32 pmnc;
121         if (armv6_pmnc_read() & PMCR_E) {
122                 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
123         }
125         /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
126         armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
127                         PMCR_C | PMCR_P);
129         /* configure control register */
130         for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
131                 unsigned long event;
133                 per_cpu(perfPrev, raw_smp_processor_id())[cnt] = 0;
135                 if (!pmnc_enabled[cnt])
136                         continue;
138                 event = pmnc_event[cnt] & 255;
140                 /*
141                  * Set event (if destined for PMNx counters)
142                  */
143                 if (cnt == PMN0) {
144                         pmnc |= event << 20;
145                 } else if (cnt == PMN1) {
146                         pmnc |= event << 12;
147                 }
149                 /*
150                  * Reset counter
151                  */
152                 armv6_pmnc_reset_counter(cnt);
153         }
154         armv6_pmnc_write(pmnc | PMCR_E);
157 static void gator_events_armv6_offline(void)
159         unsigned int cnt;
161         armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
162         for (cnt = PMN0; cnt <= CCNT; cnt++) {
163                 armv6_pmnc_reset_counter(cnt);
164         }
167 static void gator_events_armv6_stop(void)
169         unsigned int cnt;
171         for (cnt = PMN0; cnt <= CCNT; cnt++) {
172                 pmnc_enabled[cnt] = 0;
173                 pmnc_event[cnt] = 0;
174         }
177 static int gator_events_armv6_read(int **buffer)
179         int cnt, len = 0;
180         int cpu = raw_smp_processor_id();
182         for (cnt = PMN0; cnt <= CCNT; cnt++) {
183                 if (pmnc_enabled[cnt]) {
184                         u32 value = 0;
185                         switch (cnt) {
186                         case CCNT:
187                                 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
188                                 break;
189                         case PMN0:
190                                 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
191                                 break;
192                         case PMN1:
193                                 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
194                                 break;
195                         }
196                         armv6_pmnc_reset_counter(cnt);
197                         if (value != per_cpu(perfPrev, cpu)[cnt]) {
198                                 per_cpu(perfPrev, cpu)[cnt] = value;
199                                 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
200                                 per_cpu(perfCnt, cpu)[len++] = value;
201                         }
202                 }
203         }
205         // update or discard
206         if (buffer)
207                 *buffer = per_cpu(perfCnt, cpu);
209         return len;
211 #endif
213 int gator_events_armv6_install(gator_interface *gi) {
214 #if defined(__arm__)
215         switch (gator_cpuid()) {
216         case ARM1136:
217         case ARM1156:
218         case ARM1176:
219                 pmnc_name = "ARM11";
220                 break;
221         default:
222                 return -1;
223         }
225         gi->create_files = gator_events_armv6_create_files;
226         gi->init = gator_events_armv6_init;
227         gi->stop = gator_events_armv6_stop;
228         gi->online = gator_events_armv6_online;
229         gi->offline = gator_events_armv6_offline;
230         gi->read = gator_events_armv6_read;
231 #endif
232         return 0;