/* 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 #include #include /* 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); } }