Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | /*
* Copyright (c) 2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file timestamp support for tickless idle testing
*
* Platform-specific timestamp support for the tickless idle test.
*/
#include <tc_util.h>
#include <stddef.h>
#include <misc/__assert.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 u32_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 u32_t *)(_TIMESTAMP_ADDR + 0)))
#define _TIMESTAMP_CTRL (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0xC)))
#define _TIMESTAMP_MODE (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x4)))
#define _TIMESTAMP_LOAD (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x28)))
#define _TIMESTAMP_IMASK (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x18)))
#define _TIMESTAMP_ISTATUS (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x1C)))
#define _TIMESTAMP_ICLEAR (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x24)))
#define _TIMESTAMP_VAL (*((volatile u32_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 ((u32_t)0x7FFFFFFF)
#define _TIMESTAMP_EXT ((u32_t)0x80000000)
#define TICKS_TO_MS (MSEC_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
/**
*
* @brief Timestamp initialization
*
* This routine initializes the timestamp timer.
*
* @return N/A
*/
void _timestamp_open(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 */
k_sleep(3 * TICKS_TO_MS);
_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
*/
u32_t _timestamp_read(void)
{
static u32_t last_timer_val;
static u32_t cnt;
u32_t timer_val = _TIMESTAMP_VAL;
/* handle rollover for every other read (end of sleep) */
if ((cnt % 2) && (timer_val > last_timer_val)) {
last_timer_val = timer_val;
/* convert to extended up-counter value */
timer_val = _TIMESTAMP_EXT + (_TIMESTAMP_MAX - timer_val);
} else {
last_timer_val = timer_val;
/* convert to up-counter value */
timer_val = _TIMESTAMP_MAX - timer_val;
}
cnt++;
return timer_val;
}
/**
*
* @brief Timestamp release
*
* This routine releases the timestamp timer.
*
* @return N/A
*/
void _timestamp_close(void)
{
/* disable/reset timer */
_TIMESTAMP_CTRL = 0x0;
_TIMESTAMP_CFG = 0x0;
/* disable timer access */
_CLKGATECTRL &= ~_CLKGATECTRL_TIMESTAMP_EN;
}
#elif defined(CONFIG_SOC_MK64F12)
/* Freescale FRDM-K64F target - use RTC (prescale value) */
#define _COUNTDOWN_TIMER false
#define _CLKGATECTRL (*((volatile u32_t *)0x4004803C))
#define _CLKGATECTRL_TIMESTAMP_EN (1 << 29)
#define _SYSOPTCTRL2 (*((volatile u32_t *)0x40048004))
#define _SYSOPTCTRL2_32KHZRTCCLK (1 << 4)
#define _TIMESTAMP_ADDR (0x4003D000)
#define _TIMESTAMP_ICLEAR (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x24)))
#define _TIMESTAMP_VAL (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0)))
#define _TIMESTAMP_PRESCALE (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x4)))
#define _TIMESTAMP_COMP (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0xC)))
#define _TIMESTAMP_CTRL (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x10)))
#define _TIMESTAMP_STATUS (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x14)))
#define _TIMESTAMP_LOCK (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x18)))
#define _TIMESTAMP_IMASK (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x1C)))
#define _TIMESTAMP_RACCESS (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x800)))
#define _TIMESTAMP_WACCESS (*((volatile u32_t *)(_TIMESTAMP_ADDR + 0x804)))
/**
*
* @brief Timestamp initialization
*
* This routine initializes the timestamp timer.
*
* @return N/A
*/
void _timestamp_open(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 */
k_sleep(0.3 * MSEC_PER_SEC);
_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
*/
u32_t _timestamp_read(void)
{
static u32_t last_prescale;
static u32_t cnt;
u32_t prescale1 = _TIMESTAMP_PRESCALE;
u32_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 < last_prescale)) {
prescale1 += 0x8000;
}
last_prescale = prescale2;
cnt++;
return prescale1;
}
/**
*
* @brief Timestamp release
*
* This routine releases the timestamp timer.
*
* @return N/A
*/
void _timestamp_close(void)
{
_TIMESTAMP_STATUS = 0x0; /* disable counter */
_TIMESTAMP_CTRL = 0x0; /* disable oscillator */
}
#elif defined(CONFIG_SOC_FAMILY_SAM)
/* Atmel SAM family processor - use RTT (Real-time Timer) */
#include <soc.h>
/**
*
* @brief Timestamp initialization
*
* This routine initializes the timestamp timer.
*
* @return N/A
*/
void _timestamp_open(void)
{
/* enable RTT clock from PMC */
soc_pmc_peripheral_enable(ID_RTT);
/* Reset RTT and set prescaler to 3, minimum required by SAM E70 SoC */
RTT->RTT_MR = RTT_MR_RTTRST | RTT_MR_RTPRES(3);
}
/**
*
* @brief Timestamp timer read
*
* This routine returns the timestamp value.
*
* @return timestamp value
*/
u32_t _timestamp_read(void)
{
u32_t timer_val_0;
u32_t timer_val_1;
/* As RTT_VR can be updated asynchronously with the Master Clock, it
* must be read twice at the same value to ensure the read value is
* correct.
*/
do {
timer_val_0 = RTT->RTT_VR;
timer_val_1 = RTT->RTT_VR;
} while (timer_val_0 != timer_val_1);
return timer_val_0;
}
/**
*
* @brief Timestamp release
*
* This routine releases the timestamp timer.
*
* @return N/A
*/
void _timestamp_close(void)
{
/* disable RTT clock from PMC */
soc_pmc_peripheral_disable(ID_RTT);
}
#else
#error "Unknown platform"
#endif /* CONFIG_SOC_xxx */
|