diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2007-09-06 13:27:25 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2007-09-06 13:27:25 +0000 |
commit | 226455f9fffef4c88b67aeef113a97dcaabd4b00 (patch) | |
tree | 8771eee8053655a1c09977a68efd2ba35ee173c5 /c/src/lib/libbsp/sparc/shared/1553 | |
parent | 2007-09-06 Daniel Hellstrom <daniel@gaisler.com> (diff) | |
download | rtems-226455f9fffef4c88b67aeef113a97dcaabd4b00.tar.bz2 |
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
New drivers: PCI, b1553BRM, SpaceWire(GRSPW), CAN (GRCAN,OC_CAN),
Raw UART.
* shared/1553/b1553brm.c, shared/1553/b1553brm_pci.c,
shared/1553/b1553brm_rasta.c, shared/can/grcan.c,
shared/can/grcan_rasta.c, shared/can/occan.c, shared/can/occan_pci.c,
shared/spw/grspw.c, shared/spw/grspw_pci.c, shared/spw/grspw_rasta.c,
shared/uart/apbuart.c, shared/uart/apbuart_pci.c,
shared/uart/apbuart_rasta.c: New files missed in previous commit.
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/1553')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/1553/b1553brm.c | 1367 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c | 132 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c | 115 |
3 files changed, 1614 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c new file mode 100644 index 0000000000..f60cfa5771 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c @@ -0,0 +1,1367 @@ +/* + * BRM driver + * + * COPYRIGHT (c) 2006. + * Gaisler Research. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + */ + +/********** Set defaults **********/ + +/* basic bus/interface of device, + * Default to direct accessed AMBA bus. + */ +#ifndef B1553BRM_NO_AMBA + #define B1553BRM_AMBA + #undef B1553BRM_PCI +#endif + +/* default name to /dev/brm */ +#if !defined(B1553BRM_DEVNAME) || !defined(B1553BRM_DEVNAME_NO) + #undef B1553BRM_DEVNAME + #undef B1553BRM_DEVNAME_NO + #define B1553BRM_DEVNAME "/dev/brm0" + #define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[8]='0'+(no)) +#endif + +#ifndef B1553BRM_PREFIX + #define B1553BRM_PREFIX(name) b1553brm##name +#endif + +/* default to no translation */ +#ifndef B1553BRM_ADR_TO + #define memarea_to_hw(x) ((unsigned int)(x)) +#endif + +#ifndef B1553BRM_REG_INT + #define B1553BRM_REG_INT(handler,irqno,arg) set_vector(handler,(irqno)+0x10,1) +#endif + +/* default to 128K memory layout */ +#if !defined(DMA_MEM_16K) + #define DMA_MEM_128K +#endif + +#include <bsp.h> +#include <rtems/libio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sched.h> +#include <ctype.h> +#include <rtems/bspIo.h> + +#include <b1553brm.h> +#include <ambapp.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) ) + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef FUNCDEBUG +#define FUNCDBG(x...) printk(x) +#else +#define FUNCDBG(x...) +#endif + +#define READ_REG(address) _BRM_REG_READ16((unsigned int)address) +#define READ_DMA(address) _BRM_REG_READ16((unsigned int)address) +static __inline__ unsigned short _BRM_REG_READ16(unsigned int addr) { + unsigned short tmp; + asm(" lduha [%1]1, %0 " + : "=r"(tmp) + : "r"(addr) + ); + return tmp; +} + +static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); +static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); +static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); +static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); +static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); +static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); + +#define BRM_DRIVER_TABLE_ENTRY { brm_initialize, brm_open, brm_close, brm_read, brm_write, brm_control } + +static rtems_driver_address_table brm_driver = BRM_DRIVER_TABLE_ENTRY; + +struct msg { + unsigned short miw; + unsigned short time; + unsigned short data[32]; +}; +#if defined(DMA_MEM_128K) +struct circ_buf { + struct msg msgs[9]; +}; +#elif defined(DMA_MEM_16K) +/* two message queue */ +struct circ_buf_2 { + struct msg msgs[2]; +}; +/* one message queue */ +struct circ_buf_1 { + struct msg msgs[1]; +}; +#endif + +typedef struct { + + unsigned int memarea_base; + struct brm_reg *regs; + + /* BRM descriptors */ + struct desc_table { + + volatile unsigned short ctrl; + volatile unsigned short top; + volatile unsigned short cur; + volatile unsigned short bot; + + } *desc; + + volatile unsigned short *mem; + /* bc mem struct */ + struct { + /* BC Descriptors */ + struct { + unsigned short ctrl; /* control */ + unsigned short cw1; /* Command word 1*/ + unsigned short cw2; /* Command word 1*/ + unsigned short dptr; /* Data pointer in halfword offset from bcmem */ + unsigned short tsw[2]; /* status word 1 & 2 */ + unsigned short ba; /* branch address */ + unsigned short timer; /* timer value */ + } descs[128]; /* 2k (1024 half words) */ + + /* message data */ + struct { + unsigned short data[32]; /* 1 message's data */ + } msg_data[128]; /* 8k */ + +#if defined(DMA_MEM_128K) + /* offset to last 64bytes of 128k */ + unsigned short unused[(64*1024-(128*8+128*32))-16*2]; +#elif defined(DMA_MEM_16K) + unsigned short unused[(8*1024-(128*8+128*32))-16*2]; +#endif + /* interrupt log at 64 bytes from end */ + struct { + unsigned short iiw; + unsigned short iaw; + } irq_logs[16]; + } *bcmem; + +#if defined(DMA_MEM_128K) + /* Memory structure of a RT being inited, just used + * for RT initialization. + * + * *mesgs[32] fit each minimally 8 messages per sub address. + */ + struct { + /* RX Sub Address descriptors */ + struct desc_table rxsubs[32]; + /* TX Sub Address descriptors */ + struct desc_table txsubs[32]; + /* RX mode code descriptors */ + struct desc_table rxmodes[32]; + /* TX mode code descriptors */ + struct desc_table txmodes[32]; + + /* RX Sub Address messages */ + struct circ_buf rxsuba_msgs[32]; + /* TX Sub Address messages */ + struct circ_buf txsuba_msgs[32]; + /* RX Mode Code messages */ + struct circ_buf rxmode_msgs[32]; + /* RX Mode Code messages */ + struct circ_buf txmode_msgs[32]; + + + /* offset to last 64bytes of 128k: tot-used-needed */ + unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2]; + + /* interrupt log at 64 bytes from end */ + struct { + unsigned short iiw; + unsigned short iaw; + } irq_logs[16]; + } *rtmem; +#elif defined(DMA_MEM_16K) + /* Memory structure of a RT being inited, just used + * for RT initialization. + * + * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue. + * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue. + */ + struct { + /* RX Sub Address descriptors */ + struct desc_table rxsubs[32]; + /* TX Sub Address descriptors */ + struct desc_table txsubs[32]; + /* RX mode code descriptors */ + struct desc_table rxmodes[32]; + /* TX mode code descriptors */ + struct desc_table txmodes[32]; + + /* RX Sub Address messages */ + struct circ_buf_2 rxsuba_msgs[32]; + /* TX Sub Address messages */ + struct circ_buf_2 txsuba_msgs[32]; + /* RX Mode Code messages */ + struct circ_buf_2 rxmode_msgs[32]; + /* RX Mode Code messages */ + struct circ_buf_1 txmode_msgs[32]; + + + /* offset to last 64bytes of 16k: tot-used-needed */ + unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2]; + + /* interrupt log at 64 bytes from end */ + struct { + unsigned short iiw; + unsigned short iaw; + } irq_logs[16]; + } *rtmem; +#else + #error You must define one DMA_MEM_???K +#endif + + /* Interrupt log list */ + struct irq_log_list { + volatile unsigned short iiw; + volatile unsigned short iaw; + } *irq_log; + unsigned int irq; + + /* Received events waiting to be read */ + struct rt_msg *rt_event; + struct bm_msg *bm_event; + + unsigned int head, tail; + + unsigned int last_read[128]; + unsigned int written[32]; + + struct bc_msg *cur_list; + + int tx_blocking, rx_blocking; + + rtems_id rx_sem, tx_sem, dev_sem; + int minor; + int irqno; + unsigned int mode; +#ifdef DEBUG + unsigned int log[EVENT_QUEUE_SIZE*4]; + unsigned int log_i; +#endif + + rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */ + unsigned int status; + int bc_list_fail; +} brm_priv; + +static int brm_cores; +static unsigned int allbrm_memarea; +static brm_priv *brms; +static amba_confarea_type *amba_bus; +static unsigned int allbrm_cfg_clksel; +static unsigned int allbrm_cfg_clkdiv; +static unsigned int allbrm_cfg_freq; + +static void brm_interrupt(brm_priv *brm); +static void b1553brm_interrupt_handler(rtems_vector_number v); + +#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1) + +static int odd_parity(unsigned int data) { + unsigned int i=0; + + while(data) + { + i++; + data &= (data - 1); + } + + return !(i&1); +} + + +static void start_operation(brm_priv *brm) { + unsigned int ctrl = READ_REG(&brm->regs->ctrl); + brm->regs->ctrl = ctrl | 0x8000; +} + +static void stop_operation(brm_priv *brm) { + unsigned int ctrl = READ_REG(&brm->regs->ctrl); + brm->regs->ctrl = ctrl & ~0x8000; +} +static int is_executing(brm_priv *brm) { + unsigned int ctrl = READ_REG(&brm->regs->ctrl); + return ((ctrl>>15) & 1); +} + +#ifdef LEON3 +#ifndef DONT_DEF_RAMON +int brm_register_leon3_ramon_fpga(void){ + /* Clock div & Clock sel is NOT available. + * The BRM is always clocked with 24MHz. + * 3 in BRM enhanced register will select 24MHz + */ + return b1553brm_register(&amba_conf,0,0,3); +} + +int brm_register_leon3_ramon_asic(void){ + /* Clock div & Clock sel is available. + * Clkdiv only matter when clksel is 1. + * clksel=2, clkdiv=don't care, brm_frq=24MHz + * + * 3 in BRM enhanced register will select 24MHz + */ + return b1553brm_register(&amba_conf,2,0,3); +} +#endif +#endif + +int B1553BRM_PREFIX(_register)(amba_confarea_type *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq) +{ + rtems_status_code r; + rtems_device_major_number m; + + FUNCDBG("brm_register:\n\r"); + + /* save amba bus pointer */ + amba_bus = bus; + if ( !bus ){ + printk("brm_register: bus is NULL\n\r"); + return 1; + } + +#ifdef B1553BRM_LOCAL_MEM + allbrm_memarea = B1553BRM_LOCAL_MEM_ADR; +#else + allbrm_memarea = NULL; +#endif + + /* Save clksel, clkdiv and brm_freq for later use */ + allbrm_cfg_clksel = clksel & CLKSEL_MASK; + allbrm_cfg_clkdiv = clkdiv & CLKDIV_MASK; + allbrm_cfg_freq = brm_freq & BRM_FREQ_MASK; + + if ((r = rtems_io_register_driver(0, &brm_driver, &m)) == RTEMS_SUCCESSFUL) { + DBG("BRM: driver successfully registered, major: %d\n",m); + + } else { + switch(r) { + case RTEMS_TOO_MANY: + printk("BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); break; + case RTEMS_INVALID_NUMBER: + printk("BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); break; + case RTEMS_RESOURCE_IN_USE: + printk("BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); break; + default: + printk("BRM rtems_io_register_driver failed\n"); + } + return 1; + } + return 0; +} + +static void clr_int_logs(struct irq_log_list *logs){ + int i; + for(i=0; i<16; i++){ + logs[i].iiw = 0xffff; + logs[i].iaw = 0x0; + } +} + +static rtems_device_driver rt_init(brm_priv *brm) { + unsigned int i; + + brm->head = brm->tail = 0; + brm->rx_blocking = brm->tx_blocking = 1; + + if ( brm->bm_event ) + free(brm->bm_event); + brm->bm_event = NULL; + + if ( brm->rt_event ) + free(brm->rt_event); + + brm->bcmem = NULL; + brm->rtmem = (void *)brm->mem; + + brm->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg)); + + if (brm->rt_event == NULL) { + DBG("BRM driver failed to allocated memory."); + return RTEMS_NO_MEMORY; + } + + brm->irq_log = &brm->rtmem->irq_logs[0]; + + brm->regs->ctrl = 0x1912; /* enable both buses, circular 1 bufmode, broadcast, interrupt log */ + brm->regs->oper = 0x0900; /* configure as RT, with addr 1 */ + brm->regs->imask = BRM_RT_ILLCMD_IRQ|BRM_SUBAD_IRQ|BRM_TAPF_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ; + brm->regs->dpoint = 0; + brm->regs->ipoint = OFS(brm->rtmem->irq_logs[0]); + brm->regs->enhanced = 0x0000 | allbrm_cfg_freq; /* BRM clocked with freq = 12,16,20 or 24MHz */ + brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1; + brm->regs->w_irqctrl = 6; + brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base); + + clr_int_logs(brm->irq_log); + + /* Legalize all commands */ + for (i = 0; i < 16; i++) { + brm->regs->rt_cmd_leg[i] = 0; + } + + /* Init descriptor table + * + * Each circular buffer has room for 8 messages with up to 34 (32 data + miw + time) words (16b) in each. + * The buffers must separated by 34 words. + */ + + + /* RX Sub-address 0 - 31 */ + for (i = 0; i < 32; i++) { + brm->rtmem->rxsubs[i].ctrl = 0x00E0; /* Interrupt: INTX, IWA, and IBRD */ + brm->rtmem->rxsubs[i].top = OFS(brm->rtmem->rxsuba_msgs[i]); /* Top address */ + brm->rtmem->rxsubs[i].cur = OFS(brm->rtmem->rxsuba_msgs[i]); /* Current address */ + brm->rtmem->rxsubs[i].bot = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ + brm->last_read[i] = OFS(brm->rtmem->rxsuba_msgs[i]); + } + /* TX Sub-address 0 - 31 */ + for (i = 0; i < 32; i++) { + brm->rtmem->txsubs[i].ctrl = 0x0060; /* Interrupt: IWA and IBRD */ + brm->rtmem->txsubs[i].top = OFS(brm->rtmem->txsuba_msgs[i]); /* Top address */ + brm->rtmem->txsubs[i].cur = OFS(brm->rtmem->txsuba_msgs[i]); /* Current address */ + brm->rtmem->txsubs[i].bot = OFS(brm->rtmem->txsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ + brm->last_read[i+32] = OFS(brm->rtmem->txsuba_msgs[i]); + brm->written[i] = OFS(brm->rtmem->txsuba_msgs[i]); + } + /* RX mode code 0 - 31 */ + for (i = 0; i < 32; i++) { + brm->rtmem->rxmodes[i].ctrl = 0x00E0; /* Interrupt: INTX, IWA, and IBRD */ + brm->rtmem->rxmodes[i].top = OFS(brm->rtmem->rxmode_msgs[i]); /* Top address */ + brm->rtmem->rxmodes[i].cur = OFS(brm->rtmem->rxmode_msgs[i]); /* Current address */ + brm->rtmem->rxmodes[i].bot = OFS(brm->rtmem->rxmode_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ + brm->last_read[i+64] = OFS(brm->rtmem->rxmode_msgs[i]); + } + /* TX mode code 0 - 31 */ + for (i = 0; i < 32; i++) { + brm->rtmem->txmodes[i].ctrl = 0x0060; /* Interrupt: IWA and IBRD */ + brm->rtmem->txmodes[i].top = OFS(brm->rtmem->txmode_msgs[i]); /* Top address */ + brm->rtmem->txmodes[i].cur = OFS(brm->rtmem->txmode_msgs[i]); /* Current address */ + brm->rtmem->txmodes[i].bot = OFS(brm->rtmem->txmode_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ + brm->last_read[i+96] = OFS(brm->rtmem->txmode_msgs[i]); + } + + brm->mode = BRM_MODE_RT; + + return RTEMS_SUCCESSFUL; +} + +static rtems_device_driver bc_init(brm_priv *brm){ + + if ( brm->bm_event ) + free(brm->bm_event); + brm->bm_event = NULL; + + if ( brm->rt_event ) + free(brm->rt_event); + brm->rt_event = NULL; + + brm->bcmem = (void *)brm->mem; + brm->rtmem = NULL; + brm->irq_log = &brm->bcmem->irq_logs[0]; + + brm->head = brm->tail = 0; + brm->rx_blocking = brm->tx_blocking = 1; + + brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */ + brm->regs->oper = 0x0800; /* configure as BC */ + brm->regs->imask = BRM_EOL_IRQ|BRM_BC_ILLCMD_IRQ|BRM_ILLOP_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ; + brm->regs->dpoint = 0; + printk("Set BC interrupt log: 0x%lx, 0x%lx, 0x%lx\n",OFS(brm->bcmem->irq_logs[0]),&brm->bcmem->irq_logs[0],brm->bcmem); + brm->regs->ipoint = OFS(brm->bcmem->irq_logs[0]); + brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */ + brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1; + brm->regs->w_irqctrl = 6; + brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base); + + clr_int_logs(brm->irq_log); + + brm->mode = BRM_MODE_BC; + + return RTEMS_SUCCESSFUL; +} + +static rtems_device_driver bm_init(brm_priv *brm) { + + + brm->head = brm->tail = 0; + brm->rx_blocking = brm->tx_blocking = 1; + + if ( brm->rt_event ) + free(brm->rt_event); + brm->rt_event = NULL; + + if ( brm->bm_event ) + free(brm->bm_event); + + brm->bcmem = NULL; + brm->rtmem = NULL; + + brm->bm_event = (struct bm_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct bm_msg)); + + if (brm->bm_event == NULL) { + DBG("BRM driver failed to allocated memory."); + return RTEMS_NO_MEMORY; + } + + /* end of 16K, fits all current modes (128K, 16K) */ + brm->irq_log = &brm->mem[8*1024-16*2]; + + brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */ + brm->regs->oper = 0x0A00; /* configure as BM */ + brm->regs->imask = BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ|BRM_MERR_IRQ; + brm->regs->dpoint = 0; + brm->regs->ipoint = OFS(brm->mem[8*1024-16*2]); + brm->regs->mcpoint = 0; /* Command pointer */ + brm->regs->mdpoint = 0x100; /* Data pointer */ + brm->regs->mbc = 1; /* Block count */ + brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */ + brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1; + brm->regs->w_irqctrl = 6; + brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base); + + clr_int_logs(brm->irq_log); + + brm->mode = BRM_MODE_BM; + + return RTEMS_SUCCESSFUL; +} + + +static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status; + int dev_cnt; + char fs_name[20]; + brm_priv *brm; + amba_ahb_device ambadev; + char *mem; + + FUNCDBG("brm_initialize\n"); + + brm_cores = 0; + strcpy(fs_name,B1553BRM_DEVNAME); + + /* Find all BRM devices */ + dev_cnt = amba_get_number_ahbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_BRM); + if ( dev_cnt < 1 ){ + /* Failed to find any CAN cores! */ + printk("BRM: Failed to find any BRM cores\n\r"); + return -1; + } + + /* allocate & zero memory for the brm devices */ + brms = malloc(sizeof(*brms)*dev_cnt); + if ( !brms ){ + printk("BRM: Failed to allocate SW memory\n\r"); + return -1; + } + memset(brms,0,sizeof(*brms)*dev_cnt); + + /* Allocate memory for all device's descriptors, + * they must be aligned to a XXX byte boundary. + */ + #define BRM_DESCS_PER_CTRL 128 + if ( allbrm_memarea ){ + mem = allbrm_memarea; + }else{ + /* sizeof(struct desc_table) * BRM_DESCS_PER_CTRL * dev_cnt */ + mem = malloc( (128*1024) * (dev_cnt+1)); /* 128k per core + 128k for alignment */ + if ( !mem ){ + free(brms); + printk("BRM: Failed to allocate HW memory\n\r"); + return -1; + } + + /* align memory to 128k boundary */ + mem = (char *)(((unsigned int)mem+0x1ffff) & ~0x1ffff); + } + + /* clear the used memory */ + memset(mem,0,(128*1024) * dev_cnt); + + /* initialize each brm device, one at a time */ + for(minor=0; minor<dev_cnt; minor++){ + brm = &brms[minor]; + + /* Get AMBA AHB device info from Plug&Play */ + amba_find_next_ahbslv(amba_bus,VENDOR_GAISLER,GAISLER_BRM,&ambadev,minor); + + /* Copy Basic HW info */ + brm->regs = (void *)ambadev.start[0]; + brm->irqno = ambadev.irq; + brm->minor = minor; + brm->irq = 0; +#ifdef DEBUG + brm->log_i = 0; + memset(brm->log,0,sizeof(brm->log)); +#endif + + /* Set unique name */ + B1553BRM_DEVNAME_NO(fs_name,minor); + + DBG("Registering BRM core at [0x%x] irq %d, minor %d as %s\n",brm->regs,brm->irqno,minor,fs_name); + + /* Bind filesystem name to device number (minor) */ + status = rtems_io_register_name(fs_name, major, minor); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + /* RX Semaphore created with count = 0 */ + if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0'+minor), + 0, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &brm->rx_sem) != RTEMS_SUCCESSFUL ){ + printk("BRM: Failed to create rx semaphore\n"); + return RTEMS_INTERNAL_ERROR; + } + + /* TX Semaphore created with count = 1 */ + if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0'+minor), + 1, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &brm->tx_sem) != RTEMS_SUCCESSFUL ){ + printk("BRM: Failed to create tx semaphore\n"); + return RTEMS_INTERNAL_ERROR; + } + + /* Device Semaphore created with count = 1 */ + if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0'+minor), + 1, + RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, + 0, + &brm->dev_sem) != RTEMS_SUCCESSFUL ){ + printk("BRM: Failed to create device semaphore\n"); + return RTEMS_INTERNAL_ERROR; + } + + + /* Set base address of all descriptors */ + brm->memarea_base = (unsigned int)&mem[(128*1024) * minor]; + brm->desc = (struct desc_table *) brm->memarea_base; + brm->mem = (volatile unsigned short *) brm->memarea_base; + brm->irq_log = (void *)(brm->memarea_base + (0xFFE0<<1)); /* last 64byte */ + + brm->bm_event = NULL; + brm->rt_event = NULL; + + /* Sel clock so that we can write to BRM's registers */ + brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5); + /* Reset BRM core */ + brm->regs->w_ctrl = 1<<10 | READ_REG(&brm->regs->w_ctrl); + + /* Register interrupt handler */ + B1553BRM_REG_INT(B1553BRM_PREFIX(_interrupt_handler), brm->irqno, brm); + + rt_init(brm); + + DBG("BRM: LOG: 0x%lx, 0x%lx\n\r",brm->log,brm); + } + + /* save number of BRM cores found */ + brm_cores = dev_cnt; + + DBG("BRM initialisation done.\n"); + + return RTEMS_SUCCESSFUL; +} + +static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { + brm_priv *brm; + + FUNCDBG("brm_open\n"); + + if (minor >= brm_cores) { + DBG("Wrong minor %d\n", minor); + return RTEMS_UNSATISFIED; /* ENODEV */ + } + + brm = &brms[minor]; + + if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) { + DBG("brm_open: resource in use\n"); + return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + } + + /* Set defaults */ + brm->event_id = 0; + + start_operation(brm); + + return RTEMS_SUCCESSFUL; +} + +static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +{ + brm_priv *brm = &brms[minor]; + FUNCDBG("brm_close"); + + stop_operation(brm); + rtems_semaphore_release(brm->dev_sem); + + return RTEMS_SUCCESSFUL; +} + +static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count) { + + struct rt_msg *dest = (struct rt_msg *) buf; + int count = 0; + + if (brm->head == brm->tail) { + return 0; + } + + do { + + DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail); + dest[count++] = brm->rt_event[INDEX(brm->tail++)]; + + } while (brm->head != brm->tail && count < msg_count); + + return count; + +} + +static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count) { + + struct bm_msg *dest = (struct bm_msg *) buf; + int count = 0; + + if (brm->head == brm->tail) { + return 0; + } + + do { + + DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail); + dest[count++] = brm->bm_event[INDEX(brm->tail++)]; + + } while (brm->head != brm->tail && count < msg_count); + + return count; + +} + +static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +{ + rtems_libio_rw_args_t *rw_args; + int count = 0; + brm_priv *brm = &brms[minor]; + int (*get_messages)(brm_priv *brm, void *buf, unsigned int count); + + if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){ + return RTEMS_INVALID_NAME; + } + + rw_args = (rtems_libio_rw_args_t *) arg; + + if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */ + get_messages = get_rt_messages; + } + else { /* BM */ + get_messages = get_bm_messages; + } + + + FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count); + + while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) { + + if (brm->rx_blocking) { + rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + } + else { + /* Translates to EBUSY */ + return RTEMS_RESOURCE_IN_USE; + } + + } + + rw_args->bytes_moved = count; + return RTEMS_SUCCESSFUL; + +} + + +static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +{ + rtems_libio_rw_args_t *rw_args; + struct rt_msg *source; + unsigned int count=0, current, next, descriptor, wc, suba; + brm_priv *brm = &brms[minor]; + + if ( ! (brm->mode & BRM_MODE_RT) ){ + return RTEMS_INVALID_NAME; + } + + rw_args = (rtems_libio_rw_args_t *) arg; + source = (struct rt_msg *) rw_args->buffer; + + FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count); + + do { + + descriptor = source[count].desc & 0x7F; + suba = descriptor-32; + wc = source[count].miw >> 11; + wc = wc ? wc : 32; + + /* Only subaddress transmission is allowed with write */ + if (descriptor < 32 || descriptor >= 64) + return RTEMS_INVALID_NAME; + + current = brm->desc[descriptor].cur; + next = brm->written[suba] + 2 + wc; + + if (brm->written[suba] < current) { + + if (next > current) { + + /* No room in transmission buffer */ + + if (brm->tx_blocking && count == 0) { + rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + } + else if ( brm->tx_blocking && (count != 0) ){ + /* return the number of messages sent so far */ + break; + } + else { + /* Translates to posix EBUSY */ + return RTEMS_RESOURCE_IN_USE; + } + } + } + + memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2); + + count++; + + if (next >= brm->desc[descriptor].bot) { + next = brm->desc[descriptor].top; + } + brm->written[suba] = next; + + } while (count < rw_args->count); + + rw_args->bytes_moved = count; + + if (count >= 0) { + return RTEMS_SUCCESSFUL; + } + return RTEMS_UNSATISFIED; +} + +static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +{ + + unsigned int i=0; + unsigned short ctrl, oper, cw1, cw2; + rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg; + unsigned int *data = ioarg->buffer; + struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer; + brm_priv *brm = &brms[minor]; + rtems_device_driver ret; + int len; + + FUNCDBG("brm_control[%d]: [%i,%i]\n",minor,major, minor); + + if (!ioarg) { + DBG("brm_control: invalid argument\n"); + return RTEMS_INVALID_NAME; + } + + ioarg->ioctl_return = 0; + switch(ioarg->command) { + + case BRM_SET_MODE: + if ( data[0] > 2 ) + return RTEMS_INVALID_NAME; + stop_operation(brm); + if (data[0] == 0) { + ret = bc_init(brm); + } + else if (data[0] == 1) { + ret = rt_init(brm); + } + else if (data[0] == 2) { + ret = bm_init(brm); + }else + ret = RTEMS_INVALID_NAME; + + if ( ret != RTEMS_SUCCESSFUL) + return ret; + + if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) ) + start_operation(brm); + break; + + case BRM_SET_BUS: + stop_operation(brm); + ctrl = READ_REG(&brm->regs->ctrl); + ctrl &= 0xE7FF; /* Clear bit 12-11 ... */ + ctrl |= (data[0]&0x3)<<11; /* ... OR in new bus status */ + brm->regs->ctrl = ctrl; + start_operation(brm); + break; + + case BRM_SET_MSGTO: + stop_operation(brm); + ctrl = READ_REG(&brm->regs->ctrl); + ctrl &= 0xFDFF; /* Clear bit 9 ... */ + ctrl |= (data[0]&1)<<9; /* ... OR in new MSGTO */ + brm->regs->ctrl = ctrl; + start_operation(brm); + break; + + case BRM_SET_RT_ADDR: + stop_operation(brm); + oper = READ_REG(&brm->regs->oper); + oper &= 0x03FF; /* Clear bit 15-10 ... */ + oper |= (data[0]&0x1f)<<11; /* ... OR in new address */ + oper |= odd_parity(data[0]&0x1f)<<10; /* ... OR in parity */ + brm->regs->oper = oper; + start_operation(brm); + break; + + case BRM_SET_STD: + stop_operation(brm); + ctrl = READ_REG(&brm->regs->ctrl); + ctrl &= 0xFF7F; /* Clear bit 7 ... */ + ctrl |= (data[0]&1)<<7; /* ... OR in new ABSTD (1=A) */ + brm->regs->ctrl = ctrl; + start_operation(brm); + break; + + case BRM_SET_BCE: + stop_operation(brm); + ctrl = READ_REG(&brm->regs->ctrl); + ctrl &= 0xFFEF; /* Clear bit 4 ... */ + ctrl |= (data[0]&1)<<4; /* ... OR in new BCE */ + brm->regs->ctrl = ctrl; + start_operation(brm); + break; + + case BRM_TX_BLOCK: + brm->tx_blocking = data[0]; + break; + + case BRM_RX_BLOCK: + brm->rx_blocking = data[0]; + break; + + case BRM_DO_LIST: + + if ( brm->mode != BRM_MODE_BC ){ + return RTEMS_INVALID_NAME; + } + + /* Check if we are bus controller */ + if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) { + return RTEMS_INVALID_NAME; + } + + /* Already processing list? */ + if (is_executing(brm)) { + return RTEMS_RESOURCE_IN_USE; + } + + /* clear any earlier releases */ + rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); + + brm->bc_list_fail = 0; + brm->cur_list = cmd_list; + brm->regs->dpoint = 0; + + i = 0; + while ( (cmd_list[i].ctrl & BC_EOL) == 0) { + + ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8); + + if (cmd_list[i].ctrl&BC_RTRT) { + cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */ + cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */ + } + else { + cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f); + cw2 = 0; + } + + + /* Set up command block */ + brm->bcmem->descs[i].ctrl = ctrl; + brm->bcmem->descs[i].cw1 = cw1; + brm->bcmem->descs[i].cw2 = cw2; + /* data pointer: + * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2 + */ + brm->bcmem->descs[i].dptr = 1024+i*32; /* data pointer */ + brm->bcmem->descs[i].tsw[0] = 0; + brm->bcmem->descs[i].tsw[1] = 0; + brm->bcmem->descs[i].ba = 0; + brm->bcmem->descs[i].timer = 0; + + memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], cmd_list[i].wc*2); + + i++; + } + + brm->bcmem->descs[i].ctrl = 0; /* end of list */ + + start_operation(brm); + + break; + + case BRM_LIST_DONE: + + if ( brm->mode != BRM_MODE_BC ){ + return RTEMS_INVALID_NAME; + } + + /* Check if we are bus controller */ + if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) { + return RTEMS_INVALID_NAME; + } + + if (is_executing(brm)) { + + data[0] = 0; + if (brm->tx_blocking) { + rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + data[0] = 1; + if ( brm->bc_list_fail ){ + return RTEMS_INVALID_NAME; + } + }else{ + return RTEMS_RESOURCE_IN_USE; + } + + + } + else { + data[0] = 1; /* done */ + } + + /* copy finished list results back into bc_msg array */ + i = 0; + while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) { + + if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) { + brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */ + } + if (brm->cur_list[i].ctrl & BC_TR) { + /* RT Transmit command, copy received data */ + len = brm->cur_list[i].wc; + while( len-- > 0){ + brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]); + } + } + brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]); + brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]); + + i++; + } + break; + + + case BRM_CLR_STATUS: + brm->status = 0; + break; + + case BRM_GET_STATUS: /* copy status */ + + if ( !ioarg->buffer ) + return RTEMS_INVALID_NAME; + + *(unsigned int *)ioarg->buffer = brm->status; + break; + + case BRM_SET_EVENTID: + brm->event_id = (rtems_id)ioarg->buffer; + break; + + default: + return RTEMS_NOT_DEFINED; + } + return RTEMS_SUCCESSFUL; +} + +static void b1553brm_interrupt_handler(rtems_vector_number v){ + int i; + /* find minor */ + for(i=0; i<brm_cores; i++){ + if ( (brms[i].irqno+0x10) == v ){ + brm_interrupt(&brms[i]); + return; + } + } +} + +static void brm_interrupt(brm_priv *brm) { + unsigned short descriptor, current, pending, miw, wc, tmp; + unsigned short msgadr, iaw, iiw; + int len; + int signal_event=0; + unsigned int event_status; + #define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16); + + while( (iiw=READ_REG(&brm->irq_log[brm->irq].iiw)) != 0xffff ){ + iaw=READ_REG(&brm->irq_log[brm->irq].iaw); + + /* indicate that the interrupt log entry has been processed */ + brm->irq_log[brm->irq].iiw = 0xffff; + + /* Interpret interrupt log entry */ + descriptor = iaw >> 2; + pending = iiw; + brm->irq = (brm->irq + 1) % 16; + + /* Clear the log so that we */ + + + /* Subaddress accessed irq (RT only) + * + * Can be either a receive or transmit command + * as well as a mode code. + */ + if (pending & BRM_SUBAD_IRQ) { + + /* Pointer to next free message in circular buffer */ + current = READ_DMA(&brm->desc[descriptor].cur); + + while ( (msgadr=brm->last_read[descriptor]) != current) { + + /* Get word count */ + miw = READ_DMA(&brm->mem[msgadr]); + wc = miw >> 11; + + /* Data received */ + if (descriptor < 32) { + wc = wc ? wc : 32; + } + /* Data transmitted */ + else if (descriptor < 64) { + wc = wc ? wc : 32; + rtems_semaphore_release(brm->tx_sem); + } + /* RX Mode code */ + else if (descriptor < 96) { + wc = (wc>>4); + } + /* TX Mode code */ + else if (descriptor < 128) { + wc = (wc>>4); + } + +#ifdef DEBUG + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc; + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current; + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr; +#endif + + /* If there is room in the event queue, copy the event there */ + if (brm->head - brm->tail != EVENT_QUEUE_SIZE) { + + /* Copy to event queue */ + brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]); + brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]); + len = wc; + while( len-- > 0){ + brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]); + } + brm->rt_event[INDEX(brm->head)].desc = descriptor; + brm->head++; + + } + else { + /* Indicate overrun */ + brm->rt_event[INDEX(brm->head)].desc |= 0x8000; + } + + msgadr += (2+wc); + + if (msgadr >= brm->desc[descriptor].bot) { + msgadr = brm->desc[descriptor].top; + } + brm->last_read[descriptor] = msgadr; + +#ifdef DEBUG + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr; +#endif + + /* Wake any blocked rx thread */ + rtems_semaphore_release(brm->rx_sem); + + } + + } + + if (pending & BRM_EOL_IRQ) { + rtems_semaphore_release(brm->tx_sem); + } + + if (pending & BRM_BC_ILLCMD_IRQ) { + brm->bc_list_fail = 1; + rtems_semaphore_release(brm->tx_sem); + SET_ERROR_DESCRIPTOR(descriptor); + FUNCDBG("BRM: ILLCMD IRQ\n\r"); + } + + /* Monitor irq */ + if (pending & BRM_MBC_IRQ) { + + stop_operation(brm); + brm->regs->mbc = 1; + start_operation(brm); + + /* If there is room in the event queue, copy the event there */ + if (brm->head - brm->tail != EVENT_QUEUE_SIZE) { + + /* Copy to event queue */ + + brm->bm_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[0]); + brm->bm_event[INDEX(brm->head)].cw1 = READ_DMA(&brm->mem[1]); + brm->bm_event[INDEX(brm->head)].cw2 = READ_DMA(&brm->mem[2]); + brm->bm_event[INDEX(brm->head)].sw1 = READ_DMA(&brm->mem[4]); + brm->bm_event[INDEX(brm->head)].sw2 = READ_DMA(&brm->mem[5]); + brm->bm_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[6]); + + len = 32; + while ( len-- ){ + brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); + len--; + brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); + len--; + brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); + len--; + brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); + } +/* memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/ + +#ifdef DEBUG + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc); + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]); + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]); + brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]); +#endif + + brm->head++; + + } + else { + /* Indicate overrun */ + brm->rt_event[INDEX(brm->head)].miw |= 0x8000; + } + + /* Wake any blocking thread */ + rtems_semaphore_release(brm->rx_sem); + + } + + /* The reset of the interrupts + * cause a event to be signalled + * so that user can handle error. + */ + if ( pending & BRM_RT_ILLCMD_IRQ){ + FUNCDBG("BRM: BRM_RT_ILLCMD_IRQ\n\r"); + brm->status |= BRM_RT_ILLCMD_IRQ; + event_status |= BRM_RT_ILLCMD_IRQ; + SET_ERROR_DESCRIPTOR(descriptor); + signal_event=1; + } + + if ( pending & BRM_ILLOP_IRQ){ + FUNCDBG("BRM: BRM_ILLOP_IRQ\n\r"); + brm->bc_list_fail = 1; + rtems_semaphore_release(brm->tx_sem); + event_status |= BRM_ILLOP_IRQ; + SET_ERROR_DESCRIPTOR(descriptor); + signal_event=1; + } + + if ( pending & BRM_MERR_IRQ){ + FUNCDBG("BRM: BRM_MERR_IRQ\n\r"); + event_status |= BRM_MERR_IRQ; + SET_ERROR_DESCRIPTOR(descriptor); + signal_event=1; + } + /* Clear Block Accessed Bit */ + tmp = READ_REG(&brm->desc[descriptor].ctrl); + brm->desc[descriptor].ctrl = tmp & ~0x10; + + } /* While */ + + /* clear interrupt flags & handle Hardware errors */ + pending = READ_REG(&brm->regs->ipend); + + if ( pending & BRM_DMAF_IRQ){ + FUNCDBG("BRM: BRM_DMAF_IRQ\n\r"); + event_status |= BRM_DMAF_IRQ; + signal_event=1; + } + + if ( pending & BRM_WRAPF_IRQ){ + FUNCDBG("BRM: BRM_WRAPF_IRQ\n\r"); + event_status |= BRM_WRAPF_IRQ; + signal_event=1; + } + + if ( pending & BRM_TAPF_IRQ){ + FUNCDBG("BRM: BRM_TAPF_IRQ\n\r"); + event_status |= BRM_TAPF_IRQ; + signal_event=1; + } + + /* Copy current mask to status mask */ + if ( event_status ){ + if ( event_status & 0xffff0000 ) + brm->status &= 0x0000ffff; + brm->status |= event_status; + } + + /* signal event once */ + if ( signal_event && (brm->event_id!=0) ){ + rtems_event_send(brm->event_id, event_status); + } + +} diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c new file mode 100644 index 0000000000..82e09e8abe --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/1553/b1553brm_pci.c @@ -0,0 +1,132 @@ +/* Select PCI driver */ +#define B1553BRM_NO_AMBA +#define B1553BRM_PCI + +#undef B1553BRM_MAXDEVS + +/* Use only 16K memory */ +#define DMA_MEM_16K + +/* Malloced memory or + * Card local memory + */ +#define B1553BRM_LOCAL_MEM + +#define DONT_DEF_RAMON + +/* memory must be aligned to a 128k boundary */ +unsigned int brmpci_memarea_address; +#define B1553BRM_LOCAL_MEM_ADR brmpci_memarea_address + +/* We have custom address tranlation for HW addresses */ +#define B1553BRM_ADR_TO + +/* No custom MEMAREA=>CPU used since BRM Core work with offsets + * in it's descriptors. + */ +#undef B1553BRM_ADR_FROM + +/* Set registered device name */ +#define B1553BRM_DEVNAME "/dev/brmpci0" +#define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[11]='0'+(no)) + +/* Any non-static function will begin with */ +#define B1553BRM_PREFIX(name) b1553brmpci##name + +/* do nothing, assume that the interrupt handler is called + * setup externally calling b1553_interrupt_handler. + */ +#define B1553BRM_REG_INT(handler,irq,arg) \ + if ( b1553brm_pci_int_reg ) \ + b1553brm_pci_int_reg(handler,irq,arg); + + +#ifdef B1553BRM_ADR_TO +/* Translate a address within the Memory Region (memarea) into an Hardware + * device address. This address is put into hardware registers or descriptors + * so that the hardware can access the Memory Region. + * Example: + * An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000, + * the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000. + */ +unsigned int brmpci_hw_address; +static inline unsigned int memarea_to_hw(unsigned int addr) { + /* don't translate? */ + if ( brmpci_hw_address == 0xffffffff ) + return addr; + return ((addr & 0x000fffff) | brmpci_hw_address); +} +#endif + +/* not used since BRM Core work with offsets */ +#ifdef B1553BRM_ADR_FROM +unsigned int brmpci_cpu_access_address; +static inline unsigned int hw_to_cpu(unsigned int addr) { + /* don't translate? */ + if ( brmpci_cpu_address == 0xffffffff ) + return addr; + return ((addr & 0x0fffffff) | brmpci_cpu_address); +} +#endif + +void (*b1553brm_pci_int_reg)(void *handler, int irq, void *arg) = 0; + +static void b1553brmpci_interrupt_handler(int irq, void *arg); + +#include "b1553brm.c" + +/* + * + * memarea = preallocated memory somewhere, pointer to start of memory. + * hw_address = how to translate a memarea address into an HW device AMBA address. + */ + +int b1553brm_pci_register( + amba_confarea_type *bus, + unsigned int clksel, + unsigned int clkdiv, + unsigned int brm_freq, + unsigned int memarea, + unsigned int hw_address + ) +{ + /* Setup configuration */ + + /* if zero malloc will be used */ + brmpci_memarea_address = memarea; + + brmpci_hw_address = hw_address; + +#ifdef B1553BRM_ADR_FROM + brmpci_cpu_address = memarea & 0xf0000000; +#endif + + /* Register the driver */ + return B1553BRM_PREFIX(_register)(bus,clksel,clkdiv,brm_freq); +} + +/* Call this from PCI interrupt handler + * irq = the irq number of the HW device local to that IRQMP controller + * + */ +static void b1553brmpci_interrupt_handler(int irq, void *arg){ + brm_interrupt(arg); +} + +#if 0 +int b1553brm_pci_interrupt_handler(int irqmask){ + int i; + unsigned int mask=0; + /* find minor */ + for(i=0; i<brm_cores; i++){ + if ( (1<<brms[i].irqno) & irqmask ){ + mask |= 1<<brms[i].irqno; + brm_interrupt(&brms[i]); + /* more interrupts to scan for? */ + if ( irqmask & ~mask ) + return mask; /* handled */ + } + } + return mask; +} +#endif diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c b/c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c new file mode 100644 index 0000000000..45e619fb0d --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/1553/b1553brm_rasta.c @@ -0,0 +1,115 @@ +/* Select PCI driver */ +#define B1553BRM_NO_AMBA +#define B1553BRM_PCI + +#undef B1553BRM_MAXDEVS + +/* Use only 16K memory */ +#define DMA_MEM_128K + +/* Malloced memory or + * Card local memory + */ +#define B1553BRM_LOCAL_MEM + +#define DONT_DEF_RAMON + +/* memory must be aligned to a 128k boundary */ +unsigned int brmrasta_memarea_address; +#define B1553BRM_LOCAL_MEM_ADR brmrasta_memarea_address + +/* We have custom address tranlation for HW addresses */ +#define B1553BRM_ADR_TO + +/* No custom MEMAREA=>CPU used since BRM Core work with offsets + * in it's descriptors. + */ +#undef B1553BRM_ADR_FROM + +/* Set registered device name */ +#define B1553BRM_DEVNAME "/dev/brmrasta0" +#define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no)) + +/* Any non-static function will begin with */ +#define B1553BRM_PREFIX(name) b1553brmrasta##name + +/* do nothing, assume that the interrupt handler is called + * setup externally calling b1553_interrupt_handler. + */ +#define B1553BRM_REG_INT(handler,irq,arg) \ + if ( b1553brm_rasta_int_reg ) \ + b1553brm_rasta_int_reg(handler,irq,arg); + + +#ifdef B1553BRM_ADR_TO +/* Translate a address within the Memory Region (memarea) into an Hardware + * device address. This address is put into hardware registers or descriptors + * so that the hardware can access the Memory Region. + * Example: + * An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000, + * the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000. + */ +unsigned int brmrasta_hw_address; +static inline unsigned int memarea_to_hw(unsigned int addr) { + /* don't translate? */ + if ( brmrasta_hw_address == 0xffffffff ) + return addr; + return ((addr & 0x0fffffff) | brmrasta_hw_address); +} +#endif + +/* not used since BRM Core work with offsets */ +#ifdef B1553BRM_ADR_FROM +unsigned int brmrasta_cpu_access_address; +static inline unsigned int hw_to_cpu(unsigned int addr) { + /* don't translate? */ + if ( brmrasta_cpu_address == 0xffffffff ) + return addr; + return ((addr & 0x0fffffff) | brmrasta_cpu_address); +} +#endif + +void (*b1553brm_rasta_int_reg)(void *handler, int irq, void *arg) = 0; + +static void b1553brmrasta_interrupt_handler(int irq, void *arg); + +#include "b1553brm.c" + +/* + * + * memarea = preallocated memory somewhere, pointer to start of memory. + * hw_address = how to translate a memarea address into an HW device AMBA address. + */ + +int b1553brm_rasta_register( + amba_confarea_type *bus, + unsigned int clksel, + unsigned int clkdiv, + unsigned int brm_freq, + unsigned int memarea, + unsigned int hw_address + ) +{ + /* Setup configuration */ + + /* if zero the malloc will be used */ + brmrasta_memarea_address = memarea; + + brmrasta_hw_address = hw_address; + +#ifdef B1553BRM_ADR_FROM + brmrasta_cpu_address = memarea & 0xf0000000; +#endif + + /* Register the driver */ + return B1553BRM_PREFIX(_register)(bus,clksel,clkdiv,brm_freq); +} + +/* Call this from RASTA interrupt handler + * irq = the irq number of the HW device local to that IRQMP controller + * + */ +static void b1553brmrasta_interrupt_handler(int irq, void *arg){ + brm_interrupt(arg); +} + |