2 * l2c310 (L2 Cache Controller) event counters for gator
4 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
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.
11 #include <linux/init.h>
13 #include <linux/module.h>
14 #if defined(CONFIG_OF)
16 #include <linux/of_address.h>
18 #include <asm/hardware/cache-l2x0.h>
22 #define L2C310_COUNTERS_NUM 2
25 unsigned long enabled;
28 } l2c310_counters[L2C310_COUNTERS_NUM];
30 static int l2c310_buffer[L2C310_COUNTERS_NUM * 2];
32 static void __iomem *l2c310_base;
34 static void gator_events_l2c310_reset_counters(void)
36 u32 val = readl(l2c310_base + L2X0_EVENT_CNT_CTRL);
38 val |= ((1 << L2C310_COUNTERS_NUM) - 1) << 1;
40 writel(val, l2c310_base + L2X0_EVENT_CNT_CTRL);
43 static int gator_events_l2c310_create_files(struct super_block *sb,
48 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
52 snprintf(buf, sizeof(buf), "L2C-310_cnt%d", i);
53 dir = gatorfs_mkdir(sb, root, buf);
56 gatorfs_create_ulong(sb, dir, "enabled",
57 &l2c310_counters[i].enabled);
58 gatorfs_create_ulong(sb, dir, "event",
59 &l2c310_counters[i].event);
60 gatorfs_create_ro_ulong(sb, dir, "key",
61 &l2c310_counters[i].key);
67 static int gator_events_l2c310_start(void)
69 static const unsigned long l2x0_event_cntx_cfg[L2C310_COUNTERS_NUM] = {
75 /* Counter event sources */
76 for (i = 0; i < L2C310_COUNTERS_NUM; i++)
77 writel((l2c310_counters[i].event & 0xf) << 2,
78 l2c310_base + l2x0_event_cntx_cfg[i]);
80 gator_events_l2c310_reset_counters();
82 /* Event counter enable */
83 writel(1, l2c310_base + L2X0_EVENT_CNT_CTRL);
88 static void gator_events_l2c310_stop(void)
90 /* Event counter disable */
91 writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
94 static int gator_events_l2c310_read(int **buffer, bool sched_switch)
96 static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
103 if (!on_primary_core())
106 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
107 if (l2c310_counters[i].enabled) {
108 l2c310_buffer[len++] = l2c310_counters[i].key;
109 l2c310_buffer[len++] = readl(l2c310_base +
110 l2x0_event_cntx_val[i]);
114 /* l2c310 counters are saturating, not wrapping in case of overflow */
115 gator_events_l2c310_reset_counters();
118 *buffer = l2c310_buffer;
123 static struct gator_interface gator_events_l2c310_interface = {
124 .create_files = gator_events_l2c310_create_files,
125 .start = gator_events_l2c310_start,
126 .stop = gator_events_l2c310_stop,
127 .read = gator_events_l2c310_read,
130 #define L2C310_ADDR_PROBE (~0)
132 MODULE_PARM_DESC(l2c310_addr, "L2C310 physical base address (0 to disable)");
133 static unsigned long l2c310_addr = L2C310_ADDR_PROBE;
134 module_param(l2c310_addr, ulong, 0444);
136 static void __iomem *gator_events_l2c310_probe(void)
138 phys_addr_t variants[] = {
139 #if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310)
142 #if defined(CONFIG_ARCH_OMAP4)
145 #if defined(CONFIG_ARCH_TEGRA)
148 #if defined(CONFIG_ARCH_U8500)
151 #if defined(CONFIG_ARCH_VEXPRESS)
152 0x1e00a000, /* A9x4 core tile (HBI-0191) */
153 0x2c0f0000, /* New memory map tiles */
158 #if defined(CONFIG_OF)
159 struct device_node *node = of_find_all_nodes(NULL);
164 node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
165 base = of_iomap(node, 0);
172 for (i = 0; i < ARRAY_SIZE(variants); i++) {
173 base = ioremap(variants[i], SZ_4K);
175 u32 cache_id = readl(base + L2X0_CACHE_ID);
177 if ((cache_id & 0xff0003c0) == 0x410000c0)
187 int gator_events_l2c310_init(void)
191 if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9)
194 if (l2c310_addr == L2C310_ADDR_PROBE)
195 l2c310_base = gator_events_l2c310_probe();
196 else if (l2c310_addr)
197 l2c310_base = ioremap(l2c310_addr, SZ_4K);
202 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
203 l2c310_counters[i].enabled = 0;
204 l2c310_counters[i].key = gator_events_get_key();
207 return gator_events_install(&gator_events_l2c310_interface);