Skip to content

Commit 2367850

Browse files
drivers: spi: nrfx_spi(m/s): enable cross domain pins for nRF54L15
SPI(M/S)20 and SPIM(M/S)21 instances enable usage of pins on different port, but require request for constant latency mode. Added handling of such scenario in the driver. Added testcase to cover it. Signed-off-by: Michał Stasiak <[email protected]>
1 parent 97550ee commit 2367850

File tree

6 files changed

+259
-22
lines changed

6 files changed

+259
-22
lines changed

drivers/spi/spi_nrfx_spim.c

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@ LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL);
4848
defined(CONFIG_HAS_HW_NRF_SPIM121))
4949
#define SPIM_REQUESTS_CLOCK(idx) UTIL_OR(IS_EQ(idx, 120), \
5050
IS_EQ(idx, 121))
51+
/*
52+
* We use NODELABEL here because the nrfx API requires us to call
53+
* functions which are named according to SoC peripheral instance
54+
* being operated on. Since DT_INST() makes no guarantees about that,
55+
* it won't work.
56+
*/
57+
#define SPIM(idx) DT_NODELABEL(spi##idx)
58+
#define SPIM_PROP(idx, prop) DT_PROP(SPIM(idx), prop)
59+
#define SPIM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(SPIM(idx), prop)
60+
61+
#if defined(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL)
62+
#define SPIM_REQUESTS_CLOCK(node) \
63+
DT_NODE_HAS_COMPAT(DT_NODELABEL(DT_CLOCKS_CTLR(node)), nordic_nrf_hsfll_global)
64+
#define SPIM_REQUESTS_CLOCK_OR(node) SPIM_REQUESTS_CLOCK(node) ||
65+
#if (DT_FOREACH_STATUS_OKAY(nordic_nrf_spim, SPIM_REQUESTS_CLOCK_OR) 0)
5166
#define USE_CLOCK_REQUESTS 1
5267
/* If fast instances are used then system managed device PM cannot be used because
5368
* it may call PM actions from locked context and fast SPIM PM actions can only be
@@ -58,6 +73,22 @@ BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED));
5873
#define SPIM_REQUESTS_CLOCK(idx) 0
5974
#endif
6075

76+
#define SPIM_PINS_CROSS_DOMAIN(unused, prefix, idx, _) \
77+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(SPIM(prefix##idx)), \
78+
(UTIL_AND(SPIM_PROP(idx, cross_domain_constlat_required), \
79+
SPIM_HAS_PROP(idx, default_port))), \
80+
(0))
81+
82+
#if (NRFX_FOREACH_PRESENT(SPIM, SPIM_PINS_CROSS_DOMAIN, (||), (0))) && defined(CONFIG_NRFX_POWER)
83+
#include <hal/nrf_gpio.h>
84+
#include <nrfx_power.h>
85+
/* Macro determines if there is any SPIM instance that needs constant latency mode if using
86+
* cross domain pins. To use constant latency, NRFX_POWER needs to be enabled.
87+
*/
88+
#define SPIM_ANY_PINS_CROSS_DOMAIN 1
89+
#endif
90+
91+
6192
struct spi_nrfx_data {
6293
struct spi_context ctx;
6394
const struct device *dev;
@@ -97,6 +128,10 @@ struct spi_nrfx_config {
97128
const struct device *clk_dev;
98129
struct nrf_clock_spec clk_spec;
99130
#endif
131+
#if SPIM_ANY_PINS_CROSS_DOMAIN
132+
bool cross_domain;
133+
uint8_t default_port;
134+
#endif
100135
};
101136

102137
static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context);
@@ -146,6 +181,31 @@ static inline void release_clock(const struct device *dev)
146181
#endif
147182
}
148183

184+
#if SPIM_ANY_PINS_CROSS_DOMAIN
185+
static bool spim_has_cross_domain_connection(const struct spi_nrfx_config *config)
186+
{
187+
const struct pinctrl_dev_config *pcfg = config->pcfg;
188+
const struct pinctrl_state *state;
189+
int ret;
190+
191+
ret = pinctrl_lookup_state(pcfg, PINCTRL_STATE_DEFAULT, &state);
192+
if (ret < 0) {
193+
LOG_ERR("Unable to read pin state");
194+
return false;
195+
}
196+
197+
for (uint8_t i = 0U; i < state->pin_cnt; i++) {
198+
uint32_t pin = NRF_GET_PIN(state->pins[i]);
199+
200+
if (nrf_gpio_pin_port_number_extract(&pin) != config->default_port) {
201+
return true;
202+
}
203+
}
204+
205+
return false;
206+
}
207+
#endif
208+
149209
static inline void finalize_spi_transaction(const struct device *dev, bool deactivate_cs)
150210
{
151211
struct spi_nrfx_data *dev_data = dev->data;
@@ -670,6 +730,15 @@ static int spim_resume(const struct device *dev)
670730
#ifdef CONFIG_SOC_NRF54H20_GPD
671731
nrf_gpd_retain_pins_set(dev_config->pcfg, false);
672732
#endif
733+
#if SPIM_ANY_PINS_CROSS_DOMAIN
734+
if (dev_config->cross_domain && spim_has_cross_domain_connection(dev_config)) {
735+
int err;
736+
737+
err = nrfx_power_constlat_mode_request();
738+
(void)err;
739+
__ASSERT_NO_MSG(err >= 0);
740+
}
741+
#endif
673742

674743
return IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) ? request_clock(dev) : 0;
675744
}
@@ -691,6 +760,15 @@ static void spim_suspend(const struct device *dev)
691760
#ifdef CONFIG_SOC_NRF54H20_GPD
692761
nrf_gpd_retain_pins_set(dev_config->pcfg, true);
693762
#endif
763+
#if SPIM_ANY_PINS_CROSS_DOMAIN
764+
if (dev_config->cross_domain && spim_has_cross_domain_connection(dev_config)) {
765+
int err;
766+
767+
err = nrfx_power_constlat_mode_free();
768+
(void)err;
769+
__ASSERT_NO_MSG(err >= 0);
770+
}
771+
#endif
694772

695773
(void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP);
696774
}
@@ -748,15 +826,7 @@ static int spi_nrfx_init(const struct device *dev)
748826
#endif
749827
return pm_device_driver_init(dev, spim_nrfx_pm_action);
750828
}
751-
/*
752-
* We use NODELABEL here because the nrfx API requires us to call
753-
* functions which are named according to SoC peripheral instance
754-
* being operated on. Since DT_INST() makes no guarantees about that,
755-
* it won't work.
756-
*/
757-
#define SPIM(idx) DT_NODELABEL(spi##idx)
758-
#define SPIM_PROP(idx, prop) DT_PROP(SPIM(idx), prop)
759-
#define SPIM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(SPIM(idx), prop)
829+
760830
#define SPIM_MEM_REGION(idx) DT_PHANDLE(SPIM(idx), memory_regions)
761831

762832
#define SPI_NRFX_SPIM_EXTENDED_CONFIG(idx) \
@@ -846,6 +916,11 @@ static int spi_nrfx_init(const struct device *dev)
846916
.clk_spec = { \
847917
.frequency = NRF_CLOCK_CONTROL_FREQUENCY_MAX, \
848918
},)) \
919+
IF_ENABLED(UTIL_AND( \
920+
SPIM_PINS_CROSS_DOMAIN(_, /*empty*/, idx, _), \
921+
CONFIG_NRFX_POWER), \
922+
(.cross_domain = true, \
923+
.default_port = SPIM_PROP(idx, default_port),)) \
849924
}; \
850925
BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \
851926
!(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\

drivers/spi/spi_nrfx_spis.c

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
LOG_MODULE_REGISTER(spi_nrfx_spis, CONFIG_SPI_LOG_LEVEL);
2020

2121
#include "spi_context.h"
22+
#include <hal/nrf_gpio.h>
23+
#include <nrfx_power.h>
2224

2325
#ifdef CONFIG_SOC_NRF54H20_GPD
2426
#include <nrf/gpd.h>
@@ -36,6 +38,32 @@ LOG_MODULE_REGISTER(spi_nrfx_spis, CONFIG_SPI_LOG_LEVEL);
3638
BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED));
3739
#endif
3840

41+
/*
42+
* Current factors requiring use of DT_NODELABEL:
43+
*
44+
* - HAL design (requirement of drv_inst_idx in nrfx_spis_t)
45+
* - Name-based HAL IRQ handlers, e.g. nrfx_spis_0_irq_handler
46+
*/
47+
#define SPIS_NODE(idx) COND_CODE_1(SPIS_IS_FAST(idx), (spis##idx), (spi##idx))
48+
#define SPIS(idx) DT_NODELABEL(SPIS_NODE(idx))
49+
#define SPIS_PROP(idx, prop) DT_PROP(SPIS(idx), prop)
50+
#define SPIS_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(SPIS(idx), prop)
51+
52+
#define SPIS_PINS_CROSS_DOMAIN(unused, prefix, idx, _) \
53+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(SPIS(prefix##idx)), \
54+
(UTIL_AND(SPIS_PROP(idx, cross_domain_constlat_required), \
55+
SPIS_HAS_PROP(idx, default_port))), \
56+
(0))
57+
58+
#if (NRFX_FOREACH_PRESENT(SPIS, SPIS_PINS_CROSS_DOMAIN, (||), (0))) && defined(CONFIG_NRFX_POWER)
59+
#include <hal/nrf_gpio.h>
60+
#include <nrfx_power.h>
61+
/* Macro determines if there is any SPIS instance that needs constant latency mode if using
62+
* cross domain pins. To use constant latency, NRFX_POWER needs to be enabled.
63+
*/
64+
#define SPIS_ANY_PINS_CROSS_DOMAIN 1
65+
#endif
66+
3967
struct spi_nrfx_data {
4068
struct spi_context ctx;
4169
const struct device *dev;
@@ -54,8 +82,37 @@ struct spi_nrfx_config {
5482
const struct pinctrl_dev_config *pcfg;
5583
struct gpio_dt_spec wake_gpio;
5684
void *mem_reg;
85+
#if SPIS_ANY_PINS_CROSS_DOMAIN
86+
bool cross_domain;
87+
uint8_t default_port;
88+
#endif
5789
};
5890

91+
#if SPIS_ANY_PINS_CROSS_DOMAIN
92+
static bool spis_has_cross_domain_connection(const struct spi_nrfx_config *config)
93+
{
94+
const struct pinctrl_dev_config *pcfg = config->pcfg;
95+
const struct pinctrl_state *state;
96+
int ret;
97+
98+
ret = pinctrl_lookup_state(pcfg, PINCTRL_STATE_DEFAULT, &state);
99+
if (ret < 0) {
100+
LOG_ERR("Unable to read pin state");
101+
return false;
102+
}
103+
104+
for (uint8_t i = 0U; i < state->pin_cnt; i++) {
105+
uint32_t pin = NRF_GET_PIN(state->pins[i]);
106+
107+
if (nrf_gpio_pin_port_number_extract(&pin) != config->default_port) {
108+
return true;
109+
}
110+
}
111+
112+
return false;
113+
}
114+
#endif
115+
59116
static inline nrf_spis_mode_t get_nrf_spis_mode(uint16_t operation)
60117
{
61118
if (SPI_MODE_GET(operation) & SPI_MODE_CPOL) {
@@ -364,6 +421,15 @@ static void spi_nrfx_suspend(const struct device *dev)
364421
nrf_gpd_retain_pins_set(dev_config->pcfg, true);
365422
}
366423
#endif
424+
#if SPIS_ANY_PINS_CROSS_DOMAIN
425+
if (dev_config->cross_domain && spis_has_cross_domain_connection(dev_config)) {
426+
int err;
427+
428+
err = nrfx_power_constlat_mode_free();
429+
(void)err;
430+
__ASSERT_NO_MSG(err >= 0);
431+
}
432+
#endif
367433

368434
(void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP);
369435
}
@@ -379,6 +445,15 @@ static void spi_nrfx_resume(const struct device *dev)
379445
nrf_gpd_retain_pins_set(dev_config->pcfg, false);
380446
}
381447
#endif
448+
#if SPIS_ANY_PINS_CROSS_DOMAIN
449+
if (dev_config->cross_domain && spis_has_cross_domain_connection(dev_config)) {
450+
int err;
451+
452+
err = nrfx_power_constlat_mode_request();
453+
(void)err;
454+
__ASSERT_NO_MSG(err >= 0);
455+
}
456+
#endif
382457

383458
if (dev_config->wake_gpio.port == NULL) {
384459
nrf_spis_enable(dev_config->spis.p_reg);
@@ -462,19 +537,6 @@ static int spi_nrfx_init(const struct device *dev)
462537
return pm_device_driver_init(dev, spi_nrfx_pm_action);
463538
}
464539

465-
/*
466-
* Current factors requiring use of DT_NODELABEL:
467-
*
468-
* - HAL design (requirement of drv_inst_idx in nrfx_spis_t)
469-
* - Name-based HAL IRQ handlers, e.g. nrfx_spis_0_irq_handler
470-
*/
471-
472-
#define SPIS_NODE(idx) COND_CODE_1(SPIS_IS_FAST(idx), (spis##idx), (spi##idx))
473-
474-
#define SPIS(idx) DT_NODELABEL(SPIS_NODE(idx))
475-
476-
#define SPIS_PROP(idx, prop) DT_PROP(SPIS(idx), prop)
477-
478540
#define SPI_NRFX_SPIS_DEFINE(idx) \
479541
static void irq_connect##idx(void) \
480542
{ \
@@ -510,6 +572,11 @@ static int spi_nrfx_init(const struct device *dev)
510572
NRFX_MHZ_TO_HZ(16UL),)) \
511573
.wake_gpio = GPIO_DT_SPEC_GET_OR(SPIS(idx), wake_gpios, {0}), \
512574
.mem_reg = DMM_DEV_TO_REG(SPIS(idx)), \
575+
IF_ENABLED(UTIL_AND( \
576+
SPIS_PINS_CROSS_DOMAIN(_, /*empty*/, idx, _), \
577+
CONFIG_NRFX_POWER), \
578+
(.cross_domain = true, \
579+
.default_port = SPIS_PROP(idx, default_port),)) \
513580
}; \
514581
BUILD_ASSERT(!DT_NODE_HAS_PROP(SPIS(idx), wake_gpios) || \
515582
!(DT_GPIO_FLAGS(SPIS(idx), wake_gpios) & GPIO_ACTIVE_LOW),\

dts/bindings/spi/nordic,nrf-spi-common.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,13 @@ properties:
6161
and SPI master again keeps the line in the low state
6262
Please note that the line must be configured and properly handled on
6363
both sides for the mechanism to work correctly.
64+
65+
cross-domain-constlat-required:
66+
type: boolean
67+
description: |
68+
SPI needs constant latency mode if using cross domain pins.
69+
70+
default-port:
71+
type: int
72+
description: |
73+
SPI default GPIO port.

dts/common/nordic/nrf54l_05_10_15.dtsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@
311311
rx-delay-supported;
312312
rx-delay = <1>;
313313
status = "disabled";
314+
cross-domain-constlat-required;
315+
default-port = <0x1>;
314316
};
315317

316318
uart20: uart@c6000 {
@@ -352,6 +354,8 @@
352354
rx-delay-supported;
353355
rx-delay = <1>;
354356
status = "disabled";
357+
cross-domain-constlat-required;
358+
default-port = <0x1>;
355359
};
356360

357361
uart21: uart@c7000 {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
&pinctrl {
8+
spi21_default_alt: spi21_default_alt {
9+
group1 {
10+
psels = <NRF_PSEL(SPIM_SCK, 2, 6)>,
11+
<NRF_PSEL(SPIM_MISO, 2, 9)>,
12+
<NRF_PSEL(SPIM_MOSI, 2, 8)>;
13+
};
14+
};
15+
16+
spi21_sleep_alt: spi21_sleep_alt {
17+
group1 {
18+
psels = <NRF_PSEL(SPIM_SCK, 2, 6)>,
19+
<NRF_PSEL(SPIM_MISO, 2, 9)>,
20+
<NRF_PSEL(SPIM_MOSI, 2, 8)>;
21+
low-power-enable;
22+
};
23+
};
24+
25+
spi22_default_alt: spi22_default_alt {
26+
group1 {
27+
psels = <NRF_PSEL(SPIS_SCK, 1, 11)>,
28+
<NRF_PSEL(SPIS_MISO, 1, 13)>,
29+
<NRF_PSEL(SPIS_MOSI, 1, 12)>,
30+
<NRF_PSEL(SPIS_CSN, 1, 14)>;
31+
};
32+
};
33+
34+
spi22_sleep_alt: spi22_sleep_alt {
35+
group1 {
36+
psels = <NRF_PSEL(SPIS_SCK, 1, 11)>,
37+
<NRF_PSEL(SPIS_MISO, 1, 13)>,
38+
<NRF_PSEL(SPIS_MOSI, 1, 12)>,
39+
<NRF_PSEL(SPIS_CSN, 1, 14)>;
40+
low-power-enable;
41+
};
42+
};
43+
};
44+
45+
&gpio2 {
46+
status = "okay";
47+
};
48+
49+
&spi21 {
50+
status = "okay";
51+
pinctrl-0 = <&spi21_default_alt>;
52+
pinctrl-1 = <&spi21_sleep_alt>;
53+
pinctrl-names = "default", "sleep";
54+
overrun-character = <0x00>;
55+
cs-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
56+
zephyr,pm-device-runtime-auto;
57+
dut_spi_dt: test-spi-dev@0 {
58+
compatible = "vnd,spi-device";
59+
reg = <0>;
60+
spi-max-frequency = <DT_FREQ_M(1)>;
61+
};
62+
};
63+
64+
dut_spis: &spi22 {
65+
compatible = "nordic,nrf-spis";
66+
status = "okay";
67+
def-char = <0x00>;
68+
pinctrl-0 = <&spi22_default_alt>;
69+
pinctrl-1 = <&spi22_sleep_alt>;
70+
pinctrl-names = "default", "sleep";
71+
/delete-property/rx-delay-supported;
72+
/delete-property/rx-delay;
73+
};

0 commit comments

Comments
 (0)