source: rtems/bsps/sparc/shared/amba/ambapp.c @ 31720925

Last change on this file since 31720925 was 31720925, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 22, 2018 at 6:13:44 AM

grlib: Move header files

Update #3678.

  • Property mode set to 100644
File size: 11.6 KB
Line 
1/*
2 *  AMBA Plug & Play routines
3 *
4 *  COPYRIGHT (c) 2011.
5 *  Aeroflex Gaisler.
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.org/license/LICENSE.
10 */
11
12#include <string.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include <grlib/ambapp.h>
17#include <bsp.h>
18
19#include <grlib/grlib_impl.h>
20
21#define AMBA_CONF_AREA 0xff000
22#define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
23#define AMBA_APB_SLAVES 16
24
25/* Allocate one AMBA device */
26static struct ambapp_dev *ambapp_alloc_dev_struct(int dev_type)
27{
28  struct ambapp_dev *dev;
29  size_t size = sizeof(*dev);
30
31  if (dev_type == DEV_APB_SLV)
32    size += sizeof(struct ambapp_apb_info);
33  else
34    size += sizeof(struct ambapp_ahb_info); /* AHB */
35  dev = grlib_calloc(1, size);
36  if (dev != NULL)
37    dev->dev_type = dev_type;
38  return dev;
39}
40
41static unsigned int
42ambapp_addr_from (struct ambapp_mmap *mmaps, unsigned int address)
43{
44  /* no translation? */
45  if (!mmaps)
46    return address;
47
48  while (mmaps->size) {
49    if ((address >= mmaps->remote_adr) &&
50        (address <= (mmaps->remote_adr + (mmaps->size - 1)))) {
51      return (address - mmaps->remote_adr) + mmaps->local_adr;
52    }
53    mmaps++;
54  }
55  return 1;
56}
57
58static void ambapp_ahb_dev_init(
59  unsigned int ioarea,
60  struct ambapp_mmap *mmaps,
61  struct ambapp_pnp_ahb *ahb,
62  struct ambapp_dev *dev,
63  int ahbidx
64  )
65{
66  int bar;
67  struct ambapp_ahb_info *ahb_info;
68  unsigned int addr, mask, mbar;
69
70  /* Setup device struct */
71  dev->vendor = ambapp_pnp_vendor(ahb->id);
72  dev->device = ambapp_pnp_device(ahb->id);
73  ahb_info = DEV_TO_AHB(dev);
74  ahb_info->ver = ambapp_pnp_ver(ahb->id);
75  ahb_info->irq = ambapp_pnp_irq(ahb->id);
76  ahb_info->ahbidx = ahbidx;
77  ahb_info->custom[0] = (unsigned int)ahb->custom[0];
78  ahb_info->custom[1] = (unsigned int)ahb->custom[1];
79  ahb_info->custom[2] = (unsigned int)ahb->custom[2];
80
81  /* Memory BARs */
82  for (bar=0; bar<4; bar++) {
83    mbar = ahb->mbar[bar];
84    if (mbar == 0) {
85      addr = 0;
86      mask = 0;
87    } else {
88      addr = ambapp_pnp_start(mbar);
89      if (ambapp_pnp_mbar_type(mbar) == AMBA_TYPE_AHBIO) {
90        /* AHB I/O area is releative IO_AREA */
91        addr = AMBA_TYPE_AHBIO_ADDR(addr, ioarea);
92        mask = (((unsigned int)(ambapp_pnp_mbar_mask(~mbar) << 8) | 0xff)) + 1;
93      } else {
94        /* AHB memory area, absolute address */
95        addr = ambapp_addr_from(mmaps, addr);
96        mask = (~((unsigned int)(ambapp_pnp_mbar_mask(mbar) << 20))) + 1;
97      }
98    }
99    ahb_info->start[bar] = addr;
100    ahb_info->mask[bar] = mask;
101    ahb_info->type[bar] = ambapp_pnp_mbar_type(mbar);
102  }
103}
104
105static void ambapp_apb_dev_init(
106  unsigned int base,
107  struct ambapp_mmap *mmaps,
108  struct ambapp_pnp_apb *apb,
109  struct ambapp_dev *dev,
110  int ahbidx
111  )
112{
113  struct ambapp_apb_info *apb_info;
114
115  /* Setup device struct */
116  dev->vendor = ambapp_pnp_vendor(apb->id);
117  dev->device = ambapp_pnp_device(apb->id);
118  apb_info = DEV_TO_APB(dev);
119  apb_info->ver = ambapp_pnp_ver(apb->id);
120  apb_info->irq = ambapp_pnp_irq(apb->id);
121  apb_info->ahbidx = ahbidx;
122  apb_info->start = ambapp_pnp_apb_start(apb->iobar, base);
123  apb_info->mask = ambapp_pnp_apb_mask(apb->iobar);
124}
125
126static int ambapp_add_ahbbus(
127  struct ambapp_bus *abus,
128  unsigned int ioarea
129  )
130{
131  int i;
132  for (i=0; i<AHB_BUS_MAX; i++) {
133    if (abus->ahbs[i].ioarea == 0) {
134      abus->ahbs[i].ioarea = ioarea;
135      return i;
136    } else if (abus->ahbs[i].ioarea == ioarea) {
137      /* Bus already added */
138      return -1;
139    }
140  }
141  return -1;
142}
143
144/* Internal AMBA Scanning Function */
145static int ambapp_scan2(
146  struct ambapp_bus *abus,
147  unsigned int ioarea,
148  ambapp_memcpy_t memfunc,
149  struct ambapp_dev *parent,
150  struct ambapp_dev **root
151  )
152{
153  struct ambapp_pnp_ahb *ahb, ahb_buf;
154  struct ambapp_pnp_apb *apb, apb_buf;
155  struct ambapp_dev *dev, *prev, *prevapb, *apbdev;
156  struct ambapp_ahb_info *ahb_info;
157  int maxloops = 64;
158  unsigned int apbbase, bridge_adr;
159  int i, j, ahbidx;
160
161  *root = NULL;
162
163  if (parent) {
164    /* scan first bus for 64 devices, rest for 16 devices */
165    maxloops = 16;
166  }
167
168  ahbidx = ambapp_add_ahbbus(abus, ioarea);
169  if (ahbidx < 0) {
170    /* Bus already scanned, stop */
171    return 0;
172  }
173
174  prev = parent;
175
176  /* AHB MASTERS */
177  ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
178  for (i = 0; i < maxloops; i++, ahb++) {
179    memfunc(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
180    if (ahb_buf.id == 0)
181      continue;
182
183    /* An AHB device present here */
184    dev = ambapp_alloc_dev_struct(DEV_AHB_MST);
185    if (!dev)
186      return -1;
187
188    ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
189
190    if (*root == NULL)
191      *root = dev;
192
193    if (prev != parent)
194      prev->next = dev;
195    dev->prev = prev;
196    prev = dev;
197  }
198
199  /* AHB SLAVES */
200  ahb = (struct ambapp_pnp_ahb *)
201    (ioarea | AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA);
202  for (i = 0; i < maxloops; i++, ahb++) {
203    memfunc(&ahb_buf, ahb, sizeof(struct ambapp_pnp_ahb), abus);
204    if (ahb_buf.id == 0)
205      continue;
206
207    /* An AHB device present here */
208    dev = ambapp_alloc_dev_struct(DEV_AHB_SLV);
209    if (!dev)
210      return -1;
211
212    ambapp_ahb_dev_init(ioarea, abus->mmaps, &ahb_buf, dev, ahbidx);
213
214    if (*root == NULL)
215      *root = dev;
216
217    if (prev != parent)
218      prev->next = dev;
219    dev->prev = prev;
220    prev = dev;
221
222    ahb_info = DEV_TO_AHB(dev);
223
224    /* Is it a AHB/AHB Bridge ? */
225    if (((dev->device == GAISLER_AHB2AHB) &&
226        (dev->vendor == VENDOR_GAISLER) && (ahb_info->ver > 0)) ||
227        ((dev->device == GAISLER_L2CACHE) &&
228        (dev->vendor == VENDOR_GAISLER)) ||
229        ((dev->device == GAISLER_GRIOMMU) &&
230        (dev->vendor == VENDOR_GAISLER))) {
231      /* AHB/AHB Bridge Found, recurse down the
232       * Bridge
233       */
234      if (ahb_info->custom[1] != 0) {
235        bridge_adr = ambapp_addr_from(abus->mmaps,
236              ahb_info->custom[1]);
237        /* Scan next bus if not already scanned */
238        if (ambapp_scan2(abus, bridge_adr, memfunc, dev,
239            &dev->children))
240          return -1;
241      }
242    } else if ((dev->device == GAISLER_APBMST) &&
243               (dev->vendor == VENDOR_GAISLER)) {
244      /* AHB/APB Bridge Found, add the APB devices to this
245       * AHB Slave's children
246       */
247      prevapb = dev;
248      apbbase = ahb_info->start[0];
249
250      /* APB SLAVES */
251      apb = (struct ambapp_pnp_apb *)
252        (apbbase | AMBA_CONF_AREA);
253      for (j=0; j<AMBA_APB_SLAVES; j++, apb++) {
254        memfunc(&apb_buf, apb, sizeof(*apb), abus);
255        if (apb_buf.id == 0)
256          continue;
257
258        apbdev = ambapp_alloc_dev_struct(DEV_APB_SLV);
259        if (!apbdev)
260          return -1;
261
262        ambapp_apb_dev_init(apbbase, abus->mmaps,
263                            &apb_buf, apbdev, ahbidx);
264
265        if (prevapb != dev)
266          prevapb->next = apbdev;
267        else
268          dev->children = apbdev;
269        apbdev->prev = prevapb;
270        prevapb = apbdev;
271      }
272    }
273  }
274
275  /* Remember first AHB MST/SLV device on bus and Parent Bridge */
276  abus->ahbs[ahbidx].dev = *root;
277  abus->ahbs[ahbidx].bridge = parent;
278
279  return 0;
280}
281
282/* Build AMBA Plug & Play device graph */
283int ambapp_scan(
284  struct ambapp_bus *abus,
285  unsigned int ioarea,
286  ambapp_memcpy_t memfunc,
287  struct ambapp_mmap *mmaps
288  )
289{
290  memset(abus, 0, sizeof(*abus));
291  abus->mmaps = mmaps;
292
293  /* Default to memcpy() */
294  if (!memfunc)
295    memfunc = (ambapp_memcpy_t)memcpy;
296
297  return ambapp_scan2(abus, ioarea, memfunc, NULL, &abus->root);
298}
299
300/* Match search options againt device */
301static int ambapp_dev_match_options(struct ambapp_dev *dev, unsigned int options, int vendor, int device)
302{
303  if ((((options & (OPTIONS_ALL_DEVS)) == OPTIONS_ALL_DEVS) || /* TYPE */
304      ((options & OPTIONS_AHB_MSTS) && (dev->dev_type == DEV_AHB_MST)) ||
305      ((options & OPTIONS_AHB_SLVS) && (dev->dev_type == DEV_AHB_SLV)) ||
306      ((options & OPTIONS_APB_SLVS) && (dev->dev_type == DEV_APB_SLV))) &&
307      ((vendor == -1) || (vendor == dev->vendor)) && /* VENDOR/DEV ID */
308      ((device == -1) || (device == dev->device)) &&
309      (((options & OPTIONS_ALL) == OPTIONS_ALL) || /* Allocated State */
310      ((options & OPTIONS_FREE) && DEV_IS_FREE(dev)) ||
311      ((options & OPTIONS_ALLOCATED) && DEV_IS_ALLOCATED(dev)))) {
312    return 1;
313  }
314  return 0;
315}
316
317/* If device is an APB bridge all devices on the APB bridge is processed */
318static int ambapp_for_each_apb(
319  struct ambapp_dev *dev,
320  unsigned int options,
321  int vendor,
322  int device,
323  ambapp_func_t func,
324  void *arg)
325{
326  int index, ret;
327  struct ambapp_dev *apbslv;
328
329  ret = 0;
330  if (dev->children && (dev->children->dev_type == DEV_APB_SLV)) {
331    /* Found a APB Bridge */
332    index = 0;
333    apbslv = dev->children;
334    while (apbslv) {
335      if (ambapp_dev_match_options(apbslv, options,
336                                   vendor, device) == 1) {
337        ret = func(apbslv, index, arg);
338        if (ret != 0)
339          break; /* Signalled stopped */
340      }
341      index++;
342      apbslv = apbslv->next;
343    }
344  }
345
346  return ret;
347}
348
349/* Traverse the prescanned device information */
350static int ambapp_for_each_dev(
351  struct ambapp_dev *root,
352  unsigned int options,
353  int vendor,
354  int device,
355  ambapp_func_t func,
356  void *arg)
357{
358  struct ambapp_dev *dev;
359  int ahb_slave = 0;
360  int index, ret;
361
362  /* Start at device 'root' and process downwards.
363   *
364   * Breadth first search, search order
365   * 1. AHB MSTS
366   * 2. AHB SLVS
367   * 3. APB SLVS on primary bus
368   * 4. AHB/AHB secondary... -> step to 1.
369   */
370
371  /* AHB MST / AHB SLV */
372  if (options & (OPTIONS_AHB_MSTS|OPTIONS_AHB_SLVS|OPTIONS_DEPTH_FIRST)) {
373    index = 0;
374    dev = root;
375    while (dev) {
376      if ((dev->dev_type == DEV_AHB_SLV) && !ahb_slave) {
377        /* First AHB Slave */
378        ahb_slave = 1;
379        index = 0;
380      }
381
382      /* Conditions must be fullfilled for function to be
383       * called
384       */
385      if (ambapp_dev_match_options(dev, options, vendor, device) == 1) {
386        /* Correct device and vendor ID */
387        ret = func(dev, index, arg);
388        if (ret != 0)
389          return ret; /* Signalled stopped */
390      }
391
392      if ((options & OPTIONS_DEPTH_FIRST) && (options & OPTIONS_APB_SLVS)) {
393        /* Check is APB bridge, and process all APB
394         * Slaves in that case
395         */
396        ret = ambapp_for_each_apb(dev, options, vendor, device, func, arg);
397        if (ret != 0)
398          return ret; /* Signalled stopped */
399      }
400
401      if (options & OPTIONS_DEPTH_FIRST) {
402        if (dev->children && (dev->children->dev_type != DEV_APB_SLV)) {
403          /* Found AHB Bridge, recurse */
404          ret = ambapp_for_each_dev(dev->children, options, vendor, device,
405                                    func, arg);
406          if (ret != 0)
407            return ret;
408        }
409      }
410
411      index++;
412      dev = dev->next;
413    }
414  }
415
416  /* Find APB Bridges */
417  if ((options & OPTIONS_APB_SLVS) && !(options & OPTIONS_DEPTH_FIRST)) {
418    dev = root;
419    while (dev) {
420      /* Check is APB bridge, and process all APB Slaves in
421       * that case
422       */
423      ret = ambapp_for_each_apb(dev, options, vendor, device, func, arg);
424      if (ret != 0)
425        return ret; /* Signalled stopped */
426      dev = dev->next;
427    }
428  }
429
430  /* Find AHB Bridges */
431  if (!(options & OPTIONS_DEPTH_FIRST)) {
432    dev = root;
433    while (dev) {
434      if (dev->children && (dev->children->dev_type != DEV_APB_SLV)) {
435        /* Found AHB Bridge, recurse */
436        ret = ambapp_for_each_dev(dev->children, options, vendor, device,
437                                  func, arg);
438        if (ret != 0)
439          return ret;
440      }
441      dev = dev->next;
442    }
443  }
444
445  return 0;
446}
447
448int ambapp_for_each(
449  struct ambapp_bus *abus,
450  unsigned int options,
451  int vendor,
452  int device,
453  ambapp_func_t func,
454  void *arg)
455{
456  return ambapp_for_each_dev(abus->root, options, vendor, device, func, arg);
457}
Note: See TracBrowser for help on using the repository browser.