[PATCH 021/111] LEON: updated shared drivers to Driver Manger framework
Daniel Hellstrom
daniel at gaisler.com
Thu Feb 26 16:38:23 UTC 2015
Some bugfixes at the same time. After this patch the drivers
may be used on RASTA systems having a big-endian PCI layout.
Removed not up to date changelogs, rely on git log instead.
---
c/src/lib/libbsp/sparc/shared/1553/b1553brm.c | 1975 ++++++++-------
c/src/lib/libbsp/sparc/shared/can/grcan.c | 1747 +++++++-------
c/src/lib/libbsp/sparc/shared/can/occan.c | 1181 +++++----
c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c | 355 ++--
c/src/lib/libbsp/sparc/shared/include/b1553brm.h | 25 +-
c/src/lib/libbsp/sparc/shared/include/grcan.h | 19 +-
c/src/lib/libbsp/sparc/shared/include/grspw.h | 57 +-
c/src/lib/libbsp/sparc/shared/include/i2cmst.h | 23 +-
c/src/lib/libbsp/sparc/shared/include/occan.h | 13 +-
c/src/lib/libbsp/sparc/shared/spw/grspw.c | 2838 ++++++++++++----------
10 files changed, 4391 insertions(+), 3842 deletions(-)
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
index 045146a..19ad36c 100644
--- a/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
+++ b/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
@@ -2,52 +2,19 @@
* BRM driver
*
* COPYRIGHT (c) 2006.
- * Gaisler Research.
+ * 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.org/license/LICENSE.
- *
*/
/********** Set defaults **********/
-/* basic bus/interface of device,
- * Default to direct accessed AMBA bus.
- */
-#ifndef B1553BRM_NO_AMBA
- #define B1553BRM_AMBA
- #undef B1553BRM_PCI
-#endif
-
-/* default name to /dev/brm */
-#if !defined(B1553BRM_DEVNAME) || !defined(B1553BRM_DEVNAME_NO)
- #undef B1553BRM_DEVNAME
- #undef B1553BRM_DEVNAME_NO
- #define B1553BRM_DEVNAME "/dev/brm0"
- #define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[8]='0'+(no))
-#endif
-
-#ifndef B1553BRM_PREFIX
- #define B1553BRM_PREFIX(name) b1553brm##name
-#else
- #define B1553BRM_REGISTER_STATIC
-#endif
-
-/* default to no translation */
-#ifndef B1553BRM_ADR_TO
- #define memarea_to_hw(x) ((unsigned int)(x))
-#endif
-
-#ifndef B1553BRM_REG_INT
- #define B1553BRM_REG_INT(handler,irqno,arg) set_vector(handler,(irqno)+0x10,1)
- #undef B1553BRM_DEFINE_INTHANDLER
- #define B1553BRM_DEFINE_INTHANDLER
-#endif
-
-/* default to 128K memory layout */
-#if !defined(DMA_MEM_16K)
- #define DMA_MEM_128K
+/* default to 16K memory layout */
+#define DMA_MEM_128K
+#if !defined(DMA_MEM_128K)
+ #define DMA_MEM_16K
#endif
#include <bsp.h>
@@ -59,8 +26,10 @@
#include <ctype.h>
#include <rtems/bspIo.h>
+#include <drvmgr/drvmgr.h>
#include <b1553brm.h>
#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
/* Uncomment for debug output */
/*#define DEBUG 1
@@ -70,24 +39,24 @@
/* EVENT_QUEUE_SIZE sets the size of the event queue
*/
-#define EVENT_QUEUE_SIZE 1024
+#define EVENT_QUEUE_SIZE 1024
#define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) )
-#ifdef DEBUG
+#if 0
#define DBG(x...) printk(x)
#else
-#define DBG(x...)
+#define DBG(x...)
#endif
#ifdef FUNCDEBUG
#define FUNCDBG(x...) printk(x)
#else
-#define FUNCDBG(x...)
+#define FUNCDBG(x...)
#endif
-#define READ_REG(address) _BRM_REG_READ16((unsigned int)address)
+#define READ_REG(address) (*(volatile unsigned int *)address)
#define READ_DMA(address) _BRM_REG_READ16((unsigned int)address)
static __inline__ unsigned short _BRM_REG_READ16(unsigned int addr) {
unsigned short tmp;
@@ -107,7 +76,7 @@ static rtems_device_driver brm_control(rtems_device_major_number major, rtems_de
#define BRM_DRIVER_TABLE_ENTRY { brm_initialize, brm_open, brm_close, brm_read, brm_write, brm_control }
-static rtems_driver_address_table brm_driver = BRM_DRIVER_TABLE_ENTRY;
+static rtems_driver_address_table b1553brm_driver = BRM_DRIVER_TABLE_ENTRY;
struct msg {
unsigned short miw;
@@ -134,165 +103,464 @@ struct irq_log_list {
volatile unsigned short iaw;
};
-typedef struct {
-
- unsigned int memarea_base;
- struct brm_reg *regs;
-
- /* BRM descriptors */
- struct desc_table {
-
- volatile unsigned short ctrl;
- volatile unsigned short top;
- volatile unsigned short cur;
- volatile unsigned short bot;
-
- } *desc;
-
- volatile unsigned short *mem;
- /* bc mem struct */
+typedef struct {
+
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ struct brm_reg *regs;
+
+ unsigned int memarea_base;
+ unsigned int memarea_base_remote;
+ unsigned int cfg_clksel;
+ unsigned int cfg_clkdiv;
+ unsigned int cfg_freq;
+
+ /* BRM descriptors */
+ struct desc_table {
+ volatile unsigned short ctrl;
+ volatile unsigned short top;
+ volatile unsigned short cur;
+ volatile unsigned short bot;
+ } *desc;
+
+ volatile unsigned short *mem;
+ /* bc mem struct */
+ struct {
+ /* BC Descriptors */
struct {
- /* BC Descriptors */
- struct {
- unsigned short ctrl; /* control */
- unsigned short cw1; /* Command word 1*/
- unsigned short cw2; /* Command word 1*/
- unsigned short dptr; /* Data pointer in halfword offset from bcmem */
- unsigned short tsw[2]; /* status word 1 & 2 */
- unsigned short ba; /* branch address */
- unsigned short timer; /* timer value */
- } descs[128]; /* 2k (1024 half words) */
-
- /* message data */
- struct {
- unsigned short data[32]; /* 1 message's data */
- } msg_data[128]; /* 8k */
+ unsigned short ctrl; /* control */
+ unsigned short cw1; /* Command word 1*/
+ unsigned short cw2; /* Command word 1*/
+ unsigned short dptr; /* Data pointer in halfword offset from bcmem */
+ unsigned short tsw[2]; /* status word 1 & 2 */
+ unsigned short ba; /* branch address */
+ unsigned short timer; /* timer value */
+ } descs[128]; /* 2k (1024 half words) */
+
+ /* message data */
+ struct {
+ unsigned short data[32]; /* 1 message's data */
+ } msg_data[128]; /* 8k */
#if defined(DMA_MEM_128K)
- /* offset to last 64bytes of 128k */
- unsigned short unused[(64*1024-(128*8+128*32))-16*2];
+ /* offset to last 64bytes of 128k */
+ unsigned short unused[(64*1024-(128*8+128*32))-16*2];
#elif defined(DMA_MEM_16K)
- unsigned short unused[(8*1024-(128*8+128*32))-16*2];
+ unsigned short unused[(8*1024-(128*8+128*32))-16*2];
#endif
- /* interrupt log at 64 bytes from end */
- struct irq_log_list irq_logs[16];
- } *bcmem;
+ /* interrupt log at 64 bytes from end */
+ struct irq_log_list irq_logs[16];
+ } *bcmem;
#if defined(DMA_MEM_128K)
- /* Memory structure of a RT being inited, just used
- * for RT initialization.
- *
- * *mesgs[32] fit each minimally 8 messages per sub address.
- */
- struct {
- /* RX Sub Address descriptors */
- struct desc_table rxsubs[32];
- /* TX Sub Address descriptors */
- struct desc_table txsubs[32];
- /* RX mode code descriptors */
- struct desc_table rxmodes[32];
- /* TX mode code descriptors */
- struct desc_table txmodes[32];
-
- /* RX Sub Address messages */
- struct circ_buf rxsuba_msgs[32];
- /* TX Sub Address messages */
- struct circ_buf txsuba_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf rxmode_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf txmode_msgs[32];
-
-
- /* offset to last 64bytes of 128k: tot-used-needed */
- unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2];
-
- /* interrupt log at 64 bytes from end */
- struct irq_log_list irq_logs[16];
- } *rtmem;
+ /* Memory structure of a RT being inited, just used
+ * for RT initialization.
+ *
+ * *mesgs[32] fit each minimally 8 messages per sub address.
+ */
+ struct {
+ /* RX Sub Address descriptors */
+ struct desc_table rxsubs[32];
+ /* TX Sub Address descriptors */
+ struct desc_table txsubs[32];
+ /* RX mode code descriptors */
+ struct desc_table rxmodes[32];
+ /* TX mode code descriptors */
+ struct desc_table txmodes[32];
+
+ /* RX Sub Address messages */
+ struct circ_buf rxsuba_msgs[32];
+ /* TX Sub Address messages */
+ struct circ_buf txsuba_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf rxmode_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf txmode_msgs[32];
+
+ /* offset to last 64bytes of 128k: tot-used-needed */
+ unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2];
+
+ /* interrupt log at 64 bytes from end */
+ struct irq_log_list irq_logs[16];
+ } *rtmem;
#elif defined(DMA_MEM_16K)
- /* Memory structure of a RT being inited, just used
- * for RT initialization.
- *
- * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue.
- * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue.
- */
- struct {
- /* RX Sub Address descriptors */
- struct desc_table rxsubs[32];
- /* TX Sub Address descriptors */
- struct desc_table txsubs[32];
- /* RX mode code descriptors */
- struct desc_table rxmodes[32];
- /* TX mode code descriptors */
- struct desc_table txmodes[32];
-
- /* RX Sub Address messages */
- struct circ_buf_2 rxsuba_msgs[32];
- /* TX Sub Address messages */
- struct circ_buf_2 txsuba_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf_2 rxmode_msgs[32];
- /* RX Mode Code messages */
- struct circ_buf_1 txmode_msgs[32];
-
-
- /* offset to last 64bytes of 16k: tot-used-needed */
- unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2];
-
- /* interrupt log at 64 bytes from end */
- struct irq_log_list irq_logs[16];
- } *rtmem;
+ /* Memory structure of a RT being inited, just used
+ * for RT initialization.
+ *
+ * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue.
+ * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue.
+ */
+ struct {
+ /* RX Sub Address descriptors */
+ struct desc_table rxsubs[32];
+ /* TX Sub Address descriptors */
+ struct desc_table txsubs[32];
+ /* RX mode code descriptors */
+ struct desc_table rxmodes[32];
+ /* TX mode code descriptors */
+ struct desc_table txmodes[32];
+
+ /* RX Sub Address messages */
+ struct circ_buf_2 rxsuba_msgs[32];
+ /* TX Sub Address messages */
+ struct circ_buf_2 txsuba_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf_2 rxmode_msgs[32];
+ /* RX Mode Code messages */
+ struct circ_buf_1 txmode_msgs[32];
+
+ /* offset to last 64bytes of 16k: tot-used-needed */
+ unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2];
+
+ /* interrupt log at 64 bytes from end */
+ struct irq_log_list irq_logs[16];
+ } *rtmem;
#else
#error You must define one DMA_MEM_???K
#endif
- /* Interrupt log list */
- struct irq_log_list *irq_log;
- unsigned int irq;
+ /* Interrupt log list */
+ struct irq_log_list *irq_log;
+ unsigned int irq;
- /* Received events waiting to be read */
- struct rt_msg *rt_event;
- struct bm_msg *bm_event;
+ /* Received events waiting to be read */
+ struct rt_msg *rt_event;
+ struct bm_msg *bm_event;
- unsigned int head, tail;
+ unsigned int head, tail;
- unsigned int last_read[128];
- unsigned int written[32];
+ unsigned int last_read[128];
+ unsigned int written[32];
- struct bc_msg *cur_list;
+ struct bc_msg *cur_list;
- int tx_blocking, rx_blocking;
+ int tx_blocking, rx_blocking;
- rtems_id rx_sem, tx_sem, dev_sem;
- int minor;
- int irqno;
- unsigned int mode;
-#ifdef DEBUG
- unsigned int log[EVENT_QUEUE_SIZE*4];
- unsigned int log_i;
+ rtems_id rx_sem, tx_sem, dev_sem;
+ int minor;
+ int irqno;
+ unsigned int mode;
+#ifdef DEBUG
+ unsigned int log[EVENT_QUEUE_SIZE*4];
+ unsigned int log_i;
#endif
- rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */
- unsigned int status;
- int bc_list_fail;
+ rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */
+ unsigned int status;
+ int bc_list_fail;
} brm_priv;
-static int brm_cores;
-static unsigned int allbrm_memarea;
-static brm_priv *brms;
-static struct ambapp_bus *amba_bus;
-static unsigned int allbrm_cfg_clksel;
-static unsigned int allbrm_cfg_clkdiv;
-static unsigned int allbrm_cfg_freq;
-
-static void brm_interrupt(brm_priv *brm);
-#ifdef B1553BRM_DEFINE_INTHANDLER
-static void b1553brm_interrupt_handler(rtems_vector_number v);
-#endif
+static void b1553brm_interrupt(void *arg);
+static rtems_device_driver rt_init(brm_priv *brm);
#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1)
+static int b1553brm_driver_io_registered = 0;
+static rtems_device_major_number b1553brm_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int b1553brm_register_io(rtems_device_major_number *m);
+int b1553brm_device_init(brm_priv *pDev);
+
+int b1553brm_init2(struct drvmgr_dev *dev);
+int b1553brm_init3(struct drvmgr_dev *dev);
+int b1553brm_remove(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops b1553brm_ops =
+{
+ .init = {NULL, b1553brm_init2, b1553brm_init3, NULL},
+ .remove = b1553brm_remove,
+ .info = NULL
+};
+
+struct amba_dev_id b1553brm_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_B1553BRM},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info b1553brm_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_B1553BRM_ID, /* Driver ID */
+ "B1553BRM_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &b1553brm_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &b1553brm_ids[0]
+};
+
+void b1553brm_register_drv (void)
+{
+ DBG("Registering B1553BRM driver\n");
+ drvmgr_drv_register(&b1553brm_drv_info.general);
+}
+
+int b1553brm_init2(struct drvmgr_dev *dev)
+{
+ brm_priv *priv;
+
+ DBG("B1553BRM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(brm_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int b1553brm_init3(struct drvmgr_dev *dev)
+{
+ brm_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( b1553brm_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( b1553brm_register_io(&b1553brm_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ b1553brm_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( b1553brm_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/b1553brm%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sb1553brm%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, b1553brm_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+int b1553brm_remove(struct drvmgr_dev *dev)
+{
+ /* Stop more tasks to open driver */
+
+ /* Throw out all tasks using this driver */
+
+ /* Unregister I/O node */
+
+ /* Unregister and disable Interrupt */
+
+ /* Free device memory */
+
+ /* Return sucessfully */
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int b1553brm_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &b1553brm_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("B1553BRM driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("B1553BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("B1553BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("B1553BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("B1553BRM rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int b1553brm_device_init(brm_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ unsigned int mem;
+ int size;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irqno = pnpinfo->irq;
+ /* Two versions of the BRM core. One where the registers are accessed using the AHB bus
+ * and one where the APB bus is used
+ */
+ if ( pnpinfo->ahb_slv ) {
+ /* Registers accessed over AHB */
+ pDev->regs = (struct brm_reg *)pnpinfo->ahb_slv->start[0];
+ } else {
+ /* Registers accessed over APB */
+ pDev->regs = (struct brm_reg *)pnpinfo->apb_slv->start;
+ }
+ pDev->minor = pDev->dev->minor_drv;
+#ifdef DEBUG
+ pDev->log_i = 0;
+ memset(pDev->log,0,sizeof(pDev->log));
+#endif
+
+#ifdef DMA_MEM_128K
+ size = 128 * 1024;
+#else
+ size = 16 * 1024;
+#endif
+
+ /* Get memory configuration from bus resources */
+ value = drvmgr_dev_key_get(pDev->dev, "dmaBaseAdr", KEY_TYPE_POINTER);
+ if (value)
+ mem = (unsigned int)value->ptr;
+
+ if (value && (mem & 1)) {
+ /* Remote address, address as BRM looks at it. */
+
+ /* Translate the base address into an address that the the CPU can understand */
+ pDev->memarea_base_remote = mem & ~1;
+ drvmgr_translate_check(pDev->dev, DMAMEM_TO_CPU,
+ (void *)pDev->memarea_base_remote,
+ (void **)&pDev->memarea_base,
+ size);
+ } else {
+ if (!value) {
+ /* Use dynamically allocated memory + 128k for
+ * alignment
+ */
+ mem = (unsigned int)malloc(size + 128 * 1024);
+ if (!mem){
+ printk("BRM: Failed to allocate HW memory\n\r");
+ return -1;
+ }
+ /* align memory to 128k boundary */
+ pDev->memarea_base = (mem + 0x1ffff) & ~0x1ffff;
+ } else {
+ pDev->memarea_base = mem;
+ }
+
+ /* Translate the base address into an address that the BRM core can understand */
+ drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA,
+ (void *)pDev->memarea_base,
+ (void **)&pDev->memarea_base_remote,
+ size);
+ }
+
+ /* clear the used memory */
+ memset((char *)pDev->memarea_base, 0, size);
+
+ /* Set base address of all descriptors */
+ pDev->desc = (struct desc_table *) pDev->memarea_base;
+ pDev->mem = (volatile unsigned short *) pDev->memarea_base;
+ pDev->irq_log = (struct irq_log_list *)(pDev->memarea_base + (0xFFE0<<1)); /* last 64byte */
+
+ pDev->bm_event = NULL;
+ pDev->rt_event = NULL;
+
+ pDev->cfg_clksel = 0;
+ pDev->cfg_clkdiv = 0;
+ pDev->cfg_freq = BRM_FREQ_24MHZ;
+
+ value = drvmgr_dev_key_get(pDev->dev, "clkSel", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_clksel = value->i & CLKSEL_MASK;
+ }
+
+ value = drvmgr_dev_key_get(pDev->dev, "clkDiv", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_clkdiv = value->i & CLKDIV_MASK;
+ }
+
+ value = drvmgr_dev_key_get(pDev->dev, "coreFreq", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_freq = value->i & BRM_FREQ_MASK;
+ }
+
+ /* Sel clock so that we can write to BRM's registers */
+ pDev->regs->w_ctrl = (pDev->cfg_clksel<<9) | (pDev->cfg_clkdiv<<5);
+ /* Reset BRM core */
+ pDev->regs->w_ctrl = 1<<10 | READ_REG(&pDev->regs->w_ctrl);
+
+ /* RX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rx_sem) != RTEMS_SUCCESSFUL ) {
+ printk("BRM: Failed to create rx semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* TX Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->tx_sem) != RTEMS_SUCCESSFUL ){
+ printk("BRM: Failed to create tx semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->dev_sem) != RTEMS_SUCCESSFUL ){
+ printk("BRM: Failed to create device semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Default to RT-mode */
+ rt_init(pDev);
+
+ return 0;
+}
+
static int odd_parity(unsigned int data) {
unsigned int i=0;
@@ -300,12 +568,11 @@ static int odd_parity(unsigned int data) {
{
i++;
data &= (data - 1);
- }
+ }
return !(i&1);
}
-
static void start_operation(brm_priv *brm) {
unsigned int ctrl = READ_REG(&brm->regs->ctrl);
brm->regs->ctrl = ctrl | 0x8000;
@@ -315,80 +582,12 @@ static void stop_operation(brm_priv *brm) {
unsigned int ctrl = READ_REG(&brm->regs->ctrl);
brm->regs->ctrl = ctrl & ~0x8000;
}
+
static int is_executing(brm_priv *brm) {
unsigned int ctrl = READ_REG(&brm->regs->ctrl);
return ((ctrl>>15) & 1);
}
-#ifdef LEON3
-#ifndef DONT_DEF_RAMON
-int brm_register_leon3_ramon_fpga(void){
- /* Clock div & Clock sel is NOT available.
- * The BRM is always clocked with 24MHz.
- * 3 in BRM enhanced register will select 24MHz
- */
- return b1553brm_register(&ambapp_plb, 0, 0, 3);
-}
-
-int brm_register_leon3_ramon_asic(void){
- /* Clock div & Clock sel is available.
- * Clkdiv only matter when clksel is 1.
- * clksel=2, clkdiv=don't care, brm_frq=24MHz
- *
- * 3 in BRM enhanced register will select 24MHz
- */
- return b1553brm_register(&ambapp_plb, 2, 0, 3);
-}
-#endif
-#endif
-
-#ifdef B1553BRM_REGISTER_STATIC
-static
-#endif
-int B1553BRM_PREFIX(_register)(struct ambapp_bus *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq)
-{
- rtems_status_code r;
- rtems_device_major_number m;
-
- FUNCDBG("brm_register:\n\r");
-
- /* save amba bus pointer */
- amba_bus = bus;
- if ( !bus ){
- printk("brm_register: bus is NULL\n\r");
- return 1;
- }
-
-#ifdef B1553BRM_LOCAL_MEM
- allbrm_memarea = B1553BRM_LOCAL_MEM_ADR;
-#else
- allbrm_memarea = 0;
-#endif
-
- /* Save clksel, clkdiv and brm_freq for later use */
- allbrm_cfg_clksel = clksel & CLKSEL_MASK;
- allbrm_cfg_clkdiv = clkdiv & CLKDIV_MASK;
- allbrm_cfg_freq = brm_freq & BRM_FREQ_MASK;
-
- if ((r = rtems_io_register_driver(0, &brm_driver, &m)) == RTEMS_SUCCESSFUL) {
- DBG("BRM: driver successfully registered, major: %d\n",m);
-
- } else {
- switch(r) {
- case RTEMS_TOO_MANY:
- printk("BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); break;
- case RTEMS_INVALID_NUMBER:
- printk("BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); break;
- case RTEMS_RESOURCE_IN_USE:
- printk("BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); break;
- default:
- printk("BRM rtems_io_register_driver failed\n");
- }
- return 1;
- }
- return 0;
-}
-
static void clr_int_logs(struct irq_log_list *logs){
int i;
for(i=0; i<16; i++){
@@ -403,18 +602,18 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->head = brm->tail = 0;
brm->rx_blocking = brm->tx_blocking = 1;
- if ( brm->bm_event )
+ if ( brm->bm_event )
free(brm->bm_event);
brm->bm_event = NULL;
- if ( brm->rt_event )
+ if ( brm->rt_event )
free(brm->rt_event);
-
+
brm->bcmem = NULL;
brm->rtmem = (void *)brm->mem;
brm->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg));
-
+
if (brm->rt_event == NULL) {
DBG("BRM driver failed to allocated memory.");
return RTEMS_NO_MEMORY;
@@ -427,11 +626,11 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->regs->imask = BRM_RT_ILLCMD_IRQ|BRM_SUBAD_IRQ|BRM_TAPF_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ;
brm->regs->dpoint = 0;
brm->regs->ipoint = OFS(brm->rtmem->irq_logs[0]);
- brm->regs->enhanced = 0x0000 | allbrm_cfg_freq; /* BRM clocked with freq = 12,16,20 or 24MHz */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
+ brm->regs->enhanced = 0x0000 | brm->cfg_freq; /* BRM clocked with freq = 12,16,20 or 24MHz */
+ brm->regs->w_ctrl = (brm->cfg_clksel<<9) | (brm->cfg_clkdiv<<5) | 1;
brm->regs->w_irqctrl = 6;
- brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);
-
+ brm->regs->w_ahbaddr = brm->memarea_base_remote;
+
clr_int_logs(brm->irq_log);
/* Legalize all commands */
@@ -439,19 +638,19 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->regs->rt_cmd_leg[i] = 0;
}
- /* Init descriptor table
- *
+ /* Init descriptor table
+ *
* Each circular buffer has room for 8 messages with up to 34 (32 data + miw + time) words (16b) in each.
* The buffers must separated by 34 words.
*/
-
+
/* RX Sub-address 0 - 31 */
for (i = 0; i < 32; i++) {
brm->rtmem->rxsubs[i].ctrl = 0x00E0; /* Interrupt: INTX, IWA, and IBRD */
brm->rtmem->rxsubs[i].top = OFS(brm->rtmem->rxsuba_msgs[i]); /* Top address */
brm->rtmem->rxsubs[i].cur = OFS(brm->rtmem->rxsuba_msgs[i]); /* Current address */
- brm->rtmem->rxsubs[i].bot = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
+ brm->rtmem->rxsubs[i].bot = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
brm->last_read[i] = OFS(brm->rtmem->rxsuba_msgs[i]);
}
/* TX Sub-address 0 - 31 */
@@ -470,7 +669,7 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->rtmem->rxmodes[i].cur = OFS(brm->rtmem->rxmode_msgs[i]); /* Current address */
brm->rtmem->rxmodes[i].bot = OFS(brm->rtmem->rxmode_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
brm->last_read[i+64] = OFS(brm->rtmem->rxmode_msgs[i]);
- }
+ }
/* TX mode code 0 - 31 */
for (i = 0; i < 32; i++) {
brm->rtmem->txmodes[i].ctrl = 0x0060; /* Interrupt: IWA and IBRD */
@@ -480,6 +679,12 @@ static rtems_device_driver rt_init(brm_priv *brm) {
brm->last_read[i+96] = OFS(brm->rtmem->txmode_msgs[i]);
}
+#ifdef DEBUG
+ printk("b1553BRM DMA_AREA: 0x%x\n", (unsigned int)brm->rtmem);
+ printk("LOG: 0x%x\n", &brm->log[0]);
+ printk("LOG_I: 0x%x\n", &brm->log_i);
+#endif
+
brm->mode = BRM_MODE_RT;
return RTEMS_SUCCESSFUL;
@@ -487,36 +692,35 @@ static rtems_device_driver rt_init(brm_priv *brm) {
static rtems_device_driver bc_init(brm_priv *brm){
- if ( brm->bm_event )
+ if ( brm->bm_event )
free(brm->bm_event);
brm->bm_event = NULL;
- if ( brm->rt_event )
+ if ( brm->rt_event )
free(brm->rt_event);
brm->rt_event = NULL;
-
+
brm->bcmem = (void *)brm->mem;
brm->rtmem = NULL;
brm->irq_log = (struct irq_log_list *)&brm->bcmem->irq_logs[0];
-
+
brm->head = brm->tail = 0;
brm->rx_blocking = brm->tx_blocking = 1;
-
+
brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */
brm->regs->oper = 0x0800; /* configure as BC */
brm->regs->imask = BRM_EOL_IRQ|BRM_BC_ILLCMD_IRQ|BRM_ILLOP_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ;
brm->regs->dpoint = 0;
- printk("Set BC interrupt log: 0x%lx, 0x%lx, 0x%lx\n",OFS(brm->bcmem->irq_logs[0]),&brm->bcmem->irq_logs[0],brm->bcmem);
brm->regs->ipoint = OFS(brm->bcmem->irq_logs[0]);
- brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
+ brm->regs->enhanced = 0x0000 | (brm->cfg_freq&BRM_FREQ_MASK); /* freq = 24 */
+ brm->regs->w_ctrl = (brm->cfg_clksel<<9) | (brm->cfg_clkdiv<<5) | 1;
brm->regs->w_irqctrl = 6;
- brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);
-
+ brm->regs->w_ahbaddr = brm->memarea_base_remote;
+
clr_int_logs(brm->irq_log);
-
+
brm->mode = BRM_MODE_BC;
-
+
return RTEMS_SUCCESSFUL;
}
@@ -526,18 +730,18 @@ static rtems_device_driver bm_init(brm_priv *brm) {
brm->head = brm->tail = 0;
brm->rx_blocking = brm->tx_blocking = 1;
- if ( brm->rt_event )
+ if ( brm->rt_event )
free(brm->rt_event);
brm->rt_event = NULL;
- if ( brm->bm_event )
+ if ( brm->bm_event )
free(brm->bm_event);
-
+
brm->bcmem = NULL;
brm->rtmem = NULL;
-
+
brm->bm_event = (struct bm_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct bm_msg));
-
+
if (brm->bm_event == NULL) {
DBG("BRM driver failed to allocated memory.");
return RTEMS_NO_MEMORY;
@@ -548,761 +752,634 @@ static rtems_device_driver bm_init(brm_priv *brm) {
brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */
brm->regs->oper = 0x0A00; /* configure as BM */
- brm->regs->imask = BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ|BRM_MERR_IRQ;
+ brm->regs->imask = BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ;
brm->regs->dpoint = 0;
brm->regs->ipoint = OFS(brm->mem[8*1024-16*2]);
brm->regs->mcpoint = 0; /* Command pointer */
brm->regs->mdpoint = 0x100; /* Data pointer */
brm->regs->mbc = 1; /* Block count */
- brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
+ brm->regs->enhanced = 0x0000 | (brm->cfg_freq&BRM_FREQ_MASK); /* freq = 24 */
+ brm->regs->w_ctrl = (brm->cfg_clksel<<9) | (brm->cfg_clkdiv<<5) | 1;
brm->regs->w_irqctrl = 6;
- brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);
-
+ brm->regs->w_ahbaddr = brm->memarea_base_remote;
+
clr_int_logs(brm->irq_log);
-
+
brm->mode = BRM_MODE_BM;
-
+
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- rtems_status_code status;
- int dev_cnt;
- char fs_name[20];
- brm_priv *brm;
- struct ambapp_ahb_info ambadev;
- char *mem;
-
- FUNCDBG("brm_initialize\n");
+ return RTEMS_SUCCESSFUL;
+}
- brm_cores = 0;
- strcpy(fs_name,B1553BRM_DEVNAME);
+static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
- /* Find all BRM devices */
- dev_cnt = ambapp_get_number_ahbslv_devices(amba_bus, VENDOR_GAISLER, GAISLER_B1553BRM);
- if ( dev_cnt < 1 ){
- /* Failed to find any CAN cores! */
- printk("BRM: Failed to find any BRM cores\n\r");
- return -1;
- }
+ FUNCDBG("brm_open\n");
- /* allocate & zero memory for the brm devices */
- brms = (brm_priv *)malloc(sizeof(*brms)*dev_cnt);
- if ( !brms ){
- printk("BRM: Failed to allocate SW memory\n\r");
- return -1;
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_UNSATISFIED;
}
- memset(brms,0,sizeof(*brms)*dev_cnt);
-
- /* Allocate memory for all device's descriptors,
- * they must be aligned to a XXX byte boundary.
- */
- #define BRM_DESCS_PER_CTRL 128
- if ( allbrm_memarea ){
- mem = (char *)allbrm_memarea;
- }else{
- /* sizeof(struct desc_table) * BRM_DESCS_PER_CTRL * dev_cnt */
- mem = (char *)malloc( (128*1024) * (dev_cnt+1)); /* 128k per core + 128k for alignment */
- if ( !mem ){
- free(brms);
- printk("BRM: Failed to allocate HW memory\n\r");
- return -1;
- }
+ brm = (brm_priv *)dev->priv;
- /* align memory to 128k boundary */
- mem = (char *)(((unsigned int)mem+0x1ffff) & ~0x1ffff);
+ if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
+ DBG("brm_open: resource in use\n");
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
}
- /* clear the used memory */
- memset(mem,0,(128*1024) * dev_cnt);
-
- /* initialize each brm device, one at a time */
- for(minor=0; minor<dev_cnt; minor++){
- brm = &brms[minor];
-
- /* Get AMBA AHB device info from Plug&Play */
- ambapp_find_ahbslv_next(amba_bus, VENDOR_GAISLER,
- GAISLER_B1553BRM, &ambadev, minor);
+ /* Set defaults */
+ brm->event_id = 0;
- /* Copy Basic HW info */
- brm->regs = (void *)ambadev.start[0];
- brm->irqno = ambadev.irq;
- brm->minor = minor;
- brm->irq = 0;
-#ifdef DEBUG
- brm->log_i = 0;
- memset(brm->log,0,sizeof(brm->log));
-#endif
+ start_operation(brm);
- /* Set unique name */
- B1553BRM_DEVNAME_NO(fs_name,minor);
-
- DBG("Registering BRM core at [0x%x] irq %d, minor %d as %s\n",brm->regs,brm->irqno,minor,fs_name);
-
- /* Bind filesystem name to device number (minor) */
- status = rtems_io_register_name(fs_name, major, minor);
- if (status != RTEMS_SUCCESSFUL)
- rtems_fatal_error_occurred(status);
-
- /* RX Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &brm->rx_sem) != RTEMS_SUCCESSFUL ){
- printk("BRM: Failed to create rx semaphore\n");
- return RTEMS_INTERNAL_ERROR;
- }
-
- /* TX Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0'+minor),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &brm->tx_sem) != RTEMS_SUCCESSFUL ){
- printk("BRM: Failed to create tx semaphore\n");
- return RTEMS_INTERNAL_ERROR;
- }
-
- /* Device Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0'+minor),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &brm->dev_sem) != RTEMS_SUCCESSFUL ){
- printk("BRM: Failed to create device semaphore\n");
- return RTEMS_INTERNAL_ERROR;
- }
-
-
- /* Set base address of all descriptors */
- brm->memarea_base = (unsigned int)&mem[(128*1024) * minor];
- brm->desc = (struct desc_table *) brm->memarea_base;
- brm->mem = (volatile unsigned short *) brm->memarea_base;
- brm->irq_log = (struct irq_log_list *)(brm->memarea_base + (0xFFE0<<1)); /* last 64byte */
-
- brm->bm_event = NULL;
- brm->rt_event = NULL;
-
- /* Sel clock so that we can write to BRM's registers */
- brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5);
- /* Reset BRM core */
- brm->regs->w_ctrl = 1<<10 | READ_REG(&brm->regs->w_ctrl);
-
- /* Register interrupt handler */
- B1553BRM_REG_INT(B1553BRM_PREFIX(_interrupt_handler), brm->irqno, brm);
-
- rt_init(brm);
-
- DBG("BRM: LOG: 0x%lx, 0x%lx\n\r",brm->log,brm);
+ /* Register interrupt routine */
+ if ( drvmgr_interrupt_register(brm->dev, 0, "b1553brm", b1553brm_interrupt, brm) ) {
+ rtems_semaphore_release(brm->dev_sem);
+ return RTEMS_UNSATISFIED;
}
- /* save number of BRM cores found */
- brm_cores = dev_cnt;
-
- DBG("BRM initialisation done.\n");
-
return RTEMS_SUCCESSFUL;
}
-
-static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
- brm_priv *brm;
-
- FUNCDBG("brm_open\n");
-
- if (minor >= brm_cores) {
- DBG("Wrong minor %d\n", minor);
- return RTEMS_UNSATISFIED; /* ENODEV */
- }
-
- brm = &brms[minor];
-
- if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
- DBG("brm_open: resource in use\n");
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- }
-
- /* Set defaults */
- brm->event_id = 0;
-
- start_operation(brm);
-
- return RTEMS_SUCCESSFUL;
-}
-
+
static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- brm_priv *brm = &brms[minor];
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+
FUNCDBG("brm_close");
+
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
+
+ drvmgr_interrupt_unregister(brm->dev, 0, b1553brm_interrupt, brm);
stop_operation(brm);
rtems_semaphore_release(brm->dev_sem);
return RTEMS_SUCCESSFUL;
}
+
+static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count)
+{
+ struct rt_msg *dest = (struct rt_msg *) buf;
+ int count = 0;
-static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count) {
-
- struct rt_msg *dest = (struct rt_msg *) buf;
- int count = 0;
-
- if (brm->head == brm->tail) {
- return 0;
- }
-
- do {
-
- DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail);
- dest[count++] = brm->rt_event[INDEX(brm->tail++)];
+ if (brm->head == brm->tail) {
+ return 0;
+ }
- } while (brm->head != brm->tail && count < msg_count);
+ do {
- return count;
+ DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail);
+ dest[count++] = brm->rt_event[INDEX(brm->tail++)];
+ } while (brm->head != brm->tail && count < msg_count);
+ return count;
}
-static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count) {
-
- struct bm_msg *dest = (struct bm_msg *) buf;
- int count = 0;
-
- if (brm->head == brm->tail) {
- return 0;
- }
+static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count)
+{
+ struct bm_msg *dest = (struct bm_msg *) buf;
+ int count = 0;
- do {
+ if (brm->head == brm->tail) {
+ return 0;
+ }
- DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail);
- dest[count++] = brm->bm_event[INDEX(brm->tail++)];
+ do {
- } while (brm->head != brm->tail && count < msg_count);
+ DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail);
+ dest[count++] = brm->bm_event[INDEX(brm->tail++)];
- return count;
+ } while (brm->head != brm->tail && count < msg_count);
+ return count;
}
static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- rtems_libio_rw_args_t *rw_args;
- int count = 0;
- brm_priv *brm = &brms[minor];
- int (*get_messages)(brm_priv *brm, void *buf, unsigned int count);
-
- if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){
- return RTEMS_INVALID_NAME;
- }
-
- rw_args = (rtems_libio_rw_args_t *) arg;
-
- if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */
- get_messages = get_rt_messages;
- }
- else { /* BM */
- get_messages = get_bm_messages;
- }
+ rtems_libio_rw_args_t *rw_args;
+ int count = 0;
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+ int (*get_messages)(brm_priv *brm, void *buf, unsigned int count);
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
- FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
+ if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){
+ return RTEMS_INVALID_NAME;
+ }
- while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) {
+ rw_args = (rtems_libio_rw_args_t *) arg;
- if (brm->rx_blocking) {
- rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- }
- else {
- /* Translates to EBUSY */
- return RTEMS_RESOURCE_IN_USE;
- }
+ if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */
+ get_messages = get_rt_messages;
+ } else { /* BM */
+ get_messages = get_bm_messages;
+ }
- }
+ FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
- rw_args->bytes_moved = count;
- return RTEMS_SUCCESSFUL;
+ while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) {
+ if (brm->rx_blocking) {
+ rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ /* Translates to EBUSY */
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
}
-
static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- rtems_libio_rw_args_t *rw_args;
- struct rt_msg *source;
- unsigned int count=0, current, next, descriptor, wc, suba;
- brm_priv *brm = &brms[minor];
-
- if ( ! (brm->mode & BRM_MODE_RT) ){
- return RTEMS_INVALID_NAME;
- }
-
- rw_args = (rtems_libio_rw_args_t *) arg;
- source = (struct rt_msg *) rw_args->buffer;
-
- FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
+ rtems_libio_rw_args_t *rw_args;
+ struct rt_msg *source;
+ unsigned int count=0, current, next, descriptor, wc, suba;
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
+
+ if ( ! (brm->mode & BRM_MODE_RT) ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ source = (struct rt_msg *) rw_args->buffer;
- do {
+ FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);
- descriptor = source[count].desc & 0x7F;
- suba = descriptor-32;
- wc = source[count].miw >> 11;
- wc = wc ? wc : 32;
+ do {
- /* Only subaddress transmission is allowed with write */
- if (descriptor < 32 || descriptor >= 64)
- return RTEMS_INVALID_NAME;
+ descriptor = source[count].desc & 0x7F;
+ suba = descriptor-32;
+ wc = source[count].miw >> 11;
+ wc = wc ? wc : 32;
- current = brm->desc[descriptor].cur;
- next = brm->written[suba] + 2 + wc;
+ /* Only subaddress transmission is allowed with write */
+ if (descriptor < 32 || descriptor >= 64)
+ return RTEMS_INVALID_NAME;
- if (brm->written[suba] < current) {
+ current = brm->desc[descriptor].cur;
+ next = brm->written[suba] + 2 + wc;
- if (next > current) {
+ if (brm->written[suba] < current) {
- /* No room in transmission buffer */
+ if (next > current) {
- if (brm->tx_blocking && count == 0) {
- rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- }
- else if ( brm->tx_blocking && (count != 0) ){
- /* return the number of messages sent so far */
- break;
- }
- else {
- /* Translates to posix EBUSY */
- return RTEMS_RESOURCE_IN_USE;
- }
- }
- }
+ /* No room in transmission buffer */
+ if (brm->tx_blocking && count == 0) {
+ rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else if ( count > 0 ) {
+ /* return the number of messages sent so far */
+ break;
+ } else {
+ /* Translates to posix EBUSY */
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ }
- memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2);
+ memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2);
- count++;
+ count++;
- if (next >= brm->desc[descriptor].bot) {
- next = brm->desc[descriptor].top;
- }
- brm->written[suba] = next;
+ if (next >= brm->desc[descriptor].bot) {
+ next = brm->desc[descriptor].top;
+ }
+ brm->written[suba] = next;
- } while (count < rw_args->count);
+ } while (count < rw_args->count);
- rw_args->bytes_moved = count;
+ rw_args->bytes_moved = count;
- if (count >= 0) {
- return RTEMS_SUCCESSFUL;
- }
- return RTEMS_UNSATISFIED;
+ if (count >= 0) {
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_UNSATISFIED;
}
static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
+
+ unsigned int i=0;
+ unsigned short ctrl, oper, cw1, cw2;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ unsigned int *data = ioarg->buffer;
+ struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer;
+ brm_priv *brm;
+ struct drvmgr_dev *dev;
+ rtems_device_driver ret;
+ int len, msglen;
+
+ FUNCDBG("brm_control[%d]: [%i,%i]\n", minor, major, minor);
+
+ if ( drvmgr_get_dev(&b1553brm_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ brm = (brm_priv *)dev->priv;
- unsigned int i=0;
- unsigned short ctrl, oper, cw1, cw2;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
- unsigned int *data = ioarg->buffer;
- struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer;
- brm_priv *brm = &brms[minor];
- rtems_device_driver ret;
- int len;
-
- FUNCDBG("brm_control[%d]: [%i,%i]\n",minor,major, minor);
-
- if (!ioarg) {
- DBG("brm_control: invalid argument\n");
- return RTEMS_INVALID_NAME;
- }
-
- ioarg->ioctl_return = 0;
- switch(ioarg->command) {
-
- case BRM_SET_MODE:
- if ( data[0] > 2 )
- return RTEMS_INVALID_NAME;
- stop_operation(brm);
- if (data[0] == 0) {
- ret = bc_init(brm);
- }
- else if (data[0] == 1) {
- ret = rt_init(brm);
- }
- else if (data[0] == 2) {
- ret = bm_init(brm);
- }else
- ret = RTEMS_INVALID_NAME;
-
- if ( ret != RTEMS_SUCCESSFUL)
- return ret;
-
- if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) )
- start_operation(brm);
- break;
-
- case BRM_SET_BUS:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xE7FF; /* Clear bit 12-11 ... */
- ctrl |= (data[0]&0x3)<<11; /* ... OR in new bus status */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_SET_MSGTO:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xFDFF; /* Clear bit 9 ... */
- ctrl |= (data[0]&1)<<9; /* ... OR in new MSGTO */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_SET_RT_ADDR:
- stop_operation(brm);
- oper = READ_REG(&brm->regs->oper);
- oper &= 0x03FF; /* Clear bit 15-10 ... */
- oper |= (data[0]&0x1f)<<11; /* ... OR in new address */
- oper |= odd_parity(data[0]&0x1f)<<10; /* ... OR in parity */
- brm->regs->oper = oper;
- start_operation(brm);
- break;
-
- case BRM_SET_STD:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xFF7F; /* Clear bit 7 ... */
- ctrl |= (data[0]&1)<<7; /* ... OR in new ABSTD (1=A) */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_SET_BCE:
- stop_operation(brm);
- ctrl = READ_REG(&brm->regs->ctrl);
- ctrl &= 0xFFEF; /* Clear bit 4 ... */
- ctrl |= (data[0]&1)<<4; /* ... OR in new BCE */
- brm->regs->ctrl = ctrl;
- start_operation(brm);
- break;
-
- case BRM_TX_BLOCK:
- brm->tx_blocking = data[0];
- break;
-
- case BRM_RX_BLOCK:
- brm->rx_blocking = data[0];
- break;
-
- case BRM_DO_LIST:
-
- if ( brm->mode != BRM_MODE_BC ){
- return RTEMS_INVALID_NAME;
- }
-
- /* Check if we are bus controller */
- if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
- return RTEMS_INVALID_NAME;
- }
-
- /* Already processing list? */
- if (is_executing(brm)) {
- return RTEMS_RESOURCE_IN_USE;
- }
-
- /* clear any earlier releases */
- rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT);
-
- brm->bc_list_fail = 0;
- brm->cur_list = cmd_list;
- brm->regs->dpoint = 0;
-
- i = 0;
- while ( (cmd_list[i].ctrl & BC_EOL) == 0) {
+ if (!ioarg) {
+ DBG("brm_control: invalid argument\n");
+ return RTEMS_INVALID_NAME;
+ }
- ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8);
+ ioarg->ioctl_return = 0;
+ switch (ioarg->command) {
- if (cmd_list[i].ctrl&BC_RTRT) {
- cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */
- cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */
- }
- else {
- cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f);
- cw2 = 0;
- }
+ case BRM_SET_MODE:
+ if ( data[0] > 2 )
+ return RTEMS_INVALID_NAME;
+ stop_operation(brm);
+ if (data[0] == 0) {
+ ret = bc_init(brm);
+ } else if (data[0] == 1) {
+ ret = rt_init(brm);
+ } else if (data[0] == 2) {
+ ret = bm_init(brm);
+ } else {
+ ret = RTEMS_INVALID_NAME;
+ }
+ if ( ret != RTEMS_SUCCESSFUL)
+ return ret;
+
+ if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) )
+ start_operation(brm);
+ break;
+
+ case BRM_SET_BUS:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xE7FF; /* Clear bit 12-11 ... */
+ ctrl |= (data[0]&0x3)<<11; /* ... OR in new bus status */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_MSGTO:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xFDFF; /* Clear bit 9 ... */
+ ctrl |= (data[0]&1)<<9; /* ... OR in new MSGTO */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_RT_ADDR:
+ stop_operation(brm);
+ oper = READ_REG(&brm->regs->oper);
+ oper &= 0x03FF; /* Clear bit 15-10 ... */
+ oper |= (data[0]&0x1f)<<11; /* ... OR in new address */
+ oper |= odd_parity(data[0]&0x1f)<<10; /* ... OR in parity */
+ brm->regs->oper = oper;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_STD:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xFF7F; /* Clear bit 7 ... */
+ ctrl |= (data[0]&1)<<7; /* ... OR in new ABSTD (1=A) */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_SET_BCE:
+ stop_operation(brm);
+ ctrl = READ_REG(&brm->regs->ctrl);
+ ctrl &= 0xFFEF; /* Clear bit 4 ... */
+ ctrl |= (data[0]&1)<<4; /* ... OR in new BCE */
+ brm->regs->ctrl = ctrl;
+ start_operation(brm);
+ break;
+
+ case BRM_TX_BLOCK:
+ brm->tx_blocking = data[0];
+ break;
+
+ case BRM_RX_BLOCK:
+ brm->rx_blocking = data[0];
+ break;
+
+ case BRM_DO_LIST:
+ if ( brm->mode != BRM_MODE_BC ){
+ return RTEMS_INVALID_NAME;
+ }
+ /* Check if we are bus controller */
+ if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
+ return RTEMS_INVALID_NAME;
+ }
- /* Set up command block */
- brm->bcmem->descs[i].ctrl = ctrl;
- brm->bcmem->descs[i].cw1 = cw1;
- brm->bcmem->descs[i].cw2 = cw2;
- /* data pointer:
- * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2
- */
- brm->bcmem->descs[i].dptr = 1024+i*32; /* data pointer */
- brm->bcmem->descs[i].tsw[0] = 0;
- brm->bcmem->descs[i].tsw[1] = 0;
- brm->bcmem->descs[i].ba = 0;
- brm->bcmem->descs[i].timer = 0;
+ /* Already processing list? */
+ if (is_executing(brm)) {
+ return RTEMS_RESOURCE_IN_USE;
+ }
- memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], cmd_list[i].wc*2);
+ /* clear any earlier releases */
+ rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT);
+
+ brm->bc_list_fail = 0;
+ brm->cur_list = cmd_list;
+ brm->regs->dpoint = 0;
+
+ i = 0;
+ while ( (cmd_list[i].ctrl & BC_EOL) == 0) {
+
+ ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8);
+
+ if (cmd_list[i].ctrl&BC_RTRT) {
+ cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */
+ cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */
+ } else {
+ cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f);
+ cw2 = 0;
+ }
+
+ /* Set up command block */
+ brm->bcmem->descs[i].ctrl = ctrl;
+ brm->bcmem->descs[i].cw1 = cw1;
+ brm->bcmem->descs[i].cw2 = cw2;
+ /* data pointer:
+ * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2
+ */
+ brm->bcmem->descs[i].dptr = 1024+i*32; /* data pointer */
+ brm->bcmem->descs[i].tsw[0] = 0;
+ brm->bcmem->descs[i].tsw[1] = 0;
+ brm->bcmem->descs[i].ba = 0;
+ brm->bcmem->descs[i].timer = 0;
+
+ msglen = cmd_list[i].wc;
+ if ( msglen == 0 )
+ msglen = 32;
+ memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], msglen*2);
+
+ i++;
+ }
- i++;
- }
+ brm->bcmem->descs[i].ctrl = 0; /* end of list */
- brm->bcmem->descs[i].ctrl = 0; /* end of list */
+ start_operation(brm);
+ break;
- start_operation(brm);
+ case BRM_LIST_DONE:
- break;
+ if ( brm->mode != BRM_MODE_BC ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Check if we are bus controller */
+ if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
+ return RTEMS_INVALID_NAME;
+ }
- case BRM_LIST_DONE:
+ if (is_executing(brm)) {
- if ( brm->mode != BRM_MODE_BC ){
- return RTEMS_INVALID_NAME;
+ data[0] = 0;
+ if (brm->tx_blocking) {
+ rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ data[0] = 1;
+ if ( brm->bc_list_fail ){
+ return RTEMS_INVALID_NAME;
}
+ } else {
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ } else {
+ data[0] = 1; /* done */
+ }
- /* Check if we are bus controller */
- if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
- return RTEMS_INVALID_NAME;
- }
-
- if (is_executing(brm)) {
-
- data[0] = 0;
- if (brm->tx_blocking) {
- rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- data[0] = 1;
- if ( brm->bc_list_fail ){
- return RTEMS_INVALID_NAME;
- }
- }else{
- return RTEMS_RESOURCE_IN_USE;
- }
-
-
- }
- else {
- data[0] = 1; /* done */
- }
-
- /* copy finished list results back into bc_msg array */
- i = 0;
- while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) {
-
- if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) {
- brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */
- }
- if (brm->cur_list[i].ctrl & BC_TR) {
- /* RT Transmit command, copy received data */
- len = brm->cur_list[i].wc;
- while( len-- > 0){
- brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]);
- }
- }
- brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]);
- brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]);
-
- i++;
- }
- break;
-
-
- case BRM_CLR_STATUS:
- brm->status = 0;
- break;
+ /* copy finished list results back into bc_msg array */
+ i = 0;
+ while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) {
+ if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) {
+ brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */
+ }
+ if (brm->cur_list[i].ctrl & BC_TR) {
+ /* RT Transmit command, copy received data */
+ len = brm->cur_list[i].wc;
+ if ( len == 0 )
+ len = 32;
+ while ( len-- > 0) {
+ brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]);
+ }
+ }
+ brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]);
+ brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]);
- case BRM_GET_STATUS: /* copy status */
+ i++;
+ }
+ break;
- if ( !ioarg->buffer )
- return RTEMS_INVALID_NAME;
+ case BRM_CLR_STATUS:
+ brm->status = 0;
+ break;
- *(unsigned int *)ioarg->buffer = brm->status;
- break;
+ case BRM_GET_STATUS: /* copy status */
+ if ( !ioarg->buffer )
+ return RTEMS_INVALID_NAME;
+ *(unsigned int *)ioarg->buffer = brm->status;
+ break;
+
case BRM_SET_EVENTID:
- brm->event_id = (rtems_id)ioarg->buffer;
- break;
+ brm->event_id = (rtems_id)ioarg->buffer;
+ break;
- default:
- return RTEMS_NOT_DEFINED;
- }
- return RTEMS_SUCCESSFUL;
-}
-
-#ifdef B1553BRM_DEFINE_INTHANDLER
-static void b1553brm_interrupt_handler(rtems_vector_number v){
- int i;
- /* find minor */
- for(i=0; i<brm_cores; i++){
- if ( (brms[i].irqno+0x10) == v ){
- brm_interrupt(&brms[i]);
- return;
- }
+ default:
+ return RTEMS_NOT_DEFINED;
}
+ return RTEMS_SUCCESSFUL;
}
-#endif
-static void brm_interrupt(brm_priv *brm) {
- unsigned short descriptor, current, pending, miw, wc, tmp;
+static void b1553brm_interrupt(void *arg)
+{
+ brm_priv *brm = arg;
+ unsigned short descriptor, current, pending, miw, wc, tmp, ctrl;
unsigned short msgadr, iaw, iiw;
int len;
- int signal_event=0;
+ int signal_event=0, wake_rx_task=0, wake_tx_task=0;
unsigned int event_status=0;
+ int accessed;
#define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16)
-
- while( (iiw=READ_REG(&brm->irq_log[brm->irq].iiw)) != 0xffff ){
- iaw=READ_REG(&brm->irq_log[brm->irq].iaw);
-
+
+ while( (iiw=READ_DMA(&brm->irq_log[brm->irq].iiw)) != 0xffff ){
+ iaw=READ_DMA(&brm->irq_log[brm->irq].iaw);
+
/* indicate that the interrupt log entry has been processed */
brm->irq_log[brm->irq].iiw = 0xffff;
/* Interpret interrupt log entry */
- descriptor = iaw >> 2;
- pending = iiw;
- brm->irq = (brm->irq + 1) % 16;
-
+ descriptor = iaw >> 2;
+ pending = iiw;
+ brm->irq = (brm->irq + 1) % 16;
+
/* Clear the log so that we */
- /* Subaddress accessed irq (RT only)
- *
- * Can be either a receive or transmit command
- * as well as a mode code.
- */
- if (pending & BRM_SUBAD_IRQ) {
-
- /* Pointer to next free message in circular buffer */
- current = READ_DMA(&brm->desc[descriptor].cur);
-
- while ( (msgadr=brm->last_read[descriptor]) != current) {
-
- /* Get word count */
- miw = READ_DMA(&brm->mem[msgadr]);
- wc = miw >> 11;
-
- /* Data received */
- if (descriptor < 32) {
- wc = wc ? wc : 32;
- }
- /* Data transmitted */
- else if (descriptor < 64) {
- wc = wc ? wc : 32;
- rtems_semaphore_release(brm->tx_sem);
- }
- /* RX Mode code */
- else if (descriptor < 96) {
- wc = (wc>>4);
- }
- /* TX Mode code */
- else if (descriptor < 128) {
- wc = (wc>>4);
- }
-
+ /* Subaddress accessed irq (RT only)
+ *
+ * Can be either a receive or transmit command
+ * as well as a mode code.
+ */
+ if (pending & BRM_SUBAD_IRQ) {
+
+ /* Pointer to next free message in circular buffer */
+ current = READ_DMA(&brm->desc[descriptor].cur);
+ ctrl = READ_DMA(&brm->desc[descriptor].ctrl);
#ifdef DEBUG
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc;
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (0xff<<16);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = ctrl;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = 0;
#endif
+ accessed = ctrl & 0x10;
+ /* Note that current may be equal to bot and top when
+ * circular buffer one can handle one message.
+ */
+ if ( accessed )
+ do {
+ msgadr = brm->last_read[descriptor];
+
+ /* Get word count */
+ miw = READ_DMA(&brm->mem[msgadr]);
+ wc = miw >> 11;
+
+ /* Data received */
+ if (descriptor < 32) {
+ wc = wc ? wc : 32;
+ }
+ /* Data transmitted */
+ else if (descriptor < 64) {
+ wc = wc ? wc : 32;
+ wake_tx_task=1;
+ }
+ /* RX Mode code */
+ else if (descriptor < 96) {
+ wc = (wc>>4);
+ }
+ /* TX Mode code */
+ else if (descriptor < 128) {
+ wc = (wc>>4);
+ }
- /* If there is room in the event queue, copy the event there */
- if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
-
- /* Copy to event queue */
- brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]);
- brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]);
- len = wc;
- while( len-- > 0){
- brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]);
- }
- brm->rt_event[INDEX(brm->head)].desc = descriptor;
- brm->head++;
+#ifdef DEBUG
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
+#endif
- }
- else {
- /* Indicate overrun */
- brm->rt_event[INDEX(brm->head)].desc |= 0x8000;
- }
+ /* If there is room in the event queue, copy the event there */
+ if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
+
+ /* Copy to event queue */
+ brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]);
+ brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]);
+ len = wc;
+ while( len-- > 0){
+ brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]);
+ }
+ brm->rt_event[INDEX(brm->head)].desc = descriptor;
+ brm->head++;
+ }
+ else {
+ /* Indicate overrun */
+ brm->rt_event[INDEX(brm->head)].desc |= 0x8000;
+ }
- msgadr += (2+wc);
+ msgadr += (2+wc);
- if (msgadr >= brm->desc[descriptor].bot) {
- msgadr = brm->desc[descriptor].top;
- }
- brm->last_read[descriptor] = msgadr;
+ if (msgadr >= READ_DMA(&brm->desc[descriptor].bot)) {
+ msgadr = READ_DMA(&brm->desc[descriptor].top);
+ }
+ brm->last_read[descriptor] = msgadr;
#ifdef DEBUG
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
#endif
+ wake_rx_task = 1;
+ } while ( (msgadr=brm->last_read[descriptor]) != current );
+ }
- /* Wake any blocked rx thread */
- rtems_semaphore_release(brm->rx_sem);
-
- }
-
- }
-
- if (pending & BRM_EOL_IRQ) {
- rtems_semaphore_release(brm->tx_sem);
- }
-
- if (pending & BRM_BC_ILLCMD_IRQ) {
- brm->bc_list_fail = 1;
- rtems_semaphore_release(brm->tx_sem);
- SET_ERROR_DESCRIPTOR(descriptor);
- FUNCDBG("BRM: ILLCMD IRQ\n\r");
- }
-
- /* Monitor irq */
- if (pending & BRM_MBC_IRQ) {
-
- stop_operation(brm);
- brm->regs->mbc = 1;
- start_operation(brm);
-
- /* If there is room in the event queue, copy the event there */
- if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
-
- /* Copy to event queue */
+ if (pending & BRM_EOL_IRQ) {
+ wake_tx_task = 1;
+ }
- brm->bm_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[0]);
- brm->bm_event[INDEX(brm->head)].cw1 = READ_DMA(&brm->mem[1]);
- brm->bm_event[INDEX(brm->head)].cw2 = READ_DMA(&brm->mem[2]);
- brm->bm_event[INDEX(brm->head)].sw1 = READ_DMA(&brm->mem[4]);
- brm->bm_event[INDEX(brm->head)].sw2 = READ_DMA(&brm->mem[5]);
- brm->bm_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[6]);
+ if (pending & BRM_BC_ILLCMD_IRQ) {
+ brm->bc_list_fail = 1;
+ wake_tx_task = 1;
+ SET_ERROR_DESCRIPTOR(descriptor);
+ FUNCDBG("BRM: ILLCMD IRQ\n\r");
+ }
- len = 32;
- while ( len-- ){
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- len--;
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- len--;
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- len--;
- brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
- }
-/* memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/
+ /* Monitor irq */
+ if (pending & BRM_MBC_IRQ) {
+
+ stop_operation(brm);
+ brm->regs->mbc = 1;
+ start_operation(brm);
+
+ /* If there is room in the event queue, copy the event there */
+ if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {
+
+ /* Copy to event queue */
+
+ brm->bm_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[0]);
+ brm->bm_event[INDEX(brm->head)].cw1 = READ_DMA(&brm->mem[1]);
+ brm->bm_event[INDEX(brm->head)].cw2 = READ_DMA(&brm->mem[2]);
+ brm->bm_event[INDEX(brm->head)].sw1 = READ_DMA(&brm->mem[4]);
+ brm->bm_event[INDEX(brm->head)].sw2 = READ_DMA(&brm->mem[5]);
+ brm->bm_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[6]);
+
+ len = 32;
+ while ( len-- ){
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ len--;
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ len--;
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ len--;
+ brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]);
+ }
+/* memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/
#ifdef DEBUG
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc);
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]);
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]);
- brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc) & 0xffff;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]);
#endif
- brm->head++;
-
- }
- else {
- /* Indicate overrun */
- brm->rt_event[INDEX(brm->head)].miw |= 0x8000;
- }
+ brm->head++;
- /* Wake any blocking thread */
- rtems_semaphore_release(brm->rx_sem);
+ }
+ else {
+ /* Indicate overrun */
+ brm->bm_event[INDEX(brm->head)].miw |= 0x8000;
+ }
- }
+ /* Wake any blocking thread */
+ wake_rx_task = 1;
+ }
- /* The reset of the interrupts
+ /* The reset of the interrupts
* cause a event to be signalled
* so that user can handle error.
*/
@@ -1317,9 +1394,9 @@ static void brm_interrupt(brm_priv *brm) {
if ( pending & BRM_ILLOP_IRQ){
FUNCDBG("BRM: BRM_ILLOP_IRQ\n\r");
brm->bc_list_fail = 1;
- rtems_semaphore_release(brm->tx_sem);
+ wake_tx_task = 1;
event_status |= BRM_ILLOP_IRQ;
- SET_ERROR_DESCRIPTOR(descriptor);
+ SET_ERROR_DESCRIPTOR(descriptor);
signal_event=1;
}
@@ -1329,10 +1406,15 @@ static void brm_interrupt(brm_priv *brm) {
SET_ERROR_DESCRIPTOR(descriptor);
signal_event=1;
}
- /* Clear Block Accessed Bit */
- tmp = READ_REG(&brm->desc[descriptor].ctrl);
- brm->desc[descriptor].ctrl = tmp & ~0x10;
-
+ /* Clear Block Accessed Bit */
+ tmp = READ_DMA(&brm->desc[descriptor].ctrl);
+ brm->desc[descriptor].ctrl = tmp & ~0x10;
+#ifdef DEBUG
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (0xfe<<16);
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = 0;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = tmp & ~0x10;
+ brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = tmp;
+#endif
} /* While */
/* clear interrupt flags & handle Hardware errors */
@@ -1363,9 +1445,88 @@ static void brm_interrupt(brm_priv *brm) {
brm->status |= event_status;
}
+ /* Wake any blocked rx thread only on receive interrupts */
+ if ( wake_rx_task ) {
+ rtems_semaphore_release(brm->rx_sem);
+ }
+
+ /* Wake any blocked tx thread only on transmit interrupts */
+ if ( wake_tx_task ) {
+ rtems_semaphore_release(brm->tx_sem);
+ }
+
/* signal event once */
if ( signal_event && (brm->event_id!=0) ){
rtems_event_send(brm->event_id, event_status);
}
}
+
+void b1553brm_print_dev(struct drvmgr_dev *dev, int options)
+{
+ brm_priv *pDev = dev->priv;
+ struct amba_dev_info *devinfo;
+ struct brm_reg *regs = pDev->regs;
+
+ devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+ /* Print */
+ printf("--- B1553BRM[%d] %s ---\n", pDev->minor, pDev->devName);
+ printf(" REGS: 0x%x\n", (unsigned int)pDev->regs);
+ printf(" IRQ: %d\n", pDev->irqno);
+ switch (pDev->mode) {
+ case BRM_MODE_BC:
+ printf(" MODE: BC\n");
+ printf(" DESCS: 0x%x\n", (unsigned int)&pDev->bcmem->descs[0]);
+ printf(" DATA: 0x%x\n", (unsigned int)&pDev->bcmem->msg_data[0].data[0]);
+ printf(" IRQLOG: 0x%x\n", (unsigned int)&pDev->bcmem->irq_logs[0]);
+ break;
+ case BRM_MODE_BM:
+ printf(" MODE: BM\n");
+ break;
+ case BRM_MODE_RT:
+ printf(" MODE: RT\n");
+ printf(" RXSUBS: 0x%x\n", (unsigned int)&pDev->rtmem->rxsubs[0]);
+ printf(" TXSUBS: 0x%x\n", (unsigned int)&pDev->rtmem->txsubs[0]);
+ printf(" RXMODES: 0x%x\n", (unsigned int)&pDev->rtmem->rxmodes[0]);
+ printf(" TXOMODES: 0x%x\n", (unsigned int)&pDev->rtmem->txmodes[0]);
+ printf(" RXSUBS MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->rxsuba_msgs[0]);
+ printf(" TXSUBS MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->txsuba_msgs[0]);
+ printf(" RXMODES MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->rxmode_msgs[0]);
+ printf(" TXMODES MSGS: 0x%x\n", (unsigned int)&pDev->rtmem->txmode_msgs[0]);
+ printf(" IRQLOG: 0x%x\n", (unsigned int)&pDev->rtmem->irq_logs[0]);
+ break;
+ }
+ printf(" CTRL: 0x%x\n", regs->ctrl);
+ printf(" OPER: 0x%x\n", regs->oper);
+ printf(" CUR_CMD: 0x%x\n", regs->cur_cmd);
+ printf(" IMASK: 0x%x\n", regs->imask);
+ printf(" IPEND: 0x%x\n", regs->ipend);
+ printf(" IPOINT: 0x%x\n", regs->ipoint);
+ printf(" BIT_REG: 0x%x\n", regs->bit_reg);
+ printf(" TTAG: 0x%x\n", regs->ttag);
+ printf(" DPOINT: 0x%x\n", regs->dpoint);
+ printf(" SW: 0x%x\n", regs->sw);
+ printf(" INITCOUNT: 0x%x\n", regs->initcount);
+ printf(" MCPOINT: 0x%x\n", regs->mcpoint);
+ printf(" MDPOINT: 0x%x\n", regs->mdpoint);
+ printf(" MBC: 0x%x\n", regs->mbc);
+ printf(" MFILTA: 0x%x\n", regs->mfilta);
+ printf(" MFILTB: 0x%x\n", regs->mfiltb);
+ printf(" ENHANCED: 0x%x\n", regs->enhanced);
+ printf(" W_CTRL: 0x%x\n", regs->w_ctrl);
+ printf(" W_IRQCTRL: 0x%x\n", regs->w_irqctrl);
+ printf(" W_AHBADDR: 0x%x\n", regs->w_ahbaddr);
+}
+
+void b1553brm_print(int options)
+{
+ struct amba_drv_info *drv = &b1553brm_drv_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ b1553brm_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan.c b/c/src/lib/libbsp/sparc/shared/can/grcan.c
index 7833f8c..7ad53e1 100644
--- a/c/src/lib/libbsp/sparc/shared/can/grcan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/grcan.c
@@ -1,19 +1,12 @@
/*
* GRCAN driver
- */
-
-/*
+ *
* COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * 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.org/license/LICENSE.
- *
- *
- * 2007-06-13, Daniel Hellstrom <daniel at gaisler.com>
- * New driver in sparc shared directory. Parts taken
- * from rasta grhcan driver.
*/
#include <bsp.h>
@@ -26,22 +19,26 @@
#include <rtems/bspIo.h>
#include <grcan.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <ambapp.h>
-#include <grlib.h>
#define WRAP_AROUND_TX_MSGS 1
#define WRAP_AROUND_RX_MSGS 2
#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
#define BLOCK_SIZE (16*4)
+/* grcan needs to have it buffers aligned to 1k boundaries */
+#define BUFFER_ALIGNMENT_NEEDS 1024
+
/* Default Maximium buffer size for statically allocated buffers */
#ifndef TX_BUF_SIZE
-#define TX_BUF_SIZE (BLOCK_SIZE*16)
+ #define TX_BUF_SIZE (BLOCK_SIZE*16)
#endif
/* Make receiver buffers bigger than transmitt */
#ifndef RX_BUF_SIZE
-#define RX_BUF_SIZE ((3*BLOCK_SIZE)*16)
+ #define RX_BUF_SIZE ((3*BLOCK_SIZE)*16)
#endif
#ifndef IRQ_GLOBAL_PREPARE
@@ -68,35 +65,13 @@
#define IRQ_MASK(irqno)
#endif
-#ifndef GRCAN_PREFIX
- #define GRCAN_PREFIX(name) grcan##name
-#endif
-
-#ifndef MEMAREA_TO_HW
- #define MEMAREA_TO_HW(x) (x)
-#endif
-
-/* default name to /dev/grcan0 */
-#if !defined(GRCAN_DEVNAME) || !defined(GRCAN_DEVNAME_NO)
- #undef GRCAN_DEVNAME
- #undef GRCAN_DEVNAME_NO
- #define GRCAN_DEVNAME "/dev/grcan0"
- #define GRCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-#endif
-
-#ifndef GRCAN_REG_INT
- #define GRCAN_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1)
- #undef GRCAN_DEFINE_INTHANDLER
- #define GRCAN_DEFINE_INTHANDLER
-#endif
-
#ifndef GRCAN_DEFAULT_BAUD
- /* default to 500kbits/s */
- #define GRCAN_DEFAULT_BAUD 500000
+ /* default to 500kbits/s */
+ #define GRCAN_DEFAULT_BAUD 500000
#endif
#ifndef GRCAN_SAMPLING_POINT
-#define GRCAN_SAMPLING_POINT 80
+ #define GRCAN_SAMPLING_POINT 80
#endif
/* Uncomment for debug output */
@@ -114,63 +89,9 @@
/*********************************************************/
-/* grcan needs to have it buffers aligned to 1k boundaries */
-#define BUFFER_ALIGNMENT_NEEDS 1024
-
-#ifdef STATICALLY_ALLOCATED_TX_BUFFER
-static unsigned int tx_circbuf[GRCAN_MAX_CORES][TX_BUF_SIZE]
- __attribute__ ((aligned(BUFFER_ALIGNMENT_NEEDS)));
-#define STATIC_TX_BUF_SIZE TX_BUF_SIZE
-#define STATIC_TX_BUF_ADDR(core) (&tx_circbuf[(core)][0])
-#endif
-
-#ifdef STATICALLY_ALLOCATED_RX_BUFFER
-static unsigned int rx_circbuf[GRCAN_MAX_CORES][RX_BUF_SIZE]
- __attribute__ ((aligned(BUFFER_ALIGNMENT_NEEDS)));
-#define STATIC_RX_BUF_SIZE RX_BUF_SIZE
-#define STATIC_RX_BUF_ADDR(core) (&rx_circbuf[(core)][0])
-#endif
-
-/*
- * If USE_AT697_RAM is defined the RAM on the AT697 board will be used for DMA buffers (but rx message queue is always in AT697 ram).
- * USE_AT697_DMA specifies whether the messages will be fetched using DMA or PIO.
- *
- * RASTA_PCI_BASE is the base address of the GRPCI AHB slave
- *
- * GRCAN_BUF_SIZE must be set to the size (in bytes) of the GRCAN DMA buffers.
- *
- * RX_QUEUE_SIZE defines the number of messages that fits in the RX message queue. On RX interrupts the messages in the DMA buffer
- * are copied into the message queue (using dma if the rx buf is not in the AT697 ram).
- */
-
-/*#define USE_AT697_RAM 1 */
-#define USE_AT697_DMA 1
-#define RASTA_PCI_BASE 0xe0000000
-#define GRCAN_BUF_SIZE 4096
-#define RX_QUEUE_SIZE 1024
-
-#define INDEX(x) ( x&(RX_QUEUE_SIZE-1) )
-
-/* pa(x)
- *
- * x: address in AT697 address space
- *
- * returns the address in the RASTA address space that can be used to access x with dma.
- *
-*/
-#ifdef USE_AT697_RAM
-static inline unsigned int pa(unsigned int addr) {
- return ((addr & 0x0fffffff) | RASTA_PCI_BASE);
-}
-#else
-static inline unsigned int pa(unsigned int addr) {
- return ((addr & 0x0fffffff) | 0x40000000);
-}
-#endif
-
struct grcan_msg {
- unsigned int head[2];
- unsigned char data[8];
+ unsigned int head[2];
+ unsigned char data[8];
};
struct grcan_config {
@@ -181,43 +102,41 @@ struct grcan_config {
};
struct grcan_priv {
- unsigned int baseaddr, ram_base;
- struct grcan_regs *regs;
- int irq;
- int minor;
- int open;
- int started;
- unsigned int channel;
- int flushing;
- unsigned int corefreq_hz;
-
- /* Circular DMA buffers */
- void *_rx;
- void *_tx;
- struct grcan_msg *rx;
- struct grcan_msg *tx;
- unsigned int rxbuf_size; /* requested RX buf size in bytes */
- unsigned int txbuf_size; /* requested TX buf size in bytes */
-
- int txblock, rxblock;
- int txcomplete, rxcomplete;
- int txerror, rxerror;
-
- struct grcan_filter sfilter;
- struct grcan_filter afilter;
- int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
- struct grcan_config config;
- struct grcan_stats stats;
-
- rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ unsigned int baseaddr, ram_base;
+ struct grcan_regs *regs;
+ int irq;
+ int minor;
+ int open;
+ int started;
+ unsigned int channel;
+ int flushing;
+ unsigned int corefreq_hz;
+
+ /* Circular DMA buffers */
+ void *_rx, *_rx_hw;
+ void *_tx, *_tx_hw;
+ void *txbuf_adr;
+ void *rxbuf_adr;
+ struct grcan_msg *rx;
+ struct grcan_msg *tx;
+ unsigned int rxbuf_size; /* requested RX buf size in bytes */
+ unsigned int txbuf_size; /* requested TX buf size in bytes */
+
+ int txblock, rxblock;
+ int txcomplete, rxcomplete;
+ int txerror, rxerror;
+
+ struct grcan_filter sfilter;
+ struct grcan_filter afilter;
+ int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
+ struct grcan_config config;
+ struct grcan_stats stats;
+
+ rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
};
-static int grcan_core_cnt;
-struct grcan_priv *grcans;
-static struct ambapp_bus *amba_bus;
-struct grcan_device_info *grcan_cores;
-static int grcan_core_cnt;
-
static rtems_device_driver grcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
@@ -227,6 +146,8 @@ static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_de
#define GRCAN_DRIVER_TABLE_ENTRY { grcan_initialize, grcan_open, grcan_close, grcan_read, grcan_write, grcan_ioctl }
+static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
+
static unsigned int grcan_hw_read_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
@@ -251,11 +172,7 @@ static void grcan_hw_sync(
struct grcan_regs *regs,
struct grcan_filter *sfilter);
-#ifndef GRCAN_DONT_DECLARE_IRQ_HANDLER
-static rtems_isr grcan_interrupt_handler(rtems_vector_number v);
-#endif
-
-static void grcan_interrupt(struct grcan_priv *pDev);
+static void grcan_interrupt(void *arg);
#ifdef GRCAN_REG_BYPASS_CACHE
#define READ_REG(address) _grcan_read_nocache((unsigned int)(address))
@@ -268,12 +185,12 @@ static void grcan_interrupt(struct grcan_priv *pDev);
#define READ_DMA_BYTE(address) _grcan_read_nocache_byte((unsigned int)(address))
static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address)
{
- unsigned char tmp;
- __asm__ (" lduba [%1]1, %0 "
- : "=r"(tmp)
- : "r"(address)
- );
- return tmp;
+ unsigned char tmp;
+ __asm__ (" lduba [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(address)
+ );
+ return tmp;
}
#else
#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
@@ -283,17 +200,228 @@ static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address)
#if defined(GRCAN_REG_BYPASS_CACHE) || defined(GRCAN_DMA_BYPASS_CACHE)
static unsigned int __inline__ _grcan_read_nocache(unsigned int address)
{
- unsigned int tmp;
- __asm__ (" lda [%1]1, %0 "
- : "=r"(tmp)
- : "r"(address)
- );
- return tmp;
+ unsigned int tmp;
+ __asm__ (" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(address)
+ );
+ return tmp;
}
#endif
static rtems_driver_address_table grcan_driver = GRCAN_DRIVER_TABLE_ENTRY;
+static int grcan_driver_io_registered = 0;
+static rtems_device_major_number grcan_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int grcan_register_io(rtems_device_major_number *m);
+int grcan_device_init(struct grcan_priv *pDev);
+
+int grcan_init2(struct drvmgr_dev *dev);
+int grcan_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grcan_ops =
+{
+ .init = {NULL, grcan_init2, grcan_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grcan_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRCAN},
+ {VENDOR_GAISLER, GAISLER_GRHCAN},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grcan_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRCAN_ID, /* Driver ID */
+ "GRCAN_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grcan_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grcan_ids[0]
+};
+
+void grcan_register_drv (void)
+{
+ DBG("Registering GRCAN driver\n");
+ drvmgr_drv_register(&grcan_drv_info.general);
+}
+
+int grcan_init2(struct drvmgr_dev *dev)
+{
+ struct grcan_priv *priv;
+
+ DBG("GRCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(struct grcan_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int grcan_init3(struct drvmgr_dev *dev)
+{
+ struct grcan_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grcan_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grcan_register_io(&grcan_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ grcan_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( grcan_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grcan%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrcan%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grcan_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int grcan_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grcan_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("GRCAN driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRCAN rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int grcan_device_init(struct grcan_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (struct grcan_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->corefreq_hz) ) {
+ return -1;
+ }
+
+ DBG("GRCAN frequency: %d Hz\n", pDev->corefreq_hz);
+
+ /* Reset Hardware before attaching IRQ handler */
+ grcan_hw_reset(pDev->regs);
+
+ /* RX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'R', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rx_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* TX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'T', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->tx_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* TX Empty Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'E', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->txempty_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'A', '0' + pDev->minor),
+ 1,
+ RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+ RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->dev_sem) != RTEMS_SUCCESSFUL ) {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ return 0;
+}
static void __inline__ grcan_hw_reset(struct grcan_regs *regs)
{
@@ -325,11 +453,11 @@ static rtems_device_driver grcan_start(struct grcan_priv *pDev)
}
/* Setup receiver */
- pDev->regs->rx0addr = MEMAREA_TO_HW((unsigned int)pDev->rx);
+ pDev->regs->rx0addr = (unsigned int)pDev->_rx_hw;
pDev->regs->rx0size = pDev->rxbuf_size;
/* Setup Transmitter */
- pDev->regs->tx0addr = MEMAREA_TO_HW((unsigned int)pDev->tx);
+ pDev->regs->tx0addr = (unsigned int)pDev->_tx_hw;
pDev->regs->tx0size = pDev->txbuf_size;
/* Setup acceptance filters */
@@ -875,7 +1003,7 @@ static int grcan_wait_txspace(
IRQ_GLOBAL_DISABLE(oldLevel);
- /*pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;*/
+ pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
size = READ_REG(&pDev->regs->tx0size);
wp = READ_REG(&pDev->regs->tx0wr);
@@ -972,851 +1100,720 @@ static int grcan_tx_flush(struct grcan_priv *pDev)
static int grcan_alloc_buffers(struct grcan_priv *pDev, int rx, int tx)
{
- FUNCDBG();
-
- if ( tx ) {
-#ifdef STATIC_TX_BUF_ADDR
- pDev->_tx = STATIC_TX_BUF_ADDR(pDev->minor);
- if ( pDev->txbuf_size > STATIC_TX_BUF_SIZE ){
- pDev->txbuf_size = STATIC_TX_BUF_SIZE;
- return -1;
- }
- /* Assume aligned buffer */
- pDev->tx = (struct grcan_msg *)pDev->_tx;
-#else
- pDev->_tx = malloc(pDev->txbuf_size + BUFFER_ALIGNMENT_NEEDS);
- if ( !pDev->_tx )
- return -1;
-
- /* Align TX buffer */
- pDev->tx = (struct grcan_msg *)
- (((unsigned int)pDev->_tx + (BUFFER_ALIGNMENT_NEEDS-1)) &
- ~(BUFFER_ALIGNMENT_NEEDS-1));
-#endif
- }
-
- if ( rx ) {
-#ifdef STATIC_RX_BUF_ADDR
- pDev->_rx = STATIC_RX_BUF_ADDR(pDev->minor);
- if ( pDev->rxbuf_size > STATIC_RX_BUF_SIZE ){
- pDev->rxbuf_size = STATIC_RX_BUF_SIZE;
- return -1;
- }
- /* Assume aligned buffer */
- pDev->rx = (struct grcan_msg *)pDev->_rx;
-#else
- pDev->_rx = malloc(pDev->rxbuf_size + BUFFER_ALIGNMENT_NEEDS);
- if ( !pDev->_rx )
- return -1;
+ unsigned int adr;
+ FUNCDBG();
+
+ if ( tx ) {
+ adr = (unsigned int)pDev->txbuf_adr;
+ if (adr & 0x1) {
+ /* User defined "remote" address. Translate it into
+ * a CPU accessible address
+ */
+ pDev->_tx_hw = (void *)(adr & ~0x1);
+ drvmgr_translate_check(
+ pDev->dev,
+ DMAMEM_TO_CPU,
+ (void *)pDev->_tx_hw,
+ (void **)&pDev->_tx,
+ pDev->txbuf_size);
+ pDev->tx = (struct grcan_msg *)pDev->_tx;
+ } else {
+ if (adr == 0) {
+ pDev->_tx = malloc(pDev->txbuf_size +
+ BUFFER_ALIGNMENT_NEEDS);
+ if (!pDev->_tx)
+ return -1;
+ } else {
+ /* User defined "cou-local" address. Translate
+ * it into a CPU accessible address
+ */
+ pDev->_tx = (void *)adr;
+ }
+ /* Align TX buffer */
+ pDev->tx = (struct grcan_msg *)
+ (((unsigned int)pDev->_tx +
+ (BUFFER_ALIGNMENT_NEEDS-1)) &
+ ~(BUFFER_ALIGNMENT_NEEDS-1));
+
+ /* Translate address into an hardware accessible
+ * address
+ */
+ drvmgr_translate_check(
+ pDev->dev,
+ CPUMEM_TO_DMA,
+ (void *)pDev->tx,
+ (void **)&pDev->_tx_hw,
+ pDev->txbuf_size);
+ }
+ }
- /* Align TX buffer */
- pDev->rx = (struct grcan_msg *)
- (((unsigned int)pDev->_rx + (BUFFER_ALIGNMENT_NEEDS-1)) &
- ~(BUFFER_ALIGNMENT_NEEDS-1));
-#endif
- }
- return 0;
+ if ( rx ) {
+ adr = (unsigned int)pDev->rxbuf_adr;
+ if (adr & 0x1) {
+ /* User defined "remote" address. Translate it into
+ * a CPU accessible address
+ */
+ pDev->_rx_hw = (void *)(adr & ~0x1);
+ drvmgr_translate_check(
+ pDev->dev,
+ DMAMEM_TO_CPU,
+ (void *)pDev->_rx_hw,
+ (void **)&pDev->_rx,
+ pDev->rxbuf_size);
+ pDev->rx = (struct grcan_msg *)pDev->_rx;
+ } else {
+ if (adr == 0) {
+ pDev->_rx = malloc(pDev->rxbuf_size +
+ BUFFER_ALIGNMENT_NEEDS);
+ if (!pDev->_rx)
+ return -1;
+ } else {
+ /* User defined "cou-local" address. Translate
+ * it into a CPU accessible address
+ */
+ pDev->_rx = (void *)adr;
+ }
+ /* Align RX buffer */
+ pDev->rx = (struct grcan_msg *)
+ (((unsigned int)pDev->_rx +
+ (BUFFER_ALIGNMENT_NEEDS-1)) &
+ ~(BUFFER_ALIGNMENT_NEEDS-1));
+
+ /* Translate address into an hardware accessible
+ * address
+ */
+ drvmgr_translate_check(
+ pDev->dev,
+ CPUMEM_TO_DMA,
+ (void *)pDev->rx,
+ (void **)&pDev->_rx_hw,
+ pDev->rxbuf_size);
+ }
+ }
+ return 0;
}
static void grcan_free_buffers(struct grcan_priv *pDev, int rx, int tx)
{
FUNCDBG();
-#ifndef STATIC_TX_BUF_ADDR
if ( tx && pDev->_tx ){
free(pDev->_tx);
pDev->_tx = NULL;
pDev->tx = NULL;
}
-#endif
-#ifndef STATIC_RX_BUF_ADDR
+
if ( rx && pDev->_rx ){
free(pDev->_rx);
pDev->_rx = NULL;
pDev->rx = NULL;
}
-#endif
}
-#if 0
-static char *almalloc(int sz)
-{
- char *tmp;
- tmp = calloc(1,2*sz);
- tmp = (char *) (((int)tmp+sz) & ~(sz -1));
- return(tmp);
-}
-#endif
-
static rtems_device_driver grcan_initialize(
rtems_device_major_number major,
rtems_device_minor_number unused,
void *arg
)
{
- int minor;
- struct grcan_priv *pDev;
- struct ambapp_apb_info dev;
- rtems_status_code status;
- char fs_name[20];
- unsigned int sys_freq_hz;
- unsigned int deviceid = GAISLER_GRHCAN;
-
- printk("grcan_initialize()\n\r");
-
- FUNCDBG();
-
- /* find GRCAN cores */
- if ( !grcan_cores ) {
- grcan_core_cnt = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER,
- deviceid);
- if ( grcan_core_cnt < 1 ){
- deviceid = GAISLER_GRCAN;
- grcan_core_cnt = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER,
- deviceid);
- if ( grcan_core_cnt < 1 ) {
- DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt);
- return RTEMS_UNSATISFIED;
- }
- }
- DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt);
- }
-
-#ifdef GRCAN_MAX_CORENR
- /* limit number of cores */
- if ( grcan_core_cnt > GRCAN_MAX_CORENR )
- grcan_core_cnt = GRCAN_MAX_CORENR;
-#endif
-
- /* Allocate memory for cores */
- grcans = malloc(grcan_core_cnt * sizeof(struct grcan_priv));
- if ( !grcans )
- return RTEMS_NO_MEMORY;
- memset(grcans,0,grcan_core_cnt * sizeof(struct grcan_priv));
-
- /* make a local copy of device name */
- strcpy(fs_name,GRCAN_DEVNAME);
-
- /* Detect System Frequency from initialized timer */
-#ifndef SYS_FREQ_HZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- struct ambapp_apb_info gptimer;
- struct gptimer_regs *tregs;
-
- if (ambapp_find_apbslv (&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, &gptimer)
- == 1) {
- tregs = (struct gptimer_regs *) gptimer.start;
- sys_freq_hz = (tregs->scaler_reload + 1) * 1000 * 1000;
- DBG("GRCAN: detected %dHZ system frequency\n\r", sys_freq_hz);
- } else {
- sys_freq_hz = 40000000; /* Default to 40MHz */
- printk("GRCAN: Failed to detect system frequency\n\r");
- }
- }
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *) 0x80000000;
-
- sys_freq_hz = (regs->Scaler_Reload + 1) * 1000 * 1000;
- }
-#else
-#error CPU not supported by driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_hz = SYS_FREQ_HZ;
-#endif
-
- for(minor=0; minor<grcan_core_cnt; minor++){
-
- pDev = &grcans[minor];
- pDev->minor = minor;
- pDev->open = 0;
- pDev->corefreq_hz = sys_freq_hz;
- GRCAN_DEVNAME_NO(fs_name,minor);
-
- /* Find core address & IRQ */
- if ( !grcan_cores ) {
- ambapp_find_apbslv_next(amba_bus, VENDOR_GAISLER, deviceid, &dev, minor);
- pDev->irq = dev.irq;
- pDev->regs = (struct grcan_regs *)dev.start;
- }else{
- pDev->irq = grcan_cores[minor].irq;
- pDev->regs = (struct grcan_regs *)grcan_cores[minor].base_address;
- }
-
- printk("Registering GRCAN core at [0x%x] irq %d, minor %d as %s\n\r",pDev->regs,pDev->irq,minor,fs_name);
-
- status = rtems_io_register_name(fs_name, major, 0);
- if (status != RTEMS_SUCCESSFUL)
- rtems_fatal_error_occurred(status);
-
- /* Reset Hardware before attaching IRQ handler */
- grcan_hw_reset(pDev->regs);
-
- /* Register interrupt handler */
- GRCAN_REG_INT(GRCAN_PREFIX(_interrupt_handler), pDev->irq+GRCAN_IRQ_IRQ, pDev);
- /*
- GRCAN_REG_INT(grcan_interrupt_handler, pDev->irq+GRCAN_IRQ_TXSYNC, pDev);
- GRCAN_REG_INT(grcan_interrupt_handler, pDev->irq+GRCAN_IRQ_RXSYNC, pDev);
- */
-
- /* RX Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'R', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->rx_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- /* TX Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'T', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->tx_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- /* TX Empty Semaphore created with count = 0 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'E', '0'+minor),
- 0,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->txempty_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
-
- /* Device Semaphore created with count = 1 */
- if ( rtems_semaphore_create(rtems_build_name('G', 'C', 'A', '0'+minor),
- 1,
- RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
- RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
- 0,
- &pDev->dev_sem) != RTEMS_SUCCESSFUL )
- return RTEMS_INTERNAL_ERROR;
- }
-
- return RTEMS_SUCCESSFUL;
+ return RTEMS_SUCCESSFUL;
}
-static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
- struct grcan_priv *pDev;
- rtems_device_driver ret;
+static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ struct grcan_priv *pDev;
+ rtems_device_driver ret;
+ struct drvmgr_dev *dev;
+ union drvmgr_key_value *value;
- FUNCDBG();
+ FUNCDBG();
- if ( (minor < 0) || (minor>=grcan_core_cnt) ) {
- DBG("Wrong minor %d\n", minor);
- return RTEMS_INVALID_NUMBER;
- }
-
- pDev = &grcans[minor];
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- /* Wait until we get semaphore */
- if ( rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) !=
- RTEMS_SUCCESSFUL ){
- return RTEMS_INTERNAL_ERROR;
- }
+ /* Wait until we get semaphore */
+ if (rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL) {
+ return RTEMS_INTERNAL_ERROR;
+ }
- /* is device busy/taken? */
- if ( pDev->open ) {
- ret=RTEMS_RESOURCE_IN_USE;
- goto out;
- }
+ /* is device busy/taken? */
+ if ( pDev->open ) {
+ ret=RTEMS_RESOURCE_IN_USE;
+ goto out;
+ }
- /* Mark device taken */
- pDev->open = 1;
-
- pDev->txblock = pDev->rxblock = 1;
- pDev->txcomplete = pDev->rxcomplete = 0;
- pDev->started = 0;
- pDev->config_changed = 1;
- pDev->config.silent = 0;
- pDev->config.abort = 0;
- pDev->config.selection.selection = 0;
- pDev->config.selection.enable0 = 0;
- pDev->config.selection.enable1 = 1;
- pDev->flushing = 0;
- pDev->rx = pDev->_rx = NULL;
- pDev->tx = pDev->_tx = NULL;
- pDev->txbuf_size = TX_BUF_SIZE;
- pDev->rxbuf_size = RX_BUF_SIZE;
- printk("Defaulting to rxbufsize: %d, txbufsize: %d\n",RX_BUF_SIZE,TX_BUF_SIZE);
-
- /* Default to accept all messages */
- pDev->afilter.mask = 0x00000000;
- pDev->afilter.code = 0x00000000;
-
- /* Default to disable sync messages (only trigger when id is set to all ones) */
- pDev->sfilter.mask = 0xffffffff;
- pDev->sfilter.code = 0x00000000;
-
- /* Calculate default timing register values */
- grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
-
- if ( grcan_alloc_buffers(pDev,1,1) ) {
- ret=RTEMS_NO_MEMORY;
- goto out;
- }
+ /* Mark device taken */
+ pDev->open = 1;
+
+ pDev->txblock = pDev->rxblock = 1;
+ pDev->txcomplete = pDev->rxcomplete = 0;
+ pDev->started = 0;
+ pDev->config_changed = 1;
+ pDev->config.silent = 0;
+ pDev->config.abort = 0;
+ pDev->config.selection.selection = 0;
+ pDev->config.selection.enable0 = 0;
+ pDev->config.selection.enable1 = 1;
+ pDev->flushing = 0;
+ pDev->rx = pDev->_rx = NULL;
+ pDev->tx = pDev->_tx = NULL;
+ pDev->txbuf_adr = 0;
+ pDev->rxbuf_adr = 0;
+ pDev->txbuf_size = TX_BUF_SIZE;
+ pDev->rxbuf_size = RX_BUF_SIZE;
+
+ /* Override default buffer sizes if available from bus resource */
+ value = drvmgr_dev_key_get(pDev->dev, "txBufSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->txbuf_size = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxBufSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->rxbuf_size = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txBufAdr", KEY_TYPE_POINTER);
+ if ( value )
+ pDev->txbuf_adr = value->ptr;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxBufAdr", KEY_TYPE_POINTER);
+ if ( value )
+ pDev->rxbuf_adr = value->ptr;
+
+ DBG("Defaulting to rxbufsize: %d, txbufsize: %d\n",RX_BUF_SIZE,TX_BUF_SIZE);
+
+ /* Default to accept all messages */
+ pDev->afilter.mask = 0x00000000;
+ pDev->afilter.code = 0x00000000;
+
+ /* Default to disable sync messages (only trigger when id is set to all ones) */
+ pDev->sfilter.mask = 0xffffffff;
+ pDev->sfilter.code = 0x00000000;
+
+ /* Calculate default timing register values */
+ grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
+
+ if ( grcan_alloc_buffers(pDev,1,1) ) {
+ ret=RTEMS_NO_MEMORY;
+ goto out;
+ }
- /* Clear statistics */
- memset(&pDev->stats,0,sizeof(struct grcan_stats));
+ /* Clear statistics */
+ memset(&pDev->stats,0,sizeof(struct grcan_stats));
- ret = RTEMS_SUCCESSFUL;
+ ret = RTEMS_SUCCESSFUL;
out:
- rtems_semaphore_release(pDev->dev_sem);
- return ret;
+ rtems_semaphore_release(pDev->dev_sem);
+ return ret;
}
static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
- FUNCDBG();
+ FUNCDBG();
- if ( pDev->started )
- grcan_stop(pDev);
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- grcan_hw_reset(pDev->regs);
+ if ( pDev->started )
+ grcan_stop(pDev);
- grcan_free_buffers(pDev,1,1);
+ grcan_hw_reset(pDev->regs);
- /* Mark Device as closed */
- pDev->open = 0;
+ grcan_free_buffers(pDev,1,1);
- return RTEMS_SUCCESSFUL;
+ /* Mark Device as closed */
+ pDev->open = 0;
+
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
- rtems_libio_rw_args_t *rw_args;
- CANMsg *dest;
- unsigned int count, left;
- int req_cnt;
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_rw_args_t *rw_args;
+ CANMsg *dest;
+ unsigned int count, left;
+ int req_cnt;
- rw_args = (rtems_libio_rw_args_t *) arg;
- dest = (CANMsg *) rw_args->buffer;
- req_cnt = rw_args->count / sizeof(CANMsg);
+ FUNCDBG();
- FUNCDBG();
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- if ( (!dest) || (req_cnt<1) )
- return RTEMS_INVALID_NAME;
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ dest = (CANMsg *) rw_args->buffer;
+ req_cnt = rw_args->count / sizeof(CANMsg);
- if ( !pDev->started )
- return RTEMS_RESOURCE_IN_USE;
+ if ( (!dest) || (req_cnt<1) )
+ return RTEMS_INVALID_NAME;
-/* FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/
+ if ( !pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
- count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
- if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
- if ( count > 0 ) {
- /* Successfully received messages (at least one) */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
- }
+ /*FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/
- /* nothing read, shall we block? */
- if ( !pDev->rxblock ) {
- /* non-blocking mode */
- rw_args->bytes_moved = 0;
- return RTEMS_TIMEOUT;
- }
- }
+ count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
+ if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
+ if ( count > 0 ) {
+ /* Successfully received messages (at least one) */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
+ }
- while(count == 0 || (pDev->rxcomplete && (count!=req_cnt)) ){
+ /* nothing read, shall we block? */
+ if ( !pDev->rxblock ) {
+ /* non-blocking mode */
+ rw_args->bytes_moved = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }
- if ( !pDev->rxcomplete ){
- left = 1; /* return as soon as there is one message available */
- }else{
- left = req_cnt - count; /* return as soon as all data are available */
-
- /* never wait for more than the half the maximum size of the receive buffer
- * Why? We need some time to copy buffer before to catch up with hw, otherwise
- * we would have to copy everything when the data has been received.
- */
- if ( left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE)/2) ){
- left = (pDev->rxbuf_size/GRCAN_MSG_SIZE)/2;
- }
- }
+ while(count == 0 || (pDev->rxcomplete && (count!=req_cnt)) ){
- if ( grcan_wait_rxdata(pDev,left) ) {
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread.
- */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_UNSATISFIED;
- }
+ if ( !pDev->rxcomplete ){
+ left = 1; /* return as soon as there is one message available */
+ }else{
+ left = req_cnt - count; /* return as soon as all data are available */
- /* Try read bytes from circular buffer */
- count += grcan_hw_read_try(
- pDev,
- pDev->regs,
- dest+count,
- req_cnt-count);
- }
- /* no need to unmask IRQ as IRQ Handler do that for us. */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
+ /* never wait for more than the half the maximum size of the receive buffer
+ * Why? We need some time to copy buffer before to catch up with hw,
+ * otherwise we would have to copy everything when the data has been
+ * received.
+ */
+ if ( left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE)/2) ){
+ left = (pDev->rxbuf_size/GRCAN_MSG_SIZE)/2;
+ }
+ }
+
+ if ( grcan_wait_rxdata(pDev,left) ) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread.
+ */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_UNSATISFIED;
+ }
+
+ /* Try read bytes from circular buffer */
+ count += grcan_hw_read_try(
+ pDev,
+ pDev->regs,
+ dest+count,
+ req_cnt-count);
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
- rtems_libio_rw_args_t *rw_args;
- CANMsg *source;
- unsigned int count, left;
- int req_cnt;
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_rw_args_t *rw_args;
+ CANMsg *source;
+ unsigned int count, left;
+ int req_cnt;
- DBGC(DBG_TX,"\n");
- /*FUNCDBG();*/
+ DBGC(DBG_TX,"\n");
- if ( !pDev->started || pDev->config.silent || pDev->flushing )
- return RTEMS_RESOURCE_IN_USE;
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- rw_args = (rtems_libio_rw_args_t *) arg;
- req_cnt = rw_args->count / sizeof(CANMsg);
- source = (CANMsg *) rw_args->buffer;
+ if ( !pDev->started || pDev->config.silent || pDev->flushing )
+ return RTEMS_RESOURCE_IN_USE;
- /* check proper length and buffer pointer */
- if (( req_cnt < 1) || (source == NULL) ){
- return RTEMS_INVALID_NAME;
- }
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ req_cnt = rw_args->count / sizeof(CANMsg);
+ source = (CANMsg *) rw_args->buffer;
- count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
- if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
- if ( count > 0 ) {
- /* Successfully transmitted chars (at least one char) */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
- }
+ /* check proper length and buffer pointer */
+ if (( req_cnt < 1) || (source == NULL) ){
+ return RTEMS_INVALID_NAME;
+ }
- /* nothing written, shall we block? */
- if ( !pDev->txblock ) {
- /* non-blocking mode */
- rw_args->bytes_moved = 0;
- return RTEMS_TIMEOUT;
- }
- }
+ count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
+ if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
+ if ( count > 0 ) {
+ /* Successfully transmitted chars (at least one char) */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
+ }
- /* if in txcomplete mode we need to transmit all chars */
- while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
- /*** block until room to fit all or as much of transmit buffer as possible IRQ comes
- * Set up a valid IRQ point so that an IRQ is received
- * when we can put a chunk of data into transmit fifo
- */
- if ( !pDev->txcomplete ){
- left = 1; /* wait for anything to fit buffer */
- }else{
- left = req_cnt - count; /* wait for all data to fit in buffer */
+ /* nothing written, shall we block? */
+ if ( !pDev->txblock ) {
+ /* non-blocking mode */
+ rw_args->bytes_moved = 0;
+ return RTEMS_TIMEOUT;
+ }
+ }
- /* never wait for more than the half the maximum size of the transmitt buffer
- * Why? We need some time to fill buffer before hw catches up.
- */
- if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
- left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
- }
- }
+ /* if in txcomplete mode we need to transmit all chars */
+ while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
+ /*** block until room to fit all or as much of transmit buffer as possible
+ * IRQ comes. Set up a valid IRQ point so that an IRQ is received
+ * when we can put a chunk of data into transmit fifo
+ */
+ if ( !pDev->txcomplete ){
+ left = 1; /* wait for anything to fit buffer */
+ }else{
+ left = req_cnt - count; /* wait for all data to fit in buffer */
+
+ /* never wait for more than the half the maximum size of the transmit
+ * buffer
+ * Why? We need some time to fill buffer before hw catches up.
+ */
+ if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
+ left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
+ }
+ }
- /* Wait until more room in transmit buffer */
- if ( grcan_wait_txspace(pDev,left) ){
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread. To avoid deadlock we return directly
- * with error status.
- */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_UNSATISFIED;
- }
+ /* Wait until more room in transmit buffer */
+ if ( grcan_wait_txspace(pDev,left) ){
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread. To avoid deadlock we return directly
+ * with error status.
+ */
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_UNSATISFIED;
+ }
- if ( pDev->txerror ){
- /* Return number of bytes sent, compare write pointers */
- pDev->txerror = 0;
-#if 0
+ if ( pDev->txerror ){
+ /* Return number of bytes sent, compare write pointers */
+ pDev->txerror = 0;
+#if 0
#error HANDLE AMBA error
#endif
- }
+ }
- /* Try read bytes from circular buffer */
- count += grcan_hw_write_try(
- pDev,
- pDev->regs,
- source+count,
- req_cnt-count);
- }
- /* no need to unmask IRQ as IRQ Handler do that for us. */
+ /* Try read bytes from circular buffer */
+ count += grcan_hw_write_try(
+ pDev,
+ pDev->regs,
+ source+count,
+ req_cnt-count);
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
- rw_args->bytes_moved = count * sizeof(CANMsg);
- return RTEMS_SUCCESSFUL;
+ rw_args->bytes_moved = count * sizeof(CANMsg);
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
- struct grcan_priv *pDev = &grcans[minor];
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
- unsigned int *data = ioarg->buffer;
- struct grcan_timing timing;
- unsigned int speed;
- struct grcan_selection *selection;
- int tmp,ret;
- rtems_device_driver status;
- struct grcan_stats *stats;
- struct grcan_filter *filter;
- IRQ_GLOBAL_PREPARE(oldLevel);
+ struct grcan_priv *pDev;
+ struct drvmgr_dev *dev;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ unsigned int *data = ioarg->buffer;
+ struct grcan_timing timing;
+ unsigned int speed;
+ struct grcan_selection *selection;
+ int tmp,ret;
+ rtems_device_driver status;
+ struct grcan_stats *stats;
+ struct grcan_filter *filter;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ FUNCDBG();
+
+ if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (struct grcan_priv *)dev->priv;
- FUNCDBG();
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
- if (!ioarg)
- return RTEMS_INVALID_NAME;
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case GRCAN_IOC_START:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- ioarg->ioctl_return = 0;
- switch(ioarg->command) {
- case GRCAN_IOC_START:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){
+ return status;
+ }
+ /* Read and write are now open... */
+ pDev->started = 1;
- if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){
- return status;
- }
- /* Read and write are now open... */
- pDev->started = 1;
- break;
+ /* Register interrupt routine and enable IRQ at IRQ ctrl */
+ drvmgr_interrupt_register(dev, 0, "grcan", grcan_interrupt, pDev);
- case GRCAN_IOC_STOP:
- if ( !pDev->started )
- return RTEMS_RESOURCE_IN_USE;
+ break;
- grcan_stop(pDev);
- pDev->started = 0;
- break;
+ case GRCAN_IOC_STOP:
+ if ( !pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
- case GRCAN_IOC_ISSTARTED:
- if ( !pDev->started )
- return RTEMS_RESOURCE_IN_USE;
- break;
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grcan_interrupt, pDev);
- case GRCAN_IOC_FLUSH:
- if ( !pDev->started || pDev->flushing || pDev->config.silent )
- return RTEMS_RESOURCE_IN_USE;
-
- pDev->flushing = 1;
- tmp = grcan_tx_flush(pDev);
- pDev->flushing = 0;
- if ( tmp ) {
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread.
- */
- return RTEMS_UNSATISFIED;
- }
- break;
+ grcan_stop(pDev);
+ pDev->started = 0;
+ break;
+
+ case GRCAN_IOC_ISSTARTED:
+ if ( !pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+ break;
+
+ case GRCAN_IOC_FLUSH:
+ if ( !pDev->started || pDev->flushing || pDev->config.silent )
+ return RTEMS_RESOURCE_IN_USE;
+
+ pDev->flushing = 1;
+ tmp = grcan_tx_flush(pDev);
+ pDev->flushing = 0;
+ if ( tmp ) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread.
+ */
+ return RTEMS_UNSATISFIED;
+ }
+ break;
#if 0
- /* Set physical link */
+ /* Set physical link */
case GRCAN_IOC_SET_LINK:
#ifdef REDUNDANT_CHANNELS
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
- /* switch HW channel */
- pDev->channel = (unsigned int)ioargs->buffer;
+ /* switch HW channel */
+ pDev->channel = (unsigned int)ioargs->buffer;
#else
- return RTEMS_NOT_IMPLEMENTED;
+ return RTEMS_NOT_IMPLEMENTED;
#endif
- break;
+ break;
#endif
- case GRCAN_IOC_SET_SILENT:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE;
- pDev->config.silent = (int)ioarg->buffer;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_ABORT:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE;
- pDev->config.abort = (int)ioarg->buffer;
- /* This Configuration parameter doesn't need HurriCANe reset
- * ==> no pDev->config_changed = 1;
- */
- break;
-
- case GRCAN_IOC_SET_SELECTION:
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE;
-
- selection = (struct grcan_selection *)ioarg->buffer;
- if ( !selection )
- return RTEMS_INVALID_NAME;
-
- pDev->config.selection = *selection;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_RXBLOCK:
- pDev->rxblock = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_SET_TXBLOCK:
- pDev->txblock = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_SET_TXCOMPLETE:
- pDev->txcomplete = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_SET_RXCOMPLETE:
- pDev->rxcomplete = (int)ioarg->buffer;
- break;
-
- case GRCAN_IOC_GET_STATS:
- stats = (struct grcan_stats *)ioarg->buffer;
- if ( !stats )
- return RTEMS_INVALID_NAME;
- *stats = pDev->stats;
- break;
-
- case GRCAN_IOC_CLR_STATS:
- IRQ_GLOBAL_DISABLE(oldLevel);
- memset(&pDev->stats,0,sizeof(struct grcan_stats));
- IRQ_GLOBAL_ENABLE(oldLevel);
- break;
+ case GRCAN_IOC_SET_SILENT:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+ pDev->config.silent = (int)ioarg->buffer;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_ABORT:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+ pDev->config.abort = (int)ioarg->buffer;
+ /* This Configuration parameter doesn't need HurriCANe reset
+ * ==> no pDev->config_changed = 1;
+ */
+ break;
+
+ case GRCAN_IOC_SET_SELECTION:
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE;
+
+ selection = (struct grcan_selection *)ioarg->buffer;
+ if ( !selection )
+ return RTEMS_INVALID_NAME;
+
+ pDev->config.selection = *selection;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_RXBLOCK:
+ pDev->rxblock = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_SET_TXBLOCK:
+ pDev->txblock = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_SET_TXCOMPLETE:
+ pDev->txcomplete = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_SET_RXCOMPLETE:
+ pDev->rxcomplete = (int)ioarg->buffer;
+ break;
+
+ case GRCAN_IOC_GET_STATS:
+ stats = (struct grcan_stats *)ioarg->buffer;
+ if ( !stats )
+ return RTEMS_INVALID_NAME;
+ *stats = pDev->stats;
+ break;
+
+ case GRCAN_IOC_CLR_STATS:
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ memset(&pDev->stats,0,sizeof(struct grcan_stats));
+ IRQ_GLOBAL_ENABLE(oldLevel);
+ break;
case GRCAN_IOC_SET_SPEED:
-
- /* cannot change speed during run mode */
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- /* get speed rate from argument */
- speed = (unsigned int)ioarg->buffer;
- ret = grcan_calc_timing(speed,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&timing);
- if ( ret )
- return RTEMS_INVALID_NAME; /* EINVAL */
-
- /* save timing/speed */
- pDev->config.timing = timing;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_BTRS:
- /* Set BTR registers manually
- * Read GRCAN/HurriCANe Manual.
- */
- if ( pDev->started )
- return RTEMS_RESOURCE_IN_USE; /* EBUSY */
-
- if ( !ioarg->buffer )
- return RTEMS_INVALID_NAME;
-
- pDev->config.timing = *(struct grcan_timing *)ioarg->buffer;
- pDev->config_changed = 1;
- break;
-
- case GRCAN_IOC_SET_AFILTER:
- filter = (struct grcan_filter *)ioarg->buffer;
- if ( !filter ){
- /* Disable filtering - let all messages pass */
- pDev->afilter.mask = 0x0;
- pDev->afilter.code = 0x0;
- }else{
- /* Save filter */
- pDev->afilter = *filter;
- }
- /* Set hardware acceptance filter */
- grcan_hw_accept(pDev->regs,&pDev->afilter);
- break;
-
- case GRCAN_IOC_SET_SFILTER:
- filter = (struct grcan_filter *)ioarg->buffer;
- if ( !filter ){
- /* disable TX/RX SYNC filtering */
- pDev->sfilter.mask = 0xffffffff;
- pDev->sfilter.mask = 0;
-
- /* disable Sync interrupt */
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
- }else{
- /* Save filter */
- pDev->sfilter = *filter;
-
- /* Enable Sync interrupt */
- pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
- }
- /* Set Sync RX/TX filter */
- grcan_hw_sync(pDev->regs,&pDev->sfilter);
- break;
-
- case GRCAN_IOC_GET_STATUS:
- if ( !data )
- return RTEMS_INVALID_NAME;
- /* Read out the statsu register from the GRCAN core */
- data[0] = READ_REG(&pDev->regs->stat);
- break;
-
- default:
- return RTEMS_NOT_DEFINED;
- }
- return RTEMS_SUCCESSFUL;
-}
-
-#ifndef GRCAN_DONT_DECLARE_IRQ_HANDLER
-/* Find what device caused the IRQ */
-static rtems_isr grcan_interrupt_handler(rtems_vector_number v)
-{
- int minor=0;
- while ( minor < grcan_core_cnt ){
- if ( (grcans[minor].irq+0x10) == v ){
- grcan_interrupt(&grcans[minor]);
- break;
- }
- }
+ /* cannot change speed during run mode */
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+
+ /* get speed rate from argument */
+ speed = (unsigned int)ioarg->buffer;
+ ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing);
+ if ( ret )
+ return RTEMS_INVALID_NAME; /* EINVAL */
+
+ /* save timing/speed */
+ pDev->config.timing = timing;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_BTRS:
+ /* Set BTR registers manually
+ * Read GRCAN/HurriCANe Manual.
+ */
+ if ( pDev->started )
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ if ( !ioarg->buffer )
+ return RTEMS_INVALID_NAME;
+
+ pDev->config.timing = *(struct grcan_timing *)ioarg->buffer;
+ pDev->config_changed = 1;
+ break;
+
+ case GRCAN_IOC_SET_AFILTER:
+ filter = (struct grcan_filter *)ioarg->buffer;
+ if ( !filter ){
+ /* Disable filtering - let all messages pass */
+ pDev->afilter.mask = 0x0;
+ pDev->afilter.code = 0x0;
+ }else{
+ /* Save filter */
+ pDev->afilter = *filter;
+ }
+ /* Set hardware acceptance filter */
+ grcan_hw_accept(pDev->regs,&pDev->afilter);
+ break;
+
+ case GRCAN_IOC_SET_SFILTER:
+ filter = (struct grcan_filter *)ioarg->buffer;
+ if ( !filter ){
+ /* disable TX/RX SYNC filtering */
+ pDev->sfilter.mask = 0xffffffff;
+ pDev->sfilter.mask = 0;
+
+ /* disable Sync interrupt */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
+ }else{
+ /* Save filter */
+ pDev->sfilter = *filter;
+
+ /* Enable Sync interrupt */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
+ }
+ /* Set Sync RX/TX filter */
+ grcan_hw_sync(pDev->regs,&pDev->sfilter);
+ break;
+
+ case GRCAN_IOC_GET_STATUS:
+ if ( !data )
+ return RTEMS_INVALID_NAME;
+ /* Read out the statsu register from the GRCAN core */
+ data[0] = READ_REG(&pDev->regs->stat);
+ break;
+
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
}
-#endif
/* Handle the IRQ */
-static void grcan_interrupt(struct grcan_priv *pDev)
+static void grcan_interrupt(void *arg)
{
- unsigned int status = READ_REG(&pDev->regs->pimsr);
- unsigned int canstat = READ_REG(&pDev->regs->stat);
+ struct grcan_priv *pDev = arg;
+ unsigned int status = READ_REG(&pDev->regs->pimsr);
+ unsigned int canstat = READ_REG(&pDev->regs->stat);
- /* Spurious IRQ call? */
- if ( !status && !canstat )
- return;
+ /* Spurious IRQ call? */
+ if ( !status && !canstat )
+ return;
- FUNCDBG();
+ FUNCDBG();
- /* Increment number of interrupts counter */
- pDev->stats.ints++;
+ /* Increment number of interrupts counter */
+ pDev->stats.ints++;
- if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){
- /* Error-Passive interrupt */
- pDev->stats.passive_cnt++;
- }
+ if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){
+ /* Error-Passive interrupt */
+ pDev->stats.passive_cnt++;
+ }
- if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){
- /* Bus-off condition interrupt
- * The link is brought down by hardware, we wake all threads
- * that is blocked in read/write calls and stop futher calls
- * to read/write until user has called ioctl(fd,START,0).
- */
- pDev->started = 0;
- grcan_stop(pDev); /* this mask all IRQ sources */
- status=0x1ffff; /* clear all interrupts */
- goto out;
- }
+ if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){
+ /* Bus-off condition interrupt
+ * The link is brought down by hardware, we wake all threads
+ * that is blocked in read/write calls and stop futher calls
+ * to read/write until user has called ioctl(fd,START,0).
+ */
+ pDev->started = 0;
+ grcan_stop(pDev); /* this mask all IRQ sources */
+ status=0x1ffff; /* clear all interrupts */
+ goto out;
+ }
- if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){
- /* Over-run during reception interrupt */
- pDev->stats.overrun_cnt++;
- }
+ if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){
+ /* Over-run during reception interrupt */
+ pDev->stats.overrun_cnt++;
+ }
- if ( (status & GRCAN_RXAHBERR_IRQ) ||
- (status & GRCAN_TXAHBERR_IRQ) ||
- (canstat & GRCAN_STAT_AHBERR) ){
- /* RX or Tx AHB Error interrupt */
- printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat);
- pDev->stats.ahberr_cnt++;
- }
+ if ( (status & GRCAN_RXAHBERR_IRQ) ||
+ (status & GRCAN_TXAHBERR_IRQ) ||
+ (canstat & GRCAN_STAT_AHBERR) ){
+ /* RX or Tx AHB Error interrupt */
+ printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat);
+ pDev->stats.ahberr_cnt++;
+ }
- if ( status & GRCAN_TXLOSS_IRQ ) {
- pDev->stats.txloss_cnt++;
- }
+ if ( status & GRCAN_TXLOSS_IRQ ) {
+ pDev->stats.txloss_cnt++;
+ }
- if ( status & GRCAN_RXIRQ_IRQ ){
- /* RX IRQ pointer interrupt */
- /*printk("RxIrq 0x%x\n",status);*/
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
- rtems_semaphore_release(pDev->rx_sem);
- }
+ if ( status & GRCAN_RXIRQ_IRQ ){
+ /* RX IRQ pointer interrupt */
+ /*printk("RxIrq 0x%x\n",status);*/
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
+ rtems_semaphore_release(pDev->rx_sem);
+ }
- if ( status & GRCAN_TXIRQ_IRQ ){
- /* TX IRQ pointer interrupt */
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
- rtems_semaphore_release(pDev->tx_sem);
- }
+ if ( status & GRCAN_TXIRQ_IRQ ){
+ /* TX IRQ pointer interrupt */
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
+ rtems_semaphore_release(pDev->tx_sem);
+ }
- if ( status & GRCAN_TXSYNC_IRQ ){
- /* TxSync message transmitted interrupt */
- pDev->stats.txsync_cnt++;
- }
+ if ( status & GRCAN_TXSYNC_IRQ ){
+ /* TxSync message transmitted interrupt */
+ pDev->stats.txsync_cnt++;
+ }
- if ( status & GRCAN_RXSYNC_IRQ ){
- /* RxSync message received interrupt */
- pDev->stats.rxsync_cnt++;
- }
+ if ( status & GRCAN_RXSYNC_IRQ ){
+ /* RxSync message received interrupt */
+ pDev->stats.rxsync_cnt++;
+ }
- if ( status & GRCAN_TXEMPTY_IRQ ){
- pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
- rtems_semaphore_release(pDev->txempty_sem);
- }
+ if ( status & GRCAN_TXEMPTY_IRQ ){
+ pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
+ rtems_semaphore_release(pDev->txempty_sem);
+ }
out:
- /* Clear IRQs */
- pDev->regs->picr = status;
-}
-
-static int grcan_register_internal(void)
-{
- rtems_status_code r;
- rtems_device_major_number m;
-
- if ((r = rtems_io_register_driver(0, &grcan_driver, &m)) !=
- RTEMS_SUCCESSFUL) {
- switch(r) {
- case RTEMS_TOO_MANY:
- DBG2("failed RTEMS_TOO_MANY\n");
- break;
- case RTEMS_INVALID_NUMBER:
- DBG2("failed RTEMS_INVALID_NUMBER\n");
- break;
- case RTEMS_RESOURCE_IN_USE:
- DBG2("failed RTEMS_RESOURCE_IN_USE\n");
- break;
- default:
- DBG("failed %i\n",r);
- break;
- }
- return 1;
- }
- DBG("Registered GRCAN on major %d\n",m);
- return 0;
-}
-
-
-int grcan_register_abs(struct grcan_device_info *devices, int dev_cnt);
-
-/* Use custom addresses and IRQs to find hardware */
-int GRCAN_PREFIX(_register_abs)(struct grcan_device_info *devices, int dev_cnt)
-{
- FUNCDBG();
-
- if ( !devices || (dev_cnt<0) )
- return 1;
- grcan_cores = devices;
- grcan_core_cnt = dev_cnt;
-
- amba_bus = NULL;
- return grcan_register_internal();
-}
-
-/* Use prescanned AMBA Plug&Play information to find all GRCAN cores */
-int GRCAN_PREFIX(_register)(struct ambapp_bus *abus)
-{
- FUNCDBG();
-
- if ( !abus )
- return 1;
- amba_bus = abus;
- grcan_cores = NULL;
- grcan_core_cnt = 0;
- return grcan_register_internal();
+ /* Clear IRQs */
+ pDev->regs->picr = status;
}
diff --git a/c/src/lib/libbsp/sparc/shared/can/occan.c b/c/src/lib/libbsp/sparc/shared/can/occan.c
index 5920af3..8ce6a66 100644
--- a/c/src/lib/libbsp/sparc/shared/can/occan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/occan.c
@@ -1,13 +1,11 @@
/* OC_CAN driver
*
* COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * 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.org/license/LICENSE.
- *
- * Author: Daniel Hellström, Gaisler Research AB, www.gaisler.com
*/
#include <rtems/libio.h>
@@ -17,9 +15,8 @@
#include <bsp.h>
#include <rtems/bspIo.h> /* printk */
-#include <leon.h>
-#include <ambapp.h>
-#include <grlib.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <occan.h>
/* RTEMS -> ERRNO decoding table
@@ -53,27 +50,8 @@ rtems_assoc_t errno_assoc[] = {
#undef OCCAN_BYTE_REGS
#endif
-#ifndef OCCAN_PREFIX
- #define OCCAN_PREFIX(name) occan##name
-#endif
-
-#if !defined(OCCAN_DEVNAME) || !defined(OCCAN_DEVNAME_NO)
- #undef OCCAN_DEVNAME
- #undef OCCAN_DEVNAME_NO
- #define OCCAN_DEVNAME "/dev/occan0"
- #define OCCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-#endif
-
-#ifndef OCCAN_REG_INT
- #define OCCAN_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1)
- #undef OCCAN_DEFINE_INTHANDLER
- #define OCCAN_DEFINE_INTHANDLER
-#endif
-
-/* Default to 40MHz system clock */
-/*#ifndef SYS_FREQ_HZ
- #define SYS_FREQ_HZ 40000000
-#endif*/
+/* Enable Fixup code older OCCAN with a TX IRQ-FLAG bug */
+#define OCCAN_TX_IRQ_FLAG_FIXUP 1
#define OCCAN_WORD_REG_OFS 0x80
#define OCCAN_NCORE_OFS 0x100
@@ -103,7 +81,7 @@ typedef struct {
} occan_fifo;
/* PELICAN */
-#ifdef OCCAN_BYTE_REGS
+
typedef struct {
unsigned char
mode,
@@ -149,8 +127,8 @@ typedef struct {
unsigned char rx_msg_cnt;
unsigned char unused1;
unsigned char clkdiv;
-} pelican_regs;
-#else
+} pelican8_regs;
+
typedef struct {
unsigned char
mode, unused0[3],
@@ -196,9 +174,15 @@ typedef struct {
unsigned char rx_msg_cnt,unused16[3];
unsigned char unused17[4];
unsigned char clkdiv,unused18[3];
-} pelican_regs;
+} pelican32_regs;
+
+#ifdef OCCAN_BYTE_REGS
+#define pelican_regs pelican8_regs
+#else
+#define pelican_regs pelican32_regs
#endif
+
#define MAX_TSEG2 7
#define MAX_TSEG1 15
@@ -217,12 +201,17 @@ typedef struct {
} occan_speed_regs;
typedef struct {
+ struct drvmgr_dev *dev;
+ char devName[32];
+
/* hardware shortcuts */
pelican_regs *regs;
+ int byte_regs;
int irq;
occan_speed_regs timing;
int channel; /* 0=default, 1=second bus */
int single_mode;
+ unsigned int sys_freq_hz;
/* driver state */
rtems_id devsem;
@@ -232,6 +221,7 @@ typedef struct {
int started;
int rxblk;
int txblk;
+ int sending;
unsigned int status;
occan_stats stats;
@@ -266,7 +256,7 @@ static int pelican_start(occan_priv *priv);
static void pelican_stop(occan_priv *priv);
static int pelican_send(occan_priv *can, CANMsg *msg);
static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask);
-static void occan_interrupt(occan_priv *can);
+void occan_interrupt(void *arg);
#ifdef DEBUG_PRINT_REGMAP
static void pelican_regadr_print(pelican_regs *regs);
#endif
@@ -278,33 +268,41 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev
static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver occan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
-#ifdef OCCAN_DEFINE_INTHANDLER
-static void occan_interrupt_handler(rtems_vector_number v);
-#endif
-static int can_cores;
-static occan_priv *cans;
-static struct ambapp_bus *amba_bus;
-static unsigned int sys_freq_hz;
+
+#define OCCAN_DRIVER_TABLE_ENTRY { occan_initialize, occan_open, occan_close, occan_read, occan_write, occan_ioctl }
+static rtems_driver_address_table occan_driver = OCCAN_DRIVER_TABLE_ENTRY;
/* Read byte bypassing */
-#ifdef OCCAN_DONT_BYPASS_CACHE
- #define READ_REG(address) (*(volatile unsigned char *)(address))
-#else
- /* Bypass cache */
- #define READ_REG(address) _OCCAN_REG_READ((unsigned int)(address))
- static __inline__ unsigned char _OCCAN_REG_READ(unsigned int addr) {
- unsigned char tmp;
- __asm__ (" lduba [%1]1, %0 "
- : "=r"(tmp)
- : "r"(addr)
- );
- return tmp;
+
+/* Bypass cache */
+#define READ_REG(priv, address) occan_reg_read(priv, (unsigned int)address)
+#define WRITE_REG(priv, address, data) occan_reg_write(priv, (unsigned int)address, data)
+
+unsigned int occan_reg_read(occan_priv *priv, unsigned int address)
+{
+ unsigned int adr;
+ if ( priv->byte_regs ) {
+ adr = address;
+ } else {
+ /* Word accessed registers */
+ adr = (address & (~0x7f)) | ((address & 0x7f)<<2);
}
-#endif
+ return *(volatile unsigned char *)adr;
+}
-#define WRITE_REG(address,data) (*(volatile unsigned char *)(address) = (data))
+void occan_reg_write(occan_priv *priv, unsigned int address, unsigned char value)
+{
+ unsigned int adr;
+ if ( priv->byte_regs ) {
+ adr = address;
+ } else {
+ /* Word accessed registers */
+ adr = (address & (~0x7f)) | ((address & 0x7f)<<2);
+ }
+ *(volatile unsigned char *)adr = value;;
+}
/* Mode register bit definitions */
#define PELICAN_MOD_RESET 0x1
@@ -391,16 +389,376 @@ static unsigned int sys_freq_hz;
#define PELICAN_S_ 0x80
*/
+static int occan_driver_io_registered = 0;
+static rtems_device_major_number occan_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int occan_register_io(rtems_device_major_number *m);
+int occan_device_init(occan_priv *pDev);
+
+int occan_init2(struct drvmgr_dev *dev);
+int occan_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops occan_ops =
+{
+ .init = {NULL, occan_init2, occan_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id occan_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_CANAHB},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info occan_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_OCCAN_ID, /* Driver ID */
+ "OCCAN_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &occan_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &occan_ids[0]
+};
+
+void occan_register_drv (void)
+{
+ DBG("Registering OCCAN driver\n");
+ drvmgr_drv_register(&occan_drv_info.general);
+}
+
+int occan_init2(struct drvmgr_dev *dev)
+{
+ occan_priv *priv;
+
+ DBG("OCCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(occan_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ return DRVMGR_OK;
+}
+
+int occan_init3(struct drvmgr_dev *dev)
+{
+ occan_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( occan_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( occan_register_io(&occan_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ occan_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( occan_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/occan%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%soccan%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ DBG("OCCAN[%d]: Registering %s\n", dev->minor_drv, priv->devName);
+ status = rtems_io_register_name(priv->devName, occan_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int occan_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &occan_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("OCCAN driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("OCCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("OCCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("OCCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("OCCAN rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int occan_device_init(occan_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ rtems_status_code status;
+ int minor;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (pelican_regs *)(pnpinfo->ahb_slv->start[0] + OCCAN_NCORE_OFS*pnpinfo->index);
+ pDev->byte_regs = 1;
+ minor = pDev->dev->minor_drv;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_AHB_SLV, &pDev->sys_freq_hz) ) {
+ return -1;
+ }
+
+ DBG("OCCAN frequency: %d Hz\n", pDev->sys_freq_hz);
+
+ /* initialize software */
+ pDev->open = 0;
+ pDev->started = 0; /* Needed for spurious interrupts */
+ pDev->rxfifo = NULL;
+ pDev->txfifo = NULL;
+ status = rtems_semaphore_create(
+ rtems_build_name('C', 'd', 'v', '0'+minor),
+ 1,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->devsem);
+ if ( status != RTEMS_SUCCESSFUL ){
+ printk("OCCAN[%d]: Failed to create dev semaphore, (%d)\n\r",minor, status);
+ return RTEMS_UNSATISFIED;
+ }
+ status = rtems_semaphore_create(
+ rtems_build_name('C', 't', 'x', '0'+minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->txsem);
+ if ( status != RTEMS_SUCCESSFUL ){
+ printk("OCCAN[%d]: Failed to create tx semaphore, (%d)\n\r",minor, status);
+ return RTEMS_UNSATISFIED;
+ }
+ status = rtems_semaphore_create(
+ rtems_build_name('C', 'r', 'x', '0'+minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &pDev->rxsem);
+ if ( status != RTEMS_SUCCESSFUL ){
+ printk("OCCAN[%d]: Failed to create rx semaphore, (%d)\n\r",minor, status);
+ return RTEMS_UNSATISFIED;
+ }
+
+ /* hardware init/reset */
+ pelican_init(pDev);
+
+#ifdef DEBUG_PRINT_REGMAP
+ pelican_regadr_print(pDev->regs);
+#endif
+
+ return 0;
+}
+
+
+#ifdef DEBUG
+static void pelican_regs_print(occan_priv *pDev){
+ pelican_regs *regs = pDev->regs;
+ printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
+ printk(" MODE: 0x%02x\n\r",READ_REG(pDev, ®s->mode));
+ printk(" CMD: 0x%02x\n\r",READ_REG(pDev, ®s->cmd));
+ printk(" STATUS: 0x%02x\n\r",READ_REG(pDev, ®s->status));
+ /*printk(" INTFLG: 0x%02x\n\r",READ_REG(pDev, ®s->intflags));*/
+ printk(" INTEN: 0x%02x\n\r",READ_REG(pDev, ®s->inten));
+ printk(" BTR0: 0x%02x\n\r",READ_REG(pDev, ®s->bustim0));
+ printk(" BTR1: 0x%02x\n\r",READ_REG(pDev, ®s->bustim1));
+ printk(" ARBCODE: 0x%02x\n\r",READ_REG(pDev, ®s->arbcode));
+ printk(" ERRCODE: 0x%02x\n\r",READ_REG(pDev, ®s->errcode));
+ printk(" ERRWARN: 0x%02x\n\r",READ_REG(pDev, ®s->errwarn));
+ printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, ®s->rx_err_cnt));
+ printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(pDev, ®s->tx_err_cnt));
+ if ( READ_REG(pDev, ®s->mode) & PELICAN_MOD_RESET ){
+ /* in reset mode it is possible to read acceptance filters */
+ printk(" ACR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->rx_fi_xff),®s->rx_fi_xff);
+ printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.code[0]),(unsigned int)®s->msg.rst_accept.code[0]);
+ printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.code[1]),(unsigned int)®s->msg.rst_accept.code[1]);
+ printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.code[2]),(unsigned int)®s->msg.rst_accept.code[2]);
+ printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[0]),(unsigned int)®s->msg.rst_accept.mask[0]);
+ printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[1]),(unsigned int)®s->msg.rst_accept.mask[1]);
+ printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[2]),(unsigned int)®s->msg.rst_accept.mask[2]);
+ printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(pDev, ®s->msg.rst_accept.mask[3]),(unsigned int)®s->msg.rst_accept.mask[3]);
+
+ }else{
+ printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(pDev, ®s->rx_fi_xff));
+ }
+ printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(pDev, ®s->rx_msg_cnt));
+ printk(" CLKDIV: 0x%02x\n\r",READ_REG(pDev, ®s->clkdiv));
+ printk("-------------------\n\r");
+}
+#endif
+
+#ifdef DEBUG_PRINT_REGMAP
+static void pelican_regadr_print(pelican_regs *regs){
+ printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
+ printk(" MODE: 0x%lx\n\r",(unsigned int)®s->mode);
+ printk(" CMD: 0x%lx\n\r",(unsigned int)®s->cmd);
+ printk(" STATUS: 0x%lx\n\r",(unsigned int)®s->status);
+ /*printk(" INTFLG: 0x%lx\n\r",®s->intflags);*/
+ printk(" INTEN: 0x%lx\n\r",(unsigned int)®s->inten);
+ printk(" BTR0: 0x%lx\n\r",(unsigned int)®s->bustim0);
+ printk(" BTR1: 0x%lx\n\r",(unsigned int)®s->bustim1);
+ printk(" ARBCODE: 0x%lx\n\r",(unsigned int)®s->arbcode);
+ printk(" ERRCODE: 0x%lx\n\r",(unsigned int)®s->errcode);
+ printk(" ERRWARN: 0x%lx\n\r",(unsigned int)®s->errwarn);
+ printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->rx_err_cnt);
+ printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->tx_err_cnt);
+
+ /* in reset mode it is possible to read acceptance filters */
+ printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff);
+
+ /* reset registers */
+ printk(" ACR0: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff);
+ printk(" ACR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[0]);
+ printk(" ACR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[1]);
+ printk(" ACR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[2]);
+ printk(" AMR0: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[0]);
+ printk(" AMR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[1]);
+ printk(" AMR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[2]);
+ printk(" AMR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[3]);
+
+ /* TX Extended */
+ printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[0]);
+ printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[1]);
+ printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[2]);
+ printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[3]);
+
+ printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[0]);
+ printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[1]);
+ printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[2]);
+ printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[3]);
+ printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[4]);
+ printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[5]);
+ printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[6]);
+ printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[7]);
+
+ /* RX Extended */
+ printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[0]);
+ printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[1]);
+ printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[2]);
+ printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[3]);
+
+ printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[0]);
+ printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[1]);
+ printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[2]);
+ printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[3]);
+ printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[4]);
+ printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[5]);
+ printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[6]);
+ printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[7]);
+
+
+ /* RX Extended */
+ printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[0]);
+ printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[1]);
+
+ printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[0]);
+ printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[1]);
+ printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[2]);
+ printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[3]);
+ printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[4]);
+ printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[5]);
+ printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[6]);
+ printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[7]);
+
+ /* TX Extended */
+ printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[0]);
+ printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[1]);
+
+ printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[0]);
+ printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[1]);
+ printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[2]);
+ printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[3]);
+ printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[4]);
+ printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[5]);
+ printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[6]);
+ printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[7]);
+
+ printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)®s->rx_msg_cnt);
+ printk(" CLKDIV: 0x%lx\n\r",(unsigned int)®s->clkdiv);
+ printk("-------------------\n\r");
+}
+#endif
+
+#ifdef DEBUG
+static void occan_stat_print(occan_stats *stats){
+ printk("----Stats----\n\r");
+ printk("rx_msgs: %d\n\r",stats->rx_msgs);
+ printk("tx_msgs: %d\n\r",stats->tx_msgs);
+ printk("err_warn: %d\n\r",stats->err_warn);
+ printk("err_dovr: %d\n\r",stats->err_dovr);
+ printk("err_errp: %d\n\r",stats->err_errp);
+ printk("err_arb: %d\n\r",stats->err_arb);
+ printk("err_bus: %d\n\r",stats->err_bus);
+ printk("Int cnt: %d\n\r",stats->ints);
+ printk("tx_buf_err: %d\n\r",stats->tx_buf_error);
+ printk("-------------\n\r");
+}
+#endif
+
static void pelican_init(occan_priv *priv){
/* Reset core */
- priv->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
/* wait for core to reset complete */
/*usleep(1);*/
}
static void pelican_open(occan_priv *priv){
- /* unsigned char tmp; */
int ret;
/* Set defaults */
@@ -418,44 +776,45 @@ static void pelican_open(occan_priv *priv){
/* Set clock divider to extended mode, clkdiv not connected
*/
- priv->regs->clkdiv = (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV);
+ WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
- ret = occan_calc_speedregs(sys_freq_hz,priv->speed,&priv->timing);
+ ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
if ( ret ){
/* failed to set speed for this system freq, try with 50K instead */
priv->speed = OCCAN_SPEED_50K;
- occan_calc_speedregs(sys_freq_hz,priv->speed,&priv->timing);
+ occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
+ &priv->timing);
}
/* disable all interrupts */
- priv->regs->inten = 0;
+ WRITE_REG(priv, &priv->regs->inten, 0);
/* clear pending interrupts by reading */
- /* tmp = */ READ_REG(&priv->regs->intflags);
+ READ_REG(priv, &priv->regs->intflags);
}
static int pelican_start(occan_priv *priv){
- /* unsigned char tmp; */
/* Start HW communication */
if ( !priv->rxfifo || !priv->txfifo )
return -1;
- /* In case we were started before and stopped we
- * should empty the TX fifo or try to resend those
- * messages. We make it simple...
- */
- occan_fifo_clr(priv->txfifo);
+ /* In case we were started before and stopped we
+ * should empty the TX fifo or try to resend those
+ * messages. We make it simple...
+ */
+ occan_fifo_clr(priv->txfifo);
/* Clear status bits */
priv->status = 0;
+ priv->sending = 0;
/* clear pending interrupts */
- /* tmp = */ READ_REG(&priv->regs->intflags);
+ READ_REG(priv, &priv->regs->intflags);
/* clear error counters */
- priv->regs->rx_err_cnt = 0;
- priv->regs->tx_err_cnt = 0;
+ WRITE_REG(priv, &priv->regs->rx_err_cnt, 0);
+ WRITE_REG(priv, &priv->regs->tx_err_cnt, 0);
#ifdef REDUNDANT_CHANNELS
if ( (priv->channel == 0) || (priv->channel >= REDUNDANT_CHANNELS) ){
@@ -469,15 +828,21 @@ static int pelican_start(occan_priv *priv){
/* set the speed regs of the CAN core */
occan_set_speedregs(priv,&priv->timing);
- DBG("OCCAN: start: set timing regs btr0: 0x%x, btr1: 0x%x\n\r",READ_REG(&priv->regs->bustim0),READ_REG(&priv->regs->bustim1));
+ DBG("OCCAN: start: set timing regs btr0: 0x%x, btr1: 0x%x\n\r",
+ READ_REG(priv, &priv->regs->bustim0),
+ READ_REG(priv, &priv->regs->bustim1));
/* Set default acceptance filter */
pelican_set_accept(priv,priv->acode,priv->amask);
- /* turn on interrupts */
- priv->regs->inten = PELICAN_IE_RX | PELICAN_IE_TX | PELICAN_IE_ERRW |
- PELICAN_IE_ERRP | PELICAN_IE_BUS;
+ /* Nothing can fail from here, this must be set before interrupts are
+ * enabled */
+ priv->started = 1;
+ /* turn on interrupts */
+ WRITE_REG(priv, &priv->regs->inten,
+ PELICAN_IE_RX | PELICAN_IE_TX | PELICAN_IE_ERRW |
+ PELICAN_IE_ERRP | PELICAN_IE_BUS);
#ifdef DEBUG
/* print setup before starting */
pelican_regs_print(priv->regs);
@@ -485,17 +850,23 @@ static int pelican_start(occan_priv *priv){
#endif
/* core already in reset mode,
- * ¤ Exit reset mode
+ * ¤ Exit reset mode
* ¤ Enter Single/Dual mode filtering.
*/
- priv->regs->mode = (priv->single_mode << 3);
+ WRITE_REG(priv, &priv->regs->mode, (priv->single_mode << 3));
+
+ /* Register interrupt routine and unmask IRQ at IRQ controller */
+ drvmgr_interrupt_register(priv->dev, 0, "occan", occan_interrupt, priv);
return 0;
}
-static void pelican_stop(occan_priv *priv){
+static void pelican_stop(occan_priv *priv)
+{
/* stop HW */
+ drvmgr_interrupt_unregister(priv->dev, 0, occan_interrupt, priv);
+
#ifdef DEBUG
/* print setup before stopping */
pelican_regs_print(priv->regs);
@@ -503,14 +874,28 @@ static void pelican_stop(occan_priv *priv){
#endif
/* put core in reset mode */
- priv->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
/* turn off interrupts */
- priv->regs->inten = 0;
+ WRITE_REG(priv, &priv->regs->inten, 0);
priv->status |= OCCAN_STATUS_RESET;
}
+static inline int pelican_tx_ready(occan_priv *can)
+{
+ unsigned char status;
+ pelican_regs *regs = can->regs;
+
+ /* is there room in send buffer? */
+ status = READ_REG(can, ®s->status);
+ if ( !(status & PELICAN_STAT_TXBUF) ) {
+ /* tx fifo taken, we have to wait */
+ return 0;
+ }
+
+ return 1;
+}
/* Try to send message "msg", if hardware txfifo is
* full, then -1 is returned.
@@ -519,12 +904,11 @@ static void pelican_stop(occan_priv *priv){
* entering this function.
*/
static int pelican_send(occan_priv *can, CANMsg *msg){
- unsigned char tmp,status;
+ unsigned char tmp;
pelican_regs *regs = can->regs;
/* is there room in send buffer? */
- status = READ_REG(®s->status);
- if ( !(status & PELICAN_STAT_TXBUF) ){
+ if ( !pelican_tx_ready(can) ) {
/* tx fifo taken, we have to wait */
return -1;
}
@@ -535,39 +919,40 @@ static int pelican_send(occan_priv *can, CANMsg *msg){
if ( msg->extended ){
/* Extended Frame */
- regs->rx_fi_xff = 0x80 | tmp;
- WRITE_REG(®s->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff);
- WRITE_REG(®s->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff);
- WRITE_REG(®s->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff);
- WRITE_REG(®s->msg.tx_eff.id[3],(msg->id << 3) & 0xf8);
+ WRITE_REG(can, ®s->rx_fi_xff, 0x80 | tmp);
+ WRITE_REG(can, ®s->msg.tx_eff.id[0],(msg->id >> (5+8+8)) & 0xff);
+ WRITE_REG(can, ®s->msg.tx_eff.id[1],(msg->id >> (5+8)) & 0xff);
+ WRITE_REG(can, ®s->msg.tx_eff.id[2],(msg->id >> (5)) & 0xff);
+ WRITE_REG(can, ®s->msg.tx_eff.id[3],(msg->id << 3) & 0xf8);
tmp = msg->len;
while(tmp--){
- WRITE_REG(®s->msg.tx_eff.data[tmp],msg->data[tmp]);
+ WRITE_REG(can, ®s->msg.tx_eff.data[tmp], msg->data[tmp]);
}
}else{
/* Standard Frame */
- regs->rx_fi_xff = tmp;
- WRITE_REG(®s->msg.tx_sff.id[0],(msg->id >> 3) & 0xff);
- WRITE_REG(®s->msg.tx_sff.id[1],(msg->id << 5) & 0xe0);
+ WRITE_REG(can, ®s->rx_fi_xff, tmp);
+ WRITE_REG(can, ®s->msg.tx_sff.id[0],(msg->id >> 3) & 0xff);
+ WRITE_REG(can, ®s->msg.tx_sff.id[1],(msg->id << 5) & 0xe0);
tmp = msg->len;
while(tmp--){
- WRITE_REG(®s->msg.tx_sff.data[tmp],msg->data[tmp]);
+ WRITE_REG(can, ®s->msg.tx_sff.data[tmp],msg->data[tmp]);
}
}
/* let HW know of new message */
if ( msg->sshot ){
- regs->cmd = PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT;
+ WRITE_REG(can, ®s->cmd, PELICAN_CMD_TXREQ | PELICAN_CMD_ABORT);
}else{
/* normal case -- try resend until sent */
- regs->cmd = PELICAN_CMD_TXREQ;
+ WRITE_REG(can, ®s->cmd, PELICAN_CMD_TXREQ);
}
return 0;
}
-static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask){
+static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned char *amask)
+{
unsigned char *acode0, *acode1, *acode2, *acode3;
unsigned char *amask0, *amask1, *amask2, *amask3;
@@ -582,159 +967,17 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
amask3 = (unsigned char *)&priv->regs->msg.rst_accept.mask[3];
/* Set new mask & code */
- *acode0 = acode[0];
- *acode1 = acode[1];
- *acode2 = acode[2];
- *acode3 = acode[3];
-
- *amask0 = amask[0];
- *amask1 = amask[1];
- *amask2 = amask[2];
- *amask3 = amask[3];
-}
-
-#ifdef DEBUG
-static void pelican_regs_print(pelican_regs *regs){
- printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
- printk(" MODE: 0x%02x\n\r",READ_REG(®s->mode));
- printk(" CMD: 0x%02x\n\r",READ_REG(®s->cmd));
- printk(" STATUS: 0x%02x\n\r",READ_REG(®s->status));
- /*printk(" INTFLG: 0x%02x\n\r",READ_REG(®s->intflags));*/
- printk(" INTEN: 0x%02x\n\r",READ_REG(®s->inten));
- printk(" BTR0: 0x%02x\n\r",READ_REG(®s->bustim0));
- printk(" BTR1: 0x%02x\n\r",READ_REG(®s->bustim1));
- printk(" ARBCODE: 0x%02x\n\r",READ_REG(®s->arbcode));
- printk(" ERRCODE: 0x%02x\n\r",READ_REG(®s->errcode));
- printk(" ERRWARN: 0x%02x\n\r",READ_REG(®s->errwarn));
- printk(" RX_ERR_CNT: 0x%02x\n\r",READ_REG(®s->rx_err_cnt));
- printk(" TX_ERR_CNT: 0x%02x\n\r",READ_REG(®s->tx_err_cnt));
- if ( READ_REG(®s->mode) & PELICAN_MOD_RESET ){
- /* in reset mode it is possible to read acceptance filters */
- printk(" ACR0: 0x%02x (0x%lx)\n\r",READ_REG(®s->rx_fi_xff),®s->rx_fi_xff);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.code[0]),(unsigned int)®s->msg.rst_accept.code[0]);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.code[1]),(unsigned int)®s->msg.rst_accept.code[1]);
- printk(" ACR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.code[2]),(unsigned int)®s->msg.rst_accept.code[2]);
- printk(" AMR0: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[0]),(unsigned int)®s->msg.rst_accept.mask[0]);
- printk(" AMR1: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[1]),(unsigned int)®s->msg.rst_accept.mask[1]);
- printk(" AMR2: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[2]),(unsigned int)®s->msg.rst_accept.mask[2]);
- printk(" AMR3: 0x%02x (0x%lx)\n\r",READ_REG(®s->msg.rst_accept.mask[3]),(unsigned int)®s->msg.rst_accept.mask[3]);
-
- }else{
- printk(" RXFI_XFF: 0x%02x\n\r",READ_REG(®s->rx_fi_xff));
- }
- printk(" RX_MSG_CNT: 0x%02x\n\r",READ_REG(®s->rx_msg_cnt));
- printk(" CLKDIV: 0x%02x\n\r",READ_REG(®s->clkdiv));
- printk("-------------------\n\r");
-}
-#endif
-
-#ifdef DEBUG_PRINT_REGMAP
-static void pelican_regadr_print(pelican_regs *regs){
- printk("--- PELICAN 0x%lx ---\n\r",(unsigned int)regs);
- printk(" MODE: 0x%lx\n\r",(unsigned int)®s->mode);
- printk(" CMD: 0x%lx\n\r",(unsigned int)®s->cmd);
- printk(" STATUS: 0x%lx\n\r",(unsigned int)®s->status);
- /*printk(" INTFLG: 0x%lx\n\r",®s->intflags);*/
- printk(" INTEN: 0x%lx\n\r",(unsigned int)®s->inten);
- printk(" BTR0: 0x%lx\n\r",(unsigned int)®s->bustim0);
- printk(" BTR1: 0x%lx\n\r",(unsigned int)®s->bustim1);
- printk(" ARBCODE: 0x%lx\n\r",(unsigned int)®s->arbcode);
- printk(" ERRCODE: 0x%lx\n\r",(unsigned int)®s->errcode);
- printk(" ERRWARN: 0x%lx\n\r",(unsigned int)®s->errwarn);
- printk(" RX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->rx_err_cnt);
- printk(" TX_ERR_CNT: 0x%lx\n\r",(unsigned int)®s->tx_err_cnt);
-
- /* in reset mode it is possible to read acceptance filters */
- printk(" RXFI_XFF: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff);
-
- /* reset registers */
- printk(" ACR0: 0x%lx\n\r",(unsigned int)®s->rx_fi_xff);
- printk(" ACR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[0]);
- printk(" ACR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[1]);
- printk(" ACR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.code[2]);
- printk(" AMR0: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[0]);
- printk(" AMR1: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[1]);
- printk(" AMR2: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[2]);
- printk(" AMR3: 0x%lx\n\r",(unsigned int)®s->msg.rst_accept.mask[3]);
-
- /* TX Extended */
- printk(" EFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[0]);
- printk(" EFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[1]);
- printk(" EFFTX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[2]);
- printk(" EFFTX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.id[3]);
-
- printk(" EFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[0]);
- printk(" EFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[1]);
- printk(" EFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[2]);
- printk(" EFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[3]);
- printk(" EFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[4]);
- printk(" EFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[5]);
- printk(" EFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[6]);
- printk(" EFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_eff.data[7]);
-
- /* RX Extended */
- printk(" EFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[0]);
- printk(" EFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[1]);
- printk(" EFFRX_ID[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[2]);
- printk(" EFFRX_ID[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.id[3]);
-
- printk(" EFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[0]);
- printk(" EFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[1]);
- printk(" EFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[2]);
- printk(" EFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[3]);
- printk(" EFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[4]);
- printk(" EFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[5]);
- printk(" EFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[6]);
- printk(" EFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_eff.data[7]);
-
-
- /* RX Extended */
- printk(" SFFRX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[0]);
- printk(" SFFRX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.id[1]);
-
- printk(" SFFRX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[0]);
- printk(" SFFRX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[1]);
- printk(" SFFRX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[2]);
- printk(" SFFRX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[3]);
- printk(" SFFRX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[4]);
- printk(" SFFRX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[5]);
- printk(" SFFRX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[6]);
- printk(" SFFRX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.rx_sff.data[7]);
-
- /* TX Extended */
- printk(" SFFTX_ID[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[0]);
- printk(" SFFTX_ID[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.id[1]);
-
- printk(" SFFTX_DATA[0]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[0]);
- printk(" SFFTX_DATA[1]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[1]);
- printk(" SFFTX_DATA[2]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[2]);
- printk(" SFFTX_DATA[3]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[3]);
- printk(" SFFTX_DATA[4]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[4]);
- printk(" SFFTX_DATA[5]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[5]);
- printk(" SFFTX_DATA[6]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[6]);
- printk(" SFFTX_DATA[7]: 0x%lx\n\r",(unsigned int)®s->msg.tx_sff.data[7]);
-
- printk(" RX_MSG_CNT: 0x%lx\n\r",(unsigned int)®s->rx_msg_cnt);
- printk(" CLKDIV: 0x%lx\n\r",(unsigned int)®s->clkdiv);
- printk("-------------------\n\r");
+ WRITE_REG(priv, acode0, acode[0]);
+ WRITE_REG(priv, acode1, acode[1]);
+ WRITE_REG(priv, acode2, acode[2]);
+ WRITE_REG(priv, acode3, acode[3]);
+
+ WRITE_REG(priv, amask0, amask[0]);
+ WRITE_REG(priv, amask1, amask[1]);
+ WRITE_REG(priv, amask2, amask[2]);
+ WRITE_REG(priv, amask3, amask[3]);
}
-#endif
-#ifdef DEBUG
-static void occan_stat_print(occan_stats *stats){
- printk("----Stats----\n\r");
- printk("rx_msgs: %d\n\r",stats->rx_msgs);
- printk("tx_msgs: %d\n\r",stats->tx_msgs);
- printk("err_warn: %d\n\r",stats->err_warn);
- printk("err_dovr: %d\n\r",stats->err_dovr);
- printk("err_errp: %d\n\r",stats->err_errp);
- printk("err_arb: %d\n\r",stats->err_arb);
- printk("err_bus: %d\n\r",stats->err_bus);
- printk("Int cnt: %d\n\r",stats->ints);
- printk("tx_buf_err: %d\n\r",stats->tx_buf_error);
- printk("-------------\n\r");
-}
-#endif
/* This function calculates BTR0 and BTR1 values for a given bitrate.
*
@@ -744,7 +987,8 @@ static void occan_stat_print(occan_stats *stats){
* \param result Pointer to where resulting BTRs will be stored.
* \return zero if successful to calculate a baud rate.
*/
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result){
+static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
+{
int best_error = 1000000000;
int error;
int best_tseg=0, best_brp=0, brp=0;
@@ -827,12 +1071,14 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_
return 0;
}
-static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing){
+static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
+{
if ( !timing || !priv || !priv->regs)
return -1;
- priv->regs->bustim0 = timing->btr0;
- priv->regs->bustim1 = timing->btr1;
+ WRITE_REG(priv, &priv->regs->bustim0, timing->btr0);
+ WRITE_REG(priv, &priv->regs->bustim1, timing->btr1);
+
return 0;
}
@@ -861,7 +1107,7 @@ static int pelican_speed_auto(occan_priv *priv){
while ( (speed=pelican_speed_auto_steplist[i]) > 0){
/* Reset core */
- priv->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(priv, &priv->regs->mode, PELICAN_MOD_RESET);
/* tell int handler about the auto speed detection test */
@@ -873,7 +1119,7 @@ static int pelican_speed_auto(occan_priv *priv){
pelican_set_accept(priv);
/* calc timing params for this */
- if ( occan_calc_speedregs(sys_freq_hz,speed,&timing) ){
+ if ( occan_calc_speedregs(priv->sys_freq_hz,speed,&timing) ){
/* failed to get good timings for this frequency
* test with next
*/
@@ -887,13 +1133,13 @@ static int pelican_speed_auto(occan_priv *priv){
/* Empty previous messages in hardware RX fifo */
/*
- while( READ_REG(&priv->regs->) ){
+ while( READ_REG(priv, &priv->regs->) ){
}
*/
/* Clear pending interrupts */
- tmp = READ_REG(&priv->regs->intflags);
+ tmp = READ_REG(priv, &priv->regs->intflags);
/* enable RX & ERR interrupt */
priv->regs->inten =
@@ -911,176 +1157,23 @@ static int pelican_speed_auto(occan_priv *priv){
#endif
}
-
-static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg){
- int dev_cnt,minor,subcore_cnt,devi,subi,subcores;
- struct ambapp_ahb_info ambadev;
- occan_priv *can;
- char fs_name[20];
- rtems_status_code status;
-
- strcpy(fs_name,OCCAN_DEVNAME);
-
- /* find device on amba bus */
- dev_cnt = ambapp_get_number_ahbslv_devices(amba_bus, VENDOR_GAISLER,
- GAISLER_CANAHB);
- if ( dev_cnt < 1 ){
- /* Failed to find any CAN cores! */
- printk("OCCAN: Failed to find any CAN cores\n\r");
- return -1;
- }
-
- /* Detect System Frequency from initialized timer */
-#ifndef SYS_FREQ_HZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- struct ambapp_apb_info gptimer;
- struct gptimer_regs *tregs;
-
- if ( ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER,
- GAISLER_GPTIMER, &gptimer) == 1 ){
- tregs = (struct gptimer_regs *)gptimer.start;
- sys_freq_hz = (tregs->scaler_reload+1)*1000*1000;
- DBG("OCCAN: detected %dHZ system frequency\n\r",sys_freq_hz);
- }else{
- sys_freq_hz = 40000000; /* Default to 40MHz */
- printk("OCCAN: Failed to detect system frequency\n\r");
- }
-
- }
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000;
- }
-#else
- #error CPU not supported for OC_CAN driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_hz = SYS_FREQ_HZ;
-#endif
-
- DBG("OCCAN: Detected %dHz system frequency\n\r",sys_freq_hz);
-
- /* OCCAN speciality:
- * Mulitple cores are supported through the same amba AHB interface.
- * The number of "sub cores" can be detected by decoding the AMBA
- * Plug&Play version information. verion = ncores. A maximum of 8
- * sub cores are supported, each separeated with 0x100 inbetween.
- *
- * Now, lets detect sub cores.
- */
-
- for(subcore_cnt=devi=0; devi<dev_cnt; devi++){
- ambapp_find_ahbslv_next(amba_bus, VENDOR_GAISLER,
- GAISLER_CANAHB, &ambadev, devi);
- subcore_cnt += (ambadev.ver & 0x7)+1;
- }
-
- printk("OCCAN: Found %d devs, totally %d sub cores\n\r",dev_cnt,subcore_cnt);
-
- /* allocate memory for cores */
- can_cores = subcore_cnt;
- cans = calloc(subcore_cnt*sizeof(occan_priv),1);
-
- minor=0;
- for(devi=0; devi<dev_cnt; devi++){
-
- /* Get AHB device info */
- ambapp_find_ahbslv_next(amba_bus, VENDOR_GAISLER,
- GAISLER_CANAHB, &ambadev, devi);
- subcores = (ambadev.ver & 0x7)+1;
- DBG("OCCAN: on dev %d found %d sub cores\n\r",devi,subcores);
-
- /* loop all subcores, at least 1 */
- for(subi=0; subi<subcores; subi++){
- can = &cans[minor];
-
-#ifdef OCCAN_BYTE_REGS
- /* regs is byte regs */
- can->regs = (void *)(ambadev.start[0] + OCCAN_NCORE_OFS*subi);
-#else
- /* regs is word regs, accessed 0x100 from base address */
- can->regs = (void *)(ambadev.start[0] + OCCAN_NCORE_OFS*subi+ OCCAN_WORD_REG_OFS);
-#endif
-
- /* remember IRQ number */
- can->irq = ambadev.irq+subi;
-
- /* bind filesystem name to device */
- OCCAN_DEVNAME_NO(fs_name,minor);
- printk("OCCAN: Registering %s to [%d %d] @ 0x%lx irq %d\n\r",fs_name,major,minor,(unsigned int)can->regs,can->irq);
- status = rtems_io_register_name(fs_name, major, minor);
- if (RTEMS_SUCCESSFUL != status )
- rtems_fatal_error_occurred(status);
-
- /* initialize software */
- can->open = 0;
- can->rxfifo = NULL;
- can->txfifo = NULL;
- status = rtems_semaphore_create(
- rtems_build_name('C', 'd', 'v', '0'+minor),
- 1,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &can->devsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN: Failed to create dev semaphore for minor %d, (%d)\n\r",minor,status);
- return RTEMS_UNSATISFIED;
- }
- status = rtems_semaphore_create(
- rtems_build_name('C', 't', 'x', '0'+minor),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &can->txsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN: Failed to create tx semaphore for minor %d, (%d)\n\r",minor,status);
- return RTEMS_UNSATISFIED;
- }
- status = rtems_semaphore_create(
- rtems_build_name('C', 'r', 'x', '0'+minor),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &can->rxsem);
- if ( status != RTEMS_SUCCESSFUL ){
- printk("OCCAN: Failed to create rx semaphore for minor %d, (%d)\n\r",minor,status);
- return RTEMS_UNSATISFIED;
- }
-
- /* hardware init/reset */
- pelican_init(can);
-
- /* Setup interrupt handler for each channel */
- OCCAN_REG_INT(OCCAN_PREFIX(_interrupt_handler), can->irq, can);
-
- minor++;
-#ifdef DEBUG_PRINT_REGMAP
- pelican_regadr_print(can->regs);
-#endif
- }
- }
-
+static rtems_device_driver occan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg)
+{
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver occan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
occan_priv *can;
+ struct drvmgr_dev *dev;
DBG("OCCAN: Opening %d\n\r",minor);
- if ( minor >= can_cores )
+ /* get can device */
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
return RTEMS_UNSATISFIED; /* NODEV */
-
- /* get can device */
- can = &cans[minor];
+ }
+ can = (occan_priv *)dev->priv;
/* already opened? */
rtems_semaphore_obtain(can->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
@@ -1126,17 +1219,24 @@ static rtems_device_driver occan_open(rtems_device_major_number major, rtems_dev
return RTEMS_SUCCESSFUL;
}
-static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
- occan_priv *can = &cans[minor];
+static rtems_device_driver occan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ occan_priv *can;
+ struct drvmgr_dev *dev;
DBG("OCCAN: Closing %d\n\r",minor);
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
/* stop if running */
if ( can->started )
pelican_stop(can);
/* Enter Reset Mode */
- can->regs->mode = PELICAN_MOD_RESET;
+ WRITE_REG(can, &can->regs->mode, PELICAN_MOD_RESET);
/* free fifo memory */
occan_fifo_free(can->rxfifo);
@@ -1145,16 +1245,24 @@ static rtems_device_driver occan_close(rtems_device_major_number major, rtems_de
can->rxfifo = NULL;
can->txfifo = NULL;
+ can->open = 0;
+
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver occan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
- occan_priv *can = &cans[minor];
+ occan_priv *can;
+ struct drvmgr_dev *dev;
rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
CANMsg *dstmsg, *srcmsg;
rtems_interrupt_level oldLevel;
int left;
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
if ( !can->started ){
DBG("OCCAN: cannot read from minor %d when not started\n\r",minor);
return RTEMS_RESOURCE_IN_USE; /* -EBUSY*/
@@ -1205,8 +1313,9 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev
DBG("OCCAN: Waiting for RX int\n\r");
- /* wait for incomming messages */
- rtems_semaphore_obtain(can->rxsem,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+ /* wait for incoming messages */
+ rtems_semaphore_obtain(can->rxsem, RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT);
/* did we get woken up by a BUS OFF error? */
if ( can->status & (OCCAN_STATUS_ERR_BUSOFF|OCCAN_STATUS_RESET) ){
@@ -1244,7 +1353,8 @@ static rtems_device_driver occan_read(rtems_device_major_number major, rtems_dev
}
static rtems_device_driver occan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
- occan_priv *can = &cans[minor];
+ occan_priv *can;
+ struct drvmgr_dev *dev;
rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
CANMsg *msg,*fifo_msg;
rtems_interrupt_level oldLevel;
@@ -1252,6 +1362,11 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
DBG("OCCAN: Writing %d bytes from 0x%lx (%d)\n\r",rw_args->count,rw_args->buffer,sizeof(CANMsg));
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
if ( !can->started )
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
@@ -1293,6 +1408,11 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
left -= sizeof(CANMsg);
msg++;
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ /* Mark that we have put at least one msg in TX FIFO */
+ can->sending = 1;
+#endif
+
/* bump stat counters */
can->stats.tx_msgs++;
@@ -1341,11 +1461,16 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
if ( occan_fifo_empty(can->txfifo) ){
if ( !pelican_send(can,msg) ) {
/* First message put directly into HW TX fifo
- * This will turn TX interrupt on.
- */
+ * This will turn TX interrupt on.
+ */
left -= sizeof(CANMsg);
msg++;
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ /* Mark that we have put at least one msg in TX FIFO */
+ can->sending = 1;
+#endif
+
/* bump stat counters */
can->stats.tx_msgs++;
@@ -1381,15 +1506,21 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg){
int ret;
occan_speed_regs timing;
- occan_priv *can = &cans[minor];
+ occan_priv *can;
+ struct drvmgr_dev *dev;
unsigned int speed;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
struct occan_afilter *afilter;
occan_stats *dststats;
unsigned int rxcnt,txcnt;
DBG("OCCAN: IOCTL %d\n\r",ioarg->command);
+ if ( drvmgr_get_dev(&occan_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ can = (occan_priv *)dev->priv;
+
ioarg->ioctl_return = 0;
switch(ioarg->command){
case OCCAN_IOC_SET_SPEED:
@@ -1400,7 +1531,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* get speed rate from argument */
speed = (unsigned int)ioarg->buffer;
- ret = occan_calc_speedregs(sys_freq_hz,speed,&timing);
+ ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
if ( ret )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -1479,8 +1610,8 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
return RTEMS_INVALID_NAME; /* EINVAL */
/* copy data stats into userspace buffer */
- if ( can->rxfifo )
- can->stats.rx_sw_dovr = can->rxfifo->ovcnt;
+ if ( can->rxfifo )
+ can->stats.rx_sw_dovr = can->rxfifo->ovcnt;
*dststats = can->stats;
break;
@@ -1543,7 +1674,9 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
if ( pelican_start(can) )
return RTEMS_NO_MEMORY; /* failed because of no memory, can happen if SET_BUFLEN failed */
- can->started = 1;
+ /* can->started = 1; -- Is set in pelican_start due to interrupt may occur before we
+ * get here.
+ */
break;
case OCCAN_IOC_STOP:
@@ -1559,7 +1692,9 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
return RTEMS_SUCCESSFUL;
}
-static void occan_interrupt(occan_priv *can){
+void occan_interrupt(void *arg)
+{
+ occan_priv *can = arg;
unsigned char iflags;
pelican_regs *regs = can->regs;
CANMsg *msg;
@@ -1567,11 +1702,33 @@ static void occan_interrupt(occan_priv *can){
unsigned char tmp, errcode, arbcode;
int tx_error_cnt,rx_error_cnt;
- can->stats.ints++;
+ if ( !can->started )
+ return; /* Spurious Interrupt, do nothing */
+
+ while (1) {
+
+ iflags = READ_REG(can, &can->regs->intflags);
+
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ /* TX IRQ may be cleared when reading regs->intflags due
+ * to a bug in some chips. Instead of looking at the TX_IRQ_FLAG
+ * the TX-fifo emoty register is looked at when something has
+ * been scheduled for transmission.
+ */
+ if ((iflags & PELICAN_IF_TX) == 0) {
+ if (can->sending && pelican_tx_ready(can)) {
+ can->sending = 0;
+ iflags |= PELICAN_IF_TX;
+ }
+ }
+#endif
- while ( (iflags = READ_REG(&can->regs->intflags)) != 0 ){
+ if (iflags == 0)
+ break;
/* still interrupts to handle */
+ can->stats.ints++;
+
if ( iflags & PELICAN_IF_RX ){
/* the rx fifo is not empty
* put 1 message into rxfifo for later use
@@ -1579,52 +1736,53 @@ static void occan_interrupt(occan_priv *can){
/* get empty (or make room) message */
msg = occan_fifo_put_claim(can->rxfifo,1);
- tmp = READ_REG(®s->rx_fi_xff);
+ tmp = READ_REG(can, ®s->rx_fi_xff);
msg->extended = tmp >> 7;
msg->rtr = (tmp >> 6) & 1;
msg->len = tmp = tmp & 0x0f;
if ( msg->extended ){
/* extended message */
- msg->id = READ_REG(®s->msg.rx_eff.id[0])<<(5+8+8) |
- READ_REG(®s->msg.rx_eff.id[1])<<(5+8) |
- READ_REG(®s->msg.rx_eff.id[2])<<5 |
- READ_REG(®s->msg.rx_eff.id[3])>>3;
+ msg->id = READ_REG(can, ®s->msg.rx_eff.id[0])<<(5+8+8) |
+ READ_REG(can, ®s->msg.rx_eff.id[1])<<(5+8) |
+ READ_REG(can, ®s->msg.rx_eff.id[2])<<5 |
+ READ_REG(can, ®s->msg.rx_eff.id[3])>>3;
+
while(tmp--){
- msg->data[tmp] = READ_REG(®s->msg.rx_eff.data[tmp]);
+ msg->data[tmp] = READ_REG(can, ®s->msg.rx_eff.data[tmp]);
}
/*
- msg->data[0] = READ_REG(®s->msg.rx_eff.data[0]);
- msg->data[1] = READ_REG(®s->msg.rx_eff.data[1]);
- msg->data[2] = READ_REG(®s->msg.rx_eff.data[2]);
- msg->data[3] = READ_REG(®s->msg.rx_eff.data[3]);
- msg->data[4] = READ_REG(®s->msg.rx_eff.data[4]);
- msg->data[5] = READ_REG(®s->msg.rx_eff.data[5]);
- msg->data[6] = READ_REG(®s->msg.rx_eff.data[6]);
- msg->data[7] = READ_REG(®s->msg.rx_eff.data[7]);
+ msg->data[0] = READ_REG(can, ®s->msg.rx_eff.data[0]);
+ msg->data[1] = READ_REG(can, ®s->msg.rx_eff.data[1]);
+ msg->data[2] = READ_REG(can, ®s->msg.rx_eff.data[2]);
+ msg->data[3] = READ_REG(can, ®s->msg.rx_eff.data[3]);
+ msg->data[4] = READ_REG(can, ®s->msg.rx_eff.data[4]);
+ msg->data[5] = READ_REG(can, ®s->msg.rx_eff.data[5]);
+ msg->data[6] = READ_REG(can, ®s->msg.rx_eff.data[6]);
+ msg->data[7] = READ_REG(can, ®s->msg.rx_eff.data[7]);
*/
}else{
/* standard message */
- msg->id = READ_REG(®s->msg.rx_sff.id[0])<<3 |
- READ_REG(®s->msg.rx_sff.id[1])>>5;
+ msg->id = READ_REG(can, ®s->msg.rx_sff.id[0])<<3 |
+ READ_REG(can, ®s->msg.rx_sff.id[1])>>5;
while(tmp--){
- msg->data[tmp] = READ_REG(®s->msg.rx_sff.data[tmp]);
+ msg->data[tmp] = READ_REG(can, ®s->msg.rx_sff.data[tmp]);
}
/*
- msg->data[0] = READ_REG(®s->msg.rx_sff.data[0]);
- msg->data[1] = READ_REG(®s->msg.rx_sff.data[1]);
- msg->data[2] = READ_REG(®s->msg.rx_sff.data[2]);
- msg->data[3] = READ_REG(®s->msg.rx_sff.data[3]);
- msg->data[4] = READ_REG(®s->msg.rx_sff.data[4]);
- msg->data[5] = READ_REG(®s->msg.rx_sff.data[5]);
- msg->data[6] = READ_REG(®s->msg.rx_sff.data[6]);
- msg->data[7] = READ_REG(®s->msg.rx_sff.data[7]);
+ msg->data[0] = READ_REG(can, ®s->msg.rx_sff.data[0]);
+ msg->data[1] = READ_REG(can, ®s->msg.rx_sff.data[1]);
+ msg->data[2] = READ_REG(can, ®s->msg.rx_sff.data[2]);
+ msg->data[3] = READ_REG(can, ®s->msg.rx_sff.data[3]);
+ msg->data[4] = READ_REG(can, ®s->msg.rx_sff.data[4]);
+ msg->data[5] = READ_REG(can, ®s->msg.rx_sff.data[5]);
+ msg->data[6] = READ_REG(can, ®s->msg.rx_sff.data[6]);
+ msg->data[7] = READ_REG(can, ®s->msg.rx_sff.data[7]);
*/
}
/* Re-Enable RX buffer for a new message */
- regs->cmd = PELICAN_CMD_RELRXBUF;
+ WRITE_REG(can, ®s->cmd, PELICAN_CMD_RELRXBUF);
/* make message available to the user */
occan_fifo_put(can->rxfifo);
@@ -1636,7 +1794,8 @@ static void occan_interrupt(occan_priv *can){
signal_rx = 1;
}
- if ( iflags & PELICAN_IF_TX ){
+ if ( iflags & PELICAN_IF_TX ) {
+
/* there is room in tx fifo of HW */
if ( !occan_fifo_empty(can->txfifo) ){
@@ -1655,6 +1814,9 @@ static void occan_interrupt(occan_priv *can){
can->status |= OCCAN_STATUS_QUEUE_ERROR;
can->stats.tx_buf_error++;
}
+#ifdef OCCAN_TX_IRQ_FLAG_FIXUP
+ can->sending = 1;
+#endif
/* free software-fifo space taken by sent message */
occan_fifo_get(can->txfifo);
@@ -1668,8 +1830,8 @@ static void occan_interrupt(occan_priv *can){
}
if ( iflags & PELICAN_IF_ERRW ){
- tx_error_cnt = READ_REG(®s->tx_err_cnt);
- rx_error_cnt = READ_REG(®s->rx_err_cnt);
+ tx_error_cnt = READ_REG(can, ®s->tx_err_cnt);
+ rx_error_cnt = READ_REG(can, ®s->rx_err_cnt);
/* 1. if bus off tx error counter = 127 */
if ( (tx_error_cnt > 96) || (rx_error_cnt > 96) ){
@@ -1677,7 +1839,7 @@ static void occan_interrupt(occan_priv *can){
can->status |= OCCAN_STATUS_WARN;
/* check reset bit for reset mode */
- if ( READ_REG(®s->mode) & PELICAN_MOD_RESET ){
+ if ( READ_REG(can, ®s->mode) & PELICAN_MOD_RESET ){
/* in reset mode ==> bus off */
can->status |= OCCAN_STATUS_ERR_BUSOFF | OCCAN_STATUS_RESET;
@@ -1685,7 +1847,7 @@ static void occan_interrupt(occan_priv *can){
* turn off interrupts
* enter reset mode (HW already done that for us)
*/
- regs->inten = 0;
+ WRITE_REG(can, ®s->inten,0);
/* Indicate that we are not started any more.
* This will make write/read return with EBUSY
@@ -1722,8 +1884,8 @@ static void occan_interrupt(occan_priv *can){
/* Let the error counters decide what kind of
* interrupt it was. In/Out of EPassive area.
*/
- tx_error_cnt = READ_REG(®s->tx_err_cnt);
- rx_error_cnt = READ_REG(®s->rx_err_cnt);
+ tx_error_cnt = READ_REG(can, ®s->tx_err_cnt);
+ rx_error_cnt = READ_REG(can, ®s->rx_err_cnt);
if ( (tx_error_cnt > 127) || (rx_error_cnt > 127) ){
can->status |= OCCAN_STATUS_ERR_PASSIVE;
@@ -1736,7 +1898,7 @@ static void occan_interrupt(occan_priv *can){
}
if ( iflags & PELICAN_IF_ARB){
- arbcode = READ_REG(®s->arbcode);
+ arbcode = READ_REG(can, ®s->arbcode);
can->stats.err_arb_bitnum[arbcode & PELICAN_ARB_BITS]++;
can->stats.err_arb++;
DBG("OCCAN_INT: ARB (0x%x)\n\r",arbcode & PELICAN_ARB_BITS);
@@ -1747,7 +1909,7 @@ static void occan_interrupt(occan_priv *can){
* statistics. Error Register is decoded
* and put into can->stats.
*/
- errcode = READ_REG(®s->errcode);
+ errcode = READ_REG(can, ®s->errcode);
switch( errcode & PELICAN_ECC_CODE ){
case PELICAN_ECC_CODE_BIT:
can->stats.err_bus_bit++;
@@ -1788,58 +1950,12 @@ static void occan_interrupt(occan_priv *can){
}
}
-#ifdef OCCAN_DEFINE_INTHANDLER
-static void occan_interrupt_handler(rtems_vector_number v){
- int minor;
-
- /* convert to */
- for(minor = 0; minor < can_cores; minor++) {
- if ( v == (cans[minor].irq+0x10) ) {
- occan_interrupt(&cans[minor]);
- return;
- }
- }
-}
-#endif
-
-#define OCCAN_DRIVER_TABLE_ENTRY { occan_initialize, occan_open, occan_close, occan_read, occan_write, occan_ioctl }
-
-static rtems_driver_address_table occan_driver = OCCAN_DRIVER_TABLE_ENTRY;
-
-int OCCAN_PREFIX(_register)(struct ambapp_bus *bus);
-
-int OCCAN_PREFIX(_register)(struct ambapp_bus *bus){
- rtems_status_code r;
- rtems_device_major_number m;
-
- amba_bus = bus;
- if ( !bus )
- return 1;
-
- if ((r = rtems_io_register_driver(0, &occan_driver, &m)) == RTEMS_SUCCESSFUL) {
- DBG("OCCAN driver successfully registered, major: %d\n\r", m);
- }else{
- switch(r) {
- case RTEMS_TOO_MANY:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
- case RTEMS_INVALID_NUMBER:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
- case RTEMS_RESOURCE_IN_USE:
- printk("OCCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
- default:
- printk("OCCAN rtems_io_register_driver failed\n\r");
- }
- return 1;
- }
- return 0;
-}
-
-
/*******************************************************************************
* FIFO IMPLEMENTATION
*/
-static occan_fifo *occan_fifo_create(int cnt){
+static occan_fifo *occan_fifo_create(int cnt)
+{
occan_fifo *fifo;
fifo = malloc(sizeof(occan_fifo)+cnt*sizeof(CANMsg));
if ( fifo ){
@@ -1854,21 +1970,25 @@ static occan_fifo *occan_fifo_create(int cnt){
return fifo;
}
-static void occan_fifo_free(occan_fifo *fifo){
+static void occan_fifo_free(occan_fifo *fifo)
+{
if ( fifo )
free(fifo);
}
-static int occan_fifo_full(occan_fifo *fifo){
+static int occan_fifo_full(occan_fifo *fifo)
+{
return fifo->full;
}
-static int occan_fifo_empty(occan_fifo *fifo){
+static int occan_fifo_empty(occan_fifo *fifo)
+{
return (!fifo->full) && (fifo->head == fifo->tail);
}
/* Stage 1 - get buffer to fill (never fails if force!=0) */
-static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force){
+static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force)
+{
if ( !fifo )
return NULL;
@@ -1886,7 +2006,8 @@ static CANMsg *occan_fifo_put_claim(occan_fifo *fifo, int force){
}
/* Stage 2 - increment indexes */
-static void occan_fifo_put(occan_fifo *fifo){
+static void occan_fifo_put(occan_fifo *fifo)
+{
if ( occan_fifo_full(fifo) )
return;
@@ -1897,7 +2018,8 @@ static void occan_fifo_put(occan_fifo *fifo){
fifo->full = 1;
}
-static CANMsg *occan_fifo_claim_get(occan_fifo *fifo){
+static CANMsg *occan_fifo_claim_get(occan_fifo *fifo)
+{
if ( occan_fifo_empty(fifo) )
return NULL;
@@ -1906,7 +2028,8 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo){
}
-static void occan_fifo_get(occan_fifo *fifo){
+static void occan_fifo_get(occan_fifo *fifo)
+{
if ( !fifo )
return;
@@ -1914,14 +2037,16 @@ static void occan_fifo_get(occan_fifo *fifo){
return;
/* increment indexes */
- fifo->tail = (fifo->tail >= &fifo->base[fifo->cnt-1])? fifo->base : fifo->tail+1;
+ fifo->tail = (fifo->tail >= &fifo->base[fifo->cnt-1]) ?
+ fifo->base : fifo->tail+1;
fifo->full = 0;
}
-static void occan_fifo_clr(occan_fifo *fifo){
- fifo->full = 0;
- fifo->ovcnt = 0;
- fifo->head = fifo->tail = fifo->base;
+static void occan_fifo_clr(occan_fifo *fifo)
+{
+ fifo->full = 0;
+ fifo->ovcnt = 0;
+ fifo->head = fifo->tail = fifo->base;
}
-/*******************************************************************************/
+/******************************************************************************/
diff --git a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
index 02710e1..f71af0b 100644
--- a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
+++ b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
@@ -1,7 +1,7 @@
/*
* Driver for GRLIB port of OpenCores I2C-master
*
- * COPYRIGHT (c) 2007 Gaisler Research
+ * COPYRIGHT (c) 2007 Cobham Gaisler AB
* based on the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH.
*
* The license and distribution terms for this file may be
@@ -9,27 +9,41 @@
* http://www.rtems.org/license/LICENSE.
*
* This file contains the driver and initialization code
- *
- * 2007-09-27: First version of driver (jan at gaisler.com)
*/
-
#include <bsp.h>
-#include <i2cmst.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <ambapp.h>
-#include <grlib.h>
#include <rtems/libi2c.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <i2cmst.h>
/* Enable debug printks? */
-/* #define DEBUG */
+/*#define DEBUG*/
-/* Default to 40 MHz system clock? */
-/*
- #ifndef SYS_FREQ_kHZ
- #define SYS_FREQ_kHZ 40000
- #endif
-*/
+#ifdef DEBUG
+ #define DBG(args...) printk(args)
+#else
+ #define DBG(args...)
+#endif
+/* The OC I2C core will perform a write after a start unless the RD bit
+ in the command register has been set. Since the rtems framework has
+ a send_start function we buffer that command and use it when the first
+ data is written. The START is buffered in the sendstart member below */
+typedef struct gr_i2cmst_prv {
+ rtems_libi2c_bus_t i2clib_desc;
+ struct drvmgr_dev *dev;
+ gr_i2cmst_regs_t *reg_ptr;
+ unsigned int sysfreq; /* System clock frequency in kHz */
+ int minor;
+ unsigned char sendstart; /* START events are buffered here */
+ /* rtems_irq_number irq_number; */
+ /* rtems_id irq_sema_id; */
+} gr_i2cmst_prv_t;
/* Calculates the scaler value for 100 kHz operation */
static int gr_i2cmst_calc_scaler(int sysfreq)
@@ -42,12 +56,12 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
{
uint32_t tout = 0;
int current_sts;
-#if defined(DEBUG)
- printk("(gr_i2cmst_wait called...");
-#endif
+
+ DBG("(gr_i2cmst_wait called...");
do {
if (tout++ > 1000000) {
+ DBG("gr_i2cmst_wait: TIMEOUT\n");
return RTEMS_TIMEOUT;
}
} while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP);
@@ -57,32 +71,31 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
if (current_sts != expected_sts) {
#if defined(DEBUG)
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) {
- printk("Transfer NAKed..");
+ DBG("Transfer NAKed..");
}
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) {
- printk("arbitration lost..");
+ DBG("arbitration lost..");
}
if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) {
- printk("transfer still in progress, huh?..");
+ DBG("transfer still in progress, huh?..");
}
- printk("exited with IO error..)");
+ DBG("exited with IO error..)");
#endif
+ DBG("gr_i2cmst_wait: IO-ERROR\n");
return RTEMS_IO_ERROR;
}
-#if defined(DEBUG)
- printk("exited...)");
-#endif
+ DBG("exited...)");
+
return RTEMS_SUCCESSFUL;
}
/* Initialize hardware core */
static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_init called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_init called...");
/* Disable core before changing prescale register */
prv_ptr->reg_ptr->ctrl = 0;
@@ -96,54 +109,48 @@ static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
/* Clear possible START condition */
prv_ptr->sendstart = 0;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_start(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_send_start called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_send_start called...");
/* The OC I2C core does not work with stand alone START events,
instead the event is buffered */
prv_ptr->sendstart = GRI2C_CMD_STA;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_stop(rtems_libi2c_bus_t *bushdl)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
-#if defined(DEBUG)
- printk("gr_i2cmst_send_stop called...");
-#endif
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
+
+ DBG("gr_i2cmst_send_stop called...");
prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO;
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return RTEMS_SUCCESSFUL;
}
static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
uint32_t addr, int rw)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
uint8_t addr_byte;
rtems_status_code rc;
-#if defined(DEBUG)
- printk("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
+
+ DBG("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
addr, rw);
-#endif
/* Check if long address is needed */
if (addr > 0x7f) {
@@ -156,9 +163,9 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
/* Wait for transfer to complete */
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+
+ DBG("exited with error\n");
+
return -rc;
}
}
@@ -176,16 +183,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
/* Wait for transfer to complete */
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+ DBG("exited with error\n");
return -rc;
}
- }
+ }
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
return rc;
}
@@ -193,13 +196,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
unsigned char *bytes, int nbytes)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
unsigned char *buf = bytes;
rtems_status_code rc;
unsigned char expected_sts = GRI2C_STATUS_IDLE;
-#if defined(DEBUG)
- printk("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
-#endif
+
+ DBG("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
while (nbytes-- > 0) {
if (nbytes == 0) {
@@ -214,34 +216,30 @@ static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
/* Wait until end of transfer */
rc = gr_i2cmst_wait(prv_ptr, expected_sts);
if (rc != RTEMS_SUCCESSFUL) {
+ DBG("exited with error\n");
return -rc;
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
}
*buf++ = prv_ptr->reg_ptr->tdrd;
}
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return buf - bytes;
}
static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
unsigned char *bytes, int nbytes)
{
- gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl;
unsigned char *buf = bytes;
rtems_status_code rc;
-#if defined(DEBUG)
- printk("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
-#endif
+
+ DBG("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
while (nbytes-- > 0) {
-#if defined(DEBUG)
- printk("writing byte 0x%02X...", *buf);
-#endif
+
+ DBG("writing byte 0x%02X...", *buf);
+
prv_ptr->reg_ptr->tdrd = *buf++;
prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
prv_ptr->sendstart = 0;
@@ -250,16 +248,13 @@ static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
if (rc != RTEMS_SUCCESSFUL) {
-#if defined(DEBUG)
- printk("exited with error\n");
-#endif
+ DBG("exited with error\n");
return -rc;
}
}
-#if defined(DEBUG)
- printk("exited\n");
-#endif
+ DBG("exited\n");
+
return buf - bytes;
}
@@ -272,88 +267,148 @@ static rtems_libi2c_bus_ops_t gr_i2cmst_ops = {
write_bytes: gr_i2cmst_write_bytes,
};
+/* Get Hardware and disable it */
+int i2cmst_device_init(gr_i2cmst_prv_t *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
-static gr_i2cmst_desc_t gr_i2cmst_desc = {
- { /* rtems_libi2c_bus_t */
- ops : &gr_i2cmst_ops,
- size : sizeof(gr_i2cmst_ops),
- },
- { /* gr_i2cmst_prv_t, private data */
- reg_ptr : NULL,
- sysfreq : 40000,
- }
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->reg_ptr = (gr_i2cmst_regs_t *)pnpinfo->apb_slv->start;
+
+ /* Disable core */
+ priv->reg_ptr->ctrl = 0;
+
+ priv->i2clib_desc.ops = &gr_i2cmst_ops;
+ priv->i2clib_desc.size = sizeof(gr_i2cmst_ops);
+ return 0;
+}
+
+
+/******************* Driver Manager Part ***********************/
+
+int i2cmst_init2(struct drvmgr_dev *dev);
+int i2cmst_init3(struct drvmgr_dev *dev);
+struct drvmgr_drv_ops i2cmst_ops =
+{
+ .init = {NULL, i2cmst_init2, i2cmst_init3, NULL},
+ .remove = NULL,
+ .info = NULL
};
-/* Scans for I2CMST core and initalizes i2c library */
-rtems_status_code leon_register_i2c(struct ambapp_bus *abus)
+struct amba_dev_id i2cmst_ids[] =
{
-#if defined(DEBUG)
- printk("leon_register_i2c called...");
-#endif
+ {VENDOR_GAISLER, GAISLER_I2CMST},
+ {0, 0} /* Mark end of table */
+};
- int rc;
- int device_found = 0;
- struct ambapp_apb_info apbi2cmst;
+struct amba_drv_info i2cmst_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_I2CMST_ID, /* Driver ID */
+ "I2CMST_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &i2cmst_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &i2cmst_ids[0]
+};
- /* Scan AMBA bus for I2CMST core */
- device_found = ambapp_find_apbslv(abus, VENDOR_GAISLER, GAISLER_I2CMST,
- &apbi2cmst);
+void i2cmst_register_drv (void)
+{
+ DBG("Registering I2CMST driver\n");
+ drvmgr_drv_register(&i2cmst_drv_info.general);
+}
- if (device_found == 1) {
+/* The I2CMST Driver is informed about a new hardware device */
+int i2cmst_init2(struct drvmgr_dev *dev)
+{
+ gr_i2cmst_prv_t *priv;
- /* Initialize i2c library */
- rc = rtems_libi2c_initialize();
- if (rc < 0) {
-#if defined(DEBUG)
- printk("rtems_libi2x_initialize failed, exiting...\n");
-#endif
- return rc;
- }
+ DBG("I2CMST[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
- gr_i2cmst_desc.prv.reg_ptr = (gr_i2cmst_regs_t *)apbi2cmst.start;
+ priv = dev->priv = malloc(sizeof(gr_i2cmst_prv_t));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
- /* Detect system frequency, same as in apbuart_initialize */
-#ifndef SYS_FREQ_kHZ
-#if defined(LEON3)
- /* LEON3: find timer address via AMBA Plug&Play info */
- {
- struct ambapp_apb_info gptimer;
- struct gptimer_regs *tregs;
-
- if (ambapp_find_apbslv(abus, VENDOR_GAISLER,
- GAISLER_GPTIMER, &gptimer) == 1 ) {
- tregs = (struct gptimer_regs *)gptimer.start;
- gr_i2cmst_desc.prv.sysfreq = (tregs->scaler_reload+1)*1000;
- } else {
- gr_i2cmst_desc.prv.sysfreq = 40000; /* Default to 40MHz */
- }
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+/* Init stage 2 */
+int i2cmst_init3(struct drvmgr_dev *dev)
+{
+ gr_i2cmst_prv_t *priv;
+ char prefix[32];
+ char devName[32];
+ int rc;
+
+ priv = (gr_i2cmst_prv_t *)dev->priv;
+
+ /* Do initialization */
+
+ /* Initialize i2c library */
+ rc = rtems_libi2c_initialize();
+ if (rc != 0) {
+ DBG("I2CMST: rtems_libi2c_initialize failed, exiting...\n");
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
}
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- gr_i2cmst_desc.prv.sysfreq = (regs->Scaler_Reload+1)*1000;
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ /* Get frequency */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->sysfreq) ) {
+ return DRVMGR_FAIL;
}
-#else
-#error CPU not supported for I2CMST driver */
-#endif
-#else
- /* Use hardcoded frequency */
- gr_i2cmst_desc.prv.sysfreq = SYS_FREQ_kHZ;
-#endif
+ priv->sysfreq = priv->sysfreq / 1000; /* Convert to kHz */
- rc = rtems_libi2c_register_bus("/dev/i2c1", &gr_i2cmst_desc.bus_desc);
- if (rc < 0) {
-#if defined(DEBUG)
- printk("rtems_libi2c_register_bus failed, exiting..\n");
-#endif
- return -rc;
- }
- }
+ if ( i2cmst_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
-#if defined(DEBUG)
- printk("exited\n");
-#endif
- return 0;
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(devName, "/dev/i2c%d", dev->minor_drv+1);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(devName, "/dev/%si2c%d", prefix, dev->minor_bus+1);
+ }
+
+ /* Register Bus for this Device */
+ rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
+ if (rc < 0) {
+ DBG("I2CMST: rtems_libi2c_register_bus(%s) failed, exiting..\n", devName);
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+ priv->minor = rc;
+
+ return DRVMGR_OK;
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/b1553brm.h b/c/src/lib/libbsp/sparc/shared/include/b1553brm.h
index 2cc5b8b..1c3b38b 100644
--- a/c/src/lib/libbsp/sparc/shared/include/b1553brm.h
+++ b/c/src/lib/libbsp/sparc/shared/include/b1553brm.h
@@ -3,24 +3,21 @@
* @ingroup sparc_bsp
* @defgroup 1553 B1553BRM
* @ingroup 1553
- * @brief Macros used for brm controller
+ * @brief B1553BRM device driver
*/
/*
* COPYRIGHT (c) 2006.
- * Gaisler Research
+ * 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.org/license/LICENSE.
- *
*/
#ifndef __B1553BRM_H__
#define __B1553BRM_H__
-#include <ambapp.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -102,6 +99,7 @@ struct bc_msg {
#define BC_RTRT 0x0002
#define BC_BUSA 0x0004
#define BC_EOL 0x0020
+#define BC_SKIP 0x0040
#define BC_BAME 0x8000
#define BRM_MBC_IRQ 1 /* Monitor Block Counter irq */
@@ -114,7 +112,7 @@ struct bc_msg {
#define BRM_IXEQ0_IRQ 256 /* Index Equal Zero irq */
#define BRM_BDRCV_IRQ 512 /* Broadcast Command Received irq */
#define BRM_SUBAD_IRQ 1024 /* Subaddress Accessed irq */
-#define BRM_MERR_IRQ 4096 /* Message Error irq */
+#define BRM_MERR_IRQ 2048 /* Message Error irq */
#define BRM_TAPF_IRQ 8192 /* Terminal Address Parity Fail irq */
#define BRM_WRAPF_IRQ 16384 /* Wrap Fail irq */
#define BRM_DMAF_IRQ 32768 /* DMA Fail irq */
@@ -144,13 +142,6 @@ struct bc_msg {
#define BRM_MODE_BM 0x2
#define BRM_MODE_BM_RT 0x3 /* both RT and BM */
-
-/* Register RAMON FPGA BRM driver, calls brm_register */
-int brm_register_leon3_ramon_fpga(void);
-
-/* Register RAMON ASIC BRM driver, calls brm_register */
-int brm_register_leon3_ramon_asic(void);
-
#define BRM_FREQ_12MHZ 0
#define BRM_FREQ_16MHZ 1
#define BRM_FREQ_20MHZ 2
@@ -161,15 +152,11 @@ int brm_register_leon3_ramon_asic(void);
#define CLKSEL_MASK 0x7
-/* Register BRM driver
- * See (struct brm_reg).w_ctrl for clksel and clkdiv.
- * See Enhanced register (the least signinficant 2 bits) in BRM Core for brm_freq
- * bus = &ambapp_plb for LEON3. (LEON2 not yet supported for this driver)
- */
-int b1553brm_register(struct ambapp_bus *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq);
+void b1553brm_register_drv(void);
#ifdef __cplusplus
}
#endif
#endif /* __BRM_H__ */
+
diff --git a/c/src/lib/libbsp/sparc/shared/include/grcan.h b/c/src/lib/libbsp/sparc/shared/include/grcan.h
index e76dee7..5f4da5d 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grcan.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grcan.h
@@ -8,19 +8,16 @@
/*
* COPYRIGHT (c) 2007.
- * Gaisler Research
+ * 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.org/license/LICENSE.
- *
*/
#ifndef __GRCAN_H__
#define __GRCAN_H__
-#include <ambapp.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -187,20 +184,8 @@ typedef struct {
#define GRCAN_IOC_SET_SFILTER 40 /* Set Sync Messages RX/TX filters, NULL disables the IRQ completely */
#define GRCAN_IOC_GET_STATUS 41 /* Get status register of GRCAN core */
-struct grcan_device_info {
- unsigned int base_address;
- int irq;
-};
-/* Use hard coded addresses and IRQs to find hardware */
-int grcan_register_abs(struct grcan_device_info *devices, int dev_cnt);
-
-/* Use prescanned AMBA Plug&Play information to find all GRFIFO cores */
-int grcan_register(struct ambapp_bus *abus);
-#if 0
-void grcan_register(unsigned int baseaddr, unsigned int ram_base);
-void grcan_interrupt_handler(rtems_vector_number v);
-#endif
+void grcan_register_drv(void);
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw.h b/c/src/lib/libbsp/sparc/shared/include/grspw.h
index 77495be..3270e8a 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grspw.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw.h
@@ -3,12 +3,12 @@
* @ingroup sparc_bsp
* @defgroup spw SpaceWire
* @ingroup spw
- * @brief Macros used for Spacewire bus
+ * @brief GRSPW Device Driver
*/
/*
* COPYRIGHT (c) 2007.
- * Gaisler Research
+ * Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -32,12 +32,18 @@ typedef struct {
unsigned int txhsize;
} spw_ioctl_packetsize;
+#define GRSPW_PKTSEND_OPTION_HDR_CRC 0x1
+#define GRSPW_PKTSEND_OPTION_DATA_CRC 0x2
+#define GRSPW_PKTSEND_OPTION_NOCRCLEN(len) ((len & 0xf) << 8)
+#define GRSPW_PKTSEND_OPTION_NOCRCLEN_MASK 0xf00
+
typedef struct {
unsigned int hlen;
char *hdr;
unsigned int dlen;
char *data;
unsigned int sent;
+ unsigned int options;
} spw_ioctl_pkt_send;
typedef struct {
@@ -84,6 +90,11 @@ typedef struct {
unsigned int is_rmapcrc;
unsigned int nodemask;
+ unsigned int keep_source; /* copy source address to user-buffer in read() operations
+ * Note that rm_prot_id has no effect when keep_source is
+ * set.
+ */
+ unsigned int rtimeout; /* Read timeout if != 0 */
} spw_config;
#define SPACEWIRE_IOCTRL_SET_NODEADDR 1
@@ -113,30 +124,42 @@ typedef struct {
#define SPACEWIRE_IOCTRL_SET_COREFREQ 32
#define SPACEWIRE_IOCTRL_SET_CLKDIVSTART 33
#define SPACEWIRE_IOCTRL_SET_NODEMASK 34
+#define SPACEWIRE_IOCTRL_SET_KEEP_SOURCE 35
+#define SPACEWIRE_IOCTRL_SET_TCODE_CTRL 36
+#define SPACEWIRE_IOCTRL_SET_TCODE 37
+#define SPACEWIRE_IOCTRL_GET_TCODE 38
+#define SPACEWIRE_IOCTRL_SET_READ_TIMEOUT 39
#define SPACEWIRE_IOCTRL_START 64
#define SPACEWIRE_IOCTRL_STOP 65
-int grspw_register(struct ambapp_bus *bus);
+/* Defines what register bits that will be touched
+ * for SPACEWIRE_IOCTRL_SET_TCODE_CTRL
+ */
+#define SPACEWIRE_TCODE_CTRL_IE_MSK 0x001
+#define SPACEWIRE_TCODE_CTRL_TT_MSK 0x004
+#define SPACEWIRE_TCODE_CTRL_TR_MSK 0x008
+/* Defines what register bits that should be set
+ * for SPACEWIRE_IOCTRL_SET_TCODE_CTRL
+ */
+#define SPACEWIRE_TCODE_CTRL_IE 0x100
+#define SPACEWIRE_TCODE_CTRL_TT 0x400
+#define SPACEWIRE_TCODE_CTRL_TR 0x800
-#if 0
-struct grspw_buf;
+/* SPACEWIRE_IOCTRL_SET_TCODE argument mask */
+#define SPACEWIRE_TCODE_TCODE 0x0ff
+#define SPACEWIRE_TCODE_SET 0x100 /* Set Timecode register */
+#define SPACEWIRE_TCODE_TX 0x400
-struct grspw_buf {
- grspw_buf *next; /* next packet in chain */
+void grspw_register_drv (void);
- /* Always used */
- unsigned int dlen; /* data length of '*data' */
- unsigned int max_dlen; /* allocated length of '*data' */
- void *data; /* pointer to beginning of cargo data */
+void grspw_print(int options);
+
+/* Global GRSPW Function pointer called upon timecode receive interrupt */
+extern void (*grspw_timecode_callback)
+ (void *pDev, void *regs, int minor, unsigned int tc);
- /* Only used when transmitting */
- unsigned int hlen; /* length of header '*header' */
- unsigned int max_hlen; /* allocated length of '*header' */
- void *header; /* pointer to beginning of header data */
-};
-#endif
#ifdef __cplusplus
}
diff --git a/c/src/lib/libbsp/sparc/shared/include/i2cmst.h b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
index 2db5cd0..e63d2f8 100644
--- a/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
+++ b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
@@ -7,13 +7,12 @@
*/
/*
- * COPYRIGHT (c) 2007 Gaisler Research
+ * COPYRIGHT (c) 2007 Cobham Gaisler AB
* with parts from the RTEMS MPC83xx I2C driver (c) 2007 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.
- *
*/
#ifndef _I2CMST_H
@@ -56,26 +55,6 @@ typedef struct gr_i2cmst_regs {
#define GRI2C_STATUS_IDLE 0x00000000
-/* The OC I2C core will perform a write after a start unless the RD bit
- in the command register has been set. Since the rtems framework has
- a send_start function we buffer that command and use it when the first
- data is written. The START is buffered in the sendstart member below */
-typedef struct gr_i2cmst_prv {
- gr_i2cmst_regs_t *reg_ptr;
- unsigned int sysfreq; /* System clock frequency in kHz */
- unsigned char sendstart; /* START events are buffered here */
- /* rtems_irq_number irq_number; */
- /* rtems_id irq_sema_id; */
-} gr_i2cmst_prv_t;
-
-typedef struct gr_i2cmst_desc {
- rtems_libi2c_bus_t bus_desc;
- gr_i2cmst_prv_t prv;
-} gr_i2cmst_desc_t;
-
-/* Scans for I2CMST core and initalizes i2c library */
-rtems_status_code leon_register_i2c(struct ambapp_bus *abus);
-
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/occan.h b/c/src/lib/libbsp/sparc/shared/include/occan.h
index 0217446..0bf34de 100644
--- a/c/src/lib/libbsp/sparc/shared/include/occan.h
+++ b/c/src/lib/libbsp/sparc/shared/include/occan.h
@@ -6,20 +6,15 @@
/*
* COPYRIGHT (c) 2007.
- * Gaisler Research.
+ * 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.org/license/LICENSE.
- *
- * Author: Daniel Hellström, Gaisler Research AB, www.gaisler.com
*/
-
-#ifndef __OCCAN_H__
-#define __OCCAN_H__
-
-#include <ambapp.h>
+#ifndef __OCCAN_DRIVER_H__
+#define __OCCAN_DRIVER_H__
#ifdef __cplusplus
extern "C" {
@@ -152,7 +147,7 @@ struct occan_afilter {
#define OCCAN_BLK_MODE_RX 0x1
#define OCCAN_BLK_MODE_TX 0x2
-int occan_register(struct ambapp_bus *bus);
+void occan_register_drv (void);
#define OCCAN_SPEED_500K 500000
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw.c b/c/src/lib/libbsp/sparc/shared/spw/grspw.c
index d869d17..83f3b97 100644
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw.c
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw.c
@@ -1,81 +1,14 @@
/*
* This file contains the GRSPW SpaceWire Driver for LEON2 and LEON3.
*
- * COPYRIGHT (c) 2007
- * Gaisler Research.
+ * COPYRIGHT (c) 2006
+ * 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.org/license/LICENSE.
- *
- * Changes:
- *
- * 2007-09-27, Daniel Hellstrom <daniel at gaisler.com>
- * Added basic support for GRSPW2 core.
- *
- * 2007-07-12, Daniel Hellstrom <daniel at gaisler.com>
- * Fixed bug in TXBLOCK mode (normally called flush).
- *
- * 2007-05-28, Daniel Hellstrom <daniel at gaisler.com>
- * Changed register call from spacewire_register to
- * grspw_register. Added one parameter (the AMBA bus
- * pointer) for LEON2 and LEON3 PCI compability.
- * Typical LEON3 register: grspw_register(&amba_conf);
- *
- * 2007-05-28, Daniel Hellstrom <daniel at gaisler.com>
- * Changed errno return values, compatible with RASTA
- * Spacewire driver
- *
- * 2007-05-25, Daniel Hellstrom <daniel at gaisler.com>
- * Changed name from /dev/spacewire,/dev/spacewire_b...
- * to /dev/grspw0,/dev/grspw1...
- *
- * 2007-05-24, Daniel Hellstrom <daniel at gaisler.com>
- * Merged LEON3, LEON2 and RASTA driver to one - this.
- * The driver is included and configured from grspw_pci.c
- * and grspw_rasta.c.
- *
- * 2007-05-23, Daniel Hellstrom <daniel at gaisler.com>
- * Changed open call, now one need to first call open
- * and then ioctl(fd,START,timeout) in order to setup
- * hardware for communication.
- *
- * 2007-05-23, Daniel Hellstrom <daniel at gaisler.com>
- * Added ioctl(fd,SET_COREFREQ,freq_arg), the command
- * can autodetect the register values disconnect and
- * timer64. It is still possible to change them manually
- * by ioctl(fd,SET_{DISCONNECT,TIMER},arg).
- *
*/
-/* default name to /dev/grspw0 */
-#if !defined(GRSPW_DEVNAME) || !defined(GRSPW_DEVNAME_NO)
- #undef GRSPW_DEVNAME
- #undef GRSPW_DEVNAME_NO
- #define GRSPW_DEVNAME "/dev/grspw0"
- #define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
-#endif
-
-#ifndef GRSPW_PREFIX
- #define GRSPW_PREFIX(name) grspw##name
-#else
- #define GRSPW_REGISTER_STATIC
-#endif
-
-/* default to no translation */
-#ifndef GRSPW_ADR_TO
- #define memarea_to_hw(x) ((unsigned int)(x))
-#endif
-#ifndef GRSPW_ADR_FROM
- #define hw_to_memarea(x) ((unsigned int)(x))
-#endif
-
-#ifndef GRSPW_REG_INT
- #define GRSPW_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1)
- #undef GRSPW_DEFINE_INTHANDLER
- #define GRSPW_DEFINE_INTHANDLER
-#endif
-
#include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h>
@@ -86,7 +19,9 @@
#include <rtems/bspIo.h>
#include <rtems/malloc.h>
#include <ambapp.h>
-#include <grlib.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
#include <grspw.h>
#define DBGSPW_IOCALLS 1
@@ -97,7 +32,7 @@
#define DEBUG_SPACEWIRE_FLAGS (DBGSPW_IOCALLS | DBGSPW_TX | DBGSPW_RX )
/* #define DEBUG_SPACEWIRE_ONOFF */
-
+
#ifdef DEBUG_SPACEWIRE_ONOFF
#define SPACEWIRE_DBG(fmt, args...) do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args); }} while(0)
#define SPACEWIRE_DBG2(fmt) do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__); }} while(0)
@@ -117,15 +52,15 @@ typedef struct {
volatile unsigned int time;
volatile unsigned int timer;
volatile unsigned int pad;
-
- volatile unsigned int dma0ctrl;
+
+ volatile unsigned int dma0ctrl;
volatile unsigned int dma0rxmax;
volatile unsigned int dma0txdesc;
volatile unsigned int dma0rxdesc;
-
+
/* For GRSPW core 2 and onwards */
volatile unsigned int dma0addr;
-
+
} LEON3_SPACEWIRE_Regs_Map;
typedef struct {
@@ -151,7 +86,10 @@ typedef struct {
#define BUFMEM_PER_LINK (SPACEWIRE_TXBUFS_NR*(SPACEWIRE_TXD_SIZE+SPACEWIRE_TXH_SIZE) + SPACEWIRE_RXBUFS_NR*SPACEWIRE_RXPCK_SIZE)
typedef struct {
- /* configuration parameters */
+ /* configuration parameters */
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ LEON3_SPACEWIRE_Regs_Map *regs;
spw_config config;
unsigned int tx_all_in_use;
@@ -165,12 +103,23 @@ typedef struct {
unsigned int txbufcnt;
unsigned int rxbufcnt;
+ /* DMA Area set by user */
+ unsigned int rx_dma_area;
+ unsigned int tx_data_dma_area;
+ unsigned int tx_hdr_dma_area;
+ unsigned int bd_dma_area;
+
/* statistics */
spw_stats stat;
char *ptr_rxbuf0;
char *ptr_txdbuf0;
char *ptr_txhbuf0;
+ char *ptr_bd0;
+
+ char *ptr_rxbuf0_remote;
+ char *ptr_txdbuf0_remote;
+ char *ptr_txhbuf0_remote;
unsigned int irq;
int minor;
@@ -178,7 +127,7 @@ typedef struct {
int open;
int running;
unsigned int core_freq_khz;
-
+ unsigned int rtimeout;
/* semaphores*/
rtems_id txsp;
@@ -187,23 +136,20 @@ typedef struct {
SPACEWIRE_RXBD *rx;
SPACEWIRE_TXBD *tx;
-#ifdef GRSPW_STATIC_MEM
- unsigned int membase, memend, mem_bdtable;
-#endif
-
- LEON3_SPACEWIRE_Regs_Map *regs;
+ unsigned int rx_remote;
+ unsigned int tx_remote;
} GRSPW_DEV;
-static int spw_cores;
-static int spw_cores2;
-static unsigned int sys_freq_khz;
-static GRSPW_DEV *grspw_devs;
+/* Function pointer called upon timecode receive */
+void (*grspw_timecode_callback)
+ (void *pDev, void *regs, int minor, unsigned int tc) = NULL;
#ifdef GRSPW_DONT_BYPASS_CACHE
#define _SPW_READ(address) (*(volatile unsigned int *)(address))
-#define _MEM_READ(address) (*(volatile unsigned char *)(address))
+#define _MEM_READ8(address) (*(volatile unsigned char *)(address))
+#define _MEM_READ32(address) (*(volatile unsigned int *)(address))
#else
-static unsigned int _SPW_READ(void *addr) {
+static inline unsigned int _SPW_READ(volatile void *addr) {
unsigned int tmp;
__asm__ (" lda [%1]1, %0 "
: "=r"(tmp)
@@ -212,20 +158,29 @@ static unsigned int _SPW_READ(void *addr) {
return tmp;
}
-static unsigned int _MEM_READ(void *addr) {
+static inline unsigned int _MEM_READ8(volatile void *addr) {
unsigned int tmp;
__asm__ (" lduba [%1]1, %0 "
: "=r"(tmp)
: "r"(addr)
);
return tmp;
+}
+static inline unsigned int _MEM_READ32(volatile void *addr) {
+ unsigned int tmp;
+ __asm__ (" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
}
#endif
-#define MEM_READ(addr) _MEM_READ((void *)(addr))
-#define SPW_READ(addr) _SPW_READ((void *)(addr))
-#define SPW_WRITE(addr,v) *addr=v
+#define MEM_READ8(addr) _MEM_READ8((volatile void *)(addr))
+#define MEM_READ32(addr) _MEM_READ32((volatile void *)(addr))
+#define SPW_READ(addr) _SPW_READ((volatile void *)(addr))
+#define SPW_WRITE(addr,v) (*(volatile unsigned int *)addr)=v
#define SPW_REG(c,r) (c->regs->r)
#define SPW_REG_CTRL(c) SPW_REG(c,ctrl)
@@ -263,6 +218,8 @@ static unsigned int _MEM_READ(void *addr) {
#define SPW_TXBD_WR (1 << 13)
#define SPW_TXBD_IE (1 << 14)
#define SPW_TXBD_LE (1 << 15)
+#define SPW_TXBD_HC (1 << 16)
+#define SPW_TXBD_DC (1 << 17)
#define SPW_TXBD_ERROR (SPW_TXBD_LE)
@@ -311,7 +268,7 @@ static unsigned int _MEM_READ(void *addr) {
#define SPW_PREPAREMASK_RX (SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE | SPW_DMACTRL_AI | SPW_DMACTRL_PR | SPW_DMACTRL_RA)
static int grspw_hw_init(GRSPW_DEV *pDev);
-static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data);
+static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data, unsigned int options);
static int grspw_hw_receive(GRSPW_DEV *pDev,char *b,int c);
static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout);
static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx);
@@ -322,7 +279,8 @@ static void grspw_hw_read_config(GRSPW_DEV *pDev);
static void check_rx_errors(GRSPW_DEV *pDev, int ctrl);
static void grspw_rxnext(GRSPW_DEV *pDev);
-static void grspw_interrupt(GRSPW_DEV *pDev);
+static void grspw_interrupt(void *arg);
+static int grspw_buffer_alloc(GRSPW_DEV *pDev);
static rtems_device_driver grspw_initialize(
rtems_device_major_number major,
@@ -369,78 +327,271 @@ static rtems_device_driver grspw_control(
grspw_control }
static rtems_driver_address_table grspw_driver = GRSPW_DRIVER_TABLE_ENTRY;
-static struct ambapp_bus *amba_bus;
+static int grspw_driver_io_registered = 0;
+static rtems_device_major_number grspw_driver_io_major = 0;
-#ifdef GRSPW_REGISTER_STATIC
-static
-#endif
-int GRSPW_PREFIX(_register)(struct ambapp_bus *bus)
-{
- rtems_status_code r;
- rtems_device_major_number m;
+/******************* Driver manager interface ***********************/
- /* Get System clock frequency */
- sys_freq_khz = 0;
+/* Driver prototypes */
+int grspw_register_io(rtems_device_major_number *m);
+int grspw_device_init(GRSPW_DEV *pDev);
- amba_bus = bus;
+int grspw_init2(struct drvmgr_dev *dev);
+int grspw_init3(struct drvmgr_dev *dev);
- /* Auto Detect the GRSPW core frequency by assuming that the system frequency is
- * is the same as the GRSPW core frequency.
- */
-#ifndef SYS_FREQ_KHZ
-#ifdef LEON3
- /* LEON3: find timer address via AMBA Plug&Play info */
+struct drvmgr_drv_ops grspw_ops =
+{
+ .init = {NULL, grspw_init2, grspw_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grspw_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_SPW},
+ {VENDOR_GAISLER, GAISLER_SPW2},
+ {VENDOR_GAISLER, GAISLER_SPW2_DMA},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grspw_drv_info =
+{
{
- struct ambapp_apb_info gptimer;
- struct gptimer_regs *tregs;
-
- if ( ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER,
- GAISLER_GPTIMER, &gptimer) == 1 ) {
- tregs = (struct gptimer_regs *)gptimer.start;
- sys_freq_khz = (tregs->scaler_reload+1)*1000;
- SPACEWIRE_DBG("GRSPW: detected %dkHZ system frequency\n\r",sys_freq_khz);
- }else{
- sys_freq_khz = 40000; /* Default to 40MHz */
- printk("GRSPW: Failed to detect system frequency\n\r");
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRSPW_ID, /* Driver ID */
+ "GRSPW_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grspw_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grspw_ids[0]
+};
+
+void grspw_register_drv (void)
+{
+ SPACEWIRE_DBG("Registering GRSPW driver\n");
+ drvmgr_drv_register(&grspw_drv_info.general);
+}
+
+int grspw_init2(struct drvmgr_dev *dev)
+{
+ GRSPW_DEV *priv;
+
+ SPACEWIRE_DBG("GRSPW[%d] on bus %s\n", dev->minor_drv,
+ dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(GRSPW_DEV));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+int grspw_init3(struct drvmgr_dev *dev)
+{
+ GRSPW_DEV *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( grspw_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( grspw_register_io(&grspw_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
}
+ grspw_driver_io_registered = 1;
}
-#elif defined(LEON2)
- /* LEON2: use hardcoded address to get to timer */
- {
- LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
- sys_freq_khz = (regs->Scaler_Reload+1)*1000;
- }
-#else
- #error CPU not supported by GRSPW driver
-#endif
-#else
- /* Use hardcoded frequency */
- sys_freq_khz = SYS_FREQ_KHZ;
-#endif
- SPACEWIRE_DBG2("register driver\n");
- if ((r = rtems_io_register_driver(0, &grspw_driver, &m)) == RTEMS_SUCCESSFUL) {
- SPACEWIRE_DBG2("success\n");
- return 0;
- } else {
- switch(r) {
- case RTEMS_TOO_MANY:
- SPACEWIRE_DBG2("failed RTEMS_TOO_MANY\n");
- break;
- case RTEMS_INVALID_NUMBER:
- SPACEWIRE_DBG2("failed RTEMS_INVALID_NUMBER\n");
- break;
- case RTEMS_RESOURCE_IN_USE:
- SPACEWIRE_DBG2("failed RTEMS_RESOURCE_IN_USE\n");
- break;
- default:
- SPACEWIRE_DBG("failed %i\n",r);
- break;
- }
- return 1;
- }
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_khz) ) {
+ return DRVMGR_FAIL;
+ }
+ /* Convert from Hz -> kHz */
+ priv->core_freq_khz = priv->core_freq_khz / 1000;
+ if ( grspw_device_init(priv) ) {
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/grspw%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgrspw%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, grspw_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+int grspw_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &grspw_driver, m)) == RTEMS_SUCCESSFUL) {
+ SPACEWIRE_DBG("GRSPW driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("GRSPW rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("GRSPW rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("GRSPW rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("GRSPW rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int grspw_device_init(GRSPW_DEV *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irq = pnpinfo->irq;
+ pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+ /* Get SpaceWire core version */
+ switch( pnpinfo->device ) {
+ case GAISLER_SPW:
+ pDev->core_ver = 1;
+ break;
+ case GAISLER_SPW2:
+ pDev->core_ver = 2;
+ break;
+ case GAISLER_SPW2_DMA:
+ pDev->core_ver = 3;
+ break;
+ default:
+ return -1;
+ }
+
+ /* initialize the code with some resonable values,
+ * actual initialization is done later using ioctl(fd)
+ * on the opened device */
+ pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE;
+ pDev->txdbufsize = SPACEWIRE_TXD_SIZE;
+ pDev->txhbufsize = SPACEWIRE_TXH_SIZE;
+ pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE;
+ pDev->txbufcnt = SPACEWIRE_TXBUFS_NR;
+ pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR;
+
+ pDev->ptr_rxbuf0 = 0;
+ pDev->ptr_txdbuf0 = 0;
+ pDev->ptr_txhbuf0 = 0;
+ pDev->ptr_bd0 = 0;
+ pDev->rx_dma_area = 0;
+ pDev->tx_data_dma_area = 0;
+ pDev->tx_hdr_dma_area = 0;
+ pDev->bd_dma_area = 0;
+
+ /* Get Configuration from Bus resources (Let user override defaults) */
+
+ value = drvmgr_dev_key_get(pDev->dev, "txBdCnt", KEY_TYPE_INT);
+ if ( value )
+ pDev->txbufcnt = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxBdCnt", KEY_TYPE_INT);
+ if ( value )
+ pDev->rxbufcnt = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txDataSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->txdbufsize = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txHdrSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->txhbufsize = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxPktSize", KEY_TYPE_INT);
+ if ( value )
+ pDev->rxbufsize = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "rxDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->rx_dma_area = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txDataDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->tx_data_dma_area = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "txHdrDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->tx_hdr_dma_area = value->i;
+
+ value = drvmgr_dev_key_get(pDev->dev, "bdDmaArea", KEY_TYPE_INT);
+ if ( value )
+ pDev->bd_dma_area = value->i;
+
+ if (grspw_buffer_alloc(pDev))
+ return RTEMS_NO_MEMORY;
+
+ /* Create semaphores */
+ rtems_semaphore_create(
+ rtems_build_name('T', 'x', 'S', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &(pDev->txsp));
+
+ rtems_semaphore_create(
+ rtems_build_name('R', 'x', 'S', '0' + pDev->minor),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+ RTEMS_NO_PRIORITY_CEILING,
+ 0,
+ &(pDev->rxsp));
+
+ grspw_hw_init(pDev);
+
+ return 0;
}
/* Get a value at least 6.4us in number of clock cycles */
@@ -455,1182 +606,1212 @@ static unsigned int grspw_calc_disconnect(int freq_khz){
return disconnect & 0x3ff;
}
-#if 0
-static int grspw_buffer_alloc(GRSPW_DEV *pDev) {
- if (pDev->ptr_rxbuf0) {
- free(pDev->ptr_rxbuf0);
- }
- if (pDev->ptr_txdbuf0) {
- free(pDev->ptr_txdbuf0);
- }
- if (pDev->ptr_txhbuf0) {
- free(pDev->ptr_txhbuf0);
- }
- pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
- pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
- pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
- if ((pDev->ptr_rxbuf0 == NULL) ||
- (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) {
- return 1;
- } else {
- return 0;
- }
-}
-#endif
-
static int grspw_buffer_alloc(GRSPW_DEV *pDev)
{
-#ifndef GRSPW_STATIC_MEM
- if (pDev->ptr_rxbuf0) {
- free(pDev->ptr_rxbuf0);
- }
- if (pDev->ptr_txdbuf0) {
- free(pDev->ptr_txdbuf0);
- }
- if (pDev->ptr_txhbuf0) {
- free(pDev->ptr_txhbuf0);
- }
-
- pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
- pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
- pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
- if ((pDev->ptr_rxbuf0 == NULL) ||
- (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) {
- return 1;
- } else {
- return 0;
- }
-#else
- if ( (pDev->membase + pDev->rxbufsize*pDev->rxbufcnt + pDev->txdbufsize*pDev->txbufcnt) >= pDev->memend ) {
- return -1;
- }
- pDev->ptr_rxbuf0 = (char *) pDev->membase;
- pDev->ptr_txdbuf0 = pDev->ptr_rxbuf0 + pDev->rxbufsize * pDev->rxbufcnt;
- pDev->ptr_txhbuf0 = pDev->ptr_txdbuf0 + pDev->txdbufsize * pDev->txbufcnt;
- return 0;
-#endif
+ if ( pDev->rx_dma_area ) {
+#warning Check size?
+ if ( pDev->rx_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->rx_dma_area & ~1), (void **)&pDev->ptr_rxbuf0);
+ } else {
+ pDev->ptr_rxbuf0 = pDev->rx_dma_area;
+ }
+ } else {
+ if (pDev->ptr_rxbuf0) {
+ free(pDev->ptr_rxbuf0);
+ }
+ pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
+ if ( !pDev->ptr_rxbuf0 )
+ return 1;
+ }
+ if ( pDev->tx_data_dma_area ) {
+ if ( pDev->tx_data_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->tx_data_dma_area & ~1), (void **)&pDev->ptr_txdbuf0);
+ } else {
+ pDev->ptr_txdbuf0 = pDev->tx_data_dma_area;
+ }
+ } else {
+ if (pDev->ptr_txdbuf0) {
+ free(pDev->ptr_txdbuf0);
+ }
+ pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
+ if ( !pDev->ptr_txdbuf0 )
+ return 1;
+ }
+ if ( pDev->tx_hdr_dma_area ) {
+ if ( pDev->tx_hdr_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->tx_hdr_dma_area & ~1), (void **)&pDev->ptr_txhbuf0);
+ } else {
+ pDev->ptr_txhbuf0 = pDev->tx_hdr_dma_area;
+ }
+ } else {
+ if (pDev->ptr_txhbuf0) {
+ free(pDev->ptr_txhbuf0);
+ }
+ pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
+ if ( !pDev->ptr_txhbuf0 )
+ return 1;
+ }
+ if ( pDev->bd_dma_area ) {
+ if ( pDev->bd_dma_area & 1 ) {
+ /* Address given in remote address */
+ drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->bd_dma_area & ~1), (void **)&pDev->ptr_bd0);
+ } else {
+ pDev->ptr_bd0 = pDev->bd_dma_area;
+ }
+ } else {
+ if (pDev->ptr_bd0) {
+ free(pDev->ptr_bd0);
+ }
+ pDev->ptr_bd0 = (char *)
+ rtems_heap_allocate_aligned_with_boundary(SPACEWIRE_BDTABLE_SIZE*2, 1024, 0);
+ if ( !pDev->ptr_bd0 )
+ return 1;
+ }
+ /* Translate into remote address */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_rxbuf0, (void **)&pDev->ptr_rxbuf0_remote);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_txdbuf0,(void **)&pDev->ptr_txdbuf0_remote);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_txhbuf0, (void **)&pDev->ptr_txhbuf0_remote);
+ return 0;
}
-#ifdef GRSPW_DEFINE_INTHANDLER
-/*
- * Standard Interrupt handler
- */
-static rtems_isr grspw_interrupt_handler(rtems_vector_number v)
+static void grspw_interrupt(void *arg)
{
- int minor;
-
- for(minor = 0; minor < spw_cores+spw_cores2; minor++) {
- if (v == (grspw_devs[minor].irq+0x10) ) {
- grspw_interrupt(&grspw_devs[minor]);
- break;
- }
- }
-}
-#endif
+ GRSPW_DEV *pDev = (GRSPW_DEV *)arg;
+ int dmactrl;
+ int status;
+ int ctrl;
+ unsigned int timecode;
+
+ status = SPW_STATUS_READ(pDev);
+ /*SPW_STATUS_WRITE(pDev, SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE | SPW_STATUS_TO);*/
+ SPW_STATUS_WRITE(pDev, status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE));
+
+ /* Make sure to put the timecode handling first in order to get the smallest
+ * possible interrupt latency
+ */
+ if ( (status & SPW_STATUS_TO) && (grspw_timecode_callback != NULL) ) {
+ /* Timecode received. Let custom function handle this */
+ SPW_STATUS_WRITE(pDev, SPW_STATUS_TO);
+ timecode = SPW_READ(&pDev->regs->time);
+ (grspw_timecode_callback)(pDev,pDev->regs,pDev->minor,timecode);
+ }
+
+ /* Clear SPW_DMACTRL_PR if set */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ /*SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR);*/
+ SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
+
+ /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the
+ process set in the config */
+ if (pDev->config.link_err_irq) {
+ if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) {
+ rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT);
+ if (pDev->config.disable_err) {
+ /* disable link*/
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED);
+ pDev->config.linkdisabled = 1;
+ pDev->config.linkstart = 0;
+ pDev->running = 0;
+ }
+ }
+ }
+ if (status & SPW_STATUS_CE) {
+ pDev->stat.credit_err++;
+ }
+ if (status & SPW_STATUS_ER) {
+ pDev->stat.escape_err++;
+ }
+ if (status & SPW_STATUS_DE) {
+ pDev->stat.disconnect_err++;
+ }
+ if (status & SPW_STATUS_PE) {
+ pDev->stat.parity_err++;
+ }
+ if (status & SPW_STATUS_WE) {
+ pDev->stat.write_sync_err++;
+ }
+ if (status & SPW_STATUS_IA) {
+ pDev->stat.invalid_address++;
+ }
+ if (status & SPW_STATUS_EE) {
+ pDev->stat.early_ep++;
+ }
+
+ /* Check for tx interrupts */
+ while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) {
+ /* Has this descriptor been sent? */
+ ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl);
+ if ( ctrl & SPW_TXBD_EN ) {
+ break;
+ }
+ /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */
+ pDev->stat.packets_sent++;
-static void grspw_interrupt(GRSPW_DEV *pDev){
- int dmactrl;
- int status;
- int ctrl;
-
- status = SPW_STATUS_READ(pDev);
- SPW_STATUS_WRITE(pDev, SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE);
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR);
- /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the
- process set in the config */
- if (pDev->config.link_err_irq) {
- if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) {
- rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT);
- if (pDev->config.disable_err) {
- /* disable link*/
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED);
- pDev->config.linkdisabled = 1;
- pDev->config.linkstart = 0;
- pDev->running = 0;
- }
- }
- }
- if (status & SPW_STATUS_CE) {
- pDev->stat.credit_err++;
- }
- if (status & SPW_STATUS_ER) {
- pDev->stat.escape_err++;
- }
- if (status & SPW_STATUS_DE) {
- pDev->stat.disconnect_err++;
- }
- if (status & SPW_STATUS_PE) {
- pDev->stat.parity_err++;
- }
- if (status & SPW_STATUS_WE) {
- pDev->stat.write_sync_err++;
- }
- if (status & SPW_STATUS_IA) {
- pDev->stat.invalid_address++;
- }
- if (status & SPW_STATUS_EE) {
- pDev->stat.early_ep++;
- }
-
- /* Check for tx interrupts */
- while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) {
- /* Has this descriptor been sent? */
- ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl);
- if ( ctrl & SPW_TXBD_EN ) {
- break;
- }
- /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */
- pDev->stat.packets_sent++;
-
- rtems_semaphore_release(pDev->txsp);
-
- if ( ctrl & SPW_TXBD_LE ) {
- pDev->stat.tx_link_err++;
- }
-
- /* step to next descriptor */
- pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt;
- pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */
- }
-
- /* Check for rx interrupts */
- if (dmactrl & SPW_DMACTRL_PR) {
- rtems_semaphore_release(pDev->rxsp);
- }
+ rtems_semaphore_release(pDev->txsp);
+
+ if ( ctrl & SPW_TXBD_LE ) {
+ pDev->stat.tx_link_err++;
+ }
+
+ /* step to next descriptor */
+ pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt;
+ pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */
+ }
+
+ /* Check for rx interrupts */
+ if (dmactrl & SPW_DMACTRL_PR) {
+ rtems_semaphore_release(pDev->rxsp);
+ }
}
static rtems_device_driver grspw_initialize(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void *arg
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
)
{
- rtems_status_code status;
- int i=0;
- char c;
- GRSPW_DEV *pDev;
- char console_name[20];
- struct ambapp_apb_info dev;
-
- SPACEWIRE_DBG2("spacewire driver initialization\n");
-
- /* Copy device name */
- strcpy(console_name,GRSPW_DEVNAME);
-
- /* Get the number of GRSPW cores */
- i=0; spw_cores = 0; spw_cores2 = 0;
-
- /* get number of GRSPW cores */
- spw_cores = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER,
- GAISLER_SPW);
- spw_cores2 = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER,
- GAISLER_SPW2);
-
- if ( (spw_cores+spw_cores2) < 1 ){
- /* No GRSPW cores around... */
- return RTEMS_SUCCESSFUL;
- }
-
- /* Allocate memory for all spacewire cores */
- grspw_devs = (GRSPW_DEV *)malloc((spw_cores+spw_cores2) * sizeof(GRSPW_DEV));
-
- /* Zero out all memory */
- memset(grspw_devs,0,(spw_cores+spw_cores2) * sizeof(GRSPW_DEV));
-
- /* loop all found spacewire cores */
- i = 0;
- for(minor=0; minor<(spw_cores+spw_cores2); minor++){
-
- pDev = &grspw_devs[minor];
-
- /* Get device */
- if ( spw_cores > minor ) {
- ambapp_find_apbslv_next(amba_bus, VENDOR_GAISLER,
- GAISLER_SPW, &dev, minor);
- pDev->core_ver = 1;
- } else {
- ambapp_find_apbslv_next(amba_bus, VENDOR_GAISLER,
- GAISLER_SPW2, &dev,
- minor - spw_cores);
- pDev->core_ver = 2;
- }
-
- pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)dev.start;
- pDev->irq = dev.irq;
- pDev->minor = minor;
- pDev->open = 0;
-
- /* register interrupt routine */
- GRSPW_REG_INT(GRSPW_PREFIX(_interrupt_handler), pDev->irq, pDev);
-
- SPACEWIRE_DBG("spacewire core at [0x%x]\n", (unsigned int) pDev->regs);
-
- /* initialize the code with some resonable values,
- actual initialization is done later using ioctl(fd)
- on the opened device */
- pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE;
- pDev->txdbufsize = SPACEWIRE_TXD_SIZE;
- pDev->txhbufsize = SPACEWIRE_TXH_SIZE;
- pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE;
- pDev->txbufcnt = SPACEWIRE_TXBUFS_NR;
- pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR;
- pDev->config.check_rmap_err = 0;
- pDev->config.tx_blocking = 0;
- pDev->config.tx_block_on_full = 0;
- pDev->config.rx_blocking = 0;
- pDev->config.disable_err = 0;
- pDev->config.link_err_irq = 0;
- pDev->config.event_id = 0;
-
- pDev->ptr_rxbuf0 = 0;
- pDev->ptr_txdbuf0 = 0;
- pDev->ptr_txhbuf0 = 0;
-
-#ifdef GRSPW_STATIC_MEM
- GRSPW_CALC_MEMOFS(spw_cores,minor,&pDev->membase,&pDev->memend,&pDev->mem_bdtable);
-#endif
-
- if (grspw_buffer_alloc(pDev))
- return RTEMS_NO_MEMORY;
-
- }
-
- /* Register Device Names, /dev/grspw0, /dev/grspw1 ... */
- for (i = 0; i < spw_cores+spw_cores2; i++) {
- GRSPW_DEVNAME_NO(console_name,i);
- SPACEWIRE_DBG("registering minor %i as %s\n", i, console_name);
- status = rtems_io_register_name( console_name, major, i);
- if (status != RTEMS_SUCCESSFUL){
- rtems_fatal_error_occurred(status);
- }
- }
-
- /* Initialize Hardware and semaphores*/
- c = 'a';
- for (i = 0; i < spw_cores+spw_cores2; i++) {
- pDev = &grspw_devs[i];
- rtems_semaphore_create(
- rtems_build_name('T', 'x', 'S', c),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &(pDev->txsp));
- rtems_semaphore_create(
- rtems_build_name('R', 'x', 'S', c),
- 0,
- RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
- RTEMS_NO_PRIORITY_CEILING,
- 0,
- &(pDev->rxsp));
- c++;
- grspw_hw_init(pDev);
- }
-
- return RTEMS_SUCCESSFUL;
+ /* Initialize device-common data structures here */
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
- void * arg
- )
+ void * arg
+ )
{
- GRSPW_DEV *pDev;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor);
- if ( minor >= (spw_cores+spw_cores2) ) {
- SPACEWIRE_DBG("minor %i too big\n", minor);
- return RTEMS_INVALID_NAME;
- }
- pDev = &grspw_devs[minor];
-
- if ( pDev->open )
- return RTEMS_RESOURCE_IN_USE;
-
- /* Mark device open */
- pDev->open = 1;
-
- pDev->stat.tx_link_err = 0;
- pDev->stat.rx_rmap_header_crc_err = 0;
- pDev->stat.rx_rmap_data_crc_err = 0;
- pDev->stat.rx_eep_err = 0;
- pDev->stat.rx_truncated = 0;
- pDev->stat.parity_err = 0;
- pDev->stat.escape_err = 0;
- pDev->stat.credit_err = 0;
- pDev->stat.write_sync_err = 0;
- pDev->stat.disconnect_err = 0;
- pDev->stat.early_ep = 0;
- pDev->stat.invalid_address = 0;
- pDev->stat.packets_sent = 0;
- pDev->stat.packets_received = 0;
-
- pDev->running = 0;
- pDev->core_freq_khz = 0;
-
- /* Reset Core */
- grspw_hw_reset(pDev);
-
- /* Read default configuration */
- grspw_hw_read_config(pDev);
-
- return RTEMS_SUCCESSFUL;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor);
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ SPACEWIRE_DBG("Wrong minor %d\n", minor);
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ if ( pDev->open )
+ return RTEMS_RESOURCE_IN_USE;
+
+ /* Mark device open */
+ pDev->open = 1;
+
+ pDev->stat.tx_link_err = 0;
+ pDev->stat.rx_rmap_header_crc_err = 0;
+ pDev->stat.rx_rmap_data_crc_err = 0;
+ pDev->stat.rx_eep_err = 0;
+ pDev->stat.rx_truncated = 0;
+ pDev->stat.parity_err = 0;
+ pDev->stat.escape_err = 0;
+ pDev->stat.credit_err = 0;
+ pDev->stat.write_sync_err = 0;
+ pDev->stat.disconnect_err = 0;
+ pDev->stat.early_ep = 0;
+ pDev->stat.invalid_address = 0;
+ pDev->stat.packets_sent = 0;
+ pDev->stat.packets_received = 0;
+
+ pDev->config.rm_prot_id = 0;
+ pDev->config.keep_source = 0;
+ pDev->config.check_rmap_err = 0;
+ pDev->config.tx_blocking = 0;
+ pDev->config.tx_block_on_full = 0;
+ pDev->config.rx_blocking = 0;
+ pDev->config.disable_err = 0;
+ pDev->config.link_err_irq = 0;
+ pDev->config.event_id = 0;
+ pDev->config.rtimeout = 0;
+
+ pDev->running = 0;
+ pDev->core_freq_khz = 0;
+
+ /* Reset Core */
+ grspw_hw_reset(pDev);
+
+ /* Read default configuration */
+ grspw_hw_read_config(pDev);
+
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_close(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
- )
-{
- GRSPW_DEV *pDev = &grspw_devs[minor];
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor);
- rtems_semaphore_delete(pDev->txsp);
- rtems_semaphore_delete(pDev->rxsp);
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor);
+ rtems_semaphore_delete(pDev->txsp);
+ rtems_semaphore_delete(pDev->rxsp);
- grspw_hw_stop(pDev,1,1);
+ grspw_hw_stop(pDev,1,1);
- grspw_hw_reset(pDev);
+ grspw_hw_reset(pDev);
- /* Mark device closed - not open */
- pDev->open = 0;
+ /* Mark device closed - not open */
+ pDev->open = 0;
- return RTEMS_SUCCESSFUL;
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_read(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
- )
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
{
- GRSPW_DEV *pDev = &grspw_devs[minor];
- rtems_libio_rw_args_t *rw_args;
- unsigned int count = 0;
- rw_args = (rtems_libio_rw_args_t *) arg;
+ rtems_libio_rw_args_t *rw_args;
+ unsigned int count = 0;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+ int status;
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
- /* is link up? */
- if ( !pDev->running ) {
- return RTEMS_INVALID_NAME;
- }
+ /* is link up? */
+ if ( !pDev->running ) {
+ return RTEMS_INVALID_NAME;
+ }
- if ((rw_args->count < 1) || (rw_args->buffer == NULL)) {
- return RTEMS_INVALID_NAME;
- }
+ if ((rw_args->count < 1) || (rw_args->buffer == NULL)) {
+ return RTEMS_INVALID_NAME;
+ }
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
- while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) {
- /* wait a moment for any descriptors to get available
- *
+ while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) {
+ /* wait a moment for any descriptors to get available
+ *
* Semaphore is signaled by interrupt handler
*/
if (pDev->config.rx_blocking) {
SPACEWIRE_DBG2("Rx blocking\n");
- rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if ( pDev->config.rtimeout ) {
+ status = rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, pDev->config.rtimeout);
+ if ( status == RTEMS_TIMEOUT )
+ return RTEMS_TIMEOUT;
+ } else {
+ rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ }
} else {
- SPACEWIRE_DBG2("Rx non blocking\n");
+ SPACEWIRE_DBG2("Rx non blocking\n");
return RTEMS_RESOURCE_IN_USE;
}
}
-#ifdef DEBUG_SPACEWIRE_ONOFF
- if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
- int k;
- for (k = 0; k < count; k++){
- if (k % 16 == 0) {
- printf ("\n");
- }
- printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' ');
- }
- printf ("\n");
- }
+#ifdef DEBUG_SPACEWIRE_ONOFF
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ int k;
+ for (k = 0; k < count; k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
#endif
- rw_args->bytes_moved = count;
- return RTEMS_SUCCESSFUL;
-
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_write(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
)
{
- GRSPW_DEV *pDev = &grspw_devs[minor];
- rtems_libio_rw_args_t *rw_args;
- rw_args = (rtems_libio_rw_args_t *) arg;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
-
- /* is link up? */
- if ( !pDev->running ) {
- return RTEMS_INVALID_NAME;
- }
-
- if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) {
- return RTEMS_INVALID_NAME;
- }
-
- while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer)) == 0) {
- if (pDev->config.tx_block_on_full == 1) {
- SPACEWIRE_DBG2("Tx Block on full \n");
- rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- } else {
- SPACEWIRE_DBG2("Tx non blocking return when full \n");
- return RTEMS_RESOURCE_IN_USE;
- }
- }
- return RTEMS_SUCCESSFUL;
+ rtems_libio_rw_args_t *rw_args;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+
+ /* is link up? */
+ if ( !pDev->running ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer, 0)) == 0) {
+ if (pDev->config.tx_block_on_full == 1) {
+ SPACEWIRE_DBG2("Tx Block on full \n");
+ rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ SPACEWIRE_DBG2("Tx non blocking return when full \n");
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ return RTEMS_SUCCESSFUL;
}
static rtems_device_driver grspw_control(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void * arg
- )
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
{
- GRSPW_DEV *pDev = &grspw_devs[minor];
- spw_ioctl_pkt_send *args;
- spw_ioctl_packetsize *ps;
- int status;
- unsigned int tmp,nodeaddr,nodemask;
- int timeout;
- rtems_device_driver ret;
- rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor);
-
- if (!ioarg)
- return RTEMS_INVALID_NAME;
-
-
- ioarg->ioctl_return = 0;
- switch(ioarg->command) {
- case SPACEWIRE_IOCTRL_SET_NODEADDR:
- /*set node address*/
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- nodeaddr = ((unsigned int)ioarg->buffer) & 0xff;
- tmp = SPW_READ(&pDev->regs->nodeaddr);
- tmp &= 0xffffff00; /* Remove old address */
- tmp |= nodeaddr;
- SPW_WRITE(&pDev->regs->nodeaddr, tmp);
- if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.nodeaddr = nodeaddr;
- break;
- case SPACEWIRE_IOCTRL_SET_NODEMASK:
- /*set node address*/
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer);
- if ( pDev->core_ver > 1 ){
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- nodemask = ((unsigned int)ioarg->buffer) & 0xff;
- tmp = SPW_READ(&pDev->regs->nodeaddr);
- tmp &= 0xffff00ff; /* Remove old mask */
- tmp |= nodemask<<8;
- SPW_WRITE(&pDev->regs->nodeaddr, tmp);
- if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.nodemask = nodemask;
- }else{
- SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n");
- }
- break;
- case SPACEWIRE_IOCTRL_SET_RXBLOCK:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.rx_blocking = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_DESTKEY:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer);
- if (!pDev->config.is_rmap) {
- return RTEMS_NOT_IMPLEMENTED;
- }
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer);
- if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.destkey = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_CLKDIV:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- tmp = SPW_READ(&pDev->regs->clkdiv);
- tmp &= ~0xff; /* Remove old Clockdiv Setting */
- tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */
- SPW_WRITE(&pDev->regs->clkdiv, tmp);
- if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.clkdiv = tmp;
- break;
- case SPACEWIRE_IOCTRL_SET_CLKDIVSTART:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 255) {
- return RTEMS_INVALID_NAME;
- }
- tmp = SPW_READ(&pDev->regs->clkdiv);
- tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */
- tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */
- SPW_WRITE(&pDev->regs->clkdiv, tmp);
- if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.clkdiv = tmp;
- break;
- case SPACEWIRE_IOCTRL_SET_TIMER:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer);
- if ( pDev->core_ver <= 1 ) {
- if ((unsigned int)ioarg->buffer > 4095) {
- return RTEMS_INVALID_NAME;
- }
- SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF));
- if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.timer = (unsigned int)ioarg->buffer;
- }else{
- SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n");
- }
- break;
- case SPACEWIRE_IOCTRL_SET_DISCONNECT:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer);
- if ( pDev->core_ver <= 1 ) {
- if ((unsigned int)ioarg->buffer > 1023) {
- return RTEMS_INVALID_NAME;
- }
- SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12));
- if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.disconnect = (unsigned int)ioarg->buffer;
- }else{
- SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n");
- }
- break;
- case SPACEWIRE_IOCTRL_SET_PROMISCUOUS:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5));
- if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.promiscuous = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_RMAPEN:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16));
- if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.rmapen = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17));
- if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.rmapbufdis = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_CHECK_RMAP:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.check_rmap_err = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_RM_PROT_ID:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.rm_prot_id = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_TXBLOCK:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.tx_blocking = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_DISABLE_ERR:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer);
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- pDev->config.disable_err = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer);
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
- if ((unsigned int)ioarg->buffer > 1) {
- return RTEMS_INVALID_NAME;
- }
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9) | (pDev->config.link_err_irq << 3));
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
- if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) {
- return RTEMS_IO_ERROR;
- }
- pDev->config.link_err_irq = (unsigned int)ioarg->buffer;
- break;
- case SPACEWIRE_IOCTRL_SET_EVENT_ID:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer);
- pDev->config.event_id = (rtems_id)ioarg->buffer;
- SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id);
- break;
-
- /* Change MAX Packet size by:
- * - stop RX/TX (if on)
- * - wait for hw to complete RX DMA (if on)
- * - reallocate buffers with new size
- * - tell hw about new size & start RX/TX again (if previously on)
- */
- case SPACEWIRE_IOCTRL_SET_PACKETSIZE:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- ps = (spw_ioctl_packetsize*) ioarg->buffer;
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer);
-
- tmp = pDev->running;
-
- if ( pDev->running ){
- /* Stop RX */
- grspw_hw_stop(pDev,1,1);
-
- /* If packetsize fails it is good to know if in running mode */
- pDev->running = 0;
-
- /* Wait for Receiver to finnish pending DMA transfers if any */
- grspw_hw_wait_rx_inactive(pDev);
- }
-
- /* Save new buffer sizes */
- pDev->rxbufsize = ps->rxsize;
- pDev->txdbufsize = ps->txdsize;
- pDev->txhbufsize = ps->txhsize;
- pDev->config.rxmaxlen = pDev->rxbufsize;
-
- /* Free previous buffers & allocate buffers with new size */
- if (grspw_buffer_alloc(pDev))
- return RTEMS_NO_MEMORY;
-
- /* if RX was actived before, we reactive it again */
- if ( tmp ) {
- if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) {
- return status;
- }
- pDev->running = 1;
- }
+ spw_ioctl_pkt_send *args;
+ spw_ioctl_packetsize *ps;
+ int status;
+ unsigned int tmp,mask,nodeaddr,nodemask;
+ int timeout;
+ rtems_device_driver ret;
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ GRSPW_DEV *pDev;
+ struct drvmgr_dev *dev;
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor);
+
+ if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev = (GRSPW_DEV *)dev->priv;
+
+ if (!ioarg)
+ return RTEMS_INVALID_NAME;
+
+ ioarg->ioctl_return = 0;
+ switch(ioarg->command) {
+ case SPACEWIRE_IOCTRL_SET_NODEADDR:
+ /*set node address*/
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ nodeaddr = ((unsigned int)ioarg->buffer) & 0xff;
+ tmp = SPW_READ(&pDev->regs->nodeaddr);
+ tmp &= 0xffffff00; /* Remove old address */
+ tmp |= nodeaddr;
+ SPW_WRITE(&pDev->regs->nodeaddr, tmp);
+ if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.nodeaddr = nodeaddr;
+ break;
+ case SPACEWIRE_IOCTRL_SET_NODEMASK:
+ /*set node address*/
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer);
+ if ( pDev->core_ver > 1 ){
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ nodemask = ((unsigned int)ioarg->buffer) & 0xff;
+ tmp = SPW_READ(&pDev->regs->nodeaddr);
+ tmp &= 0xffff00ff; /* Remove old mask */
+ tmp |= nodemask<<8;
+ SPW_WRITE(&pDev->regs->nodeaddr, tmp);
+ if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.nodemask = nodemask;
+ }else{
+ SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n");
+ }
+ break;
+ case SPACEWIRE_IOCTRL_SET_RXBLOCK:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.rx_blocking = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_DESTKEY:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer);
+ if (!pDev->config.is_rmap) {
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer);
+ if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.destkey = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_CLKDIV:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ if ( pDev->core_ver == 3 )
+ break;
+ tmp = SPW_READ(&pDev->regs->clkdiv);
+ tmp &= ~0xff; /* Remove old Clockdiv Setting */
+ tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */
+ SPW_WRITE(&pDev->regs->clkdiv, tmp);
+ if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.clkdiv = tmp;
+ break;
+ case SPACEWIRE_IOCTRL_SET_CLKDIVSTART:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 255) {
+ return RTEMS_INVALID_NAME;
+ }
+ if ( pDev->core_ver == 3 )
+ break;
+ tmp = SPW_READ(&pDev->regs->clkdiv);
+ tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */
+ tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */
+ SPW_WRITE(&pDev->regs->clkdiv, tmp);
+ if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.clkdiv = tmp;
+ break;
+ case SPACEWIRE_IOCTRL_SET_TIMER:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer);
+ if ( pDev->core_ver <= 1 ) {
+ if ((unsigned int)ioarg->buffer > 4095) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF));
+ if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.timer = (unsigned int)ioarg->buffer;
+ }else{
+ SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n");
+ }
+ break;
+ case SPACEWIRE_IOCTRL_SET_DISCONNECT:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer);
+ if ( pDev->core_ver <= 1 ) {
+ if ((unsigned int)ioarg->buffer > 1023) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12));
+ if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.disconnect = (unsigned int)ioarg->buffer;
+ }else{
+ SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n");
+ }
+ break;
+ case SPACEWIRE_IOCTRL_SET_PROMISCUOUS:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5));
+ if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.promiscuous = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_RMAPEN:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16));
+ if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.rmapen = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17));
+ if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.rmapbufdis = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_CHECK_RMAP:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.check_rmap_err = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_RM_PROT_ID:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.rm_prot_id = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_KEEP_SOURCE:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_KEEP_SOURCE %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.keep_source = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_TXBLOCK:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.tx_blocking = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_DISABLE_ERR:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer);
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ pDev->config.disable_err = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer);
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
+ if ((unsigned int)ioarg->buffer > 1) {
+ return RTEMS_INVALID_NAME;
+ }
+ tmp = (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9);
+ if (tmp & (SPW_CTRL_LI|SPW_CTRL_TQ))
+ tmp |= SPW_CTRL_IE;
+ SPW_CTRL_WRITE(pDev, tmp);
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
+ if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) {
+ return RTEMS_IO_ERROR;
+ }
+ pDev->config.link_err_irq = (unsigned int)ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_EVENT_ID:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer);
+ pDev->config.event_id = (rtems_id)ioarg->buffer;
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id);
+ break;
+
+ /* Change MAX Packet size by:
+ * - stop RX/TX (if on)
+ * - wait for hw to complete RX DMA (if on)
+ * - reallocate buffers with new size
+ * - tell hw about new size & start RX/TX again (if previously on)
+ */
+ case SPACEWIRE_IOCTRL_SET_PACKETSIZE:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ ps = (spw_ioctl_packetsize*) ioarg->buffer;
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer);
+
+ tmp = pDev->running;
+
+ if ( pDev->running ){
+ /* Stop RX */
+ grspw_hw_stop(pDev,1,1);
+
+ /* If packetsize fails it is good to know if in running mode */
+ pDev->running = 0;
+
+ /* Wait for Receiver to finnish pending DMA transfers if any */
+ grspw_hw_wait_rx_inactive(pDev);
+ }
+
+ /* Save new buffer sizes */
+ pDev->rxbufsize = ps->rxsize;
+ pDev->txdbufsize = ps->txdsize;
+ pDev->txhbufsize = ps->txhsize;
+ pDev->config.rxmaxlen = pDev->rxbufsize;
+
+ /* Free previous buffers & allocate buffers with new size */
+ if (grspw_buffer_alloc(pDev))
+ return RTEMS_NO_MEMORY;
+
+ /* if RX was actived before, we reactive it again */
+ if ( tmp ) {
+ if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) {
+ return status;
+ }
+ pDev->running = 1;
+ }
#if 0
- /* Rewrite previous config which was wasted due to reset in hw_startup */
- SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr);
- SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey);
- SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv);
- SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) );
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & !(SPW_CTRL_LINKSTART | SPW_CTRL_PM | SPW_CTRL_RE | SPW_CTRL_RD | SPW_CTRL_TT | SPW_CTRL_TR)) | \
- (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \
- (pDev->config.linkdisabled) | (pDev->config.linkstart << 1));
+ /* Rewrite previous config which was wasted due to reset in hw_startup */
+ SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr);
+ SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey);
+ SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv);
+ SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) );
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & !(SPW_CTRL_LINKSTART | SPW_CTRL_PM | SPW_CTRL_RE | SPW_CTRL_RD | SPW_CTRL_TT | SPW_CTRL_TR)) | \
+ (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \
+ (pDev->config.linkdisabled) | (pDev->config.linkstart << 1));
#endif
- break;
- case SPACEWIRE_IOCTRL_GET_CONFIG:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n");
- (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr;
- (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask;
- (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey;
- (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv;
- (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen;
- (*(spw_config *)ioarg->buffer).timer = pDev->config.timer;
- (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect;
- (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous;
- (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen;
- (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis;
- (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err;
- (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id;
- (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking;
- (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err;
- (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq;
- (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id;
- (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap;
- (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc;
- (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned;
- (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled;
- (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart;
- (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking;
- (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full;
- break;
- case SPACEWIRE_IOCTRL_GET_LINK_STATUS:
- SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7));
- *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7);
- break;
- case SPACEWIRE_IOCTRL_GET_STATISTICS:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n");
- (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err;
- (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err;
- (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err;
- (*(spw_stats *)ioarg->buffer).rx_eep_err = pDev->stat.rx_eep_err;
- (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated;
- (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err;
- (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err;
- (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err;
- (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err;
- (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err;
- (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep;
- (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address;
- (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent;
- (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received;
- break;
- case SPACEWIRE_IOCTRL_CLR_STATISTICS:
- SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n");
- pDev->stat.tx_link_err = 0;
- pDev->stat.rx_rmap_header_crc_err = 0;
- pDev->stat.rx_rmap_data_crc_err = 0;
- pDev->stat.rx_eep_err = 0;
- pDev->stat.rx_truncated = 0;
- pDev->stat.parity_err = 0;
- pDev->stat.escape_err = 0;
- pDev->stat.credit_err = 0;
- pDev->stat.write_sync_err = 0;
- pDev->stat.disconnect_err = 0;
- pDev->stat.early_ep = 0;
- pDev->stat.invalid_address = 0;
- pDev->stat.packets_sent = 0;
- pDev->stat.packets_received = 0;
- break;
- case SPACEWIRE_IOCTRL_SEND:
- if (ioarg->buffer == NULL)
- return RTEMS_INVALID_NAME;
- args = (spw_ioctl_pkt_send *)ioarg->buffer;
- args->sent = 0;
-
- /* is link up? */
- if ( !pDev->running ) {
- return RTEMS_INVALID_NAME;
- }
-
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor,
- (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data);
-
- if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) ||
- ((args->hlen+args->dlen) < 1) ||
- ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) {
- return RTEMS_INVALID_NAME;
- }
- while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data)) == 0) {
- if (pDev->config.tx_block_on_full == 1) {
- SPACEWIRE_DBG2("Tx Block on full \n");
- rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- } else {
- SPACEWIRE_DBG2("Tx non blocking return when full \n");
- return RTEMS_RESOURCE_IN_USE;
- }
- }
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i \n", args->sent);
- break;
-
- case SPACEWIRE_IOCTRL_LINKDISABLE:
- pDev->config.linkdisabled = 1;
- pDev->config.linkstart = 0;
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1);
- if ((SPW_CTRL_READ(pDev) & 3) != 1) {
- return RTEMS_IO_ERROR;
- }
- break;
-
- case SPACEWIRE_IOCTRL_LINKSTART:
- pDev->config.linkdisabled = 0;
- pDev->config.linkstart = 1;
- SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2);
- if ((SPW_CTRL_READ(pDev) & 3) != 2) {
- return RTEMS_IO_ERROR;
- }
- break;
-
- /* Calculate timer register from GRSPW Core frequency
- * Also possible to set disconnect and timer64 from
- * - SPACEWIRE_IOCTRL_SET_DISCONNECT
- * - SPACEWIRE_IOCTRL_SET_TIMER
- */
- case SPACEWIRE_IOCTRL_SET_COREFREQ:
- pDev->core_freq_khz = (unsigned int)ioarg->buffer;
- if ( pDev->core_freq_khz == 0 ){
- /* Get GRSPW clock frequency from system clock.
- * System clock has been read from timer inited
- * by RTEMS loader (mkprom)
- */
- pDev->core_freq_khz = sys_freq_khz;
- }
-
- /* Only GRSPW1 needs the Timer64 and Disconnect values
- * GRSPW2 and onwards doesn't have this register.
- */
- if ( pDev->core_ver <= 1 ){
- /* Calculate Timer64 & Disconnect */
- pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz);
- pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz);
-
- /* Set Timer64 & Disconnect Register */
- SPW_WRITE(&pDev->regs->timer,
- (SPW_READ(&pDev->regs->timer) & 0xFFC00000) |
- ((pDev->config.disconnect & 0x3FF)<<12) |
- (pDev->config.timer & 0xFFF));
-
- /* Check that the registers were written successfully */
- tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff;
- if ( ((tmp & 0xFFF) != pDev->config.timer) ||
- (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) {
- return RTEMS_IO_ERROR;
- }
- }
- break;
-
- case SPACEWIRE_IOCTRL_START:
- if ( pDev->running ){
- return RTEMS_INVALID_NAME;
- }
-
- /* Get timeout from userspace
- * timeout:
- * ¤ -1 = Default timeout
- * ¤ less than -1 = forever
- * ¤ 0 = no wait, proceed if link is up
- * ¤ positive = specifies number of system clock ticks that
- * startup will wait for link to enter ready mode.
- */
- timeout = (int)ioarg->buffer;
-
- if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) {
- return ret;
- }
- pDev->running = 1;
- break;
-
- case SPACEWIRE_IOCTRL_STOP:
- if ( !pDev->running ){
- return RTEMS_INVALID_NAME;
- }
- pDev->running = 0;
-
- /* Stop Receiver and transmitter */
- grspw_hw_stop(pDev,1,1);
- break;
-
- default:
- return RTEMS_NOT_IMPLEMENTED;
- }
-
- SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n");
- return RTEMS_SUCCESSFUL;
+ break;
+ case SPACEWIRE_IOCTRL_GET_CONFIG:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n");
+ (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr;
+ (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask;
+ (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey;
+ (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv;
+ (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen;
+ (*(spw_config *)ioarg->buffer).timer = pDev->config.timer;
+ (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect;
+ (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous;
+ (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen;
+ (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis;
+ (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err;
+ (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id;
+ (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking;
+ (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err;
+ (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq;
+ (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id;
+ (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap;
+ (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc;
+ (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned;
+ (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled;
+ (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart;
+ (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking;
+ (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full;
+ (*(spw_config *)ioarg->buffer).keep_source = pDev->config.keep_source;
+ (*(spw_config *)ioarg->buffer).rtimeout = pDev->config.rtimeout;
+ break;
+ case SPACEWIRE_IOCTRL_GET_LINK_STATUS:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7));
+ *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7);
+ break;
+ case SPACEWIRE_IOCTRL_GET_STATISTICS:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n");
+ (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err;
+ (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err;
+ (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err;
+ (*(spw_stats *)ioarg->buffer).rx_eep_err = pDev->stat.rx_eep_err;
+ (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated;
+ (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err;
+ (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err;
+ (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err;
+ (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err;
+ (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err;
+ (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep;
+ (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address;
+ (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent;
+ (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received;
+ break;
+ case SPACEWIRE_IOCTRL_CLR_STATISTICS:
+ SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n");
+ pDev->stat.tx_link_err = 0;
+ pDev->stat.rx_rmap_header_crc_err = 0;
+ pDev->stat.rx_rmap_data_crc_err = 0;
+ pDev->stat.rx_eep_err = 0;
+ pDev->stat.rx_truncated = 0;
+ pDev->stat.parity_err = 0;
+ pDev->stat.escape_err = 0;
+ pDev->stat.credit_err = 0;
+ pDev->stat.write_sync_err = 0;
+ pDev->stat.disconnect_err = 0;
+ pDev->stat.early_ep = 0;
+ pDev->stat.invalid_address = 0;
+ pDev->stat.packets_sent = 0;
+ pDev->stat.packets_received = 0;
+ break;
+ case SPACEWIRE_IOCTRL_SEND:
+ if (ioarg->buffer == NULL)
+ return RTEMS_INVALID_NAME;
+ args = (spw_ioctl_pkt_send *)ioarg->buffer;
+ args->sent = 0;
+
+ /* is link up? */
+ if ( !pDev->running ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor,
+ (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data);
+
+ if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) ||
+ ((args->hlen+args->dlen) < 1) ||
+ ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) {
+ return RTEMS_INVALID_NAME;
+ }
+ while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data, args->options)) == 0) {
+ if (pDev->config.tx_block_on_full == 1) {
+ SPACEWIRE_DBG2("Tx Block on full \n");
+ rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ } else {
+ SPACEWIRE_DBG2("Tx non blocking return when full \n");
+ return RTEMS_RESOURCE_IN_USE;
+ }
+ }
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i \n", args->sent);
+ break;
+
+ case SPACEWIRE_IOCTRL_LINKDISABLE:
+ pDev->config.linkdisabled = 1;
+ pDev->config.linkstart = 0;
+ if ( pDev->core_ver != 3 ) {
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1);
+ if ((SPW_CTRL_READ(pDev) & 3) != 1) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+ break;
+
+ case SPACEWIRE_IOCTRL_LINKSTART:
+ pDev->config.linkdisabled = 0;
+ pDev->config.linkstart = 1;
+ if ( pDev->core_ver != 3 ) {
+ SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2);
+ if ((SPW_CTRL_READ(pDev) & 3) != 2) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+ break;
+
+ /* Calculate timer register from GRSPW Core frequency
+ * Also possible to set disconnect and timer64 from
+ * - SPACEWIRE_IOCTRL_SET_DISCONNECT
+ * - SPACEWIRE_IOCTRL_SET_TIMER
+ */
+ case SPACEWIRE_IOCTRL_SET_COREFREQ:
+ pDev->core_freq_khz = (unsigned int)ioarg->buffer;
+ if ( pDev->core_freq_khz == 0 ){
+ /* Get GRSPW clock frequency from system clock.
+ * System clock has been read from timer inited
+ * by RTEMS loader (mkprom)
+ */
+ drvmgr_freq_get(pDev->dev, DEV_APB_SLV,
+ &pDev->core_freq_khz);
+ /* Convert from Hz -> kHz */
+ pDev->core_freq_khz = pDev->core_freq_khz / 1000;
+ }
+
+ /* Only GRSPW1 needs the Timer64 and Disconnect values
+ * GRSPW2 and onwards doesn't have this register.
+ */
+ if ( pDev->core_ver <= 1 ){
+ /* Calculate Timer64 & Disconnect */
+ pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz);
+ pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz);
+
+ /* Set Timer64 & Disconnect Register */
+ SPW_WRITE(&pDev->regs->timer,
+ (SPW_READ(&pDev->regs->timer) & 0xFFC00000) |
+ ((pDev->config.disconnect & 0x3FF)<<12) |
+ (pDev->config.timer & 0xFFF));
+
+ /* Check that the registers were written successfully */
+ tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff;
+ if ( ((tmp & 0xFFF) != pDev->config.timer) ||
+ (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) {
+ return RTEMS_IO_ERROR;
+ }
+ }
+ break;
+
+ case SPACEWIRE_IOCTRL_START:
+ if ( pDev->running ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Get timeout from userspace
+ * timeout:
+ * ¤ -1 = Default timeout
+ * ¤ less than -1 = forever
+ * ¤ 0 = no wait, proceed if link is up
+ * ¤ positive = specifies number of system clock ticks that
+ * startup will wait for link to enter ready mode.
+ */
+ timeout = (int)ioarg->buffer;
+
+ if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) {
+ return ret;
+ }
+ pDev->running = 1;
+ /* Register interrupt routine and unmask IRQ */
+ drvmgr_interrupt_register(pDev->dev, 0, "grspw", grspw_interrupt, pDev);
+
+ break;
+
+ case SPACEWIRE_IOCTRL_STOP:
+ if ( !pDev->running ){
+ return RTEMS_INVALID_NAME;
+ }
+ /* Disable interrupts */
+ drvmgr_interrupt_unregister(dev, 0, grspw_interrupt, pDev);
+
+ pDev->running = 0;
+
+ /* Stop Receiver and transmitter */
+ grspw_hw_stop(pDev,1,1);
+ break;
+
+ /* Set time-code control register bits, and Enables/Disables
+ * Time code interrupt, make sure to connect the callback
+ * grspw_timecode_callback if using interrupts.
+ */
+ case SPACEWIRE_IOCTRL_SET_TCODE_CTRL:
+ tmp = (unsigned int)ioarg->buffer;
+ mask = tmp & (SPACEWIRE_TCODE_CTRL_IE_MSK|SPACEWIRE_TCODE_CTRL_TT_MSK|SPACEWIRE_TCODE_CTRL_TR_MSK);
+ mask <<= 8;
+ tmp &= mask;
+ tmp = (SPW_CTRL_READ(pDev) & ~(mask | SPW_CTRL_IE)) | tmp;
+ if (tmp & (SPW_CTRL_LI|SPW_CTRL_TQ))
+ tmp |= SPW_CTRL_IE;
+ SPW_CTRL_WRITE(pDev, tmp);
+ break;
+
+ /* Set time register and optionaly send a time code */
+ case SPACEWIRE_IOCTRL_SET_TCODE:
+ tmp = (unsigned int)ioarg->buffer;
+ /* Set timecode register */
+ if (tmp & SPACEWIRE_TCODE_SET) {
+ SPW_WRITE(&pDev->regs->time,
+ ((SPW_READ(&pDev->regs->time) & ~(0xff)) |
+ (tmp & SPACEWIRE_TCODE_TCODE)));
+ }
+ /* Send timecode directly (tick-in) ? */
+ if (tmp & SPACEWIRE_TCODE_TX) {
+ SPW_CTRL_WRITE(pDev,
+ ((SPW_CTRL_READ(pDev) & ~(SPW_CTRL_TI)) | SPW_CTRL_TI));
+ }
+ break;
+
+ /* Read time code register and tick-out status bit */
+ case SPACEWIRE_IOCTRL_GET_TCODE:
+ tmp = (unsigned int)ioarg->buffer;
+ if ( !tmp ){
+ return RTEMS_INVALID_NAME;
+ }
+
+ /* Copy timecode register */
+ if (SPW_READ(&pDev->regs->status) & SPW_STATUS_TO) {
+ *(unsigned int *)tmp = (1 << 8) | SPW_READ(&pDev->regs->time);
+ } else {
+ *(unsigned int *)tmp = SPW_READ(&pDev->regs->time);
+ }
+ break;
+
+ case SPACEWIRE_IOCTRL_SET_READ_TIMEOUT:
+ pDev->config.rtimeout = (unsigned int)ioarg->buffer;
+ break;
+
+ default:
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n");
+ return RTEMS_SUCCESSFUL;
}
/* ============================================================================== */
static int grspw_set_rxmaxlen(GRSPW_DEV *pDev) {
- unsigned int rxmax;
- SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/
- rxmax = SPW_READ(&pDev->regs->dma0rxmax);
- if (rxmax != pDev->config.rxmaxlen) {
- return 0;
- }
- return 1;
+ unsigned int rxmax;
+ SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/
+ rxmax = SPW_READ(&pDev->regs->dma0rxmax);
+ if (rxmax != pDev->config.rxmaxlen) {
+ return 0;
+ }
+ return 1;
}
static int grspw_hw_init(GRSPW_DEV *pDev) {
- unsigned int ctrl;
+ unsigned int ctrl;
- ctrl = SPW_CTRL_READ(pDev);
+ ctrl = SPW_CTRL_READ(pDev);
-#ifdef GRSPW_STATIC_MEM
- pDev->rx = (SPACEWIRE_RXBD *) pDev->mem_bdtable;
- pDev->tx = (SPACEWIRE_RXBD *) pDev->mem_bdtable + SPACEWIRE_BDTABLE_SIZE;
-#else
- pDev->rx = (SPACEWIRE_RXBD *) rtems_heap_allocate_aligned_with_boundary( SPACEWIRE_BDTABLE_SIZE, 1024, 0 );
- pDev->tx = (SPACEWIRE_TXBD *) rtems_heap_allocate_aligned_with_boundary( SPACEWIRE_BDTABLE_SIZE, 1024, 0 );
-#endif
- SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor);
+ pDev->rx = (SPACEWIRE_RXBD *) pDev->ptr_bd0;
+ pDev->tx = (SPACEWIRE_TXBD *) &pDev->rx[SPACEWIRE_RXBUFS_NR];
+
+ /* Translate into remote address */
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->rx, (void **)&pDev->rx_remote);
+ drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->tx, (void **)&pDev->tx_remote);
+
+ SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor);
- pDev->config.is_rmap = ctrl & SPW_CTRL_RA;
- pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX;
- pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC;
- return 0;
+ pDev->config.is_rmap = ctrl & SPW_CTRL_RA;
+ pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX;
+ pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC;
+ return 0;
}
-static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout)
+static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout)
{
- int j;
-
- if ( timeout == -1 ){
- /* Wait default timeout */
- timeout = SPACEWIRE_INIT_TIMEOUT;
- }
-
- j=0;
- while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) {
- if ( timeout < -1 ) {
- /* wait forever */
- }else if ( j >= timeout ){
- /* timeout reached, return fail */
- return 1;
- }
-
- /* Sleep for 10 ticks */
- rtems_task_wake_after(10);
- j+=10;
- }
- return 0;
+ int j;
+
+ /* No actual link interface on a DMA-only GRSPW2 connected to the
+ * SPW router
+ */
+ if (pDev->core_ver == 3)
+ return 0;
+
+ if ( timeout == -1 ){
+ /* Wait default timeout */
+ timeout = SPACEWIRE_INIT_TIMEOUT;
+ }
+
+ j=0;
+ while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) {
+ if ( timeout < -1 ) {
+ /* wait forever */
+ }else if ( j >= timeout ){
+ /* timeout reached, return fail */
+ return 1;
+ }
+
+ /* Sleep for 10 ticks */
+ rtems_task_wake_after(10);
+ j+=10;
+ }
+ return 0;
}
static void grspw_hw_reset(GRSPW_DEV *pDev)
{
- SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/
- SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE |
- SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/
- SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/
- #ifndef GRSPW_STATIC_MEM
- free(pDev->rx);
- free(pDev->tx);
- #endif
+ SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/
+ SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE |
+ SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/
+ SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/
}
static void grspw_hw_read_config(GRSPW_DEV *pDev)
{
- unsigned int tmp;
+ unsigned int tmp;
+
+ tmp = SPW_READ(&pDev->regs->nodeaddr);
+ pDev->config.nodeaddr = 0xFF & tmp;
+ pDev->config.nodemask = 0xFF & (tmp>>8);
+ pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey);
+ pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv);
+
+ tmp = SPW_CTRL_READ(pDev);
+ pDev->config.promiscuous = 1 & (tmp >> 5);
+ pDev->config.rmapen = 1 & (tmp >> 16);
+ pDev->config.rmapbufdis = 1 & (tmp >> 17);
+ pDev->config.is_rmap = 1 & (tmp >> 31);
+ pDev->config.is_rxunaligned = 1 & (tmp >> 30);
+ pDev->config.is_rmapcrc = 1 & (tmp >> 29);
+ pDev->config.linkdisabled = 1 & tmp;
+ pDev->config.linkstart = 1 & (tmp >> 1);
+
+ if ( pDev->core_ver <= 1 ){
+ tmp = SPW_READ(&pDev->regs->timer);
+ pDev->config.timer = 0xFFF & tmp;
+ pDev->config.disconnect = 0x3FF & (tmp >> 12);
+ }else{
+ pDev->config.timer = 0;
+ pDev->config.disconnect = 0;
+ }
- tmp = SPW_READ(&pDev->regs->nodeaddr);
- pDev->config.nodeaddr = 0xFF & tmp;
- pDev->config.nodemask = 0xFF & (tmp>>8);
- pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey);
- pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv);
-
- tmp = SPW_CTRL_READ(pDev);
- pDev->config.promiscuous = 1 & (tmp >> 5);
- pDev->config.rmapen = 1 & (tmp >> 16);
- pDev->config.rmapbufdis = 1 & (tmp >> 17);
- pDev->config.is_rmap = 1 & (tmp >> 31);
- pDev->config.is_rxunaligned = 1 & (tmp >> 30);
- pDev->config.is_rmapcrc = 1 & (tmp >> 29);
- pDev->config.linkdisabled = 1 & tmp;
- pDev->config.linkstart = 1 & (tmp >> 1);
-
- if ( pDev->core_ver <= 1 ){
- tmp = SPW_READ(&pDev->regs->timer);
- pDev->config.timer = 0xFFF & tmp;
- pDev->config.disconnect = 0x3FF & (tmp >> 12);
- }else{
- pDev->config.timer = 0;
- pDev->config.disconnect = 0;
- }
-
- return;
+ return;
}
/* timeout is given in ticks */
static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout)
{
- int i;
- unsigned int dmactrl;
-
- SPW_WRITE(&pDev->regs->status, (SPW_STATUS_TO|SPW_STATUS_CE|SPW_STATUS_ER|SPW_STATUS_DE|SPW_STATUS_PE|SPW_STATUS_WE|SPW_STATUS_IA|SPW_STATUS_EE)); /*clear status*/
-
- if (grspw_hw_waitlink(pDev,timeout)) {
- SPACEWIRE_DBG2("Device open. Link is not up\n");
- return RTEMS_TIMEOUT;
- }
-
- SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/
-
-
- if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) {
- SPACEWIRE_DBG2("DMACtrl is not cleared\n");
- return RTEMS_IO_ERROR;
- }
-
- /* prepare transmit buffers */
- for (i = 0; i < pDev->txbufcnt; i++) {
- pDev->tx[i].ctrl = 0;
- pDev->tx[i].addr_header = memarea_to_hw(((unsigned int)&pDev->ptr_txhbuf0[0]) + (i * pDev->txhbufsize));
- pDev->tx[i].addr_data = memarea_to_hw(((unsigned int)&pDev->ptr_txdbuf0[0]) + (i * pDev->txdbufsize));
- }
- pDev->tx_cur = 0;
- pDev->tx_sent = 0;
- pDev->tx_all_in_use = 0;
-
- /* prepare receive buffers */
- for (i = 0; i < pDev->rxbufcnt; i++) {
- if (i+1 == pDev->rxbufcnt) {
- pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR;
- } else {
- pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN;
- }
- pDev->rx[i].addr = memarea_to_hw(((unsigned int)&pDev->ptr_rxbuf0[0]) + (i * pDev->rxbufsize));
- }
- pDev->rxcur = 0;
- pDev->rxbufcur = -1;
- grspw_set_rxmaxlen(pDev);
-
- SPW_WRITE(&pDev->regs->dma0txdesc, memarea_to_hw((unsigned int) pDev->tx));
- SPW_WRITE(&pDev->regs->dma0rxdesc, memarea_to_hw((unsigned int) pDev->rx));
-
- /* start RX */
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE);
-
- SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs);
- return RTEMS_SUCCESSFUL;
+ int i;
+ unsigned int dmactrl;
+
+ SPW_WRITE(&pDev->regs->status, (SPW_STATUS_TO|SPW_STATUS_CE|SPW_STATUS_ER|SPW_STATUS_DE|SPW_STATUS_PE|SPW_STATUS_WE|SPW_STATUS_IA|SPW_STATUS_EE)); /*clear status*/
+
+ if (grspw_hw_waitlink(pDev,timeout)) {
+ SPACEWIRE_DBG2("Device open. Link is not up\n");
+ return RTEMS_TIMEOUT;
+ }
+
+ SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/
+
+ if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) {
+ SPACEWIRE_DBG2("DMACtrl is not cleared\n");
+ return RTEMS_IO_ERROR;
+ }
+
+ /* prepare transmit buffers */
+ for (i = 0; i < pDev->txbufcnt; i++) {
+ pDev->tx[i].ctrl = 0;
+ pDev->tx[i].addr_header = ((unsigned int)&pDev->ptr_txhbuf0_remote[0]) + (i * pDev->txhbufsize);
+ pDev->tx[i].addr_data = ((unsigned int)&pDev->ptr_txdbuf0_remote[0]) + (i * pDev->txdbufsize);
+ }
+ pDev->tx_cur = 0;
+ pDev->tx_sent = 0;
+ pDev->tx_all_in_use = 0;
+
+ /* prepare receive buffers */
+ for (i = 0; i < pDev->rxbufcnt; i++) {
+ if (i+1 == pDev->rxbufcnt) {
+ pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR;
+ } else {
+ pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN;
+ }
+ pDev->rx[i].addr = ((unsigned int)&pDev->ptr_rxbuf0_remote[0]) + (i * pDev->rxbufsize);
+ }
+ pDev->rxcur = 0;
+ pDev->rxbufcur = -1;
+ grspw_set_rxmaxlen(pDev);
+
+ SPW_WRITE(&pDev->regs->dma0txdesc, pDev->tx_remote);
+ SPW_WRITE(&pDev->regs->dma0rxdesc, pDev->rx_remote);
+
+ /* start RX */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE);
+
+ SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs);
+ return RTEMS_SUCCESSFUL;
}
/* Wait until the receiver is inactive */
static void grspw_hw_wait_rx_inactive(GRSPW_DEV *pDev)
{
- while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){
- /* switching may be needed:
- * - low frequency GRSPW
- * - mega packet incoming
- */
- rtems_task_wake_after(1);
- }
+ while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){
+ /* switching may be needed:
+ * - low frequency GRSPW
+ * - mega packet incoming
+ */
+ rtems_task_wake_after(1);
+ }
}
/* Stop the rx or/and tx by disabling the receiver/transmitter */
-static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx)
-{
- unsigned int dmactrl;
-
- /* stop rx and/or tx */
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- if ( rx ) {
- dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD);
- }
- if ( tx ) {
- dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE);
- }
- /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/
-
- /* don't clear status flags */
- dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI);
- SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
- return RTEMS_SUCCESSFUL;
-}
-
-int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data)
+static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx)
{
+ unsigned int dmactrl;
- unsigned int dmactrl, ctrl;
-#ifdef DEBUG_SPACEWIRE_ONOFF
- unsigned int k;
-#endif
- rtems_interrupt_level level;
- unsigned int cur = pDev->tx_cur;
- char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize);
- char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize);
+ /* stop rx and/or tx */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ if ( rx ) {
+ dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD);
+ }
+ if ( tx ) {
+ dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE);
+ }
+ /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/
- ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl);
+ /* don't clear status flags */
+ dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI);
+ SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
+ return RTEMS_SUCCESSFUL;
+}
- if (ctrl & SPW_TXBD_EN) {
- return 0;
- }
- memcpy(&txd[0], data, dlen);
- memcpy(&txh[0], hdr, hlen);
+int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data, unsigned int options)
+{
+ unsigned int dmactrl, ctrl;
#ifdef DEBUG_SPACEWIRE_ONOFF
- if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
- for (k = 0; k < hlen; k++){
- if (k % 16 == 0) {
- printf ("\n");
- }
- printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' ');
- }
- printf ("\n");
- }
- if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
- for (k = 0; k < dlen; k++){
- if (k % 16 == 0) {
- printf ("\n");
- }
- printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' ');
- }
- printf ("\n");
- }
+ unsigned int k;
#endif
+ rtems_interrupt_level level;
+ unsigned int cur = pDev->tx_cur, bdctrl;
+ char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize);
+ char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize);
+ char *txh_remote = pDev->ptr_txhbuf0_remote + (cur * pDev->txhbufsize);
+ char *txd_remote = pDev->ptr_txdbuf0_remote + (cur * pDev->txdbufsize);
+ unsigned int tmp, tmp2;
+
+ ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl);
+
+ if (ctrl & SPW_TXBD_EN) {
+ return 0;
+ }
- pDev->tx[cur].addr_header = memarea_to_hw((unsigned int)txh);
- pDev->tx[cur].len = dlen;
- pDev->tx[cur].addr_data = memarea_to_hw((unsigned int)txd);
- if (pDev->tx_cur == (pDev->txbufcnt - 1) ) {
- pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_WR | SPW_TXBD_EN | hlen;
- } else {
- pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen;
- }
+ memcpy(&txd[0], data, dlen);
+ memcpy(&txh[0], hdr, hlen);
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE);
+#ifdef DEBUG_SPACEWIRE_ONOFF
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ for (k = 0; k < hlen; k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ for (k = 0; k < dlen; k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
+#endif
+
+ pDev->tx[cur].addr_header = (unsigned int)txh_remote;
+ pDev->tx[cur].len = dlen;
+ pDev->tx[cur].addr_data = (unsigned int)txd_remote;
+
+ bdctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen;
+ if ( options & GRSPW_PKTSEND_OPTION_HDR_CRC )
+ bdctrl |= SPW_TXBD_HC;
+ if ( options & GRSPW_PKTSEND_OPTION_DATA_CRC )
+ bdctrl |= SPW_TXBD_DC;
+ bdctrl |= options & GRSPW_PKTSEND_OPTION_NOCRCLEN_MASK;
+
+ /* Update counters */
+ rtems_interrupt_disable(level);
+ if (pDev->tx_cur == (pDev->txbufcnt - 1) ) {
+ bdctrl |= SPW_TXBD_WR;
+ }
+ pDev->tx[cur].ctrl = bdctrl;
- /* Update counters */
- rtems_interrupt_disable(level);
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE);
- pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt;
- if (pDev->tx_cur == pDev->tx_sent) {
- pDev->tx_all_in_use = 1;
- }
- rtems_interrupt_enable(level);
+ pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt;
+ if (pDev->tx_cur == pDev->tx_sent) {
+ pDev->tx_all_in_use = 1;
+ }
+ rtems_interrupt_enable(level);
- /* In blocking mode wait until message is sent */
+ /* In blocking mode wait until message is sent */
if (pDev->config.tx_blocking) {
while ( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_TXEN) {
/* if changed to blocking mode */
- SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n");
- rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n");
+ rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
}
}
- SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen);
- return hlen + dlen;
+ SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen);
+ return hlen + dlen;
}
static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) {
- unsigned int len, rxlen, ctrl;
- unsigned int cur;
- unsigned int tmp;
- unsigned int dump_start_len;
- int i;
- char *rxb;
-
- if ( pDev->config.promiscuous ) {
+ unsigned int len, rxlen, ctrl;
+ unsigned int cur;
+ unsigned int tmp;
+ unsigned int dump_start_len;
+ int i;
+ char *rxb;
+
+ if ( pDev->config.promiscuous || pDev->config.keep_source ) {
dump_start_len = 0; /* make sure address and prot can be read in promiscuous mode */
} else if (pDev->config.rm_prot_id) {
dump_start_len = 2; /* skip source address and protocol id */
@@ -1638,92 +1819,153 @@ static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) {
dump_start_len = 1; /* default: skip only source address */
}
- rxlen = 0;
- cur = pDev->rxcur;
- rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize);
-
- SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur);
-
- ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl);
- if (ctrl & SPW_RXBD_EN) {
- return rxlen;
- }
- SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n");
-
- len = SPW_RXBD_LENGTH & ctrl;
- if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) {
- if (pDev->rxbufcur == -1) {
- SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len);
- pDev->stat.packets_received++;
- pDev->rxbufcur = dump_start_len;
- }
- rxlen = tmp = len - pDev->rxbufcur;
- SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c);
- SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len);
- SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur);
- SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen );
- if (rxlen > c) {
- rxlen = c;
- }
- if (CPU_SPARC_HAS_SNOOPING) {
- memcpy(b, rxb+pDev->rxbufcur, rxlen);
- } else {
- for(i = 0; i < rxlen; i++) {
- b[i] = MEM_READ(rxb+pDev->rxbufcur);
- }
- }
-
- pDev->rxbufcur += rxlen;
- if (c >= tmp) {
- SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n");
- grspw_rxnext(pDev);
- }
- } else {
- check_rx_errors(pDev, ctrl);
- }
- return rxlen;
+ rxlen = 0;
+ cur = pDev->rxcur;
+ rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize);
+
+ SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur);
+
+ ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl);
+ if (ctrl & SPW_RXBD_EN) {
+ return rxlen;
+ }
+ SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n");
+
+ len = SPW_RXBD_LENGTH & ctrl;
+ if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) {
+ if (pDev->rxbufcur == -1) {
+ SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len);
+ pDev->stat.packets_received++;
+ pDev->rxbufcur = dump_start_len;
+ }
+ rxlen = tmp = len - pDev->rxbufcur;
+ SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c);
+ SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len);
+ SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur);
+ SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen );
+ if (rxlen > c) {
+ rxlen = c;
+ }
+ if (CPU_SPARC_HAS_SNOOPING) {
+/* if ( 1 ) {*/
+ /*printf("RX_MEMCPY(0x%x, 0x%x, 0x%x)\n", (unsigned int)b, (unsigned int)(rxb+pDev->rxbufcur), (unsigned int)rxlen);*/
+ memcpy(b, rxb+pDev->rxbufcur, rxlen);
+ } else {
+ int left = rxlen;
+ /* Copy word wise if Aligned */
+ if ( (((int)b & 3) == 0) && (((int)(rxb+pDev->rxbufcur) & 3) == 0) ){
+ while(left>=32){
+ *(int *)(b+0) = MEM_READ32(rxb+pDev->rxbufcur+0);
+ *(int *)(b+4) = MEM_READ32(rxb+pDev->rxbufcur+4);
+ *(int *)(b+8) = MEM_READ32(rxb+pDev->rxbufcur+8);
+ *(int *)(b+12) = MEM_READ32(rxb+pDev->rxbufcur+12);
+ *(int *)(b+16) = MEM_READ32(rxb+pDev->rxbufcur+16);
+ *(int *)(b+20) = MEM_READ32(rxb+pDev->rxbufcur+20);
+ *(int *)(b+24) = MEM_READ32(rxb+pDev->rxbufcur+24);
+ *(int *)(b+28) = MEM_READ32(rxb+pDev->rxbufcur+28);
+ rxb+=32;
+ b+=32;
+ left-=32;
+ }
+ while(left>=4){
+ *(int *)b = MEM_READ32(rxb+pDev->rxbufcur);
+ rxb+=4;
+ b+=4;
+ left-=4;
+ }
+ }
+ for(i = 0; i < left; i++) {
+ b[i] = MEM_READ8(rxb+pDev->rxbufcur+i);
+ }
+ }
+
+ pDev->rxbufcur += rxlen;
+ if (c >= tmp) {
+ SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n");
+ grspw_rxnext(pDev);
+ }
+ } else {
+ check_rx_errors(pDev, ctrl);
+ grspw_rxnext(pDev);
+ }
+ return rxlen;
}
-static void grspw_rxnext(GRSPW_DEV *pDev)
+static void grspw_rxnext(GRSPW_DEV *pDev)
{
- unsigned int dmactrl;
- unsigned int cur = pDev->rxcur;
- unsigned int ctrl = 0;
- if (cur == (pDev->rxbufcnt - 1)) {
- pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR;
- cur = 0;
- } else {
- pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE;
- cur++;
- }
-
- pDev->rxcur = cur;
- pDev->rxbufcur = -1;
-
- /* start RX */
- dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
- SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS);
+ unsigned int dmactrl;
+ unsigned int cur = pDev->rxcur;
+ unsigned int ctrl = 0;
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+
+ if (cur == (pDev->rxbufcnt - 1)) {
+ pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR;
+ cur = 0;
+ } else {
+ pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE;
+ cur++;
+ }
+
+ pDev->rxcur = cur;
+ pDev->rxbufcur = -1;
+
+ /* start RX */
+ dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
+ SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS);
+ rtems_interrupt_enable(level);
+}
+
+static void check_rx_errors(GRSPW_DEV *pDev, int ctrl)
+{
+ if (ctrl & SPW_RXBD_EEP) {
+ pDev->stat.rx_eep_err++;
+ }
+ if (ctrl & SPW_RXBD_EHC) {
+ if (pDev->config.check_rmap_err) {
+ pDev->stat.rx_rmap_header_crc_err++;
+ }
+ }
+ if (ctrl & SPW_RXBD_EDC) {
+ if (pDev->config.check_rmap_err) {
+ pDev->stat.rx_rmap_data_crc_err++;
+ }
+ }
+ if (ctrl & SPW_RXBD_ETR) {
+ pDev->stat.rx_truncated++;
+ }
}
-static void check_rx_errors(GRSPW_DEV *pDev, int ctrl)
+
+void grspw_print_dev(struct drvmgr_dev *dev, int options)
{
- if (ctrl & SPW_RXBD_EEP) {
- pDev->stat.rx_eep_err++;
- }
- if (ctrl & SPW_RXBD_EHC) {
- if (pDev->config.check_rmap_err) {
- pDev->stat.rx_rmap_header_crc_err++;
- }
- }
- if (ctrl & SPW_RXBD_EDC) {
- if (pDev->config.check_rmap_err) {
- pDev->stat.rx_rmap_data_crc_err++;
- }
- }
- if (ctrl & SPW_RXBD_ETR) {
- pDev->stat.rx_truncated++;
- }
+ GRSPW_DEV *pDev = dev->priv;
+ struct amba_dev_info *devinfo;
+
+ devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+ /* Print */
+ printf("--- GRSPW %s ---\n", pDev->devName);
+ printf(" REGS: 0x%x\n", (unsigned int)pDev->regs);
+ printf(" IRQ: %d\n", pDev->irq);
+ printf(" CORE VERSION: %d\n", pDev->core_ver);
+ printf(" CTRL: 0x%x\n", pDev->regs->ctrl);
+ printf(" STATUS: 0x%x\n", pDev->regs->status);
+ printf(" DMA0CTRL: 0x%x\n", pDev->regs->dma0ctrl);
+ printf(" TXBD: 0x%x\n", (unsigned int)pDev->tx);
+ printf(" RXBD: 0x%x\n", (unsigned int)pDev->rx);
}
+void grspw_print(int options)
+{
+ struct amba_drv_info *drv = &grspw_drv_info;
+ struct drvmgr_dev *dev;
+ dev = drv->general.dev;
+ while(dev) {
+ grspw_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
--
1.7.0.4
More information about the devel
mailing list