Daniel Hellstrom | 898cc81 | 2010-01-25 09:54:51 +0100 | [diff] [blame] | 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 | */ |