Skip to content

Commit d0c686d

Browse files
dchat-nordicrlubos
authored andcommitted
esb: Cleanup workaround implementations
Remove HMPAN-18 and HMPAN-102. Correct HMPAN-103 and HMPAN-229. Move workarounds to separate file for easier tracking. Jira: NCSDK-36550 Signed-off-by: Dominik Chat <[email protected]> (cherry picked from commit be9f5d7)
1 parent 08d1e6f commit d0c686d

File tree

2 files changed

+188
-121
lines changed

2 files changed

+188
-121
lines changed

subsys/esb/esb.c

Lines changed: 22 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@
2222
#include <zephyr/kernel.h>
2323
#include <zephyr/sys/byteorder.h>
2424
#include <zephyr/drivers/gpio.h>
25-
#if NRF54H_ERRATA_216_PRESENT
26-
#include <zephyr/drivers/mbox.h>
27-
#endif /* NRF54H_ERRATA_216_PRESENT */
2825

2926
#include <mpsl_fem_protocol_api.h>
3027

3128
#include "esb_peripherals.h"
3229
#include "esb_ppi_api.h"
30+
#include "esb_workarounds.h"
3331

3432
LOG_MODULE_REGISTER(esb, CONFIG_ESB_LOG_LEVEL);
3533

@@ -266,13 +264,6 @@ enum {
266264
static atomic_t errata_216_status = ATOMIC_INIT(ERRATA_216_DISABLED);
267265
static uint32_t errata_216_timer_shorts;
268266

269-
#if NRF54H_ERRATA_216_PRESENT
270-
static const struct mbox_dt_spec on_channel =
271-
MBOX_DT_SPEC_GET(DT_NODELABEL(cpurad_cpusys_errata216_mboxes), on_req);
272-
static const struct mbox_dt_spec off_channel =
273-
MBOX_DT_SPEC_GET(DT_NODELABEL(cpurad_cpusys_errata216_mboxes), off_req);
274-
#endif /* NRF54H_ERRATA_216_PRESENT */
275-
276267
static esb_event_handler event_handler;
277268
static struct esb_payload *current_payload;
278269

@@ -378,39 +369,14 @@ static inline void apply_errata143_workaround(void)
378369
* use a unique address 0 since this will avoid the 3dBm penalty
379370
* incurred from the workaround.
380371
*/
381-
uint32_t base_address_mask =
382-
esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000;
383372

384-
/* Load the two addresses before comparing them to ensure
385-
* defined ordering of volatile accesses.
386-
*/
387-
uint32_t addr0 = nrf_radio_base0_get(NRF_RADIO) & base_address_mask;
388-
uint32_t addr1 = nrf_radio_base1_get(NRF_RADIO) & base_address_mask;
389-
390-
if (addr0 == addr1) {
391-
uint32_t radio_prefix0 = nrf_radio_prefix0_get(NRF_RADIO);
392-
uint32_t radio_prefix1 = nrf_radio_prefix1_get(NRF_RADIO);
393-
394-
uint8_t prefix0 = radio_prefix0 & RADIO_PREFIX0_AP0_Msk;
395-
uint8_t prefix1 = (radio_prefix0 & RADIO_PREFIX0_AP1_Msk) >> RADIO_PREFIX0_AP1_Pos;
396-
uint8_t prefix2 = (radio_prefix0 & RADIO_PREFIX0_AP2_Msk) >> RADIO_PREFIX0_AP2_Pos;
397-
uint8_t prefix3 = (radio_prefix0 & RADIO_PREFIX0_AP3_Msk) >> RADIO_PREFIX0_AP3_Pos;
398-
uint8_t prefix4 = radio_prefix1 & RADIO_PREFIX1_AP4_Msk;
399-
uint8_t prefix5 = (radio_prefix1 & RADIO_PREFIX1_AP5_Msk) >> RADIO_PREFIX1_AP5_Pos;
400-
uint8_t prefix6 = (radio_prefix1 & RADIO_PREFIX1_AP6_Msk) >> RADIO_PREFIX1_AP6_Pos;
401-
uint8_t prefix7 = (radio_prefix1 & RADIO_PREFIX1_AP7_Msk) >> RADIO_PREFIX1_AP7_Pos;
402-
403-
if ((prefix0 == prefix1) || (prefix0 == prefix2) ||
404-
(prefix0 == prefix3) || (prefix0 == prefix4) ||
405-
(prefix0 == prefix5) || (prefix0 == prefix6) ||
406-
(prefix0 == prefix7)) {
407-
/* This will cause a 3dBm sensitivity loss,
408-
* avoid using such address combinations if possible.
409-
*/
410-
*(volatile uint32_t *)0x40001774 =
411-
((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000;
412-
}
373+
if (!nrf52_errata_143()) {
374+
return;
413375
}
376+
377+
uint32_t base_address_mask =
378+
esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000;
379+
esb_apply_nrf52_143(base_address_mask);
414380
}
415381

416382
static void errata_216_on(void)
@@ -419,15 +385,11 @@ static void errata_216_on(void)
419385
return;
420386
}
421387

422-
#if NRF54H_ERRATA_216_PRESENT
423-
if (mbox_send_dt(&on_channel, NULL) != 0) {
424-
LOG_ERR("Failed to enable Errata 216");
425-
/* Should not happen. */
426-
__ASSERT_NO_MSG(false);
427-
} else {
428-
atomic_set(&errata_216_status, ERRATA_216_ENABLED);
429-
}
430-
#endif /* NRF54H_ERRATA_216_PRESENT */
388+
esb_apply_nrf54h_216(true);
389+
390+
#if NRF54H_ERRATA_216_ENABLE_WORKAROUND
391+
atomic_set(&errata_216_status, ERRATA_216_ENABLED);
392+
#endif /* NRF54H_ERRATA_216_ENABLE_WORKAROUND */
431393
}
432394

433395
static void errata_216_off(void)
@@ -436,86 +398,25 @@ static void errata_216_off(void)
436398
return;
437399
}
438400

439-
#if NRF54H_ERRATA_216_PRESENT
440-
if (mbox_send_dt(&off_channel, NULL) != 0) {
441-
LOG_ERR("Failed to disable Errata 216");
442-
/* Should not happen. */
443-
__ASSERT_NO_MSG(false);
444-
} else {
445-
atomic_set(&errata_216_status, ERRATA_216_DISABLED);
446-
}
447-
#endif /* NRF54H_ERRATA_216_PRESENT */
401+
esb_apply_nrf54h_216(false);
402+
403+
#if NRF54H_ERRATA_216_ENABLE_WORKAROUND
404+
atomic_set(&errata_216_status, ERRATA_216_DISABLED);
405+
#endif /* NRF54H_ERRATA_216_ENABLE_WORKAROUND */
448406
}
449407

450408
static void apply_radio_init_workarounds(void)
451409
{
452410
if (nrf52_errata_182()) {
453-
/* Check if the device is an nRF52832 Rev. 2. */
454-
/* Workaround for nRF52832 rev 2 errata 182 */
455-
*(volatile uint32_t *)0x4000173C |= (1 << 10);
456-
}
457-
458-
#if defined(CONFIG_SOC_SERIES_NRF54HX)
459-
/* Apply HMPAN-102 workaround for nRF54H series */
460-
*(volatile uint32_t *)0x5302C7E4 =
461-
(((*((volatile uint32_t *)0x5302C7E4)) & 0xFF000FFF) | 0x0012C000);
462-
463-
/* Apply HMPAN-18 workaround for nRF54H series - load trim values*/
464-
if (*(volatile uint32_t *)0x0FFFE458 != TRIM_VALUE_EMPTY) {
465-
*(volatile uint32_t *)0x5302C734 = *(volatile uint32_t *)0x0FFFE458;
466-
}
467-
468-
if (*(volatile uint32_t *)0x0FFFE45C != TRIM_VALUE_EMPTY) {
469-
*(volatile uint32_t *)0x5302C738 = *(volatile uint32_t *)0x0FFFE45C;
470-
}
471-
472-
if (*(volatile uint32_t *)0x0FFFE460 != TRIM_VALUE_EMPTY) {
473-
*(volatile uint32_t *)0x5302C73C = *(volatile uint32_t *)0x0FFFE460;
474-
}
475-
476-
if (*(volatile uint32_t *)0x0FFFE464 != TRIM_VALUE_EMPTY) {
477-
*(volatile uint32_t *)0x5302C740 = *(volatile uint32_t *)0x0FFFE464;
478-
}
479-
480-
if (*(volatile uint32_t *)0x0FFFE468 != TRIM_VALUE_EMPTY) {
481-
*(volatile uint32_t *)0x5302C74C = *(volatile uint32_t *)0x0FFFE468;
482-
}
483-
484-
/* HMPAN-229 provides hardcoded value if the trim value is 0 */
485-
if ((*(volatile uint32_t *)0x0FFFE46C != TRIM_VALUE_EMPTY) &&
486-
(*(volatile uint32_t *)0x0FFFE46C != 0)) {
487-
*(volatile uint32_t *)0x5302C7D8 = *(volatile uint32_t *)0x0FFFE46C;
488-
} else {
489-
*(volatile uint32_t *)0x5302C7D8 = 0x00000004;
490-
}
491-
492-
if (*(volatile uint32_t *)0x0FFFE470 != TRIM_VALUE_EMPTY) {
493-
*(volatile uint32_t *)0x5302C840 = *(volatile uint32_t *)0x0FFFE470;
494-
}
495-
496-
if (*(volatile uint32_t *)0x0FFFE474 != TRIM_VALUE_EMPTY) {
497-
*(volatile uint32_t *)0x5302C844 = *(volatile uint32_t *)0x0FFFE474;
498-
}
499-
500-
if (*(volatile uint32_t *)0x0FFFE478 != TRIM_VALUE_EMPTY) {
501-
*(volatile uint32_t *)0x5302C848 = *(volatile uint32_t *)0x0FFFE478;
502-
}
503-
504-
if (*(volatile uint32_t *)0x0FFFE47C != TRIM_VALUE_EMPTY) {
505-
*(volatile uint32_t *)0x5302C84C = *(volatile uint32_t *)0x0FFFE47C;
411+
esb_apply_nrf52_182();
506412
}
507413

508-
/* Apply HMPAN-103 workaround for nRF54H series*/
509-
if ((*(volatile uint32_t *)0x5302C8A0 == 0x80000000) ||
510-
(*(volatile uint32_t *)0x5302C8A0 == 0x0058120E)) {
511-
*(volatile uint32_t *)0x5302C8A0 = 0x0058090E;
414+
if (nrf54h_errata_103()) {
415+
esb_apply_nrf54h_103();
512416
}
513417

514-
*(volatile uint32_t *)0x5302C8A4 = 0x00F8AA5F;
515-
*(volatile uint32_t *)0x5302C7AC = 0x8672827A;
516-
*(volatile uint32_t *)0x5302C7B0 = 0x7E768672;
517-
*(volatile uint32_t *)0x5302C7B4 = 0x0406007E;
518-
#endif /* (CONFIG_SOC_SERIES_NRF54HX) */
418+
/* Currently there is no check for this workaround */
419+
esb_apply_nrf54h_229();
519420
}
520421

521422
static void esb_fem_for_tx_set(bool ack)

subsys/esb/esb_workarounds.h

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#ifndef ESB_WORKAROUNDS_H__
8+
#define ESB_WORKAROUNDS_H__
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
#include <stddef.h>
15+
#include <zephyr/kernel.h>
16+
17+
#include <hal/nrf_radio.h>
18+
19+
#if NRF54H_ERRATA_216_ENABLE_WORKAROUND
20+
#include <zephyr/drivers/mbox.h>
21+
#endif /* NRF54H_ERRATA_216_ENABLE_WORKAROUND */
22+
23+
/* nRF52 Workaround 182 */
24+
static void esb_apply_nrf52_182(void);
25+
26+
/* nRF52 Workaround 143 */
27+
static void esb_apply_nrf52_143(uint32_t base_address_mask);
28+
29+
/* nRF54H Workaround 84 */
30+
/* HMPAN-84 is implemented in the ESB samples in the clocks_start function */
31+
32+
/* nRF54H Workaround 103 */
33+
static void esb_apply_nrf54h_103(void);
34+
35+
/* nRF54H Workaround 216 */
36+
static void esb_apply_nrf54h_216(bool on);
37+
38+
/* nRF54H Workaround 229 */
39+
static void esb_apply_nrf54h_229(void);
40+
41+
/* nRF54L Workaround 20 */
42+
/* MLTPAN-20 is implemented in the ESB samples in the clocks_start function */
43+
44+
/* nRF54L Workaround 39 */
45+
/* MLTPAN-39 is implemented in the ESB samples in the clocks_start function */
46+
47+
#if NRF52_ERRATA_143_ENABLE_WORKAROUND
48+
static void esb_apply_nrf52_143(uint32_t base_address_mask)
49+
{
50+
/* Load the two addresses before comparing them to ensure
51+
* defined ordering of volatile accesses.
52+
*/
53+
uint32_t addr0 = nrf_radio_base0_get(NRF_RADIO) & base_address_mask;
54+
uint32_t addr1 = nrf_radio_base1_get(NRF_RADIO) & base_address_mask;
55+
56+
if (addr0 == addr1) {
57+
uint32_t radio_prefix0 = nrf_radio_prefix0_get(NRF_RADIO);
58+
uint32_t radio_prefix1 = nrf_radio_prefix1_get(NRF_RADIO);
59+
60+
uint8_t prefix0 = radio_prefix0 & RADIO_PREFIX0_AP0_Msk;
61+
uint8_t prefix1 = (radio_prefix0 & RADIO_PREFIX0_AP1_Msk) >> RADIO_PREFIX0_AP1_Pos;
62+
uint8_t prefix2 = (radio_prefix0 & RADIO_PREFIX0_AP2_Msk) >> RADIO_PREFIX0_AP2_Pos;
63+
uint8_t prefix3 = (radio_prefix0 & RADIO_PREFIX0_AP3_Msk) >> RADIO_PREFIX0_AP3_Pos;
64+
uint8_t prefix4 = radio_prefix1 & RADIO_PREFIX1_AP4_Msk;
65+
uint8_t prefix5 = (radio_prefix1 & RADIO_PREFIX1_AP5_Msk) >> RADIO_PREFIX1_AP5_Pos;
66+
uint8_t prefix6 = (radio_prefix1 & RADIO_PREFIX1_AP6_Msk) >> RADIO_PREFIX1_AP6_Pos;
67+
uint8_t prefix7 = (radio_prefix1 & RADIO_PREFIX1_AP7_Msk) >> RADIO_PREFIX1_AP7_Pos;
68+
69+
if ((prefix0 == prefix1) || (prefix0 == prefix2) ||
70+
(prefix0 == prefix3) || (prefix0 == prefix4) ||
71+
(prefix0 == prefix5) || (prefix0 == prefix6) ||
72+
(prefix0 == prefix7)) {
73+
/* This will cause a 3dBm sensitivity loss,
74+
* avoid using such address combinations if possible.
75+
*/
76+
*(volatile uint32_t *)0x40001774 =
77+
((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000;
78+
}
79+
}
80+
}
81+
#else
82+
static void esb_apply_nrf52_143(uint32_t base_address_mask)
83+
{
84+
ARG_UNUSED(base_address_mask);
85+
}
86+
#endif /* NRF52_ERRATA_143_ENABLE_WORKAROUND */
87+
88+
#if NRF52_ERRATA_182_ENABLE_WORKAROUND
89+
static void esb_apply_nrf52_182(void)
90+
{
91+
*(volatile uint32_t *)0x4000173C |= (1 << 10);
92+
}
93+
#else
94+
static void esb_apply_nrf52_182(void)
95+
{
96+
/* No implementation needed */
97+
}
98+
#endif /* NRF52_ERRATA_182_ENABLE_WORKAROUND */
99+
100+
#if NRF54H_ERRATA_103_ENABLE_WORKAROUND
101+
static void esb_apply_nrf54h_103(void)
102+
{
103+
if ((*(volatile uint32_t *)0x5302C8A0 == 0x80000000) ||
104+
(*(volatile uint32_t *)0x5302C8A0 == 0x0058120E)) {
105+
*(volatile uint32_t *)0x5302C8A0 = 0x0058090E;
106+
}
107+
108+
*(volatile uint32_t *)0x5302C8A4 = 0x00F8AA5F;
109+
*(volatile uint32_t *)0x5302C8A8 = 0x00C00030;
110+
*(volatile uint32_t *)0x5302C8AC = 0x00A80030;
111+
*(volatile uint32_t *)0x5302C7AC = 0x8672827A;
112+
*(volatile uint32_t *)0x5302C7B0 = 0x7E768672;
113+
*(volatile uint32_t *)0x5302C7B4 = 0x0406007E;
114+
*(volatile uint32_t *)0x5302C7E4 = 0x0412C384;
115+
}
116+
#else
117+
static void esb_apply_nrf54h_103(void)
118+
{
119+
/* No implementation needed */
120+
}
121+
#endif /* NRF54H_ERRATA_103_ENABLE_WORKAROUND */
122+
123+
#if NRF54H_ERRATA_216_ENABLE_WORKAROUND
124+
static inline void esb_apply_nrf54h_216(bool on)
125+
{
126+
static const struct mbox_dt_spec on_channel =
127+
MBOX_DT_SPEC_GET(DT_NODELABEL(cpurad_cpusys_errata216_mboxes), on_req);
128+
static const struct mbox_dt_spec off_channel =
129+
MBOX_DT_SPEC_GET(DT_NODELABEL(cpurad_cpusys_errata216_mboxes), off_req);
130+
const struct mbox_dt_spec *spec = on ? &on_channel : &off_channel;
131+
132+
if (!IS_ENABLED(NRF54H_ERRATA_216_ENABLE_WORKAROUND)) {
133+
return;
134+
}
135+
136+
if (mbox_send_dt(spec, NULL)) {
137+
/* Should not happen. */
138+
__ASSERT_NO_MSG(false);
139+
}
140+
}
141+
#else
142+
static void esb_apply_nrf54h_216(bool on)
143+
{
144+
ARG_UNUSED(on);
145+
}
146+
#endif /* NRF54H_ERRATA_216_ENABLE_WORKAROUND*/
147+
148+
#if defined(CONFIG_SOC_SERIES_NRF54HX)
149+
static void esb_apply_nrf54h_229(void)
150+
{
151+
if (*(volatile uint32_t *)0x0FFFE46C == 0x0) {
152+
*(volatile uint32_t *)0x5302C7D8 = 0x00000004;
153+
}
154+
}
155+
#else
156+
static void esb_apply_nrf54h_229(void)
157+
{
158+
/* No implementation needed */
159+
}
160+
#endif /* (CONFIG_SOC_SERIES_NRF54HX) */
161+
162+
#ifdef __cplusplus
163+
}
164+
#endif
165+
166+
#endif /* ESB_WORKAROUNDS_H__ */

0 commit comments

Comments
 (0)