diff options
Diffstat (limited to 'arch/arm/cpu/armv8/fsl-layerscape')
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/Makefile | 30 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/README.lsch2 | 10 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/README.lsch3 | 244 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 539 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/cpu.h | 8 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 204 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c | 117 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c | 180 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c | 146 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c | 189 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S | 363 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/ls1043a_serdes.c | 86 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/ls2085a_serdes.c | 116 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/mp.c | 197 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/soc.c | 103 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/spl.c | 79 |
16 files changed, 2611 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Makefile b/arch/arm/cpu/armv8/fsl-layerscape/Makefile new file mode 100644 index 0000000000..6fa08c8f3c --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/Makefile @@ -0,0 +1,30 @@ +# +# Copyright 2014-2015, Freescale Semiconductor +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += cpu.o +obj-y += lowlevel.o +obj-y += soc.o +obj-$(CONFIG_MP) += mp.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o +obj-$(CONFIG_SPL) += spl.o + +ifneq ($(CONFIG_FSL_LSCH3),) +obj-y += fsl_lsch3_speed.o +obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch3_serdes.o +else +ifneq ($(CONFIG_FSL_LSCH2),) +obj-y += fsl_lsch2_speed.o +obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch2_serdes.o +endif +endif + +ifneq ($(CONFIG_LS2085A),) +obj-$(CONFIG_SYS_HAS_SERDES) += ls2085a_serdes.o +else +ifneq ($(CONFIG_LS1043A),) +obj-$(CONFIG_SYS_HAS_SERDES) += ls1043a_serdes.o +endif +endif diff --git a/arch/arm/cpu/armv8/fsl-layerscape/README.lsch2 b/arch/arm/cpu/armv8/fsl-layerscape/README.lsch2 new file mode 100644 index 0000000000..a6ef830069 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/README.lsch2 @@ -0,0 +1,10 @@ +# +# Copyright 2015 Freescale Semiconductor +# +# SPDX-License-Identifier: GPL-2.0+ +# + +Freescale LayerScape with Chassis Generation 2 + +This architecture supports Freescale ARMv8 SoCs with Chassis generation 2, +for example LS1043A. diff --git a/arch/arm/cpu/armv8/fsl-layerscape/README.lsch3 b/arch/arm/cpu/armv8/fsl-layerscape/README.lsch3 new file mode 100644 index 0000000000..03e18f6573 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/README.lsch3 @@ -0,0 +1,244 @@ +# +# Copyright 2014-2015 Freescale Semiconductor +# +# SPDX-License-Identifier: GPL-2.0+ +# + +Freescale LayerScape with Chassis Generation 3 + +This architecture supports Freescale ARMv8 SoCs with Chassis generation 3, +for example LS2085A. + +DDR Layout +============ +Entire DDR region splits into two regions. + - Region 1 is at address 0x8000_0000 to 0xffff_ffff. + - Region 2 is at 0x80_8000_0000 to the top of total memory, + for example 16GB, 0x83_ffff_ffff. + +All DDR memory is marked as cache-enabled. + +When MC and Debug server is enabled, they carve 512MB away from the high +end of DDR. For example, if the total DDR is 16GB, it shrinks to 15.5GB +with MC and Debug server enabled. Linux only sees 15.5GB. + +The reserved 512MB layout looks like + + +---------------+ <-- top/end of memory + | 256MB | debug server + +---------------+ + | 256MB | MC + +---------------+ + | ... | + +MC requires the memory to be aligned with 512MB, so even debug server is +not enabled, 512MB is reserved, not 256MB. + +Flash Layout +============ + +(1) A typical layout of various images (including Linux and other firmware images) + is shown below considering a 32MB NOR flash device present on most + pre-silicon platforms (simulator and emulator): + + ------------------------- + | FIT Image | + | (linux + DTB + RFS) | + ------------------------- ----> 0x0120_0000 + | Debug Server FW | + ------------------------- ----> 0x00C0_0000 + | AIOP FW | + ------------------------- ----> 0x0070_0000 + | MC FW | + ------------------------- ----> 0x006C_0000 + | MC DPL Blob | + ------------------------- ----> 0x0020_0000 + | BootLoader + Env| + ------------------------- ----> 0x0000_1000 + | PBI | + ------------------------- ----> 0x0000_0080 + | RCW | + ------------------------- ----> 0x0000_0000 + + 32-MB NOR flash layout for pre-silicon platforms (simulator and emulator) + +(2) A typical layout of various images (including Linux and other firmware images) + is shown below considering a 128MB NOR flash device present on QDS and RDB + boards: + ----------------------------------------- ----> 0x5_8800_0000 --- + | .. Unused .. (7M) | | + ----------------------------------------- ----> 0x5_8790_0000 | + | FIT Image (linux + DTB + RFS) (40M) | | + ----------------------------------------- ----> 0x5_8510_0000 | + | PHY firmware (2M) | | + ----------------------------------------- ----> 0x5_84F0_0000 | 64K + | Debug Server FW (2M) | | Alt + ----------------------------------------- ----> 0x5_84D0_0000 | Bank + | AIOP FW (4M) | | + ----------------------------------------- ----> 0x5_8490_0000 (vbank4) + | MC DPC Blob (1M) | | + ----------------------------------------- ----> 0x5_8480_0000 | + | MC DPL Blob (1M) | | + ----------------------------------------- ----> 0x5_8470_0000 | + | MC FW (4M) | | + ----------------------------------------- ----> 0x5_8430_0000 | + | BootLoader Environment (1M) | | + ----------------------------------------- ----> 0x5_8420_0000 | + | BootLoader (1M) | | + ----------------------------------------- ----> 0x5_8410_0000 | + | RCW and PBI (1M) | | + ----------------------------------------- ----> 0x5_8400_0000 --- + | .. Unused .. (7M) | | + ----------------------------------------- ----> 0x5_8390_0000 | + | FIT Image (linux + DTB + RFS) (40M) | | + ----------------------------------------- ----> 0x5_8110_0000 | + | PHY firmware (2M) | | + ----------------------------------------- ----> 0x5_80F0_0000 | 64K + | Debug Server FW (2M) | | Bank + ----------------------------------------- ----> 0x5_80D0_0000 | + | AIOP FW (4M) | | + ----------------------------------------- ----> 0x5_8090_0000 (vbank0) + | MC DPC Blob (1M) | | + ----------------------------------------- ----> 0x5_8080_0000 | + | MC DPL Blob (1M) | | + ----------------------------------------- ----> 0x5_8070_0000 | + | MC FW (4M) | | + ----------------------------------------- ----> 0x5_8030_0000 | + | BootLoader Environment (1M) | | + ----------------------------------------- ----> 0x5_8020_0000 | + | BootLoader (1M) | | + ----------------------------------------- ----> 0x5_8010_0000 | + | RCW and PBI (1M) | | + ----------------------------------------- ----> 0x5_8000_0000 --- + + 128-MB NOR flash layout for QDS and RDB boards + +Environment Variables +===================== +mcboottimeout: MC boot timeout in milliseconds. If this variable is not defined + the value CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS will be assumed. + +mcmemsize: MC DRAM block size. If this variable is not defined, the value + CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE will be assumed. + +Booting from NAND +------------------- +Booting from NAND requires two images, RCW and u-boot-with-spl.bin. +The difference between NAND boot RCW image and NOR boot image is the PBI +command sequence. Below is one example for PBI commands for QDS which uses +NAND device with 2KB/page, block size 128KB. + +1) CCSR 4-byte write to 0x00e00404, data=0x00000000 +2) CCSR 4-byte write to 0x00e00400, data=0x1800a000 +The above two commands set bootloc register to 0x00000000_1800a000 where +the u-boot code will be running in OCRAM. + +3) Block Copy: SRC=0x0107, SRC_ADDR=0x00020000, DEST_ADDR=0x1800a000, +BLOCK_SIZE=0x00014000 +This command copies u-boot image from NAND device into OCRAM. The values need +to adjust accordingly. + +SRC should match the cfg_rcw_src, the reset config pins. It depends + on the NAND device. See reference manual for cfg_rcw_src. +SRC_ADDR is the offset of u-boot-with-spl.bin image in NAND device. In + the example above, 128KB. For easy maintenance, we put it at + the beginning of next block from RCW. +DEST_ADDR is fixed at 0x1800a000, matching bootloc set above. +BLOCK_SIZE is the size to be copied by PBI. + +RCW image should be written to the beginning of NAND device. Example of using +u-boot command + +nand write <rcw image in memory> 0 <size of rcw image> + +To form the NAND image, build u-boot with NAND config, for example, +ls2085aqds_nand_defconfig. The image needed is u-boot-with-spl.bin. +The u-boot image should be written to match SRC_ADDR, in above example 0x20000. + +nand write <u-boot image in memory> 200000 <size of u-boot image> + +With these two images in NAND device, the board can boot from NAND. + +Another example for RDB boards, + +1) CCSR 4-byte write to 0x00e00404, data=0x00000000 +2) CCSR 4-byte write to 0x00e00400, data=0x1800a000 +3) Block Copy: SRC=0x0119, SRC_ADDR=0x00080000, DEST_ADDR=0x1800a000, +BLOCK_SIZE=0x00014000 + +nand write <rcw image in memory> 0 <size of rcw image> +nand write <u-boot image in memory> 80000 <size of u-boot image> + +Notice the difference from QDS is SRC, SRC_ADDR and the offset of u-boot image +to match board NAND device with 4KB/page, block size 512KB. + +MMU Translation Tables +====================== + +(1) Early MMU Tables: + + Level 0 Level 1 Level 2 +------------------ ------------------ ------------------ +| 0x00_0000_0000 | -----> | 0x00_0000_0000 | -----> | 0x00_0000_0000 | +------------------ ------------------ ------------------ +| 0x80_0000_0000 | --| | 0x00_4000_0000 | | 0x00_0020_0000 | +------------------ | ------------------ ------------------ +| invalid | | | 0x00_8000_0000 | | 0x00_0040_0000 | +------------------ | ------------------ ------------------ + | | 0x00_c000_0000 | | 0x00_0060_0000 | + | ------------------ ------------------ + | | 0x01_0000_0000 | | 0x00_0080_0000 | + | ------------------ ------------------ + | ... ... + | ------------------ + | | 0x05_8000_0000 | --| + | ------------------ | + | | 0x05_c000_0000 | | + | ------------------ | + | ... | + | ------------------ | ------------------ + |--> | 0x80_0000_0000 | |-> | 0x00_3000_0000 | + ------------------ ------------------ + | 0x80_4000_0000 | | 0x00_3020_0000 | + ------------------ ------------------ + | 0x80_8000_0000 | | 0x00_3040_0000 | + ------------------ ------------------ + | 0x80_c000_0000 | | 0x00_3060_0000 | + ------------------ ------------------ + | 0x81_0000_0000 | | 0x00_3080_0000 | + ------------------ ------------------ + ... ... + +(2) Final MMU Tables: + + Level 0 Level 1 Level 2 +------------------ ------------------ ------------------ +| 0x00_0000_0000 | -----> | 0x00_0000_0000 | -----> | 0x00_0000_0000 | +------------------ ------------------ ------------------ +| 0x80_0000_0000 | --| | 0x00_4000_0000 | | 0x00_0020_0000 | +------------------ | ------------------ ------------------ +| invalid | | | 0x00_8000_0000 | | 0x00_0040_0000 | +------------------ | ------------------ ------------------ + | | 0x00_c000_0000 | | 0x00_0060_0000 | + | ------------------ ------------------ + | | 0x01_0000_0000 | | 0x00_0080_0000 | + | ------------------ ------------------ + | ... ... + | ------------------ + | | 0x08_0000_0000 | --| + | ------------------ | + | | 0x08_4000_0000 | | + | ------------------ | + | ... | + | ------------------ | ------------------ + |--> | 0x80_0000_0000 | |--> | 0x08_0000_0000 | + ------------------ ------------------ + | 0x80_4000_0000 | | 0x08_0020_0000 | + ------------------ ------------------ + | 0x80_8000_0000 | | 0x08_0040_0000 | + ------------------ ------------------ + | 0x80_c000_0000 | | 0x08_0060_0000 | + ------------------ ------------------ + | 0x81_0000_0000 | | 0x08_0080_0000 | + ------------------ ------------------ + ... ... diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c new file mode 100644 index 0000000000..0cb0afa0b3 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -0,0 +1,539 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/system.h> +#include <asm/armv8/mmu.h> +#include <asm/io.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch/soc.h> +#include <asm/arch/cpu.h> +#include <asm/arch/speed.h> +#ifdef CONFIG_MP +#include <asm/arch/mp.h> +#endif +#include <fm_eth.h> +#include <fsl_debug_server.h> +#include <fsl-mc/fsl_mc.h> +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +void cpu_name(char *name) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + unsigned int i, svr, ver; + + svr = gur_in32(&gur->svr); + ver = SVR_SOC_VER(svr); + + for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++) + if ((cpu_type_list[i].soc_ver & SVR_WO_E) == ver) { + strcpy(name, cpu_type_list[i].name); + + if (IS_E_PROCESSOR(svr)) + strcat(name, "E"); + break; + } + + if (i == ARRAY_SIZE(cpu_type_list)) + strcpy(name, "unknown"); +} + +#ifndef CONFIG_SYS_DCACHE_OFF +/* + * 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->share); + 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] & PMD_TYPE_MASK) == + PMD_TYPE_TABLE) { + level_table = (u64 *)(level_table[index - 1] & + ~PMD_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. + */ +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); + +#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. + */ + } + } + + el = current_el(); + + set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR, + MEMORY_ATTRIBUTES); + set_sctlr(get_sctlr() | CR_M); +} + +/* + * 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. + * + * 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. + */ +static inline void final_mmu_setup(void) +{ + unsigned int el, i; + u64 *level0_table = (u64 *)gd->arch.tlb_addr; + u64 *level1_table0 = (u64 *)(gd->arch.tlb_addr + 0x1000); + u64 *level1_table1 = (u64 *)(gd->arch.tlb_addr + 0x2000); + u64 *level2_table0 = (u64 *)(gd->arch.tlb_addr + 0x3000); +#ifdef CONFIG_FSL_LSCH3 + u64 *level2_table1 = (u64 *)(gd->arch.tlb_addr + 0x4000); +#elif defined(CONFIG_FSL_LSCH2) + u64 *level2_table1 = (u64 *)(gd->arch.tlb_addr + 0x4000); + u64 *level2_table2 = (u64 *)(gd->arch.tlb_addr + 0x5000); +#endif + struct table_info table = {level0_table, 0, BLOCK_SIZE_L0}; + + /* Invalidate all table entries */ + memset(level0_table, 0, PGTABLE_SIZE); + + /* 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]); + } + } + + /* flush new MMU table */ + flush_dcache_range(gd->arch.tlb_addr, + gd->arch.tlb_addr + gd->arch.tlb_size); + +#ifdef CONFIG_SYS_DPAA_FMAN + flush_dcache_all(); +#endif + /* point TTBR to the new table */ + el = current_el(); + + set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR_FINAL, + MEMORY_ATTRIBUTES); + /* + * MMU is already enabled, just need to invalidate TLB to load the + * new table. The new table is compatible with the current table, if + * MMU somehow walks through the new table before invalidation TLB, + * it still works. So we don't need to turn off MMU here. + */ +} + +int arch_cpu_init(void) +{ + icache_enable(); + __asm_invalidate_dcache_all(); + __asm_invalidate_tlb_all(); + early_mmu_setup(); + set_sctlr(get_sctlr() | CR_C); + return 0; +} + +/* + * 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. + */ +void enable_caches(void) +{ + final_mmu_setup(); + __asm_invalidate_tlb_all(); +} +#endif + +static inline u32 initiator_type(u32 cluster, int init_id) +{ + struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 idx = (cluster >> (init_id * 8)) & TP_CLUSTER_INIT_MASK; + u32 type = 0; + + type = gur_in32(&gur->tp_ityp[idx]); + if (type & TP_ITYP_AV) + return type; + + return 0; +} + +u32 cpu_mask(void) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + int i = 0, count = 0; + u32 cluster, type, mask = 0; + + do { + int j; + + cluster = gur_in32(&gur->tp_cluster[i].lower); + for (j = 0; j < TP_INIT_PER_CLUSTER; j++) { + type = initiator_type(cluster, j); + if (type) { + if (TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM) + mask |= 1 << count; + count++; + } + } + i++; + } while ((cluster & TP_CLUSTER_EOC) == 0x0); + + return mask; +} + +/* + * Return the number of cores on this SOC. + */ +int cpu_numcores(void) +{ + return hweight32(cpu_mask()); +} + +int fsl_qoriq_core_to_cluster(unsigned int core) +{ + struct ccsr_gur __iomem *gur = + (void __iomem *)(CONFIG_SYS_FSL_GUTS_ADDR); + int i = 0, count = 0; + u32 cluster; + + do { + int j; + + cluster = gur_in32(&gur->tp_cluster[i].lower); + for (j = 0; j < TP_INIT_PER_CLUSTER; j++) { + if (initiator_type(cluster, j)) { + if (count == core) + return i; + count++; + } + } + i++; + } while ((cluster & TP_CLUSTER_EOC) == 0x0); + + return -1; /* cannot identify the cluster */ +} + +u32 fsl_qoriq_core_to_type(unsigned int core) +{ + struct ccsr_gur __iomem *gur = + (void __iomem *)(CONFIG_SYS_FSL_GUTS_ADDR); + int i = 0, count = 0; + u32 cluster, type; + + do { + int j; + + cluster = gur_in32(&gur->tp_cluster[i].lower); + for (j = 0; j < TP_INIT_PER_CLUSTER; j++) { + type = initiator_type(cluster, j); + if (type) { + if (count == core) + return type; + count++; + } + } + i++; + } while ((cluster & TP_CLUSTER_EOC) == 0x0); + + return -1; /* cannot identify the cluster */ +} + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + struct sys_info sysinfo; + char buf[32]; + unsigned int i, core; + u32 type, rcw; + + puts("SoC: "); + + cpu_name(buf); + printf(" %s (0x%x)\n", buf, gur_in32(&gur->svr)); + memset((u8 *)buf, 0x00, ARRAY_SIZE(buf)); + get_sys_info(&sysinfo); + puts("Clock Configuration:"); + for_each_cpu(i, core, cpu_numcores(), cpu_mask()) { + if (!(i % 3)) + puts("\n "); + type = TP_ITYP_VER(fsl_qoriq_core_to_type(core)); + printf("CPU%d(%s):%-4s MHz ", core, + type == TY_ITYP_VER_A7 ? "A7 " : + (type == TY_ITYP_VER_A53 ? "A53" : + (type == TY_ITYP_VER_A57 ? "A57" : " ")), + strmhz(buf, sysinfo.freq_processor[core])); + } + printf("\n Bus: %-4s MHz ", + strmhz(buf, sysinfo.freq_systembus)); + printf("DDR: %-4s MT/s", strmhz(buf, sysinfo.freq_ddrbus)); +#ifdef CONFIG_SYS_DPAA_FMAN + printf(" FMAN: %-4s MHz", strmhz(buf, sysinfo.freq_fman[0])); +#endif +#ifdef CONFIG_FSL_LSCH3 + printf(" DP-DDR: %-4s MT/s", strmhz(buf, sysinfo.freq_ddrbus2)); +#endif + puts("\n"); + + /* + * Display the RCW, so that no one gets confused as to what RCW + * we're actually using for this boot. + */ + puts("Reset Configuration Word (RCW):"); + for (i = 0; i < ARRAY_SIZE(gur->rcwsr); i++) { + rcw = gur_in32(&gur->rcwsr[i]); + if ((i % 4) == 0) + printf("\n %08x:", i * 4); + printf(" %08x", rcw); + } + puts("\n"); + + return 0; +} +#endif + +#ifdef CONFIG_FSL_ESDHC +int cpu_mmc_init(bd_t *bis) +{ + return fsl_esdhc_mmc_init(bis); +} +#endif + +int cpu_eth_init(bd_t *bis) +{ + int error = 0; + +#ifdef CONFIG_FSL_MC_ENET + error = fsl_mc_ldpaa_init(bis); +#endif +#ifdef CONFIG_FMAN_ENET + fm_standard_init(bis); +#endif + return error; +} + +int arch_early_init_r(void) +{ +#ifdef CONFIG_MP + int rv = 1; + + rv = fsl_layerscape_wake_seconday_cores(); + if (rv) + printf("Did not wake secondary cores\n"); +#endif + +#ifdef CONFIG_SYS_HAS_SERDES + fsl_serdes_init(); +#endif +#ifdef CONFIG_FMAN_ENET + fman_enet_init(); +#endif + return 0; +} + +int timer_init(void) +{ + u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR; +#ifdef CONFIG_FSL_LSCH3 + u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR; +#endif +#ifdef COUNTER_FREQUENCY_REAL + unsigned long cntfrq = COUNTER_FREQUENCY_REAL; + + /* Update with accurate clock frequency */ + asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory"); +#endif + +#ifdef CONFIG_FSL_LSCH3 + /* Enable timebase for all clusters. + * It is safe to do so even some clusters are not enabled. + */ + out_le32(cltbenr, 0xf); +#endif + + /* Enable clock for timer + * This is a global setting. + */ + out_le32(cntcr, 0x1); + + return 0; +} + +void reset_cpu(ulong addr) +{ + u32 __iomem *rstcr = (u32 *)CONFIG_SYS_FSL_RST_ADDR; + u32 val; + + /* Raise RESET_REQ_B */ + val = scfg_in32(rstcr); + val |= 0x02; + scfg_out32(rstcr, val); +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.h b/arch/arm/cpu/armv8/fsl-layerscape/cpu.h new file mode 100644 index 0000000000..8072f3ca6a --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.h @@ -0,0 +1,8 @@ +/* + * Copyright 2014-2015, Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +int fsl_qoriq_core_to_cluster(unsigned int core); +u32 cpu_mask(void); diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c new file mode 100644 index 0000000000..47599c1217 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -0,0 +1,204 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <phy.h> +#ifdef CONFIG_FSL_LSCH3 +#include <asm/arch/fdt.h> +#endif +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> +#endif +#ifdef CONFIG_MP +#include <asm/arch/mp.h> +#endif + +int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc) +{ + return fdt_setprop_string(blob, offset, "phy-connection-type", + phy_string_for_interface(phyc)); +} + +#ifdef CONFIG_MP +void ft_fixup_cpu(void *blob) +{ + int off; + __maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); + fdt32_t *reg; + int addr_cells; + u64 val, core_id; + size_t *boot_code_size = &(__secondary_boot_code_size); + + off = fdt_path_offset(blob, "/cpus"); + if (off < 0) { + puts("couldn't find /cpus node\n"); + return; + } + of_bus_default_count_cells(blob, off, &addr_cells, NULL); + + off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); + while (off != -FDT_ERR_NOTFOUND) { + reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); + if (reg) { + core_id = of_read_number(reg, addr_cells); + if (core_id == 0 || (is_core_online(core_id))) { + val = spin_tbl_addr; + val += id_to_core(core_id) * + SPIN_TABLE_ELEM_SIZE; + val = cpu_to_fdt64(val); + fdt_setprop_string(blob, off, "enable-method", + "spin-table"); + fdt_setprop(blob, off, "cpu-release-addr", + &val, sizeof(val)); + } else { + debug("skipping offline core\n"); + } + } else { + puts("Warning: found cpu node without reg property\n"); + } + off = fdt_node_offset_by_prop_value(blob, off, "device_type", + "cpu", 4); + } + + fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, + *boot_code_size); +} +#endif + +/* + * the burden is on the the caller to not request a count + * exceeding the bounds of the stream_ids[] array + */ +void alloc_stream_ids(int start_id, int count, u32 *stream_ids, int max_cnt) +{ + int i; + + if (count > max_cnt) { + printf("\n%s: ERROR: max per-device stream ID count exceed\n", + __func__); + return; + } + + for (i = 0; i < count; i++) + stream_ids[i] = start_id++; +} + +/* + * This function updates the mmu-masters property on the SMMU + * node as per the SMMU binding-- phandle and list of stream IDs + * for each MMU master. + */ +void append_mmu_masters(void *blob, const char *smmu_path, + const char *master_name, u32 *stream_ids, int count) +{ + u32 phandle; + int smmu_nodeoffset; + int master_nodeoffset; + int i; + + /* get phandle of mmu master device */ + master_nodeoffset = fdt_path_offset(blob, master_name); + if (master_nodeoffset < 0) { + printf("\n%s: ERROR: master not found\n", __func__); + return; + } + phandle = fdt_get_phandle(blob, master_nodeoffset); + if (!phandle) { /* if master has no phandle, create one */ + phandle = fdt_create_phandle(blob, master_nodeoffset); + if (!phandle) { + printf("\n%s: ERROR: unable to create phandle\n", + __func__); + return; + } + } + + /* append it to mmu-masters */ + smmu_nodeoffset = fdt_path_offset(blob, smmu_path); + if (fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", + phandle) < 0) { + printf("\n%s: ERROR: unable to update SMMU node\n", __func__); + return; + } + + /* for each stream ID, append to mmu-masters */ + for (i = 0; i < count; i++) { + fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", + stream_ids[i]); + } + + /* fix up #stream-id-cells with stream ID count */ + if (fdt_setprop_u32(blob, master_nodeoffset, "#stream-id-cells", + count) < 0) + printf("\n%s: ERROR: unable to update #stream-id-cells\n", + __func__); +} + + +/* + * The info below summarizes how streamID partitioning works + * for ls2085a and how it is conveyed to the OS via the device tree. + * + * -non-PCI legacy, platform devices (USB, SD/MMC, SATA, DMA) + * -all legacy devices get a unique ICID assigned and programmed in + * their AMQR registers by u-boot + * -u-boot updates the hardware device tree with streamID properties + * for each platform/legacy device (smmu-masters property) + * + * -PCIe + * -for each PCI controller that is active (as per RCW settings), + * u-boot will allocate a range of ICID and convey that to Linux via + * the device tree (smmu-masters property) + * + * -DPAA2 + * -u-boot will allocate a range of ICIDs to be used by the Management + * Complex for containers and will set these values in the MC DPC image. + * -the MC is responsible for allocating and setting up ICIDs + * for all DPAA2 devices. + * + */ +#ifdef CONFIG_FSL_LSCH3 +static void fdt_fixup_smmu(void *blob) +{ + int nodeoffset; + + nodeoffset = fdt_path_offset(blob, "/iommu@5000000"); + if (nodeoffset < 0) { + printf("\n%s: WARNING: no SMMU node found\n", __func__); + return; + } + + /* fixup for all PCI controllers */ +#ifdef CONFIG_PCI + fdt_fixup_smmu_pcie(blob); +#endif +} +#endif + +void ft_cpu_setup(void *blob, bd_t *bd) +{ +#ifdef CONFIG_MP + ft_fixup_cpu(blob); +#endif + +#ifdef CONFIG_SYS_NS16550 + do_fixup_by_compat_u32(blob, "fsl,ns16550", + "clock-frequency", CONFIG_SYS_NS16550_CLK, 1); +#endif + +#ifdef CONFIG_PCI + ft_pci_setup(blob, bd); +#endif + +#ifdef CONFIG_FSL_ESDHC + fdt_fixup_esdhc(blob, bd); +#endif + +#ifdef CONFIG_FSL_LSCH3 + fdt_fixup_smmu(blob); +#endif +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c new file mode 100644 index 0000000000..f7178d1470 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c @@ -0,0 +1,117 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch/soc.h> + +#ifdef CONFIG_SYS_FSL_SRDS_1 +static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT]; +#endif + +int is_serdes_configured(enum srds_prtcl device) +{ + int ret = 0; + +#ifdef CONFIG_SYS_FSL_SRDS_1 + ret |= serdes1_prtcl_map[device]; +#endif + + return !!ret; +} + +int serdes_get_first_lane(u32 sd, enum srds_prtcl device) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg = gur_in32(&gur->rcwsr[4]); + int i; + + switch (sd) { +#ifdef CONFIG_SYS_FSL_SRDS_1 + case FSL_SRDS_1: + cfg &= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; + cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT; + break; +#endif + default: + printf("invalid SerDes%d\n", sd); + break; + } + + /* Is serdes enabled at all? */ + if (unlikely(cfg == 0)) + return -ENODEV; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (serdes_get_prtcl(sd, cfg, i) == device) + return i; + } + + return -ENODEV; +} + +int get_serdes_protocol(void) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg = gur_in32(&gur->rcwsr[4]) & + FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; + cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT; + + return cfg; +} + +const char *serdes_clock_to_string(u32 clock) +{ + switch (clock) { + case SRDS_PLLCR0_RFCK_SEL_100: + return "100"; + case SRDS_PLLCR0_RFCK_SEL_125: + return "125"; + case SRDS_PLLCR0_RFCK_SEL_156_25: + return "156.25"; + default: + return "100"; + } +} + +void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift, + u8 serdes_prtcl_map[SERDES_PRCTL_COUNT]) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg; + int lane; + + memset(serdes_prtcl_map, 0, sizeof(serdes_prtcl_map)); + + cfg = gur_in32(&gur->rcwsr[4]) & sd_prctl_mask; + cfg >>= sd_prctl_shift; + printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg); + + if (!is_serdes_prtcl_valid(sd, cfg)) + printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg); + + for (lane = 0; lane < SRDS_MAX_LANES; lane++) { + enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane); + + if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT)) + debug("Unknown SerDes lane protocol %d\n", lane_prtcl); + else + serdes_prtcl_map[lane_prtcl] = 1; + } +} + +void fsl_serdes_init(void) +{ +#ifdef CONFIG_SYS_FSL_SRDS_1 + serdes_init(FSL_SRDS_1, + CONFIG_SYS_FSL_SERDES_ADDR, + FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK, + FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT, + serdes1_prtcl_map); +#endif +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c new file mode 100644 index 0000000000..6f6a588292 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c @@ -0,0 +1,180 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <linux/compiler.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/arch/clock.h> +#include <asm/arch/soc.h> +#include <fsl_ifc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS +#define CONFIG_SYS_FSL_NUM_CC_PLLS 2 +#endif + +void get_sys_info(struct sys_info *sys_info) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); +#ifdef CONFIG_FSL_IFC + struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL}; + u32 ccr; +#endif +#if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_SYS_DPAA_FMAN) + u32 rcw_tmp; +#endif + struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_CLK_ADDR); + unsigned int cpu; + const u8 core_cplx_pll[8] = { + [0] = 0, /* CC1 PPL / 1 */ + [1] = 0, /* CC1 PPL / 2 */ + [4] = 1, /* CC2 PPL / 1 */ + [5] = 1, /* CC2 PPL / 2 */ + }; + + const u8 core_cplx_pll_div[8] = { + [0] = 1, /* CC1 PPL / 1 */ + [1] = 2, /* CC1 PPL / 2 */ + [4] = 1, /* CC2 PPL / 1 */ + [5] = 2, /* CC2 PPL / 2 */ + }; + + uint i; + uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS]; + uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS]; + unsigned long sysclk = CONFIG_SYS_CLK_FREQ; + + sys_info->freq_systembus = sysclk; +#ifdef CONFIG_DDR_CLK_FREQ + sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ; +#else + sys_info->freq_ddrbus = sysclk; +#endif + + sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >> + FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) & + FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK; + sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >> + FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_SHIFT) & + FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_MASK; + + for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) { + ratio[i] = (in_be32(&clk->pllcgsr[i].pllcngsr) >> 1) & 0xff; + if (ratio[i] > 4) + freq_c_pll[i] = sysclk * ratio[i]; + else + freq_c_pll[i] = sys_info->freq_systembus * ratio[i]; + } + + for (cpu = 0; cpu < CONFIG_MAX_CPUS; cpu++) { + u32 c_pll_sel = (in_be32(&clk->clkcsr[cpu].clkcncsr) >> 27) + & 0xf; + u32 cplx_pll = core_cplx_pll[c_pll_sel]; + + sys_info->freq_processor[cpu] = + freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel]; + } + +#define HWA_CGA_M1_CLK_SEL 0xe0000000 +#define HWA_CGA_M1_CLK_SHIFT 29 +#ifdef CONFIG_SYS_DPAA_FMAN + rcw_tmp = in_be32(&gur->rcwsr[7]); + switch ((rcw_tmp & HWA_CGA_M1_CLK_SEL) >> HWA_CGA_M1_CLK_SHIFT) { + case 2: + sys_info->freq_fman[0] = freq_c_pll[0] / 2; + break; + case 3: + sys_info->freq_fman[0] = freq_c_pll[0] / 3; + break; + case 6: + sys_info->freq_fman[0] = freq_c_pll[1] / 2; + break; + case 7: + sys_info->freq_fman[0] = freq_c_pll[1] / 3; + break; + default: + printf("Error: Unknown FMan1 clock select!\n"); + break; + } +#endif + +#define HWA_CGA_M2_CLK_SEL 0x00000007 +#define HWA_CGA_M2_CLK_SHIFT 0 +#ifdef CONFIG_FSL_ESDHC + rcw_tmp = in_be32(&gur->rcwsr[15]); + rcw_tmp = (rcw_tmp & HWA_CGA_M2_CLK_SEL) >> HWA_CGA_M2_CLK_SHIFT; + sys_info->freq_sdhc = freq_c_pll[1] / rcw_tmp; +#endif + +#if defined(CONFIG_FSL_IFC) + ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr); + ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1; + + sys_info->freq_localbus = sys_info->freq_systembus / ccr; +#endif +} + +int get_clocks(void) +{ + struct sys_info sys_info; + + get_sys_info(&sys_info); + gd->cpu_clk = sys_info.freq_processor[0]; + gd->bus_clk = sys_info.freq_systembus; + gd->mem_clk = sys_info.freq_ddrbus; + +#ifdef CONFIG_FSL_ESDHC + gd->arch.sdhc_clk = sys_info.freq_sdhc; +#endif + + if (gd->cpu_clk != 0) + return 0; + else + return 1; +} + +ulong get_bus_freq(ulong dummy) +{ + return gd->bus_clk; +} + +ulong get_ddr_freq(ulong dummy) +{ + return gd->mem_clk; +} + +#ifdef CONFIG_FSL_ESDHC +int get_sdhc_freq(ulong dummy) +{ + return gd->arch.sdhc_clk; +} +#endif + +int get_serial_clock(void) +{ + return gd->bus_clk; +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_I2C_CLK: + return get_bus_freq(0); +#if defined(CONFIG_FSL_ESDHC) + case MXC_ESDHC_CLK: + return get_sdhc_freq(0); +#endif + case MXC_DSPI_CLK: + return get_bus_freq(0); + case MXC_UART_CLK: + return get_bus_freq(0); + default: + printf("Unsupported clock\n"); + } + return 0; +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c new file mode 100644 index 0000000000..2ab8da6403 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c @@ -0,0 +1,146 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch/soc.h> +#include <fsl-mc/ldpaa_wriop.h> + +#ifdef CONFIG_SYS_FSL_SRDS_1 +static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT]; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 +static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT]; +#endif + +int is_serdes_configured(enum srds_prtcl device) +{ + int ret = 0; + +#ifdef CONFIG_SYS_FSL_SRDS_1 + ret |= serdes1_prtcl_map[device]; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + ret |= serdes2_prtcl_map[device]; +#endif + + return !!ret; +} + +int serdes_get_first_lane(u32 sd, enum srds_prtcl device) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg = gur_in32(&gur->rcwsr[28]); + int i; + + switch (sd) { +#ifdef CONFIG_SYS_FSL_SRDS_1 + case FSL_SRDS_1: + cfg &= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK; + cfg >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT; + break; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + case FSL_SRDS_2: + cfg &= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK; + cfg >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT; + break; +#endif + default: + printf("invalid SerDes%d\n", sd); + break; + } + /* Is serdes enabled at all? */ + if (cfg == 0) + return -ENODEV; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (serdes_get_prtcl(sd, cfg, i) == device) + return i; + } + + return -ENODEV; +} + +void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift, + u8 serdes_prtcl_map[SERDES_PRCTL_COUNT]) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg; + int lane; + + memset(serdes_prtcl_map, 0, sizeof(serdes_prtcl_map)); + + cfg = gur_in32(&gur->rcwsr[28]) & sd_prctl_mask; + cfg >>= sd_prctl_shift; + printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg); + + if (!is_serdes_prtcl_valid(sd, cfg)) + printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg); + + for (lane = 0; lane < SRDS_MAX_LANES; lane++) { + enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane); + if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT)) + debug("Unknown SerDes lane protocol %d\n", lane_prtcl); + else { + serdes_prtcl_map[lane_prtcl] = 1; +#ifdef CONFIG_FSL_MC_ENET + switch (lane_prtcl) { + case QSGMII_A: + wriop_init_dpmac(sd, 5, (int)lane_prtcl); + wriop_init_dpmac(sd, 6, (int)lane_prtcl); + wriop_init_dpmac(sd, 7, (int)lane_prtcl); + wriop_init_dpmac(sd, 8, (int)lane_prtcl); + break; + case QSGMII_B: + wriop_init_dpmac(sd, 1, (int)lane_prtcl); + wriop_init_dpmac(sd, 2, (int)lane_prtcl); + wriop_init_dpmac(sd, 3, (int)lane_prtcl); + wriop_init_dpmac(sd, 4, (int)lane_prtcl); + break; + case QSGMII_C: + wriop_init_dpmac(sd, 13, (int)lane_prtcl); + wriop_init_dpmac(sd, 14, (int)lane_prtcl); + wriop_init_dpmac(sd, 15, (int)lane_prtcl); + wriop_init_dpmac(sd, 16, (int)lane_prtcl); + break; + case QSGMII_D: + wriop_init_dpmac(sd, 9, (int)lane_prtcl); + wriop_init_dpmac(sd, 10, (int)lane_prtcl); + wriop_init_dpmac(sd, 11, (int)lane_prtcl); + wriop_init_dpmac(sd, 12, (int)lane_prtcl); + break; + default: + if (lane_prtcl >= SGMII1 && + lane_prtcl <= SGMII16) + wriop_init_dpmac(sd, lane + 1, + (int)lane_prtcl); + break; + } +#endif + } + } +} + +void fsl_serdes_init(void) +{ +#ifdef CONFIG_SYS_FSL_SRDS_1 + serdes_init(FSL_SRDS_1, + CONFIG_SYS_FSL_LSCH3_SERDES_ADDR, + FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK, + FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT, + serdes1_prtcl_map); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + serdes_init(FSL_SRDS_2, + CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + FSL_SRDS_2 * 0x10000, + FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK, + FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT, + serdes2_prtcl_map); +#endif +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c new file mode 100644 index 0000000000..4054c3c7d2 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c @@ -0,0 +1,189 @@ +/* + * Copyright 2014-2015, Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Derived from arch/power/cpu/mpc85xx/speed.c + */ + +#include <common.h> +#include <linux/compiler.h> +#include <fsl_ifc.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/soc.h> +#include "cpu.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS +#define CONFIG_SYS_FSL_NUM_CC_PLLS 6 +#endif + + +void get_sys_info(struct sys_info *sys_info) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); +#ifdef CONFIG_FSL_IFC + struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL}; + u32 ccr; +#endif + struct ccsr_clk_cluster_group __iomem *clk_grp[2] = { + (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR), + (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR) + }; + struct ccsr_clk_ctrl __iomem *clk_ctrl = + (void *)(CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR); + unsigned int cpu; + const u8 core_cplx_pll[16] = { + [0] = 0, /* CC1 PPL / 1 */ + [1] = 0, /* CC1 PPL / 2 */ + [2] = 0, /* CC1 PPL / 4 */ + [4] = 1, /* CC2 PPL / 1 */ + [5] = 1, /* CC2 PPL / 2 */ + [6] = 1, /* CC2 PPL / 4 */ + [8] = 2, /* CC3 PPL / 1 */ + [9] = 2, /* CC3 PPL / 2 */ + [10] = 2, /* CC3 PPL / 4 */ + [12] = 3, /* CC4 PPL / 1 */ + [13] = 3, /* CC4 PPL / 2 */ + [14] = 3, /* CC4 PPL / 4 */ + }; + + const u8 core_cplx_pll_div[16] = { + [0] = 1, /* CC1 PPL / 1 */ + [1] = 2, /* CC1 PPL / 2 */ + [2] = 4, /* CC1 PPL / 4 */ + [4] = 1, /* CC2 PPL / 1 */ + [5] = 2, /* CC2 PPL / 2 */ + [6] = 4, /* CC2 PPL / 4 */ + [8] = 1, /* CC3 PPL / 1 */ + [9] = 2, /* CC3 PPL / 2 */ + [10] = 4, /* CC3 PPL / 4 */ + [12] = 1, /* CC4 PPL / 1 */ + [13] = 2, /* CC4 PPL / 2 */ + [14] = 4, /* CC4 PPL / 4 */ + }; + + uint i, cluster; + uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS]; + uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS]; + unsigned long sysclk = CONFIG_SYS_CLK_FREQ; + int cc_group[12] = CONFIG_SYS_FSL_CLUSTER_CLOCKS; + u32 c_pll_sel, cplx_pll; + void *offset; + + sys_info->freq_systembus = sysclk; +#ifdef CONFIG_DDR_CLK_FREQ + sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ; + sys_info->freq_ddrbus2 = CONFIG_DDR_CLK_FREQ; +#else + sys_info->freq_ddrbus = sysclk; + sys_info->freq_ddrbus2 = sysclk; +#endif + + sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >> + FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) & + FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK; + /* Platform clock is half of platform PLL */ + sys_info->freq_systembus /= 2; + sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >> + FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) & + FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK; + sys_info->freq_ddrbus2 *= (gur_in32(&gur->rcwsr[0]) >> + FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_SHIFT) & + FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_MASK; + + for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) { + /* + * fixme: prefer to combine the following into one line, but + * cannot pass compiling without warning about in_le32. + */ + offset = (void *)((size_t)clk_grp[i/3] + + offsetof(struct ccsr_clk_cluster_group, + pllngsr[i%3].gsr)); + ratio[i] = (in_le32(offset) >> 1) & 0x3f; + freq_c_pll[i] = sysclk * ratio[i]; + } + + for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) { + cluster = fsl_qoriq_core_to_cluster(cpu); + c_pll_sel = (in_le32(&clk_ctrl->clkcncsr[cluster].csr) >> 27) + & 0xf; + cplx_pll = core_cplx_pll[c_pll_sel]; + cplx_pll += cc_group[cluster] - 1; + sys_info->freq_processor[cpu] = + freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel]; + } + +#if defined(CONFIG_FSL_IFC) + ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr); + ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1; + + sys_info->freq_localbus = sys_info->freq_systembus / ccr; +#endif +} + + +int get_clocks(void) +{ + struct sys_info sys_info; + get_sys_info(&sys_info); + gd->cpu_clk = sys_info.freq_processor[0]; + gd->bus_clk = sys_info.freq_systembus; + gd->mem_clk = sys_info.freq_ddrbus; + gd->arch.mem2_clk = sys_info.freq_ddrbus2; +#if defined(CONFIG_FSL_ESDHC) + gd->arch.sdhc_clk = gd->bus_clk / 2; +#endif /* defined(CONFIG_FSL_ESDHC) */ + + if (gd->cpu_clk != 0) + return 0; + else + return 1; +} + +/******************************************** + * get_bus_freq + * return system bus freq in Hz + *********************************************/ +ulong get_bus_freq(ulong dummy) +{ + if (!gd->bus_clk) + get_clocks(); + + return gd->bus_clk; +} + +/******************************************** + * get_ddr_freq + * return ddr bus freq in Hz + *********************************************/ +ulong get_ddr_freq(ulong ctrl_num) +{ + if (!gd->mem_clk) + get_clocks(); + + /* + * DDR controller 0 & 1 are on memory complex 0 + * DDR controler 2 is on memory complext 1 + */ + if (ctrl_num >= 2) + return gd->arch.mem2_clk; + + return gd->mem_clk; +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_I2C_CLK: + return get_bus_freq(0) / 2; + case MXC_DSPI_CLK: + return get_bus_freq(0) / 2; + default: + printf("Unsupported clock\n"); + } + return 0; +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S new file mode 100644 index 0000000000..41e1704986 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S @@ -0,0 +1,363 @@ +/* + * (C) Copyright 2014-2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Extracted from armv8/start.S + */ + +#include <config.h> +#include <linux/linkage.h> +#include <asm/gic.h> +#include <asm/macro.h> +#ifdef CONFIG_MP +#include <asm/arch/mp.h> +#endif + +ENTRY(lowlevel_init) + mov x29, lr /* Save LR */ + +#ifdef CONFIG_FSL_LSCH3 + /* Add fully-coherent masters to DVM domain */ + ldr x0, =CCI_MN_BASE + ldr x1, =CCI_MN_RNF_NODEID_LIST + ldr x2, =CCI_MN_DVM_DOMAIN_CTL_SET + bl ccn504_add_masters_to_dvm + + /* Set all RN-I ports to QoS of 15 */ + ldr x0, =CCI_S0_QOS_CONTROL_BASE(0) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S1_QOS_CONTROL_BASE(0) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S2_QOS_CONTROL_BASE(0) + ldr x1, =0x00FF000C + bl ccn504_set_qos + + ldr x0, =CCI_S0_QOS_CONTROL_BASE(2) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S1_QOS_CONTROL_BASE(2) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S2_QOS_CONTROL_BASE(2) + ldr x1, =0x00FF000C + bl ccn504_set_qos + + ldr x0, =CCI_S0_QOS_CONTROL_BASE(6) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S1_QOS_CONTROL_BASE(6) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S2_QOS_CONTROL_BASE(6) + ldr x1, =0x00FF000C + bl ccn504_set_qos + + ldr x0, =CCI_S0_QOS_CONTROL_BASE(12) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S1_QOS_CONTROL_BASE(12) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S2_QOS_CONTROL_BASE(12) + ldr x1, =0x00FF000C + bl ccn504_set_qos + + ldr x0, =CCI_S0_QOS_CONTROL_BASE(16) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S1_QOS_CONTROL_BASE(16) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S2_QOS_CONTROL_BASE(16) + ldr x1, =0x00FF000C + bl ccn504_set_qos + + ldr x0, =CCI_S0_QOS_CONTROL_BASE(20) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S1_QOS_CONTROL_BASE(20) + ldr x1, =0x00FF000C + bl ccn504_set_qos + ldr x0, =CCI_S2_QOS_CONTROL_BASE(20) + ldr x1, =0x00FF000C + bl ccn504_set_qos +#endif + + /* Set the SMMU page size in the sACR register */ + ldr x1, =SMMU_BASE + ldr w0, [x1, #0x10] + orr w0, w0, #1 << 16 /* set sACR.pagesize to indicate 64K page */ + str w0, [x1, #0x10] + + /* Initialize GIC Secure Bank Status */ +#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3) + branch_if_slave x0, 1f + ldr x0, =GICD_BASE + bl gic_init_secure +1: +#ifdef CONFIG_GICV3 + ldr x0, =GICR_BASE + bl gic_init_secure_percpu +#elif defined(CONFIG_GICV2) + ldr x0, =GICD_BASE + ldr x1, =GICC_BASE + bl gic_init_secure_percpu +#endif +#endif + + branch_if_master x0, x1, 2f + +#if defined(CONFIG_MP) && defined(CONFIG_ARMV8_MULTIENTRY) + ldr x0, =secondary_boot_func + blr x0 +#endif + +2: +#ifdef CONFIG_FSL_TZPC_BP147 + /* Set Non Secure access for all devices protected via TZPC */ + ldr x1, =TZPCDECPROT_0_SET_BASE /* Decode Protection-0 Set Reg */ + orr w0, w0, #1 << 3 /* DCFG_RESET is accessible from NS world */ + str w0, [x1] + + isb + dsb sy +#endif + +#ifdef CONFIG_FSL_TZASC_400 + /* Set TZASC so that: + * a. We use only Region0 whose global secure write/read is EN + * b. We use only Region0 whose NSAID write/read is EN + * + * NOTE: As per the CCSR map doc, TZASC 3 and TZASC 4 are just + * placeholders. + */ + ldr x1, =TZASC_GATE_KEEPER(0) + ldr x0, [x1] /* Filter 0 Gate Keeper Register */ + orr x0, x0, #1 << 0 /* Set open_request for Filter 0 */ + str x0, [x1] + + ldr x1, =TZASC_GATE_KEEPER(1) + ldr x0, [x1] /* Filter 0 Gate Keeper Register */ + orr x0, x0, #1 << 0 /* Set open_request for Filter 0 */ + str x0, [x1] + + ldr x1, =TZASC_REGION_ATTRIBUTES_0(0) + ldr x0, [x1] /* Region-0 Attributes Register */ + orr x0, x0, #1 << 31 /* Set Sec global write en, Bit[31] */ + orr x0, x0, #1 << 30 /* Set Sec global read en, Bit[30] */ + str x0, [x1] + + ldr x1, =TZASC_REGION_ATTRIBUTES_0(1) + ldr x0, [x1] /* Region-1 Attributes Register */ + orr x0, x0, #1 << 31 /* Set Sec global write en, Bit[31] */ + orr x0, x0, #1 << 30 /* Set Sec global read en, Bit[30] */ + str x0, [x1] + + ldr x1, =TZASC_REGION_ID_ACCESS_0(0) + ldr w0, [x1] /* Region-0 Access Register */ + mov w0, #0xFFFFFFFF /* Set nsaid_wr_en and nsaid_rd_en */ + str w0, [x1] + + ldr x1, =TZASC_REGION_ID_ACCESS_0(1) + ldr w0, [x1] /* Region-1 Attributes Register */ + mov w0, #0xFFFFFFFF /* Set nsaid_wr_en and nsaid_rd_en */ + str w0, [x1] + + isb + dsb sy +#endif + mov lr, x29 /* Restore LR */ + ret +ENDPROC(lowlevel_init) + +hnf_pstate_poll: + /* x0 has the desired status, return 0 for success, 1 for timeout + * clobber x1, x2, x3, x4, x6, x7 + */ + mov x1, x0 + mov x7, #0 /* flag for timeout */ + mrs x3, cntpct_el0 /* read timer */ + add x3, x3, #1200 /* timeout after 100 microseconds */ + mov x0, #0x18 + movk x0, #0x420, lsl #16 /* HNF0_PSTATE_STATUS */ + mov w6, #8 /* HN-F node count */ +1: + ldr x2, [x0] + cmp x2, x1 /* check status */ + b.eq 2f + mrs x4, cntpct_el0 + cmp x4, x3 + b.ls 1b + mov x7, #1 /* timeout */ + b 3f +2: + add x0, x0, #0x10000 /* move to next node */ + subs w6, w6, #1 + cbnz w6, 1b +3: + mov x0, x7 + ret + +hnf_set_pstate: + /* x0 has the desired state, clobber x1, x2, x6 */ + mov x1, x0 + /* power state to SFONLY */ + mov w6, #8 /* HN-F node count */ + mov x0, #0x10 + movk x0, #0x420, lsl #16 /* HNF0_PSTATE_REQ */ +1: /* set pstate to sfonly */ + ldr x2, [x0] + and x2, x2, #0xfffffffffffffffc /* & HNFPSTAT_MASK */ + orr x2, x2, x1 + str x2, [x0] + add x0, x0, #0x10000 /* move to next node */ + subs w6, w6, #1 + cbnz w6, 1b + + ret + +ENTRY(__asm_flush_l3_cache) + /* + * Return status in x0 + * success 0 + * tmeout 1 for setting SFONLY, 2 for FAM, 3 for both + */ + mov x29, lr + mov x8, #0 + + dsb sy + mov x0, #0x1 /* HNFPSTAT_SFONLY */ + bl hnf_set_pstate + + mov x0, #0x4 /* SFONLY status */ + bl hnf_pstate_poll + cbz x0, 1f + mov x8, #1 /* timeout */ +1: + dsb sy + mov x0, #0x3 /* HNFPSTAT_FAM */ + bl hnf_set_pstate + + mov x0, #0xc /* FAM status */ + bl hnf_pstate_poll + cbz x0, 1f + add x8, x8, #0x2 +1: + mov x0, x8 + mov lr, x29 + ret +ENDPROC(__asm_flush_l3_cache) + +#ifdef CONFIG_MP + /* Keep literals not used by the secondary boot code outside it */ + .ltorg + + /* Using 64 bit alignment since the spin table is accessed as data */ + .align 4 + .global secondary_boot_code + /* Secondary Boot Code starts here */ +secondary_boot_code: + .global __spin_table +__spin_table: + .space CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE + + .align 2 +ENTRY(secondary_boot_func) + /* + * MPIDR_EL1 Fields: + * MPIDR[1:0] = AFF0_CPUID <- Core ID (0,1) + * MPIDR[7:2] = AFF0_RES + * MPIDR[15:8] = AFF1_CLUSTERID <- Cluster ID (0,1,2,3) + * MPIDR[23:16] = AFF2_CLUSTERID + * MPIDR[24] = MT + * MPIDR[29:25] = RES0 + * MPIDR[30] = U + * MPIDR[31] = ME + * MPIDR[39:32] = AFF3 + * + * Linear Processor ID (LPID) calculation from MPIDR_EL1: + * (We only use AFF0_CPUID and AFF1_CLUSTERID for now + * until AFF2_CLUSTERID and AFF3 have non-zero values) + * + * LPID = MPIDR[15:8] | MPIDR[1:0] + */ + mrs x0, mpidr_el1 + ubfm x1, x0, #8, #15 + ubfm x2, x0, #0, #1 + orr x10, x2, x1, lsl #2 /* x10 has LPID */ + ubfm x9, x0, #0, #15 /* x9 contains MPIDR[15:0] */ + /* + * offset of the spin table element for this core from start of spin + * table (each elem is padded to 64 bytes) + */ + lsl x1, x10, #6 + ldr x0, =__spin_table + /* physical address of this cpus spin table element */ + add x11, x1, x0 + + ldr x0, =__real_cntfrq + ldr x0, [x0] + msr cntfrq_el0, x0 /* set with real frequency */ + str x9, [x11, #16] /* LPID */ + mov x4, #1 + str x4, [x11, #8] /* STATUS */ + dsb sy +#if defined(CONFIG_GICV3) + gic_wait_for_interrupt_m x0 +#elif defined(CONFIG_GICV2) + ldr x0, =GICC_BASE + gic_wait_for_interrupt_m x0, w1 +#endif + + bl secondary_switch_to_el2 +#ifdef CONFIG_ARMV8_SWITCH_TO_EL1 + bl secondary_switch_to_el1 +#endif + +slave_cpu: + wfe + ldr x0, [x11] + cbz x0, slave_cpu +#ifndef CONFIG_ARMV8_SWITCH_TO_EL1 + mrs x1, sctlr_el2 +#else + mrs x1, sctlr_el1 +#endif + tbz x1, #25, cpu_is_le + rev x0, x0 /* BE to LE conversion */ +cpu_is_le: + br x0 /* branch to the given address */ +ENDPROC(secondary_boot_func) + +ENTRY(secondary_switch_to_el2) + switch_el x0, 1f, 0f, 0f +0: ret +1: armv8_switch_to_el2_m x0 +ENDPROC(secondary_switch_to_el2) + +ENTRY(secondary_switch_to_el1) + switch_el x0, 0f, 1f, 0f +0: ret +1: armv8_switch_to_el1_m x0, x1 +ENDPROC(secondary_switch_to_el1) + + /* Ensure that the literals used by the secondary boot code are + * assembled within it (this is required so that we can protect + * this area with a single memreserve region + */ + .ltorg + + /* 64 bit alignment for elements accessed as data */ + .align 4 + .global __real_cntfrq +__real_cntfrq: + .quad COUNTER_FREQUENCY + .globl __secondary_boot_code_size + .type __secondary_boot_code_size, %object + /* Secondary Boot Code ends here */ +__secondary_boot_code_size: + .quad .-secondary_boot_code +#endif diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ls1043a_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/ls1043a_serdes.c new file mode 100644 index 0000000000..e54d3899bb --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/ls1043a_serdes.c @@ -0,0 +1,86 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch/immap_lsch2.h> + +struct serdes_config { + u32 protocol; + u8 lanes[SRDS_MAX_LANES]; +}; + +static struct serdes_config serdes1_cfg_tbl[] = { + /* SerDes 1 */ + {0x1555, {XFI_FM1_MAC9, PCIE1, PCIE2, PCIE3} }, + {0x2555, {SGMII_2500_FM1_DTSEC9, PCIE1, PCIE2, PCIE3} }, + {0x4555, {QSGMII_FM1_A, PCIE1, PCIE2, PCIE3} }, + {0x4558, {QSGMII_FM1_A, PCIE1, PCIE2, SATA1} }, + {0x1355, {XFI_FM1_MAC9, SGMII_FM1_DTSEC2, PCIE2, PCIE3} }, + {0x2355, {SGMII_2500_FM1_DTSEC9, SGMII_FM1_DTSEC2, PCIE2, PCIE3} }, + {0x3335, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC5, + PCIE3} }, + {0x3355, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, PCIE2, PCIE3} }, + {0x3358, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, PCIE2, SATA1} }, + {0x3555, {SGMII_FM1_DTSEC9, PCIE1, PCIE2, PCIE3} }, + {0x3558, {SGMII_FM1_DTSEC9, PCIE1, PCIE2, SATA1} }, + {0x7000, {PCIE1, PCIE1, PCIE1, PCIE1} }, + {0x9998, {PCIE1, PCIE2, PCIE3, SATA1} }, + {0x6058, {PCIE1, PCIE1, PCIE2, SATA1} }, + {0x1455, {XFI_FM1_MAC9, QSGMII_FM1_A, PCIE2, PCIE3} }, + {0x2455, {SGMII_2500_FM1_DTSEC9, QSGMII_FM1_A, PCIE2, PCIE3} }, + {0x2255, {SGMII_2500_FM1_DTSEC9, SGMII_2500_FM1_DTSEC2, PCIE2, PCIE3} }, + {0x3333, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC5, + SGMII_FM1_DTSEC6} }, + {} +}; + +static struct serdes_config *serdes_cfg_tbl[] = { + serdes1_cfg_tbl, +}; + +enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane) +{ + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == cfg) + return ptr->lanes[lane]; + ptr++; + } + + return 0; +} + +int is_serdes_prtcl_valid(int serdes, u32 prtcl) +{ + int i; + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == prtcl) + break; + ptr++; + } + + if (!ptr->protocol) + return 0; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (ptr->lanes[i] != NONE) + return 1; + } + + return 0; +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ls2085a_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/ls2085a_serdes.c new file mode 100644 index 0000000000..ea3114cca4 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/ls2085a_serdes.c @@ -0,0 +1,116 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/fsl_serdes.h> + +struct serdes_config { + u8 protocol; + u8 lanes[SRDS_MAX_LANES]; +}; + +static struct serdes_config serdes1_cfg_tbl[] = { + /* SerDes 1 */ + {0x03, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2 } }, + {0x05, {PCIE2, PCIE2, PCIE2, PCIE2, SGMII4, SGMII3, SGMII2, SGMII1 } }, + {0x07, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x09, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0A, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0C, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0E, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x26, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, XFI2, XFI1 } }, + {0x28, {SGMII8, SGMII7, SGMII6, SGMII5, XFI4, XFI3, XFI2, XFI1 } }, + {0x2A, {XFI8, XFI7, XFI6, XFI5, XFI4, XFI3, XFI2, XFI1 } }, + {0x2B, {SGMII8, SGMII7, SGMII6, SGMII5, XAUI1, XAUI1, XAUI1, XAUI1 } }, + {0x32, {XAUI2, XAUI2, XAUI2, XAUI2, XAUI1, XAUI1, XAUI1, XAUI1 } }, + {0x33, {PCIE2, PCIE2, PCIE2, PCIE2, QSGMII_C, QSGMII_D, QSGMII_A, + QSGMII_B} }, + {0x35, {QSGMII_C, QSGMII_D, QSGMII_A, PCIE2, XFI4, XFI3, XFI2, XFI1 } }, + {} +}; +static struct serdes_config serdes2_cfg_tbl[] = { + /* SerDes 2 */ + {0x07, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x09, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0A, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0C, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0E, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x3D, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } }, + {0x3E, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } }, + {0x3F, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } }, + {0x40, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } }, + {0x41, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } }, + {0x42, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } }, + {0x43, {PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE, SATA1, SATA2 } }, + {0x44, {PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE, SATA1, SATA2 } }, + {0x45, {PCIE3, SGMII10, SGMII11, SGMII12, PCIE4, SGMII14, SGMII15, + SGMII16 } }, + {0x47, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, PCIE4, + PCIE4 } }, + {0x49, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1, + SATA2 } }, + {0x4A, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1, + SATA2 } }, + {} +}; + +static struct serdes_config *serdes_cfg_tbl[] = { + serdes1_cfg_tbl, + serdes2_cfg_tbl, +}; + +enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane) +{ + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == cfg) + return ptr->lanes[lane]; + ptr++; + } + + return 0; +} + +int is_serdes_prtcl_valid(int serdes, u32 prtcl) +{ + int i; + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == prtcl) + break; + ptr++; + } + + if (!ptr->protocol) + return 0; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (ptr->lanes[i] != NONE) + return 1; + } + + return 0; +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/mp.c b/arch/arm/cpu/armv8/fsl-layerscape/mp.c new file mode 100644 index 0000000000..0d600db090 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/mp.c @@ -0,0 +1,197 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/arch/mp.h> +#include <asm/arch/soc.h> + +DECLARE_GLOBAL_DATA_PTR; + +void *get_spin_tbl_addr(void) +{ + return &__spin_table; +} + +phys_addr_t determine_mp_bootpg(void) +{ + return (phys_addr_t)&secondary_boot_code; +} + +int fsl_layerscape_wake_seconday_cores(void) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); +#ifdef CONFIG_FSL_LSCH3 + struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR); +#elif defined(CONFIG_FSL_LSCH2) + struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR); +#endif + u32 cores, cpu_up_mask = 1; + int i, timeout = 10; + u64 *table = get_spin_tbl_addr(); + +#ifdef COUNTER_FREQUENCY_REAL + /* update for secondary cores */ + __real_cntfrq = COUNTER_FREQUENCY_REAL; + flush_dcache_range((unsigned long)&__real_cntfrq, + (unsigned long)&__real_cntfrq + 8); +#endif + + cores = cpu_mask(); + /* Clear spin table so that secondary processors + * observe the correct value after waking up from wfe. + */ + memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE); + flush_dcache_range((unsigned long)table, + (unsigned long)table + + (CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE)); + + printf("Waking secondary cores to start from %lx\n", gd->relocaddr); + +#ifdef CONFIG_FSL_LSCH3 + gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32)); + gur_out32(&gur->bootlocptrl, (u32)gd->relocaddr); + gur_out32(&gur->scratchrw[6], 1); + asm volatile("dsb st" : : : "memory"); + rst->brrl = cores; + asm volatile("dsb st" : : : "memory"); +#elif defined(CONFIG_FSL_LSCH2) + scfg_out32(&scfg->scratchrw[0], (u32)(gd->relocaddr >> 32)); + scfg_out32(&scfg->scratchrw[1], (u32)gd->relocaddr); + asm volatile("dsb st" : : : "memory"); + gur_out32(&gur->brrl, cores); + asm volatile("dsb st" : : : "memory"); + + /* Bootup online cores */ + scfg_out32(&scfg->corebcr, cores); +#endif + /* This is needed as a precautionary measure. + * If some code before this has accidentally released the secondary + * cores then the pre-bootloader code will trap them in a "wfe" unless + * the scratchrw[6] is set. In this case we need a sev here to get these + * cores moving again. + */ + asm volatile("sev"); + + while (timeout--) { + flush_dcache_range((unsigned long)table, (unsigned long)table + + CONFIG_MAX_CPUS * 64); + for (i = 1; i < CONFIG_MAX_CPUS; i++) { + if (table[i * WORDS_PER_SPIN_TABLE_ENTRY + + SPIN_TABLE_ELEM_STATUS_IDX]) + cpu_up_mask |= 1 << i; + } + if (hweight32(cpu_up_mask) == hweight32(cores)) + break; + udelay(10); + } + if (timeout <= 0) { + printf("Not all cores (0x%x) are up (0x%x)\n", + cores, cpu_up_mask); + return 1; + } + printf("All (%d) cores are up.\n", hweight32(cores)); + + return 0; +} + +int is_core_valid(unsigned int core) +{ + return !!((1 << core) & cpu_mask()); +} + +int is_core_online(u64 cpu_id) +{ + u64 *table; + int pos = id_to_core(cpu_id); + table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY; + return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1; +} + +int cpu_reset(int nr) +{ + puts("Feature is not implemented.\n"); + + return 0; +} + +int cpu_disable(int nr) +{ + puts("Feature is not implemented.\n"); + + return 0; +} + +int core_to_pos(int nr) +{ + u32 cores = cpu_mask(); + int i, count = 0; + + if (nr == 0) { + return 0; + } else if (nr >= hweight32(cores)) { + puts("Not a valid core number.\n"); + return -1; + } + + for (i = 1; i < 32; i++) { + if (is_core_valid(i)) { + count++; + if (count == nr) + break; + } + } + + return count; +} + +int cpu_status(int nr) +{ + u64 *table; + int pos; + + if (nr == 0) { + table = (u64 *)get_spin_tbl_addr(); + printf("table base @ 0x%p\n", table); + } else { + pos = core_to_pos(nr); + if (pos < 0) + return -1; + table = (u64 *)get_spin_tbl_addr() + pos * + WORDS_PER_SPIN_TABLE_ENTRY; + printf("table @ 0x%p\n", table); + printf(" addr - 0x%016llx\n", + table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]); + printf(" status - 0x%016llx\n", + table[SPIN_TABLE_ELEM_STATUS_IDX]); + printf(" lpid - 0x%016llx\n", + table[SPIN_TABLE_ELEM_LPID_IDX]); + } + + return 0; +} + +int cpu_release(int nr, int argc, char * const argv[]) +{ + u64 boot_addr; + u64 *table = (u64 *)get_spin_tbl_addr(); + int pos; + + pos = core_to_pos(nr); + if (pos <= 0) + return -1; + + table += pos * WORDS_PER_SPIN_TABLE_ENTRY; + boot_addr = simple_strtoull(argv[0], NULL, 16); + table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr; + flush_dcache_range((unsigned long)table, + (unsigned long)table + SPIN_TABLE_ELEM_SIZE); + asm volatile("dsb st"); + smp_kick_all_cpus(); /* only those with entry addr set will run */ + + return 0; +} diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c new file mode 100644 index 0000000000..637853d51f --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c @@ -0,0 +1,103 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fsl_ifc.h> +#include <asm/arch/soc.h> +#include <asm/io.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_LS2085A +static void erratum_a008751(void) +{ +#ifdef CONFIG_SYS_FSL_ERRATUM_A008751 + u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE; + + writel(0x27672b2a, scfg + SCFG_USB3PRM1CR / 4); +#endif +} + +static void erratum_rcw_src(void) +{ +#if defined(CONFIG_SPL) + u32 __iomem *dcfg_ccsr = (u32 __iomem *)DCFG_BASE; + u32 __iomem *dcfg_dcsr = (u32 __iomem *)DCFG_DCSR_BASE; + u32 val; + + val = in_le32(dcfg_ccsr + DCFG_PORSR1 / 4); + val &= ~DCFG_PORSR1_RCW_SRC; + val |= DCFG_PORSR1_RCW_SRC_NOR; + out_le32(dcfg_dcsr + DCFG_DCSR_PORCR1 / 4, val); +#endif +} + +#define I2C_DEBUG_REG 0x6 +#define I2C_GLITCH_EN 0x8 +/* + * This erratum requires setting glitch_en bit to enable + * digital glitch filter to improve clock stability. + */ +static void erratum_a009203(void) +{ + u8 __iomem *ptr; +#ifdef CONFIG_SYS_I2C +#ifdef I2C1_BASE_ADDR + ptr = (u8 __iomem *)(I2C1_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#ifdef I2C2_BASE_ADDR + ptr = (u8 __iomem *)(I2C2_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#ifdef I2C3_BASE_ADDR + ptr = (u8 __iomem *)(I2C3_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#ifdef I2C4_BASE_ADDR + ptr = (u8 __iomem *)(I2C4_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#endif +} + +void fsl_lsch3_early_init_f(void) +{ + erratum_a008751(); + erratum_rcw_src(); + init_early_memctl_regs(); /* tighten IFC timing */ + erratum_a009203(); +} + +#elif defined(CONFIG_LS1043A) +void fsl_lsch2_early_init_f(void) +{ + struct ccsr_cci400 *cci = (struct ccsr_cci400 *)CONFIG_SYS_CCI400_ADDR; + +#ifdef CONFIG_FSL_IFC + init_early_memctl_regs(); /* tighten IFC timing */ +#endif + + /* + * Enable snoop requests and DVM message requests for + * Slave insterface S4 (A53 core cluster) + */ + out_le32(&cci->slave[4].snoop_ctrl, + CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN); +} +#endif + +#ifdef CONFIG_BOARD_LATE_INIT +int board_late_init(void) +{ + return 0; +} +#endif diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spl.c b/arch/arm/cpu/armv8/fsl-layerscape/spl.c new file mode 100644 index 0000000000..ba551aaa6e --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c @@ -0,0 +1,79 @@ +/* + * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <spl.h> +#include <asm/io.h> +#include <fsl_ifc.h> +#include <fsl_csu.h> +#include <i2c.h> + +DECLARE_GLOBAL_DATA_PTR; + +u32 spl_boot_device(void) +{ +#ifdef CONFIG_SPL_MMC_SUPPORT + return BOOT_DEVICE_MMC1; +#endif +#ifdef CONFIG_SPL_NAND_SUPPORT + return BOOT_DEVICE_NAND; +#endif + return 0; +} + +u32 spl_boot_mode(void) +{ + switch (spl_boot_device()) { + case BOOT_DEVICE_MMC1: +#ifdef CONFIG_SPL_FAT_SUPPORT + return MMCSD_MODE_FAT; +#else + return MMCSD_MODE_RAW; +#endif + case BOOT_DEVICE_NAND: + return 0; + default: + puts("spl: error: unsupported device\n"); + hang(); + } +} + +#ifdef CONFIG_SPL_BUILD +void board_init_f(ulong dummy) +{ + /* Set global data pointer */ + gd = &gdata; + /* Clear global data */ + memset((void *)gd, 0, sizeof(gd_t)); +#ifdef CONFIG_LS2085A + arch_cpu_init(); +#endif +#ifdef CONFIG_FSL_IFC + init_early_memctl_regs(); +#endif + board_early_init_f(); + timer_init(); +#ifdef CONFIG_LS2085A + env_init(); +#endif + get_clocks(); + + preloader_console_init(); + +#ifdef CONFIG_SPL_I2C_SUPPORT + i2c_init_all(); +#endif + dram_init(); + + /* Clear the BSS */ + memset(__bss_start, 0, __bss_end - __bss_start); + +#ifdef CONFIG_LAYERSCAPE_NS_ACCESS + enable_layerscape_ns_access(); +#endif + board_init_r(NULL, 0); +} +#endif |