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
8 * - support for AHB2AHB & L2CACHE bridges
10 * (C) Copyright 2010, 2015
11 * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
13 * SPDX-License-Identifier: GPL-2.0+
19 .globl _nomem_amba_init
20 .globl _nomem_ambapp_find_buses
21 .globl _nomem_find_apb
22 .globl _nomem_find_ahb
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
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.
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.
45 * AHB Bus result and requirements of i0-i5
46 * ========================================
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
57 * Bits 31-20 (0xfff00000) contain the found bus I/O Area (AHB PnP area).
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)..
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.
75 /* Function initializes the AHB Bridge I/O AREA storage. (Clears i0-i5)
96 /* Function returns AHB Bridge I/O AREA for specified bus.
132 /* o0 > 6: only 6 buses supported */
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.
142 * - o0 = AHB Bridge I/O area
151 /* Check that bridge hasn't already been added */
172 /* Insert into first free posistion */
200 /* FUNCTION int _nomem_find_ahb_bus(
201 * unsigned int bridge,
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.
214 * i0-i7,l0,l1,l2,l3,l4,g2,o6 is not available for use.
215 * o1,o5 Must be left untouched
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)
223 * - o3 (Clobbered when no device was found)
224 * - o4 (Number of Devices left to search)
225 * - o0 (Bus ID, PnP ID, Device)
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.
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:
239 /* Get start address of AHB Slave or AHB Master area depending on what
240 * we are searching for.
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 */
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:
252 /* Iterate over all AHB device and try to find matching DEVICE:VENDOR
255 * o3 - Current AHB Device Configuration address
256 * o5 - Type (leave untouched)
258 * o4 - Number of AHB device left to process
264 cmp %o0, 0 /* No device if zero */
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? */
271 .L_process_ahb_dev_found:
272 /* Found a Matching VENDOR:DEVICE, index must also match */
276 /* Index matches also, return happy with o3 set to AHB Conf Address */
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 */
290 /* FUNCTION int _nomem_find_ahb(
295 * int *ahb_bus_index,
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).
302 * Calls _nomem_find_ahb_bus for every AHB bus.
304 * i0-i7, l0, l1, o6, g1, g4-g7 is not available for use.
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
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)
323 mov %o7, %g2 /* Save return address */
324 /* Scan all AHB Buses found for the AHB Master/Slave matching VENDOR:DEVICE */
326 .L_search_next_ahb_bus:
328 call get_ahb_bridge /* Get bus %l0 I/O Area */
331 be .L_no_device_found /* If no more AHB bus is left to be scanned, proceed */
333 call _nomem_find_ahb_bus /* Scan AHB bus %o0 for VENDOR:DEVICE. Index in o3 is decremented */
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) */
338 /* The device was found, o0 is 1 */
339 mov %g2, %o7 /* Restore return address */
341 mov %l2, %o4 /* The AHB bus index the device was found on */
343 /* No device found matching */
345 mov %g2, %o7 /* Restore return address */
350 /* FUNCTION int _nomem_find_apb_bus(
357 * Find a APB Slave device, it puts the address of the APB PnP configuration
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.
364 * - o0 Number of found devices (1 or 0)
365 * - o2 Decremented Index
366 * - o3 Address of the found APB device PnP configuration entry
369 * - o5 PnP VENDOR:DEVICE ID
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:
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
387 .L_process_apb_dev_found:
388 /* Found matching device, compare index */
390 bne .L_process_apb_dev_not_found
392 /* Matching index and VENDOR:DEVICE */
396 .L_process_apb_dev_not_found:
398 bne .L_process_one_apb_conf
403 /* FUNCTION int _nomem_find_apb(
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).
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.
417 * i0-i7, l0, l1, o6 is not available for use.
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
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)
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 */
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 */
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.
461 ld [%o3 + AMBA_AHB_MBAR0_OFS], %o3
463 and %o0, %o3, %o0 /* Address AND Address Mask */
464 sethi %hi(0xfff00000), %o3
465 and %o0, %o3, %o0 /* AHB/APB Bridge address */
467 srl %l2, 4, %o2 /* APB DEV Index */
468 call _nomem_find_apb_bus
469 mov %l4, %o1 /* APB VENDOR:DEVICE */
471 be .L_apb_dev_not_found
472 mov %g2, %o7 /* Restore return address */
475 * o2 Index is decremented to zero
476 * o3 APB configuration address,
477 * o4 APB Bridge Configuration address.
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.
490 /* Try finding the next AHB/APB Bridge on the same AHB bus
491 * to find more APB devices
493 ba .L2_search_next_ahb_bus /* Find next AHB/APB bridge */
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 */
502 mov %g2, %o7 /* Restore return address */
503 srl %l2, 4, %o2 /* APB DEV Index */
509 /* FUNCTION _nomem_amba_scan_gaisler_ahb2ahb_bridge(unsigned int bridge, int bus)
512 * - o1 may not be used
513 * - o0, o2, o3 may be used.
516 * - o0 PnP Address of Bridge AHB device
517 * - o2 PnP ID of AHB device
520 * - o0 Address of new bus PnP area or a 1 if AHB device is no bridge
526 _nomem_amba_scan_gaisler_ahb2ahb_bridge:
528 sethi %hi(AMBA_PNP_ID(VENDOR_GAISLER,GAISLER_AHB2AHB)), %o3
530 beq .L_is_ahb2ahb_bridge
536 .L_is_ahb2ahb_bridge:
537 /* Found a GAISLER AHB2AHB bridge */
539 ld [%o0 + AMBA_AHB_CUSTOM1_OFS], %o0 /* Get address of bridge PnP area */
542 /* FUNCTION _nomem_amba_scan_gaisler_l2cache_bridge(unsigned int bridge, int bus)
545 * - o1 may not be used
546 * - o0, o2, o3 may be used.
549 * - o0 PnP Address of Bridge AHB device
550 * - o2 PnP ID of AHB device
553 * - o0 Address of new bus PnP area or a 1 if AHB device is no bridge
559 _nomem_amba_scan_gaisler_l2cache_bridge:
561 sethi %hi(AMBA_PNP_ID(VENDOR_GAISLER,GAISLER_L2CACHE)), %o3
563 beq .L_is_l2cache_bridge
569 .L_is_l2cache_bridge:
570 /* Found a GAISLER l2cache bridge */
572 ld [%o0 + AMBA_AHB_CUSTOM1_OFS], %o0 /* Get address of bridge PnP area */
575 /* FUNCTION _nomem_amba_scan(unsigned int bridge, int bus)
578 * i0-i7, l0 is used by caller
579 * o5-o7 may not be used.
582 * - o0 Bridge Information: I/O AREA and parent bus
586 * - o0 Number of AHB bridges found
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)
597 mov %o7, %g2 /* Save return address */
600 be,a .L2_maxloops_detected
602 .L2_maxloops_detected:
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
609 set (AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA), %l2
612 /* Scan AHB Slave area for AHB<->AHB bridges. For each AHB device
613 * all "bridge drivers" are called, the driver function interface:
616 * - o0 PnP Address of Bridge AHB device
617 * - o2 PnP ID of AHB device
619 * - o0 Address of new bus PnP area, returning a 1 in o2 means not found
622 * - o1 may not be used
623 * - o0, o2, o3 may be used.
626 .L_scan_one_ahb_slave:
630 beq .L_scan_next_ahb_slave
633 /* Call the GAISLER AHB2AHB bridge driver */
634 call _nomem_amba_scan_gaisler_ahb2ahb_bridge
640 /* Call the GAISLER L2CACHE bridge driver */
641 call _nomem_amba_scan_gaisler_l2cache_bridge
647 /* Insert next bridge "driver" function here */
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
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 */
662 .L_scan_next_ahb_slave:
663 /* More Slaves to process? */
665 bne .L_scan_one_ahb_slave
666 add %l2, AMBA_AHB_CONF_LENGH, %l2
668 /* No more AHB devices to process */
669 mov %g2, %o7 /* Restore return address */
673 /* FUNCTION _nomem_ambapp_find_buses(unsigned int ioarea)
675 * Find AMBA AHB buses.
678 * i6-i7, l7 is used by caller
681 * - o0 Bridge Information: I/O AREA and parent bus
684 * - o0 Number of AHB bridges found
685 * - i0-i5 initialized
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)
697 * - g1 (level 1 return address)
698 * - g2 (Used by nomem_amba_scan)
700 _nomem_ambapp_find_buses:
701 mov %o7, %g1 /* Save return address */
703 /* Initialize AHB Bus storage */
704 call init_ahb_bridges
707 /* Insert AHB Bus 0 */
708 call insert_ahb_bridge
709 nop /* Argument already prepared by caller */
711 /* Scan AHB Bus 0 for AHB Bridges */
712 call _nomem_amba_scan
715 /* Scan all AHB Buses found for more AHB Bridges */
717 .L100_search_next_ahb_bus:
718 call get_ahb_bridge /* Get bus %l0 I/O Area */
721 be .L100_return /* If no more AHB bus is left to be scanned, proceed */
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 */
734 /* FUNCTION _nomem_amba_init(unsigned int ioarea)
739 * i6, i7, o6, o7, l7, l6, g3, g4, g5, g6, g7 is used by caller
742 * - o0 Bridge Information: I/O AREA and parent bus
745 * - o0 Number of AHB bridges found
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)
755 mov %o7, %o5 /* Save return address, o5 not used */
757 /* Scan for buses, it will init i0-i5 */
758 call _nomem_ambapp_find_buses
765 /* Call tree and their return address register
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)
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)