1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2022 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include <linux/of_platform.h>
23 #include <coresight-priv.h>
24 #include <coresight-etm4x.h>
25 #include "sources/coresight_mali_sources.h"
26
27 #define CS_ETM_BASE_ADDR 0xE0041000
28 #define CS_MALI_TRACE_ID 0x00000010
29
30 #ifndef TRCVICTLR_SSSTATUS
31 #define TRCVICTLR_SSSTATUS BIT(9)
32 #endif
33
34 #if KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE
35 static char *type_name = "mali-source-etm";
36 #endif
37
38 #define NELEMS(s) (sizeof(s) / sizeof((s)[0]))
39
40 enum cs_etm_dynamic_regs {
41 CS_ETM_TRCCONFIGR,
42 CS_ETM_TRCTRACEIDR,
43 CS_ETM_TRCVDARCCTLR,
44 CS_ETM_TRCSTALLCTLR,
45 CS_ETM_TRCVIIECTLR,
46 CS_ETM_NR_DYN_REGS
47 };
48
49 struct cs_etm_state {
50 int enabled;
51 u32 regs[CS_ETM_NR_DYN_REGS];
52 };
53
54 static struct cs_etm_state etm_state = { 0 };
55
56 static struct kbase_debug_coresight_csf_address_range etm_range[] = {
57 { CS_ETM_BASE_ADDR, CS_ETM_BASE_ADDR + CORESIGHT_DEVTYPE },
58 };
59
60 struct kbase_debug_coresight_csf_op etm_enable_ops[] = {
61 // Unlock ETM configuration
62 WRITE_IMM_OP(CS_ETM_BASE_ADDR + CORESIGHT_LAR, CS_MALI_UNLOCK_COMPONENT),
63 // Power up request
64 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCPDCR, TRCPDCR_PU),
65 // Disable Tracing
66 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCPRGCTLR, 0x00000000),
67 // Check the tracing unit is inactive before programming
68 POLL_OP(CS_ETM_BASE_ADDR + TRCSTATR, BIT(TRCSTATR_IDLE_BIT), BIT(TRCSTATR_IDLE_BIT)),
69 // Set trace configuration to enable global timestamping, and data value tracing
70 WRITE_PTR_OP(CS_ETM_BASE_ADDR + TRCCONFIGR, &etm_state.regs[CS_ETM_TRCCONFIGR]),
71 // Set event control 0 register
72 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCEVENTCTL0R, 0x00000000),
73 // Set event control 1 register
74 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCEVENTCTL1R, 0x00000000),
75 // Set trace ID
76 WRITE_PTR_OP(CS_ETM_BASE_ADDR + TRCTRACEIDR, &etm_state.regs[CS_ETM_TRCTRACEIDR]),
77 // Configure stall control register
78 WRITE_PTR_OP(CS_ETM_BASE_ADDR + TRCSTALLCTLR, &etm_state.regs[CS_ETM_TRCSTALLCTLR]),
79 // Synchronization period register - sync every 2^11 bytes
80 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCSYNCPR, 0x0000000C),
81 // Set global timestamp control register to select resource 0
82 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCTSCTLR, 0x00000000),
83 // Set viewData include/exclude address range comparators to 0
84 WRITE_PTR_OP(CS_ETM_BASE_ADDR + TRCVDARCCTLR, &etm_state.regs[CS_ETM_TRCVDARCCTLR]),
85 // Set viewData main control to select resource 0
86 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCVDCTLR, 0x00000001),
87 //Set viewData comparators to 0
88 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCVDSACCTLR, 0x00000000),
89 // Set stop/start logic to started state, select resource 1
90 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCVICTLR, TRCVICTLR_SSSTATUS | BIT(0)),
91 // Set viewInst start and stop control
92 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCVISSCTLR, 0x00000000),
93 // Set viewInst include and exclude control to math all addresses in range
94 WRITE_PTR_OP(CS_ETM_BASE_ADDR + TRCVIIECTLR, &etm_state.regs[CS_ETM_TRCVIIECTLR]),
95 // enable trace
96 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCPRGCTLR, 0x1),
97 // Wait that the unit is busy
98 POLL_OP(CS_ETM_BASE_ADDR + TRCSTATR, BIT(TRCSTATR_IDLE_BIT), 0),
99 // Lock the ETM configuration
100 WRITE_IMM_OP(CS_ETM_BASE_ADDR + CORESIGHT_LAR, 0x00000000),
101 // Set enabled bit on at the end of sequence
102 BIT_OR_OP(&etm_state.enabled, 0x1),
103 };
104
105 struct kbase_debug_coresight_csf_op etm_disable_ops[] = {
106 // Unlock ETM configuration
107 WRITE_IMM_OP(CS_ETM_BASE_ADDR + CORESIGHT_LAR, CS_MALI_UNLOCK_COMPONENT),
108 // Disable trace unit
109 WRITE_IMM_OP(CS_ETM_BASE_ADDR + TRCPRGCTLR, 0x00000000),
110 // Poll until idle
111 POLL_OP(CS_ETM_BASE_ADDR + TRCSTATR, BIT(TRCSTATR_IDLE_BIT), BIT(TRCSTATR_IDLE_BIT)),
112 // Lock ETM configuration
113 WRITE_IMM_OP(CS_ETM_BASE_ADDR + CORESIGHT_LAR, 0x00000000),
114 // Set enabled bit off at the end of sequence
115 BIT_AND_OP(&etm_state.enabled, 0x0),
116 };
117
set_default_regs(void)118 static void set_default_regs(void)
119 {
120 // Turn on instruction tracing
121 etm_state.regs[CS_ETM_TRCCONFIGR] = 0x00000800;
122 // Set ID
123 etm_state.regs[CS_ETM_TRCTRACEIDR] = CS_MALI_TRACE_ID;
124 // Set data comparators to none
125 etm_state.regs[CS_ETM_TRCVDARCCTLR] = 0x00000000;
126 // Set instructions address filter to none
127 etm_state.regs[CS_ETM_TRCVIIECTLR] = 0x00000000;
128 // Set stall configuration to a basic setting
129 etm_state.regs[CS_ETM_TRCSTALLCTLR] = 0x00000000;
130 }
131
132 static const struct of_device_id mali_source_ids[] = { { .compatible =
133 "arm,coresight-mali-source-etm" },
134 {} };
135
coresight_mali_sources_init_drvdata(struct coresight_mali_source_drvdata * drvdata)136 int coresight_mali_sources_init_drvdata(struct coresight_mali_source_drvdata *drvdata)
137 {
138 int ret = 0;
139
140 if (drvdata == NULL)
141 return -EINVAL;
142
143 #if KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE
144 drvdata->type_name = type_name;
145 #endif
146 etm_state.enabled = 0x0;
147
148 drvdata->base.kbase_client = kbase_debug_coresight_csf_register(
149 drvdata->base.gpu_dev, etm_range, NELEMS(etm_range));
150 if (drvdata->base.kbase_client == NULL) {
151 dev_err(drvdata->base.dev, "Registration with full range failed unexpectedly\n");
152 return -EINVAL;
153 }
154
155 set_default_regs();
156 drvdata->trcid = CS_MALI_TRACE_ID;
157
158 drvdata->base.enable_seq.ops = etm_enable_ops;
159 drvdata->base.enable_seq.nr_ops = NELEMS(etm_enable_ops);
160
161 drvdata->base.disable_seq.ops = etm_disable_ops;
162 drvdata->base.disable_seq.nr_ops = NELEMS(etm_disable_ops);
163
164 drvdata->base.config = kbase_debug_coresight_csf_config_create(
165 drvdata->base.kbase_client, &drvdata->base.enable_seq, &drvdata->base.disable_seq);
166 if (!drvdata->base.config) {
167 dev_err(drvdata->base.dev, "Config create failed unexpectedly\n");
168 kbase_debug_coresight_csf_unregister(drvdata->base.kbase_client);
169 return -EINVAL;
170 }
171
172 return ret;
173 }
174
coresight_mali_sources_deinit_drvdata(struct coresight_mali_source_drvdata * drvdata)175 void coresight_mali_sources_deinit_drvdata(struct coresight_mali_source_drvdata *drvdata)
176 {
177 if (drvdata->base.config != NULL)
178 kbase_debug_coresight_csf_config_free(drvdata->base.config);
179
180 if (drvdata->base.kbase_client != NULL)
181 kbase_debug_coresight_csf_unregister(drvdata->base.kbase_client);
182 }
183
verify_store_reg(struct device * dev,const char * buf,size_t count,int reg)184 static int verify_store_reg(struct device *dev, const char *buf, size_t count, int reg)
185 {
186 struct coresight_mali_source_drvdata *drvdata = dev_get_drvdata(dev->parent);
187 u32 val;
188 int err;
189
190 if (buf == NULL)
191 return -EINVAL;
192
193 if (etm_state.enabled == 1) {
194 dev_err(drvdata->base.dev,
195 "Config needs to be disabled before modifying registers\n");
196 return -EINVAL;
197 }
198
199 err = kstrtou32(buf, 0, &val);
200 if (err) {
201 dev_err(drvdata->base.dev, "Invalid input value\n");
202 return -EINVAL;
203 }
204
205 etm_state.regs[reg] = val;
206 return count;
207 }
208
209 #define CS_ETM_REG_ATTR_RW(_a, _b) \
210 static ssize_t _a##_show(struct device *dev, struct device_attribute *attr, \
211 char *const buf) \
212 { \
213 return sprintf(buf, "%#x\n", etm_state.regs[CS_ETM_##_b]); \
214 } \
215 static ssize_t _a##_store(struct device *dev, struct device_attribute *attr, \
216 const char *buf, size_t count) \
217 { \
218 return verify_store_reg(dev, buf, count, CS_ETM_##_b); \
219 } \
220 static DEVICE_ATTR_RW(_a)
221
222 CS_ETM_REG_ATTR_RW(trcconfigr, TRCCONFIGR);
223 CS_ETM_REG_ATTR_RW(trctraceidr, TRCTRACEIDR);
224 CS_ETM_REG_ATTR_RW(trcvdarcctlr, TRCVDARCCTLR);
225 CS_ETM_REG_ATTR_RW(trcviiectlr, TRCVIIECTLR);
226 CS_ETM_REG_ATTR_RW(trcstallctlr, TRCSTALLCTLR);
227
is_enabled_show(struct device * dev,struct device_attribute * attr,char * const buf)228 static ssize_t is_enabled_show(struct device *dev, struct device_attribute *attr, char *const buf)
229 {
230 return sprintf(buf, "%d\n", etm_state.enabled);
231 }
232 static DEVICE_ATTR_RO(is_enabled);
233
234 static struct attribute *coresight_etm_attrs[] = {
235 &dev_attr_is_enabled.attr,
236 &dev_attr_trcconfigr.attr,
237 &dev_attr_trctraceidr.attr,
238 &dev_attr_trcvdarcctlr.attr,
239 &dev_attr_trcviiectlr.attr,
240 &dev_attr_trcstallctlr.attr,
241 NULL,
242 };
243 static struct attribute_group coresight_etm_group = { .attrs = coresight_etm_attrs,
244 .name = "mgmt" };
245 static const struct attribute_group *coresight_etm_groups[] = {
246 &coresight_etm_group,
247 NULL,
248 };
coresight_mali_source_groups_get(void)249 const struct attribute_group **coresight_mali_source_groups_get(void)
250 {
251 return coresight_etm_groups;
252 }
253
254 static struct platform_driver mali_sources_platform_driver = {
255 .probe = coresight_mali_sources_probe,
256 .remove = coresight_mali_sources_remove,
257 .driver = {
258 .name = "coresight-mali-source-etm",
259 .owner = THIS_MODULE,
260 .of_match_table = mali_source_ids,
261 .suppress_bind_attrs = true,
262 },
263 };
264
mali_sources_init(void)265 static int __init mali_sources_init(void)
266 {
267 return platform_driver_register(&mali_sources_platform_driver);
268 }
269
mali_sources_exit(void)270 static void __exit mali_sources_exit(void)
271 {
272 platform_driver_unregister(&mali_sources_platform_driver);
273 }
274
275 module_init(mali_sources_init);
276 module_exit(mali_sources_exit);
277
278 MODULE_AUTHOR("ARM Ltd.");
279 MODULE_DESCRIPTION("Arm Coresight Mali source ETM");
280 MODULE_LICENSE("GPL");
281