bsps: Move clock drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.
This commit is contained in:
Sebastian Huber
2018-04-19 06:35:52 +02:00
parent 5c5b021f51
commit 7632906fc2
142 changed files with 140 additions and 140 deletions

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2016 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <chip.h>
uint32_t atsam_systick_frequency(void)
{
uint32_t mdiv = (PMC->PMC_MCKR & PMC_MCKR_MDIV_Msk) >> PMC_MCKR_MDIV_Pos;
uint32_t fclk;
if (mdiv == 3) {
fclk = BOARD_MCK * mdiv;
} else {
fclk = BOARD_MCK * (1 << mdiv);
}
return fclk;
}

View File

@@ -0,0 +1,134 @@
/*
* MC9328MXL clock specific using the System Timer
*/
/*
* Copyright (c) 2004 by Cogent Computer Systems
* Written by Jay Monkman <jtm@lopingdog.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <mc9328mxl.h>
#include <rtems/bspIo.h> /* for printk */
/* this is defined in ../../../shared/dev/clock/clockimpl.h */
void Clock_isr(rtems_irq_hdl_param arg);
static void clock_isr_on(const rtems_irq_connect_data *unused);
static void clock_isr_off(const rtems_irq_connect_data *unused);
static int clock_isr_is_on(const rtems_irq_connect_data *irq);
/* Replace the first value with the clock's interrupt name. */
rtems_irq_connect_data clock_isr_data = {
.name = BSP_INT_TIMER1,
.hdl = Clock_isr,
.handle = (void *)BSP_INT_TIMER1,
.on = clock_isr_on,
.off = clock_isr_off,
.isOn = clock_isr_is_on,
};
/**
* When we get the clock interrupt
* - clear the interrupt bit?
* - restart the timer?
*/
#define Clock_driver_support_at_tick() \
do { \
uint32_t reg; \
\
reg = MC9328MXL_TMR1_TSTAT; \
(void) reg; /* avoid set but not used warning */ \
MC9328MXL_TMR1_TSTAT = 0; \
} while(0)
/**
* Installs the clock ISR. You shouldn't need to change this.
*/
#define Clock_driver_support_install_isr( _new ) \
BSP_install_rtems_irq_handler(&clock_isr_data)
/**
* Initialize the hardware for the clock
* - Set the frequency
* - enable it
* - clear any pending interrupts
*
* Since you may want the clock always running, you can
* enable interrupts here. If you do so, the clock_isr_on(),
* clock_isr_off(), and clock_isr_is_on() functions can be
* NOPs.
*/
#define Clock_driver_support_initialize_hardware() \
do { \
int freq; \
int cnt; \
freq = get_perclk1_freq(); \
printk("perclk1 freq is %d\n", freq); \
cnt = ((long long)freq * rtems_configuration_get_microseconds_per_tick() + 500000) / 1000000;\
printk("cnt freq is %d\n", cnt); \
MC9328MXL_TMR1_TCMP = cnt; \
/* use PERCLK1 as input, enable timer */ \
MC9328MXL_TMR1_TCTL = (MC9328MXL_TMR_TCTL_CLKSRC_PCLK1 | \
MC9328MXL_TMR_TCTL_TEN | \
MC9328MXL_TMR_TCTL_IRQEN); \
/* set prescaler to 1 (register value + 1) */ \
MC9328MXL_TMR1_TPRER = 0; \
} while (0)
/**
* Do whatever you need to shut the clock down and remove the
* interrupt handler. Since this normally only gets called on
* RTEMS shutdown, you may not need to do anything other than
* remove the ISR.
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
/* Disable timer */ \
MC9328MXL_TMR1_TCTL = 0; \
BSP_remove_rtems_irq_handler(&clock_isr_data); \
} while (0)
/**
* Enables clock interrupt.
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_on(const rtems_irq_connect_data *unused)
{
MC9328MXL_TMR1_TCTL |= MC9328MXL_TMR_TCTL_IRQEN;
MC9328MXL_AITC_INTENNUM = MC9328MXL_INT_TIMER1;
}
/**
* Disables clock interrupts
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_off(const rtems_irq_connect_data *unused)
{
MC9328MXL_TMR1_TCTL &= ~MC9328MXL_TMR_TCTL_IRQEN;
MC9328MXL_AITC_INTDISNUM = MC9328MXL_INT_TIMER1;
}
/**
* Tests to see if clock interrupt is enabled, and returns 1 if so.
* If interrupt is not enabled, returns 0.
*
* If the interrupt is always on, this always returns 1.
*/
static int clock_isr_is_on(const rtems_irq_connect_data *irq)
{
return MC9328MXL_TMR1_TCTL & MC9328MXL_TMR_TCTL_IRQEN;
}
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
/* Make sure to include this, and only at the end of the file */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,113 @@
/*
* AT91RM9200 clock specific using the System Timer
*/
/*
* Copyright (c) 2003 by Cogent Computer Systems
* Written by Mike Kelly <mike@cogcomp.com>
* and Jay Monkman <jtm@lopingdog.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <rtems/clockdrv.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <at91rm9200.h>
#include <at91rm9200_pmc.h>
/**
* Enables clock interrupt.
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_on(const rtems_irq_connect_data *unused)
{
/* enable timer interrupt */
ST_REG(ST_IER) = ST_SR_PITS;
}
/**
* Disables clock interrupts
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_off(const rtems_irq_connect_data *unused)
{
/* disable timer interrupt */
ST_REG(ST_IDR) = ST_SR_PITS;
}
/**
* Tests to see if clock interrupt is enabled, and returns 1 if so.
* If interrupt is not enabled, returns 0.
*
* If the interrupt is always on, this always returns 1.
*/
static int clock_isr_is_on(const rtems_irq_connect_data *irq)
{
/* check timer interrupt */
return ST_REG(ST_IMR) & ST_SR_PITS;
}
void Clock_isr(rtems_irq_hdl_param arg);
/* Replace the first value with the clock's interrupt name. */
rtems_irq_connect_data clock_isr_data = {
.name = AT91RM9200_INT_SYSIRQ,
.hdl = Clock_isr,
.handle = NULL,
.on = clock_isr_on,
.off = clock_isr_off,
.isOn = clock_isr_is_on,
};
#define Clock_driver_support_install_isr( _new ) \
BSP_install_rtems_irq_handler(&clock_isr_data)
static void Clock_driver_support_initialize_hardware(void)
{
uint32_t st_str;
int slck;
unsigned long value;
/* the system timer is driven from SLCK */
slck = at91rm9200_get_slck();
value = (((rtems_configuration_get_microseconds_per_tick() * slck) +
(1000000/2))/ 1000000);
/* read the status to clear the int */
st_str = ST_REG(ST_SR);
(void) st_str; /* avoid set but not used warning */ \
/* set priority */
AIC_SMR_REG(AIC_SMR_SYSIRQ) = AIC_SMR_PRIOR(0x7);
/* set the timer value */
ST_REG(ST_PIMR) = value;
}
#define Clock_driver_support_at_tick() \
do { \
uint32_t st_str; \
\
/* read the status to clear the int */ \
st_str = ST_REG(ST_SR); \
(void) st_str; /* avoid set but not used warning */ \
} while (0)
#define Clock_driver_support_shutdown_hardware() \
do { \
BSP_remove_rtems_irq_handler(&clock_isr_data); \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,72 @@
/*
* Cirrus EP7312 Clock driver
*
* Copyright (c) 2002 by Jay Monkman <jtm@smoothsmoothie.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <ep7312.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <assert.h>
#if ON_SKYEYE==1
#define CLOCK_DRIVER_USE_FAST_IDLE 1
#endif
void Clock_isr(void * arg);
#define Clock_driver_support_at_tick() \
do { \
*EP7312_TC1EOI = 0xffffffff; \
} while(0)
#define Clock_driver_support_install_isr( _new ) \
do { \
rtems_status_code status = RTEMS_SUCCESSFUL; \
status = rtems_interrupt_handler_install( \
BSP_TC1OI, \
"Clock", \
RTEMS_INTERRUPT_UNIQUE, \
Clock_isr, \
NULL \
); \
assert(status == RTEMS_SUCCESSFUL); \
} while(0)
/*
* Set up the clock hardware
*/
#if ON_SKYEYE
#define TCD_VALUE \
(rtems_configuration_get_microseconds_per_tick() * 2000)/25000
#else
#define TCD_VALUE \
(rtems_configuration_get_microseconds_per_tick() * 2000)/1000000
#endif
#define Clock_driver_support_initialize_hardware() \
do { \
*EP7312_SYSCON1 |= EP7312_SYSCON1_TC1_PRESCALE; \
*EP7312_TC1D = TCD_VALUE; \
*EP7312_TC1EOI = 0xFFFFFFFF; \
} while (0)
#define Clock_driver_support_shutdown_hardware() \
do { \
rtems_status_code status = RTEMS_SUCCESSFUL; \
status = rtems_interrupt_handler_remove( \
BSP_TC1OI, \
Clock_isr, \
NULL \
); \
assert(status == RTEMS_SUCCESSFUL); \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,118 @@
/*
* PXA255 clock specific using the System Timer
*
* RTEMS uses IRQ 26 as Clock Source
*/
/*
* By Yang Xi <hiyangxi@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <rtems/clockdrv.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <bsp.h>
#include <bspopts.h>
#include <bsp/irq.h>
#include <pxa255.h>
#if ON_SKYEYE==1
#define CLOCK_DRIVER_USE_FAST_IDLE 1
#endif
static unsigned long period_num;
/**
* Enables clock interrupt.
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_on(const rtems_irq_connect_data *unused)
{
/*Clear the interrupt bit */
XSCALE_OS_TIMER_TSR = 0x1;
/* enable timer interrupt */
XSCALE_OS_TIMER_IER |= 0x1;
#if ON_SKYEYE==1
period_num = (TIMER_RATE* rtems_configuration_get_microseconds_per_tick())/100000;
#else
period_num = (TIMER_RATE* rtems_configuration_get_microseconds_per_tick())/10000;
#endif
XSCALE_OS_TIMER_MR0 = XSCALE_OS_TIMER_TCR + period_num;
}
/**
* Disables clock interrupts
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_off(const rtems_irq_connect_data *unused)
{
/*Clear the interrupt bit */
XSCALE_OS_TIMER_TSR = 0x1;
/* disable timer interrupt*/
XSCALE_OS_TIMER_IER &= ~0x1;
}
/**
* Tests to see if clock interrupt is enabled, and returns 1 if so.
* If interrupt is not enabled, returns 0.
*
* If the interrupt is always on, this always returns 1.
*/
static int clock_isr_is_on(const rtems_irq_connect_data *irq)
{
/* check timer interrupt */
return XSCALE_OS_TIMER_IER & 0x1;
}
void Clock_isr(rtems_irq_hdl_param arg);
rtems_irq_connect_data clock_isr_data = {
.name = XSCALE_IRQ_OS_TIMER,
.hdl = Clock_isr,
.handle = NULL,
.on = clock_isr_on,
.off = clock_isr_off,
.isOn = clock_isr_is_on,
};
#define Clock_driver_support_install_isr( _new ) \
BSP_install_rtems_irq_handler(&clock_isr_data)
static void Clock_driver_support_initialize_hardware(void)
{
period_num = TIMER_RATE* rtems_configuration_get_microseconds_per_tick();
#if ON_SKYEYE==1
period_num /= 100000;
#else
period_num /= 10000;
#endif
}
#define Clock_driver_support_at_tick() \
do { \
/* read the status to clear the int */ \
XSCALE_OS_TIMER_TSR = 0x1; \
\
/*Add the match register*/ \
XSCALE_OS_TIMER_MR0 = XSCALE_OS_TIMER_TCR + period_num; \
} while (0)
#define Clock_driver_support_shutdown_hardware() \
do { \
BSP_remove_rtems_irq_handler(&clock_isr_data); \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,114 @@
/**
* @file
*
* @ingroup bsp_clock
*
* @brief Raspberry Pi clock support.
*/
/*
* BCM2835 Clock driver
*
* Copyright (c) 2013 Alan Cudmore
* Copyright (c) 2016 Pavel Pisa
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.org/license/LICENSE
*
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/irq-generic.h>
#include <bsp/raspberrypi.h>
#include <rtems/timecounter.h>
/* This is defined in ../../../shared/dev/clock/clockimpl.h */
void Clock_isr(rtems_irq_hdl_param arg);
static struct timecounter raspberrypi_tc;
static uint32_t raspberrypi_clock_get_timecount(struct timecounter *tc)
{
return BCM2835_REG(BCM2835_GPU_TIMER_CLO);
}
static void raspberrypi_clock_at_tick(void)
{
uint32_t act_val;
uint32_t next_cmp = BCM2835_REG(BCM2835_GPU_TIMER_C3);
next_cmp += rtems_configuration_get_microseconds_per_tick();
BCM2835_REG(BCM2835_GPU_TIMER_C3) = next_cmp;
act_val = BCM2835_REG(BCM2835_GPU_TIMER_CLO);
/*
* Clear interrupt only if there is time left to the next tick.
* If time of the next tick has already passed then interrupt
* request stays active and fires immediately after current tick
* processing is finished.
*/
if ((int32_t)(next_cmp - act_val) > 0)
BCM2835_REG(BCM2835_GPU_TIMER_CS) = BCM2835_GPU_TIMER_CS_M3;
}
static void raspberrypi_clock_handler_install_isr(
rtems_isr_entry clock_isr
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
if (clock_isr != NULL) {
sc = rtems_interrupt_handler_install(
BCM2835_IRQ_ID_GPU_TIMER_M3,
"Clock",
RTEMS_INTERRUPT_UNIQUE,
(rtems_interrupt_handler) clock_isr,
NULL
);
} else {
/* Remove interrupt handler */
sc = rtems_interrupt_handler_remove(
BCM2835_IRQ_ID_GPU_TIMER_M3,
(rtems_interrupt_handler) Clock_isr,
NULL
);
}
if ( sc != RTEMS_SUCCESSFUL ) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
static void raspberrypi_clock_initialize_hardware(void)
{
uint32_t next_cmp = BCM2835_REG(BCM2835_GPU_TIMER_CLO);
next_cmp += rtems_configuration_get_microseconds_per_tick();
BCM2835_REG(BCM2835_GPU_TIMER_C3) = next_cmp;
BCM2835_REG(BCM2835_GPU_TIMER_CS) = BCM2835_GPU_TIMER_CS_M3;
raspberrypi_tc.tc_get_timecount = raspberrypi_clock_get_timecount;
raspberrypi_tc.tc_counter_mask = 0xffffffff;
raspberrypi_tc.tc_frequency = 1000000; /* 1 MHz */
raspberrypi_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&raspberrypi_tc);
}
static void raspberrypi_clock_cleanup(void)
{
bsp_interrupt_vector_disable(BCM2835_IRQ_ID_GPU_TIMER_M3);
}
#define Clock_driver_support_at_tick() raspberrypi_clock_at_tick()
#define Clock_driver_support_initialize_hardware() raspberrypi_clock_initialize_hardware()
#define Clock_driver_support_shutdown_hardware() raspberrypi_clock_cleanup()
#define Clock_driver_support_install_isr(clock_isr) \
raspberrypi_clock_handler_install_isr(clock_isr)
#define CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR 1
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,177 @@
/*
* LPC22XX/LPC21xx clock specific using the System Timer
*
* Set the Time0 to generate click for RTEMS
*/
/*
* Copyright (c) 2006 by Ray <rayx.cn@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <lpc22xx.h>
#include <rtems/bspIo.h> /* for printk */
#include <rtems/timecounter.h>
void Clock_isr(rtems_irq_hdl_param arg);
static void clock_isr_on(const rtems_irq_connect_data *unused);
static void clock_isr_off(const rtems_irq_connect_data *unused);
static int clock_isr_is_on(const rtems_irq_connect_data *irq);
static rtems_timecounter_simple lpc22xx_tc;
static uint32_t lpc22xx_tc_get(rtems_timecounter_simple *tc)
{
return T0TC;
}
static bool lpc22xx_tc_is_pending(rtems_timecounter_simple *tc)
{
return (T0IR & 0x1) != 0;
}
static uint32_t lpc22xx_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_upcounter_get(
tc,
lpc22xx_tc_get,
lpc22xx_tc_is_pending
);
}
/**
* When we get the clock interrupt
* - clear the interrupt bit?
* - restart the timer?
*/
static void lpc22xx_tc_at_tick(rtems_timecounter_simple *tc)
{
if (!(T0IR & 0x01))
return;
T0IR = 0x01;
VICVectAddr = 0x00;
}
static void lpc22xx_tc_tick(void)
{
rtems_timecounter_simple_upcounter_tick(
&lpc22xx_tc,
lpc22xx_tc_get,
lpc22xx_tc_at_tick
);
}
/* Replace the first value with the clock's interrupt name. */
rtems_irq_connect_data clock_isr_data = {
.name = LPC22xx_INTERRUPT_TIMER0,
.hdl = Clock_isr,
.handle = NULL,
.on = clock_isr_on,
.off = clock_isr_off,
.isOn = clock_isr_is_on,
};
/* use the /shared/dev/clock/clockimpl.h code template */
/**
* Installs the clock ISR. You shouldn't need to change this.
*/
#define Clock_driver_support_install_isr( _new ) \
BSP_install_rtems_irq_handler(&clock_isr_data)
/**
* Initialize the hardware for the clock
* - Set the frequency
* - enable it
* - clear any pending interrupts
*
* Since you may want the clock always running, you can
* enable interrupts here. If you do so, the clock_isr_on(),
* clock_isr_off(), and clock_isr_is_on() functions can be
* NOPs.
*
* set timer to generate interrupt every
* rtems_configuration_get_microseconds_per_tick()
* MR0/(LPC22xx_Fpclk/(PR0+1)) = 10/1000 = 0.01s
*/
#define Clock_driver_support_initialize_hardware() \
do { \
/* disable and clear timer 0, set to */ \
T0TCR &= 0; \
/* TC is incremented on every pclk.*/ \
T0PC = 0; \
/* initialize the timer period and prescaler */ \
T0MR0 = ((LPC22xx_Fpclk/1000 * \
rtems_configuration_get_microseconds_per_tick()) / 1000); \
/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/ \
T0MCR |= 0x03; \
/* No external match */ \
T0EMR = 0; \
/* enable timer0 */ \
T0TCR = 1; \
/* enable interrupt, skyeye will check this*/ \
T0IR |= 0x01; \
/* install timecounter */ \
rtems_timecounter_simple_install( \
&lpc22xx_tc, \
LPC22xx_Fpclk, \
T0MR0, \
lpc22xx_tc_get_timecount \
); \
} while (0)
/**
* Do whatever you need to shut the clock down and remove the
* interrupt handler. Since this normally only gets called on
* RTEMS shutdown, you may not need to do anything other than
* remove the ISR.
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
/* Disable timer */ \
T0TCR&=~0x02; \
BSP_remove_rtems_irq_handler(&clock_isr_data); \
} while (0)
/**
* Enables clock interrupt.
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_on(const rtems_irq_connect_data *unused)
{
T0IR&=0x01;
}
/**
* Disables clock interrupts
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_off(const rtems_irq_connect_data *unused)
{
T0IR=0x00;
}
/**
* Tests to see if clock interrupt is enabled, and returns 1 if so.
* If interrupt is not enabled, returns 0.
*
* If the interrupt is always on, this always returns 1.
*/
static int clock_isr_is_on(const rtems_irq_connect_data *irq)
{
return T0IR & 0x01; /* MR0 mask */
}
#define Clock_driver_timecounter_tick() lpc22xx_tc_tick()
/* Make sure to include this, and only at the end of the file */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 2011-2012 Sebastian Huber. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <rtems/timecounter.h>
#include <rtems/score/armv7m.h>
#include <bsp.h>
#ifdef ARM_MULTILIB_ARCH_V7M
/* This is defined in dev/clock/clockimpl.h */
static void Clock_isr(void *arg);
typedef struct {
rtems_timecounter_simple base;
void (*tick)(void);
bool countflag;
} ARMV7M_Timecounter;
static ARMV7M_Timecounter _ARMV7M_TC;
static uint32_t _ARMV7M_TC_systick_get(rtems_timecounter_simple *tc)
{
volatile ARMV7M_Systick *systick = _ARMV7M_Systick;
return systick->cvr;
}
static bool _ARMV7M_TC_systick_is_pending(rtems_timecounter_simple *base)
{
ARMV7M_Timecounter *tc = (ARMV7M_Timecounter *) base;
rtems_interrupt_level level;
bool countflag;
rtems_interrupt_disable(level);
countflag = tc->countflag;
if (!countflag) {
volatile ARMV7M_Systick *systick = _ARMV7M_Systick;
countflag = ((systick->csr & ARMV7M_SYSTICK_CSR_COUNTFLAG) != 0);
tc->countflag = countflag;
}
rtems_interrupt_enable(level);
return countflag;
}
static uint32_t _ARMV7M_TC_systick_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
_ARMV7M_TC_systick_get,
_ARMV7M_TC_systick_is_pending
);
}
static void _ARMV7M_TC_systick_at_tick(rtems_timecounter_simple *base)
{
ARMV7M_Timecounter *tc = (ARMV7M_Timecounter *) base;
volatile ARMV7M_Systick *systick = _ARMV7M_Systick;
tc->countflag = false;
/* Clear COUNTFLAG */
systick->csr;
}
static void _ARMV7M_TC_systick_tick(void)
{
rtems_timecounter_simple_downcounter_tick(
&_ARMV7M_TC.base,
_ARMV7M_TC_systick_get,
_ARMV7M_TC_systick_at_tick
);
}
static void _ARMV7M_TC_tick(void)
{
(*_ARMV7M_TC.tick)();
}
static void _ARMV7M_Systick_handler(void)
{
_ARMV7M_Interrupt_service_enter();
Clock_isr(NULL);
_ARMV7M_Interrupt_service_leave();
}
static void _ARMV7M_Systick_handler_install(void)
{
_ARMV7M_Set_exception_priority_and_handler(
ARMV7M_VECTOR_SYSTICK,
BSP_ARMV7M_SYSTICK_PRIORITY,
_ARMV7M_Systick_handler
);
}
static void _ARMV7M_Systick_initialize(void)
{
volatile ARMV7M_Systick *systick = _ARMV7M_Systick;
#ifdef BSP_ARMV7M_SYSTICK_FREQUENCY
uint64_t freq = BSP_ARMV7M_SYSTICK_FREQUENCY;
#else
uint64_t freq = ARMV7M_SYSTICK_CALIB_TENMS_GET(systick->calib) * 100ULL;
#endif
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint64_t interval = (freq * us_per_tick) / 1000000ULL;
systick->rvr = (uint32_t) interval;
systick->cvr = 0;
systick->csr = ARMV7M_SYSTICK_CSR_ENABLE
| ARMV7M_SYSTICK_CSR_TICKINT
| ARMV7M_SYSTICK_CSR_CLKSOURCE;
_ARMV7M_TC.tick = _ARMV7M_TC_systick_tick;
rtems_timecounter_simple_install(
&_ARMV7M_TC.base,
freq,
interval,
_ARMV7M_TC_systick_get_timecount
);
}
static void _ARMV7M_Systick_cleanup(void)
{
volatile ARMV7M_Systick *systick = _ARMV7M_Systick;
systick->csr = 0;
}
#define Clock_driver_timecounter_tick() _ARMV7M_TC_tick()
#define Clock_driver_support_initialize_hardware() \
_ARMV7M_Systick_initialize()
#define Clock_driver_support_install_isr(isr) \
_ARMV7M_Systick_handler_install()
#define Clock_driver_support_shutdown_hardware() \
_ARMV7M_Systick_cleanup()
/* Include shared source clock driver code */
#include "../../../shared/dev/clock/clockimpl.h"
#endif /* ARM_MULTILIB_ARCH_V7M */

View File

@@ -0,0 +1,136 @@
/**
* @file
*
* @ingroup lpc_clock
*
* @brief Clock driver configuration.
*/
/*
* Copyright (c) 2009-2015 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <rtems/timecounter.h>
#include <bsp/lpc-clock-config.h>
#include <bsp/lpc-timer.h>
#ifdef ARM_MULTILIB_ARCH_V4
/* This is defined in ../../../shared/dev/clock/clockimpl.h */
void Clock_isr(rtems_irq_hdl_param arg);
static volatile lpc_timer *const lpc_clock =
(volatile lpc_timer *) LPC_CLOCK_TIMER_BASE;
static volatile lpc_timer *const lpc_timecounter =
(volatile lpc_timer *) LPC_CLOCK_TIMECOUNTER_BASE;
static struct timecounter lpc_clock_tc;
static uint32_t lpc_clock_tc_get_timecount(struct timecounter *tc)
{
return lpc_timecounter->tc;
}
static void lpc_clock_at_tick(void)
{
lpc_clock->ir = LPC_TIMER_IR_MR0;
}
static void lpc_clock_handler_install(void)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
sc = rtems_interrupt_handler_install(
LPC_CLOCK_INTERRUPT,
"Clock",
RTEMS_INTERRUPT_UNIQUE,
(rtems_interrupt_handler) Clock_isr,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
static void lpc_clock_initialize(void)
{
uint64_t interval = ((uint64_t) LPC_CLOCK_REFERENCE
* (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000;
/* Enable module */
LPC_CLOCK_MODULE_ENABLE();
/* Reset timer */
lpc_clock->tcr = LPC_TIMER_TCR_RST;
/* Clear interrupt flags */
lpc_clock->ir = LPC_TIMER_IR_ALL;
/* Set timer mode */
lpc_clock->ccr = 0;
/* Timer is incremented every PERIPH_CLK tick */
lpc_clock->pr = 0;
/* Set match registers */
lpc_clock->mr0 = (uint32_t) interval;
/* Generate interrupt and reset counter on match with MR0 */
lpc_clock->mcr = LPC_TIMER_MCR_MR0_INTR | LPC_TIMER_MCR_MR0_RST;
/* No external match */
lpc_clock->emr = 0x0;
/* Enable timer */
lpc_clock->tcr = LPC_TIMER_TCR_EN;
/* Install timecounter */
lpc_clock_tc.tc_get_timecount = lpc_clock_tc_get_timecount;
lpc_clock_tc.tc_counter_mask = 0xffffffff;
lpc_clock_tc.tc_frequency = LPC_CLOCK_REFERENCE;
lpc_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&lpc_clock_tc);
}
static void lpc_clock_cleanup(void)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
/* Disable timer */
lpc_clock->tcr = 0x0;
/* Remove interrupt handler */
sc = rtems_interrupt_handler_remove(
LPC_CLOCK_INTERRUPT,
(rtems_interrupt_handler) Clock_isr,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
#define Clock_driver_support_at_tick() lpc_clock_at_tick()
#define Clock_driver_support_initialize_hardware() lpc_clock_initialize()
#define Clock_driver_support_install_isr(isr) \
lpc_clock_handler_install()
#define Clock_driver_support_shutdown_hardware() lpc_clock_cleanup()
/* Include shared source clock driver code */
#include "../../../shared/dev/clock/clockimpl.h"
#endif /* ARM_MULTILIB_ARCH_V4 */

View File

@@ -0,0 +1,123 @@
/*
* S3C2400 clock specific using the System Timer
*/
/*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp/irq.h>
#include <bsp.h>
#include <s3c24xx.h>
void Clock_isr(rtems_irq_hdl_param arg);
static void clock_isr_on(const rtems_irq_connect_data *unused);
static void clock_isr_off(const rtems_irq_connect_data *unused);
static int clock_isr_is_on(const rtems_irq_connect_data *irq);
rtems_irq_connect_data clock_isr_data = {
.name = BSP_INT_TIMER4,
.hdl = Clock_isr,
.handle = NULL,
.on = clock_isr_on,
.off = clock_isr_off,
.isOn = clock_isr_is_on,
};
/**
* When we get the clock interrupt
* - clear the interrupt bit?
* - restart the timer?
*/
#define Clock_driver_support_at_tick() \
do { \
ClearPending(BIT_TIMER4); \
} while(0)
/**
* Installs the clock ISR. You shouldn't need to change this.
*/
#define Clock_driver_support_install_isr( _new ) \
BSP_install_rtems_irq_handler(&clock_isr_data)
/**
* Initialize the hardware for the clock
* - Set the frequency
* - enable it
* - clear any pending interrupts
*
* Since you may want the clock always running, you can
* enable interrupts here. If you do so, the clock_isr_on(),
* clock_isr_off(), and clock_isr_is_on() functions can be
* NOPs.
*/
#define Clock_driver_support_initialize_hardware() \
do { \
uint32_t cr; \
uint32_t freq; \
/* set MUX for Timer4 to 1/16 */ \
cr=rTCFG1 & 0xFFF0FFFF; \
rTCFG1=(cr | (3<<16)); \
freq = get_PCLK(); \
/* set TIMER4 counter, input freq=PLCK/16/16Mhz*/ \
freq = (freq /16)/16; \
rTCNTB4 = ((freq / 1000) * rtems_configuration_get_microseconds_per_tick()) / 1000; \
/*unmask TIMER4 irq*/ \
rINTMSK&=~BIT_TIMER4; \
/* start TIMER4 with autoreload */ \
cr=rTCON & 0xFF8FFFFF; \
rTCON=(cr|(0x6<<20)); \
rTCON=(cr|(0x5<<20)); \
} while (0)
/**
* Do whatever you need to shut the clock down and remove the
* interrupt handler. Since this normally only gets called on
* RTEMS shutdown, you may not need to do anything other than
* remove the ISR.
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
/* Disable timer */ \
BSP_remove_rtems_irq_handler(&clock_isr_data); \
} while (0)
/**
* Enables clock interrupt.
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_on(const rtems_irq_connect_data *unused)
{
}
/**
* Disables clock interrupts
*
* If the interrupt is always on, this can be a NOP.
*/
static void clock_isr_off(const rtems_irq_connect_data *unused)
{
return;
}
/**
* Tests to see if clock interrupt is enabled, and returns 1 if so.
* If interrupt is not enabled, returns 0.
*
* If the interrupt is always on, this always returns 1.
*/
static int clock_isr_is_on(const rtems_irq_connect_data *irq)
{
return 1;
}
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
/* Make sure to include this, and only at the end of the file */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,57 @@
#include <rtems.h>
#include <bsp.h>
#include <s3c24xx.h>
/* ------------------------------------------------------------------------- */
/* NOTE: This describes the proper use of this file.
*
* BSP_OSC_FREQ should be defined as the input frequency of the PLL.
*
* get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of
* the specified bus in HZ.
*/
/* ------------------------------------------------------------------------- */
/* return FCLK frequency */
uint32_t get_FCLK(void)
{
uint32_t r, m, p, s;
r = rMPLLCON;
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
return((BSP_OSC_FREQ * m) / (p << s));
}
/* return UCLK frequency */
uint32_t get_UCLK(void)
{
uint32_t r, m, p, s;
r = rUPLLCON;
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
return((BSP_OSC_FREQ * m) / (p << s));
}
/* return HCLK frequency */
uint32_t get_HCLK(void)
{
if (rCLKDIVN & 0x2)
return get_FCLK()/2;
else
return get_FCLK();
}
/* return PCLK frequency */
uint32_t get_PCLK(void)
{
if (rCLKDIVN & 0x1)
return get_HCLK()/2;
else
return get_HCLK();
}

View File

@@ -0,0 +1,190 @@
/**
* @file clock.c
*
* @ingroup tms570
*
* @brief clock functions definitions.
*/
/*
* Copyright (c) 2014 Premysl Houdek <kom541000@gmail.com>
*
* Google Summer of Code 2014 at
* Czech Technical University in Prague
* Zikova 1903/4
* 166 36 Praha 6
* Czech Republic
*
* Based on LPC24xx and LPC1768 BSP
* by embedded brains GmbH and others
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdlib.h>
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/tms570-rti.h>
#include <rtems/timecounter.h>
static struct timecounter tms570_rti_tc;
static uint32_t tms570_rti_get_timecount(struct timecounter *tc)
{
return TMS570_RTI.CNT[0].FRCx;
}
#ifndef TMS570_PREFERRED_TC_FREQUENCY
/*
* Define preferred main time base counter frequency
* The value of 1MHz is the best matching RTEMS
* timing system because then there is no need
* to scale RTEMS configuration microseconds_per_tick
* parameter
*/
#define TMS570_PREFERRED_TC_FREQUENCY 1000000
#endif /* TMS570_PREFERRED_TC_FREQUENCY */
/**
* @brief Initialize the HW peripheral for clock driver
*
* Clock driver is implemented by RTI module
*
* @retval Void
*/
static void tms570_clock_driver_support_initialize_hardware( void )
{
uint32_t microsec_per_tick;
uint32_t tc_frequency;
uint32_t tc_prescaler;
uint32_t tc_increments_per_tick;
microsec_per_tick = rtems_configuration_get_microseconds_per_tick();
tc_frequency = TMS570_PREFERRED_TC_FREQUENCY;
tc_prescaler = (BSP_PLL_OUT_CLOCK + tc_frequency) / (tc_frequency * 2);
/* Recompute actual most close frequency which can be realized */
tc_frequency = (BSP_PLL_OUT_CLOCK + tc_prescaler) / (tc_prescaler * 2);
/*
* Recompute tick period to adjust for configurable or exact
* preferred time base 1 usec resolution.
*/
tc_increments_per_tick = ((uint64_t)microsec_per_tick * tc_frequency +
500000) / 1000000;
/* Hardware specific initialize */
TMS570_RTI.GCTRL = 0;
TMS570_RTI.CNT[0].CPUCx = tc_prescaler - 1;
TMS570_RTI.TBCTRL = TMS570_RTI_TBCTRL_INC;
TMS570_RTI.CAPCTRL = 0;
TMS570_RTI.COMPCTRL = 0;
/* set counter to zero */
TMS570_RTI.CNT[0].UCx = 0;
TMS570_RTI.CNT[0].FRCx = 0;
/* clear interrupts*/
TMS570_RTI.CLEARINTENA = TMS570_RTI_CLEARINTENA_CLEAROVL1INT |
TMS570_RTI_CLEARINTENA_CLEAROVL0INT |
TMS570_RTI_CLEARINTENA_CLEARTBINT |
TMS570_RTI_CLEARINTENA_CLEARDMA3 |
TMS570_RTI_CLEARINTENA_CLEARDMA2 |
TMS570_RTI_CLEARINTENA_CLEARDMA1 |
TMS570_RTI_CLEARINTENA_CLEARDMA0 |
TMS570_RTI_CLEARINTENA_CLEARINT3 |
TMS570_RTI_CLEARINTENA_CLEARINT2 |
TMS570_RTI_CLEARINTENA_CLEARINT1 |
TMS570_RTI_CLEARINTENA_CLEARINT0;
TMS570_RTI.INTFLAG = TMS570_RTI_INTFLAG_OVL1INT |
TMS570_RTI_INTFLAG_OVL0INT |
TMS570_RTI_INTFLAG_TBINT |
TMS570_RTI_INTFLAG_INT3 |
TMS570_RTI_INTFLAG_INT2 |
TMS570_RTI_INTFLAG_INT1 |
TMS570_RTI_INTFLAG_INT0;
/* set timer */
TMS570_RTI.CMP[0].COMPx = TMS570_RTI.CNT[0].FRCx + tc_increments_per_tick;
TMS570_RTI.COMP0CLR = TMS570_RTI.CMP[0].COMPx + tc_increments_per_tick / 2;
TMS570_RTI.CMP[0].UDCPx = tc_increments_per_tick;
/* enable interupt */
TMS570_RTI.SETINTENA = TMS570_RTI_SETINTENA_SETINT0;
/* enable timer */
TMS570_RTI.GCTRL = TMS570_RTI_GCTRL_CNT0EN;
/* set timecounter */
tms570_rti_tc.tc_get_timecount = tms570_rti_get_timecount;
tms570_rti_tc.tc_counter_mask = 0xffffffff;
tms570_rti_tc.tc_frequency = tc_frequency;
tms570_rti_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&tms570_rti_tc);
}
/**
* @brief Clears interrupt source
*
* @retval Void
*/
static void tms570_clock_driver_support_at_tick( void )
{
TMS570_RTI.INTFLAG = TMS570_RTI_INTFLAG_INT0;
}
/**
* @brief registers RTI interrupt handler
*
* @param[in] Clock_isr new ISR handler
* @param[in] Old_ticker old ISR handler (unused and type broken)
*
* @retval Void
*/
static void tms570_clock_driver_support_install_isr(
rtems_isr_entry Clock_isr
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
sc = rtems_interrupt_handler_install(
TMS570_IRQ_TIMER_0,
"Clock",
RTEMS_INTERRUPT_UNIQUE,
(rtems_interrupt_handler) Clock_isr,
NULL
);
if ( sc != RTEMS_SUCCESSFUL ) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
/**
* @brief disables RTI interrupt
*
* Called when closing clock driver
*
* @retval Void
*/
static void tms570_clock_driver_support_shutdown_hardware( void )
{
/* turn off the timer interrupts */
TMS570_RTI.CLEARINTENA = TMS570_RTI_CLEARINTENA_CLEAROVL0INT |
TMS570_RTI_CLEARINTENA_CLEARINT0;
}
#define Clock_driver_support_initialize_hardware \
tms570_clock_driver_support_initialize_hardware
#define Clock_driver_support_at_tick \
tms570_clock_driver_support_at_tick
#define Clock_driver_support_initialize_hardware \
tms570_clock_driver_support_initialize_hardware
#define Clock_driver_support_shutdown_hardware \
tms570_clock_driver_support_shutdown_hardware
#define Clock_driver_support_install_isr(Clock_isr) \
tms570_clock_driver_support_install_isr( Clock_isr )
void Clock_isr(void *arg); /* to supress warning */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,262 @@
/**
* @file
*
* Clock Tick Device Driver
*
* History:
* + Original driver was go32 clock by Joel Sherrill
* + go32 clock driver hardware code was inserted into new
* boilerplate when the pc386 BSP by:
* Pedro Miguel Da Cruz Neto Romano <pmcnr@camoes.rnl.ist.utl.pt>
* Jose Rufino <ruf@asterix.ist.utl.pt>
* + Reworked by Joel Sherrill to use clock driver template.
* This removes all boilerplate and leave original hardware
* code I developed for the go32 BSP.
*/
/*
* COPYRIGHT (c) 1989-2012.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <bsp/irq-generic.h>
#include <bspopts.h>
#include <libcpu/cpuModel.h>
#include <assert.h>
#include <rtems/timecounter.h>
#define CLOCK_VECTOR 0
volatile uint32_t pc386_microseconds_per_isr;
volatile uint32_t pc386_isrs_per_tick;
uint32_t pc386_clock_click_count;
/* forward declaration */
void Clock_isr(void *param);
static void clockOff(void);
static void Clock_isr_handler(void *param);
/*
* Roughly the number of cycles per second. Note that these
* will be wildly inaccurate if the chip speed changes due to power saving
* or thermal modes.
*
* NOTE: These are only used when the TSC method is used.
*/
static uint64_t pc586_tsc_frequency;
static struct timecounter pc386_tc;
/* this driver may need to count ISRs per tick */
#define CLOCK_DRIVER_ISRS_PER_TICK 1
#define CLOCK_DRIVER_ISRS_PER_TICK_VALUE pc386_isrs_per_tick
extern volatile uint32_t Clock_driver_ticks;
#define READ_8254( _lsb, _msb ) \
do { outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); \
inport_byte(TIMER_CNTR0, _lsb); \
inport_byte(TIMER_CNTR0, _msb); \
} while (0)
#ifdef RTEMS_SMP
#define Clock_driver_support_at_tick() \
_SMP_Send_message_broadcast(SMP_MESSAGE_CLOCK_TICK)
#endif
static uint32_t pc386_get_timecount_tsc(struct timecounter *tc)
{
return (uint32_t)rdtsc();
}
static uint32_t pc386_get_timecount_i8254(struct timecounter *tc)
{
uint32_t irqs;
uint8_t lsb, msb;
rtems_interrupt_lock_context lock_context;
/*
* Fetch all the data in an interrupt critical section.
*/
rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
READ_8254(lsb, msb);
irqs = Clock_driver_ticks;
rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
return (irqs + 1) * pc386_microseconds_per_isr - ((msb << 8) | lsb);
}
/*
* Calibrate CPU cycles per tick. Interrupts should be disabled.
*/
static void calibrate_tsc(void)
{
uint64_t begin_time;
uint8_t then_lsb, then_msb, now_lsb, now_msb;
uint32_t i;
/*
* We just reset the timer, so we know we're at the beginning of a tick.
*/
/*
* Count cycles. Watching the timer introduces a several microsecond
* uncertaintity, so let it cook for a while and divide by the number of
* ticks actually executed.
*/
begin_time = rdtsc();
for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick;
i != 0; --i ) {
/* We know we've just completed a tick when timer goes from low to high */
then_lsb = then_msb = 0xff;
do {
READ_8254(now_lsb, now_msb);
if ((then_msb < now_msb) ||
((then_msb == now_msb) && (then_lsb < now_lsb)))
break;
then_lsb = now_lsb;
then_msb = now_msb;
} while (1);
}
pc586_tsc_frequency = rdtsc() - begin_time;
#if 0
printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / 1000000));
#endif
}
static void clockOn(void)
{
rtems_interrupt_lock_context lock_context;
pc386_isrs_per_tick = 1;
pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick();
while (US_TO_TICK(pc386_microseconds_per_isr) > 65535) {
pc386_isrs_per_tick *= 10;
pc386_microseconds_per_isr /= 10;
}
pc386_clock_click_count = US_TO_TICK(pc386_microseconds_per_isr);
#if 0
printk( "configured usecs per tick=%d \n",
rtems_configuration_get_microseconds_per_tick() );
printk( "Microseconds per ISR =%d\n", pc386_microseconds_per_isr );
printk( "final ISRs per=%d\n", pc386_isrs_per_tick );
printk( "final timer counts=%d\n", pc386_clock_click_count );
#endif
rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 0 & 0xff);
outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 8 & 0xff);
rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER - BSP_IRQ_VECTOR_BASE );
/*
* Now calibrate cycles per tick. Do this every time we
* turn the clock on in case the CPU clock speed has changed.
*/
if ( x86_has_tsc() )
calibrate_tsc();
}
static void clockOff(void)
{
rtems_interrupt_lock_context lock_context;
rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
/* reset timer mode to standard (BIOS) value */
outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, 0);
outport_byte(TIMER_CNTR0, 0);
rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
} /* Clock_exit */
bool Clock_isr_enabled = false;
static void Clock_isr_handler(void *param)
{
if ( Clock_isr_enabled )
Clock_isr( param );
}
void Clock_driver_install_handler(void)
{
rtems_status_code status;
status = rtems_interrupt_handler_install(
BSP_PERIODIC_TIMER,
"ckinit",
RTEMS_INTERRUPT_UNIQUE,
Clock_isr_handler,
NULL
);
assert(status == RTEMS_SUCCESSFUL);
clockOn();
}
#define Clock_driver_support_set_interrupt_affinity(online_processors) \
do { \
/* FIXME: Is there a way to do this on x86? */ \
(void) online_processors; \
} while (0)
void Clock_driver_support_initialize_hardware(void)
{
bool use_tsc = false;
bool use_8254 = false;
#if (CLOCK_DRIVER_USE_TSC == 1)
use_tsc = true;
#endif
#if (CLOCK_DRIVER_USE_8254 == 1)
use_8254 = true;
#endif
if ( !use_tsc && !use_8254 ) {
if ( x86_has_tsc() ) use_tsc = true;
else use_8254 = true;
}
if ( use_8254 ) {
/* printk( "Use 8254\n" ); */
pc386_tc.tc_get_timecount = pc386_get_timecount_i8254;
pc386_tc.tc_counter_mask = 0xffffffff;
pc386_tc.tc_frequency = TIMER_TICK;
} else {
/* printk( "Use TSC\n" ); */
pc386_tc.tc_get_timecount = pc386_get_timecount_tsc;
pc386_tc.tc_counter_mask = 0xffffffff;
pc386_tc.tc_frequency = pc586_tsc_frequency;
}
pc386_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&pc386_tc);
Clock_isr_enabled = true;
}
#define Clock_driver_support_shutdown_hardware() \
do { \
rtems_status_code status; \
clockOff(); \
status = rtems_interrupt_handler_remove( \
BSP_PERIODIC_TIMER, \
Clock_isr_handler, \
NULL \
); \
assert(status == RTEMS_SUCCESSFUL); \
} while (0)
#include "../../../shared/dev/clock/clockimpl.h"

216
bsps/i386/pc386/clock/rtc.c Normal file
View File

@@ -0,0 +1,216 @@
/*-------------------------------------------------------------------------+
| rtc.c v1.1 - PC386 BSP - 1997/08/07
+--------------------------------------------------------------------------+
| This file contains the real time clock manipulation package for the
| PC386 board.
+--------------------------------------------------------------------------+
| (C) Copyright 1997 -
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
| http://pandora.ist.utl.pt
|
| Instituto Superior Tecnico * Lisboa * PORTUGAL
+--------------------------------------------------------------------------+
| Disclaimer:
|
| This file is provided "AS IS" without warranty of any kind, either
| expressed or implied.
+--------------------------------------------------------------------------+
| This code is based on:
| rtc.c,v 1.4 1995/12/19 20:07:15 joel Exp - go32 BSP
| With the following copyright notice:
| **************************************************************************
| * COPYRIGHT (c) 1989-1999.
| * On-Line Applications Research Corporation (OAR).
| *
| * The license and distribution terms for this file may be
| * found in the file LICENSE in this distribution or at
| * http://www.rtems.org/license/LICENSE.
| **************************************************************************
+--------------------------------------------------------------------------*/
#include <string.h>
#include <bsp.h>
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
#define IO_RTC 0x70 /* RTC */
#define RTC_SEC 0x00 /* seconds */
#define RTC_SECALRM 0x01 /* seconds alarm */
#define RTC_MIN 0x02 /* minutes */
#define RTC_MINALRM 0x03 /* minutes alarm */
#define RTC_HRS 0x04 /* hours */
#define RTC_HRSALRM 0x05 /* hours alarm */
#define RTC_WDAY 0x06 /* week day */
#define RTC_DAY 0x07 /* day of month */
#define RTC_MONTH 0x08 /* month of year */
#define RTC_YEAR 0x09 /* month of year */
#define RTC_STATUSA 0x0a /* status register A */
#define RTCSA_TUP 0x80 /* time update, don't look now */
#define RTC_STATUSB 0x0b /* status register B */
#define RTC_INTR 0x0c /* status register C (R) interrupt source */
#define RTCIR_UPDATE 0x10 /* update intr */
#define RTCIR_ALARM 0x20 /* alarm intr */
#define RTCIR_PERIOD 0x40 /* periodic intr */
#define RTCIR_INT 0x80 /* interrupt output signal */
#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
#define RTCSD_PWR 0x80 /* clock lost power */
#define RTC_DIAG 0x0e /* status register E - bios diagnostic */
#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"
#define RTC_CENTURY 0x32 /* current century - increment in Dec99 */
/*-------------------------------------------------------------------------+
| Auxiliary Functions
+--------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------+
| Function: bcd
| Description: Convert 2 digit number to its BCD representation.
| Global Variables: None.
| Arguments: i - Number to convert.
| Returns: BCD representation of number.
+--------------------------------------------------------------------------*/
static inline uint8_t
bcd(uint8_t i)
{
return ((i / 16) * 10 + (i % 16));
} /* bcd */
#define QUICK_READ /* Quick read of the RTC: don't return number of seconds. */
#ifndef QUICK_READ
#define SECS_PER_DAY (24 * 60 * 60)
#define SECS_PER_REG_YEAR (365 * SECS_PER_DAY)
/*-------------------------------------------------------------------------+
| Function: ytos
| Description: Convert years to seconds (since 1970).
| Global Variables: None.
| Arguments: y - year to convert (1970 <= y <= 2100).
| Returns: number of seconds since 1970.
+--------------------------------------------------------------------------*/
static inline uint32_t
ytos(uint16_t y)
{ /* v NUM LEAP YEARS v */
return ((y - 1970) * SECS_PER_REG_YEAR + (y - 1970 + 1) / 4 * SECS_PER_DAY);
} /* ytos */
/*-------------------------------------------------------------------------+
| Function: mtos
| Description: Convert months to seconds since January.
| Global Variables: None.
| Arguments: m - month to convert, leap - is this a month of a leap year.
| Returns: number of seconds since January.
+--------------------------------------------------------------------------*/
static inline uint32_t
mtos(uint8_t m, bool leap)
{
static uint16_t daysMonth[] = { 0, 0, 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334, 365 };
/* Days since beginning of year until beginning of month. */
return ((daysMonth[m] + (leap ? 1 : 0)) * SECS_PER_DAY);
} /* mtos */
#endif /* QUICK_READ */
/*-------------------------------------------------------------------------+
| Function: rtcin
| Description: Perform action on RTC and return its result.
| Global Variables: None.
| Arguments: what - what to write to RTC port (what to do).
| Returns: result received from RTC port after action performed.
+--------------------------------------------------------------------------*/
static inline uint8_t
rtcin(uint8_t what)
{
uint8_t r;
outport_byte(IO_RTC, what);
inport_byte (IO_RTC+1, r);
return r;
} /* rtcin */
/*-------------------------------------------------------------------------+
| Functions
+--------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------+
| Function: init_rtc
| Description: Initialize real-time clock (RTC).
| Global Variables: None.
| Arguments: None.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
init_rtc(void)
{
uint8_t s;
/* initialize brain-dead battery powered clock */
outport_byte(IO_RTC, RTC_STATUSA);
outport_byte(IO_RTC+1, 0x26);
outport_byte(IO_RTC, RTC_STATUSB);
outport_byte(IO_RTC+1, 2);
outport_byte(IO_RTC, RTC_DIAG);
inport_byte (IO_RTC+1, s);
if (s)
printk("RTC BIOS diagnostic error %b\n", s);
/* FIXME: This was last line's original version. How was it supposed to work?
printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); */
} /* init_rtc */
/*-------------------------------------------------------------------------+
| Function: rtc_read
| Description: Read present time from RTC and return it.
| Global Variables: None.
| Arguments: tod - to return present time in 'rtems_time_of_day' format.
| Returns: number of seconds from 1970/01/01 corresponding to 'tod'.
+--------------------------------------------------------------------------*/
long int
rtc_read(rtems_time_of_day *tod)
{
uint8_t sa;
uint32_t sec = 0;
memset(tod, 0, sizeof *tod); /* zero tod structure */
/* do we have a realtime clock present? (otherwise we loop below) */
sa = rtcin(RTC_STATUSA);
if (sa == 0xff || sa == 0)
return -1;
/* ready for a read? */
while ((sa&RTCSA_TUP) == RTCSA_TUP)
sa = rtcin(RTC_STATUSA);
tod->year = bcd(rtcin(RTC_YEAR)) + 1900; /* year */
if (tod->year < 1970) tod->year += 100;
tod->month = bcd(rtcin(RTC_MONTH)); /* month */
tod->day = bcd(rtcin(RTC_DAY)); /* day */
(void) bcd(rtcin(RTC_WDAY)); /* weekday */
tod->hour = bcd(rtcin(RTC_HRS)); /* hour */
tod->minute = bcd(rtcin(RTC_MIN)); /* minutes */
tod->second = bcd(rtcin(RTC_SEC)); /* seconds */
tod->ticks = 0;
#ifndef QUICK_READ /* Quick read of the RTC: don't return number of seconds. */
sec = ytos(tod->year);
sec += mtos(tod->month, (tod->year % 4) == 0);
sec += tod->day * SECS_PER_DAY;
sec += tod->hour * 60 * 60; /* hour */
sec += tod->minute * 60; /* minutes */
sec += tod->second; /* seconds */
#endif /* QUICK_READ */
return (long int)sec;
} /* rtc_read */

View File

@@ -0,0 +1,32 @@
/*
* This file contains the RTC driver table for Motorola shared BSPs.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <libchip/rtc.h>
#include <libchip/mc146818a.h>
/* The following table configures the RTC drivers used in this BSP */
rtc_tbl RTC_Table[] = {
{
"/dev/rtc", /* sDeviceName */
RTC_MC146818A, /* deviceType */
&mc146818a_fns, /* pDeviceFns */
mc146818a_probe, /* deviceProbe */
NULL, /* pDeviceParams */
0x70, /* ulCtrlPort1 */
0x00, /* ulDataPort */
mc146818a_get_register, /* getRegister */
mc146818a_set_register /* setRegister */
}
};
/* Some information used by the RTC driver */
#define NUM_RTCS (sizeof(RTC_Table)/sizeof(rtc_tbl))
size_t RTC_Count = NUM_RTCS;

View File

@@ -0,0 +1,78 @@
/*
* Clock device driver for Lattice Mico32 (lm32).
*/
/*
* COPYRIGHT (c) 1989-2009.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Jukka Pietarinen <jukka.pietarinen@mrf.fi>, 2008,
* Micro-Research Finland Oy
*/
#include <bsp.h>
#include "../include/system_conf.h"
#include "clock.h"
#include "bspopts.h"
#if LM32_ON_SIMULATOR
#define CLOCK_DRIVER_USE_FAST_IDLE 1
#endif
static inline int clockread(unsigned int reg)
{
return *((int*)(TIMER0_BASE_ADDRESS + reg));
}
static inline void clockwrite(unsigned int reg, int value)
{
*((int*)(TIMER0_BASE_ADDRESS + reg)) = value;
}
/*
* The interrupt vector number associated with the clock tick device
* driver.
*/
#define CLOCK_VECTOR ( TIMER0_IRQ )
#define CLOCK_IRQMASK ( 1 << CLOCK_VECTOR )
#define Clock_driver_support_at_tick() \
do { \
/* Clear overflow flag */ \
clockwrite(LM32_CLOCK_SR, 0); \
lm32_interrupt_ack(CLOCK_IRQMASK); \
} while (0)
#define Clock_driver_support_install_isr(_new ) \
set_vector( _new, CLOCK_VECTOR, 1 )
static void Clock_driver_support_initialize_hardware(void)
{
/* Set clock period */
clockwrite(LM32_CLOCK_PERIOD,
(CPU_FREQUENCY /
(1000000 / rtems_configuration_get_microseconds_per_tick())));
/* Enable clock interrupts and start in continuous mode */
clockwrite(LM32_CLOCK_CR, LM32_CLOCK_CR_ITO |
LM32_CLOCK_CR_CONT |
LM32_CLOCK_CR_START);
lm32_interrupt_unmask(CLOCK_IRQMASK);
}
#define Clock_driver_support_shutdown_hardware() \
do { \
/* Disable clock interrupts and stop */ \
lm32_interrupt_unmask(CLOCK_IRQMASK); \
clockwrite(LM32_CLOCK_CR, LM32_CLOCK_CR_STOP); \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,55 @@
/**
* @file
* @ingroup lm32_clock
* @brief LatticeMico32 Timer (Clock) definitions
*/
/*
* This file contains definitions for LatticeMico32 Timer (Clock)
*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Jukka Pietarinen <jukka.pietarinen@mrf.fi>, 2008,
* Micro-Research Finland Oy
*/
/**
* @defgroup lm32_clock LM32 Clock
* @ingroup lm32_shared
* @brief LatticeMico32 Timer (Clock) definitions.
* @{
*/
#ifndef _BSPCLOCK_H
#define _BSPCLOCK_H
/** @brief Status Register */
#define LM32_CLOCK_SR (0x0000)
#define LM32_CLOCK_SR_TO (0x0001)
#define LM32_CLOCK_SR_RUN (0x0002)
/** @brief Control Register */
#define LM32_CLOCK_CR (0x0004)
#define LM32_CLOCK_CR_ITO (0x0001)
#define LM32_CLOCK_CR_CONT (0x0002)
#define LM32_CLOCK_CR_START (0x0004)
#define LM32_CLOCK_CR_STOP (0x0008)
/** @brief Period Register */
#define LM32_CLOCK_PERIOD (0x0008)
/** @brief Snapshot Register */
#define LM32_CLOCK_SNAPSHOT (0x000C)
#endif /* _BSPCLOCK_H */
/** @} */

View File

@@ -0,0 +1,61 @@
/*
* Use the last periodic interval timer (PIT3) as the system clock.
*/
#include <rtems.h>
#include <bsp.h>
#include <mcf5282/mcf5282.h>
/*
* Use INTC0 base
*/
#define CLOCK_VECTOR (64+58)
/*
* Periodic interval timer interrupt handler
*/
#define Clock_driver_support_at_tick() \
do { \
MCF5282_PIT3_PCSR |= MCF5282_PIT_PCSR_PIF; \
} while (0) \
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF5282_PIT3_PCSR &= ~MCF5282_PIT_PCSR_EN; \
} while(0)
/*
* Set up the clock hardware
*
* We need to have 1 interrupt every 10,000 microseconds
* so we need to set prescaler to 64 and the PMR register to 0x23FE
*/
#define Clock_driver_support_initialize_hardware() \
do { \
int level; \
int preScaleCode = 5; \
MCF5282_INTC0_ICR58 = MCF5282_INTC_ICR_IL(PIT3_IRQ_LEVEL) | \
MCF5282_INTC_ICR_IP(PIT3_IRQ_PRIORITY); \
rtems_interrupt_disable( level ); \
MCF5282_INTC0_IMRH &= ~MCF5282_INTC_IMRH_INT58; \
MCF5282_PIT3_PCSR &= ~MCF5282_PIT_PCSR_EN; \
rtems_interrupt_enable( level ); \
MCF5282_PIT3_PMR = 0x23FE; \
MCF5282_PIT3_PCSR = MCF5282_PIT_PCSR_PRE(preScaleCode) | \
MCF5282_PIT_PCSR_PIE | \
MCF5282_PIT_PCSR_RLD | \
MCF5282_PIT_PCSR_EN; \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,104 @@
/*
* This routine initializes the MC68340/349 Periodic Interval Timer
*/
/*
* Based on the `gen68360' board support package, and covered by the
* original distribution terms.
*
* Geoffroy Montel
* France Telecom - CNET/DSM/TAM/CAT
* 4, rue du Clos Courtel
* 35512 CESSON-SEVIGNE
* FRANCE
*
* e-mail: g_montel@yahoo.com
*/
/*
* COPYRIGHT (c) 1989-2014.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdlib.h> /* for atexit() */
#include <bsp.h>
#include <m68340.h>
#include <rtems/clockdrv.h>
#define CLOCK_VECTOR 120 /* clock isr routine vector in the vbr */
#define CLOCK_IRQ_LEVEL 6 /* clock isr level */
/*
* Clock_driver_ticks is a monotonically increasing counter of the
* number of clock ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
/*
* Periodic interval timer interrupt handler
*/
static rtems_isr
Clock_isr (rtems_vector_number vector)
{
/*
* Announce the clock tick
*/
Clock_driver_ticks++;
rtems_clock_tick();
}
void
Clock_exit (void)
{
/*
* Turn off periodic interval timer
*/
SIMPITR = 0;
}
static void
Install_clock (rtems_isr_entry clock_isr)
{
uint32_t pitr_tmp;
uint32_t usecs_per_tick;
Clock_driver_ticks = 0;
set_vector (clock_isr, CLOCK_VECTOR, 1);
/* sets the Periodic Interrupt Control Register PICR */
SIMPICR = ( CLOCK_IRQ_LEVEL << 8 ) | ( CLOCK_VECTOR );
/* sets the PITR count value */
/* this assumes a 32.765 kHz crystal */
usecs_per_tick = rtems_configuration_get_microseconds_per_tick();
/* find out whether prescaler should be enabled or not */
if ( usecs_per_tick <= 31128 ) {
pitr_tmp = ( usecs_per_tick * 8192 ) / 1000000 ;
} else {
pitr_tmp = ( usecs_per_tick / 1000000 ) * 16;
/* enable it */
pitr_tmp |= 0x100;
}
SIMPITR = (unsigned char) pitr_tmp;
atexit (Clock_exit);
}
rtems_device_driver
Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock (Clock_isr);
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,101 @@
/*
* This routine initializes the MC68360 Periodic Interval Timer
*
* The PIT has rather poor resolution, but it is easy to set up
* and requires no housekeeping once it is going.
*
* W. Eric Norum
* Saskatchewan Accelerator Laboratory
* University of Saskatchewan
* Saskatoon, Saskatchewan, CANADA
* eric@skatter.usask.ca
*/
#include <rtems.h>
#include <bsp.h>
#include <rtems/m68k/m68360.h>
#define CLOCK_VECTOR 120
#define CLOCK_IRQ_LEVEL 4
char M360DefaultWatchdogFeeder = 1;
/*
* RTEMS and hardware have different notions of clock rate.
*/
static unsigned long rtems_nsec_per_tick;
static unsigned long pit_nsec_per_tick;
static unsigned long nsec;
/*
* Periodic interval timer interrupt handler
* See if it's really time for a `tick'
* Perform a dummy read of DPRAM (work around bug in Rev. B of the 68360).
* Feed the watchdog
* Application code can override this by
* setting M360DefaultWatchdogFeeder to zero.
*/
#define Clock_driver_support_at_tick() \
do { \
nsec += pit_nsec_per_tick; \
if (nsec >= rtems_nsec_per_tick) \
return; \
nsec -= rtems_nsec_per_tick; \
m360.dpram0[0]; \
if (M360DefaultWatchdogFeeder) { \
m360.swsr = 0x55; \
m360.swsr = 0xAA; \
} \
} while (0) \
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
m360.pitr &= ~0xFF; \
} while(0)
/*
* Set up the clock hardware
* The rate at which the periodic interval timer
* can generate interrupts is almost certainly not
* the same as desired by the BSP configuration.
* Handle the difference by choosing the largest PIT
* interval which is less than or equal to the RTEMS
* interval and skipping some hardware interrupts.
* To reduce the jitter in the calls to RTEMS the
* hardware interrupt interval is never greater than
* the maximum non-prescaled value from the PIT.
*
* For a 25 MHz external clock the basic clock rate is
* 40 nsec * 128 * 4 = 20.48 usec/tick
*/
extern int m360_clock_rate;
#define Clock_driver_support_initialize_hardware() \
do { \
unsigned int divisor; \
unsigned long nsec_per_chip_tick = 1000000000 / m360_clock_rate; \
unsigned long nsec_per_pit_tick = 512 * nsec_per_chip_tick; \
rtems_nsec_per_tick = rtems_configuration_get_microseconds_per_tick() * 1000; \
divisor = rtems_nsec_per_tick / nsec_per_pit_tick; \
if (divisor > 255) \
divisor = 255; \
else if (divisor == 0) \
divisor = 1; \
pit_nsec_per_tick = nsec_per_pit_tick * divisor; \
m360.pitr &= ~0x1FF; \
m360.picr = (CLOCK_IRQ_LEVEL << 8) | CLOCK_VECTOR; \
m360.pitr |= divisor; \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,102 @@
/*===============================================================*\
| Project: RTEMS generic mcf548x BSP |
+-----------------------------------------------------------------+
| File: clock.c |
+-----------------------------------------------------------------+
| The file contains the clock driver code of generic MCF548x BSP. |
+-----------------------------------------------------------------+
| Copyright (c) 2007 |
| Embedded Brains GmbH |
| Obere Lagerstr. 30 |
| D-82178 Puchheim |
| Germany |
| rtems@embedded-brains.de |
+-----------------------------------------------------------------+
| |
| Parts of the code has been derived from the "dBUG source code" |
| package Freescale is providing for M548X EVBs. The usage of |
| the modified or unmodified code and it's integration into the |
| generic mcf548x BSP has been done according to the Freescale |
| license terms. |
| |
| The Freescale license terms can be reviewed in the file |
| |
| Freescale_license.txt |
| |
+-----------------------------------------------------------------+
| |
| The generic mcf548x BSP has been developed on the basic |
| structures and modules of the av5282 BSP. |
| |
+-----------------------------------------------------------------+
| |
| The license and distribution terms for this file may be |
| found in the file LICENSE in this distribution or at |
| |
| http://www.rtems.org/license/LICENSE. |
| |
+-----------------------------------------------------------------+
| |
| date history ID |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 12.11.07 1.0 ras |
| |
\*===============================================================*/
/*
* Use first slice timer (SLT0) as the system clock.
*
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq-generic.h>
#include <mcf548x/mcf548x.h>
/*
* Use SLT 0
*/
#define CLOCK_IRQ MCF548X_IRQ_SLT0
/*
* Periodic interval timer interrupt handler
*/
#define Clock_driver_support_at_tick() \
do { \
MCF548X_SLT_SSR0 = MCF548X_SLT_SSR_ST; \
} while (0) \
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_IRQ + 64, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF548X_SLT_SCR0 &= ~(MCF548X_SLT_SCR_TEN | MCF548X_SLT_SCR_RUN | MCF548X_SLT_SCR_IEN); \
} while(0)
/*
* Set up the clock hardware
*
* We need to have 1 interrupt every 10,000 microseconds
* XLB clock 100 MHz / MCF548X_SLT_SLTCNT0 = XLB clock/100
*/
#define Clock_driver_support_initialize_hardware() \
do { \
bsp_interrupt_vector_enable(CLOCK_IRQ); \
MCF548X_SLT_SLTCNT0 = get_CPU_clock_speed() \
/ 1000 \
* rtems_configuration_get_microseconds_per_tick() \
/ 1000; \
MCF548X_SLT_SCR0 |= (MCF548X_SLT_SCR_TEN | MCF548X_SLT_SCR_RUN | MCF548X_SLT_SCR_IEN); \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,106 @@
/*
* Use the last periodic interval timer (PIT2) as the system clock.
*/
#include <rtems.h>
#include <rtems/timecounter.h>
#include <bsp.h>
/*
* Use INTC0 base
*/
#define CLOCK_VECTOR (64+56)
static rtems_timecounter_simple mcf52235_tc;
static uint32_t mcf52235_tc_get(rtems_timecounter_simple *tc)
{
return MCF_PIT1_PCNTR;
}
static bool mcf52235_tc_is_pending(rtems_timecounter_simple *tc)
{
return (MCF_PIT1_PCSR & MCF_PIT_PCSR_PIF) != 0;
}
static uint32_t mcf52235_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
mcf52235_tc_get,
mcf52235_tc_is_pending
);
}
static void mcf52235_tc_at_tick(rtems_timecounter_simple *tc)
{
MCF_PIT1_PCSR |= MCF_PIT_PCSR_PIF;
}
static void mcf52235_tc_tick(void)
{
rtems_timecounter_simple_downcounter_tick(
&mcf52235_tc,
mcf52235_tc_get,
mcf52235_tc_at_tick
);
}
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF_PIT1_PCSR &= ~MCF_PIT_PCSR_EN; \
} while (0)
/*
* Set up the clock hardware
*
* We need to have 1 interrupt every rtems_configuration_get_microseconds_per_tick()
*/
static void Clock_driver_support_initialize_hardware(void)
{
int level;
uint32_t pmr;
uint32_t preScaleCode = 0;
uint32_t clk = bsp_get_CPU_clock_speed() >> 1;
uint32_t tps = 1000000 / rtems_configuration_get_microseconds_per_tick();
while (preScaleCode < 15) {
pmr = (clk >> preScaleCode) / tps;
if (pmr < (1 << 15))
break;
preScaleCode++;
}
MCF_INTC0_ICR56 = MCF_INTC_ICR_IL(PIT3_IRQ_LEVEL) |
MCF_INTC_ICR_IP(PIT3_IRQ_PRIORITY);
rtems_interrupt_disable(level);
MCF_INTC0_IMRH &= ~MCF_INTC_IMRH_MASK56;
MCF_PIT1_PCSR &= ~MCF_PIT_PCSR_EN;
rtems_interrupt_enable(level);
MCF_PIT1_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) |
MCF_PIT_PCSR_OVW | MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD;
MCF_PIT1_PMR = pmr;
MCF_PIT1_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) |
MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD | MCF_PIT_PCSR_EN;
rtems_timecounter_simple_install(
&mcf52235_tc,
clk >> preScaleCode,
pmr,
mcf52235_tc_get_timecount
);
}
#define Clock_driver_timecounter_tick() mcf52235_tc_tick()
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,106 @@
/*
* Use the last periodic interval timer (PIT2) as the system clock.
*/
#include <rtems.h>
#include <rtems/timecounter.h>
#include <bsp.h>
/*
* Use INTC0 base
*/
#define CLOCK_VECTOR (64+56)
static rtems_timecounter_simple mcf5225x_tc;
static uint32_t mcf5225x_tc_get(rtems_timecounter_simple *tc)
{
return MCF_PIT1_PCNTR;
}
static bool mcf5225x_tc_is_pending(rtems_timecounter_simple *tc)
{
return (MCF_PIT1_PCSR & MCF_PIT_PCSR_PIF) != 0;
}
static uint32_t mcf5225x_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
mcf5225x_tc_get,
mcf5225x_tc_is_pending
);
}
static void mcf5225x_tc_at_tick(rtems_timecounter_simple *tc)
{
MCF_PIT1_PCSR |= MCF_PIT_PCSR_PIF;
}
static void mcf5225x_tc_tick(void)
{
rtems_timecounter_simple_downcounter_tick(
&mcf5225x_tc,
mcf5225x_tc_get,
mcf5225x_tc_at_tick
);
}
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF_PIT1_PCSR &= ~MCF_PIT_PCSR_EN; \
} while (0)
/*
* Set up the clock hardware
*
* We need to have 1 interrupt every BSP_rtems_configuration_get_microseconds_per_tick()
*/
static void Clock_driver_support_initialize_hardware(void)
{
int level;
uint32_t pmr;
uint32_t preScaleCode = 0;
uint32_t clk = bsp_get_CPU_clock_speed() >> 1;
uint32_t tps = 1000000 / rtems_configuration_get_microseconds_per_tick();
while (preScaleCode < 15) {
pmr = (clk >> preScaleCode) / tps;
if (pmr < (1 << 15))
break;
preScaleCode++;
}
MCF_INTC0_ICR56 = MCF_INTC_ICR_IL(PIT3_IRQ_LEVEL) |
MCF_INTC_ICR_IP(PIT3_IRQ_PRIORITY);
rtems_interrupt_disable(level);
MCF_INTC0_IMRH &= ~MCF_INTC_IMRH_MASK56;
MCF_PIT1_PCSR &= ~MCF_PIT_PCSR_EN;
rtems_interrupt_enable(level);
MCF_PIT1_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) |
MCF_PIT_PCSR_OVW | MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD;
MCF_PIT1_PMR = pmr;
MCF_PIT1_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) |
MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD | MCF_PIT_PCSR_EN;
rtems_timecounter_simple_install(
&mcf5225x_tc,
clk >> preScaleCode,
pmr,
mcf5225x_tc_get_timecount
);
}
#define Clock_driver_timecounter_tick() mcf5225x_tc_tick()
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,61 @@
/*
* Use the last periodic interval timer (PIT3) as the system clock.
*/
#include <rtems.h>
#include <bsp.h>
#include <mcf5235/mcf5235.h>
/*
* Use INTC0 base
*/
#define CLOCK_VECTOR (64+39)
/*
* Periodic interval timer interrupt handler
*/
#define Clock_driver_support_at_tick() \
do { \
MCF5235_PIT_PCSR3 |= MCF5235_PIT_PCSR_PIF; \
} while (0) \
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF5235_PIT_PCSR3 &= ~MCF5235_PIT_PCSR_EN; \
} while(0)
/*
* Set up the clock hardware
*
* We need to have 1 interrupt every 10,000 microseconds
* so we need to set prescaler to 64 and the PMR register to 0x2DC6
*/
#define Clock_driver_support_initialize_hardware() \
do { \
int level; \
int preScaleCode = 6; \
MCF5235_INTC0_ICR39 = MCF5235_INTC_ICR_IL(PIT3_IRQ_LEVEL) | \
MCF5235_INTC_ICR_IP(PIT3_IRQ_PRIORITY); \
rtems_interrupt_disable( level ); \
MCF5235_INTC0_IMRH &= ~MCF5235_INTC0_IMRH_INT39; \
MCF5235_PIT_PCSR3 &= ~MCF5235_PIT_PCSR_EN; \
rtems_interrupt_enable( level ); \
MCF5235_PIT_PMR3 = 0x2DC6; \
MCF5235_PIT_PCSR3 = MCF5235_PIT_PCSR_PRE(preScaleCode) | \
MCF5235_PIT_PCSR_PIE | \
MCF5235_PIT_PCSR_RLD | \
MCF5235_PIT_PCSR_EN; \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,105 @@
/*
* Use the last periodic interval timer (PIT2) as the system clock.
*/
#include <rtems.h>
#include <rtems/timecounter.h>
#include <bsp.h>
/*
* Use INTC1 base
*/
#define CLOCK_VECTOR (128+46)
static rtems_timecounter_simple mcf5329_tc;
static uint32_t mcf5329_tc_get(rtems_timecounter_simple *tc)
{
return MCF_PIT3_PCNTR;
}
static bool mcf5329_tc_is_pending(rtems_timecounter_simple *tc)
{
return (MCF_PIT3_PCSR & MCF_PIT_PCSR_PIF) != 0;
}
static uint32_t mcf5329_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
mcf5329_tc_get,
mcf5329_tc_is_pending
);
}
static void mcf5329_tc_at_tick(rtems_timecounter_simple *tc)
{
MCF_PIT3_PCSR |= MCF_PIT_PCSR_PIF;
}
static void mcf5329_tc_tick(void)
{
rtems_timecounter_simple_downcounter_tick(
&mcf5329_tc,
mcf5329_tc_get,
mcf5329_tc_at_tick
);
}
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF_PIT3_PCSR &= ~MCF_PIT_PCSR_EN; \
} while (0)
/*
* Set up the clock hardware
*
* We need to have 1 interrupt every rtems_configuration_get_microseconds_per_tick()
*/
static void Clock_driver_support_initialize_hardware(void)
{
int level;
uint32_t pmr;
uint32_t preScaleCode = 0;
uint32_t clk = bsp_get_BUS_clock_speed();
uint32_t tps = 1000000 / rtems_configuration_get_microseconds_per_tick();
while (preScaleCode < 15) {
pmr = (clk >> preScaleCode) / tps;
if (pmr < (1 << 15))
break;
preScaleCode++;
}
MCF_INTC1_ICR46 = MCF_INTC_ICR_IL(PIT3_IRQ_LEVEL);
rtems_interrupt_disable(level);
MCF_INTC1_IMRH &= ~MCF_INTC_IMRH_INT_MASK46;
MCF_PIT3_PCSR &= ~MCF_PIT_PCSR_EN;
rtems_interrupt_enable(level);
MCF_PIT3_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) |
MCF_PIT_PCSR_OVW | MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD;
MCF_PIT3_PMR = pmr;
MCF_PIT3_PCSR = MCF_PIT_PCSR_PRE(preScaleCode) |
MCF_PIT_PCSR_PIE | MCF_PIT_PCSR_RLD | MCF_PIT_PCSR_EN;
rtems_timecounter_simple_install(
&mcf5329_tc,
clk >> preScaleCode,
pmr,
mcf5329_tc_get_timecount
);
}
#define Clock_driver_timecounter_tick() mcf5329_tc_tick()
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,75 @@
/*
* This routine initailizes the periodic interrupt timer on
* the Motorola 68332.
*/
/*
* COPYRIGHT (c) 1989-2014.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdlib.h>
#include <bsp.h>
#include <mrm332.h>
#include <rtems/clockdrv.h>
#include <rtems/m68k/sim.h>
#define CLOCK_VECTOR MRM_PIV
uint32_t Clock_isrs; /* ISRs until next tick */
volatile uint32_t Clock_driver_ticks; /* ticks since initialization */
static rtems_isr_entry Old_ticker;
void Clock_exit( void );
static rtems_isr Clock_isr(rtems_vector_number vector)
{
Clock_driver_ticks += 1;
if ( Clock_isrs == 1 ) {
rtems_clock_tick();
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
}
else
Clock_isrs -= 1;
}
static void Install_clock(rtems_isr_entry clock_isr)
{
Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
Old_ticker = (rtems_isr_entry) set_vector( clock_isr, CLOCK_VECTOR, 1 );
/* enable 1mS interrupts */
*PITR = (unsigned short int)( SAM(0x09,0,PITM) );/* load counter */
*PICR = (unsigned short int) /* enable interrupt */
( SAM(ISRL_PIT,8,PIRQL) | SAM(CLOCK_VECTOR,0,PIV) );
atexit( Clock_exit );
}
void Clock_exit( void )
{
/* shutdown the periodic interrupt */
*PICR = (unsigned short int)
( SAM(0,8,PIRQL) | SAM(CLOCK_VECTOR,0,PIV) );
/* ^^ zero disables interrupt */
/* do not restore old vector */
}
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,82 @@
/*
* This routine initializes the Tick Timer 2 on the MVME147 board.
* The tick frequency is 1 millisecond.
*/
/*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* MVME147 port for TNI - Telecom Bretagne
* by Dominique LE CAMPION (Dominique.LECAMPION@enst-bretagne.fr)
* May 1996
*/
#include <stdlib.h>
#include <bsp.h>
#include <rtems/clockdrv.h>
#define MS_COUNT 65376 /* 1ms */
/* MS_COUNT = 0x10000 - 1e-3/6.25e-6 */
#define CLOCK_INT_LEVEL 6 /* T2's interrupt level */
uint32_t Clock_isrs; /* ISRs until next tick */
volatile uint32_t Clock_driver_ticks; /* ticks since initialization */
rtems_isr_entry Old_ticker;
void Clock_exit( void );
/*
* ISR Handler
*/
static rtems_isr Clock_isr(rtems_vector_number vector)
{
Clock_driver_ticks += 1;
pcc->timer2_int_control |= 0x80; /* Acknowledge interr. */
if (Clock_isrs == 1) {
rtems_clock_tick();
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
}
else
Clock_isrs -= 1;
}
static void Install_clock(rtems_isr_entry clock_isr )
{
Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
Old_ticker = (rtems_isr_entry) set_vector( clock_isr, TIMER_2_VECTOR, 1 );
pcc->timer2_int_control = 0x00; /* Disable T2 Interr. */
pcc->timer2_preload = MS_COUNT;
/* write preload value */
pcc->timer2_control = 0x07; /* clear T2 overflow counter, enable counter */
pcc->timer2_int_control = CLOCK_INT_LEVEL|0x08;
/* Enable Timer 2 and set its int. level */
atexit( Clock_exit );
}
void Clock_exit( void )
{
pcc->timer2_int_control = 0x00; /* Disable T2 Interr. */
}
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,89 @@
/*
* This routine initializes the Tick Timer 2 on the MVME162 board.
* The tick frequency is 1 millisecond.
*/
/*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Modifications of respective RTEMS file: COPYRIGHT (c) 1994.
* EISCAT Scientific Association. M.Savitski
*
* This material is a part of the MVME162 Board Support Package
* for the RTEMS executive. Its licensing policies are those of the
* RTEMS above.
*/
#include <stdlib.h>
#include <bsp.h>
#include <rtems/clockdrv.h>
#define MS_COUNT 1000 /* T2's countdown constant (1 ms) */
#define CLOCK_INT_LEVEL 6 /* T2's interrupt level */
uint32_t Clock_isrs; /* ISRs until next tick */
volatile uint32_t Clock_driver_ticks; /* ticks since initialization */
rtems_isr_entry Old_ticker;
void Clock_exit( void );
#define CLOCK_VECTOR (VBR0 * 0x10 + 0x9)
/*
* ISR Handler
*/
static rtems_isr Clock_isr(rtems_vector_number vector)
{
Clock_driver_ticks += 1;
lcsr->timer_cnt_2 = 0; /* clear counter */
lcsr->intr_clear |= 0x02000000;
if ( Clock_isrs == 1 ) {
rtems_clock_tick();
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
}
else
Clock_isrs -= 1;
}
static void Install_clock(rtems_isr_entry clock_isr )
{
Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
Old_ticker = (rtems_isr_entry) set_vector( clock_isr, CLOCK_VECTOR, 1 );
lcsr->vector_base |= MASK_INT; /* unmask VMEchip2 interrupts */
lcsr->to_ctl = 0xE7; /* prescaler to 1 MHz (see Appendix A1) */
lcsr->timer_cmp_2 = MS_COUNT;
lcsr->timer_cnt_2 = 0; /* clear counter */
lcsr->board_ctl |= 0x700; /* increment, reset-on-compare, and */
/* clear-overflow-cnt */
lcsr->intr_level[0] |= CLOCK_INT_LEVEL * 0x10; /* set int level */
lcsr->intr_ena |= 0x02000000; /* enable tick timer 2 interrupt */
atexit( Clock_exit );
}
void Clock_exit( void )
{
/* Dummy for now. See other m68k BSP's for code examples */
}
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,159 @@
/*
* Implementation of the Clock_initialize() functions
* prototyped in rtems/c/src/lib/include/clockdrv.h.
*
* This port does not allow the application to select which timer on the
* MVME167 to use for the clock, nor does it allow the application to
* configure the clock. The clock uses the VMEchip2 Tick Timer #2. This
* timer is set up to raise a MC680x0 level-6 interrupt every 1 ms. The
* interrupt vector is 0x69.
*
* All page references are to the MVME166/MVME167/MVME187 Single Board
* Computer Programmer's Reference Guide (MVME187PG/D2) with the April
* 1993 supplements/addenda (MVME187PG/D2A1).
*/
/*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Modifications of respective RTEMS files:
* Copyright (c) 1998, National Research Council of Canada
*/
#include <stdlib.h>
#include <bsp.h>
#include <rtems/clockdrv.h>
#define MS_COUNT 1000 /* T2's countdown constant (1 ms) */
#define CLOCK_INT_LEVEL 6 /* T2's interrupt level */
#define CLOCK_VECTOR (VBR0 * 0x10 + 0x9) /* T2 is vector $X9 (p. 2-71)*/
/*
* Clock_driver_ticks is a monotonically increasing counter of the number of
* VMEchip2 timer #2 ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
/*
* Clock_isrs is the number of clock ISRs until the next invocation of the
* RTEMS clock tick routine. This clock tick device driver gets an interrupt
* once a millisecond and counts down until the length of time between the
* user configured microseconds per tick has passed. This allows the clock
* device to "tick" faster than the kernel clock. Of course, the kernel clock
* cannot tick faster than the hardware clock. Therefore, the kernel clock
* ticks cannot occur more frequently than every 1 millisecond.
*/
uint32_t Clock_isrs;
/*
* Records the previous clock ISR (should be NULL)
*/
rtems_isr_entry Old_ticker;
/*
* Called when the kernel exits.
*/
void clock_exit( void );
/*
* VMEchip2_T2_isr
*
* C ISR Handler. Increment the number of internal ticks. If it is time for a
* kernel clock tick (if Clock_isrs == 1), call rtems_clock_tick() to signal
* the event and reset the Clock_isrs counter; else, just decrement it.
*/
static rtems_isr VMEchip2_T2_isr(
rtems_vector_number vector
)
{
char overflow; /* Content of overflow counter */
long i;
long ct; /* Number of T2 ticks per RTEMS ticks */
ct = rtems_configuration_get_microseconds_per_tick() / 1000;
/*
* May have missed interrupts, so should look at the overflow counter.
*/
lcsr->intr_clear |= 0x02000000; /* Clear the interrupt */
overflow = (lcsr->board_ctl >> 12) & 0xF;
lcsr->board_ctl |= 0x400; /* Reset overflow counter */
/* Attempt to protect against one more period */
if ( overflow == 0 )
overflow = 16;
Clock_driver_ticks += overflow; /* One or more internal ticks */
if ( Clock_isrs <= overflow ) {
/* If its time for kernel clock ticks, signal the events to RTEMS */
for( i = overflow - Clock_isrs; i >= 0; i -= ct ) {
rtems_clock_tick();
}
/* Reset the counter */
Clock_isrs = (uint32_t)-i;
}
else
Clock_isrs -= overflow;
}
/*
* VMEchip2_T2_initialize
*
* Initialize the VMEchip2 Tick Timer #2.
*
* THE VMECHIP2 PRESCALER REGISTER IS ASSUMED TO BE SET!
* The prescaler is used by all VMEchip2 timers, including the VMEbus grant
* timeout counter, the DMAC time off timer, the DMAC timer on timer, and the
* VMEbus global timeout timer. The prescaler value is normally set by the
* boot ROM to provide a 1 MHz clock to the timers. For a 25 MHz MVME167, the
* prescaler value should be 0xE7 (page 2-63).
*/
static void VMEchip2_T2_initialize( void )
{
Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
lcsr->intr_ena &= 0xFDFFFFFF; /* Disable tick timer 2 interrupt */
lcsr->intr_clear = 0x02000000; /* Clear tick timer 2 interrupt */
lcsr->intr_level[0] = /* Set tick timer 2 interrupt level */
(lcsr->intr_level[0] & 0xFFFFFF0F ) | (CLOCK_INT_LEVEL << 4);
lcsr->timer_cmp_2 = MS_COUNT; /* Period in compare register */
lcsr->timer_cnt_2 = 0; /* Clear tick timer 2 counter */
Old_ticker = /* Install C ISR */
(rtems_isr_entry) set_vector( VMEchip2_T2_isr, CLOCK_VECTOR, 1 );
lcsr->board_ctl |= 0x700; /* Start tick timer 2, reset-on-compare, */
/* and clear tick timer 2 overflow counter */
lcsr->intr_ena |= 0x02000000; /* Enable tick timer 2 interrupt */
lcsr->vector_base |= 0x00800000;/* Unmask VMEchip2 interrupts */
atexit( clock_exit ); /* Turn off T2 interrupts when we exit */
}
/*
* This routine stops the VMEchip2 T2 timer, disables its interrupt, and
* re-install the old interrupt vectors.
*/
void clock_exit( void )
{
lcsr->board_ctl &= 0xFFFFFEFF; /* Stop tick timer 2 */
lcsr->intr_ena &= 0xFDFFFFFF; /* Disable tick timer 2 interrupt */
lcsr->intr_clear = 0x02000000; /* Clear tick timer 2 interrupt */
set_vector( Old_ticker, CLOCK_VECTOR, 1 );
}
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
VMEchip2_T2_initialize();
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,161 @@
/*
* Use the last periodic interval timer (PIT3) as the system clock.
*
* Author: W. Eric Norum <norume@aps.anl.gov>
*
* COPYRIGHT (c) 2005.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <rtems/timecounter.h>
#include <bsp.h>
#include <mcf5282/mcf5282.h>
/*
* CPU load counters
* Place in static RAM so updates don't hit the SDRAM
*/
#define IDLE_COUNTER __SRAMBASE.idle_counter
#define FILTERED_IDLE __SRAMBASE.filtered_idle
#define MAX_IDLE_COUNT __SRAMBASE.max_idle_count
#define PITC_PER_TICK __SRAMBASE.pitc_per_tick
#define NSEC_PER_PITC __SRAMBASE.nsec_per_pitc
#define FILTER_SHIFT 6
/*
* Use INTC0 base
*/
#define CLOCK_VECTOR (64+58)
static rtems_timecounter_simple uC5282_tc;
static uint32_t uC5282_tc_get(rtems_timecounter_simple *tc)
{
return MCF5282_PIT3_PCNTR;
}
static bool uC5282_tc_is_pending(rtems_timecounter_simple *tc)
{
return (MCF5282_PIT3_PCSR & MCF5282_PIT_PCSR_PIF) != 0;
}
static uint32_t uC5282_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
uC5282_tc_get,
uC5282_tc_is_pending
);
}
static void uC5282_tc_at_tick(rtems_timecounter_simple *tc)
{
unsigned idle = IDLE_COUNTER;
IDLE_COUNTER = 0;
if (idle > MAX_IDLE_COUNT)
MAX_IDLE_COUNT = idle;
FILTERED_IDLE = idle + FILTERED_IDLE - (FILTERED_IDLE>>FILTER_SHIFT);
MCF5282_PIT3_PCSR |= MCF5282_PIT_PCSR_PIF;
}
static void uC5282_tc_tick(void)
{
rtems_timecounter_simple_downcounter_tick(
&uC5282_tc,
uC5282_tc_get,
uC5282_tc_at_tick
);
}
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr( _new ) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
MCF5282_PIT3_PCSR &= ~MCF5282_PIT_PCSR_EN; \
} while(0)
/*
* Set up the clock hardware
*
* f_pit = f_clk / 2^(preScaleCode+1) / N = 1/(us_per_tick/us_per_s)
*
* N = f_clk / 2^(preScaleCode+1) * us_per_tick / us_per_s
*
* ns_per_pit_clk = ns_per_s / (f_clk / 2^(preScaleCode+1))
* = ns_per_s * 2^(preScaleCode+1) / f_clk;
*/
#define Clock_driver_support_initialize_hardware() \
do { \
unsigned long long N; \
int level; \
int preScaleCode = 0; \
N = bsp_get_CPU_clock_speed(); \
N *= rtems_configuration_get_microseconds_per_tick(); \
N /= 2*1000000; /* min_prescale * us_per_s */ \
while ( N > 0x10000 ) { \
preScaleCode++; \
N >>= 1; \
} \
PITC_PER_TICK = N; \
N = 2000000000ULL << preScaleCode; \
N /= bsp_get_CPU_clock_speed(); \
NSEC_PER_PITC = N; \
IDLE_COUNTER = 0; \
FILTERED_IDLE = 0; \
MAX_IDLE_COUNT = 0; \
bsp_allocate_interrupt(PIT3_IRQ_LEVEL, PIT3_IRQ_PRIORITY); \
MCF5282_INTC0_ICR58 = MCF5282_INTC_ICR_IL(PIT3_IRQ_LEVEL) | \
MCF5282_INTC_ICR_IP(PIT3_IRQ_PRIORITY); \
rtems_interrupt_disable( level ); \
MCF5282_INTC0_IMRH &= ~MCF5282_INTC_IMRH_INT58; \
MCF5282_PIT3_PCSR &= ~MCF5282_PIT_PCSR_EN; \
rtems_interrupt_enable( level ); \
MCF5282_PIT3_PCSR = MCF5282_PIT_PCSR_PRE(preScaleCode) | \
MCF5282_PIT_PCSR_OVW | \
MCF5282_PIT_PCSR_PIE | \
MCF5282_PIT_PCSR_RLD; \
MCF5282_PIT3_PMR = PITC_PER_TICK - 1; \
MCF5282_PIT3_PCSR = MCF5282_PIT_PCSR_PRE(preScaleCode) | \
MCF5282_PIT_PCSR_PIE | \
MCF5282_PIT_PCSR_RLD | \
MCF5282_PIT_PCSR_EN; \
rtems_timecounter_simple_install( \
&uC5282_tc, \
bsp_get_CPU_clock_speed() >> (preScaleCode + 1), \
PITC_PER_TICK, \
uC5282_tc_get_timecount \
); \
} while (0)
/*
* Provide our own version of the idle task
*/
void * bsp_idle_thread(uint32_t ignored)
{
/* Atomic increment */
for(;;)
__asm__ volatile ("addq.l #1,%0"::"m"(IDLE_COUNTER));
}
int bsp_cpu_load_percentage(void)
{
return MAX_IDLE_COUNT ?
(100 - ((100 * (FILTERED_IDLE >> FILTER_SHIFT)) / MAX_IDLE_COUNT)) :
0;
}
#define Clock_driver_timecounter_tick() uC5282_tc_tick()
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,90 @@
/**
* @file
*
* Instantiate the clock driver shell.
*
* This uses the TOY (Time of Year) timer to implement the clock.
*/
/*
* Copyright (c) 2005 by Cogent Computer Systems
* Written by Jay Monkman <jtm@lopingdog.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/bspIo.h>
uint32_t tick_interval;
uint32_t last_match;
void au1x00_clock_init(void);
#define CLOCK_VECTOR AU1X00_IRQ_TOY_MATCH2
#define Clock_driver_support_at_tick() \
do { \
while (AU1X00_SYS_CNTCTRL(AU1X00_SYS_ADDR) & AU1X00_SYS_CNTCTRL_TM0); \
last_match = AU1X00_SYS_TOYREAD(AU1X00_SYS_ADDR); \
AU1X00_SYS_TOYMATCH2(AU1X00_SYS_ADDR) = last_match + tick_interval; \
au_sync(); \
} while(0)
/* Set for rising edge interrupt */
#define Clock_driver_support_install_isr( _new ) \
do { \
rtems_interrupt_handler_install( \
CLOCK_VECTOR, \
"clock", \
0, \
_new, \
NULL \
); \
AU1X00_IC_MASKCLR(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2; \
AU1X00_IC_SRCSET(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2; \
AU1X00_IC_CFG0SET(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2; \
AU1X00_IC_CFG1CLR(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2; \
AU1X00_IC_CFG2CLR(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2; \
AU1X00_IC_ASSIGNSET(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2; \
} while(0)
void au1x00_clock_init(void)
{
uint32_t wakemask;
/* Clear the trim register */
AU1X00_SYS_TOYTRIM(AU1X00_SYS_ADDR) = 0;
/* Clear the TOY counter */
while (AU1X00_SYS_CNTCTRL(AU1X00_SYS_ADDR) & AU1X00_SYS_CNTCTRL_TS);
AU1X00_SYS_TOYWRITE(AU1X00_SYS_ADDR) = 0;
while (AU1X00_SYS_CNTCTRL(AU1X00_SYS_ADDR) & AU1X00_SYS_CNTCTRL_TS);
wakemask = AU1X00_SYS_WAKEMSK(AU1X00_SYS_ADDR);
wakemask |= AU1X00_SYS_WAKEMSK_M20;
AU1X00_SYS_WAKEMSK(AU1X00_SYS_ADDR) = wakemask;
AU1X00_IC_WAKESET(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2;
tick_interval = 32768 * rtems_configuration_get_microseconds_per_tick();
tick_interval = tick_interval / 1000000;
last_match = AU1X00_SYS_TOYREAD(AU1X00_SYS_ADDR);
AU1X00_SYS_TOYMATCH2(AU1X00_SYS_ADDR) = last_match + (50*tick_interval);
AU1X00_IC_MASKSET(AU1X00_IC0_ADDR) = AU1X00_IC_IRQ_TOY_MATCH2;
while (AU1X00_SYS_CNTCTRL(AU1X00_SYS_ADDR) & AU1X00_SYS_CNTCTRL_TM0);
}
#define Clock_driver_support_initialize_hardware() \
do { \
au1x00_clock_init(); \
} while(0)
#define Clock_driver_support_shutdown_hardware()
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,219 @@
/**
* @file
*
* This file contains the clock driver initialization for the Hurricane BSP.
*/
/*
* Author: Craig Lebakken <craigl@transition.com>
*
* COPYRIGHT (c) 1996 by Transition Networks Inc.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of Transition Networks not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* Transition Networks makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/lib/libbsp/no_cpu/no_bsp/clock/ckinit.c
*
* COPYRIGHT (c) 1989-2012.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
/*
* Rather than deleting this, it is commented out to (hopefully) help
* the submitter send updates.
*
* static char _sccsid[] = "@(#)ckinit.c 08/20/96 1.3\n";
*/
#include <stdlib.h>
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/clockdrv.h>
extern uint32_t bsp_clicks_per_microsecond;
#define EXT_INT1 0x800 /* external interrupt 5 */
#include "clock.h"
rtems_isr USC_isr(void *unused);
void reset_wdt(void);
void enable_wdi(void);
void init_hbt(void);
void enable_hbi(void);
void disable_hbi(void);
void Clock_exit(void);
rtems_isr Clock_isr(rtems_vector_number vector);
rtems_isr User_Clock_isr(rtems_vector_number vector);
void Install_clock(rtems_isr_entry clock_isr);
/*
* The interrupt vector number associated with the clock tick device
* driver.
*/
#define CLOCK_VECTOR_MASK EXT_INT1
#define CLOCK_VECTOR MIPS_INTERRUPT_BASE + 0x3
/*
* Clock_driver_ticks is a monotonically increasing counter of the
* number of clock ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
/*
* Clock_isrs is the number of clock ISRs until the next invocation of
* the RTEMS clock tick routine. The clock tick device driver
* gets an interrupt once a millisecond and counts down until the
* length of time between the user configured microseconds per tick
* has passed.
*/
uint32_t Clock_isrs; /* ISRs until next tick */
/*
* The previous ISR on this clock tick interrupt vector.
*/
rtems_isr_entry Old_ticker;
void Clock_exit( void );
static uint32_t mips_timer_rate = 0;
/*
* Isr Handler
*/
rtems_isr Clock_isr(
rtems_vector_number vector
)
{
/*
* bump the number of clock driver ticks since initialization
*
* determine if it is time to announce the passing of tick as configured
* to RTEMS through the rtems_clock_tick directive
*
* perform any timer dependent tasks
*/
reset_wdt(); /* Reset hardware watchdog timer */
Clock_driver_ticks += 1;
rtems_clock_tick();
}
/* User callback shell (set from Clock_Control) */
static void (*user_callback)(void);
rtems_isr User_Clock_isr(
rtems_vector_number vector
)
{
if (user_callback)
user_callback();
}
/*
* Install_clock
*
* Install a clock tick handleR and reprograms the chip. This
* is used to initially establish the clock tick.
*/
void Install_clock(
rtems_isr_entry clock_isr
)
{
/*
* Initialize the clock tick device driver variables
*/
Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_milliseconds_per_tick();
mips_timer_rate = rtems_configuration_get_microseconds_per_tick() *
bsp_clicks_per_microsecond;
/*
* Hardware specific initialize goes here
*/
/* Set up USC heartbeat timer to generate interrupts */
disable_hbi(); /* Disable heartbeat interrupt in USC */
/* Install interrupt handler */
rtems_interrupt_handler_install(
CLOCK_VECTOR,
"clock",
0,
USC_isr,
NULL
);
init_hbt(); /* Initialize heartbeat timer */
reset_wdt(); /* Reset watchdog timer */
enable_wdi(); /* Enable watchdog interrupt in USC */
enable_hbi(); /* Enable heartbeat interrupt in USC */
/* Enable USC interrupt in MIPS processor */
mips_enable_in_interrupt_mask(CLOCK_VECTOR_MASK);
/*
* Schedule the clock cleanup routine to execute if the application exits.
*/
atexit( Clock_exit );
}
/*
* Clean up before the application exits
*/
void Clock_exit( void )
{
/* mips: turn off the timer interrupts */
mips_disable_in_interrupt_mask(~CLOCK_VECTOR_MASK);
}
/*
* Clock_initialize
*
* Device driver entry point for clock tick driver initialization.
*/
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,42 @@
/* clock.s
*
* This file contains the assembly code for the Hurricane BSP clock driver.
*
* Author: Craig Lebakken <craigl@transition.com>
*
* COPYRIGHT (c) 1996 by Transition Networks Inc.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of Transition Networks not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* Transition Networks makes no representations about the suitability
* of this software for any purpose.
*/
#include <iregdef.h>
#include <idtcpu.h>
#include <asm.h>
FRAME(mips_set_timer,sp,0,ra)
.set noreorder
mfc0 t0,C0_COUNT
nop
addu t0,a0,t0
mtc0 t0,C0_COMPARE
j ra
nop
.set reorder
ENDFRAME(mips_set_timer)
FRAME(mips_get_timer,sp,0,ra)
.set noreorder
mfc0 v0,C0_COUNT
j ra
nop
.set reorder
ENDFRAME(mips_get_timer)

View File

@@ -0,0 +1,21 @@
/* clock.s
*
* This file contains the assembly code for the Hurricane BSP clock driver.
*
* Author: Craig Lebakken <craigl@transition.com>
*
* COPYRIGHT (c) 1996 by Transition Networks Inc.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of Transition Networks not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* Transition Networks makes no representations about the suitability
* of this software for any purpose.
*/
extern void mips_set_timer( uint32_t timer_clock_interval );

View File

@@ -0,0 +1,50 @@
/**
* @file
*
* Instantiate the clock driver shell.
*
* The TX3904 simulator in gdb counts instructions.
*/
/*
* COPYRIGHT (c) 1989-2012.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp/irq.h>
#include <bsp.h>
#define CLOCK_DRIVER_USE_FAST_IDLE 1
#define CLOCK_VECTOR TX3904_IRQ_TMR0
/*
* 5000 clicks per tick ISR is HIGHLY arbitrary
*/
#define CLICKS 5000
#define Clock_driver_support_install_isr( _new ) \
rtems_interrupt_handler_install( CLOCK_VECTOR, "clock", 0, _new, NULL )
#define Clock_driver_support_initialize_hardware() \
do { \
uint32_t _clicks = CLICKS; \
TX3904_TIMER_WRITE( TX3904_TIMER0_BASE, TX3904_TIMER_CCDR, 0x3 ); \
TX3904_TIMER_WRITE( TX3904_TIMER0_BASE, TX3904_TIMER_CPRA, _clicks ); \
TX3904_TIMER_WRITE( TX3904_TIMER0_BASE, TX3904_TIMER_TISR, 0x00 ); \
TX3904_TIMER_WRITE( TX3904_TIMER0_BASE, TX3904_TIMER_ITMR, 0x8001 ); \
TX3904_TIMER_WRITE( TX3904_TIMER0_BASE, TX3904_TIMER_TCR, 0xC0 ); \
*((volatile uint32_t*) 0xFFFFC01C) = 0x00000700; \
} while(0)
#define Clock_driver_support_shutdown_hardware()
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,120 @@
/**
* @file
*
* Instantiate the clock driver shell.
*/
/*
* COPYRIGHT (c) 1989-2012.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp/irq.h>
#include <bsp.h>
/* #define CLOCK_DRIVER_USE_FAST_IDLE 1 */
#define CLOCK_VECTOR TX4925_IRQ_TMR0
#define TX4925_TIMER_INTERVAL_MODE 1
#define TX4925_TIMER_PULSE_MODE 2
#define TX4925_TIMER_MODE TX4925_TIMER_INTERVAL_MODE
#if (TX4925_TIMER_MODE == TX4925_TIMER_INTERVAL_MODE)
#define TX4925_TIMER_INTERRUPT_FLAG TIIS
#define Clock_driver_support_initialize_hardware() \
Initialize_timer0_in_interval_mode()
#elif (TX4925_TIMER_MODE == TX4925_TIMER_PULSE_MODE)
#define TX4925_TIMER_INTERRUPT_FLAG TPIBS
#define Clock_driver_support_initialize_hardware() \
Initialize_timer0_in_pulse_mode()
#else
#error "Build Error: need to select timer mode"
#endif
#define Clock_driver_support_install_isr( _new ) \
rtems_interrupt_handler_install( CLOCK_VECTOR, "clock", 0, _new, NULL )
#define Clock_driver_support_at_tick() \
do { \
uint32_t interrupt_flag; \
do { \
int loop_count; \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TISR, 0x0 ); /* Clear timer 0 interrupt */ \
loop_count = 0; \
do { /* Wait until interrupt flag is cleared (this prevents re-entering interrupt) */ \
/* Read back interrupt status register and isolate interval timer flag */ \
interrupt_flag = TX4925_REG_READ( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TISR ) & TX4925_TIMER_INTERRUPT_FLAG; \
} while (interrupt_flag && (++loop_count < 10)); /* Loop while timer interrupt bit is set, or loop count is lees than 10 */ \
} while(interrupt_flag); \
} while(0)
/* Setup timer in interval mode to generate peiodic interrupts */
#define Initialize_timer0_in_interval_mode() \
do { \
uint32_t temp; \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TCR, 0x0 ); /* Disable timer */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_CCDR, 0x0 ); /* Set register for divide by 2 clock */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_ITMR, TIMER_CLEAR_ENABLE_MASK ); /* Set interval timer mode register */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_CPRA, 0x30d40 ); /* Set tmier period ,10.0 msec (20 MHz timer clock) */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TCR, 0xC0 ); /* Enable timer in interval mode */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_DM0, 0x0 ); /* Set interrupt controller detection mode */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_LVL2, 0x1000000 ); /* Set interrupt controller level */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_MSK, 0x0 ); /* Set interrupt controller mask */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_DEN, 0x1 ); /* Enable interrupts from controller */ \
temp = TX4925_REG_READ( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_ITMR ); /* Enable interval timer interrupts */ \
temp |= TIMER_INT_ENABLE_MASK; \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_ITMR, temp ); \
} while(0)
/* This mode is used to generate periodic interrupts and also output a pulse on PIO20 pin */
#define Initialize_timer0_in_pulse_mode() \
do { \
uint32_t temp; \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TCR, 0x0 ); /* Disable timer */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_CCDR, 0x0 ); /* Set register for divide by 2 clock */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_PGMR, FFI ); /* Set pulse generator mode register */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_CPRA, 0x3e8 ); /* Set pulse high duration ,0.05 msec (20 MHz timer clock) */ \
/* TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_CPRB, 0x1388 ); */ /* Set pulse total period, 0.25 msec (20 MHz timer clock) */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_CPRB, 0x30d40 ); /* Set pulse total period, 10 msec (20 MHz timer clock) */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TCR, 0xC1 ); /* Enable timer in pulse generator mode */ \
\
/* Enable timer 0 output pulses on PIO20 */ \
temp = TX4925_REG_READ( TX4925_REG_BASE, TX4925_CFG_PCFG ); \
temp = (temp & ~ SELCHI) | SELTMR0; /* Enable timer 0 pulses on PIO20 */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_CFG_PCFG, temp ); \
\
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_DM0, 0x0 ); /* Set interrupt controller detection mode */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_LVL2, 0x1000000 ); /* Set interrupt controller level */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_MSK, 0x0 ); /* Set interrupt controller mask */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_IRQCTL_DEN, 0x1 ); /* Enable interrupts from controller */ \
temp = TX4925_REG_READ( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_PGMR ); /* Enable pulse generator interrupt */ \
temp |= TPIBE; /* Only want interrupts on B compare (where clock count is cleared) */ \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_PGMR, temp ); \
} while(0)
#define Clock_driver_support_shutdown_hardware() \
do { \
uint32_t temp; \
temp = TX4925_REG_READ( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_ITMR ); /* Disable interval timer interrupt */ \
temp &= ~TIMER_INT_ENABLE_MASK; \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_ITMR, temp ); \
temp = TX4925_REG_READ( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_PGMR ); /* Disable pulse generator interrupt */ \
temp &= ~(TPIAE | TPIBE); \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_PGMR, temp ); \
TX4925_REG_WRITE( TX4925_REG_BASE, TX4925_TIMER0_BASE + TX4925_TIMER_TCR, 0x0 ); /* Disable timer */ \
} while(0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,119 @@
/**
* @file
*
* Instantiate the clock driver shell.
*/
/*
* COPYRIGHT (c) 1989-2012.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <bsp/irq.h>
#include <bsp.h>
#include <stdio.h>
#include <stdlib.h>
#include "yamon_api.h"
/* #define CLOCK_DRIVER_USE_FAST_IDLE 1 */
#define CLOCK_VECTOR TX4938_IRQ_TMR0
#define TX4938_TIMER_INTERVAL_MODE 1
#define TX4938_TIMER_MODE TX4938_TIMER_INTERVAL_MODE
#if (TX4938_TIMER_MODE == TX4938_TIMER_INTERVAL_MODE)
#define TX4938_TIMER_INTERRUPT_FLAG TIIS
#define Clock_driver_support_initialize_hardware() \
Initialize_timer0_in_interval_mode()
#else
#error "Build Error: unsupported timer mode"
#endif
void new_brk_esr(void);
t_yamon_retfunc esr_retfunc = 0;
t_yamon_ref original_brk_esr = 0;
t_yamon_ref original_tmr0_isr = 0;
void new_brk_esr(void)
{
if (original_tmr0_isr)
{
YAMON_FUNC_DEREGISTER_IC_ISR( original_tmr0_isr );
original_tmr0_isr = 0;
}
if (esr_retfunc)
esr_retfunc();
}
#define Clock_driver_support_install_isr( _new ) \
do { \
rtems_interrupt_handler_install( \
CLOCK_VECTOR, \
"clock", \
0, \
_new, \
NULL \
); \
YAMON_FUNC_REGISTER_IC_ISR(17,(t_yamon_isr)_new,0,&original_tmr0_isr); /* Call Yamon to enable interrupt */ \
} while(0)
#define Clock_driver_support_at_tick() \
do { \
uint32_t interrupt_flag; \
do { \
int loop_count; \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_TISR, 0x0 ); /* Clear timer 0 interrupt */ \
loop_count = 0; \
do { /* Wait until interrupt flag is cleared (this prevents re-entering interrupt) */ \
/* Read back interrupt status register and isolate interval timer flag */ \
interrupt_flag = TX4938_REG_READ( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_TISR ) & TX4938_TIMER_INTERRUPT_FLAG; \
} while (interrupt_flag && (++loop_count < 10)); /* Loop while timer interrupt bit is set, or loop count is lees than 10 */ \
} while(interrupt_flag); \
} while(0)
/* Setup timer in interval mode to generate peiodic interrupts */
#define Initialize_timer0_in_interval_mode() \
do { \
uint32_t temp; \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_TCR, 0x0 ); /* Disable timer */ \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_CCDR, 0x0 ); /* Set register for divide by 2 clock */ \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_ITMR, TIMER_CLEAR_ENABLE_MASK ); /* Set interval timer mode register */ \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_CPRA, 0x3d090 ); /* Set tmier period ,10.0 msec (25 MHz timer clock) */ \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_TCR, 0xC0 ); /* Enable timer in interval mode */ \
temp = TX4938_REG_READ( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_ITMR ); /* Enable interval timer interrupts */ \
temp |= TIMER_INT_ENABLE_MASK; \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_ITMR, temp ); \
} while(0)
#define Clock_driver_support_shutdown_hardware() \
do { \
uint32_t temp; \
temp = TX4938_REG_READ( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_ITMR ); /* Disable interval timer interrupt */ \
temp &= ~TIMER_INT_ENABLE_MASK; \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_ITMR, temp ); \
temp = TX4938_REG_READ( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_PGMR ); /* Disable pulse generator interrupt */ \
temp &= ~(TPIAE | TPIBE); \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_PGMR, temp ); \
TX4938_REG_WRITE( TX4938_REG_BASE, TX4938_TIMER0_BASE + TX4938_TIMER_TCR, 0x0 ); /* Disable timer */ \
} while(0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,631 @@
/************************************************************************
*
* yamon_api.h
*
* YAMON interface definitions
*
* ######################################################################
*
* mips_start_of_legal_notice
*
* Copyright (c) 2003 MIPS Technologies, Inc. All rights reserved.
*
*
* Unpublished rights (if any) reserved under the copyright laws of the
* United States of America and other countries.
*
* This code is proprietary to MIPS Technologies, Inc. ("MIPS
* Technologies"). Any copying, reproducing, modifying or use of this code
* (in whole or in part) that is not expressly permitted in writing by MIPS
* Technologies or an authorized third party is strictly prohibited. At a
* minimum, this code is protected under unfair competition and copyright
* laws. Violations thereof may result in criminal penalties and fines.
*
* MIPS Technologies reserves the right to change this code to improve
* function, design or otherwise. MIPS Technologies does not assume any
* liability arising out of the application or use of this code, or of any
* error or omission in such code. Any warranties, whether express,
* statutory, implied or otherwise, including but not limited to the implied
* warranties of merchantability or fitness for a particular purpose, are
* excluded. Except as expressly provided in any written license agreement
* from MIPS Technologies or an authorized third party, the furnishing of
* this code does not give recipient any license to any intellectual
* property rights, including any patent rights, that cover this code.
*
* This code shall not be exported or transferred for the purpose of
* reexporting in violation of any U.S. or non-U.S. regulation, treaty,
* Executive Order, law, statute, amendment or supplement thereto.
*
* This code constitutes one or more of the following: commercial computer
* software, commercial computer software documentation or other commercial
* items. If the user of this code, or any related documentation of any
* kind, including related technical data or manuals, is an agency,
* department, or other entity of the United States government
* ("Government"), the use, duplication, reproduction, release,
* modification, disclosure, or transfer of this code, or any related
* documentation of any kind, is restricted in accordance with Federal
* Acquisition Regulation 12.212 for civilian agencies and Defense Federal
* Acquisition Regulation Supplement 227.7202 for military agencies. The use
* of this code by the Government is further restricted in accordance with
* the terms of the license agreement(s) and/or applicable contract terms
* and conditions covering this code from MIPS Technologies or an authorized
* third party.
*
*
* mips_end_of_legal_notice
*
*
************************************************************************/
#ifndef YAMON_API_H
#define YAMON_API_H
/************************************************************************
* Include files
************************************************************************/
/************************************************************************
* Definitions
*************************************************************************/
/* Basic types */
typedef unsigned int t_yamon_uint32;
typedef unsigned short t_yamon_uint16;
typedef unsigned char t_yamon_uint8;
typedef signed int t_yamon_int32;
typedef signed short t_yamon_int16;
typedef signed char t_yamon_int8;
typedef unsigned char t_yamon_bool;
#define YAMON_FALSE 0
#define YAMON_TRUE (!YAMON_FALSE)
/* YAMON Environment variable */
typedef struct
{
char *name;
char *val;
}
t_yamon_env_var;
/* Format of application function */
typedef t_yamon_uint32
(*t_yamon_appl_main)(
t_yamon_uint32 argc, /* Number of tokens in argv array */
char **argv, /* Array of tokens (first is "go") */
t_yamon_env_var *env, /* Array of env. variables */
t_yamon_uint32 memsize ); /* Size of memory (byte count) */
/* ID of YAMON configuration object */
typedef t_yamon_uint32 t_yamon_syscon_id;
/* Number used by the exception registration functions in order to register
* a default ISR/ESR.
*/
#define YAMON_DEFAULT_HANDLER 0xfffffff0
/* Number used by the exception registration functions in order to register
* an EJTAG debug exception ESR.
*/
#define YAMON_DEFAULT_EJTAG_ESR 0xfffffff1
/* Registered Interrupt Service Routine (ISR) */
typedef void (*t_yamon_isr)(void *data);
/* Registered Exception Service Routine (ESR) */
typedef void (*t_yamon_esr)(void);
/* Entry point called by ESRs wishing to pass control back to YAMON */
typedef void (*t_yamon_retfunc)(void);
/* Handle used for deregistration of ISR/ESR */
typedef void *t_yamon_ref;
/* YAMONE Vector table address */
#define YAMON_FUNCTION_BASE 0x9fc00500
/* YAMON Vector table offsets */
#define YAMON_FUNC_PRINT_COUNT_OFS 0x04
#define YAMON_FUNC_EXIT_OFS 0x20
#define YAMON_FUNC_FLUSH_CACHE_OFS 0x2C
#define YAMON_FUNC_PRINT_OFS 0x34
#define YAMON_FUNC_REGISTER_CPU_ISR_OFS 0x38
#define YAMON_FUNC_DEREGISTER_CPU_ISR_OFS 0x3c
#define YAMON_FUNC_REGISTER_IC_ISR_OFS 0x40
#define YAMON_FUNC_DEREGISTER_IC_ISR_OFS 0x44
#define YAMON_FUNC_REGISTER_ESR_OFS 0x48
#define YAMON_FUNC_DEREGISTER_ESR_OFS 0x4c
#define YAMON_FUNC_GETCHAR_OFS 0x50
#define YAMON_FUNC_SYSCON_READ_OFS 0x54
/* Macro for accessing YAMON function */
#define YAMON_FUNC(ofs)\
(*(t_yamon_uint32 *)(YAMON_FUNCTION_BASE + (ofs)))
/************************************************************************
* Public variables
************************************************************************/
/************************************************************************
* Public functions
************************************************************************/
/************************************************************************
*
* t_yamon_exit
* Description :
* -------------
*
* Exit application and return to YAMON.
*
* Parameters :
* ------------
*
* 'rc' (OUT) : Return code
*
* Return values :
* ---------------
*
* None (never returns)
*
************************************************************************/
typedef void
(*t_yamon_exit)(
t_yamon_uint32 rc ); /* Return code */
#define YAMON_FUNC_EXIT( rc )\
((t_yamon_exit)( YAMON_FUNC(YAMON_FUNC_EXIT_OFS) ))\
( rc )
/************************************************************************
*
* t_yamon_print
* Description :
* -------------
*
* Print null-terminated string to tty0.
*
* Parameters :
* ------------
*
* 'port' (OUT) : Ignored, always prints to tty0. Not included in macro.
* 's' (OUT) : String to print.
*
* Return values :
* ---------------
*
* None
*
************************************************************************/
typedef void
(*t_yamon_print)(
t_yamon_uint32 port, /* Output port (not used, always tty0) */
const char *s ); /* String to output */
#define YAMON_FUNC_PRINT( s )\
((t_yamon_print)( YAMON_FUNC(YAMON_FUNC_PRINT_OFS) ))\
( 0, s )
/************************************************************************
*
* t_yamon_print_count
* Description :
* -------------
*
* Print specified number of characters to tty0.
*
* Parameters :
* ------------
*
* 'port' (OUT) : Ignored, always prints to tty0. Not included in macro.
* 's' (OUT) : Array of characters to print.
* 'count' (OUT) : Number of characters to print.
*
* Return values :
* ---------------
*
* None
*
************************************************************************/
typedef void
(*t_yamon_print_count)(
t_yamon_uint32 port, /* Output port (not used, always tty0 */
char *s, /* String to output */
t_yamon_uint32 count ); /* Number of characters to output */
#define YAMON_FUNC_PRINT_COUNT( s, count )\
((t_yamon_print_count)( YAMON_FUNC(YAMON_FUNC_PRINT_COUNT_OFS) ))\
( 0, s, count )
/************************************************************************
*
* t_yamon_getchar
* Description :
* -------------
*
* Get character from tty0 if character is available. Function
* returns immediately if no character is available.
*
* Parameters :
* ------------
*
* 'port' (OUT) : Ignored, always uses tty0. Not included in macro.
* 'ch' (OUT) : Character read (if available).
*
* Return values :
* ---------------
*
* YAMON_TRUE if character was available, else YAMON_FALSE.
*
************************************************************************/
typedef t_yamon_bool
(*t_yamon_getchar)(
t_yamon_uint32 port, /* Output port (not used, always tty0 */
char *ch ); /* Character to output */
#define YAMON_FUNC_GETCHAR( ch )\
((t_yamon_getchar)( YAMON_FUNC(YAMON_FUNC_GETCHAR_OFS) ))\
( 0, ch )
/************************************************************************
*
* t_yamon_syscon_read
* Description :
* -------------
*
* Read the value of system configuration object given by 'id'.
*
* See syscon_api.h in YAMON source distribution for further details
* on object IDs and error codes.
*
* Parameters :
* ------------
*
* 'id' (IN) : Object id.
* 'param' (INOUT) : Buffer for object value.
* 'size' (IN) : Size of buffer (must match size of object).
*
* Return values :
* ---------------
*
* 0 : Returned parameter is valid.
* Other values indicate error.
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_syscon_read)(
t_yamon_syscon_id id, /* Object ID */
void *param, /* Buffer for object value */
t_yamon_uint32 size); /* Buffer size (bytes) */
#define YAMON_FUNC_SYSCON_READ( id, param, size )\
((t_yamon_syscon_read)( YAMON_FUNC(YAMON_FUNC_SYSCON_READ_OFS) ))\
( id, param, size )
/************************************************************************
*
* t_yamon_flush_cache
* Description :
* -------------
*
* Flush I-or D-cache
*
* Function performs "writeback and invalidate" operations on D-cache
* lines and "invalidate" operations on I-cache lines.
*
* Parameters :
* ------------
*
* 'type' (IN) : Cache to be flushed.
*
* Return values :
* ---------------
*
* None
*
************************************************************************/
typedef void
(*t_yamon_flush_cache)(
#define YAMON_FLUSH_ICACHE 0
#define YAMON_FLUSH_DCACHE 1
t_yamon_uint32 type ); /* I- or D-cache indication */
#define YAMON_FUNC_FLUSH_CACHE( type )\
((t_yamon_flush_cache)( YAMON_FUNC(YAMON_FUNC_FLUSH_CACHE_OFS) ))\
( type )
/************************************************************************
*
* t_yamon_register_esr
* Description :
* -------------
*
* Registers an exception handler, also known as an "Exception Service
* Routine" (ESR) for the specified exception.
*
* Two special exception IDs are defined :
* YAMON_DEFAULT_HANDLER used for a default ESR.
* YAMON_DEFAULT_EJTAG_ESR used for EJTAG exceptions.
*
* The default ESR is called if no other ESR is registered
* for an exception. If no default ESR is registered, a static
* (i.e. not registered) "super default" function is invoked.
* This function prints out the registers and halts.
*
* Deregistration of an ESR may be be done by calling this function
* with 'esr' set to NULL.
* An ESR can also be deregistered using the 'yamon_deregister_esr'
* function.
*
* An ESR may be registered even if a previously registered
* ESR has not been deregistered. In this case the previously
* registered ESR is lost.
*
* The ESR will get called with registers in the state they were
* when the exception occurred. This includes all CP0 registers and
* CPU registers $0..$31, except for k0,k1 ($26,$27).
*
* In case an ESR does not want to handle the exception, it may
* call the return function passed in the 'retfunc' parameter.
*
* Case 1 : 'retfunc' called by ESR registered for the
* INTERRUPT exception.
*
* We assume an application has registered this ESR and wants
* YAMON to process the (remaining) interrupts.
*
* Case 2 : 'retfunc' called by an ESR registered for a specific
* exception (not INTERRUPT).
*
* Default handling will be done.
*
* Case 3 : 'retfunc' is called by the ESR registered as default ESR.
*
* The exception will be handled as though no ESR is registered
* (i.e. the "super default" function is called).
*
* Parameters :
* ------------
*
* 'exception' (IN) : Exception code
* or YAMON_DEFAULT_HANDLER for a default ESR
* or YAMON_DEFAULT_EJTAG_ESR for ejtag exceptions.
* 'esr' (IN) : Function pointer for ESR.
* 'ref' (OUT) : Handle used for deregistration of ESR.
* 'retfunc' (OUT) : Pointer to function pointer for the return
* function described above.
*
* Return values :
* ---------------
*
* 0 : Registration went well.
* Other values indicate error.
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_register_esr)(
t_yamon_uint32 exception, /* Exception identification */
t_yamon_esr esr, /* ESR to be registered */
t_yamon_ref *ref, /* Handle for deregistration */
t_yamon_retfunc *retfunc ); /* Return function */
#define YAMON_FUNC_REGISTER_ESR( exc, esr, ref, retfunc )\
((t_yamon_register_esr)( YAMON_FUNC(YAMON_FUNC_REGISTER_ESR_OFS) ))\
( exc, esr, ref, retfunc )
/************************************************************************
*
* t_yamon_deregister_esr
* Description :
* -------------
*
* Deregisters ESR..
*
* Parameters :
* ------------
*
* 'ref' (IN) : Handle obtained when calling 'yamon_register_esr'.
*
* Return values :
* ---------------
*
* 0 : Deregistration went well.
* Other values indicate error.
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_deregister_esr)(
t_yamon_ref ref ); /* Handle for deregistration */
#define YAMON_FUNC_DEREGISTER_ESR( ref )\
((t_yamon_deregister_esr)( YAMON_FUNC(YAMON_FUNC_DEREGISTER_ESR_OFS) ))\
( ref )
/************************************************************************
*
* t_yamon_register_cpu_isr
* Description :
* -------------
*
* Registers an Interrupt Service Routine (ISR) for the specified
* CPU interrupt.
* The highest service priority is attached to HW-INT5, which is
* connected to the CPU-built-in CP0-timer. SW_INT0 gets the lowest
* service priority. During registration, the interrupt mask field
* in the CPU CP0-status register is updated to enable interrupts
* from the specified interrupt source.
*
* A special ID is defined :
* YAMON_DEFAULT_HANDLER used for a default ISR.
*
* The default ISR is called if no other ISR is registered
* for a CPU interrupt.
*
* Deregistration of the default ISR may be done by calling
* this function with 'isr' set to NULL.
* Also, a new default ISR may be registered even if a
* previously registered ISR has not been deregistered.
* ISRs for specific CPU interrupts must be deregistered using
* 'yamon_deregister_cpu_isr'.
*
* Parameters :
* ------------
*
* 'cpu_int' (IN) : CPU interrupt (0..7)
* or YAMON_DEFAULT_HANDLER for a default ISR.
* 'isr' (IN) : Function pointer for ISR.
* 'data' (IN) : Data pointer (may be NULL). Will be passed to
* ISR when called.
* 'ref' (OUT) : Handle used for deregistration of ISR.
*
* Return values :
* ---------------
*
* 0 : Registration went well.
* Other values indicate error.
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_register_cpu_isr)(
t_yamon_uint32 cpu_int, /* CPU interrupt (0..7) */
t_yamon_isr isr, /* ISR to be registered */
void *data, /* Data reference to be registered */
t_yamon_ref *ref ); /* Handle for deregistration */
#define YAMON_FUNC_REGISTER_CPU_ISR( cpu_int, isr, data, ref )\
((t_yamon_register_cpu_isr)( YAMON_FUNC(YAMON_FUNC_REGISTER_CPU_ISR_OFS) ))\
( cpu_int, isr, data, ref )
/************************************************************************
*
* t_yamon_deregister_cpu_isr
* Description :
* -------------
*
* Deregisters ISR for CPU interrupt.
*
* Parameters :
* ------------
*
* 'ref' (IN) : Handle obtained when calling 'yamon_register_cpu_isr'.
*
* Return values :
* ---------------
*
* 0 : Deregistration went well.
* Other values indicate error
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_deregister_cpu_isr)(
t_yamon_ref ref ); /* Handle for deregistration */
#define YAMON_FUNC_DEREGISTER_CPU_ISR( ref )\
((t_yamon_deregister_cpu_isr)( YAMON_FUNC(YAMON_FUNC_DEREGISTER_CPU_ISR_OFS) ))\
( ref )
/************************************************************************
*
* t_yamon_register_ic_isr
* Description :
* -------------
*
* Registers an Interrupt Service Routine (ISR) for the specified
* source in the interrupt controller.
*
* A special ID is defined :
* YAMON_DEFAULT_HANDLER used for a default ISR.
*
* The default ISR is called if no other ISR is registered
* for an interrupt.
*
* Deregistration of the default ISR may be done by calling
* this function with 'isr' set to NULL.
* Also, a new default ISR may be registered even if a
* previously registered ISR has not been deregistered.
* ISRs for specific interrupts must be deregistered using
* 'yamon_deregister_ic_isr'.
*
* Parameters :
* ------------
*
* 'ic_line' (IN) : Interrupt source line in Int. Controller
* or YAMON_DEFAULT_HANDLER for a default ISR.
* 'isr', (IN) : Function pointer for user defined ISR.
* 'data' (IN) : Data pointer (may be NULL). Will be passed to
* ISR when called.
* 'ref', (OUT) : Handle used for deregistration of ISR.
*
* Return values :
* ---------------
*
* 0 : Registration went well.
* Other values indicate error.
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_register_ic_isr)(
t_yamon_uint32 ic_line, /* Interrupt controller line */
t_yamon_isr isr, /* ISR to be registered */
void *data, /* Data reference to be registered */
t_yamon_ref *ref ); /* Handle for deregistration */
#define YAMON_FUNC_REGISTER_IC_ISR( ic_line, isr, data, ref )\
((t_yamon_register_ic_isr)( YAMON_FUNC(YAMON_FUNC_REGISTER_IC_ISR_OFS) ))\
( ic_line, isr, data, ref )
/************************************************************************
*
* t_yamon_deregister_ic_isr
* Description :
* -------------
*
* Deregisters ISR for source in interrupt controller.
*
* Parameters :
* ------------
*
* 'ref' (IN) : Handle obtained when calling 'yamon_register_ic_isr'.
*
* Return values :
* ---------------
*
* 0 : Deregistration went well.
* Other values indicate error
*
************************************************************************/
typedef t_yamon_int32
(*t_yamon_deregister_ic_isr)(
t_yamon_ref ref ); /* Handle for deregistration */
#define YAMON_FUNC_DEREGISTER_IC_ISR( ref )\
((t_yamon_deregister_ic_isr)( YAMON_FUNC(YAMON_FUNC_DEREGISTER_IC_ISR_OFS) ))\
( ref )
#endif /* #ifndef YAMON_API_H */

View File

@@ -0,0 +1,49 @@
/*
* COPYRIGHT (c) 1989-2013.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <bsp/irq.h>
#include <bspopts.h>
/* XXX convert to macros? Move to score/cpu? */
void mips_set_timer(uint32_t timer_clock_interval);
uint32_t mips_get_timer(void);
/* XXX move to BSP.h or irq.h?? */
#define EXT_INT5 0x8000 /* external interrupt 5 */
#define CLOCK_VECTOR_MASK EXT_INT5
#define CLOCK_VECTOR (MIPS_INTERRUPT_BASE+0x7)
extern uint32_t bsp_clicks_per_microsecond;
static uint32_t mips_timer_rate = 0;
/* refresh the internal CPU timer */
#define Clock_driver_support_at_tick() \
mips_set_timer( mips_timer_rate );
#define Clock_driver_support_install_isr( _new ) \
rtems_interrupt_handler_install(CLOCK_VECTOR, "PIT clock",0, _new, NULL)
#define Clock_driver_support_initialize_hardware() \
do { \
mips_timer_rate = rtems_configuration_get_microseconds_per_tick() * \
bsp_clicks_per_microsecond; \
mips_set_timer( mips_timer_rate ); \
mips_enable_in_interrupt_mask(CLOCK_VECTOR_MASK); \
} while(0)
#define Clock_driver_support_shutdown_hardware() \
do { \
mips_disable_in_interrupt_mask(CLOCK_VECTOR_MASK); \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,43 @@
/* clock.s
*
* This file contains the assembly code for the IDT 4650 clock driver.
*
* Author: Craig Lebakken <craigl@transition.com>
*
* COPYRIGHT (c) 1996 by Transition Networks Inc.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of Transition Networks not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* Transition Networks makes no representations about the suitability
* of this software for any purpose.
*/
/* @(#)clock.S 08/20/96 1.2 */
#include <rtems/mips/iregdef.h>
#include <rtems/mips/idtcpu.h>
#include <rtems/asm.h>
FRAME(mips_set_timer,sp,0,ra)
.set noreorder
mfc0 t0,C0_COUNT
nop
addu t0,a0,t0
mtc0 t0,C0_COMPARE
j ra
nop
.set reorder
ENDFRAME(mips_set_timer)
FRAME(mips_get_timer,sp,0,ra)
.set noreorder
mfc0 v0,C0_COUNT
j ra
nop
.set reorder
ENDFRAME(mips_get_timer)

View File

@@ -0,0 +1,55 @@
/*
* Use SYS_CLK as system clock
*
* Copyright (c) 2005-2006 Kolja Waschk, rtemsdev/ixo.de
*/
#include <rtems.h>
#include <bsp.h>
#define CLOCK_REGS ((altera_avalon_timer_regs*)NIOS2_IO_BASE(CLOCK_BASE))
/*
* Periodic interval timer interrupt handler
*/
#define Clock_driver_support_at_tick() \
do { CLOCK_REGS->status = 0; } while(0)
/*
* Attach clock interrupt handler
*/
#define Clock_driver_support_install_isr(_new) \
set_vector(_new, CLOCK_VECTOR, 1)
/*
* Turn off the clock
*/
#define Clock_driver_support_shutdown_hardware() \
do { \
CLOCK_REGS->control = ALTERA_AVALON_TIMER_CONTROL_STOP_MSK; \
} while (0)
/*
* Set up the clock hardware
*/
static void Clock_driver_support_initialize_hardware(void)
{
uint32_t period;
CLOCK_REGS->control = ALTERA_AVALON_TIMER_CONTROL_STOP_MSK;
period = (CLOCK_FREQ/1000000L)*rtems_configuration_get_microseconds_per_tick() - 1;
CLOCK_REGS->period_hi = period >> 16;
CLOCK_REGS->period_lo = period & 0xFFFF;
CLOCK_REGS->control = ALTERA_AVALON_TIMER_CONTROL_ITO_MSK |
ALTERA_AVALON_TIMER_CONTROL_CONT_MSK |
ALTERA_AVALON_TIMER_CONTROL_START_MSK;
NIOS2_IENABLE(1 << CLOCK_VECTOR);
}
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,127 @@
/*
* This file provides a template for the clock device driver initialization.
*
* If possible, please use the dev/clock/clockimpl.h method for instantiating
* a clock driver.
*/
/*
* COPYRIGHT (c) 1989-2014.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdlib.h>
#include <rtems.h>
#include <bsp.h>
void Clock_exit( void );
rtems_isr Clock_isr( rtems_vector_number vector );
/*
* The interrupt vector number associated with the clock tick device
* driver.
*/
#define CLOCK_VECTOR 4
/*
* Clock_driver_ticks is a monotonically increasing counter of the
* number of clock ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
/*
* Clock_isrs is the number of clock ISRs until the next invocation of
* the RTEMS clock tick routine. The clock tick device driver
* gets an interrupt once a millisecond and counts down until the
* length of time between the user configured microseconds per tick
* has passed.
*/
uint32_t Clock_isrs; /* ISRs until next tick */
/*
* The previous ISR on this clock tick interrupt vector.
*/
rtems_isr_entry Old_ticker;
void Clock_exit( void );
/*
* Isr Handler
*/
static rtems_isr Clock_isr(
rtems_vector_number vector
)
{
/*
* bump the number of clock driver ticks since initialization
*
* determine if it is time to announce the passing of tick as configured
* to RTEMS through the rtems_clock_tick directive
*
* perform any timer dependent tasks
*/
}
/*
* Install_clock
*
* Install a clock tick handler and reprograms the chip. This
* is used to initially establish the clock tick.
*/
void Install_clock(
rtems_isr_entry clock_isr
)
{
/*
* Initialize the clock tick device driver variables
*/
Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
Old_ticker = (rtems_isr_entry) set_vector( clock_isr, CLOCK_VECTOR, 1 );
/*
* Hardware specific initialize goes here
*/
/* XXX */
/*
* Schedule the clock cleanup routine to execute if the application exits.
*/
atexit( Clock_exit );
}
/*
* Clean up before the application exits
*/
void Clock_exit( void )
{
/* XXX: turn off the timer interrupts */
/* XXX: If necessary, restore the old vector */
}
/*
* Clock_initialize
*
* Device driver entry point for clock tick driver initialization.
*/
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,147 @@
/**
* @file
*
* @ingroup bsp_clock
*
* @brief or1k clock support.
*/
/*
* generic_or1k Clock driver
*
* COPYRIGHT (c) 2014-2015 Hesham ALMatary <heshamelmatary@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/generic_or1k.h>
#include <rtems/score/cpu.h>
#include <rtems/score/or1k-utility.h>
#include <rtems/timecounter.h>
/* The number of clock cycles before generating a tick timer interrupt. */
#define TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT 0x09ED9
#define OR1K_CLOCK_CYCLE_TIME_NANOSECONDS 10
static struct timecounter or1ksim_tc;
/* CPU counter */
static CPU_Counter_ticks cpu_counter_ticks;
/* This prototype is added here to Avoid warnings */
void Clock_isr(void *arg);
static void generic_or1k_clock_at_tick(void)
{
uint32_t TTMR;
/* For TTMR register,
* The least significant 28 bits are the number of clock cycles
* before generating a tick timer interrupt. While the most
* significant 4 bits are used for mode configuration, tick timer
* interrupt enable and pending interrupts status.
*/
TTMR = (CPU_OR1K_SPR_TTMR_MODE_RESTART | CPU_OR1K_SPR_TTMR_IE |
(TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT & CPU_OR1K_SPR_TTMR_TP_MASK)
) & ~(CPU_OR1K_SPR_TTMR_IP);
_OR1K_mtspr(CPU_OR1K_SPR_TTMR, TTMR);
_OR1K_mtspr(CPU_OR1K_SPR_TTCR, 0);
cpu_counter_ticks += TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT;
}
static void generic_or1k_clock_handler_install(proc_ptr new_isr)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
_CPU_ISR_install_vector(OR1K_EXCEPTION_TICK_TIMER,
new_isr,
NULL);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
static uint32_t or1ksim_get_timecount(struct timecounter *tc)
{
uint32_t ticks_since_last_timer_interrupt;
ticks_since_last_timer_interrupt = _OR1K_mfspr(CPU_OR1K_SPR_TTCR);
return cpu_counter_ticks + ticks_since_last_timer_interrupt;
}
CPU_Counter_ticks _CPU_Counter_read(void)
{
return or1ksim_get_timecount(NULL);
}
static void generic_or1k_clock_initialize(void)
{
uint64_t frequency = (1000000000 / OR1K_CLOCK_CYCLE_TIME_NANOSECONDS);
uint32_t TTMR;
/* For TTMR register,
* The least significant 28 bits are the number of clock cycles
* before generating a tick timer interrupt. While the most
* significant 4 bits are used for mode configuration, tick timer
* interrupt enable and pending interrupts status.
*/
/* FIXME: Long interval should pass since initializing the tick timer
* registers fires exceptions dispite interrupts has not been enabled yet.
*/
TTMR = (CPU_OR1K_SPR_TTMR_MODE_RESTART | CPU_OR1K_SPR_TTMR_IE |
(0xFFED9 & CPU_OR1K_SPR_TTMR_TP_MASK)
) & ~(CPU_OR1K_SPR_TTMR_IP);
_OR1K_mtspr(CPU_OR1K_SPR_TTMR, TTMR);
_OR1K_mtspr(CPU_OR1K_SPR_TTCR, 0);
/* Initialize timecounter */
or1ksim_tc.tc_get_timecount = or1ksim_get_timecount;
or1ksim_tc.tc_counter_mask = 0xffffffff;
or1ksim_tc.tc_frequency = frequency;
or1ksim_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&or1ksim_tc);
}
static void generic_or1k_clock_cleanup(void)
{
uint32_t sr;
sr = _OR1K_mfspr(CPU_OR1K_SPR_SR);
/* Disable tick timer exceptions */
_OR1K_mtspr(CPU_OR1K_SPR_SR, (sr & ~CPU_OR1K_SPR_SR_IEE)
& ~CPU_OR1K_SPR_SR_TEE);
/* Invalidate tick timer config registers */
_OR1K_mtspr(CPU_OR1K_SPR_TTCR, 0);
_OR1K_mtspr(CPU_OR1K_SPR_TTMR, 0);
}
CPU_Counter_ticks _CPU_Counter_difference(
CPU_Counter_ticks second,
CPU_Counter_ticks first
)
{
return second - first;
}
#define Clock_driver_support_at_tick() generic_or1k_clock_at_tick()
#define Clock_driver_support_initialize_hardware() generic_or1k_clock_initialize()
#define Clock_driver_support_install_isr(isr) \
generic_or1k_clock_handler_install(isr)
#define Clock_driver_support_shutdown_hardware() generic_or1k_clock_cleanup()
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,257 @@
/**
* @file
*
* @ingroup mpc55xx
*
* @brief Clock driver configuration.
*/
/*
* Copyright (c) 2009-2013 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <bsp/fatal.h>
#include <bsp/irq.h>
#include <mpc55xx/regs.h>
#include <rtems/timecounter.h>
void Clock_isr(void *arg);
static rtems_timecounter_simple mpc55xx_tc;
#if defined(MPC55XX_CLOCK_EMIOS_CHANNEL)
#include <mpc55xx/emios.h>
static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc)
{
return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CCNTR.R;
}
static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc)
{
return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.B.FLAG != 0;
}
static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_upcounter_get(
tc,
mpc55xx_tc_get,
mpc55xx_tc_is_pending
);
}
static void mpc55xx_tc_at_tick(rtems_timecounter_simple *tc)
{
union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS;
csr.B.FLAG = 1;
EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.R = csr.R;
}
static void mpc55xx_tc_tick(void)
{
rtems_timecounter_simple_upcounter_tick(
&mpc55xx_tc,
mpc55xx_tc_get,
mpc55xx_tc_at_tick
);
}
static void mpc55xx_clock_handler_install(rtems_isr_entry isr)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
sc = mpc55xx_interrupt_handler_install(
MPC55XX_IRQ_EMIOS(MPC55XX_CLOCK_EMIOS_CHANNEL),
"clock",
RTEMS_INTERRUPT_UNIQUE,
MPC55XX_INTC_MIN_PRIORITY,
(rtems_interrupt_handler) isr,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_IRQ_INSTALL);
}
}
static void mpc55xx_clock_initialize(void)
{
volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL];
union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS;
union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS;
unsigned prescaler = mpc55xx_emios_global_prescaler();
uint64_t reference_clock = bsp_clock_speed;
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint64_t interval = (reference_clock * us_per_tick) / 1000000;
/* Apply prescaler */
if (prescaler > 0) {
interval /= (uint64_t) prescaler;
} else {
bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_PRESCALER);
}
/* Check interval */
if (interval == 0 || interval > MPC55XX_EMIOS_VALUE_MAX) {
bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_INTERVAL);
}
/* Configure eMIOS channel */
/* Set channel in GPIO mode */
ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT;
regs->CCR.R = ccr.R;
/* Clear status flags */
csr.B.OVR = 1;
csr.B.OVFL = 1;
csr.B.FLAG = 1;
regs->CSR.R = csr.R;
/* Set internal counter start value */
regs->CCNTR.R = 1;
/* Set timer period */
regs->CADR.R = (uint32_t) interval - 1;
/* Set control register */
#if MPC55XX_CHIP_FAMILY == 551
ccr.B.MODE = MPC55XX_EMIOS_MODE_MCB_UP_INT_CLK;
#else
ccr.B.MODE = MPC55XX_EMIOS_MODE_MC_UP_INT_CLK;
#endif
ccr.B.UCPREN = 1;
ccr.B.FEN = 1;
ccr.B.FREN = 1;
regs->CCR.R = ccr.R;
rtems_timecounter_simple_install(
&mpc55xx_tc,
reference_clock,
interval,
mpc55xx_tc_get_timecount
);
}
static void mpc55xx_clock_cleanup(void)
{
volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL];
union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS;
/* Set channel in GPIO mode */
ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT;
regs->CCR.R = ccr.R;
}
#elif defined(MPC55XX_CLOCK_PIT_CHANNEL)
static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc)
{
return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].CVAL.R;
}
static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc)
{
return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].TFLG.B.TIF != 0;
}
static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
mpc55xx_tc_get,
mpc55xx_tc_is_pending
);
}
static void mpc55xx_tc_at_tick(rtems_timecounter_simple *tc)
{
volatile PIT_RTI_CHANNEL_tag *channel =
&PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL];
PIT_RTI_TFLG_32B_tag tflg = { .B = { .TIF = 1 } };
channel->TFLG.R = tflg.R;
}
static void mpc55xx_tc_tick(void)
{
rtems_timecounter_simple_downcounter_tick(
&mpc55xx_tc,
mpc55xx_tc_get,
mpc55xx_tc_at_tick
);
}
static void mpc55xx_clock_handler_install(rtems_isr_entry isr)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
sc = mpc55xx_interrupt_handler_install(
MPC55XX_IRQ_PIT_CHANNEL(MPC55XX_CLOCK_PIT_CHANNEL),
"clock",
RTEMS_INTERRUPT_UNIQUE,
MPC55XX_INTC_MIN_PRIORITY,
(rtems_interrupt_handler) isr,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CLOCK_PIT_IRQ_INSTALL);
}
}
static void mpc55xx_clock_initialize(void)
{
volatile PIT_RTI_CHANNEL_tag *channel =
&PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL];
uint64_t reference_clock = bsp_clock_speed;
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint64_t interval = (reference_clock * us_per_tick) / 1000000;
PIT_RTI_PITMCR_32B_tag pitmcr = { .B = { .FRZ = 1 } };
PIT_RTI_TCTRL_32B_tag tctrl = { .B = { .TIE = 1, .TEN = 1 } };
PIT_RTI.PITMCR.R = pitmcr.R;
channel->LDVAL.R = interval;
channel->TCTRL.R = tctrl.R;
rtems_timecounter_simple_install(
&mpc55xx_tc,
reference_clock,
interval,
mpc55xx_tc_get_timecount
);
}
static void mpc55xx_clock_cleanup(void)
{
volatile PIT_RTI_CHANNEL_tag *channel =
&PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL];
channel->TCTRL.R = 0;
}
#endif
#define Clock_driver_timecounter_tick() mpc55xx_tc_tick()
#define Clock_driver_support_initialize_hardware() \
mpc55xx_clock_initialize()
#define Clock_driver_support_install_isr(isr) \
mpc55xx_clock_handler_install(isr)
#define Clock_driver_support_shutdown_hardware() \
mpc55xx_clock_cleanup()
/* Include shared source clock driver code */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,69 @@
/*
* Clock Tick interrupt conexion code.
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Modified to support the MPC750.
* Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
*/
#include <bsp.h>
#include <rtems/bspIo.h>
#include <bsp/irq.h>
extern void clockOn(void*);
extern void clockOff (void*);
extern int clockIsOn(void*);
extern void Clock_isr(void);
static rtems_irq_connect_data clockIrqData = {BSP_PERIODIC_TIMER,
(rtems_irq_hdl)Clock_isr,
NULL,
(rtems_irq_enable)clockOn,
(rtems_irq_disable)clockOff,
(rtems_irq_is_enabled)clockIsOn};
int BSP_get_clock_irq_level(void)
{
/*
* Caution : if you change this, you must change the
* definition of BSP_PERIODIC_TIMER accordingly
*/
return BSP_PERIODIC_TIMER;
}
int BSP_disconnect_clock_handler (void)
{
if (!BSP_get_current_rtems_irq_handler(&clockIrqData)) {
printk("Unable to stop system clock\n");
rtems_fatal_error_occurred(1);
}
return BSP_remove_rtems_irq_handler (&clockIrqData);
}
int BSP_connect_clock_handler (rtems_irq_hdl hdl)
{
if (!BSP_get_current_rtems_irq_handler(&clockIrqData)) {
printk("Unable to get system clock handler\n");
rtems_fatal_error_occurred(1);
}
if (!BSP_remove_rtems_irq_handler (&clockIrqData)) {
printk("Unable to remove current system clock handler\n");
rtems_fatal_error_occurred(1);
}
/*
* Reinit structure
*/
clockIrqData.name = BSP_PERIODIC_TIMER;
clockIrqData.hdl = (rtems_irq_hdl) hdl;
clockIrqData.on = (rtems_irq_enable)clockOn;
clockIrqData.off = (rtems_irq_enable)clockOff;
clockIrqData.isOn = (rtems_irq_is_enabled)clockIsOn;
return BSP_install_rtems_irq_handler (&clockIrqData);
}

View File

@@ -0,0 +1,178 @@
/**
* @file
*
* @ingroup QorIQ
*
* @brief QorIQ clock configuration.
*/
/*
* Copyright (c) 2011, 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems/timecounter.h>
#include <libcpu/powerpc-utility.h>
#include <bsp.h>
#include <bsp/qoriq.h>
#include <bsp/irq.h>
/* This is defined in dev/clock/clockimpl.h */
static rtems_isr Clock_isr(void *arg);
static struct timecounter qoriq_clock_tc;
#ifdef QORIQ_IS_HYPERVISOR_GUEST
#define CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR
void qoriq_decrementer_dispatch(void)
{
PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_TSR, BOOKE_TSR_DIS);
Clock_isr(NULL);
}
static uint32_t qoriq_clock_get_timecount(struct timecounter *tc)
{
return ppc_alternate_time_base();
}
static void qoriq_clock_initialize(void)
{
uint64_t frequency = bsp_time_base_frequency;
uint32_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_DECAR, interval - 1);
PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(
BOOKE_TCR,
BOOKE_TCR_DIE | BOOKE_TCR_ARE
);
ppc_set_decrementer_register(interval - 1);
qoriq_clock_tc.tc_get_timecount = qoriq_clock_get_timecount;
qoriq_clock_tc.tc_counter_mask = 0xffffffff;
qoriq_clock_tc.tc_frequency = qoriq_clock_frequency;
qoriq_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&qoriq_clock_tc);
}
#else /* !QORIQ_IS_HYPERVISOR_GUEST */
static volatile qoriq_pic_global_timer *const qoriq_clock =
#if QORIQ_CLOCK_TIMER < 4
&qoriq.pic.gta [QORIQ_CLOCK_TIMER];
#else
&qoriq.pic.gtb [QORIQ_CLOCK_TIMER - 4];
#endif
static volatile qoriq_pic_global_timer *const qoriq_timecounter =
#if QORIQ_CLOCK_TIMECOUNTER < 4
&qoriq.pic.gta [QORIQ_CLOCK_TIMECOUNTER];
#else
&qoriq.pic.gtb [QORIQ_CLOCK_TIMECOUNTER - 4];
#endif
#define CLOCK_INTERRUPT (QORIQ_IRQ_GT_BASE + QORIQ_CLOCK_TIMER)
static void qoriq_clock_handler_install(void)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
#if defined(RTEMS_MULTIPROCESSING) && !defined(RTEMS_SMP)
{
Processor_mask affinity;
_Processor_mask_From_index(&affinity, ppc_processor_id());
bsp_interrupt_set_affinity(CLOCK_INTERRUPT, &affinity);
}
#endif
sc = qoriq_pic_set_priority(
CLOCK_INTERRUPT,
QORIQ_PIC_PRIORITY_LOWEST,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
sc = rtems_interrupt_handler_install(
CLOCK_INTERRUPT,
"Clock",
RTEMS_INTERRUPT_UNIQUE,
Clock_isr,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
static uint32_t qoriq_clock_get_timecount(struct timecounter *tc)
{
uint32_t ccr = qoriq_timecounter->ccr;
return GTCCR_COUNT_GET(-ccr);
}
static void qoriq_clock_initialize(void)
{
uint32_t timer_frequency = BSP_bus_frequency / 8;
uint32_t interval = (uint32_t) (((uint64_t) timer_frequency
* (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000);
qoriq_clock->bcr = GTBCR_COUNT(interval);
qoriq_timecounter->bcr = GTBCR_COUNT(0xffffffff);
qoriq_clock_tc.tc_get_timecount = qoriq_clock_get_timecount;
qoriq_clock_tc.tc_counter_mask = GTCCR_COUNT_GET(0xffffffff);
qoriq_clock_tc.tc_frequency = timer_frequency;
qoriq_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&qoriq_clock_tc);
}
static void qoriq_clock_cleanup(void)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
qoriq_clock->bcr = GTBCR_CI;
sc = rtems_interrupt_handler_remove(
CLOCK_INTERRUPT,
Clock_isr,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
#define Clock_driver_support_install_isr(clock_isr) \
qoriq_clock_handler_install()
#define Clock_driver_support_set_interrupt_affinity(online_processors) \
bsp_interrupt_set_affinity(CLOCK_INTERRUPT, online_processors)
#define Clock_driver_support_shutdown_hardware() \
qoriq_clock_cleanup()
#endif /* QORIQ_IS_HYPERVISOR_GUEST */
#define Clock_driver_support_initialize_hardware() \
qoriq_clock_initialize()
/* Include shared source clock driver code */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,247 @@
/**
* @file
*
* @ingroup powerpc_shared
*
* @brief Source file for a clock driver.
*/
/*
* Copyright (c) 2008-2015 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <rtems/clockdrv.h>
#include <rtems/timecounter.h>
#include <libcpu/powerpc-utility.h>
#include <bsp/vectors.h>
#define RTEMS_STATUS_CHECKS_USE_PRINTK
#include <rtems/status-checks.h>
/*
* This variable must be defined in the BSP and valid before clock driver
* initialization.
*/
extern uint32_t bsp_time_base_frequency;
#define PPC405_PIT 0x3db
#define PPC_CLOCK_DECREMENTER_MAX UINT32_MAX
volatile uint32_t Clock_driver_ticks = 0;
static uint32_t ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
static uint32_t ppc_clock_next_time_base;
static struct timecounter ppc_tc;
static uint32_t ppc_get_timecount(struct timecounter *tc)
{
return ppc_time_base();
}
static void ppc_clock_no_tick(void)
{
/* Do nothing */
}
static void (*ppc_clock_tick)(void) = ppc_clock_no_tick;
static int ppc_clock_exception_handler(
BSP_Exception_frame *frame,
unsigned number
)
{
uint32_t delta = ppc_clock_decrementer_value;
uint32_t next = ppc_clock_next_time_base;
uint32_t dec = 0;
uint32_t now = 0;
uint32_t msr = 0;
do {
/* Increment clock ticks */
Clock_driver_ticks += 1;
/* Enable external exceptions */
msr = ppc_external_exceptions_enable();
/* Call clock ticker */
ppc_clock_tick();
/* Restore machine state */
ppc_external_exceptions_disable( msr);
/* Next time base */
next += delta;
/* Current time */
now = ppc_time_base();
/* New decrementer value */
dec = next - now;
} while (dec > delta);
/* Set decrementer */
ppc_set_decrementer_register( dec);
/* Expected next time base */
ppc_clock_next_time_base = next;
return 0;
}
static int ppc_clock_exception_handler_first(
BSP_Exception_frame *frame,
unsigned number
)
{
/* We have to clear the first pending decrementer exception this way */
if (ppc_decrementer_register() >= 0x80000000) {
ppc_clock_exception_handler( frame, number);
}
ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler);
return 0;
}
static int ppc_clock_exception_handler_booke(
BSP_Exception_frame *frame,
unsigned number
)
{
uint32_t msr;
/* Acknowledge decrementer request */
PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_TSR, BOOKE_TSR_DIS);
/* Increment clock ticks */
Clock_driver_ticks += 1;
/* Enable external exceptions */
msr = ppc_external_exceptions_enable();
/* Call clock ticker */
ppc_clock_tick();
/* Restore machine state */
ppc_external_exceptions_disable( msr);
return 0;
}
static int ppc_clock_exception_handler_ppc405(BSP_Exception_frame *frame, unsigned number)
{
uint32_t msr;
/* Acknowledge PIT request */
PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_TSR, BOOKE_TSR_DIS);
/* Increment clock ticks */
Clock_driver_ticks += 1;
/* Enable external exceptions */
msr = ppc_external_exceptions_enable();
/* Call clock ticker */
ppc_clock_tick();
/* Restore machine state */
ppc_external_exceptions_disable(msr);
return 0;
}
void Clock_exit(void)
{
/* Set the decrementer to the maximum value */
ppc_set_decrementer_register( PPC_CLOCK_DECREMENTER_MAX);
/* Use default clock handler */
ppc_clock_tick = ppc_clock_no_tick;
}
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
uint64_t frequency = bsp_time_base_frequency;
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
/*
* Set default ticker.
*/
ppc_clock_tick = rtems_timecounter_tick;
if (ppc_cpu_is_bookE() != PPC_BOOKE_405) {
/* Decrementer value */
ppc_clock_decrementer_value = interval - 1;
/* Check decrementer value */
if (ppc_clock_decrementer_value == 0) {
ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n");
}
if (ppc_cpu_is_bookE()) {
/* Set decrementer auto-reload value */
PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);
/* Install exception handler */
ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);
/* Enable decrementer and auto-reload */
PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
} else {
/* Here the decrementer value is actually the interval */
++ppc_clock_decrementer_value;
/* Initialize next time base */
ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;
/* Install exception handler */
ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
}
/* Set the decrementer value */
ppc_set_decrementer_register( ppc_clock_decrementer_value);
} else {
/* PIT interval value */
ppc_clock_decrementer_value = interval;
/* Install exception handler */
ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405);
/* Enable PIT and auto-reload */
PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(PPC405_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
/* Set PIT auto-reload and initial value */
PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval);
}
/* Install timecounter */
ppc_tc.tc_get_timecount = ppc_get_timecount;
ppc_tc.tc_counter_mask = 0xffffffff;
ppc_tc.tc_frequency = frequency;
ppc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&ppc_tc);
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,43 @@
/*
* Clock Tick interrupt conexion code.
*/
/*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Modified to support the MPC750.
* Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
*/
#include <bsp.h>
#include <bsp/irq.h>
#include <libcpu/c_clock.h>
#include <libcpu/cpuIdent.h>
static rtems_irq_connect_data clockIrqData;
static rtems_irq_connect_data clockIrqData = {
BSP_DECREMENTER,
clockIsr,
NULL,
(rtems_irq_enable)clockOn,
(rtems_irq_disable)clockOff,
(rtems_irq_is_enabled) clockIsOn
};
int BSP_disconnect_clock_handler(void)
{
return BSP_remove_rtems_irq_handler(&clockIrqData);
}
int BSP_connect_clock_handler(void)
{
if ( ppc_cpu_is_bookE() )
clockIrqData.hdl = clockIsrBookE;
return BSP_install_rtems_irq_handler(&clockIrqData);
}

View File

@@ -0,0 +1,63 @@
/*
* Clock Tick interrupt conexion code.
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* SS555 port sponsored by Defence Research and Development Canada - Suffield
* Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
*
* Derived from c/src/lib/libbsp/powerpc/mbx8xx/clock/p_clock.c:
*
* Modified to support the MPC750.
* Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
*/
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/bspIo.h>
#include <mpc5xx.h>
static rtems_irq_connect_data clockIrqData = {
CPU_PERIODIC_TIMER,
(rtems_irq_hdl)Clock_isr,
NULL,
(rtems_irq_enable)clockOn,
(rtems_irq_disable)clockOff,
(rtems_irq_is_enabled)clockIsOn
};
int BSP_disconnect_clock_handler (void)
{
if (!BSP_get_current_rtems_irq_handler(&clockIrqData)) {
printk("Unable to stop system clock\n");
rtems_fatal_error_occurred(1);
}
return BSP_remove_rtems_irq_handler (&clockIrqData);
}
int BSP_connect_clock_handler (rtems_irq_hdl hdl)
{
if (!BSP_get_current_rtems_irq_handler(&clockIrqData)) {
printk("Unable to get system clock handler\n");
rtems_fatal_error_occurred(1);
}
if (!BSP_remove_rtems_irq_handler (&clockIrqData)) {
printk("Unable to remove current system clock handler\n");
rtems_fatal_error_occurred(1);
}
/*
* Reinit structure
*/
clockIrqData.name = CPU_PERIODIC_TIMER;
clockIrqData.hdl = (rtems_irq_hdl) hdl;
clockIrqData.on = (rtems_irq_enable)clockOn;
clockIrqData.off = (rtems_irq_enable)clockOff;
clockIrqData.isOn = (rtems_irq_is_enabled)clockIsOn;
return BSP_install_rtems_irq_handler (&clockIrqData);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2011, 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems/timecounter.h>
#include <libcpu/powerpc-utility.h>
#include <bsp.h>
#include <bsp/irq.h>
/* This is defined in dev/clock/clockimpl.h */
static rtems_isr Clock_isr(void *arg);
static struct timecounter t32mppc_clock_tc;
#define CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR
void t32mppc_decrementer_dispatch(void)
{
PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_TSR, BOOKE_TSR_DIS);
Clock_isr(NULL);
}
static uint32_t t32mppc_clock_get_timecount(struct timecounter *tc)
{
return ppc_time_base();
}
static void t32mppc_clock_initialize(void)
{
uint64_t frequency = bsp_time_base_frequency / 10;
uint32_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_DECAR, interval - 1);
PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(
BOOKE_TCR,
BOOKE_TCR_DIE | BOOKE_TCR_ARE
);
ppc_set_decrementer_register(interval - 1);
t32mppc_clock_tc.tc_get_timecount = t32mppc_clock_get_timecount;
t32mppc_clock_tc.tc_counter_mask = 0xffffffff;
t32mppc_clock_tc.tc_frequency = bsp_time_base_frequency;
t32mppc_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&t32mppc_clock_tc);
}
#define Clock_driver_support_initialize_hardware() \
t32mppc_clock_initialize()
/* Include shared source clock driver code */
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,58 @@
/*
* Clock Tick interrupt conexion code.
*/
/*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Modified to support the MPC750.
* Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
*/
#include <bsp.h>
#include <bsp/irq-generic.h>
#include <rtems/bspIo.h>
extern void clockOn(void*);
extern void clockOff (void*);
extern int clockIsOn(void*);
extern void Clock_isr(void*);
static void BSP_clock_hdl(void * arg)
{
Clock_isr(arg);
}
int BSP_disconnect_clock_handler (void)
{
rtems_status_code sc;
clockOff(NULL);
/*
* remove interrupt handler
*/
sc = rtems_interrupt_handler_remove(BSP_PERIODIC_TIMER,
BSP_clock_hdl,NULL);
return sc == RTEMS_SUCCESSFUL;
}
int BSP_connect_clock_handler (rtems_irq_hdl hdl)
{
rtems_status_code sc;
/*
* install interrupt handler
*/
sc = rtems_interrupt_handler_install(BSP_PERIODIC_TIMER,
"PIT clock",0,
BSP_clock_hdl,NULL);
if (sc == RTEMS_SUCCESSFUL) {
clockOn(NULL);
}
return sc == RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,131 @@
/**
* @file
*
* @ingroup bsp_clock
*
* @brief riscv clock support.
*/
/*
* riscv_generic Clock driver
*
* COPYRIGHT (c) 2015 Hesham Alatary <hesham@alumni.york.ac.uk>
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/score/riscv-utility.h>
#include <rtems/score/cpu.h>
#include <rtems/timecounter.h>
/* The number of clock cycles before generating a tick timer interrupt. */
#define TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT 1000
#define RISCV_CLOCK_CYCLE_TIME_NANOSECONDS 1
static struct timecounter riscv_generic_tc;
/* CPU counter */
static CPU_Counter_ticks cpu_counter_ticks;
/* This prototype is added here to Avoid warnings */
void Clock_isr(void *arg);
static void riscv_generic_clock_at_tick(void)
{
REG(MTIME_MM) = 0;
REG(MTIMECMP_MM) = TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT;
cpu_counter_ticks += TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT * 10000;
}
static void riscv_generic_clock_handler_install(proc_ptr new_isr)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
_CPU_ISR_install_vector(RISCV_MACHINE_TIMER_INTERRUPT,
new_isr,
NULL);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(0xdeadbeef);
}
}
static uint32_t riscv_generic_get_timecount(struct timecounter *tc)
{
uint32_t ticks_since_last_timer_interrupt = REG(MTIME_MM);
return cpu_counter_ticks + ticks_since_last_timer_interrupt;
}
CPU_Counter_ticks _CPU_Counter_read(void)
{
return riscv_generic_get_timecount(NULL);
}
static void riscv_generic_clock_initialize(void)
{
uint32_t mtimecmp = TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT;
uint64_t frequency = (1000000000 / RISCV_CLOCK_CYCLE_TIME_NANOSECONDS);
REG(MTIME_MM) = 0;
REG(MTIMECMP_MM) = TTMR_NUM_OF_CLOCK_TICKS_INTERRUPT;
/* Enable mtimer interrupts */
set_csr(mie, MIP_MTIP);
set_csr(mip, MIP_MTIP);
/* Initialize timecounter */
riscv_generic_tc.tc_get_timecount = riscv_generic_get_timecount;
riscv_generic_tc.tc_counter_mask = 0xffffffff;
riscv_generic_tc.tc_frequency = frequency;
riscv_generic_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
rtems_timecounter_install(&riscv_generic_tc);
}
static void riscv_generic_clock_cleanup(void)
{
/* Disable mtimer interrupts */
clear_csr(mie, MIP_MTIP);
clear_csr(mip, MIP_MTIP);
}
CPU_Counter_ticks _CPU_Counter_difference(
CPU_Counter_ticks second,
CPU_Counter_ticks first
)
{
return second - first;
}
#define Clock_driver_support_at_tick() riscv_generic_clock_at_tick()
#define Clock_driver_support_initialize_hardware() riscv_generic_clock_initialize()
#define Clock_driver_support_install_isr(isr) \
riscv_generic_clock_handler_install(isr)
#define Clock_driver_support_shutdown_hardware() riscv_generic_clock_cleanup()
#include "../../../shared/dev/clock/clockimpl.h"

View File

@@ -0,0 +1,306 @@
/*
* This file contains the clock driver the Hitachi SH 703X
*/
/*
* Authors: Ralf Corsepius (corsepiu@faw.uni-ulm.de) and
* Bernd Becker (becker@faw.uni-ulm.de)
*
* COPYRIGHT (c) 1997-1998, FAW Ulm, Germany
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* COPYRIGHT (c) 1998.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <stdlib.h>
#include <rtems/clockdrv.h>
#include <rtems/score/sh_io.h>
#include <rtems/score/sh.h>
#include <rtems/score/ispsh7032.h>
#include <rtems/score/iosh7032.h>
extern uint32_t bsp_clicks_per_second;
#ifndef CLOCKPRIO
#define CLOCKPRIO 10
#endif
#define I_CLK_PHI_1 0
#define I_CLK_PHI_2 1
#define I_CLK_PHI_4 2
#define I_CLK_PHI_8 3
/*
* Set I_CLK_PHI to one of the I_CLK_PHI_X values from above to choose
* a PHI/X clock rate.
*/
#define I_CLK_PHI I_CLK_PHI_4
#define CLOCK_SCALE (1<<I_CLK_PHI)
#define ITU0_STARTMASK 0xfe
#define ITU0_SYNCMASK 0xfe
#define ITU0_MODEMASK 0xfe
#define ITU0_TCRMASK (0x20 | I_CLK_PHI)
#define ITU_STAT_MASK 0xf8
#define ITU0_IRQMASK 0xfe
#define ITU0_TIERMASK 0x01
#define IPRC_ITU0_MASK 0xff0f
#define ITU0_TIORVAL 0x08
/*
* clicks_per_tick := clicks_per_sec * usec_per_tick
*
* This is a very expensive function ;-)
*
* Below are two variants:
* 1. A variant applying integer arithmetics, only.
* 2. A variant applying floating point arithmetics
*
* The floating point variant pulls in the fmath routines when linking,
* resulting in slightly larger executables for applications that do not
* apply fmath otherwise. However, the imath variant is significantly slower
* than the fmath variant and more complex.
*
* Assuming that most applications will not use fmath, but are critical
* in memory size constraints, we apply the integer variant.
*
* To the sake of simplicity, we might abandon one of both variants in
* future.
*/
static unsigned int sh_clicks_per_tick(
unsigned int clicks_per_sec,
unsigned int usec_per_tick
)
{
#if 1
unsigned int clicks_per_tick = 0 ;
unsigned int b = clicks_per_sec ;
unsigned int c = 1000000 ;
unsigned int d = 1 ;
unsigned int a = ( ( b / c ) * usec_per_tick ) / d;
clicks_per_tick += a ;
while ( ( b %= c ) > 0 )
{
c /= 10 ;
d *= 10 ;
a = ( ( b / c ) * usec_per_tick ) / d ;
clicks_per_tick += a ;
}
return clicks_per_tick ;
#else
double fclicks_per_tick =
((double) clicks_per_sec * (double) usec_per_tick) / 1000000.0 ;
return (uint32_t) fclicks_per_tick ;
#endif
}
/*
* The interrupt vector number associated with the clock tick device
* driver.
*/
#define CLOCK_VECTOR IMIA0_ISP_V
/*
* Clock_driver_ticks is a monotonically increasing counter of the
* number of clock ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
void Clock_exit( void );
static rtems_isr Clock_isr( rtems_vector_number vector );
/*
* Clock_isrs is the number of clock ISRs until the next invocation of
* the RTEMS clock tick routine. The clock tick device driver
* gets an interrupt once a millisecond and counts down until the
* length of time between the user configured microseconds per tick
* has passed.
*/
uint32_t Clock_isrs; /* ISRs until next tick */
static uint32_t Clock_isrs_const; /* only calculated once */
/*
* The previous ISR on this clock tick interrupt vector.
*/
rtems_isr_entry Old_ticker;
/*
* Isr Handler
*/
static rtems_isr Clock_isr(
rtems_vector_number vector
)
{
/*
* bump the number of clock driver ticks since initialization
*
* determine if it is time to announce the passing of tick as configured
* to RTEMS through the rtems_clock_tick directive
*
* perform any timer dependent tasks
*/
uint8_t temp;
/* reset the flags of the status register */
temp = read8( ITU_TSR0) & ITU_STAT_MASK;
write8( temp, ITU_TSR0);
Clock_driver_ticks++ ;
if( Clock_isrs == 1)
{
rtems_clock_tick();
Clock_isrs = Clock_isrs_const;
}
else
{
Clock_isrs-- ;
}
}
/*
* Install_clock
*
* Install a clock tick handler and reprograms the chip. This
* is used to initially establish the clock tick.
*/
static void Install_clock(
rtems_isr_entry clock_isr
)
{
uint8_t temp8 = 0;
uint32_t microseconds_per_tick;
uint32_t cclicks_per_tick;
uint16_t Clock_limit;
/*
* Initialize the clock tick device driver variables
*/
Clock_driver_ticks = 0;
if ( rtems_configuration_get_microseconds_per_tick() != 0 )
microseconds_per_tick = rtems_configuration_get_microseconds_per_tick() ;
else
microseconds_per_tick = 10000 ; /* 10000 us */
/* clock clicks per tick */
cclicks_per_tick = sh_clicks_per_tick(
bsp_clicks_per_second / CLOCK_SCALE, microseconds_per_tick );
Clock_isrs_const = cclicks_per_tick >> 16 ;
if ( ( cclicks_per_tick | 0xffff ) > 0 )
Clock_isrs_const++ ;
Clock_limit = cclicks_per_tick / Clock_isrs_const ;
Clock_isrs = Clock_isrs_const;
rtems_interrupt_catch( Clock_isr, CLOCK_VECTOR, &Old_ticker );
/*
* Hardware specific initialize goes here
*/
/* stop Timer 0 */
temp8 = read8( ITU_TSTR) & ITU0_STARTMASK;
write8( temp8, ITU_TSTR);
/* set initial counter value to 0 */
write16( 0, ITU_TCNT0);
/* Timer 0 runs independent */
temp8 = read8( ITU_TSNC) & ITU0_SYNCMASK;
write8( temp8, ITU_TSNC);
/* Timer 0 normal mode */
temp8 = read8( ITU_TMDR) & ITU0_MODEMASK;
write8( temp8, ITU_TMDR);
/* TCNT is cleared by GRA ; internal clock /4 */
write8( ITU0_TCRMASK , ITU_TCR0);
/* use GRA without I/O - pins */
write8( ITU0_TIORVAL, ITU_TIOR0);
/* reset flags of the status register */
temp8 = read8( ITU_TSR0) & ITU_STAT_MASK;
write8( temp8, ITU_TSR0);
/* Irq if is equal GRA */
temp8 = read8( ITU_TIER0) | ITU0_TIERMASK;
write8( temp8, ITU_TIER0);
/* set interrupt priority */
if( sh_set_irq_priority( CLOCK_VECTOR, CLOCKPRIO ) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
/* set counter limits */
write16( Clock_limit, ITU_GRA0);
/* start counter */
temp8 = read8( ITU_TSTR) |~ITU0_STARTMASK;
write8( temp8, ITU_TSTR);
/*
* Schedule the clock cleanup routine to execute if the application exits.
*/
atexit( Clock_exit );
}
/*
* Clean up before the application exits
*/
void Clock_exit( void )
{
uint8_t temp8 = 0;
/* turn off the timer interrupts */
/* set interrupt priority to 0 */
if( sh_set_irq_priority( CLOCK_VECTOR, 0 ) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred( RTEMS_UNSATISFIED);
/*
* temp16 = read16( ITU_TIER0) & IPRC_ITU0_IRQMASK;
* write16( temp16, ITU_TIER0);
*/
/* stop counter */
temp8 = read8( ITU_TSTR) & ITU0_STARTMASK;
write8( temp8, ITU_TSTR);
/* old vector shall not be installed */
}
/*
* Clock_initialize
*
* Device driver entry point for clock tick driver initialization.
*/
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,51 @@
/*
* This routine is a simple spin delay
*
* Author: Ralf Corsepius (corsepiu@faw.uni-ulm.de)
*
* COPYRIGHT (c) 1999, Ralf Corsepius, Ulm, Germany
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
extern uint32_t bsp_clicks_per_second;
/*
* Simple spin delay in microsecond units for device drivers.
* This is very dependent on the clock speed of the target.
*
* Since we don't have a real time clock, this is a very rough
* approximation, assuming that each cycle of the delay loop takes
* approx. 4 machine cycles.
*
* e.g.: clicks_per_second = 20MHz
* => 5e-8 secs per instruction
* => 4 * 5e-8 secs per delay loop
*/
void CPU_delay( uint32_t microseconds )
{
register uint32_t clicks_per_usec = bsp_clicks_per_second / 1000000;
register uint32_t _delay = (microseconds) * (clicks_per_usec);
__asm__ volatile (
"0: add #-4,%0\n\
nop\n\
cmp/pl %0\n\
bt 0b\n\
nop"
:: "r" (_delay) );
}

View File

@@ -0,0 +1,243 @@
/*
* This file contains the clock driver the Hitachi SH 704X
*/
/*
* Authors: Ralf Corsepius (corsepiu@faw.uni-ulm.de) and
* Bernd Becker (becker@faw.uni-ulm.de)
*
* COPYRIGHT (c) 1997-1998, FAW Ulm, Germany
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* COPYRIGHT (c) 1998.
* On-Line Applications Research Corporation (OAR).
*
* Modified to reflect registers of sh7045 processor:
* John M. Mills (jmills@tga.com)
* TGA Technologies, Inc.
* 100 Pinnacle Way, Suite 140
* Norcross, GA 30071 U.S.A.
* August, 1999
*
* This modified file may be copied and distributed in accordance
* the above-referenced license. It is provided for critique and
* developmental purposes without any warranty nor representation
* by the authors or by TGA Technologies.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <stdlib.h>
#include <rtems/clockdrv.h>
#include <rtems/score/sh_io.h>
#include <rtems/score/sh.h>
#include <rtems/score/ispsh7045.h>
#include <rtems/score/iosh7045.h>
extern uint32_t bsp_clicks_per_second;
#define _MTU_COUNTER0_MICROSECOND (Clock_MHZ/16)
#ifndef CLOCKPRIO
#define CLOCKPRIO 10
#endif
#define MTU0_STARTMASK 0xfe
#define MTU0_SYNCMASK 0xfe
#define MTU0_MODEMASK 0xc0
#define MTU0_TCRMASK 0x22 /* bit 7 also used, vs 703x */
#define MTU0_STAT_MASK 0xc0
#define MTU0_IRQMASK 0xfe
#define MTU0_TIERMASK 0x01
#define IPRC_MTU0_MASK 0xff0f
#define MTU0_TIORVAL 0x08
/*
* The interrupt vector number associated with the clock tick device
* driver.
*/
#define CLOCK_VECTOR MTUA0_ISP_V
/*
* Clock_driver_ticks is a monotonically increasing counter of the
* number of clock ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
static rtems_isr Clock_isr( rtems_vector_number vector );
static uint32_t Clock_MHZ ;
/*
* Clock_isrs is the number of clock ISRs until the next invocation of
* the RTEMS clock tick routine. The clock tick device driver
* gets an interrupt once a millisecond and counts down until the
* length of time between the user configured microseconds per tick
* has passed.
*/
uint32_t Clock_isrs; /* ISRs until next tick */
static uint32_t Clock_isrs_const; /* only calculated once */
/*
* The previous ISR on this clock tick interrupt vector.
*/
rtems_isr_entry Old_ticker;
/*
* Isr Handler
*/
static rtems_isr Clock_isr(
rtems_vector_number vector
)
{
/*
* bump the number of clock driver ticks since initialization
*
* determine if it is time to announce the passing of tick as configured
* to RTEMS through the rtems_clock_tick directive
*
* perform any timer dependent tasks
*/
uint8_t temp;
/* reset the flags of the status register */
temp = read8( MTU_TSR0) & MTU0_STAT_MASK;
write8( temp, MTU_TSR0);
Clock_driver_ticks++ ;
if( Clock_isrs == 1)
{
rtems_clock_tick();
Clock_isrs = Clock_isrs_const;
}
else
{
Clock_isrs-- ;
}
}
/*
* Install_clock
*
* Install a clock tick handler and reprograms the chip. This
* is used to initially establish the clock tick.
*/
static void Install_clock(
rtems_isr_entry clock_isr
)
{
uint8_t temp8 = 0;
uint32_t factor = 1000000;
/*
* Initialize the clock tick device driver variables
*/
Clock_driver_ticks = 0;
Clock_isrs_const = rtems_configuration_get_microseconds_per_tick() / 10000;
Clock_isrs = Clock_isrs_const;
factor /= rtems_configuration_get_microseconds_per_tick(); /* minimalization of integer division error */
Clock_MHZ = bsp_clicks_per_second / factor ;
rtems_interrupt_catch( Clock_isr, CLOCK_VECTOR, &Old_ticker );
/*
* Hardware specific initialize goes here
*/
/* stop Timer 0 */
temp8 = read8( MTU_TSTR) & MTU0_STARTMASK;
write8( temp8, MTU_TSTR);
/* set initial counter value to 0 */
write16( 0, MTU_TCNT0);
/* Timer 0 runs independent */
temp8 = read8( MTU_TSYR) & MTU0_SYNCMASK;
write8( temp8, MTU_TSYR);
/* Timer 0 normal mode */
temp8 = read8( MTU_TMDR0) & MTU0_MODEMASK;
write8( temp8, MTU_TMDR0);
/* TCNT is cleared by GRA ; internal clock /16 */
write8( MTU0_TCRMASK , MTU_TCR0);
/* use GRA without I/O - pins */
write8( MTU0_TIORVAL, MTU_TIORL0);
/* reset flags of the status register */
temp8 = read8( MTU_TSR0) & MTU0_STAT_MASK;
write8( temp8, MTU_TSR0);
/* Irq if is equal GRA */
temp8 = read8( MTU_TIER0) | MTU0_TIERMASK;
write8( temp8, MTU_TIER0);
/* set interrupt priority */
if( sh_set_irq_priority( CLOCK_VECTOR, CLOCKPRIO ) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
/* set counter limits */
write16( _MTU_COUNTER0_MICROSECOND, MTU_GR0A);
/* start counter */
temp8 = read8( MTU_TSTR) |~MTU0_STARTMASK;
write8( temp8, MTU_TSTR);
/*
* Schedule the clock cleanup routine to execute if the application exits.
*/
atexit( Clock_exit );
}
/*
* Clean up before the application exits
*/
void Clock_exit( void )
{
uint8_t temp8 = 0;
/* turn off the timer interrupts */
/* set interrupt priority to 0 */
if( sh_set_irq_priority( CLOCK_VECTOR, 0 ) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred( RTEMS_UNSATISFIED);
/*
* temp16 = read16( MTU_TIER0) & IPRC_MTU0_IRQMASK;
* write16( temp16, MTU_TIER0);
*/
/* stop counter */
temp8 = read8( MTU_TSTR) & MTU0_STARTMASK;
write8( temp8, MTU_TSTR);
/* old vector shall not be installed */
}
/*
* Clock_initialize
*
* Device driver entry point for clock tick driver initialization.
*/
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,244 @@
/*
* This file contains the generic RTEMS clock driver the Hitachi SH 7750
*/
/*
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
* Author: Victor V. Vengerov <vvv@oktet.ru>
*
* COPYRIGHT (c) 2001
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <rtems.h>
#include <stdlib.h>
#include <rtems/clockdrv.h>
#include <rtems/score/sh_io.h>
#include <rtems/score/sh.h>
#include <rtems/score/ispsh7750.h>
#include <rtems/score/iosh7750.h>
extern uint32_t bsp_clicks_per_second;
#ifndef CLOCKPRIO
#define CLOCKPRIO 10
#endif
/* Clock timer prescaler division ratio */
#define CLOCK_PRESCALER 4
#define TCR0_TPSC SH7750_TCR_TPSC_DIV4
/*
* The interrupt vector number associated with the clock tick device
* driver.
*/
#define CLOCK_VECTOR SH7750_EVT_TO_NUM(SH7750_EVT_TUNI0)
/*
* Clock_driver_ticks is a monotonically increasing counter of the
* number of clock ticks since the driver was initialized.
*/
volatile uint32_t Clock_driver_ticks;
static rtems_isr Clock_isr( rtems_vector_number vector );
/*
* The previous ISR on this clock tick interrupt vector.
*/
rtems_isr_entry Old_ticker;
/*
* Isr Handler
*/
/*
* Clock_isr
*
* Clock interrupt handling routine.
*/
static rtems_isr Clock_isr(rtems_vector_number vector)
{
uint16_t tcr;
/* reset the timer underflow flag */
tcr = read16(SH7750_TCR0);
write16(tcr & ~SH7750_TCR_UNF, SH7750_TCR0);
/* Increment the clock interrupt counter */
Clock_driver_ticks++ ;
/* Invoke rtems clock service routine */
rtems_clock_tick();
}
/*
* Install_clock
*
* Install a clock tick handler and reprograms the chip. This
* is used to initially establish the clock tick.
*
* SIDE EFFECTS:
* Establish clock interrupt handler, configure Timer 0 hardware
*/
static void Install_clock(rtems_isr_entry clock_isr)
{
int cpudiv = 1; /* CPU frequency divider */
int tidiv = 1; /* Timer input frequency divider */
uint32_t timer_divider; /* Calculated Timer Divider value */
uint8_t temp8;
uint16_t temp16;
/*
* Initialize the clock tick device driver variables
*/
Clock_driver_ticks = 0;
/* Get CPU frequency divider from clock unit */
switch (read16(SH7750_FRQCR) & SH7750_FRQCR_IFC) {
case SH7750_FRQCR_IFCDIV1:
cpudiv = 1;
break;
case SH7750_FRQCR_IFCDIV2:
cpudiv = 2;
break;
case SH7750_FRQCR_IFCDIV3:
cpudiv = 3;
break;
case SH7750_FRQCR_IFCDIV4:
cpudiv = 4;
break;
case SH7750_FRQCR_IFCDIV6:
cpudiv = 6;
break;
case SH7750_FRQCR_IFCDIV8:
cpudiv = 8;
break;
default:
rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
}
/* Get peripheral module frequency divider from clock unit */
switch (read16(SH7750_FRQCR) & SH7750_FRQCR_PFC) {
case SH7750_FRQCR_PFCDIV2:
tidiv = 2 * CLOCK_PRESCALER;
break;
case SH7750_FRQCR_PFCDIV3:
tidiv = 3 * CLOCK_PRESCALER;
break;
case SH7750_FRQCR_PFCDIV4:
tidiv = 4 * CLOCK_PRESCALER;
break;
case SH7750_FRQCR_PFCDIV6:
tidiv = 6 * CLOCK_PRESCALER;
break;
case SH7750_FRQCR_PFCDIV8:
tidiv = 8 * CLOCK_PRESCALER;
break;
default:
rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
}
timer_divider =
(bsp_clicks_per_second * cpudiv / (tidiv*1000000)) *
rtems_configuration_get_microseconds_per_tick();
/*
* Hardware specific initialization
*/
/* Stop the Timer 0 */
temp8 = read8(SH7750_TSTR);
temp8 &= ~SH7750_TSTR_STR0;
write8(temp8, SH7750_TSTR);
/* Establish interrupt handler */
rtems_interrupt_catch( Clock_isr, CLOCK_VECTOR, &Old_ticker );
/* Reset counter */
write32(timer_divider, SH7750_TCNT0);
/* Load divider */
write32(timer_divider, SH7750_TCOR0);
write16(
SH7750_TCR_UNIE | /* Enable Underflow Interrupt */
SH7750_TCR_CKEG_RAISE | /* Count on rising edge */
TCR0_TPSC, /* Timer prescaler ratio */
SH7750_TCR0);
/* Set clock interrupt priority */
temp16 = read16(SH7750_IPRA);
temp16 = (temp16 & ~SH7750_IPRA_TMU0) | (CLOCKPRIO << SH7750_IPRA_TMU0_S);
write16(temp16, SH7750_IPRA);
/* Start the Timer 0 */
temp8 = read8(SH7750_TSTR);
temp8 |= SH7750_TSTR_STR0;
write8(temp8, SH7750_TSTR);
/*
* Schedule the clock cleanup routine to execute if the application exits.
*/
atexit( Clock_exit );
}
/*
* Clock_exit
*
* Clean up before the application exits
*
* SIDE EFFECTS:
* Stop Timer 0 counting, set timer 0 interrupt priority level to 0.
*/
void
Clock_exit(void)
{
uint8_t temp8 = 0;
uint16_t temp16 = 0;
/* turn off the timer interrupts */
/* Stop the Timer 0 */
temp8 = read8(SH7750_TSTR);
temp8 &= ~SH7750_TSTR_STR0;
write8(temp8, SH7750_TSTR);
/* Lower timer interrupt priority to 0 */
temp16 = read16(SH7750_IPRA);
temp16 = (temp16 & ~SH7750_IPRA_TMU0) | (0 << SH7750_IPRA_TMU0_S);
write16(temp16, SH7750_IPRA);
/* old vector shall not be installed */
}
/*
* Clock_initialize
*
* Device driver entry point for clock tick driver initialization.
*/
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Install_clock( Clock_isr );
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,59 @@
/*
* Instantiate the clock driver shell.
*
* Since there is no clock source on the simulator, we fake
* it with a special IDLE task.
*/
#include <rtems.h>
#include <rtems/score/percpu.h>
#include <rtems/score/threaddispatch.h>
#define CLOCK_VECTOR 0
volatile bool clock_driver_enabled;
#define Clock_driver_support_initialize_hardware() \
do { \
clock_driver_enabled = true; \
} while (0)
#define Clock_driver_support_shutdown_hardware() \
do { \
clock_driver_enabled = false; \
} while (0)
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "clockimpl.h"
/*
* If this is defined, then the BSP has defined a delay of some sort so
* time passage appears somewhat correctly. Otherwise, it runs extremely
* fast with no delays.
*/
#ifndef BSP_CLOCK_DRIVER_DELAY
#define BSP_CLOCK_DRIVER_DELAY()
#endif
/*
* Since there is no interrupt on this simulator, let's just
* fake time passing. This will not let preemption from an
* interrupt work but is enough for many tests.
*/
void *clock_driver_sim_idle_body(
uintptr_t ignored
)
{
for( ; ; ) {
if ( clock_driver_enabled ) {
Per_CPU_Control *cpu = _Thread_Dispatch_disable();
_ISR_Nest_level++;
rtems_clock_tick();
_ISR_Nest_level--;
_Thread_Dispatch_enable( cpu );
BSP_CLOCK_DRIVER_DELAY();
}
}
return 0; /* to avoid warning */
}

View File

@@ -0,0 +1,260 @@
/**
* @file
*
* @ingroup bsp_clock
*
* @brief Clock Tick Device Driver Shell
*/
/*
* COPYRIGHT (c) 1989-2014.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdlib.h>
#include <bsp.h>
#include <rtems/clockdrv.h>
#include <rtems/score/percpu.h>
#include <rtems/score/smpimpl.h>
#include <rtems/score/watchdogimpl.h>
#ifdef Clock_driver_nanoseconds_since_last_tick
#error "Update driver to use the timecounter instead of nanoseconds extension"
#endif
/**
* @defgroup bsp_clock Clock Support
*
* @ingroup bsp_shared
*
* @brief Clock support
*
*/
#if CLOCK_DRIVER_USE_FAST_IDLE && CLOCK_DRIVER_ISRS_PER_TICK
#error "Fast Idle PLUS n ISRs per tick is not supported"
#endif
/**
* @brief Do nothing by default.
*/
#ifndef Clock_driver_support_install_isr
#define Clock_driver_support_install_isr(isr)
#endif
/**
* @brief This method is rarely used so default it.
*/
#ifndef Clock_driver_support_find_timer
#define Clock_driver_support_find_timer()
#endif
/**
* @brief Do nothing by default.
*/
#ifndef Clock_driver_support_at_tick
#define Clock_driver_support_at_tick()
#endif
/**
* @brief Do nothing by default.
*/
#ifndef Clock_driver_support_set_interrupt_affinity
#define Clock_driver_support_set_interrupt_affinity(online_processors)
#endif
/*
* A specialized clock driver may use for example rtems_timecounter_tick_simple()
* instead of the default.
*/
#ifndef Clock_driver_timecounter_tick
static void Clock_driver_timecounter_tick( void )
{
#if defined(CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER)
rtems_clock_tick();
#elif defined(RTEMS_SMP) && defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
uint32_t cpu_count = _SMP_Get_processor_count();
uint32_t cpu_index;
for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
Per_CPU_Control *cpu;
cpu = _Per_CPU_Get_by_index( cpu_index );
if ( _Per_CPU_Is_boot_processor( cpu ) ) {
rtems_timecounter_tick();
} else if ( _Processor_mask_Is_set( _SMP_Get_online_processors(), cpu_index ) ) {
_Watchdog_Tick( cpu );
}
}
#else
rtems_timecounter_tick();
#endif
}
#endif
/**
* @brief ISRs until next clock tick
*/
#if CLOCK_DRIVER_ISRS_PER_TICK
volatile uint32_t Clock_driver_isrs;
#endif
/**
* @brief Clock ticks since initialization
*/
volatile uint32_t Clock_driver_ticks;
#ifdef Clock_driver_support_shutdown_hardware
void Clock_exit( void );
#endif
/**
* @brief Clock_isr
*
* This is the clock tick interrupt handler.
*
* @param vector Vector number.
*/
#if defined(BSP_FEATURE_IRQ_EXTENSION) || \
(CPU_SIMPLE_VECTORED_INTERRUPTS != TRUE)
void Clock_isr(void *arg);
void Clock_isr(void *arg)
{
#else
rtems_isr Clock_isr(rtems_vector_number vector);
rtems_isr Clock_isr(
rtems_vector_number vector
)
{
#endif
/*
* Accurate count of ISRs
*/
Clock_driver_ticks += 1;
#if CLOCK_DRIVER_USE_FAST_IDLE
{
struct timecounter *tc = _Timecounter;
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
uint32_t interval = (uint32_t)
((tc->tc_frequency * us_per_tick) / 1000000);
Clock_driver_timecounter_tick();
if (!rtems_configuration_is_smp_enabled()) {
while (
_Thread_Heir == _Thread_Executing && _Thread_Executing->is_idle
) {
ISR_lock_Context lock_context;
_Timecounter_Acquire(&lock_context);
_Timecounter_Tick_simple(
interval,
(*tc->tc_get_timecount)(tc),
&lock_context
);
}
}
Clock_driver_support_at_tick();
}
#else
/*
* Do the hardware specific per-tick action.
*
* The counter/timer may or may not be set to automatically reload.
*/
Clock_driver_support_at_tick();
#if CLOCK_DRIVER_ISRS_PER_TICK
/*
* The driver is multiple ISRs per clock tick.
*/
if ( !Clock_driver_isrs ) {
Clock_driver_timecounter_tick();
Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
}
Clock_driver_isrs--;
#else
/*
* The driver is one ISR per clock tick.
*/
Clock_driver_timecounter_tick();
#endif
#endif
}
#ifdef Clock_driver_support_shutdown_hardware
/**
* @brief Clock_exit
*
* This routine allows the clock driver to exit by masking the interrupt and
* disabling the clock's counter.
*/
void Clock_exit( void )
{
Clock_driver_support_shutdown_hardware();
/* do not restore old vector */
}
#endif
/**
* @brief Clock_initialize
*
* This routine initializes the clock driver.
*
* @param[in] major Clock device major number.
* @param[in] minor Clock device minor number.
* @param[in] parg Pointer to optional device driver arguments
*
* @retval rtems_device_driver status code
*/
rtems_device_driver Clock_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp
)
{
Clock_driver_ticks = 0;
/*
* Find timer -- some BSPs search buses for hardware timer
*/
Clock_driver_support_find_timer();
/*
* Install vector
*/
Clock_driver_support_install_isr( Clock_isr );
#ifdef RTEMS_SMP
Clock_driver_support_set_interrupt_affinity(
_SMP_Get_online_processors()
);
#endif
/*
* Now initialize the hardware that is the source of the tick ISR.
*/
Clock_driver_support_initialize_hardware();
#ifdef Clock_driver_support_shutdown_hardware
atexit( Clock_exit );
#endif
/*
* If we are counting ISRs per tick, then initialize the counter.
*/
#if CLOCK_DRIVER_ISRS_PER_TICK
Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK_VALUE;
#endif
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,131 @@
/*
* This routine initializes the Real Time Clock Counter Timer which is
* part of the MEC on the ERC32 CPU.
*
* The tick frequency is directly programmed to the configured number of
* microseconds per tick.
*/
/*
* COPYRIGHT (c) 1989-2008.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Ported to ERC32 implementation of the SPARC by On-Line Applications
* Research Corporation (OAR) under contract to the European Space
* Agency (ESA).
*
* ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995.
* European Space Agency.
*/
#include <bsp.h>
#include <bspopts.h>
#include <rtems/counter.h>
#include <rtems/timecounter.h>
#include <rtems/score/sparcimpl.h>
/*
* The Real Time Clock Counter Timer uses this trap type.
*/
#define CLOCK_VECTOR ERC32_TRAP_TYPE( ERC32_INTERRUPT_REAL_TIME_CLOCK )
#define Clock_driver_support_install_isr( _new ) \
set_vector( _new, CLOCK_VECTOR, 1 )
#define Clock_driver_support_set_interrupt_affinity( _online_processors ) \
do { \
(void) _online_processors; \
} while (0)
extern int CLOCK_SPEED;
static rtems_timecounter_simple erc32_tc;
static uint32_t erc32_tc_get( rtems_timecounter_simple *tc )
{
return ERC32_MEC.Real_Time_Clock_Counter;
}
static bool erc32_tc_is_pending( rtems_timecounter_simple *tc )
{
return ERC32_Is_interrupt_pending( ERC32_INTERRUPT_REAL_TIME_CLOCK );
}
static uint32_t erc32_tc_get_timecount( struct timecounter *tc )
{
return rtems_timecounter_simple_downcounter_get(
tc,
erc32_tc_get,
erc32_tc_is_pending
);
}
static void erc32_tc_at_tick( rtems_timecounter_simple *tc )
{
/* Nothing to do */
}
static void erc32_tc_tick( void )
{
rtems_timecounter_simple_downcounter_tick(
&erc32_tc,
erc32_tc_get,
erc32_tc_at_tick
);
}
static void erc32_counter_initialize( uint32_t frequency )
{
_SPARC_Counter_initialize(
_SPARC_Counter_read_address,
_SPARC_Counter_difference_clock_period,
&ERC32_MEC.Real_Time_Clock_Counter
);
rtems_counter_initialize_converter( frequency );
}
#define Clock_driver_support_initialize_hardware() \
do { \
uint32_t frequency = 1000000; \
/* approximately 1 us per countdown */ \
ERC32_MEC.Real_Time_Clock_Scalar = CLOCK_SPEED - 1; \
ERC32_MEC.Real_Time_Clock_Counter = \
rtems_configuration_get_microseconds_per_tick(); \
\
ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \
ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \
ERC32_MEC_TIMER_COUNTER_LOAD_SCALER | \
ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER \
); \
\
ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \
ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \
ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO \
); \
rtems_timecounter_simple_install( \
&erc32_tc, \
frequency, \
rtems_configuration_get_microseconds_per_tick(), \
erc32_tc_get_timecount \
); \
erc32_counter_initialize( frequency ); \
} while (0)
#define Clock_driver_timecounter_tick() erc32_tc_tick()
#define Clock_driver_support_shutdown_hardware() \
do { \
ERC32_Mask_interrupt( ERC32_INTERRUPT_REAL_TIME_CLOCK ); \
\
ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \
ERC32_MEC_TIMER_COUNTER_DISABLE_COUNTING \
); \
} while (0)
#include "../../../shared/dev/clock/clockimpl.h"
SPARC_COUNTER_DEFINITION;

View File

@@ -0,0 +1,104 @@
/**
* @file
* @ingroup sparc_leon2
* @brief Clock Tick Device Driver
*
* This routine initializes LEON timer 1 which used for the clock tick.
*
* The tick frequency is directly programmed to the configured number of
* microseconds per tick.
*/
/*
* COPYRIGHT (c) 1989-2008.
* On-Line Applications Research Corporation (OAR).
*
* Modified for LEON BSP
* COPYRIGHT (c) 2004.
* Gaisler Research.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <bspopts.h>
#include <rtems/timecounter.h>
#include <rtems/score/sparcimpl.h>
static rtems_timecounter_simple leon2_tc;
static uint32_t leon2_tc_get( rtems_timecounter_simple *tc )
{
return LEON_REG.Timer_Counter_1;
}
static bool leon2_tc_is_pending( rtems_timecounter_simple *tc )
{
return LEON_Is_interrupt_pending( LEON_INTERRUPT_TIMER1 );
}
static uint32_t leon2_tc_get_timecount( struct timecounter *tc )
{
return rtems_timecounter_simple_downcounter_get(
tc,
leon2_tc_get,
leon2_tc_is_pending
);
}
static void leon2_tc_at_tick( rtems_timecounter_simple *tc )
{
/* Nothing to do */
}
static void leon2_tc_tick( void )
{
rtems_timecounter_simple_downcounter_tick(
&leon2_tc,
leon2_tc_get,
leon2_tc_at_tick
);
}
/*
* The Real Time Clock Counter Timer uses this trap type.
*/
#define CLOCK_VECTOR LEON_TRAP_TYPE( LEON_INTERRUPT_TIMER1 )
#define Clock_driver_support_install_isr( _new ) \
set_vector( _new, CLOCK_VECTOR, 1 )
extern int CLOCK_SPEED;
#define Clock_driver_support_initialize_hardware() \
do { \
LEON_REG.Timer_Reload_1 = \
rtems_configuration_get_microseconds_per_tick() - 1; \
\
LEON_REG.Timer_Control_1 = ( \
LEON_REG_TIMER_COUNTER_ENABLE_COUNTING | \
LEON_REG_TIMER_COUNTER_RELOAD_AT_ZERO | \
LEON_REG_TIMER_COUNTER_LOAD_COUNTER \
); \
rtems_timecounter_simple_install( \
&leon2_tc, \
1000000, \
rtems_configuration_get_microseconds_per_tick(), \
leon2_tc_get_timecount \
); \
} while (0)
#define Clock_driver_support_shutdown_hardware() \
do { \
LEON_Mask_interrupt( LEON_INTERRUPT_TIMER1 ); \
LEON_REG.Timer_Control_1 = 0; \
} while (0)
#define Clock_driver_timecounter_tick() leon2_tc_tick()
#include "../../../shared/dev/clock/clockimpl.h"
SPARC_COUNTER_DEFINITION;

View File

@@ -0,0 +1,280 @@
/*
* Clock Tick Device Driver
*
* This routine initializes LEON timer 1 which used for the clock tick.
*
* The tick frequency is directly programmed to the configured number of
* microseconds per tick.
*
* COPYRIGHT (c) 1989-2006.
* On-Line Applications Research Corporation (OAR).
*
* Modified for LEON3 BSP.
* COPYRIGHT (c) 2004.
* Gaisler Research.
*
* Copyright (c) 2014, 2018 embedded brains GmbH
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <bspopts.h>
#include <bsp/fatal.h>
#include <rtems/rtems/intr.h>
#include <ambapp.h>
#include <rtems/score/profiling.h>
#include <rtems/timecounter.h>
/* The LEON3 BSP Timer driver can rely on the Driver Manager if the
* DrvMgr is initialized during startup. Otherwise the classic driver
* must be used.
*
* The DrvMgr Clock driver is located in the shared/timer directory
*/
#ifndef RTEMS_DRVMGR_STARTUP
/* LEON3 Timer system interrupt number */
static int clkirq;
static void (*leon3_tc_tick)(void);
static rtems_timecounter_simple leon3_tc;
#ifndef RTEMS_SMP
static uint32_t leon3_tc_get(rtems_timecounter_simple *tc)
{
return LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
}
static bool leon3_tc_is_pending(rtems_timecounter_simple *tc)
{
return LEON_Is_interrupt_pending(clkirq);
}
static void leon3_tc_at_tick( rtems_timecounter_simple *tc )
{
/* Nothing to do */
}
static uint32_t leon3_tc_get_timecount(struct timecounter *tc)
{
return rtems_timecounter_simple_downcounter_get(
tc,
leon3_tc_get,
leon3_tc_is_pending
);
}
static void leon3_tc_tick_simple(void)
{
rtems_timecounter_simple_downcounter_tick(
&leon3_tc,
leon3_tc_get,
leon3_tc_at_tick
);
}
#endif
static uint32_t leon3_tc_get_timecount_up_counter(struct timecounter *tc)
{
return leon3_up_counter_low();
}
static uint32_t leon3_tc_get_timecount_irqmp(struct timecounter *tc)
{
return LEON3_IrqCtrl_Regs->timestamp[0].counter;
}
#ifdef RTEMS_SMP
static uint32_t leon3_tc_get_timecount_second_timer(struct timecounter *tc)
{
return 0xffffffff - LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX + 1].value;
}
#endif
#ifdef RTEMS_PROFILING
#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
static void leon3_tc_tick_irqmp_timestamp(void)
{
volatile struct irqmp_timestamp_regs *irqmp_ts =
&LEON3_IrqCtrl_Regs->timestamp[0];
unsigned int first = irqmp_ts->assertion;
unsigned int second = irqmp_ts->counter;
irqmp_ts->control |= IRQMP_TIMESTAMP_S1_S2;
_Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first);
rtems_timecounter_tick();
}
#endif
static void leon3_tc_tick_irqmp_timestamp_init(void)
{
#ifdef RTEMS_PROFILING
/*
* Ignore the first clock interrupt, since it contains the sequential system
* initialization time. Do the timestamp initialization on the fly.
*/
#ifdef RTEMS_SMP
static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0);
bool done =
_Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED)
== rtems_get_processor_count() - 1;
#else
bool done = true;
#endif
volatile struct irqmp_timestamp_regs *irqmp_ts =
&LEON3_IrqCtrl_Regs->timestamp[0];
unsigned int ks = 1U << 5;
irqmp_ts->control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq;
if (done) {
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp;
}
#endif
rtems_timecounter_tick();
}
#ifdef RTEMS_SMP
static void leon3_tc_tick_second_timer(void)
{
rtems_timecounter_tick();
}
#endif
static void leon3_tc_do_tick(void)
{
(*leon3_tc_tick)();
}
#define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
#define Clock_driver_support_find_timer() \
do { \
/* Assume timer found during BSP initialization */ \
if (LEON3_Timer_Regs) { \
clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \
\
Adjust_clkirq_for_node(); \
} \
} while (0)
#define Clock_driver_support_install_isr( _new ) \
bsp_clock_handler_install(_new)
static void bsp_clock_handler_install(rtems_isr *new)
{
rtems_status_code sc;
sc = rtems_interrupt_handler_install(
clkirq,
"Clock",
RTEMS_INTERRUPT_UNIQUE,
new,
NULL
);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION);
}
}
#define Clock_driver_support_set_interrupt_affinity(online_processors) \
bsp_interrupt_set_affinity(clkirq, online_processors)
static void leon3_clock_initialize(void)
{
volatile struct irqmp_timestamp_regs *irqmp_ts;
volatile struct gptimer_regs *gpt;
irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
gpt = LEON3_Timer_Regs;
gpt->timer[LEON3_CLOCK_INDEX].reload =
rtems_configuration_get_microseconds_per_tick() - 1;
gpt->timer[LEON3_CLOCK_INDEX].ctrl =
GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS |
GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE;
leon3_up_counter_enable();
if (leon3_up_counter_is_available()) {
/* Use the LEON4 up-counter if available */
leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_up_counter;
leon3_tc.tc.tc_counter_mask = 0xffffffff;
leon3_tc.tc.tc_frequency = leon3_up_counter_frequency();
leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
#ifdef RTEMS_PROFILING
if (!leon3_irqmp_has_timestamp(irqmp_ts)) {
bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
}
#endif
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
rtems_timecounter_install(&leon3_tc.tc);
} else if (leon3_irqmp_has_timestamp(irqmp_ts)) {
/* Use the interrupt controller timestamp counter if available */
leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_irqmp;
leon3_tc.tc.tc_counter_mask = 0xffffffff;
leon3_tc.tc.tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
/*
* At least one TSISEL field must be non-zero to enable the timestamp
* counter. Use an arbitrary interrupt source.
*/
irqmp_ts->control = 0x1;
rtems_timecounter_install(&leon3_tc.tc);
} else {
#ifdef RTEMS_SMP
/*
* The GR712RC for example has no timestamp unit in the interrupt
* controller. At least on SMP configurations we must use a second timer
* in free running mode for the timecounter.
*/
gpt->timer[LEON3_CLOCK_INDEX + 1].ctrl =
GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_IE;
leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_second_timer;
leon3_tc.tc.tc_counter_mask = 0xffffffff;
leon3_tc.tc.tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER;
leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
leon3_tc_tick = leon3_tc_tick_second_timer;
rtems_timecounter_install(&leon3_tc.tc);
#else
leon3_tc_tick = leon3_tc_tick_simple;
rtems_timecounter_simple_install(
&leon3_tc,
LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
rtems_configuration_get_microseconds_per_tick(),
leon3_tc_get_timecount
);
#endif
}
}
#define Clock_driver_support_initialize_hardware() \
leon3_clock_initialize()
#define Clock_driver_support_shutdown_hardware() \
do { \
LEON_Mask_interrupt(LEON_TRAP_TYPE(clkirq)); \
LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = 0; \
} while (0)
#define Clock_driver_timecounter_tick() leon3_tc_do_tick()
#include "../../../shared/dev/clock/clockimpl.h"
#endif

View File

@@ -0,0 +1,122 @@
/* ckinit.c
*
* This file provides a template for the clock device driver initialization.
*
* Modified for sun4v - niagara
*/
/*
* Copyright (c) 2010 Gedare Bloom.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <stdlib.h>
#include <rtems.h>
#include <bsp.h>
#include <bspopts.h>
#include <boot/ofw.h>
#include <rtems/bspIo.h>
/* This is default frequency for simics simulator of niagara. Use the
* get_Frequency function to determine the CPU clock frequency at runtime.
*/
#define CPU_FREQ (5000000)
uint64_t sparc64_cycles_per_tick;
/* TICK_CMPR and STICK_CMPR trigger soft interrupt 14 */
#define CLOCK_VECTOR SPARC_SYNCHRONOUS_TRAP(0x4E)
static unsigned int get_Frequency(void)
{
phandle root = ofw_find_device("/");
unsigned int freq;
if (ofw_get_property(root, "clock-frequency", &freq, sizeof(freq)) <= 0) {
printk("Unable to determine frequency, default: 0x%x\n",CPU_FREQ);
return CPU_FREQ;
}
return freq;
}
#define Clock_driver_support_at_tick() \
Clock_driver_support_at_tick_helper()
static void Clock_driver_support_at_tick_helper(void)
{
uint64_t tick_reg;
int bit_mask;
uint64_t pil_reg;
bit_mask = SPARC_SOFTINT_TM_MASK | SPARC_SOFTINT_SM_MASK | (1<<14);
sparc64_clear_interrupt_bits(bit_mask);
sparc64_get_pil(pil_reg);
if(pil_reg == 0xe) { /* 0xe is the tick compare interrupt (softint(14)) */
pil_reg--;
sparc64_set_pil(pil_reg); /* enable the next timer interrupt */
}
/* Note: sun4v uses stick_cmpr for clock driver for M5 simulator, which
* does not currently have tick_cmpr implemented */
/* TODO: this could be more efficiently implemented as a single assembly
* inline */
#if defined (SUN4U)
sparc64_read_tick(tick_reg);
#elif defined (SUN4V)
sparc64_read_stick(tick_reg);
#endif
tick_reg &= ~(1UL<<63); /* mask out NPT bit, prevents int_dis from being set */
tick_reg += sparc64_cycles_per_tick;
#if defined (SUN4U)
sparc64_write_tick_cmpr(tick_reg);
#elif defined (SUN4V)
sparc64_write_stick_cmpr(tick_reg);
#endif
}
#define Clock_driver_support_install_isr(_new) \
set_vector( _new, CLOCK_VECTOR, 1 )
static void Clock_driver_support_initialize_hardware(void)
{
uint64_t tick_reg;
int bit_mask;
bit_mask = SPARC_SOFTINT_TM_MASK | SPARC_SOFTINT_SM_MASK | (1<<14);
sparc64_clear_interrupt_bits(bit_mask);
sparc64_cycles_per_tick =
rtems_configuration_get_microseconds_per_tick()*(get_Frequency()/1000000);
#if defined (SUN4U)
sparc64_read_tick(tick_reg);
#elif defined (SUN4V)
sparc64_read_stick(tick_reg);
#endif
tick_reg &= ~(1UL<<63); /* mask out NPT bit, prevents int_dis from being set */
tick_reg += sparc64_cycles_per_tick;
#if defined (SUN4U)
sparc64_write_tick_cmpr(tick_reg);
#elif defined (SUN4V)
sparc64_write_stick_cmpr(tick_reg);
#endif
}
#define Clock_driver_support_shutdown_hardware( ) \
do { \
\
} while ( 0 )
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
#include "../../../shared/dev/clock/clockimpl.h"