diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 151cf1a830c5c..d9eb9129937bf 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -14,6 +14,10 @@ #include +#ifdef CONFIG_SOC_NRF54H20_GPD +#include +#endif + struct gpio_nrfx_data { /* gpio_driver_data needs to be first */ struct gpio_driver_data common; @@ -27,6 +31,9 @@ struct gpio_nrfx_cfg { 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 @@ static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) 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 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, 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 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, : 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 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, 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 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, } if (err != NRFX_SUCCESS) { - return -EINVAL; + ret = -EINVAL; + goto end; } } @@ -171,7 +236,9 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, __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 @@ static int gpio_nrfx_port_set_masked_raw(const struct device *port, 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 @@ static int gpio_nrfx_port_toggle_bits(const struct device *port, 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 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { "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 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { .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; \ diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index 7c6d83020bf8a..1e80de8fe67c3 100644 --- a/drivers/pinctrl/pinctrl_nrf.c +++ b/drivers/pinctrl/pinctrl_nrf.c @@ -7,6 +7,9 @@ #include #include +#ifdef CONFIG_SOC_NRF54H20_GPD +#include +#endif BUILD_ASSERT(((NRF_PULL_NONE == NRF_GPIO_PIN_NOPULL) && (NRF_PULL_DOWN == NRF_GPIO_PIN_PULLDOWN) && @@ -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); } @@ -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 */ } } diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 5c19485946c4e..e1af63b7993e7 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -23,6 +23,11 @@ #include #include #include + +#ifdef CONFIG_SOC_NRF54H20_GPD +#include +#endif + LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #if !defined(CONFIG_ARCH_POSIX) @@ -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 } } @@ -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); diff --git a/dts/bindings/power/nordic,nrf-gpd.yaml b/dts/bindings/power/nordic,nrf-gpd.yaml new file mode 100644 index 0000000000000..feb5f2862e913 --- /dev/null +++ b/dts/bindings/power/nordic,nrf-gpd.yaml @@ -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 diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index 92a4880cf1795..8da783386865b 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -13,6 +13,7 @@ #include #include #include +#include /delete-node/ &sw_pwm; @@ -194,6 +195,11 @@ }; }; + gpd: global-power-domain { + compatible = "nordic,nrf-gpd"; + #power-domain-cells = <1>; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -201,6 +207,7 @@ mram1x: mram@e000000 { compatible = "nordic,mram"; reg = <0xe000000 DT_SIZE_K(2048)>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; erase-block-size = <4096>; write-block-size = <16>; }; @@ -477,6 +484,7 @@ reg = <0x86000 0x1000>, <0x2f700000 0x40000>; reg-names = "wrapper", "core"; interrupts = <134 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; num-in-eps = <8>; num-out-eps = <10>; ghwcfg1 = <0xaa555000>; @@ -492,6 +500,7 @@ reg = <0x95000 0x500 0x95500 0xb00>; reg-names = "wrapper", "core"; interrupts = <149 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; clock-frequency = ; fifo-depth = <32>; max-xfer-size = <16>; @@ -501,18 +510,21 @@ cpusec_bellboard: mailbox@99000 { reg = <0x99000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; #mbox-cells = <1>; }; cpuapp_bellboard: mailbox@9a000 { reg = <0x9a000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; #mbox-cells = <1>; }; cpurad_bellboard: mailbox@9b000 { reg = <0x9b000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; #mbox-cells = <1>; }; @@ -553,6 +565,7 @@ compatible = "nordic,nrf-vpr-coprocessor"; reg = <0x8d4000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x8d4000 0x1000>; @@ -573,6 +586,7 @@ reg-names = "wrapper", "m_can", "message_ram"; interrupts = <216 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&canpll>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; status = "disabled"; }; @@ -581,6 +595,7 @@ compatible = "nordic,nrf-dppic-global"; reg = <0x8e1000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; }; timer120: timer@8e2000 { @@ -589,6 +604,7 @@ status = "disabled"; cc-num = <6>; interrupts = <226 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; max-bit-width = <32>; max-frequency = ; prescaler = <0>; @@ -600,6 +616,7 @@ status = "disabled"; cc-num = <6>; interrupts = <227 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; max-bit-width = <32>; max-frequency = ; prescaler = <0>; @@ -610,6 +627,7 @@ reg = <0x8e4000 0x1000>; status = "disabled"; interrupts = <228 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; #pwm-cells = <3>; }; @@ -617,6 +635,7 @@ compatible = "nordic,nrf-spim"; reg = <0x8e6000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; easydma-maxcnt-bits = <15>; interrupts = <230 NRF_DEFAULT_IRQ_PRIORITY>; max-frequency = ; @@ -634,6 +653,7 @@ status = "disabled"; interrupts = <230 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&hsfll120>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; endtx-stoptx-supported; frame-timeout-supported; }; @@ -644,6 +664,7 @@ status = "disabled"; easydma-maxcnt-bits = <15>; interrupts = <231 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -660,6 +681,7 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x908000 0x1000>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; cpuppr_vevif_tx: mailbox@0 { compatible = "nordic,nrf-vevif-task-tx"; @@ -675,6 +697,7 @@ compatible = "nordic,nrf-ipct-global"; reg = <0x921000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; channels = <8>; global-domain-id = <13>; }; @@ -683,6 +706,7 @@ compatible = "nordic,nrf-dppic-global"; reg = <0x922000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; }; rtc130: rtc@928000 { @@ -692,6 +716,7 @@ cc-num = <4>; clock-frequency = <32768>; interrupts = <296 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; clocks = <&lfclk>; prescaler = <1>; }; @@ -703,6 +728,7 @@ cc-num = <4>; clock-frequency = <32768>; interrupts = <297 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; clocks = <&lfclk>; prescaler = <1>; }; @@ -713,6 +739,7 @@ status = "disabled"; interrupts = <299 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&lfclk>; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; }; wdt132: watchdog@92c000 { @@ -721,6 +748,7 @@ status = "disabled"; interrupts = <300 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&lfclk>; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; }; egu130: egu@92d000 { @@ -728,12 +756,14 @@ reg = <0x92d000 0x1000>; status = "disabled"; interrupts = <301 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; }; gpiote130: gpiote@934000 { compatible = "nordic,nrf-gpiote"; reg = <0x934000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; instance = <130>; }; @@ -743,6 +773,7 @@ status = "disabled"; #gpio-cells = <2>; gpio-controller; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; gpiote-instance = <&gpiote130>; ngpios = <12>; port = <0>; @@ -754,6 +785,7 @@ status = "disabled"; #gpio-cells = <2>; gpio-controller; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; gpiote-instance = <&gpiote130>; ngpios = <12>; port = <1>; @@ -765,6 +797,7 @@ status = "disabled"; #gpio-cells = <2>; gpio-controller; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; gpiote-instance = <&gpiote130>; ngpios = <12>; port = <2>; @@ -776,6 +809,9 @@ status = "disabled"; #gpio-cells = <2>; gpio-controller; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>, + <&gpd NRF_GPD_FAST_ACTIVE1>; + power-domain-names = "peripheral", "pad"; ngpios = <14>; port = <6>; }; @@ -786,6 +822,9 @@ status = "disabled"; #gpio-cells = <2>; gpio-controller; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>, + <&gpd NRF_GPD_FAST_ACTIVE1>; + power-domain-names = "peripheral", "pad"; ngpios = <8>; port = <7>; }; @@ -796,6 +835,7 @@ status = "disabled"; #gpio-cells = <2>; gpio-controller; + power-domains = <&gpd NRF_GPD_SLOW_MAIN>; gpiote-instance = <&gpiote130>; ngpios = <6>; port = <9>; @@ -805,6 +845,7 @@ compatible = "nordic,nrf-dppic-global"; reg = <0x981000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; adc: adc@982000 { @@ -813,6 +854,7 @@ interrupts = <386 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; comp: comparator@983000 { @@ -824,6 +866,7 @@ reg = <0x983000 0x1000>; status = "disabled"; interrupts = <387 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; temp: temperature-sensor@984000 { @@ -831,6 +874,7 @@ reg = <0x984000 0x1000>; interrupts = <388 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; nfct: nfct@985000 { @@ -838,12 +882,14 @@ reg = <0x985000 0x1000>; status = "disabled"; interrupts = <389 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; dppic132: dppic@991000 { compatible = "nordic,nrf-dppic-global"; reg = <0x991000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; qdec130: qdec@994000 { @@ -851,6 +897,7 @@ reg = <0x994000 0x1000>; status = "disabled"; interrupts = <404 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; qdec131: qdec@995000 { @@ -858,6 +905,7 @@ reg = <0x995000 0x1000>; status = "disabled"; interrupts = <405 NRF_DEFAULT_IRQ_PRIORITY>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; grtc: grtc@99c000 { @@ -870,12 +918,14 @@ * one is linked here. */ clocks = <&lfclk>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; dppic133: dppic@9a1000 { compatible = "nordic,nrf-dppic-global"; reg = <0x9a1000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; timer130: timer@9a2000 { @@ -885,6 +935,7 @@ cc-num = <6>; interrupts = <418 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -896,6 +947,7 @@ cc-num = <6>; interrupts = <419 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -906,6 +958,7 @@ status = "disabled"; interrupts = <420 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; #pwm-cells = <3>; }; @@ -915,6 +968,7 @@ status = "disabled"; interrupts = <421 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -930,6 +984,7 @@ easydma-maxcnt-bits = <15>; interrupts = <421 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -947,6 +1002,7 @@ status = "disabled"; interrupts = <421 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -958,6 +1014,7 @@ status = "disabled"; interrupts = <422 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -973,6 +1030,7 @@ easydma-maxcnt-bits = <15>; interrupts = <422 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -990,6 +1048,7 @@ status = "disabled"; interrupts = <422 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -999,6 +1058,7 @@ compatible = "nordic,nrf-dppic-global"; reg = <0x9b1000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; timer132: timer@9b2000 { @@ -1008,6 +1068,7 @@ cc-num = <6>; interrupts = <434 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -1019,6 +1080,7 @@ cc-num = <6>; interrupts = <435 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -1029,6 +1091,7 @@ status = "disabled"; interrupts = <436 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; #pwm-cells = <3>; }; @@ -1038,6 +1101,7 @@ status = "disabled"; interrupts = <437 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -1053,6 +1117,7 @@ easydma-maxcnt-bits = <15>; interrupts = <437 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -1070,6 +1135,7 @@ status = "disabled"; interrupts = <437 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -1081,6 +1147,7 @@ status = "disabled"; interrupts = <438 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -1096,6 +1163,7 @@ easydma-maxcnt-bits = <15>; interrupts = <438 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -1113,6 +1181,7 @@ status = "disabled"; interrupts = <438 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -1122,6 +1191,7 @@ compatible = "nordic,nrf-dppic-global"; reg = <0x9c1000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; timer134: timer@9c2000 { @@ -1131,6 +1201,7 @@ cc-num = <6>; interrupts = <450 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -1142,6 +1213,7 @@ cc-num = <6>; interrupts = <451 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -1153,6 +1225,7 @@ interrupts = <452 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; #pwm-cells = <3>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; i2c134: i2c@9c5000 { @@ -1161,6 +1234,7 @@ status = "disabled"; interrupts = <453 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -1176,6 +1250,7 @@ easydma-maxcnt-bits = <15>; interrupts = <453 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -1193,6 +1268,7 @@ status = "disabled"; interrupts = <453 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -1204,6 +1280,7 @@ status = "disabled"; interrupts = <454 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -1219,6 +1296,7 @@ easydma-maxcnt-bits = <15>; interrupts = <454 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -1236,6 +1314,7 @@ status = "disabled"; interrupts = <454 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -1245,6 +1324,7 @@ compatible = "nordic,nrf-dppic-global"; reg = <0x9d1000 0x1000>; status = "disabled"; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; timer136: timer@9d2000 { @@ -1254,6 +1334,7 @@ cc-num = <6>; interrupts = <466 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -1265,6 +1346,7 @@ cc-num = <6>; interrupts = <467 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-bit-width = <32>; prescaler = <0>; }; @@ -1276,6 +1358,7 @@ interrupts = <468 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; #pwm-cells = <3>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; }; i2c136: i2c@9d5000 { @@ -1284,6 +1367,7 @@ status = "disabled"; interrupts = <469 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -1299,6 +1383,7 @@ easydma-maxcnt-bits = <15>; interrupts = <469 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -1316,6 +1401,7 @@ status = "disabled"; interrupts = <469 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; @@ -1327,6 +1413,7 @@ status = "disabled"; interrupts = <470 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; easydma-maxcnt-bits = <15>; #address-cells = <1>; #size-cells = <0>; @@ -1342,6 +1429,7 @@ easydma-maxcnt-bits = <15>; interrupts = <470 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; max-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -1359,6 +1447,7 @@ status = "disabled"; interrupts = <470 NRF_DEFAULT_IRQ_PRIORITY>; clocks = <&fll16m>; + power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; nordic,clockpin-enable = ; endtx-stoptx-supported; frame-timeout-supported; diff --git a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h index 7afa678381431..4611baef95c2b 100644 --- a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h @@ -10,7 +10,9 @@ * The whole nRF pin configuration information is encoded in a 32-bit bitfield * organized as follows: * - * - 31..18: Pin function. + * - 31..24: Pin function. + * - 19-23: Reserved. + * - 18: Associated peripheral belongs to GD FAST ACTIVE1 (nRF54H only) * - 17: Clockpin enable. * - 16: Pin inversion mode. * - 15: Pin low power mode. @@ -25,9 +27,13 @@ */ /** Position of the function field. */ -#define NRF_FUN_POS 18U +#define NRF_FUN_POS 24U /** Mask for the function field. */ -#define NRF_FUN_MSK 0x3FFFU +#define NRF_FUN_MSK 0xFFU +/** Position of the GPD FAST ACTIVE1 */ +#define NRF_GPD_FAST_ACTIVE1_POS 18U +/** Mask for the GPD FAST ACTIVE1 */ +#define NRF_GPD_FAST_ACTIVE1_MSK 0x1U /** Position of the clockpin enable field. */ #define NRF_CLOCKPIN_ENABLE_POS 17U /** Mask for the clockpin enable field. */ diff --git a/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h b/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h new file mode 100644 index 0000000000000..7f6952f6f0bcb --- /dev/null +++ b/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_POWER_NORDIC_NRF_GLOBAL_PD +#define ZEPHYR_INCLUDE_DT_BINDINGS_POWER_NORDIC_NRF_GLOBAL_PD + +/* numbers aligned to nrfs service identifiers */ +#define NRF_GPD_SLOW_MAIN 2U +#define NRF_GPD_SLOW_ACTIVE 1U +#define NRF_GPD_FAST_MAIN 3U +#define NRF_GPD_FAST_ACTIVE1 0U +#define NRF_GPD_FAST_ACTIVE0 4U + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_POWER_NORDIC_NRF_GLOBAL_PD */ diff --git a/modules/hal_nordic/CMakeLists.txt b/modules/hal_nordic/CMakeLists.txt index 9be36d4998d41..5209efdced978 100644 --- a/modules/hal_nordic/CMakeLists.txt +++ b/modules/hal_nordic/CMakeLists.txt @@ -12,7 +12,7 @@ if(CONFIG_NRF_REGTOOL_GENERATE_UICR) list(APPEND nrf_regtool_components GENERATE:UICR) endif() if(DEFINED nrf_regtool_components) - find_package(nrf-regtool 7.0.0 REQUIRED + find_package(nrf-regtool 8.0.0 COMPONENTS ${nrf_regtool_components} PATHS ${CMAKE_CURRENT_LIST_DIR}/nrf-regtool NO_CMAKE_PATH diff --git a/scripts/checkpatch/typedefsfile b/scripts/checkpatch/typedefsfile index 62febe44e1bd8..0fc22b9779b43 100644 --- a/scripts/checkpatch/typedefsfile +++ b/scripts/checkpatch/typedefsfile @@ -8,3 +8,4 @@ io_rw_32 \b[a-zA-Z_][a-zA-Z0-9_]*TypeDef Pwm FILE +NRF_GPIO_Type diff --git a/soc/nordic/common/pinctrl_soc.h b/soc/nordic/common/pinctrl_soc.h index ea0f0196e2b1b..f1d3b6357f97d 100644 --- a/soc/nordic/common/pinctrl_soc.h +++ b/soc/nordic/common/pinctrl_soc.h @@ -14,6 +14,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -55,6 +56,16 @@ typedef uint32_t pinctrl_soc_pin_t; (), NRF_GET_FUN(DT_PROP_BY_IDX(node_id, prop, idx))) \ 0)), (0)) +/** + * @brief Utility macro to get the GPD_FAST_ACTIVE1 flag + * + * @param p_node_id Parent node identifier. + */ +#define Z_GET_GPD_FAST_ACTIVE1(p_node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(p_node_id, power_domains), \ + ((DT_PHA(p_node_id, power_domains, id) == \ + NRF_GPD_FAST_ACTIVE1) << NRF_GPD_FAST_ACTIVE1_POS), (0)) + /** * @brief Utility macro to initialize each pin. * @@ -70,7 +81,8 @@ typedef uint32_t pinctrl_soc_pin_t; (DT_PROP(node_id, nordic_drive_mode) << NRF_DRIVE_POS) | \ ((NRF_LP_ENABLE * DT_PROP(node_id, low_power_enable)) << NRF_LP_POS) |\ (DT_PROP(node_id, nordic_invert) << NRF_INVERT_POS) | \ - Z_GET_CLOCKPIN_ENABLE(node_id, prop, idx, p_node_id) \ + Z_GET_CLOCKPIN_ENABLE(node_id, prop, idx, p_node_id) | \ + Z_GET_GPD_FAST_ACTIVE1(p_node_id) \ ), /** @@ -99,6 +111,14 @@ typedef uint32_t pinctrl_soc_pin_t; #define NRF_GET_CLOCKPIN_ENABLE(pincfg) \ (((pincfg) >> NRF_CLOCKPIN_ENABLE_POS) & NRF_CLOCKPIN_ENABLE_MSK) +/** + * @brief Utility macro to obtain GPD_FAST_ACTIVE1 flag + * + * @param pincfg Pin configuration bit field. + */ +#define NRF_GET_GPD_FAST_ACTIVE1(pincfg) \ + (((pincfg) >> NRF_GPD_FAST_ACTIVE1_POS) & NRF_GPD_FAST_ACTIVE1_MSK) + /** * @brief Utility macro to obtain pin inversion flag. * diff --git a/soc/nordic/nrf54h/CMakeLists.txt b/soc/nordic/nrf54h/CMakeLists.txt index 0496841ffe791..7edc4d43ea128 100644 --- a/soc/nordic/nrf54h/CMakeLists.txt +++ b/soc/nordic/nrf54h/CMakeLists.txt @@ -15,3 +15,5 @@ zephyr_include_directories(.) # Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes # for the image correctly zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld) + +add_subdirectory(gpd) diff --git a/soc/nordic/nrf54h/Kconfig b/soc/nordic/nrf54h/Kconfig index 9132ca8458b82..1b667e259853c 100644 --- a/soc/nordic/nrf54h/Kconfig +++ b/soc/nordic/nrf54h/Kconfig @@ -75,3 +75,5 @@ config SOC_NRF54H20_CPUFLPR config SOC_NRF54H20_ENGB_CPUFLPR depends on RISCV_CORE_NORDIC_VPR + +rsource "gpd/Kconfig" diff --git a/soc/nordic/nrf54h/Kconfig.defconfig b/soc/nordic/nrf54h/Kconfig.defconfig index b09b24e5e7040..65023fc18ca91 100644 --- a/soc/nordic/nrf54h/Kconfig.defconfig +++ b/soc/nordic/nrf54h/Kconfig.defconfig @@ -39,4 +39,7 @@ config SPI_DW_HSSI config SPI_DW_ACCESS_WORD_ONLY default y if SPI_DW +config PM_DEVICE_POWER_DOMAIN + default n if PM_DEVICE + endif # SOC_SERIES_NRF54HX diff --git a/soc/nordic/nrf54h/gpd/CMakeLists.txt b/soc/nordic/nrf54h/gpd/CMakeLists.txt new file mode 100644 index 0000000000000..7d029d2c8fcd3 --- /dev/null +++ b/soc/nordic/nrf54h/gpd/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_SOC_NRF54H20_GPD gpd.c) +zephyr_include_directories(include) diff --git a/soc/nordic/nrf54h/gpd/Kconfig b/soc/nordic/nrf54h/gpd/Kconfig new file mode 100644 index 0000000000000..b9bd568cda630 --- /dev/null +++ b/soc/nordic/nrf54h/gpd/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +config SOC_NRF54H20_GPD + bool "Global Power Domain service" + imply NRFS + imply NRFS_GDPWR_SERVICE_ENABLED + select ONOFF + default y if SOC_NRF54H20_CPUAPP || SOC_NRF54H20_ENGB_CPUAPP || \ + SOC_NRF54H20_CPURAD || SOC_NRF54H20_ENGB_CPURAD + help + This option enables the Global Power Domain service. diff --git a/soc/nordic/nrf54h/gpd/gpd.c b/soc/nordic/nrf54h/gpd/gpd.c new file mode 100644 index 0000000000000..ea439a5446034 --- /dev/null +++ b/soc/nordic/nrf54h/gpd/gpd.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(gpd, CONFIG_SOC_LOG_LEVEL); + +/* enforce alignment between DT<->nrfs */ +BUILD_ASSERT(GDPWR_POWER_DOMAIN_ACTIVE_FAST == NRF_GPD_FAST_ACTIVE1); +BUILD_ASSERT(GDPWR_POWER_DOMAIN_ACTIVE_SLOW == NRF_GPD_SLOW_ACTIVE); +BUILD_ASSERT(GDPWR_POWER_DOMAIN_MAIN_SLOW == NRF_GPD_SLOW_MAIN); + +struct gpd_onoff_manager { + struct onoff_manager mgr; + onoff_notify_fn notify; + uint8_t id; +}; + +static void start(struct onoff_manager *mgr, onoff_notify_fn notify); +static void stop(struct onoff_manager *mgr, onoff_notify_fn notify); + +#define GPD_READY_TIMEOUT_MS 1000 + +#define GPD_SERVICE_READY BIT(0) +#define GPD_SERVICE_ERROR BIT(1) +#define GPD_SERVICE_REQ_OK BIT(2) +#define GPD_SERVICE_REQ_ERR BIT(3) +static atomic_t gpd_service_status = ATOMIC_INIT(0); + +static struct gpd_onoff_manager fast_active1 = {.id = NRF_GPD_FAST_ACTIVE1}; +static struct gpd_onoff_manager slow_active = {.id = NRF_GPD_SLOW_ACTIVE}; +static struct gpd_onoff_manager slow_main = {.id = NRF_GPD_SLOW_MAIN}; + +static const struct onoff_transitions transitions = + ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL); + +static struct gpd_onoff_manager *get_mgr(uint8_t id) +{ + switch (id) { + case NRF_GPD_FAST_ACTIVE1: + return &fast_active1; + case NRF_GPD_SLOW_ACTIVE: + return &slow_active; + case NRF_GPD_SLOW_MAIN: + return &slow_main; + default: + return NULL; + } +} + +static int nrf_gpd_sync(struct gpd_onoff_manager *gpd_mgr) +{ + int64_t start; + nrfs_err_t err; + gdpwr_request_type_t request; + + K_SPINLOCK(&gpd_mgr->mgr.lock) { + if (gpd_mgr->mgr.refs == 0) { + request = GDPWR_POWER_REQUEST_CLEAR; + } else { + request = GDPWR_POWER_REQUEST_SET; + } + } + + atomic_clear_bit(&gpd_service_status, GPD_SERVICE_REQ_ERR); + atomic_clear_bit(&gpd_service_status, GPD_SERVICE_REQ_OK); + + err = nrfs_gdpwr_power_request(gpd_mgr->id, request, gpd_mgr); + if (err != NRFS_SUCCESS) { + return -EIO; + } + + start = k_uptime_get(); + while (k_uptime_get() - start < GPD_READY_TIMEOUT_MS) { + if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_REQ_ERR)) { + return -EIO; + } + + if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_REQ_OK)) { + return 0; + } + } + + LOG_ERR("nRFs GDPWR request timed out"); + + return -ETIMEDOUT; +} + +static void evt_handler(nrfs_gdpwr_evt_t const *p_evt, void *context) +{ + if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_READY)) { + struct gpd_onoff_manager *gpd_mgr = context; + + switch (p_evt->type) { + case NRFS_GDPWR_REQ_APPLIED: + gpd_mgr->notify(&gpd_mgr->mgr, 0); + break; + default: + LOG_ERR("nRFs GDPWR request not applied"); + gpd_mgr->notify(&gpd_mgr->mgr, -EIO); + break; + } + } else { + switch (p_evt->type) { + case NRFS_GDPWR_REQ_APPLIED: + atomic_set_bit(&gpd_service_status, GPD_SERVICE_REQ_OK); + break; + default: + LOG_ERR("nRFs GDPWR request not applied"); + atomic_set_bit(&gpd_service_status, GPD_SERVICE_REQ_ERR); + break; + } + } +} + +static void start(struct onoff_manager *mgr, onoff_notify_fn notify) +{ + struct gpd_onoff_manager *gpd_mgr = CONTAINER_OF(mgr, struct gpd_onoff_manager, mgr); + + gpd_mgr->notify = notify; + + if (!atomic_test_bit(&gpd_service_status, GPD_SERVICE_READY)) { + notify(mgr, 0); + } else { + nrfs_err_t err; + + err = nrfs_gdpwr_power_request(gpd_mgr->id, GDPWR_POWER_REQUEST_SET, gpd_mgr); + if (err != NRFS_SUCCESS) { + LOG_ERR("nRFs GDPWR request failed (%d)", err); + notify(mgr, -EIO); + } + } +} + +static void stop(struct onoff_manager *mgr, onoff_notify_fn notify) +{ + struct gpd_onoff_manager *gpd_mgr = CONTAINER_OF(mgr, struct gpd_onoff_manager, mgr); + + gpd_mgr->notify = notify; + + if (!atomic_test_bit(&gpd_service_status, GPD_SERVICE_READY)) { + notify(mgr, 0); + } else { + nrfs_err_t err; + + err = nrfs_gdpwr_power_request(gpd_mgr->id, GDPWR_POWER_REQUEST_CLEAR, gpd_mgr); + if (err != NRFS_SUCCESS) { + LOG_ERR("nRFs GDPWR request failed (%d)", err); + notify(mgr, -EIO); + } + } +} + +int nrf_gpd_request(uint8_t id) +{ + int ret; + struct onoff_client client; + struct gpd_onoff_manager *gpd_mgr; + + gpd_mgr = get_mgr(id); + if (gpd_mgr == NULL) { + return -EINVAL; + } + + if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_ERROR)) { + LOG_ERR("GPD service did not initialize properly"); + return -EIO; + } + + sys_notify_init_spinwait(&client.notify); + + onoff_request(&gpd_mgr->mgr, &client); + + while (sys_notify_fetch_result(&client.notify, &ret) == -EAGAIN) { + } + + return ret; +} + +int nrf_gpd_release(uint8_t id) +{ + struct gpd_onoff_manager *gpd_mgr; + + gpd_mgr = get_mgr(id); + if (gpd_mgr == NULL) { + return -EINVAL; + } + + if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_ERROR)) { + LOG_ERR("GPD service did not initialize properly"); + return -EIO; + } + + return onoff_release(&gpd_mgr->mgr); +} + +int nrf_gpd_retain_pins_set(const struct pinctrl_dev_config *pcfg, bool retain) +{ + const struct pinctrl_state *state; + int ret; + + ret = pinctrl_lookup_state(pcfg, PINCTRL_STATE_DEFAULT, &state); + if (ret < 0) { + return ret; + } + + for (uint8_t i = 0U; i < state->pin_cnt; i++) { + uint32_t pin = NRF_GET_PIN(state->pins[i]); + NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&pin); + + if (pin == NRF_PIN_DISCONNECTED) { + continue; + } + + if (retain) { + reg->RETAINSET = BIT(pin); + } else { + reg->RETAINCLR = BIT(pin); + } + } + + return 0; +} + +static int nrf_gpd_pre_init(void) +{ + int ret; + + ret = onoff_manager_init(&fast_active1.mgr, &transitions); + if (ret < 0) { + return ret; + } + + ret = onoff_manager_init(&slow_active.mgr, &transitions); + if (ret < 0) { + return ret; + } + + ret = onoff_manager_init(&slow_main.mgr, &transitions); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int nrf_gpd_post_init(void) +{ + nrfs_err_t err; + int ret; + + err = nrfs_backend_wait_for_connection(K_FOREVER); + if (err != NRFS_SUCCESS) { + ret = -EIO; + goto err; + } + + err = nrfs_gdpwr_init(evt_handler); + if (err != NRFS_SUCCESS) { + ret = -EIO; + goto err; + } + + /* submit GD requests now to align collected statuses */ + ret = nrf_gpd_sync(&fast_active1); + if (ret < 0) { + goto err; + } + + ret = nrf_gpd_sync(&slow_active); + if (ret < 0) { + goto err; + } + + ret = nrf_gpd_sync(&slow_main); + if (ret < 0) { + goto err; + } + + atomic_set_bit(&gpd_service_status, GPD_SERVICE_READY); + + return 0; + +err: + atomic_set_bit(&gpd_service_status, GPD_SERVICE_ERROR); + + return ret; +} + +SYS_INIT(nrf_gpd_pre_init, PRE_KERNEL_1, 0); +SYS_INIT(nrf_gpd_post_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/soc/nordic/nrf54h/gpd/include/nrf/gpd.h b/soc/nordic/nrf54h/gpd/include/nrf/gpd.h new file mode 100644 index 0000000000000..b8aab94accbd0 --- /dev/null +++ b/soc/nordic/nrf54h/gpd/include/nrf/gpd.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_NORDIC_NRF54H_GPD_INCLUDE_NRF_GPD_H_ +#define ZEPHYR_SOC_NORDIC_NRF54H_GPD_INCLUDE_NRF_GPD_H_ + +#include + +#include +#include + +/** + * @brief Request a global power domain. + * + * @param id Domain ID. + * + * @retval 0 If the request was successful. + * @retval -errno If the request was not successful. + */ +int nrf_gpd_request(uint8_t id); + +/** + * @brief Release a global power domain. + * + * @param id Domain ID. + * + * @retval 0 If the request was successful. + * @retval -errno If the request was not successful. + */ +int nrf_gpd_release(uint8_t id); + +/** + * @brief Retain set/clear a set of pins. + * + * @param pcfg Device pin configuration. + * @param retain Retain or not. + * + * @retval 0 If the request was successful. + * @retval -errno If the request was not successful. + */ +int nrf_gpd_retain_pins_set(const struct pinctrl_dev_config *pcfg, bool retain); + +#endif /* ZEPHYR_SOC_NORDIC_NRF54H_GPD_INCLUDE_NRF_GPD_H_ */