mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-27 06:21:25 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			360 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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
 | |
|  *
 | |
|  * See file CREDITS for list of people who contributed to this
 | |
|  * project.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License as
 | |
|  * published by the Free Software Foundation; either version 2 of
 | |
|  * the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | |
|  * MA 02111-1307 USA
 | |
|  */
 | |
| 
 | |
| #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);
 | |
| }
 |