* configure.in: Add SPARC LEON support.
        * configure: Regenerated.
        * sparc_leon/asm-leon/amba.h, sparc_leon/asm-leon/asmmacro.h,
        sparc_leon/asm-leon/clock.h, sparc_leon/asm-leon/contextswitch.h,
        sparc_leon/asm-leon/elfmacro.h, sparc_leon/asm-leon/head.h,
        sparc_leon/asm-leon/irq.h, sparc_leon/asm-leon/jiffies.h,
        sparc_leon/asm-leon/lambapp.h, sparc_leon/asm-leon/lambapp_devs.h,
        sparc_leon/asm-leon/leon.h, sparc_leon/asm-leon/leon3.h,
        sparc_leon/asm-leon/leonbare_debug.h, sparc_leon/asm-leon/leonbare_kernel.h,
        sparc_leon/asm-leon/leonbare_kernel_queue.h, sparc_leon/asm-leon/leoncompat.h,
        sparc_leon/asm-leon/leondbg.h, sparc_leon/asm-leon/leonstack.h,
        sparc_leon/asm-leon/liblocks.h, sparc_leon/asm-leon/linkage.h,
        sparc_leon/asm-leon/param.h, sparc_leon/asm-leon/queue.h,
        sparc_leon/asm-leon/spinlock.h, sparc_leon/asm-leon/stack.h,
        sparc_leon/asm-leon/time.h, sparc_leon/asm-leon/timer.h,
        sparc_leon/asm-leon/types.h, sparc_leon/asm-leon/winmacros.h:
        New file.
        * sparc_leon/Makefile.in, sparc_leon/_exit.c,
        sparc_leon/amba.c, sparc_leon/amba_dbg.c,
        sparc_leon/amba_driver.c, sparc_leon/amba_scan.c,
        sparc_leon/asm-leon, sparc_leon/bdinit.S,
        sparc_leon/busscan.S, sparc_leon/cacheA.S,
        sparc_leon/catch_interrupt.c, sparc_leon/catch_interrupt_mvt.c,
        sparc_leon/catch_interrupt_pending.c, sparc_leon/catch_interrupt_svt.c,
        sparc_leon/configure.in,
        sparc_leon/console.c, sparc_leon/console_dbg.c,
        sparc_leon/console_init.c, sparc_leon/contextswitch.c,
        sparc_leon/contextswitch_asm.S, sparc_leon/crt0.S,
        sparc_leon/crti.S, sparc_leon/crtn.S,
        sparc_leon/etrap.S, sparc_leon/etrap_fast.S,
        sparc_leon/fpu.S, sparc_leon/gettimeofday.c,
        sparc_leon/initcalls.c, sparc_leon/io.c,
        sparc_leon/irqinstall.S, sparc_leon/irqtrap.S,
        sparc_leon/irqtrap_fast.S, sparc_leon/jiffies.c,
        sparc_leon/kernel.c, sparc_leon/kernel_context.S,
        sparc_leon/kernel_debug.c, sparc_leon/kernel_debug_var.c,
        sparc_leon/kernel_mm.c, sparc_leon/kernel_mutex.c,
        sparc_leon/kernel_queue.c, sparc_leon/kernel_sched.c,
        sparc_leon/kernel_thread.c, sparc_leon/lcpuinit.S,
        sparc_leon/locore.S, sparc_leon/locore_atexit.c,
        sparc_leon/locore_clean.S, sparc_leon/locore_mvt.S,
        sparc_leon/locore_mvt_reset.S, sparc_leon/locore_svt.S,
        sparc_leon/locore_svt_reset.S, sparc_leon/locore_svtdisp.S,
        sparc_leon/locore_var.S, sparc_leon/locore_var_svt.S,
        sparc_leon/mmu_asm.S, sparc_leon/mutex.c,
        sparc_leon/nocache.S, sparc_leon/pnpinit.c,
        sparc_leon/pnpinit_malloc.c, sparc_leon/pnpinit_simple.c,
        sparc_leon/regwin.S, sparc_leon/regwin_patch.c,
        sparc_leon/regwin_slow.S, sparc_leon/regwinflush.S,
        sparc_leon/rtc.c, sparc_leon/rtrap.S,
        sparc_leon/rtrap_fast.S, sparc_leon/stop.S,
        sparc_leon/timer.c, sparc_leon/times.c:
        New file
        * sparc_leon/configure: Regenerate
		
	
		
			
				
	
	
		
			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));
 | |
|     }
 | |
| }
 |