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