summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/sparc/Makefile.am6
-rw-r--r--c/src/lib/libbsp/sparc/leon2/Makefile.am6
-rw-r--r--c/src/lib/libbsp/sparc/leon2/include/bsp.h1
-rw-r--r--c/src/lib/libbsp/sparc/leon2/preinstall.am4
-rw-r--r--c/src/lib/libbsp/sparc/leon3/Makefile.am14
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/bsp.h1
-rw-r--r--c/src/lib/libbsp/sparc/leon3/preinstall.am4
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h3
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/tlib.h169
-rw-r--r--c/src/lib/libbsp/sparc/shared/timer/gptimer.c503
-rw-r--r--c/src/lib/libbsp/sparc/shared/timer/tlib.c77
-rw-r--r--c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c264
12 files changed, 1049 insertions, 3 deletions
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am
index 59a212c624..67b62ca585 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -28,6 +28,12 @@ EXTRA_DIST += shared/amba/ambapp_names.c
EXTRA_DIST += shared/amba/ambapp_old.c
EXTRA_DIST += shared/amba/ambapp_show.c
+# Clock Driver and Timer Library
+EXTRA_DIST += shared/include/tlib.h
+EXTRA_DIST += shared/timer/gptimer.c
+EXTRA_DIST += shared/timer/tlib.c
+EXTRA_DIST += shared/timer/tlib_ckinit.c
+
# PCI bus
EXTRA_DIST += shared/include/pci.h
EXTRA_DIST += shared/pci/pcifinddevice.c
diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am
index bb30517dd0..e9dcfd8e75 100644
--- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
@@ -102,6 +102,12 @@ libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_parent.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
+
+# Clock Driver and Timer Library
+include_HEADERS += ../../sparc/shared/include/tlib.h
+libbsp_a_SOURCES += ../../sparc/shared/timer/gptimer.c
+libbsp_a_SOURCES += ../../sparc/shared/timer/tlib.c
+
# PCI
libbsp_a_SOURCES += pci/pci.c ../../sparc/shared/pci/pcifinddevice.c
# RASTA Kit
diff --git a/c/src/lib/libbsp/sparc/leon2/include/bsp.h b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
index dce8bea661..d669d8910e 100644
--- a/c/src/lib/libbsp/sparc/leon2/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
@@ -226,6 +226,7 @@ int cchip1_register(void);
* image bigger.
*/
#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
+#define GPTIMER_INFO_AVAIL /* GPTIMER Timer driver */
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/leon2/preinstall.am b/c/src/lib/libbsp/sparc/leon2/preinstall.am
index 7260f63767..10a0bbcd1f 100644
--- a/c/src/lib/libbsp/sparc/leon2/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon2/preinstall.am
@@ -169,6 +169,10 @@ $(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grlib.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/grlib.h
+$(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
+
$(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index 6e6f04d2ef..f57b24591b 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -66,14 +66,22 @@ libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_parent.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
+
+# Clock Driver and Timer Library
+include_HEADERS += ../../sparc/shared/include/tlib.h
+libbsp_a_SOURCES += ../../sparc/shared/timer/gptimer.c
+libbsp_a_SOURCES += ../../sparc/shared/timer/tlib.c
+libbsp_a_SOURCES += ../../sparc/shared/timer/tlib_ckinit.c
+# non-Driver Manager Clock Implementation
+libbsp_a_SOURCES += clock/ckinit.c
+libbsp_a_SOURCES += ../../shared/clockdrv_shell.h
+
# console
libbsp_a_SOURCES += ../../shared/console-termios.c
libbsp_a_SOURCES += console/console.c
# debugio
libbsp_a_SOURCES += console/printk_support.c
-# clock
-libbsp_a_SOURCES += clock/ckinit.c
-libbsp_a_SOURCES += ../../shared/clockdrv_shell.h
+
# IRQ
include_bsp_HEADERS += \
../../shared/include/irq-generic.h \
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp.h b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
index 9239d2bc9b..37dfedb1e9 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
@@ -255,6 +255,7 @@ extern const unsigned char LEON3_irq_to_cpu[32];
* image bigger.
*/
#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
+#define GPTIMER_INFO_AVAIL /* GPTIMER Timer driver */
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index 32525609c6..99c8b22604 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -105,6 +105,10 @@ $(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grlib.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/grlib.h
+$(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
+
$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
index a1a47b1698..23e8cbd3a9 100644
--- a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
@@ -27,6 +27,9 @@ extern "C" {
#define DRIVER_AMBAPP_ID(vendor, device) \
DRIVER_ID(DRVMGR_BUS_TYPE_AMBAPP, ((((vendor) & 0xff) << 16) | ((device) & 0xfff)))
+/*** Gaisler Hardware Device Driver IDs ***/
+#define DRIVER_AMBAPP_GAISLER_GPTIMER_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPTIMER)
+
struct amba_dev_id {
unsigned short vendor;
unsigned short device;
diff --git a/c/src/lib/libbsp/sparc/shared/include/tlib.h b/c/src/lib/libbsp/sparc/shared/include/tlib.h
new file mode 100644
index 0000000000..75ca6997f5
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/tlib.h
@@ -0,0 +1,169 @@
+/*
+ * Timer Library (TLIB)
+ *
+ * The Library rely on timer drivers, the timer presented by the
+ * timer driver must look like a down-counter timer, which generates
+ * interrupt (if configured) when underflown.
+ *
+ * If Timer hardware is an up-counter the Timer driver must recalculate
+ * into values that would match as if it was a down-counter.
+ *
+ * COPYRIGHT (c) 2011.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+struct tlib_dev;
+
+typedef void (*tlib_isr_t)(void *data);
+
+struct tlib_drv {
+ /*** Functions ***/
+ void (*reset)(struct tlib_dev *hand);
+ void (*get_freq)(
+ struct tlib_dev *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate);
+ int (*set_freq)(struct tlib_dev *hand, unsigned int tickrate);
+ void (*irq_reg)(struct tlib_dev *hand, tlib_isr_t func, void *data);
+ void (*irq_unreg)(struct tlib_dev *hand, tlib_isr_t func,void *data);
+ void (*start)(struct tlib_dev *hand, int once);
+ void (*stop)(struct tlib_dev *hand);
+ void (*restart)(struct tlib_dev *hand);
+ void (*get_counter)(struct tlib_dev *hand, unsigned int *counter);
+ int (*custom)(struct tlib_dev *hand, int cmd, void *arg);
+};
+
+struct tlib_dev {
+ struct tlib_dev *next;
+ char status; /* 0=closed, 1=open, 2=timer started */
+ char index; /* Timer Index */
+ tlib_isr_t isr_func;
+ void *isr_data;
+ struct tlib_drv *drv;
+};
+
+#ifdef RTEMS_DRVMGR_STARTUP
+/* Clock Driver Timer register function. Only used when the TLIB-Clock
+ * driver is used. A specific Timer is registered as the System Clock
+ * timer.
+ */
+extern void Clock_timer_register(int timer_number);
+#endif
+
+/* Register Timer. Called by Timer Drivers in order to register
+ * a Timer to the Timer Library. The registration order determines
+ * the Timer Number used in tlib_open() to identify a specific
+ * Timer.
+ */
+extern int tlib_dev_reg(struct tlib_dev *newdev);
+
+/* Allocate a Timer.
+ *
+ * A Timer handle is returned identifying the timer in later calls.
+ */
+extern void *tlib_open(int timer_no);
+
+/* Close Timer */
+extern void tlib_close(void *hand);
+
+/* Returns Number of Timers currently registered to Timer Library */
+extern int tlib_ntimer(void);
+
+static inline void tlib_reset(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->reset(dev);
+}
+/* Get Frequencies:
+ * - Base Frequency (unchangable base freq rate of timer, prescaler, clkinput)
+ * - Current Tick Rate [in multiples of Base Frequency]
+ */
+static inline void tlib_get_freq(
+ void *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->get_freq(dev, basefreq, tickrate);
+}
+
+/* Set current Tick Rate in number of "Base-Frequency ticks" */
+static inline int tlib_set_freq(void *hand, unsigned int tickrate)
+{
+ struct tlib_dev *dev = hand;
+
+ return dev->drv->set_freq(dev, tickrate);
+}
+
+/* Register ISR at Timer ISR */
+static inline void tlib_irq_unregister(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ if ( dev->isr_func ) {
+ dev->drv->irq_unreg(dev, dev->isr_func, dev->isr_data);
+ dev->isr_func = NULL;
+ }
+}
+
+/* Register ISR at Timer ISR */
+static inline void tlib_irq_register(void *hand, tlib_isr_t func, void *data)
+{
+ struct tlib_dev *dev = hand;
+
+ /* Unregister previous ISR if installed */
+ tlib_irq_unregister(hand);
+ dev->isr_func = func;
+ dev->isr_data = data;
+ dev->drv->irq_reg(dev, func, data);
+}
+
+/* Start Timer, ISRs will be generated if enabled.
+ *
+ * once determines if timer should restart (=0) on underflow automatically,
+ * or stop when underflow is reached (=1).
+ */
+static inline void tlib_start(void *hand, int once)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->start(dev, once);
+}
+
+/* Stop Timer, no more ISRs will be generated */
+static inline void tlib_stop(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->stop(dev);
+}
+
+/* Restart/Reload Timer, may be usefull if a Watchdog Timer */
+static inline void tlib_restart(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->restart(dev);
+}
+
+/* Get current counter value (since last tick) */
+static inline void tlib_get_counter(void *hand, unsigned int *counter)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->get_counter(dev, counter);
+}
+
+/* Do a custom operation */
+static inline void tlib_custom(void *hand, int cmd, void *arg)
+{
+ struct tlib_dev *dev = hand;
+
+ dev->drv->custom(dev, cmd, arg);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/timer/gptimer.c b/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
new file mode 100644
index 0000000000..b15aaf1673
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
@@ -0,0 +1,503 @@
+/* This file contains the driver for the GRLIB GPTIMER timers port. The driver
+ * is implemented by using the tlib.c simple timer layer and the Driver
+ * Manager.
+ *
+ * The Driver can be configured using driver resources:
+ *
+ * - timerStart Timer Index if first Timer, this parameters is typically used
+ * in AMP systems for resource allocation. The Timers before
+ * timerStart will not be accessed.
+ * - timerCnt Number of timers that the driver will use, this parameters is
+ * typically used in AMP systems for resource allocation between
+ * OS instances.
+ * - prescaler Base prescaler, normally set by bootloader but can be
+ * overridden. The default scaler reload value set by bootloader
+ * is so that Timers operate in 1MHz. Setting the prescaler to a
+ * lower value increase the accuracy of the timers but shortens
+ * the time until underflow happens.
+ * - clockTimer Used to select a particular timer to be the system clock
+ * timer. This is useful when multiple GPTIMERs cores are
+ * available, or in AMP systems. By default the TLIB selects the
+ * first timer registered as system clock timer.
+ *
+ * The BSP define APBUART_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <stdlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grlib.h>
+#include "tlib.h"
+
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+#include <leon.h>
+volatile struct gptimer_regs *LEON3_Timer_Regs = 0;
+#endif
+
+#ifdef GPTIMER_INFO_AVAIL
+#include <stdio.h>
+#endif
+
+/* GPTIMER Core Configuration Register (READ-ONLY) */
+#define GPTIMER_CFG_TIMERS_BIT 0
+#define GPTIMER_CFG_IRQ_BIT 3
+#define GPTIMER_CFG_SI_BIT 8
+#define GPTIMER_CFG_DF_BIT 9
+
+#define GPTIMER_CFG_TIMERS (0x7<<GPTIMER_CFG_TIMERS_BIT)
+#define GPTIMER_CFG_IRQ (0x1f<<GPTIMER_CFG_IRQ_BIT)
+#define GPTIMER_CFG_SI (1<<GPTIMER_CFG_SI_BIT)
+#define GPTIMER_CFG_DF (1<<GPTIMER_CFG_DF_BIT)
+
+/* GPTIMER Timer Control Register */
+#define GPTIMER_CTRL_EN_BIT 0
+#define GPTIMER_CTRL_RS_BIT 1
+#define GPTIMER_CTRL_LD_BIT 2
+#define GPTIMER_CTRL_IE_BIT 3
+#define GPTIMER_CTRL_IP_BIT 4
+#define GPTIMER_CTRL_CH_BIT 5
+#define GPTIMER_CTRL_DH_BIT 6
+
+#define GPTIMER_CTRL_EN (1<<GPTIMER_CTRL_EN_BIT)
+#define GPTIMER_CTRL_RS (1<<GPTIMER_CTRL_RS_BIT)
+#define GPTIMER_CTRL_LD (1<<GPTIMER_CTRL_LD_BIT)
+#define GPTIMER_CTRL_IE (1<<GPTIMER_CTRL_IE_BIT)
+#define GPTIMER_CTRL_IP (1<<GPTIMER_CTRL_IP_BIT)
+#define GPTIMER_CTRL_CH (1<<GPTIMER_CTRL_CH_BIT)
+#define GPTIMER_CTRL_DH (1<<GPTIMER_CTRL_DH_BIT)
+
+#define DBG(x...)
+
+/* GPTIMER timer private */
+struct gptimer_timer {
+ struct tlib_dev tdev; /* Must be first in struct */
+ struct gptimer_timer_regs *tregs;
+ char index; /* Timer Index in this driver */
+ char tindex; /* Timer Index In Hardware */
+};
+
+/* GPTIMER Core private */
+struct gptimer_priv {
+ struct drvmgr_dev *dev;
+ struct gptimer_regs *regs;
+ unsigned int base_clk;
+ unsigned int base_freq;
+ int separate_interrupt;
+
+ /* Structure per Timer unit, the core supports up to 8 timers */
+ int timer_cnt;
+ struct gptimer_timer timers[0];
+};
+
+void gptimer_isr(void *data);
+
+#if 0
+void gptimer_tlib_irq_register(struct tlib_drv *tdrv, tlib_isr_t func, void *data)
+{
+ struct gptimer_priv *priv = (struct gptimer_priv *)tdrv;
+
+ if ( SHARED ...)
+
+
+ drvmgr_interrupt_register();
+}
+#endif
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+struct tlib_drv gptimer_tlib_drv;
+int gptimer_device_init(struct gptimer_priv *priv);
+
+int gptimer_init1(struct drvmgr_dev *dev);
+#ifdef GPTIMER_INFO_AVAIL
+static int gptimer_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int, char *argv[]);
+#define GTIMER_INFO_FUNC gptimer_info
+#else
+#define GTIMER_INFO_FUNC NULL
+#endif
+
+struct drvmgr_drv_ops gptimer_ops =
+{
+ .init = {gptimer_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = GTIMER_INFO_FUNC,
+};
+
+struct amba_dev_id gptimer_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GPTIMER},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gptimer_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GPTIMER_ID,/* Driver ID */
+ "GPTIMER_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gptimer_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gptimer_ids[0]
+};
+
+void gptimer_register_drv (void)
+{
+ DBG("Registering GPTIMER driver\n");
+ drvmgr_drv_register(&gptimer_drv_info.general);
+}
+
+int gptimer_init1(struct drvmgr_dev *dev)
+{
+ struct gptimer_priv *priv;
+ struct gptimer_regs *regs;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int timer_hw_cnt, timer_cnt, timer_start;
+ int i, size;
+ struct gptimer_timer *timer;
+ union drvmgr_key_value *value;
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ char timer_index[7];
+#endif
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gptimer_regs *)pnpinfo->apb_slv->start;
+
+ DBG("GPTIMER[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ /* Get number of Timers */
+ timer_hw_cnt = regs->cfg & GPTIMER_CFG_TIMERS;
+
+ /* Let user spelect a range of timers to be used. In AMP systems
+ * it is sometimes neccessary to leave timers for other CPU instances.
+ *
+ * The default operation in AMP is to shared the timers within the
+ * first GPTIMER core as below. This can of course be overrided by
+ * driver resources.
+ */
+ timer_cnt = timer_hw_cnt;
+ timer_start = 0;
+#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
+ if ((dev->minor_drv == 0) && drvmgr_on_rootbus(dev)) {
+ timer_cnt = 1;
+ timer_start = LEON3_Cpu_Index;
+ }
+#endif
+ value = drvmgr_dev_key_get(dev, "timerStart", KEY_TYPE_INT);
+ if ( value) {
+ timer_start = value->i;
+ timer_cnt = timer_hw_cnt - timer_start;
+ }
+ value = drvmgr_dev_key_get(dev, "timerCnt", KEY_TYPE_INT);
+ if ( value && (value->i < timer_cnt) ) {
+ timer_cnt = value->i;
+ }
+
+ /* Allocate Common Timer Description, size depends on how many timers
+ * are present.
+ */
+ size = sizeof(struct gptimer_priv) +
+ timer_cnt*sizeof(struct gptimer_timer);
+ priv = dev->priv = (struct gptimer_priv *)malloc(size);
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, size);
+ priv->dev = dev;
+ priv->regs = regs;
+
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ if ( drvmgr_on_rootbus(priv->dev) && !LEON3_Timer_Regs) {
+ /* Bootloader has initialized the Timer prescaler to 1MHz,
+ * this means that the AMBA Frequency is 1MHz * PRESCALER.
+ */
+ priv->base_clk = (regs->scaler_reload + 1) * 1000000;
+ ambapp_bus_freq_register(priv->dev,DEV_APB_SLV,priv->base_clk);
+ LEON3_Timer_Regs = (void *)regs;
+ } else
+#endif
+ {
+ /* The Base Frequency of the GPTIMER core is the same as the
+ * frequency of the AMBA bus it is situated on.
+ */
+ drvmgr_freq_get(dev, DEV_APB_SLV, &priv->base_clk);
+ }
+
+ /* This core will may provide important Timer functionality
+ * to other drivers and the RTEMS kernel, the Clock driver
+ * may for example use this device. So the Timer driver must be
+ * initialized in the first iiitialization stage.
+ */
+
+ /*** Initialize Hardware ***/
+
+ /* If user request to set prescaler, we will do that. However, note
+ * that doing so for the Root-Bus GPTIMER may affect the RTEMS Clock
+ * so that Clock frequency is wrong.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "prescaler", KEY_TYPE_INT);
+ if ( value )
+ regs->scaler_reload = value->i;
+
+ /* Get Frequency that the timers are operating in (after prescaler) */
+ priv->base_freq = priv->base_clk / (priv->regs->scaler_reload + 1);
+
+ priv->timer_cnt = timer_cnt;
+ for (i=0; i<timer_cnt; i++) {
+ timer = &priv->timers[i];
+ timer->index = i;
+ timer->tindex = i + timer_start;
+ timer->tregs = &regs->timer[(int)timer->tindex];
+ timer->tdev.drv = &gptimer_tlib_drv;
+
+ /* Stop Timer */
+ timer->tregs->ctrl = 0;
+
+ /* Register Timer at Timer Library */
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ timer_index[i] =
+#endif
+ tlib_dev_reg(&timer->tdev);
+ }
+
+ /* Check Interrupt support implementation, two cases:
+ * A. All Timers share one IRQ
+ * B. Each Timer have an individual IRQ. The number is:
+ * BASE_IRQ + timer_index
+ */
+ priv->separate_interrupt = regs->cfg & GPTIMER_CFG_SI;
+
+ if ( priv->separate_interrupt == 0 ) {
+ /* Shared IRQ handler */
+ drvmgr_interrupt_register(
+ priv->dev,
+ 0,
+ "gptimer_shared",
+ gptimer_isr,
+ priv);
+ }
+
+ /* If the user request a certain Timer to be the RTEMS Clock Timer,
+ * the timer must be registered at the Clock Driver.
+ */
+#if defined(LEON3) && defined(RTEMS_DRVMGR_STARTUP)
+ value = drvmgr_dev_key_get(priv->dev, "clockTimer", KEY_TYPE_INT);
+ if ( value && (value->i < timer_cnt) ) {
+ LEON3_Timer_Regs = (void *)regs;
+ Clock_timer_register(timer_index[value->i]);
+ }
+#endif
+
+ return DRVMGR_OK;
+}
+
+#ifdef GPTIMER_INFO_AVAIL
+static int gptimer_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct gptimer_priv *priv = dev->priv;
+ struct gptimer_timer *timer;
+ char buf[64];
+ int i;
+
+ if (priv == NULL || argc != 0)
+ return -DRVMGR_EINVAL;
+
+ sprintf(buf, "Timer Count: %d", priv->timer_cnt);
+ print_line(p, buf);
+ sprintf(buf, "REGS: 0x%08x", (unsigned int)priv->regs);
+ print_line(p, buf);
+ sprintf(buf, "BASE SCALER: %d", priv->regs->scaler_reload);
+ print_line(p, buf);
+ sprintf(buf, "BASE FREQ: %dkHz", priv->base_freq / 1000);
+ print_line(p, buf);
+ sprintf(buf, "SeparateIRQ: %s", priv->separate_interrupt ? "YES":"NO");
+ print_line(p, buf);
+
+ for (i=0; i<priv->timer_cnt; i++) {
+ timer = &priv->timers[i];
+ sprintf(buf, " - TIMER HW Index %d -", timer->tindex);
+ print_line(p, buf);
+ sprintf(buf, " TLIB Index: %d", timer->index);
+ print_line(p, buf);
+ sprintf(buf, " RELOAD REG: %d", timer->tregs->reload);
+ print_line(p, buf);
+ sprintf(buf, " CTRL REG: %d", timer->tregs->ctrl);
+ print_line(p, buf);
+ }
+
+ return DRVMGR_OK;
+}
+#endif
+
+static inline struct gptimer_priv *priv_from_timer(struct gptimer_timer *t)
+{
+ return (struct gptimer_priv *)
+ ((unsigned int)t -
+ sizeof(struct gptimer_priv) -
+ t->index * sizeof(struct gptimer_timer));
+}
+
+void gptimer_isr(void *data)
+{
+ struct gptimer_priv *priv = data;
+ struct gptimer_timer_regs *tregs;
+ int i;
+ unsigned int ctrl;
+
+ /* Check all timers for IRQ */
+ for (i=0;i<priv->timer_cnt; i++) {
+ tregs = priv->timers[i].tregs;
+ ctrl = tregs->ctrl;
+ if ( ctrl & GPTIMER_CTRL_IP ) {
+ /* IRQ Was generated by Timer, Clear Pending flag
+ * call ISR registered
+ */
+ tregs->ctrl = ctrl | GPTIMER_CTRL_IP;
+ if ( priv->timers[i].tdev.isr_func ) {
+ priv->timers[i].tdev.isr_func(
+ priv->timers[i].tdev.isr_data);
+ }
+ }
+ }
+}
+
+void gptimer_tlib_reset(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->ctrl = 0;
+ timer->tregs->reload = 0xffffffff;
+ timer->tregs->ctrl = GPTIMER_CTRL_LD;
+}
+
+void gptimer_tlib_get_freq(
+ struct tlib_dev *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ /* Calculate base frequency from Timer Clock and Prescaler */
+ if ( basefreq )
+ *basefreq = priv->base_freq;
+ if ( tickrate )
+ *tickrate = timer->tregs->reload + 1;
+}
+
+int gptimer_tlib_set_freq(struct tlib_dev *hand, unsigned int tickrate)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->reload = tickrate - 1;
+
+ /*Check that value was allowed (Timer may not be as wide as expected)*/
+ if ( timer->tregs->reload != (tickrate - 1) )
+ return -1;
+ else
+ return 0;
+}
+
+void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *data)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ if ( priv->separate_interrupt ) {
+ drvmgr_interrupt_register(priv->dev, timer->tindex,
+ "gptimer", func, data);
+ }
+
+ timer->tregs->ctrl |= GPTIMER_CTRL_IE;
+}
+
+void gptimer_tlib_irq_unreg(struct tlib_dev *hand, tlib_isr_t func, void *data)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ /* Turn off IRQ at source, unregister IRQ handler */
+ timer->tregs->ctrl &= ~GPTIMER_CTRL_IE;
+
+ if ( priv->separate_interrupt ) {
+ drvmgr_interrupt_unregister(priv->dev, timer->tindex,
+ func, data);
+ } else {
+ timer->tdev.isr_func = NULL;
+ }
+}
+
+void gptimer_tlib_start(struct tlib_dev *hand, int once)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ unsigned int ctrl;
+
+ /* Load the selected frequency before starting Frequency */
+ ctrl = GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
+ if ( once == 0 )
+ ctrl |= GPTIMER_CTRL_RS; /* Restart Timer */
+ timer->tregs->ctrl |= ctrl;
+}
+
+void gptimer_tlib_stop(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ /* Load the selected Frequency */
+ timer->tregs->ctrl &= ~(GPTIMER_CTRL_EN|GPTIMER_CTRL_IP);
+}
+
+void gptimer_tlib_restart(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->ctrl |= GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
+}
+
+void gptimer_tlib_get_counter(struct tlib_dev *hand, unsigned int *counter)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ *counter = timer->tregs->value;
+}
+
+struct tlib_drv gptimer_tlib_drv =
+{
+ .reset = gptimer_tlib_reset,
+ .get_freq = gptimer_tlib_get_freq,
+ .set_freq = gptimer_tlib_set_freq,
+ .irq_reg = gptimer_tlib_irq_reg,
+ .irq_unreg = gptimer_tlib_irq_unreg,
+ .start = gptimer_tlib_start,
+ .stop = gptimer_tlib_stop,
+ .restart = gptimer_tlib_restart,
+ .get_counter = gptimer_tlib_get_counter,
+ .custom = NULL,
+};
diff --git a/c/src/lib/libbsp/sparc/shared/timer/tlib.c b/c/src/lib/libbsp/sparc/shared/timer/tlib.c
new file mode 100644
index 0000000000..d1f68eded2
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/timer/tlib.c
@@ -0,0 +1,77 @@
+/*
+ * Timer Library (TLIB)
+ *
+ * COPYRIGHT (c) 2011.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <tlib.h>
+
+struct tlib_dev *tlib_dev_head = NULL;
+struct tlib_dev *tlib_dev_tail = NULL;
+static int tlib_dev_cnt = 0;
+
+/* Register Timer device to Timer Library */
+int tlib_dev_reg(struct tlib_dev *newdev)
+{
+ /* Reset device */
+ newdev->status = 0;
+ newdev->isr_func = NULL;
+ newdev->index = tlib_dev_cnt;
+
+ /* Insert last in queue */
+ newdev->next = NULL;
+ if ( tlib_dev_tail == NULL ) {
+ tlib_dev_head = newdev;
+ } else {
+ tlib_dev_tail->next = newdev;
+ }
+ tlib_dev_tail = newdev;
+
+ /* Return Index of Registered Timer */
+ return tlib_dev_cnt++;
+}
+
+void *tlib_open(int timer_no)
+{
+ struct tlib_dev *dev;
+
+ if ( timer_no < 0 )
+ return NULL;
+
+ dev = tlib_dev_head;
+ while ( (timer_no > 0) && dev ) {
+ timer_no--;
+ dev = dev->next;
+ }
+ if ( dev ) {
+ if ( dev->status )
+ return NULL;
+ dev->status = 1;
+ /* Reset Timer to initial state */
+ tlib_reset(dev);
+ }
+ return dev;
+}
+
+void tlib_close(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ /* Stop any ongoing timer operation and unregister IRQ if registered */
+ tlib_stop(dev);
+ tlib_irq_unregister(dev);
+
+ /* Mark not open */
+ dev->status = 0;
+}
+
+int tlib_ntimer(void)
+{
+ return tlib_dev_cnt;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c b/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
new file mode 100644
index 0000000000..5758f5bf0d
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
@@ -0,0 +1,264 @@
+/*
+ * Clock Tick Device Driver using Timer Library implemented
+ * by the GRLIB GPTIMER / LEON2 Timer drivers.
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ */
+
+#include <stdlib.h>
+#include <bsp.h>
+#include <tlib.h>
+
+/* Undefine (default) this to save space in standard LEON configurations,
+ * it will assume that Prescaler is running at 1MHz.
+ */
+/*#undef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ*/
+
+/* Set the below defines from bsp.h if function needed.
+#undef CLOCK_DRIVER_ISRS_PER_TICK
+#undef CLOCK_DRIVER_USE_FAST_IDLE
+*/
+#define Clock_driver_support_at_tick()
+
+/*
+ * Number of Clock ticks since initialization
+ */
+volatile uint32_t Clock_driver_ticks;
+
+/*
+ * Timer Number in Timer Library. Defaults to the first Timer in
+ * the System.
+ */
+int Clock_timer = 0;
+
+/*
+ * Timer Handle in Timer Library
+ */
+void *Clock_handle = NULL;
+
+#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+unsigned int Clock_basefreq;
+#endif
+
+void Clock_exit(void);
+
+/*
+ * Major and minor number.
+ */
+
+rtems_device_major_number rtems_clock_major = UINT32_MAX;
+rtems_device_minor_number rtems_clock_minor;
+
+/*
+ * Clock_isr
+ *
+ * This is the clock tick interrupt handler.
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ *
+ */
+
+void Clock_isr(void *arg_unused)
+{
+ /*
+ * Accurate count of ISRs
+ */
+
+ Clock_driver_ticks += 1;
+
+#ifdef CLOCK_DRIVER_USE_FAST_IDLE
+ do {
+ rtems_clock_tick();
+ } while ( _Thread_Executing == _Thread_Idle &&
+ _Thread_Heir == _Thread_Executing);
+
+ Clock_driver_support_at_tick();
+ return;
+
+#else
+
+ /*
+ * Add custom handling at every tick from bsp.h
+ */
+ Clock_driver_support_at_tick();
+
+#ifdef CLOCK_DRIVER_ISRS_PER_TICK
+ /*
+ * The driver is multiple ISRs per clock tick.
+ */
+
+ if ( !Clock_driver_isrs ) {
+
+ rtems_clock_tick();
+
+ Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
+ }
+ Clock_driver_isrs--;
+#else
+
+ /*
+ * The driver is one ISR per clock tick.
+ */
+ rtems_clock_tick();
+#endif
+#endif
+}
+
+/*
+ * Clock_exit
+ *
+ * This routine allows the clock driver to exit by masking the interrupt and
+ * disabling the clock's counter.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ *
+ */
+
+void Clock_exit( void )
+{
+ /* Stop all activity of the Timer, no more ISRs.
+ * We could be using tlib_close(), however tlib_stop() is quicker
+ * and independent of IRQ unregister code.
+ */
+ if ( Clock_handle ) {
+ tlib_stop(Clock_handle);
+ Clock_handle = NULL;
+ }
+}
+
+uint32_t Clock_nanoseconds_since_last_tick(void)
+{
+ uint32_t clicks;
+ if ( !Clock_handle )
+ return 0;
+
+ tlib_get_counter(Clock_handle, (unsigned int *)&clicks);
+
+#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+ {
+ /* Down counter. Calc from BaseFreq. */
+ uint64_t tmp;
+ tmp = ((uint64_t)clicks * 1000000000) / ((uint64_t)Clock_basefreq);
+ return (uint32_t)tmp;
+ }
+#else
+ /* Down counter. Timer base frequency is initialized to 1 MHz */
+ return (uint32_t)
+ (rtems_configuration_get_microseconds_per_tick() - clicks) * 1000;
+#endif
+}
+
+/*
+ * Clock_initialize
+ *
+ * This routine initializes the clock driver and starts the Clock.
+ *
+ * Input parameters:
+ * major - clock device major number
+ * minor - clock device minor number
+ * parg - pointer to optional device driver arguments
+ *
+ * Output parameters: NONE
+ *
+ * Return values:
+ * rtems_device_driver status code
+ */
+
+rtems_device_driver Clock_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *pargp
+)
+{
+ unsigned int tick_hz;
+
+ /*
+ * Take Timer that should be used as system timer.
+ *
+ */
+ Clock_handle = tlib_open(Clock_timer);
+ if ( Clock_handle == NULL ) {
+ /* System Clock Timer not found */
+ return RTEMS_NOT_DEFINED;
+ }
+
+ /*
+ * Install Clock ISR before starting timer
+ */
+ tlib_irq_register(Clock_handle, Clock_isr, NULL);
+
+ /* Set Timer Frequency to tick at Configured value. The Timer
+ * Frequency is set in multiples of the timer base frequency.
+ *
+ * In standard LEON3 designs the base frequency is is 1MHz, to
+ * save instructions define CLOCK_DRIVER_ASSUME_PRESCALER_1MHZ
+ * to avoid 64-bit calculation.
+ */
+#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+ {
+ uint64_t tmp;
+
+ tlib_get_freq(Clock_handle, &Clock_basefreq, NULL);
+
+ tmp = (uint64_t)Clock_basefreq;
+ tmp = tmp * (unint64_t)rtems_configuration_get_microseconds_per_tick();
+ tick_hz = tmp / 1000000;
+ }
+#else
+ tick_hz = rtems_configuration_get_microseconds_per_tick();
+#endif
+
+ tlib_set_freq(Clock_handle, tick_hz);
+
+ rtems_clock_set_nanoseconds_extension(Clock_nanoseconds_since_last_tick);
+
+ /*
+ * IRQ and Frequency is setup, now we start the Timer. IRQ is still
+ * disabled globally during startup, so IRQ will hold for a while.
+ */
+ tlib_start(Clock_handle, 0);
+
+ /*
+ * Register function called at system shutdown
+ */
+ atexit( Clock_exit );
+
+ /*
+ * make major/minor avail to others such as shared memory driver
+ */
+
+ rtems_clock_major = major;
+ rtems_clock_minor = minor;
+
+ /*
+ * If we are counting ISRs per tick, then initialize the counter.
+ */
+
+#ifdef CLOCK_DRIVER_ISRS_PER_TICK
+ Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
+#endif
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*** Timer Driver Interface ***/
+
+void Clock_timer_register(int timer_number)
+{
+ Clock_timer = timer_number;
+}