diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2013-12-20 14:06:37 +0100 |
---|---|---|
committer | Daniel Hellstrom <daniel@gaisler.com> | 2013-12-22 11:06:05 +0100 |
commit | 119023e8c2268ab44129d1b9f34dc66699beea61 (patch) | |
tree | 2d31429b7b0d085b43d340748354d52798775b5e | |
parent | 32b900f134dd86b470bc6226bb603c09bed9deef (diff) |
SPWTDP: added SpW Time Distribution Protocol driverrcc-v1.2.14
This driver supports mainly device discovery and
interrupt handling.
-rw-r--r-- | c/src/lib/libbsp/sparc/Makefile.am | 2 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/leon2/Makefile.am | 2 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/leon2/preinstall.am | 4 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/leon3/Makefile.am | 2 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/leon3/preinstall.am | 4 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/include/spwtdp.h | 114 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/time/spwtdp.c | 252 |
7 files changed, 380 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am index 12aeb8d194..cbf7a08ddc 100644 --- a/c/src/lib/libbsp/sparc/Makefile.am +++ b/c/src/lib/libbsp/sparc/Makefile.am @@ -122,8 +122,10 @@ EXTRA_DIST += shared/include/spictrl.h # TIME EXTRA_DIST += shared/time/spwcuc.c +EXTRA_DIST += shared/time/spwtdp.c EXTRA_DIST += shared/time/grctm.c EXTRA_DIST += shared/include/spwcuc.h +EXTRA_DIST += shared/include/spwtdp.h EXTRA_DIST += shared/include/grctm.h # GPIO diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am index 94133d6dc1..2fedddc83e 100644 --- a/c/src/lib/libbsp/sparc/leon2/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am @@ -155,8 +155,10 @@ libbsp_a_SOURCES += ../../sparc/shared/spi/spictrl.c # TIME include_HEADERS += ../../sparc/shared/include/spwcuc.h +include_HEADERS += ../../sparc/shared/include/spwtdp.h include_HEADERS += ../../sparc/shared/include/grctm.h libbsp_a_SOURCES += ../../sparc/shared/time/spwcuc.c +libbsp_a_SOURCES += ../../sparc/shared/time/spwtdp.c libbsp_a_SOURCES += ../../sparc/shared/time/grctm.c # GPIO diff --git a/c/src/lib/libbsp/sparc/leon2/preinstall.am b/c/src/lib/libbsp/sparc/leon2/preinstall.am index d9c77cddeb..61ff4802c8 100644 --- a/c/src/lib/libbsp/sparc/leon2/preinstall.am +++ b/c/src/lib/libbsp/sparc/leon2/preinstall.am @@ -205,6 +205,10 @@ $(PROJECT_INCLUDE)/spwcuc.h: ../../sparc/shared/include/spwcuc.h $(PROJECT_INCLU $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwcuc.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwcuc.h +$(PROJECT_INCLUDE)/spwtdp.h: ../../sparc/shared/include/spwtdp.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwtdp.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwtdp.h + $(PROJECT_INCLUDE)/grctm.h: ../../sparc/shared/include/grctm.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grctm.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/grctm.h diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am index 617f7bb5d1..d71200f738 100644 --- a/c/src/lib/libbsp/sparc/leon3/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am @@ -171,8 +171,10 @@ libbsp_a_SOURCES += ../../sparc/shared/spi/spictrl.c # TIME include_HEADERS += ../../sparc/shared/include/spwcuc.h +include_HEADERS += ../../sparc/shared/include/spwtdp.h include_HEADERS += ../../sparc/shared/include/grctm.h libbsp_a_SOURCES += ../../sparc/shared/time/spwcuc.c +libbsp_a_SOURCES += ../../sparc/shared/time/spwtdp.c libbsp_a_SOURCES += ../../sparc/shared/time/grctm.c # GPIO diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am index 8bc841b5c6..c4bad50ba1 100644 --- a/c/src/lib/libbsp/sparc/leon3/preinstall.am +++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am @@ -225,6 +225,10 @@ $(PROJECT_INCLUDE)/spwcuc.h: ../../sparc/shared/include/spwcuc.h $(PROJECT_INCLU $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwcuc.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwcuc.h +$(PROJECT_INCLUDE)/spwtdp.h: ../../sparc/shared/include/spwtdp.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwtdp.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwtdp.h + $(PROJECT_INCLUDE)/grctm.h: ../../sparc/shared/include/grctm.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grctm.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/grctm.h diff --git a/c/src/lib/libbsp/sparc/shared/include/spwtdp.h b/c/src/lib/libbsp/sparc/shared/include/spwtdp.h new file mode 100644 index 0000000000..31ef0cbf12 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/include/spwtdp.h @@ -0,0 +1,114 @@ +/* SPWTDP - SpaceWire Time Distribution Protocol. The driver provides + * device discovery and interrupt management. + * + * COPYRIGHT (c) 2013. + * Aeroflex 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. + * + */ + +#ifndef __SPWTDP_H__ +#define __SPWTDP_H__ + +#define SPWTDP_IRQ_SYNC 0x01 +#define SPWTDP_IRQ_TICKRX_ERR 0x02 +#define SPWTDP_IRQ_TICKRX 0x04 +#define SPWTDP_IRQ_TIME_MSG_TX 0x08 +#define SPWTDP_IRQ_TICKTX 0x10 +#define SPWTDP_IRQ_RX 0x20 +#define SPWTDP_IRQ_TX 0x40 + +/* SPWTDP Register layout */ +struct spwtdp_regs { + volatile unsigned int conf[4]; /* 00 */ + volatile unsigned int stat[4]; /* 10 */ + volatile unsigned int cmd_ctrl; /* 20 */ + volatile unsigned int cmd_et[5]; /* 24 */ + volatile unsigned int resv1[2]; /* 38 */ + volatile unsigned int dat_ctrl; /* 40 */ + volatile unsigned int dat_et[5]; /* 44 */ + volatile unsigned int resv2[2]; /* 58 */ + volatile unsigned int ts_tx_ctrl; /* 60 */ + volatile unsigned int ts_tx_et[5]; /* 64 */ + volatile unsigned int resv3[2]; /* 78 */ + volatile unsigned int ts_rx_ctrl; /* 80 */ + volatile unsigned int ts_rx_et[5]; /* 84 */ + volatile unsigned int resv4[2]; /* 98 */ + volatile unsigned int lat_ctrl; /* A0 */ + volatile unsigned int lat_et[5]; /* A4 */ + volatile unsigned int resv5[2]; /* B8 */ + volatile unsigned int ien; /* C0 */ + volatile unsigned int ists; /* C4 */ +}; + +/* SPWTDP Statistics gathered by driver */ +struct spwtdp_stats { + + /* IRQ Stats */ + unsigned int nirqs; + unsigned int tx; + unsigned int rx; + unsigned int tick_tx; + unsigned int time_msg_tx; + unsigned int tick_rx; + unsigned int tick_rx_err; + unsigned int sync; +}; + +/* Function ISR callback prototype + * + * ists - Interrupt STatus register of the SPWTDP core read by ISR + * data - Custom data provided by user + */ +typedef void (*spwtdp_isr_t)(unsigned int ists, void *data); + +/* Open a SPWTDP device by minor number. A SPWTDP device can only by opened + * once. The handle returned must be used as the input parameter 'spwtdp' in + * the rest of the calls in the function interface. + */ +extern void *spwtdp_open(int minor); + +/* Close a previously opened SPWTDP device */ +extern void spwtdp_close(void *spwtdp); + +/* Reset SPWTDP Core */ +extern int spwtdp_reset(void *spwtdp); + +/* Enable Interrupts at Interrupt controller */ +extern void spwtdp_int_enable(void *spwtdp); + +/* Disable Interrupts at Interrupt controller */ +extern void spwtdp_int_disable(void *spwtdp); + +/* Clear Statistics gathered by the driver */ +extern void spwtdp_clr_stats(void *spwtdp); + +/* Get Statistics gathered by the driver. The statistics are stored into + * the location pointed to by 'stats'. + */ +extern void spwtdp_get_stats(void *spwtdp, struct spwtdp_stats *stats); + +/* Register an Interrupt handler and custom data, the function call is + * removed by setting func to NULL. + * + * The driver's interrupt handler is installed on open(), however the user + * callback called from the driver's ISR is installed using this function. + */ +extern void spwtdp_int_register(void *spwtdp, spwtdp_isr_t func, void *data); + +/* Clear interrupts */ +extern void spwtdp_clear_irqs(void *spwtdp, int irqs); + +/* Enable interrupts */ +extern void spwtdp_enable_irqs(void *spwtdp, int irqs); + +/* Get Register */ +extern struct spwtdp_regs *spwtdp_get_regs(void *spwtdp); + +/* Register the SPWTDP Driver to the Driver Manager */ +extern void spwtdp_register(void); + +#endif diff --git a/c/src/lib/libbsp/sparc/shared/time/spwtdp.c b/c/src/lib/libbsp/sparc/shared/time/spwtdp.c new file mode 100644 index 0000000000..4b22346ab0 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/time/spwtdp.c @@ -0,0 +1,252 @@ +/* SPWTDP - SpaceWire Time Distribution Protocol. The driver provides + * device discovery and interrupt management. + * + * COPYRIGHT (c) 2009. + * Aeroflex 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 <drvmgr/drvmgr.h> +#include <drvmgr/ambapp_bus.h> +#include <stdlib.h> + +#include <spwtdp.h> + +#define DRIVER_AMBAPP_GAISLER_SPWTDP_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPWTDP) + +/* Private structure of SPWTDP driver. */ +struct spwtdp_priv { + struct drvmgr_dev *dev; + struct spwtdp_regs *regs; + int open; + + spwtdp_isr_t user_isr; + void *user_isr_arg; + + struct spwtdp_stats stats; +}; + +void spwtdp_isr(void *data); + +struct amba_drv_info spwtdp_drv_info; + +/* Hardware Reset of SPWTDP */ +int spwtdp_hw_reset(struct spwtdp_priv *priv) +{ + struct spwtdp_regs *r = priv->regs; + int i = 1000; + + r->conf[0] = 1; + + while ((r->conf[0] & 1) && i > 0) { + i--; + } + + spwtdp_clear_irqs(priv, -1); + + return i ? 0 : -1; +} + +int spwtdp_reset(void *spwtdp) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + return spwtdp_hw_reset(priv); +} + +void *spwtdp_open(int minor) +{ + struct spwtdp_priv *priv; + struct drvmgr_dev *dev; + + /* Get Device from Minor */ + if ( drvmgr_get_dev(&spwtdp_drv_info.general, minor, &dev) ) { + return NULL; + } + + priv = dev->priv; + if ( (priv == NULL) || priv->open ) + return NULL; + + /* Set initial state of software */ + priv->open = 1; + + /* Clear Statistics */ + spwtdp_clr_stats(priv); + priv->user_isr = NULL; + priv->user_isr_arg = NULL; + + return priv; +} + +void spwtdp_close(void *spwtdp) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + if ( priv->open == 0 ) + return; + + /* Reset Hardware */ + spwtdp_hw_reset(priv); + + priv->open = 0; +} + +void spwtdp_int_enable(void *spwtdp) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + /* Register and Enable Interrupt at Interrupt controller */ + drvmgr_interrupt_register(priv->dev, 0, "spwtdp", spwtdp_isr, priv); +} + +void spwtdp_int_disable(void *spwtdp) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + /* Enable Interrupt at Interrupt controller */ + drvmgr_interrupt_unregister(priv->dev, 0, spwtdp_isr, priv); +} + +void spwtdp_clr_stats(void *spwtdp) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + memset(&priv->stats, 0, sizeof(priv->stats)); +} + +void spwtdp_get_stats(void *spwtdp, struct spwtdp_stats *stats) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + memcpy(stats, &priv->stats, sizeof(priv->stats)); +} + +/* Clear interrupts */ +void spwtdp_clear_irqs(void *spwtdp, int irqs) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + priv->regs->ists = irqs; +} + +/* Enable interrupts */ +void spwtdp_enable_irqs(void *spwtdp, int irqs) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + priv->regs->ien = irqs; +} + +struct spwtdp_regs *spwtdp_get_regs(void *spwtdp) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + return priv->regs; +} + +void spwtdp_int_register(void *spwtdp, spwtdp_isr_t func, void *data) +{ + struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp; + + priv->user_isr = func; + priv->user_isr_arg = data; +} + +void spwtdp_isr(void *data) +{ + struct spwtdp_priv *priv = data; + struct spwtdp_stats *stats = &priv->stats; + unsigned int ists = priv->regs->ists; + + stats->nirqs++; + + if (ists & SPWTDP_IRQ_TX) + stats->tx++; + if (ists & SPWTDP_IRQ_RX) + stats->rx++; + if (ists & SPWTDP_IRQ_TICKTX) + stats->tick_tx++; + if (ists & SPWTDP_IRQ_TIME_MSG_TX) + stats->time_msg_tx++; + if (ists & SPWTDP_IRQ_TICKRX) + stats->tick_rx++; + if (ists & SPWTDP_IRQ_TICKRX_ERR) + stats->tick_rx_err++; + if (ists & SPWTDP_IRQ_SYNC) + stats->sync++; + + /* Let user Handle Interrupt */ + if (priv->user_isr) + priv->user_isr(ists, priv->user_isr_arg); +} + +/*** INTERFACE TO DRIVER MANAGER ***/ + +int spwtdp_init2(struct drvmgr_dev *dev) +{ + struct amba_dev_info *ambadev; + struct ambapp_core *pnpinfo; + struct spwtdp_priv *priv; + struct spwtdp_regs *regs; + + priv = dev->priv; + if (priv == NULL) + return DRVMGR_NOMEM; + memset(priv, 0, sizeof(*priv)); + priv->dev = dev; + + /* Get device information from AMBA PnP information */ + ambadev = (struct amba_dev_info *)dev->businfo; + if ( ambadev == NULL ) { + return DRVMGR_ENORES; + } + pnpinfo = &ambadev->info; + regs = (struct spwtdp_regs *)pnpinfo->apb_slv->start; + + priv->regs = regs; + + spwtdp_hw_reset(priv); + + return DRVMGR_OK; +} + +struct drvmgr_drv_ops spwtdp_ops = +{ + {NULL, spwtdp_init2, NULL, NULL}, + NULL, + NULL +}; + +struct amba_dev_id spwtdp_ids[] = +{ + {VENDOR_GAISLER, GAISLER_SPWTDP}, + {0, 0} /* Mark end of table */ +}; + +struct amba_drv_info spwtdp_drv_info = +{ + { + DRVMGR_OBJ_DRV, /* Driver */ + NULL, /* Next driver */ + NULL, /* Device list */ + DRIVER_AMBAPP_GAISLER_SPWTDP_ID,/* Driver ID */ + "SPWTDP_DRV", /* Driver Name */ + DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ + &spwtdp_ops, + NULL, /* Funcs */ + 0, /* No devices yet */ + sizeof(struct spwtdp_priv), /* Let DrvMgr allocate priv */ + }, + &spwtdp_ids[0] +}; + +/* Register the SPWTDP Driver */ +void spwtdp_register(void) +{ + drvmgr_drv_register(&spwtdp_drv_info.general); +} |