xref: /OK3568_Linux_fs/kernel/drivers/hwtracing/coresight/mali/sources/itm/coresight_mali_source_itm_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 "sources/coresight_mali_sources.h"
25 
26 /* Linux Coresight framework does not support multiple sources enabled
27  * at the same time.
28  *
29  * To avoid Kernel instability, all Mali Coresight sources use the
30  * same trace ID value as the mandatory ETM one.
31  */
32 #define CS_MALI_TRACE_ID 0x00000010
33 
34 #define CS_SCS_BASE_ADDR 0xE000E000
35 #define SCS_DEMCR 0xDFC
36 #define CS_ITM_BASE_ADDR 0xE0000000
37 #define ITM_TCR 0xE80
38 #define ITM_TCR_BUSY_BIT (0x1 << 22)
39 #define CS_DWT_BASE_ADDR 0xE0001000
40 #define DWT_CTRL 0x000
41 #define DWT_CYCCNT 0x004
42 
43 #if KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE
44 static char *type_name = "mali-source-itm";
45 #endif
46 
47 #define NELEMS(s) (sizeof(s) / sizeof((s)[0]))
48 
49 enum cs_itm_dwt_dynamic_regs { CS_DWT_CTRL, CS_ITM_TCR, CS_ITM_DWT_NR_DYN_REGS };
50 
51 struct cs_itm_state {
52 	int enabled;
53 	u32 regs[CS_ITM_DWT_NR_DYN_REGS];
54 };
55 
56 static struct cs_itm_state itm_state = { 0 };
57 
58 static struct kbase_debug_coresight_csf_address_range dwt_itm_range[] = {
59 	{ CS_SCS_BASE_ADDR, CS_SCS_BASE_ADDR + CORESIGHT_DEVTYPE },
60 	{ CS_ITM_BASE_ADDR, CS_ITM_BASE_ADDR + CORESIGHT_DEVTYPE },
61 	{ CS_DWT_BASE_ADDR, CS_DWT_BASE_ADDR + CORESIGHT_DEVTYPE }
62 };
63 
64 static struct kbase_debug_coresight_csf_op dwt_itm_enable_ops[] = {
65 	// enable ITM/DWT functionality via DEMCR register
66 	WRITE_IMM_OP(CS_SCS_BASE_ADDR + SCS_DEMCR, 0x01000000),
67 	// Unlock DWT configuration
68 	WRITE_IMM_OP(CS_DWT_BASE_ADDR + CORESIGHT_LAR, CS_MALI_UNLOCK_COMPONENT),
69 	// prep DWT counter to immediately send sync packet ((1 << 24) - 1)
70 	WRITE_IMM_OP(CS_DWT_BASE_ADDR + DWT_CYCCNT, 0x00ffffff),
71 	// Write initial value of post count counter
72 	WRITE_IMM_OP(CS_DWT_BASE_ADDR + DWT_CTRL, 0x00000020),
73 	// Set DWT configuration:
74 	WRITE_PTR_OP(CS_DWT_BASE_ADDR + DWT_CTRL, &itm_state.regs[CS_DWT_CTRL]),
75 	// Lock DWT Configuration
76 	WRITE_IMM_OP(CS_DWT_BASE_ADDR + CORESIGHT_LAR, 0x00000000),
77 	// Unlock DWT configuration
78 	WRITE_IMM_OP(CS_ITM_BASE_ADDR + CORESIGHT_LAR, CS_MALI_UNLOCK_COMPONENT),
79 	// Set ITM configuration:
80 	WRITE_PTR_OP(CS_ITM_BASE_ADDR + ITM_TCR, &itm_state.regs[CS_ITM_TCR]),
81 	// Lock DWT configuration
82 	WRITE_IMM_OP(CS_ITM_BASE_ADDR + CORESIGHT_LAR, 0x00000000),
83 	// Set enabled bit on at the end of sequence
84 	BIT_OR_OP(&itm_state.enabled, 0x1),
85 };
86 
87 static struct kbase_debug_coresight_csf_op dwt_itm_disable_ops[] = {
88 	// Disable ITM/DWT functionality via DEMCR register
89 	WRITE_IMM_OP(CS_SCS_BASE_ADDR + SCS_DEMCR, 0x00000000),
90 	// Unlock ITM configuration
91 	WRITE_IMM_OP(CS_ITM_BASE_ADDR + CORESIGHT_LAR, CS_MALI_UNLOCK_COMPONENT),
92 	// Check ITM is disabled
93 	POLL_OP(CS_ITM_BASE_ADDR + ITM_TCR, ITM_TCR_BUSY_BIT, 0x0),
94 	// Lock
95 	WRITE_IMM_OP(CS_ITM_BASE_ADDR + CORESIGHT_LAR, 0x00000000),
96 	// Set enabled bit off at the end of sequence
97 	BIT_AND_OP(&itm_state.enabled, 0x0),
98 };
99 
set_default_regs(void)100 static void set_default_regs(void)
101 {
102 	// DWT configuration:
103 	// [0] = 1, enable cycle counter
104 	// [4:1] = 4, set PC sample rate pf 256 cycles
105 	// [8:5] = 1, set initial post count value
106 	// [9] = 1, select position of post count tap on the cycle counter
107 	// [10:11] = 1, enable sync packets
108 	// [12] = 1, enable periodic PC sample packets
109 	itm_state.regs[CS_DWT_CTRL] = 0x00001629;
110 	// ITM configuration:
111 	// [0] = 1, Enable ITM
112 	// [1] = 1, Enable Time stamp generation
113 	// [2] = 1, Enable sync packet transmission
114 	// [3] = 1, Enable HW event forwarding
115 	// [11:10] = 1, Generate TS request approx every 128 cycles
116 	// [22:16] = 1, Trace bus ID
117 	itm_state.regs[CS_ITM_TCR] = 0x0001040F;
118 }
119 
verify_store_reg(struct device * dev,const char * buf,size_t count,int reg)120 static int verify_store_reg(struct device *dev, const char *buf, size_t count, int reg)
121 {
122 	struct coresight_mali_source_drvdata *drvdata = dev_get_drvdata(dev->parent);
123 	u32 val;
124 	int err;
125 
126 	if (buf == NULL)
127 		return -EINVAL;
128 
129 	if (itm_state.enabled == 1) {
130 		dev_err(drvdata->base.dev,
131 			"Config needs to be disabled before modifying registers\n");
132 		return -EINVAL;
133 	}
134 
135 	err = kstrtou32(buf, 0, &val);
136 	if (err) {
137 		dev_err(drvdata->base.dev, "Invalid input value\n");
138 		return -EINVAL;
139 	}
140 
141 	itm_state.regs[reg] = val;
142 	return count;
143 }
144 
is_enabled_show(struct device * dev,struct device_attribute * attr,char * const buf)145 static ssize_t is_enabled_show(struct device *dev, struct device_attribute *attr, char *const buf)
146 {
147 	return sprintf(buf, "%d\n", itm_state.enabled);
148 }
149 static DEVICE_ATTR_RO(is_enabled);
150 
151 #define CS_ITM_DWT_REG_ATTR_RW(_a, _b)                                                             \
152 	static ssize_t _a##_show(struct device *dev, struct device_attribute *attr,                \
153 				 char *const buf)                                                  \
154 	{                                                                                          \
155 		return sprintf(buf, "%#x\n", itm_state.regs[CS_##_b]);                             \
156 	}                                                                                          \
157 	static ssize_t _a##_store(struct device *dev, struct device_attribute *attr,               \
158 				  const char *buf, size_t count)                                   \
159 	{                                                                                          \
160 		return verify_store_reg(dev, buf, count, CS_##_b);                                 \
161 	}                                                                                          \
162 	static DEVICE_ATTR_RW(_a)
163 
164 CS_ITM_DWT_REG_ATTR_RW(dwt_ctrl, DWT_CTRL);
165 CS_ITM_DWT_REG_ATTR_RW(itm_tcr, ITM_TCR);
166 
167 static struct attribute *coresight_mali_source_attrs[] = {
168 	&dev_attr_is_enabled.attr,
169 	&dev_attr_dwt_ctrl.attr,
170 	&dev_attr_itm_tcr.attr,
171 	NULL,
172 };
173 
174 static const struct attribute_group coresight_mali_source_group = {
175 	.attrs = coresight_mali_source_attrs,
176 	.name = "mgmt"
177 };
178 
179 static const struct attribute_group *coresight_mali_source_groups[] = {
180 	&coresight_mali_source_group,
181 	NULL,
182 };
183 
coresight_mali_source_groups_get(void)184 const struct attribute_group **coresight_mali_source_groups_get(void)
185 {
186 	return coresight_mali_source_groups;
187 }
188 
coresight_mali_sources_init_drvdata(struct coresight_mali_source_drvdata * drvdata)189 int coresight_mali_sources_init_drvdata(struct coresight_mali_source_drvdata *drvdata)
190 {
191 	if (drvdata == NULL)
192 		return -EINVAL;
193 
194 #if KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE
195 	drvdata->type_name = type_name;
196 #endif
197 
198 	drvdata->base.kbase_client = kbase_debug_coresight_csf_register(
199 		drvdata->base.gpu_dev, dwt_itm_range, NELEMS(dwt_itm_range));
200 	if (drvdata->base.kbase_client == NULL) {
201 		dev_err(drvdata->base.dev, "Registration with full range failed unexpectedly\n");
202 		return -EINVAL;
203 	}
204 
205 	drvdata->trcid = CS_MALI_TRACE_ID;
206 
207 	drvdata->base.enable_seq.ops = dwt_itm_enable_ops;
208 	drvdata->base.enable_seq.nr_ops = NELEMS(dwt_itm_enable_ops);
209 
210 	drvdata->base.disable_seq.ops = dwt_itm_disable_ops;
211 	drvdata->base.disable_seq.nr_ops = NELEMS(dwt_itm_disable_ops);
212 
213 	set_default_regs();
214 
215 	drvdata->base.config = kbase_debug_coresight_csf_config_create(
216 		drvdata->base.kbase_client, &drvdata->base.enable_seq, &drvdata->base.disable_seq);
217 	if (!drvdata->base.config) {
218 		dev_err(drvdata->base.dev, "config create failed unexpectedly\n");
219 		kbase_debug_coresight_csf_unregister(drvdata->base.kbase_client);
220 		return -EINVAL;
221 	}
222 
223 	return 0;
224 }
225 
coresight_mali_sources_deinit_drvdata(struct coresight_mali_source_drvdata * drvdata)226 void coresight_mali_sources_deinit_drvdata(struct coresight_mali_source_drvdata *drvdata)
227 {
228 	if (drvdata->base.config != NULL)
229 		kbase_debug_coresight_csf_config_free(drvdata->base.config);
230 
231 	if (drvdata->base.kbase_client != NULL)
232 		kbase_debug_coresight_csf_unregister(drvdata->base.kbase_client);
233 }
234 
235 static const struct of_device_id mali_source_ids[] = { { .compatible =
236 								 "arm,coresight-mali-source-itm" },
237 						       {} };
238 
239 static struct platform_driver mali_sources_platform_driver = {
240 	.probe      = coresight_mali_sources_probe,
241 	.remove     = coresight_mali_sources_remove,
242 	.driver = {
243 		.name = "coresight-mali-source-itm",
244 		.owner = THIS_MODULE,
245 		.of_match_table = mali_source_ids,
246 		.suppress_bind_attrs    = true,
247 	},
248 };
249 
mali_sources_init(void)250 static int __init mali_sources_init(void)
251 {
252 	return platform_driver_register(&mali_sources_platform_driver);
253 }
254 
mali_sources_exit(void)255 static void __exit mali_sources_exit(void)
256 {
257 	platform_driver_unregister(&mali_sources_platform_driver);
258 }
259 
260 module_init(mali_sources_init);
261 module_exit(mali_sources_exit);
262 
263 MODULE_AUTHOR("ARM Ltd.");
264 MODULE_DESCRIPTION("Arm Coresight Mali source ITM");
265 MODULE_LICENSE("GPL");
266