[PATCH 014/111] LEON3: implemented AMBA PnP Bus Driver for Driver Manager
Daniel Hellstrom
daniel at gaisler.com
Thu Feb 26 16:38:16 UTC 2015
---
c/src/lib/libbsp/sparc/Makefile.am | 7 +
c/src/lib/libbsp/sparc/leon3/Makefile.am | 7 +
c/src/lib/libbsp/sparc/leon3/include/bsp.h | 7 +
c/src/lib/libbsp/sparc/leon3/preinstall.am | 12 +
c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c | 754 ++++++++++++++++++++
.../libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c | 227 ++++++
.../sparc/shared/include/drvmgr/ambapp_bus.h | 101 +++
.../sparc/shared/include/drvmgr/ambapp_bus_grlib.h | 33 +
8 files changed, 1148 insertions(+), 0 deletions(-)
create mode 100644 c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c
create mode 100644 c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c
create mode 100644 c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
create mode 100644 c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am
index 615aea7..eb20f37 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -73,5 +73,12 @@ EXTRA_DIST += shared/include/b1553brm_rasta.h
EXTRA_DIST += shared/i2c/i2cmst.c
EXTRA_DIST += shared/include/i2cmst.h
+# Driver Manager
+EXTRA_DIST += shared/drvmgr/ambapp_bus.c
+EXTRA_DIST += shared/drvmgr/ambapp_bus_grlib.c
+
+EXTRA_DIST += shared/include/drvmgr/ambapp_bus_grlib.h
+EXTRA_DIST += shared/include/drvmgr/ambapp_bus.h
+
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index 4cb6e79..6e6f04d 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -133,6 +133,13 @@ libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
libbsp_a_SOURCES += include/cache_.h
libbsp_a_CPPFLAGS = -I$(srcdir)/include
+# Driver Manager
+include_drvmgrdir = $(includedir)/drvmgr
+include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus_grlib.h
+include_drvmgr_HEADERS += ../../sparc/shared/include/drvmgr/ambapp_bus.h
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus.c
+libbsp_a_SOURCES += ../../sparc/shared/drvmgr/ambapp_bus_grlib.c
+
if HAS_SMP
libbsp_a_SOURCES += startup/bspsmp.c
endif
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp.h b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
index 09738c9..9239d2b 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
@@ -249,6 +249,13 @@ extern const unsigned char LEON3_irq_to_cpu[32];
#define BSP_PCI_shared_interrupt_mask BSP_shared_interrupt_mask
#define BSP_PCI_shared_interrupt_clear BSP_shared_interrupt_clear
+/* Common driver build-time configurations. On small systems undefine
+ * [DRIVER]_INFO_AVAIL to avoid info routines get dragged in. It is good
+ * for debugging and printing information about the system, but makes the
+ * image bigger.
+ */
+#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
+
#ifdef __cplusplus
}
#endif
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index 0c0139f..3252560 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -169,3 +169,15 @@ $(PROJECT_INCLUDE)/watchdog.h: include/watchdog.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/watchdog.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/watchdog.h
+$(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
+ @: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus_grlib.h: ../../sparc/shared/include/drvmgr/ambapp_bus_grlib.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_grlib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus_grlib.h
+
+$(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h: ../../sparc/shared/include/drvmgr/ambapp_bus.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c
new file mode 100644
index 0000000..c95e8fd
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus.c
@@ -0,0 +1,754 @@
+/* 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.com/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>
+
+/*#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 */
+
+int ambapp_bus_init1(struct drvmgr_bus *bus);
+int ambapp_bus_remove(struct drvmgr_bus *bus);
+int ambapp_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
+int ambapp_int_register(struct drvmgr_dev *dev, int index, const char *info, drvmgr_isr isr, void *arg);
+int ambapp_int_unregister(struct drvmgr_dev *dev, int index, drvmgr_isr isr, void *arg);
+int ambapp_int_clear(struct drvmgr_dev *dev, int index);
+int ambapp_int_mask(struct drvmgr_dev *dev, int index);
+int ambapp_int_unmask(struct drvmgr_dev *dev, int index);
+int ambapp_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params);
+int ambapp_bus_freq_get(
+ struct drvmgr_dev *dev,
+ int options,
+ unsigned int *freq_hz);
+void ambapp_dev_info(struct drvmgr_dev *, void (*print)(void *p, char *str), void *p);
+
+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,
+ .int_unmask = ambapp_int_unmask,
+ .get_params = ambapp_get_params,
+ .freq_get = ambapp_bus_freq_get,
+#ifdef AMBAPPBUS_INFO_AVAIL
+ .info_dev = ambapp_dev_info,
+#endif
+};
+
+struct ambapp_priv {
+ struct ambapp_config *config;
+};
+
+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;
+}
+
+int ambapp_int_register(
+ struct drvmgr_dev *dev,
+ int index,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ 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)busdev, (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;
+ }
+}
+
+int ambapp_int_unregister(
+ struct drvmgr_dev *dev,
+ int index,
+ drvmgr_isr isr,
+ void *arg)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ 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)busdev, (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;
+ }
+}
+
+int ambapp_int_clear(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ 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)busdev, (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;
+ }
+}
+
+int ambapp_int_mask(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ 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)busdev, (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;
+ }
+}
+
+int ambapp_int_unmask(
+ struct drvmgr_dev *dev,
+ int index)
+{
+ struct drvmgr_dev *busdev;
+ struct ambapp_priv *priv;
+ int irq;
+
+ busdev = dev->parent->dev;
+ 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)busdev, (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);
+}
+
+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;
+}
+
+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
+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 */
+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;
+ struct amba_dev_info *pnpinfo;
+ int subcores;
+ int core;
+
+ 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;
+
+ /* Register device */
+ drvmgr_dev_register(newdev);
+ }
+ } 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;
+};
+
+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;
+
+ ambapp_dev_fixup(newdev, pnpinfo);
+
+ /* Register New Device */
+ drvmgr_dev_register(newdev);
+}
+
+/* Register one AMBA device */
+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
+
+ 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 */
+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 */
+int ambapp_bus_init1(struct drvmgr_bus *bus)
+{
+ /* Initialize the bus, register devices on this bus */
+ return ambapp_ids_register(bus);
+}
+
+int ambapp_bus_remove(struct drvmgr_bus *bus)
+{
+ return DRVMGR_OK;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c
new file mode 100644
index 0000000..69b2816
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/drvmgr/ambapp_bus_grlib.c
@@ -0,0 +1,227 @@
+/* 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.com/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 <genirq.h>
+
+#include <bsp.h>
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+int ambapp_grlib_int_register(
+ struct drvmgr_dev *dev,
+ int irq,
+ const char *info,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_grlib_int_unregister(
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg);
+int ambapp_grlib_int_clear(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_grlib_int_mask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_grlib_int_unmask(
+ struct drvmgr_dev *dev,
+ int irq);
+int ambapp_grlib_get_params(
+ struct drvmgr_dev *dev,
+ struct drvmgr_bus_params *params);
+
+int ambapp_grlib_init1(struct drvmgr_dev *dev);
+int ambapp_grlib_init2(struct drvmgr_dev *dev);
+int ambapp_grlib_remove(struct drvmgr_dev *dev);
+
+/* READ/WRITE access to SpaceWire target over RMAP */
+void *ambapp_grlib_rw_arg(struct drvmgr_dev *dev);
+
+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,
+ .get_params = ambapp_grlib_get_params
+};
+
+void *ambapp_grlib_rw_arg(struct drvmgr_dev *dev)
+{
+ return dev; /* No argument really needed, but for debug? */
+}
+
+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,
+};
+
+struct drvmgr_drv_ops ambapp_grlib_drv_ops =
+{
+ .init = {ambapp_grlib_init1, ambapp_grlib_init2, NULL, NULL},
+ .remove = ambapp_grlib_remove,
+ .info = NULL,
+};
+
+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 */
+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);
+}
+
+int ambapp_grlib_init2(struct drvmgr_dev *dev)
+{
+ return 0;
+}
+
+int ambapp_grlib_remove(struct drvmgr_dev *dev)
+{
+ return 0;
+}
+
+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);
+}
+
+int ambapp_grlib_int_unregister
+ (
+ struct drvmgr_dev *dev,
+ int irq,
+ drvmgr_isr isr,
+ void *arg
+ )
+{
+ return BSP_shared_interrupt_unregister(irq, isr, arg);
+}
+
+int ambapp_grlib_int_clear
+ (
+ struct drvmgr_dev *dev,
+ int irq)
+{
+ BSP_shared_interrupt_clear(irq);
+ return DRVMGR_OK;
+}
+
+int ambapp_grlib_int_mask
+ (
+ struct drvmgr_dev *dev,
+ int irq
+ )
+{
+ BSP_shared_interrupt_mask(irq);
+ return DRVMGR_OK;
+}
+
+int ambapp_grlib_int_unmask
+ (
+ struct drvmgr_dev *dev,
+ int irq
+ )
+{
+ BSP_shared_interrupt_unmask(irq);
+ return DRVMGR_OK;
+}
+
+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;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
new file mode 100644
index 0000000..a1a47b1
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
@@ -0,0 +1,101 @@
+/* General part of a AMBA Plug & Play bus driver.
+ *
+ * COPYRIGHT (c) 2008.
+ * Cobham Gaisler AB
+ *
+ * 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 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.
+ */
+
+#ifndef __AMBAPP_BUS_H__
+#define __AMBAPP_BUS_H__
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GRLIB AMBA Plug&Play Driver ID generation */
+#define DRIVER_AMBAPP_ID(vendor, device) \
+ DRIVER_ID(DRVMGR_BUS_TYPE_AMBAPP, ((((vendor) & 0xff) << 16) | ((device) & 0xfff)))
+
+struct amba_dev_id {
+ unsigned short vendor;
+ unsigned short device;
+ /* Version ? */
+};
+
+struct amba_drv_info {
+ struct drvmgr_drv general; /* General bus info */
+ /* AMBA specific bus information */
+ struct amba_dev_id *ids; /* Supported hardware */
+};
+
+struct amba_dev_info {
+ struct amba_dev_id id;
+ struct ambapp_core info;
+};
+
+struct ambapp_ops {
+ int (*int_register)
+ (struct drvmgr_dev *dev, int index, const char *info, drvmgr_isr isr, void *arg);
+ int (*int_unregister)
+ (struct drvmgr_dev *dev, int index, drvmgr_isr isr, void *arg);
+ int (*int_clear)(struct drvmgr_dev *dev, int index);
+ int (*int_mask)(struct drvmgr_dev *dev, int index);
+ int (*int_unmask)(struct drvmgr_dev *dev, int index);
+ int (*get_params)
+ (struct drvmgr_dev *, struct drvmgr_bus_params *);
+};
+
+struct ambapp_config {
+ struct ambapp_bus *abus; /* Prescanned AMBA PnP bus */
+ struct ambapp_ops *ops; /* AMBA bus operations */
+ struct drvmgr_map_entry *maps_up; /* Bus memory map up-stream towards CPU */
+ struct drvmgr_map_entry *maps_down; /* Bus memory map down-stream towards HW */
+ struct drvmgr_bus_res *resources; /* Driver Resources */
+ int bus_type; /* Set DRVMGR_BUS_TYPE_AMBAPP_DIST if distributed AMBA Bus */
+ struct drvmgr_func *funcs; /* Custom functions */
+};
+
+/*** Bus operations with READ/WRITE access operations ***
+ *
+ * The functions are implemented using the standard drvmgr RW interface
+ */
+#define AMBAPP_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_REG)
+#define AMBAPP_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_REG)
+#define AMBAPP_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_REG)
+#define AMBAPP_R64 DRVMGR_RWFUNC(RW_SIZE_8|RW_READ|RW_REG)
+#define AMBAPP_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_REG)
+#define AMBAPP_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_REG)
+#define AMBAPP_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_REG)
+#define AMBAPP_W64 DRVMGR_RWFUNC(RW_SIZE_8|RW_WRITE|RW_REG)
+#define AMBAPP_RMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_READ|RW_MEM)
+#define AMBAPP_WMEM DRVMGR_RWFUNC(RW_SIZE_ANY|RW_WRITE|RW_MEM)
+#define AMBAPP_MEMSET DRVMGR_RWFUNC(RW_SIZE_ANY|RW_SET|RW_MEM)
+#define AMBAPP_RW_ARG DRVMGR_RWFUNC(RW_ARG)
+
+/* Register an ambapp bus on-top of a device */
+extern int ambapp_bus_register(
+ struct drvmgr_dev *dev,
+ struct ambapp_config *config
+ );
+
+extern void ambapp_bus_freq_register(
+ struct drvmgr_dev *dev,
+ int amba_interface,
+ unsigned int freq_hz);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h
new file mode 100644
index 0000000..a0e0548
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus_grlib.h
@@ -0,0 +1,33 @@
+/* LEON3 GRLIB AMBA Plug & Play bus driver interface.
+ *
+ * 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.com/license/LICENSE.
+ */
+
+#ifndef __AMBAPP_BUS_GRLIB_H__
+#define __AMBAPP_BUS_GRLIB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct grlib_config {
+ struct ambapp_bus *abus;
+ struct drvmgr_bus_res *resources;
+};
+
+/* Register GRLIB AMBA PnP Bus as root bus at driver manager */
+extern int ambapp_grlib_root_register(struct grlib_config *config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--
1.7.0.4
More information about the devel
mailing list