-
Notifications
You must be signed in to change notification settings - Fork 8.4k
soc: nrf54h20: fix some power consumption issues by managing GD domains on certain scenarios #80291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9b9a68f
f2aac02
07d139b
1540ad9
0348a75
44de2ce
3c6a591
574929e
8f4e1bc
261c7f3
b109023
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
@@ -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) | ||
|
|
@@ -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) { | ||
|
||
| 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; | ||
|
|
@@ -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) { | ||
|
|
@@ -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 | ||
|
|
@@ -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; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -162,7 +226,8 @@ | |
| } | ||
|
|
||
| if (err != NRFX_SUCCESS) { | ||
| return -EINVAL; | ||
| ret = -EINVAL; | ||
| goto end; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -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, | ||
|
|
@@ -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, | ||
|
|
@@ -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 | ||
|
|
@@ -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 = { \ | ||
|
|
@@ -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; \ | ||
|
|
@@ -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
|
||
| DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE) | ||
| 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 |
There was a problem hiding this comment.
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
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?