| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright 2020 Broadcom. |
| * |
| */ |
| |
| #include <common.h> |
| #include <fdt_support.h> |
| #include <asm/io.h> |
| #include <asm/gic-v3.h> |
| #include <asm/global_data.h> |
| #include <asm/system.h> |
| #include <asm/armv8/mmu.h> |
| #include <asm/arch-bcmns3/bl33_info.h> |
| #include <dt-bindings/memory/bcm-ns3-mc.h> |
| #include <broadcom/chimp.h> |
| |
| #define BANK_OFFSET(bank) ((u64)BCM_NS3_DDR_INFO_BASE + 8 + ((bank) * 16)) |
| |
| /* |
| * ns3_dram_bank - DDR bank details |
| * |
| * @start: DDR bank start address |
| * @len: DDR bank length |
| */ |
| struct ns3_dram_bank { |
| u64 start[BCM_NS3_MAX_NR_BANKS]; |
| u64 len[BCM_NS3_MAX_NR_BANKS]; |
| }; |
| |
| /* |
| * ns3_dram_hdr - DDR header info |
| * |
| * @sig: DDR info signature |
| * @bank: DDR bank details |
| */ |
| struct ns3_dram_hdr { |
| u32 sig; |
| struct ns3_dram_bank bank; |
| }; |
| |
| static struct mm_region ns3_mem_map[] = { |
| { |
| .virt = 0x0UL, |
| .phys = 0x0UL, |
| .size = 0x80000000UL, |
| .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
| PTE_BLOCK_NON_SHARE | |
| PTE_BLOCK_PXN | PTE_BLOCK_UXN |
| }, { |
| .virt = BCM_NS3_MEM_START, |
| .phys = BCM_NS3_MEM_START, |
| .size = BCM_NS3_MEM_LEN, |
| .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
| PTE_BLOCK_INNER_SHARE |
| }, { |
| .virt = BCM_NS3_BANK_1_MEM_START, |
| .phys = BCM_NS3_BANK_1_MEM_START, |
| .size = BCM_NS3_BANK_1_MEM_LEN, |
| .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
| PTE_BLOCK_INNER_SHARE |
| }, { |
| /* List terminator */ |
| 0, |
| } |
| }; |
| |
| struct mm_region *mem_map = ns3_mem_map; |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| /* |
| * Force the bl33_info to the data-section, as .bss will not be valid |
| * when save_boot_params is invoked. |
| */ |
| struct bl33_info *bl33_info __section(".data"); |
| |
| /* |
| * Run modulo 256 checksum calculation and return the calculated checksum |
| */ |
| static u8 checksum_calc(u8 *p, unsigned int len) |
| { |
| unsigned int i; |
| u8 chksum = 0; |
| |
| for (i = 0; i < len; i++) |
| chksum += p[i]; |
| |
| return chksum; |
| } |
| |
| /* |
| * This function parses the memory layout information from a reserved area in |
| * DDR, and then fix up the FDT before passing it to Linux. |
| * |
| * In the case of error, do nothing and the default memory layout in DT will |
| * be used |
| */ |
| static int mem_info_parse_fixup(void *fdt) |
| { |
| struct ns3_dram_hdr hdr; |
| u32 *p32, i, nr_banks; |
| u64 *p64; |
| |
| /* validate signature */ |
| p32 = (u32 *)BCM_NS3_DDR_INFO_BASE; |
| hdr.sig = *p32; |
| if (hdr.sig != BCM_NS3_DDR_INFO_SIG) { |
| printf("DDR info signature 0x%x invalid\n", hdr.sig); |
| return -EINVAL; |
| } |
| |
| /* run checksum test to validate data */ |
| if (checksum_calc((u8 *)p32, BCM_NS3_DDR_INFO_LEN) != 0) { |
| printf("Checksum on DDR info failed\n"); |
| return -EINVAL; |
| } |
| |
| /* parse information for each bank */ |
| nr_banks = 0; |
| for (i = 0; i < BCM_NS3_MAX_NR_BANKS; i++) { |
| /* skip banks with a length of zero */ |
| p64 = (u64 *)BANK_OFFSET(i); |
| if (*(p64 + 1) == 0) |
| continue; |
| |
| hdr.bank.start[i] = *p64; |
| hdr.bank.len[i] = *(p64 + 1); |
| |
| printf("mem[%u] 0x%llx - 0x%llx\n", i, hdr.bank.start[i], |
| hdr.bank.start[i] + hdr.bank.len[i] - 1); |
| nr_banks++; |
| } |
| |
| if (!nr_banks) { |
| printf("No DDR banks detected\n"); |
| return -ENOMEM; |
| } |
| |
| return fdt_fixup_memory_banks(fdt, hdr.bank.start, hdr.bank.len, |
| nr_banks); |
| } |
| |
| int board_init(void) |
| { |
| /* Setup memory using "memory" node from DTB */ |
| if (fdtdec_setup_mem_size_base() != 0) |
| return -EINVAL; |
| fdtdec_setup_memory_banksize(); |
| |
| if (bl33_info->version != BL33_INFO_VERSION) |
| printf("*** warning: ATF BL31 and U-Boot not in sync! ***\n"); |
| |
| return 0; |
| } |
| |
| int board_late_init(void) |
| { |
| return 0; |
| } |
| |
| int dram_init(void) |
| { |
| /* |
| * Mark ram base as the last 16MB of 2GB DDR, which is 0xFF00_0000. |
| * So that relocation happens with in the last 16MB memory. |
| */ |
| gd->ram_base = (phys_size_t)(BCM_NS3_MEM_END - SZ_16M); |
| gd->ram_size = (unsigned long)SZ_16M; |
| |
| return 0; |
| } |
| |
| int dram_init_banksize(void) |
| { |
| gd->bd->bi_dram[0].start = (BCM_NS3_MEM_END - SZ_16M); |
| gd->bd->bi_dram[0].size = SZ_16M; |
| |
| return 0; |
| } |
| |
| /* Limit RAM used by U-Boot to the DDR first bank End region */ |
| ulong board_get_usable_ram_top(ulong total_size) |
| { |
| return BCM_NS3_MEM_END; |
| } |
| |
| void reset_cpu(void) |
| { |
| /* Perform a level 3 reset */ |
| psci_system_reset2(3, 0); |
| } |
| |
| #ifdef CONFIG_OF_BOARD_SETUP |
| int ft_board_setup(void *fdt, struct bd_info *bd) |
| { |
| u32 chimp_hs = CHIMP_HANDSHAKE_WAIT_TIMEOUT; |
| |
| gic_lpi_tables_init(); |
| |
| /* |
| * Check for chimp handshake status. |
| * Zero timeout value will actually fall to default timeout. |
| * |
| * System boot is independent of chimp handshake. |
| * chimp handshake failure is not a catastrophic error. |
| * Hence continue booting if chimp handshake fails. |
| */ |
| chimp_handshake_status_optee(0, &chimp_hs); |
| if (chimp_hs == CHIMP_HANDSHAKE_SUCCESS) |
| printf("ChiMP handshake successful\n"); |
| else |
| printf("ERROR: ChiMP handshake status 0x%x\n", chimp_hs); |
| |
| return mem_info_parse_fixup(fdt); |
| } |
| #endif /* CONFIG_OF_BOARD_SETUP */ |