@@ -258,6 +258,112 @@ ZTEST(policy_api, test_pm_policy_next_state_default_latency)
258
258
pm_policy_latency_request_remove (& req1 );
259
259
zassert_equal (latency_cb_call_cnt , 1 );
260
260
}
261
+
262
+ /**
263
+ * @brief Test pm_policy_state_constraints_get/put functions using devicetree
264
+ * test-states property and PM_STATE_CONSTRAINTS macros.
265
+ */
266
+ ZTEST (policy_api , test_pm_policy_state_constraints )
267
+ {
268
+ /* Define constraints list from the zephyr,user test-states property */
269
+ PM_STATE_CONSTRAINTS_LIST_DEFINE (DT_PATH (zephyr_user ), test_states );
270
+
271
+ /* Get the constraints structure from devicetree */
272
+ struct pm_state_constraints test_constraints =
273
+ PM_STATE_CONSTRAINTS_GET (DT_PATH (zephyr_user ), test_states );
274
+
275
+ /* Verify the constraints were parsed correctly from devicetree
276
+ * test-states = <&state0 &state2> from app.overlay
277
+ */
278
+ zassert_equal (test_constraints .count , 2 ,
279
+ "Expected 2 constraints from test-states property" );
280
+
281
+ /* Check that the constraints contain the expected states:
282
+ * state0 (runtime-idle, substate 1) and state2 (suspend-to-ram, substate 100)
283
+ */
284
+ bool found_runtime_idle = false;
285
+ bool found_suspend_to_ram = false;
286
+
287
+ for (size_t i = 0 ; i < test_constraints .count ; i ++ ) {
288
+ TC_PRINT ("Constraint %zu: state=%d, substate_id=%d\n" ,
289
+ i , test_constraints .list [i ].state , test_constraints .list [i ].substate_id );
290
+
291
+ if (test_constraints .list [i ].state == PM_STATE_RUNTIME_IDLE &&
292
+ test_constraints .list [i ].substate_id == 1 ) {
293
+ found_runtime_idle = true;
294
+ }
295
+ if (test_constraints .list [i ].state == PM_STATE_SUSPEND_TO_RAM &&
296
+ test_constraints .list [i ].substate_id == 100 ) {
297
+ found_suspend_to_ram = true;
298
+ }
299
+ }
300
+
301
+ zassert_true (found_runtime_idle ,
302
+ "Expected runtime-idle state with substate 1 in constraints" );
303
+ zassert_true (found_suspend_to_ram ,
304
+ "Expected suspend-to-ram state with substate 100 in constraints" );
305
+
306
+ /* Test that states are initially available */
307
+ zassert_false (pm_policy_state_lock_is_active (PM_STATE_RUNTIME_IDLE , 1 ),
308
+ "runtime-idle substate 1 should be initially available" );
309
+ zassert_false (pm_policy_state_lock_is_active (PM_STATE_SUSPEND_TO_RAM , 100 ),
310
+ "suspend-to-ram substate 100 should be initially available" );
311
+
312
+ /* Apply the constraints - this should lock the specified states */
313
+ pm_policy_state_constraints_get (& test_constraints );
314
+
315
+ /* Verify that the constrained states are now locked */
316
+ zassert_true (pm_policy_state_lock_is_active (PM_STATE_RUNTIME_IDLE , 1 ),
317
+ "runtime-idle substate 1 should be locked after applying constraints" );
318
+ zassert_true (pm_policy_state_lock_is_active (PM_STATE_SUSPEND_TO_RAM , 100 ),
319
+ "suspend-to-ram substate 100 should be locked after applying constraints" );
320
+
321
+ /* Verify that non-constrained states are still available */
322
+ zassert_false (pm_policy_state_lock_is_active (PM_STATE_SUSPEND_TO_RAM , 10 ),
323
+ "suspend-to-ram substate 10 should not be locked" );
324
+
325
+ /* Test that policy respects the constraints */
326
+ const struct pm_state_info * next ;
327
+
328
+ /* This should not return the locked runtime-idle state,
329
+ * but should return suspend-to-ram substate 10
330
+ */
331
+ next = pm_policy_next_state (0U , k_us_to_ticks_floor32 (1100000 ));
332
+ zassert_not_null (next , "Policy should return an available state" );
333
+ zassert_equal (next -> state , PM_STATE_SUSPEND_TO_RAM );
334
+ zassert_equal (next -> substate_id , 10 );
335
+
336
+ /* Remove the constraints - this should unlock the states */
337
+ pm_policy_state_constraints_put (& test_constraints );
338
+
339
+ /* Verify that the previously constrained states are now unlocked */
340
+ zassert_false (pm_policy_state_lock_is_active (PM_STATE_RUNTIME_IDLE , 1 ),
341
+ "runtime-idle substate 1 should be unlocked after removing constraints" );
342
+ zassert_false (pm_policy_state_lock_is_active (PM_STATE_SUSPEND_TO_RAM , 100 ),
343
+ "suspend-to-ram substate 100 should be unlocked after removing constraints" );
344
+
345
+ /* Verify policy works normally again */
346
+ next = pm_policy_next_state (0U , k_us_to_ticks_floor32 (110000 ));
347
+ zassert_not_null (next , "Policy should return a state after removing constraints" );
348
+ zassert_equal (next -> state , PM_STATE_RUNTIME_IDLE );
349
+
350
+ /* Test multiple get/put cycles to verify reference counting */
351
+ pm_policy_state_constraints_get (& test_constraints );
352
+ pm_policy_state_constraints_get (& test_constraints );
353
+
354
+ zassert_true (pm_policy_state_lock_is_active (PM_STATE_RUNTIME_IDLE , 1 ),
355
+ "runtime-idle substate 1 should remain locked with multiple gets" );
356
+
357
+ /* First put should not unlock (reference count > 1) */
358
+ pm_policy_state_constraints_put (& test_constraints );
359
+ zassert_true (pm_policy_state_lock_is_active (PM_STATE_RUNTIME_IDLE , 1 ),
360
+ "runtime-idle substate 1 should remain locked after first put" );
361
+
362
+ /* Second put should unlock (reference count = 0) */
363
+ pm_policy_state_constraints_put (& test_constraints );
364
+ zassert_false (pm_policy_state_lock_is_active (PM_STATE_RUNTIME_IDLE , 1 ),
365
+ "runtime-idle substate 1 should be unlocked after final put" );
366
+ }
261
367
#else
262
368
ZTEST (policy_api , test_pm_policy_next_state_default )
263
369
{
@@ -273,6 +379,11 @@ ZTEST(policy_api, test_pm_policy_next_state_default_latency)
273
379
{
274
380
ztest_test_skip ();
275
381
}
382
+
383
+ ZTEST (policy_api , test_pm_policy_state_constraints )
384
+ {
385
+ ztest_test_skip ();
386
+ }
276
387
#endif /* CONFIG_PM_POLICY_DEFAULT */
277
388
278
389
#ifdef CONFIG_PM_POLICY_CUSTOM
0 commit comments