diff --git a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts index a69c026e8cd..510544a2e55 100644 --- a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts +++ b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts @@ -125,7 +125,7 @@ pc_girq = <15>; }; -&timer3 { +&timer5 { status = "okay"; }; diff --git a/boards/arm/mec172xevb_assy6906/Kconfig.defconfig b/boards/arm/mec172xevb_assy6906/Kconfig.defconfig index d5598995817..8b23b520e1f 100644 --- a/boards/arm/mec172xevb_assy6906/Kconfig.defconfig +++ b/boards/arm/mec172xevb_assy6906/Kconfig.defconfig @@ -6,4 +6,34 @@ if BOARD_MEC172XEVB_ASSY6906 config BOARD default "mec172xevb_assy6906" +if RTOS_TIMER + +# XEC RTOS timer HW frequency is fixed at 32768 Hz. +# The driver requires tickless mode and ticks per second to be 32768 for +# accurate operation. + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config SYS_CLOCK_TICKS_PER_SEC + default 32768 + +endif # RTOS_TIMER + +if !RTOS_TIMER + +# If RTOS timer is not enabled we use ARM Cortex-M +# SYSTICK. SYSTICK frequency is 96 MHz divided down by the MEC172x PCR +# processor clock divider register. We assume PCR processor clock divider +# is set to 1. Refer to SOC_MEC172X_PROC_CLK_DIV +# + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 96000000 + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +endif # RTOS_TIMER + endif # BOARD_MEC172XEVB_ASSY6906 diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts index 198acaf45d3..466568d0e2f 100644 --- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts +++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts @@ -20,7 +20,7 @@ }; &cpu0 { - clock-frequency = <96000000>; + status = "okay"; }; /* Initialize ECIA. Does not initialize child devices */ @@ -28,7 +28,7 @@ status = "okay"; }; -&systick { +&rtimer { status = "okay"; }; diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig index f8c33a22e59..bd2a206cc56 100644 --- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig +++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig @@ -7,8 +7,7 @@ CONFIG_SOC_MEC172X_NSZ=y CONFIG_SOC_SERIES_MEC172X=y CONFIG_BOARD_MEC172XEVB_ASSY6906=y - -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 +CONFIG_RTOS_TIMER=y CONFIG_CLOCK_CONTROL=y CONFIG_SERIAL=y diff --git a/drivers/counter/counter_mchp_xec.c b/drivers/counter/counter_mchp_xec.c index a75d7634f25..39583ac278f 100644 --- a/drivers/counter/counter_mchp_xec.c +++ b/drivers/counter/counter_mchp_xec.c @@ -318,8 +318,8 @@ static int counter_xec_init(const struct device *dev) .config_func = counter_xec_irq_config_##inst, \ .base_address = DT_INST_REG_ADDR(inst), \ .prescaler = DT_INST_PROP(inst, prescaler), \ - .girq_id = DT_INST_PROP(inst, girq), \ - .girq_bit = DT_INST_PROP(inst, girq_bit), \ + .girq_id = DT_INST_PROP_BY_IDX(0, girqs, 0), \ + .girq_bit = DT_INST_PROP_BY_IDX(0, girqs, 1), \ }; \ \ DEVICE_DT_INST_DEFINE(inst, \ diff --git a/drivers/timer/mchp_xec_rtos_timer.c b/drivers/timer/mchp_xec_rtos_timer.c index 360c83194ff..7dd853dd13f 100644 --- a/drivers/timer/mchp_xec_rtos_timer.c +++ b/drivers/timer/mchp_xec_rtos_timer.c @@ -6,10 +6,12 @@ #define DT_DRV_COMPAT microchip_xec_rtos_timer +#include #include #include #include #include +#include BUILD_ASSERT(!IS_ENABLED(CONFIG_SMP), "XEC RTOS timer doesn't support SMP"); BUILD_ASSERT(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 32768, @@ -50,14 +52,30 @@ BUILD_ASSERT(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 32768, (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC) #define TIMER_REGS \ - ((RTMR_Type *) DT_INST_REG_ADDR(0)) + ((struct rtmr_regs *)DT_INST_REG_ADDR(0)) + +#define ECIA_XEC_REGS \ + ((struct ecia_regs *)DT_REG_ADDR(DT_NODELABEL(ecia))) + +#ifdef CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT +#define PCR_XEC_REGS \ + ((struct pcr_regs *)DT_REG_ADDR(DT_NODELABEL(pcr))) + +/* + * pcrs property at index 0 is register index into array of 32-bit PCR SLP_EN, + * CLK_REQ, or RST_EN registers. Property at index 1 is the bit position. + */ /*DT_PROP_BY_IDX(DT_NODELABEL(kbc0), girqs, 0)*/ +#define BTMR32_0_PCR_REG_IDX (DT_PROP_BY_IDX(DT_NODELABEL(timer4), pcrs, 0)) +#define BTMR32_0_PCR_BITPOS (DT_PROP_BY_IDX(DT_NODELABEL(timer4), pcrs, 1)) + +#define BTMR32_0_REGS \ + ((struct btmr_regs *)(DT_REG_ADDR(DT_NODELABEL(timer4)))) +#endif /* Mask off bits[31:28] of 32-bit count */ -#define TIMER_MAX 0x0FFFFFFFUL - -#define TIMER_COUNT_MASK 0x0FFFFFFFUL - -#define TIMER_STOPPED 0xF0000000UL +#define TIMER_MAX 0x0fffffffu +#define TIMER_COUNT_MASK 0x0fffffffu +#define TIMER_STOPPED 0xf0000000u /* Adjust cycle count programmed into timer for HW restart latency */ #define TIMER_ADJUST_LIMIT 2 @@ -66,6 +84,11 @@ BUILD_ASSERT(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 32768, /* max number of ticks we can load into the timer in one shot */ #define MAX_TICKS (TIMER_MAX / CYCLES_PER_TICK) +#define TIMER_GIRQ DT_INST_PROP_BY_IDX(0, girqs, 0) +#define TIMER_GIRQ_POS DT_INST_PROP_BY_IDX(0, girqs, 1) +#define TIMER_NVIC_NO DT_INST_IRQN(0) +#define TIMER_NVIC_PRIO DT_INST_IRQ(0, priority) + /* * The spinlock protects all access to the RTMR registers, as well as * 'total_cycles', 'last_announcement', and 'cached_icr'. @@ -79,6 +102,38 @@ static struct k_spinlock lock; static uint32_t total_cycles; static uint32_t cached_icr = CYCLES_PER_TICK; +/* + * NOTE: using inline for speed instead of call to external SoC function. + * MEC GIRQ numbers are documented as 8 to 26, check and convert to zero + * based index. + */ +static inline void girq_src_clr(int girq, int bitpos) +{ + if ((girq < 8) || (girq > 26)) { + return; + } + + ECIA_XEC_REGS->GIRQ[girq - 8].SRC = BIT(bitpos); +} + +static inline void girq_src_en(int girq, int bitpos) +{ + if ((girq < 8) || (girq > 26)) { + return; + } + + ECIA_XEC_REGS->GIRQ[girq - 8].EN_SET = BIT(bitpos); +} + +static inline void girq_src_dis(int girq, int bitpos) +{ + if ((girq < 8) || (girq > 26)) { + return; + } + + ECIA_XEC_REGS->GIRQ[girq - 8].EN_CLR = BIT(bitpos); +} + static void timer_restart(uint32_t countdown) { TIMER_REGS->CTRL = 0U; @@ -160,10 +215,9 @@ void sys_clock_set_timeout(int32_t n, bool idle) ccr = timer_count(); /* turn off to clear any pending interrupt status */ - TIMER_REGS->CTRL = 0U; - MCHP_GIRQ_SRC(DT_INST_PROP(0, girq)) = - BIT(DT_INST_PROP(0, girq_bit)); - NVIC_ClearPendingIRQ(RTMR_IRQn); + TIMER_REGS->CTRL = 0u; + girq_src_clr(TIMER_GIRQ, TIMER_GIRQ_POS); + NVIC_ClearPendingIRQ(TIMER_NVIC_NO); temp = total_cycles; temp += (cached_icr - ccr); @@ -222,8 +276,7 @@ static void xec_rtos_timer_isr(const void *arg) k_spinlock_key_t key = k_spin_lock(&lock); - MCHP_GIRQ_SRC(DT_INST_PROP(0, girq)) = - BIT(DT_INST_PROP(0, girq_bit)); + girq_src_clr(TIMER_GIRQ, TIMER_GIRQ_POS); /* Restart the timer as early as possible to minimize drift... */ timer_restart(MAX_TICKS * CYCLES_PER_TICK); @@ -255,8 +308,7 @@ static void xec_rtos_timer_isr(const void *arg) k_spinlock_key_t key = k_spin_lock(&lock); - MCHP_GIRQ_SRC(DT_INST_PROP(0, girq)) = - BIT(DT_INST_PROP(0, girq_bit)); + girq_src_clr(TIMER_GIRQ, TIMER_GIRQ_POS); /* Restart the timer as early as possible to minimize drift... */ timer_restart(cached_icr); @@ -318,40 +370,42 @@ int sys_clock_driver_init(const struct device *dev) { ARG_UNUSED(dev); - mchp_pcr_periph_slp_ctrl(PCR_RTMR, MCHP_PCR_SLEEP_DIS); - #ifdef CONFIG_TICKLESS_KERNEL cached_icr = MAX_TICKS; #endif - TIMER_REGS->CTRL = 0U; - MCHP_GIRQ_SRC(DT_INST_PROP(0, girq)) = - BIT(DT_INST_PROP(0, girq_bit)); - NVIC_ClearPendingIRQ(RTMR_IRQn); + TIMER_REGS->CTRL = 0u; + girq_src_clr(TIMER_GIRQ, TIMER_GIRQ_POS); + girq_src_dis(TIMER_GIRQ, TIMER_GIRQ_POS); + NVIC_ClearPendingIRQ(TIMER_NVIC_NO); - IRQ_CONNECT(RTMR_IRQn, - DT_INST_IRQ(0, priority), - xec_rtos_timer_isr, 0, 0); - - MCHP_GIRQ_ENSET(DT_INST_PROP(0, girq)) = - BIT(DT_INST_PROP(0, girq_bit)); - irq_enable(RTMR_IRQn); + IRQ_CONNECT(TIMER_NVIC_NO, TIMER_NVIC_PRIO, xec_rtos_timer_isr, 0, 0); + irq_enable(TIMER_NVIC_NO); + girq_src_en(TIMER_GIRQ, TIMER_GIRQ_POS); #ifdef CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT - uint32_t btmr_ctrl = B32TMR0_REGS->CTRL = (MCHP_BTMR_CTRL_ENABLE - | MCHP_BTMR_CTRL_AUTO_RESTART - | MCHP_BTMR_CTRL_COUNT_UP - | (47UL << MCHP_BTMR_CTRL_PRESCALE_POS)); - B32TMR0_REGS->CTRL = MCHP_BTMR_CTRL_SOFT_RESET; - B32TMR0_REGS->CTRL = btmr_ctrl; - B32TMR0_REGS->PRLD = 0xFFFFFFFFUL; + uint32_t btmr_ctrl = (MCHP_BTMR_CTRL_ENABLE + | MCHP_BTMR_CTRL_AUTO_RESTART + | MCHP_BTMR_CTRL_COUNT_UP + | (47UL << MCHP_BTMR_CTRL_PRESCALE_POS)); + +#if CONFIG_SOC_SERIES_MEC1501X + mchp_pcr_periph_slp_ctrl(PCR_B32TMR0, 0); +#else + PCR_XEC_REGS->SLP_EN[BTMR32_0_PCR_REG_IDX] &= ~BIT(BTMR32_0_PCR_BITPOS); +#endif + BTMR32_0_REGS->CTRL = MCHP_BTMR_CTRL_SOFT_RESET; + BTMR32_0_REGS->CTRL = btmr_ctrl; + BTMR32_0_REGS->PRLD = UINT32_MAX; btmr_ctrl |= MCHP_BTMR_CTRL_START; timer_restart(cached_icr); - /* wait for Hibernation timer to load count register from preload */ - while (TIMER_REGS->CNT == 0) + /* wait for RTOS timer to load count register from preload */ + while (TIMER_REGS->CNT == 0) { ; - B32TMR0_REGS->CTRL = btmr_ctrl; + } + + BTMR32_0_REGS->CTRL = btmr_ctrl; #else timer_restart(cached_icr); #endif @@ -377,10 +431,10 @@ void arch_busy_wait(uint32_t usec_to_wait) return; } - uint32_t start = B32TMR0_REGS->CNT; + uint32_t start = BTMR32_0_REGS->CNT; for (;;) { - uint32_t curr = B32TMR0_REGS->CNT; + uint32_t curr = BTMR32_0_REGS->CNT; if ((curr - start) >= usec_to_wait) { break; diff --git a/dts/arm/microchip/mec1501hsz.dtsi b/dts/arm/microchip/mec1501hsz.dtsi index 29d49e68853..e8441b81efc 100644 --- a/dts/arm/microchip/mec1501hsz.dtsi +++ b/dts/arm/microchip/mec1501hsz.dtsi @@ -61,13 +61,23 @@ }; soc { + pcr: pcr@40080100 { + reg = <0x40080100 0x100 0x4000a400 0x100>; + reg-names = "pcrr", "vbatr"; + label = "PCR"; + }; + ecia: ecia@4000e000 { + reg = <0x4000e000 0x400>; + label = "ECIA_0"; + #address-cells = <1>; + #size-cells = <1>; + }; rtimer: timer@40007400 { compatible = "microchip,xec-rtos-timer"; reg = <0x40007400 0x10>; interrupts = <111 0>; label = "RTIMER"; - girq = <23>; - girq-bit = <10>; + girqs = <23 10>; }; wdog: watchdog@40000400 { compatible = "microchip,xec-watchdog"; @@ -242,37 +252,55 @@ timer0: timer@40000c00 { compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C00 0x20>; + reg = <0x40000c00 0x20>; interrupts = <136 0>; label = "TIMER_0"; max-value = <0xFFFF>; prescaler = <0>; status = "disabled"; - girq = <23>; - girq-bit = <0>; + girqs = <23 0>; + pcrs = <1 30>; }; timer1: timer@40000c20 { compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C20 0x20>; + reg = <0x40000c20 0x20>; interrupts = <137 0>; label = "TIMER_1"; max-value = <0xFFFF>; prescaler = <0>; status = "disabled"; - girq = <23>; - girq-bit = <1>; + girqs = <23 1>; + pcrs = <1 31>; }; - timer3: timer@40000ca0 { + /* + * NOTE 1: timers 2 and 3 not implemented in MEC152x. + * NOTE 2: When RTOS timer used as kernel timer, timer4 used + * to provide high speed busy wait counter. Keep disabled to + * prevent counter driver from claiming it. + */ + timer4: timer@40000c80 { compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000CA0 0x20>; - interrupts = <141 0>; - label = "TIMER_3"; + reg = <0x40000c80 0x20>; + interrupts = <140 0>; + label = "TIMER_4"; max-value = <0xFFFFFFFF>; prescaler = <0>; - girq = <23>; - girq-bit = <5>; + girqs = <23 4>; + pcrs = <3 23>; + status = "disabled"; + }; + timer5: timer@40000ca0 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000ca0 0x20>; + interrupts = <141 0>; + label = "TIMER_5"; + max-value = <0xFFFFFFFF>; + prescaler = <0>; + girqs = <23 5>; + pcrs = <3 24>; }; ps2_0: ps2@40009000 { compatible = "microchip,xec-ps2"; diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 29c2597ffc5..017ecaaf208 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -314,14 +314,16 @@ #pcrs-cells = <2>; }; rtimer: timer@40007400 { + compatible = "microchip,xec-rtos-timer"; reg = <0x40007400 0x10>; interrupts = <111 0>; label = "RTIMER"; girqs = <23 10>; }; timer0: timer@40000c00 { + compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C00 0x20>; + reg = <0x40000c00 0x20>; interrupts = <136 0>; girqs = <23 0>; pcrs = <1 30>; @@ -333,8 +335,9 @@ status = "disabled"; }; timer1: timer@40000c20 { + compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C20 0x20>; + reg = <0x40000c20 0x20>; interrupts = <137 0>; girqs = <23 1>; pcrs = <1 31>; @@ -346,8 +349,9 @@ status = "disabled"; }; timer2: timer@40000c40 { + compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C40 0x20>; + reg = <0x40000c40 0x20>; interrupts = <138 0>; girqs = <23 2>; pcrs = <3 21>; @@ -359,8 +363,9 @@ status = "disabled"; }; timer3: timer@40000c60 { + compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C60 0x20>; + reg = <0x40000c60 0x20>; interrupts = <139 0>; girqs = <23 3>; pcrs = <3 22>; @@ -371,23 +376,29 @@ #pcrs-cells = <2>; status = "disabled"; }; + /* + * NOTE: When RTOS timer used as kernel timer, timer4 used + * to provide high speed busy wait counter. Keep disabled to + * prevent counter driver from claiming it. + */ timer4: timer@40000c80 { + compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000C80 0x20>; + reg = <0x40000c80 0x20>; interrupts = <140 0>; girqs = <23 4>; pcrs = <3 23>; label = "TIMER_4"; max-value = <0xFFFFFFFF>; prescaler = <0>; - exclude; #girqs-cells = <2>; #pcrs-cells = <2>; status = "disabled"; }; timer5: timer@40000ca0 { + compatible = "microchip,xec-timer"; clock-frequency = <48000000>; - reg = <0x40000CA0 0x20>; + reg = <0x40000ca0 0x20>; interrupts = <141 0>; girqs = <23 5>; pcrs = <3 24>; diff --git a/dts/bindings/rtc/microchip,xec-timer.yaml b/dts/bindings/rtc/microchip,xec-timer.yaml index f10498c896f..a83c5e0bc23 100644 --- a/dts/bindings/rtc/microchip,xec-timer.yaml +++ b/dts/bindings/rtc/microchip,xec-timer.yaml @@ -27,12 +27,28 @@ properties: required: true description: Maximum counter value the instance can handle - girq: - type: int + girqs: + type: array required: true - description: GIRQ for this device + description: Array of GIRQ numbers [8:26] and bit positions [0:31]. - girq-bit: - type: int + pcrs: + type: array required: true - description: Bit position in GIRQ for this device + description: PCR sleep enable register index and bit position. + + "girqs-cells": + type: int + const: 2 + + "#pcrs-cells": + type: int + const: 2 + +girqs-cells: + - girq_num + - bitpos + +pcrs-cells: + - reg_index + - bitpos diff --git a/dts/bindings/timer/microchip,xec-rtos-timer.yaml b/dts/bindings/timer/microchip,xec-rtos-timer.yaml index 3cad9d65ad3..d26976738a2 100644 --- a/dts/bindings/timer/microchip,xec-rtos-timer.yaml +++ b/dts/bindings/timer/microchip,xec-rtos-timer.yaml @@ -17,12 +17,15 @@ properties: label: required: true - girq: - type: int + girqs: + type: array required: true - description: GIRQ for this device + description: Array of GIRQ numbers [8:26] and bit positions [0:31]. - girq-bit: + "girqs-cells": type: int - required: true - description: Bit position in GIRQ for this device + const: 2 + +girqs-cells: + - girq_num + - bitpos diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series index 76244dde6a9..1a34351051b 100644 --- a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series +++ b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series @@ -16,8 +16,22 @@ config NUM_IRQS source "soc/arm/microchip_mec/mec172x/Kconfig.defconfig.mec172x*" +if RTOS_TIMER + +config MCHP_XEC_RTOS_TIMER + default y + +config SOC_HAS_TIMING_FUNCTIONS + default y if !CORTEX_M_DWT + +config ARCH_HAS_CUSTOM_BUSY_WAIT + default y + +endif # RTOS_TIMER + config CORTEX_M_SYSTICK default y + depends on !RTOS_TIMER config CLOCK_CONTROL_MCHP_XEC default y diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.soc b/soc/arm/microchip_mec/mec172x/Kconfig.soc index 827819c80a0..4b910c154de 100644 --- a/soc/arm/microchip_mec/mec172x/Kconfig.soc +++ b/soc/arm/microchip_mec/mec172x/Kconfig.soc @@ -12,6 +12,9 @@ config SOC_MEC172X_NSZ endchoice +config RTOS_TIMER + bool "MEC172x RTOS Timer(32KHz) as kernel timer" + config SOC_MEC172X_PROC_CLK_DIV int "PROC_CLK_DIV" default 1