Skip to content

Commit d8082ca

Browse files
committed
drivers: firmware: nrf_ironside: Add TDD
Added support for the IronSide TDD service which allows configuring and powering the trace and debug domain of the nrf54h20. Also provide option to start the trace and debug domain in the soc start sequence and extend the JLinkScript to configure the coresight subsystem for ETM traces to the TPIU. Upstream PR #: 92340 Signed-off-by: Karsten Koenig <[email protected]>
1 parent 360c80c commit d8082ca

File tree

7 files changed

+254
-5
lines changed

7 files changed

+254
-5
lines changed

boards/nordic/nrf54h20dk/support/nrf54h20_cpuapp.JLinkScript

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,158 @@
11
__constant U32 _CPUCONF_ADDR = 0x52011000;
22
__constant U32 _CPUCONF_CPUWAIT_OFFSET = 0x50C;
33

4+
// ATBFUNNEL
5+
__constant U32 _ATBFUNNEL211_ADDR = 0xBF04D000;
6+
__constant U32 _ATBFUNNEL212_ADDR = 0xBF04E000;
7+
__constant U32 _ATBFUNNEL_CTRLREG_OFFSET = 0x0;
8+
__constant U32 _HOLDTIME_4 = 0x300;
9+
__constant U32 _ENS0 = 0x1;
10+
__constant U32 _ENS1 = 0x2;
11+
__constant U32 _ENS2 = 0x4;
12+
13+
// ATBREPLICATOR
14+
__constant U32 _ATBREPLICATOR212_ADDR = 0xBF04A000;
15+
__constant U32 _ATBREPLICATOR213_ADDR = 0xBF04B000;
16+
__constant U32 _ATBREPLICATOR_IDFILTER0_OFFSET = 0x0;
17+
__constant U32 _ATBREPLICATOR_IDFILTER1_OFFSET = 0x4;
18+
__constant U32 _ID_NONE = 0xFFFFFFFF;
19+
__constant U32 _ID1x = 0xFFFFFFFD;
20+
21+
// TSGEN
22+
__constant U32 _TSGEN_ADDR = 0xBF041000;
23+
__constant U32 _TSGEN_CNTCR_OFFSET = 0x0;
24+
__constant U32 _TSGEN_CNTFID0_OFFSET = 0x20;
25+
// Clock rate = TDD Freq. / 8
26+
__constant U32 _TS_CLOCKRATE = 40000000;
27+
28+
// CTI
29+
__constant U32 _CTI210_ADDR = 0xBF046000;
30+
__constant U32 _CTICONTROL_OFFSET = 0x0;
31+
__constant U32 _CTIOUTEN_OFFSET = 0xA0;
32+
__constant U32 _CTIGATE_OFFSET = 0x140;
33+
__constant U32 _TPIU_FLUSH_TRIG = 0x2;
34+
35+
// TPIU
36+
__constant U32 _TPIU_ADDR = 0xBF043000;
37+
__constant U32 _CURRENTPORTSIZE_OFFSET = 0x4;
38+
__constant U32 _FFCR_OFFSET = 0x304;
39+
__constant U32 _FSCR_OFFSET = 0x308;
40+
__constant U32 _ENFCONT = 0x02;
41+
__constant U32 _FONFLIN = 0x10;
42+
__constant U32 _ENFTC = 0x1;
43+
__constant U32 _TPIU_SYNC_FRAME_COUNT = 0x8;
44+
__constant U32 _CURRENTPORTSIZE_4 = 0x8;
45+
46+
// TDDCONF
47+
__constant U32 _TDDCONF_ADDR = 0xBF001000;
48+
__constant U32 _TRACEPORTSPEED_OFFSET = 0x408;
49+
__constant U32 _SPEED80MHZ = 0x0;
50+
51+
// CoreSight general
52+
__constant U32 _CORESIGHT_CLAIMSET_OFFSET = 0xFA0;
53+
__constant U32 _CORESIGHT_CLAIMCLR_OFFSET = 0xFA4;
54+
__constant U32 _CORESIGHT_LAR_OFFSET = 0xFB0;
55+
__constant U32 _CORESIGHT_UNLOCK_KEY = 0xC5ACCE55;
56+
57+
// Settings
58+
__constant U32 _DEBUGGER_CLAIM_MASK = 0x2;
59+
60+
// Used to check if we have already set up tracing
61+
int _needCoresightSetup = 1;
62+
63+
// Unlock a CoreSight peripheral
64+
void _CSUnlock(U32 addr)
65+
{
66+
JLINK_MEM_WriteU32(addr + _CORESIGHT_LAR_OFFSET, _CORESIGHT_UNLOCK_KEY);
67+
}
68+
69+
// Lock a CoreSight peripheral
70+
void _CSLock(U32 addr)
71+
{
72+
JLINK_MEM_WriteU32(addr + _CORESIGHT_LAR_OFFSET, 0);
73+
}
74+
75+
// Set claim bits in the CoreSight peripheral to indicate to the firmware that it
76+
// has been configured by the host debugger
77+
void _CSClaim(U32 addr)
78+
{
79+
JLINK_MEM_WriteU32(addr + _CORESIGHT_CLAIMSET_OFFSET, _DEBUGGER_CLAIM_MASK);
80+
}
81+
82+
// Set up CoreSight and other necessary configuration so to enable ETM -> TPIU tracing.
83+
int _SetupETMTPIUTrace(void)
84+
{
85+
// Set up ATB funnels/replicators to route ApplicationDomain ETM to TPIU
86+
_CSUnlock(_ATBFUNNEL212_ADDR);
87+
JLINK_MEM_WriteU32(_ATBFUNNEL212_ADDR + _ATBFUNNEL_CTRLREG_OFFSET, _HOLDTIME_4 | _ENS0);
88+
_CSClaim(_ATBFUNNEL212_ADDR);
89+
_CSLock(_ATBFUNNEL212_ADDR);
90+
91+
_CSUnlock(_ATBREPLICATOR212_ADDR);
92+
JLINK_MEM_WriteU32(_ATBREPLICATOR212_ADDR + _ATBREPLICATOR_IDFILTER0_OFFSET, _ID_NONE);
93+
JLINK_MEM_WriteU32(_ATBREPLICATOR212_ADDR + _ATBREPLICATOR_IDFILTER1_OFFSET, _ID1x);
94+
_CSLock(_ATBREPLICATOR212_ADDR);
95+
_CSClaim(_ATBREPLICATOR212_ADDR);
96+
_CSLock(_ATBREPLICATOR212_ADDR);
97+
98+
_CSUnlock(_ATBFUNNEL211_ADDR);
99+
JLINK_MEM_WriteU32(_ATBFUNNEL211_ADDR + _ATBFUNNEL_CTRLREG_OFFSET, _HOLDTIME_4 | _ENS0);
100+
_CSClaim(_ATBFUNNEL211_ADDR);
101+
_CSLock(_ATBFUNNEL211_ADDR);
102+
103+
_CSUnlock(_ATBREPLICATOR213_ADDR);
104+
JLINK_MEM_WriteU32(_ATBREPLICATOR213_ADDR + _ATBREPLICATOR_IDFILTER0_OFFSET, _ID1x);
105+
JLINK_MEM_WriteU32(_ATBREPLICATOR213_ADDR + _ATBREPLICATOR_IDFILTER1_OFFSET, _ID_NONE);
106+
_CSClaim(_ATBREPLICATOR213_ADDR);
107+
_CSLock(_ATBREPLICATOR213_ADDR);
108+
109+
// Configure timestamp generator for the correct clock rate
110+
JLINK_MEM_WriteU32(_TSGEN_ADDR + _TSGEN_CNTFID0_OFFSET, _TS_CLOCKRATE);
111+
JLINK_MEM_WriteU32(_TSGEN_ADDR + _TSGEN_CNTCR_OFFSET, 1);
112+
_CSClaim(_TSGEN_ADDR);
113+
114+
// Configure CTI1 for TPIU formatter flushing
115+
_CSUnlock(_CTI210_ADDR);
116+
JLINK_MEM_WriteU32(_CTI210_ADDR + _CTIOUTEN_OFFSET, _TPIU_FLUSH_TRIG);
117+
JLINK_MEM_WriteU32(_CTI210_ADDR + _CTIGATE_OFFSET, _TPIU_FLUSH_TRIG);
118+
JLINK_MEM_WriteU32(_CTI210_ADDR + _CTICONTROL_OFFSET, 1);
119+
_CSClaim(_CTI210_ADDR);
120+
_CSLock(_CTI210_ADDR);
121+
122+
// Configure TPIU for port size 4, continuous formatting
123+
_CSUnlock(_TPIU_ADDR);
124+
JLINK_MEM_WriteU32(_TPIU_ADDR + _CURRENTPORTSIZE_OFFSET, _CURRENTPORTSIZE_4);
125+
JLINK_MEM_WriteU32(_TPIU_ADDR + _FFCR_OFFSET, _ENFCONT | _FONFLIN | _ENFTC);
126+
JLINK_MEM_WriteU32(_TPIU_ADDR + _FSCR_OFFSET, _TPIU_SYNC_FRAME_COUNT);
127+
_CSClaim(_TPIU_ADDR);
128+
_CSLock(_TPIU_ADDR);
129+
130+
return 0;
131+
}
132+
133+
int ConfigTargetSettings(void)
134+
{
135+
JLINK_ExecCommand("CORESIGHT_AddAP = Index=0 Type=AHB-AP");
136+
CORESIGHT_IndexAHBAPToUse = 0;
137+
138+
// Adjust trace sample delay to compensate for timing when using 320MHz
139+
JLINK_ExecCommand("TraceSampleAdjust TD = 1000");
140+
141+
return 0;
142+
}
143+
144+
int OnTraceStart(void)
145+
{
146+
// Set up CoreSight if not already configured
147+
if (_needCoresightSetup) {
148+
_SetupETMTPIUTrace();
149+
_needCoresightSetup = 0;
150+
}
151+
152+
return 0;
153+
}
154+
155+
4156
int SetupTarget(void)
5157
{
6158
JLINK_TARGET_Halt();

drivers/firmware/nrf_ironside/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CALL call.c)
77

88
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_BOOT_REPORT boot_report.c)
99
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CPUCONF_SERVICE cpuconf.c)
10+
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_TDD_SERVICE tdd.c)
1011
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_UPDATE_SERVICE update.c)

drivers/firmware/nrf_ironside/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ config NRF_IRONSIDE_CPUCONF_SERVICE
3737
help
3838
Service used to boot local domain cores.
3939

40+
config NRF_IRONSIDE_TDD_SERVICE
41+
bool "IRONside tdd service"
42+
select NRF_IRONSIDE_CALL
43+
help
44+
Service used to control the trace and debug domain.
45+
4046
config NRF_IRONSIDE_UPDATE_SERVICE
4147
bool "IRONside update service"
4248
select NRF_IRONSIDE_CALL
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <zephyr/drivers/firmware/nrf_ironside/tdd.h>
7+
#include <zephyr/drivers/firmware/nrf_ironside/call.h>
8+
9+
int ironside_se_tdd_configure(const enum ironside_se_tdd_config config)
10+
{
11+
int err;
12+
struct ironside_call_buf *const buf = ironside_call_alloc();
13+
14+
buf->id = IRONSIDE_SE_CALL_ID_TDD_V0;
15+
buf->args[IRONSIDE_SE_TDD_SERVICE_REQ_CONFIG_IDX] = (uint32_t)config;
16+
17+
ironside_call_dispatch(buf);
18+
19+
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
20+
err = buf->args[IRONSIDE_SE_TDD_SERVICE_RSP_RETCODE_IDX];
21+
} else {
22+
err = buf->status;
23+
}
24+
25+
ironside_call_release(buf);
26+
27+
return err;
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_TDD_H_
7+
#define ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_TDD_H_
8+
9+
#include <zephyr/drivers/firmware/nrf_ironside/call.h>
10+
11+
#include <nrfx.h>
12+
13+
#define IRONSIDE_SE_TDD_SERVICE_ERROR_INVALID_CONFIG (1)
14+
15+
#define IRONSIDE_SE_CALL_ID_TDD_V0 4
16+
17+
#define IRONSIDE_SE_TDD_SERVICE_REQ_CONFIG_IDX 0
18+
#define IRONSIDE_SE_TDD_SERVICE_RSP_RETCODE_IDX 0
19+
20+
enum ironside_se_tdd_config {
21+
/** Don't touch the configuration */
22+
IRONSIDE_SE_TDD_CONFIG_NO_CHANGE = 0, /* This allows future extensions to the TDD service */
23+
/** Turn off the TDD */
24+
IRONSIDE_SE_TDD_CONFIG_OFF = 1,
25+
/** Turn on the TDD with default configuration */
26+
IRONSIDE_SE_TDD_CONFIG_ON_DEFAULT = 2,
27+
};
28+
29+
/**
30+
* @brief Control the Trace and Debug Domain (TDD).
31+
*
32+
* @param config The configuration to be applied.
33+
*
34+
* @retval 0 on success.
35+
* @retval -IRONSIDE_SE_TDD_ERROR_EINVAL on invalid argument.
36+
*/
37+
int ironside_se_tdd_configure(const enum ironside_se_tdd_config config);
38+
39+
#endif /* ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_TDD_H_ */

soc/nordic/nrf54h/Kconfig

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ config SOC_SERIES_NRF54HX
88
select HAS_NRFX
99
select HAS_NORDIC_DRIVERS
1010
select SOC_EARLY_INIT_HOOK if ARM
11-
select SOC_LATE_INIT_HOOK if SOC_NRF54H20_CPURAD_ENABLE
1211
select NRF_PLATFORM_HALTIUM
1312

1413
config SOC_NRF54H20_CPUAPP_COMMON
@@ -72,11 +71,23 @@ config SOC_NRF54H20_CPURAD_ENABLE
7271
default y if NRF_802154_SER_HOST
7372
depends on SOC_NRF54H20_CPUAPP
7473
select NRF_IRONSIDE_CPUCONF_SERVICE
74+
select SOC_LATE_INIT_HOOK
7575
help
7676
This will at application boot time enable clock to the
7777
Radiocore, and also power will be requested to the Radiocore
7878
subsystem. The Radiocore will then start executing instructions.
7979

80+
config SOC_NRF54H20_TDD_ENABLE
81+
bool "Enable the trace and debug domain (TDD)"
82+
depends on SOC_NRF54H20_CPUAPP
83+
select NRF_IRONSIDE_TDD_SERVICE
84+
select SOC_LATE_INIT_HOOK
85+
help
86+
This will at application boot time request that the trace and
87+
debug domain (TDD) is powered up and that the TPIU pins are
88+
configured. This allows configuring the coresight peripherals from
89+
the application domain.
90+
8091
config SOC_NRF54H20_CPURAD
8192
select SOC_NRF54H20_CPURAD_COMMON
8293

soc/nordic/nrf54h/soc.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <soc_lrcconf.h>
2424
#include <dmm.h>
2525
#include <zephyr/drivers/firmware/nrf_ironside/cpuconf.h>
26+
#include <zephyr/drivers/firmware/nrf_ironside/tdd.h>
2627

2728
LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
2829

@@ -161,10 +162,19 @@ void soc_early_init_hook(void)
161162
}
162163
}
163164

164-
#if defined(CONFIG_SOC_NRF54H20_CPURAD_ENABLE)
165+
#if defined(CONFIG_SOC_LATE_INIT_HOOK)
166+
165167
void soc_late_init_hook(void)
166168
{
167-
int err;
169+
#if defined(CONFIG_SOC_NRF54H20_TDD_ENABLE)
170+
int err_tdd;
171+
172+
err_tdd = ironside_se_tdd_configure(IRONSIDE_SE_TDD_CONFIG_ON_DEFAULT);
173+
__ASSERT(err_tdd == 0, "err_tdd was %d", err_tdd);
174+
#endif
175+
176+
#if defined(CONFIG_SOC_NRF54H20_CPURAD_ENABLE)
177+
int err_cpuconf;
168178

169179
/* The msg will be used for communication prior to IPC
170180
* communication being set up. But at this moment no such
@@ -180,8 +190,10 @@ void soc_late_init_hook(void)
180190
/* Don't wait as this is not yet supported. */
181191
bool cpu_wait = false;
182192

183-
err = ironside_cpuconf(NRF_PROCESSOR_RADIOCORE, radiocore_address, cpu_wait, msg, msg_size);
184-
__ASSERT(err == 0, "err was %d", err);
193+
err_cpuconf = ironside_cpuconf(NRF_PROCESSOR_RADIOCORE, radiocore_address, cpu_wait, msg,
194+
msg_size);
195+
__ASSERT(err_cpuconf == 0, "err_cpuconf was %d", err);
196+
#endif
185197
}
186198
#endif
187199

0 commit comments

Comments
 (0)