1 /*
2  * Copyright (c) 2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stddef.h>
8 #include <stdbool.h>
9 #include <zephyr/drivers/pinctrl.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/sys/sys_io.h>
12 #include <ironside/se/api.h>
13 #include <ironside_zephyr/se/uicr_periphconf.h>
14 
15 #undef ETR_MODE_MODE_CIRCULARBUF
16 
17 #include "coresight_arm.h"
18 
19 #define DT_DRV_COMPAT nordic_coresight_nrf
20 
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(cs_trace, CONFIG_DEBUG_CORESIGHT_NRF_LOG_LEVEL);
23 
24 #define CTI_CH_TPIU_FLUSH_REQ_OFFSET (1)
25 
26 #define TS_CLOCKRATE                                                                               \
27 	(DT_PROP(DT_NODELABEL(hsfll200), clock_frequency) /                                        \
28 	 CONFIG_DEBUG_CORESIGHT_NRF_TSGEN_CLK_DIV)
29 
30 #define ATBREPLICATOR_IDFILTER_FORWARD_STM                                                         \
31 	BIT(CONFIG_DEBUG_CORESIGHT_NRF_ATB_TRACE_ID_STM_GLOBAL >> 4)
32 #define ATBFUNNEL211_STM_ENS_MASK BIT(2)
33 
34 enum coresight_nrf_mode {
35 	CORESIGHT_NRF_MODE_UNCONFIGURED,
36 	CORESIGHT_NRF_MODE_STM_TPIU,
37 	CORESIGHT_NRF_MODE_STM_ETR,
38 };
39 
40 struct coresight_nrf_config {
41 	enum coresight_nrf_mode mode;
42 	const struct pinctrl_dev_config *pcfg;
43 };
44 
nrf_tsgen_init(void)45 static void nrf_tsgen_init(void)
46 {
47 	mem_addr_t tsgen = DT_REG_ADDR(DT_NODELABEL(tsgen));
48 
49 	coresight_unlock(tsgen);
50 
51 	sys_write32(TS_CLOCKRATE, tsgen + TSGEN_CNTFID0_OFFSET);
52 	sys_write32(TSGEN_CNTCR_EN_Msk, tsgen + TSGEN_CNTCR_OFFSET);
53 
54 	coresight_lock(tsgen);
55 
56 	LOG_INF("CoreSight Host TSGEN initialized with clockrate %u", TS_CLOCKRATE);
57 }
58 
nrf_cti_for_tpiu_init(void)59 static void nrf_cti_for_tpiu_init(void)
60 {
61 	mem_addr_t cti210 = DT_REG_ADDR(DT_NODELABEL(cti210));
62 
63 	coresight_unlock(cti210);
64 
65 	/* Connect CTI channel to TPIU formatter flushin */
66 	sys_write32(BIT(CTI_CH_TPIU_FLUSH_REQ_OFFSET), cti210 + CTI_CTIOUTEN0_OFFSET);
67 	sys_write32(BIT(CTI_CH_TPIU_FLUSH_REQ_OFFSET), cti210 + CTI_CTIGATE_OFFSET);
68 	sys_write32(CTI_CTICONTROL_GLBEN_Msk, cti210 + CTI_CTICONTROL_OFFSET);
69 
70 	coresight_lock(cti210);
71 
72 	LOG_INF("CoreSight Host CTI initialized");
73 }
74 
nrf_tpiu_init(void)75 static void nrf_tpiu_init(void)
76 {
77 	mem_addr_t tpiu = DT_REG_ADDR(DT_NODELABEL(tpiu));
78 
79 	coresight_unlock(tpiu);
80 
81 	sys_write32(BIT((CONFIG_DEBUG_CORESIGHT_NRF_TPIU_PORTSIZE - 1)), tpiu + TPIU_CSPSR_OFFSET);
82 
83 	/* Continuous formatting  */
84 	if (IS_ENABLED(CONFIG_DEBUG_CORESIGHT_NRF_TPIU_FFCR_TRIG)) {
85 		sys_write32((TPIU_FFCR_ENFCONT_Msk | TPIU_FFCR_FONFLIN_Msk | TPIU_FFCR_ENFTC_Msk),
86 			    tpiu + TPIU_FFCR_OFFSET);
87 	} else {
88 		sys_write32((TPIU_FFCR_ENFCONT_Msk | TPIU_FFCR_ENFTC_Msk), tpiu + TPIU_FFCR_OFFSET);
89 	}
90 
91 	sys_write32(CONFIG_DEBUG_CORESIGHT_NRF_TPIU_SYNC_FRAME_COUNT, tpiu + TPIU_FSCR_OFFSET);
92 
93 	coresight_lock(tpiu);
94 
95 	LOG_INF("CoreSight Host TPIU initialized");
96 }
97 
nrf_etr_init(uintptr_t buf,size_t buf_word_len)98 static void nrf_etr_init(uintptr_t buf, size_t buf_word_len)
99 {
100 	mem_addr_t etr = DT_REG_ADDR(DT_NODELABEL(etr));
101 
102 	coresight_unlock(etr);
103 
104 	sys_write32(buf_word_len, etr + ETR_RSZ_OFFSET);
105 	sys_write32(buf, etr + ETR_RWP_OFFSET);
106 	sys_write32(buf, etr + ETR_DBALO_OFFSET);
107 	sys_write32(0UL, etr + ETR_DBAHI_OFFSET);
108 	sys_write32(ETR_FFCR_ENFT_Msk, etr + ETR_FFCR_OFFSET);
109 	sys_write32(ETR_MODE_MODE_CIRCULARBUF, etr + ETR_MODE_OFFSET);
110 	sys_write32(ETR_CTL_TRACECAPTEN_Msk, etr + ETR_CTL_OFFSET);
111 
112 	coresight_lock(etr);
113 
114 	LOG_INF("Coresight Host ETR initialized");
115 }
116 
nrf_stm_init(void)117 static void nrf_stm_init(void)
118 {
119 	mem_addr_t stm = DT_REG_ADDR(DT_NODELABEL(stm));
120 
121 	coresight_unlock(stm);
122 
123 	sys_write32(1, stm + STM_STMAUXCR_OFFSET);
124 
125 	sys_write32(TS_CLOCKRATE, stm + STM_STMTSFREQR_OFFSET);
126 
127 	sys_write32((CONFIG_DEBUG_CORESIGHT_NRF_STM_SYNC_BYTE_COUNT & 0xFFF),
128 		    stm + STM_STMSYNCR_OFFSET);
129 
130 	sys_write32(0xFFFFFFFF, stm + STM_STMSPER_OFFSET);
131 
132 	if (IS_ENABLED(CONFIG_DEBUG_CORESIGHT_NRF_STM_HWEVENTS)) {
133 		sys_write32(0xFFFFFFFF, stm + STM_STMHEER_OFFSET);
134 		sys_write32((1 << STM_STMHEMCR_EN_Pos), stm + STM_STMHEMCR_OFFSET);
135 	}
136 
137 	sys_write32(((CONFIG_DEBUG_CORESIGHT_NRF_ATB_TRACE_ID_STM_GLOBAL & STM_STMTCSR_TRACEID_Msk)
138 		     << STM_STMTCSR_TRACEID_Pos) |
139 			    (1 << STM_STMTCSR_EN_Pos) | (1 << STM_STMTCSR_TSEN_Pos),
140 		    stm + STM_STMTCSR_OFFSET);
141 
142 	coresight_lock(stm);
143 
144 	LOG_INF("CoreSight STM initialized with clockrate %u", TS_CLOCKRATE);
145 }
146 
nrf_atbfunnel_init(mem_addr_t funnel_addr,uint32_t enable_set_mask)147 static void nrf_atbfunnel_init(mem_addr_t funnel_addr, uint32_t enable_set_mask)
148 {
149 	coresight_unlock(funnel_addr);
150 
151 	uint32_t ctrlreg_old = sys_read32(funnel_addr + ATBFUNNEL_CTRLREG_OFFSET);
152 
153 	const uint32_t funnel_hold_time = (((CONFIG_DEBUG_CORESIGHT_NRF_ATBFUNNEL_HOLD_TIME - 1)
154 					    << ATBFUNNEL_CTRLREG_HT_Pos) &
155 					   ATBFUNNEL_CTRLREG_HT_Msk);
156 
157 	uint32_t ctrlreg_new = (ctrlreg_old & ~ATBFUNNEL_CTRLREG_HT_Msk) | funnel_hold_time |
158 			       (enable_set_mask & 0xFF);
159 
160 	sys_write32(ctrlreg_new, funnel_addr + ATBFUNNEL_CTRLREG_OFFSET);
161 
162 	coresight_lock(funnel_addr);
163 }
164 
nrf_atbreplicator_init(mem_addr_t replicator_addr,uint32_t filter,bool ch0_allow,bool ch1_allow)165 static void nrf_atbreplicator_init(mem_addr_t replicator_addr, uint32_t filter, bool ch0_allow,
166 				   bool ch1_allow)
167 {
168 	coresight_unlock(replicator_addr);
169 
170 	uint32_t ch0_current = sys_read32(replicator_addr + ATBREPLICATOR_IDFILTER0_OFFSET);
171 	uint32_t ch1_current = sys_read32(replicator_addr + ATBREPLICATOR_IDFILTER1_OFFSET);
172 
173 	if (ch0_allow) {
174 		sys_write32(ch0_current & ~filter,
175 			    replicator_addr + ATBREPLICATOR_IDFILTER0_OFFSET);
176 	} else {
177 		sys_write32(ch0_current | filter, replicator_addr + ATBREPLICATOR_IDFILTER0_OFFSET);
178 	}
179 
180 	if (ch1_allow) {
181 		sys_write32(ch1_current & ~filter,
182 			    replicator_addr + ATBREPLICATOR_IDFILTER1_OFFSET);
183 	} else {
184 		sys_write32(ch1_current | filter, replicator_addr + ATBREPLICATOR_IDFILTER1_OFFSET);
185 	}
186 
187 	coresight_lock(replicator_addr);
188 }
189 
coresight_nrf_init_stm_etr(uintptr_t buf,size_t buf_word_len)190 static int coresight_nrf_init_stm_etr(uintptr_t buf, size_t buf_word_len)
191 {
192 	mem_addr_t atbfunnel211 = DT_REG_ADDR(DT_NODELABEL(atbfunnel211));
193 	mem_addr_t atbreplicator210 = DT_REG_ADDR(DT_NODELABEL(atbreplicator210));
194 	mem_addr_t atbreplicator213 = DT_REG_ADDR(DT_NODELABEL(atbreplicator213));
195 
196 	nrf_atbfunnel_init(atbfunnel211, ATBFUNNEL211_STM_ENS_MASK);
197 	nrf_atbreplicator_init(atbreplicator210, ATBREPLICATOR_IDFILTER_FORWARD_STM, false, true);
198 	nrf_atbreplicator_init(atbreplicator213, ATBREPLICATOR_IDFILTER_FORWARD_STM, false, true);
199 
200 	nrf_tsgen_init();
201 	nrf_etr_init(buf, buf_word_len);
202 	nrf_stm_init();
203 
204 	return 0;
205 }
206 
coresight_nrf_init_stm_tpiu(void)207 static int coresight_nrf_init_stm_tpiu(void)
208 {
209 	mem_addr_t atbfunnel211 = DT_REG_ADDR(DT_NODELABEL(atbfunnel211));
210 	mem_addr_t atbreplicator210 = DT_REG_ADDR(DT_NODELABEL(atbreplicator210));
211 	mem_addr_t atbreplicator213 = DT_REG_ADDR(DT_NODELABEL(atbreplicator213));
212 
213 	nrf_atbfunnel_init(atbfunnel211, ATBFUNNEL211_STM_ENS_MASK);
214 	nrf_atbreplicator_init(atbreplicator210, ATBREPLICATOR_IDFILTER_FORWARD_STM, false, true);
215 	nrf_atbreplicator_init(atbreplicator213, ATBREPLICATOR_IDFILTER_FORWARD_STM, true, false);
216 
217 	nrf_tsgen_init();
218 	nrf_cti_for_tpiu_init();
219 	nrf_tpiu_init();
220 	nrf_stm_init();
221 
222 	return 0;
223 }
224 
coresight_nrf_init(const struct device * dev)225 static int coresight_nrf_init(const struct device *dev)
226 {
227 	int err;
228 	struct coresight_nrf_config *cfg = (struct coresight_nrf_config *)dev->config;
229 
230 	if (cfg->pcfg) {
231 		err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
232 		if (err) {
233 			LOG_ERR("Failed to configure pins (%d)", err);
234 			return err;
235 		}
236 	}
237 
238 	err = ironside_se_tdd_configure(IRONSIDE_SE_TDD_CONFIG_ON_DEFAULT);
239 	if (err) {
240 		LOG_ERR("Failed to configure TDD (%d)", err);
241 		return err;
242 	}
243 
244 	switch (cfg->mode) {
245 	case CORESIGHT_NRF_MODE_UNCONFIGURED: {
246 		return 0;
247 	}
248 	case CORESIGHT_NRF_MODE_STM_TPIU: {
249 		return coresight_nrf_init_stm_tpiu();
250 	}
251 	case CORESIGHT_NRF_MODE_STM_ETR: {
252 		uintptr_t etr_buffer = DT_REG_ADDR(DT_NODELABEL(etr_buffer));
253 		size_t buf_word_len = DT_REG_SIZE(DT_NODELABEL(etr_buffer)) / sizeof(uint32_t);
254 
255 		return coresight_nrf_init_stm_etr(etr_buffer, buf_word_len);
256 	}
257 	default: {
258 		LOG_ERR("Unsupported Coresight mode");
259 		return -ENOTSUP;
260 	}
261 	}
262 	return 0;
263 }
264 
265 #define DEBUG_CORESIGHT_NRF_INIT_PRIORITY UTIL_INC(CONFIG_IRONSIDE_SE_CALL_INIT_PRIORITY)
266 
267 #define CORESIGHT_NRF_INST(inst)                                                                   \
268 	COND_CODE_1(DT_INST_PINCTRL_HAS_IDX(inst, 0),                                      \
269 		    (PINCTRL_DT_INST_DEFINE(inst);), ())       \
270                                                                                                    \
271 	static struct coresight_nrf_config coresight_nrf_cfg_##inst = {                            \
272 		.mode = _CONCAT(CORESIGHT_NRF_MODE_,                                               \
273 				DT_STRING_UPPER_TOKEN(DT_DRV_INST(inst), mode)),                   \
274 		.pcfg = COND_CODE_1(DT_INST_PINCTRL_HAS_IDX(inst, 0),                     \
275 				    (PINCTRL_DT_INST_DEV_CONFIG_GET(inst)),               \
276 				    (NULL)) };                  \
277                                                                                                    \
278 	DEVICE_DT_INST_DEFINE(inst, coresight_nrf_init, NULL, NULL, &coresight_nrf_cfg_##inst,     \
279 			      POST_KERNEL, DEBUG_CORESIGHT_NRF_INIT_PRIORITY, NULL);
280 
281 DT_INST_FOREACH_STATUS_OKAY(CORESIGHT_NRF_INST)
282