diff options
Diffstat (limited to 'arch/arm/cpu/armv8/fsl-layerscape')
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 396 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 33 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/ppa.c | 48 |
4 files changed, 159 insertions, 319 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Makefile b/arch/arm/cpu/armv8/fsl-layerscape/Makefile index eb2cbc3f7e..bcf6b48a51 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Makefile +++ b/arch/arm/cpu/armv8/fsl-layerscape/Makefile @@ -10,6 +10,7 @@ obj-y += soc.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_OF_LIBFDT) += fdt.o obj-$(CONFIG_SPL) += spl.o +obj-$(CONFIG_FSL_LS_PPA) += ppa.o ifneq ($(CONFIG_FSL_LSCH3),) obj-y += fsl_lsch3_speed.o diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index 8062106e3e..7a2ec6bf59 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -23,16 +23,13 @@ #ifdef CONFIG_FSL_ESDHC #include <fsl_esdhc.h> #endif +#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#include <asm/armv8/sec_firmware.h> +#endif DECLARE_GLOBAL_DATA_PTR; -static struct mm_region layerscape_mem_map[] = { - { - /* List terminator */ - 0, - } -}; -struct mm_region *mem_map = layerscape_mem_map; +struct mm_region *mem_map = early_map; void cpu_name(char *name) { @@ -56,348 +53,96 @@ void cpu_name(char *name) } #ifndef CONFIG_SYS_DCACHE_OFF -static void set_pgtable_section(u64 *page_table, u64 index, u64 section, - u64 memory_type, u64 attribute) -{ - u64 value; - - value = section | PTE_TYPE_BLOCK | PTE_BLOCK_AF; - value |= PMD_ATTRINDX(memory_type); - value |= attribute; - page_table[index] = value; -} - -static void set_pgtable_table(u64 *page_table, u64 index, u64 *table_addr) -{ - u64 value; - - value = (u64)table_addr | PTE_TYPE_TABLE; - page_table[index] = value; -} - -/* - * Set the block entries according to the information of the table. - */ -static int set_block_entry(const struct sys_mmu_table *list, - struct table_info *table) -{ - u64 block_size = 0, block_shift = 0; - u64 block_addr, index; - int j; - - if (table->entry_size == BLOCK_SIZE_L1) { - block_size = BLOCK_SIZE_L1; - block_shift = SECTION_SHIFT_L1; - } else if (table->entry_size == BLOCK_SIZE_L2) { - block_size = BLOCK_SIZE_L2; - block_shift = SECTION_SHIFT_L2; - } else { - return -EINVAL; - } - - block_addr = list->phys_addr; - index = (list->virt_addr - table->table_base) >> block_shift; - - for (j = 0; j < (list->size >> block_shift); j++) { - set_pgtable_section(table->ptr, - index, - block_addr, - list->memory_type, - list->attribute); - block_addr += block_size; - index++; - } - - return 0; -} - -/* - * Find the corresponding table entry for the list. - */ -static int find_table(const struct sys_mmu_table *list, - struct table_info *table, u64 *level0_table) -{ - u64 index = 0, level = 0; - u64 *level_table = level0_table; - u64 temp_base = 0, block_size = 0, block_shift = 0; - - while (level < 3) { - if (level == 0) { - block_size = BLOCK_SIZE_L0; - block_shift = SECTION_SHIFT_L0; - } else if (level == 1) { - block_size = BLOCK_SIZE_L1; - block_shift = SECTION_SHIFT_L1; - } else if (level == 2) { - block_size = BLOCK_SIZE_L2; - block_shift = SECTION_SHIFT_L2; - } - - index = 0; - while (list->virt_addr >= temp_base) { - index++; - temp_base += block_size; - } - - temp_base -= block_size; - - if ((level_table[index - 1] & PTE_TYPE_MASK) == - PTE_TYPE_TABLE) { - level_table = (u64 *)(level_table[index - 1] & - ~PTE_TYPE_MASK); - level++; - continue; - } else { - if (level == 0) - return -EINVAL; - - if ((list->phys_addr + list->size) > - (temp_base + block_size * NUM_OF_ENTRY)) - return -EINVAL; - - /* - * Check the address and size of the list member is - * aligned with the block size. - */ - if (((list->phys_addr & (block_size - 1)) != 0) || - ((list->size & (block_size - 1)) != 0)) - return -EINVAL; - - table->ptr = level_table; - table->table_base = temp_base - - ((index - 1) << block_shift); - table->entry_size = block_size; - - return 0; - } - } - return -EINVAL; -} - /* * To start MMU before DDR is available, we create MMU table in SRAM. * The base address of SRAM is CONFIG_SYS_FSL_OCRAM_BASE. We use three * levels of translation tables here to cover 40-bit address space. * We use 4KB granule size, with 40 bits physical address, T0SZ=24 - * Level 0 IA[39], table address @0 - * Level 1 IA[38:30], table address @0x1000, 0x2000 - * Level 2 IA[29:21], table address @0x3000, 0x4000 - * Address above 0x5000 is free for other purpose. + * Address above EARLY_PGTABLE_SIZE (0x5000) is free for other purpose. + * Note, the debug print in cache_v8.c is not usable for debugging + * these early MMU tables because UART is not yet available. */ static inline void early_mmu_setup(void) { - unsigned int el, i; - u64 *level0_table = (u64 *)CONFIG_SYS_FSL_OCRAM_BASE; - u64 *level1_table0 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x1000); - u64 *level1_table1 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x2000); - u64 *level2_table0 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x3000); - u64 *level2_table1 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x4000); - - struct table_info table = {level0_table, 0, BLOCK_SIZE_L0}; - - /* Invalidate all table entries */ - memset(level0_table, 0, 0x5000); - - /* Fill in the table entries */ - set_pgtable_table(level0_table, 0, level1_table0); - set_pgtable_table(level0_table, 1, level1_table1); - set_pgtable_table(level1_table0, 0, level2_table0); + unsigned int el = current_el(); -#ifdef CONFIG_FSL_LSCH3 - set_pgtable_table(level1_table0, - CONFIG_SYS_FLASH_BASE >> SECTION_SHIFT_L1, - level2_table1); -#elif defined(CONFIG_FSL_LSCH2) - set_pgtable_table(level1_table0, 1, level2_table1); -#endif - /* Find the table and fill in the block entries */ - for (i = 0; i < ARRAY_SIZE(early_mmu_table); i++) { - if (find_table(&early_mmu_table[i], - &table, level0_table) == 0) { - /* - * If find_table() returns error, it cannot be dealt - * with here. Breakpoint can be added for debugging. - */ - set_block_entry(&early_mmu_table[i], &table); - /* - * If set_block_entry() returns error, it cannot be - * dealt with here too. - */ - } - } + /* global data is already setup, no allocation yet */ + gd->arch.tlb_addr = CONFIG_SYS_FSL_OCRAM_BASE; + gd->arch.tlb_fillptr = gd->arch.tlb_addr; + gd->arch.tlb_size = EARLY_PGTABLE_SIZE; - el = current_el(); + /* Create early page tables */ + setup_pgtables(); - set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR, + /* point TTBR to the new table */ + set_ttbr_tcr_mair(el, gd->arch.tlb_addr, + get_tcr(el, NULL, NULL) & + ~(TCR_ORGN_MASK | TCR_IRGN_MASK), MEMORY_ATTRIBUTES); - set_sctlr(get_sctlr() | CR_M); -} -#ifdef CONFIG_SYS_MEM_RESERVE_SECURE -/* - * Called from final mmu setup. The phys_addr is new, non-existing - * address. A new sub table is created @level2_table_secure to cover - * size of CONFIG_SYS_MEM_RESERVE_SECURE memory. - */ -static inline int final_secure_ddr(u64 *level0_table, - u64 *level2_table_secure, - phys_addr_t phys_addr) -{ - int ret = -EINVAL; - struct table_info table = {}; - struct sys_mmu_table ddr_entry = { - 0, 0, BLOCK_SIZE_L1, MT_NORMAL, - PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS - }; - u64 index; - - /* Need to create a new table */ - ddr_entry.virt_addr = phys_addr & ~(BLOCK_SIZE_L1 - 1); - ddr_entry.phys_addr = phys_addr & ~(BLOCK_SIZE_L1 - 1); - ret = find_table(&ddr_entry, &table, level0_table); - if (ret) - return ret; - index = (ddr_entry.virt_addr - table.table_base) >> SECTION_SHIFT_L1; - set_pgtable_table(table.ptr, index, level2_table_secure); - table.ptr = level2_table_secure; - table.table_base = ddr_entry.virt_addr; - table.entry_size = BLOCK_SIZE_L2; - ret = set_block_entry(&ddr_entry, &table); - if (ret) { - printf("MMU error: could not fill non-secure ddr block entries\n"); - return ret; - } - ddr_entry.virt_addr = phys_addr; - ddr_entry.phys_addr = phys_addr; - ddr_entry.size = CONFIG_SYS_MEM_RESERVE_SECURE; - ddr_entry.attribute = PTE_BLOCK_OUTER_SHARE; - ret = find_table(&ddr_entry, &table, level0_table); - if (ret) { - printf("MMU error: could not find secure ddr table\n"); - return ret; - } - ret = set_block_entry(&ddr_entry, &table); - if (ret) - printf("MMU error: could not set secure ddr block entry\n"); - - return ret; + set_sctlr(get_sctlr() | CR_M); } -#endif /* * The final tables look similar to early tables, but different in detail. * These tables are in DRAM. Sub tables are added to enable cache for * QBMan and OCRAM. * - * Put the MMU table in secure memory if gd->secure_ram is valid. - * OCRAM will be not used for this purpose so gd->secure_ram can't be 0. - * - * Level 1 table 0 contains 512 entries for each 1GB from 0 to 512GB. - * Level 1 table 1 contains 512 entries for each 1GB from 512GB to 1TB. - * Level 2 table 0 contains 512 entries for each 2MB from 0 to 1GB. - * - * For LSCH3: - * Level 2 table 1 contains 512 entries for each 2MB from 32GB to 33GB. - * For LSCH2: - * Level 2 table 1 contains 512 entries for each 2MB from 1GB to 2GB. - * Level 2 table 2 contains 512 entries for each 2MB from 20GB to 21GB. + * Put the MMU table in secure memory if gd->arch.secure_ram is valid. + * OCRAM will be not used for this purpose so gd->arch.secure_ram can't be 0. */ static inline void final_mmu_setup(void) { + u64 tlb_addr_save = gd->arch.tlb_addr; unsigned int el = current_el(); - unsigned int i; - u64 *level0_table = (u64 *)gd->arch.tlb_addr; - u64 *level1_table0; - u64 *level1_table1; - u64 *level2_table0; - u64 *level2_table1; -#ifdef CONFIG_FSL_LSCH2 - u64 *level2_table2; -#endif - struct table_info table = {NULL, 0, BLOCK_SIZE_L0}; - #ifdef CONFIG_SYS_MEM_RESERVE_SECURE - u64 *level2_table_secure; - - if (el == 3) { - /* - * Only use gd->secure_ram if the address is recalculated - * Align to 4KB for MMU table - */ - if (gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED) - level0_table = (u64 *)(gd->secure_ram & ~0xfff); - else - printf("MMU warning: gd->secure_ram is not maintained, disabled.\n"); - } -#endif - level1_table0 = level0_table + 512; - level1_table1 = level1_table0 + 512; - level2_table0 = level1_table1 + 512; - level2_table1 = level2_table0 + 512; -#ifdef CONFIG_FSL_LSCH2 - level2_table2 = level2_table1 + 512; + int index; #endif - table.ptr = level0_table; - /* Invalidate all table entries */ - memset(level0_table, 0, PGTABLE_SIZE); + mem_map = final_map; - /* Fill in the table entries */ - set_pgtable_table(level0_table, 0, level1_table0); - set_pgtable_table(level0_table, 1, level1_table1); - set_pgtable_table(level1_table0, 0, level2_table0); -#ifdef CONFIG_FSL_LSCH3 - set_pgtable_table(level1_table0, - CONFIG_SYS_FSL_QBMAN_BASE >> SECTION_SHIFT_L1, - level2_table1); -#elif defined(CONFIG_FSL_LSCH2) - set_pgtable_table(level1_table0, 1, level2_table1); - set_pgtable_table(level1_table0, - CONFIG_SYS_FSL_QBMAN_BASE >> SECTION_SHIFT_L1, - level2_table2); -#endif - - /* Find the table and fill in the block entries */ - for (i = 0; i < ARRAY_SIZE(final_mmu_table); i++) { - if (find_table(&final_mmu_table[i], - &table, level0_table) == 0) { - if (set_block_entry(&final_mmu_table[i], - &table) != 0) { - printf("MMU error: could not set block entry for %p\n", - &final_mmu_table[i]); - } - - } else { - printf("MMU error: could not find the table for %p\n", - &final_mmu_table[i]); - } - } - /* Set the secure memory to secure in MMU */ #ifdef CONFIG_SYS_MEM_RESERVE_SECURE - if (el == 3 && gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED) { -#ifdef CONFIG_FSL_LSCH3 - level2_table_secure = level2_table1 + 512; -#elif defined(CONFIG_FSL_LSCH2) - level2_table_secure = level2_table2 + 512; -#endif - if (!final_secure_ddr(level0_table, - level2_table_secure, - gd->secure_ram & ~0x3)) { - gd->secure_ram |= MEM_RESERVE_SECURE_SECURED; - debug("Now MMU table is in secured memory at 0x%llx\n", - gd->secure_ram & ~0x3); + if (gd->arch.secure_ram & MEM_RESERVE_SECURE_MAINTAINED) { + if (el == 3) { + /* + * Only use gd->arch.secure_ram if the address is + * recalculated. Align to 4KB for MMU table. + */ + /* put page tables in secure ram */ + index = ARRAY_SIZE(final_map) - 2; + gd->arch.tlb_addr = gd->arch.secure_ram & ~0xfff; + final_map[index].virt = gd->arch.secure_ram & ~0x3; + final_map[index].phys = final_map[index].virt; + final_map[index].size = CONFIG_SYS_MEM_RESERVE_SECURE; + final_map[index].attrs = PTE_BLOCK_OUTER_SHARE; + gd->arch.secure_ram |= MEM_RESERVE_SECURE_SECURED; + tlb_addr_save = gd->arch.tlb_addr; } else { - printf("MMU warning: Failed to secure DDR\n"); + /* Use allocated (board_f.c) memory for TLB */ + tlb_addr_save = gd->arch.tlb_allocated; + gd->arch.tlb_addr = tlb_addr_save; } } #endif + /* Reset the fill ptr */ + gd->arch.tlb_fillptr = tlb_addr_save; + + /* Create normal system page tables */ + setup_pgtables(); + + /* Create emergency page tables */ + gd->arch.tlb_addr = gd->arch.tlb_fillptr; + gd->arch.tlb_emerg = gd->arch.tlb_addr; + setup_pgtables(); + gd->arch.tlb_addr = tlb_addr_save; + /* flush new MMU table */ - flush_dcache_range((ulong)level0_table, - (ulong)level0_table + gd->arch.tlb_size); + flush_dcache_range(gd->arch.tlb_addr, + gd->arch.tlb_addr + gd->arch.tlb_size); /* point TTBR to the new table */ - set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR_FINAL, + set_ttbr_tcr_mair(el, gd->arch.tlb_addr, get_tcr(el, NULL, NULL), MEMORY_ATTRIBUTES); /* * MMU is already enabled, just need to invalidate TLB to load the @@ -422,15 +167,21 @@ int arch_cpu_init(void) return 0; } +void mmu_setup(void) +{ + final_mmu_setup(); +} + /* - * This function is called from lib/board.c. - * It recreates MMU table in main memory. MMU and d-cache are enabled earlier. - * There is no need to disable d-cache for this operation. + * This function is called from common/board_r.c. + * It recreates MMU table in main memory. */ void enable_caches(void) { - final_mmu_setup(); + mmu_setup(); __asm_invalidate_tlb_all(); + icache_enable(); + dcache_enable(); } #endif @@ -616,6 +367,7 @@ int arch_early_init_r(void) { #ifdef CONFIG_MP int rv = 1; + u32 psci_ver = 0xffffffff; #endif #ifdef CONFIG_SYS_FSL_ERRATUM_A009635 @@ -623,9 +375,15 @@ int arch_early_init_r(void) #endif #ifdef CONFIG_MP - rv = fsl_layerscape_wake_seconday_cores(); - if (rv) - printf("Did not wake secondary cores\n"); +#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && defined(CONFIG_ARMV8_PSCI) + /* Check the psci version to determine if the psci is supported */ + psci_ver = sec_firmware_support_psci_version(); +#endif + if (psci_ver == 0xffffffff) { + rv = fsl_layerscape_wake_seconday_cores(); + if (rv) + printf("Did not wake secondary cores\n"); + } #endif #ifdef CONFIG_SYS_HAS_SERDES diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index d17227ab2b..40d6a761e8 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -22,6 +22,9 @@ #endif #include <fsl_sec.h> #include <asm/arch-fsl-layerscape/soc.h> +#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#include <asm/armv8/sec_firmware.h> +#endif int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc) { @@ -38,7 +41,37 @@ void ft_fixup_cpu(void *blob) int addr_cells; u64 val, core_id; size_t *boot_code_size = &(__secondary_boot_code_size); +#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && defined(CONFIG_ARMV8_PSCI) + int node; + u32 psci_ver; + + /* Check the psci version to determine if the psci is supported */ + psci_ver = sec_firmware_support_psci_version(); + if (psci_ver == 0xffffffff) { + /* remove psci DT node */ + node = fdt_path_offset(blob, "/psci"); + if (node >= 0) + goto remove_psci_node; + + node = fdt_node_offset_by_compatible(blob, -1, "arm,psci"); + if (node >= 0) + goto remove_psci_node; + + node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-0.2"); + if (node >= 0) + goto remove_psci_node; + node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-1.0"); + if (node >= 0) + goto remove_psci_node; + +remove_psci_node: + if (node >= 0) + fdt_del_node(blob, node); + } else { + return; + } +#endif off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ppa.c b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c new file mode 100644 index 0000000000..541b251bf4 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c @@ -0,0 +1,48 @@ +/* + * Copyright 2016 NXP Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <config.h> +#include <errno.h> +#include <asm/system.h> +#include <asm/types.h> +#include <asm/arch/soc.h> +#ifdef CONFIG_FSL_LSCH3 +#include <asm/arch/immap_lsch3.h> +#elif defined(CONFIG_FSL_LSCH2) +#include <asm/arch/immap_lsch2.h> +#endif +#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#include <asm/armv8/sec_firmware.h> +#endif + +int ppa_init(void) +{ + const void *ppa_fit_addr; + u32 *boot_loc_ptr_l, *boot_loc_ptr_h; + int ret; + +#ifdef CONFIG_SYS_LS_PPA_FW_IN_NOR + ppa_fit_addr = (void *)CONFIG_SYS_LS_PPA_FW_ADDR; +#else +#error "No CONFIG_SYS_LS_PPA_FW_IN_xxx defined" +#endif + +#ifdef CONFIG_FSL_LSCH3 + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + boot_loc_ptr_l = &gur->bootlocptrl; + boot_loc_ptr_h = &gur->bootlocptrh; +#elif defined(CONFIG_FSL_LSCH2) + struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR); + boot_loc_ptr_l = &scfg->scratchrw[1]; + boot_loc_ptr_h = &scfg->scratchrw[0]; +#endif + + debug("fsl-ppa: boot_loc_ptr_l = 0x%p, boot_loc_ptr_h =0x%p\n", + boot_loc_ptr_l, boot_loc_ptr_h); + ret = sec_firmware_init(ppa_fit_addr, boot_loc_ptr_l, boot_loc_ptr_h); + + return ret; +} |