source: trunk/libs/newlib/src/libgloss/sparc_leon/pnpinit_malloc.c @ 551

Last change on this file since 551 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 16.1 KB
Line 
1/*
2 * Copyright (c) 2011 Aeroflex Gaisler
3 *
4 * BSD license:
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25
26#include <asm-leon/amba.h>
27#undef AMBA_TYPE_AHBIO_ADDR
28#include <asm-leon/lambapp.h>
29#include <string.h>
30
31#define AMBA_CONF_AREA 0xff000
32#define AMBA_AHB_SLAVE_CONF_AREA (1 << 11)
33#define AMBA_APB_SLAVES 16
34
35#define DPRINTF(p)  printf p
36
37/* Allocate */
38struct ambapp_dev_hdr *
39ambapp_alloc_dev_struct (int dev_type)
40{
41  int size = sizeof (struct ambapp_dev_hdr);
42  struct ambapp_dev_hdr *dev;
43
44  if (dev_type == DEV_APB_SLV)
45    {
46      size += sizeof (struct ambapp_apb_info);
47    }
48  else
49    {
50      /* AHB */
51      size += sizeof (struct ambapp_ahb_info);
52    }
53  dev = malloc (size);
54  if (dev == NULL)
55    return NULL;
56  memset (dev, 0, size);
57  dev->devinfo = (void *) (dev + 1);
58  dev->dev_type = dev_type;
59  return dev;
60}
61
62unsigned int
63ambapp_addr_from (struct ambapp_mmap *mmaps, unsigned int address)
64{
65  /* no translation? */
66  if (!mmaps)
67    return address;
68
69  while (mmaps->size)
70    {
71      if ((address >= mmaps->remote_adr)
72          && (address <= (mmaps->remote_adr + (mmaps->size - 1))))
73        {
74          return (address - mmaps->remote_adr) + mmaps->local_adr;
75        }
76      mmaps++;
77    }
78  return 1;
79}
80
81void
82ambapp_ahb_dev_init (unsigned int ioarea,
83                     struct ambapp_mmap *mmaps,
84                     struct ambapp_pnp_ahb *ahb, struct ambapp_dev_hdr *dev)
85{
86  int bar;
87  struct ambapp_ahb_info *ahb_info;
88  unsigned int addr, mask, mbar;
89
90  /* Setup device struct */
91  dev->vendor = ambapp_pnp_vendor (ahb->id);
92  dev->device = ambapp_pnp_device (ahb->id);
93  ahb_info = dev->devinfo;
94  ahb_info->ver = ambapp_pnp_ver (ahb->id);
95  ahb_info->irq = ambapp_pnp_irq (ahb->id);
96  ahb_info->custom[0] = (unsigned int) ahb->custom[0];
97  ahb_info->custom[1] = (unsigned int) ahb->custom[1];
98  ahb_info->custom[2] = (unsigned int) ahb->custom[2];
99
100  DPRINTF (("+AHB device %d:%d\n", dev->device, dev->vendor));
101
102  /* Memory BARs */
103  for (bar = 0; bar < 4; bar++)
104    {
105      mbar = ahb->mbar[bar];
106      if (mbar == 0)
107        {
108          addr = 0;
109          mask = 0;
110        }
111      else
112        {
113          addr = ambapp_pnp_start (mbar);
114          if (ambapp_pnp_mbar_type (mbar) == AMBA_TYPE_AHBIO)
115            {
116              /* AHB I/O area is releative IO_AREA */
117              addr = AMBA_TYPE_AHBIO_ADDR (addr, ioarea);
118              mask =
119                (((unsigned int) (ambapp_pnp_mbar_mask ((~mbar)) << 8) |
120                  0xff)) + 1;
121            }
122          else
123            {
124              /* AHB memory area, absolute address */
125              addr = ambapp_addr_from (mmaps, addr);
126              mask =
127                (~((unsigned int) (ambapp_pnp_mbar_mask (mbar) << 20))) + 1;
128            }
129        }
130      ahb_info->start[bar] = addr;
131      ahb_info->mask[bar] = mask;
132    }
133}
134
135void
136ambapp_apb_dev_init (unsigned int base,
137                     struct ambapp_mmap *mmaps,
138                     struct ambapp_pnp_apb *apb, struct ambapp_dev_hdr *dev)
139{
140  struct ambapp_apb_info *apb_info;
141
142  /* Setup device struct */
143  dev->vendor = ambapp_pnp_vendor (apb->id);
144  dev->device = ambapp_pnp_device (apb->id);
145  apb_info = dev->devinfo;
146  apb_info->ver = ambapp_pnp_ver (apb->id);
147  apb_info->irq = ambapp_pnp_irq (apb->id);
148  apb_info->start = ambapp_pnp_apb_start (apb->iobar, base);
149  apb_info->mask = ambapp_pnp_apb_mask (apb->iobar);
150
151  DPRINTF (("+APB device %d:%d\n", dev->device, dev->vendor));
152
153
154}
155
156#define MAX_NUM_BUSES 16
157void
158ambapp_add_scanned_bus (unsigned int *ioareas, unsigned int ioarea)
159{
160  int i;
161  for (i = 0; i < MAX_NUM_BUSES; i++)
162    {
163      if (ioareas[i] == 0)
164        {
165          ioareas[i] = ioarea;
166          return;
167        }
168    }
169}
170
171int
172ambapp_has_been_scanned (unsigned int *ioareas, unsigned int ioarea)
173{
174  int i;
175  if (!ioareas)
176    return 0;
177
178  for (i = 0; i < MAX_NUM_BUSES; i++)
179    {
180      if (ioareas[i] == 0)
181        {
182          break;
183        }
184      else if (ioareas[i] == ioarea)
185        {
186          return 1;
187        }
188    }
189  return 0;
190}
191
192int
193ambapp_scan (unsigned int ioarea,
194             struct ambapp_dev_hdr *parent,
195             struct ambapp_mmap *mmaps,
196             void *(*memfunc) (void *dest, const void *src, int n),
197             struct ambapp_dev_hdr **root, void *internal)
198{
199  struct ambapp_pnp_ahb *ahb, ahb_buf;
200  struct ambapp_pnp_apb *apb, apb_buf;
201  struct ambapp_dev_hdr *dev, *prev, *prevapb, *apbdev;
202  struct ambapp_ahb_info *ahb_info;
203  int maxloops = 64;
204  unsigned int apbbase, bridge_address;
205  int i, j;
206
207  DPRINTF (("Scan at 0x%08x\n", ioarea));
208
209  /* Default to memcpy() */
210  if (!memfunc)
211    memfunc = (void *(*)(void *dest, const void *src, int n)) memcpy;
212
213  *root = NULL;
214
215  if (parent)
216    {
217      /* scan first bus for 64 devices, rest for 16 devices */
218      maxloops = 16;
219    }
220  else
221    {
222      DPRINTF (("+(malloc:"));
223      internal = malloc (sizeof (unsigned int) * MAX_NUM_BUSES);
224      DPRINTF (("0x%x)\n", internal));
225
226      if (!internal)
227        return -1;
228      memset (internal, 0, sizeof (unsigned int) * MAX_NUM_BUSES);
229
230      ambapp_add_scanned_bus (internal, ioarea);
231    }
232
233  prev = parent;
234
235  /* AHB MASTERS */
236  ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
237  for (i = 0; i < maxloops; i++)
238    {
239      memfunc (&ahb_buf, ahb, sizeof (struct ambapp_pnp_ahb));
240      if (ahb_buf.id != 0)
241        {
242          /* A AHB device present here */
243          dev = ambapp_alloc_dev_struct (DEV_AHB_MST);
244          if (!dev)
245            return -1;
246
247          ambapp_ahb_dev_init (ioarea, mmaps, &ahb_buf, dev);
248
249          if (*root == NULL)
250            *root = dev;
251
252          if (prev != parent)
253            prev->next = dev;
254          dev->prev = prev;
255          prev = dev;
256        }
257      ahb++;
258    }
259
260  /* AHB SLAVES */
261  ahb =
262    (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA |
263                               AMBA_AHB_SLAVE_CONF_AREA);
264  for (i = 0; i < maxloops; i++)
265    {
266      memfunc (&ahb_buf, ahb, sizeof (struct ambapp_pnp_ahb));
267      if (ahb_buf.id != 0)
268        {
269          /* A AHB device present here */
270          dev = ambapp_alloc_dev_struct (DEV_AHB_SLV);
271          if (!dev)
272            return -1;
273
274          ambapp_ahb_dev_init (ioarea, mmaps, &ahb_buf, dev);
275
276          if (prev != parent)
277            prev->next = dev;
278          dev->prev = prev;
279          prev = dev;
280
281          /* Is it a AHB/AHB Bridge ? */
282          if ((dev->device == GAISLER_AHB2AHB)
283              && (dev->vendor == VENDOR_GAISLER))
284            {
285              /* AHB/AHB Bridge Found, recurse down the Bridge */
286              ahb_info = dev->devinfo;
287              if (ahb_info->ver)
288                {
289                  bridge_address =
290                    ambapp_addr_from (mmaps, ahb_info->custom[1]);
291
292                  DPRINTF (("+(AHBAHB:0x%x)\n", bridge_address));
293
294                  /* Makes sure bus only scanned once */
295                  if (ambapp_has_been_scanned (internal, bridge_address) ==
296                      NULL)
297                    {
298                      ambapp_add_scanned_bus (internal, bridge_address);
299                      if (ambapp_scan
300                          (bridge_address, dev, mmaps, memfunc,
301                           &dev->children, internal))
302                        return -1;
303                    }
304                }
305            }
306          else if ((dev->device == GAISLER_APBMST)
307                   && (dev->vendor == VENDOR_GAISLER))
308            {
309              /* AHB/APB Bridge Found, add the APB devices to this AHB Slave's children */
310              prevapb = dev;
311              ahb_info = dev->devinfo;
312              apbbase = ahb_info->start[0];
313              apb = (struct ambapp_pnp_apb *) (apbbase | AMBA_CONF_AREA);
314              for (j = 0; j < AMBA_APB_SLAVES; j++)
315                {
316                  memfunc (&apb_buf, apb, sizeof (struct ambapp_pnp_apb));
317                  if (apb_buf.id)
318                    {
319                      apbdev = ambapp_alloc_dev_struct (DEV_APB_SLV);
320                      if (!dev)
321                        return -1;
322
323                      ambapp_apb_dev_init (apbbase, mmaps, &apb_buf, apbdev);
324
325                      if (prevapb != dev)
326                        prevapb->next = apbdev;
327                      else
328                        dev->children = apbdev;
329                      apbdev->prev = prevapb;
330                      prevapb = apbdev;
331                    }
332                  apb++;
333                }
334            }
335        }
336      ahb++;
337    }
338
339  if (parent == NULL)
340    {
341      free (internal);
342    }
343
344  return 0;
345}
346
347/* Match search options againt device */
348int
349ambapp_dev_match_options (struct ambapp_dev_hdr *dev, unsigned int options,
350                          int vendor, int device)
351{
352  if ((((options & (OPTIONS_ALL_DEVS)) == OPTIONS_ALL_DEVS) ||  /* Match TYPE */
353       ((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 */
354      ((device == -1) || (device == dev->device)) && (((options & OPTIONS_ALL) == OPTIONS_ALL) ||       /* Match Allocated State */
355                                                      ((options &
356                                                        OPTIONS_FREE)
357                                                       && DEV_IS_FREE (dev))
358                                                      ||
359                                                      ((options &
360                                                        OPTIONS_ALLOCATED)
361                                                       &&
362                                                       DEV_IS_ALLOCATED
363                                                       (dev))))
364    {
365      return 1;
366    }
367  return 0;
368}
369
370/* If device is an APB bridge all devices on the APB bridge is processed */
371static int
372ambapp_for_each_apb (struct ambapp_dev_hdr *dev,
373                     unsigned int options,
374                     int vendor,
375                     int device, int maxdepth, ambapp_func_t func, void *arg)
376{
377  int index;
378  struct ambapp_dev_hdr *apbslv;
379
380  if (maxdepth < 0)
381    return 0;
382
383  if (dev->children && (dev->children->dev_type == DEV_APB_SLV))
384    {
385      /* Found a APB Bridge */
386      index = 0;
387      apbslv = dev->children;
388      while (apbslv)
389        {
390          if (ambapp_dev_match_options (apbslv, options, vendor, device) == 1)
391            {
392              if (func (apbslv, index, maxdepth, arg) == 1)
393                return 1;       /* Signalled stopped */
394            }
395          index++;
396          apbslv = apbslv->next;
397        }
398    }
399  return 0;
400}
401
402/* Traverse the prescanned device information */
403int
404ambapp_for_each (struct ambapp_dev_hdr *root,
405                 unsigned int options,
406                 int vendor,
407                 int device, int maxdepth, ambapp_func_t func, void *arg)
408{
409  struct ambapp_dev_hdr *dev;
410  int ahb_slave = 0;
411  int index;
412
413  if (maxdepth < 0)
414    return 0;
415
416  /* Start at device 'root' and process downwards.
417   *
418   * Breadth first search, search order
419   * 1. AHB MSTS
420   * 2. AHB SLVS
421   * 3. APB SLVS on primary bus
422   * 4. AHB/AHB secondary... -> step to 1.
423   */
424
425  /* AHB MST / AHB SLV */
426  if (options & (OPTIONS_AHB_MSTS | OPTIONS_AHB_SLVS | OPTIONS_DEPTH_FIRST))
427    {
428      index = 0;
429      dev = root;
430      while (dev)
431        {
432          if ((dev->dev_type == DEV_AHB_SLV) && !ahb_slave)
433            {
434              /* First AHB Slave */
435              ahb_slave = 1;
436              index = 0;
437            }
438
439          /* Conditions must be fullfilled for function to be called */
440          if (ambapp_dev_match_options (dev, options, vendor, device) == 1)
441            {
442              /* Correct device and vendor ID */
443              if (func (dev, index, maxdepth, arg) == 1)
444                return 1;       /* Signalled stopped */
445            }
446
447          if ((options & OPTIONS_DEPTH_FIRST) && (options & OPTIONS_APB_SLVS))
448            {
449              /* Check is APB bridge, and process all APB Slaves in that case */
450              if (ambapp_for_each_apb
451                  (dev, options, vendor, device, (maxdepth - 1), func,
452                   arg) == 1)
453                return 1;       /* Signalled stopped */
454            }
455
456          if (options & OPTIONS_DEPTH_FIRST)
457            {
458              if (dev->children && (dev->children->dev_type != DEV_APB_SLV))
459                {
460                  /* Found AHB Bridge, recurse */
461                  if (ambapp_for_each
462                      (dev->children, options, vendor, device, (maxdepth - 1),
463                       func, arg) == 1)
464                    return 1;
465                }
466            }
467
468          index++;
469          dev = dev->next;
470        }
471    }
472
473  /* Find APB Bridges */
474  if ((options & OPTIONS_APB_SLVS) && !(options & OPTIONS_DEPTH_FIRST))
475    {
476      dev = root;
477      while (dev)
478        {
479          /* Check is APB bridge, and process all APB Slaves in that case */
480          if (ambapp_for_each_apb
481              (dev, options, vendor, device, (maxdepth - 1), func, arg) == 1)
482            return 1;           /* Signalled stopped */
483          dev = dev->next;
484        }
485    }
486
487  /* Find AHB Bridges */
488  if (!(options & OPTIONS_DEPTH_FIRST))
489    {
490      dev = root;
491      while (dev)
492        {
493          if (dev->children && (dev->children->dev_type != DEV_APB_SLV))
494            {
495              /* Found AHB Bridge, recurse */
496              if (ambapp_for_each
497                  (dev->children, options, vendor, device, (maxdepth - 1),
498                   func, arg) == 1)
499                return 1;
500            }
501          dev = dev->next;
502        }
503    }
504
505  return 0;
506}
507
508int
509ambapp_alloc_dev (struct ambapp_dev_hdr *dev, void *owner)
510{
511  if (dev->owner)
512    return -1;
513  dev->owner = owner;
514  return 0;
515}
516
517void
518ambapp_free_dev (struct ambapp_dev_hdr *dev)
519{
520  dev->owner = NULL;
521}
522
523struct ambapp_dev_find_match_arg
524{
525  int index;
526  int count;
527  int type;
528  void *dev;
529};
530
531/* AMBA PP find routines */
532int
533ambapp_dev_find_match (struct ambapp_dev_hdr *dev, int index, int maxdepth,
534                       void *arg)
535{
536  struct ambapp_dev_find_match_arg *p = arg;
537
538  if (p->index == 0)
539    {
540      /* Found controller, stop */
541      if (p->type == DEV_APB_SLV)
542        {
543          *(struct ambapp_apb_info *) p->dev =
544            *(struct ambapp_apb_info *) dev->devinfo;
545          p->dev = ((struct ambapp_apb_info *) p->dev) + 1;
546        }
547      else
548        {
549          *(struct ambapp_ahb_info *) p->dev =
550            *(struct ambapp_ahb_info *) dev->devinfo;
551          p->dev = ((struct ambapp_ahb_info *) p->dev) + 1;
552        }
553      p->count--;
554      if (p->count < 1)
555        return 1;
556    }
557  else
558    {
559      p->index--;
560    }
561  return 0;
562}
563
564int
565ambapp_find_apbslvs_next (struct ambapp_dev_hdr *root, int vendor, int device,
566                          struct ambapp_apb_info *dev, int index, int maxno)
567{
568  struct ambapp_dev_find_match_arg arg;
569
570  arg.index = index;
571  arg.count = maxno;
572  arg.type = DEV_APB_SLV;       /* APB */
573  arg.dev = dev;
574
575  ambapp_for_each (root, (OPTIONS_ALL | OPTIONS_APB_SLVS), vendor, device, 10,
576                   ambapp_dev_find_match, &arg);
577
578  return maxno - arg.count;
579}
580
581int
582ambapp_find_apbslv (struct ambapp_dev_hdr *root, int vendor, int device,
583                    struct ambapp_apb_info *dev)
584{
585  return ambapp_find_apbslvs_next (root, vendor, device, dev, 0, 1);
586}
587
588int
589ambapp_find_apbslv_next (struct ambapp_dev_hdr *root, int vendor, int device,
590                         struct ambapp_apb_info *dev, int index)
591{
592  return ambapp_find_apbslvs_next (root, vendor, device, dev, index, 1);
593}
594
595int
596ambapp_find_apbslvs (struct ambapp_dev_hdr *root, int vendor, int device,
597                     struct ambapp_apb_info *dev, int maxno)
598{
599  return ambapp_find_apbslvs_next (root, vendor, device, dev, 0, maxno);
600}
601
602int
603ambapp_find_ahbslvs_next (struct ambapp_dev_hdr *root, int vendor, int device,
604                          struct ambapp_ahb_info *dev, int index, int maxno)
605{
606  struct ambapp_dev_find_match_arg arg;
607
608  arg.index = index;
609  arg.count = maxno;
610  arg.type = DEV_AHB_SLV;       /* AHB SLV */
611  arg.dev = dev;
612
613  ambapp_for_each (root, (OPTIONS_ALL | OPTIONS_AHB_SLVS), vendor, device, 10,
614                   ambapp_dev_find_match, &arg);
615
616  return maxno - arg.count;
617}
618
619int
620ambapp_find_ahbslv_next (struct ambapp_dev_hdr *root, int vendor, int device,
621                         struct ambapp_ahb_info *dev, int index)
622{
623  return ambapp_find_ahbslvs_next (root, vendor, device, dev, index, 1);
624}
625
626int
627ambapp_find_ahbslv (struct ambapp_dev_hdr *root, int vendor, int device,
628                    struct ambapp_ahb_info *dev)
629{
630  return ambapp_find_ahbslvs_next (root, vendor, device, dev, 0, 1);
631}
632
633int
634ambapp_find_ahbslvs (struct ambapp_dev_hdr *root, int vendor, int device,
635                     struct ambapp_ahb_info *dev, int maxno)
636{
637  return ambapp_find_ahbslvs_next (root, vendor, device, dev, 0, maxno);
638}
639
640struct ambapp_dev_hdr *
641ambapp_find_parent (struct ambapp_dev_hdr *dev)
642{
643  while (dev->prev)
644    {
645      if (dev == dev->prev->children)
646        {
647          return dev->prev;
648        }
649      dev = dev->prev;
650    }
651  return NULL;
652}
653
654
655struct ambapp_dev_hdr *ambapp_root = NULL;
656extern unsigned int console;
657extern unsigned int rtc;
658
659void
660pnpinit (void)
661{
662  struct ambapp_apb_info dev;
663  int n;
664  ambapp_scan (LEON3_IO_AREA, NULL, NULL, NULL, &ambapp_root, NULL);
665  if ((n =
666       ambapp_find_apbslv (ambapp_root, VENDOR_GAISLER, GAISLER_APBUART,
667                           &dev)) == 1)
668    {
669      console = dev.start;
670      DPRINTF (("Found abuart at 0x%x\n", console));
671    }
672  if ((n =
673       ambapp_find_apbslv (ambapp_root, VENDOR_GAISLER, GAISLER_GPTIMER,
674                           &dev)) == 1)
675    {
676      rtc = dev.start + 0x10;
677      DPRINTF (("Found rtc at 0x%x\n", rtc));
678    }
679}
Note: See TracBrowser for help on using the repository browser.