summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/1553
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2015-02-23 13:02:39 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:17 +0200
commit3bb41226e0941b86d58ecb97f7d292677de573c8 (patch)
tree907aa270343f7c6d1bc08bf73288fb9b10da6197 /c/src/lib/libbsp/sparc/shared/1553
parentLEON: added network device configuration helper function (diff)
downloadrtems-3bb41226e0941b86d58ecb97f7d292677de573c8.tar.bz2
LEON: added new drivers to the LEON2/LEON3 BSPs
Most drivers use the Driver Manager for device probing, they work on AMBA-over-PCI systems if PCI is big-endian. New APIs: * GPIO Library, interfaced to GRGPIO * GENIRQ, Generic interrupt service implementation helper New GRLIB Drivers: * ACTEL 1553 RT, user interface is similar to 1553 BRM driver * GR1553 (1553 BC, RT and BM core) * AHBSTAT (AHB error status core) * GRADCDAC (Core interfacing to ADC/DAC hardware) * GRGPIO (GPIO port accessed from GPIO Library) * MCTRL (Memory controller settings configuration) * GRETH (10/100/1000 Ethernet driver using Driver manager) * GRPWM (Pulse Width Modulation core) * SPICTRL (SPI master interface) * GRSPW_ROUTER (SpaceWire Router AMBA configuration interface) * GRCTM (SpaceCraft on-board Time Management core) * SPWCUC (Time distribution over SpaceWire) * GRTC (SpaceCraft up-link Tele core) * GRTM (SpaceCraft down-link Tele Metry core) GR712RC ASIC specific interfaces: * GRASCS * CANMUX (select between OCCAN and SATCAN) * SATCAN * SLINK
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/1553')
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/b1553rt.c859
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553b.c305
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c1674
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c519
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c1256
5 files changed, 4613 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
new file mode 100644
index 0000000000..3dfb40309c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
@@ -0,0 +1,859 @@
+/*
+ * B1553RT driver implmenetation
+ *
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <b1553rt.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+
+/* Uncomment for debug output */
+/*#define DEBUG 1*/
+
+/*
+ #define FUNCDEBUG 1*/
+/*#undef DEBUG*/
+#undef FUNCDEBUG
+
+/* EVENT_QUEUE_SIZE sets the size of the event queue
+ */
+#define EVENT_QUEUE_SIZE 1024
+
+
+#define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) )
+
+#if 0
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef FUNCDEBUG
+#define FUNCDBG(x...) printk(x)
+#else
+#define FUNCDBG(x...)
+#endif
+
+#define READ_DMA(address) _READ16((unsigned int)address)
+
+static __inline__ unsigned short _READ16(unsigned int addr) {
+ unsigned short tmp;
+ asm(" lduha [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
+}
+
+static rtems_device_driver rt_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define RT_DRIVER_TABLE_ENTRY { rt_initialize, rt_open, rt_close, rt_read, rt_write, rt_control }
+
+static rtems_driver_address_table b1553rt_driver = RT_DRIVER_TABLE_ENTRY;
+
+typedef struct {
+
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+
+ struct rt_reg *regs;
+ unsigned int ctrl_copy; /* Local copy of config register */
+
+ unsigned int cfg_freq;
+
+ unsigned int memarea_base;
+ unsigned int memarea_base_remote;
+
+ volatile unsigned short *mem;
+
+ /* Received events waiting to be read */
+ struct rt_msg *rt_event;
+ unsigned int head, tail;
+
+ int rx_blocking;
+
+ rtems_id rx_sem, tx_sem, dev_sem;
+ int minor;
+ int irqno;
+
+#ifdef DEBUG
+ unsigned int log[EVENT_QUEUE_SIZE*4];
+ unsigned int log_i;
+#endif
+
+ unsigned int status;
+ rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command RT_SET_EVENTID */
+
+} rt_priv;
+
+static void b1553rt_interrupt(void *arg);
+static rtems_device_driver rt_init(rt_priv *rt);
+
+#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1)
+
+static int b1553rt_driver_io_registered = 0;
+static rtems_device_major_number b1553rt_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int b1553rt_register_io(rtems_device_major_number *m);
+int b1553rt_device_init(rt_priv *pDev);
+
+int b1553rt_init2(struct drvmgr_dev *dev);
+int b1553rt_init3(struct drvmgr_dev *dev);
+int b1553rt_remove(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops b1553rt_ops =
+{
+ .init = {NULL, b1553rt_init2, b1553rt_init3, NULL},
+ .remove = b1553rt_remove,
+ .info = NULL
+};
+
+struct amba_dev_id b1553rt_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_B1553RT},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info b1553rt_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_B1553RT_ID, /* Driver ID */
+ "B1553RT_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &b1553rt_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+
+ },
+ &b1553rt_ids[0]
+};
+
+void b1553rt_register_drv (void)
+{
+ DBG("Registering B1553RT driver\n");
+ drvmgr_drv_register(&b1553rt_drv_info.general);
+}
+
+int b1553rt_init2(struct drvmgr_dev *dev)
+{
+ rt_priv *priv;
+
+ DBG("B1553RT[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ priv = dev->priv = malloc(sizeof(rt_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 b1553rt_init3(struct drvmgr_dev *dev)
+{
+ rt_priv *priv;
+ char prefix[32];
+ rtems_status_code status;
+
+ priv = dev->priv;
+
+ /* Do initialization */
+
+ if ( b1553rt_driver_io_registered == 0) {
+ /* Register the I/O driver only once for all cores */
+ if ( b1553rt_register_io(&b1553rt_driver_io_major) ) {
+ /* Failed to register I/O driver */
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ b1553rt_driver_io_registered = 1;
+ }
+
+ /* I/O system registered and initialized
+ * Now we take care of device initialization.
+ */
+
+ if ( b1553rt_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/b1553rt%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/%sb1553rt%d", prefix, dev->minor_bus);
+ }
+
+ /* Register Device */
+ status = rtems_io_register_name(priv->devName, b1553rt_driver_io_major, dev->minor_drv);
+ if (status != RTEMS_SUCCESSFUL) {
+ return DRVMGR_FAIL;
+ }
+
+ return DRVMGR_OK;
+}
+
+int b1553rt_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_FAIL;
+}
+
+/******************* Driver Implementation ***********************/
+
+int b1553rt_register_io(rtems_device_major_number *m)
+{
+ rtems_status_code r;
+
+ if ((r = rtems_io_register_driver(0, &b1553rt_driver, m)) == RTEMS_SUCCESSFUL) {
+ DBG("B1553RT driver successfully registered, major: %d\n", *m);
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ printk("B1553RT rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+ return -1;
+ case RTEMS_INVALID_NUMBER:
+ printk("B1553RT rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+ return -1;
+ case RTEMS_RESOURCE_IN_USE:
+ printk("B1553RT rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+ return -1;
+ default:
+ printk("B1553RT rtems_io_register_driver failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int b1553rt_device_init(rt_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ unsigned int mem;
+ unsigned int sys_freq_hz;
+
+ /* 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;
+ pDev->regs = (struct rt_reg *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+#ifdef DEBUG
+ pDev->log_i = 0;
+ memset(pDev->log,0,sizeof(pDev->log));
+ printf("LOG: 0x%x\n", &pDev->log[0]);
+ printf("LOG_I: 0x%x\n", &pDev->log_i);
+#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 RT looks at it. */
+
+ /* Translate the base address into an address that the the CPU can understand */
+ pDev->memarea_base = mem & ~1;
+ drvmgr_translate_check(pDev->dev, DMAMEM_TO_CPU,
+ (void *)pDev->memarea_base_remote,
+ (void **)&pDev->memarea_base,
+ 4 * 1024);
+ } else {
+ if (!value) {
+ /* Use dynamically allocated memory,
+ * 4k DMA memory + 4k for alignment
+ */
+ mem = (char *)malloc(4 * 1024 * 2);
+ if ( !mem ){
+ printk("RT: Failed to allocate HW memory\n\r");
+ return -1;
+ }
+ /* align memory to 4k boundary */
+ pDev->memarea_base = (mem + 0xfff) & ~0xfff;
+ } else {
+ pDev->memarea_base = mem;
+ }
+
+ /* Translate the base address into an address that the RT core can understand */
+ drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA,
+ (void *)pDev->memarea_base,
+ (void **)&pDev->memarea_base_remote,
+ 4 * 1024);
+ }
+
+ /* clear the used memory */
+ memset((char *)pDev->memarea_base, 0, 4 * 1024);
+
+ /* Set base address of all descriptors */
+ pDev->memarea_base = (unsigned int)mem;
+ pDev->mem = (volatile unsigned short *)pDev->memarea_base;
+
+ pDev->rt_event = NULL;
+
+ /* The RT is always clocked at the same frequency as the bus
+ * If the frequency doesnt match it is defaulted to 24MHz,
+ * user can always override it.
+ */
+ pDev->cfg_freq = RT_FREQ_24MHZ;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &sys_freq_hz) == 0 ) {
+ if ( sys_freq_hz == 20000000 ) {
+ pDev->cfg_freq = RT_FREQ_20MHZ;
+ } else if ( sys_freq_hz == 16000000 ) {
+ pDev->cfg_freq = RT_FREQ_16MHZ;
+ } else if ( sys_freq_hz == 12000000 ) {
+ pDev->cfg_freq = RT_FREQ_12MHZ;
+ }
+ }
+
+ value = drvmgr_dev_key_get(pDev->dev, "coreFreq", KEY_TYPE_INT);
+ if ( value ) {
+ pDev->cfg_freq = value->i & RT_FREQ_MASK;
+ }
+
+ /* RX Semaphore created with count = 0 */
+ if ( rtems_semaphore_create(rtems_build_name('R', 'T', '0', '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("RT: Failed to create rx semaphore\n");
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* Device Semaphore created with count = 1 */
+ if ( rtems_semaphore_create(rtems_build_name('R', 'T', '0', '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("RT: 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;
+
+ while(data)
+ {
+ i++;
+ data &= (data - 1);
+ }
+
+ return !(i&1);
+}
+
+static void start_operation(rt_priv *rt)
+{
+
+}
+
+static void stop_operation(rt_priv *rt)
+{
+
+}
+
+static void set_extmdata_en(rt_priv *rt, int extmdata)
+{
+ if ( extmdata )
+ extmdata = 1;
+ rt->ctrl_copy = (rt->ctrl_copy & ~(1<<16)) | (extmdata<<16);
+ rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static void set_vector_word(rt_priv *rt, unsigned short vword)
+{
+ rt->regs->vword = vword;
+}
+
+/* Set clock speed */
+static void set_clkspd(rt_priv *rt, int spd)
+{
+ rt->ctrl_copy = (rt->ctrl_copy & ~0xC0) | (spd<<6);
+ rt->regs->ctrl = rt->ctrl_copy;
+ asm volatile("nop"::);
+ rt->regs->ctrl = rt->ctrl_copy | (1<<20);
+}
+
+static void set_rtaddr(rt_priv *rt, int addr)
+{
+ rt->ctrl_copy = (rt->ctrl_copy & ~0x3F00) | (addr << 8) | (odd_parity(addr)<<13);
+ rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static void set_broadcast_en(rt_priv *rt, int data)
+{
+ rt->ctrl_copy = (rt->ctrl_copy & ~0x40000) | (data<<18);
+ rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static rtems_device_driver rt_init(rt_priv *rt)
+{
+ rt->rx_blocking = 1;
+
+ if ( rt->rt_event )
+ free(rt->rt_event);
+ rt->rt_event = NULL;
+
+ rt->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg));
+
+ if (rt->rt_event == NULL) {
+ DBG("RT driver failed to allocated memory.");
+ return RTEMS_NO_MEMORY;
+ }
+
+ rt->ctrl_copy = rt->regs->ctrl & 0x3F00; /* Keep rtaddr and rtaddrp */
+ rt->ctrl_copy |= 0x3C0D0; /* broadcast disabled, extmdata=1, writetsw = writecmd = 1 */
+ rt->regs->ctrl = rt->ctrl_copy;
+
+ /* Set Clock speed */
+ set_clkspd(rt, rt->cfg_freq);
+
+ rt->regs->addr = rt->memarea_base_remote;
+ rt->regs->ipm = 0x70000; /* Enable RT RX, MEM Failure and AHB Error interrupts */
+
+ DBG("B1553RT DMA_AREA: 0x%x\n", (unsigned int)rt->mem);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver rt_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG("rt_open\n");
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ DBG("Wrong minor %d\n", minor);
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ if (rtems_semaphore_obtain(rt->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
+ DBG("rt_open: resource in use\n");
+ return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+ }
+
+ /* Set defaults */
+ rt->event_id = 0;
+
+ start_operation(rt);
+
+ /* Register interrupt routine */
+ if (drvmgr_interrupt_register(rt->dev, 0, "b1553rt", b1553rt_interrupt, rt)) {
+ rtems_semaphore_release(rt->dev_sem);
+ return -1;
+ }
+
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG("rt_close");
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ drvmgr_interrupt_unregister(rt->dev, 0, b1553rt_interrupt, rt);
+
+ stop_operation(rt);
+ rtems_semaphore_release(rt->dev_sem);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static int get_messages(rt_priv *rt, void *buf, unsigned int msg_count)
+{
+
+ struct rt_msg *dest = (struct rt_msg *) buf;
+ int count = 0;
+
+ if (rt->head == rt->tail) {
+ return 0;
+ }
+
+ do {
+
+ DBG("rt read - head: %d, tail: %d\n", rt->head, rt->tail);
+ dest[count++] = rt->rt_event[INDEX(rt->tail++)];
+
+ } while (rt->head != rt->tail && count < msg_count);
+
+ return count;
+
+}
+static rtems_device_driver rt_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args;
+ int count = 0;
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ FUNCDBG("rt_read [%i,%i]: buf: 0x%x, len: %i\n",major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+
+ while ( (count = get_messages(rt,rw_args->buffer, rw_args->count)) == 0 ) {
+
+ if (rt->rx_blocking) {
+ rtems_semaphore_obtain(rt->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 rt_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_rw_args_t *rw_args;
+ struct rt_msg *source;
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+ unsigned int descriptor, suba, wc;
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ if ( rw_args->count != 1 ) {
+ return RTEMS_INVALID_NAME;
+ }
+
+ source = (struct rt_msg *) rw_args->buffer;
+
+ descriptor = source[0].desc & 0x7F;
+ suba = descriptor-32;
+ wc = source[0].miw >> 11;
+ wc = wc ? wc : 32;
+
+ FUNCDBG("rt_write [%i,%i]: buf: 0x%x\n",major, minor, (unsigned int)rw_args->buffer);
+
+ memcpy((void *)&rt->mem[0x400 + suba*32], &source[0].data[0], wc*2);
+
+ rw_args->bytes_moved = 1;
+
+ return RTEMS_SUCCESSFUL;
+
+}
+
+static rtems_device_driver rt_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+ unsigned int *data = ioarg->buffer;
+
+ rt_priv *rt;
+ struct drvmgr_dev *dev;
+
+ FUNCDBG("rt_control[%d]: [%i,%i]\n", minor, major, minor);
+
+ if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+ return RTEMS_UNSATISFIED;
+ }
+ rt = (rt_priv *)dev->priv;
+
+ if (!ioarg) {
+ DBG("rt_control: invalid argument\n");
+ return RTEMS_INVALID_NAME;
+ }
+
+ ioarg->ioctl_return = 0;
+ switch (ioarg->command) {
+
+ case RT_SET_ADDR:
+ set_rtaddr(rt, data[0]);
+ break;
+
+ case RT_SET_BCE:
+ set_broadcast_en(rt, data[0]);
+ break;
+
+ case RT_SET_VECTORW:
+ set_vector_word(rt, data[0]);
+ break;
+
+ case RT_SET_EXTMDATA:
+ set_extmdata_en(rt, data[0]);
+ break;
+
+ case RT_RX_BLOCK:
+ rt->rx_blocking = data[0];
+ break;
+
+ case RT_CLR_STATUS:
+ rt->status = 0;
+ break;
+
+ case RT_GET_STATUS: /* copy status */
+ if ( !ioarg->buffer )
+ return RTEMS_INVALID_NAME;
+
+ *(unsigned int *)ioarg->buffer = rt->status;
+ break;
+
+ case RT_SET_EVENTID:
+ rt->event_id = (rtems_id)ioarg->buffer;
+ break;
+
+ default:
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void b1553rt_interrupt(void *arg)
+{
+ rt_priv *rt = arg;
+ unsigned short descriptor;
+ int signal_event=0, wake_rx_task=0;
+ unsigned int event_status=0;
+ unsigned int wc, irqv, cmd, tsw, suba, tx, miw, i;
+ unsigned int ipend;
+
+ #define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16)
+ ipend = rt->regs->ipm;
+
+ if (ipend == 0) {
+ /* IRQ mask has been cleared, we must have been reset */
+ /* Restore ctrl registers */
+ rt->regs->ctrl = rt->ctrl_copy;
+ rt->regs->addr = rt->memarea_base_remote;
+ rt->regs->ipm = 0x70000;
+ /* Send reset mode code event */
+ if (rt->head - rt->tail != EVENT_QUEUE_SIZE) {
+ miw = (8<<11);
+ descriptor = 64 + 32 + 8;
+ rt->rt_event[INDEX(rt->head)].miw = miw;
+ rt->rt_event[INDEX(rt->head)].time = 0;
+ rt->rt_event[INDEX(rt->head)].desc = descriptor;
+ rt->head++;
+ }
+ }
+
+ if ( ipend & 0x1 ) {
+ /* RT IRQ */
+ if (rt->head - rt->tail != EVENT_QUEUE_SIZE) {
+
+ irqv = rt->regs->irq;
+ cmd = irqv >> 7;
+ wc = cmd & 0x1F; /* word count / mode code */
+ suba = irqv & 0x1F; /* sub address (0-31) */
+ tx = (irqv >> 5) & 1;
+
+ /* read status word */
+ tsw = READ_DMA(&rt->mem[tx*0x3E0+suba]);
+
+ /* Build Message Information Word (B1553BRM-style) */
+ miw = (wc<<11) | (tsw&RT_TSW_BUS)>>4 | !(tsw&RT_TSW_OK)>>7 | (tsw&RT_TSW_ILL)>>5 |
+ (tsw&RT_TSW_PAR)>>5 | (tsw&RT_TSW_MAN)>>7;
+
+ descriptor = (tx << 5) | suba;
+
+ /* Mode codes */
+ if (suba == 0 || suba == 31) {
+ descriptor = 64 + (tx*32) + wc;
+ }
+
+ /* Data received or transmitted */
+ if (descriptor < 64) {
+ wc = wc ? wc : 32; /* wc = 0 means 32 words transmitted */
+ }
+ /* RX Mode code */
+ else if (descriptor < 96) {
+ wc = (wc>>4);
+ }
+ /* TX Mode code */
+ else if (descriptor < 128) {
+ wc = (wc>>4);
+ }
+
+ /* Copy to event queue */
+ rt->rt_event[INDEX(rt->head)].miw = miw;
+ rt->rt_event[INDEX(rt->head)].time = 0;
+
+ for (i = 0; i < wc; i++) {
+ rt->rt_event[INDEX(rt->head)].data[i] = READ_DMA(&rt->mem[tx*0x400 + suba*32 + i]);
+ }
+ rt->rt_event[INDEX(rt->head)].desc = descriptor;
+ rt->head++;
+
+
+ /* Handle errors */
+ if ( tsw & RT_TSW_ILL){
+ FUNCDBG("RT: RT_ILLCMD\n\r");
+ rt->status |= RT_ILLCMD_IRQ;
+ event_status |= RT_ILLCMD_IRQ;
+ SET_ERROR_DESCRIPTOR(descriptor);
+ signal_event=1;
+ }
+
+ if ( !(tsw & RT_TSW_OK) ) {
+ FUNCDBG("RT: RT_MERR_IRQ\n\r");
+ rt->status |= RT_MERR_IRQ;
+ event_status |= RT_MERR_IRQ;
+ SET_ERROR_DESCRIPTOR(descriptor);
+ signal_event=1;
+ }
+
+ }
+ else {
+ /* Indicate overrun */
+ rt->rt_event[INDEX(rt->head)].desc |= 0x8000;
+ }
+ }
+
+ if ( ipend & 0x2 ) {
+ /* Memory failure IRQ */
+ FUNCDBG("B1553RT: Memory failure\n");
+ event_status |= RT_DMAF_IRQ;
+ signal_event=1;
+ }
+
+ if ( ipend & 0x4 ) {
+ /* AHB Error */
+ FUNCDBG("B1553RT: AHB ERROR\n");
+ event_status |= RT_DMAF_IRQ;
+ signal_event=1;
+ }
+
+#ifdef DEBUG
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = descriptor;
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = cmd;
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = miw;
+ rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = tsw;
+#endif
+
+ wake_rx_task = 1;
+
+ /* Wake any blocked rx thread only on receive interrupts */
+ if ( wake_rx_task ) {
+ rtems_semaphore_release(rt->rx_sem);
+ }
+
+ /* Copy current mask to status mask */
+ if ( event_status ) {
+ if ( event_status & 0xffff0000 )
+ rt->status &= 0x0000ffff;
+ rt->status |= event_status;
+ }
+
+ /* signal event once */
+ if ( signal_event && (rt->event_id != 0) ) {
+ rtems_event_send(rt->event_id, event_status);
+ }
+
+}
+
+void b1553rt_print_dev(struct drvmgr_dev *dev, int options)
+{
+ rt_priv *pDev = dev->priv;
+ struct amba_dev_info *devinfo;
+
+ devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+ /* Print */
+ printf("--- B1553RT[%d] %s ---\n", pDev->minor, pDev->devName);
+ printf(" REGS: 0x%x\n", (unsigned int)pDev->regs);
+ printf(" IRQ: %d\n", pDev->irqno);
+
+}
+
+void b1553rt_print(int options)
+{
+ struct amba_drv_info *drv = &b1553rt_drv_info;
+ struct drvmgr_dev *dev;
+
+ dev = drv->general.dev;
+ while(dev) {
+ b1553rt_print_dev(dev, options);
+ dev = dev->next_in_drv;
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
new file mode 100644
index 0000000000..26d7b400c3
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
@@ -0,0 +1,305 @@
+/* GR1553B driver, used by BC, RT and/or BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+
+/* Driver Manager interface for BC, RT, BM, BRM, BC-BM and RT-BM */
+
+#define GR1553B_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553B_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#define FEAT_BC 0x1
+#define FEAT_RT 0x2
+#define FEAT_BM 0x4
+
+#define ALLOC_BC 0x1
+#define ALLOC_RT 0x2
+#define ALLOC_BM 0x4
+
+struct gr1553_device {
+ struct drvmgr_dev *dev;
+ int features;
+ int alloc;
+};
+
+struct gr1553_device_feature {
+ struct gr1553_device_feature *next;
+ struct gr1553_device *dev;
+ int minor;
+};
+
+/* Device lists */
+struct gr1553_device_feature *gr1553_bm_root = NULL;
+struct gr1553_device_feature *gr1553_rt_root = NULL;
+struct gr1553_device_feature *gr1553_bc_root = NULL;
+
+/* Driver registered */
+int gr1553_driver_registerd = 0;
+
+/* Add 'feat' to linked list pointed to by 'root'. A minor is also assigned. */
+void gr1553_list_add
+ (
+ struct gr1553_device_feature **root,
+ struct gr1553_device_feature *feat
+ )
+{
+ int minor;
+ struct gr1553_device_feature *curr;
+
+ if ( *root == NULL ) {
+ *root = feat;
+ feat->next = NULL;
+ feat->minor = 0;
+ return;
+ }
+
+ minor = 0;
+retry_new_minor:
+ curr = *root;
+ while ( curr->next ) {
+ if ( curr->minor == minor ) {
+ minor++;
+ goto retry_new_minor;
+ }
+ curr = curr->next;
+ }
+
+ feat->next = NULL;
+ feat->minor = minor;
+ curr->next = feat;
+}
+
+struct gr1553_device_feature *gr1553_list_find
+ (
+ struct gr1553_device_feature *root,
+ int minor
+ )
+{
+ struct gr1553_device_feature *curr = root;
+ while ( curr ) {
+ if ( curr->minor == minor ) {
+ return curr;
+ }
+ curr = curr->next;
+ }
+ return NULL;
+}
+
+struct drvmgr_dev **gr1553_bc_open(int minor)
+{
+ struct gr1553_device_feature *feat;
+
+ feat = gr1553_list_find(gr1553_bc_root, minor);
+ if ( feat == NULL )
+ return NULL;
+
+ /* Only possible to allocate is RT and BC is free,
+ * this is beacuse it is not possible to use the
+ * RT and the BC at the same time.
+ */
+ if ( feat->dev->alloc & (ALLOC_BC|ALLOC_RT) )
+ return NULL;
+
+ /* Alloc BC device */
+ feat->dev->alloc |= ALLOC_BC;
+
+ return &feat->dev->dev;
+}
+
+void gr1553_bc_close(struct drvmgr_dev **dev)
+{
+ struct gr1553_device *d = (struct gr1553_device *)dev;
+
+ d->alloc &= ~ALLOC_BC;
+}
+
+struct drvmgr_dev **gr1553_rt_open(int minor)
+{
+ struct gr1553_device_feature *feat;
+
+ feat = gr1553_list_find(gr1553_rt_root, minor);
+ if ( feat == NULL )
+ return NULL;
+
+ /* Only possible to allocate is RT and BC is free,
+ * this is beacuse it is not possible to use the
+ * RT and the BC at the same time.
+ */
+ if ( feat->dev->alloc & (ALLOC_BC|ALLOC_RT) )
+ return NULL;
+
+ /* Alloc RT device */
+ feat->dev->alloc |= ALLOC_RT;
+
+ return &feat->dev->dev;
+}
+
+void gr1553_rt_close(struct drvmgr_dev **dev)
+{
+ struct gr1553_device *d = (struct gr1553_device *)dev;
+
+ d->alloc &= ~ALLOC_RT;
+}
+
+struct drvmgr_dev **gr1553_bm_open(int minor)
+{
+ struct gr1553_device_feature *feat;
+
+ feat = gr1553_list_find(gr1553_bm_root, minor);
+ if ( feat == NULL )
+ return NULL;
+
+ /* Only possible to allocate is RT and BC is free,
+ * this is beacuse it is not possible to use the
+ * RT and the BC at the same time.
+ */
+ if ( feat->dev->alloc & ALLOC_BM )
+ return NULL;
+
+ /* Alloc BM device */
+ feat->dev->alloc |= ALLOC_BM;
+
+ return &feat->dev->dev;
+}
+
+void gr1553_bm_close(struct drvmgr_dev **dev)
+{
+ struct gr1553_device *d = (struct gr1553_device *)dev;
+
+ d->alloc &= ~ALLOC_BM;
+}
+
+int gr1553_init2(struct drvmgr_dev *dev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ struct gr1553b_regs *regs;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ /* Stop IRQ */
+ GR1553B_WRITE_REG(&regs->imask, 0);
+ GR1553B_WRITE_REG(&regs->irq, 0xffffffff);
+ /* Stop BC if not already stopped (just in case) */
+ GR1553B_WRITE_REG(&regs->bc_ctrl, 0x15520204);
+ /* Stop RT rx (just in case) */
+ GR1553B_WRITE_REG(&regs->rt_cfg, 0x15530000);
+ /* Stop BM logging (just in case) */
+ GR1553B_WRITE_REG(&regs->bm_ctrl, 0);
+
+ return DRVMGR_OK;
+}
+
+/* Register the different functionalities that the
+ * core supports.
+ */
+int gr1553_init3(struct drvmgr_dev *dev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ struct gr1553_device *priv;
+ struct gr1553_device_feature *feat;
+ struct gr1553b_regs *regs;
+
+ priv = malloc(sizeof(struct gr1553_device));
+ if ( priv == NULL )
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+ priv->alloc = 0;
+ priv->features = 0;
+ dev->priv = NULL; /* Let higher level driver handle this */
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return DRVMGR_FAIL;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ if ( GR1553B_READ_REG(&regs->bm_stat) & GR1553B_BM_STAT_BMSUP ) {
+ priv->features |= FEAT_BM;
+ feat = malloc(sizeof(struct gr1553_device_feature));
+ feat->dev = priv;
+ /* Init Minor and Next */
+ gr1553_list_add(&gr1553_bm_root, feat);
+ }
+
+ if ( GR1553B_READ_REG(&regs->bc_stat) & GR1553B_BC_STAT_BCSUP ) {
+ priv->features |= FEAT_BC;
+ feat = malloc(sizeof(struct gr1553_device_feature));
+ feat->dev = priv;
+ /* Init Minor and Next */
+ gr1553_list_add(&gr1553_bc_root, feat);
+ }
+
+ if ( GR1553B_READ_REG(&regs->rt_stat) & GR1553B_RT_STAT_RTSUP ) {
+ priv->features |= FEAT_RT;
+ feat = malloc(sizeof(struct gr1553_device_feature));
+ feat->dev = priv;
+ /* Init Minor and Next */
+ gr1553_list_add(&gr1553_rt_root, feat);
+ }
+
+ return DRVMGR_OK;
+}
+
+struct drvmgr_drv_ops gr1553_ops =
+{
+ {NULL, gr1553_init2, gr1553_init3, NULL},
+ NULL,
+ NULL
+};
+
+struct amba_dev_id gr1553_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GR1553B},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gr1553_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GR1553B_ID,/* Driver ID */
+ "GR1553_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gr1553_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gr1553_ids[0]
+};
+
+/* Multiple drivers may call this function. The drivers that depends on
+ * this driver:
+ * - BM driver
+ * - BC driver
+ * - RT driver
+ */
+void gr1553_register(void)
+{
+ if ( gr1553_driver_registerd == 0 ) {
+ gr1553_driver_registerd = 1;
+ drvmgr_drv_register(&gr1553_drv_info.general);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
new file mode 100644
index 0000000000..4133200709
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
@@ -0,0 +1,1674 @@
+/* GR1553B BC driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+#include <gr1553bc.h>
+
+#define GR1553BC_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
+#define GR1553BC_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553BC_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
+#define GR1553BC_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* Needed by list for data pinter and BD translation */
+struct gr1553bc_priv {
+ struct drvmgr_dev **pdev;
+ struct gr1553b_regs *regs;
+ struct gr1553bc_list *list;
+ struct gr1553bc_list *alist;
+ int started;
+
+ /* IRQ log management */
+ void *irq_log_p;
+ uint32_t *irq_log_base;
+ uint32_t *irq_log_curr;
+ uint32_t *irq_log_end;
+ uint32_t *irq_log_base_hw;
+
+ /* Standard IRQ handler function */
+ bcirq_func_t irq_func;
+ void *irq_data;
+};
+
+
+/*************** LIST HANDLING ROUTINES ***************/
+
+/* This marks that the jump is a jump to next Minor.
+ * It is important that it sets one of the two LSB
+ * so that we can separate it from a JUMP-IRQ function,
+ * function pointers must be aligned to 4bytes.
+ *
+ * This marker is used to optimize the INDICATION process,
+ * from a descriptor pointer we can step to next Jump that
+ * has this MARKER set, then we know that the MID is stored
+ * there.
+ *
+ * The marker is limited to 1 byte.
+ */
+#define NEXT_MINOR_MARKER 0x01
+
+/* To separate ASYNC list from SYNC list we mark them differently, but with
+ * LSB always set. This can be used to get the list the descriptor is a part
+ * of.
+ */
+#define NEXT_MINOR_MARKER_ASYNC 0x80
+
+struct gr1553bc_list_cfg gr1553bc_def_cfg =
+{
+ .rt_timeout =
+ {
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20, 20,
+ 20, 20, 20
+ },
+ .bc_timeout = 30,
+ .tropt_irq_on_err = 0,
+ .tropt_pause_on_err = 0,
+ .async_list = 0,
+};
+
+int gr1553bc_list_alloc(struct gr1553bc_list **list, int max_major)
+{
+ int size;
+ struct gr1553bc_list *l;
+
+ size = sizeof(struct gr1553bc_list) + max_major * sizeof(void *);
+ l = malloc(size);
+ if ( l == NULL )
+ return -1;
+ memset(l, 0, size);
+
+ l->major_cnt = max_major;
+ *list = l;
+
+ /* Set default options:
+ * - RT timeout tolerance 20us
+ * - Global transfer options used when generating transfer descriptors
+ * - No BC device, note that this only works when no translation is
+ * required
+ */
+ if ( gr1553bc_list_config(l, &gr1553bc_def_cfg, NULL) ) {
+ free(l);
+ return -1;
+ }
+
+ return 0;
+}
+
+void gr1553bc_list_free(struct gr1553bc_list *list)
+{
+ gr1553bc_list_table_free(list);
+ free(list);
+}
+
+int gr1553bc_list_config
+ (
+ struct gr1553bc_list *list,
+ struct gr1553bc_list_cfg *cfg,
+ void *bc
+ )
+{
+ int timeout, i, tropts;
+
+ /* RT Time Tolerances */
+ for (i=0; i<31; i++) {
+ /* 0=14us, 1=18us ... 0xf=74us
+ * round upwards: 15us will be 18us
+ */
+ timeout = ((cfg->rt_timeout[i] + 1) - 14) / 4;
+ if ( (timeout > 0xf) || (timeout < 0) )
+ return -1;
+ list->rt_timeout[i] = timeout;
+ }
+ timeout = ((cfg->bc_timeout + 1) - 14) / 4;
+ if ( timeout > 0xf )
+ return -1;
+ list->rt_timeout[i] = timeout;
+
+ /* Transfer descriptor generation options */
+ tropts = 0;
+ if ( cfg->tropt_irq_on_err )
+ tropts |= 1<<28;
+ if ( cfg->tropt_pause_on_err )
+ tropts |= 1<<26;
+ list->tropts = tropts;
+
+ list->async_list = cfg->async_list;
+ list->bc = bc;
+
+ return 0;
+}
+
+void gr1553bc_list_link_major(
+ struct gr1553bc_major *major,
+ struct gr1553bc_major *next
+ )
+{
+ if ( major ) {
+ major->next = next;
+ if ( next ) {
+ major->minors[major->cfg->minor_cnt-1]->next =
+ next->minors[0];
+ } else {
+ major->minors[major->cfg->minor_cnt-1]->next = NULL;
+ }
+ }
+}
+
+int gr1553bc_list_set_major(
+ struct gr1553bc_list *list,
+ struct gr1553bc_major *major,
+ int no)
+{
+ struct gr1553bc_major *prev, *next;
+
+ if ( no >= list->major_cnt )
+ return -1;
+
+ list->majors[no] = major;
+
+ /* Link previous Major frame with this one */
+ if ( no > 0 ) {
+ prev = list->majors[no-1];
+ } else {
+ /* First Major is linked with last major */
+ prev = list->majors[list->major_cnt-1];
+ }
+
+ /* Link to next Major if not the last one and if there is
+ * a next major
+ */
+ if ( no == list->major_cnt-1 ) {
+ /* The last major, assume that it is connected with the first */
+ next = list->majors[0];
+ } else {
+ next = list->majors[no+1];
+ }
+
+ /* Link previous frame to jump into this */
+ gr1553bc_list_link_major(prev, major);
+
+ /* Link This frame to jump into the next */
+ gr1553bc_list_link_major(major, next);
+
+ return 0;
+}
+
+/* Translate Descriptor address from CPU-address to Hardware Address */
+static inline union gr1553bc_bd *gr1553bc_bd_cpu2hw
+ (
+ struct gr1553bc_list *list,
+ union gr1553bc_bd *bd
+ )
+{
+ return (union gr1553bc_bd *)(((unsigned int)bd - list->table_cpu) +
+ list->table_hw);
+}
+
+/* Translate Descriptor address from HW-address to CPU Address */
+static inline union gr1553bc_bd *gr1553bc_bd_hw2cpu
+ (
+ struct gr1553bc_list *list,
+ union gr1553bc_bd *bd
+ )
+{
+ return (union gr1553bc_bd *)(((unsigned int)bd - list->table_hw) +
+ list->table_cpu);
+}
+
+int gr1553bc_minor_table_size(struct gr1553bc_minor *minor)
+{
+ struct gr1553bc_minor_cfg *mincfg = minor->cfg;
+ int slot_cnt;
+
+ /* SLOTS + JUMP */
+ slot_cnt = mincfg->slot_cnt + 1;
+ if ( mincfg->timeslot ) {
+ /* time management requires 1 extra slot */
+ slot_cnt++;
+ }
+
+ return slot_cnt * GR1553BC_BD_SIZE;
+}
+
+int gr1553bc_list_table_size(struct gr1553bc_list *list)
+{
+ struct gr1553bc_major *major;
+ int i, j, minor_cnt, size;
+
+ size = 0;
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ for (j=0; j<minor_cnt; j++) {
+ /* 128-bit Alignment required by HW */
+ size += (GR1553BC_BD_ALIGN -
+ (size & (GR1553BC_BD_ALIGN-1))) &
+ ~(GR1553BC_BD_ALIGN-1);
+
+ /* Size required by descriptors */
+ size += gr1553bc_minor_table_size(major->minors[j]);
+ }
+ }
+
+ return size;
+}
+
+int gr1553bc_list_table_alloc
+ (
+ struct gr1553bc_list *list,
+ void *bdtab_custom
+ )
+{
+ struct gr1553bc_major *major;
+ int i, j, minor_cnt, size;
+ unsigned int table;
+ struct gr1553bc_priv *bcpriv = list->bc;
+
+ /* Free previous allocated descriptor table */
+ gr1553bc_list_table_free(list);
+
+ /* Remember user's settings for uninitialization */
+ list->_table_custom = bdtab_custom;
+
+ /* Get Size required for descriptors */
+ size = gr1553bc_list_table_size(list);
+
+ if ((unsigned int)bdtab_custom & 0x1) {
+ /* Address given in Hardware accessible address, we
+ * convert it into CPU-accessible address.
+ */
+ list->table_hw = (unsigned int)bdtab_custom & ~0x1;
+ list->_table = bdtab_custom;
+ drvmgr_translate_check(
+ *bcpriv->pdev,
+ DMAMEM_TO_CPU,
+ (void *)list->table_hw,
+ (void **)&list->table_cpu,
+ size);
+ } else {
+ if (bdtab_custom == NULL) {
+ /* Allocate descriptors */
+ list->_table = malloc(size + (GR1553BC_BD_ALIGN-1));
+ if ( list->_table == NULL )
+ return -1;
+ } else {
+ /* Custom address, given in CPU-accessible address */
+ list->_table = bdtab_custom;
+ }
+ /* 128-bit Alignment required by HW */
+ list->table_cpu =
+ (((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
+ ~(GR1553BC_BD_ALIGN-1));
+
+ /* We got CPU accessible descriptor table address, now we
+ * translate that into an address that the Hardware can
+ * understand
+ */
+ if (bcpriv) {
+ drvmgr_translate_check(
+ *bcpriv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)list->table_cpu,
+ (void **)&list->table_hw,
+ size
+ );
+ } else {
+ list->table_hw = list->table_cpu;
+ }
+ }
+
+ /* Write End-Of-List all over the descriptor table here,
+ * For debugging/safety?
+ */
+
+ /* Assign descriptors to all minor frames. The addresses is
+ * CPU-accessible addresses.
+ */
+ table = list->table_cpu;
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ for (j=0; j<minor_cnt; j++) {
+ /* 128-bit Alignment required by HW */
+ table = (table + (GR1553BC_BD_ALIGN-1)) &
+ ~(GR1553BC_BD_ALIGN-1);
+ major->minors[j]->bds = (union gr1553bc_bd *)table;
+
+ /* Calc size required by descriptors */
+ table += gr1553bc_minor_table_size(major->minors[j]);
+ }
+ }
+
+ return 0;
+}
+
+void gr1553bc_list_table_free(struct gr1553bc_list *list)
+{
+ if ( (list->_table_custom == NULL) && list->_table ) {
+ free(list->_table);
+ }
+ list->_table = NULL;
+ list->_table_custom = NULL;
+ list->table_cpu = 0;
+ list->table_hw = 0;
+}
+
+/* Init descriptor table provided by each minor frame,
+ * we link them together using unconditional JUMP.
+ */
+int gr1553bc_list_table_build(struct gr1553bc_list *list)
+{
+ struct gr1553bc_major *major;
+ struct gr1553bc_minor *minor;
+ struct gr1553bc_minor_cfg *mincfg;
+ int i, j, k, minor_cnt, marker;
+ union gr1553bc_bd *bds, *hwbd;
+
+ marker = NEXT_MINOR_MARKER;
+ if ( list->async_list )
+ marker |= NEXT_MINOR_MARKER_ASYNC;
+
+ /* Create Major linking */
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ for (j=0; j<minor_cnt; j++) {
+ minor = major->minors[j];
+ mincfg = minor->cfg;
+ bds = minor->bds;
+
+ /* BD[0..SLOTCNT-1] = message slots
+ * BD[SLOTCNT+0] = END
+ * BD[SLOTCNT+1] = JUMP
+ *
+ * or if no optional time slot handling:
+ *
+ * BD[0..SLOTCNT-1] = message slots
+ * BD[SLOTCNT] = JUMP
+ */
+
+ /* BD[0..SLOTCNT-1] */
+ for (k=0; k<mincfg->slot_cnt; k++) {
+ gr1553bc_bd_tr_init(
+ &bds[k].tr,
+ GR1553BC_TR_DUMMY_0,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+ }
+
+ /* BD[SLOTCNT] (OPTIONAL)
+ * If a minor frame is configured to be executed in
+ * certain time (given a time slot), this descriptor
+ * sums up all unused time. The time slot is
+ * decremented when messages are inserted into the
+ * minor frame and increased when messages are removed.
+ */
+ if ( mincfg->timeslot > 0 ) {
+ gr1553bc_bd_tr_init(
+ &bds[k].tr,
+ GR1553BC_TR_DUMMY_0 | (mincfg->timeslot >> 2),
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+ k++;
+ }
+
+ /* Last descriptor is a jump to next minor frame, to a
+ * synchronization point. If chain ends here, the list
+ * is marked with a "end-of-list" marker.
+ *
+ */
+ if ( minor->next ) {
+ /* Translate CPU address of BD into HW address */
+ hwbd = gr1553bc_bd_cpu2hw(
+ list,
+ &minor->next->bds[0]
+ );
+ gr1553bc_bd_init(
+ &bds[k],
+ 0xf,
+ GR1553BC_UNCOND_JMP,
+ (uint32_t)hwbd,
+ ((GR1553BC_ID(i,j,k) << 8) | marker),
+ 0
+ );
+ } else {
+ gr1553bc_bd_init(
+ &bds[k],
+ 0xf,
+ GR1553BC_TR_EOL,
+ 0,
+ ((GR1553BC_ID(i,j,k) << 8) | marker),
+ 0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void gr1553bc_bd_init(
+ union gr1553bc_bd *bd,
+ unsigned int flags,
+ uint32_t word0,
+ uint32_t word1,
+ uint32_t word2,
+ uint32_t word3
+ )
+{
+ struct gr1553bc_bd_raw *raw = &bd->raw;
+
+ if ( flags & 0x1 ) {
+ if ( (flags & KEEP_TIMESLOT) &&
+ ((word0 & GR1553BC_BD_TYPE) == 0) ) {
+ /* Don't touch timeslot previously allocated */
+ word0 &= ~GR1553BC_TR_TIME;
+ word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
+ GR1553BC_TR_TIME;
+ }
+ GR1553BC_WRITE_MEM(&raw->words[0], word0);
+ }
+ if ( flags & 0x2 )
+ GR1553BC_WRITE_MEM(&raw->words[1], word1);
+ if ( flags & 0x4 )
+ GR1553BC_WRITE_MEM(&raw->words[2], word2);
+ if ( flags & 0x8 )
+ GR1553BC_WRITE_MEM(&raw->words[3], word3);
+}
+
+/* Alloc a Major frame according to the configuration structure */
+int gr1553bc_major_alloc_skel
+ (
+ struct gr1553bc_major **major,
+ struct gr1553bc_major_cfg *cfg
+ )
+{
+ struct gr1553bc_major *maj;
+ struct gr1553bc_minor *minor;
+ int size, i;
+
+ if ( (cfg == NULL) || (major == NULL) || (cfg->minor_cnt <= 0) )
+ return -1;
+
+ /* Allocate Major Frame description, but no descriptors */
+ size = sizeof(struct gr1553bc_major) + cfg->minor_cnt *
+ (sizeof(struct gr1553bc_minor) + sizeof(void *));
+ maj = (struct gr1553bc_major *)malloc(size);
+ if ( maj == NULL )
+ return -1;
+
+ maj->cfg = cfg;
+ maj->next = NULL;
+
+ /* Create links between minor frames, and from minor frames
+ * to configuration structure.
+ */
+ minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
+ for (i=0; i<cfg->minor_cnt; i++, minor++) {
+ maj->minors[i] = minor;
+ minor->next = minor + 1;
+ minor->cfg = &cfg->minor_cfgs[i];
+ minor->alloc = 0;
+ minor->bds = NULL;
+ }
+ /* last Minor should point to next Major frame's first minor,
+ * we do that somewhere else.
+ */
+ (minor - 1)->next = NULL;
+
+ *major = maj;
+
+ return 0;
+}
+
+struct gr1553bc_major *gr1553bc_major_from_id
+ (
+ struct gr1553bc_list *list,
+ int mid
+ )
+{
+ int major_no;
+
+ /* Find Minor Frame from MID */
+ major_no = GR1553BC_MAJID_FROM_ID(mid);
+
+ if ( major_no >= list->major_cnt )
+ return NULL;
+ return list->majors[major_no];
+}
+
+struct gr1553bc_minor *gr1553bc_minor_from_id
+ (
+ struct gr1553bc_list *list,
+ int mid
+ )
+{
+ int minor_no;
+ struct gr1553bc_major *major;
+
+ /* Get Major from ID */
+ major = gr1553bc_major_from_id(list, mid);
+ if ( major == NULL )
+ return NULL;
+
+ /* Find Minor Frame from MID */
+ minor_no = GR1553BC_MINID_FROM_ID(mid);
+
+ if ( minor_no >= major->cfg->minor_cnt )
+ return NULL;
+ return major->minors[minor_no];
+}
+
+union gr1553bc_bd *gr1553bc_slot_bd
+ (
+ struct gr1553bc_list *list,
+ int mid
+ )
+{
+ struct gr1553bc_minor *minor;
+ int slot_no;
+
+ /*** look up BD ***/
+
+ /* Get minor */
+ minor = gr1553bc_minor_from_id(list, mid);
+ if ( minor == NULL )
+ return NULL;
+
+ /* Get Slot */
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+ if ( slot_no >= 0xff )
+ slot_no = 0;
+
+ /* Get BD address */
+ return &minor->bds[slot_no];
+}
+
+int gr1553bc_minor_first_avail(struct gr1553bc_minor *minor)
+{
+ int slot_num;
+ uint32_t alloc;
+
+ alloc = minor->alloc;
+ if ( alloc == 0xffffffff ) {
+ /* No free */
+ return -1;
+ }
+ slot_num = 0;
+ while ( alloc & 1 ) {
+ alloc = alloc >> 1;
+ slot_num++;
+ }
+ if ( slot_num >= minor->cfg->slot_cnt ) {
+ /* no free */
+ return -1;
+ }
+ return slot_num;
+}
+
+int gr1553bc_slot_alloc(
+ struct gr1553bc_list *list,
+ int *mid,
+ int timeslot,
+ union gr1553bc_bd **bd
+ )
+{
+ struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, *mid);
+
+ return gr1553bc_slot_alloc2(minor, mid, timeslot, bd);
+}
+
+/* Same as gr1553bc_slot_alloc but identifies a minor instead of list.
+ * The major/minor part of MID is ignored.
+ */
+int gr1553bc_slot_alloc2(
+ struct gr1553bc_minor *minor,
+ int *mid,
+ int timeslot,
+ union gr1553bc_bd **bd
+ )
+{
+ int slot_no;
+ uint32_t set0;
+ int timefree;
+ struct gr1553bc_bd_tr *trbd;
+ struct gr1553bc_minor_cfg *mincfg;
+
+ if ( minor == NULL )
+ return -1;
+
+ mincfg = minor->cfg;
+
+ /* Find first free slot if not a certain slot is requested */
+ slot_no = GR1553BC_SLOTID_FROM_ID(*mid);
+ if ( slot_no == 0xff ) {
+ slot_no = gr1553bc_minor_first_avail(minor);
+ if ( slot_no < 0 )
+ return -1;
+ } else {
+ /* Allocate a certain slot, check that it is free */
+ if ( slot_no >= mincfg->slot_cnt )
+ return -1;
+ if ( (1<<slot_no) & minor->alloc )
+ return -1;
+ }
+
+ /* Ok, we got our slot. Lets allocate time for slot if requested by user
+ * and time management is enabled for this Minor Frame.
+ */
+ if ( timeslot > 0 ) {
+ /* Make timeslot on a 4us boundary (time resolution of core) */
+ timeslot = (timeslot + 0x3) >> 2;
+
+ if ( mincfg->timeslot ) {
+ /* Subtract requested time from free time */
+ trbd = &minor->bds[mincfg->slot_cnt].tr;
+ set0 = GR1553BC_READ_MEM(&trbd->settings[0]);
+ timefree = set0 & GR1553BC_TR_TIME;
+ if ( timefree < timeslot ) {
+ /* Not enough time left to schedule slot in minor */
+ return -1;
+ }
+ /* Store back the time left */
+ timefree -= timeslot;
+ set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
+ GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
+ /* Note: at the moment the minor frame can be executed faster
+ * than expected, we hurry up writing requested
+ * descriptor.
+ */
+ }
+ }
+
+ /* Make the allocated descriptor be an empty slot with the
+ * timeslot requested.
+ */
+ trbd = &minor->bds[slot_no].tr;
+ gr1553bc_bd_tr_init(
+ trbd,
+ GR1553BC_TR_DUMMY_0 | timeslot,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+
+ /* Allocate slot */
+ minor->alloc |= 1<<slot_no;
+
+ if ( bd )
+ *bd = (union gr1553bc_bd *)trbd;
+ *mid = GR1553BC_ID_SET_SLOT(*mid, slot_no);
+
+ return 0;
+}
+
+/* Return time slot freed (if time is managed by driver), negative on error */
+int gr1553bc_slot_free(struct gr1553bc_list *list, int mid)
+{
+ struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
+
+ return gr1553bc_slot_free2(minor, mid);
+}
+
+/* Return time slot freed (if time is managed by driver), negative on error */
+int gr1553bc_slot_free2(struct gr1553bc_minor *minor, int mid)
+{
+ union gr1553bc_bd *bd;
+ struct gr1553bc_bd_tr *endbd;
+ struct gr1553bc_minor_cfg *mincfg;
+ int slot_no, timeslot, timefree;
+ uint32_t word0, set0;
+
+ if ( minor == NULL )
+ return -1;
+
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+
+ if ( (minor->alloc & (1<<slot_no)) == 0 )
+ return -1;
+
+ bd = &minor->bds[slot_no];
+
+ /* If the driver handles time for this minor frame, return
+ * time if previuosly requested.
+ */
+ timeslot = 0;
+ mincfg = minor->cfg;
+ if ( mincfg->timeslot > 0 ) {
+ /* Find out if message slot had time allocated */
+ word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+ if ( word0 & GR1553BC_BD_TYPE ) {
+ /* Condition ==> no time slot allocated */
+ } else {
+ /* Transfer descriptor, may have time slot */
+ timeslot = word0 & GR1553BC_TR_TIME;
+ if ( timeslot > 0 ) {
+ /* Return previously allocated time to END
+ * TIME descriptor.
+ */
+ endbd = &minor->bds[mincfg->slot_cnt].tr;
+ set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
+ timefree = set0 & GR1553BC_TR_TIME;
+ timefree += timeslot;
+ set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
+ GR1553BC_WRITE_MEM(&endbd->settings[0], set0);
+ /* Note: at the moment the minor frame can be
+ * executed slower than expected, the
+ * timeslot is at two locations.
+ */
+ }
+ }
+ }
+
+ /* Make slot an empty message */
+ gr1553bc_bd_tr_init(
+ &bd->tr,
+ GR1553BC_TR_DUMMY_0,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+
+ /* unallocate descriptor */
+ minor->alloc &= ~(1<<slot_no);
+
+ /* Return time freed in microseconds */
+ return timeslot << 2;
+}
+
+int gr1553bc_list_freetime(struct gr1553bc_list *list, int mid)
+{
+ struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
+
+ return gr1553bc_minor_freetime(minor);
+}
+
+int gr1553bc_minor_freetime(struct gr1553bc_minor *minor)
+{
+ struct gr1553bc_bd_tr *endbd;
+ struct gr1553bc_minor_cfg *mincfg;
+ int timefree;
+ uint32_t set0;
+
+ if ( minor == NULL )
+ return -1;
+
+ /* If the driver handles time for this minor frame, return
+ * time if previuosly requested.
+ */
+ timefree = 0;
+ mincfg = minor->cfg;
+ if ( mincfg->timeslot > 0 ) {
+ /* Return previously allocated time to END
+ * TIME descriptor.
+ */
+ endbd = &minor->bds[mincfg->slot_cnt].tr;
+ set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
+ timefree = (set0 & GR1553BC_TR_TIME) << 2;
+ }
+
+ /* Return time freed */
+ return timefree;
+}
+
+int gr1553bc_slot_raw
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ unsigned int flags,
+ uint32_t word0,
+ uint32_t word1,
+ uint32_t word2,
+ uint32_t word3
+ )
+{
+ struct gr1553bc_minor *minor;
+ union gr1553bc_bd *bd;
+ int slot_no;
+
+ minor = gr1553bc_minor_from_id(list, mid);
+ if ( minor == NULL )
+ return -1;
+
+ /* Get Slot */
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+ if ( slot_no >= minor->cfg->slot_cnt ) {
+ return -1;
+ }
+
+ /* Get descriptor */
+ bd = &minor->bds[slot_no];
+
+ /* Build empty descriptor. */
+ gr1553bc_bd_init(
+ bd,
+ flags,
+ word0,
+ word1,
+ word2,
+ word3);
+
+ return 0;
+}
+
+/* Create unconditional IRQ customly defined location
+ * The IRQ is disabled, enable it with gr1553bc_slot_irq_enable().
+ */
+int gr1553bc_slot_irq_prepare
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ bcirq_func_t func,
+ void *data
+ )
+{
+ union gr1553bc_bd *bd;
+ int slot_no, to_mid;
+
+ /* Build unconditional IRQ descriptor. The padding is used
+ * for identifying the MINOR frame and function and custom data.
+ *
+ * The IRQ is disabled at first, a unconditional jump to next
+ * descriptor in table.
+ */
+
+ /* Get BD address of jump destination */
+ slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+ to_mid = GR1553BC_ID_SET_SLOT(mid, slot_no + 1);
+ bd = gr1553bc_slot_bd(list, to_mid);
+ if ( bd == NULL )
+ return -1;
+ bd = gr1553bc_bd_cpu2hw(list, bd);
+
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF,
+ GR1553BC_UNCOND_JMP,
+ (uint32_t)bd,
+ (uint32_t)func,
+ (uint32_t)data
+ );
+}
+
+/* Enable previously prepared unconditional IRQ */
+int gr1553bc_slot_irq_enable(struct gr1553bc_list *list, int mid)
+{
+ /* Leave word1..3 untouched:
+ * 1. Unconditional Jump address
+ * 2. Function
+ * 3. Custom Data
+ *
+ * Since only one bit is changed in word0 (Condition word),
+ * no hardware/software races will exist ==> it is safe
+ * to enable/disable IRQ at any time independent of where
+ * hardware is in table.
+ */
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0x1, /* change only WORD0 */
+ GR1553BC_UNCOND_IRQ,
+ 0,
+ 0,
+ 0);
+}
+
+/* Disable unconditional IRQ point, changed to unconditional JUMP
+ * to descriptor following.
+ * After disabling it it can be enabled again, or freed.
+ */
+int gr1553bc_slot_irq_disable(struct gr1553bc_list *list, int mid)
+{
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0x1, /* change only WORD0, JUMP address already set */
+ GR1553BC_UNCOND_JMP,
+ 0,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_empty(struct gr1553bc_list *list, int mid)
+{
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF | KEEP_TIMESLOT,
+ GR1553BC_TR_DUMMY_0,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_exttrig(struct gr1553bc_list *list, int mid)
+{
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF | KEEP_TIMESLOT,
+ GR1553BC_TR_DUMMY_0 | GR1553BC_TR_EXTTRIG,
+ GR1553BC_TR_DUMMY_1,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_jump
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ uint32_t condition,
+ int to_mid
+ )
+{
+ union gr1553bc_bd *bd;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, to_mid);
+ if ( bd == NULL )
+ return -1;
+ /* Convert into an address that the HW understand */
+ bd = gr1553bc_bd_cpu2hw(list, bd);
+
+ return gr1553bc_slot_raw(
+ list,
+ mid,
+ 0xF,
+ condition,
+ (uint32_t)bd,
+ 0,
+ 0);
+}
+
+int gr1553bc_slot_transfer(
+ struct gr1553bc_list *list,
+ int mid,
+ int options,
+ int tt,
+ uint16_t *dptr)
+{
+ uint32_t set0, set1;
+ union gr1553bc_bd *bd;
+ int rx_rtadr, tx_rtadr, timeout;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, mid);
+ if ( bd == NULL )
+ return -1;
+
+ /* Translate Data pointer from CPU-local to 1553-core accessible
+ * address if user wants that. This may be useful for AMBA-over-PCI
+ * cores.
+ */
+ if ( (unsigned int)dptr & 0x1 ) {
+ struct gr1553bc_priv *bcpriv = list->bc;
+
+ drvmgr_translate(
+ *bcpriv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)((unsigned int)dptr & ~0x1),
+ (void **)&dptr);
+ }
+
+ /* It is assumed that the descriptor has already been initialized
+ * as a empty slot (Dummy bit set), so to avoid races the dummy
+ * bit is cleared last.
+ *
+ * If we knew that the write would do a burst (for example over SpW)
+ * it would be safe to write in order.
+ */
+
+ /* Preserve timeslot */
+ set0 = GR1553BC_READ_MEM(&bd->tr.settings[0]);
+ set0 &= GR1553BC_TR_TIME;
+ set0 |= options & 0x61f00000;
+ set0 |= list->tropts; /* Global options */
+
+ /* Set transfer type, bus and let RT tolerance table descide
+ * responce tolerance.
+ *
+ * If a destination address is specified the longest timeout
+ * tolerance is taken.
+ */
+ rx_rtadr = (tt >> 22) & 0x1f;
+ tx_rtadr = (tt >> 12) & 0x1f;
+ if ( (tx_rtadr != 0x1f) &&
+ (list->rt_timeout[rx_rtadr] < list->rt_timeout[tx_rtadr]) ) {
+ timeout = list->rt_timeout[tx_rtadr];
+ } else {
+ timeout = list->rt_timeout[rx_rtadr];
+ }
+ set1 = ((timeout & 0xf) << 27) | (tt & 0x27ffffff) | ((options & 0x3)<<30);
+
+ GR1553BC_WRITE_MEM(&bd->tr.settings[0], set0);
+ GR1553BC_WRITE_MEM(&bd->tr.dptr, (uint32_t)dptr);
+ /* Write UNUSED BIT, when cleared it Indicates that BC has written it */
+ GR1553BC_WRITE_MEM(&bd->tr.status, 0x80000000);
+ GR1553BC_WRITE_MEM(&bd->tr.settings[1], set1);
+
+ return 0;
+}
+
+int gr1553bc_slot_update
+ (
+ struct gr1553bc_list *list,
+ int mid,
+ uint16_t *dptr,
+ unsigned int *stat
+ )
+{
+ union gr1553bc_bd *bd;
+ unsigned int status;
+ unsigned int dataptr = (unsigned int)dptr;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, mid);
+ if ( bd == NULL )
+ return -1;
+
+ /* Write new Data Pointer if needed */
+ if ( dataptr ) {
+ struct gr1553bc_priv *bcpriv = list->bc;
+
+ /* Translate Data pointer from CPU-local to 1553-core accessible
+ * address if user wants that. This may be useful for AMBA-over-PCI
+ * cores.
+ */
+ if ( dataptr & 0x1 ) {
+ drvmgr_translate(
+ *bcpriv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)(dataptr & ~0x1),
+ (void **)&dptr
+ );
+ }
+
+ /* Update Data Pointer */
+ GR1553BC_WRITE_MEM(&bd->tr.dptr, dataptr);
+ }
+
+ /* Get status of transfer descriptor */
+ if ( stat ) {
+ status = *stat;
+ *stat = GR1553BC_READ_MEM(&bd->tr.status);
+ if ( status ) {
+ /* Clear status fields user selects, then
+ * or bit31 if user wants that. The bit31
+ * may be used to indicate if the BC has
+ * performed the access.
+ */
+ status = (*stat & (status & 0xffffff)) |
+ (status & (1<<31));
+ GR1553BC_WRITE_MEM(&bd->tr.status, status);
+ }
+ }
+
+ return 0;
+}
+
+int gr1553bc_slot_dummy(
+ struct gr1553bc_list *list,
+ int mid,
+ unsigned int *dummy)
+{
+ union gr1553bc_bd *bd;
+ unsigned int set1, new_set1;
+
+ /* Get BD address */
+ bd = gr1553bc_slot_bd(list, mid);
+ if ( bd == NULL )
+ return -1;
+ /* Update the Dummy Bit */
+ set1 = GR1553BC_READ_MEM(&bd->tr.settings[1]);
+ new_set1 = (set1 & ~GR1553BC_TR_DUMMY_1) | (*dummy & GR1553BC_TR_DUMMY_1);
+ GR1553BC_WRITE_MEM(&bd->tr.settings[1], new_set1);
+
+ *dummy = set1;
+
+ return 0;
+}
+
+/* Find MID from Descriptor pointer */
+int gr1553bc_mid_from_bd(
+ union gr1553bc_bd *bd,
+ int *mid,
+ int *async
+ )
+{
+ int i, bdmid, slot_no;
+ uint32_t word0, word2;
+
+ /* Find Jump to next Minor Frame or End-Of-List,
+ * at those locations we have stored a MID
+ *
+ * GR1553BC_SLOT_MAX+2 = Worst case, BD is max distance from jump
+ * descriptor. 2=END and Jump descriptors.
+ */
+ for (i=0; i<GR1553BC_SLOT_MAX+2; i++) {
+ word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+ if ( word0 & GR1553BC_BD_TYPE ) {
+ if ( word0 == GR1553BC_UNCOND_JMP ) {
+ /* May be a unconditional IRQ set by user. In
+ * that case the function is stored in WORD3,
+ * functions must be aligned to 4 byte boudary.
+ */
+ word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+ if ( word2 & NEXT_MINOR_MARKER ) {
+ goto found_mid;
+ }
+ } else if ( word0 == GR1553BC_TR_EOL ) {
+ /* End-Of-List, does contain a MID */
+ word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+ goto found_mid;
+ }
+ }
+ bd++;
+ }
+
+ return -1;
+
+found_mid:
+ /* Get MID of JUMP descriptor */
+ bdmid = word2 >> 8;
+ /* Subtract distance from JUMP descriptor to find MID
+ * of requested BD.
+ */
+ slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
+ slot_no -= i;
+ bdmid = GR1553BC_ID_SET_SLOT(bdmid, slot_no);
+
+ if ( mid )
+ *mid = bdmid;
+
+ /* Determine which list BD belongs to: async or sync */
+ if ( async )
+ *async = word2 & NEXT_MINOR_MARKER_ASYNC;
+
+ return 0;
+}
+
+/*************** END OF LIST HANDLING ROUTINES ***************/
+
+/*************** DEVICE HANDLING ROUTINES ***************/
+
+void gr1553bc_device_init(struct gr1553bc_priv *priv);
+void gr1553bc_device_uninit(struct gr1553bc_priv *priv);
+void gr1553bc_isr(void *data);
+
+/*** GR1553BC driver ***/
+
+void gr1553bc_register(void)
+{
+ /* The BC driver rely on the GR1553B Driver */
+ gr1553_register();
+}
+
+void gr1553bc_isr_std(union gr1553bc_bd *bd, void *data)
+{
+ /* Do nothing */
+}
+
+/* Take a GR1553BC hardware device identified by minor.
+ * A pointer is returned that is used internally by the GR1553BC
+ * driver, it is used as an input paramter 'bc' to all other
+ * functions that manipulate the hardware.
+ */
+void *gr1553bc_open(int minor)
+{
+ struct drvmgr_dev **pdev = NULL;
+ struct gr1553bc_priv *priv = NULL;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ void *irq_log_p = NULL;
+
+ /* Allocate requested device */
+ pdev = gr1553_bc_open(minor);
+ if ( pdev == NULL )
+ goto fail;
+
+ irq_log_p = malloc(GR1553BC_IRQLOG_SIZE*2);
+ if ( irq_log_p == NULL )
+ goto fail;
+
+ priv = malloc(sizeof(struct gr1553bc_priv));
+ if ( priv == NULL )
+ goto fail;
+ memset(priv, 0, sizeof(struct gr1553bc_priv));
+
+ /* Init BC device */
+ priv->pdev = pdev;
+ (*pdev)->priv = priv;
+ priv->irq_log_p = irq_log_p;
+ priv->started = 0;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ gr1553bc_device_init(priv);
+
+ /* Register ISR handler (unmask at IRQ controller) */
+ if ( drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bc",
+ gr1553bc_isr, priv) ) {
+ goto fail;
+ }
+
+ return priv;
+
+fail:
+ if ( pdev )
+ gr1553_bc_close(pdev);
+ if ( irq_log_p )
+ free(irq_log_p);
+ if ( priv )
+ free(priv);
+ return NULL;
+}
+
+void gr1553bc_close(void *bc)
+{
+ struct gr1553bc_priv *priv = bc;
+
+ /* Stop Hardware */
+ gr1553bc_stop(bc, 0x3);
+
+ gr1553bc_device_uninit(priv);
+
+ /* Remove interrupt handler (mask IRQ at IRQ controller) */
+ drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bc_isr, priv);
+
+ /* Free device */
+ gr1553_bc_close(priv->pdev);
+ free(priv->irq_log_p);
+ free(priv);
+}
+
+/* Return Current Minor frame number */
+int gr1553bc_indication(void *bc, int async, int *mid)
+{
+ struct gr1553bc_priv *priv = bc;
+ union gr1553bc_bd *bd;
+
+ /* Get current descriptor pointer */
+ if ( async ) {
+ bd = (union gr1553bc_bd *)
+ GR1553BC_READ_REG(&priv->regs->bc_aslot);
+ bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
+ } else {
+ bd = (union gr1553bc_bd *)
+ GR1553BC_READ_REG(&priv->regs->bc_slot);
+ bd = gr1553bc_bd_hw2cpu(priv->list, bd);
+ }
+
+ return gr1553bc_mid_from_bd(bd, mid, NULL);
+}
+
+/* Start major frame processing, wait for TimerManager tick or start directly */
+int gr1553bc_start(void *bc, struct gr1553bc_list *list, struct gr1553bc_list *list_async)
+{
+ struct gr1553bc_priv *priv = bc;
+ union gr1553bc_bd *bd = NULL, *bd_async = NULL;
+ uint32_t ctrl, irqmask;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( (list == NULL) && (list_async == NULL) )
+ return 0;
+
+ /* Find first descriptor in list, the descriptor
+ * first to be executed.
+ */
+ ctrl = GR1553BC_KEY;
+ if ( list ) {
+ bd = gr1553bc_slot_bd(list, GR1553BC_ID(0,0,0));
+ if ( bd == NULL )
+ return -1;
+ bd = gr1553bc_bd_cpu2hw(list, bd);
+ ctrl |= GR1553B_BC_ACT_SCSRT;
+ }
+ if ( list_async ) {
+ bd_async = gr1553bc_slot_bd(list_async, GR1553BC_ID(0,0,0));
+ if ( bd_async == NULL )
+ return -1;
+ bd_async = gr1553bc_bd_cpu2hw(list_async, bd_async);
+ ctrl |= GR1553B_BC_ACT_ASSRT;
+ }
+
+ /* Do "hot-swapping" of lists */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ if ( list ) {
+ priv->list = list;
+ GR1553BC_WRITE_REG(&priv->regs->bc_bd, (uint32_t)bd);
+ }
+ if ( list_async ) {
+ priv->alist = list_async;
+ GR1553BC_WRITE_REG(&priv->regs->bc_abd, (uint32_t)bd_async);
+ }
+
+ /* If not enabled before, we enable it now. */
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+
+ /* Enable IRQ */
+ if ( priv->started == 0 ) {
+ priv->started = 1;
+ irqmask = GR1553BC_READ_REG(&priv->regs->imask);
+ irqmask |= GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE;
+ GR1553BC_WRITE_REG(&priv->regs->imask, irqmask);
+ }
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Pause GR1553 BC transfers */
+int gr1553bc_pause(void *bc)
+{
+ struct gr1553bc_priv *priv = bc;
+ uint32_t ctrl;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ /* Do "hot-swapping" of lists */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSUS;
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Restart GR1553 BC transfers, after being paused */
+int gr1553bc_restart(void *bc)
+{
+ struct gr1553bc_priv *priv = bc;
+ uint32_t ctrl;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSRT;
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Stop BC transmission */
+int gr1553bc_stop(void *bc, int options)
+{
+ struct gr1553bc_priv *priv = bc;
+ uint32_t ctrl;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ ctrl = GR1553BC_KEY;
+ if ( options & 0x1 )
+ ctrl |= GR1553B_BC_ACT_SCSTP;
+ if ( options & 0x2 )
+ ctrl |= GR1553B_BC_ACT_ASSTP;
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+ priv->started = 0;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* Reset software and BC hardware into a known "unused/init" state */
+void gr1553bc_device_init(struct gr1553bc_priv *priv)
+{
+/* RESET HARDWARE REGISTERS */
+ /* Stop BC if not already stopped */
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+ /* Since RT can not be used at the same time as BC, we stop
+ * RT rx, it should already be stopped...
+ */
+ GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+ /* Clear some registers */
+ GR1553BC_WRITE_REG(&priv->regs->bc_bd, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_abd, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_timer, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_wake, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_irqptr, 0);
+ GR1553BC_WRITE_REG(&priv->regs->bc_busmsk, 0);
+
+/* PUT SOFTWARE INTO INITIAL STATE */
+ priv->list = NULL;
+ priv->alist = NULL;
+
+ priv->irq_log_base = (uint32_t *)
+ (((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
+ ~(GR1553BC_IRQLOG_SIZE-1));
+ /* Translate into a hardware accessible address */
+ drvmgr_translate_check(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)priv->irq_log_base,
+ (void **)&priv->irq_log_base_hw,
+ GR1553BC_IRQLOG_SIZE);
+ priv->irq_log_curr = priv->irq_log_base;
+ priv->irq_log_end = &priv->irq_log_base[GR1553BC_IRQLOG_CNT-1];
+ priv->irq_func = gr1553bc_isr_std;
+ priv->irq_data = NULL;
+
+ GR1553BC_WRITE_REG(&priv->regs->bc_irqptr,(uint32_t)priv->irq_log_base_hw);
+}
+
+void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
+{
+ uint32_t irqmask;
+
+ /* Stop BC if not already stopped */
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+ /* Since RT can not be used at the same time as BC, we stop
+ * RT rx, it should already be stopped...
+ */
+ GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+ /* Turn off IRQ generation */
+ irqmask=GR1553BC_READ_REG(&priv->regs->imask);
+ irqmask&=~(GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
+ GR1553BC_WRITE_REG(&priv->regs->irq, irqmask);
+}
+
+/* Interrupt handler */
+void gr1553bc_isr(void *arg)
+{
+ struct gr1553bc_priv *priv = arg;
+ uint32_t *curr, *pos, word0, word2;
+ union gr1553bc_bd *bd;
+ bcirq_func_t func;
+ void *data;
+ int handled, irq;
+
+ /* Did core make IRQ */
+ irq = GR1553BC_READ_REG(&priv->regs->irq);
+ irq &= (GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
+ if ( irq == 0 )
+ return; /* Shared IRQ: some one else may have caused the IRQ */
+
+ /* Clear handled IRQs */
+ GR1553BC_WRITE_REG(&priv->regs->irq, irq);
+
+ /* DMA error. This IRQ does not affect the IRQ log.
+ * We let standard IRQ handle handle it.
+ */
+ if ( irq & GR1553B_IRQEN_BCDE ) {
+ priv->irq_func(NULL, priv->irq_data);
+ }
+
+ /* Get current posistion in hardware */
+ pos = (uint32_t *)GR1553BC_READ_REG(&priv->regs->bc_irqptr);
+ /* Convertin into CPU address */
+ pos = priv->irq_log_base +
+ ((unsigned int)pos - (unsigned int)priv->irq_log_base_hw)/4;
+
+ /* Step in IRQ log until we reach the end. */
+ handled = 0;
+ curr = priv->irq_log_curr;
+ while ( curr != pos ) {
+ bd = (union gr1553bc_bd *)(GR1553BC_READ_MEM(curr) & ~1);
+ GR1553BC_WRITE_MEM(curr, 0x2); /* Mark Handled */
+
+ /* Convert Descriptor in IRQ log into CPU address. In order
+ * to convert we must know which list the descriptor belongs
+ * to, we compare the address of the bd to the ASYNC list
+ * descriptor table area.
+ */
+ if ( priv->alist && ((unsigned int)bd>=priv->alist->table_hw) &&
+ ((unsigned int)bd <
+ (priv->alist->table_hw + priv->alist->table_size))) {
+ /* BD in async list */
+ bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
+ } else {
+ /* BD in sync list */
+ bd = gr1553bc_bd_hw2cpu(priv->list, bd);
+ }
+
+ /* Handle Descriptor that cased IRQ
+ *
+ * If someone have inserted an IRQ descriptor and tied
+ * that to a custom function we call that function, otherwise
+ * we let the standard IRQ handle handle it.
+ */
+ word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+ if ( word0 == GR1553BC_UNCOND_IRQ ) {
+ word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+ if ( (word2 & 0x3) == 0 ) {
+ func = (bcirq_func_t)(word2 & ~0x3);
+ data = (void *)
+ GR1553BC_READ_MEM(&bd->raw.words[3]);
+ func(bd, data);
+ handled = 1;
+ }
+ }
+
+ if ( handled == 0 ) {
+ /* Let standard IRQ handle handle it */
+ priv->irq_func(bd, priv->irq_data);
+ } else {
+ handled = 0;
+ }
+
+ /* Increment to next entry in IRQ LOG */
+ if ( curr == priv->irq_log_end )
+ curr = priv->irq_log_base;
+ else
+ curr++;
+ }
+ priv->irq_log_curr = curr;
+}
+
+int gr1553bc_irq_setup
+ (
+ void *bc,
+ bcirq_func_t func,
+ void *data
+ )
+{
+ struct gr1553bc_priv *priv = bc;
+
+ if ( func == NULL )
+ priv->irq_func = gr1553bc_isr_std;
+ else
+ priv->irq_func = func;
+ priv->irq_data = data;
+
+ return 0;
+}
+
+void gr1553bc_ext_trig(void *bc, int trig)
+{
+ struct gr1553bc_priv *priv = bc;
+ unsigned int trigger;
+
+ if ( trig )
+ trigger = GR1553B_BC_ACT_SETT;
+ else
+ trigger = GR1553B_BC_ACT_CLRT;
+
+ GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | trigger);
+}
+
+void gr1553bc_status(void *bc, struct gr1553bc_status *status)
+{
+ struct gr1553bc_priv *priv = bc;
+
+ status->status = GR1553BC_READ_REG(&priv->regs->bc_stat);
+ status->time = GR1553BC_READ_REG(&priv->regs->bc_timer);
+}
+
+/*** DEBUGGING HELP FUNCTIONS ***/
+
+#include <stdio.h>
+
+void gr1553bc_show_list(struct gr1553bc_list *list, int options)
+{
+ struct gr1553bc_major *major;
+ struct gr1553bc_minor *minor;
+ int i, j, minor_cnt, timefree;
+
+ printf("LIST\n");
+ printf(" major cnt: %d\n", list->major_cnt);
+ for (i=0; i<32; i++) {
+ printf(" RT[%d] timeout: %d\n", i, 14+(list->rt_timeout[i]*4));
+ }
+
+ for (i=0; i<list->major_cnt; i++) {
+ major = list->majors[i];
+ minor_cnt = major->cfg->minor_cnt;
+ printf(" MAJOR[%d]\n", i);
+ printf(" minor count: %d\n", minor_cnt);
+
+ for (j=0; j<minor_cnt; j++) {
+ minor = major->minors[j];
+
+ printf(" MINOR[%d]\n", j);
+ printf(" bd: 0x%08x (HW:0x%08x)\n",
+ (unsigned int)&minor->bds[0],
+ (unsigned int)gr1553bc_bd_cpu2hw(list,
+ &minor->bds[0]));
+ printf(" slot cnt: %d\n", minor->cfg->slot_cnt);
+ if ( minor->cfg->timeslot ) {
+ timefree = gr1553bc_minor_freetime(minor);
+ printf(" timefree: %d\n", timefree);
+ printf(" timetotal: %d\n",
+ minor->cfg->timeslot);
+ } else {
+ printf(" no time mgr\n");
+ }
+ }
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
new file mode 100644
index 0000000000..1ce731ec43
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
@@ -0,0 +1,519 @@
+/* GR1553B BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+#include <gr1553bm.h>
+
+
+#define GR1553BM_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553BM_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553BM_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553BM_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+struct gr1553bm_priv {
+ struct drvmgr_dev **pdev;
+ struct gr1553b_regs *regs;
+
+ void *buffer;
+ unsigned int buffer_base_hw;
+ unsigned int buffer_base;
+ unsigned int buffer_end;
+ unsigned int buffer_size;
+ unsigned int read_pos;
+ int started;
+ struct gr1553bm_config cfg;
+
+ /* Time updated by IRQ when 24-bit Time counter overflows */
+ volatile uint64_t time;
+};
+
+void gr1553bm_isr(void *data);
+
+/* Default Driver configuration */
+struct gr1553bm_config gr1553bm_default_config =
+{
+ /* Highest resolution, use Time overflow IRQ to track */
+ .time_resolution = 0,
+ .time_ovf_irq = 1,
+
+ /* No filtering, log all */
+ .filt_error_options = GR1553BM_ERROPTS_ALL,
+ .filt_rtadr = 0xffffffff,
+ .filt_subadr = 0xffffffff,
+ .filt_mc = 0x0007ffff,
+
+ /* 128Kbyte dynamically allocated buffer. */
+ .buffer_size = 128*1024,
+ .buffer_custom = NULL,
+};
+
+void gr1553bm_register(void)
+{
+ /* The BM driver rely on the GR1553B Driver */
+ gr1553_register();
+}
+
+static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
+{
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ /* Enable IRQ source and mark running state */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ priv->started = 1;
+
+ /* Clear old IRQ flags */
+ priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
+
+ /* Unmask IRQ sources */
+ if ( priv->cfg.time_ovf_irq ) {
+ priv->regs->imask |= GR1553B_IRQEN_BMDE | GR1553B_IRQEN_BMTOE;
+ } else {
+ priv->regs->imask |= GR1553B_IRQEN_BMDE;
+ }
+
+ /* Start logging */
+ priv->regs->bm_ctrl =
+ (priv->cfg.filt_error_options &
+ (GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
+ | GR1553B_BM_CTRL_BMEN;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+static void gr1553bm_hw_stop(struct gr1553bm_priv *priv)
+{
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /* Stop Logging */
+ priv->regs->bm_ctrl = 0;
+
+ /* Stop IRQ source */
+ priv->regs->imask &= ~(GR1553B_IRQEN_BMDE|GR1553B_IRQEN_BMTOE);
+
+ /* Clear IRQ flags */
+ priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
+
+ priv->started = 0;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+/* Open device by number */
+void *gr1553bm_open(int minor)
+{
+ struct drvmgr_dev **pdev = NULL;
+ struct gr1553bm_priv *priv = NULL;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Allocate requested device */
+ pdev = gr1553_bm_open(minor);
+ if ( pdev == NULL )
+ goto fail;
+
+ priv = malloc(sizeof(struct gr1553bm_priv));
+ if ( priv == NULL )
+ goto fail;
+ memset(priv, 0, sizeof(struct gr1553bm_priv));
+
+ /* Init BC device */
+ priv->pdev = pdev;
+ (*pdev)->priv = priv;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ /* Start with default configuration */
+ priv->cfg = gr1553bm_default_config;
+
+ /* Unmask IRQs */
+ gr1553bm_hw_stop(priv);
+
+ return priv;
+
+fail:
+ if ( pdev )
+ gr1553_bm_close(pdev);
+ if ( priv )
+ free(priv);
+ return NULL;
+}
+
+/* Close previously */
+void gr1553bm_close(void *bm)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ if ( priv->started ) {
+ gr1553bm_stop(bm);
+ }
+
+ if ( (priv->cfg.buffer_custom == NULL) && priv->buffer )
+ free(priv->buffer);
+
+ gr1553_bm_close(priv->pdev);
+ free(priv);
+}
+
+/* Configure the BM driver */
+int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ if ( priv->started )
+ return -1;
+
+ /* Check Config validity? */
+/*#warning IMPLEMENT.*/
+
+ /* Free old buffer if dynamically allocated */
+ if ( (priv->cfg.buffer_custom == NULL) && priv->buffer ) {
+ free(priv->buffer);
+ priv->buffer = NULL;
+ }
+ priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
+ if ((unsigned int)cfg->buffer_custom & 1) {
+ /* Custom Address Given in Remote address. We need
+ * to convert it intoTranslate into Hardware a
+ * hardware accessible address
+ */
+ priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
+ priv->buffer = cfg->buffer_custom;
+ drvmgr_translate_check(
+ *priv->pdev,
+ DMAMEM_TO_CPU,
+ (void *)priv->buffer_base_hw,
+ (void **)&priv->buffer_base,
+ priv->buffer_size);
+ } else {
+ if (cfg->buffer_custom == NULL) {
+ /* Allocate new buffer dynamically */
+ priv->buffer = malloc(priv->buffer_size + 8);
+ if (priv->buffer == NULL)
+ return -1;
+ } else {
+ /* Address given in CPU accessible address, no
+ * translation required.
+ */
+ priv->buffer = cfg->buffer_custom;
+ }
+ /* Align to 16 bytes */
+ priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
+ ~(8-1);
+ /* Translate address of buffer base into address that Hardware must
+ * use to access the buffer.
+ */
+ drvmgr_translate_check(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)priv->buffer_base,
+ (void **)&priv->buffer_base_hw,
+ priv->buffer_size);
+
+ }
+
+ /* Copy valid config */
+ priv->cfg = *cfg;
+
+ return 0;
+}
+
+/* Start logging */
+int gr1553bm_start(void *bm)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ if ( priv->started )
+ return -1;
+ if ( priv->buffer == NULL )
+ return -2;
+
+ /* Start at Time = 0 */
+ priv->regs->bm_ttag =
+ priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
+
+ /* Configure Filters */
+ priv->regs->bm_adr = priv->cfg.filt_rtadr;
+ priv->regs->bm_subadr = priv->cfg.filt_subadr;
+ priv->regs->bm_mc = priv->cfg.filt_mc;
+
+ /* Set up buffer */
+ priv->regs->bm_start = priv->buffer_base_hw;
+ priv->regs->bm_end = priv->buffer_base_hw + priv->cfg.buffer_size - 4;
+ priv->regs->bm_pos = priv->buffer_base_hw;
+ priv->read_pos = priv->buffer_base;
+ priv->buffer_end = priv->buffer_base + priv->cfg.buffer_size;
+
+ /* Register ISR handler and unmask IRQ source at IRQ controller */
+ if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bm", gr1553bm_isr, priv))
+ return -3;
+
+ /* Start hardware and set priv->started */
+ gr1553bm_hw_start(priv);
+
+ return 0;
+}
+
+/* Stop logging */
+void gr1553bm_stop(void *bm)
+{
+ struct gr1553bm_priv *priv = bm;
+
+ /* Stop Hardware */
+ gr1553bm_hw_stop(priv);
+
+ /* At this point the hardware must be stopped and IRQ
+ * sources unmasked.
+ */
+
+ /* Unregister ISR handler and unmask 1553 IRQ source at IRQ ctrl */
+ drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bm_isr, priv);
+}
+
+int gr1553bm_started(void *bm)
+{
+ return ((struct gr1553bm_priv *)bm)->started;
+}
+
+/* Get 64-bit 1553 Time.
+ *
+ * Update software time counters and return the current time.
+ */
+void gr1553bm_time(void *bm, uint64_t *time)
+{
+ struct gr1553bm_priv *priv = bm;
+ unsigned int hwtime, hwtime2;
+
+resample:
+ if ( priv->started && (priv->cfg.time_ovf_irq == 0) ) {
+ /* Update Time overflow counter. The carry bit from Time counter
+ * is located in IRQ Flag.
+ *
+ * When IRQ is not used this function must be called often
+ * enough to avoid that the Time overflows and the carry
+ * bit is already set. The frequency depends on the Time
+ * resolution.
+ */
+ if ( priv->regs->irq & GR1553B_IRQ_BMTOF ) {
+ /* Clear carry bit */
+ priv->regs->irq = GR1553B_IRQ_BMTOF;
+ priv->time += (GR1553B_BM_TTAG_VAL + 1);
+ }
+ }
+
+ /* Report current Time, even if stopped */
+ hwtime = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
+ if ( time )
+ *time = priv->time | hwtime;
+
+ if ( priv->cfg.time_ovf_irq ) {
+ /* Detect wrap around */
+ hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
+ if ( hwtime > hwtime2 ) {
+ /* priv->time and hwtime may be out of sync if
+ * IRQ updated priv->time just after bm_ttag was read
+ * here, we resample if we detect inconsistancy.
+ */
+ goto resample;
+ }
+ }
+}
+
+/* Number of entries available in DMA buffer */
+int gr1553bm_available(void *bm, int *nentries)
+{
+ struct gr1553bm_priv *priv = bm;
+ unsigned int top, bot, pos;
+
+ if ( !priv->started )
+ return -1;
+
+ /* Get BM posistion in log */
+ pos = priv->regs->bm_pos;
+
+ /* Convert into CPU accessible address */
+ pos = priv->buffer_base + (pos - priv->buffer_base_hw);
+
+ if ( pos >= priv->read_pos ) {
+ top = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ bot = 0;
+ } else {
+ top = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ bot = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
+ }
+
+ if ( nentries )
+ *nentries = top+bot;
+
+ return 0;
+}
+
+/* Read a maximum number of entries from LOG buffer. */
+int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max)
+{
+ struct gr1553bm_priv *priv = bm;
+ unsigned int dest, pos, left, newPos, len;
+ unsigned int topAdr, botAdr, topLen, botLen;
+
+ if ( !priv || !priv->started )
+ return -1;
+
+ left = *max;
+ pos = priv->regs->bm_pos & ~0x7;
+
+ /* Convert into CPU accessible address */
+ pos = priv->buffer_base + (pos - priv->buffer_base_hw);
+
+ if ( (pos == priv->read_pos) || (left < 1) ) {
+ /* No data available */
+ *max = 0;
+ return 0;
+ }
+ newPos = 0;
+
+ /* Addresses and lengths of BM log buffer */
+ if ( pos >= priv->read_pos ) {
+ /* Read Top only */
+ topAdr = priv->read_pos;
+ botAdr = 0;
+ topLen = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ botLen = 0;
+ } else {
+ /* Read Top and Bottom */
+ topAdr = priv->read_pos;
+ botAdr = priv->buffer_base;
+ topLen = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
+ botLen = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
+ }
+
+ dest = (unsigned int)dst;
+ if ( topLen > 0 ) {
+ /* Copy from top area first */
+ if ( topLen > left ) {
+ len = left;
+ left = 0;
+ } else {
+ len = topLen;
+ left -= topLen;
+ }
+ newPos = topAdr + (len * sizeof(struct gr1553bm_entry));
+ if ( newPos >= priv->buffer_end )
+ newPos -= priv->buffer_size;
+ if ( priv->cfg.copy_func ) {
+ dest += priv->cfg.copy_func(
+ dest, /*Optional Destination*/
+ (void *)topAdr, /* DMA start address */
+ len, /* Number of entries */
+ priv->cfg.copy_func_arg /* Custom ARG */
+ );
+ } else {
+ memcpy( (void *)dest,
+ (void *)topAdr,
+ len * sizeof(struct gr1553bm_entry));
+ dest += len * sizeof(struct gr1553bm_entry);
+ }
+ }
+
+ if ( (botLen > 0) && (left > 0) ) {
+ /* Copy bottom area last */
+ if ( botLen > left ) {
+ len = left;
+ left = 0;
+ } else {
+ len = botLen;
+ left -= botLen;
+ }
+ newPos = botAdr + (len * sizeof(struct gr1553bm_entry));
+
+ if ( priv->cfg.copy_func ) {
+ priv->cfg.copy_func(
+ dest, /*Optional Destination*/
+ (void *)botAdr, /* DMA start address */
+ len, /* Number of entries */
+ priv->cfg.copy_func_arg /* Custom ARG */
+ );
+ } else {
+ memcpy( (void *)dest,
+ (void *)botAdr,
+ len * sizeof(struct gr1553bm_entry));
+ }
+ }
+
+ /* Remember last read posistion in buffer */
+ /*printf("New pos: 0x%08x (0x%08x), %d\n", newPos, priv->read_pos, *max - left);*/
+ priv->read_pos = newPos;
+
+ /* Return number of entries read */
+ *max = *max - left;
+
+ return 0;
+}
+
+/* Note: This is a shared interrupt handler, with BC/RT driver
+ * we must determine the cause of IRQ before handling it.
+ */
+void gr1553bm_isr(void *data)
+{
+ struct gr1553bm_priv *priv = data;
+ uint32_t irqflag;
+
+ /* Get Causes */
+ irqflag = priv->regs->irq & (GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF);
+
+ /* Check spurious IRQs */
+ if ( (irqflag == 0) || (priv->started == 0) )
+ return;
+
+ if ( (irqflag & GR1553B_IRQ_BMTOF) && priv->cfg.time_ovf_irq ) {
+ /* 1553 Time Over flow. Time is 24-bits */
+ priv->time += (GR1553B_BM_TTAG_VAL + 1);
+
+ /* Clear cause handled */
+ priv->regs->irq = GR1553B_IRQ_BMTOF;
+ }
+
+ if ( irqflag & GR1553B_IRQ_BMD ) {
+ /* BM DMA ERROR. Fatal error, we stop BM hardware and let
+ * user take care of it. From now on all calls will result
+ * in an error because the BM is stopped (priv->started=0).
+ */
+
+ /* Clear cause handled */
+ priv->regs->irq = GR1553B_IRQ_BMD;
+
+ if ( priv->cfg.dma_error_isr )
+ priv->cfg.dma_error_isr(data, priv->cfg.dma_error_arg);
+
+ gr1553bm_hw_stop(priv);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
new file mode 100644
index 0000000000..ff05ce5d73
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
@@ -0,0 +1,1256 @@
+/* GR1553B RT driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gr1553b.h>
+#include <gr1553rt.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#define GR1553RT_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553RT_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553RT_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553RT_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* Software representation of one hardware descriptor */
+struct gr1553rt_sw_bd {
+ unsigned short this_next;/* Next entry or this entry. 0xffff: no next */
+ unsigned char listid; /* ListID of List the descriptor is attached */
+ char unused;
+} __attribute__((packed));
+
+/* Software description of a subaddress */
+struct gr1553rt_subadr {
+ /* RX LIST */
+ unsigned char rxlistid;
+ /* TX LIST */
+ unsigned char txlistid;
+};
+
+struct gr1553rt_irqerr {
+ gr1553rt_irqerr_t func;
+ void *data;
+};
+
+struct gr1553rt_irqmc {
+ gr1553rt_irqmc_t func;
+ void *data;
+};
+
+struct gr1553rt_irq {
+ gr1553rt_irq_t func;
+ void *data;
+};
+
+struct gr1553rt_priv {
+ /* Pointer to Hardware registers */
+ struct gr1553b_regs *regs;
+
+ /* Software State */
+ int started;
+ struct gr1553rt_cfg cfg;
+
+ /* Handle to GR1553B RT device layer */
+ struct drvmgr_dev **pdev;
+
+ /* Each Index represents one RT Subaddress. 31 = Broadcast */
+ struct gr1553rt_subadr subadrs[32];
+
+ /* Pointer to array of Software's description of a hardware
+ * descriptor.
+ */
+#if (RTBD_MAX == 0)
+ struct gr1553rt_sw_bd *swbds;
+#else
+ struct gr1553rt_sw_bd swbds[RTBD_MAX];
+#endif
+
+ /* List of Free descriptors */
+ unsigned short swbd_free;
+ int swbd_free_cnt;
+
+ /* Hardware SubAddress descriptors given for CPU and Hardware */
+ void *satab_buffer;
+ struct gr1553rt_sa *sas_cpu; /* Translated for CPU */
+ struct gr1553rt_sa *sas_hw; /* Translated for Hardware */
+
+ /* Hardware descriptors address given for CPU and hardware */
+ void *bd_buffer;
+ int bds_cnt; /* Number of descriptors */
+ struct gr1553rt_bd *bds_cpu; /* Translated for CPU */
+ struct gr1553rt_bd *bds_hw; /* Translated for Hardware */
+
+
+ /* Event Log buffer in */
+ void *evlog_buffer;
+ unsigned int *evlog_cpu_next; /* Next LOG entry to be handled */
+ unsigned int *evlog_cpu_base; /* First Entry in LOG */
+ unsigned int *evlog_cpu_end; /* Last+1 Entry in LOG */
+ unsigned int *evlog_hw_base; /* Translated for Hardware */
+
+ /* Each Index represents a LIST ID */
+ struct gr1553rt_list *lists[RTLISTID_MAX];
+
+ /* IRQ handlers, one per SUBADDRESS */
+ struct gr1553rt_irq irq_rx[32];
+ struct gr1553rt_irq irq_tx[32];
+
+ /* ISR called when an ERROR IRQ is received */
+ struct gr1553rt_irqerr irq_err;
+
+ /* ISR called when an Mode Code is received */
+ struct gr1553rt_irqmc irq_mc;
+};
+
+void gr1553rt_sw_init(struct gr1553rt_priv *priv);
+void gr1553rt_sw_free(struct gr1553rt_priv *priv);
+int gr1553rt_sw_alloc(struct gr1553rt_priv *priv);
+
+/* Assign and ID to the list. An LIST ID is needed before scheduling list
+ * on an RT subaddress.
+ *
+ * Only 64 lists can be registered at a time on the same device.
+ */
+int gr1553rt_list_reg(struct gr1553rt_list *list)
+{
+ struct gr1553rt_priv *priv = list->rt;
+ int i;
+
+ /* Find first free list ID */
+ for ( i=0; i<RTLISTID_MAX; i++) {
+ if ( priv->lists[i] == NULL ) {
+ priv->lists[i] = list;
+ list->listid = i;
+ return i;
+ }
+ }
+
+ /* No available LIST IDs */
+ list->listid = -1;
+
+ return -1;
+}
+
+/* Unregister List from device */
+void gr1553rt_list_unreg(struct gr1553rt_list *list)
+{
+ struct gr1553rt_priv *priv = list->rt;
+
+ priv->lists[list->listid] = NULL;
+ list->listid = -1;
+}
+
+static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
+{
+ struct gr1553rt_priv *priv = rt;
+
+ unsigned short index;
+
+ /* Get Index of Software BD */
+ index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
+ sizeof(struct gr1553rt_sw_bd);
+
+ return index;
+}
+
+void gr1553rt_bd_alloc_init(void *rt, int count)
+{
+ struct gr1553rt_priv *priv = rt;
+ int i;
+
+ for (i=0; i<count-1; i++) {
+ priv->swbds[i].this_next = i+1;
+ }
+ priv->swbds[count-1].this_next = 0xffff;
+ priv->swbd_free = 0;
+ priv->swbd_free_cnt = count;
+}
+
+/* Allocate a Chain of descriptors */
+int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
+{
+ struct gr1553rt_priv *priv = rt;
+ struct gr1553rt_sw_bd *curr;
+ int i;
+
+ if ((priv->swbd_free_cnt < cnt) || (cnt <= 0)) {
+ *bd = NULL;
+ return -1;
+ }
+
+ *bd = &priv->swbds[priv->swbd_free];
+ for (i=0; i<cnt; i++) {
+ if ( i == 0) {
+ curr = &priv->swbds[priv->swbd_free];
+ } else {
+ curr = &priv->swbds[curr->this_next];
+ }
+ if ( curr->this_next == 0xffff ) {
+ *bd = NULL;
+ return -1;
+ }
+ }
+ priv->swbd_free = curr->this_next;
+ priv->swbd_free_cnt -= cnt;
+ curr->this_next = 0xffff; /* Mark end of chain on last entry */
+
+ return 0;
+}
+
+void gr1553rt_bd_free(void *rt, struct gr1553rt_sw_bd *bd)
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned short index;
+
+ /* Get Index of Software BD */
+ index = gr1553rt_bdid(priv, bd);
+
+ /* Insert first in list */
+ bd->this_next = priv->swbd_free;
+ priv->swbd_free = index;
+ priv->swbd_free_cnt++;
+}
+
+int gr1553rt_list_init
+ (
+ void *rt,
+ struct gr1553rt_list **plist,
+ struct gr1553rt_list_cfg *cfg
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ int i, size;
+ struct gr1553rt_sw_bd *swbd;
+ unsigned short index;
+ struct gr1553rt_list *list;
+
+ /* The user may provide a pre allocated LIST, or
+ * let the driver handle allocation by using malloc()
+ *
+ * If the IN/OUT plist argument points to NULL a list
+ * dynamically allocated here.
+ */
+ list = *plist;
+ if ( list == NULL ) {
+ /* Dynamically allocate LIST */
+ size = offsetof(struct gr1553rt_list, bds) +
+ (cfg->bd_cnt * sizeof(unsigned short));
+ list = (struct gr1553rt_list *)malloc(size);
+ if ( list == NULL )
+ return -1;
+ *plist = list;
+ }
+
+ list->rt = rt;
+ list->subadr = -1;
+ list->listid = gr1553rt_list_reg(list);
+ if ( list->listid == -1 )
+ return -2; /* Too many lists */
+ list->cfg = cfg;
+ list->bd_cnt = cfg->bd_cnt;
+
+ /* Allocate all BDs needed by list */
+ if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
+ return -3; /* Too few descriptors */
+ }
+
+ /* Get ID/INDEX of Software BDs */
+ index = gr1553rt_bdid(rt, swbd);
+ list->bds[0] = index;
+ for (i=1; i<list->bd_cnt; i++) {
+ list->bds[i] = priv->swbds[list->bds[i-1]].this_next;
+ }
+
+ /* Now that the next pointer has fullfilled it's job and not
+ * needed anymore, we use it as list entry pointer instead.
+ * The this_next pointer is a list entry number.
+ */
+ for (i=0; i<list->bd_cnt; i++) {
+ priv->swbds[list->bds[i]].this_next = i;
+ }
+
+ return 0;
+}
+
+int gr1553rt_bd_init(
+ struct gr1553rt_list *list,
+ unsigned short entry_no,
+ unsigned int flags,
+ uint16_t *dptr,
+ unsigned short next
+ )
+{
+ struct gr1553rt_priv *priv;
+ unsigned short bdid;
+ struct gr1553rt_bd *bd;
+ unsigned int nextbd, dataptr;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( entry_no >= list->bd_cnt )
+ return -1;
+
+ /* Find Descriptor */
+ bdid = list->bds[entry_no];
+ priv = list->rt;
+ bd = &priv->bds_cpu[bdid];
+
+ if ( next == 0xfffe ) {
+ next = entry_no + 1;
+ if ( next >= list->bd_cnt )
+ next = 0;
+ }
+
+ /* Find next descriptor in address space that the
+ * Hardware understand.
+ */
+ if ( next >= 0xffff ) {
+ nextbd = 0x3; /* End of list */
+ } else if ( next >= list->bd_cnt ) {
+ return -1;
+ } else {
+ bdid = list->bds[next];
+ nextbd = (unsigned int)&priv->bds_hw[bdid];
+ }
+
+ dataptr = (unsigned int)dptr;
+ if ( dataptr & 1 ) {
+ /* Translate address from CPU-local into remote */
+ dataptr &= ~1;
+ drvmgr_translate(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)dataptr,
+ (void **)&dataptr
+ );
+ }
+
+ /* Get current status, and clear */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ bd->ctrl = flags & GR1553RT_BD_FLAGS_IRQEN;
+ bd->dptr = (unsigned int)dptr;
+ bd->next = nextbd;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_bd_update(
+ struct gr1553rt_list *list,
+ int entry_no,
+ unsigned int *status,
+ uint16_t **dptr
+ )
+{
+ struct gr1553rt_priv *priv;
+ unsigned short bdid;
+ struct gr1553rt_bd *bd;
+ unsigned int tmp, dataptr;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( entry_no >= list->bd_cnt )
+ return -1;
+
+ /* Find Descriptor */
+ bdid = list->bds[entry_no];
+ priv = list->rt;
+ bd = &priv->bds_cpu[bdid];
+
+ /* Prepare translation if needed */
+ if ( dptr && (dataptr=(unsigned int)*dptr) ) {
+ if ( dataptr & 1 ) {
+ /* Translate address from CPU-local into remote. May
+ * be used when RT core is accessed over the PCI bus.
+ */
+ dataptr &= ~1;
+ drvmgr_translate(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)dataptr,
+ (void **)&dataptr
+ );
+ }
+ }
+
+ /* Get current status, and clear */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ /* READ/WRITE Status/Control word */
+ if ( status ) {
+ tmp = bd->ctrl;
+ if ( *status ) {
+ bd->ctrl = *status;
+ }
+ *status = tmp;
+ }
+ /* READ/WRITE Data-Pointer word */
+ if ( dptr ) {
+ tmp = bd->dptr;
+ if ( dataptr ) {
+ bd->dptr = dataptr;
+ }
+ *dptr = (uint16_t *)tmp;
+ }
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_irq_err
+ (
+ void *rt,
+ gr1553rt_irqerr_t func,
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ priv->irq_err.func = func;
+ priv->irq_err.data = data;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_irq_mc
+ (
+ void *rt,
+ gr1553rt_irqmc_t func,
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ priv->irq_mc.func = func;
+ priv->irq_mc.data = data;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+int gr1553rt_irq_sa
+ (
+ void *rt,
+ int subadr,
+ int tx,
+ gr1553rt_irq_t func,
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ if ( tx ) {
+ priv->irq_tx[subadr].func = func;
+ priv->irq_tx[subadr].data = data;
+ } else {
+ priv->irq_rx[subadr].func = func;
+ priv->irq_rx[subadr].data = data;
+ }
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+/* GR1553-RT Interrupt Service Routine */
+void gr1553rt_isr(void *data)
+{
+ struct gr1553rt_priv *priv = data;
+ unsigned int firstirq, lastpos;
+ int index;
+ unsigned int *last, *curr, entry, hwbd;
+ int type, samc, mcode, subadr;
+ int listid;
+ struct gr1553rt_irq *isr;
+ struct gr1553rt_irqerr *isrerr;
+ struct gr1553rt_irqmc *isrmc;
+ unsigned int irq;
+
+ /* Ack IRQ before reading current write pointer, but after
+ * reading current IRQ pointer. This is because RT_EVIRQ
+ * may be updated after we ACK the IRQ source.
+ */
+ irq = priv->regs->irq &
+ (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD|GR1553B_IRQ_RTEV);
+ if ( irq == 0 )
+ return;
+
+ firstirq = priv->regs->rt_evirq;
+ priv->regs->irq = irq;
+ lastpos = priv->regs->rt_evlog;
+
+ /* Quit if nothing has been added to the log */
+ if ( lastpos == firstirq )
+ return;
+
+ if ( irq & (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD) ) {
+ isrerr = &priv->irq_err;
+ if ( isrerr->func ) {
+ isrerr->func(irq, isrerr->data);
+ }
+
+ /* Stop Hardware and enter non-started mode. This will
+ * make all future calls to driver result in an error.
+ */
+ gr1553rt_stop(priv);
+ }
+
+ /* Step between first log entry causing an IRQ to last
+ * entry. Each entry that has caused an IRQ will be handled
+ * by calling user-defined function.
+ *
+ * We convert hardware addresses into CPU accessable addresses
+ * first.
+ */
+ index = (firstirq - (unsigned int)priv->evlog_hw_base) /
+ sizeof(unsigned int);
+ curr = priv->evlog_cpu_base + index;
+ index = (lastpos - (unsigned int)priv->evlog_hw_base) /
+ sizeof(unsigned int);
+ last = priv->evlog_cpu_base + index;
+
+ do {
+ /* Process one entry */
+ entry = *curr;
+
+ if ( entry & 0x80000000 ) {
+ /* Entry caused IRQ */
+ type = (entry >> 29) & 0x3;
+ samc = (entry >> 24) & 0x1f;
+ if ( (type & 0x2) == 0 ) {
+ /* Transmit/Receive Data */
+ subadr = samc;
+ if ( type ) {
+ /* Receive */
+ listid = priv->subadrs[subadr].rxlistid;
+ hwbd = priv->sas_cpu[subadr].rxptr;
+ isr = &priv->irq_rx[subadr];
+ } else {
+ /* Transmit */
+ listid = priv->subadrs[subadr].txlistid;
+ hwbd = priv->sas_cpu[subadr].txptr;
+ isr = &priv->irq_tx[subadr];
+ }
+
+ index = ((unsigned int)hwbd - (unsigned int)
+ priv->bds_hw)/sizeof(struct gr1553rt_bd);
+
+ /* Call user ISR of RX/TX transfer */
+ if ( isr->func ) {
+ isr->func(
+ priv->lists[listid],
+ entry,
+ priv->swbds[index].this_next,
+ isr->data
+ );
+ }
+ } else if ( type == 0x2) {
+ /* Modecode */
+ mcode = samc;
+ isrmc = &priv->irq_mc;
+
+ /* Call user ISR of ModeCodes RX/TX */
+ if ( isrmc->func ) {
+ isrmc->func(
+ mcode,
+ entry,
+ isrmc->data
+ );
+ }
+ } else {
+ /* ERROR OF SOME KIND, EVLOG OVERWRITTEN? */
+ exit(-1);
+ }
+ }
+
+ /* Calc next entry posistion */
+ curr++;
+ if ( curr == priv->evlog_cpu_end )
+ curr = priv->evlog_cpu_base;
+
+ } while ( curr != last );
+}
+
+int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno)
+{
+ struct gr1553rt_priv *priv = rt;
+ struct gr1553rt_sa *sa;
+ unsigned int bd, index;
+
+ /* Sub address valid */
+ if ( (subadr < 0) || (subadr > 31) )
+ return -1;
+
+ /* Get SubAddress Descriptor address as accessed from CPU */
+ sa = &priv->sas_cpu[subadr];
+
+ /* Indication of TX descriptor? */
+ if ( txeno ) {
+ bd = sa->txptr;
+ /* Get Index of Hardware BD */
+ index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
+ sizeof(struct gr1553rt_bd);
+ *txeno = priv->swbds[index].this_next;
+ }
+
+ /* Indication of RX descriptor? */
+ if ( rxeno ) {
+ bd = sa->rxptr;
+ /* Get Index of Hardware BD */
+ index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
+ sizeof(struct gr1553rt_bd);
+ *rxeno = priv->swbds[index].this_next;
+ }
+
+ return 0;
+}
+
+#if 0
+int gr1553rt_bd_irq(
+ struct gr1553rt_list *list,
+ unsigned short entry_no,
+ void (*func)(struct gr1553rt_list *list, int entry, void *data),
+ void *data
+ )
+{
+ struct gr1553rt_priv *priv = list->rt;
+ int irqid;
+ int ret;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( entry_no == 0xffff ) {
+ /* Default interrupt for all list entries without
+ * assigned IRQ function.
+ */
+ list->irqs[0].func = func;
+ list->irqs[0].data = data;
+ return 0;
+ }
+
+ if ( entry_no >= list->bd_cnt ) {
+ return -1;
+ }
+
+ bdid = list->bds[entry_no];
+ irqid = priv->swbds[bdid].irqid;
+
+ ret = 0;
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ if ( (irqid != 0) && (func == 0) ) {
+ /* Unassign IRQ function */
+ list->irqs[irqid].func = NULL;
+ list->irqs[irqid].data = NULL;
+ irqid = 0; /* Disable IRQ (default handler) */
+ } else if ( priv->swbds[bdid].irqid != 0 ) {
+ /* reassign IRQ function */
+ list->irqs[irqid].func = func;
+ list->irqs[irqid].data = data;
+ } else {
+ /* Find free IRQ spot. If no free irqid=0 (general IRQ) */
+ ret = -1;
+ for (i=0; i<list->cfg->maxirq; i++) {
+ if ( list->irqs[i].func == NULL ) {
+ irqid = i;
+ list->irqs[i].func = func;
+ list->irqs[i].data = data;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ priv->swbds[bdid].irqid = irqid;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return ret;
+}
+#endif
+
+void gr1553rt_hw_stop(struct gr1553rt_priv *priv);
+
+void gr1553rt_register(void)
+{
+ /* The RT driver rely on the GR1553B Driver */
+ gr1553_register();
+}
+
+void *gr1553rt_open(int minor)
+{
+ struct drvmgr_dev **pdev = NULL;
+ struct gr1553rt_priv *priv = NULL;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Allocate requested device */
+ pdev = gr1553_rt_open(minor);
+ if ( pdev == NULL )
+ goto fail;
+
+ priv = malloc(sizeof(struct gr1553rt_priv));
+ if ( priv == NULL )
+ goto fail;
+ memset(priv, 0, sizeof(struct gr1553rt_priv));
+
+ /* Assign a device private to RT device */
+ priv->pdev = pdev;
+ (*pdev)->priv = priv;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+ /* Start with default configuration */
+ /*priv->cfg = gr1553rt_default_config;*/
+
+ /* Unmask IRQs and so */
+ gr1553rt_hw_stop(priv);
+
+ /* Register ISR handler. hardware mask IRQ, so it is safe to unmask
+ * at IRQ controller.
+ */
+ if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553rt", gr1553rt_isr, priv))
+ goto fail;
+
+ return priv;
+
+fail:
+ if ( pdev )
+ gr1553_rt_close(pdev);
+ if ( priv )
+ free(priv);
+ return NULL;
+}
+
+void gr1553rt_close(void *rt)
+{
+ struct gr1553rt_priv *priv = rt;
+
+ if ( priv->started ) {
+ gr1553rt_stop(priv);
+ }
+
+ /* Remove ISR handler */
+ drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553rt_isr, priv);
+
+ /* Free dynamically allocated buffers if any */
+ gr1553rt_sw_free(priv);
+
+ /* Return RT/BC device */
+ gr1553_rt_close(priv->pdev);
+}
+
+/* Stop Hardware and disable IRQ */
+void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
+{
+ uint32_t irqmask;
+
+ /* Disable RT */
+ GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+ /* Stop BC if not already stopped: BC can not be used simultaneously
+ * as the RT anyway
+ */
+ GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+ /* Turn off RT IRQ generation */
+ irqmask=GR1553RT_READ_REG(&priv->regs->imask);
+ irqmask&=~(GR1553B_IRQEN_RTEVE|GR1553B_IRQEN_RTDE);
+ GR1553RT_WRITE_REG(&priv->regs->irq, irqmask);
+}
+
+/* Free dynamically allocated buffers, if any */
+void gr1553rt_sw_free(struct gr1553rt_priv *priv)
+{
+ /* Event log */
+ if ( (priv->cfg.evlog_buffer == NULL) && priv->evlog_buffer ) {
+ free(priv->evlog_buffer);
+ priv->evlog_buffer = NULL;
+ }
+
+ /* RX/TX Descriptors */
+ if ( (priv->cfg.bd_buffer == NULL) && priv->bd_buffer ) {
+ free(priv->bd_buffer);
+ priv->bd_buffer = NULL;
+ }
+
+#if (RTBD_MAX == 0)
+ if ( priv->swbds ) {
+ free(priv->swbds);
+ priv->swbds = NULL;
+ }
+#endif
+
+ /* Sub address table */
+ if ( (priv->cfg.satab_buffer == NULL) && priv->satab_buffer ) {
+ free(priv->satab_buffer);
+ priv->satab_buffer = NULL;
+ }
+}
+
+/* Free dynamically allocated buffers, if any */
+int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
+{
+ int size;
+
+ /* Allocate Event log */
+ if ((unsigned int)priv->cfg.evlog_buffer & 1) {
+ /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+ priv->evlog_hw_base = (unsigned int *)
+ ((unsigned int)priv->cfg.evlog_buffer & ~0x1);
+ priv->evlog_buffer = priv->cfg.evlog_buffer;
+ drvmgr_translate_check(
+ *priv->pdev,
+ DMAMEM_TO_CPU,
+ (void *)priv->evlog_hw_base,
+ (void **)&priv->evlog_cpu_base,
+ priv->cfg.evlog_size
+ );
+ } else {
+ if (priv->cfg.evlog_buffer == NULL) {
+ priv->evlog_buffer = malloc(priv->cfg.evlog_size * 2);
+ if (priv->evlog_buffer == NULL)
+ return -1;
+ } else {
+ /* Addess already CPU-LOCAL */
+ priv->evlog_buffer = priv->cfg.evlog_buffer;
+ }
+ /* Align to SIZE bytes boundary */
+ priv->evlog_cpu_base = (unsigned int *)
+ (((unsigned int)priv->evlog_buffer +
+ (priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
+
+ drvmgr_translate_check(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)priv->evlog_cpu_base,
+ (void **)&priv->evlog_hw_base,
+ priv->cfg.evlog_size
+ );
+ }
+ priv->evlog_cpu_end = priv->evlog_cpu_base +
+ priv->cfg.evlog_size/sizeof(unsigned int *);
+
+ /* Allocate Transfer Descriptors */
+ priv->bds_cnt = priv->cfg.bd_count;
+ size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
+ if ((unsigned int)priv->cfg.bd_buffer & 1) {
+ /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+ priv->bds_hw = (unsigned int)priv->cfg.bd_buffer & ~0x1;
+ priv->bd_buffer = priv->cfg.bd_buffer;
+ drvmgr_translate_check(
+ *priv->pdev,
+ DMAMEM_TO_CPU,
+ (void *)priv->bds_hw,
+ (void **)&priv->bds_cpu,
+ size
+ );
+ } else {
+ if ( priv->cfg.bd_buffer == NULL ) {
+ priv->bd_buffer = malloc(size + 0xf);
+ if (priv->bd_buffer == NULL)
+ return -1;
+ } else {
+ /* Addess already CPU-LOCAL */
+ priv->bd_buffer = priv->cfg.bd_buffer;
+ }
+ /* Align to 16 bytes boundary */
+ priv->bds_cpu = (struct gr1553rt_bd *)
+ (((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
+
+ /* Translate from CPU address to hardware address */
+ drvmgr_translate_check(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)priv->bds_cpu,
+ (void **)&priv->bds_hw,
+ size
+ );
+ }
+
+#if (RTBD_MAX == 0)
+ /* Allocate software description of */
+ priv->swbds = malloc(priv->cfg.bd_count * sizeof(struct gr1553rt_sw_bd));
+ if ( priv->swbds == NULL ) {
+ return -1;
+ }
+#endif
+
+ /* Allocate Sub address table */
+ if ((unsigned int)priv->cfg.satab_buffer & 1) {
+ /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+ priv->sas_hw = (unsigned int)priv->cfg.satab_buffer & ~0x1;
+ priv->satab_buffer = priv->cfg.satab_buffer;
+ drvmgr_translate_check(
+ *priv->pdev,
+ DMAMEM_TO_CPU,
+ (void *)priv->sas_hw,
+ (void **)&priv->sas_cpu,
+ 16 * 32);
+ } else {
+ if (priv->cfg.satab_buffer == NULL) {
+ priv->satab_buffer = malloc((16 * 32) * 2);
+ if (priv->satab_buffer == NULL)
+ return -1;
+ } else {
+ /* Addess already CPU-LOCAL */
+ priv->satab_buffer = priv->cfg.satab_buffer;
+ }
+ /* Align to 512 bytes boundary */
+ priv->sas_cpu = (struct gr1553rt_sa *)
+ (((unsigned int)priv->satab_buffer + 0x1ff) &
+ ~0x1ff);
+
+ /* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
+ drvmgr_translate_check(
+ *priv->pdev,
+ CPUMEM_TO_DMA,
+ (void *)priv->sas_cpu,
+ (void **)&priv->sas_hw,
+ 16 * 32);
+ }
+
+ return 0;
+}
+
+void gr1553rt_sw_init(struct gr1553rt_priv *priv)
+{
+ int i;
+
+ /* Clear Sub Address table */
+ memset(priv->sas_cpu, 0, 512);
+
+ /* Clear Transfer descriptors */
+ memset(priv->bds_cpu, 0, priv->bds_cnt * 16);
+
+ /* Clear the Event log */
+ memset(priv->evlog_cpu_base, 0, priv->cfg.evlog_size);
+
+ /* Init descriptor allocation algorithm */
+ gr1553rt_bd_alloc_init(priv, priv->bds_cnt);
+
+ /* Init table used to convert from sub address to list.
+ * Currently non assigned.
+ */
+ for (i=0; i<32; i++) {
+ priv->subadrs[i].rxlistid = 0xff;
+ priv->subadrs[i].txlistid = 0xff;
+ }
+
+ /* Clear all previous IRQ handlers */
+ for (i=0; i<32; i++) {
+ priv->irq_rx[i].func = NULL;
+ priv->irq_tx[i].data = NULL;
+ }
+ priv->irq_err.func = NULL;
+ priv->irq_err.data = NULL;
+ priv->irq_mc.func = NULL;
+ priv->irq_mc.data = NULL;
+
+ /* Clear LIST to LISTID table */
+ for (i=0; i<RTLISTID_MAX; i++) {
+ priv->lists[i] = NULL;
+ }
+}
+
+int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
+{
+ struct gr1553rt_priv *priv = rt;
+
+ if ( priv->started )
+ return -1;
+
+ /*** Free dynamically allocated buffers ***/
+
+ gr1553rt_sw_free(priv);
+
+ /*** Check new config ***/
+ if ( cfg->rtaddress > 30 )
+ return -1;
+ if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
+ return -1; /* SIZE: Not aligned to a power of 2 */
+ if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
+ return -1; /* Buffer: Not aligned to size */
+#if (RTBD_MAX > 0)
+ if ( cfg->bd_count > RTBD_MAX )
+ return -1;
+#endif
+
+ /*** Make new config current ***/
+ priv->cfg = *cfg;
+
+ /*** Adapt to new config ***/
+
+ if ( gr1553rt_sw_alloc(priv) != 0 )
+ return -1;
+
+ gr1553rt_sw_init(priv);
+
+ return 0;
+}
+
+int gr1553rt_start(void *rt)
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ if ( priv->started )
+ return -1;
+
+ /*** Initialize software Pointers and stuff ***/
+
+ if ( !priv->satab_buffer || !priv->bd_buffer || !priv->evlog_buffer )
+ return -2;
+
+ priv->evlog_cpu_next = priv->evlog_cpu_base;
+
+ /*** Initialize Registers ***/
+
+ /* Subaddress table base */
+ priv->regs->rt_tab = (unsigned int)priv->sas_hw;
+
+ /* Mode code configuration */
+ priv->regs->rt_mcctrl = priv->cfg.modecode;
+
+ /* RT Time Tag resolution */
+ priv->regs->rt_ttag = priv->cfg.time_res << 16;
+
+ /* Event LOG base and size */
+ priv->regs->rt_evsz = ~(priv->cfg.evlog_size - 1);
+ priv->regs->rt_evlog = (unsigned int)priv->evlog_hw_base;
+ priv->regs->rt_evirq = 0;
+
+ /* Clear and old IRQ flag and Enable IRQ */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ priv->regs->irq = GR1553B_IRQ_RTEV|GR1553B_IRQ_RTD|GR1553B_IRQ_RTTE;
+ priv->regs->imask |= GR1553B_IRQEN_RTEVE | GR1553B_IRQEN_RTDE |
+ GR1553B_IRQEN_RTTEE;
+
+ /* Enable and Set RT address */
+ priv->regs->rt_cfg = GR1553RT_KEY |
+ (priv->cfg.rtaddress << GR1553B_RT_CFG_RTADDR_BIT) |
+ GR1553B_RT_CFG_RTEN;
+
+ /* Tell software RT is started */
+ priv->started = 1;
+ IRQ_GLOBAL_ENABLE(oldLevel);
+
+ return 0;
+}
+
+void gr1553rt_stop(void *rt)
+{
+ struct gr1553rt_priv *priv = rt;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /* Stop Hardware */
+ gr1553rt_hw_stop(priv);
+
+ /* Software state */
+ priv->started = 0;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+void gr1553rt_sa_schedule(
+ void *rt,
+ int subadr,
+ int tx,
+ struct gr1553rt_list *list
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned short bdid;
+ struct gr1553rt_bd *bd;
+
+ if ( !list || (list->listid == -1) )
+ return;
+
+ /* Get Hardware address of first descriptor in list */
+ bdid = list->bds[0];
+ if ( bdid == 0xffff )
+ return;
+ bd = &priv->bds_hw[bdid];
+
+ list->subadr = subadr;
+
+ /* Update Sub address table */
+ if ( tx ) {
+ list->subadr |= 0x100;
+ priv->subadrs[subadr].txlistid = list->listid;
+ priv->sas_cpu[subadr].txptr = (unsigned int)bd;
+ } else {
+ priv->subadrs[subadr].rxlistid = list->listid;
+ priv->sas_cpu[subadr].rxptr = (unsigned int)bd;
+ }
+}
+
+void gr1553rt_sa_setopts(
+ void *rt,
+ int subadr,
+ unsigned int mask,
+ unsigned int options
+ )
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned int ctrl;
+
+ if ( (subadr > 31) || (priv->sas_cpu == NULL) )
+ return;
+
+ ctrl = priv->sas_cpu[subadr].ctrl;
+ priv->sas_cpu[subadr].ctrl = (ctrl & ~mask) | options;
+}
+
+void gr1553rt_set_vecword(void *rt, unsigned int mask, unsigned int words)
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned int vword;
+
+ if ( mask == 0 )
+ return;
+
+ vword = priv->regs->rt_statw;
+
+ priv->regs->rt_statw = (vword & ~mask) | (words & mask);
+}
+
+void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts)
+{
+ struct gr1553rt_priv *priv = rt;
+ unsigned int stat;
+
+ stat = priv->regs->rt_stat2;
+ priv->regs->rt_stat2 = (stat & ~mask) | (mask & sts);
+}
+
+void gr1553rt_status(void *rt, struct gr1553rt_status *status)
+{
+ struct gr1553rt_priv *priv = rt;
+ struct gr1553b_regs *regs = priv->regs;
+ unsigned int tmp;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
+ IRQ_GLOBAL_DISABLE(oldLevel);
+ status->status = regs->rt_stat;
+ status->bus_status = regs->rt_stat2;
+
+ tmp = regs->rt_sync;
+ status->synctime = tmp >> 16;
+ status->syncword = tmp & 0xffff;
+
+ tmp = regs->rt_ttag;
+ status->time_res = tmp >> 16;
+ status->time = tmp & 0xffff;
+
+ IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+void gr1553rt_list_sa(struct gr1553rt_list *list, int *subadr, int *tx)
+{
+ int sa, trt;
+
+ if ( list->subadr == -1 ) {
+ sa = -1;
+ trt = -1;
+ } else {
+ sa = list->subadr & 0xff;
+ trt = (list->subadr & 0x100) >> 8;
+ }
+
+ if ( subadr )
+ *subadr = sa;
+ if ( tx )
+ *tx = trt;
+}
+
+int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max)
+{
+ struct gr1553rt_priv *priv = rt;
+ int cnt, top, bot, left;
+ unsigned int *hwpos;
+
+ /* Get address of hardware's current working entry */
+ hwpos = (unsigned int *)priv->regs->rt_evlog;
+
+ /* Convert into CPU address */
+ hwpos = (unsigned int *)
+ ((unsigned int)hwpos - (unsigned int)priv->evlog_hw_base +
+ (unsigned int)priv->evlog_cpu_base);
+
+ if ( priv->evlog_cpu_next == hwpos )
+ return 0;
+
+ if ( priv->evlog_cpu_next > hwpos ) {
+ top = (unsigned int)priv->evlog_cpu_end -
+ (unsigned int)priv->evlog_cpu_next;
+ bot = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_base;
+ } else {
+ top = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_next;
+ bot = 0;
+ }
+ top = top / 4;
+ bot = bot / 4;
+
+ left = max;
+ if ( top > 0 ) {
+ if ( top > left ) {
+ cnt = left;
+ } else {
+ cnt = top;
+ }
+ memcpy(dst, priv->evlog_cpu_next, cnt*4);
+ dst += cnt;
+ left -= cnt;
+ }
+
+ if ( (bot > 0) && (left > 0) ) {
+ if ( bot > left ) {
+ cnt = left;
+ } else {
+ cnt = bot;
+ }
+ memcpy(dst, priv->evlog_cpu_base, cnt*4);
+ left -= cnt;
+ }
+
+ cnt = max - left;
+ priv->evlog_cpu_next += cnt;
+ if ( priv->evlog_cpu_next >= priv->evlog_cpu_end ) {
+ priv->evlog_cpu_next = (unsigned int *)
+ ((unsigned int)priv->evlog_cpu_base +
+ ((unsigned int)priv->evlog_cpu_next -
+ (unsigned int)priv->evlog_cpu_end ));
+ }
+
+ return max - left;
+}