Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions boards/nxp/frdm_mcxn947/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,11 @@ void board_early_init_hook(void)
CLOCK_EnableClock(kCLOCK_Ewm0);
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(utick0))
/* Enable FRO 1MHz clock for UTICK */
CLOCK_SetupClockCtrl(kCLOCK_FRO1MHZ_ENA);
#endif

/* Set SystemCoreClock variable. */
SystemCoreClock = CLOCK_INIT_CORE_CLOCK;
}
7 changes: 7 additions & 0 deletions boards/nxp/mimxrt700_evk/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,13 @@ void board_early_init_hook(void)
CLOCK_EnableClock(kCLOCK_Acmp0);
RESET_ClearPeripheralReset(kACMP0_RST_SHIFT_RSTn);
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(utick0))
/* Enable FRO1_DIV2 clock for UTICK */
CLOCK_AttachClk(kFRO1_DIV2_to_UTICK0_CLK);
/* Use 1MHz clock */
CLOCK_SetClkDiv(kCLOCK_DivUtick0Clk, 96U);
#endif
}

static void GlikeyWriteEnable(GLIKEY_Type *base, uint8_t idx)
Expand Down
1 change: 1 addition & 0 deletions drivers/timer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_MCHP_SAM_PIT64B_TIMER mchp_sam_pit64b_timer.
zephyr_library_sources_ifdef(CONFIG_MCUX_LPTMR_TIMER mcux_lptmr_timer.c)
zephyr_library_sources_ifdef(CONFIG_MCUX_OS_TIMER mcux_os_timer.c)
zephyr_library_sources_ifdef(CONFIG_MCUX_GPT_TIMER mcux_gpt_timer.c)
zephyr_library_sources_ifdef(CONFIG_MCUX_UTICK_TIMER mcux_utick_timer.c)
zephyr_library_sources_ifdef(CONFIG_MIPS_CP0_TIMER mips_cp0_timer.c)
zephyr_library_sources_ifdef(CONFIG_NATIVE_SIM_TIMER native_sim_timer.c)
zephyr_library_sources_ifdef(CONFIG_NPCX_ITIM_TIMER npcx_itim_timer.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/timer/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ source "drivers/timer/Kconfig.mchp_sam"
source "drivers/timer/Kconfig.mcux_gpt"
source "drivers/timer/Kconfig.mcux_lptmr"
source "drivers/timer/Kconfig.mcux_os"
source "drivers/timer/Kconfig.mcux_utick"
source "drivers/timer/Kconfig.mips_cp0"
source "drivers/timer/Kconfig.native_sim"
source "drivers/timer/Kconfig.npcx_itim"
Expand Down
22 changes: 22 additions & 0 deletions drivers/timer/Kconfig.mcux_utick
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

config MCUX_UTICK_TIMER
bool "MCUX Micro-Tick Timer"
default n
depends on DT_HAS_NXP_UTICK_ENABLED
select TICKLESS_CAPABLE
select SYSTEM_TIMER_HAS_DISABLE_SUPPORT
help
This module implements a kernel device driver for the NXP MCUX Micro
Tick timer and provides the standard "system clock driver" interfaces.

if MCUX_UTICK_TIMER

config SYS_CLOCK_HW_CYCLES_PER_SEC
int
default 1000000
help
UTICK source frequency in Hz (e.g. 1 MHz). Must match real UTICK clock.

endif
125 changes: 125 additions & 0 deletions drivers/timer/mcux_utick_timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nxp_utick

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/irq.h>
#include <zephyr/sys_clock.h>
#include <zephyr/spinlock.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/timer/system_timer.h>
#include "fsl_utick.h"

LOG_MODULE_REGISTER(mcux_utick_timer, LOG_LEVEL_ERR);

/* Timer cycles per tick */
#define CYC_PER_TICK \
((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() / \
(uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC))
/* UTICK: DELAYVAL is 31-bit; actual delay = (DELAYVAL+1) cycles */
#define MAX_CYC (UTICK_CTRL_DELAYVAL_MASK)
/* The minimum usable tick interval is one clock cycle, for a delay of two timer clocks. */
#define MIN_CYC (1u)
#define MAX_TICKS ((MAX_CYC + 1u) / CYC_PER_TICK)

static struct k_spinlock lock;
/* UTICK did not provide a readable counter register, so use accumulate software cycles */
static volatile uint64_t sw_cycle64;
/* Ticks programmed for the next interrupt (used as elapsed on IRQ) */
static volatile uint32_t programmed_ticks;

static UTICK_Type *base = (UTICK_Type *)DT_INST_REG_ADDR(0);

static inline uint32_t ticks_to_cycles(uint32_t ticks)
{
uint64_t cyc = (uint64_t)ticks * (uint64_t)CYC_PER_TICK;

if (cyc < MIN_CYC + 1) {
cyc = MIN_CYC + 1;
}
if (cyc > MAX_CYC + 1) {
cyc = MAX_CYC + 1;
}
return (uint32_t)(cyc - 1);
}

static void utick_cb(void)
{
uint32_t elapsed = programmed_ticks ? programmed_ticks : 1u;

sw_cycle64 += (uint64_t)elapsed * (uint64_t)CYC_PER_TICK;
programmed_ticks = 0u;

if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
programmed_ticks = 1u;
UTICK_SetTick(base, kUTICK_Onetime, ticks_to_cycles(programmed_ticks), utick_cb);
sys_clock_announce(1);
} else {
sys_clock_announce((int32_t)elapsed);
}
}

static void mcux_utick_isr(const void *arg)
{
ARG_UNUSED(arg);

UTICK_HandleIRQ(base, utick_cb);
}

void sys_clock_set_timeout(int32_t ticks, bool idle)
{
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
/* Not supported on tickful kernels */
return;
}
ARG_UNUSED(idle);

ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = CLAMP((ticks - 1), 0, (int32_t)MAX_TICKS);

k_spinlock_key_t key = k_spin_lock(&lock);

programmed_ticks = (uint32_t)ticks;
UTICK_SetTick(base, kUTICK_Onetime, ticks_to_cycles(programmed_ticks), utick_cb);
k_spin_unlock(&lock, key);
}

void sys_clock_disable(void)
{
UTICK_Deinit(base);
}

uint32_t sys_clock_elapsed(void)
{
return 0;
}

uint32_t sys_clock_cycle_get_32(void)
{
return (uint32_t)sw_cycle64;
}

uint64_t sys_clock_cycle_get_64(void)
{
return sw_cycle64;
}

static int sys_clock_driver_init(void)
{
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), mcux_utick_isr, NULL, 0);
irq_enable(DT_INST_IRQN(0));
UTICK_Init(base);

programmed_ticks = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? MAX_TICKS : 1u;
UTICK_SetTick(base, kUTICK_Onetime, ticks_to_cycles(programmed_ticks), utick_cb);

return 0;
}

SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
10 changes: 10 additions & 0 deletions dts/arm/nxp/nxp_mcxa153.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@
prescale = <0>;
};

utick0: utick@4000b000 {
compatible = "nxp,utick";
reg = <0x4000b000 0x20>;
interrupts = <59 0>;
clocks = <&syscon MCUX_UTICK0_CLK>;
clk-source = <2>;
clk-divider = <0>;
status = "disabled";
};

edma0: dma-controller@40080000 {
#dma-cells = <2>;
compatible = "nxp,mcux-edma";
Expand Down
10 changes: 10 additions & 0 deletions dts/arm/nxp/nxp_mcxn23x_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
};
};

utick0: utick@12000 {
compatible = "nxp,utick";
reg = <0x12000 0x20>;
interrupts = <29 0>;
clocks = <&syscon MCUX_UTICK0_CLK>;
clk-source = <2>;
clk-divider = <0>;
status = "disabled";
};

porta: pinmux@116000 {
compatible = "nxp,port-pinmux";
reg = <0x116000 0x1000>;
Expand Down
8 changes: 8 additions & 0 deletions dts/arm/nxp/nxp_mcxnx4x_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@
};
};

utick0: utick@12000 {
compatible = "nxp,utick";
reg = <0x12000 0x20>;
interrupts = <29 0>;
clocks = <&syscon MCUX_UTICK0_CLK>;
status = "disabled";
};

porta: pinmux@116000 {
compatible = "nxp,port-pinmux";
reg = <0x116000 0x1000>;
Expand Down
10 changes: 10 additions & 0 deletions dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@
* and secure modes (0x50000000).
*/

utick0: utick@f000 {
compatible = "nxp,utick";
reg = <0xf000 0x20>;
interrupts = <1 0>;
clk-source = <3>;
clk-divider = <96>;
clocks = <&clkctl0 MCUX_UTICK0_CLK>;
status = "disabled";
};

lpadc0: adc@20c000 {
compatible = "nxp,lpc-lpadc";
reg = <0x20c000 0x304>;
Expand Down
24 changes: 24 additions & 0 deletions dts/bindings/timer/nxp,utick.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

description: NXP Micro-Tick Timer

compatible: "nxp,utick"

include: base.yaml

properties:
reg:
required: true

interrupts:
required: true

clk-source:
type: int
enum: [0, 1, 2, 3]
description: Utick function clock source

clk-divider:
type: int
description: Utick function clock divider
4 changes: 3 additions & 1 deletion include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2024 NXP
* Copyright 2020-2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -129,4 +129,6 @@
#define MCUX_LPSPI0_CLK MCUX_LPC_CLK_ID(0x17, 0x00)
#define MCUX_LPSPI1_CLK MCUX_LPC_CLK_ID(0x17, 0x01)

#define MCUX_UTICK0_CLK MCUX_LPC_CLK_ID(0x18, 0x00)

#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */
1 change: 1 addition & 0 deletions modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set_variable_ifdef(CONFIG_SPI_MCUX_FLEXCOMM CONFIG_MCUX_COMPONENT_driver.fle
set_variable_ifdef(CONFIG_UART_MCUX_FLEXCOMM CONFIG_MCUX_COMPONENT_driver.flexcomm)
set_variable_ifdef(CONFIG_UART_MCUX_FLEXCOMM CONFIG_MCUX_COMPONENT_driver.flexcomm_usart)
set_variable_ifdef(CONFIG_MCUX_OS_TIMER CONFIG_MCUX_COMPONENT_driver.ostimer)
set_variable_ifdef(CONFIG_MCUX_UTICK_TIMER CONFIG_MCUX_COMPONENT_driver.utick)
set_variable_ifdef(CONFIG_PWM_MCUX_SCTIMER CONFIG_MCUX_COMPONENT_driver.sctimer)
set_variable_ifdef(CONFIG_PWM_MCUX_CTIMER CONFIG_MCUX_COMPONENT_driver.ctimer)
set_variable_ifdef(CONFIG_SOC_FLASH_LPC CONFIG_MCUX_COMPONENT_driver.flashiap)
Expand Down
10 changes: 10 additions & 0 deletions tests/drivers/timer/nxp_utick_timer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(nxp_utick_timer)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
10 changes: 10 additions & 0 deletions tests/drivers/timer/nxp_utick_timer/app.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

&utick0
{
status = "okay";
};
5 changes: 5 additions & 0 deletions tests/drivers/timer/nxp_utick_timer/boards/common.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

CONFIG_CORTEX_M_SYSTICK=n
CONFIG_MCUX_OS_TIMER=n
5 changes: 5 additions & 0 deletions tests/drivers/timer/nxp_utick_timer/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

CONFIG_ZTEST=y
CONFIG_MCUX_UTICK_TIMER=y
Loading
Loading