/* GR1553B driver, used by BC, RT and/or BM driver
*
* COPYRIGHT (c) 2010.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <stdlib.h>
#include <drvmgr/ambapp_bus.h>
#include <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;
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;
if ( ambadev == NULL ) {
return DRVMGR_FAIL;
}
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);
}
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);
}
}