From aeb8d017b5ce771df7858f1fca643182a5216da3 Mon Sep 17 00:00:00 2001 From: Vincent Wan Date: Tue, 20 Aug 2019 09:58:04 -0700 Subject: [PATCH] drivers: timer: add RTC support as system clock for CC13X2/CC26X2 Add RTC timer driver for CC13X2/CC26X2, and use it instead of systick as system clock. It is necessary to use this timer for power management support, so that the system can exit from deep sleep upon expiry of timeouts. Signed-off-by: Vincent Wan --- .../cc1352r1_launchxl/cc1352r1_launchxl.dts | 4 + .../cc1352r1_launchxl_defconfig | 1 - .../cc26x2r1_launchxl/cc26x2r1_launchxl.dts | 4 + .../cc26x2r1_launchxl_defconfig | 1 - drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 9 + drivers/timer/cc13x2_cc26x2_rtc_timer.c | 242 ++++++++++++++++++ dts/arm/ti/cc13x2_cc26x2.dtsi | 8 + dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml | 18 ++ .../cc13x2_cc26x2/Kconfig.defconfig.series | 12 +- 10 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 drivers/timer/cc13x2_cc26x2_rtc_timer.c create mode 100644 dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml diff --git a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts index 21eea886a35..c66460528c3 100644 --- a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts +++ b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts @@ -82,3 +82,7 @@ cs-pin = <11>; cs-gpios = <&gpio0 11 0>; }; + +&rtc { + status = "okay"; +}; diff --git a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl_defconfig b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl_defconfig index e91fe3733ee..728956c9478 100644 --- a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl_defconfig +++ b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl_defconfig @@ -7,7 +7,6 @@ CONFIG_ARM=y CONFIG_SOC_SERIES_CC13X2_CC26X2=y CONFIG_SOC_CC1352R=y -CONFIG_CORTEX_M_SYSTICK=y CONFIG_BOARD_CC1352R1_LAUNCHXL=y CONFIG_CC13X2_CC26X2_BOOTLOADER_ENABLE=y diff --git a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts index 4a0b2d13ae7..52829ba2405 100644 --- a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts +++ b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts @@ -82,3 +82,7 @@ cs-pin = <11>; cs-gpios = <&gpio0 11 0>; }; + +&rtc { + status = "okay"; +}; diff --git a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl_defconfig b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl_defconfig index 77e94fcb441..703fdcccd9a 100644 --- a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl_defconfig +++ b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl_defconfig @@ -7,7 +7,6 @@ CONFIG_ARM=y CONFIG_SOC_SERIES_CC13X2_CC26X2=y CONFIG_SOC_CC2652R=y -CONFIG_CORTEX_M_SYSTICK=y CONFIG_BOARD_CC26X2R1_LAUNCHXL=y CONFIG_CC13X2_CC26X2_BOOTLOADER_ENABLE=y diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index b124c6ff664..90e5f0417ff 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -16,3 +16,4 @@ zephyr_sources_if_kconfig( sam0_rtc_timer.c) zephyr_sources_if_kconfig( litex_timer.c) zephyr_sources_if_kconfig( mchp_xec_rtos_timer.c) zephyr_sources_if_kconfig( xlnx_psttc_timer.c) +zephyr_sources_if_kconfig( cc13x2_cc26x2_rtc_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index ad5da1be01c..e9fb28e250d 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -220,6 +220,15 @@ config MCHP_XEC_RTOS_TIMER XEC series RTOS timer and provides the standard "system clock driver" interfaces. +config CC13X2_CC26X2_RTC_TIMER + bool "TI SimpleLink CC13x2/CC26x2 RTC timer" + depends on SOC_SERIES_CC13X2_CC26X2 + select TICKLESS_CAPABLE + help + This module implements a kernel device driver for the TI SimpleLink + CC13X2_CC26X2 series Real Time Counter and provides the standard + "system clock driver" interfaces. + config XLNX_PSTTC_TIMER bool "Xilinx PS ttc timer support" default y diff --git a/drivers/timer/cc13x2_cc26x2_rtc_timer.c b/drivers/timer/cc13x2_cc26x2_rtc_timer.c new file mode 100644 index 00000000000..91924e03712 --- /dev/null +++ b/drivers/timer/cc13x2_cc26x2_rtc_timer.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2019, Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * TI SimpleLink CC13X2/CC26X2 RTC-based system timer + * + * This system timer implementation supports both tickless and ticking modes. + * RTC counts continually in 64-bit mode and timeouts are + * scheduled using the RTC comparator. An interrupt is triggered whenever + * the comparator value set is reached. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define RTC_COUNTS_PER_SEC 0x100000000ULL + +/* Number of counts per rtc timer cycle */ +#define RTC_COUNTS_PER_CYCLE (RTC_COUNTS_PER_SEC / \ + sys_clock_hw_cycles_per_sec()) + +/* Number of counts per system clock tick */ +#define RTC_COUNTS_PER_TICK (RTC_COUNTS_PER_SEC / \ + CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +/* Number of RTC cycles per system clock tick */ +#define CYCLES_PER_TICK (sys_clock_hw_cycles_per_sec() / \ + CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +/* + * Maximum number of ticks. + */ +#define MAX_TICKS (0x7FFFFFFFFFFFULL / RTC_COUNTS_PER_TICK) + +/* + * Due to the nature of clock synchronization, the comparator cannot be set + * to a value that is too close to the current time. This constant defines + * a safe threshold for the comparator. + */ +#define COMPARE_MARGIN 6 + +/* RTC count of the last announce call, rounded down to tick boundary. */ +static volatile u64_t rtc_last; + +#ifdef CONFIG_TICKLESS_KERNEL +static struct k_spinlock lock; +#else +static u64_t nextThreshold = RTC_COUNTS_PER_TICK; +#endif /* CONFIG_TICKLESS_KERNEL */ + + +static void setThreshold(u32_t next) +{ + u32_t now; + unsigned int key; + + key = irq_lock(); + + /* get the current RTC count corresponding to compare window */ + now = AONRTCCurrentCompareValueGet(); + + /* if next is too soon, set at least one RTC tick in future */ + /* assume next never be more than half the maximum 32 bit count value */ + if ((next - now) > (u32_t)0x80000000) { + /* now is past next */ + next = now + COMPARE_MARGIN; + } else if ((now + COMPARE_MARGIN - next) < (u32_t)0x80000000) { + if (next < now + COMPARE_MARGIN) { + next = now + COMPARE_MARGIN; + } + } + + /* set next compare threshold in RTC */ + AONRTCCompareValueSet(AON_RTC_CH0, next); + + irq_unlock(key); +} + +void rtc_isr(void *arg) +{ +#ifndef CONFIG_TICKLESS_KERNEL + u64_t newThreshold; + u32_t next; +#else + u64_t ticks, currCount; +#endif + + ARG_UNUSED(arg); + + AONRTCEventClear(AON_RTC_CH0); + +#ifdef CONFIG_TICKLESS_KERNEL + k_spinlock_key_t key = k_spin_lock(&lock); + currCount = (u64_t)AONRTCCurrent64BitValueGet(); + ticks = (currCount - rtc_last) / RTC_COUNTS_PER_TICK; + + rtc_last += ticks * RTC_COUNTS_PER_TICK; + k_spin_unlock(&lock, key); + + z_clock_announce(ticks); + +#else /* !CONFIG_TICKLESS_KERNEL */ + + /* calculate new 64-bit RTC count for next interrupt */ + newThreshold = nextThreshold + RTC_COUNTS_PER_TICK; + + next = (u32_t)((u64_t)newThreshold >> 16); + setThreshold(next); + + nextThreshold = newThreshold; + + rtc_last += RTC_COUNTS_PER_TICK; + + z_clock_announce(1); + +#endif /* CONFIG_TICKLESS_KERNEL */ +} + +static void initDevice(void) +{ + AONRTCDisable(); + AONRTCReset(); + + HWREG(AON_RTC_BASE + AON_RTC_O_SYNC) = 1; + /* read sync register to complete reset */ + HWREG(AON_RTC_BASE + AON_RTC_O_SYNC); + + AONRTCEventClear(AON_RTC_CH0); + IntPendClear(INT_AON_RTC_COMB); + + HWREG(AON_RTC_BASE + AON_RTC_O_SYNC); +} + +static void startDevice(void) +{ + u32_t compare; + u64_t period; + unsigned int key; + + key = irq_lock(); + + /* reset timer */ + AONRTCReset(); + AONRTCEventClear(AON_RTC_CH0); + IntPendClear(INT_AON_RTC_COMB); + + /* + * set the compare register to one period. + * For a very small period round up to interrupt upon 4th tick in + * compare register + */ + period = RTC_COUNTS_PER_TICK; + if (period < 0x40000) { + compare = 0x4; /* 4 * 15.5us ~= 62us */ + } else { + /* else, interrupt on first period expiration */ + compare = period >> 16; + } + + /* set the compare value at the RTC */ + AONRTCCompareValueSet(AON_RTC_CH0, compare); + + /* enable compare channel 0 */ + AONEventMcuWakeUpSet(AON_EVENT_MCU_WU0, AON_EVENT_RTC0); + AONRTCChannelEnable(AON_RTC_CH0); + AONRTCCombinedEventConfig(AON_RTC_CH0); + + /* start timer */ + AONRTCEnable(); + + irq_unlock(key); +} + +int z_clock_driver_init(struct device *device) +{ + ARG_UNUSED(device); + + rtc_last = 0U; + + initDevice(); + startDevice(); + + /* Enable RTC interrupt. */ + IRQ_CONNECT(DT_INST_0_TI_CC13XX_CC26XX_RTC_IRQ_0, + DT_INST_0_TI_CC13XX_CC26XX_RTC_IRQ_0_PRIORITY, + rtc_isr, 0, 0); + irq_enable(DT_INST_0_TI_CC13XX_CC26XX_RTC_IRQ_0); + + return 0; +} + +void z_clock_set_timeout(s32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + +#ifdef CONFIG_TICKLESS_KERNEL + + ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks; + ticks = MAX(MIN(ticks - 1, (s32_t) MAX_TICKS), 0); + + k_spinlock_key_t key = k_spin_lock(&lock); + + /* Compute number of RTC cycles until the next timeout. */ + u64_t count = AONRTCCurrent64BitValueGet(); + u64_t timeout = ticks * RTC_COUNTS_PER_TICK + + (count - rtc_last); + + /* Round to the nearest tick boundary. */ + timeout = (timeout + RTC_COUNTS_PER_TICK - 1) / RTC_COUNTS_PER_TICK + * RTC_COUNTS_PER_TICK; + + timeout += rtc_last; + + /* Set the comparator */ + setThreshold(timeout >> 16); + + k_spin_unlock(&lock, key); +#endif /* CONFIG_TICKLESS_KERNEL */ +} + +u32_t z_clock_elapsed(void) +{ + u32_t ret = (AONRTCCurrent64BitValueGet() - rtc_last) / + RTC_COUNTS_PER_TICK; + + return ret; +} + +u32_t z_timer_cycle_get_32(void) +{ + return (AONRTCCurrent64BitValueGet() / RTC_COUNTS_PER_CYCLE) + & 0xFFFFFFFF; +} diff --git a/dts/arm/ti/cc13x2_cc26x2.dtsi b/dts/arm/ti/cc13x2_cc26x2.dtsi index 3e4feb53fdd..5fe867c06b8 100644 --- a/dts/arm/ti/cc13x2_cc26x2.dtsi +++ b/dts/arm/ti/cc13x2_cc26x2.dtsi @@ -113,6 +113,14 @@ status = "disabled"; label = "SPI_1"; }; + + rtc: rtc@40092000 { + compatible = "ti,cc13xx-cc26xx-rtc"; + reg = <0x40092000 0x1000>; + interrupts = <4 0>; /* interrupt #20 = 4 + 16 */ + status = "disabled"; + label = "RTC"; + }; }; }; diff --git a/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml b/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml new file mode 100644 index 00000000000..265e0d88b0a --- /dev/null +++ b/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2019, Texas Instruments Incorporated +# +# SPDX-License-Identifier: Apache-2.0 +# + +title: TI SimpleLink CC13xx/CC26xx RTC + +description: > + This binding gives a base representation of the TI SimpleLink CC13xx/CC26xx RTC + +compatible: "ti,cc13xx-cc26xx-rtc" + +include: rtc.yaml + +properties: + reg: + required: true diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.defconfig.series b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.defconfig.series index 9fcf14b8745..c35685b39df 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.defconfig.series +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.defconfig.series @@ -15,7 +15,14 @@ config SOC_SERIES config SYS_CLOCK_HW_CYCLES_PER_SEC int - default 48000000 + default 32768 + +# Note that when using the RTC as system clock, this needs to be 32768 +# to reduce truncation errors from accumulating due to conversion to/from +# time, ticks, and HW cycles +config SYS_CLOCK_TICKS_PER_SEC + int + default 32768 config NUM_IRQS int @@ -25,6 +32,9 @@ config TI_CCFG_PRESENT bool default y +config CC13X2_CC26X2_RTC_TIMER + default y + if PINMUX config PINMUX_CC13XX_CC26XX