From d1e870cd61072b37a885f32cfb4f8ef0b85b429b Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Mon, 14 Sep 2026 10:58:42 -0500 Subject: [PATCH 1/3] UPSTREAM-PEND: driver: mspm0 counter: Fix formatting using clang-format PR: 118364 Zephyr compliance check indicated clang-format should be ran on this driver. So incorporate the formatting changes before adding my driver changes. Signed-off-by: Franklin Cooper Jr --- drivers/counter/counter_mspm0_timer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/counter/counter_mspm0_timer.c b/drivers/counter/counter_mspm0_timer.c index ebab86bd1eb8..4ff3511ebf9b 100644 --- a/drivers/counter/counter_mspm0_timer.c +++ b/drivers/counter/counter_mspm0_timer.c @@ -537,6 +537,7 @@ static void counter_mspm0_isr(void *arg) } } +/* clang-format off */ #define MSPM0_COUNTER_IRQ_REGISTER(n) \ static void mspm0_ ## n ##_irq_register(void) \ { \ @@ -560,7 +561,7 @@ static void counter_mspm0_isr(void *arg) .clk = DT_CLOCKS_CELL_BY_IDX(DT_INST_PARENT(n), 0, clk), \ }, \ .irq_config_func = (mspm0_ ## n ##_irq_register), \ - .clk_sel = MSPM0_CLOCK_PERIPH_REG_MASK( \ + .clk_sel = MSPM0_CLOCK_PERIPH_REG_MASK( \ DT_CLOCKS_CELL_BY_IDX(DT_INST_PARENT(n), 0, clk)), \ .clk_div_reg = DT_PROP(DT_INST_PARENT(n), ti_clk_div) - 1U, \ .prescaler = DT_PROP(DT_INST_PARENT(n), ti_clk_prescaler), \ @@ -568,7 +569,7 @@ static void counter_mspm0_isr(void *arg) .counter_info = {.max_top_value = (DT_INST_PROP(n, resolution) == 32) \ ? UINT32_MAX : UINT16_MAX, \ .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ - .channels = DT_INST_PROP(n, channels)}, \ + .channels = DT_INST_PROP(n, channels)}, \ }; \ \ DEVICE_DT_INST_DEFINE(n, \ @@ -578,4 +579,5 @@ static void counter_mspm0_isr(void *arg) &counter_mspm0_config_ ## n, \ POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ &mspm0_counter_api); +/* clang-format on */ DT_INST_FOREACH_STATUS_OKAY(COUNTER_DEVICE_INIT_MSPM0) From c4bf8f03c6fc4a23cc37d5be919234b12e8cda12 Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Fri, 4 Sep 2026 16:25:23 -0500 Subject: [PATCH 2/3] UPSTREAM-PEND: driver: mspm0 counter: Auto start when used as lpm compan... PR: 118364 GP timer across mspm0 family are the most consistent option to run during all of the devices low power mode excluding shutdown. Counter drivers already are supported to be used as system timer low power companions. However, it assumes that the counter is already running. Therefore, if the specific counter instance is being used as a low power companion then auto start during init. Signed-off-by: Franklin Cooper Jr --- drivers/counter/counter_mspm0_timer.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/counter/counter_mspm0_timer.c b/drivers/counter/counter_mspm0_timer.c index 4ff3511ebf9b..d04a1724255a 100644 --- a/drivers/counter/counter_mspm0_timer.c +++ b/drivers/counter/counter_mspm0_timer.c @@ -16,6 +16,14 @@ #include #include +/* True for the instance chosen as the system-timer low-power companion. */ +#if DT_HAS_CHOSEN(zephyr_system_timer_companion) +#define COUNTER_MSPM_TIMER_IS_COMPANION(n) \ + DT_SAME_NODE(DT_DRV_INST(n), DT_CHOSEN(zephyr_system_timer_companion)) +#else +#define COUNTER_MSPM_TIMER_IS_COMPANION(n) 0 +#endif /* DT_HAS_CHOSEN(zephyr_system_timer_companion) */ + LOG_MODULE_REGISTER(mspm0_counter, CONFIG_COUNTER_LOG_LEVEL); /* GPTIMER register map — TRM Chapter 34 */ @@ -187,6 +195,7 @@ struct counter_mspm0_config { uint32_t prescaler; unsigned int irqn; void (*irq_config_func)(void); + bool is_companion; }; /* Software-pending interrupt for late alarm detection */ @@ -471,6 +480,13 @@ static int counter_mspm0_init(const struct device *dev) config->irq_config_func(); + /* Start the counter since its expected to be on when its used as lpm + * companion. + */ + if (config->is_companion) { + counter_mspm0_start(dev); + } + return 0; } @@ -570,6 +586,7 @@ static void counter_mspm0_isr(void *arg) ? UINT32_MAX : UINT16_MAX, \ .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ .channels = DT_INST_PROP(n, channels)}, \ + .is_companion = COUNTER_MSPM_TIMER_IS_COMPANION(n), \ }; \ \ DEVICE_DT_INST_DEFINE(n, \ From c5fcbe48b0975615d9e39927683a27456b8be15c Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Fri, 4 Sep 2026 19:32:11 -0500 Subject: [PATCH 3/3] UPSTREAM-PEND: tests: ti - Add low power mode test PR: 118364 The test allows a targetted low-power mode to be specified and verifies suspending and resuming works three different times. User can specify in device tree a system-timer-companion that can be used. If not specified then Systick will be used by default. However, Systick doesn't work in specific low power states such as standby on MSPM0 devices. Tested on: lp_mspm0g3519 Signed-off-by: Franklin Cooper Jr --- .../ti/pm/companion_timer/CMakeLists.txt | 6 + tests/boards/ti/pm/companion_timer/README.rst | 29 ++++ .../boards/lp_mspm0g3519.overlay | 26 +++ tests/boards/ti/pm/companion_timer/prj.conf | 7 + tests/boards/ti/pm/companion_timer/src/main.c | 155 ++++++++++++++++++ tests/boards/ti/pm/companion_timer/tests.yaml | 7 + 6 files changed, 230 insertions(+) create mode 100644 tests/boards/ti/pm/companion_timer/CMakeLists.txt create mode 100644 tests/boards/ti/pm/companion_timer/README.rst create mode 100644 tests/boards/ti/pm/companion_timer/boards/lp_mspm0g3519.overlay create mode 100644 tests/boards/ti/pm/companion_timer/prj.conf create mode 100644 tests/boards/ti/pm/companion_timer/src/main.c create mode 100644 tests/boards/ti/pm/companion_timer/tests.yaml diff --git a/tests/boards/ti/pm/companion_timer/CMakeLists.txt b/tests/boards/ti/pm/companion_timer/CMakeLists.txt new file mode 100644 index 000000000000..d0ba376763f7 --- /dev/null +++ b/tests/boards/ti/pm/companion_timer/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(pm_companion_timer_test) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/boards/ti/pm/companion_timer/README.rst b/tests/boards/ti/pm/companion_timer/README.rst new file mode 100644 index 000000000000..f7c926139ae2 --- /dev/null +++ b/tests/boards/ti/pm/companion_timer/README.rst @@ -0,0 +1,29 @@ +PM Companion Timer Test +####################### + +Overview +******** + +Tests low-power state entry and measures sleep duration. The test automatically +adapts to available timing sources: + +- **Systick**: Uses ARM SysTick timer when no companion timer is + available. Timing granularity is coarser and doesn't run in certain + low power modes. + +- **Companion Timer**: Uses dedicated low-power counter for precise + microsecond-level timing that works in all sleep states. + +Device Tree +*********** + +Optionally configure a companion timer in the board overlay: + +.. code-block:: devicetree + + chosen { + zephyr,system-timer-companion = &counterg0; /* Optional */ + zephyr,test-pm-state = &stdby1; + }; + +If not defined, the test automatically uses systick. diff --git a/tests/boards/ti/pm/companion_timer/boards/lp_mspm0g3519.overlay b/tests/boards/ti/pm/companion_timer/boards/lp_mspm0g3519.overlay new file mode 100644 index 000000000000..a66342027eb3 --- /dev/null +++ b/tests/boards/ti/pm/companion_timer/boards/lp_mspm0g3519.overlay @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 Texas Instruments + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,system-timer-companion = &counterg0; + zephyr,test-pm-state = &stdby1; + }; +}; + +&counterg0 { + status = "okay"; +}; + +&timg0 { + status = "okay"; + clocks = <&ckm MSPM0_CLOCK_LFCLK>; + ti,clk-prescaler = <59>; + wakeup-source; +}; + +&cpu0 { + cpu-power-states = <&run0 &run1 &run2 &stdby1>; +}; diff --git a/tests/boards/ti/pm/companion_timer/prj.conf b/tests/boards/ti/pm/companion_timer/prj.conf new file mode 100644 index 000000000000..525c1dee5818 --- /dev/null +++ b/tests/boards/ti/pm/companion_timer/prj.conf @@ -0,0 +1,7 @@ +CONFIG_TICKLESS_KERNEL=y +CONFIG_PM=y +CONFIG_COUNTER=y +CONFIG_SYSTEM_TIMER_LPM_COMPANION_COUNTER=y +CONFIG_LOG=y +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MODE_IMMEDIATE=y diff --git a/tests/boards/ti/pm/companion_timer/src/main.c b/tests/boards/ti/pm/companion_timer/src/main.c new file mode 100644 index 000000000000..43378c76d67e --- /dev/null +++ b/tests/boards/ti/pm/companion_timer/src/main.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2026 Texas Instruments + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(pm_companion_timer_test); + +#define FIRST_SLEEP_OFFSET_US 129923 +#define SECOND_SLEEP_OFFSET_US 1413080 +#define THIRD_SLEEP_OFFSET_US 2590173 + +const struct device *lpm_timer_dev; +atomic_t correct_state_entered_during_sleep; +enum pm_state target_pm_state; +uint8_t target_pm_substate; + +static void pm_state_entry(enum pm_state state) +{ + if (state == target_pm_state) { + atomic_set(&correct_state_entered_during_sleep, 1); + } +} + +static void pm_state_exit(enum pm_state state) +{ + ARG_UNUSED(state); +} + +static struct pm_notifier notifier = { + .state_entry = pm_state_entry, + .state_exit = pm_state_exit, +}; + +void get_lpm_timer_count(uint32_t *count) +{ + if (lpm_timer_dev == NULL) { + *count = (uint32_t)k_uptime_ticks(); + } else { + counter_get_value(lpm_timer_dev, count); + } +} + +uint32_t get_lpm_timer_duration(uint32_t *start, uint32_t *end) +{ + if (lpm_timer_dev == NULL) { + uint32_t tick_delta = *end - *start; + + return (uint64_t)tick_delta * 1000000 / CONFIG_SYS_CLOCK_TICKS_PER_SEC; + } else { + return counter_ticks_to_us(lpm_timer_dev, (*end - *start)); + } +} + +uint32_t get_lpm_timer_frequency(void) +{ + if (lpm_timer_dev == NULL) { + return CONFIG_SYS_CLOCK_TICKS_PER_SEC; + } else { + return counter_get_frequency(lpm_timer_dev); + } +} + +const struct device *get_lpm_timer(void) +{ +#if DT_HAS_CHOSEN(zephyr_system_timer_companion) + return DEVICE_DT_GET(DT_CHOSEN(zephyr_system_timer_companion)); +#else + return NULL; +#endif +} + +int main(void) +{ + lpm_timer_dev = get_lpm_timer(); + + if (lpm_timer_dev == NULL) { + LOG_INF("Using Systick timer"); + } else { + LOG_INF("Using Companion Counter"); + if (!device_is_ready(lpm_timer_dev)) { + LOG_ERR("ERROR: Counter device not ready"); + return -1; + } + } + + uint32_t counter_freq = get_lpm_timer_frequency(); + + LOG_INF("Low Power Mode Clock frequency: %u Hz", counter_freq); + + /* Get test power state from device tree */ + const struct pm_state_info target_state = + PM_STATE_INFO_DT_INIT(DT_CHOSEN(zephyr_test_pm_state)); + + target_pm_state = target_state.state; + target_pm_substate = target_state.substate_id; + + /* Get power state node name */ + const char *pm_state_name = DT_NODE_FULL_NAME(DT_CHOSEN(zephyr_test_pm_state)); + + /* Register power state notifier */ + pm_notifier_register(¬ifier); + + /* Force the target power state */ + pm_state_force(0, &target_state); + + LOG_INF("Forcing LPM '%s' (mapped to system power state: '%s')", pm_state_name, + pm_state_to_str(target_pm_state)); + LOG_INF("Min residency: %u us, Exit latency: %u us", target_state.min_residency_us, + target_state.exit_latency_us); + + uint32_t min_residency_us = target_state.min_residency_us; + uint32_t sleep_durations_us[] = {min_residency_us + FIRST_SLEEP_OFFSET_US, + min_residency_us + SECOND_SLEEP_OFFSET_US, + min_residency_us + THIRD_SLEEP_OFFSET_US}; + + for (int i = 0; i < 3; i++) { + LOG_INF("--- Sleep cycle %d: %u us ---", i + 1, sleep_durations_us[i]); + log_process(); + + uint32_t end_time = 0; + uint32_t start_time = 0; + + atomic_set(&correct_state_entered_during_sleep, 0); + + get_lpm_timer_count(&start_time); + + k_sleep(K_USEC(sleep_durations_us[i])); + + get_lpm_timer_count(&end_time); + + uint32_t actual_duration_us = get_lpm_timer_duration(&start_time, &end_time); + + if (atomic_get(&correct_state_entered_during_sleep)) { + LOG_INF("✓ Duration: %u us (expected: %u us)", actual_duration_us, + sleep_durations_us[i]); + } else { + LOG_ERR("✗ Duration: %u us (expected: %u us) - " + "WARNING: Did not enter target state", + actual_duration_us, sleep_durations_us[i]); + } + } + + pm_notifier_unregister(¬ifier); + LOG_INF("=== Test Complete ==="); + + return 0; +} diff --git a/tests/boards/ti/pm/companion_timer/tests.yaml b/tests/boards/ti/pm/companion_timer/tests.yaml new file mode 100644 index 000000000000..49cea0a0a4a0 --- /dev/null +++ b/tests/boards/ti/pm/companion_timer/tests.yaml @@ -0,0 +1,7 @@ +tests: + boards.ti.pm.companion_timer: + tags: pm + harness: ztest + platform_allow: + - lp_mspm0g3519/mspm0g3519 + timeout: 10