Browse Source

Microchip: XEC RTOS timer: Add MEC172x support to driver

Update Microchip XEC RTOS timer driver adding MEC172x support and
using more device tree properities in the driver. We must also update
the XEC counter driver to use the new GIRQ DT properties.
Add new properties to RTOS timer and RTC timer YAML. These two timers
are linked due to option using a high speed timer for kernel busy wait.
Add Kconfig logic for XEC RTOS timer to MEC172x SoC.
Enable the Microchip XEC RTOS timer in the MEC172x evaluation board.
Add device tree nodes for most peripeherals.

Signed-off-by: Scott Worley <scott.worley@microchip.com>
pull/37252/head
Scott Worley 4 years ago committed by Christopher Friedt
parent
commit
dd1a9559be
  1. 2
      boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts
  2. 30
      boards/arm/mec172xevb_assy6906/Kconfig.defconfig
  3. 4
      boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts
  4. 3
      boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig
  5. 4
      drivers/counter/counter_mchp_xec.c
  6. 130
      drivers/timer/mchp_xec_rtos_timer.c
  7. 54
      dts/arm/microchip/mec1501hsz.dtsi
  8. 25
      dts/arm/microchip/mec172xnsz.dtsi
  9. 28
      dts/bindings/rtc/microchip,xec-timer.yaml
  10. 15
      dts/bindings/timer/microchip,xec-rtos-timer.yaml
  11. 14
      soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series
  12. 3
      soc/arm/microchip_mec/mec172x/Kconfig.soc

2
boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts

@ -125,7 +125,7 @@ @@ -125,7 +125,7 @@
pc_girq = <15>;
};
&timer3 {
&timer5 {
status = "okay";
};

30
boards/arm/mec172xevb_assy6906/Kconfig.defconfig

@ -6,4 +6,34 @@ if BOARD_MEC172XEVB_ASSY6906 @@ -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

4
boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
};
&cpu0 {
clock-frequency = <96000000>;
status = "okay";
};
/* Initialize ECIA. Does not initialize child devices */
@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
status = "okay";
};
&systick {
&rtimer {
status = "okay";
};

3
boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig

@ -7,8 +7,7 @@ @@ -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

4
drivers/counter/counter_mchp_xec.c

@ -318,8 +318,8 @@ static int counter_xec_init(const struct device *dev) @@ -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, \

130
drivers/timer/mchp_xec_rtos_timer.c

@ -6,10 +6,12 @@ @@ -6,10 +6,12 @@
#define DT_DRV_COMPAT microchip_xec_rtos_timer
#include <devicetree.h>
#include <soc.h>
#include <drivers/timer/system_timer.h>
#include <sys_clock.h>
#include <spinlock.h>
#include <arch/arm/aarch32/cortex_m/cmsis.h>
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, @@ -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))
/* Mask off bits[31:28] of 32-bit count */
#define TIMER_MAX 0x0FFFFFFFUL
#define ECIA_XEC_REGS \
((struct ecia_regs *)DT_REG_ADDR(DT_NODELABEL(ecia)))
#define TIMER_COUNT_MASK 0x0FFFFFFFUL
#ifdef CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT
#define PCR_XEC_REGS \
((struct pcr_regs *)DT_REG_ADDR(DT_NODELABEL(pcr)))
#define TIMER_STOPPED 0xF0000000UL
/*
* 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 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, @@ -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; @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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;

54
dts/arm/microchip/mec1501hsz.dtsi

@ -61,13 +61,23 @@ @@ -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 @@ @@ -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>;
};
/*
* 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 = <0x40000c80 0x20>;
interrupts = <140 0>;
label = "TIMER_4";
max-value = <0xFFFFFFFF>;
prescaler = <0>;
girqs = <23 4>;
pcrs = <3 23>;
status = "disabled";
};
timer3: timer@40000ca0 {
timer5: timer@40000ca0 {
compatible = "microchip,xec-timer";
clock-frequency = <48000000>;
reg = <0x40000CA0 0x20>;
reg = <0x40000ca0 0x20>;
interrupts = <141 0>;
label = "TIMER_3";
label = "TIMER_5";
max-value = <0xFFFFFFFF>;
prescaler = <0>;
girq = <23>;
girq-bit = <5>;
girqs = <23 5>;
pcrs = <3 24>;
};
ps2_0: ps2@40009000 {
compatible = "microchip,xec-ps2";

25
dts/arm/microchip/mec172xnsz.dtsi

@ -314,14 +314,16 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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>;

28
dts/bindings/rtc/microchip,xec-timer.yaml

@ -27,12 +27,28 @@ properties: @@ -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

15
dts/bindings/timer/microchip,xec-rtos-timer.yaml

@ -17,12 +17,15 @@ properties: @@ -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

14
soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series

@ -16,8 +16,22 @@ config NUM_IRQS @@ -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

3
soc/arm/microchip_mec/mec172x/Kconfig.soc

@ -12,6 +12,9 @@ config SOC_MEC172X_NSZ @@ -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

Loading…
Cancel
Save