xref: /OK3568_Linux_fs/kernel/drivers/hwtracing/coresight/mali/sources/etm/coresight_mali_source_etm_core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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