Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  AMBA Plug & Play routines
0005  *
0006  *  COPYRIGHT (c) 2011.
0007  *  Aeroflex Gaisler.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include <string.h>
0032 #include <stdlib.h>
0033 #include <string.h>
0034 
0035 #include <grlib/ambapp.h>
0036 #include <bsp.h>
0037 
0038 #include <grlib/grlib_impl.h>
0039 
0040 #define AMBA_CONF_AREA 0xff000
0041 #define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
0042 #define AMBA_APB_SLAVES 16
0043 
0044 /* Allocate one AMBA device */
0045 static struct ambapp_dev *
0046 ambapp_alloc_dev_struct(const struct ambapp_context *ctx, int dev_type)
0047 {
0048   struct ambapp_dev *dev;
0049   size_t size = sizeof(*dev);
0050 
0051   if (dev_type == DEV_APB_SLV)
0052     size += sizeof(struct ambapp_apb_info);
0053   else
0054     size += sizeof(struct ambapp_ahb_info); /* AHB */
0055   dev = (*ctx->alloc)(size);
0056   if (dev != NULL) {
0057     dev = memset(dev, 0, size);
0058     dev->dev_type = dev_type;
0059   }
0060   return dev;
0061 }
0062 
0063 static unsigned int
0064 ambapp_addr_from (struct ambapp_mmap *mmaps, unsigned int address)
0065 {
0066   /* no translation? */
0067   if (!mmaps)
0068     return address;
0069 
0070   while (mmaps->size) {
0071     if ((address >= mmaps->remote_adr) &&
0072         (address <= (mmaps->remote_adr + (mmaps->size - 1)))) {
0073       return (address - mmaps->remote_adr) + mmaps->local_adr;
0074     }
0075     mmaps++;
0076   }
0077   return 1;
0078 }
0079 
0080 static void ambapp_ahb_dev_init(
0081   unsigned int ioarea,
0082   struct ambapp_mmap *mmaps,
0083   struct ambapp_pnp_ahb *ahb,
0084   struct ambapp_dev *dev,
0085   int ahbidx
0086   )
0087 {
0088   int bar;
0089   struct ambapp_ahb_info *ahb_info;
0090   unsigned int addr, mask, mbar;
0091 
0092   /* Setup device struct */
0093   dev->vendor = ambapp_pnp_vendor(ahb->id);
0094   dev->device = ambapp_pnp_device(ahb->id);
0095   ahb_info = DEV_TO_AHB(dev);
0096   ahb_info->common.ver = ambapp_pnp_ver(ahb->id);
0097   ahb_info->common.irq = ambapp_pnp_irq(ahb->id);
0098   ahb_info->common.ahbidx = ahbidx;
0099   ahb_info->custom[0] = (unsigned int)ahb->custom[0];
0100   ahb_info->custom[1] = (unsigned int)ahb->custom[1];
0101   ahb_info->custom[2] = (unsigned int)ahb->custom[2];
0102 
0103   /* Memory BARs */
0104   for (bar=0; bar<4; bar++) {
0105     mbar = ahb->mbar[bar];
0106     if (mbar == 0) {
0107       addr = 0;
0108       mask = 0;
0109     } else {
0110       addr = ambapp_pnp_start(mbar);
0111       if (ambapp_pnp_mbar_type(mbar) == AMBA_TYPE_AHBIO) {
0112         /* AHB I/O area is releative IO_AREA */
0113         addr = AMBA_TYPE_AHBIO_ADDR(addr, ioarea);
0114         mask = (((unsigned int)(ambapp_pnp_mbar_mask(~mbar) << 8) | 0xff)) + 1;
0115       } else {
0116         /* AHB memory area, absolute address */
0117         addr = ambapp_addr_from(mmaps, addr);
0118         mask = (~((unsigned int)(ambapp_pnp_mbar_mask(mbar) << 20))) + 1;
0119       }
0120     }
0121     ahb_info->start[bar] = addr;
0122     ahb_info->mask[bar] = mask;
0123     ahb_info->type[bar] = ambapp_pnp_mbar_type(mbar);
0124   }
0125 }
0126 
0127 static void ambapp_apb_dev_init(
0128   unsigned int base,
0129   struct ambapp_mmap *mmaps,
0130   struct ambapp_pnp_apb *apb,
0131   struct ambapp_dev *dev,
0132   int ahbidx
0133   )
0134 {
0135   struct ambapp_apb_info *apb_info;
0136 
0137   /* Setup device struct */
0138   dev->vendor = ambapp_pnp_vendor(apb->id);
0139   dev->device = ambapp_pnp_device(apb->id);
0140   apb_info = DEV_TO_APB(dev);
0141   apb_info->common.ver = ambapp_pnp_ver(apb->id);
0142   apb_info->common.irq = ambapp_pnp_irq(apb->id);
0143   apb_info->common.ahbidx = ahbidx;
0144   apb_info->start = ambapp_pnp_apb_start(apb->iobar, base);
0145   apb_info->mask = ambapp_pnp_apb_mask(apb->iobar);
0146 }
0147 
0148 static int ambapp_add_ahbbus(
0149   struct ambapp_bus *abus,
0150   unsigned int ioarea
0151   )
0152 {
0153   int i;
0154   for (i=0; i<AHB_BUS_MAX; i++) {
0155     if (abus->ahbs[i].ioarea == 0) {
0156       abus->ahbs[i].ioarea = ioarea;
0157       return i;
0158     } else if (abus->ahbs[i].ioarea == ioarea) {
0159       /* Bus already added */
0160       return -1;
0161     }
0162   }
0163   return -1;
0164 }
0165 
0166 /* Internal AMBA Scanning Function */
0167 static int ambapp_scan2(
0168   struct ambapp_bus *abus,
0169   unsigned int ioarea,
0170   const struct ambapp_context *ctx,
0171   struct ambapp_dev *parent,
0172   struct ambapp_dev **root
0173   )
0174 {
0175   struct ambapp_pnp_ahb *ahb, ahb_buf;
0176   struct ambapp_pnp_apb *apb, apb_buf;
0177   struct ambapp_dev *dev, *prev, *prevapb, *apbdev;
0178   struct ambapp_ahb_info *ahb_info;
0179   int maxloops = 64;
0180   unsigned int apbbase, bridge_adr;
0181   int i, j, ahbidx;
0182 
0183   *root = NULL;
0184 
0185   if (parent) {
0186     /* scan first bus for 64 devices, rest for 16 devices */
0187     maxloops = 16;
0188   }
0189 
0190   ahbidx = ambapp_add_ahbbus(abus, ioarea);
0191   if (ahbidx < 0) {
0192     /* Bus already scanned, stop */
0193     return 0;
0194   }
0195 
0196   prev = parent;
0197 
0198   /* AHB MASTERS */
0199   ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
0200   for (i = 0; i < maxloops; i++, ahb++) {
0201     (*ctx->copy_from_device)(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
0202     if (ahb_buf.id == 0)
0203       continue;
0204 
0205     /* An AHB device present here */
0206     dev = ambapp_alloc_dev_struct(ctx, DEV_AHB_MST);
0207     if (!dev)
0208       return -1;
0209 
0210     ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
0211 
0212     if (*root == NULL)
0213       *root = dev;
0214 
0215     if (prev != parent)
0216       prev->next = dev;
0217     dev->prev = prev;
0218     prev = dev;
0219   }
0220 
0221   /* AHB SLAVES */
0222   ahb = (struct ambapp_pnp_ahb *)
0223     (ioarea | AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA);
0224   for (i = 0; i < maxloops; i++, ahb++) {
0225     (*ctx->copy_from_device)(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
0226     if (ahb_buf.id == 0)
0227       continue;
0228 
0229     /* An AHB device present here */
0230     dev = ambapp_alloc_dev_struct(ctx, DEV_AHB_SLV);
0231     if (!dev)
0232       return -1;
0233 
0234     ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
0235 
0236     if (*root == NULL)
0237       *root = dev;
0238 
0239     if (prev != parent)
0240       prev->next = dev;
0241     dev->prev = prev;
0242     prev = dev;
0243 
0244     ahb_info = DEV_TO_AHB(dev);
0245 
0246     /* Is it a AHB/AHB Bridge ? */
0247     if (((dev->device == GAISLER_AHB2AHB) &&
0248         (dev->vendor == VENDOR_GAISLER) && (ahb_info->common.ver > 0)) ||
0249         ((dev->device == GAISLER_L2CACHE) &&
0250         (dev->vendor == VENDOR_GAISLER)) ||
0251         ((dev->device == GAISLER_GRIOMMU) &&
0252         (dev->vendor == VENDOR_GAISLER))) {
0253       /* AHB/AHB Bridge Found, recurse down the
0254        * Bridge
0255        */
0256       if (ahb_info->custom[1] != 0) {
0257         bridge_adr = ambapp_addr_from(abus->mmaps,
0258               ahb_info->custom[1]);
0259         /* Scan next bus if not already scanned */
0260         if (ambapp_scan2(abus, bridge_adr, ctx, dev,
0261             &dev->children))
0262           return -1;
0263       }
0264     } else if ((dev->device == GAISLER_APBMST) &&
0265                (dev->vendor == VENDOR_GAISLER)) {
0266       /* AHB/APB Bridge Found, add the APB devices to this
0267        * AHB Slave's children
0268        */
0269       prevapb = dev;
0270       apbbase = ahb_info->start[0];
0271 
0272       /* APB SLAVES */
0273       apb = (struct ambapp_pnp_apb *)
0274         (apbbase | AMBA_CONF_AREA);
0275       for (j=0; j<AMBA_APB_SLAVES; j++, apb++) {
0276         (*ctx->copy_from_device)(&apb_buf, apb, sizeof(*apb), abus);
0277         if (apb_buf.id == 0)
0278           continue;
0279 
0280         apbdev = ambapp_alloc_dev_struct(ctx, DEV_APB_SLV);
0281         if (!apbdev)
0282           return -1;
0283 
0284         ambapp_apb_dev_init(apbbase, abus->mmaps,
0285                             &apb_buf, apbdev, ahbidx);
0286 
0287         if (prevapb != dev)
0288           prevapb->next = apbdev;
0289         else
0290           dev->children = apbdev;
0291         apbdev->prev = prevapb;
0292         prevapb = apbdev;
0293       }
0294     }
0295   }
0296 
0297   /* Remember first AHB MST/SLV device on bus and Parent Bridge */
0298   abus->ahbs[ahbidx].dev = *root;
0299   abus->ahbs[ahbidx].bridge = parent;
0300 
0301   return 0;
0302 }
0303 
0304 static const struct ambapp_context default_ctx = {
0305   .copy_from_device = (ambapp_memcpy_t)memcpy,
0306   .alloc = rtems_malloc
0307 };
0308 
0309 /* Build AMBA Plug & Play device graph */
0310 int ambapp_scan(
0311   struct ambapp_bus *abus,
0312   unsigned int ioarea,
0313   const struct ambapp_context *ctx,
0314   struct ambapp_mmap *mmaps
0315   )
0316 {
0317 
0318   memset(abus, 0, sizeof(*abus));
0319   abus->mmaps = mmaps;
0320 
0321   if (ctx == NULL) {
0322     ctx = &default_ctx;
0323   }
0324 
0325   return ambapp_scan2(abus, ioarea, ctx, NULL, &abus->root);
0326 }
0327 
0328 /* Match search options againt device */
0329 static int ambapp_dev_match_options(struct ambapp_dev *dev, unsigned int options, int vendor, int device)
0330 {
0331   if ((((options & (OPTIONS_ALL_DEVS)) == OPTIONS_ALL_DEVS) || /* TYPE */
0332       ((options & OPTIONS_AHB_MSTS) && (dev->dev_type == DEV_AHB_MST)) ||
0333       ((options & OPTIONS_AHB_SLVS) && (dev->dev_type == DEV_AHB_SLV)) ||
0334       ((options & OPTIONS_APB_SLVS) && (dev->dev_type == DEV_APB_SLV))) &&
0335       ((vendor == -1) || (vendor == dev->vendor)) && /* VENDOR/DEV ID */
0336       ((device == -1) || (device == dev->device)) &&
0337       (((options & OPTIONS_ALL) == OPTIONS_ALL) || /* Allocated State */
0338       ((options & OPTIONS_FREE) && DEV_IS_FREE(dev)) ||
0339       ((options & OPTIONS_ALLOCATED) && DEV_IS_ALLOCATED(dev)))) {
0340     return 1;
0341   }
0342   return 0;
0343 }
0344 
0345 /* If device is an APB bridge all devices on the APB bridge is processed */
0346 static int ambapp_for_each_apb(
0347   struct ambapp_dev *dev,
0348   unsigned int options,
0349   int vendor,
0350   int device,
0351   ambapp_func_t func,
0352   void *arg)
0353 {
0354   int index, ret;
0355   struct ambapp_dev *apbslv;
0356 
0357   ret = 0;
0358   if (dev->children && (dev->children->dev_type == DEV_APB_SLV)) {
0359     /* Found a APB Bridge */
0360     index = 0;
0361     apbslv = dev->children;
0362     while (apbslv) {
0363       if (ambapp_dev_match_options(apbslv, options,
0364                                    vendor, device) == 1) {
0365         ret = func(apbslv, index, arg);
0366         if (ret != 0)
0367           break; /* Signalled stopped */
0368       }
0369       index++;
0370       apbslv = apbslv->next;
0371     }
0372   }
0373 
0374   return ret;
0375 }
0376 
0377 /* Traverse the prescanned device information */
0378 static int ambapp_for_each_dev(
0379   struct ambapp_dev *root,
0380   unsigned int options,
0381   int vendor,
0382   int device,
0383   ambapp_func_t func,
0384   void *arg)
0385 {
0386   struct ambapp_dev *dev;
0387   int ahb_slave = 0;
0388   int index, ret;
0389 
0390   /* Start at device 'root' and process downwards.
0391    *
0392    * Breadth first search, search order
0393    * 1. AHB MSTS
0394    * 2. AHB SLVS
0395    * 3. APB SLVS on primary bus
0396    * 4. AHB/AHB secondary... -> step to 1.
0397    */
0398 
0399   /* AHB MST / AHB SLV */
0400   if (options & (OPTIONS_AHB_MSTS|OPTIONS_AHB_SLVS|OPTIONS_DEPTH_FIRST)) {
0401     index = 0;
0402     dev = root;
0403     while (dev) {
0404       if ((dev->dev_type == DEV_AHB_SLV) && !ahb_slave) {
0405         /* First AHB Slave */
0406         ahb_slave = 1;
0407         index = 0;
0408       }
0409 
0410       /* Conditions must be fullfilled for function to be
0411        * called
0412        */
0413       if (ambapp_dev_match_options(dev, options, vendor, device) == 1) {
0414         /* Correct device and vendor ID */
0415         ret = func(dev, index, arg);
0416         if (ret != 0)
0417           return ret; /* Signalled stopped */
0418       }
0419 
0420       if ((options & OPTIONS_DEPTH_FIRST) && (options & OPTIONS_APB_SLVS)) {
0421         /* Check is APB bridge, and process all APB
0422          * Slaves in that case
0423          */
0424         ret = ambapp_for_each_apb(dev, options, vendor, device, func, arg);
0425         if (ret != 0)
0426           return ret; /* Signalled stopped */
0427       }
0428 
0429       if (options & OPTIONS_DEPTH_FIRST) {
0430         if (dev->children && (dev->children->dev_type != DEV_APB_SLV)) {
0431           /* Found AHB Bridge, recurse */
0432           ret = ambapp_for_each_dev(dev->children, options, vendor, device,
0433                                     func, arg);
0434           if (ret != 0)
0435             return ret;
0436         }
0437       }
0438 
0439       index++;
0440       dev = dev->next;
0441     }
0442   }
0443 
0444   /* Find APB Bridges */
0445   if ((options & OPTIONS_APB_SLVS) && !(options & OPTIONS_DEPTH_FIRST)) {
0446     dev = root;
0447     while (dev) {
0448       /* Check is APB bridge, and process all APB Slaves in
0449        * that case
0450        */
0451       ret = ambapp_for_each_apb(dev, options, vendor, device, func, arg);
0452       if (ret != 0)
0453         return ret; /* Signalled stopped */
0454       dev = dev->next;
0455     }
0456   }
0457 
0458   /* Find AHB Bridges */
0459   if (!(options & OPTIONS_DEPTH_FIRST)) {
0460     dev = root;
0461     while (dev) {
0462       if (dev->children && (dev->children->dev_type != DEV_APB_SLV)) {
0463         /* Found AHB Bridge, recurse */
0464         ret = ambapp_for_each_dev(dev->children, options, vendor, device,
0465                               func, arg);
0466         if (ret != 0)
0467           return ret;
0468       }
0469       dev = dev->next;
0470     }
0471   }
0472 
0473   return 0;
0474 }
0475 
0476 int ambapp_for_each(
0477   struct ambapp_bus *abus,
0478   unsigned int options,
0479   int vendor,
0480   int device,
0481   ambapp_func_t func,
0482   void *arg)
0483 {
0484   return ambapp_for_each_dev(abus->root, options, vendor, device, func, arg);
0485 }