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
41 unsigned int
ambapp_addr_from(struct ambapp_mmap * mmaps,unsigned int address)42 ambapp_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
61 static void
ambapp_ahb_dev_init(unsigned int ioarea,struct ambapp_mmap * mmaps,struct ambapp_pnp_ahb * ahb,struct ambapp_dev_hdr * dev)62 ambapp_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
115 static void
ambapp_apb_dev_init(unsigned int base,struct ambapp_mmap * mmaps,struct ambapp_pnp_apb * apb,struct ambapp_dev_hdr * dev)116 ambapp_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
137 static void
ambapp_add_scanned_bus(unsigned int * ioareas,unsigned int ioarea)138 ambapp_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
151 static int
ambapp_has_been_scanned(unsigned int * ioareas,unsigned int ioarea)152 ambapp_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
172 static int
ambapp_find(unsigned int ioarea,struct ambapp_dev_hdr * parent,struct ambapp_mmap * mmaps,void * internal,int (* find_match)(struct ambapp_dev_hdr * dev,void * arg),void * arg,int vendor,int device)173 ambapp_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
339 struct 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 */
348 static int
ambapp_dev_find_match(struct ambapp_dev_hdr * dev,void * arg)349 ambapp_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
379 static int
find_apbslvs_next(int vendor,int device,struct ambapp_apb_info * dev,int index,int maxno)380 find_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
398 int
find_apbslv(int vendor,int device,struct ambapp_apb_info * dev)399 find_apbslv (int vendor, int device, struct ambapp_apb_info *dev)
400 {
401 return find_apbslvs_next (vendor, device, dev, 0, 1);
402 }
403
404 struct ambapp_dev_hdr *ambapp_root = NULL;
405 unsigned int busses[MAX_NUM_BUSES];
406 extern unsigned int console;
407 extern unsigned int rtc;
408 extern unsigned int irqmp;
409
410 void
pnpinit(void)411 pnpinit (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 }
431