summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/amba/ambapp.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp.c794
1 files changed, 376 insertions, 418 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
index 814ee8c28e..504a3e7e75 100644
--- a/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp.c
@@ -1,499 +1,457 @@
/*
- * AMBA Plag & Play Bus Driver
+ * AMBA Plug & Play routines
*
- * This driver hook performs bus scanning.
- *
- * COPYRIGHT (c) 2004.
- * Gaisler Research
+ * COPYRIGHT (c) 2011.
+ * Aeroflex Gaisler.
*
* 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.
- *
- * $Id$
*/
-#include <bsp.h>
-#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+
#include <ambapp.h>
+#include <bsp.h>
-#define amba_insert_device(tab, address) \
-{ \
- if (*(address)) \
- { \
- (tab)->addr[(tab)->devnr] = (address); \
- (tab)->devnr ++; \
- } \
-} while(0)
-
-#define amba_insert_apb_device(tab, address, apbmst) \
-{ \
- if (*(address)) \
- { \
- (tab)->addr[(tab)->devnr] = (address); \
- (tab)->apbmst[(tab)->devnr] = (apbmst); \
- (tab)->devnr ++; \
- } \
-} while(0)
-
-static unsigned int
-addr_from (struct amba_mmap *mmaps, unsigned int address)
+#define AMBA_CONF_AREA 0xff000
+#define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
+#define AMBA_APB_SLAVES 16
+
+/* Allocate one AMBA device */
+struct ambapp_dev *ambapp_alloc_dev_struct(int dev_type)
+{
+ int size = sizeof(struct ambapp_dev);
+ struct ambapp_dev *dev;
+
+ if (dev_type == DEV_APB_SLV)
+ size += sizeof(struct ambapp_apb_info);
+ else
+ size += sizeof(struct ambapp_ahb_info); /* AHB */
+ dev = (struct ambapp_dev *)bsp_early_malloc(size);
+ if (dev == NULL)
+ return NULL;
+ memset(dev, 0 , size);
+ dev->dev_type = dev_type;
+ return dev;
+}
+
+unsigned int
+ambapp_addr_from (struct ambapp_mmap *mmaps, unsigned int address)
{
/* no translation? */
if (!mmaps)
return address;
while (mmaps->size) {
- if ((address >= mmaps->remote_amba_adr)
- && (address <= (mmaps->remote_amba_adr + (mmaps->size - 1)))) {
- return (address - mmaps->remote_amba_adr) + mmaps->cpu_adr;
+ if ((address >= mmaps->remote_adr) &&
+ (address <= (mmaps->remote_adr + (mmaps->size - 1)))) {
+ return (address - mmaps->remote_adr) + mmaps->local_adr;
}
mmaps++;
}
return 1;
}
-
-void
-amba_scan (amba_confarea_type * amba_conf, unsigned int ioarea,
- struct amba_mmap *mmaps)
+void ambapp_ahb_dev_init(
+ unsigned int ioarea,
+ struct ambapp_mmap *mmaps,
+ struct ambapp_pnp_ahb *ahb,
+ struct ambapp_dev *dev,
+ int ahbidx
+ )
{
- unsigned int *cfg_area; /* address to configuration area */
- unsigned int mbar, conf, custom;
- int i, j;
- unsigned int apbmst;
- int maxloops = amba_conf->notroot ? 16 : 64; /* scan first bus for 64 devices, rest for 16 devices */
-
- amba_conf->ahbmst.devnr = 0;
- amba_conf->ahbslv.devnr = 0;
- amba_conf->apbslv.devnr = 0;
- cfg_area = (unsigned int *) (ioarea | AMBA_CONF_AREA);
- amba_conf->ioarea = ioarea;
- amba_conf->mmaps = mmaps;
-
- for (i = 0; i < maxloops; i++) {
- amba_insert_device (&amba_conf->ahbmst, cfg_area);
- cfg_area += AMBA_AHB_CONF_WORDS;
- }
-
- cfg_area =
- (unsigned int *) (ioarea | AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA);
- for (i = 0; i < maxloops; i++) {
- amba_insert_device (&amba_conf->ahbslv, cfg_area);
- cfg_area += AMBA_AHB_CONF_WORDS;
- }
-
- for (i = 0; i < amba_conf->ahbslv.devnr; i++){
- conf = amba_get_confword(amba_conf->ahbslv, i, 0);
- mbar = amba_ahb_get_membar(amba_conf->ahbslv, i, 0);
- if ( (amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_AHB2AHB) ){
- /* Found AHB->AHB bus bridge, scan it if more free amba_confarea_type:s available
- * Custom config 1 contain ioarea.
- */
- custom = amba_ahb_get_custom(amba_conf->ahbslv,i,1);
-
- if ( amba_ver(conf) && amba_conf->next ){
- amba_conf->next->notroot = 1;
- amba_scan(amba_conf->next,custom,mmaps);
- }
- }else if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_APBMST))
- {
- apbmst = amba_membar_start(mbar);
- if ( (apbmst=addr_from(mmaps,apbmst)) == 1 )
- continue; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB/APB bridge. Skip it.
- */
- cfg_area = (unsigned int *)( apbmst | AMBA_CONF_AREA);
- for (j=0; (amba_conf->apbslv.devnr<AMBA_APB_SLAVES) && (j<AMBA_APB_SLAVES); j++){
- amba_insert_apb_device(&amba_conf->apbslv, cfg_area, apbmst);
- cfg_area += AMBA_APB_CONF_WORDS;
+ int bar;
+ struct ambapp_ahb_info *ahb_info;
+ unsigned int addr, mask, mbar;
+
+ /* Setup device struct */
+ dev->vendor = ambapp_pnp_vendor(ahb->id);
+ dev->device = ambapp_pnp_device(ahb->id);
+ ahb_info = DEV_TO_AHB(dev);
+ ahb_info->ver = ambapp_pnp_ver(ahb->id);
+ ahb_info->irq = ambapp_pnp_irq(ahb->id);
+ ahb_info->ahbidx = ahbidx;
+ ahb_info->custom[0] = (unsigned int)ahb->custom[0];
+ ahb_info->custom[1] = (unsigned int)ahb->custom[1];
+ ahb_info->custom[2] = (unsigned int)ahb->custom[2];
+
+ /* Memory BARs */
+ for (bar=0; bar<4; bar++) {
+ mbar = ahb->mbar[bar];
+ if (mbar == 0) {
+ addr = 0;
+ mask = 0;
+ } else {
+ addr = ambapp_pnp_start(mbar);
+ if (ambapp_pnp_mbar_type(mbar) == AMBA_TYPE_AHBIO) {
+ /* AHB I/O area is releative IO_AREA */
+ addr = AMBA_TYPE_AHBIO_ADDR(addr, ioarea);
+ mask = (((unsigned int)(ambapp_pnp_mbar_mask(~mbar) << 8) | 0xff)) + 1;
+ } else {
+ /* AHB memory area, absolute address */
+ addr = ambapp_addr_from(mmaps, addr);
+ mask = (~((unsigned int)(ambapp_pnp_mbar_mask(mbar) << 20))) + 1;
}
}
+ ahb_info->start[bar] = addr;
+ ahb_info->mask[bar] = mask;
+ ahb_info->type[bar] = ambapp_pnp_mbar_type(mbar);
}
}
-void
-amba_print_dev(int devno, unsigned int conf){
- int irq = amba_irq(conf);
- if ( irq > 0 ){
- printk("%x.%x.%x: irq %d\n",devno,amba_vendor(conf),amba_device(conf),irq);
- }else{
- printk("%x.%x.%x: no irq\n",devno,amba_vendor(conf),amba_device(conf));
- }
-}
-
-void
-amba_apb_print_dev(int devno, unsigned int conf, unsigned int address){
- int irq = amba_irq(conf);
- if ( irq > 0 ){
- printk("%x.%x.%x: irq %d, apb: 0x%lx\n",devno,amba_vendor(conf),amba_device(conf),irq,address);
- }else{
- printk("%x.%x.%x: no irq, apb: 0x%lx\n",devno,amba_vendor(conf),amba_device(conf),address);
- }
+void ambapp_apb_dev_init(
+ unsigned int base,
+ struct ambapp_mmap *mmaps,
+ struct ambapp_pnp_apb *apb,
+ struct ambapp_dev *dev,
+ int ahbidx
+ )
+{
+ struct ambapp_apb_info *apb_info;
+
+ /* Setup device struct */
+ dev->vendor = ambapp_pnp_vendor(apb->id);
+ dev->device = ambapp_pnp_device(apb->id);
+ apb_info = DEV_TO_APB(dev);
+ apb_info->ver = ambapp_pnp_ver(apb->id);
+ apb_info->irq = ambapp_pnp_irq(apb->id);
+ apb_info->ahbidx = ahbidx;
+ apb_info->start = ambapp_pnp_apb_start(apb->iobar, base);
+ apb_info->mask = ambapp_pnp_apb_mask(apb->iobar);
}
-/* Print AMBA Plug&Play info on terminal */
-void
-amba_print_conf (amba_confarea_type * amba_conf)
+int ambapp_add_ahbbus(
+ struct ambapp_bus *abus,
+ unsigned int ioarea
+ )
{
- int i,base=0;
- unsigned int conf, iobar, address;
- unsigned int apbmst;
-
- /* print all ahb masters */
- printk("--- AMBA AHB Masters ---\n");
- for(i=0; i<amba_conf->ahbmst.devnr; i++){
- conf = amba_get_confword(amba_conf->ahbmst, i, 0);
- amba_print_dev(i,conf);
- }
-
- /* print all ahb slaves */
- printk("--- AMBA AHB Slaves ---\n");
- for(i=0; i<amba_conf->ahbslv.devnr; i++){
- conf = amba_get_confword(amba_conf->ahbslv, i, 0);
- amba_print_dev(i,conf);
- }
-
- /* print all apb slaves */
- apbmst = 0;
- for(i=0; i<amba_conf->apbslv.devnr; i++){
- if ( apbmst != amba_conf->apbslv.apbmst[i] ){
- apbmst = amba_conf->apbslv.apbmst[i];
- printk("--- AMBA APB Slaves on 0x%x ---\n",apbmst);
- base=i;
- }
- conf = amba_get_confword(amba_conf->apbslv, i, 0);
- iobar = amba_apb_get_membar(amba_conf->apbslv, i);
- address = amba_iobar_start(amba_conf->apbslv.apbmst[i], iobar);
- amba_apb_print_dev(i-base,conf,address);
- }
-
+ int i;
+ for (i=0; i<AHB_BUS_MAX; i++) {
+ if (abus->ahbs[i].ioarea == 0) {
+ abus->ahbs[i].ioarea = ioarea;
+ return i;
+ } else if (abus->ahbs[i].ioarea == ioarea) {
+ /* Bus already added */
+ return -1;
+ }
+ }
+ return -1;
}
-/**** APB Slaves ****/
-/* Return number of APB Slave devices which has given vendor and device */
-int
-amba_get_number_apbslv_devices (amba_confarea_type * amba_conf, int vendor,
- int device)
+/* Internal AMBA Scanning Function */
+static int ambapp_scan2(
+ struct ambapp_bus *abus,
+ unsigned int ioarea,
+ ambapp_memcpy_t memfunc,
+ struct ambapp_dev *parent,
+ struct ambapp_dev **root
+ )
{
- unsigned int conf;
- int cnt, i;
+ struct ambapp_pnp_ahb *ahb, ahb_buf;
+ struct ambapp_pnp_apb *apb, apb_buf;
+ struct ambapp_dev *dev, *prev, *prevapb, *apbdev;
+ struct ambapp_ahb_info *ahb_info;
+ int maxloops = 64;
+ unsigned int apbbase, bridge_adr;
+ int i, j, ahbidx;
+
+ *root = NULL;
+
+ if (parent) {
+ /* scan first bus for 64 devices, rest for 16 devices */
+ maxloops = 16;
+ }
- for (cnt = i = 0; i < amba_conf->apbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
- cnt++;
+ ahbidx = ambapp_add_ahbbus(abus, ioarea);
+ if (ahbidx < 0) {
+ /* Bus already scanned, stop */
+ return 0;
}
- return cnt;
-}
-/* Get First APB Slave device of this vendor&device id */
-int
-amba_find_apbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * dev)
-{
- unsigned int conf, iobar;
- int i;
+ prev = parent;
- for (i = 0; i < amba_conf->apbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- iobar = amba_apb_get_membar (amba_conf->apbslv, i);
- dev->start = amba_iobar_start (amba_conf->apbslv.apbmst[i], iobar);
- dev->irq = amba_irq (conf);
- return 1;
- }
+ /* AHB MASTERS */
+ ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
+ for (i = 0; i < maxloops; i++, ahb++) {
+ memfunc(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
+ if (ahb_buf.id == 0)
+ continue;
+
+ /* An AHB device present here */
+ dev = ambapp_alloc_dev_struct(DEV_AHB_MST);
+ if (!dev)
+ return -1;
+
+ ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
+
+ if (*root == NULL)
+ *root = dev;
+
+ if (prev != parent)
+ prev->next = dev;
+ dev->prev = prev;
+ prev = dev;
}
- return 0;
-}
-/* Get APB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_apbslv() ) */
-int
-amba_find_next_apbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * dev, int index)
-{
- unsigned int conf, iobar;
- int cnt, i;
-
- for (cnt = i = 0; i < amba_conf->apbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- if (cnt == index) {
- /* found device */
- iobar = amba_apb_get_membar (amba_conf->apbslv, i);
- dev->start = amba_iobar_start (amba_conf->apbslv.apbmst[i], iobar);
- dev->irq = amba_irq (conf);
- return 1;
+ /* AHB SLAVES */
+ ahb = (struct ambapp_pnp_ahb *)
+ (ioarea | AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA);
+ for (i = 0; i < maxloops; i++, ahb++) {
+ memfunc(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
+ if (ahb_buf.id == 0)
+ continue;
+
+ /* An AHB device present here */
+ dev = ambapp_alloc_dev_struct(DEV_AHB_SLV);
+ if (!dev)
+ return -1;
+
+ ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
+
+ if (*root == NULL)
+ *root = dev;
+
+ if (prev != parent)
+ prev->next = dev;
+ dev->prev = prev;
+ prev = dev;
+
+ ahb_info = DEV_TO_AHB(dev);
+
+ /* Is it a AHB/AHB Bridge ? */
+ if (((dev->device == GAISLER_AHB2AHB) &&
+ (dev->vendor == VENDOR_GAISLER) && (ahb_info->ver > 0)) ||
+ ((dev->device == GAISLER_L2CACHE) &&
+ (dev->vendor == VENDOR_GAISLER)) ||
+ ((dev->device == GAISLER_GRIOMMU) &&
+ (dev->vendor == VENDOR_GAISLER))) {
+ /* AHB/AHB Bridge Found, recurse down the
+ * Bridge
+ */
+ if (ahb_info->custom[1] != 0) {
+ bridge_adr = ambapp_addr_from(abus->mmaps,
+ ahb_info->custom[1]);
+ /* Scan next bus if not already scanned */
+ if (ambapp_scan2(abus, bridge_adr, memfunc, dev,
+ &dev->children))
+ return -1;
+ }
+ } else if ((dev->device == GAISLER_APBMST) &&
+ (dev->vendor == VENDOR_GAISLER)) {
+ /* AHB/APB Bridge Found, add the APB devices to this
+ * AHB Slave's children
+ */
+ prevapb = dev;
+ apbbase = ahb_info->start[0];
+
+ /* APB SLAVES */
+ apb = (struct ambapp_pnp_apb *)
+ (apbbase | AMBA_CONF_AREA);
+ for (j=0; j<AMBA_APB_SLAVES; j++, apb++) {
+ memfunc(&apb_buf, apb, sizeof(*apb), abus);
+ if (apb_buf.id == 0)
+ continue;
+
+ apbdev = ambapp_alloc_dev_struct(DEV_APB_SLV);
+ if (!dev)
+ return -1;
+
+ ambapp_apb_dev_init(apbbase, abus->mmaps,
+ &apb_buf, apbdev, ahbidx);
+
+ if (prevapb != dev)
+ prevapb->next = apbdev;
+ else
+ dev->children = apbdev;
+ apbdev->prev = prevapb;
+ prevapb = apbdev;
}
- cnt++;
}
}
+
+ /* Remember first AHB MST/SLV device on bus and Parent Bridge */
+ abus->ahbs[ahbidx].dev = *root;
+ abus->ahbs[ahbidx].bridge = parent;
+
return 0;
}
-/* Get first nr APB Slave devices, put them into dev (which is an array of nr length) */
-int
-amba_find_apbslvs (amba_confarea_type * amba_conf, int vendor, int device,
- amba_apb_device * devs, int maxno)
+/* Build AMBA Plug & Play device graph */
+int ambapp_scan(
+ struct ambapp_bus *abus,
+ unsigned int ioarea,
+ ambapp_memcpy_t memfunc,
+ struct ambapp_mmap *mmaps
+ )
{
- unsigned int conf, iobar;
- int cnt, i;
-
- for (cnt = i = 0; (i < amba_conf->apbslv.devnr) && (cnt < maxno); i++) {
- conf = amba_get_confword (amba_conf->apbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- /* found device */
- iobar = amba_apb_get_membar (amba_conf->apbslv, i);
- devs[cnt].start = amba_iobar_start (amba_conf->apbslv.apbmst[i], iobar);
- devs[cnt].irq = amba_irq (conf);
- cnt++;
- }
- }
- return cnt;
-}
+ memset(abus, 0, sizeof(*abus));
+ abus->mmaps = mmaps;
-/***** AHB SLAVES *****/
+ /* Default to memcpy() */
+ if (!memfunc)
+ memfunc = (ambapp_memcpy_t)memcpy;
-/* Return number of AHB Slave devices which has given vendor and device */
-int
-amba_get_number_ahbslv_devices (amba_confarea_type * amba_conf, int vendor,
- int device)
-{
- unsigned int conf;
- int cnt, i;
-
- for (cnt = i = 0; i < amba_conf->ahbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
- cnt++;
- }
- return cnt;
+ return ambapp_scan2(abus, ioarea, memfunc, NULL, &abus->root);
}
-/* Get First AHB Slave device of this vendor&device id */
-int
-amba_find_ahbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev)
+/* Match search options againt device */
+int ambapp_dev_match_options(struct ambapp_dev *dev, unsigned int options, int vendor, int device)
{
- unsigned int conf, mbar, addr;
- int j, i;
-
- for (i = 0; i < amba_conf->ahbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbslv, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else { /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
- }
+ if ((((options & (OPTIONS_ALL_DEVS)) == OPTIONS_ALL_DEVS) || /* TYPE */
+ ((options & OPTIONS_AHB_MSTS) && (dev->dev_type == DEV_AHB_MST)) ||
+ ((options & OPTIONS_AHB_SLVS) && (dev->dev_type == DEV_AHB_SLV)) ||
+ ((options & OPTIONS_APB_SLVS) && (dev->dev_type == DEV_APB_SLV))) &&
+ ((vendor == -1) || (vendor == dev->vendor)) && /* VENDOR/DEV ID */
+ ((device == -1) || (device == dev->device)) &&
+ (((options & OPTIONS_ALL) == OPTIONS_ALL) || /* Allocated State */
+ ((options & OPTIONS_FREE) && DEV_IS_FREE(dev)) ||
+ ((options & OPTIONS_ALLOCATED) && DEV_IS_ALLOCATED(dev)))) {
+ return 1;
}
return 0;
}
-/* Get AHB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_ahbslv() ) */
-int
-amba_find_next_ahbslv (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev, int index)
+/* If device is an APB bridge all devices on the APB bridge is processed */
+static int ambapp_for_each_apb(
+ struct ambapp_dev *dev,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg)
{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; i < amba_conf->ahbslv.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- if (cnt == index) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbslv, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
+ int index, ret;
+ struct ambapp_dev *apbslv;
+
+ ret = 0;
+ if (dev->children && (dev->children->dev_type == DEV_APB_SLV)) {
+ /* Found a APB Bridge */
+ index = 0;
+ apbslv = dev->children;
+ while (apbslv) {
+ if (ambapp_dev_match_options(apbslv, options,
+ vendor, device) == 1) {
+ ret = func(apbslv, index, arg);
+ if (ret != 0)
+ break; /* Signalled stopped */
}
- cnt++;
+ index++;
+ apbslv = apbslv->next;
}
}
- return 0;
+
+ return ret;
}
-/* Get first nr AHB Slave devices, put them into dev (which is an array of nr length) */
-int
-amba_find_ahbslvs (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * devs, int maxno)
+/* Traverse the prescanned device information */
+static int ambapp_for_each_dev(
+ struct ambapp_dev *root,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg)
{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; (i < amba_conf->ahbslv.devnr) && (maxno < cnt); i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbslv, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- devs[cnt].start[j] = addr;
+ struct ambapp_dev *dev;
+ int ahb_slave = 0;
+ int index, ret;
+
+ /* Start at device 'root' and process downwards.
+ *
+ * Breadth first search, search order
+ * 1. AHB MSTS
+ * 2. AHB SLVS
+ * 3. APB SLVS on primary bus
+ * 4. AHB/AHB secondary... -> step to 1.
+ */
+
+ /* AHB MST / AHB SLV */
+ if (options & (OPTIONS_AHB_MSTS|OPTIONS_AHB_SLVS|OPTIONS_DEPTH_FIRST)) {
+ index = 0;
+ dev = root;
+ while (dev) {
+ if ((dev->dev_type == DEV_AHB_SLV) && !ahb_slave) {
+ /* First AHB Slave */
+ ahb_slave = 1;
+ index = 0;
}
- devs[cnt].irq = amba_irq (conf);
- devs[cnt].ver = amba_ver (conf);
- cnt++;
- }
- }
- return cnt;
-}
+ /* Conditions must be fullfilled for function to be
+ * called
+ */
+ if (ambapp_dev_match_options(dev, options, vendor, device) == 1) {
+ /* Correct device and vendor ID */
+ ret = func(dev, index, arg);
+ if (ret != 0)
+ return ret; /* Signalled stopped */
+ }
-/***** AHB Masters *****/
+ if ((options & OPTIONS_DEPTH_FIRST) && (options & OPTIONS_APB_SLVS)) {
+ /* Check is APB bridge, and process all APB
+ * Slaves in that case
+ */
+ ret = ambapp_for_each_apb(dev, options, vendor, device, func, arg);
+ if (ret != 0)
+ return ret; /* Signalled stopped */
+ }
-/* Return number of AHB Slave devices which has given vendor and device */
-int
-amba_get_number_ahbmst_devices (amba_confarea_type * amba_conf, int vendor,
- int device)
-{
- unsigned int conf;
- int cnt, i;
+ if (options & OPTIONS_DEPTH_FIRST) {
+ if (dev->children && (dev->children->dev_type != DEV_APB_SLV)) {
+ /* Found AHB Bridge, recurse */
+ ret = ambapp_for_each_dev(dev->children, options, vendor, device,
+ func, arg);
+ if (ret != 0)
+ return ret;
+ }
+ }
- for (cnt = i = 0; i < amba_conf->ahbmst.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbmst, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
- cnt++;
+ index++;
+ dev = dev->next;
+ }
}
- return cnt;
-}
-/* Get First AHB Slave device of this vendor&device id */
-int
-amba_find_ahbmst (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev)
-{
- unsigned int conf, mbar, addr;
- int j, i;
-
- for (i = 0; i < amba_conf->ahbmst.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbmst, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
+ /* Find APB Bridges */
+ if ((options & OPTIONS_APB_SLVS) && !(options & OPTIONS_DEPTH_FIRST)) {
+ dev = root;
+ while (dev) {
+ /* Check is APB bridge, and process all APB Slaves in
+ * that case
+ */
+ ret = ambapp_for_each_apb(dev, options, vendor, device, func, arg);
+ if (ret != 0)
+ return ret; /* Signalled stopped */
+ dev = dev->next;
}
}
- return 0;
-}
-/* Get AHB Slave device of this vendor&device id. (setting nr to 0 is eqivalent to calling amba_find_ahbslv() ) */
-int
-amba_find_next_ahbmst (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * dev, int index)
-{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; i < amba_conf->ahbmst.devnr; i++) {
- conf = amba_get_confword (amba_conf->ahbmst, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- if (cnt == index) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbmst, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- dev->start[j] = addr;
- }
- dev->irq = amba_irq (conf);
- dev->ver = amba_ver (conf);
- return 1;
+ /* Find AHB Bridges */
+ if (!(options & OPTIONS_DEPTH_FIRST)) {
+ dev = root;
+ while (dev) {
+ if (dev->children && (dev->children->dev_type != DEV_APB_SLV)) {
+ /* Found AHB Bridge, recurse */
+ ret = ambapp_for_each_dev(dev->children, options, vendor, device,
+ func, arg);
+ if (ret != 0)
+ return ret;
}
- cnt++;
+ dev = dev->next;
}
}
+
return 0;
}
-/* Get first nr AHB Slave devices, put them into dev (which is an array of nr length) */
-int
-amba_find_ahbmsts (amba_confarea_type * amba_conf, int vendor, int device,
- amba_ahb_device * devs, int maxno)
+int ambapp_for_each(
+ struct ambapp_bus *abus,
+ unsigned int options,
+ int vendor,
+ int device,
+ ambapp_func_t func,
+ void *arg)
{
- unsigned int conf, mbar, addr;
- int i, j, cnt;
-
- for (cnt = i = 0; (i < amba_conf->ahbmst.devnr) && (maxno < cnt); i++) {
- conf = amba_get_confword (amba_conf->ahbslv, i, 0);
- if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device)) {
- for (j = 0; j < 4; j++) {
- mbar = amba_ahb_get_membar (amba_conf->ahbmst, i, j);
- addr = amba_membar_start (mbar);
- if (amba_membar_type (mbar) == AMBA_TYPE_AHBIO) {
- addr = AMBA_TYPE_AHBIO_ADDR (addr, amba_conf->ioarea);
- } else {
- /* convert address if needed */
- if ((addr = addr_from (amba_conf->mmaps, addr)) == 1) {
- addr = 0; /* no available memory translation available, will not be able to access
- * Plug&Play information for this AHB address. Skip it.
- */
- }
- }
- devs[cnt].start[j] = addr;
- }
- devs[cnt].irq = amba_irq (conf);
- devs[cnt].ver = amba_ver (conf);
- cnt++;
- }
- }
- return cnt;
+ return ambapp_for_each_dev(abus->root, options, vendor, device, func, arg);
}