Skip to content

Commit 643a223

Browse files
drivers: power-domain: add nrfs-gdpwr driver and bindings
Add NRFS Global Domain Power Request device driver and hardware bindings. Signed-off-by: Bjarki Arge Andreasen <bjarki.andreasen@nordicsemi.no>
1 parent 093140d commit 643a223

File tree

5 files changed

+325
-0
lines changed

5 files changed

+325
-0
lines changed

drivers/power_domain/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO power_domain_gpio.c)
77
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO_MONITOR power_domain_gpio_monitor.c)
88
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_INTEL_ADSP power_domain_intel_adsp.c)
99
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_NXP_SCU power_domain_nxp_scu.c)
10+
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_NRFS_GDPWR power_domain_nrfs_gdpwr.c)
1011
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_NRFS_SWEXT power_domain_nrfs_swext.c)
1112
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_SOC_PM_STATE power_domain_soc_state_change.c)
1213
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_TISCI power_domain_tisci.c)

drivers/power_domain/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,6 @@ config SOC_POWER_DOMAIN_INIT
124124
endif #POWER_DOMAIN_TISCI
125125

126126
rsource "Kconfig.nrfs_swext"
127+
rsource "Kconfig.nrfs_gdpwr"
127128

128129
endif
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config POWER_DOMAIN_NRFS_GDPWR
5+
bool "NRFS Global Domain Power Request driver"
6+
depends on DT_HAS_NORDIC_NRFS_GDPWR_ENABLED
7+
select NRFS
8+
select NRFS_GDPWR_SERVICE_ENABLED
9+
default y
10+
11+
if POWER_DOMAIN_NRFS_GDPWR
12+
13+
config POWER_DOMAIN_NRFS_GDPWR_TIMEOUT_MS
14+
int "GDPWR request timeout in milliseconds"
15+
default 500
16+
17+
endif # POWER_DOMAIN_NRFS_GDPWR
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT nordic_nrfs_gdpwr
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/pm/device.h>
12+
#include <zephyr/logging/log.h>
13+
14+
#include <nrfs_gdpwr.h>
15+
#include <nrfs_backend_ipc_service.h>
16+
17+
LOG_MODULE_REGISTER(nrfs_gdpwr, CONFIG_POWER_DOMAIN_LOG_LEVEL);
18+
19+
#define MANAGER_REQUEST_TIMEOUT K_MSEC(CONFIG_POWER_DOMAIN_NRFS_GDPWR_TIMEOUT_MS)
20+
21+
static K_SEM_DEFINE(lock_sem, 1, 1);
22+
static K_SEM_DEFINE(req_sem, 0, 1);
23+
static nrfs_gdpwr_evt_type_t req_resp;
24+
static const struct device *const domains[] = {
25+
DT_INST_FOREACH_CHILD_SEP(0, DEVICE_DT_GET, (,))
26+
};
27+
28+
struct domain_data {
29+
bool off;
30+
bool synced;
31+
};
32+
33+
struct domain_config {
34+
gdpwr_power_domain_t domain;
35+
};
36+
37+
static void manager_event_handler(nrfs_gdpwr_evt_t const *evt, void *context)
38+
{
39+
ARG_UNUSED(context);
40+
41+
req_resp = evt->type;
42+
k_sem_give(&req_sem);
43+
}
44+
45+
static void manager_lock(void)
46+
{
47+
if (k_is_pre_kernel()) {
48+
return;
49+
}
50+
51+
(void)k_sem_take(&lock_sem, K_FOREVER);
52+
}
53+
54+
static void manager_unlock(void)
55+
{
56+
if (k_is_pre_kernel()) {
57+
return;
58+
}
59+
60+
k_sem_give(&lock_sem);
61+
}
62+
63+
static int manager_set_domain_locked(gdpwr_power_domain_t domain, bool on)
64+
{
65+
nrfs_err_t err;
66+
gdpwr_request_type_t req = on ? GDPWR_POWER_REQUEST_SET : GDPWR_POWER_REQUEST_CLEAR;
67+
int ret;
68+
69+
err = nrfs_gdpwr_power_request(domain, req, NULL);
70+
if (err != NRFS_SUCCESS) {
71+
LOG_ERR("%s %s", "nrfs gdpwr request", "failed");
72+
return -EIO;
73+
}
74+
75+
ret = k_sem_take(&req_sem, MANAGER_REQUEST_TIMEOUT);
76+
if (ret < 0) {
77+
LOG_ERR("%s %s", "nrfs gdpwr request", "timed out");
78+
return -ETIMEDOUT;
79+
}
80+
81+
if (req_resp != NRFS_GDPWR_REQ_APPLIED) {
82+
LOG_ERR("%s %s", "nrfs gdpwr request", "rejected");
83+
return -EIO;
84+
}
85+
86+
return 0;
87+
}
88+
89+
static int manager_set_domain(const struct device *dev, bool on)
90+
{
91+
struct domain_data *dev_data = dev->data;
92+
const struct domain_config *dev_config = dev->config;
93+
int ret;
94+
95+
manager_lock();
96+
97+
if (dev_data->synced) {
98+
/* NRFS GDPWR service is ready so we request domain change state */
99+
ret = manager_set_domain_locked(dev_config->domain, on);
100+
} else {
101+
/*
102+
* NRFS GDPWR service is not ready so we track what the expected
103+
* state of the power domain to be requested once the service
104+
* is ready.
105+
*/
106+
ret = 0;
107+
dev_data->off = !on;
108+
}
109+
110+
manager_unlock();
111+
return ret;
112+
}
113+
114+
static int manager_sync_domain_locked(const struct device *dev)
115+
{
116+
struct domain_data *dev_data = dev->data;
117+
const struct domain_config *dev_config = dev->config;
118+
119+
/*
120+
* NRFS service is now ready. We will now synchronize the state
121+
* of the power domain with the expected state we tracked with
122+
* the struct domain_data off member. Following this, tracking
123+
* the power domain state is handled by device PM, thus the
124+
* struct domain_data off is no longer used.
125+
*/
126+
dev_data->synced = true;
127+
128+
/*
129+
* Power domains initialize ON so we only need to send a request
130+
* if the expected state of the power domain is OFF.
131+
*/
132+
if (dev_data->off) {
133+
return manager_set_domain_locked(dev_config->domain, false);
134+
}
135+
136+
return 0;
137+
}
138+
139+
static int manager_sync_domains_locked(void)
140+
{
141+
int ret;
142+
143+
ARRAY_FOR_EACH(domains, i) {
144+
ret = manager_sync_domain_locked(domains[i]);
145+
if (ret) {
146+
break;
147+
}
148+
}
149+
150+
return ret;
151+
}
152+
153+
static int manager_init(void)
154+
{
155+
nrfs_err_t err;
156+
int ret;
157+
158+
err = nrfs_backend_wait_for_connection(K_FOREVER);
159+
if (err != NRFS_SUCCESS) {
160+
LOG_ERR("%s %s", "nrfs backend connection", "failed");
161+
return -EIO;
162+
}
163+
164+
err = nrfs_gdpwr_init(manager_event_handler);
165+
if (err != NRFS_SUCCESS) {
166+
LOG_ERR("%s %s", "nrfs gdpwr init", "failed");
167+
return -EIO;
168+
}
169+
170+
manager_lock();
171+
ret = manager_sync_domains_locked();
172+
manager_unlock();
173+
return ret;
174+
}
175+
176+
SYS_INIT(manager_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
177+
178+
static int domain_pm_suspend(const struct device *dev)
179+
{
180+
return manager_set_domain(dev, false);
181+
}
182+
183+
static int domain_pm_resume(const struct device *dev)
184+
{
185+
return manager_set_domain(dev, true);
186+
}
187+
188+
static int domain_pm_action(const struct device *dev, enum pm_device_action action)
189+
{
190+
int ret;
191+
192+
switch (action) {
193+
case PM_DEVICE_ACTION_SUSPEND:
194+
ret = domain_pm_suspend(dev);
195+
break;
196+
197+
case PM_DEVICE_ACTION_RESUME:
198+
ret = domain_pm_resume(dev);
199+
break;
200+
201+
case PM_DEVICE_ACTION_TURN_OFF:
202+
case PM_DEVICE_ACTION_TURN_ON:
203+
ret = -ENOTSUP;
204+
break;
205+
206+
default:
207+
ret = -EINVAL;
208+
break;
209+
}
210+
211+
return ret;
212+
}
213+
214+
static int domain_init(const struct device *dev)
215+
{
216+
return pm_device_driver_init(dev, domain_pm_action);
217+
}
218+
219+
#define DOMAIN_NODE_SYMNAME(node, sym) \
220+
_CONCAT_4(domain, _, sym, DT_NODE_CHILD_IDX(node))
221+
222+
#define DOMAIN_NODE_TO_GDPWR_ENUM(node) \
223+
_CONCAT(GDPWR_GD_, DT_NODE_FULL_NAME_UPPER_TOKEN(node))
224+
225+
#define DOMAIN_DEFINE(node) \
226+
static struct domain_config DOMAIN_NODE_SYMNAME(node, data); \
227+
static const struct domain_config DOMAIN_NODE_SYMNAME(node, config) = { \
228+
.domain = DOMAIN_NODE_TO_GDPWR_ENUM(node), \
229+
}; \
230+
\
231+
PM_DEVICE_DT_DEFINE(node, domain_pm_action); \
232+
\
233+
DEVICE_DT_DEFINE( \
234+
node, \
235+
domain_init, \
236+
PM_DEVICE_DT_GET(node), \
237+
&DOMAIN_NODE_SYMNAME(node, data), \
238+
&DOMAIN_NODE_SYMNAME(node, config), \
239+
PRE_KERNEL_1, \
240+
0, \
241+
NULL \
242+
);
243+
244+
DT_INST_FOREACH_CHILD(0, DOMAIN_DEFINE)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Copyright 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
Nordic NRFS Global Domain Power Request
6+
7+
The NRFS Global Domain Power Request service manages
8+
global power domains using NRFS.
9+
10+
Each child node represents a global power domain, mapped
11+
by name. The fast-active-0 child node is mapped to the
12+
FAST_ACTIVE_0 global power domain. The nodelabel of each
13+
child node is the node name prepended with "gdpwr",
14+
using underscores.
15+
16+
Example layout:
17+
18+
gdpwr {
19+
compatible = "nordic,nrfs-gdpwr";
20+
status = "disabled";
21+
22+
gdpwr_fast_active_0: fast-active-0 {
23+
#power-domain-cells = <0>;
24+
};
25+
26+
gdpwr_fast_active_1: fast-active-1 {
27+
#power-domain-cells = <0>;
28+
};
29+
30+
gdpwr_fast_main: fast-main {
31+
#power-domain-cells = <0>;
32+
};
33+
34+
gdpwr_slow_active: slow-active {
35+
#power-domain-cells = <0>;
36+
};
37+
38+
gdpwr_slow_main: slow-main {
39+
#power-domain-cells = <0>;
40+
};
41+
};
42+
43+
Example usage:
44+
45+
uart120: uart@8e6000 {
46+
compatible = "nordic,nrf-uarte";
47+
reg = <0x8e6000 0x1000>;
48+
status = "disabled";
49+
power-domains = <&gdpwr_fast_active_1>;
50+
};
51+
52+
compatible: "nordic,nrfs-gdpwr"
53+
54+
include: base.yaml
55+
56+
child-binding:
57+
description: Nordic NRFS Global Power Domain
58+
59+
properties:
60+
"#power-domain-cells":
61+
type: int
62+
const: 0

0 commit comments

Comments
 (0)