Merge remote-tracking branch 'arm-landing/lsk-3.10-gator' into linux-linaro-lsk-test
[firefly-linux-kernel-4.4.55.git] / drivers / gator / gator_events_ccn-504.c
1 /**
2  * Copyright (C) ARM Limited 2013. 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  */
8
9 /*******************************************************************************
10  * WARNING: This code is an experimental implementation of the CCN-504 hardware
11  * counters which has not been tested on the hardware. Commented debug
12  * statements are present and can be uncommented for diagnostic purposes.
13  ******************************************************************************/
14
15 #include <linux/io.h>
16 #include <linux/module.h>
17
18 #include "gator.h"
19
20 #define PERIPHBASE 0x2E000000
21
22 #define NUM_REGIONS 256
23 #define REGION_SIZE (64*1024)
24 #define REGION_DEBUG 1
25 #define REGION_XP 64
26
27 // DT (Debug) region
28 #define PMEVCNTSR0    0x0150
29 #define PMCCNTRSR     0x0190
30 #define PMCR          0x01A8
31 #define PMSR          0x01B0
32 #define PMSR_REQ      0x01B8
33 #define PMSR_CLR      0x01C0
34
35 // XP region
36 #define DT_CONFIG     0x0300
37
38 // Multiple
39 #define PMU_EVENT_SEL 0x0600
40 #define OLY_ID        0xFF00
41
42 #define CCNT 4
43 #define CNTMAX (4 + 1)
44
45 #define get_pmu_event_id(event) (((event) >> 0) & 0xFF)
46 #define get_node_type(event) (((event) >> 8) & 0xFF)
47 #define get_region(event) (((event) >> 16) & 0xFF)
48
49 MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address");
50 static unsigned long ccn504_addr = 0;
51 module_param(ccn504_addr, ulong, 0444);
52
53 static void __iomem *gator_events_ccn504_base;
54 static unsigned long gator_events_ccn504_enabled[CNTMAX];
55 static unsigned long gator_events_ccn504_event[CNTMAX];
56 static unsigned long gator_events_ccn504_key[CNTMAX];
57 static int gator_events_ccn504_buffer[2*CNTMAX];
58
59 static void gator_events_ccn504_create_shutdown(void)
60 {
61         if (gator_events_ccn504_base != NULL) {
62                 iounmap(gator_events_ccn504_base);
63         }
64 }
65
66 static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root)
67 {
68         struct dentry *dir;
69         int i;
70         char buf[32];
71
72         for (i = 0; i < CNTMAX; ++i) {
73                 if (i == CCNT) {
74                         snprintf(buf, sizeof(buf), "CCN-504_ccnt");
75                 } else {
76                         snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i);
77                 }
78                 dir = gatorfs_mkdir(sb, root, buf);
79                 if (!dir) {
80                         return -1;
81                 }
82
83                 gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]);
84                 if (i != CCNT) {
85                         gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]);
86                 }
87                 gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]);
88         }
89
90         return 0;
91 }
92
93 static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value)
94 {
95         u32 dt_config;
96
97         dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
98         dt_config |= (value + event_num) << (4*event_num);
99         //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, dt_config, (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
100         writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
101 }
102
103 static int gator_events_ccn504_start(void)
104 {
105         int i;
106
107         // Disable INTREQ on overflow
108         // [6] ovfl_intr_en = 0
109         // perhaps set to 1?
110         // [5] cntr_rst = 0
111         // No register paring
112         // [4:1] cntcfg = 0
113         // Enable PMU features
114         // [0] pmu_en = 1
115         //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0x1, REGION_DEBUG*REGION_SIZE + PMCR);
116         writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR);
117
118         // Assume no other pmu_event_sel registers are set
119
120         // cycle counter does not need to be enabled
121         for (i = 0; i < CCNT; ++i) {
122                 int pmu_event_id;
123                 int node_type;
124                 int region;
125                 u32 pmu_event_sel;
126                 u32 oly_id_whole;
127                 u32 oly_id;
128                 u32 node_id;
129
130                 if (!gator_events_ccn504_enabled[i]) {
131                         continue;
132                 }
133
134                 pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]);
135                 node_type = get_node_type(gator_events_ccn504_event[i]);
136                 region = get_region(gator_events_ccn504_event[i]);
137                 //printk(KERN_ERR "%s(%s:%i) pmu_event_id: %x node_type: %x region: %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_id, node_type, region);
138
139                 // Verify the node_type
140                 oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID);
141                 oly_id = oly_id_whole & 0x1F;
142                 node_id = (oly_id_whole >> 8) & 0x7F;
143                 if ((oly_id != node_type) ||
144                                 ((node_type == 0x16) && ((oly_id == 0x14) || (oly_id == 0x15) || (oly_id == 0x16) || (oly_id == 0x18) || (oly_id == 0x19) || (oly_id == 0x1A)))) {
145                         printk(KERN_ERR "%s(%s:%i) oly_id is %x expected %x\n", __FUNCTION__, __FILE__, __LINE__, oly_id, node_type);
146                         return -1;
147                 }
148
149                 // Set the control register
150                 pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
151                 switch (node_type) {
152                 case 0x08: // XP
153                         pmu_event_sel |= pmu_event_id << (7*i);
154                         gator_events_ccn504_set_dt_config(node_id, i, 0x4);
155                         break;
156                 case 0x04: // HN-F
157                 case 0x16: // RN-I
158                 case 0x10: // SBAS
159                         pmu_event_sel |= pmu_event_id << (4*i);
160                         gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC);
161                         break;
162                 }
163                 //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_sel, region*REGION_SIZE + PMU_EVENT_SEL);
164                 writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
165         }
166
167         return 0;
168 }
169
170 static void gator_events_ccn504_stop(void)
171 {
172         int i;
173
174         // cycle counter does not need to be disabled
175         for (i = 0; i < CCNT; ++i) {
176                 int node_type;
177                 int region;
178
179                 node_type = get_node_type(gator_events_ccn504_event[i]);
180                 region = get_region(gator_events_ccn504_event[i]);
181
182                 //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, region*REGION_SIZE + PMU_EVENT_SEL);
183                 writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
184         }
185
186         // Clear dt_config
187         for (i = 0; i < 11; ++i) {
188                 //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
189                 writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
190         }
191 }
192
193 static int gator_events_ccn504_read(int **buffer)
194 {
195         int i;
196         int len = 0;
197
198         if (!on_primary_core()) {
199                 return 0;
200         }
201
202         // Verify the pmsr register is zero
203         //i = 0;
204         while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0) {
205                 //++i;
206         }
207         //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i);
208
209         // Request a PMU snapshot
210         writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ);
211
212         // Wait for the snapshot
213         //i = 0;
214         while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0) {
215                 //++i;
216         }
217         //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i);
218
219         // Read the shadow registers
220         for (i = 0; i < CNTMAX; ++i) {
221                 if (!gator_events_ccn504_enabled[i]) {
222                         continue;
223                 }
224
225                 gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i];
226                 gator_events_ccn504_buffer[len++] = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i));
227
228                 // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does?
229         }
230
231         // Clear the PMU snapshot status
232         writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR);
233
234         return len;
235 }
236
237 static void __maybe_unused gator_events_ccn504_enumerate(int pos, int size)
238 {
239         int i;
240         u32 oly_id;
241
242         for (i = pos; i < pos + size; ++i) {
243                 oly_id = readl(gator_events_ccn504_base + i*REGION_SIZE + OLY_ID);
244                 printk(KERN_ERR "%s(%s:%i) %i %08x\n", __FUNCTION__, __FILE__, __LINE__, i, oly_id);
245         }
246 }
247
248 static struct gator_interface gator_events_ccn504_interface = {
249         .shutdown = gator_events_ccn504_create_shutdown,
250         .create_files = gator_events_ccn504_create_files,
251         .start = gator_events_ccn504_start,
252         .stop = gator_events_ccn504_stop,
253         .read = gator_events_ccn504_read,
254 };
255
256 int gator_events_ccn504_init(void)
257 {
258         int i;
259
260         if (ccn504_addr == 0) {
261                 return -1;
262         }
263
264         gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE);
265         if (gator_events_ccn504_base == NULL) {
266                 printk(KERN_ERR "%s(%s:%i) ioremap returned NULL\n", __FUNCTION__, __FILE__, __LINE__);
267                 return -1;
268         }
269         //printk(KERN_ERR "%s(%s:%i)\n", __FUNCTION__, __FILE__, __LINE__);
270
271         // Test - can memory be read
272         {
273                 //gator_events_ccn504_enumerate(0, NUM_REGIONS);
274
275 #if 0
276                 // DT
277                 gator_events_ccn504_enumerate(1, 1);
278                 // HN-F
279                 gator_events_ccn504_enumerate(32, 8);
280                 // XP
281                 gator_events_ccn504_enumerate(64, 11);
282                 // RN-I
283                 gator_events_ccn504_enumerate(128, 1);
284                 gator_events_ccn504_enumerate(130, 1);
285                 gator_events_ccn504_enumerate(134, 1);
286                 gator_events_ccn504_enumerate(140, 1);
287                 gator_events_ccn504_enumerate(144, 1);
288                 gator_events_ccn504_enumerate(148, 1);
289                 // SBAS
290                 gator_events_ccn504_enumerate(129, 1);
291                 gator_events_ccn504_enumerate(137, 1);
292                 gator_events_ccn504_enumerate(139, 1);
293                 gator_events_ccn504_enumerate(147, 1);
294 #endif
295         }
296
297         for (i = 0; i < CNTMAX; ++i) {
298                 gator_events_ccn504_enabled[i] = 0;
299                 gator_events_ccn504_event[i] = 0;
300                 gator_events_ccn504_key[i] = gator_events_get_key();
301         }
302
303         return gator_events_install(&gator_events_ccn504_interface);
304 }
305
306 gator_events_init(gator_events_ccn504_init);