Skip to content

Commit 2e1f53f

Browse files
[nrf fromlist] drivers: clock_control: nrf: Apply fix for nRF54L anomaly 30.
Applied fix for nRF54L anomaly 30, which requires a periodic calibration of high-frequency clock. Upstream PR #: 88112 Signed-off-by: Michał Stasiak <[email protected]>
1 parent e48bca4 commit 2e1f53f

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

drivers/clock_control/Kconfig.nrf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,31 @@ config CLOCK_CONTROL_NRF_USES_TEMP_SENSOR
128128
endif # CLOCK_CONTROL_NRF_DRIVER_CALIBRATION
129129
endif # CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION
130130

131+
config CLOCK_CONTROL_NRF_HFINT_CALIBRATION
132+
bool "HFINT clock calibration"
133+
depends on SOC_NRF54L05 || SOC_NRF54L10 || SOC_NRF54L15
134+
depends on DT_HAS_NORDIC_NRF_HFXO_ENABLED
135+
depends on !TRUSTED_EXECUTION_NONSECURE
136+
select EXPERIMENTAL
137+
help
138+
Enables calibration of high-frequency clock on its
139+
every start.
140+
141+
if CLOCK_CONTROL_NRF_HFINT_CALIBRATION
142+
143+
config CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD
144+
int "HFINT clock calibration period in milliseconds"
145+
default 60000
146+
help
147+
Periodically, high-frequency internal clock calibration is
148+
performed. This includes requesting high-frequency clock and
149+
starting actual calibration. Once calibration is finished,
150+
the clock is released. Set to 0 to disable periodic calibration -
151+
in such case calibration will be performed only before HFXO is
152+
started by the application itself.
153+
154+
endif # CLOCK_CONTROL_NRF_HFINT_CALIBRATION
155+
131156
choice CLOCK_CONTROL_NRF_ACCURACY_PPM
132157
prompt "32KHz clock accuracy"
133158
default CLOCK_CONTROL_NRF_K32SRC_500PPM if CLOCK_CONTROL_NRF_K32SRC_RC && SOC_COMPATIBLE_NRF52X

drivers/clock_control/clock_control_nrf.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <zephyr/logging/log.h>
1515
#include <zephyr/shell/shell.h>
1616
#include <zephyr/irq.h>
17+
#include <nrf_erratas.h>
1718

1819
LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
1920

@@ -84,6 +85,10 @@ static uint64_t hf_stop_tstamp;
8485
static struct onoff_client lfsynth_cli;
8586
#endif
8687

88+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD
89+
static struct onoff_client hf_cal_cli;
90+
#endif
91+
8792
static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev,
8893
enum clock_control_nrf_type type)
8994
{
@@ -172,9 +177,92 @@ static void set_on_state(uint32_t *flags)
172177
irq_unlock(key);
173178
}
174179

180+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
181+
182+
static void nrf_errata_30_workaround(void)
183+
{
184+
if (!nrf54l_errata_30()) {
185+
return;
186+
}
187+
188+
while ((NRF_CLOCK->XO.STAT & CLOCK_XO_STAT_STATE_Msk) != CLOCK_XO_STAT_STATE_Running
189+
<< CLOCK_XO_STAT_STATE_Pos) {
190+
}
191+
const uint32_t higher_bits = *((volatile uint32_t *)0x50120820UL) & 0xFFFFFFC0;
192+
*((volatile uint32_t *)0x50120864UL) = 1 | (1 << 31);
193+
*((volatile uint32_t *)0x50120848UL) = 1;
194+
uint32_t off_abs = 24;
195+
196+
while (off_abs >= 24) {
197+
*((volatile uint32_t *)0x50120844UL) = 1;
198+
while (((*((volatile uint32_t *)0x50120840UL)) & (1 << 16)) != 0) {
199+
}
200+
const uint32_t current_cal = *((volatile uint32_t *)0x50120820UL) & 0x3F;
201+
const uint32_t cal_result = *((volatile uint32_t *)0x50120840UL) & 0x7FF;
202+
int32_t off = 1024 - cal_result;
203+
204+
off_abs = (off < 0) ? -off : off;
205+
206+
if (off >= 24 && current_cal < 0x3F) {
207+
*((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal + 1);
208+
} else if (off <= -24 && current_cal > 0) {
209+
*((volatile uint32_t *)0x50120820UL) = higher_bits | (current_cal - 1);
210+
}
211+
}
212+
213+
*((volatile uint32_t *)0x50120848UL) = 0;
214+
*((volatile uint32_t *)0x50120864UL) = 0;
215+
}
216+
217+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD
218+
219+
static void calibration_handler(struct k_timer *timer)
220+
{
221+
nrf_clock_hfclk_t clk_src;
222+
223+
bool ret = nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src);
224+
225+
if (ret && (clk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY)) {
226+
return;
227+
}
228+
229+
(void)onoff_request(z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF),
230+
&hf_cal_cli);
231+
}
232+
233+
static K_TIMER_DEFINE(calibration_timer, calibration_handler, NULL);
234+
235+
static void calibration_finished_callback(struct onoff_manager *mgr,
236+
struct onoff_client *cli,
237+
uint32_t state,
238+
int res)
239+
{
240+
(void)onoff_cancel_or_release(mgr, cli);
241+
}
242+
243+
static int calibration_init(void)
244+
{
245+
sys_notify_init_callback(&hf_cal_cli.notify, calibration_finished_callback);
246+
k_timer_start(&calibration_timer,
247+
K_NO_WAIT,
248+
K_MSEC(CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD));
249+
250+
return 0;
251+
}
252+
253+
SYS_INIT(calibration_init, APPLICATION, 0);
254+
255+
#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION_PERIOD */
256+
#endif /* CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION */
257+
175258
static void clkstarted_handle(const struct device *dev,
176259
enum clock_control_nrf_type type)
177260
{
261+
#if CONFIG_CLOCK_CONTROL_NRF_HFINT_CALIBRATION
262+
if (type == CLOCK_CONTROL_NRF_TYPE_HFCLK) {
263+
nrf_errata_30_workaround();
264+
}
265+
#endif
178266
struct nrf_clock_control_sub_data *sub_data = get_sub_data(dev, type);
179267
clock_control_cb_t callback = sub_data->cb;
180268
void *user_data = sub_data->user_data;

0 commit comments

Comments
 (0)