forked from Imagelibrary/rtems
bsps/sparc: Move shared files to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
1548
bsps/sparc/shared/1553/b1553brm.c
Normal file
1548
bsps/sparc/shared/1553/b1553brm.c
Normal file
File diff suppressed because it is too large
Load Diff
856
bsps/sparc/shared/1553/b1553rt.c
Normal file
856
bsps/sparc/shared/1553/b1553rt.c
Normal file
@@ -0,0 +1,856 @@
|
||||
/*
|
||||
* 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.org/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 <bsp/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", DRVMGR_KT_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 = (unsigned int)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", DRVMGR_KT_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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
310
bsps/sparc/shared/1553/gr1553b.c
Normal file
310
bsps/sparc/shared/1553/gr1553b.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/* 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.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <drvmgr/ambapp_bus.h>
|
||||
|
||||
#include <bsp/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 */
|
||||
static struct gr1553_device_feature *gr1553_bm_root = NULL;
|
||||
static struct gr1553_device_feature *gr1553_rt_root = NULL;
|
||||
static struct gr1553_device_feature *gr1553_bc_root = NULL;
|
||||
|
||||
/* Driver registered */
|
||||
static int gr1553_driver_registerd = 0;
|
||||
|
||||
/* Add 'feat' to linked list pointed to by 'root'. A minor is also assigned. */
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
if ( pnpinfo->apb_slv == NULL )
|
||||
return DRVMGR_EIO;
|
||||
regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
|
||||
|
||||
/* Stop IRQ */
|
||||
GR1553B_WRITE_REG(®s->imask, 0);
|
||||
GR1553B_WRITE_REG(®s->irq, 0xffffffff);
|
||||
/* Stop BC if not already stopped (just in case) */
|
||||
GR1553B_WRITE_REG(®s->bc_ctrl, 0x15520204);
|
||||
/* Stop RT rx (just in case) */
|
||||
GR1553B_WRITE_REG(®s->rt_cfg, 0x15530000);
|
||||
/* Stop BM logging (just in case) */
|
||||
GR1553B_WRITE_REG(®s->bm_ctrl, 0);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
/* Register the different functionalities that the
|
||||
* core supports.
|
||||
*/
|
||||
static 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;
|
||||
pnpinfo = &ambadev->info;
|
||||
regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
|
||||
|
||||
if ( GR1553B_READ_REG(®s->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(®s->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(®s->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);
|
||||
}
|
||||
|
||||
if ( priv->features == 0 ) {
|
||||
/* no features in HW should never happen.. an I/O error? */
|
||||
free(priv);
|
||||
return DRVMGR_EIO;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
1719
bsps/sparc/shared/1553/gr1553bc.c
Normal file
1719
bsps/sparc/shared/1553/gr1553bc.c
Normal file
File diff suppressed because it is too large
Load Diff
544
bsps/sparc/shared/1553/gr1553bm.c
Normal file
544
bsps/sparc/shared/1553/gr1553bm.c
Normal file
@@ -0,0 +1,544 @@
|
||||
/* 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.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <drvmgr/ambapp_bus.h>
|
||||
|
||||
#include <bsp/gr1553b.h>
|
||||
#include <bsp/gr1553bm.h>
|
||||
|
||||
|
||||
#define GR1553BM_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
|
||||
#define GR1553BM_READ_MEM(adr) (*(volatile uint32_t *)(adr))
|
||||
|
||||
#define GR1553BM_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
|
||||
#define GR1553BM_READ_REG(adr) (*(volatile uint32_t *)(adr))
|
||||
|
||||
/* Use interrupt lock privmitives compatible with SMP defined in
|
||||
* RTEMS 4.11.99 and higher.
|
||||
*/
|
||||
#if (((__RTEMS_MAJOR__ << 16) | (__RTEMS_MINOR__ << 8) | __RTEMS_REVISION__) >= 0x040b63)
|
||||
|
||||
/* map via rtems_interrupt_lock_* API: */
|
||||
#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock)
|
||||
#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name)
|
||||
#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level)
|
||||
#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level)
|
||||
#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level)
|
||||
#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level)
|
||||
#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k
|
||||
#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
|
||||
#define SPIN_FREE(lock) rtems_interrupt_lock_destroy(lock)
|
||||
|
||||
#else
|
||||
|
||||
/* maintain single-core compatibility with older versions of RTEMS: */
|
||||
#define SPIN_DECLARE(name)
|
||||
#define SPIN_INIT(lock, name)
|
||||
#define SPIN_LOCK(lock, level)
|
||||
#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_disable(level)
|
||||
#define SPIN_UNLOCK(lock, level)
|
||||
#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_enable(level)
|
||||
#define SPIN_IRQFLAGS(k) rtems_interrupt_level k
|
||||
#define SPIN_ISR_IRQFLAGS(k)
|
||||
#define SPIN_FREE(lock)
|
||||
|
||||
#ifdef RTEMS_SMP
|
||||
#error SMP mode not compatible with these interrupt lock primitives
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
struct gr1553bm_priv {
|
||||
struct drvmgr_dev **pdev;
|
||||
struct gr1553b_regs *regs;
|
||||
SPIN_DECLARE(devlock);
|
||||
|
||||
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)
|
||||
{
|
||||
SPIN_IRQFLAGS(irqflags);
|
||||
|
||||
/* Enable IRQ source and mark running state */
|
||||
SPIN_LOCK_IRQ(&priv->devlock, irqflags);
|
||||
|
||||
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;
|
||||
|
||||
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
|
||||
}
|
||||
|
||||
static void gr1553bm_hw_stop(struct gr1553bm_priv *priv)
|
||||
{
|
||||
SPIN_IRQFLAGS(irqflags);
|
||||
|
||||
SPIN_LOCK_IRQ(&priv->devlock, irqflags);
|
||||
|
||||
/* 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;
|
||||
|
||||
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
SPIN_INIT(&priv->devlock, "gr1553bm");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
1218
bsps/sparc/shared/1553/gr1553rt.c
Normal file
1218
bsps/sparc/shared/1553/gr1553rt.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user