mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-15 06:16:49 +00:00
Some arches may want to define this as an inline function, or define in core arch code instead of timer driver code. Unfortunately, this means we need to remove from the footprint tests, but this is not typically a large function. Issue: ZEP-1546 Change-Id: Ic0d7a33507da855995838f4703d872cd613a2ca2 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
120 lines
3.8 KiB
C
120 lines
3.8 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <kernel.h>
|
|
#include <arch/cpu.h>
|
|
#include <device.h>
|
|
#include <system_timer.h>
|
|
|
|
/* STATUS register */
|
|
#define ALTERA_AVALON_TIMER_STATUS_REG 0
|
|
#define ALTERA_AVALON_TIMER_STATUS_TO_MSK (0x1)
|
|
#define ALTERA_AVALON_TIMER_STATUS_TO_OFST (0)
|
|
#define ALTERA_AVALON_TIMER_STATUS_RUN_MSK (0x2)
|
|
#define ALTERA_AVALON_TIMER_STATUS_RUN_OFST (1)
|
|
|
|
/* CONTROL register */
|
|
#define ALTERA_AVALON_TIMER_CONTROL_REG 1
|
|
#define ALTERA_AVALON_TIMER_CONTROL_ITO_MSK (0x1)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_ITO_OFST (0)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_CONT_MSK (0x2)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_CONT_OFST (1)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_START_MSK (0x4)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_START_OFST (2)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_STOP_MSK (0x8)
|
|
#define ALTERA_AVALON_TIMER_CONTROL_STOP_OFST (3)
|
|
|
|
/* Period and SnapShot Register for COUNTER_SIZE = 32 */
|
|
/*----------------------------------------------------*/
|
|
/* PERIODL register */
|
|
#define ALTERA_AVALON_TIMER_PERIODL_REG 2
|
|
#define ALTERA_AVALON_TIMER_PERIODL_MSK (0xFFFF)
|
|
#define ALTERA_AVALON_TIMER_PERIODL_OFST (0)
|
|
|
|
/* PERIODH register */
|
|
#define ALTERA_AVALON_TIMER_PERIODH_REG 3
|
|
#define ALTERA_AVALON_TIMER_PERIODH_MSK (0xFFFF)
|
|
#define ALTERA_AVALON_TIMER_PERIODH_OFST (0)
|
|
|
|
/* SNAPL register */
|
|
#define ALTERA_AVALON_TIMER_SNAPL_REG 4
|
|
#define ALTERA_AVALON_TIMER_SNAPL_MSK (0xFFFF)
|
|
#define ALTERA_AVALON_TIMER_SNAPL_OFST (0)
|
|
|
|
/* SNAPH register */
|
|
#define ALTERA_AVALON_TIMER_SNAPH_REG 5
|
|
#define ALTERA_AVALON_TIMER_SNAPH_MSK (0xFFFF)
|
|
#define ALTERA_AVALON_TIMER_SNAPH_OFST (0)
|
|
|
|
static uint32_t accumulated_cycle_count;
|
|
|
|
static void timer_irq_handler(void *unused)
|
|
{
|
|
ARG_UNUSED(unused);
|
|
|
|
/* Clear the interrupt */
|
|
_nios2_reg_write((void *)TIMER_0_BASE, ALTERA_AVALON_TIMER_STATUS_REG,
|
|
0);
|
|
accumulated_cycle_count += sys_clock_hw_cycles_per_tick;
|
|
|
|
_sys_clock_tick_announce();
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_TICKLESS_IDLE
|
|
#error "Tickless idle not yet implemented for Avalon timer"
|
|
#endif
|
|
|
|
|
|
int _sys_clock_driver_init(struct device *device)
|
|
{
|
|
ARG_UNUSED(device);
|
|
|
|
#if TIMER_0_FIXED_PERIOD
|
|
#error "Can't set timer period!"
|
|
#else
|
|
_nios2_reg_write((void *)TIMER_0_BASE, ALTERA_AVALON_TIMER_PERIODL_REG,
|
|
sys_clock_hw_cycles_per_tick & 0xFFFF);
|
|
_nios2_reg_write((void *)TIMER_0_BASE, ALTERA_AVALON_TIMER_PERIODH_REG,
|
|
(sys_clock_hw_cycles_per_tick >> 16) & 0xFFFF);
|
|
#endif
|
|
|
|
IRQ_CONNECT(TIMER_0_IRQ, 0, timer_irq_handler, NULL, 0);
|
|
irq_enable(TIMER_0_IRQ);
|
|
|
|
/* Initial configuration: Generate interrupts, run continuously,
|
|
* start running
|
|
*/
|
|
_nios2_reg_write((void *)TIMER_0_BASE, ALTERA_AVALON_TIMER_CONTROL_REG,
|
|
ALTERA_AVALON_TIMER_CONTROL_ITO_MSK |
|
|
ALTERA_AVALON_TIMER_CONTROL_CONT_MSK |
|
|
ALTERA_AVALON_TIMER_CONTROL_START_MSK);
|
|
return 0;
|
|
}
|
|
|
|
|
|
uint32_t _timer_cycle_get_32(void)
|
|
{
|
|
/* XXX Per the Altera Embedded IP Peripherals guide, you cannot
|
|
* use a timer instance for both the system clock and timestamps
|
|
* at the same time.
|
|
*
|
|
* Having this function return accumulated_cycle_count + get_snapshot()
|
|
* does not work reliably. It's possible for the current countdown
|
|
* to reset to the next interval before the timer interrupt is
|
|
* delivered (and accumulated cycle count gets updated). The result
|
|
* is an unlucky call to this function will appear to jump backward
|
|
* in time.
|
|
*
|
|
* To properly obtain timestamps, the CPU must be configured with
|
|
* a second timer peripheral instance that is configured to
|
|
* count down from some large initial 64-bit value. This
|
|
* is currently unimplemented.
|
|
*/
|
|
return accumulated_cycle_count;
|
|
}
|
|
|