blob: a30d1f2a99b35c4060b435d5416f72efb2ca8a62 [file] [log] [blame]
/* Gaisler AMBA Plug&Play bus scanning. Functions
* ending on _nomem is inteded to be used only during
* initialization, only registers are used (no ram).
*
* (C) Copyright 2007
* Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <ambapp.h>
#if defined(CONFIG_CMD_AMBAPP)
extern void ambapp_print_apb(apbctrl_pp_dev * apb,
ambapp_ahbdev * apbmst, int index);
extern void ambapp_print_ahb(ahbctrl_pp_dev * ahb, int index);
extern int ambapp_apb_print;
extern int ambapp_ahb_print;
#endif
static int ambapp_apb_scan(unsigned int vendor, /* Plug&Play Vendor ID */
unsigned int driver, /* Plug&Play Device ID */
ambapp_apbdev * dev, /* Result(s) is placed here */
int index, /* Index of device to start copying Plug&Play
* info into dev
*/
int max_cnt /* Maximal count that dev can hold, if dev
* is NULL function will stop scanning after
* max_cnt devices are found.
*/
)
{
int i, cnt = 0;
unsigned int apbmst_base;
ambapp_ahbdev apbmst;
apbctrl_pp_dev *apb;
if (max_cnt == 0)
return 0;
/* Get AMBA APB Master */
if (ambapp_ahbslv_first(VENDOR_GAISLER, GAISLER_APBMST, &apbmst) != 1) {
return 0;
}
/* Get APB CTRL Plug&Play info area */
apbmst_base = apbmst.address[0] & LEON3_IO_AREA;
apb = (apbctrl_pp_dev *) (apbmst_base | LEON3_CONF_AREA);
for (i = 0; i < LEON3_APB_SLAVES; i++) {
#if defined(CONFIG_CMD_AMBAPP)
if (ambapp_apb_print && amba_vendor(apb->conf)
&& amba_device(apb->conf)) {
ambapp_print_apb(apb, &apbmst, i);
}
#endif
if ((amba_vendor(apb->conf) == vendor) &&
(amba_device(apb->conf) == driver) && ((index < 0)
|| (index-- == 0))) {
/* Convert Plug&Play info into a more readable format */
cnt++;
if (dev) {
dev->irq = amba_irq(apb->conf);
dev->ver = amba_ver(apb->conf);
dev->address =
(apbmst_base |
(((apb->
bar & 0xfff00000) >> 12))) & (((apb->
bar &
0x0000fff0)
<< 4) |
0xfff00000);
dev++;
}
/* found max devices? */
if (cnt >= max_cnt)
return cnt;
}
/* Get next Plug&Play entry */
apb++;
}
return cnt;
}
unsigned int ambapp_apb_next_nomem(register unsigned int vendor, /* Plug&Play Vendor ID */
register unsigned int driver, /* Plug&Play Device ID */
register int index)
{
register int i;
register ahbctrl_pp_dev *apbmst;
register apbctrl_pp_dev *apb;
register unsigned int apbmst_base;
/* APBMST is a AHB Slave */
apbmst = ambapp_ahb_next_nomem(VENDOR_GAISLER, GAISLER_APBMST, 1, 0);
if (!apbmst)
return 0;
apbmst_base = amba_membar_start(apbmst->bars[0]);
if (amba_membar_type(apbmst->bars[0]) == AMBA_TYPE_AHBIO)
apbmst_base = AMBA_TYPE_AHBIO_ADDR(apbmst_base);
apbmst_base &= LEON3_IO_AREA;
/* Find the vendor/driver device on the first APB bus */
apb = (apbctrl_pp_dev *) (apbmst_base | LEON3_CONF_AREA);
for (i = 0; i < LEON3_APB_SLAVES; i++) {
if ((amba_vendor(apb->conf) == vendor) &&
(amba_device(apb->conf) == driver) && ((index < 0)
|| (index-- == 0))) {
/* Convert Plug&Play info info a more readable format */
return (apbmst_base | (((apb->bar & 0xfff00000) >> 12)))
& (((apb->bar & 0x0000fff0) << 4) | 0xfff00000);
}
/* Get next Plug&Play entry */
apb++;
}
return 0;
}
/****************************** APB SLAVES ******************************/
int ambapp_apb_count(unsigned int vendor, unsigned int driver)
{
return ambapp_apb_scan(vendor, driver, NULL, 0, LEON3_APB_SLAVES);
}
int ambapp_apb_first(unsigned int vendor,
unsigned int driver, ambapp_apbdev * dev)
{
return ambapp_apb_scan(vendor, driver, dev, 0, 1);
}
int ambapp_apb_next(unsigned int vendor,
unsigned int driver, ambapp_apbdev * dev, int index)
{
return ambapp_apb_scan(vendor, driver, dev, index, 1);
}
int ambapp_apbs_first(unsigned int vendor,
unsigned int driver, ambapp_apbdev * dev, int max_cnt)
{
return ambapp_apb_scan(vendor, driver, dev, 0, max_cnt);
}
enum {
AHB_SCAN_MASTER = 0,
AHB_SCAN_SLAVE = 1
};
/* Scan AMBA Plug&Play bus for AMBA AHB Masters or AHB Slaves
* for a certain matching Vendor and Device ID.
*
* Return number of devices found.
*
* Compact edition...
*/
static int ambapp_ahb_scan(unsigned int vendor, /* Plug&Play Vendor ID */
unsigned int driver, /* Plug&Play Device ID */
ambapp_ahbdev * dev, /* Result(s) is placed here */
int index, /* Index of device to start copying Plug&Play
* info into dev
*/
int max_cnt, /* Maximal count that dev can hold, if dev
* is NULL function will stop scanning after
* max_cnt devices are found.
*/
int type /* Selectes what type of devices to scan.
* 0=AHB Masters
* 1=AHB Slaves
*/
)
{
int i, j, cnt = 0, max_pp_devs;
unsigned int addr;
ahbctrl_info *info = (ahbctrl_info *) (LEON3_IO_AREA | LEON3_CONF_AREA);
ahbctrl_pp_dev *ahb;
if (max_cnt == 0)
return 0;
if (type == 0) {
max_pp_devs = LEON3_AHB_MASTERS;
ahb = info->masters;
} else {
max_pp_devs = LEON3_AHB_SLAVES;
ahb = info->slaves;
}
for (i = 0; i < max_pp_devs; i++) {
#if defined(CONFIG_CMD_AMBAPP)
if (ambapp_ahb_print && amba_vendor(ahb->conf) &&
amba_device(ahb->conf)) {
ambapp_print_ahb(ahb, i);
}
#endif
if ((amba_vendor(ahb->conf) == vendor) &&
(amba_device(ahb->conf) == driver) &&
((index < 0) || (index-- == 0))) {
/* Convert Plug&Play info info a more readable format */
cnt++;
if (dev) {
dev->irq = amba_irq(ahb->conf);
dev->ver = amba_ver(ahb->conf);
dev->userdef[0] = ahb->userdef[0];
dev->userdef[1] = ahb->userdef[1];
dev->userdef[2] = ahb->userdef[2];
for (j = 0; j < 4; j++) {
addr = amba_membar_start(ahb->bars[j]);
if (amba_membar_type(ahb->bars[j]) ==
AMBA_TYPE_AHBIO)
addr =
AMBA_TYPE_AHBIO_ADDR(addr);
dev->address[j] = addr;
}
dev++;
}
/* found max devices? */
if (cnt >= max_cnt)
return cnt;
}
/* Get next Plug&Play entry */
ahb++;
}
return cnt;
}
unsigned int ambapp_ahb_get_info(ahbctrl_pp_dev * ahb, int info)
{
register unsigned int ret;
if (!ahb)
return 0;
switch (info) {
default:
info = 0;
case 0:
case 1:
case 2:
case 3:
/* Get Address from PnP Info */
ret = amba_membar_start(ahb->bars[info]);
if (amba_membar_type(ahb->bars[info]) == AMBA_TYPE_AHBIO)
ret = AMBA_TYPE_AHBIO_ADDR(ret);
return ret;
}
return 0;
}
ahbctrl_pp_dev *ambapp_ahb_next_nomem(register unsigned int vendor, /* Plug&Play Vendor ID */
register unsigned int driver, /* Plug&Play Device ID */
register unsigned int opts, /* 1=slave, 0=master */
register int index)
{
register ahbctrl_pp_dev *ahb;
register ahbctrl_info *info =
(ahbctrl_info *) (LEON3_IO_AREA | LEON3_CONF_AREA);
register int i;
register int max_pp_devs;
if (opts == 0) {
max_pp_devs = LEON3_AHB_MASTERS;
ahb = info->masters;
} else {
max_pp_devs = LEON3_AHB_SLAVES;
ahb = info->slaves;
}
for (i = 0; i < max_pp_devs; i++) {
if ((amba_vendor(ahb->conf) == vendor) &&
(amba_device(ahb->conf) == driver) &&
((index < 0) || (index-- == 0))) {
/* Convert Plug&Play info info a more readable format */
return ahb;
}
/* Get next Plug&Play entry */
ahb++;
}
return 0;
}
/****************************** AHB MASTERS ******************************/
int ambapp_ahbmst_count(unsigned int vendor, unsigned int driver)
{
/* Get number of devices of this vendor&device ID */
return ambapp_ahb_scan(vendor, driver, NULL, 0, LEON3_AHB_MASTERS,
AHB_SCAN_MASTER);
}
int ambapp_ahbmst_first(unsigned int vendor, unsigned int driver,
ambapp_ahbdev * dev)
{
/* find first device of this */
return ambapp_ahb_scan(vendor, driver, dev, 0, 1, AHB_SCAN_MASTER);
}
int ambapp_ahbmst_next(unsigned int vendor,
unsigned int driver, ambapp_ahbdev * dev, int index)
{
/* find first device of this */
return ambapp_ahb_scan(vendor, driver, dev, index, 1, AHB_SCAN_MASTER);
}
int ambapp_ahbmsts_first(unsigned int vendor,
unsigned int driver, ambapp_ahbdev * dev, int max_cnt)
{
/* find first device of this */
return ambapp_ahb_scan(vendor, driver, dev, 0, max_cnt,
AHB_SCAN_MASTER);
}
/****************************** AHB SLAVES ******************************/
int ambapp_ahbslv_count(unsigned int vendor, unsigned int driver)
{
/* Get number of devices of this vendor&device ID */
return ambapp_ahb_scan(vendor, driver, NULL, 0, LEON3_AHB_SLAVES,
AHB_SCAN_SLAVE);
}
int ambapp_ahbslv_first(unsigned int vendor, unsigned int driver,
ambapp_ahbdev * dev)
{
/* find first device of this */
return ambapp_ahb_scan(vendor, driver, dev, 0, 1, AHB_SCAN_SLAVE);
}
int ambapp_ahbslv_next(unsigned int vendor,
unsigned int driver, ambapp_ahbdev * dev, int index)
{
/* find first device of this */
return ambapp_ahb_scan(vendor, driver, dev, index, 1, AHB_SCAN_SLAVE);
}
int ambapp_ahbslvs_first(unsigned int vendor,
unsigned int driver, ambapp_ahbdev * dev, int max_cnt)
{
/* find first device of this */
return ambapp_ahb_scan(vendor, driver, dev, 0, max_cnt, AHB_SCAN_SLAVE);
}