--- 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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel