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:
840
bsps/sparc/shared/drvmgr/ambapp_bus.c
Normal file
840
bsps/sparc/shared/drvmgr/ambapp_bus.c
Normal file
@@ -0,0 +1,840 @@
|
||||
/* General part of a AMBA Plug & Play bus driver.
|
||||
*
|
||||
* COPYRIGHT (c) 2008.
|
||||
* 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.
|
||||
*
|
||||
* This is the general part of the different AMBA Plug & Play
|
||||
* drivers. The drivers are wrappers around this driver, making
|
||||
* the code size smaller for systems with multiple AMBA Plug &
|
||||
* Play buses.
|
||||
*
|
||||
* The BSP define APBUART_INFO_AVAIL in order to add the info routine
|
||||
* used for debugging.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <drvmgr/ambapp_bus.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <ambapp.h>
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
/*#define DEBUG 1*/
|
||||
#define DBG(args...)
|
||||
/*#define DBG(args...) printk(args)*/
|
||||
|
||||
struct grlib_gptimer_regs {
|
||||
volatile unsigned int scaler_value; /* common timer registers */
|
||||
volatile unsigned int scaler_reload;
|
||||
volatile unsigned int status;
|
||||
volatile unsigned int notused;
|
||||
};
|
||||
|
||||
/* AMBA IMPLEMENTATION */
|
||||
|
||||
static int ambapp_bus_init1(struct drvmgr_bus *bus);
|
||||
static int ambapp_bus_remove(struct drvmgr_bus *bus);
|
||||
static int ambapp_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
|
||||
static int ambapp_int_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
static int ambapp_int_unregister(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
static int ambapp_int_clear(struct drvmgr_dev *dev, int index);
|
||||
static int ambapp_int_mask(struct drvmgr_dev *dev, int index);
|
||||
static int ambapp_int_unmask(struct drvmgr_dev *dev, int index);
|
||||
static int ambapp_get_params(
|
||||
struct drvmgr_dev *dev,
|
||||
struct drvmgr_bus_params *params);
|
||||
static int ambapp_bus_freq_get(
|
||||
struct drvmgr_dev *dev,
|
||||
int options,
|
||||
unsigned int *freq_hz);
|
||||
#ifdef AMBAPPBUS_INFO_AVAIL
|
||||
static void ambapp_dev_info(
|
||||
struct drvmgr_dev *,
|
||||
void (*print)(void *p, char *str),
|
||||
void *p);
|
||||
#endif
|
||||
|
||||
#ifdef RTEMS_SMP
|
||||
static int ambapp_int_set_affinity(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const Processor_mask *cpus);
|
||||
#endif
|
||||
|
||||
static struct drvmgr_bus_ops ambapp_bus_ops =
|
||||
{
|
||||
.init =
|
||||
{
|
||||
/* init1 */ ambapp_bus_init1,
|
||||
/* init2 */ NULL,
|
||||
/* init3 */ NULL,
|
||||
/* init4 */ NULL
|
||||
},
|
||||
.remove = ambapp_bus_remove,
|
||||
.unite = ambapp_unite,
|
||||
.int_register = ambapp_int_register,
|
||||
.int_unregister = ambapp_int_unregister,
|
||||
.int_clear = ambapp_int_clear,
|
||||
.int_mask = ambapp_int_mask,
|
||||
#ifdef RTEMS_SMP
|
||||
.int_set_affinity = ambapp_int_set_affinity,
|
||||
#endif
|
||||
.int_unmask = ambapp_int_unmask,
|
||||
.get_params = ambapp_get_params,
|
||||
.get_freq = ambapp_bus_freq_get,
|
||||
#ifdef AMBAPPBUS_INFO_AVAIL
|
||||
.get_info_dev = ambapp_dev_info,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ambapp_priv {
|
||||
struct ambapp_config *config;
|
||||
};
|
||||
|
||||
static int ambapp_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev)
|
||||
{
|
||||
struct amba_drv_info *adrv;
|
||||
struct amba_dev_id *id;
|
||||
struct amba_dev_info *amba;
|
||||
|
||||
if ( !drv || !dev || !dev->parent )
|
||||
return 0;
|
||||
|
||||
if ( ! (((drv->bus_type == DRVMGR_BUS_TYPE_AMBAPP) && (dev->parent->bus_type == DRVMGR_BUS_TYPE_AMBAPP)) ||
|
||||
((drv->bus_type == DRVMGR_BUS_TYPE_AMBAPP_RMAP) && (dev->parent->bus_type == DRVMGR_BUS_TYPE_AMBAPP_RMAP)) ||
|
||||
((drv->bus_type == DRVMGR_BUS_TYPE_AMBAPP_DIST) && (dev->parent->bus_type == DRVMGR_BUS_TYPE_AMBAPP_DIST)))
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
amba = (struct amba_dev_info *)dev->businfo;
|
||||
if ( !amba )
|
||||
return 0;
|
||||
|
||||
adrv = (struct amba_drv_info *)drv;
|
||||
id = adrv->ids;
|
||||
if ( !id )
|
||||
return 0;
|
||||
while( id->vendor != 0 ) {
|
||||
if ( (id->vendor == amba->id.vendor) &&
|
||||
(id->device == amba->id.device) ) {
|
||||
/* Unite device and driver */
|
||||
DBG("DRV 0x%x and DEV 0x%x united\n", (unsigned int)drv, (unsigned int)dev);
|
||||
return 1;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ambapp_int_get(struct drvmgr_dev *dev, int index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
/* Relative (positive) or absolute (negative) IRQ number */
|
||||
if ( index >= 0 ) {
|
||||
/* IRQ Index relative to Cores base IRQ */
|
||||
|
||||
/* Get Base IRQ */
|
||||
irq = ((struct amba_dev_info *)dev->businfo)->info.irq;
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
irq += index;
|
||||
} else {
|
||||
/* Absolute IRQ number */
|
||||
irq = -index;
|
||||
}
|
||||
return irq;
|
||||
}
|
||||
|
||||
static int ambapp_int_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
int irq;
|
||||
|
||||
priv = dev->parent->priv;
|
||||
|
||||
/* Get IRQ number from index and device information */
|
||||
irq = ambapp_int_get(dev, index);
|
||||
if ( irq < 0 )
|
||||
return DRVMGR_EINVAL;
|
||||
|
||||
DBG("Register interrupt on 0x%x for dev 0x%x (IRQ: %d)\n",
|
||||
(unsigned int)dev->parent->dev, (unsigned int)dev, irq);
|
||||
|
||||
if ( priv->config->ops->int_register ) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->int_register(dev, irq, info, isr, arg);
|
||||
} else {
|
||||
return DRVMGR_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static int ambapp_int_unregister(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
int irq;
|
||||
|
||||
priv = dev->parent->priv;
|
||||
|
||||
/* Get IRQ number from index and device information */
|
||||
irq = ambapp_int_get(dev, index);
|
||||
if ( irq < 0 )
|
||||
return DRVMGR_EINVAL;
|
||||
|
||||
DBG("Unregister interrupt on 0x%x for dev 0x%x (IRQ: %d)\n",
|
||||
(unsigned int)dev->parent->dev, (unsigned int)dev, irq);
|
||||
|
||||
if ( priv->config->ops->int_unregister ) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->int_unregister(dev, irq, isr, arg);
|
||||
} else {
|
||||
return DRVMGR_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static int ambapp_int_clear(
|
||||
struct drvmgr_dev *dev,
|
||||
int index)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
int irq;
|
||||
|
||||
priv = dev->parent->priv;
|
||||
|
||||
/* Get IRQ number from index and device information */
|
||||
irq = ambapp_int_get(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
DBG("Clear interrupt on 0x%x for dev 0x%x (IRQ: %d)\n",
|
||||
(unsigned int)dev->parent->dev, (unsigned int)dev, irq);
|
||||
|
||||
if ( priv->config->ops->int_clear ) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->int_clear(dev, irq);
|
||||
} else {
|
||||
return DRVMGR_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static int ambapp_int_mask(
|
||||
struct drvmgr_dev *dev,
|
||||
int index)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
int irq;
|
||||
|
||||
priv = dev->parent->priv;
|
||||
|
||||
/* Get IRQ number from index and device information */
|
||||
irq = ambapp_int_get(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
DBG("MASK interrupt on 0x%x for dev 0x%x (IRQ: %d)\n",
|
||||
(unsigned int)dev->parent->dev, (unsigned int)dev, irq);
|
||||
|
||||
if ( priv->config->ops->int_mask ) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->int_mask(dev, irq);
|
||||
} else {
|
||||
return DRVMGR_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static int ambapp_int_unmask(
|
||||
struct drvmgr_dev *dev,
|
||||
int index)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
int irq;
|
||||
|
||||
priv = dev->parent->priv;
|
||||
|
||||
/* Get IRQ number from index and device information */
|
||||
irq = ambapp_int_get(dev, index);
|
||||
if ( irq < 0 )
|
||||
return DRVMGR_EINVAL;
|
||||
|
||||
DBG("UNMASK interrupt on 0x%x for dev 0x%x (IRQ: %d)\n",
|
||||
(unsigned int)dev->parent->dev, (unsigned int)dev, irq);
|
||||
|
||||
if ( priv->config->ops->int_unmask ) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->int_unmask(dev, irq);
|
||||
} else {
|
||||
return DRVMGR_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign frequency to an AMBA Bus */
|
||||
void ambapp_bus_freq_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int amba_interface,
|
||||
unsigned int freq_hz
|
||||
)
|
||||
{
|
||||
struct ambapp_priv *priv = (struct ambapp_priv *)dev->parent->priv;
|
||||
struct ambapp_dev *adev;
|
||||
struct amba_dev_info *pnp = dev->businfo;
|
||||
|
||||
if ( freq_hz == 0 )
|
||||
return;
|
||||
|
||||
if ( amba_interface == DEV_AHB_MST ) {
|
||||
adev = (struct ambapp_dev *)
|
||||
((unsigned int)pnp->info.ahb_mst -
|
||||
sizeof(struct ambapp_dev));
|
||||
} else if ( amba_interface == DEV_AHB_SLV ) {
|
||||
adev = (struct ambapp_dev *)
|
||||
((unsigned int)pnp->info.ahb_slv -
|
||||
sizeof(struct ambapp_dev));
|
||||
} else if ( amba_interface == DEV_APB_SLV ) {
|
||||
adev = (struct ambapp_dev *)
|
||||
((unsigned int)pnp->info.apb_slv -
|
||||
sizeof(struct ambapp_dev));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate Top bus frequency from lower part. The frequency comes
|
||||
* from some kind of hardware able to report local bus frequency.
|
||||
*/
|
||||
ambapp_freq_init(priv->config->abus, adev, freq_hz);
|
||||
}
|
||||
|
||||
static int ambapp_bus_freq_get(
|
||||
struct drvmgr_dev *dev,
|
||||
int options,
|
||||
unsigned int *freq_hz)
|
||||
{
|
||||
struct ambapp_priv *priv = (struct ambapp_priv *)dev->parent->priv;
|
||||
struct ambapp_dev *adev;
|
||||
struct amba_dev_info *pnp = dev->businfo;
|
||||
|
||||
if ( options == DEV_AHB_MST ) {
|
||||
adev = (struct ambapp_dev *)
|
||||
((unsigned int)pnp->info.ahb_mst -
|
||||
sizeof(struct ambapp_dev));
|
||||
} else if ( options == DEV_AHB_SLV ) {
|
||||
adev = (struct ambapp_dev *)
|
||||
((unsigned int)pnp->info.ahb_slv -
|
||||
sizeof(struct ambapp_dev));
|
||||
} else if ( options == DEV_APB_SLV ) {
|
||||
adev = (struct ambapp_dev *)
|
||||
((unsigned int)pnp->info.apb_slv -
|
||||
sizeof(struct ambapp_dev));
|
||||
} else {
|
||||
*freq_hz = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate core/bus frequency from top most bus frequency. */
|
||||
*freq_hz = ambapp_freq_get(priv->config->abus, adev);
|
||||
if ( *freq_hz == 0 )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ambapp_get_params(
|
||||
struct drvmgr_dev *dev,
|
||||
struct drvmgr_bus_params *params)
|
||||
{
|
||||
struct ambapp_priv *priv = dev->parent->priv;
|
||||
|
||||
if ( priv->config->ops->get_params ) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->get_params(dev, params);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AMBAPPBUS_INFO_AVAIL
|
||||
static void ambapp_dev_info(
|
||||
struct drvmgr_dev *dev,
|
||||
void (*print_line)(void *p, char *str),
|
||||
void *p)
|
||||
{
|
||||
struct amba_dev_info *devinfo;
|
||||
struct ambapp_core *core;
|
||||
char buf[64];
|
||||
int ver, i;
|
||||
char *str1, *str2, *str3;
|
||||
unsigned int ahbmst_freq, ahbslv_freq, apbslv_freq;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
devinfo = (struct amba_dev_info *)dev->businfo;
|
||||
if (!devinfo)
|
||||
return;
|
||||
core = &devinfo->info;
|
||||
|
||||
print_line(p, "AMBA PnP DEVICE");
|
||||
|
||||
str1 = ambapp_vendor_id2str(devinfo->id.vendor);
|
||||
if (str1 == NULL)
|
||||
str1 = "unknown";
|
||||
sprintf(buf, "VENDOR ID: 0x%04x (%s)", devinfo->id.vendor, str1);
|
||||
print_line(p, buf);
|
||||
|
||||
str1 = ambapp_device_id2str(devinfo->id.vendor, devinfo->id.device);
|
||||
if (str1 == NULL)
|
||||
str1 = "unknown";
|
||||
sprintf(buf, "DEVICE ID: 0x%04x (%s)", devinfo->id.device, str1);
|
||||
print_line(p, buf);
|
||||
|
||||
ahbmst_freq = ahbslv_freq = apbslv_freq = 0;
|
||||
ver = 0;
|
||||
str1 = str2 = str3 = "";
|
||||
if (core->ahb_mst) {
|
||||
str1 = "AHBMST ";
|
||||
ver = core->ahb_mst->ver;
|
||||
ambapp_bus_freq_get(dev, DEV_AHB_MST, &ahbmst_freq);
|
||||
}
|
||||
if (core->ahb_slv) {
|
||||
str2 = "AHBSLV ";
|
||||
ver = core->ahb_slv->ver;
|
||||
ambapp_bus_freq_get(dev, DEV_AHB_SLV, &ahbslv_freq);
|
||||
}
|
||||
if (core->apb_slv) {
|
||||
str3 = "APBSLV";
|
||||
ver = core->apb_slv->ver;
|
||||
ambapp_bus_freq_get(dev, DEV_APB_SLV, &apbslv_freq);
|
||||
}
|
||||
|
||||
sprintf(buf, "IRQ: %d", ambapp_int_get(dev, 0));
|
||||
print_line(p, buf);
|
||||
|
||||
sprintf(buf, "VERSION: 0x%x", ver);
|
||||
print_line(p, buf);
|
||||
|
||||
sprintf(buf, "ambapp_core: %p", core);
|
||||
print_line(p, buf);
|
||||
|
||||
sprintf(buf, "interfaces: %s%s%s", str1, str2, str3);
|
||||
print_line(p, buf);
|
||||
|
||||
if (ahbmst_freq != 0) {
|
||||
sprintf(buf, "AHBMST FREQ: %dkHz", ahbmst_freq/1000);
|
||||
print_line(p, buf);
|
||||
}
|
||||
|
||||
if (ahbslv_freq != 0) {
|
||||
sprintf(buf, "AHBSLV FREQ: %dkHz", ahbslv_freq/1000);
|
||||
print_line(p, buf);
|
||||
}
|
||||
|
||||
if (apbslv_freq != 0) {
|
||||
sprintf(buf, "APBSLV FREQ: %dkHz", apbslv_freq/1000);
|
||||
print_line(p, buf);
|
||||
}
|
||||
|
||||
if (core->ahb_slv) {
|
||||
for(i=0; i<4; i++) {
|
||||
if (core->ahb_slv->type[i] == AMBA_TYPE_AHBIO)
|
||||
str1 = " ahbio";
|
||||
else if (core->ahb_slv->type[i] == AMBA_TYPE_MEM)
|
||||
str1 = "ahbmem";
|
||||
else
|
||||
continue;
|
||||
sprintf(buf, " %s[%d]: 0x%08x-0x%08x", str1, i,
|
||||
core->ahb_slv->start[i],
|
||||
core->ahb_slv->start[i]+core->ahb_slv->mask[i]-1);
|
||||
print_line(p, buf);
|
||||
}
|
||||
}
|
||||
if (core->apb_slv) {
|
||||
sprintf(buf, " apb: 0x%08x-0x%08x",
|
||||
core->apb_slv->start,
|
||||
core->apb_slv->start + core->apb_slv->mask - 1);
|
||||
print_line(p, buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fix device in last stage and/or register additional devices.
|
||||
* Function returns:
|
||||
* 0 Register device as normal
|
||||
* 1 Fixup function handles registration
|
||||
*/
|
||||
static int ambapp_dev_fixup(struct drvmgr_dev *dev, struct amba_dev_info *pnp)
|
||||
{
|
||||
/* OCCAN speciality:
|
||||
* Mulitple cores are supported through the same amba AHB interface.
|
||||
* The number of "sub cores" can be detected by decoding the AMBA
|
||||
* Plug&Play version information. verion = ncores. A maximum of 8
|
||||
* sub cores are supported, each separeated with 0x100 inbetween.
|
||||
*
|
||||
* Now, lets detect sub cores.
|
||||
*/
|
||||
if ( (pnp->info.device == GAISLER_CANAHB) &&
|
||||
(pnp->info.vendor == VENDOR_GAISLER) ) {
|
||||
struct drvmgr_dev *newdev, *devs_to_register[8];
|
||||
struct amba_dev_info *pnpinfo;
|
||||
int subcores;
|
||||
int core;
|
||||
|
||||
devs_to_register[0] = dev;
|
||||
subcores = (pnp->info.ahb_slv->ver & 0x7) + 1;
|
||||
for(core = 1; core < subcores; core++) {
|
||||
drvmgr_alloc_dev(&newdev, sizeof(*pnpinfo));
|
||||
memcpy(newdev, dev, sizeof(*newdev));
|
||||
pnpinfo = (struct amba_dev_info *)(newdev+1);
|
||||
memcpy(pnpinfo, pnp, sizeof(*pnp));
|
||||
pnpinfo->info.index = core;
|
||||
pnpinfo->info.irq += core;
|
||||
newdev->businfo = (void *)pnpinfo;
|
||||
|
||||
devs_to_register[core] = newdev;
|
||||
}
|
||||
/* Register all CAN devices */
|
||||
for(core = 0; core < subcores; core++)
|
||||
drvmgr_dev_register(devs_to_register[core]);
|
||||
return 1;
|
||||
} else if ( (pnp->info.device == GAISLER_GPIO) &&
|
||||
(pnp->info.vendor == VENDOR_GAISLER) ) {
|
||||
/* PIO[N] is connected to IRQ[N]. */
|
||||
pnp->info.irq = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ambapp_dev_reg_struct {
|
||||
struct ambapp_bus *abus;
|
||||
struct drvmgr_bus *bus;
|
||||
struct ambapp_dev *ahb_mst;
|
||||
struct ambapp_dev *ahb_slv;
|
||||
struct ambapp_dev *apb_slv;
|
||||
};
|
||||
|
||||
static void ambapp_core_register(
|
||||
struct ambapp_dev *ahb_mst,
|
||||
struct ambapp_dev *ahb_slv,
|
||||
struct ambapp_dev *apb_slv,
|
||||
struct ambapp_dev_reg_struct *arg
|
||||
)
|
||||
{
|
||||
struct drvmgr_dev *newdev;
|
||||
struct amba_dev_info *pnpinfo;
|
||||
unsigned short device;
|
||||
unsigned char vendor;
|
||||
int namelen;
|
||||
char buf[64];
|
||||
|
||||
if ( ahb_mst ) {
|
||||
device = ahb_mst->device;
|
||||
vendor = ahb_mst->vendor;
|
||||
}else if ( ahb_slv ) {
|
||||
device = ahb_slv->device;
|
||||
vendor = ahb_slv->vendor;
|
||||
}else if( apb_slv ) {
|
||||
device = apb_slv->device;
|
||||
vendor = apb_slv->vendor;
|
||||
} else {
|
||||
DBG("NO DEV!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("CORE REGISTER DEV [%x:%x] MST: 0x%x, SLV: 0x%x, APB: 0x%x\n", vendor, device, (unsigned int)ahb_mst, (unsigned int)ahb_slv, (unsigned int)apb_slv);
|
||||
|
||||
/* Get unique device name from AMBA data base by combining VENDOR and
|
||||
* DEVICE short names
|
||||
*/
|
||||
namelen = ambapp_vendev_id2str(vendor, device, buf);
|
||||
|
||||
/* Allocate a device */
|
||||
drvmgr_alloc_dev(&newdev, sizeof(struct amba_dev_info) + namelen);
|
||||
pnpinfo = (struct amba_dev_info *)(newdev + 1);
|
||||
newdev->parent = arg->bus; /* Ourselfs */
|
||||
newdev->minor_drv = 0;
|
||||
newdev->minor_bus = 0;
|
||||
newdev->priv = NULL;
|
||||
newdev->drv = NULL;
|
||||
if (namelen > 0) {
|
||||
newdev->name = (char *)(pnpinfo + 1);
|
||||
strcpy(newdev->name, buf);
|
||||
} else {
|
||||
newdev->name = NULL;
|
||||
}
|
||||
newdev->next_in_drv = NULL;
|
||||
newdev->bus = NULL;
|
||||
|
||||
/* Init PnP information, Assign Core interfaces with this device */
|
||||
pnpinfo->id.vendor = vendor;
|
||||
pnpinfo->id.device = device;
|
||||
pnpinfo->info.vendor = vendor;
|
||||
pnpinfo->info.device = device;
|
||||
pnpinfo->info.index = 0;
|
||||
if ( ahb_mst ) {
|
||||
pnpinfo->info.ahb_mst = (struct ambapp_ahb_info *)
|
||||
ahb_mst->devinfo;
|
||||
ambapp_alloc_dev(ahb_mst, (void *)newdev);
|
||||
if ( pnpinfo->info.ahb_mst->irq )
|
||||
pnpinfo->info.irq = pnpinfo->info.ahb_mst->irq;
|
||||
}
|
||||
if ( ahb_slv ) {
|
||||
pnpinfo->info.ahb_slv = (struct ambapp_ahb_info *)
|
||||
ahb_slv->devinfo;
|
||||
ambapp_alloc_dev(ahb_slv, (void *)newdev);
|
||||
if ( pnpinfo->info.ahb_slv->irq )
|
||||
pnpinfo->info.irq = pnpinfo->info.ahb_slv->irq;
|
||||
}
|
||||
if ( apb_slv ) {
|
||||
pnpinfo->info.apb_slv = (struct ambapp_apb_info *)
|
||||
apb_slv->devinfo;
|
||||
ambapp_alloc_dev(apb_slv, (void *)newdev);
|
||||
if ( pnpinfo->info.apb_slv->irq )
|
||||
pnpinfo->info.irq = pnpinfo->info.apb_slv->irq;
|
||||
}
|
||||
if ( pnpinfo->info.irq == 0 )
|
||||
pnpinfo->info.irq = -1; /* indicate no IRQ */
|
||||
|
||||
/* Connect device with PnP information */
|
||||
newdev->businfo = (void *)pnpinfo;
|
||||
|
||||
if ( ambapp_dev_fixup(newdev, pnpinfo) == 0 )
|
||||
drvmgr_dev_register(newdev); /* Register New Device */
|
||||
}
|
||||
|
||||
/* Fix device registration.
|
||||
* Function returns:
|
||||
* 0 Register device as normal
|
||||
* 1 Fixup function handles registration
|
||||
*/
|
||||
static int ambapp_dev_register_fixup(struct ambapp_dev *dev, struct ambapp_dev_reg_struct *p)
|
||||
{
|
||||
/* GR740 GRPCI2 speciality:
|
||||
* - In the GR740 the APB_SLV is detected before the AHB_SLV
|
||||
* which makes the registration incorrect. We deal with it in
|
||||
* this function. */
|
||||
if ( (dev->dev_type == DEV_APB_SLV) &&
|
||||
(dev->device == GAISLER_GRPCI2) &&
|
||||
(dev->vendor == VENDOR_GAISLER) &&
|
||||
(p->ahb_slv == NULL) ) {
|
||||
DBG("GRPCI2 APB_SLV detected before AHB_SLV. Skipping APB_SLV registration.\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register one AMBA device */
|
||||
static int ambapp_dev_register(struct ambapp_dev *dev, int index, void *arg)
|
||||
{
|
||||
struct ambapp_dev_reg_struct *p = arg;
|
||||
|
||||
#ifdef DEBUG
|
||||
char *type;
|
||||
|
||||
if ( dev->dev_type == DEV_AHB_MST )
|
||||
type = "AHB MST";
|
||||
else if ( dev->dev_type == DEV_AHB_SLV )
|
||||
type = "AHB SLV";
|
||||
else if ( dev->dev_type == DEV_APB_SLV )
|
||||
type = "APB SLV";
|
||||
|
||||
DBG("Found [%d:%x:%x], %s\n", index, dev->vendor, dev->device, type);
|
||||
#endif
|
||||
|
||||
/* Fixup for device registration */
|
||||
if (ambapp_dev_register_fixup(dev, p)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( dev->dev_type == DEV_AHB_MST ) {
|
||||
if ( p->ahb_mst ) {
|
||||
/* This should not happen */
|
||||
printk("ambapp_dev_register: ahb_mst not NULL!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Remember AHB Master */
|
||||
p->ahb_mst = dev;
|
||||
|
||||
/* Find AHB Slave and APB slave for this Core */
|
||||
ambapp_for_each(p->abus, (OPTIONS_AHB_SLVS|OPTIONS_APB_SLVS|OPTIONS_FREE), dev->vendor, dev->device, ambapp_dev_register, p);
|
||||
|
||||
ambapp_core_register(p->ahb_mst, p->ahb_slv, p->apb_slv, p);
|
||||
p->ahb_mst = p->ahb_slv = p->apb_slv = NULL;
|
||||
return 0;
|
||||
|
||||
} else if ( dev->dev_type == DEV_AHB_SLV ) {
|
||||
if ( p->ahb_slv ) {
|
||||
/* Already got our AHB Slave interface */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remember AHB Slave */
|
||||
p->ahb_slv = dev;
|
||||
|
||||
if ( p->ahb_mst ) {
|
||||
/* Continue searching for APB Slave */
|
||||
return 0;
|
||||
} else {
|
||||
/* Find APB Slave interface for this Core */
|
||||
ambapp_for_each(p->abus, (OPTIONS_APB_SLVS|OPTIONS_FREE), dev->vendor, dev->device, ambapp_dev_register, p);
|
||||
|
||||
ambapp_core_register(p->ahb_mst, p->ahb_slv, p->apb_slv, p);
|
||||
p->ahb_mst = p->ahb_slv = p->apb_slv = NULL;
|
||||
return 0;
|
||||
}
|
||||
} else if ( dev->dev_type == DEV_APB_SLV ) {
|
||||
if ( p->apb_slv ) {
|
||||
/* This should not happen */
|
||||
printk("ambapp_dev_register: apb_slv not NULL!\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Remember APB Slave */
|
||||
p->apb_slv = dev;
|
||||
|
||||
if ( p->ahb_mst || p->ahb_slv ) {
|
||||
/* Stop scanning */
|
||||
return 1;
|
||||
} else {
|
||||
ambapp_core_register(p->ahb_mst, p->ahb_slv, p->apb_slv, p);
|
||||
p->ahb_mst = p->ahb_slv = p->apb_slv = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register all AMBA devices available on the AMBAPP bus */
|
||||
static int ambapp_ids_register(struct drvmgr_bus *bus)
|
||||
{
|
||||
struct ambapp_priv *priv = bus->priv;
|
||||
struct ambapp_bus *abus;
|
||||
struct ambapp_dev_reg_struct arg;
|
||||
|
||||
DBG("ambapp_ids_register:\n");
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
|
||||
abus = priv->config->abus;
|
||||
arg.abus = abus;
|
||||
arg.bus = bus;
|
||||
|
||||
/* Combine the AHB MST, AHB SLV and APB SLV interfaces of a core. A core has often more than
|
||||
* one interface. A core can not have more than one interface of the same type.
|
||||
*/
|
||||
ambapp_for_each(abus, (OPTIONS_ALL_DEVS|OPTIONS_FREE), -1, -1, ambapp_dev_register, &arg);
|
||||
|
||||
#ifdef DEBUG
|
||||
ambapp_print(abus->root, 1);
|
||||
#endif
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
/*** DEVICE FUNCTIONS ***/
|
||||
|
||||
int ambapp_bus_register(struct drvmgr_dev *dev, struct ambapp_config *config)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
|
||||
if ( !config || !config->ops )
|
||||
return DRVMGR_OK;
|
||||
|
||||
DBG("AMBAPP BUS: initializing\n");
|
||||
|
||||
/* Register BUS */
|
||||
drvmgr_alloc_bus(&dev->bus, sizeof(struct ambapp_priv));
|
||||
priv = (struct ambapp_priv *)(dev->bus + 1);
|
||||
priv->config = config;
|
||||
if ( priv->config->bus_type == DRVMGR_BUS_TYPE_AMBAPP_DIST )
|
||||
dev->bus->bus_type = DRVMGR_BUS_TYPE_AMBAPP_DIST;
|
||||
else if ( priv->config->bus_type == DRVMGR_BUS_TYPE_AMBAPP_RMAP )
|
||||
dev->bus->bus_type = DRVMGR_BUS_TYPE_AMBAPP_RMAP;
|
||||
else
|
||||
dev->bus->bus_type = DRVMGR_BUS_TYPE_AMBAPP;
|
||||
dev->bus->next = NULL;
|
||||
dev->bus->dev = dev;
|
||||
dev->bus->priv = priv;
|
||||
dev->bus->children = NULL;
|
||||
dev->bus->ops = &ambapp_bus_ops;
|
||||
dev->bus->funcs = config->funcs;
|
||||
dev->bus->dev_cnt = 0;
|
||||
dev->bus->reslist = NULL;
|
||||
dev->bus->maps_up = config->maps_up;
|
||||
dev->bus->maps_down = config->maps_down;
|
||||
|
||||
/* Add resource configuration */
|
||||
if ( priv->config->resources )
|
||||
drvmgr_bus_res_add(dev->bus, priv->config->resources);
|
||||
|
||||
drvmgr_bus_register(dev->bus);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
/*** BUS INITIALIZE FUNCTIONS ***/
|
||||
|
||||
/* Initialize the bus, register devices on this bus */
|
||||
static int ambapp_bus_init1(struct drvmgr_bus *bus)
|
||||
{
|
||||
/* Initialize the bus, register devices on this bus */
|
||||
return ambapp_ids_register(bus);
|
||||
}
|
||||
|
||||
static int ambapp_bus_remove(struct drvmgr_bus *bus)
|
||||
{
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
#ifdef RTEMS_SMP
|
||||
static int ambapp_int_set_affinity(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const Processor_mask *cpus)
|
||||
{
|
||||
struct ambapp_priv *priv;
|
||||
int irq;
|
||||
|
||||
priv = dev->parent->priv;
|
||||
|
||||
/* Get IRQ number from index and device information */
|
||||
irq = ambapp_int_get(dev, index);
|
||||
if (irq < 0)
|
||||
return DRVMGR_EINVAL;
|
||||
|
||||
DBG("Set interrupt affinity on 0x%x for dev 0x%x (IRQ: %d)\n",
|
||||
(unsigned int)dev->parent->dev, (unsigned int)dev, irq);
|
||||
|
||||
if (priv->config->ops->int_set_affinity) {
|
||||
/* Let device override driver default */
|
||||
return priv->config->ops->int_set_affinity(dev, irq, cpus);
|
||||
} else {
|
||||
return DRVMGR_ENOSYS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
250
bsps/sparc/shared/drvmgr/ambapp_bus_grlib.c
Normal file
250
bsps/sparc/shared/drvmgr/ambapp_bus_grlib.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/* LEON3 GRLIB AMBA Plug & Play bus driver.
|
||||
*
|
||||
* COPYRIGHT (c) 2008.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* This is driver is a wrapper for the general AMBA Plug & Play bus
|
||||
* driver. This is the root bus driver for GRLIB systems.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <libcpu/access.h>
|
||||
|
||||
#include <drvmgr/ambapp_bus.h>
|
||||
#include <drvmgr/ambapp_bus_grlib.h>
|
||||
#include <bsp/genirq.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#define DBG(args...)
|
||||
/*#define DBG(args...) printk(args)*/
|
||||
|
||||
static int ambapp_grlib_int_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
static int ambapp_grlib_int_unregister(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
static int ambapp_grlib_int_clear(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq);
|
||||
static int ambapp_grlib_int_mask(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq);
|
||||
static int ambapp_grlib_int_unmask(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq);
|
||||
#ifdef RTEMS_SMP
|
||||
static int ambapp_grlib_int_set_affinity(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq,
|
||||
const Processor_mask *cpus);
|
||||
#endif
|
||||
static int ambapp_grlib_get_params(
|
||||
struct drvmgr_dev *dev,
|
||||
struct drvmgr_bus_params *params);
|
||||
|
||||
static int ambapp_grlib_init1(struct drvmgr_dev *dev);
|
||||
static int ambapp_grlib_init2(struct drvmgr_dev *dev);
|
||||
static int ambapp_grlib_remove(struct drvmgr_dev *dev);
|
||||
|
||||
/* READ/WRITE access to SpaceWire target over RMAP */
|
||||
static void *ambapp_grlib_rw_arg(struct drvmgr_dev *dev);
|
||||
|
||||
static struct ambapp_ops ambapp_grlib_ops = {
|
||||
.int_register = ambapp_grlib_int_register,
|
||||
.int_unregister = ambapp_grlib_int_unregister,
|
||||
.int_clear = ambapp_grlib_int_clear,
|
||||
.int_mask = ambapp_grlib_int_mask,
|
||||
.int_unmask = ambapp_grlib_int_unmask,
|
||||
#ifdef RTEMS_SMP
|
||||
.int_set_affinity = ambapp_grlib_int_set_affinity,
|
||||
#endif
|
||||
.get_params = ambapp_grlib_get_params
|
||||
};
|
||||
|
||||
static void *ambapp_grlib_rw_arg(struct drvmgr_dev *dev)
|
||||
{
|
||||
return dev; /* No argument really needed, but for debug? */
|
||||
}
|
||||
|
||||
static struct drvmgr_func ambapp_grlib_funcs[] =
|
||||
{
|
||||
DRVMGR_FUNC(AMBAPP_RW_ARG, ambapp_grlib_rw_arg),
|
||||
|
||||
DRVMGR_FUNC(AMBAPP_R8, _ld8),
|
||||
DRVMGR_FUNC(AMBAPP_R16, _ld16),
|
||||
DRVMGR_FUNC(AMBAPP_R32, _ld32),
|
||||
DRVMGR_FUNC(AMBAPP_R64, _ld64),
|
||||
|
||||
DRVMGR_FUNC(AMBAPP_W8, _st8),
|
||||
DRVMGR_FUNC(AMBAPP_W16, _st16),
|
||||
DRVMGR_FUNC(AMBAPP_W32, _st32),
|
||||
DRVMGR_FUNC(AMBAPP_W64, _st64),
|
||||
|
||||
DRVMGR_FUNC(AMBAPP_RMEM, memcpy),
|
||||
DRVMGR_FUNC(AMBAPP_WMEM, memcpy),
|
||||
|
||||
DRVMGR_FUNC_END,
|
||||
};
|
||||
|
||||
static struct drvmgr_drv_ops ambapp_grlib_drv_ops =
|
||||
{
|
||||
.init = {ambapp_grlib_init1, ambapp_grlib_init2, NULL, NULL},
|
||||
.remove = ambapp_grlib_remove,
|
||||
.info = NULL,
|
||||
};
|
||||
|
||||
static struct drvmgr_drv ambapp_bus_drv_grlib =
|
||||
{
|
||||
DRVMGR_OBJ_DRV, /* Driver */
|
||||
NULL, /* Next driver */
|
||||
NULL, /* Device list */
|
||||
DRIVER_GRLIB_AMBAPP_ID, /* Driver ID */
|
||||
"AMBAPP_GRLIB_DRV", /* Driver Name */
|
||||
DRVMGR_BUS_TYPE_ROOT, /* Bus Type */
|
||||
&ambapp_grlib_drv_ops,
|
||||
NULL, /* Funcs */
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
static struct grlib_config *drv_mgr_grlib_config = NULL;
|
||||
|
||||
void ambapp_grlib_register(void)
|
||||
{
|
||||
drvmgr_drv_register(&ambapp_bus_drv_grlib);
|
||||
}
|
||||
|
||||
int ambapp_grlib_root_register(struct grlib_config *config)
|
||||
{
|
||||
|
||||
/* Save the configuration for later */
|
||||
drv_mgr_grlib_config = config;
|
||||
|
||||
/* Register root device driver */
|
||||
drvmgr_root_drv_register(&ambapp_bus_drv_grlib);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function called from Driver Manager Initialization Stage 1 */
|
||||
static int ambapp_grlib_init1(struct drvmgr_dev *dev)
|
||||
{
|
||||
struct ambapp_config *config;
|
||||
|
||||
dev->priv = NULL;
|
||||
dev->name = "GRLIB AMBA PnP";
|
||||
|
||||
DBG("AMBAPP GRLIB: intializing\n");
|
||||
|
||||
config = malloc(sizeof(struct ambapp_config));
|
||||
if ( !config )
|
||||
return RTEMS_NO_MEMORY;
|
||||
|
||||
config->ops = &ambapp_grlib_ops;
|
||||
config->maps_up = DRVMGR_TRANSLATE_ONE2ONE;
|
||||
config->maps_down = DRVMGR_TRANSLATE_ONE2ONE;
|
||||
config->abus = drv_mgr_grlib_config->abus;
|
||||
config->resources = drv_mgr_grlib_config->resources;
|
||||
config->funcs = ambapp_grlib_funcs;
|
||||
config->bus_type = DRVMGR_BUS_TYPE_AMBAPP;
|
||||
|
||||
/* Initialize the generic part of the AMBA Bus */
|
||||
return ambapp_bus_register(dev, config);
|
||||
}
|
||||
|
||||
static int ambapp_grlib_init2(struct drvmgr_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ambapp_grlib_remove(struct drvmgr_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ambapp_grlib_int_register
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
return BSP_shared_interrupt_register(irq, info, isr, arg);
|
||||
}
|
||||
|
||||
static int ambapp_grlib_int_unregister
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq,
|
||||
drvmgr_isr isr,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
return BSP_shared_interrupt_unregister(irq, isr, arg);
|
||||
}
|
||||
|
||||
static int ambapp_grlib_int_clear
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq)
|
||||
{
|
||||
BSP_shared_interrupt_clear(irq);
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
static int ambapp_grlib_int_mask
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq
|
||||
)
|
||||
{
|
||||
BSP_shared_interrupt_mask(irq);
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
static int ambapp_grlib_int_unmask
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq
|
||||
)
|
||||
{
|
||||
BSP_shared_interrupt_unmask(irq);
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
#ifdef RTEMS_SMP
|
||||
static int ambapp_grlib_int_set_affinity
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq,
|
||||
const Processor_mask *cpus
|
||||
)
|
||||
{
|
||||
bsp_interrupt_set_affinity(irq, cpus);
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ambapp_grlib_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
|
||||
{
|
||||
/* Leave params->freq_hz untouched for default */
|
||||
params->dev_prefix = "";
|
||||
return 0;
|
||||
}
|
||||
266
bsps/sparc/shared/drvmgr/ambapp_bus_leon2.c
Normal file
266
bsps/sparc/shared/drvmgr/ambapp_bus_leon2.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/* LEON2 GRLIB AMBA Plug & Play bus driver.
|
||||
*
|
||||
* COPYRIGHT (c) 2008.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* This is driver is a wrapper for the general AMBA Plug & Play bus
|
||||
* driver. This is a bus driver for LEON2-GRLIB systems providing a
|
||||
* AMBA Plug & Play bus, the parent bus must be a LEON2 hardcoded
|
||||
* Bus. All IRQs must be routed to this bus driver in order for IRQs
|
||||
* to work. The PnP information is used to extract IRQs and base
|
||||
* register addresses.
|
||||
*
|
||||
* 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>
|
||||
|
||||
#ifdef LEON2
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libcpu/access.h>
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <drvmgr/ambapp_bus.h>
|
||||
#include <drvmgr/leon2_amba_bus.h>
|
||||
|
||||
#define DBG(args...)
|
||||
|
||||
int ambapp_leon2_int_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
int ambapp_leon2_int_unregister(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
int ambapp_leon2_int_clear(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
int ambapp_leon2_int_mask(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq);
|
||||
int ambapp_leon2_int_unmask(
|
||||
struct drvmgr_dev *dev,
|
||||
int irq);
|
||||
int ambapp_leon2_get_params(
|
||||
struct drvmgr_dev *dev,
|
||||
struct drvmgr_bus_params *params);
|
||||
|
||||
int ambapp_leon2_init1(struct drvmgr_dev *dev);
|
||||
int ambapp_leon2_init2(struct drvmgr_dev *dev);
|
||||
int ambapp_leon2_remove(struct drvmgr_dev *dev);
|
||||
void ambapp_leon2_register(void);
|
||||
|
||||
/* READ/WRITE access to SpaceWire target over RMAP */
|
||||
void *ambapp_leon2_rw_arg(struct drvmgr_dev *dev);
|
||||
|
||||
struct ambappl2_priv {
|
||||
struct ambapp_bus abus;
|
||||
struct ambapp_config config;
|
||||
};
|
||||
|
||||
struct ambapp_ops ambapp_leon2_ops = {
|
||||
.int_register = ambapp_leon2_int_register,
|
||||
.int_unregister = ambapp_leon2_int_unregister,
|
||||
.int_clear = ambapp_leon2_int_clear,
|
||||
.int_mask = ambapp_leon2_int_mask,
|
||||
.int_unmask = ambapp_leon2_int_unmask,
|
||||
.get_params = ambapp_leon2_get_params
|
||||
};
|
||||
|
||||
struct drvmgr_func ambapp_leon2_funcs[] = {
|
||||
DRVMGR_FUNC(AMBAPP_RW_ARG, ambapp_leon2_rw_arg),
|
||||
|
||||
DRVMGR_FUNC(AMBAPP_R8, _ld8),
|
||||
DRVMGR_FUNC(AMBAPP_R16, _ld16),
|
||||
DRVMGR_FUNC(AMBAPP_R32, _ld32),
|
||||
DRVMGR_FUNC(AMBAPP_R64, _ld64),
|
||||
|
||||
DRVMGR_FUNC(AMBAPP_W8, _st8),
|
||||
DRVMGR_FUNC(AMBAPP_W16, _st16),
|
||||
DRVMGR_FUNC(AMBAPP_W32, _st32),
|
||||
DRVMGR_FUNC(AMBAPP_W64, _st64),
|
||||
|
||||
DRVMGR_FUNC(AMBAPP_RMEM, memcpy),
|
||||
DRVMGR_FUNC(AMBAPP_WMEM, memcpy),
|
||||
|
||||
DRVMGR_FUNC_END
|
||||
};
|
||||
|
||||
struct drvmgr_drv_ops ambapp_ops = {
|
||||
.init = {ambapp_leon2_init1, ambapp_leon2_init2, NULL, NULL},
|
||||
.remove = ambapp_leon2_remove,
|
||||
.info = NULL,
|
||||
};
|
||||
|
||||
struct leon2_amba_dev_id ambapp_leon2_ids[] = {
|
||||
{LEON2_AMBA_AMBAPP_ID},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct leon2_amba_drv_info ambapp_bus_drv_leon2 = {
|
||||
{
|
||||
DRVMGR_OBJ_DRV, /* Driver */
|
||||
NULL, /* Next driver */
|
||||
NULL, /* Device list */
|
||||
DRIVER_LEON2_AMBA_AMBAPP, /* Driver ID */
|
||||
"AMBAPP_LEON2_DRV", /* Driver Name */
|
||||
DRVMGR_BUS_TYPE_LEON2_AMBA, /* Bus Type */
|
||||
&ambapp_ops,
|
||||
NULL, /* Funcs */
|
||||
0,
|
||||
sizeof(struct ambappl2_priv), /* Let DrvMgr allocate priv */
|
||||
},
|
||||
&ambapp_leon2_ids[0]
|
||||
};
|
||||
|
||||
void ambapp_leon2_register(void)
|
||||
{
|
||||
drvmgr_drv_register(&ambapp_bus_drv_leon2.general);
|
||||
}
|
||||
|
||||
/* Function called from a hard configuration */
|
||||
int ambapp_leon2_init1(struct drvmgr_dev *dev)
|
||||
{
|
||||
union drvmgr_key_value *value;
|
||||
struct ambappl2_priv *priv = dev->priv;
|
||||
struct leon2_amba_dev_info *devinfo;
|
||||
struct ambapp_config *config;
|
||||
unsigned int ioarea;
|
||||
unsigned int freq_hz;
|
||||
LEON_Register_Map *regs;
|
||||
|
||||
dev->name = "LEON2 AMBA PnP";
|
||||
|
||||
if (!priv)
|
||||
return DRVMGR_NOMEM;
|
||||
|
||||
config = &priv->config;
|
||||
config->abus = &priv->abus;
|
||||
config->ops = &ambapp_leon2_ops;
|
||||
config->maps_up = DRVMGR_TRANSLATE_ONE2ONE;
|
||||
config->maps_down = DRVMGR_TRANSLATE_ONE2ONE;
|
||||
config->funcs = ambapp_leon2_funcs;
|
||||
config->bus_type = DRVMGR_BUS_TYPE_LEON2_AMBA;
|
||||
|
||||
/* Get AMBA PnP Area from REG0 */
|
||||
devinfo = (struct leon2_amba_dev_info *)dev->businfo;
|
||||
ioarea = devinfo->reg_base;
|
||||
|
||||
/* Scan AMBA PnP Bus. ABUS has already been cleared with memset() */
|
||||
ambapp_scan(&priv->abus, ioarea, NULL, NULL);
|
||||
|
||||
/* Try to get Configuration from resource configuration */
|
||||
|
||||
value = drvmgr_dev_key_get(dev, "busFreq", DRVMGR_KT_INT);
|
||||
if (value) {
|
||||
/* Set frequency of AMBA bus if specified by user. The frequency
|
||||
* must be for AHB bus which IOAREA matches (AHB bus 0).
|
||||
*/
|
||||
freq_hz = value->i;
|
||||
} else {
|
||||
/* Get Bus/LEON2 Frequency from timer prescaler,
|
||||
* the hardcoded address is used to get to timer
|
||||
*/
|
||||
regs = (LEON_Register_Map *) 0x80000000;
|
||||
freq_hz = (regs->Scaler_Reload + 1) * 1000 * 1000;
|
||||
}
|
||||
/* Note that this can be overrided by a driver on the AMBA PnP bus.*/
|
||||
ambapp_freq_init(&priv->abus, NULL, freq_hz);
|
||||
|
||||
value = drvmgr_dev_key_get(dev, "drvRes", DRVMGR_KT_POINTER);
|
||||
if (!value) {
|
||||
DBG("ambapp_leon2_init1: Failed getting resource drvRes\n");
|
||||
config->resources = NULL;
|
||||
} else {
|
||||
DBG("ambapp_leon2_init1: drvRes: 0x%08x\n", (unsigned int)value->ptr);
|
||||
config->resources = (struct drvmgr_bus_res *)value->ptr;
|
||||
}
|
||||
|
||||
/* Initialize the AMBA Bus */
|
||||
return ambapp_bus_register(dev, config);
|
||||
}
|
||||
|
||||
int ambapp_leon2_init2(struct drvmgr_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ambapp_leon2_remove(struct drvmgr_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *ambapp_leon2_rw_arg(struct drvmgr_dev *dev)
|
||||
{
|
||||
return dev; /* No argument really needed, by for debug */
|
||||
}
|
||||
|
||||
int ambapp_leon2_int_register
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
/* Let LEON2 bus handle interrupt requests */
|
||||
return drvmgr_interrupt_register(dev->parent->dev, index, info, isr, arg);
|
||||
}
|
||||
|
||||
int ambapp_leon2_int_unregister
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
/* Let LEON2 bus handle interrupt requests */
|
||||
return drvmgr_interrupt_unregister(dev->parent->dev, index, isr, arg);
|
||||
}
|
||||
|
||||
int ambapp_leon2_int_clear
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index
|
||||
)
|
||||
{
|
||||
/* Let LEON2 bus handle interrupt requests */
|
||||
return drvmgr_interrupt_clear(dev->parent->dev, index);
|
||||
}
|
||||
|
||||
int ambapp_leon2_int_mask
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index
|
||||
)
|
||||
{
|
||||
/* Let LEON2 bus handle interrupt requests */
|
||||
return drvmgr_interrupt_mask(dev->parent->dev, index);
|
||||
}
|
||||
|
||||
int ambapp_leon2_int_unmask
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index
|
||||
)
|
||||
{
|
||||
/* Let LEON2 bus handle interrupt requests */
|
||||
return drvmgr_interrupt_unmask(dev->parent->dev, index);
|
||||
}
|
||||
|
||||
int ambapp_leon2_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
|
||||
{
|
||||
params->dev_prefix = "";
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
20
bsps/sparc/shared/drvmgr/get_resarray_count.c
Normal file
20
bsps/sparc/shared/drvmgr/get_resarray_count.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/* Common driver configuration routines.
|
||||
*
|
||||
* COPYRIGHT (c) 2015.
|
||||
* Cobham Gaisler.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <drvmgr/bspcommon.h>
|
||||
|
||||
int get_resarray_count(struct drvmgr_bus_res **array)
|
||||
{
|
||||
int i = 0;
|
||||
while (array[i] != NULL)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
449
bsps/sparc/shared/drvmgr/leon2_amba_bus.c
Normal file
449
bsps/sparc/shared/drvmgr/leon2_amba_bus.c
Normal file
@@ -0,0 +1,449 @@
|
||||
/* LEON2 Hardcoded bus driver.
|
||||
*
|
||||
* COPYRIGHT (c) 2008.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* Bus driver for a hardcoded setup. LEON2 systems have some
|
||||
* cores always present, here called "Standard Cores". In
|
||||
* addtion to the standard cores there are often extra cores
|
||||
* that can be defined using the "Custom Cores" mechanism.
|
||||
*
|
||||
* A Core is described by assigning a base register and
|
||||
* IRQ0..IRQ15 using the leon2_core structure.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <drvmgr/leon2_amba_bus.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#define DBG(args...)
|
||||
/*#define DBG(args...) printk(args)*/
|
||||
|
||||
struct drvmgr_drv leon2_bus_drv;
|
||||
|
||||
int leon2_amba_bus_init1(struct drvmgr_bus *bus);
|
||||
int leon2_amba_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
|
||||
int leon2_amba_int_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
int leon2_amba_int_unregister(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
int leon2_amba_int_clear(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
int leon2_amba_int_mask(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
int leon2_amba_int_unmask(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
|
||||
/* LEON2 bus operations */
|
||||
struct drvmgr_bus_ops leon2_amba_bus_ops =
|
||||
{
|
||||
.init = {
|
||||
leon2_amba_bus_init1,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
.remove = NULL,
|
||||
.unite = leon2_amba_unite,
|
||||
.int_register = leon2_amba_int_register,
|
||||
.int_unregister = leon2_amba_int_unregister,
|
||||
.int_clear = leon2_amba_int_clear,
|
||||
.int_mask = leon2_amba_int_mask,
|
||||
.int_unmask = leon2_amba_int_unmask,
|
||||
.get_params = NULL,
|
||||
};
|
||||
|
||||
struct leon2_isr_handler {
|
||||
void (*handler)(int irq, void *arg);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
/* Standard LEON2 configuration */
|
||||
|
||||
struct drvmgr_key leon2_timers[] =
|
||||
{
|
||||
{"REG0", DRVMGR_KT_INT, {0x80000040}},
|
||||
{"IRQ0", DRVMGR_KT_INT, {8}},
|
||||
{"IRQ1", DRVMGR_KT_INT, {9}},
|
||||
DRVMGR_KEY_EMPTY
|
||||
};
|
||||
|
||||
struct drvmgr_key leon2_uart1[] =
|
||||
{
|
||||
{"REG0", DRVMGR_KT_INT, {0x80000070}},
|
||||
{"IRQ0", DRVMGR_KT_INT, {3}},
|
||||
DRVMGR_KEY_EMPTY
|
||||
};
|
||||
|
||||
struct drvmgr_key leon2_uart2[] =
|
||||
{
|
||||
{"REG0", DRVMGR_KT_INT, {0x80000080}},
|
||||
{"IRQ0", DRVMGR_KT_INT, {2}},
|
||||
DRVMGR_KEY_EMPTY
|
||||
};
|
||||
|
||||
struct drvmgr_key leon2_irqctrl[] =
|
||||
{
|
||||
{"REG0", DRVMGR_KT_INT, {0x80000090}},
|
||||
DRVMGR_KEY_EMPTY
|
||||
};
|
||||
|
||||
struct drvmgr_key leon2_gpio0[] =
|
||||
{
|
||||
{"REG0", DRVMGR_KT_INT, {0x800000A0}},
|
||||
{"IRQ0", DRVMGR_KT_INT, {4}},
|
||||
{"IRQ1", DRVMGR_KT_INT, {5}},
|
||||
{"IRQ2", DRVMGR_KT_INT, {6}},
|
||||
{"IRQ3", DRVMGR_KT_INT, {7}},
|
||||
DRVMGR_KEY_EMPTY
|
||||
};
|
||||
|
||||
struct leon2_core leon2_std_cores[] =
|
||||
{
|
||||
{{LEON2_AMBA_TIMER_ID}, "Timers", &leon2_timers[0]},
|
||||
{{LEON2_AMBA_UART_ID}, "Uart1", &leon2_uart1[0]},
|
||||
{{LEON2_AMBA_UART_ID}, "Uart2", &leon2_uart2[0]},
|
||||
{{LEON2_AMBA_IRQCTRL_ID}, "IRQCtrl", &leon2_irqctrl[0]},
|
||||
{{LEON2_AMBA_GPIO_ID}, "GPIO", &leon2_gpio0[0]},
|
||||
EMPTY_LEON2_CORE
|
||||
};
|
||||
|
||||
static struct leon2_bus *leon2_bus_config = NULL;
|
||||
static struct drvmgr_bus_res *leon2_bus_res = NULL;
|
||||
|
||||
int leon2_root_register(
|
||||
struct leon2_bus *bus_config,
|
||||
struct drvmgr_bus_res *resources)
|
||||
{
|
||||
/* Save the configuration for later */
|
||||
leon2_bus_config = bus_config;
|
||||
leon2_bus_res = resources;
|
||||
|
||||
/* Register root device driver */
|
||||
drvmgr_root_drv_register(&leon2_bus_drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leon2_amba_dev_register(
|
||||
struct drvmgr_bus *bus,
|
||||
struct leon2_core *core,
|
||||
int index)
|
||||
{
|
||||
struct drvmgr_dev *newdev;
|
||||
struct leon2_amba_dev_info *info;
|
||||
union drvmgr_key_value *value;
|
||||
char irq_name[8];
|
||||
int i;
|
||||
|
||||
/* Allocate new device and businfo */
|
||||
drvmgr_alloc_dev(&newdev, sizeof(struct leon2_amba_dev_info));
|
||||
info = (struct leon2_amba_dev_info *)(newdev + 1);
|
||||
|
||||
/* Set Core ID */
|
||||
info->core_id = core->id.core_id;
|
||||
|
||||
/* Get information from bus configuration */
|
||||
value = drvmgr_key_val_get(core->keys, "REG0", DRVMGR_KT_INT);
|
||||
if ( !value ) {
|
||||
printk("leon2_amba_dev_register: Failed getting resource REG0\n");
|
||||
info->reg_base = 0x00000000;
|
||||
} else {
|
||||
DBG("leon2_amba_dev_register: REG0: 0x%08x\n", value->i);
|
||||
info->reg_base = value->i;
|
||||
}
|
||||
|
||||
strcpy(irq_name, "IRQ");
|
||||
for(i=0; i<16; i++){
|
||||
if ( i < 10 ){
|
||||
irq_name[3] = '0' + i;
|
||||
irq_name[4] = '\0';
|
||||
} else {
|
||||
irq_name[3] = '1';
|
||||
irq_name[4] = '0' + (i-10);
|
||||
irq_name[5] = '\0';
|
||||
}
|
||||
|
||||
value = drvmgr_key_val_get(core->keys, irq_name, DRVMGR_KT_INT);
|
||||
if ( !value ) {
|
||||
DBG("leon2_amba_dev_register: Failed getting resource IRQ%d for REG 0x%x\n", i, info->reg_base);
|
||||
info->irqs[i] = 0;
|
||||
} else {
|
||||
DBG("leon2_amba_dev_register: IRQ%d: %d\n", i, value->i);
|
||||
info->irqs[i] = value->i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init new device */
|
||||
newdev->next = NULL;
|
||||
newdev->parent = bus; /* Ourselfs */
|
||||
newdev->minor_drv = 0;
|
||||
newdev->minor_bus = 0;
|
||||
newdev->businfo = (void *)info;
|
||||
newdev->priv = NULL;
|
||||
newdev->drv = NULL;
|
||||
newdev->name = core->name;
|
||||
newdev->next_in_drv = NULL;
|
||||
newdev->bus = NULL;
|
||||
|
||||
/* Register new device */
|
||||
drvmgr_dev_register(newdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leon2_amba_init1(struct drvmgr_dev *dev)
|
||||
{
|
||||
/* Init our own device */
|
||||
dev->priv = NULL;
|
||||
dev->name = "LEON2 AMBA";
|
||||
|
||||
/* Init the bus */
|
||||
drvmgr_alloc_bus(&dev->bus, 0);
|
||||
dev->bus->bus_type = DRVMGR_BUS_TYPE_LEON2_AMBA;
|
||||
dev->bus->next = NULL;
|
||||
dev->bus->dev = dev;
|
||||
dev->bus->priv = NULL;
|
||||
dev->bus->children = NULL;
|
||||
dev->bus->ops = &leon2_amba_bus_ops;
|
||||
dev->bus->dev_cnt = 0;
|
||||
dev->bus->reslist = NULL;
|
||||
dev->bus->maps_up = leon2_bus_config->maps_up;
|
||||
dev->bus->maps_down = leon2_bus_config->maps_down;
|
||||
drvmgr_bus_register(dev->bus);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
static int leon2_amba_init2(struct drvmgr_dev *dev)
|
||||
{
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
static int leon2_amba_remove(struct drvmgr_dev *dev)
|
||||
{
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
int leon2_amba_bus_init1(struct drvmgr_bus *bus)
|
||||
{
|
||||
struct leon2_core *core;
|
||||
int i;
|
||||
|
||||
if ( leon2_bus_res )
|
||||
drvmgr_bus_res_add(bus, leon2_bus_res);
|
||||
|
||||
/**** REGISTER NEW DEVICES ****/
|
||||
i=0;
|
||||
core = leon2_bus_config->std_cores;
|
||||
if ( core ) {
|
||||
while ( core->id.core_id ) {
|
||||
if ( leon2_amba_dev_register(bus, core, i) ) {
|
||||
return RTEMS_UNSATISFIED;
|
||||
}
|
||||
i++;
|
||||
core++;
|
||||
}
|
||||
}
|
||||
core = leon2_bus_config->custom_cores;
|
||||
if ( core ) {
|
||||
while ( core->id.core_id ) {
|
||||
if ( leon2_amba_dev_register(bus, core, i) ) {
|
||||
return RTEMS_UNSATISFIED;
|
||||
}
|
||||
i++;
|
||||
core++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leon2_amba_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev)
|
||||
{
|
||||
struct leon2_amba_dev_info *info;
|
||||
struct leon2_amba_drv_info *adrv;
|
||||
struct leon2_amba_dev_id *id;
|
||||
|
||||
if ( !drv || !dev || !dev->parent )
|
||||
return 0;
|
||||
|
||||
if ( (drv->bus_type!=DRVMGR_BUS_TYPE_LEON2_AMBA) || (dev->parent->bus_type != DRVMGR_BUS_TYPE_LEON2_AMBA) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
info = (struct leon2_amba_dev_info *)dev->businfo;
|
||||
if ( !info )
|
||||
return 0;
|
||||
|
||||
/* Get LEON2 AMBA driver info */
|
||||
adrv = (struct leon2_amba_drv_info *)drv;
|
||||
id = adrv->ids;
|
||||
if ( !id )
|
||||
return 0;
|
||||
|
||||
while ( id->core_id ) {
|
||||
if ( id->core_id == info->core_id ) {
|
||||
/* Driver is suitable for device, Unite them */
|
||||
return 1;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leon2_amba_get_irq(struct drvmgr_dev *dev, int index)
|
||||
{
|
||||
int irq;
|
||||
struct leon2_amba_dev_info *info;
|
||||
|
||||
if ( !dev || (index > 15) )
|
||||
return -1;
|
||||
|
||||
/* Relative (positive) or absolute (negative) IRQ number */
|
||||
if ( index >= 0 ) {
|
||||
/* IRQ Index relative to Cores base IRQ */
|
||||
|
||||
/* Get IRQ array configured by user */
|
||||
info = (struct leon2_amba_dev_info *)dev->businfo;
|
||||
irq = info->irqs[index];
|
||||
if ( irq == 0 )
|
||||
return -1;
|
||||
} else {
|
||||
/* Absolute IRQ number */
|
||||
irq = -index;
|
||||
}
|
||||
return irq;
|
||||
}
|
||||
|
||||
int leon2_amba_int_register
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = leon2_amba_get_irq(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
DBG("Registering IRQ %d to func 0x%x arg 0x%x\n", irq, (unsigned int)isr, (unsigned int)arg);
|
||||
|
||||
return BSP_shared_interrupt_register(irq, info, isr, arg);
|
||||
}
|
||||
|
||||
int leon2_amba_int_unregister
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = leon2_amba_get_irq(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
DBG("Unregistering IRQ %d to func 0x%x arg 0x%x\n", irq, (unsigned int)handler, (unsigned int)arg);
|
||||
|
||||
return BSP_shared_interrupt_unregister(irq, isr, arg);
|
||||
}
|
||||
|
||||
int leon2_amba_int_clear
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index
|
||||
)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = leon2_amba_get_irq(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
BSP_shared_interrupt_clear(irq);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
int leon2_amba_int_mask
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index
|
||||
)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = leon2_amba_get_irq(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
BSP_shared_interrupt_mask(irq);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
int leon2_amba_int_unmask
|
||||
(
|
||||
struct drvmgr_dev *dev,
|
||||
int index
|
||||
)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = leon2_amba_get_irq(dev, index);
|
||||
if ( irq < 0 )
|
||||
return -1;
|
||||
|
||||
BSP_shared_interrupt_unmask(irq);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
struct drvmgr_drv_ops leon2_amba_ops =
|
||||
{
|
||||
.init = {leon2_amba_init1, leon2_amba_init2, NULL, NULL},
|
||||
.remove = leon2_amba_remove,
|
||||
.info = NULL
|
||||
};
|
||||
|
||||
struct drvmgr_drv leon2_bus_drv =
|
||||
{
|
||||
DRVMGR_OBJ_DRV, /* Driver */
|
||||
NULL, /* Next driver */
|
||||
NULL, /* Device list */
|
||||
DRIVER_LEON2_AMBA_ID, /* Driver ID */
|
||||
"LEON2_AMBA_DRV", /* Must be placed at top bus */
|
||||
DRVMGR_BUS_TYPE_ROOT, /* Bus Type */
|
||||
&leon2_amba_ops, /* Bus Operations */
|
||||
NULL, /* Funcs */
|
||||
0, /* Device Count */
|
||||
0, /* Private structure size */
|
||||
};
|
||||
Reference in New Issue
Block a user