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