diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a53cda6b54..7c07f13e64 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -134,6 +134,7 @@ config ARCH_CHIP_SAMA5 select ARCH_HAVE_FPU select ARCH_HAVE_LOWVECTORS select ARCH_HAVE_I2CRESET + select ARCH_HAVE_TICKLESS ---help--- Atmel SAMA5 (ARM Cortex-A5) diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index 1d854843ee..e81b890d70 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -3564,16 +3564,16 @@ if SCHED_TICKLESS config SAMA5_TICKLESS_ONESHOT int "Tickless one-shot timer channel" - range 0 8 default 0 + range 0 8 ---help--- If the Tickless OS feature is enabled, the one clock must be assigned to provided the one-shot timer needed by the OS. config SAMA5_TICKLESS_FREERUN int "Tickless free-running timer channel" + default 1 range 0 8 - default 0 ---help--- If the Tickless OS feature is enabled, the one clock must be assigned to provided the free-running timer needed by the OS. diff --git a/arch/arm/src/sama5/Make.defs b/arch/arm/src/sama5/Make.defs index cd08660fe4..29d4adef6c 100644 --- a/arch/arm/src/sama5/Make.defs +++ b/arch/arm/src/sama5/Make.defs @@ -258,6 +258,9 @@ endif ifeq ($(CONFIG_SAMA5_FREERUN),y) CHIP_CSRCS += sam_freerun.c endif +ifeq ($(CONFIG_SCHED_TICKLESS),y) +CHIP_CSRCS += sam_tickless.c +endif endif ifeq ($(CONFIG_SAMA5_EBICS0_NAND),y) diff --git a/arch/arm/src/sama5/sam_tickless.c b/arch/arm/src/sama5/sam_tickless.c new file mode 100644 index 0000000000..ce728a454a --- /dev/null +++ b/arch/arm/src/sama5/sam_tickless.c @@ -0,0 +1,365 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_tickless.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +/**************************************************************************** + * Tickless OS Support. + * + * When CONFIG_SCHED_TICKLESS is enabled, all support for timer interrupts + * is suppressed and the platform specific code is expected to provide the + * following custom functions. + * + * void up_timer_initialize(void): Initializes the timer facilities. Called + * early in the intialization sequence (by up_intialize()). + * int up_timer_gettime(FAR struct timespec *ts): Returns the current + * time from the platform specific time source. + * int up_timer_cancel(void): Cancels the interval timer. + * int up_timer_start(FAR const struct timespec *ts): Start (or re-starts) + * the interval timer. + * + * The RTOS will provide the following interfaces for use by the platform- + * specific interval timer implementation: + * + * void sched_timer_expiration(void): Called by the platform-specific + * logic when the interval timer expires. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "sam_oneshot.h" +#include "sam_freerun.h" + +#ifdef CONFIG_SCHED_TICKLESS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_SAMA5_HAVE_TC +# error Timer/counters must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMA5_ONESHOT +# error CONFIG_SAMA5_ONESHOT must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMA5_FREERUN +# error CONFIG_SAMA5_FREERUN must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMA5_TICKLESS_FREERUN +# error CONFIG_SAMA5_TICKLESS_FREERUN must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMA5_TICKLESS_ONESHOT +# error CONFIG_SAMA5_TICKLESS_ONESHOT must be selected for the Tickless OS option +#endif + +#if CONFIG_SAMA5_TICKLESS_ONESHOT == 0 && !defined(CONFIG_SAMA5_TC0) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 0 && CONFIG_SAMA5_TC0 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 1 && !defined(CONFIG_SAMA5_TC1) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 1 && CONFIG_SAMA5_TC1 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 2 && !defined(CONFIG_SAMA5_TC2) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 2 && CONFIG_SAMA5_TC2 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 3 && !defined(CONFIG_SAMA5_TC3) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 3 && CONFIG_SAMA5_TC3 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 4 && !defined(CONFIG_SAMA5_TC4) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 4 && CONFIG_SAMA5_TC4 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 5 && !defined(CONFIG_SAMA5_TC5) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 5 && CONFIG_SAMA5_TC5 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 6 && !defined(CONFIG_SAMA5_TC6) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 6 && CONFIG_SAMA5_TC6 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 7 && !defined(CONFIG_SAMA5_TC7) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 7 && CONFIG_SAMA5_TC7 not selected +#elif CONFIG_SAMA5_TICKLESS_ONESHOT == 8 && !defined(CONFIG_SAMA5_TC8) +# error CONFIG_SAMA5_TICKLESS_ONESHOT == 8 && CONFIG_SAMA5_TC8 not selected +#endif + +#if CONFIG_SAMA5_TICKLESS_ONESHOT < 0 || CONFIG_SAMA5_TICKLESS_ONESHOT > 8 +# error CONFIG_SAMA5_TICKLESS_ONESHOT is not valid +#endif + +#if CONFIG_SAMA5_TICKLESS_FREERUN == 0 && !defined(CONFIG_SAMA5_TC0) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 0 && CONFIG_SAMA5_TC0 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 1 && !defined(CONFIG_SAMA5_TC1) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 1 && CONFIG_SAMA5_TC1 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 2 && !defined(CONFIG_SAMA5_TC2) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 2 && CONFIG_SAMA5_TC2 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 3 && !defined(CONFIG_SAMA5_TC3) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 3 && CONFIG_SAMA5_TC3 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 4 && !defined(CONFIG_SAMA5_TC4) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 4 && CONFIG_SAMA5_TC4 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 5 && !defined(CONFIG_SAMA5_TC5) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 5 && CONFIG_SAMA5_TC5 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 6 && !defined(CONFIG_SAMA5_TC6) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 6 && CONFIG_SAMA5_TC6 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 7 && !defined(CONFIG_SAMA5_TC7) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 7 && CONFIG_SAMA5_TC7 not selected +#elif CONFIG_SAMA5_TICKLESS_FREERUN == 8 && !defined(CONFIG_SAMA5_TC8) +# error CONFIG_SAMA5_TICKLESS_FREERUN == 8 && CONFIG_SAMA5_TC8 not selected +#endif + +#if CONFIG_SAMA5_TICKLESS_FREERUN < 0 || CONFIG_SAMA5_TICKLESS_FREERUN > 8 +# error CONFIG_SAMA5_TICKLESS_FREERUN is not valid +#endif + +#if CONFIG_SAMA5_TICKLESS_FREERUN == CONFIG_SAMA5_TICKLESS_ONESHOT +# error CONFIG_SAMA5_TICKLESS_FREERUN is the same as CONFIG_SAMA5_TICKLESS_ONESHOT +#endif + +#ifdef CONFIG_SAMA5_TC_DEBUG +# define tcdbg dbg +# define tcvdbg vdbg +#else +# define tcdbg(x...) +# define tcvdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sam_tickless_s +{ + struct sam_oneshot_s oneshot; + struct sam_freerun_s freerun; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct sam_tickless_s g_tickless; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_oneshot_handler + * + * Description: + * Called when the one shot timer expires + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence before any special + * concurrency protections are required. + * + ****************************************************************************/ + +static void sam_oneshot_handler(void *arg) +{ + sched_timer_expiration(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_timer_initialize + * + * Description: + * Initializes all platform-specific timer facilities. This function is + * called early in the initialization sequence by up_intialize(). + * On return, the current up-time should be available from + * up_timer_gettime() and the interval timer is ready for use (but not + * actively timing. + * + * Provided by platform-specific code and called from the architecture- + * specific logic. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence before any special + * concurrency protections are required. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + int ret; + + /* Initialize the one-shot timer */ + + ret = sam_oneshot_initialize(&g_tickless.oneshot, + CONFIG_SAMA5_TICKLESS_ONESHOT, + CONFIG_USEC_PER_TICK); + if (ret < 0) + { + tcdbg("ERROR: sam_oneshot_initialize failed\n"); + PANIC(); + } + + /* Initialize the free-running timer */ + + ret = sam_freerun_initialize(&g_tickless.freerun, + CONFIG_SAMA5_TICKLESS_FREERUN, + CONFIG_USEC_PER_TICK); + if (ret < 0) + { + tcdbg("ERROR: sam_freerun_initialize failed\n"); + PANIC(); + } +} + +/**************************************************************************** + * Name: up_timer_gettime + * + * Description: + * Return the elapsed time since power-up (or, more correctly, since + * up_timer_initialize() was called). This function is functionally + * equivalent to: + * + * int clock_gettime(clockid_t clockid, FAR struct timespec *ts); + * + * when clockid is CLOCK_MONOTONIC. + * + * This function provides the basis for reporting the current time and + * also is used to eliminate error build-up from small erros in interval + * time calculations. + * + * Provided by platform-specific code and called from the RTOS base code. + * + * Input Parameters: + * ts - Provides the location in which to return the up-time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * Called from the the normal tasking context. The implementation must + * provide whatever mutual exclusion is necessary for correct operation. + * This can include disabling interrupts in order to assure atomic register + * operations. + * + ****************************************************************************/ + +int up_timer_gettime(FAR struct timespec *ts) +{ + return sam_freerun_counter(&g_tickless.freerun, ts); +} + +/**************************************************************************** + * Name: up_timer_cancel + * + * Description: + * Cancel the interval timer and return the time remaining on the timer. + * These two steps need to be as nearly atomic as possible. + * sched_timer_expiration() will not be called unless the timer is + * restarted with up_timer_start(). + * + * If, as a race condition, the timer has already expired when this + * function is called, then that pending interrupt must be cleared so + * that up_timer_start() and the remaining time of zero should be + * returned. + * + * Provided by platform-specific code and called from the RTOS base code. + * + * Input Parameters: + * ts - Location to return the remaining time. Zero should be returned + * if the timer is not active. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * May be called from interrupt level handling or from the normal tasking + * level. Interrupts may need to be disabled internally to assure + * non-reentrancy. + * + ****************************************************************************/ + +int up_timer_cancel(FAR struct timespec *ts) +{ + return sam_oneshot_cancel(&g_tickless.oneshot, ts); +} + +/**************************************************************************** + * Name: up_timer_start + * + * Description: + * Start the interval timer. sched_timer_expiration() will be + * called at the completion of the timeout (unless up_timer_cancel + * is called to stop the timing. + * + * Provided by platform-specific code and called from the RTOS base code. + * + * Input Parameters: + * ts - Provides the time interval until sched_timer_expiration() is + * called. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * May be called from interrupt level handling or from the normal tasking + * level. Interrupts may need to be disabled internally to assure + * non-reentrancy. + * + ****************************************************************************/ + +int up_timer_start(FAR const struct timespec *ts) +{ + return sam_oneshot_start(&g_tickless.oneshot, sam_oneshot_handler, NULL, ts); +} +#endif /* CONFIG_SCHED_TICKLESS */