| /* |
| * SPDX-License-Identifier: BSD-3-Clause |
| * SPDX-FileCopyrightText: Copyright TF-RMM Contributors. |
| */ |
| |
| #include <arm_memory.h> |
| #include <assert.h> |
| #include <platform_api.h> |
| #include <utils_def.h> |
| |
| static struct arm_memory_layout arm_dram; |
| static struct arm_memory_layout arm_dev_ncoh; |
| static struct arm_memory_layout arm_dev_coh; |
| |
| struct arm_memory_layout *arm_get_dram_layout(void) |
| { |
| return &arm_dram; |
| } |
| |
| struct arm_memory_layout *arm_get_dev_ncoh_layout(void) |
| { |
| return &arm_dev_ncoh; |
| } |
| |
| struct arm_memory_layout *arm_get_dev_coh_layout(void) |
| { |
| return &arm_dev_coh; |
| } |
| |
| static unsigned long granule_addr_to_idx(unsigned long addr, |
| struct arm_memory_layout *memory_ptr) |
| { |
| unsigned long r, l = 0UL; |
| |
| if (!GRANULE_ALIGNED(addr) || (memory_ptr->num_banks == 0UL)) { |
| return UINT64_MAX; |
| } |
| |
| assert(memory_ptr->num_banks <= PLAT_ARM_MAX_MEM_BANKS); |
| r = memory_ptr->num_banks - 1UL; |
| |
| /* |
| * Use a binary search rather than a linear one to locate the bank which |
| * the address falls within, then use the start_gran_idx (which is a |
| * cumulative idx from previous memory banks) to calculate the required |
| * granule index. |
| */ |
| while (l <= r) { |
| const struct arm_memory_bank *bank; |
| unsigned long i; |
| |
| i = l + ((r - l) / 2UL); |
| assert(i < PLAT_ARM_MAX_MEM_BANKS); |
| |
| bank = &memory_ptr->bank[i]; |
| |
| if (addr < bank->base) { |
| if (i == 0UL) { |
| break; |
| } |
| r = i - 1UL; |
| } else if (addr > (bank->base + bank->size - 1UL)) { |
| l = i + 1UL; |
| } else { |
| return (bank->start_gran_idx + |
| ((addr - bank->base) >> GRANULE_SHIFT)); |
| } |
| } |
| return UINT64_MAX; |
| } |
| |
| unsigned long plat_granule_addr_to_idx(unsigned long addr) |
| { |
| return granule_addr_to_idx(addr, &arm_dram); |
| } |
| |
| unsigned long plat_dev_granule_addr_to_idx(unsigned long addr, enum dev_type *type) |
| { |
| unsigned long ret; |
| |
| assert(type != NULL); |
| |
| /* Check non-coherent device granules */ |
| if (arm_dev_ncoh.num_granules != 0UL) { |
| ret = granule_addr_to_idx(addr, &arm_dev_ncoh); |
| if (ret != UINT64_MAX) { |
| *type = DEV_RANGE_NON_COHERENT; |
| return ret; |
| } |
| } |
| |
| /* Check coherent device granules */ |
| if (arm_dev_coh.num_granules != 0UL) { |
| ret = granule_addr_to_idx(addr, &arm_dev_coh); |
| if (ret != UINT64_MAX) { |
| *type = DEV_RANGE_COHERENT; |
| return ret; |
| } |
| } |
| |
| *type = DEV_RANGE_MAX; |
| return UINT64_MAX; |
| } |
| |
| static unsigned long granule_idx_to_addr(unsigned long idx, |
| struct arm_memory_layout *memory_ptr) |
| { |
| unsigned long r, l = 0UL, addr = 0UL; |
| |
| assert(memory_ptr->num_banks != 0UL); |
| assert(idx < memory_ptr->num_granules); |
| |
| r = memory_ptr->num_banks - 1UL; |
| |
| /* |
| * Calculate the start and end granule index of each bank using the |
| * start_gran_idx (which is a cumulative idx from previous memory banks) |
| * and then check whether the given index falls within it. |
| */ |
| while (l <= r) { |
| const struct arm_memory_bank *bank; |
| unsigned long i; |
| unsigned long idx_start, idx_end; |
| |
| i = l + ((r - l) / 2UL); |
| assert(i < PLAT_ARM_MAX_MEM_BANKS); |
| |
| bank = &memory_ptr->bank[i]; |
| |
| idx_start = bank->start_gran_idx; |
| idx_end = idx_start + (bank->size >> GRANULE_SHIFT) - 1UL; |
| |
| if (idx < idx_start) { |
| assert(i != 0UL); |
| r = i - 1UL; |
| } else if (idx > idx_end) { |
| l = i + 1UL; |
| } else { |
| addr = bank->base + ((idx - idx_start) << GRANULE_SHIFT); |
| break; |
| } |
| } |
| /* Assert that the search was successful */ |
| assert(l <= r); |
| return addr; |
| } |
| |
| unsigned long plat_granule_idx_to_addr(unsigned long idx) |
| { |
| return granule_idx_to_addr(idx, &arm_dram); |
| } |
| |
| unsigned long plat_dev_granule_idx_to_addr(unsigned long idx, enum dev_type type) |
| { |
| (void)type; |
| |
| /* No coherent device memory */ |
| assert(type == DEV_RANGE_NON_COHERENT); |
| |
| return granule_idx_to_addr(idx, &arm_dev_ncoh); |
| } |
| |