680 lines
16 KiB
C
680 lines
16 KiB
C
/*
|
|
* Copyright (c) 2011 Aeroflex Gaisler
|
|
*
|
|
* BSD license:
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
|
|
#include <asm-leon/amba.h>
|
|
#undef AMBA_TYPE_AHBIO_ADDR
|
|
#include <asm-leon/lambapp.h>
|
|
#include <string.h>
|
|
|
|
#define AMBA_CONF_AREA 0xff000
|
|
#define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
|
|
#define AMBA_APB_SLAVES 16
|
|
|
|
#define DPRINTF(p) printf p
|
|
|
|
/* Allocate */
|
|
struct ambapp_dev_hdr *
|
|
ambapp_alloc_dev_struct (int dev_type)
|
|
{
|
|
int size = sizeof (struct ambapp_dev_hdr);
|
|
struct ambapp_dev_hdr *dev;
|
|
|
|
if (dev_type == DEV_APB_SLV)
|
|
{
|
|
size += sizeof (struct ambapp_apb_info);
|
|
}
|
|
else
|
|
{
|
|
/* AHB */
|
|
size += sizeof (struct ambapp_ahb_info);
|
|
}
|
|
dev = malloc (size);
|
|
if (dev == NULL)
|
|
return NULL;
|
|
memset (dev, 0, size);
|
|
dev->devinfo = (void *) (dev + 1);
|
|
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_adr)
|
|
&& (address <= (mmaps->remote_adr + (mmaps->size - 1))))
|
|
{
|
|
return (address - mmaps->remote_adr) + mmaps->local_adr;
|
|
}
|
|
mmaps++;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
ambapp_ahb_dev_init (unsigned int ioarea,
|
|
struct ambapp_mmap *mmaps,
|
|
struct ambapp_pnp_ahb *ahb, struct ambapp_dev_hdr *dev)
|
|
{
|
|
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->devinfo;
|
|
ahb_info->ver = ambapp_pnp_ver (ahb->id);
|
|
ahb_info->irq = ambapp_pnp_irq (ahb->id);
|
|
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];
|
|
|
|
DPRINTF (("+AHB device %d:%d\n", dev->device, dev->vendor));
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
void
|
|
ambapp_apb_dev_init (unsigned int base,
|
|
struct ambapp_mmap *mmaps,
|
|
struct ambapp_pnp_apb *apb, struct ambapp_dev_hdr *dev)
|
|
{
|
|
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->devinfo;
|
|
apb_info->ver = ambapp_pnp_ver (apb->id);
|
|
apb_info->irq = ambapp_pnp_irq (apb->id);
|
|
apb_info->start = ambapp_pnp_apb_start (apb->iobar, base);
|
|
apb_info->mask = ambapp_pnp_apb_mask (apb->iobar);
|
|
|
|
DPRINTF (("+APB device %d:%d\n", dev->device, dev->vendor));
|
|
|
|
|
|
}
|
|
|
|
#define MAX_NUM_BUSES 16
|
|
void
|
|
ambapp_add_scanned_bus (unsigned int *ioareas, unsigned int ioarea)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_NUM_BUSES; i++)
|
|
{
|
|
if (ioareas[i] == 0)
|
|
{
|
|
ioareas[i] = ioarea;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
ambapp_has_been_scanned (unsigned int *ioareas, unsigned int ioarea)
|
|
{
|
|
int i;
|
|
if (!ioareas)
|
|
return 0;
|
|
|
|
for (i = 0; i < MAX_NUM_BUSES; i++)
|
|
{
|
|
if (ioareas[i] == 0)
|
|
{
|
|
break;
|
|
}
|
|
else if (ioareas[i] == ioarea)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ambapp_scan (unsigned int ioarea,
|
|
struct ambapp_dev_hdr *parent,
|
|
struct ambapp_mmap *mmaps,
|
|
void *(*memfunc) (void *dest, const void *src, int n),
|
|
struct ambapp_dev_hdr **root, void *internal)
|
|
{
|
|
struct ambapp_pnp_ahb *ahb, ahb_buf;
|
|
struct ambapp_pnp_apb *apb, apb_buf;
|
|
struct ambapp_dev_hdr *dev, *prev, *prevapb, *apbdev;
|
|
struct ambapp_ahb_info *ahb_info;
|
|
int maxloops = 64;
|
|
unsigned int apbbase, bridge_address;
|
|
int i, j;
|
|
|
|
DPRINTF (("Scan at 0x%08x\n", ioarea));
|
|
|
|
/* Default to memcpy() */
|
|
if (!memfunc)
|
|
memfunc = (void *(*)(void *dest, const void *src, int n)) memcpy;
|
|
|
|
*root = NULL;
|
|
|
|
if (parent)
|
|
{
|
|
/* scan first bus for 64 devices, rest for 16 devices */
|
|
maxloops = 16;
|
|
}
|
|
else
|
|
{
|
|
DPRINTF (("+(malloc:"));
|
|
internal = malloc (sizeof (unsigned int) * MAX_NUM_BUSES);
|
|
DPRINTF (("0x%x)\n", internal));
|
|
|
|
if (!internal)
|
|
return -1;
|
|
memset (internal, 0, sizeof (unsigned int) * MAX_NUM_BUSES);
|
|
|
|
ambapp_add_scanned_bus (internal, ioarea);
|
|
}
|
|
|
|
prev = parent;
|
|
|
|
/* AHB MASTERS */
|
|
ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
|
|
for (i = 0; i < maxloops; i++)
|
|
{
|
|
memfunc (&ahb_buf, ahb, sizeof (struct ambapp_pnp_ahb));
|
|
if (ahb_buf.id != 0)
|
|
{
|
|
/* A AHB device present here */
|
|
dev = ambapp_alloc_dev_struct (DEV_AHB_MST);
|
|
if (!dev)
|
|
return -1;
|
|
|
|
ambapp_ahb_dev_init (ioarea, mmaps, &ahb_buf, dev);
|
|
|
|
if (*root == NULL)
|
|
*root = dev;
|
|
|
|
if (prev != parent)
|
|
prev->next = dev;
|
|
dev->prev = prev;
|
|
prev = dev;
|
|
}
|
|
ahb++;
|
|
}
|
|
|
|
/* AHB SLAVES */
|
|
ahb =
|
|
(struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA |
|
|
AMBA_AHB_SLAVE_CONF_AREA);
|
|
for (i = 0; i < maxloops; i++)
|
|
{
|
|
memfunc (&ahb_buf, ahb, sizeof (struct ambapp_pnp_ahb));
|
|
if (ahb_buf.id != 0)
|
|
{
|
|
/* A AHB device present here */
|
|
dev = ambapp_alloc_dev_struct (DEV_AHB_SLV);
|
|
if (!dev)
|
|
return -1;
|
|
|
|
ambapp_ahb_dev_init (ioarea, mmaps, &ahb_buf, dev);
|
|
|
|
if (prev != parent)
|
|
prev->next = dev;
|
|
dev->prev = prev;
|
|
prev = dev;
|
|
|
|
/* Is it a AHB/AHB Bridge ? */
|
|
if ((dev->device == GAISLER_AHB2AHB)
|
|
&& (dev->vendor == VENDOR_GAISLER))
|
|
{
|
|
/* AHB/AHB Bridge Found, recurse down the Bridge */
|
|
ahb_info = dev->devinfo;
|
|
if (ahb_info->ver)
|
|
{
|
|
bridge_address =
|
|
ambapp_addr_from (mmaps, ahb_info->custom[1]);
|
|
|
|
DPRINTF (("+(AHBAHB:0x%x)\n", bridge_address));
|
|
|
|
/* Makes sure bus only scanned once */
|
|
if (ambapp_has_been_scanned (internal, bridge_address) ==
|
|
NULL)
|
|
{
|
|
ambapp_add_scanned_bus (internal, bridge_address);
|
|
if (ambapp_scan
|
|
(bridge_address, dev, mmaps, memfunc,
|
|
&dev->children, internal))
|
|
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;
|
|
ahb_info = dev->devinfo;
|
|
apbbase = ahb_info->start[0];
|
|
apb = (struct ambapp_pnp_apb *) (apbbase | AMBA_CONF_AREA);
|
|
for (j = 0; j < AMBA_APB_SLAVES; j++)
|
|
{
|
|
memfunc (&apb_buf, apb, sizeof (struct ambapp_pnp_apb));
|
|
if (apb_buf.id)
|
|
{
|
|
apbdev = ambapp_alloc_dev_struct (DEV_APB_SLV);
|
|
if (!dev)
|
|
return -1;
|
|
|
|
ambapp_apb_dev_init (apbbase, mmaps, &apb_buf, apbdev);
|
|
|
|
if (prevapb != dev)
|
|
prevapb->next = apbdev;
|
|
else
|
|
dev->children = apbdev;
|
|
apbdev->prev = prevapb;
|
|
prevapb = apbdev;
|
|
}
|
|
apb++;
|
|
}
|
|
}
|
|
}
|
|
ahb++;
|
|
}
|
|
|
|
if (parent == NULL)
|
|
{
|
|
free (internal);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Match search options againt device */
|
|
int
|
|
ambapp_dev_match_options (struct ambapp_dev_hdr *dev, unsigned int options,
|
|
int vendor, int device)
|
|
{
|
|
if ((((options & (OPTIONS_ALL_DEVS)) == OPTIONS_ALL_DEVS) || /* Match 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)) && /* Match ID */
|
|
((device == -1) || (device == dev->device)) && (((options & OPTIONS_ALL) == OPTIONS_ALL) || /* Match Allocated State */
|
|
((options &
|
|
OPTIONS_FREE)
|
|
&& DEV_IS_FREE (dev))
|
|
||
|
|
((options &
|
|
OPTIONS_ALLOCATED)
|
|
&&
|
|
DEV_IS_ALLOCATED
|
|
(dev))))
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* If device is an APB bridge all devices on the APB bridge is processed */
|
|
static int
|
|
ambapp_for_each_apb (struct ambapp_dev_hdr *dev,
|
|
unsigned int options,
|
|
int vendor,
|
|
int device, int maxdepth, ambapp_func_t func, void *arg)
|
|
{
|
|
int index;
|
|
struct ambapp_dev_hdr *apbslv;
|
|
|
|
if (maxdepth < 0)
|
|
return 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)
|
|
{
|
|
if (func (apbslv, index, maxdepth, arg) == 1)
|
|
return 1; /* Signalled stopped */
|
|
}
|
|
index++;
|
|
apbslv = apbslv->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Traverse the prescanned device information */
|
|
int
|
|
ambapp_for_each (struct ambapp_dev_hdr *root,
|
|
unsigned int options,
|
|
int vendor,
|
|
int device, int maxdepth, ambapp_func_t func, void *arg)
|
|
{
|
|
struct ambapp_dev_hdr *dev;
|
|
int ahb_slave = 0;
|
|
int index;
|
|
|
|
if (maxdepth < 0)
|
|
return 0;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Conditions must be fullfilled for function to be called */
|
|
if (ambapp_dev_match_options (dev, options, vendor, device) == 1)
|
|
{
|
|
/* Correct device and vendor ID */
|
|
if (func (dev, index, maxdepth, arg) == 1)
|
|
return 1; /* Signalled stopped */
|
|
}
|
|
|
|
if ((options & OPTIONS_DEPTH_FIRST) && (options & OPTIONS_APB_SLVS))
|
|
{
|
|
/* Check is APB bridge, and process all APB Slaves in that case */
|
|
if (ambapp_for_each_apb
|
|
(dev, options, vendor, device, (maxdepth - 1), func,
|
|
arg) == 1)
|
|
return 1; /* Signalled stopped */
|
|
}
|
|
|
|
if (options & OPTIONS_DEPTH_FIRST)
|
|
{
|
|
if (dev->children && (dev->children->dev_type != DEV_APB_SLV))
|
|
{
|
|
/* Found AHB Bridge, recurse */
|
|
if (ambapp_for_each
|
|
(dev->children, options, vendor, device, (maxdepth - 1),
|
|
func, arg) == 1)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
index++;
|
|
dev = dev->next;
|
|
}
|
|
}
|
|
|
|
/* 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 */
|
|
if (ambapp_for_each_apb
|
|
(dev, options, vendor, device, (maxdepth - 1), func, arg) == 1)
|
|
return 1; /* Signalled stopped */
|
|
dev = dev->next;
|
|
}
|
|
}
|
|
|
|
/* 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 */
|
|
if (ambapp_for_each
|
|
(dev->children, options, vendor, device, (maxdepth - 1),
|
|
func, arg) == 1)
|
|
return 1;
|
|
}
|
|
dev = dev->next;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ambapp_alloc_dev (struct ambapp_dev_hdr *dev, void *owner)
|
|
{
|
|
if (dev->owner)
|
|
return -1;
|
|
dev->owner = owner;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ambapp_free_dev (struct ambapp_dev_hdr *dev)
|
|
{
|
|
dev->owner = NULL;
|
|
}
|
|
|
|
struct ambapp_dev_find_match_arg
|
|
{
|
|
int index;
|
|
int count;
|
|
int type;
|
|
void *dev;
|
|
};
|
|
|
|
/* AMBA PP find routines */
|
|
int
|
|
ambapp_dev_find_match (struct ambapp_dev_hdr *dev, int index, int maxdepth,
|
|
void *arg)
|
|
{
|
|
struct ambapp_dev_find_match_arg *p = arg;
|
|
|
|
if (p->index == 0)
|
|
{
|
|
/* Found controller, stop */
|
|
if (p->type == DEV_APB_SLV)
|
|
{
|
|
*(struct ambapp_apb_info *) p->dev =
|
|
*(struct ambapp_apb_info *) dev->devinfo;
|
|
p->dev = ((struct ambapp_apb_info *) p->dev) + 1;
|
|
}
|
|
else
|
|
{
|
|
*(struct ambapp_ahb_info *) p->dev =
|
|
*(struct ambapp_ahb_info *) dev->devinfo;
|
|
p->dev = ((struct ambapp_ahb_info *) p->dev) + 1;
|
|
}
|
|
p->count--;
|
|
if (p->count < 1)
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
p->index--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ambapp_find_apbslvs_next (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_apb_info *dev, int index, int maxno)
|
|
{
|
|
struct ambapp_dev_find_match_arg arg;
|
|
|
|
arg.index = index;
|
|
arg.count = maxno;
|
|
arg.type = DEV_APB_SLV; /* APB */
|
|
arg.dev = dev;
|
|
|
|
ambapp_for_each (root, (OPTIONS_ALL | OPTIONS_APB_SLVS), vendor, device, 10,
|
|
ambapp_dev_find_match, &arg);
|
|
|
|
return maxno - arg.count;
|
|
}
|
|
|
|
int
|
|
ambapp_find_apbslv (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_apb_info *dev)
|
|
{
|
|
return ambapp_find_apbslvs_next (root, vendor, device, dev, 0, 1);
|
|
}
|
|
|
|
int
|
|
ambapp_find_apbslv_next (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_apb_info *dev, int index)
|
|
{
|
|
return ambapp_find_apbslvs_next (root, vendor, device, dev, index, 1);
|
|
}
|
|
|
|
int
|
|
ambapp_find_apbslvs (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_apb_info *dev, int maxno)
|
|
{
|
|
return ambapp_find_apbslvs_next (root, vendor, device, dev, 0, maxno);
|
|
}
|
|
|
|
int
|
|
ambapp_find_ahbslvs_next (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_ahb_info *dev, int index, int maxno)
|
|
{
|
|
struct ambapp_dev_find_match_arg arg;
|
|
|
|
arg.index = index;
|
|
arg.count = maxno;
|
|
arg.type = DEV_AHB_SLV; /* AHB SLV */
|
|
arg.dev = dev;
|
|
|
|
ambapp_for_each (root, (OPTIONS_ALL | OPTIONS_AHB_SLVS), vendor, device, 10,
|
|
ambapp_dev_find_match, &arg);
|
|
|
|
return maxno - arg.count;
|
|
}
|
|
|
|
int
|
|
ambapp_find_ahbslv_next (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_ahb_info *dev, int index)
|
|
{
|
|
return ambapp_find_ahbslvs_next (root, vendor, device, dev, index, 1);
|
|
}
|
|
|
|
int
|
|
ambapp_find_ahbslv (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_ahb_info *dev)
|
|
{
|
|
return ambapp_find_ahbslvs_next (root, vendor, device, dev, 0, 1);
|
|
}
|
|
|
|
int
|
|
ambapp_find_ahbslvs (struct ambapp_dev_hdr *root, int vendor, int device,
|
|
struct ambapp_ahb_info *dev, int maxno)
|
|
{
|
|
return ambapp_find_ahbslvs_next (root, vendor, device, dev, 0, maxno);
|
|
}
|
|
|
|
struct ambapp_dev_hdr *
|
|
ambapp_find_parent (struct ambapp_dev_hdr *dev)
|
|
{
|
|
while (dev->prev)
|
|
{
|
|
if (dev == dev->prev->children)
|
|
{
|
|
return dev->prev;
|
|
}
|
|
dev = dev->prev;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
struct ambapp_dev_hdr *ambapp_root = NULL;
|
|
extern unsigned int console;
|
|
extern unsigned int rtc;
|
|
|
|
void
|
|
pnpinit (void)
|
|
{
|
|
struct ambapp_apb_info dev;
|
|
int n;
|
|
ambapp_scan (LEON3_IO_AREA, NULL, NULL, NULL, &ambapp_root, NULL);
|
|
if ((n =
|
|
ambapp_find_apbslv (ambapp_root, VENDOR_GAISLER, GAISLER_APBUART,
|
|
&dev)) == 1)
|
|
{
|
|
console = dev.start;
|
|
DPRINTF (("Found abuart at 0x%x\n", console));
|
|
}
|
|
if ((n =
|
|
ambapp_find_apbslv (ambapp_root, VENDOR_GAISLER, GAISLER_GPTIMER,
|
|
&dev)) == 1)
|
|
{
|
|
rtc = dev.start + 0x10;
|
|
DPRINTF (("Found rtc at 0x%x\n", rtc));
|
|
}
|
|
}
|