altera_avalon_timer: new timer driver for Nios II

Tickless idle is not yet supported. We program the timer period
to the desired system clock tick rate (sys_clock_hw_cycles_per_tick).

This was renamed to the same name used in the Altera Embedded IP
Peripherals Guide; used by other CPUs than Nios II.

Change-Id: Ic4fca8c16b923295b77b63f98f45cd3483c5f560
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2016-06-21 10:51:46 -07:00 committed by Inaky Perez-Gonzalez
commit 133dab4a63
5 changed files with 162 additions and 50 deletions

View file

@ -141,6 +141,7 @@ S: Supported
F: arch/nios2/
F: include/arch/nios2/
F: drivers/serial/uart_altera_jtag.c
F: drivers/timer/altera_avalon_timer.c
NORDIC MDK
M: Carles Cufi <carles.cufi@nordicsemi.no>

View file

@ -141,14 +141,15 @@ config CORTEX_M_SYSTICK
This module implements a kernel device driver for the Cortex-M processor
SYSTICK timer and provides the standard "system clock driver" interfaces.
config NIOS2_AVALON_TIMER
bool "Nios II Avalon Interval Timer"
config ALTERA_AVALON_TIMER
bool "Altera Avalon Interval Timer"
default y
depends on NIOS2
help
This module implements a kernel device driver for the Nios II Avalon
Interval Timer as described in the Embedded IP documentation. It
provides the standard "system clock driver" interfaces.
This module implements a kernel device driver for the Altera Avalon
Interval Timer as described in the Embedded IP documentation, for use
with Nios II and possibly other Altera soft CPUs. It provides the
standard "system clock driver" interfaces.
config SYSTEM_CLOCK_DISABLE
bool "API to disable system clock"

View file

@ -1,7 +1,7 @@
obj-$(CONFIG_HPET_TIMER) += hpet.o
obj-$(CONFIG_LOAPIC_TIMER) += loapic_timer.o
obj-$(CONFIG_ARCV2_TIMER) += arcv2_timer0.o
obj-$(CONFIG_NIOS2_AVALON_TIMER) += nios2_avalon_timer.o
obj-$(CONFIG_ALTERA_AVALON_TIMER) += altera_avalon_timer.o
_CORTEX_M_SYSTICK_AND_GDB_INFO_yy = y
obj-$(CONFIG_CORTEX_M_SYSTICK) += cortex_m_systick.o

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* 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.
*/
#include <nanokernel.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 uint32_t get_snapshot(void)
{
#if TIMER_0_SNAPSHOT
uint32_t snap, s1, s2;
int key;
key = irq_lock();
/* Writing any data to one of the snapshot registers populates all
* of them with the value of the counter. The data written is ignored
*/
_nios2_reg_write((void *)TIMER_0_BASE, ALTERA_AVALON_TIMER_SNAPL_REG,
1);
s1 = _nios2_reg_read((void *)TIMER_0_BASE,
ALTERA_AVALON_TIMER_SNAPL_REG) &
ALTERA_AVALON_TIMER_SNAPL_MSK;
s2 = _nios2_reg_read((void *)TIMER_0_BASE,
ALTERA_AVALON_TIMER_SNAPH_REG) &
ALTERA_AVALON_TIMER_SNAPH_MSK;
irq_unlock(key);
snap = s1 | (s2 << 16);
return sys_clock_hw_cycles_per_tick - snap;
#else
return 0;
#endif
}
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;
}
/**
*
* @brief Read the platform's timer hardware
*
* This routine returns the current time in terms of timer hardware clock
* cycles.
*
* @return up counter of elapsed clock cycles
*/
uint32_t sys_cycle_get_32(void)
{
return accumulated_cycle_count + get_snapshot();
}

View file

@ -1,44 +0,0 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* 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.
*/
#include <nanokernel.h>
#include <arch/cpu.h>
#include <device.h>
int _sys_clock_driver_init(struct device *device)
{
ARG_UNUSED(device);
/* STUB */
return 0;
}
/**
*
* @brief Read the platform's timer hardware
*
* This routine returns the current time in terms of timer hardware clock
* cycles.
*
* @return up counter of elapsed clock cycles
*/
uint32_t sys_cycle_get_32(void)
{
/* STUB */
return 0;
}