1 /**
2 * l2c310 (L2 Cache Controller) event counters for gator
3 *
4 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
11 #include <linux/init.h>
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <asm/hardware/cache-l2x0.h>
16 #include "gator.h"
18 #define L2C310_COUNTERS_NUM 2
20 static struct {
21 unsigned long enabled;
22 unsigned long event;
23 unsigned long key;
24 } l2c310_counters[L2C310_COUNTERS_NUM];
26 static int l2c310_buffer[L2C310_COUNTERS_NUM * 2];
28 static void __iomem *l2c310_base;
30 static void gator_events_l2c310_reset_counters(void)
31 {
32 u32 val = readl(l2c310_base + L2X0_EVENT_CNT_CTRL);
34 val |= ((1 << L2C310_COUNTERS_NUM) - 1) << 1;
36 writel(val, l2c310_base + L2X0_EVENT_CNT_CTRL);
37 }
39 static int gator_events_l2c310_create_files(struct super_block *sb,
40 struct dentry *root)
41 {
42 int i;
44 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
45 char buf[16];
46 struct dentry *dir;
48 snprintf(buf, sizeof(buf), "L2C-310_cnt%d", i);
49 dir = gatorfs_mkdir(sb, root, buf);
50 if (WARN_ON(!dir))
51 return -1;
52 gatorfs_create_ulong(sb, dir, "enabled",
53 &l2c310_counters[i].enabled);
54 gatorfs_create_ulong(sb, dir, "event",
55 &l2c310_counters[i].event);
56 gatorfs_create_ro_ulong(sb, dir, "key",
57 &l2c310_counters[i].key);
58 }
60 return 0;
61 }
63 static int gator_events_l2c310_start(void)
64 {
65 static const unsigned long l2x0_event_cntx_cfg[L2C310_COUNTERS_NUM] = {
66 L2X0_EVENT_CNT0_CFG,
67 L2X0_EVENT_CNT1_CFG,
68 };
69 int i;
71 /* Counter event sources */
72 for (i = 0; i < L2C310_COUNTERS_NUM; i++)
73 writel((l2c310_counters[i].event & 0xf) << 2,
74 l2c310_base + l2x0_event_cntx_cfg[i]);
76 gator_events_l2c310_reset_counters();
78 /* Event counter enable */
79 writel(1, l2c310_base + L2X0_EVENT_CNT_CTRL);
81 return 0;
82 }
84 static void gator_events_l2c310_stop(void)
85 {
86 /* Event counter disable */
87 writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
88 }
90 static int gator_events_l2c310_read(int **buffer)
91 {
92 static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
93 L2X0_EVENT_CNT0_VAL,
94 L2X0_EVENT_CNT1_VAL,
95 };
96 int i;
97 int len = 0;
99 if (!on_primary_core())
100 return 0;
102 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
103 if (l2c310_counters[i].enabled) {
104 l2c310_buffer[len++] = l2c310_counters[i].key;
105 l2c310_buffer[len++] = readl(l2c310_base +
106 l2x0_event_cntx_val[i]);
107 }
108 }
110 /* l2c310 counters are saturating, not wrapping in case of overflow */
111 gator_events_l2c310_reset_counters();
113 if (buffer)
114 *buffer = l2c310_buffer;
116 return len;
117 }
119 static struct gator_interface gator_events_l2c310_interface = {
120 .create_files = gator_events_l2c310_create_files,
121 .start = gator_events_l2c310_start,
122 .stop = gator_events_l2c310_stop,
123 .read = gator_events_l2c310_read,
124 };
126 #define L2C310_ADDR_PROBE (~0)
128 MODULE_PARM_DESC(l2c310_addr, "L2C310 physical base address (0 to disable)");
129 static unsigned long l2c310_addr = L2C310_ADDR_PROBE;
130 module_param(l2c310_addr, ulong, 0444);
132 static void __iomem *gator_events_l2c310_probe(void)
133 {
134 phys_addr_t variants[] = {
135 #if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310)
136 0x10502000,
137 #endif
138 #if defined(CONFIG_ARCH_OMAP4)
139 0x48242000,
140 #endif
141 #if defined(CONFIG_ARCH_TEGRA)
142 0x50043000,
143 #endif
144 #if defined(CONFIG_ARCH_U8500)
145 0xa0412000,
146 #endif
147 #if defined(CONFIG_ARCH_VEXPRESS)
148 0x1e00a000, // A9x4 core tile (HBI-0191)
149 0x2c0f0000, // New memory map tiles
150 #endif
151 };
152 int i;
154 for (i = 0; i < ARRAY_SIZE(variants); i++) {
155 void __iomem *base = ioremap(variants[i], SZ_4K);
157 if (base) {
158 u32 cache_id = readl(base + L2X0_CACHE_ID);
160 if ((cache_id & 0xff0003c0) == 0x410000c0)
161 return base;
163 iounmap(base);
164 }
165 }
167 return NULL;
168 }
170 int gator_events_l2c310_init(void)
171 {
172 int i;
174 if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9)
175 return -1;
177 if (l2c310_addr == L2C310_ADDR_PROBE)
178 l2c310_base = gator_events_l2c310_probe();
179 else if (l2c310_addr)
180 l2c310_base = ioremap(l2c310_addr, SZ_4K);
182 if (!l2c310_base)
183 return -1;
185 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
186 l2c310_counters[i].enabled = 0;
187 l2c310_counters[i].key = gator_events_get_key();
188 }
190 return gator_events_install(&gator_events_l2c310_interface);
191 }
193 gator_events_init(gator_events_l2c310_init);