Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 108 additions & 8 deletions drivers/gpio/gpio_nrfx.c
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to figure out the power domain management required for the input pins.

It seems that gpio_nrfx_pin_interrupt_configure() should be enhanced:

If the

if (!(BIT(pin) & cfg->edge_sense) &&
	    (mode == GPIO_INT_MODE_EDGE) &&
	    (nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT))

is met and the driver uses event IN, the relevant power domain should be kept powered up (nrf_gpd_request()). Alternatively, if the driver uses event SENSE, the GPIO.RETAIN should be applied to the pin (cfg->port->RETAINSET = mask).

However, I'm not sure in which procedure this configuration should be cleared. @nordic-krch, could you help to identify the correct place?

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

#include <zephyr/drivers/gpio/gpio_utils.h>

#ifdef CONFIG_SOC_NRF54H20_GPD
#include <nrf/gpd.h>
#endif

struct gpio_nrfx_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data common;
Expand All @@ -27,6 +31,9 @@
uint32_t edge_sense;
uint8_t port_num;
nrfx_gpiote_t gpiote;
#ifdef CONFIG_SOC_NRF54H20_GPD
uint8_t pad_pd;
#endif
};

static inline struct gpio_nrfx_data *get_port_data(const struct device *port)
Expand Down Expand Up @@ -55,9 +62,59 @@
return NRF_GPIO_PIN_NOPULL;
}

static int gpio_nrfx_gpd_retain_set(const struct device *port, uint32_t mask, gpio_flags_t flags)
{
#ifdef CONFIG_SOC_NRF54H20_GPD
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);

if (cfg->pad_pd == NRF_GPD_FAST_ACTIVE1) {
int ret;

if (flags & GPIO_OUTPUT) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be safe to use RETAIN as well on input pins and avoid the special case here. @hubertmis?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how RETAIN works with input pins. It's safer to apply it to output for now. We can figure out later how to correctly handle input

cfg->port->RETAINSET = mask;
}

ret = nrf_gpd_release(NRF_GPD_FAST_ACTIVE1);
if (ret < 0) {
return ret;
}
}
#else
ARG_UNUSED(port);
ARG_UNUSED(mask);
ARG_UNUSED(flags);
#endif

return 0;
}

static int gpio_nrfx_gpd_retain_clear(const struct device *port, uint32_t mask)
{
#ifdef CONFIG_SOC_NRF54H20_GPD
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);

if (cfg->pad_pd == NRF_GPD_FAST_ACTIVE1) {
int ret;

ret = nrf_gpd_request(NRF_GPD_FAST_ACTIVE1);
if (ret < 0) {
return ret;
}

cfg->port->RETAINCLR = mask;
}
#else
ARG_UNUSED(port);
ARG_UNUSED(mask);
#endif

return 0;
}

static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
gpio_flags_t flags)
{
int ret = 0;
nrfx_err_t err = NRFX_SUCCESS;
uint8_t ch;
bool free_ch = false;
Expand Down Expand Up @@ -95,6 +152,11 @@
return -EINVAL;
}

ret = gpio_nrfx_gpd_retain_clear(port, BIT(pin));
if (ret < 0) {
return ret;
}

if (flags & GPIO_OUTPUT_INIT_HIGH) {
nrf_gpio_port_out_set(cfg->port, BIT(pin));
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
Expand All @@ -110,7 +172,8 @@
: NRF_GPIO_PIN_INPUT_DISCONNECT;

nrf_gpio_reconfigure(abs_pin, &dir, &input, &pull, &drive, NULL);
return 0;

goto end;
}

/* Get the GPIOTE channel associated with this pin, if any. It needs
Expand All @@ -137,7 +200,8 @@
err = nrfx_gpiote_input_configure(&cfg->gpiote,
abs_pin, &input_pin_config);
if (err != NRFX_SUCCESS) {
return -EINVAL;
ret = -EINVAL;
goto end;
}
}

Expand All @@ -162,7 +226,8 @@
}

if (err != NRFX_SUCCESS) {
return -EINVAL;
ret = -EINVAL;
goto end;
}
}

Expand All @@ -171,7 +236,9 @@
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
}

return 0;
end:
(void)gpio_nrfx_gpd_retain_set(port, BIT(pin), flags);
return ret;
}

static int gpio_nrfx_port_get_raw(const struct device *port,
Expand All @@ -189,34 +256,52 @@
gpio_port_value_t value)
{
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;

const uint32_t set_mask = value & mask;
const uint32_t clear_mask = (~set_mask) & mask;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}

nrf_gpio_port_out_set(reg, set_mask);
nrf_gpio_port_out_clear(reg, clear_mask);

return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}

static int gpio_nrfx_port_set_bits_raw(const struct device *port,
gpio_port_pins_t mask)
{
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}

nrf_gpio_port_out_set(reg, mask);

return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}

static int gpio_nrfx_port_clear_bits_raw(const struct device *port,
gpio_port_pins_t mask)
{
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}

nrf_gpio_port_out_clear(reg, mask);

return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}

static int gpio_nrfx_port_toggle_bits(const struct device *port,
Expand All @@ -226,11 +311,17 @@
const uint32_t value = nrf_gpio_port_out_read(reg) ^ mask;
const uint32_t set_mask = value & mask;
const uint32_t clear_mask = (~value) & mask;
int ret;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}

nrf_gpio_port_out_set(reg, set_mask);
nrf_gpio_port_out_clear(reg, clear_mask);

return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}

#ifdef CONFIG_GPIO_NRFX_INTERRUPT
Expand Down Expand Up @@ -450,6 +541,14 @@
"Please enable GPIOTE instance for used GPIO port!")), \
())

#ifdef CONFIG_SOC_NRF54H20_GPD
#define PAD_PD(inst) \
.pad_pd = DT_INST_PHA_BY_NAME_OR(inst, power_domains, pad, id, \
NRF_GPD_SLOW_MAIN),
#else
#define PAD_PD(inst)
#endif

#define GPIO_NRF_DEVICE(id) \
GPIOTE_CHECK(id); \
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
Expand All @@ -461,6 +560,7 @@
.port_num = DT_INST_PROP(id, port), \
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
.gpiote = GPIOTE_INSTANCE(id), \
PAD_PD(id) \
}; \
\
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
Expand All @@ -472,5 +572,5 @@
PRE_KERNEL_1, \
CONFIG_GPIO_INIT_PRIORITY, \
&gpio_nrfx_drv_api_funcs);

Check notice on line 575 in drivers/gpio/gpio_nrfx.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/gpio/gpio_nrfx.c:575 -#define PAD_PD(inst) \ - .pad_pd = DT_INST_PHA_BY_NAME_OR(inst, power_domains, pad, id, \ - NRF_GPD_SLOW_MAIN), +#define PAD_PD(inst) \ + .pad_pd = DT_INST_PHA_BY_NAME_OR(inst, power_domains, pad, id, NRF_GPD_SLOW_MAIN), #else #define PAD_PD(inst) #endif -#define GPIO_NRF_DEVICE(id) \ - GPIOTE_CHECK(id); \ - static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \ - .common = { \ - .port_pin_mask = \ - GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \ - }, \ - .port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \ - .port_num = DT_INST_PROP(id, port), \ - .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \ - .gpiote = GPIOTE_INSTANCE(id), \ - PAD_PD(id) \ - }; \ - \ - static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \ - \ - DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \ - NULL, \ - &gpio_nrfx_p##id##_data, \ - &gpio_nrfx_p##id##_cfg, \ - PRE_KERNEL_1, \ - CONFIG_GPIO_INIT_PRIORITY, \ - &gpio_nrfx_drv_api_funcs); +#define GPIO_NRF_DEVICE(id) \ + GPIOTE_CHECK(id); \ + static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \ + }, \ + .port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \ + .port_num = DT_INST_PROP(id, port), \ + .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \ + .gpiote = GPIOTE_INSTANCE(id), \ + PAD_PD(id)}; \ + \ + static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \ + \ + DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, NULL, &gpio_nrfx_p##id##_data, \ + &gpio_nrfx_p##id##_cfg, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_nrfx_drv_api_funcs);
DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)
32 changes: 32 additions & 0 deletions drivers/pinctrl/pinctrl_nrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <zephyr/drivers/pinctrl.h>

#include <hal/nrf_gpio.h>
#ifdef CONFIG_SOC_NRF54H20_GPD
#include <nrf/gpd.h>
#endif

BUILD_ASSERT(((NRF_PULL_NONE == NRF_GPIO_PIN_NOPULL) &&
(NRF_PULL_DOWN == NRF_GPIO_PIN_PULLDOWN) &&
Expand Down Expand Up @@ -352,6 +355,21 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
if (psel != PSEL_DISCONNECTED) {
uint32_t pin = psel;

#ifdef CONFIG_SOC_NRF54H20_GPD
if (NRF_GET_GPD_FAST_ACTIVE1(pins[i]) == 1U) {
int ret;
uint32_t d_pin = pin;
NRF_GPIO_Type *port = nrf_gpio_pin_port_decode(&d_pin);

ret = nrf_gpd_request(NRF_GPD_SLOW_ACTIVE);
if (ret < 0) {
return ret;
}

port->RETAINCLR = BIT(d_pin);
}
#endif /* CONFIG_SOC_NRF54H20_GPD */

if (write != NO_WRITE) {
nrf_gpio_pin_write(pin, write);
}
Expand All @@ -367,6 +385,20 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
#if NRF_GPIO_HAS_CLOCKPIN
nrf_gpio_pin_clock_set(pin, NRF_GET_CLOCKPIN_ENABLE(pins[i]));
#endif
#ifdef CONFIG_SOC_NRF54H20_GPD
if (NRF_GET_GPD_FAST_ACTIVE1(pins[i]) == 1U) {
int ret;
uint32_t d_pin = pin;
NRF_GPIO_Type *port = nrf_gpio_pin_port_decode(&d_pin);

port->RETAINSET = BIT(d_pin);

ret = nrf_gpd_release(NRF_GPD_SLOW_ACTIVE);
if (ret < 0) {
return ret;
}
}
#endif /* CONFIG_SOC_NRF54H20_GPD */
}
}

Expand Down
12 changes: 12 additions & 0 deletions drivers/serial/uart_nrfx_uarte.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
#include <zephyr/linker/devicetree_regions.h>
#include <zephyr/irq.h>
#include <zephyr/logging/log.h>

#ifdef CONFIG_SOC_NRF54H20_GPD
#include <nrf/gpd.h>
#endif

LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL);

#if !defined(CONFIG_ARCH_POSIX)
Expand Down Expand Up @@ -2098,6 +2103,9 @@ static void uarte_pm_resume(const struct device *dev)

if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) || !LOW_POWER_ENABLED(cfg)) {
uarte_periph_enable(dev);
#ifdef CONFIG_SOC_NRF54H20_GPD
nrf_gpd_retain_pins_set(cfg->pcfg, false);
#endif
}
}

Expand Down Expand Up @@ -2160,6 +2168,10 @@ static void uarte_pm_suspend(const struct device *dev)
wait_for_tx_stopped(dev);
}

#ifdef CONFIG_SOC_NRF54H20_GPD
nrf_gpd_retain_pins_set(cfg->pcfg, true);
#endif

nrf_uarte_disable(uarte);

(void)pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP);
Expand Down
11 changes: 11 additions & 0 deletions dts/bindings/power/nordic,nrf-gpd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: Nordic nRF Global Power Domain

compatible: "nordic,nrf-gpd"

include: base.yaml

power-domain-cells:
- id
Loading
Loading