Skip to content

Commit ff502ff

Browse files
[nrf fromlist] 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. Upstream PR #: 90197 Signed-off-by: Michał Stasiak <[email protected]>
1 parent f1d1913 commit ff502ff

File tree

6 files changed

+285
-22
lines changed

6 files changed

+285
-22
lines changed

drivers/spi/spi_nrfx_spim.c

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL);
4343
#define SPI_BUFFER_IN_RAM 1
4444
#endif
4545

46+
/*
47+
* We use NODELABEL here because the nrfx API requires us to call
48+
* functions which are named according to SoC peripheral instance
49+
* being operated on. Since DT_INST() makes no guarantees about that,
50+
* it won't work.
51+
*/
52+
#define SPIM(idx) DT_NODELABEL(spi##idx)
53+
#define SPIM_PROP(idx, prop) DT_PROP(SPIM(idx), prop)
54+
#define SPIM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(SPIM(idx), prop)
55+
4656
#if defined(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL)
4757
#define SPIM_REQUESTS_CLOCK(node) \
4858
DT_NODE_HAS_COMPAT(DT_NODELABEL(DT_CLOCKS_CTLR(node)), nordic_nrf_hsfll_global)
@@ -59,6 +69,28 @@ BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED));
5969
#define SPIM_REQUESTS_CLOCK(idx) 0
6070
#endif
6171

72+
#define SPIM_PINS_CROSS_DOMAIN(unused, prefix, idx, _) \
73+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(SPIM(prefix##idx)), \
74+
(SPIM_PROP(idx, cross_domain_pins_supported)), \
75+
(0))
76+
77+
#if NRFX_FOREACH_PRESENT(SPIM, SPIM_PINS_CROSS_DOMAIN, (||), (0))
78+
#include <hal/nrf_gpio.h>
79+
/* Certain SPIM instances support usage of cross domain pins in form of dedicated pins on
80+
* a port different from the default one.
81+
*/
82+
#define SPIM_CROSS_DOMAIN_SUPPORTED 1
83+
#endif
84+
85+
#if SPIM_CROSS_DOMAIN_SUPPORTED && defined(CONFIG_NRF_SYS_EVENT)
86+
#include <nrf_sys_event.h>
87+
/* To use cross domain pins, constant latency mode needs to be applied, which is
88+
* handled via nrf_sys_event requests.
89+
*/
90+
#define SPIM_CROSS_DOMAIN_PINS_HANDLE 1
91+
#endif
92+
93+
6294
struct spi_nrfx_data {
6395
struct spi_context ctx;
6496
const struct device *dev;
@@ -98,6 +130,10 @@ struct spi_nrfx_config {
98130
const struct device *clk_dev;
99131
struct nrf_clock_spec clk_spec;
100132
#endif
133+
#if SPIM_CROSS_DOMAIN_SUPPORTED
134+
bool cross_domain;
135+
int8_t default_port;
136+
#endif
101137
};
102138

103139
static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context);
@@ -147,6 +183,31 @@ static inline void release_clock(const struct device *dev)
147183
#endif
148184
}
149185

186+
#if SPIM_CROSS_DOMAIN_SUPPORTED
187+
static bool spim_has_cross_domain_connection(const struct spi_nrfx_config *config)
188+
{
189+
const struct pinctrl_dev_config *pcfg = config->pcfg;
190+
const struct pinctrl_state *state;
191+
int ret;
192+
193+
ret = pinctrl_lookup_state(pcfg, PINCTRL_STATE_DEFAULT, &state);
194+
if (ret < 0) {
195+
LOG_ERR("Unable to read pin state");
196+
return false;
197+
}
198+
199+
for (uint8_t i = 0U; i < state->pin_cnt; i++) {
200+
uint32_t pin = NRF_GET_PIN(state->pins[i]);
201+
202+
if (nrf_gpio_pin_port_number_extract(&pin) != config->default_port) {
203+
return true;
204+
}
205+
}
206+
207+
return false;
208+
}
209+
#endif
210+
150211
static inline void finalize_spi_transaction(const struct device *dev, bool deactivate_cs)
151212
{
152213
struct spi_nrfx_data *dev_data = dev->data;
@@ -675,6 +736,19 @@ static int spim_resume(const struct device *dev)
675736
#ifdef CONFIG_SOC_NRF54H20_GPD
676737
nrf_gpd_retain_pins_set(dev_config->pcfg, false);
677738
#endif
739+
#if SPIM_CROSS_DOMAIN_SUPPORTED
740+
if (dev_config->cross_domain && spim_has_cross_domain_connection(dev_config)) {
741+
#if SPIM_CROSS_DOMAIN_PINS_HANDLE
742+
int err;
743+
744+
err = nrf_sys_event_request_global_constlat();
745+
(void)err;
746+
__ASSERT_NO_MSG(err >= 0);
747+
#else
748+
__ASSERT(false, "NRF_SYS_EVENT needs to be enabled to use cross domain pins.\n");
749+
#endif
750+
}
751+
#endif
678752

679753
return IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) ? request_clock(dev) : 0;
680754
}
@@ -696,6 +770,19 @@ static void spim_suspend(const struct device *dev)
696770
#ifdef CONFIG_SOC_NRF54H20_GPD
697771
nrf_gpd_retain_pins_set(dev_config->pcfg, true);
698772
#endif
773+
#if SPIM_CROSS_DOMAIN_SUPPORTED
774+
if (dev_config->cross_domain && spim_has_cross_domain_connection(dev_config)) {
775+
#if SPIM_CROSS_DOMAIN_PINS_HANDLE
776+
int err;
777+
778+
err = nrf_sys_event_request_global_constlat();
779+
(void)err;
780+
__ASSERT_NO_MSG(err >= 0);
781+
#else
782+
__ASSERT(false, "NRF_SYS_EVENT needs to be enabled to use cross domain pins.\n");
783+
#endif
784+
}
785+
#endif
699786

700787
(void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP);
701788
}
@@ -753,15 +840,7 @@ static int spi_nrfx_init(const struct device *dev)
753840
#endif
754841
return pm_device_driver_init(dev, spim_nrfx_pm_action);
755842
}
756-
/*
757-
* We use NODELABEL here because the nrfx API requires us to call
758-
* functions which are named according to SoC peripheral instance
759-
* being operated on. Since DT_INST() makes no guarantees about that,
760-
* it won't work.
761-
*/
762-
#define SPIM(idx) DT_NODELABEL(spi##idx)
763-
#define SPIM_PROP(idx, prop) DT_PROP(SPIM(idx), prop)
764-
#define SPIM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(SPIM(idx), prop)
843+
765844
#define SPIM_MEM_REGION(idx) DT_PHANDLE(SPIM(idx), memory_regions)
766845

767846
#define SPI_NRFX_SPIM_EXTENDED_CONFIG(idx) \
@@ -853,6 +932,11 @@ static int spi_nrfx_init(const struct device *dev)
853932
.clk_spec = { \
854933
.frequency = NRF_CLOCK_CONTROL_FREQUENCY_MAX, \
855934
},)) \
935+
IF_ENABLED(SPIM_PINS_CROSS_DOMAIN(_, /*empty*/, idx, _), \
936+
(.cross_domain = true, \
937+
.default_port = \
938+
DT_PROP_OR(DT_PHANDLE(SPIM(idx), \
939+
default_gpio_port), port, -1),)) \
856940
}; \
857941
BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \
858942
!(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\

drivers/spi/spi_nrfx_spis.c

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,38 @@ LOG_MODULE_REGISTER(spi_nrfx_spis, CONFIG_SPI_LOG_LEVEL);
3636
BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED));
3737
#endif
3838

39+
/*
40+
* Current factors requiring use of DT_NODELABEL:
41+
*
42+
* - HAL design (requirement of drv_inst_idx in nrfx_spis_t)
43+
* - Name-based HAL IRQ handlers, e.g. nrfx_spis_0_irq_handler
44+
*/
45+
#define SPIS_NODE(idx) COND_CODE_1(SPIS_IS_FAST(idx), (spis##idx), (spi##idx))
46+
#define SPIS(idx) DT_NODELABEL(SPIS_NODE(idx))
47+
#define SPIS_PROP(idx, prop) DT_PROP(SPIS(idx), prop)
48+
#define SPIS_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(SPIS(idx), prop)
49+
50+
#define SPIS_PINS_CROSS_DOMAIN(unused, prefix, idx, _) \
51+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(SPIS(prefix##idx)), \
52+
(SPIS_PROP(idx, cross_domain_pins_supported)), \
53+
(0))
54+
55+
#if NRFX_FOREACH_PRESENT(SPIS, SPIS_PINS_CROSS_DOMAIN, (||), (0))
56+
#include <hal/nrf_gpio.h>
57+
/* Certain SPIM instances support usage of cross domain pins in form of dedicated pins on
58+
* a port different from the default one.
59+
*/
60+
#define SPIS_CROSS_DOMAIN_SUPPORTED 1
61+
#endif
62+
63+
#if SPIS_CROSS_DOMAIN_SUPPORTED && defined(CONFIG_NRF_SYS_EVENT)
64+
#include <nrf_sys_event.h>
65+
/* To use cross domain pins, constant latency mode needs to be applied, which is
66+
* handled via nrf_sys_event requests.
67+
*/
68+
#define SPIS_CROSS_DOMAIN_PINS_HANDLE 1
69+
#endif
70+
3971
struct spi_nrfx_data {
4072
struct spi_context ctx;
4173
const struct device *dev;
@@ -58,8 +90,37 @@ struct spi_nrfx_config {
5890
const struct pinctrl_dev_config *pcfg;
5991
struct gpio_dt_spec wake_gpio;
6092
void *mem_reg;
93+
#if SPIS_CROSS_DOMAIN_SUPPORTED
94+
bool cross_domain;
95+
int8_t default_port;
96+
#endif
6197
};
6298

99+
#if SPIS_CROSS_DOMAIN_SUPPORTED
100+
static bool spis_has_cross_domain_connection(const struct spi_nrfx_config *config)
101+
{
102+
const struct pinctrl_dev_config *pcfg = config->pcfg;
103+
const struct pinctrl_state *state;
104+
int ret;
105+
106+
ret = pinctrl_lookup_state(pcfg, PINCTRL_STATE_DEFAULT, &state);
107+
if (ret < 0) {
108+
LOG_ERR("Unable to read pin state");
109+
return false;
110+
}
111+
112+
for (uint8_t i = 0U; i < state->pin_cnt; i++) {
113+
uint32_t pin = NRF_GET_PIN(state->pins[i]);
114+
115+
if (nrf_gpio_pin_port_number_extract(&pin) != config->default_port) {
116+
return true;
117+
}
118+
}
119+
120+
return false;
121+
}
122+
#endif
123+
63124
static inline nrf_spis_mode_t get_nrf_spis_mode(uint16_t operation)
64125
{
65126
if (SPI_MODE_GET(operation) & SPI_MODE_CPOL) {
@@ -384,6 +445,19 @@ static void spi_nrfx_suspend(const struct device *dev)
384445
nrf_gpd_retain_pins_set(dev_config->pcfg, true);
385446
}
386447
#endif
448+
#if SPIS_CROSS_DOMAIN_SUPPORTED
449+
if (dev_config->cross_domain && spis_has_cross_domain_connection(dev_config)) {
450+
#if SPIS_CROSS_DOMAIN_PINS_HANDLE
451+
int err;
452+
453+
err = nrf_sys_event_request_global_constlat();
454+
(void)err;
455+
__ASSERT_NO_MSG(err >= 0);
456+
#else
457+
__ASSERT(false, "NRF_SYS_EVENT needs to be enabled to use cross domain pins.\n");
458+
#endif
459+
}
460+
#endif
387461

388462
(void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP);
389463
}
@@ -399,6 +473,19 @@ static void spi_nrfx_resume(const struct device *dev)
399473
nrf_gpd_retain_pins_set(dev_config->pcfg, false);
400474
}
401475
#endif
476+
#if SPIS_CROSS_DOMAIN_SUPPORTED
477+
if (dev_config->cross_domain && spis_has_cross_domain_connection(dev_config)) {
478+
#if SPIS_CROSS_DOMAIN_PINS_HANDLE
479+
int err;
480+
481+
err = nrf_sys_event_request_global_constlat();
482+
(void)err;
483+
__ASSERT_NO_MSG(err >= 0);
484+
#else
485+
__ASSERT(false, "NRF_SYS_EVENT needs to be enabled to use cross domain pins.\n");
486+
#endif
487+
}
488+
#endif
402489

403490
if (dev_config->wake_gpio.port == NULL) {
404491
nrf_spis_enable(dev_config->spis.p_reg);
@@ -482,19 +569,6 @@ static int spi_nrfx_init(const struct device *dev)
482569
return pm_device_driver_init(dev, spi_nrfx_pm_action);
483570
}
484571

485-
/*
486-
* Current factors requiring use of DT_NODELABEL:
487-
*
488-
* - HAL design (requirement of drv_inst_idx in nrfx_spis_t)
489-
* - Name-based HAL IRQ handlers, e.g. nrfx_spis_0_irq_handler
490-
*/
491-
492-
#define SPIS_NODE(idx) COND_CODE_1(SPIS_IS_FAST(idx), (spis##idx), (spi##idx))
493-
494-
#define SPIS(idx) DT_NODELABEL(SPIS_NODE(idx))
495-
496-
#define SPIS_PROP(idx, prop) DT_PROP(SPIS(idx), prop)
497-
498572
#define SPI_NRFX_SPIS_DEFINE(idx) \
499573
static void irq_connect##idx(void) \
500574
{ \
@@ -533,6 +607,11 @@ static int spi_nrfx_init(const struct device *dev)
533607
NRFX_MHZ_TO_HZ(16UL),)) \
534608
.wake_gpio = GPIO_DT_SPEC_GET_OR(SPIS(idx), wake_gpios, {0}), \
535609
.mem_reg = DMM_DEV_TO_REG(SPIS(idx)), \
610+
IF_ENABLED(SPIS_PINS_CROSS_DOMAIN(_, /*empty*/, idx, _), \
611+
(.cross_domain = true, \
612+
.default_port = \
613+
DT_PROP_OR(DT_PHANDLE(SPIS(idx), \
614+
default_gpio_port), port, -1),)) \
536615
}; \
537616
BUILD_ASSERT(!DT_NODE_HAS_PROP(SPIS(idx), wake_gpios) || \
538617
!(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+
default-gpio-port:
66+
type: phandle
67+
description: |
68+
SPI default GPIO port.
69+
70+
cross-domain-pins-supported:
71+
type: boolean
72+
description: |
73+
SPI allows usage of cross domain pins with constant latency mode required.

dts/common/nordic/nrf54l_05_10_15.dtsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@
312312
rx-delay-supported;
313313
rx-delay = <1>;
314314
status = "disabled";
315+
default-gpio-port = <&gpio1>;
316+
cross-domain-pins-supported;
315317
};
316318

317319
uart20: uart@c6000 {
@@ -353,6 +355,8 @@
353355
rx-delay-supported;
354356
rx-delay = <1>;
355357
status = "disabled";
358+
default-gpio-port = <&gpio1>;
359+
cross-domain-pins-supported;
356360
};
357361

358362
uart21: uart@c7000 {

0 commit comments

Comments
 (0)