forked from Imagelibrary/rtems
267 lines
6.3 KiB
C
267 lines
6.3 KiB
C
/* 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 <grlib/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
|