Skip to content

Commit 0ec672a

Browse files
committed
[nrf fromlist] soc: nordic: nrf54h: add SoC level API to request/release GPD
Add a new soc-level API that allows to manually request/release global power domains. Upstream PR #: 80291 Signed-off-by: Gerard Marull-Paretas <[email protected]> (cherry picked from commit f74eb93c6644e8333461d926a225003e122ba5f7)
1 parent f917955 commit 0ec672a

File tree

6 files changed

+329
-0
lines changed

6 files changed

+329
-0
lines changed

soc/nordic/nrf54h/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ if(CONFIG_ARM)
88
endif()
99
endif()
1010

11+
zephyr_library_sources_ifdef(SOC_NRF54H20_GPD nrf_gpd.c)
1112
zephyr_library_sources_ifdef(CONFIG_PM_S2RAM pm_s2ram.c)
1213

1314
zephyr_include_directories(.)
1415

1516
# Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes
1617
# for the image correctly
1718
zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld)
19+
20+
add_subdirectory(gpd)

soc/nordic/nrf54h/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,5 @@ config SOC_NRF54H20_CPUFLPR
7575

7676
config SOC_NRF54H20_ENGB_CPUFLPR
7777
depends on RISCV_CORE_NORDIC_VPR
78+
79+
rsource "gpd/Kconfig"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright (c) 2024 Nordic Semiconductor
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
zephyr_library_sources_ifdef(CONFIG_SOC_NRF54H20_GPD gpd.c)
5+
zephyr_include_directories(include)

soc/nordic/nrf54h/gpd/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2024 Nordic Semiconductor
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config SOC_NRF54H20_GPD
5+
bool "Global Power Domain service"
6+
imply NRFS
7+
imply NRFS_GDPWR_SERVICE_ENABLED
8+
select ONOFF
9+
depends on PM
10+
default y if SOC_NRF54H20_CPUAPP || SOC_NRF54H20_ENGB_CPUAPP || \
11+
SOC_NRF54H20_CPURAD || SOC_NRF54H20_ENGB_CPURAD
12+
help
13+
This option enables the Global Power Domain service.

soc/nordic/nrf54h/gpd/gpd.c

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <errno.h>
7+
8+
#include <zephyr/init.h>
9+
#include <zephyr/logging/log.h>
10+
#include <zephyr/sys/atomic.h>
11+
#include <zephyr/sys/onoff.h>
12+
#include <zephyr/spinlock.h>
13+
#include <zephyr/sys/util.h>
14+
15+
#include <nrf/gpd.h>
16+
#include <nrfs_gdpwr.h>
17+
#include <nrfs_backend_ipc_service.h>
18+
19+
LOG_MODULE_REGISTER(gpd, CONFIG_SOC_LOG_LEVEL);
20+
21+
/* enforce alignment between DT<->nrfs */
22+
BUILD_ASSERT(GDPWR_POWER_DOMAIN_ACTIVE_FAST == NRF_GPD_FAST_ACTIVE1);
23+
BUILD_ASSERT(GDPWR_POWER_DOMAIN_ACTIVE_SLOW == NRF_GPD_SLOW_ACTIVE);
24+
BUILD_ASSERT(GDPWR_POWER_DOMAIN_MAIN_SLOW == NRF_GPD_SLOW_MAIN);
25+
26+
struct gpd_onoff_manager {
27+
struct onoff_manager mgr;
28+
onoff_notify_fn notify;
29+
uint8_t id;
30+
};
31+
32+
static void start(struct onoff_manager *mgr, onoff_notify_fn notify);
33+
static void stop(struct onoff_manager *mgr, onoff_notify_fn notify);
34+
35+
#define GPD_READY_TIMEOUT 1000
36+
37+
#define GPD_SERVICE_READY BIT(0)
38+
#define GPD_SERVICE_ERROR BIT(1)
39+
#define GPD_SERVICE_REQ_OK BIT(2)
40+
#define GPD_SERVICE_REQ_ERR BIT(3)
41+
static atomic_t gpd_service_status = ATOMIC_INIT(0);
42+
43+
static struct gpd_onoff_manager fast_active1 = {.id = NRF_GPD_FAST_ACTIVE1};
44+
static struct gpd_onoff_manager slow_active = {.id = NRF_GPD_SLOW_ACTIVE};
45+
static struct gpd_onoff_manager slow_main = {.id = NRF_GPD_SLOW_MAIN};
46+
47+
static const struct onoff_transitions transitions =
48+
ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL);
49+
50+
static struct gpd_onoff_manager *get_mgr(uint8_t id)
51+
{
52+
switch (id) {
53+
case NRF_GPD_FAST_ACTIVE1:
54+
return &fast_active1;
55+
case NRF_GPD_SLOW_ACTIVE:
56+
return &slow_active;
57+
case NRF_GPD_SLOW_MAIN:
58+
return &slow_main;
59+
default:
60+
return NULL;
61+
}
62+
}
63+
64+
static int nrf_gpd_sync(struct gpd_onoff_manager *gpd_mgr)
65+
{
66+
int64_t start;
67+
nrfs_err_t err;
68+
gdpwr_request_type_t request;
69+
70+
K_SPINLOCK(&gpd_mgr->mgr.lock) {
71+
if (gpd_mgr->mgr.refs == 0) {
72+
request = GDPWR_POWER_REQUEST_CLEAR;
73+
} else {
74+
request = GDPWR_POWER_REQUEST_SET;
75+
}
76+
}
77+
78+
atomic_clear_bit(&gpd_service_status, GPD_SERVICE_REQ_ERR);
79+
atomic_clear_bit(&gpd_service_status, GPD_SERVICE_REQ_OK);
80+
81+
err = nrfs_gdpwr_power_request(gpd_mgr->id, request, gpd_mgr);
82+
if (err != NRFS_SUCCESS) {
83+
atomic_set_bit(&gpd_service_status, GPD_SERVICE_ERROR);
84+
return -EIO;
85+
}
86+
87+
start = k_uptime_get();
88+
while (k_uptime_get() - start < GPD_READY_TIMEOUT) {
89+
if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_REQ_ERR)) {
90+
atomic_set_bit(&gpd_service_status, GPD_SERVICE_ERROR);
91+
return -EIO;
92+
}
93+
94+
if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_REQ_OK)) {
95+
return 0;
96+
}
97+
}
98+
99+
LOG_ERR("nRFs GDPWR request timed out");
100+
101+
atomic_set_bit(&gpd_service_status, GPD_SERVICE_ERROR);
102+
103+
return -ETIMEDOUT;
104+
}
105+
106+
static void evt_handler(nrfs_gdpwr_evt_t const *p_evt, void *context)
107+
{
108+
if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_READY)) {
109+
struct gpd_onoff_manager *gpd_mgr = context;
110+
111+
switch (p_evt->type) {
112+
case NRFS_GDPWR_REQ_APPLIED:
113+
gpd_mgr->notify(&gpd_mgr->mgr, 0);
114+
break;
115+
default:
116+
LOG_ERR("nRFs GDPWR request not applied");
117+
gpd_mgr->notify(&gpd_mgr->mgr, -EIO);
118+
break;
119+
}
120+
} else {
121+
switch (p_evt->type) {
122+
case NRFS_GDPWR_REQ_APPLIED:
123+
atomic_set_bit(&gpd_service_status, GPD_SERVICE_REQ_OK);
124+
break;
125+
default:
126+
LOG_ERR("nRFs GDPWR request not applied");
127+
atomic_set_bit(&gpd_service_status, GPD_SERVICE_REQ_ERR);
128+
break;
129+
}
130+
}
131+
}
132+
133+
static void start(struct onoff_manager *mgr, onoff_notify_fn notify)
134+
{
135+
struct gpd_onoff_manager *gpd_mgr = CONTAINER_OF(mgr, struct gpd_onoff_manager, mgr);
136+
137+
gpd_mgr->notify = notify;
138+
139+
if (!atomic_test_bit(&gpd_service_status, GPD_SERVICE_READY)) {
140+
notify(mgr, 0);
141+
} else {
142+
nrfs_err_t err;
143+
144+
err = nrfs_gdpwr_power_request(gpd_mgr->id, GDPWR_POWER_REQUEST_SET, gpd_mgr);
145+
if (err != NRFS_SUCCESS) {
146+
LOG_ERR("nRFs GDPWR request failed (%d)", err);
147+
notify(mgr, -EIO);
148+
}
149+
}
150+
}
151+
152+
static void stop(struct onoff_manager *mgr, onoff_notify_fn notify)
153+
{
154+
struct gpd_onoff_manager *gpd_mgr = CONTAINER_OF(mgr, struct gpd_onoff_manager, mgr);
155+
156+
gpd_mgr->notify = notify;
157+
158+
if (!atomic_test_bit(&gpd_service_status, GPD_SERVICE_READY)) {
159+
notify(mgr, 0);
160+
} else {
161+
nrfs_err_t err;
162+
163+
err = nrfs_gdpwr_power_request(gpd_mgr->id, GDPWR_POWER_REQUEST_CLEAR, gpd_mgr);
164+
if (err != NRFS_SUCCESS) {
165+
LOG_ERR("nRFs GDPWR request failed (%d)", err);
166+
notify(mgr, -EIO);
167+
}
168+
}
169+
}
170+
171+
int nrf_gpd_request(uint8_t id)
172+
{
173+
int ret;
174+
struct onoff_client client;
175+
struct gpd_onoff_manager *gpd_mgr;
176+
177+
gpd_mgr = get_mgr(id);
178+
if (gpd_mgr == NULL) {
179+
return -EINVAL;
180+
}
181+
182+
if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_ERROR)) {
183+
LOG_ERR("GPD service did not initialize properly");
184+
return -EIO;
185+
}
186+
187+
sys_notify_init_spinwait(&client.notify);
188+
189+
onoff_request(&gpd_mgr->mgr, &client);
190+
191+
while (sys_notify_fetch_result(&client.notify, &ret) == -EAGAIN) {
192+
}
193+
194+
return ret;
195+
}
196+
197+
int nrf_gpd_release(uint8_t id)
198+
{
199+
struct gpd_onoff_manager *gpd_mgr;
200+
201+
gpd_mgr = get_mgr(id);
202+
if (gpd_mgr == NULL) {
203+
return -EINVAL;
204+
}
205+
206+
if (atomic_test_bit(&gpd_service_status, GPD_SERVICE_ERROR)) {
207+
LOG_ERR("GPD service did not initialize properly");
208+
return -EIO;
209+
}
210+
211+
return onoff_release(&gpd_mgr->mgr);
212+
}
213+
214+
static int nrf_gpd_pre_init(void)
215+
{
216+
int ret;
217+
218+
ret = onoff_manager_init(&fast_active1.mgr, &transitions);
219+
if (ret < 0) {
220+
return ret;
221+
}
222+
223+
ret = onoff_manager_init(&slow_active.mgr, &transitions);
224+
if (ret < 0) {
225+
return ret;
226+
}
227+
228+
ret = onoff_manager_init(&slow_main.mgr, &transitions);
229+
if (ret < 0) {
230+
return ret;
231+
}
232+
233+
return 0;
234+
}
235+
236+
static int nrf_gpd_post_init(void)
237+
{
238+
nrfs_err_t err;
239+
int ret;
240+
241+
ret = nrfs_backend_wait_for_connection(K_NO_WAIT);
242+
if (ret < 0) {
243+
return ret;
244+
}
245+
246+
err = nrfs_gdpwr_init(evt_handler);
247+
if (err != NRFS_SUCCESS) {
248+
return -EIO;
249+
}
250+
251+
/* submit GD requests now to align collected statuses */
252+
ret = nrf_gpd_sync(&fast_active1);
253+
if (ret < 0) {
254+
return ret;
255+
}
256+
257+
ret = nrf_gpd_sync(&slow_active);
258+
if (ret < 0) {
259+
return ret;
260+
}
261+
262+
ret = nrf_gpd_sync(&slow_main);
263+
if (ret < 0) {
264+
return ret;
265+
}
266+
267+
atomic_set_bit(&gpd_service_status, GPD_SERVICE_READY);
268+
269+
return 0;
270+
}
271+
272+
SYS_INIT(nrf_gpd_pre_init, PRE_KERNEL_1, 0);
273+
SYS_INIT(nrf_gpd_post_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef ZEPHYR_SOC_NORDIC_NRF54H_GPD_INCLUDE_NRF_GPD_H_
7+
#define ZEPHYR_SOC_NORDIC_NRF54H_GPD_INCLUDE_NRF_GPD_H_
8+
9+
#include <stdint.h>
10+
11+
#include <zephyr/dt-bindings/power/nordic-nrf-gpd.h>
12+
13+
/**
14+
* @brief Request a global power domain.
15+
*
16+
* @param id Domain ID.
17+
*
18+
* @retval 0 If the request was successful.
19+
* @retval -errno If the request was not successful.
20+
*/
21+
int nrf_gpd_request(uint8_t id);
22+
23+
/**
24+
* @brief Release a global power domain.
25+
*
26+
* @param id Domain ID.
27+
*
28+
* @retval 0 If the request was successful.
29+
* @retval -errno If the request was not successful.
30+
*/
31+
int nrf_gpd_release(uint8_t id);
32+
33+
#endif /* ZEPHYR_SOC_NORDIC_NRF54H_GPD_INCLUDE_NRF_GPD_H_ */

0 commit comments

Comments
 (0)