2 * Copyright (C) ARM Limited 2013. All rights reserved.
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.
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 ******************************************************************************/
16 #include <linux/module.h>
20 #define PERIPHBASE 0x2E000000
22 #define NUM_REGIONS 256
23 #define REGION_SIZE (64*1024)
24 #define REGION_DEBUG 1
28 #define PMEVCNTSR0 0x0150
29 #define PMCCNTRSR 0x0190
32 #define PMSR_REQ 0x01B8
33 #define PMSR_CLR 0x01C0
36 #define DT_CONFIG 0x0300
39 #define PMU_EVENT_SEL 0x0600
43 #define CNTMAX (4 + 1)
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)
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);
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];
59 static void gator_events_ccn504_create_shutdown(void)
61 if (gator_events_ccn504_base != NULL) {
62 iounmap(gator_events_ccn504_base);
66 static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root)
72 for (i = 0; i < CNTMAX; ++i) {
74 snprintf(buf, sizeof(buf), "CCN-504_ccnt");
76 snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i);
78 dir = gatorfs_mkdir(sb, root, buf);
83 gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]);
85 gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]);
87 gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]);
93 static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value)
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);
103 static int gator_events_ccn504_start(void)
107 // Disable INTREQ on overflow
108 // [6] ovfl_intr_en = 0
111 // No register paring
113 // Enable PMU features
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);
118 // Assume no other pmu_event_sel registers are set
120 // cycle counter does not need to be enabled
121 for (i = 0; i < CCNT; ++i) {
130 if (!gator_events_ccn504_enabled[i]) {
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);
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);
149 // Set the control register
150 pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
153 pmu_event_sel |= pmu_event_id << (7*i);
154 gator_events_ccn504_set_dt_config(node_id, i, 0x4);
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);
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);
170 static void gator_events_ccn504_stop(void)
174 // cycle counter does not need to be disabled
175 for (i = 0; i < CCNT; ++i) {
179 node_type = get_node_type(gator_events_ccn504_event[i]);
180 region = get_region(gator_events_ccn504_event[i]);
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);
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);
193 static int gator_events_ccn504_read(int **buffer)
198 if (!on_primary_core()) {
202 // Verify the pmsr register is zero
204 while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0) {
207 //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i);
209 // Request a PMU snapshot
210 writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ);
212 // Wait for the snapshot
214 while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0) {
217 //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i);
219 // Read the shadow registers
220 for (i = 0; i < CNTMAX; ++i) {
221 if (!gator_events_ccn504_enabled[i]) {
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));
228 // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does?
231 // Clear the PMU snapshot status
232 writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR);
237 static void __maybe_unused gator_events_ccn504_enumerate(int pos, int size)
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);
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,
256 int gator_events_ccn504_init(void)
260 if (ccn504_addr == 0) {
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__);
269 //printk(KERN_ERR "%s(%s:%i)\n", __FUNCTION__, __FILE__, __LINE__);
271 // Test - can memory be read
273 //gator_events_ccn504_enumerate(0, NUM_REGIONS);
277 gator_events_ccn504_enumerate(1, 1);
279 gator_events_ccn504_enumerate(32, 8);
281 gator_events_ccn504_enumerate(64, 11);
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);
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);
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();
303 return gator_events_install(&gator_events_ccn504_interface);
306 gator_events_init(gator_events_ccn504_init);