blob: 7d3ccf1f3bab6bd66592ddf1e47d853057ce42f9 [file] [log] [blame]
/* timestamps.c - timestamp support for tickless idle testing */
/*
* Copyright (c) 2014 Wind River Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
DESCRIPTION
Platform-specific timestamp support for the tickless idle test.
*/
#include <tc_util.h>
#include <stddef.h>
#if defined(CONFIG_SOC_TI_LM3S6965_QEMU)
/*
* @brief Use a General Purpose Timer in
* 32-bit periodic timer mode (down-counter)
* (RTC mode's resolution of 1 second is insufficient.)
*/
#define _TIMESTAMP_NUM 0 /* set to timer # for use by timestamp (0-3) */
#define _CLKGATECTRL *((volatile uint32_t *)0x400FE104)
#define _CLKGATECTRL_TIMESTAMP_EN (1 << (16 + _TIMESTAMP_NUM))
#define _TIMESTAMP_BASE 0x40030000
#define _TIMESTAMP_OFFSET (0x1000 * _TIMESTAMP_NUM)
#define _TIMESTAMP_ADDR (_TIMESTAMP_BASE + _TIMESTAMP_OFFSET)
#define _TIMESTAMP_CFG *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0))
#define _TIMESTAMP_CTRL *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0xC))
#define _TIMESTAMP_MODE *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x4))
#define _TIMESTAMP_LOAD *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x28))
#define _TIMESTAMP_IMASK *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x18))
#define _TIMESTAMP_ISTATUS *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x1C))
#define _TIMESTAMP_ICLEAR *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x24))
#define _TIMESTAMP_VAL *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x48))
/*
* Set the rollover value such that it leaves the most significant bit of
* the returned timestamp value unused. This allows room for extended values
* when handling rollovers when converting to an up-counter value.
*/
#define _TIMESTAMP_MAX ((uint32_t)0x7FFFFFFF)
#define _TIMESTAMP_EXT ((uint32_t)0x80000000)
/**
*
* @brief Timestamp initialization
*
* This routine initializes the timestamp timer.
*
* @return N/A
*/
void _TimestampOpen(void)
{
/* QEMU does not currently support the 32-bit timer modes of the GPTM */
printk("WARNING! Timestamp is not supported for this target!\n");
/* enable timer access */
_CLKGATECTRL |= _CLKGATECTRL_TIMESTAMP_EN;
/* minimum 3 clk delay is required before timer register access */
task_sleep(3);
_TIMESTAMP_CTRL = 0x0; /* disable/reset timer */
_TIMESTAMP_CFG = 0x0; /* 32-bit timer */
_TIMESTAMP_MODE = 0x2; /* periodic mode */
_TIMESTAMP_LOAD = _TIMESTAMP_MAX; /* maximum interval to reduce rollovers */
_TIMESTAMP_IMASK = 0x70F; /* mask all timer interrupts */
_TIMESTAMP_ICLEAR = 0x70F; /* clear all interrupt status */
_TIMESTAMP_CTRL = 0x1; /* enable timer */
}
/**
*
* @brief Timestamp timer read
*
* This routine returns the timestamp value.
*
* @return timestamp value
*/
uint32_t _TimestampRead(void)
{
static uint32_t lastTimerVal = 0;
static uint32_t cnt = 0;
uint32_t timerVal = _TIMESTAMP_VAL;
/* handle rollover for every other read (end of sleep) */
if ((cnt % 2) && (timerVal > lastTimerVal)) {
lastTimerVal = timerVal;
/* convert to extended up-counter value */
timerVal = _TIMESTAMP_EXT + (_TIMESTAMP_MAX - timerVal);
} else {
lastTimerVal = timerVal;
/* convert to up-counter value */
timerVal = _TIMESTAMP_MAX - timerVal;
}
cnt++;
return timerVal;
}
/**
*
* @brief Timestamp release
*
* This routine releases the timestamp timer.
*
* @return N/A
*/
void _TimestampClose(void)
{
/* disable/reset timer */
_TIMESTAMP_CTRL = 0x0;
_TIMESTAMP_CFG = 0x0;
/* disable timer access */
_CLKGATECTRL &= ~_CLKGATECTRL_TIMESTAMP_EN;
}
#elif defined(CONFIG_SOC_FSL_FRDM_K64F)
/* Freescale FRDM-K64F target - use RTC (prescale value) */
#define _COUNTDOWN_TIMER false
#define _CLKGATECTRL *((volatile uint32_t *)0x4004803C)
#define _CLKGATECTRL_TIMESTAMP_EN (1 << 29)
#define _SYSOPTCTRL2 *((volatile uint32_t *)0x40048004)
#define _SYSOPTCTRL2_32KHZRTCCLK (1 << 4)
#define _TIMESTAMP_ADDR (0x4003D000)
#define _TIMESTAMP_ICLEAR *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x24))
#define _TIMESTAMP_VAL *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0))
#define _TIMESTAMP_PRESCALE *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x4))
#define _TIMESTAMP_COMP *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0xC))
#define _TIMESTAMP_CTRL *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x10))
#define _TIMESTAMP_STATUS *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x14))
#define _TIMESTAMP_LOCK *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x18))
#define _TIMESTAMP_IMASK *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x1C))
#define _TIMESTAMP_RACCESS *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x800))
#define _TIMESTAMP_WACCESS *((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x804))
/**
*
* @brief Timestamp initialization
*
* This routine initializes the timestamp timer.
*
* @return N/A
*/
void _TimestampOpen(void)
{
/* enable timer access */
_CLKGATECTRL |= _CLKGATECTRL_TIMESTAMP_EN;
/* set 32 KHz RTC clk */
_SYSOPTCTRL2 |= _SYSOPTCTRL2_32KHZRTCCLK;
_TIMESTAMP_STATUS = 0x0; /* disable counter */
_TIMESTAMP_CTRL = 0x100; /* enable oscillator */
_TIMESTAMP_LOCK = 0xFF; /* unlock registers */
_TIMESTAMP_PRESCALE = 0x0; /* reset prescale value */
_TIMESTAMP_COMP = 0x0; /* reset compensation values */
_TIMESTAMP_RACCESS = 0xFF; /* allow register read access */
_TIMESTAMP_WACCESS = 0xFF; /* allow register write access */
_TIMESTAMP_IMASK = 0x0; /* mask all timer interrupts */
/* minimum 0.3 sec delay required for oscillator stabilization */
task_sleep(300000/sys_clock_us_per_tick);
_TIMESTAMP_VAL = 0x0; /* clear invalid time flag in status register */
_TIMESTAMP_STATUS = 0x10; /* enable counter */
}
/**
*
* @brief Timestamp timer read
*
* This routine returns the timestamp value.
*
* @return timestamp value
*/
uint32_t _TimestampRead(void)
{
static uint32_t lastPrescale = 0;
static uint32_t cnt = 0;
uint32_t prescale1 = _TIMESTAMP_PRESCALE;
uint32_t prescale2 = _TIMESTAMP_PRESCALE;
/* ensure a valid reading */
while (prescale1 != prescale2) {
prescale1 = _TIMESTAMP_PRESCALE;
prescale2 = _TIMESTAMP_PRESCALE;
}
/* handle prescale rollover @ 0x8000 for every other read (end of sleep) */
if ((cnt % 2) && (prescale1 < lastPrescale)) {
prescale1 += 0x8000;
}
lastPrescale = prescale2;
cnt++;
return prescale1;
}
/**
*
* @brief Timestamp release
*
* This routine releases the timestamp timer.
*
* @return N/A
*/
void _TimestampClose(void)
{
_TIMESTAMP_STATUS = 0x0; /* disable counter */
_TIMESTAMP_CTRL = 0x0; /* disable oscillator */
}
#elif defined(CONFIG_SOC_ATMEL_SAM3)
/* Atmel SAM3 family processor - use RTT (Real-time Timer) */
#include <soc.h>
#define _TIMESTAMP_ADDR (0x400E1A30)
#define _TIMESTAMP_MODE (*((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x00)))
#define _TIMESTAMP_VAL (*((volatile uint32_t *)(_TIMESTAMP_ADDR + 0x08)))
/**
*
* @brief Timestamp initialization
*
* This routine initializes the timestamp timer.
*
* @return N/A
*/
void _TimestampOpen(void)
{
/* enable RTT clock from PMC */
__PMC->pcer0 = (1 << PID_RTT);
/* Reset RTT and set prescaler to 1 */
_TIMESTAMP_MODE = (1 << 18) | (1 << 0);
}
/**
*
* @brief Timestamp timer read
*
* This routine returns the timestamp value.
*
* @return timestamp value
*/
uint32_t _TimestampRead(void)
{
static uint32_t last_val;
uint32_t tmr_val = _TIMESTAMP_VAL;
uint32_t ticks;
/* handle rollover */
if (tmr_val < last_val) {
ticks = ((0xFFFFFFFF - last_val)) + 1 + tmr_val;
} else {
ticks = tmr_val - last_val;
}
last_val = tmr_val;
return ticks;
}
/**
*
* @brief Timestamp release
*
* This routine releases the timestamp timer.
*
* @return N/A
*/
void _TimestampClose(void)
{
/* disable RTT clock from PMC */
__PMC->pcdr0 = (1 << PID_RTT);
}
#else
#error "Unknown platform"
#endif /* CONFIG_SOC_xxx */