source: trunk/libs/newlib/src/libgloss/sparc_leon/pnpinit.c @ 684

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

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

File size: 10.2 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#ifdef PDEBUG
36#define DPRINTF(p)  printf p
37#else
38#define DPRINTF(p)
39#endif
40
41unsigned 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    {
50      if ((address >= mmaps->remote_adr)
51          && (address <= (mmaps->remote_adr + (mmaps->size - 1))))
52        {
53          return (address - mmaps->remote_adr) + mmaps->local_adr;
54        }
55      mmaps++;
56    }
57  return 1;
58}
59
60
61static void
62ambapp_ahb_dev_init (unsigned int ioarea,
63                     struct ambapp_mmap *mmaps,
64                     struct ambapp_pnp_ahb *ahb, struct ambapp_dev_hdr *dev)
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->devinfo;
74  ahb_info->ver = ambapp_pnp_ver (ahb->id);
75  ahb_info->irq = ambapp_pnp_irq (ahb->id);
76  ahb_info->custom[0] = (unsigned int) ahb->custom[0];
77  ahb_info->custom[1] = (unsigned int) ahb->custom[1];
78  ahb_info->custom[2] = (unsigned int) ahb->custom[2];
79
80  DPRINTF (("+AHB device %d:%d\n", dev->device, dev->vendor));
81
82  /* Memory BARs */
83  for (bar = 0; bar < 4; bar++)
84    {
85      mbar = ahb->mbar[bar];
86      if (mbar == 0)
87        {
88          addr = 0;
89          mask = 0;
90        }
91      else
92        {
93          addr = ambapp_pnp_start (mbar);
94          if (ambapp_pnp_mbar_type (mbar) == AMBA_TYPE_AHBIO)
95            {
96              /* AHB I/O area is releative IO_AREA */
97              addr = AMBA_TYPE_AHBIO_ADDR (addr, ioarea);
98              mask =
99                (((unsigned int) (ambapp_pnp_mbar_mask ((~mbar)) << 8) |
100                  0xff)) + 1;
101            }
102          else
103            {
104              /* AHB memory area, absolute address */
105              addr = ambapp_addr_from (mmaps, addr);
106              mask =
107                (~((unsigned int) (ambapp_pnp_mbar_mask (mbar) << 20))) + 1;
108            }
109        }
110      ahb_info->start[bar] = addr;
111      ahb_info->mask[bar] = mask;
112    }
113}
114
115static void
116ambapp_apb_dev_init (unsigned int base,
117                     struct ambapp_mmap *mmaps,
118                     struct ambapp_pnp_apb *apb, struct ambapp_dev_hdr *dev)
119{
120  struct ambapp_apb_info *apb_info;
121
122  /* Setup device struct */
123  dev->vendor = ambapp_pnp_vendor (apb->id);
124  dev->device = ambapp_pnp_device (apb->id);
125  apb_info = dev->devinfo;
126  apb_info->ver = ambapp_pnp_ver (apb->id);
127  apb_info->irq = ambapp_pnp_irq (apb->id);
128  apb_info->start = ambapp_pnp_apb_start (apb->iobar, base);
129  apb_info->mask = ambapp_pnp_apb_mask (apb->iobar);
130
131  DPRINTF (("+APB device %d:%d\n", dev->device, dev->vendor));
132
133
134}
135
136#define MAX_NUM_BUSES 16
137static void
138ambapp_add_scanned_bus (unsigned int *ioareas, unsigned int ioarea)
139{
140  int i;
141  for (i = 0; i < MAX_NUM_BUSES; i++)
142    {
143      if (ioareas[i] == 0)
144        {
145          ioareas[i] = ioarea;
146          return;
147        }
148    }
149}
150
151static int
152ambapp_has_been_scanned (unsigned int *ioareas, unsigned int ioarea)
153{
154  int i;
155  if (!ioareas)
156    return 0;
157
158  for (i = 0; i < MAX_NUM_BUSES; i++)
159    {
160      if (ioareas[i] == 0)
161        {
162          break;
163        }
164      else if (ioareas[i] == ioarea)
165        {
166          return 1;
167        }
168    }
169  return 0;
170}
171
172static int
173ambapp_find (unsigned int ioarea,
174             struct ambapp_dev_hdr *parent,
175             struct ambapp_mmap *mmaps,
176             void *internal,
177             int (*find_match) (struct ambapp_dev_hdr * dev, void *arg),
178             void *arg, int vendor, int device)
179{
180  struct ambapp_pnp_ahb *ahb, ahb_buf;
181  struct ambapp_pnp_apb *apb, apb_buf;
182  struct ambapp_dev_hdr *dev, *prev, *prevapb, *apbdev;
183  struct ambapp_ahb_info *ahb_info;
184  int maxloops = 64;
185  unsigned int apbbase, bridge_address;
186  int i, j;
187
188  DPRINTF (("Scan at 0x%08x\n", ioarea));
189
190  if (parent)
191    {
192      /* scan first bus for 64 devices, rest for 16 devices */
193      maxloops = 16;
194    }
195  else
196    {
197      if (internal)
198        {
199          ambapp_add_scanned_bus (internal, ioarea);
200        }
201    }
202
203  prev = parent;
204
205  /* AHB MASTERS */
206  ahb = (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA);
207  for (i = 0; i < maxloops; i++)
208    {
209      memcpy (&ahb_buf, ahb, sizeof (struct ambapp_pnp_ahb));
210      if (ahb_buf.id != 0)
211        {
212          struct ambapp_dev_hdr _dev;
213          struct ambapp_ahb_info _ahb;
214          memset (&_dev, 0, sizeof (_dev));
215          memset (&_ahb, 0, sizeof (_ahb));
216          _dev.devinfo = &_ahb;
217          _dev.dev_type = DEV_AHB_MST;
218          dev = &_dev;
219
220          ambapp_ahb_dev_init (ioarea, mmaps, &ahb_buf, dev);
221
222          DPRINTF ((" = test %d:%d == %d:%d\n", vendor, device, dev->vendor,
223                    dev->device));
224
225          if (vendor == dev->vendor &&
226              device == dev->device && find_match (dev, arg))
227            {
228              return 1;
229            }
230        }
231      ahb++;
232    }
233
234
235  /* AHB SLAVES */
236  ahb =
237    (struct ambapp_pnp_ahb *) (ioarea | AMBA_CONF_AREA |
238                               AMBA_AHB_SLAVE_CONF_AREA);
239  for (i = 0; i < maxloops; i++)
240    {
241      memcpy (&ahb_buf, ahb, sizeof (struct ambapp_pnp_ahb));
242      if (ahb_buf.id != 0)
243        {
244          struct ambapp_dev_hdr _dev;
245          struct ambapp_ahb_info _ahb;
246          memset (&_dev, 0, sizeof (_dev));
247          memset (&_ahb, 0, sizeof (_ahb));
248          _dev.devinfo = &_ahb;
249          _dev.dev_type = DEV_AHB_MST;
250          dev = &_dev;
251
252          ambapp_ahb_dev_init (ioarea, mmaps, &ahb_buf, dev);
253
254          DPRINTF ((" = test %d:%d == %d:%d\n", vendor, device, dev->vendor,
255                    dev->device));
256
257          if (vendor == dev->vendor &&
258              device == dev->device && find_match (dev, arg))
259            {
260              return 1;
261            }
262
263          /* Is it a AHB/AHB Bridge ? */
264          if ((dev->device == GAISLER_AHB2AHB)
265              && (dev->vendor == VENDOR_GAISLER))
266            {
267              /* AHB/AHB Bridge Found, recurse down the Bridge */
268              ahb_info = dev->devinfo;
269              if (ahb_info->ver)
270                {
271                  bridge_address =
272                    ambapp_addr_from (mmaps, ahb_info->custom[1]);
273
274                  DPRINTF (("+(AHBAHB:0x%x)\n", bridge_address));
275
276                  /* Makes sure bus only scanned once */
277                  if (internal == 0
278                      || ambapp_has_been_scanned (internal,
279                                                  bridge_address) == NULL)
280                    {
281                      if (internal)
282                        ambapp_add_scanned_bus (internal, bridge_address);
283
284                      if (ambapp_find (bridge_address, dev, mmaps, internal,
285                                       find_match, arg, vendor, device))
286                        return 1;
287                    }
288                }
289            }
290          else if ((dev->device == GAISLER_APBMST)
291                   && (dev->vendor == VENDOR_GAISLER))
292            {
293              /* AHB/APB Bridge Found, add the APB devices to this AHB Slave's children */
294              prevapb = dev;
295              ahb_info = dev->devinfo;
296              apbbase = ahb_info->start[0];
297              apb = (struct ambapp_pnp_apb *) (apbbase | AMBA_CONF_AREA);
298              for (j = 0; j < AMBA_APB_SLAVES; j++)
299                {
300                  memcpy (&apb_buf, apb, sizeof (struct ambapp_pnp_apb));
301                  if (apb_buf.id)
302                    {
303                      struct ambapp_dev_hdr _apbdev;
304                      struct ambapp_apb_info _apb;
305                      memset (&_apbdev, 0, sizeof (_apbdev));
306                      memset (&_apb, 0, sizeof (_apb));
307                      _apbdev.devinfo = &_apb;
308                      _apbdev.dev_type = DEV_APB_SLV;
309                      apbdev = &_apbdev;
310
311                      ambapp_apb_dev_init (apbbase, mmaps, &apb_buf, apbdev);
312
313                      DPRINTF ((" = test %d:%d == %d:%d\n", vendor, device,
314                                apbdev->vendor, apbdev->device));
315
316                      if (vendor == apbdev->vendor &&
317                          device == apbdev->device &&
318                          find_match (apbdev, arg))
319                        {
320
321                          return 1;
322                        }
323                    }
324                  apb++;
325                }
326            }
327        }
328      ahb++;
329    }
330
331  if (parent == NULL)
332    {
333      /*free(internal); */
334    }
335
336  return 0;
337}
338
339struct ambapp_dev_find_match_arg
340{
341  int index;
342  int count;
343  int type;
344  void *dev;
345};
346
347/* AMBA PP find routines */
348static int
349ambapp_dev_find_match (struct ambapp_dev_hdr *dev, void *arg)
350{
351  struct ambapp_dev_find_match_arg *p = arg;
352
353  if (p->index == 0)
354    {
355      /* Found controller, stop */
356      if (p->type == DEV_APB_SLV)
357        {
358          *(struct ambapp_apb_info *) p->dev =
359            *(struct ambapp_apb_info *) dev->devinfo;
360          p->dev = ((struct ambapp_apb_info *) p->dev) + 1;
361        }
362      else
363        {
364          *(struct ambapp_ahb_info *) p->dev =
365            *(struct ambapp_ahb_info *) dev->devinfo;
366          p->dev = ((struct ambapp_ahb_info *) p->dev) + 1;
367        }
368      p->count--;
369      if (p->count < 1)
370        return 1;
371    }
372  else
373    {
374      p->index--;
375    }
376  return 0;
377}
378
379static int
380find_apbslvs_next (int vendor, int device, struct ambapp_apb_info *dev,
381                   int index, int maxno)
382{
383  struct ambapp_dev_find_match_arg arg;
384  unsigned int busses[MAX_NUM_BUSES];
385  memset (busses, 0, sizeof (busses));
386
387  arg.index = index;
388  arg.count = maxno;
389  arg.type = DEV_APB_SLV;       /* APB */
390  arg.dev = dev;
391
392  ambapp_find (LEON3_IO_AREA, NULL, NULL, &busses,
393               ambapp_dev_find_match, &arg, vendor, device);
394
395  return maxno - arg.count;
396}
397
398int
399find_apbslv (int vendor, int device, struct ambapp_apb_info *dev)
400{
401  return find_apbslvs_next (vendor, device, dev, 0, 1);
402}
403
404struct ambapp_dev_hdr *ambapp_root = NULL;
405unsigned int busses[MAX_NUM_BUSES];
406extern unsigned int console;
407extern unsigned int rtc;
408extern unsigned int irqmp;
409
410void
411pnpinit (void)
412{
413  struct ambapp_apb_info dev;
414  int n;
415  if ((n = find_apbslv (VENDOR_GAISLER, GAISLER_APBUART, &dev)) == 1)
416    {
417      console = dev.start;
418      DPRINTF (("Found abuart at 0x%x\n", console));
419    }
420  if ((n = find_apbslv (VENDOR_GAISLER, GAISLER_GPTIMER, &dev)) == 1)
421    {
422      rtc = dev.start + 0x10;
423      DPRINTF (("Found rtc at 0x%x\n", rtc));
424    }
425  if ((n = find_apbslv (VENDOR_GAISLER, GAISLER_IRQMP, &dev)) == 1)
426    {
427      irqmp = dev.start;
428      DPRINTF (("Found irqmp at 0x%x\n", rtc));
429    }
430}
Note: See TracBrowser for help on using the repository browser.