Blackfin: Remove
[oweals/u-boot.git] / arch / sparc / cpu / leon3 / ambapp_low.S
1 /* GRLIB AMBA Plug&Play information scanning implemented without
2  * using memory (stack) and one register window. The code scan
3  * the PnP info and inserts the AHB bridges/buses into register
4  * i0-i5.
5  * The code support
6  *  - up to 6 AHB buses
7  *  - multiple APB buses
8  *  - support for AHB2AHB & L2CACHE bridges
9  *
10  * (C) Copyright 2010, 2015
11  * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
12  *
13  * SPDX-License-Identifier:     GPL-2.0+
14  */
15
16 #include <ambapp.h>
17
18         .seg    "text"
19         .globl  _nomem_amba_init
20         .globl  _nomem_ambapp_find_buses
21         .globl  _nomem_find_apb
22         .globl  _nomem_find_ahb
23
24 /* Overview
25  * ========
26  *
27  * _nomem_amba_init         - Init AMBA bus and calls _nomem_ambapp_find_buses
28  * _nomem_ambapp_find_buses - Scan AMBA PnP info for AHB buses/bridges and
29  *                            place them in i0-i5, see below
30  * _nomem_find_apb          - Find one APB device identified by VENDOR:DEVICE
31  *                            ID and an index.
32  * _nomem_find_ahb          - Find one AHB Master or Slave device identified
33  *                            by VENDOR:DEVICE ID and an index.
34  * init_ahb_bridges         - Local function. Clears i0-i5
35  * insert_ahb_bridge        - Local function. Insert a new AHB bus into first
36  *                            free register in i0-i5. It also checks that the
37  *                            bus has not already been added.
38  * get_ahb_bridge           - Local function. Get AHB bus from registers,
39  *                            return register iN, where N is defined by o0.
40  *
41  * The _nomem_find_apb and _nomem_find_ahb function requires that i0-i5
42  * are populated with the AHB buses of the system. The registers are
43  * initialized by _nomem_ambapp_find_buses.
44  *
45  * AHB Bus result and requirements of i0-i5
46  * ========================================
47  *
48  * i0: AHB BUS0 IOAREA, no parent bus
49  * i1: AHB BUS1 IOAREA, parent bus is always i0 (AHB BUS0) and bridge address
50  * i2: AHB BUS2 IOAREA, 3-bit parent bus number and bridge address
51  * i3: AHB BUS3 IOAREA, 3-bit parent bus number and bridge address
52  * i4: AHB BUS4 IOAREA, 3-bit parent bus number and bridge address
53  * i5: AHB BUS5 IOAREA, 3-bit parent bus number and bridge address
54  *
55  * AHB BUS
56  * -------
57  * Bits 31-20 (0xfff00000) contain the found bus I/O Area (AHB PnP area).
58  *
59  * 3-bit Parent bus
60  * ----------------
61  * Bits 2-0 (0x00000007) contain parent bus number. Zero if no parent
62  * bus, 1 = parent is AHB BUS 0 (i0), 2 = parent is AHB BUS 1 (i1)..
63  *
64  * Bridge Address
65  * --------------
66  * Bits 10-5 (0x000007e0) contain the index of the Bridge's PnP
67  * information on the parent. Since all bridges are found in the
68  * PnP information they all have a PnP entry. Together with the
69  * parent bus number the PnP entry can be found:
70  *  PnPEntry = (BRIDGE_ADDRESS + (iN & 0xfff00000)) | 0x000ff800
71  *  where N is the parent bus minus one.
72  *
73  */
74
75 /* Function initializes the AHB Bridge I/O AREA storage. (Clears i0-i5)
76  *
77  * Arguments
78  *  none
79  *
80  * Results
81  *  none
82  *
83  * Clobbered
84  *  none
85  */
86
87 init_ahb_bridges:
88         mov     %g0, %i0
89         mov     %g0, %i1
90         mov     %g0, %i2
91         mov     %g0, %i3
92         mov     %g0, %i4
93         retl
94          mov    %g0, %i5
95
96 /* Function returns AHB Bridge I/O AREA for specified bus.
97  *
98  * Arguments
99  *  - o0 = bus number
100  *
101  * Results
102  *  - o0 = I/O AREA
103  *
104  * Clobbered
105  *  none
106  */
107 get_ahb_bridge:
108         cmp     %o0, 1
109         be,a    L1
110          mov    %i0, %o0
111
112         cmp     %o0, 2
113         be,a    L1
114          mov    %i1, %o0
115
116         cmp     %o0, 3
117         be,a    L1
118          mov    %i2, %o0
119
120         cmp     %o0, 4
121         be,a    L1
122          mov    %i3, %o0
123
124         cmp     %o0, 5
125         be,a    L1
126          mov    %i4, %o0
127
128         cmp     %o0, 6
129         be,a    L1
130          mov    %i5, %o0
131
132         /* o0 > 6: only 6 buses supported */
133         mov     %g0, %o0
134 L1:
135         retl
136          nop
137
138 /* Function adds a AHB Bridge I/O AREA to the i0-i5 registers if
139  * not already added. It stores the bus PnP start information.
140  *
141  * Arguments
142  *  - o0 = AHB Bridge I/O area
143  *
144  * Results
145  *  none
146  *
147  * Clobbered
148  *  o2, o3
149  */
150 insert_ahb_bridge:
151         /* Check that bridge hasn't already been added */
152         andn    %o0, 0x7ff, %o2
153         andn    %i0, 0x7ff, %o3
154         cmp     %o3, %o2
155         be      L2
156          andn   %i1, 0x7ff, %o3
157         cmp     %o3, %o2
158         be      L2
159          andn   %i2, 0x7ff, %o3
160         cmp     %o3, %o2
161         be      L2
162          andn   %i3, 0x7ff, %o3
163         cmp     %o3, %o2
164         be      L2
165          andn   %i4, 0x7ff, %o3
166         cmp     %o3, %o2
167         be      L2
168          andn   %i5, 0x7ff, %o3
169         cmp     %o3, %o2
170         be      L2
171
172         /* Insert into first free posistion */
173          cmp    %i0, %g0
174         be,a    L2
175          mov    %o0, %i0
176
177         cmp     %i1, %g0
178         be,a    L2
179          mov    %o0, %i1
180
181         cmp     %i2, %g0
182         be,a    L2
183          mov    %o0, %i2
184
185         cmp     %i3, %g0
186         be,a    L2
187          mov    %o0, %i3
188
189         cmp     %i4, %g0
190         be,a    L2
191          mov    %o0, %i4
192
193         cmp     %i5, %g0
194         be,a    L2
195          mov    %o0, %i5
196 L2:
197         retl
198          nop
199
200 /* FUNCTION int _nomem_find_ahb_bus(
201  *      unsigned int bridge,
202  *      int vendor_device,
203  *      int index,
204  *      void **pconf,
205  *      int not_used,
206  *      int option
207  *      )
208  *
209  * Scans the AHB Master or Slave area for a matching VENDOR:DEVICE, the
210  * index is decremented when a matching device is found but index is
211  * greater than zero. When index is zero and a matching DEVICE:VENDOR
212  * is found the AHB configuration address and AHB I/O area is returned.
213  *
214  * i0-i7,l0,l1,l2,l3,l4,g2,o6 is not available for use.
215  * o1,o5 Must be left untouched
216  *
217  * Results
218  *  - o0 Number of found devices (1 or 0)
219  *  - o2 is decremented for each matching VENDOR:DEVICE found, zero if found
220  *  - o3 Address of the AHB PnP configuration entry (Only valid if o0=1)
221  *
222  * Clobbered
223  *  - o3 (Clobbered when no device was found)
224  *  - o4 (Number of Devices left to search)
225  *  - o0 (Bus ID, PnP ID, Device)
226  */
227 _nomem_find_ahb_bus:
228
229         /* Get the number of Slaves/Masters.
230          * Only AHB Bus 0 has 64 AHB Masters/Slaves the
231          * other AHB buses has 16 slaves and 16 masters.
232          */
233         add     %g0, 16, %o4            /* Defaulting to 16 */
234         andcc   %o0, 0x7, %g0           /* 3-bit bus id */
235         be,a    .L_maxloops_detected
236          add    %g0, 64, %o4            /* AHB Bus 0 has 64 AHB Masters/Slaves */
237 .L_maxloops_detected:
238
239         /* Get start address of AHB Slave or AHB Master area depending on what
240          * we are searching for.
241          */
242         andn    %o0, 0x7ff, %o0         /* Remove Bus ID and 5-bit AHB/AHB
243                                          * Bridge PnP Address to get I/O Area */
244         set     AMBA_CONF_AREA, %o3
245         or      %o3, %o0, %o3           /* Master area address */
246
247         cmp     %o5, DEV_AHB_SLV
248         be,a    .L_conf_area_calculated
249          or     %o3, AMBA_AHB_SLAVE_CONF_AREA, %o3      /* Add 0x800 to get to slave area */
250 .L_conf_area_calculated:
251
252         /* Iterate over all AHB device and try to find matching DEVICE:VENDOR
253          * o1 - VENDOR|DEVICE
254          * o2 - Index
255          * o3 - Current AHB Device Configuration address
256          * o5 - Type (leave untouched)
257          *
258          * o4 - Number of AHB device left to process
259          * o0 - tmp
260          */
261 .L_process_one_conf:
262         ld      [%o3], %o0
263         andn    %o0, 0xfff, %o0
264         cmp     %o0, 0                  /* No device if zero */
265         beq     .L_next_conf
266          cmp    %o1, 0                  /* If VENDOR:DEVICE==0, consider all matching */
267         beq     .L_process_ahb_dev_found
268          cmp    %o0, %o1                /* Does VENDOR and DEVICE Match? */
269         bne     .L_next_conf
270          nop
271 .L_process_ahb_dev_found:
272         /* Found a Matching VENDOR:DEVICE, index must also match */
273         cmp     %o2, %g0
274         bne     .L_next_conf
275          dec    %o2
276         /* Index matches also, return happy with o3 set to AHB Conf Address */
277         mov     %g0, %o2
278         retl
279          add    %g0, 1, %o0
280
281 .L_next_conf:
282         subcc   %o4, 1, %o4             /* One device has been processed,
283                                          * Are there more devices to process? */
284         bne     .L_process_one_conf
285          add    %o3, AMBA_AHB_CONF_LENGH, %o3   /* Next Configuration entry */
286         /* No Matching device found */
287         retl
288          mov    %g0, %o0
289
290 /* FUNCTION int _nomem_find_ahb(
291  *      int unused,
292  *      int vendor_device,
293  *      int index,
294  *      void **pconf,
295  *      int *ahb_bus_index,
296  *      int option,
297  *      )
298  *
299  * Find a AHB Master or AHB Slave device, it puts the address of the AHB PnP
300  * configuration in o3 (pconf), the I/O Area base address in o4 (pioarea).
301  *
302  * Calls _nomem_find_ahb_bus for every AHB bus.
303  *
304  * i0-i7, l0, l1, o6, g1, g4-g7 is not available for use.
305  *
306  * Arguments
307  *  - o0 Unused
308  *
309  * Results
310  *  - o0 Number of found devices (1 or 0)
311  *  - o2 Decremented Index (Zero if found)
312  *  - o3 Address of the AHB PnP configuration entry
313  *  - o4 AHB Bus index the device was found on (if o0=1)
314  *  - o5 Left untouched
315  *
316  * Clobbered
317  *  - o0 (AHB Bridge and used by _nomem_find_ahb_bus)
318  *  - o2 (index is decremented)
319  *  - l2 (Current AHB Bus index)
320  *  - g2 (return address)
321  */
322 _nomem_find_ahb:
323         mov     %o7, %g2                /* Save return address */
324         /* Scan all AHB Buses found for the AHB Master/Slave matching VENDOR:DEVICE */
325         clr     %l2
326 .L_search_next_ahb_bus:
327         add     %l2, 1, %l2
328         call    get_ahb_bridge                  /* Get bus %l0 I/O Area */
329          mov    %l2, %o0
330         cmp     %o0, %g0
331         be      .L_no_device_found              /* If no more AHB bus is left to be scanned, proceed */
332          nop
333         call    _nomem_find_ahb_bus             /* Scan AHB bus %o0 for VENDOR:DEVICE. Index in o3 is decremented  */
334          nop
335         cmp     %o0, %g0                        /* If VENDOR:DEVICE was not found scan next AHB Bus */
336         be      .L_search_next_ahb_bus          /* Do next bus is o0=0 (not found) */
337          nop
338         /* The device was found, o0 is 1 */
339         mov     %g2, %o7                /* Restore return address */
340         retl
341          mov    %l2, %o4                /* The AHB bus index the device was found on */
342
343         /* No device found matching */
344 .L_no_device_found:
345         mov     %g2, %o7                /* Restore return address */
346         retl
347          mov    %g0, %o0
348
349
350 /* FUNCTION int _nomem_find_apb_bus(
351  *      int apbmst,
352  *      int vendor_device,
353  *      int index,
354  *      void **pconf
355  *      )
356  *
357  * Find a APB Slave device, it puts the address of the APB PnP configuration
358  * in o3 (pconf).
359  *
360  * Calls _nomem_find_ahb_bus for every AHB bus searching for AHB/APB Bridges.
361  * The AHB/APB bridges are AHB Slaves with ID GAISLER_APBMST.
362  *
363  * Results
364  *  - o0 Number of found devices (1 or 0)
365  *  - o2 Decremented Index
366  *  - o3 Address of the found APB device PnP configuration entry
367  *
368  * Clobbered
369  *  - o5 PnP VENDOR:DEVICE ID
370  */
371
372 _nomem_find_apb_bus:
373         set     AMBA_CONF_AREA, %o3
374         or      %o0, %o3, %o3           /* Calc start of APB device PnP info */
375         add     %g0, 16, %o0            /* o0, number of APB Slaves left to scan */
376 .L_process_one_apb_conf:
377         ld      [%o3], %o5
378         andn    %o5, 0xfff, %o5
379         cmp     %o5, 0                  /* No device if zero */
380         beq     .L_process_apb_dev_not_found
381          cmp    %o1, 0                  /* If VENDOR:DEVICE == -1, consider all matching */
382         beq     .L_process_apb_dev_found
383          cmp    %o1, %o5                /* Found VENDOR:DEVICE */
384         bne     .L_process_apb_dev_not_found
385          nop
386
387 .L_process_apb_dev_found:
388         /* Found matching device, compare index */
389         cmp     %o2, %g0
390         bne     .L_process_apb_dev_not_found
391          dec    %o2
392         /* Matching index and VENDOR:DEVICE */
393         retl
394          add    %g0, 1, %o0
395
396 .L_process_apb_dev_not_found:
397         subcc   %o0, 1, %o0
398         bne     .L_process_one_apb_conf
399          add    %o3, 8, %o3
400         retl
401          mov    %g0, %o0
402
403 /* FUNCTION int _nomem_find_apb(
404  *      int unused,
405  *      int vendor_device,
406  *      int index,
407  *      void **pconf,
408  *      int *ahb_bus_index
409  *      )
410  *
411  * Find a APB Slave device, it puts the address of the APB PnP configuration
412  * in o3 (pconf), the APB Master I/O Area base address in o4 (papbarea).
413  *
414  * Calls _nomem_find_ahb_bus for every AHB bus searching for AHB/APB Bridges.
415  * The AHB/APB bridges are AHB Slaves with ID GAISLER_APBMST.
416  *
417  * i0-i7, l0, l1, o6 is not available for use.
418  *
419  * Arguments
420  *  - o0 Unused
421  *
422  * Results
423  *  - o0 Number of found devices (1 or 0)
424  *  - o2 Decremented Index if not found
425  *  - o3 Address of the APB PnP configuration entry
426  *  - o4 AHB Bus index of APB Bridge/APB Device
427  *
428  * Clobbered
429  *  - o0 (AHB Bridge)
430  *  - o2 (index is decremented)
431  *  - l2 (APB DEV Index [7..4] : APBMST AHB Index [3..0])
432  *  - l3 (Current AHB Bus index)
433  *  - l4 (temporary storage for APB VENDOR:DEVICE)
434  *  - o5 (AHB Slave ID)
435  *  - o0 (clobbered by _nomem_find_ahb_bus)
436  *  - g2 (Return address)
437  */
438 _nomem_find_apb:
439         /* Scan all AHB Buses found for AHB/APB Bridges */
440         mov     %o7, %g2                /* Save return address */
441         mov     %o1, %l4                /* Save APB VENDOR:DEVICE */
442         sll     %o2, 4, %l2             /* APB MST index = 0 */
443         add     %g0, 1, %l3             /* AHB Bus index = 0 */
444 .L2_search_next_ahb_bus:
445         call    get_ahb_bridge          /* Get bus %l3 I/O Area */
446          mov    %l3, %o0
447         cmp     %o0, %g0
448         be      .L2_no_device_found     /* If no more AHB bus is left to be scanned, proceed */
449          add    %g0, DEV_AHB_SLV, %o5   /* Search for AHB Slave */
450         sethi   %hi(AMBA_PNP_ID(VENDOR_GAISLER, GAISLER_APBMST)), %o1
451         call    _nomem_find_ahb_bus     /* Scan AHB bus %o0 for VENDOR:DEVICE. Index in o3 is decremented */
452          and    %l2, 0xf, %o2           /* Set APBMST index */
453         cmp     %o0, %g0                /* If no AHB/APB Bridge was not found, scan next AHB Bus */
454         be      .L_no_apb_bridge_found  /* Do next bus */
455          nop
456
457         /* The AHB/APB Bridge was found.
458          * Search for the requested APB Device on the APB bus using
459          * find_apb_bus, it will decrement the index.
460          */
461         ld      [%o3 + AMBA_AHB_MBAR0_OFS], %o3
462         sll     %o3, 16, %o0
463         and     %o0, %o3, %o0           /* Address AND Address Mask */
464         sethi   %hi(0xfff00000), %o3
465         and     %o0, %o3, %o0           /* AHB/APB Bridge address */
466
467         srl     %l2, 4, %o2             /* APB DEV Index */
468         call    _nomem_find_apb_bus
469          mov    %l4, %o1                /* APB VENDOR:DEVICE */
470         cmp     %o0, %g0
471         be      .L_apb_dev_not_found
472          mov    %g2, %o7                /* Restore return address */
473         /* APB Device found
474          * o0 1
475          * o2 Index is decremented to zero
476          * o3 APB configuration address,
477          * o4 APB Bridge Configuration address.
478          */
479         mov     %g0, %o2
480         retl
481          mov    %l3, %o4
482
483 .L_apb_dev_not_found:
484         /* Update APB DEV Index by saving output from find_apb_bus
485          * (index parameter) into bits [31..4] in L2.
486          */
487         sll     %o2, 4, %o2
488         and     %l2, 0xf, %l2
489         or      %o2, %l2, %l2
490         /* Try finding the next AHB/APB Bridge on the same AHB bus
491          * to find more APB devices
492          */
493         ba      .L2_search_next_ahb_bus /* Find next AHB/APB bridge */
494          inc    %l2
495
496 .L_no_apb_bridge_found:
497         inc     %l3                     /* Next AHB Bus */
498         ba      .L2_search_next_ahb_bus /* Process next AHB bus */
499          andn   %l2, 0xf, %l2           /* Start at APB Bridge index 0 at every AHB Bus */
500         /* No device found matching */
501 .L2_no_device_found:
502         mov     %g2, %o7                /* Restore return address */
503         srl     %l2, 4, %o2             /* APB DEV Index */
504         retl
505          mov    %g0, %o0
506
507
508
509 /* FUNCTION _nomem_amba_scan_gaisler_ahb2ahb_bridge(unsigned int bridge, int bus)
510  *
511  * Constraints:
512  *   - o1 may not be used
513  *   - o0, o2, o3 may be used.
514  *
515  * Arguments
516  *  - o0 PnP Address of Bridge AHB device
517  *  - o2 PnP ID of AHB device
518  *
519  * Results
520  *  - o0 Address of new bus PnP area or a 1 if AHB device is no bridge
521  *
522  * Clobbered
523  *   - o0, o2
524  *
525  */
526 _nomem_amba_scan_gaisler_ahb2ahb_bridge:
527         andn    %o2, 0xfff, %o2
528         sethi   %hi(AMBA_PNP_ID(VENDOR_GAISLER,GAISLER_AHB2AHB)), %o3
529         cmp     %o2, %o3
530         beq     .L_is_ahb2ahb_bridge
531          nop
532
533         retl
534          add    %g0, 1, %o0
535
536 .L_is_ahb2ahb_bridge:
537         /* Found a GAISLER AHB2AHB bridge */
538         retl
539          ld     [%o0 + AMBA_AHB_CUSTOM1_OFS], %o0 /* Get address of bridge PnP area */
540
541
542 /* FUNCTION _nomem_amba_scan_gaisler_l2cache_bridge(unsigned int bridge, int bus)
543  *
544  * Constraints:
545  *   - o1 may not be used
546  *   - o0, o2, o3 may be used.
547  *
548  * Arguments
549  *  - o0 PnP Address of Bridge AHB device
550  *  - o2 PnP ID of AHB device
551  *
552  * Results
553  *  - o0 Address of new bus PnP area or a 1 if AHB device is no bridge
554  *
555  * Clobbered
556  *   - o0, o2
557  *
558  */
559 _nomem_amba_scan_gaisler_l2cache_bridge:
560         andn    %o2, 0xfff, %o2
561         sethi   %hi(AMBA_PNP_ID(VENDOR_GAISLER,GAISLER_L2CACHE)), %o3
562         cmp     %o2, %o3
563         beq     .L_is_l2cache_bridge
564          nop
565
566         retl
567          add    %g0, 1, %o0
568
569 .L_is_l2cache_bridge:
570         /* Found a GAISLER l2cache bridge */
571         retl
572          ld     [%o0 + AMBA_AHB_CUSTOM1_OFS], %o0 /* Get address of bridge PnP area */
573
574
575 /* FUNCTION _nomem_amba_scan(unsigned int bridge, int bus)
576  *
577  * Constraints:
578  *  i0-i7, l0 is used by caller
579  *  o5-o7 may not be used.
580  *
581  * Arguments
582  *  - o0 Bridge Information: I/O AREA and parent bus
583  *  - o1 Bus
584  *
585  * Results
586  *  - o0 Number of AHB bridges found
587  *
588  * Clobbered
589  *  - o0 (Current AHB slave conf address)
590  *  - o2 (Used by insert_bridge)
591  *  - o3 (Used by insert_bridge)
592  *  - l1 (Number of AHB Slaves left to process)
593  *  - l2 (Current AHB slave conf address)
594  *  - g2 (Return address)
595  */
596 _nomem_amba_scan:
597         mov     %o7, %g2        /* Save return address */
598         set     16, %l1
599         cmp     %o1, 1
600         be,a    .L2_maxloops_detected
601          add    %g0, 64, %l1
602 .L2_maxloops_detected:
603
604         /* Clear 3-bit parent bus from bridge to get I/O AREA, then or
605          * (AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA) to get first AHB slave
606          * conf address.
607          */
608         andn    %o0, 0x7ff, %o0
609         set     (AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA), %l2
610         or      %o0, %l2, %l2
611
612         /* Scan AHB Slave area for AHB<->AHB bridges. For each AHB device
613          * all "bridge drivers" are called, the driver function interface:
614          *
615          * Input:
616          *   - o0 PnP Address of Bridge AHB device
617          *   - o2 PnP ID of AHB device
618          * Return values:
619          *   - o0 Address of new bus PnP area, returning a 1 in o2 means not found
620          *
621          * Constraints:
622          *   - o1 may not be used
623          *   - o0, o2, o3 may be used.
624          *
625          */
626 .L_scan_one_ahb_slave:
627         ld      [%l2], %o2
628
629         cmp     %o2, %g0
630         beq     .L_scan_next_ahb_slave
631          nop
632
633         /* Call the GAISLER AHB2AHB bridge driver */
634         call    _nomem_amba_scan_gaisler_ahb2ahb_bridge
635          mov    %l2, %o0
636         cmp     %o0, 1
637         bne     .L_found_bridge
638          ld     [%l2], %o2
639
640         /* Call the GAISLER L2CACHE bridge driver */
641         call    _nomem_amba_scan_gaisler_l2cache_bridge
642          mov    %l2, %o0
643         cmp     %o0, 1
644         bne     .L_found_bridge
645          ld     [%l2], %o2
646
647         /* Insert next bridge "driver" function here */
648
649
650         /* The PnP ID did not match a bridge - a new bus was not found ==>
651          * step to next AHB device */
652         ba      .L_scan_next_ahb_slave
653          nop
654
655         /* Add Found bus */
656 .L_found_bridge:
657         and     %l2, 0x7e0, %o2
658         or      %o2, %o0, %o0           /* Add AHB/AHB Bridge PnP address */
659         call    insert_ahb_bridge       /* Insert Bridge into found buses storage */
660          or     %o1, %o0, %o0           /* Add parent bus LSB 3-bits */
661
662 .L_scan_next_ahb_slave:
663         /* More Slaves to process? */
664         subcc   %l1, 1, %l1
665         bne     .L_scan_one_ahb_slave
666          add    %l2, AMBA_AHB_CONF_LENGH, %l2
667
668         /* No more AHB devices to process */
669         mov     %g2, %o7        /* Restore return address */
670         retl
671          nop
672
673 /* FUNCTION _nomem_ambapp_find_buses(unsigned int ioarea)
674  *
675  * Find AMBA AHB buses.
676  *
677  * Constraints:
678  *  i6-i7, l7 is used by caller
679  *
680  * Arguments
681  *  - o0 Bridge Information: I/O AREA and parent bus
682  *
683  * Results
684  *  - o0 Number of AHB bridges found
685  *  - i0-i5 initialized
686  *
687  * Clobbered
688  *  - o0 (Current AHB slave conf address)
689  *  - o2 (Used by insert_bridge)
690  *  - o3 (Used by insert_bridge)
691  *  - l0 (Current AHB Bus)
692  *  - l1 (Used by nomem_amba_scan)
693  *  - l2 (Used by nomem_amba_scan)
694  *  - l3 (Used by nomem_amba_scan)
695  *  - l4 (Used by nomem_amba_scan)
696  *
697  *  - g1 (level 1 return address)
698  *  - g2 (Used by nomem_amba_scan)
699  */
700 _nomem_ambapp_find_buses:
701         mov     %o7, %g1        /* Save return address */
702
703         /* Initialize AHB Bus storage */
704         call    init_ahb_bridges
705          nop
706
707         /* Insert AHB Bus 0 */
708         call    insert_ahb_bridge
709          nop                    /* Argument already prepared by caller */
710
711         /* Scan AHB Bus 0 for AHB Bridges */
712         call    _nomem_amba_scan
713          add    %g0, 1, %o1
714
715         /* Scan all AHB Buses found for more AHB Bridges */
716         add     %g0, 2, %l0
717 .L100_search_next_ahb_bus:
718         call    get_ahb_bridge                  /* Get bus %l0 I/O Area */
719          mov    %l0, %o0
720         cmp     %o0, %g0
721         be      .L100_return                    /* If no more AHB bus is left to be scanned, proceed */
722          nop
723         call    _nomem_amba_scan                /* Scan bus %l0 for AHB Bridges. i0-i7,l0 is used */
724          mov    %l0, %o1                        /* I/O AREA untouched in o0 */
725         ba      .L100_search_next_ahb_bus       /* Do next bus */
726          add    %l0, 1, %l0
727
728 .L100_return:
729         mov     %g1, %o7
730         retl
731          nop
732
733
734 /* FUNCTION _nomem_amba_init(unsigned int ioarea)
735  *
736  *  Find all AHB buses
737  *
738  * Constraints:
739  *  i6, i7, o6, o7, l7, l6, g3, g4, g5, g6, g7 is used by caller
740  *
741  * Arguments
742  *  - o0 Bridge Information: I/O AREA and parent bus
743  *
744  * Results
745  *  - o0 Number of AHB bridges found
746  *
747  * Clobbered
748  *  - l0, l1, l2, l3, l4, g1, g2 (used by _nomem_ambapp_find_buses)
749  *  - o0, o1, o2, o3 (Used as arguments)
750  *  - o5 (return address)
751  *  - g1 (level 1 return address)
752  *  - g2 (level 2 return address)
753  */
754 _nomem_amba_init:
755         mov     %o7, %o5        /* Save return address, o5 not used */
756
757         /* Scan for buses, it will init i0-i5 */
758         call    _nomem_ambapp_find_buses
759          nop
760
761         mov     %o5, %o7
762         retl
763          nop
764
765 /* Call tree and their return address register
766  *
767  *_nomem_amba_scan           (g1)
768  * -> init_ahb_bridges       (o7)
769  * -> insert_ahb_bridge      (o7)
770  * -> _nomem_amba_scan       (g2)
771  *    -> insert_ahb_bridge   (o7)
772  * -> get_ahb_bridge         (o7)
773  *
774  *
775  * -> _nomem_find_apb        (g2)
776  *    -> get_ahb_bridge      (o7)
777  *    -> _nomem_find_ahb_bus (o7)
778  *    -> _nomem_find_apb_bus (o7)
779  * -> _nomem_find_ahb        (g2)
780  *    -> get_ahb_bridge      (o7)
781  *    -> _nomem_find_ahb_bus (o7)
782  * -> mem_handler.func()     (o7)
783  *
784  */