| // 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/system.h> |
| #include <asm/armv8/mmu.h> |
| #include <asm/arch-bcmns3/bl33_info.h> |
| #include <dt-bindings/memory/bcm-ns3-mc.h> |
| |
| /* Default reset-level = 3 and strap-val = 0 */ |
| #define L3_RESET 30 |
| |
| #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(ulong level) |
| { |
| u32 reset_level, strap_val; |
| |
| /* Default reset type is L3 reset */ |
| if (!level) { |
| /* |
| * Encoding: U-Boot reset command expects decimal argument, |
| * Boot strap val: Bits[3:0] |
| * reset level: Bits[7:4] |
| */ |
| strap_val = L3_RESET % 10; |
| level = L3_RESET / 10; |
| reset_level = level % 10; |
| psci_system_reset2(reset_level, strap_val); |
| } else { |
| /* U-Boot cmd "reset" with any arg will trigger L1 reset */ |
| psci_system_reset(); |
| } |
| } |
| |
| #ifdef CONFIG_OF_BOARD_SETUP |
| int ft_board_setup(void *fdt, struct bd_info *bd) |
| { |
| gic_lpi_tables_init(); |
| |
| return mem_info_parse_fixup(fdt); |
| } |
| #endif /* CONFIG_OF_BOARD_SETUP */ |