GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
if ARM64
|
||||
|
||||
config ARMV8_SPL_EXCEPTION_VECTORS
|
||||
bool "Install crash dump exception vectors"
|
||||
depends on SPL
|
||||
default n
|
||||
help
|
||||
The default exception vector table is only used for the crash
|
||||
dump, but still takes quite a lot of space in the image size.
|
||||
|
||||
Say N here if you are running out of code space in the image
|
||||
and want to save some space at the cost of less debugging info.
|
||||
|
||||
config ARMV8_MULTIENTRY
|
||||
bool "Enable multiple CPUs to enter into U-Boot"
|
||||
|
||||
config ARMV8_SET_SMPEN
|
||||
bool "Enable data coherency with other cores in cluster"
|
||||
help
|
||||
Say Y here if there is not any trust firmware to set
|
||||
CPUECTLR_EL1.SMPEN bit before U-Boot.
|
||||
|
||||
For A53, it enables data coherency with other cores in the
|
||||
cluster, and for A57/A72, it enables receiving of instruction
|
||||
cache and TLB maintenance operations.
|
||||
Cortex A53/57/72 cores require CPUECTLR_EL1.SMPEN set even
|
||||
for single core systems. Unfortunately write access to this
|
||||
register may be controlled by EL3/EL2 firmware. To be more
|
||||
precise, by default (if there is EL2/EL3 firmware running)
|
||||
this register is RO for NS EL1.
|
||||
This switch can be used to avoid writing to CPUECTLR_EL1,
|
||||
it can be safely enabled when EL2/EL3 initialized SMPEN bit
|
||||
or when CPU implementation doesn't include that register.
|
||||
|
||||
config ARMV8_SPIN_TABLE
|
||||
bool "Support spin-table enable method"
|
||||
depends on ARMV8_MULTIENTRY && OF_LIBFDT
|
||||
help
|
||||
Say Y here to support "spin-table" enable method for booting Linux.
|
||||
|
||||
To use this feature, you must do:
|
||||
- Specify enable-method = "spin-table" in each CPU node in the
|
||||
Device Tree you are using to boot the kernel
|
||||
- Bring secondary CPUs into U-Boot proper in a board specific
|
||||
manner. This must be done *after* relocation. Otherwise, the
|
||||
secondary CPUs will spin in unprotected memory area because the
|
||||
master CPU protects the relocated spin code.
|
||||
|
||||
U-Boot automatically does:
|
||||
- Set "cpu-release-addr" property of each CPU node
|
||||
(overwrites it if already exists).
|
||||
- Reserve the code for the spin-table and the release address
|
||||
via a /memreserve/ region in the Device Tree.
|
||||
|
||||
menu "ARMv8 secure monitor firmware"
|
||||
config ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
bool "Enable ARMv8 secure monitor firmware framework support"
|
||||
select FIT
|
||||
select OF_LIBFDT
|
||||
help
|
||||
This framework is aimed at making secure monitor firmware load
|
||||
process brief.
|
||||
Note: Only FIT format image is supported.
|
||||
You should prepare and provide the below information:
|
||||
- Address of secure firmware.
|
||||
- Address to hold the return address from secure firmware.
|
||||
- Secure firmware FIT image related information.
|
||||
Such as: SEC_FIRMWARE_FIT_IMAGE and SEC_FIRMWARE_FIT_CNF_NAME
|
||||
- The target exception level that secure monitor firmware will
|
||||
return to.
|
||||
|
||||
config SPL_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
bool "Enable ARMv8 secure monitor firmware framework support for SPL"
|
||||
select SPL_FIT
|
||||
select SPL_OF_LIBFDT
|
||||
help
|
||||
Say Y here to support this framework in SPL phase.
|
||||
|
||||
config SEC_FIRMWARE_ARMV8_PSCI
|
||||
bool "PSCI implementation in secure monitor firmware"
|
||||
depends on ARMV8_SEC_FIRMWARE_SUPPORT || SPL_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
help
|
||||
This config enables the ARMv8 PSCI implementation in secure monitor
|
||||
firmware. This is a private PSCI implementation and different from
|
||||
those implemented under the common ARMv8 PSCI framework.
|
||||
|
||||
config ARMV8_SEC_FIRMWARE_ERET_ADDR_REVERT
|
||||
bool "ARMv8 secure monitor firmware ERET address byteorder swap"
|
||||
depends on ARMV8_SEC_FIRMWARE_SUPPORT || SPL_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
help
|
||||
Say Y here when the endianness of the register or memory holding the
|
||||
Secure firmware exception return address is different with core's.
|
||||
|
||||
endmenu
|
||||
|
||||
config PSCI_RESET
|
||||
bool "Use PSCI for reset and shutdown"
|
||||
default y
|
||||
select ARM_SMCCC if OF_CONTROL
|
||||
depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \
|
||||
!TARGET_LS2080A_SIMU && !TARGET_LS2080AQDS && \
|
||||
!TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \
|
||||
!TARGET_LS1088ARDB && !TARGET_LS1088AQDS && \
|
||||
!TARGET_LS1012ARDB && !TARGET_LS1012AFRDM && \
|
||||
!TARGET_LS1012A2G5RDB && !TARGET_LS1012AQDS && \
|
||||
!TARGET_LS1012AFRWY && \
|
||||
!TARGET_LS1028ARDB && !TARGET_LS1028AQDS && \
|
||||
!TARGET_LS1043ARDB && !TARGET_LS1043AQDS && \
|
||||
!TARGET_LS1046ARDB && !TARGET_LS1046AQDS && \
|
||||
!TARGET_LS1046AFRWY && \
|
||||
!TARGET_LS2081ARDB && !TARGET_LX2160ARDB && \
|
||||
!TARGET_LX2160AQDS && \
|
||||
!ARCH_UNIPHIER && !TARGET_S32V234EVB
|
||||
help
|
||||
Most armv8 systems have PSCI support enabled in EL3, either through
|
||||
ARM Trusted Firmware or other firmware.
|
||||
|
||||
On these systems, we do not need to implement system reset manually,
|
||||
but can instead rely on higher level firmware to deal with it.
|
||||
|
||||
Select Y here to make use of PSCI calls for system reset
|
||||
|
||||
config ARMV8_PSCI
|
||||
bool "Enable PSCI support" if EXPERT
|
||||
default n
|
||||
help
|
||||
PSCI is Power State Coordination Interface defined by ARM.
|
||||
The PSCI in U-boot provides a general framework and each platform
|
||||
can implement their own specific PSCI functions.
|
||||
Say Y here to enable PSCI support on ARMv8 platform.
|
||||
|
||||
config ARMV8_PSCI_NR_CPUS
|
||||
int "Maximum supported CPUs for PSCI"
|
||||
depends on ARMV8_PSCI
|
||||
default 4
|
||||
help
|
||||
The maximum number of CPUs supported in the PSCI firmware.
|
||||
It is no problem to set a larger value than the number of CPUs in
|
||||
the actual hardware implementation.
|
||||
|
||||
config ARMV8_PSCI_CPUS_PER_CLUSTER
|
||||
int "Number of CPUs per cluster"
|
||||
depends on ARMV8_PSCI
|
||||
default 0
|
||||
help
|
||||
The number of CPUs per cluster, suppose each cluster has same number
|
||||
of CPU cores, platforms with asymmetric clusters don't apply here.
|
||||
A value 0 or no definition of it works for single cluster system.
|
||||
System with multi-cluster should difine their own exact value.
|
||||
|
||||
config ARMV8_EA_EL3_FIRST
|
||||
bool "External aborts and SError interrupt exception are taken in EL3"
|
||||
default n
|
||||
help
|
||||
Exception handling at all exception levels for External Abort and
|
||||
SError interrupt exception are taken in EL3.
|
||||
|
||||
if SYS_HAS_ARMV8_SECURE_BASE
|
||||
|
||||
config ARMV8_SECURE_BASE
|
||||
hex "Secure address for PSCI image"
|
||||
depends on ARMV8_PSCI
|
||||
help
|
||||
Address for placing the PSCI text, data and stack sections.
|
||||
If not defined, the PSCI sections are placed together with the u-boot
|
||||
but platform can choose to place PSCI code image separately in other
|
||||
places such as some secure RAM built-in SOC etc.
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,37 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2000-2003
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
extra-y := start.o
|
||||
|
||||
obj-y += cpu.o
|
||||
ifndef CONFIG_$(SPL_TPL_)TIMER
|
||||
obj-$(CONFIG_SYS_ARCH_TIMER) += generic_timer.o
|
||||
endif
|
||||
obj-y += cache_v8.o
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_ARMV8_SPL_EXCEPTION_VECTORS) += exceptions.o
|
||||
else
|
||||
obj-y += exceptions.o
|
||||
obj-y += exception_level.o
|
||||
endif
|
||||
obj-y += cache.o
|
||||
obj-y += tlb.o
|
||||
obj-y += transition.o
|
||||
ifndef CONFIG_ARMV8_PSCI
|
||||
obj-y += fwcall.o
|
||||
endif
|
||||
obj-y += cpu-dt.o
|
||||
obj-$(CONFIG_ARM_SMCCC) += smccc-call.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
|
||||
endif
|
||||
obj-$(CONFIG_$(SPL_)ARMV8_SEC_FIRMWARE_SUPPORT) += sec_firmware.o sec_firmware_asm.o
|
||||
|
||||
obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
|
||||
obj-$(CONFIG_S32V234) += s32v234/
|
||||
obj-$(CONFIG_TARGET_HIKEY) += hisilicon/
|
||||
obj-$(CONFIG_ARMV8_PSCI) += psci.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += lowlevel_init.o
|
||||
@@ -0,0 +1,267 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* This file is based on sample code from ARMv8 ARM.
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <asm/macro.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* void __asm_dcache_level(level)
|
||||
*
|
||||
* flush or invalidate one level cache.
|
||||
*
|
||||
* x0: cache level
|
||||
* x1: 0 clean & invalidate, 1 invalidate only
|
||||
* x2~x9: clobbered
|
||||
*/
|
||||
.pushsection .text.__asm_dcache_level, "ax"
|
||||
ENTRY(__asm_dcache_level)
|
||||
lsl x12, x0, #1
|
||||
msr csselr_el1, x12 /* select cache level */
|
||||
isb /* sync change of cssidr_el1 */
|
||||
mrs x6, ccsidr_el1 /* read the new cssidr_el1 */
|
||||
and x2, x6, #7 /* x2 <- log2(cache line size)-4 */
|
||||
add x2, x2, #4 /* x2 <- log2(cache line size) */
|
||||
mov x3, #0x3ff
|
||||
and x3, x3, x6, lsr #3 /* x3 <- max number of #ways */
|
||||
clz w5, w3 /* bit position of #ways */
|
||||
mov x4, #0x7fff
|
||||
and x4, x4, x6, lsr #13 /* x4 <- max number of #sets */
|
||||
/* x12 <- cache level << 1 */
|
||||
/* x2 <- line length offset */
|
||||
/* x3 <- number of cache ways - 1 */
|
||||
/* x4 <- number of cache sets - 1 */
|
||||
/* x5 <- bit position of #ways */
|
||||
|
||||
loop_set:
|
||||
mov x6, x3 /* x6 <- working copy of #ways */
|
||||
loop_way:
|
||||
lsl x7, x6, x5
|
||||
orr x9, x12, x7 /* map way and level to cisw value */
|
||||
lsl x7, x4, x2
|
||||
orr x9, x9, x7 /* map set number to cisw value */
|
||||
tbz w1, #0, 1f
|
||||
dc isw, x9
|
||||
b 2f
|
||||
1: dc cisw, x9 /* clean & invalidate by set/way */
|
||||
2: subs x6, x6, #1 /* decrement the way */
|
||||
b.ge loop_way
|
||||
subs x4, x4, #1 /* decrement the set */
|
||||
b.ge loop_set
|
||||
|
||||
ret
|
||||
ENDPROC(__asm_dcache_level)
|
||||
.popsection
|
||||
|
||||
/*
|
||||
* void __asm_flush_dcache_all(int invalidate_only)
|
||||
*
|
||||
* x0: 0 clean & invalidate, 1 invalidate only
|
||||
*
|
||||
* flush or invalidate all data cache by SET/WAY.
|
||||
*/
|
||||
.pushsection .text.__asm_dcache_all, "ax"
|
||||
ENTRY(__asm_dcache_all)
|
||||
mov x1, x0
|
||||
dsb sy
|
||||
mrs x10, clidr_el1 /* read clidr_el1 */
|
||||
lsr x11, x10, #24
|
||||
and x11, x11, #0x7 /* x11 <- loc */
|
||||
cbz x11, finished /* if loc is 0, exit */
|
||||
mov x15, lr
|
||||
mov x0, #0 /* start flush at cache level 0 */
|
||||
/* x0 <- cache level */
|
||||
/* x10 <- clidr_el1 */
|
||||
/* x11 <- loc */
|
||||
/* x15 <- return address */
|
||||
|
||||
loop_level:
|
||||
lsl x12, x0, #1
|
||||
add x12, x12, x0 /* x0 <- tripled cache level */
|
||||
lsr x12, x10, x12
|
||||
and x12, x12, #7 /* x12 <- cache type */
|
||||
cmp x12, #2
|
||||
b.lt skip /* skip if no cache or icache */
|
||||
bl __asm_dcache_level /* x1 = 0 flush, 1 invalidate */
|
||||
skip:
|
||||
add x0, x0, #1 /* increment cache level */
|
||||
cmp x11, x0
|
||||
b.gt loop_level
|
||||
|
||||
mov x0, #0
|
||||
msr csselr_el1, x0 /* restore csselr_el1 */
|
||||
dsb sy
|
||||
isb
|
||||
mov lr, x15
|
||||
|
||||
finished:
|
||||
ret
|
||||
ENDPROC(__asm_dcache_all)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__asm_flush_dcache_all, "ax"
|
||||
ENTRY(__asm_flush_dcache_all)
|
||||
mov x0, #0
|
||||
b __asm_dcache_all
|
||||
ENDPROC(__asm_flush_dcache_all)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__asm_invalidate_dcache_all, "ax"
|
||||
ENTRY(__asm_invalidate_dcache_all)
|
||||
mov x0, #0x1
|
||||
b __asm_dcache_all
|
||||
ENDPROC(__asm_invalidate_dcache_all)
|
||||
.popsection
|
||||
|
||||
/*
|
||||
* void __asm_flush_dcache_range(start, end)
|
||||
*
|
||||
* clean & invalidate data cache in the range
|
||||
*
|
||||
* x0: start address
|
||||
* x1: end address
|
||||
*/
|
||||
.pushsection .text.__asm_flush_dcache_range, "ax"
|
||||
ENTRY(__asm_flush_dcache_range)
|
||||
mrs x3, ctr_el0
|
||||
lsr x3, x3, #16
|
||||
and x3, x3, #0xf
|
||||
mov x2, #4
|
||||
lsl x2, x2, x3 /* cache line size */
|
||||
|
||||
/* x2 <- minimal cache line size in cache system */
|
||||
sub x3, x2, #1
|
||||
bic x0, x0, x3
|
||||
1: dc civac, x0 /* clean & invalidate data or unified cache */
|
||||
add x0, x0, x2
|
||||
cmp x0, x1
|
||||
b.lo 1b
|
||||
dsb sy
|
||||
ret
|
||||
ENDPROC(__asm_flush_dcache_range)
|
||||
.popsection
|
||||
/*
|
||||
* void __asm_invalidate_dcache_range(start, end)
|
||||
*
|
||||
* invalidate data cache in the range
|
||||
*
|
||||
* x0: start address
|
||||
* x1: end address
|
||||
*/
|
||||
.pushsection .text.__asm_invalidate_dcache_range, "ax"
|
||||
ENTRY(__asm_invalidate_dcache_range)
|
||||
mrs x3, ctr_el0
|
||||
ubfm x3, x3, #16, #19
|
||||
mov x2, #4
|
||||
lsl x2, x2, x3 /* cache line size */
|
||||
|
||||
/* x2 <- minimal cache line size in cache system */
|
||||
sub x3, x2, #1
|
||||
bic x0, x0, x3
|
||||
1: dc ivac, x0 /* invalidate data or unified cache */
|
||||
add x0, x0, x2
|
||||
cmp x0, x1
|
||||
b.lo 1b
|
||||
dsb sy
|
||||
ret
|
||||
ENDPROC(__asm_invalidate_dcache_range)
|
||||
.popsection
|
||||
|
||||
/*
|
||||
* void __asm_invalidate_icache_all(void)
|
||||
*
|
||||
* invalidate all tlb entries.
|
||||
*/
|
||||
.pushsection .text.__asm_invalidate_icache_all, "ax"
|
||||
ENTRY(__asm_invalidate_icache_all)
|
||||
ic ialluis
|
||||
isb sy
|
||||
ret
|
||||
ENDPROC(__asm_invalidate_icache_all)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__asm_invalidate_l3_dcache, "ax"
|
||||
ENTRY(__asm_invalidate_l3_dcache)
|
||||
mov x0, #0 /* return status as success */
|
||||
ret
|
||||
ENDPROC(__asm_invalidate_l3_dcache)
|
||||
.weak __asm_invalidate_l3_dcache
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__asm_flush_l3_dcache, "ax"
|
||||
ENTRY(__asm_flush_l3_dcache)
|
||||
mov x0, #0 /* return status as success */
|
||||
ret
|
||||
ENDPROC(__asm_flush_l3_dcache)
|
||||
.weak __asm_flush_l3_dcache
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__asm_invalidate_l3_icache, "ax"
|
||||
ENTRY(__asm_invalidate_l3_icache)
|
||||
mov x0, #0 /* return status as success */
|
||||
ret
|
||||
ENDPROC(__asm_invalidate_l3_icache)
|
||||
.weak __asm_invalidate_l3_icache
|
||||
.popsection
|
||||
|
||||
/*
|
||||
* void __asm_switch_ttbr(ulong new_ttbr)
|
||||
*
|
||||
* Safely switches to a new page table.
|
||||
*/
|
||||
.pushsection .text.__asm_switch_ttbr, "ax"
|
||||
ENTRY(__asm_switch_ttbr)
|
||||
/* x2 = SCTLR (alive throghout the function) */
|
||||
switch_el x4, 3f, 2f, 1f
|
||||
3: mrs x2, sctlr_el3
|
||||
b 0f
|
||||
2: mrs x2, sctlr_el2
|
||||
b 0f
|
||||
1: mrs x2, sctlr_el1
|
||||
0:
|
||||
|
||||
/* Unset CR_M | CR_C | CR_I from SCTLR to disable all caches */
|
||||
movn x1, #(CR_M | CR_C | CR_I)
|
||||
and x1, x2, x1
|
||||
switch_el x4, 3f, 2f, 1f
|
||||
3: msr sctlr_el3, x1
|
||||
b 0f
|
||||
2: msr sctlr_el2, x1
|
||||
b 0f
|
||||
1: msr sctlr_el1, x1
|
||||
0: isb
|
||||
|
||||
/* This call only clobbers x30 (lr) and x9 (unused) */
|
||||
mov x3, x30
|
||||
bl __asm_invalidate_tlb_all
|
||||
|
||||
/* From here on we're running safely with caches disabled */
|
||||
|
||||
/* Set TTBR to our first argument */
|
||||
switch_el x4, 3f, 2f, 1f
|
||||
3: msr ttbr0_el3, x0
|
||||
b 0f
|
||||
2: msr ttbr0_el2, x0
|
||||
b 0f
|
||||
1: msr ttbr0_el1, x0
|
||||
0: isb
|
||||
|
||||
/* Restore original SCTLR and thus enable caches again */
|
||||
switch_el x4, 3f, 2f, 1f
|
||||
3: msr sctlr_el3, x2
|
||||
b 0f
|
||||
2: msr sctlr_el2, x2
|
||||
b 0f
|
||||
1: msr sctlr_el1, x2
|
||||
0: isb
|
||||
|
||||
ret x3
|
||||
ENDPROC(__asm_switch_ttbr)
|
||||
.popsection
|
||||
@@ -0,0 +1,753 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* (C) Copyright 2016
|
||||
* Alexander Graf <agraf@suse.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
|
||||
|
||||
/*
|
||||
* With 4k page granule, a virtual address is split into 4 lookup parts
|
||||
* spanning 9 bits each:
|
||||
*
|
||||
* _______________________________________________
|
||||
* | | | | | | |
|
||||
* | 0 | Lv0 | Lv1 | Lv2 | Lv3 | off |
|
||||
* |_______|_______|_______|_______|_______|_______|
|
||||
* 63-48 47-39 38-30 29-21 20-12 11-00
|
||||
*
|
||||
* mask page size
|
||||
*
|
||||
* Lv0: FF8000000000 --
|
||||
* Lv1: 7FC0000000 1G
|
||||
* Lv2: 3FE00000 2M
|
||||
* Lv3: 1FF000 4K
|
||||
* off: FFF
|
||||
*/
|
||||
|
||||
u64 get_tcr(int el, u64 *pips, u64 *pva_bits)
|
||||
{
|
||||
u64 max_addr = 0;
|
||||
u64 ips, va_bits;
|
||||
u64 tcr;
|
||||
int i;
|
||||
|
||||
/* Find the largest address we need to support */
|
||||
for (i = 0; mem_map[i].size || mem_map[i].attrs; i++)
|
||||
max_addr = max(max_addr, mem_map[i].virt + mem_map[i].size);
|
||||
|
||||
/* Calculate the maximum physical (and thus virtual) address */
|
||||
if (max_addr > (1ULL << 44)) {
|
||||
ips = 5;
|
||||
va_bits = 48;
|
||||
} else if (max_addr > (1ULL << 42)) {
|
||||
ips = 4;
|
||||
va_bits = 44;
|
||||
} else if (max_addr > (1ULL << 40)) {
|
||||
ips = 3;
|
||||
va_bits = 42;
|
||||
} else if (max_addr > (1ULL << 36)) {
|
||||
ips = 2;
|
||||
va_bits = 40;
|
||||
} else if (max_addr > (1ULL << 32)) {
|
||||
ips = 1;
|
||||
va_bits = 36;
|
||||
} else {
|
||||
ips = 0;
|
||||
va_bits = 32;
|
||||
}
|
||||
|
||||
if (el == 1) {
|
||||
tcr = TCR_EL1_RSVD | (ips << 32) | TCR_EPD1_DISABLE;
|
||||
} else if (el == 2) {
|
||||
tcr = TCR_EL2_RSVD | (ips << 16);
|
||||
} else {
|
||||
tcr = TCR_EL3_RSVD | (ips << 16);
|
||||
}
|
||||
|
||||
/* PTWs cacheable, inner/outer WBWA and inner shareable */
|
||||
tcr |= TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA;
|
||||
tcr |= TCR_T0SZ(va_bits);
|
||||
|
||||
if (pips)
|
||||
*pips = ips;
|
||||
if (pva_bits)
|
||||
*pva_bits = va_bits;
|
||||
|
||||
return tcr;
|
||||
}
|
||||
|
||||
#define MAX_PTE_ENTRIES 512
|
||||
|
||||
static int pte_type(u64 *pte)
|
||||
{
|
||||
return *pte & PTE_TYPE_MASK;
|
||||
}
|
||||
|
||||
/* Returns the LSB number for a PTE on level <level> */
|
||||
static int level2shift(int level)
|
||||
{
|
||||
/* Page is 12 bits wide, every level translates 9 bits */
|
||||
return (12 + 9 * (3 - level));
|
||||
}
|
||||
|
||||
static u64 *find_pte(u64 addr, int level)
|
||||
{
|
||||
int start_level = 0;
|
||||
u64 *pte;
|
||||
u64 idx;
|
||||
u64 va_bits;
|
||||
int i;
|
||||
|
||||
debug("addr=%llx level=%d\n", addr, level);
|
||||
|
||||
get_tcr(0, NULL, &va_bits);
|
||||
if (va_bits < 39)
|
||||
start_level = 1;
|
||||
|
||||
if (level < start_level)
|
||||
return NULL;
|
||||
|
||||
/* Walk through all page table levels to find our PTE */
|
||||
pte = (u64*)gd->arch.tlb_addr;
|
||||
for (i = start_level; i < 4; i++) {
|
||||
idx = (addr >> level2shift(i)) & 0x1FF;
|
||||
pte += idx;
|
||||
debug("idx=%llx PTE %p at level %d: %llx\n", idx, pte, i, *pte);
|
||||
|
||||
/* Found it */
|
||||
if (i == level)
|
||||
return pte;
|
||||
/* PTE is no table (either invalid or block), can't traverse */
|
||||
if (pte_type(pte) != PTE_TYPE_TABLE)
|
||||
return NULL;
|
||||
/* Off to the next level */
|
||||
pte = (u64*)(*pte & 0x0000fffffffff000ULL);
|
||||
}
|
||||
|
||||
/* Should never reach here */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns and creates a new full table (512 entries) */
|
||||
static u64 *create_table(void)
|
||||
{
|
||||
u64 *new_table = (u64*)gd->arch.tlb_fillptr;
|
||||
u64 pt_len = MAX_PTE_ENTRIES * sizeof(u64);
|
||||
|
||||
/* Allocate MAX_PTE_ENTRIES pte entries */
|
||||
gd->arch.tlb_fillptr += pt_len;
|
||||
|
||||
if (gd->arch.tlb_fillptr - gd->arch.tlb_addr > gd->arch.tlb_size)
|
||||
panic("Insufficient RAM for page table: 0x%lx > 0x%lx. "
|
||||
"Please increase the size in get_page_table_size()",
|
||||
gd->arch.tlb_fillptr - gd->arch.tlb_addr,
|
||||
gd->arch.tlb_size);
|
||||
|
||||
/* Mark all entries as invalid */
|
||||
memset(new_table, 0, pt_len);
|
||||
|
||||
return new_table;
|
||||
}
|
||||
|
||||
static void set_pte_table(u64 *pte, u64 *table)
|
||||
{
|
||||
/* Point *pte to the new table */
|
||||
debug("Setting %p to addr=%p\n", pte, table);
|
||||
*pte = PTE_TYPE_TABLE | (ulong)table;
|
||||
}
|
||||
|
||||
/* Splits a block PTE into table with subpages spanning the old block */
|
||||
static void split_block(u64 *pte, int level)
|
||||
{
|
||||
u64 old_pte = *pte;
|
||||
u64 *new_table;
|
||||
u64 i = 0;
|
||||
/* level describes the parent level, we need the child ones */
|
||||
int levelshift = level2shift(level + 1);
|
||||
|
||||
if (pte_type(pte) != PTE_TYPE_BLOCK)
|
||||
panic("PTE %p (%llx) is not a block. Some driver code wants to "
|
||||
"modify dcache settings for an range not covered in "
|
||||
"mem_map.", pte, old_pte);
|
||||
|
||||
new_table = create_table();
|
||||
debug("Splitting pte %p (%llx) into %p\n", pte, old_pte, new_table);
|
||||
|
||||
for (i = 0; i < MAX_PTE_ENTRIES; i++) {
|
||||
new_table[i] = old_pte | (i << levelshift);
|
||||
|
||||
/* Level 3 block PTEs have the table type */
|
||||
if ((level + 1) == 3)
|
||||
new_table[i] |= PTE_TYPE_TABLE;
|
||||
|
||||
debug("Setting new_table[%lld] = %llx\n", i, new_table[i]);
|
||||
}
|
||||
|
||||
/* Set the new table into effect */
|
||||
set_pte_table(pte, new_table);
|
||||
}
|
||||
|
||||
/* Add one mm_region map entry to the page tables */
|
||||
static void add_map(struct mm_region *map)
|
||||
{
|
||||
u64 *pte;
|
||||
u64 virt = map->virt;
|
||||
u64 phys = map->phys;
|
||||
u64 size = map->size;
|
||||
u64 attrs = map->attrs | PTE_TYPE_BLOCK | PTE_BLOCK_AF;
|
||||
u64 blocksize;
|
||||
int level;
|
||||
u64 *new_table;
|
||||
|
||||
while (size) {
|
||||
pte = find_pte(virt, 0);
|
||||
if (pte && (pte_type(pte) == PTE_TYPE_FAULT)) {
|
||||
debug("Creating table for virt 0x%llx\n", virt);
|
||||
new_table = create_table();
|
||||
set_pte_table(pte, new_table);
|
||||
}
|
||||
|
||||
for (level = 1; level < 4; level++) {
|
||||
pte = find_pte(virt, level);
|
||||
if (!pte)
|
||||
panic("pte not found\n");
|
||||
|
||||
blocksize = 1ULL << level2shift(level);
|
||||
debug("Checking if pte fits for virt=%llx size=%llx blocksize=%llx\n",
|
||||
virt, size, blocksize);
|
||||
if (size >= blocksize && !(virt & (blocksize - 1))) {
|
||||
/* Page fits, create block PTE */
|
||||
debug("Setting PTE %p to block virt=%llx\n",
|
||||
pte, virt);
|
||||
if (level == 3)
|
||||
*pte = phys | attrs | PTE_TYPE_PAGE;
|
||||
else
|
||||
*pte = phys | attrs;
|
||||
virt += blocksize;
|
||||
phys += blocksize;
|
||||
size -= blocksize;
|
||||
break;
|
||||
} else if (pte_type(pte) == PTE_TYPE_FAULT) {
|
||||
/* Page doesn't fit, create subpages */
|
||||
debug("Creating subtable for virt 0x%llx blksize=%llx\n",
|
||||
virt, blocksize);
|
||||
new_table = create_table();
|
||||
set_pte_table(pte, new_table);
|
||||
} else if (pte_type(pte) == PTE_TYPE_BLOCK) {
|
||||
debug("Split block into subtable for virt 0x%llx blksize=0x%llx\n",
|
||||
virt, blocksize);
|
||||
split_block(pte, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum pte_type {
|
||||
PTE_INVAL,
|
||||
PTE_BLOCK,
|
||||
PTE_LEVEL,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a recursively called function to count the number of
|
||||
* page tables we need to cover a particular PTE range. If you
|
||||
* call this with level = -1 you basically get the full 48 bit
|
||||
* coverage.
|
||||
*/
|
||||
static int count_required_pts(u64 addr, int level, u64 maxaddr)
|
||||
{
|
||||
int levelshift = level2shift(level);
|
||||
u64 levelsize = 1ULL << levelshift;
|
||||
u64 levelmask = levelsize - 1;
|
||||
u64 levelend = addr + levelsize;
|
||||
int r = 0;
|
||||
int i;
|
||||
enum pte_type pte_type = PTE_INVAL;
|
||||
|
||||
for (i = 0; mem_map[i].size || mem_map[i].attrs; i++) {
|
||||
struct mm_region *map = &mem_map[i];
|
||||
u64 start = map->virt;
|
||||
u64 end = start + map->size;
|
||||
|
||||
/* Check if the PTE would overlap with the map */
|
||||
if (max(addr, start) <= min(levelend, end)) {
|
||||
start = max(addr, start);
|
||||
end = min(levelend, end);
|
||||
|
||||
/* We need a sub-pt for this level */
|
||||
if ((start & levelmask) || (end & levelmask)) {
|
||||
pte_type = PTE_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Lv0 can not do block PTEs, so do levels here too */
|
||||
if (level <= 0) {
|
||||
pte_type = PTE_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* PTE is active, but fits into a block */
|
||||
pte_type = PTE_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Block PTEs at this level are already covered by the parent page
|
||||
* table, so we only need to count sub page tables.
|
||||
*/
|
||||
if (pte_type == PTE_LEVEL) {
|
||||
int sublevel = level + 1;
|
||||
u64 sublevelsize = 1ULL << level2shift(sublevel);
|
||||
|
||||
/* Account for the new sub page table ... */
|
||||
r = 1;
|
||||
|
||||
/* ... and for all child page tables that one might have */
|
||||
for (i = 0; i < MAX_PTE_ENTRIES; i++) {
|
||||
r += count_required_pts(addr, sublevel, maxaddr);
|
||||
addr += sublevelsize;
|
||||
|
||||
if (addr >= maxaddr) {
|
||||
/*
|
||||
* We reached the end of address space, no need
|
||||
* to look any further.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Returns the estimated required size of all page tables */
|
||||
__weak u64 get_page_table_size(void)
|
||||
{
|
||||
u64 one_pt = MAX_PTE_ENTRIES * sizeof(u64);
|
||||
u64 size = 0;
|
||||
u64 va_bits;
|
||||
int start_level = 0;
|
||||
|
||||
get_tcr(0, NULL, &va_bits);
|
||||
if (va_bits < 39)
|
||||
start_level = 1;
|
||||
|
||||
/* Account for all page tables we would need to cover our memory map */
|
||||
size = one_pt * count_required_pts(0, start_level - 1, 1ULL << va_bits);
|
||||
|
||||
/*
|
||||
* We need to duplicate our page table once to have an emergency pt to
|
||||
* resort to when splitting page tables later on
|
||||
*/
|
||||
size *= 2;
|
||||
|
||||
/*
|
||||
* We may need to split page tables later on if dcache settings change,
|
||||
* so reserve up to 4 (random pick) page tables for that.
|
||||
*/
|
||||
size += one_pt * 4;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void setup_pgtables(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!gd->arch.tlb_fillptr || !gd->arch.tlb_addr)
|
||||
panic("Page table pointer not setup.");
|
||||
|
||||
/*
|
||||
* Allocate the first level we're on with invalidate entries.
|
||||
* If the starting level is 0 (va_bits >= 39), then this is our
|
||||
* Lv0 page table, otherwise it's the entry Lv1 page table.
|
||||
*/
|
||||
create_table();
|
||||
|
||||
/* Now add all MMU table entries one after another to the table */
|
||||
for (i = 0; mem_map[i].size || mem_map[i].attrs; i++)
|
||||
add_map(&mem_map[i]);
|
||||
}
|
||||
|
||||
static void setup_all_pgtables(void)
|
||||
{
|
||||
u64 tlb_addr = gd->arch.tlb_addr;
|
||||
u64 tlb_size = gd->arch.tlb_size;
|
||||
|
||||
/* Reset the fill ptr */
|
||||
gd->arch.tlb_fillptr = tlb_addr;
|
||||
|
||||
/* Create normal system page tables */
|
||||
setup_pgtables();
|
||||
|
||||
/* Create emergency page tables */
|
||||
gd->arch.tlb_size -= (uintptr_t)gd->arch.tlb_fillptr -
|
||||
(uintptr_t)gd->arch.tlb_addr;
|
||||
gd->arch.tlb_addr = gd->arch.tlb_fillptr;
|
||||
setup_pgtables();
|
||||
gd->arch.tlb_emerg = gd->arch.tlb_addr;
|
||||
gd->arch.tlb_addr = tlb_addr;
|
||||
gd->arch.tlb_size = tlb_size;
|
||||
}
|
||||
|
||||
/* to activate the MMU we need to set up virtual memory */
|
||||
__weak void mmu_setup(void)
|
||||
{
|
||||
int el;
|
||||
|
||||
/* Set up page tables only once */
|
||||
if (!gd->arch.tlb_fillptr)
|
||||
setup_all_pgtables();
|
||||
|
||||
el = current_el();
|
||||
set_ttbr_tcr_mair(el, gd->arch.tlb_addr, get_tcr(el, NULL, NULL),
|
||||
MEMORY_ATTRIBUTES);
|
||||
|
||||
/* enable the mmu */
|
||||
set_sctlr(get_sctlr() | CR_M);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a invalidation of the entire data cache at all levels
|
||||
*/
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
__asm_invalidate_dcache_all();
|
||||
__asm_invalidate_l3_dcache();
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a clean & invalidation of the entire data cache at all levels.
|
||||
* This function needs to be inline to avoid using stack.
|
||||
* __asm_flush_l3_dcache return status of timeout
|
||||
*/
|
||||
inline void flush_dcache_all(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm_flush_dcache_all();
|
||||
ret = __asm_flush_l3_dcache();
|
||||
if (ret)
|
||||
debug("flushing dcache returns 0x%x\n", ret);
|
||||
else
|
||||
debug("flushing dcache successfully.\n");
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SYS_DISABLE_DCACHE_OPS
|
||||
/*
|
||||
* Invalidates range in all levels of D-cache/unified cache
|
||||
*/
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
__asm_invalidate_dcache_range(start, stop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush range(clean & invalidate) from all levels of D-cache/unified cache
|
||||
*/
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
__asm_flush_dcache_range(start, stop);
|
||||
}
|
||||
#else
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_SYS_DISABLE_DCACHE_OPS */
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
/* The data cache is not active unless the mmu is enabled */
|
||||
if (!(get_sctlr() & CR_M)) {
|
||||
invalidate_dcache_all();
|
||||
__asm_invalidate_tlb_all();
|
||||
mmu_setup();
|
||||
}
|
||||
|
||||
set_sctlr(get_sctlr() | CR_C);
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
uint32_t sctlr;
|
||||
|
||||
sctlr = get_sctlr();
|
||||
|
||||
/* if cache isn't enabled no need to disable */
|
||||
if (!(sctlr & CR_C))
|
||||
return;
|
||||
|
||||
set_sctlr(sctlr & ~(CR_C|CR_M));
|
||||
|
||||
flush_dcache_all();
|
||||
__asm_invalidate_tlb_all();
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return (get_sctlr() & CR_C) != 0;
|
||||
}
|
||||
|
||||
u64 *__weak arch_get_page_table(void) {
|
||||
puts("No page table offset defined\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool is_aligned(u64 addr, u64 size, u64 align)
|
||||
{
|
||||
return !(addr & (align - 1)) && !(size & (align - 1));
|
||||
}
|
||||
|
||||
/* Use flag to indicate if attrs has more than d-cache attributes */
|
||||
static u64 set_one_region(u64 start, u64 size, u64 attrs, bool flag, int level)
|
||||
{
|
||||
int levelshift = level2shift(level);
|
||||
u64 levelsize = 1ULL << levelshift;
|
||||
u64 *pte = find_pte(start, level);
|
||||
|
||||
/* Can we can just modify the current level block PTE? */
|
||||
if (is_aligned(start, size, levelsize)) {
|
||||
if (flag) {
|
||||
*pte &= ~PMD_ATTRMASK;
|
||||
*pte |= attrs & PMD_ATTRMASK;
|
||||
} else {
|
||||
*pte &= ~PMD_ATTRINDX_MASK;
|
||||
*pte |= attrs & PMD_ATTRINDX_MASK;
|
||||
}
|
||||
debug("Set attrs=%llx pte=%p level=%d\n", attrs, pte, level);
|
||||
|
||||
return levelsize;
|
||||
}
|
||||
|
||||
/* Unaligned or doesn't fit, maybe split block into table */
|
||||
debug("addr=%llx level=%d pte=%p (%llx)\n", start, level, pte, *pte);
|
||||
|
||||
/* Maybe we need to split the block into a table */
|
||||
if (pte_type(pte) == PTE_TYPE_BLOCK)
|
||||
split_block(pte, level);
|
||||
|
||||
/* And then double-check it became a table or already is one */
|
||||
if (pte_type(pte) != PTE_TYPE_TABLE)
|
||||
panic("PTE %p (%llx) for addr=%llx should be a table",
|
||||
pte, *pte, start);
|
||||
|
||||
/* Roll on to the next page table level */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
|
||||
enum dcache_option option)
|
||||
{
|
||||
u64 attrs = PMD_ATTRINDX(option);
|
||||
u64 real_start = start;
|
||||
u64 real_size = size;
|
||||
|
||||
debug("start=%lx size=%lx\n", (ulong)start, (ulong)size);
|
||||
|
||||
if (!gd->arch.tlb_emerg)
|
||||
panic("Emergency page table not setup.");
|
||||
|
||||
/*
|
||||
* We can not modify page tables that we're currently running on,
|
||||
* so we first need to switch to the "emergency" page tables where
|
||||
* we can safely modify our primary page tables and then switch back
|
||||
*/
|
||||
__asm_switch_ttbr(gd->arch.tlb_emerg);
|
||||
|
||||
/*
|
||||
* Loop through the address range until we find a page granule that fits
|
||||
* our alignment constraints, then set it to the new cache attributes
|
||||
*/
|
||||
while (size > 0) {
|
||||
int level;
|
||||
u64 r;
|
||||
|
||||
for (level = 1; level < 4; level++) {
|
||||
/* Set d-cache attributes only */
|
||||
r = set_one_region(start, size, attrs, false, level);
|
||||
if (r) {
|
||||
/* PTE successfully replaced */
|
||||
size -= r;
|
||||
start += r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We're done modifying page tables, switch back to our primary ones */
|
||||
__asm_switch_ttbr(gd->arch.tlb_addr);
|
||||
|
||||
/*
|
||||
* Make sure there's nothing stale in dcache for a region that might
|
||||
* have caches off now
|
||||
*/
|
||||
flush_dcache_range(real_start, real_start + real_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify MMU table for a region with updated PXN/UXN/Memory type/valid bits.
|
||||
* The procecess is break-before-make. The target region will be marked as
|
||||
* invalid during the process of changing.
|
||||
*/
|
||||
void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs)
|
||||
{
|
||||
int level;
|
||||
u64 r, size, start;
|
||||
|
||||
start = addr;
|
||||
size = siz;
|
||||
/*
|
||||
* Loop through the address range until we find a page granule that fits
|
||||
* our alignment constraints, then set it to "invalid".
|
||||
*/
|
||||
while (size > 0) {
|
||||
for (level = 1; level < 4; level++) {
|
||||
/* Set PTE to fault */
|
||||
r = set_one_region(start, size, PTE_TYPE_FAULT, true,
|
||||
level);
|
||||
if (r) {
|
||||
/* PTE successfully invalidated */
|
||||
size -= r;
|
||||
start += r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flush_dcache_range(gd->arch.tlb_addr,
|
||||
gd->arch.tlb_addr + gd->arch.tlb_size);
|
||||
__asm_invalidate_tlb_all();
|
||||
|
||||
/*
|
||||
* Loop through the address range until we find a page granule that fits
|
||||
* our alignment constraints, then set it to the new cache attributes
|
||||
*/
|
||||
start = addr;
|
||||
size = siz;
|
||||
while (size > 0) {
|
||||
for (level = 1; level < 4; level++) {
|
||||
/* Set PTE to new attributes */
|
||||
r = set_one_region(start, size, attrs, true, level);
|
||||
if (r) {
|
||||
/* PTE successfully updated */
|
||||
size -= r;
|
||||
start += r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
flush_dcache_range(gd->arch.tlb_addr,
|
||||
gd->arch.tlb_addr + gd->arch.tlb_size);
|
||||
__asm_invalidate_tlb_all();
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
|
||||
|
||||
/*
|
||||
* For SPL builds, we may want to not have dcache enabled. Any real U-Boot
|
||||
* running however really wants to have dcache and the MMU active. Check that
|
||||
* everything is sane and give the developer a hint if it isn't.
|
||||
*/
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
#error Please describe your MMU layout in CONFIG_SYS_MEM_MAP and enable dcache.
|
||||
#endif
|
||||
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_dcache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
|
||||
enum dcache_option option)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
|
||||
|
||||
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
invalidate_icache_all();
|
||||
set_sctlr(get_sctlr() | CR_I);
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
set_sctlr(get_sctlr() & ~CR_I);
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return (get_sctlr() & CR_I) != 0;
|
||||
}
|
||||
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
__asm_invalidate_icache_all();
|
||||
__asm_invalidate_l3_icache();
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IS_ENABLED(SYS_ICACHE_OFF) */
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_IS_ENABLED(SYS_ICACHE_OFF) */
|
||||
|
||||
/*
|
||||
* Enable dCache & iCache, whether cache is actually enabled
|
||||
* depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF
|
||||
*/
|
||||
void __weak enable_caches(void)
|
||||
{
|
||||
icache_enable();
|
||||
dcache_enable();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
PLATFORM_RELFLAGS += -fno-common -ffixed-x18
|
||||
|
||||
PF_NO_UNALIGNED := $(call cc-option, -mstrict-align)
|
||||
PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
|
||||
|
||||
EFI_LDS := elf_aarch64_efi.lds
|
||||
EFI_CRT0 := crt0_aarch64_efi.o
|
||||
EFI_RELOC := reloc_aarch64_efi.o
|
||||
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 NXP Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/psci.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/sec_firmware.h>
|
||||
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
int psci_update_dt(void *fdt)
|
||||
{
|
||||
/*
|
||||
* If the PSCI in SEC Firmware didn't work, avoid to update the
|
||||
* device node of PSCI. But still return 0 instead of an error
|
||||
* number to support detecting PSCI dynamically and then switching
|
||||
* the SMP boot method between PSCI and spin-table.
|
||||
*/
|
||||
if (sec_firmware_support_psci_version() == PSCI_INVALID_VER)
|
||||
return 0;
|
||||
fdt_psci(fdt);
|
||||
|
||||
#if defined(CONFIG_ARMV8_PSCI) && !defined(CONFIG_ARMV8_SECURE_BASE)
|
||||
/* secure code lives in RAM, keep it alive */
|
||||
fdt_add_mem_rsv(fdt, (unsigned long)__secure_start,
|
||||
__secure_end - __secure_start);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008 Texas Insturments
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
#include <irq_func.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/secure.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/*
|
||||
* sdelay() - simple spin loop.
|
||||
*
|
||||
* Will delay execution by roughly (@loops * 2) cycles.
|
||||
* This is necessary to be used before timers are accessible.
|
||||
*
|
||||
* A value of "0" will results in 2^64 loops.
|
||||
*/
|
||||
void sdelay(unsigned long loops)
|
||||
{
|
||||
__asm__ volatile ("1:\n" "subs %0, %0, #1\n"
|
||||
"b.ne 1b" : "=r" (loops) : "0"(loops) : "cc");
|
||||
}
|
||||
|
||||
int cleanup_before_linux(void)
|
||||
{
|
||||
/*
|
||||
* this function is called just before we call linux
|
||||
* it prepares the processor for linux
|
||||
*
|
||||
* disable interrupt and turn off caches etc ...
|
||||
*/
|
||||
disable_interrupts();
|
||||
|
||||
/*
|
||||
* Turn off I-cache and invalidate it
|
||||
*/
|
||||
icache_disable();
|
||||
invalidate_icache_all();
|
||||
|
||||
/*
|
||||
* turn off D-cache
|
||||
* dcache_disable() in turn flushes the d-cache and disables MMU
|
||||
*/
|
||||
dcache_disable();
|
||||
invalidate_dcache_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARMV8_PSCI
|
||||
static void relocate_secure_section(void)
|
||||
{
|
||||
#ifdef CONFIG_ARMV8_SECURE_BASE
|
||||
size_t sz = __secure_end - __secure_start;
|
||||
|
||||
memcpy((void *)CONFIG_ARMV8_SECURE_BASE, __secure_start, sz);
|
||||
flush_dcache_range(CONFIG_ARMV8_SECURE_BASE,
|
||||
CONFIG_ARMV8_SECURE_BASE + sz + 1);
|
||||
invalidate_icache_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
void armv8_setup_psci(void)
|
||||
{
|
||||
relocate_secure_section();
|
||||
secure_ram_addr(psci_setup_vectors)();
|
||||
secure_ram_addr(psci_arch_init)();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Switch to non-secure mode
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt
|
||||
*
|
||||
* This module contains the ARMv8 specific code required to adjust the exception
|
||||
* level before booting an operating system.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <bootm.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/setjmp.h>
|
||||
|
||||
/**
|
||||
* entry_non_secure() - entry point when switching to non-secure mode
|
||||
*
|
||||
* When switching to non-secure mode switch_to_non_secure_mode() calls this
|
||||
* function passing a jump buffer. We use this jump buffer to restore the
|
||||
* original stack and register state.
|
||||
*
|
||||
* @non_secure_jmp: jump buffer for restoring stack and registers
|
||||
*/
|
||||
static void entry_non_secure(struct jmp_buf_data *non_secure_jmp)
|
||||
{
|
||||
dcache_enable();
|
||||
debug("Reached non-secure mode\n");
|
||||
|
||||
/* Restore stack and registers saved in switch_to_non_secure_mode() */
|
||||
longjmp(non_secure_jmp, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* switch_to_non_secure_mode() - switch to non-secure mode
|
||||
*
|
||||
* Exception level EL3 is meant to be used by the secure monitor only (ARM
|
||||
* trusted firmware being one embodiment). The operating system shall be
|
||||
* started at exception level EL2. So here we check the exception level
|
||||
* and switch it if necessary.
|
||||
*/
|
||||
void switch_to_non_secure_mode(void)
|
||||
{
|
||||
struct jmp_buf_data non_secure_jmp;
|
||||
|
||||
/* On AArch64 we need to make sure we call our payload in < EL3 */
|
||||
if (current_el() == 3) {
|
||||
if (setjmp(&non_secure_jmp))
|
||||
return;
|
||||
dcache_disable(); /* flush cache before switch to EL2 */
|
||||
|
||||
/* Move into EL2 and keep running there */
|
||||
armv8_switch_to_el2((uintptr_t)&non_secure_jmp, 0, 0, 0,
|
||||
(uintptr_t)entry_non_secure, ES_TO_AARCH64);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/macro.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* AArch64 exception vectors:
|
||||
* We have four types of exceptions:
|
||||
* - synchronous: traps, data aborts, undefined instructions, ...
|
||||
* - IRQ: group 1 (normal) interrupts
|
||||
* - FIQ: group 0 or secure interrupts
|
||||
* - SError: fatal system errors
|
||||
* There are entries for all four of those for different contexts:
|
||||
* - from same exception level, when using the SP_EL0 stack pointer
|
||||
* - from same exception level, when using the SP_ELx stack pointer
|
||||
* - from lower exception level, when this is AArch64
|
||||
* - from lower exception level, when this is AArch32
|
||||
* Each of those 16 entries have space for 32 instructions, each entry must
|
||||
* be 128 byte aligned, the whole table must be 2K aligned.
|
||||
* The 32 instructions are not enough to save and restore all registers and
|
||||
* to branch to the actual handler, so we split this up:
|
||||
* Each entry saves the LR, branches to the save routine, then to the actual
|
||||
* handler, then to the restore routine. The save and restore routines are
|
||||
* each split in half and stuffed in the unused gap between the entries.
|
||||
* Also as we do not run anything in a lower exception level, we just provide
|
||||
* the first 8 entries for exceptions from the same EL.
|
||||
*/
|
||||
.align 11
|
||||
.globl vectors
|
||||
vectors:
|
||||
.align 7 /* Current EL Synchronous Thread */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_bad_sync
|
||||
b exception_exit
|
||||
|
||||
/*
|
||||
* Save (most of) the GP registers to the stack frame.
|
||||
* This is the first part of the shared routine called into from all entries.
|
||||
*/
|
||||
_exception_entry:
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
stp x17, x18, [sp, #-16]!
|
||||
stp x15, x16, [sp, #-16]!
|
||||
stp x13, x14, [sp, #-16]!
|
||||
stp x11, x12, [sp, #-16]!
|
||||
stp x9, x10, [sp, #-16]!
|
||||
stp x7, x8, [sp, #-16]!
|
||||
stp x5, x6, [sp, #-16]!
|
||||
stp x3, x4, [sp, #-16]!
|
||||
stp x1, x2, [sp, #-16]!
|
||||
b _save_el_regs /* jump to the second part */
|
||||
|
||||
.align 7 /* Current EL IRQ Thread */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_bad_irq
|
||||
b exception_exit
|
||||
|
||||
/*
|
||||
* Save exception specific context: ESR and ELR, for all exception levels.
|
||||
* This is the second part of the shared routine called into from all entries.
|
||||
*/
|
||||
_save_el_regs:
|
||||
/* Could be running at EL3/EL2/EL1 */
|
||||
switch_el x11, 3f, 2f, 1f
|
||||
3: mrs x1, esr_el3
|
||||
mrs x2, elr_el3
|
||||
b 0f
|
||||
2: mrs x1, esr_el2
|
||||
mrs x2, elr_el2
|
||||
b 0f
|
||||
1: mrs x1, esr_el1
|
||||
mrs x2, elr_el1
|
||||
0:
|
||||
stp x2, x0, [sp, #-16]!
|
||||
mov x0, sp
|
||||
ret
|
||||
|
||||
.align 7 /* Current EL FIQ Thread */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_bad_fiq
|
||||
/* falling through to _exception_exit */
|
||||
/*
|
||||
* Restore the exception return address, for all exception levels.
|
||||
* This is the first part of the shared routine called into from all entries.
|
||||
*/
|
||||
exception_exit:
|
||||
ldp x2, x0, [sp],#16
|
||||
switch_el x11, 3f, 2f, 1f
|
||||
3: msr elr_el3, x2
|
||||
b _restore_regs
|
||||
2: msr elr_el2, x2
|
||||
b _restore_regs
|
||||
1: msr elr_el1, x2
|
||||
b _restore_regs /* jump to the second part */
|
||||
|
||||
.align 7 /* Current EL Error Thread */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_bad_error
|
||||
b exception_exit
|
||||
|
||||
/*
|
||||
* Restore the general purpose registers from the exception stack, then return.
|
||||
* This is the second part of the shared routine called into from all entries.
|
||||
*/
|
||||
_restore_regs:
|
||||
ldp x1, x2, [sp],#16
|
||||
ldp x3, x4, [sp],#16
|
||||
ldp x5, x6, [sp],#16
|
||||
ldp x7, x8, [sp],#16
|
||||
ldp x9, x10, [sp],#16
|
||||
ldp x11, x12, [sp],#16
|
||||
ldp x13, x14, [sp],#16
|
||||
ldp x15, x16, [sp],#16
|
||||
ldp x17, x18, [sp],#16
|
||||
ldp x19, x20, [sp],#16
|
||||
ldp x21, x22, [sp],#16
|
||||
ldp x23, x24, [sp],#16
|
||||
ldp x25, x26, [sp],#16
|
||||
ldp x27, x28, [sp],#16
|
||||
ldp x29, x30, [sp],#16
|
||||
eret
|
||||
|
||||
.align 7 /* Current EL (SP_ELx) Synchronous Handler */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_sync
|
||||
b exception_exit
|
||||
|
||||
.align 7 /* Current EL (SP_ELx) IRQ Handler */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_irq
|
||||
b exception_exit
|
||||
|
||||
.align 7 /* Current EL (SP_ELx) FIQ Handler */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_fiq
|
||||
b exception_exit
|
||||
|
||||
.align 7 /* Current EL (SP_ELx) Error Handler */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _exception_entry
|
||||
bl do_error
|
||||
b exception_exit
|
||||
@@ -0,0 +1,603 @@
|
||||
config ARCH_LS1012A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select ARM_ERRATA_855873 if !TFABOOT
|
||||
select FSL_LAYERSCAPE
|
||||
select FSL_LSCH2
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_DDR_BE
|
||||
select SYS_FSL_MMDC
|
||||
select SYS_FSL_ERRATUM_A010315
|
||||
select SYS_FSL_ERRATUM_A009798
|
||||
select SYS_FSL_ERRATUM_A008997
|
||||
select SYS_FSL_ERRATUM_A009007
|
||||
select SYS_FSL_ERRATUM_A009008
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
select SYS_I2C_MXC_I2C1
|
||||
select SYS_I2C_MXC_I2C2
|
||||
imply PANIC_HANG
|
||||
|
||||
config ARCH_LS1028A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select FSL_LSCH3
|
||||
select NXP_LSCH3_2
|
||||
select SYS_FSL_HAS_CCI400
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_DDR
|
||||
select SYS_FSL_DDR_LE
|
||||
select SYS_FSL_DDR_VER_50
|
||||
select SYS_FSL_HAS_DDR3
|
||||
select SYS_FSL_HAS_DDR4
|
||||
select SYS_FSL_HAS_SEC
|
||||
select SYS_FSL_SEC_COMPAT_5
|
||||
select SYS_FSL_SEC_LE
|
||||
select FSL_TZASC_1
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
select SYS_FSL_ERRATUM_A008997
|
||||
select SYS_FSL_ERRATUM_A009007
|
||||
select SYS_FSL_ERRATUM_A008514 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009663 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009942 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A050382
|
||||
imply PANIC_HANG
|
||||
|
||||
config ARCH_LS1043A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select ARM_ERRATA_855873 if !TFABOOT
|
||||
select FSL_LAYERSCAPE
|
||||
select FSL_LSCH2
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_DDR
|
||||
select SYS_FSL_DDR_BE
|
||||
select SYS_FSL_DDR_VER_50
|
||||
select SYS_FSL_ERRATUM_A008850 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008997
|
||||
select SYS_FSL_ERRATUM_A009007
|
||||
select SYS_FSL_ERRATUM_A009008
|
||||
select SYS_FSL_ERRATUM_A009660 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009663 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009798
|
||||
select SYS_FSL_ERRATUM_A009929
|
||||
select SYS_FSL_ERRATUM_A009942 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A010315
|
||||
select SYS_FSL_ERRATUM_A010539
|
||||
select SYS_FSL_HAS_DDR3
|
||||
select SYS_FSL_HAS_DDR4
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
select SYS_I2C_MXC_I2C1
|
||||
select SYS_I2C_MXC_I2C2
|
||||
select SYS_I2C_MXC_I2C3
|
||||
select SYS_I2C_MXC_I2C4
|
||||
imply CMD_PCI
|
||||
|
||||
config ARCH_LS1046A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select FSL_LAYERSCAPE
|
||||
select FSL_LSCH2
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_DDR
|
||||
select SYS_FSL_DDR_BE
|
||||
select SYS_FSL_DDR_VER_50
|
||||
select SYS_FSL_ERRATUM_A008336 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008511 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008850 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008997
|
||||
select SYS_FSL_ERRATUM_A009007
|
||||
select SYS_FSL_ERRATUM_A009008
|
||||
select SYS_FSL_ERRATUM_A009798
|
||||
select SYS_FSL_ERRATUM_A009801
|
||||
select SYS_FSL_ERRATUM_A009803 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009942 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A010165 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A010539
|
||||
select SYS_FSL_HAS_DDR4
|
||||
select SYS_FSL_SRDS_2
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
select SYS_I2C_MXC_I2C1
|
||||
select SYS_I2C_MXC_I2C2
|
||||
select SYS_I2C_MXC_I2C3
|
||||
select SYS_I2C_MXC_I2C4
|
||||
imply SCSI
|
||||
imply SCSI_AHCI
|
||||
|
||||
config ARCH_LS1088A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select ARM_ERRATA_855873 if !TFABOOT
|
||||
select FSL_LAYERSCAPE
|
||||
select FSL_LSCH3
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_DDR
|
||||
select SYS_FSL_DDR_LE
|
||||
select SYS_FSL_DDR_VER_50
|
||||
select SYS_FSL_EC1
|
||||
select SYS_FSL_EC2
|
||||
select SYS_FSL_ERRATUM_A009803 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009942 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A010165 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008511 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008850 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009007
|
||||
select SYS_FSL_HAS_CCI400
|
||||
select SYS_FSL_HAS_DDR4
|
||||
select SYS_FSL_HAS_RGMII
|
||||
select SYS_FSL_HAS_SEC
|
||||
select SYS_FSL_SEC_COMPAT_5
|
||||
select SYS_FSL_SEC_LE
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_FSL_SRDS_2
|
||||
select FSL_TZASC_1
|
||||
select FSL_TZASC_400
|
||||
select FSL_TZPC_BP147
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
select SYS_I2C_MXC_I2C1 if !TFABOOT
|
||||
select SYS_I2C_MXC_I2C2 if !TFABOOT
|
||||
select SYS_I2C_MXC_I2C3 if !TFABOOT
|
||||
select SYS_I2C_MXC_I2C4 if !TFABOOT
|
||||
imply SCSI
|
||||
imply PANIC_HANG
|
||||
|
||||
config ARCH_LS2080A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select ARM_ERRATA_826974
|
||||
select ARM_ERRATA_828024
|
||||
select ARM_ERRATA_829520
|
||||
select ARM_ERRATA_833471
|
||||
select FSL_LAYERSCAPE
|
||||
select FSL_LSCH3
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_DDR
|
||||
select SYS_FSL_DDR_LE
|
||||
select SYS_FSL_DDR_VER_50
|
||||
select SYS_FSL_HAS_CCN504
|
||||
select SYS_FSL_HAS_DP_DDR
|
||||
select SYS_FSL_HAS_SEC
|
||||
select SYS_FSL_HAS_DDR4
|
||||
select SYS_FSL_SEC_COMPAT_5
|
||||
select SYS_FSL_SEC_LE
|
||||
select SYS_FSL_SRDS_2
|
||||
select FSL_TZASC_1
|
||||
select FSL_TZASC_2
|
||||
select FSL_TZASC_400
|
||||
select FSL_TZPC_BP147
|
||||
select SYS_FSL_ERRATUM_A008336 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008511 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008514 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A008585
|
||||
select SYS_FSL_ERRATUM_A008997
|
||||
select SYS_FSL_ERRATUM_A009007
|
||||
select SYS_FSL_ERRATUM_A009008
|
||||
select SYS_FSL_ERRATUM_A009635
|
||||
select SYS_FSL_ERRATUM_A009663 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009798
|
||||
select SYS_FSL_ERRATUM_A009801
|
||||
select SYS_FSL_ERRATUM_A009803 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009942 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A010165 if !TFABOOT
|
||||
select SYS_FSL_ERRATUM_A009203
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
select SYS_I2C_MXC_I2C1 if !TFABOOT
|
||||
select SYS_I2C_MXC_I2C2 if !TFABOOT
|
||||
select SYS_I2C_MXC_I2C3 if !TFABOOT
|
||||
select SYS_I2C_MXC_I2C4 if !TFABOOT
|
||||
imply DISTRO_DEFAULTS
|
||||
imply PANIC_HANG
|
||||
|
||||
config ARCH_LX2160A
|
||||
bool
|
||||
select ARMV8_SET_SMPEN
|
||||
select FSL_LSCH3
|
||||
select NXP_LSCH3_2
|
||||
select SYS_HAS_SERDES
|
||||
select SYS_FSL_SRDS_1
|
||||
select SYS_FSL_SRDS_2
|
||||
select SYS_NXP_SRDS_3
|
||||
select SYS_FSL_DDR
|
||||
select SYS_FSL_DDR_LE
|
||||
select SYS_FSL_DDR_VER_50
|
||||
select SYS_FSL_EC1
|
||||
select SYS_FSL_EC2
|
||||
select SYS_FSL_HAS_RGMII
|
||||
select SYS_FSL_HAS_SEC
|
||||
select SYS_FSL_HAS_CCN508
|
||||
select SYS_FSL_HAS_DDR4
|
||||
select SYS_FSL_SEC_COMPAT_5
|
||||
select SYS_FSL_SEC_LE
|
||||
select ARCH_EARLY_INIT_R
|
||||
select BOARD_EARLY_INIT_F
|
||||
select SYS_I2C_MXC
|
||||
imply DISTRO_DEFAULTS
|
||||
imply PANIC_HANG
|
||||
imply SCSI
|
||||
imply SCSI_AHCI
|
||||
|
||||
config FSL_LSCH2
|
||||
bool
|
||||
select SYS_FSL_HAS_CCI400
|
||||
select SYS_FSL_HAS_SEC
|
||||
select SYS_FSL_SEC_COMPAT_5
|
||||
select SYS_FSL_SEC_BE
|
||||
|
||||
config FSL_LSCH3
|
||||
bool
|
||||
|
||||
config NXP_LSCH3_2
|
||||
bool
|
||||
|
||||
menu "Layerscape architecture"
|
||||
depends on FSL_LSCH2 || FSL_LSCH3
|
||||
|
||||
config FSL_LAYERSCAPE
|
||||
bool
|
||||
|
||||
config FSL_PCIE_COMPAT
|
||||
string "PCIe compatible of Kernel DT"
|
||||
depends on PCIE_LAYERSCAPE || PCIE_LAYERSCAPE_GEN4
|
||||
default "fsl,ls1012a-pcie" if ARCH_LS1012A
|
||||
default "fsl,ls1028a-pcie" if ARCH_LS1028A
|
||||
default "fsl,ls1043a-pcie" if ARCH_LS1043A
|
||||
default "fsl,ls1046a-pcie" if ARCH_LS1046A
|
||||
default "fsl,ls2080a-pcie" if ARCH_LS2080A
|
||||
default "fsl,ls1088a-pcie" if ARCH_LS1088A
|
||||
default "fsl,lx2160a-pcie" if ARCH_LX2160A
|
||||
help
|
||||
This compatible is used to find pci controller node in Kernel DT
|
||||
to complete fixup.
|
||||
|
||||
config HAS_FEATURE_GIC64K_ALIGN
|
||||
bool
|
||||
default y if ARCH_LS1043A
|
||||
|
||||
config HAS_FEATURE_ENHANCED_MSI
|
||||
bool
|
||||
default y if ARCH_LS1043A
|
||||
|
||||
menu "Layerscape PPA"
|
||||
config FSL_LS_PPA
|
||||
bool "FSL Layerscape PPA firmware support"
|
||||
depends on !ARMV8_PSCI
|
||||
select ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
select SEC_FIRMWARE_ARMV8_PSCI
|
||||
select ARMV8_SEC_FIRMWARE_ERET_ADDR_REVERT if FSL_LSCH2
|
||||
help
|
||||
The FSL Primary Protected Application (PPA) is a software component
|
||||
which is loaded during boot stage, and then remains resident in RAM
|
||||
and runs in the TrustZone after boot.
|
||||
Say y to enable it.
|
||||
|
||||
config SPL_FSL_LS_PPA
|
||||
bool "FSL Layerscape PPA firmware support for SPL build"
|
||||
depends on !ARMV8_PSCI
|
||||
select SPL_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
select SEC_FIRMWARE_ARMV8_PSCI
|
||||
select ARMV8_SEC_FIRMWARE_ERET_ADDR_REVERT if FSL_LSCH2
|
||||
help
|
||||
The FSL Primary Protected Application (PPA) is a software component
|
||||
which is loaded during boot stage, and then remains resident in RAM
|
||||
and runs in the TrustZone after boot. This is to load PPA during SPL
|
||||
stage instead of the RAM version of U-Boot. Once PPA is initialized,
|
||||
the rest of U-Boot (including RAM version) runs at EL2.
|
||||
choice
|
||||
prompt "FSL Layerscape PPA firmware loading-media select"
|
||||
depends on FSL_LS_PPA
|
||||
default SYS_LS_PPA_FW_IN_MMC if SD_BOOT
|
||||
default SYS_LS_PPA_FW_IN_NAND if NAND_BOOT
|
||||
default SYS_LS_PPA_FW_IN_XIP
|
||||
|
||||
config SYS_LS_PPA_FW_IN_XIP
|
||||
bool "XIP"
|
||||
help
|
||||
Say Y here if the PPA firmware locate at XIP flash, such
|
||||
as NOR or QSPI flash.
|
||||
|
||||
config SYS_LS_PPA_FW_IN_MMC
|
||||
bool "eMMC or SD Card"
|
||||
help
|
||||
Say Y here if the PPA firmware locate at eMMC/SD card.
|
||||
|
||||
config SYS_LS_PPA_FW_IN_NAND
|
||||
bool "NAND"
|
||||
help
|
||||
Say Y here if the PPA firmware locate at NAND flash.
|
||||
|
||||
endchoice
|
||||
|
||||
config LS_PPA_ESBC_HDR_SIZE
|
||||
hex "Length of PPA ESBC header"
|
||||
depends on FSL_LS_PPA && CHAIN_OF_TRUST && !SYS_LS_PPA_FW_IN_XIP
|
||||
default 0x2000
|
||||
help
|
||||
Length (in bytes) of PPA ESBC header to be copied from MMC/SD or
|
||||
NAND to memory to validate PPA image.
|
||||
|
||||
endmenu
|
||||
|
||||
config SYS_FSL_ERRATUM_A008997
|
||||
bool "Workaround for USB PHY erratum A008997"
|
||||
|
||||
config SYS_FSL_ERRATUM_A009007
|
||||
bool
|
||||
help
|
||||
Workaround for USB PHY erratum A009007
|
||||
|
||||
config SYS_FSL_ERRATUM_A009008
|
||||
bool "Workaround for USB PHY erratum A009008"
|
||||
|
||||
config SYS_FSL_ERRATUM_A009798
|
||||
bool "Workaround for USB PHY erratum A009798"
|
||||
|
||||
config SYS_FSL_ERRATUM_A010315
|
||||
bool "Workaround for PCIe erratum A010315"
|
||||
|
||||
config SYS_FSL_ERRATUM_A010539
|
||||
bool "Workaround for PIN MUX erratum A010539"
|
||||
|
||||
config MAX_CPUS
|
||||
int "Maximum number of CPUs permitted for Layerscape"
|
||||
default 2 if ARCH_LS1028A
|
||||
default 4 if ARCH_LS1043A
|
||||
default 4 if ARCH_LS1046A
|
||||
default 16 if ARCH_LS2080A
|
||||
default 8 if ARCH_LS1088A
|
||||
default 16 if ARCH_LX2160A
|
||||
default 1
|
||||
help
|
||||
Set this number to the maximum number of possible CPUs in the SoC.
|
||||
SoCs may have multiple clusters with each cluster may have multiple
|
||||
ports. If some ports are reserved but higher ports are used for
|
||||
cores, count the reserved ports. This will allocate enough memory
|
||||
in spin table to properly handle all cores.
|
||||
|
||||
config EMC2305
|
||||
bool "Fan controller"
|
||||
help
|
||||
Enable the EMC2305 fan controller for configuration of fan
|
||||
speed.
|
||||
|
||||
config NXP_ESBC
|
||||
bool "NXP_ESBC"
|
||||
help
|
||||
Enable Freescale Secure Boot feature
|
||||
|
||||
config QSPI_AHB_INIT
|
||||
bool "Init the QSPI AHB bus"
|
||||
help
|
||||
The default setting for QSPI AHB bus just support 3bytes addressing.
|
||||
But some QSPI flash size up to 64MBytes, so initialize the QSPI AHB
|
||||
bus for those flashes to support the full QSPI flash size.
|
||||
|
||||
config SYS_CCI400_OFFSET
|
||||
hex "Offset for CCI400 base"
|
||||
depends on SYS_FSL_HAS_CCI400
|
||||
default 0x3090000 if ARCH_LS1088A || ARCH_LS1028A
|
||||
default 0x180000 if FSL_LSCH2
|
||||
help
|
||||
Offset for CCI400 base
|
||||
CCI400 base addr = CCSRBAR + CCI400_OFFSET
|
||||
|
||||
config SYS_FSL_IFC_BANK_COUNT
|
||||
int "Maximum banks of Integrated flash controller"
|
||||
depends on ARCH_LS1043A || ARCH_LS1046A || ARCH_LS2080A || ARCH_LS1088A
|
||||
default 4 if ARCH_LS1043A
|
||||
default 4 if ARCH_LS1046A
|
||||
default 8 if ARCH_LS2080A || ARCH_LS1088A
|
||||
|
||||
config SYS_FSL_HAS_CCI400
|
||||
bool
|
||||
|
||||
config SYS_FSL_HAS_CCN504
|
||||
bool
|
||||
|
||||
config SYS_FSL_HAS_CCN508
|
||||
bool
|
||||
|
||||
config SYS_FSL_HAS_DP_DDR
|
||||
bool
|
||||
|
||||
config SYS_FSL_SRDS_1
|
||||
bool
|
||||
|
||||
config SYS_FSL_SRDS_2
|
||||
bool
|
||||
|
||||
config SYS_NXP_SRDS_3
|
||||
bool
|
||||
|
||||
config SYS_HAS_SERDES
|
||||
bool
|
||||
|
||||
config FSL_TZASC_1
|
||||
bool
|
||||
|
||||
config FSL_TZASC_2
|
||||
bool
|
||||
|
||||
config FSL_TZASC_400
|
||||
bool
|
||||
|
||||
config FSL_TZPC_BP147
|
||||
bool
|
||||
endmenu
|
||||
|
||||
menu "Layerscape clock tree configuration"
|
||||
depends on FSL_LSCH2 || FSL_LSCH3
|
||||
|
||||
config SYS_FSL_CLK
|
||||
bool "Enable clock tree initialization"
|
||||
default y
|
||||
|
||||
config CLUSTER_CLK_FREQ
|
||||
int "Reference clock of core cluster"
|
||||
depends on ARCH_LS1012A
|
||||
default 100000000
|
||||
help
|
||||
This number is the reference clock frequency of core PLL.
|
||||
For most platforms, the core PLL and Platform PLL have the same
|
||||
reference clock, but for some platforms, LS1012A for instance,
|
||||
they are provided sepatately.
|
||||
|
||||
config SYS_FSL_PCLK_DIV
|
||||
int "Platform clock divider"
|
||||
default 1 if ARCH_LS1028A
|
||||
default 1 if ARCH_LS1043A
|
||||
default 1 if ARCH_LS1046A
|
||||
default 1 if ARCH_LS1088A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive Platform clock from
|
||||
Platform PLL, in another word:
|
||||
Platform_clk = Platform_PLL_freq / this_divider
|
||||
|
||||
config SYS_FSL_DSPI_CLK_DIV
|
||||
int "DSPI clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive DSPI clock from Platform
|
||||
clock, in another word DSPI_clk = Platform_clk / this_divider.
|
||||
|
||||
config SYS_FSL_DUART_CLK_DIV
|
||||
int "DUART clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 4 if ARCH_LX2160A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive DUART clock from Platform
|
||||
clock, in another word DUART_clk = Platform_clk / this_divider.
|
||||
|
||||
config SYS_FSL_I2C_CLK_DIV
|
||||
int "I2C clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 4 if ARCH_LS1012A
|
||||
default 4 if ARCH_LS1028A
|
||||
default 8 if ARCH_LX2160A
|
||||
default 8 if ARCH_LS1088A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive I2C clock from Platform
|
||||
clock, in another word I2C_clk = Platform_clk / this_divider.
|
||||
|
||||
config SYS_FSL_IFC_CLK_DIV
|
||||
int "IFC clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 4 if ARCH_LS1012A
|
||||
default 4 if ARCH_LS1028A
|
||||
default 8 if ARCH_LX2160A
|
||||
default 8 if ARCH_LS1088A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive IFC clock from Platform
|
||||
clock, in another word IFC_clk = Platform_clk / this_divider.
|
||||
|
||||
config SYS_FSL_LPUART_CLK_DIV
|
||||
int "LPUART clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive LPUART clock from Platform
|
||||
clock, in another word LPUART_clk = Platform_clk / this_divider.
|
||||
|
||||
config SYS_FSL_SDHC_CLK_DIV
|
||||
int "SDHC clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 1 if ARCH_LS1012A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive SDHC clock from Platform
|
||||
clock, in another word SDHC_clk = Platform_clk / this_divider.
|
||||
|
||||
config SYS_FSL_QMAN_CLK_DIV
|
||||
int "QMAN clock divider"
|
||||
default 1 if ARCH_LS1043A
|
||||
default 2
|
||||
help
|
||||
This is the divider that is used to derive QMAN clock from Platform
|
||||
clock, in another word QMAN_clk = Platform_clk / this_divider.
|
||||
endmenu
|
||||
|
||||
config RESV_RAM
|
||||
bool
|
||||
help
|
||||
Reserve memory from the top, tracked by gd->arch.resv_ram. This
|
||||
reserved RAM can be used by special driver that resides in memory
|
||||
after U-Boot exits. It's up to implementation to allocate and allow
|
||||
access to this reserved memory. For example, the reserved RAM can
|
||||
be at the high end of physical memory. The reserve RAM may be
|
||||
excluded from memory bank(s) passed to OS, or marked as reserved.
|
||||
|
||||
config SYS_FSL_EC1
|
||||
bool
|
||||
help
|
||||
Ethernet controller 1, this is connected to
|
||||
MAC17 for LX2160A or to MAC3 for other SoCs
|
||||
Provides DPAA2 capabilities
|
||||
|
||||
config SYS_FSL_EC2
|
||||
bool
|
||||
help
|
||||
Ethernet controller 2, this is connected to
|
||||
MAC18 for LX2160A or to MAC4 for other SoCs
|
||||
Provides DPAA2 capabilities
|
||||
|
||||
config SYS_FSL_ERRATUM_A008336
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A008514
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A008585
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A008850
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A009203
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A009635
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A009660
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A009929
|
||||
bool
|
||||
|
||||
config SYS_FSL_ERRATUM_A050382
|
||||
bool
|
||||
|
||||
config SYS_FSL_HAS_RGMII
|
||||
bool
|
||||
depends on SYS_FSL_EC1 || SYS_FSL_EC2
|
||||
|
||||
config SPL_LDSCRIPT
|
||||
default "arch/arm/cpu/armv8/u-boot-spl.lds" if ARCH_LS1043A || ARCH_LS1046A || ARCH_LS2080A
|
||||
|
||||
config HAS_FSL_XHCI_USB
|
||||
bool
|
||||
default y if ARCH_LS1043A || ARCH_LS1046A
|
||||
help
|
||||
For some SoC(such as LS1043A and LS1046A), USB and QE-HDLC multiplex use
|
||||
pins, select it when the pins are assigned to USB.
|
||||
@@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright 2016-2018 NXP
|
||||
# Copyright 2014-2015, Freescale Semiconductor
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += lowlevel.o
|
||||
obj-y += soc.o
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_MP) += mp.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += fdt.o
|
||||
endif
|
||||
obj-$(CONFIG_SPL) += spl.o
|
||||
obj-$(CONFIG_$(SPL_)FSL_LS_PPA) += ppa.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_ARCH_LX2160A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += lx2160a_serdes.o
|
||||
obj-y += icid.o lx2160_ids.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_LS2080A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls2080a_serdes.o
|
||||
obj-y += icid.o ls2088_ids.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_LS1043A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1043a_serdes.o
|
||||
obj-$(CONFIG_ARMV8_PSCI) += ls1043a_psci.o
|
||||
obj-y += icid.o ls1043_ids.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_LS1012A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1012a_serdes.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_LS1046A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1046a_serdes.o
|
||||
obj-y += icid.o ls1046_ids.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_LS1088A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1088a_serdes.o
|
||||
obj-y += icid.o ls1088_ids.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_LS1028A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1028a_serdes.o
|
||||
obj-y += icid.o ls1028_ids.o
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2014-2015, Freescale Semiconductor
|
||||
*/
|
||||
|
||||
int fsl_qoriq_core_to_cluster(unsigned int core);
|
||||
u32 initiator_type(u32 cluster, int init_id);
|
||||
u32 cpu_mask(void);
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Core instruction prefetch disable
|
||||
---------------------------------
|
||||
To disable instruction prefetch of core; hwconfig needs to be updated.
|
||||
for e.g.
|
||||
setenv hwconfig 'fsl_ddr:bank_intlv=auto;core_prefetch:disable=0x02'
|
||||
|
||||
Here 0x02 can be replaced with any valid value except Mask[0] bit. It
|
||||
represents 64 bit mask. The 64-bit Mask has one bit for each core.
|
||||
Mask[0] = core0
|
||||
Mask[1] = core1
|
||||
Mask[2] = core2
|
||||
etc
|
||||
If the bit is set ('b1) in the mask, then prefetch is disabled for
|
||||
that core when it is released from reset.
|
||||
|
||||
core0 prefetch should not be disabled i.e. Mask[0] should never be set.
|
||||
Setting Mask[0] may lead to undefined behavior.
|
||||
|
||||
Once disabled, prefetch remains disabled until the next reset.
|
||||
There is no function to re-enable prefetch.
|
||||
@@ -0,0 +1,150 @@
|
||||
Falcon boot option
|
||||
------------------
|
||||
Falcon boot is a short cut boot method for SD/eMMC targets. It skips loading the
|
||||
RAM version U-Boot. Instead, it loads FIT image and boot directly to Linux.
|
||||
CONFIG_SPL_OS_BOOT enables falcon boot. CONFIG_SPL_LOAD_FIT enables the FIT
|
||||
image support (also need CONFIG_SPL_OF_LIBFDT, CONFIG_SPL_FIT and optionally
|
||||
CONFIG_SPL_GZIP).
|
||||
|
||||
To enable falcon boot, a hook function spl_start_uboot() returns 0 to indicate
|
||||
booting U-Boot is not the first choice. The kernel FIT image needs to be put
|
||||
at CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR. SPL mmc driver reads the header to
|
||||
determine if this is a FIT image. If true, FIT image components are parsed and
|
||||
copied or decompressed (if applicable) to their destinations. If FIT image is
|
||||
not found, normal U-Boot flow will follow.
|
||||
|
||||
An important part of falcon boot is to prepare the device tree. A normal U-Boot
|
||||
does FDT fixups when booting Linux. For falcon boot, Linux boots directly from
|
||||
SPL, skipping the normal U-Boot. The device tree has to be prepared in advance.
|
||||
A command "spl export" should be called under the normal RAM version U-Boot.
|
||||
It is equivalent to go through "bootm" step-by-step until device tree fixup is
|
||||
done. The device tree in memory is the one needed for falcon boot. Falcon boot
|
||||
flow suggests to save this image to SD/eMMC at the location pointed by macro
|
||||
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, with maximum size specified by macro
|
||||
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS. However, when FIT image is used for
|
||||
Linux, the device tree stored in FIT image overwrites the memory loaded by spl
|
||||
driver from these sectors. We could change this loading order to favor the
|
||||
stored sectors. But when secure boot is enabled, these sectors are used for
|
||||
signature header and needs to be loaded before the FIT image. So it is important
|
||||
to understand the device tree in FIT image should be the one actually used, or
|
||||
leave it absent to favor the stored sectors. It is easier to deploy the FIT
|
||||
image with embedded static device tree to multiple boards.
|
||||
|
||||
Macro CONFIG_SYS_SPL_ARGS_ADDR serves two purposes. One is the pointer to load
|
||||
the stored sectors to. Normally this is the static device tree. The second
|
||||
purpose is the memory location of signature header for secure boot. After the
|
||||
FIT image is loaded into memory, it is validated against the signature header
|
||||
before individual components are extracted (and optionally decompressed) into
|
||||
their final memory locations, respectively. After the validation, the header
|
||||
is no longer used. The static device tree is copied into this location. So
|
||||
this macro is passed as the location of device tree when booting Linux.
|
||||
|
||||
Steps to prepare static device tree
|
||||
-----------------------------------
|
||||
To prepare the static device tree for Layerscape boards, it is important to
|
||||
understand the fixups in U-Boot. Memory size and location, as well as reserved
|
||||
memory blocks are added/updated. Ethernet MAC addressed are updated. FMan
|
||||
microcode (if used) is embedded in the device tree. Kernel command line and
|
||||
initrd information are embedded. Others including CPU status, boot method,
|
||||
Ethernet port status, etc. are also updated.
|
||||
|
||||
Following normal booting process, all variables are set, all images are loaded
|
||||
before "bootm" command would be issued to boot, run command
|
||||
|
||||
spl export fdt <address>
|
||||
|
||||
where the address is the location of FIT image. U-Boot goes through the booting
|
||||
process as if "bootm start", "bootm loados", "bootm ramdisk"... commands but
|
||||
stops before "bootm go". There we have the fixed-up device tree in memory.
|
||||
We can check the device tree header by these commands
|
||||
|
||||
fdt addr <fdt address>
|
||||
fdt header
|
||||
|
||||
Where the fdt address is the device tree in memory. It is printed by U-Boot.
|
||||
It is useful to know the exact size. One way to extract this static device
|
||||
tree is to save it to eMMC/SD using command in U-Boot, and extract under Linux
|
||||
with these commands, repectively
|
||||
|
||||
mmc write <address> <sector> <sectors>
|
||||
dd if=/dev/mmcblk0 of=<filename> bs=512 skip=<sector> count=<sectors>
|
||||
|
||||
Note, U-Boot takes values as hexadecimals while Linux takes them as decimals by
|
||||
default. If using NAND or other storage, the commands are slightly different.
|
||||
When we have the static device tree image, we can re-make the FIT image with
|
||||
it. It is important to specify the load addresses in FIT image for every
|
||||
components. Otherwise U-Boot cannot load them correctly.
|
||||
|
||||
Generate FIT image with static device tree
|
||||
------------------------------------------
|
||||
Example:
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
description = "Image file for the LS1043A Linux Kernel";
|
||||
#address-cells = <1>;
|
||||
|
||||
images {
|
||||
kernel {
|
||||
description = "ARM64 Linux kernel";
|
||||
data = /incbin/("./arch/arm64/boot/Image.gz");
|
||||
type = "kernel";
|
||||
arch = "arm64";
|
||||
os = "linux";
|
||||
compression = "gzip";
|
||||
load = <0x80080000>;
|
||||
entry = <0x80080000>;
|
||||
};
|
||||
fdt-1 {
|
||||
description = "Flattened Device Tree blob";
|
||||
data = /incbin/("./fsl-ls1043ardb-static.dtb");
|
||||
type = "flat_dt";
|
||||
arch = "arm64";
|
||||
compression = "none";
|
||||
load = <0x90000000>;
|
||||
};
|
||||
ramdisk {
|
||||
description = "LS1043 Ramdisk";
|
||||
data = /incbin/("./rootfs.cpio.gz");
|
||||
type = "ramdisk";
|
||||
arch = "arm64";
|
||||
os = "linux";
|
||||
compression = "none";
|
||||
load = <0xa0000000>;
|
||||
};
|
||||
};
|
||||
|
||||
configurations {
|
||||
default = "config-1";
|
||||
config-1 {
|
||||
description = "Boot Linux kernel";
|
||||
kernel = "kernel";
|
||||
fdt = "fdt-1";
|
||||
ramdisk = "ramdisk";
|
||||
loadables = "fdt", "ramdisk";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
The "loadables" is not optional. It tells SPL which images to load into memory.
|
||||
|
||||
Falcon mode with QSPI boot
|
||||
--------------------------
|
||||
To use falcon mode with QSPI boot, SPL needs to be enabled. Similar to SD or
|
||||
NAND boot, a RAM version full feature U-Boot is needed. Unlike SD or NAND boot,
|
||||
SPL with QSPI doesn't need to combine SPL image with RAM version image. Two
|
||||
separated images are used, u-boot-spl.pbl and u-boot.img. The former is SPL
|
||||
image with RCW and PBI commands to load the SPL payload into On-Chip RAM. The
|
||||
latter is RAM version U-Boot in FIT format (or legacy format if FIT is not
|
||||
used).
|
||||
|
||||
Other things to consider
|
||||
-----------------------
|
||||
Falcon boot skips a lot of initialization in U-Boot. If Linux expects the
|
||||
hardware to be initialized by U-Boot, the related code should be ported to SPL
|
||||
build. For example, if Linux expect Ethernet PHY to be initialized in U-Boot
|
||||
(which is not a common case), the PHY initialization has to be included in
|
||||
falcon boot. This increases the SPL image size and should be handled carefully.
|
||||
If Linux has PHY driver enabled, it still depends on the correct MDIO bus setup
|
||||
in U-Boot. Normal U-Boot sets the MDC ratio to generate a proper clock signal.
|
||||
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
Watchdog support Overview
|
||||
-------------------
|
||||
Support watchdog driver for LSCH2. The driver is disabled in default.
|
||||
You can enable it by setting CONFIG_IMX_WATCHDOG.
|
||||
Use following config to set watchdog timeout, if this config is not defined,
|
||||
the default timeout value is 128s which is the maximum. Set 10 seconds for
|
||||
example:
|
||||
Set CONFIG_WATCHDOG_RESET_DISABLE to disable reset watchdog, so that the
|
||||
watchdog will not be fed in u-boot.
|
||||
@@ -0,0 +1,400 @@
|
||||
#
|
||||
# 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 LS2080A.
|
||||
|
||||
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 in hex. If this variable is not defined, the value
|
||||
CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE will be assumed.
|
||||
|
||||
mcinitcmd: This environment variable is defined to initiate MC and DPL deployment
|
||||
from the location where it is stored(NOR, NAND, SD, SATA, USB)during
|
||||
u-boot booting.If this variable is not defined then MC_BOOT_ENV_VAR
|
||||
will be null and MC will not be booted and DPL will not be applied
|
||||
during U-boot booting.However the MC, DPC and DPL can be applied from
|
||||
console independently.
|
||||
The variable needs to be set from the console once and then on
|
||||
rebooting the parameters set in the variable will automatically be
|
||||
executed. The commmand is demostrated taking an example of mc boot
|
||||
using NOR Flash i.e. MC, DPL, and DPC is stored in the NOR flash:
|
||||
|
||||
cp.b 0xa0000000 0x580300000 $filesize
|
||||
cp.b 0x80000000 0x580800000 $filesize
|
||||
cp.b 0x90000000 0x580700000 $filesize
|
||||
|
||||
setenv mcinitcmd 'fsl_mc start mc 0x580300000 0x580800000'
|
||||
|
||||
If only linux is to be booted then the mcinitcmd environment should be set as
|
||||
|
||||
setenv mcinitcmd 'fsl_mc start mc 0x580300000 0x580800000;fsl_mc apply DPL 0x580700000'
|
||||
|
||||
Here the addresses 0xa0000000, 0x80000000, 0x80000000 are of DDR to where
|
||||
MC binary, DPC binary and DPL binary are stored and 0x580300000, 0x580800000
|
||||
and 0x580700000 are addresses in NOR where these are copied. It is to be
|
||||
noted that these addresses in 'fsl_mc start mc 0x580300000 0x580800000;fsl_mc apply DPL 0x580700000'
|
||||
can be replaced with the addresses of DDR to
|
||||
which these will be copied in case of these binaries being stored in other
|
||||
devices like SATA, USB, NAND, SD etc.
|
||||
|
||||
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 LS2085AQDS 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,
|
||||
ls2080aqds_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 LS2085ARDB 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.
|
||||
|
||||
Note, LS2088A and LS1088A don't support booting from NAND.
|
||||
|
||||
Booting from SD/eMMC
|
||||
-------------------
|
||||
Booting from SD/eMMC requires two images, RCW and u-boot-with-spl.bin.
|
||||
The difference between SD boot RCW image and QSPI-NOR boot image is the
|
||||
PBI command sequence. Below is one example for PBI commands for RDB
|
||||
and QDS which uses SD device with block size 512. Block location can be
|
||||
calculated by dividing offset with block size.
|
||||
|
||||
1) Block Copy: SRC=0x0040, SRC_ADDR=0x00100000, DEST_ADDR=0x1800a000,
|
||||
BLOCK_SIZE=0x00016000
|
||||
|
||||
This command copies u-boot image from SD device into OCRAM. The values
|
||||
need to adjust accordingly for SD/eMMC
|
||||
|
||||
SRC should match the cfg_rcw_src, the reset config pins.
|
||||
The value for source(SRC) can be 0x0040 or 0x0041
|
||||
depending upon SD or eMMC.
|
||||
SRC_ADDR is the offset of u-boot-with-spl.bin image in SD device.
|
||||
In the example above, 1MB. This is same as QSPI-NOR.
|
||||
DEST_ADDR is configured at 0x1800a000, matching bootloc set above.
|
||||
BLOCK_SIZE is the size to be copied by PBI.
|
||||
|
||||
2) CCSR 4-byte write to 0x01e00404, data=0x00000000
|
||||
3) CCSR 4-byte write to 0x01e00400, data=0x1800a000
|
||||
The above two commands set bootloc register to 0x00000000_1800a000 where
|
||||
the u-boot code will be running in OCRAM.
|
||||
|
||||
|
||||
RCW image should be written at 8th block of device(SD/eMMC). Example of
|
||||
using u-boot command
|
||||
|
||||
mmc erase 0x8 0x10
|
||||
mmc write <rcw image in memory> 0x8 <size of rcw in block count typical value=10>
|
||||
|
||||
To form the SD-Boot image, build u-boot with SD config, for example,
|
||||
ls1088ardb_sdcard_qspi_defconfig. The image needed is u-boot-with-spl.bin.
|
||||
The u-boot image should be written to match SRC_ADDR, in above example
|
||||
offset 0x100000 in other work it means block location 0x800
|
||||
|
||||
mmc erase 0x800 0x1800
|
||||
mmc write <u-boot image in memory> 0x800 <size of u-boot image in block count>
|
||||
|
||||
With these two images in SD/eMMC device, the board can boot from SD/eMMC.
|
||||
|
||||
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 |
|
||||
------------------ ------------------
|
||||
... ...
|
||||
|
||||
|
||||
DPAA2 commands to manage Management Complex (MC)
|
||||
------------------------------------------------
|
||||
DPAA2 commands has been introduced to manage Management Complex
|
||||
(MC). These commands are used to start mc, aiop and apply DPL
|
||||
from u-boot command prompt.
|
||||
|
||||
Please note Management complex Firmware(MC), DPL and DPC are no
|
||||
more deployed during u-boot boot-sequence.
|
||||
|
||||
Commands:
|
||||
a) fsl_mc start mc <FW_addr> <DPC_addr> - Start Management Complex
|
||||
b) fsl_mc apply DPL <DPL_addr> - Apply DPL file
|
||||
c) fsl_mc start aiop <FW_addr> - Start AIOP
|
||||
|
||||
How to use commands :-
|
||||
1. Command sequence for u-boot ethernet:
|
||||
a) fsl_mc start mc <FW_addr> <DPC_addr> - Start Management Complex
|
||||
b) DPMAC net-devices are now available for use
|
||||
|
||||
Example-
|
||||
Assumption: MC firmware, DPL and DPC dtb is already programmed
|
||||
on NOR flash.
|
||||
|
||||
=> fsl_mc start mc 580300000 580800000
|
||||
=> setenv ethact DPMAC1@xgmii
|
||||
=> ping $serverip
|
||||
|
||||
2. Command sequence for Linux boot:
|
||||
a) fsl_mc start mc <FW_addr> <DPC_addr> - Start Management Complex
|
||||
b) fsl_mc apply DPL <DPL_addr> - Apply DPL file
|
||||
c) No DPMAC net-devices are available for use in u-boot
|
||||
d) boot Linux
|
||||
|
||||
Example-
|
||||
Assumption: MC firmware, DPL and DPC dtb is already programmed
|
||||
on NOR flash.
|
||||
|
||||
=> fsl_mc start mc 580300000 580800000
|
||||
=> setenv ethact DPMAC1@xgmii
|
||||
=> tftp a0000000 kernel.itb
|
||||
=> fsl_mc apply dpl 580700000
|
||||
=> bootm a0000000
|
||||
|
||||
3. Command sequence for AIOP boot:
|
||||
a) fsl_mc start mc <FW_addr> <DPC_addr> - Start Management Complex
|
||||
b) fsl_mc start aiop <FW_addr> - Start AIOP
|
||||
c) fsl_mc apply DPL <DPL_addr> - Apply DPL file
|
||||
d) No DPMAC net-devices are availabe for use in u-boot
|
||||
Please note actual AIOP start will happen during DPL parsing of
|
||||
Management complex
|
||||
|
||||
Example-
|
||||
Assumption: MC firmware, DPL, DPC dtb and AIOP firmware is already
|
||||
programmed on NOR flash.
|
||||
|
||||
=> fsl_mc start mc 580300000 580800000
|
||||
=> fsl_mc start aiop 0x580900000
|
||||
=> setenv ethact DPMAC1@xgmii
|
||||
=> fsl_mc apply dpl 580700000
|
||||
|
||||
Errata A009635
|
||||
---------------
|
||||
If the core runs at higher than x3 speed of the platform, there is
|
||||
possiblity about sev instruction to getting missed by other cores.
|
||||
This is because of SoC Run Control block may not able to sample
|
||||
the EVENTI(Sev) signals.
|
||||
|
||||
Workaround: Configure Run Control and EPU to periodically send out EVENTI signals to
|
||||
wake up A57 cores
|
||||
|
||||
Errata workaround uses Env variable "a009635_interval_val". It uses decimal
|
||||
value.
|
||||
- Default value of env variable is platform clock (MHz)
|
||||
|
||||
- User can modify default value by updating the env variable
|
||||
setenv a009635_interval_val 600; saveenv;
|
||||
It configure platform clock as 600 MHz
|
||||
|
||||
- Env variable as 0 signifies no workaround
|
||||
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# Copyright 2018 NXP
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
NXP LayerScape with Chassis Generation 3.2
|
||||
|
||||
This architecture supports NXP ARMv8 SoCs with Chassis generation 3.2
|
||||
for example LX2160A.
|
||||
|
||||
This architecture is enhancement over Chassis Generation 3 with
|
||||
few differences mentioned below
|
||||
|
||||
1)DDR Layout
|
||||
============
|
||||
Entire DDR region splits into three regions.
|
||||
- Region 1 is at address 0x8000_0000 to 0xffff_ffff.
|
||||
- Region 2 is at address 0x20_8000_0000 to 0x3f_ffff_ffff,
|
||||
- Region 3 is at address 0x60_0000_0000 to the top of memory,
|
||||
for example 140GB, 0x63_7fff_ffff.
|
||||
|
||||
All DDR memory is marked as cache-enabled.
|
||||
|
||||
2)IFC is removed
|
||||
|
||||
3)Number of I2C controllers increased to 8
|
||||
@@ -0,0 +1,42 @@
|
||||
QSPI Boot source support Overview
|
||||
-------------------
|
||||
1. LS1043A
|
||||
LS1043AQDS
|
||||
2. LS2080A
|
||||
LS2080AQDS
|
||||
3. LS1012A
|
||||
LS1012AQDS
|
||||
LS1012ARDB
|
||||
4. LS1046A
|
||||
LS1046AQDS
|
||||
LS1046ARDB
|
||||
|
||||
Booting from QSPI
|
||||
-------------------
|
||||
Booting from QSPI requires two images, RCW and u-boot-dtb.bin.
|
||||
The difference between QSPI boot RCW image and NOR boot image is the PBI
|
||||
command sequence for setting the boot location pointer. It's should point
|
||||
to the address for u-boot in QSPI flash.
|
||||
|
||||
RCW image should be written to the beginning of QSPI flash device.
|
||||
Example of using u-boot command
|
||||
|
||||
=> sf probe 0:0
|
||||
SF: Detected S25FL256S_64K with page size 256 Bytes, erase size 64 KiB, total 32 MiB
|
||||
=> sf erase 0 +<size of rcw image>
|
||||
SF: 65536 bytes @ 0x0 Erased: OK
|
||||
=> sf write <rcw image in memory> 0 <size of rcw image>
|
||||
SF: 164 bytes @ 0x0 Written: OK
|
||||
|
||||
To get the QSPI image, build u-boot with QSPI config, for example,
|
||||
<board_name>_qspi_defconfig. The image needed is u-boot-dtb.bin.
|
||||
The u-boot image should be written to 0x10000(but 0x1000 for LS1043A, LS2080A).
|
||||
|
||||
=> sf probe 0:0
|
||||
SF: Detected S25FL256S_64K with page size 256 Bytes, erase size 64 KiB, total 32 MiB
|
||||
=> sf erase 10000 +<size of u-boot image>
|
||||
SF: 589824 bytes @ 0x10000 Erased: OK
|
||||
=> sf write <u-boot image in memory> 10000 <size of u-boot image>
|
||||
SF: 580966 bytes @ 0x10000 Written: OK
|
||||
|
||||
With these two images in QSPI flash device, the board can boot from QSPI.
|
||||
@@ -0,0 +1,381 @@
|
||||
SoC overview
|
||||
|
||||
1. LS1043A
|
||||
2. LS1088A
|
||||
3. LS2080A
|
||||
4. LS1012A
|
||||
5. LS1046A
|
||||
6. LS2088A
|
||||
7. LS2081A
|
||||
8. LX2160A
|
||||
9. LS1028A
|
||||
|
||||
LS1043A
|
||||
---------
|
||||
The LS1043A integrated multicore processor combines four ARM Cortex-A53
|
||||
processor cores with datapath acceleration optimized for L2/3 packet
|
||||
processing, single pass security offload and robust traffic management
|
||||
and quality of service.
|
||||
|
||||
The LS1043A SoC includes the following function and features:
|
||||
- Four 64-bit ARM Cortex-A53 CPUs
|
||||
- 1 MB unified L2 Cache
|
||||
- One 32-bit DDR3L/DDR4 SDRAM memory controllers with ECC and interleaving
|
||||
support
|
||||
- Data Path Acceleration Architecture (DPAA) incorporating acceleration the
|
||||
the following functions:
|
||||
- Packet parsing, classification, and distribution (FMan)
|
||||
- Queue management for scheduling, packet sequencing, and congestion
|
||||
management (QMan)
|
||||
- Hardware buffer management for buffer allocation and de-allocation (BMan)
|
||||
- Cryptography acceleration (SEC)
|
||||
- Ethernet interfaces by FMan
|
||||
- Up to 1 x XFI supporting 10G interface
|
||||
- Up to 1 x QSGMII
|
||||
- Up to 4 x SGMII supporting 1000Mbps
|
||||
- Up to 2 x SGMII supporting 2500Mbps
|
||||
- Up to 2 x RGMII supporting 1000Mbps
|
||||
- High-speed peripheral interfaces
|
||||
- Three PCIe 2.0 controllers, one supporting x4 operation
|
||||
- One serial ATA (SATA 3.0) controllers
|
||||
- Additional peripheral interfaces
|
||||
- Three high-speed USB 3.0 controllers with integrated PHY
|
||||
- Enhanced secure digital host controller (eSDXC/eMMC)
|
||||
- Quad Serial Peripheral Interface (QSPI) Controller
|
||||
- Serial peripheral interface (SPI) controller
|
||||
- Four I2C controllers
|
||||
- Two DUARTs
|
||||
- Integrated flash controller supporting NAND and NOR flash
|
||||
- QorIQ platform's trust architecture 2.1
|
||||
|
||||
LS1088A
|
||||
--------
|
||||
The QorIQ LS1088A processor is built on the Layerscape
|
||||
architecture combining eight ARM A53 processor cores
|
||||
with advanced, high-performance datapath acceleration
|
||||
and networks, peripheral interfaces required for
|
||||
networking, wireless infrastructure, and general-purpose
|
||||
embedded applications.
|
||||
|
||||
LS1088A is compliant with the Layerscape Chassis Generation 3.
|
||||
|
||||
Features summary:
|
||||
- 8 32-bit / 64-bit ARM v8 Cortex-A53 CPUs
|
||||
- Cores are in 2 cluster of 4-cores each
|
||||
- 1MB L2 - Cache per cluster
|
||||
- Cache coherent interconnect (CCI-400)
|
||||
- 1 64-bit DDR4 SDRAM memory controller with ECC
|
||||
- Data path acceleration architecture 2.0 (DPAA2)
|
||||
- 4-Lane 10GHz SerDes comprising of WRIOP
|
||||
- 4-Lane 10GHz SerDes comprising of PCI, SATA, uQE(TDM/HLDC/UART)
|
||||
- Ethernet interfaces: SGMIIs, RGMIIs, QSGMIIs, XFIs
|
||||
- QSPI, SPI, IFC2.0 supporting NAND, NOR flash
|
||||
- 3 PCIe3.0 , 1 SATA3.0, 2 USB3.0, 1 SDXC, 2 DUARTs etc
|
||||
- 2 DUARTs
|
||||
- 4 I2C, GPIO
|
||||
- Thermal monitor unit(TMU)
|
||||
- 4 Flextimers and 1 generic timer
|
||||
- Support for hardware virtualization and partitioning enforcement
|
||||
- QorIQ platform's trust architecture 3.0
|
||||
- Service processor (SP) provides pre-boot initialization and secure-boot
|
||||
capabilities
|
||||
|
||||
LS2080A
|
||||
--------
|
||||
The LS2080A integrated multicore processor combines eight ARM Cortex-A57
|
||||
processor cores with high-performance data path acceleration logic and network
|
||||
and peripheral bus interfaces required for networking, telecom/datacom,
|
||||
wireless infrastructure, and mil/aerospace applications.
|
||||
|
||||
The LS2080A SoC includes the following function and features:
|
||||
|
||||
- Eight 64-bit ARM Cortex-A57 CPUs
|
||||
- 1 MB platform cache with ECC
|
||||
- Two 64-bit DDR4 SDRAM memory controllers with ECC and interleaving support
|
||||
- One secondary 32-bit DDR4 SDRAM memory controller, intended for use by
|
||||
the AIOP
|
||||
- Data path acceleration architecture (DPAA2) incorporating acceleration for
|
||||
the following functions:
|
||||
- Packet parsing, classification, and distribution (WRIOP)
|
||||
- Queue and Hardware buffer management for scheduling, packet sequencing, and
|
||||
congestion management, buffer allocation and de-allocation (QBMan)
|
||||
- Cryptography acceleration (SEC) at up to 10 Gbps
|
||||
- RegEx pattern matching acceleration (PME) at up to 10 Gbps
|
||||
- Decompression/compression acceleration (DCE) at up to 20 Gbps
|
||||
- Accelerated I/O processing (AIOP) at up to 20 Gbps
|
||||
- QDMA engine
|
||||
- 16 SerDes lanes at up to 10.3125 GHz
|
||||
- Ethernet interfaces
|
||||
- Up to eight 10 Gbps Ethernet MACs
|
||||
- Up to eight 1 / 2.5 Gbps Ethernet MACs
|
||||
- High-speed peripheral interfaces
|
||||
- Four PCIe 3.0 controllers, one supporting SR-IOV
|
||||
- Additional peripheral interfaces
|
||||
- Two serial ATA (SATA 3.0) controllers
|
||||
- Two high-speed USB 3.0 controllers with integrated PHY
|
||||
- Enhanced secure digital host controller (eSDXC/eMMC)
|
||||
- Serial peripheral interface (SPI) controller
|
||||
- Quad Serial Peripheral Interface (QSPI) Controller
|
||||
- Four I2C controllers
|
||||
- Two DUARTs
|
||||
- Integrated flash controller (IFC 2.0) supporting NAND and NOR flash
|
||||
- Support for hardware virtualization and partitioning enforcement
|
||||
- QorIQ platform's trust architecture 3.0
|
||||
- Service processor (SP) provides pre-boot initialization and secure-boot
|
||||
capabilities
|
||||
|
||||
LS1012A
|
||||
--------
|
||||
The LS1012A features an advanced 64-bit ARM v8 Cortex-
|
||||
A53 processor, with 32 KB of parity protected L1-I cache,
|
||||
32 KB of ECC protected L1-D cache, as well as 256 KB of
|
||||
ECC protected L2 cache.
|
||||
|
||||
The LS1012A SoC includes the following function and features:
|
||||
- One 64-bit ARM v8 Cortex-A53 core with the following capabilities:
|
||||
- ARM v8 cryptography extensions
|
||||
- One 16-bit DDR3L SDRAM memory controller, Up to 1.0 GT/s, Supports
|
||||
16-/8-bit operation (no ECC support)
|
||||
- ARM core-link CCI-400 cache coherent interconnect
|
||||
- Packet Forwarding Engine (PFE)
|
||||
- Cryptography acceleration (SEC)
|
||||
- Ethernet interfaces supported by PFE:
|
||||
- One Configurable x3 SerDes:
|
||||
Two Serdes PLLs supported for usage by any SerDes data lane
|
||||
Support for up to 6 GBaud operation
|
||||
- High-speed peripheral interfaces:
|
||||
- One PCI Express Gen2 controller, supporting x1 operation
|
||||
- One serial ATA (SATA Gen 3.0) controller
|
||||
- One USB 3.0/2.0 controller with integrated PHY
|
||||
- One USB 2.0 controller with ULPI interface. .
|
||||
- Additional peripheral interfaces:
|
||||
- One quad serial peripheral interface (QuadSPI) controller
|
||||
- One serial peripheral interface (SPI) controller
|
||||
- Two enhanced secure digital host controllers
|
||||
- Two I2C controllers
|
||||
- One 16550 compliant DUART (two UART interfaces)
|
||||
- Two general purpose IOs (GPIO)
|
||||
- Two FlexTimers
|
||||
- Five synchronous audio interfaces (SAI)
|
||||
- Pre-boot loader (PBL) provides pre-boot initialization and RCW loading
|
||||
- Single-source clocking solution enabling generation of core, platform,
|
||||
DDR, SerDes, and USB clocks from a single external crystal and internal
|
||||
crystaloscillator
|
||||
- Thermal monitor unit (TMU) with +/- 3C accuracy
|
||||
- Two WatchDog timers
|
||||
- ARM generic timer
|
||||
- QorIQ platform's trust architecture 2.1
|
||||
|
||||
LS1046A
|
||||
--------
|
||||
The LS1046A integrated multicore processor combines four ARM Cortex-A72
|
||||
processor cores with datapath acceleration optimized for L2/3 packet
|
||||
processing, single pass security offload and robust traffic management
|
||||
and quality of service.
|
||||
|
||||
The LS1046A SoC includes the following function and features:
|
||||
- Four 64-bit ARM Cortex-A72 CPUs
|
||||
- 2 MB unified L2 Cache
|
||||
- One 64-bit DDR4 SDRAM memory controllers with ECC and interleaving
|
||||
support
|
||||
- Data Path Acceleration Architecture (DPAA) incorporating acceleration the
|
||||
the following functions:
|
||||
- Packet parsing, classification, and distribution (FMan)
|
||||
- Queue management for scheduling, packet sequencing, and congestion
|
||||
management (QMan)
|
||||
- Hardware buffer management for buffer allocation and de-allocation (BMan)
|
||||
- Cryptography acceleration (SEC)
|
||||
- Two Configurable x4 SerDes
|
||||
- Two PLLs per four-lane SerDes
|
||||
- Support for 10G operation
|
||||
- Ethernet interfaces by FMan
|
||||
- Up to 2 x XFI supporting 10G interface (MAC 9, 10)
|
||||
- Up to 1 x QSGMII (MAC 5, 6, 10, 1)
|
||||
- Up to 4 x SGMII supporting 1000Mbps (MAC 5, 6, 9, 10)
|
||||
- Up to 3 x SGMII supporting 2500Mbps (MAC 5, 9, 10)
|
||||
- Up to 2 x RGMII supporting 1000Mbps (MAC 3, 4)
|
||||
- High-speed peripheral interfaces
|
||||
- Three PCIe 3.0 controllers, one supporting x4 operation
|
||||
- One serial ATA (SATA 3.0) controllers
|
||||
- Additional peripheral interfaces
|
||||
- Three high-speed USB 3.0 controllers with integrated PHY
|
||||
- Enhanced secure digital host controller (eSDXC/eMMC)
|
||||
- Quad Serial Peripheral Interface (QSPI) Controller
|
||||
- Serial peripheral interface (SPI) controller
|
||||
- Four I2C controllers
|
||||
- Two DUARTs
|
||||
- Integrated flash controller (IFC) supporting NAND and NOR flash
|
||||
- QorIQ platform's trust architecture 2.1
|
||||
|
||||
LS2088A
|
||||
--------
|
||||
The LS2088A integrated multicore processor combines eight ARM Cortex-A72
|
||||
processor cores with high-performance data path acceleration logic and network
|
||||
and peripheral bus interfaces required for networking, telecom/datacom,
|
||||
wireless infrastructure, and mil/aerospace applications.
|
||||
|
||||
The LS2088A SoC includes the following function and features:
|
||||
|
||||
- Eight 64-bit ARM Cortex-A72 CPUs
|
||||
- 1 MB platform cache with ECC
|
||||
- Two 64-bit DDR4 SDRAM memory controllers with ECC and interleaving support
|
||||
- One secondary 32-bit DDR4 SDRAM memory controller, intended for use by
|
||||
the AIOP
|
||||
- Data path acceleration architecture (DPAA2) incorporating acceleration for
|
||||
the following functions:
|
||||
- Packet parsing, classification, and distribution (WRIOP)
|
||||
- Queue and Hardware buffer management for scheduling, packet sequencing, and
|
||||
congestion management, buffer allocation and de-allocation (QBMan)
|
||||
- Cryptography acceleration (SEC) at up to 10 Gbps
|
||||
- RegEx pattern matching acceleration (PME) at up to 10 Gbps
|
||||
- Decompression/compression acceleration (DCE) at up to 20 Gbps
|
||||
- Accelerated I/O processing (AIOP) at up to 20 Gbps
|
||||
- QDMA engine
|
||||
- 16 SerDes lanes at up to 10.3125 GHz
|
||||
- Ethernet interfaces
|
||||
- Up to eight 10 Gbps Ethernet MACs
|
||||
- Up to eight 1 / 2.5 Gbps Ethernet MACs
|
||||
- High-speed peripheral interfaces
|
||||
- Four PCIe 3.0 controllers, one supporting SR-IOV
|
||||
- Additional peripheral interfaces
|
||||
- Two serial ATA (SATA 3.0) controllers
|
||||
- Two high-speed USB 3.0 controllers with integrated PHY
|
||||
- Enhanced secure digital host controller (eSDXC/eMMC)
|
||||
- Serial peripheral interface (SPI) controller
|
||||
- Quad Serial Peripheral Interface (QSPI) Controller
|
||||
- Four I2C controllers
|
||||
- Two DUARTs
|
||||
- Integrated flash controller (IFC 2.0) supporting NAND and NOR flash
|
||||
- Support for hardware virtualization and partitioning enforcement
|
||||
- QorIQ platform's trust architecture 3.0
|
||||
- Service processor (SP) provides pre-boot initialization and secure-boot
|
||||
capabilities
|
||||
|
||||
LS2088A SoC has 3 more similar SoC personalities
|
||||
1)LS2048A, few difference w.r.t. LS2088A:
|
||||
a) Four 64-bit ARM v8 Cortex-A72 CPUs
|
||||
|
||||
2)LS2084A, few difference w.r.t. LS2088A:
|
||||
a) No AIOP
|
||||
b) No 32-bit DDR3 SDRAM memory
|
||||
c) 5 * 1/10G + 5 *1G WRIOP
|
||||
d) No L2 switch
|
||||
|
||||
3)LS2044A, few difference w.r.t. LS2084A:
|
||||
a) Four 64-bit ARM v8 Cortex-A72 CPUs
|
||||
|
||||
LS2081A
|
||||
--------
|
||||
LS2081A is 40-pin derivative of LS2084A.
|
||||
So feature-wise it is same as LS2084A.
|
||||
Refer to LS2084A(LS2088A) section above for details.
|
||||
|
||||
It has one more similar SoC personality
|
||||
1)LS2041A, few difference w.r.t. LS2081A:
|
||||
a) Four 64-bit ARM v8 Cortex-A72 CPUs
|
||||
|
||||
LX2160A
|
||||
--------
|
||||
The QorIQ LX2160A processor is built in the 16FFC process on
|
||||
the Layerscape architecture combining sixteen ARM A72 processor
|
||||
cores with advanced, high-performance datapath acceleration and
|
||||
network, peripheral interfaces required for networking, wireless
|
||||
infrastructure, storage, and general-purpose embedded applications.
|
||||
|
||||
LX2160A is compliant with the Layerscape Chassis Generation 3.2.
|
||||
|
||||
The LX2160A SoC includes the following function and features:
|
||||
Sixteen 32-bit / 64-bit ARM v8 A72 CPUs
|
||||
Cache Coherent Interconnect Fabric (CCN508 aka “Eliot”)
|
||||
Two 64-bit 3.2GT/s DDR4 SDRAM memory controllers with ECC.
|
||||
Data path acceleration architecture (DPAA2)
|
||||
24 Serdes lanes at up to 25 GHz
|
||||
Ethernet interfaces
|
||||
Single WRIOP tile supporting 130Gbps using 18 MACs
|
||||
Support for 10G-SXGMII (aka USXGMII).
|
||||
Support for SGMII (and 1000Base-KX)
|
||||
Support for XFI (and 10GBase-KR)
|
||||
Support for CAUI4 (100G); CAUI2 (50G) and 25G-AUI(25G).
|
||||
Support for XLAUI (and 40GBase-KR4) for 40G.
|
||||
Support for two RGMII parallel interfaces.
|
||||
Energy efficient Ethernet support (802.3az)
|
||||
IEEE 1588 support.
|
||||
High-speed peripheral interfaces
|
||||
Two PCIe Gen 4.0 8-lane controllers supporting SR-IOV,
|
||||
Four PCIe Gen 4.0 4-lane controllers.
|
||||
Four serial ATA (SATA 3.0) controllers.
|
||||
Two USB 3.0 controllers with integrated PHY
|
||||
Two Enhanced secure digital host controllers
|
||||
Two Controller Area Network (CAN) modules
|
||||
Flexible Serial peripheral interface (FlexSPI) controller.
|
||||
Three Serial peripheral interface (SPI) controllers.
|
||||
Eight I2C Controllers.
|
||||
Four PL011 UARTs supporting two 4-pin UART ports or four 2-pin UART ports.
|
||||
General Purpose IO (GPIO)
|
||||
Support for hardware virtualization and partitioning (ARM MMU-500)
|
||||
Support for GIC (ARM GIC-500)
|
||||
QorIQ platform Trust Architecture 3.0
|
||||
One Secure WatchDog timer and one Non-Secure Watchdog timer.
|
||||
ARM Generic Timer
|
||||
Two Flextimers
|
||||
Debug supporting run control, data acquisition, high-speed trace,
|
||||
performance/event monitoring
|
||||
Thermal Monitor Unit (TMU) with +/- 2C accuracy
|
||||
Support for Voltage ID (VID) for yield improvement
|
||||
|
||||
LX2160A SoC has 2 more similar SoC personalities
|
||||
1)LX2120A, few difference w.r.t. LX2160A:
|
||||
a) Twelve 64-bit ARM v8 Cortex-A72 CPUs
|
||||
|
||||
2)LX2080A, few difference w.r.t. LX2160A:
|
||||
a) Eight 64-bit ARM v8 Cortex-A72 CPUs
|
||||
|
||||
|
||||
LS1028A
|
||||
--------
|
||||
The QorIQ LS1028A processor integrates two 64-bit Arm Cortex-A72 cores with
|
||||
a GPU and LCD controller, as well as two TSN-enabled Ethernet controllers and
|
||||
a TSNenabled 4-port switch.
|
||||
|
||||
The high performance Cortex-A72 cores, performing above 16,000 CoreMarks,
|
||||
combined with 2.5 Gbit Ethernet, PCI express Gen 3.0, SATA 3.0, USB 3.0 and
|
||||
Octal/Quad SPI interfaces provide capabilities for a number of industrial and
|
||||
embedded applications. The device provides excellent integration with the
|
||||
new Time-Sensitive Networking standard, and enables a number of
|
||||
TSN applications.
|
||||
|
||||
The LS1028A SoC includes the following function and features:
|
||||
- Two 64-bit ARM v8 A72 CPUs
|
||||
- Cache Coherent interconnect (CCI-400)
|
||||
- One 32-bit DDR3L/DDR4 SDRAM memory controller with ECC
|
||||
- eDP/Displayport interface
|
||||
- Graphics processing unit
|
||||
- One Configurable x4 SerDes
|
||||
- Ethernet interfaces
|
||||
- Non-switched: One Ethernet MAC supporting 2.5G, 1G, 100M, 10M, one
|
||||
ethernet MAC supporting 1G, 100M, 10M.
|
||||
- Switched: TSN IP to support four 2.5/1G interfaces.
|
||||
- None of the MACs support MACSEC
|
||||
- Support for RGMII, SGMII (and 1000Base-KX), SGMII 2.5x, QSGMII
|
||||
- Support for 10G-SXGMII and 10G-QXGMII.
|
||||
- Energy efficient Ethernet support (802.3az)
|
||||
- IEEE 1588 support
|
||||
- High-speed peripheral interfaces
|
||||
- Two PCIe 3.0 controllers, one supporting x4 operation
|
||||
- One serial ATA (SATA 3.0) controller
|
||||
- Additional peripheral interfaces
|
||||
- Two high-speed USB 2.0/3.0 controllers with integrated PHY each
|
||||
supporting host or device modes
|
||||
- Two Enhanced secure digital host controllers (SD/SDIO/eMMC)
|
||||
- Two Serial peripheral interface (SPI) controllers
|
||||
- Eight I2C controllers
|
||||
- Two UART controllers
|
||||
- Additional six Industrual UARTs (LPUART).
|
||||
- One FlexSPI controller
|
||||
- General Purpose IO (GPIO)
|
||||
- Two CAN-FD interfaces
|
||||
- Eight Flextimers with PWM I/O
|
||||
- Support for hardware virtualization and partitioning enforcement
|
||||
- Layerscape Trust Architecture
|
||||
- Service Processor (SP) provides pre-boot initialization and secure-boot
|
||||
capabilities
|
||||
@@ -0,0 +1,488 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <linux/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_SYS_DPAA_FMAN
|
||||
#include <fsl_fman.h>
|
||||
#endif
|
||||
#ifdef CONFIG_MP
|
||||
#include <asm/arch/mp.h>
|
||||
#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
|
||||
#include <asm/arch/speed.h>
|
||||
#include <fsl_qbman.h>
|
||||
|
||||
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);
|
||||
u32 mask = cpu_pos_mask();
|
||||
int off_prev = -1;
|
||||
|
||||
off = fdt_path_offset(blob, "/cpus");
|
||||
if (off < 0) {
|
||||
puts("couldn't find /cpus node\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fdt_support_default_count_cells(blob, off, &addr_cells, NULL);
|
||||
|
||||
off = fdt_node_offset_by_prop_value(blob, off_prev, "device_type",
|
||||
"cpu", 4);
|
||||
while (off != -FDT_ERR_NOTFOUND) {
|
||||
reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
|
||||
if (reg) {
|
||||
core_id = fdt_read_number(reg, addr_cells);
|
||||
if (!test_bit(id_to_core(core_id), &mask)) {
|
||||
fdt_del_node(blob, off);
|
||||
off = off_prev;
|
||||
}
|
||||
}
|
||||
off_prev = off;
|
||||
off = fdt_node_offset_by_prop_value(blob, off_prev,
|
||||
"device_type", "cpu", 4);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && \
|
||||
defined(CONFIG_SEC_FIRMWARE_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");
|
||||
return;
|
||||
}
|
||||
fdt_support_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 = fdt_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);
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER)
|
||||
efi_add_memory_map((uintptr_t)&secondary_boot_code,
|
||||
ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT,
|
||||
EFI_RESERVED_MEMORY_TYPE, false);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void fsl_fdt_disable_usb(void *blob)
|
||||
{
|
||||
int off;
|
||||
/*
|
||||
* SYSCLK is used as a reference clock for USB. When the USB
|
||||
* controller is used, SYSCLK must meet the additional requirement
|
||||
* of 100 MHz.
|
||||
*/
|
||||
if (CONFIG_SYS_CLK_FREQ != 100000000) {
|
||||
off = fdt_node_offset_by_compatible(blob, -1, "snps,dwc3");
|
||||
while (off != -FDT_ERR_NOTFOUND) {
|
||||
fdt_status_disabled(blob, off);
|
||||
off = fdt_node_offset_by_compatible(blob, off,
|
||||
"snps,dwc3");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
|
||||
static void fdt_fixup_gic(void *blob)
|
||||
{
|
||||
int offset, err;
|
||||
u64 reg[8];
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int val;
|
||||
struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
|
||||
int align_64k = 0;
|
||||
|
||||
val = gur_in32(&gur->svr);
|
||||
|
||||
if (!IS_SVR_DEV(val, SVR_DEV(SVR_LS1043A))) {
|
||||
align_64k = 1;
|
||||
} else if (SVR_REV(val) != REV1_0) {
|
||||
val = scfg_in32(&scfg->gic_align) & (0x01 << GIC_ADDR_BIT);
|
||||
if (!val)
|
||||
align_64k = 1;
|
||||
}
|
||||
|
||||
offset = fdt_subnode_offset(blob, 0, "interrupt-controller@1400000");
|
||||
if (offset < 0) {
|
||||
printf("WARNING: fdt_subnode_offset can't find node %s: %s\n",
|
||||
"interrupt-controller@1400000", fdt_strerror(offset));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fixup gic node align with 64K */
|
||||
if (align_64k) {
|
||||
reg[0] = cpu_to_fdt64(GICD_BASE_64K);
|
||||
reg[1] = cpu_to_fdt64(GICD_SIZE_64K);
|
||||
reg[2] = cpu_to_fdt64(GICC_BASE_64K);
|
||||
reg[3] = cpu_to_fdt64(GICC_SIZE_64K);
|
||||
reg[4] = cpu_to_fdt64(GICH_BASE_64K);
|
||||
reg[5] = cpu_to_fdt64(GICH_SIZE_64K);
|
||||
reg[6] = cpu_to_fdt64(GICV_BASE_64K);
|
||||
reg[7] = cpu_to_fdt64(GICV_SIZE_64K);
|
||||
} else {
|
||||
/* Fixup gic node align with default */
|
||||
reg[0] = cpu_to_fdt64(GICD_BASE);
|
||||
reg[1] = cpu_to_fdt64(GICD_SIZE);
|
||||
reg[2] = cpu_to_fdt64(GICC_BASE);
|
||||
reg[3] = cpu_to_fdt64(GICC_SIZE);
|
||||
reg[4] = cpu_to_fdt64(GICH_BASE);
|
||||
reg[5] = cpu_to_fdt64(GICH_SIZE);
|
||||
reg[6] = cpu_to_fdt64(GICV_BASE);
|
||||
reg[7] = cpu_to_fdt64(GICV_SIZE);
|
||||
}
|
||||
|
||||
err = fdt_setprop(blob, offset, "reg", reg, sizeof(reg));
|
||||
if (err < 0) {
|
||||
printf("WARNING: fdt_setprop can't set %s from node %s: %s\n",
|
||||
"reg", "interrupt-controller@1400000",
|
||||
fdt_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAS_FEATURE_ENHANCED_MSI
|
||||
static int _fdt_fixup_msi_node(void *blob, const char *name,
|
||||
int irq_0, int irq_1, int rev)
|
||||
{
|
||||
int err, offset, len;
|
||||
u32 tmp[4][3];
|
||||
void *p;
|
||||
|
||||
offset = fdt_path_offset(blob, name);
|
||||
if (offset < 0) {
|
||||
printf("WARNING: fdt_path_offset can't find path %s: %s\n",
|
||||
name, fdt_strerror(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*fixup the property of interrupts*/
|
||||
|
||||
tmp[0][0] = cpu_to_fdt32(0x0);
|
||||
tmp[0][1] = cpu_to_fdt32(irq_0);
|
||||
tmp[0][2] = cpu_to_fdt32(0x4);
|
||||
|
||||
if (rev > REV1_0) {
|
||||
tmp[1][0] = cpu_to_fdt32(0x0);
|
||||
tmp[1][1] = cpu_to_fdt32(irq_1);
|
||||
tmp[1][2] = cpu_to_fdt32(0x4);
|
||||
tmp[2][0] = cpu_to_fdt32(0x0);
|
||||
tmp[2][1] = cpu_to_fdt32(irq_1 + 1);
|
||||
tmp[2][2] = cpu_to_fdt32(0x4);
|
||||
tmp[3][0] = cpu_to_fdt32(0x0);
|
||||
tmp[3][1] = cpu_to_fdt32(irq_1 + 2);
|
||||
tmp[3][2] = cpu_to_fdt32(0x4);
|
||||
len = sizeof(tmp);
|
||||
} else {
|
||||
len = sizeof(tmp[0]);
|
||||
}
|
||||
|
||||
err = fdt_setprop(blob, offset, "interrupts", tmp, len);
|
||||
if (err < 0) {
|
||||
printf("WARNING: fdt_setprop can't set %s from node %s: %s\n",
|
||||
"interrupts", name, fdt_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*fixup the property of reg*/
|
||||
p = (char *)fdt_getprop(blob, offset, "reg", &len);
|
||||
if (!p) {
|
||||
printf("WARNING: fdt_getprop can't get %s from node %s\n",
|
||||
"reg", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy((char *)tmp, p, len);
|
||||
|
||||
if (rev > REV1_0)
|
||||
*((u32 *)tmp + 3) = cpu_to_fdt32(0x1000);
|
||||
else
|
||||
*((u32 *)tmp + 3) = cpu_to_fdt32(0x8);
|
||||
|
||||
err = fdt_setprop(blob, offset, "reg", tmp, len);
|
||||
if (err < 0) {
|
||||
printf("WARNING: fdt_setprop can't set %s from node %s: %s\n",
|
||||
"reg", name, fdt_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*fixup the property of compatible*/
|
||||
if (rev > REV1_0)
|
||||
err = fdt_setprop_string(blob, offset, "compatible",
|
||||
"fsl,ls1043a-v1.1-msi");
|
||||
else
|
||||
err = fdt_setprop_string(blob, offset, "compatible",
|
||||
"fsl,ls1043a-msi");
|
||||
if (err < 0) {
|
||||
printf("WARNING: fdt_setprop can't set %s from node %s: %s\n",
|
||||
"compatible", name, fdt_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _fdt_fixup_pci_msi(void *blob, const char *name, int rev)
|
||||
{
|
||||
int offset, len, err;
|
||||
void *p;
|
||||
int val;
|
||||
u32 tmp[4][8];
|
||||
|
||||
offset = fdt_path_offset(blob, name);
|
||||
if (offset < 0) {
|
||||
printf("WARNING: fdt_path_offset can't find path %s: %s\n",
|
||||
name, fdt_strerror(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = (char *)fdt_getprop(blob, offset, "interrupt-map", &len);
|
||||
if (!p || len != sizeof(tmp)) {
|
||||
printf("WARNING: fdt_getprop can't get %s from node %s\n",
|
||||
"interrupt-map", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy((char *)tmp, p, len);
|
||||
|
||||
val = fdt32_to_cpu(tmp[0][6]);
|
||||
if (rev == REV1_0) {
|
||||
tmp[1][6] = cpu_to_fdt32(val + 1);
|
||||
tmp[2][6] = cpu_to_fdt32(val + 2);
|
||||
tmp[3][6] = cpu_to_fdt32(val + 3);
|
||||
} else {
|
||||
tmp[1][6] = cpu_to_fdt32(val);
|
||||
tmp[2][6] = cpu_to_fdt32(val);
|
||||
tmp[3][6] = cpu_to_fdt32(val);
|
||||
}
|
||||
|
||||
err = fdt_setprop(blob, offset, "interrupt-map", tmp, sizeof(tmp));
|
||||
if (err < 0) {
|
||||
printf("WARNING: fdt_setprop can't set %s from node %s: %s.\n",
|
||||
"interrupt-map", name, fdt_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Fixup msi node for ls1043a rev1.1*/
|
||||
|
||||
static void fdt_fixup_msi(void *blob)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int rev;
|
||||
|
||||
rev = gur_in32(&gur->svr);
|
||||
|
||||
if (!IS_SVR_DEV(rev, SVR_DEV(SVR_LS1043A)))
|
||||
return;
|
||||
|
||||
rev = SVR_REV(rev);
|
||||
|
||||
_fdt_fixup_msi_node(blob, "/soc/msi-controller1@1571000",
|
||||
116, 111, rev);
|
||||
_fdt_fixup_msi_node(blob, "/soc/msi-controller2@1572000",
|
||||
126, 121, rev);
|
||||
_fdt_fixup_msi_node(blob, "/soc/msi-controller3@1573000",
|
||||
160, 155, rev);
|
||||
|
||||
_fdt_fixup_pci_msi(blob, "/soc/pcie@3400000", rev);
|
||||
_fdt_fixup_pci_msi(blob, "/soc/pcie@3500000", rev);
|
||||
_fdt_fixup_pci_msi(blob, "/soc/pcie@3600000", rev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
/* Remove JR node used by SEC firmware */
|
||||
void fdt_fixup_remove_jr(void *blob)
|
||||
{
|
||||
int jr_node, addr_cells, len;
|
||||
int crypto_node = fdt_path_offset(blob, "crypto");
|
||||
u64 jr_offset, used_jr;
|
||||
fdt32_t *reg;
|
||||
|
||||
used_jr = sec_firmware_used_jobring_offset();
|
||||
fdt_support_default_count_cells(blob, crypto_node, &addr_cells, NULL);
|
||||
|
||||
jr_node = fdt_node_offset_by_compatible(blob, crypto_node,
|
||||
"fsl,sec-v4.0-job-ring");
|
||||
|
||||
while (jr_node != -FDT_ERR_NOTFOUND) {
|
||||
reg = (fdt32_t *)fdt_getprop(blob, jr_node, "reg", &len);
|
||||
jr_offset = fdt_read_number(reg, addr_cells);
|
||||
if (jr_offset == used_jr) {
|
||||
fdt_del_node(blob, jr_node);
|
||||
break;
|
||||
}
|
||||
jr_node = fdt_node_offset_by_compatible(blob, jr_node,
|
||||
"fsl,sec-v4.0-job-ring");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_LS1028A
|
||||
static void fdt_disable_multimedia(void *blob, unsigned int svr)
|
||||
{
|
||||
int off;
|
||||
|
||||
if (IS_MULTIMEDIA_EN(svr))
|
||||
return;
|
||||
|
||||
/* Disable eDP/LCD node */
|
||||
off = fdt_node_offset_by_compatible(blob, -1, "arm,mali-dp500");
|
||||
if (off != -FDT_ERR_NOTFOUND)
|
||||
fdt_status_disabled(blob, off);
|
||||
|
||||
/* Disable GPU node */
|
||||
off = fdt_node_offset_by_compatible(blob, -1, "fsl,ls1028a-gpu");
|
||||
if (off != -FDT_ERR_NOTFOUND)
|
||||
fdt_status_disabled(blob, off);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ft_cpu_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int svr = gur_in32(&gur->svr);
|
||||
|
||||
/* delete crypto node if not on an E-processor */
|
||||
if (!IS_E_PROCESSOR(svr))
|
||||
fdt_fixup_crypto_node(blob, 0);
|
||||
#if CONFIG_SYS_FSL_SEC_COMPAT >= 4
|
||||
else {
|
||||
ccsr_sec_t __iomem *sec;
|
||||
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
fdt_fixup_remove_jr(blob);
|
||||
fdt_fixup_kaslr(blob);
|
||||
#endif
|
||||
|
||||
sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
fdt_fixup_crypto_node(blob, sec_in32(&sec->secvid_ms));
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
do_fixup_by_path_u32(blob, "/sysclk", "clock-frequency",
|
||||
CONFIG_SYS_CLK_FREQ, 1);
|
||||
|
||||
#if defined(CONFIG_PCIE_LAYERSCAPE) || defined(CONFIG_PCIE_LAYERSCAPE_GEN4)
|
||||
ft_pci_setup(blob, bd);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
fdt_fixup_esdhc(blob, bd);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
fdt_fixup_bportals(blob);
|
||||
fdt_fixup_qportals(blob);
|
||||
do_fixup_by_compat_u32(blob, "fsl,qman",
|
||||
"clock-frequency", get_qman_freq(), 1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
fdt_fixup_fman_firmware(blob);
|
||||
#endif
|
||||
#ifndef CONFIG_ARCH_LS1012A
|
||||
fsl_fdt_disable_usb(blob);
|
||||
#endif
|
||||
#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
|
||||
fdt_fixup_gic(blob);
|
||||
#endif
|
||||
#ifdef CONFIG_HAS_FEATURE_ENHANCED_MSI
|
||||
fdt_fixup_msi(blob);
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_LS1028A
|
||||
fdt_disable_multimedia(blob, svr);
|
||||
#endif
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/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
|
||||
#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
|
||||
if (!serdes1_prtcl_map[NONE])
|
||||
fsl_serdes_init();
|
||||
|
||||
ret |= serdes1_prtcl_map[device];
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
if (!serdes2_prtcl_map[NONE])
|
||||
fsl_serdes_init();
|
||||
|
||||
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[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
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
case FSL_SRDS_2:
|
||||
cfg &= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS2_RCWSR4_SRDS2_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;
|
||||
|
||||
if (serdes_prtcl_map[NONE])
|
||||
return;
|
||||
|
||||
memset(serdes_prtcl_map, 0, sizeof(u8) * SERDES_PRCTL_COUNT);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Set the first element to indicate serdes has been initialized */
|
||||
serdes_prtcl_map[NONE] = 1;
|
||||
}
|
||||
|
||||
__weak int get_serdes_volt(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
__weak int set_serdes_volt(int svdd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int setup_serdes_volt(u32 svdd)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
struct ccsr_serdes *serdes1_base;
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
struct ccsr_serdes *serdes2_base;
|
||||
#endif
|
||||
u32 cfg_rcw4 = gur_in32(&gur->rcwsr[4]);
|
||||
u32 cfg_rcw5 = gur_in32(&gur->rcwsr[5]);
|
||||
u32 cfg_tmp, reg = 0;
|
||||
int svdd_cur, svdd_tar;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Only support switch SVDD to 900mV/1000mV */
|
||||
if (svdd != 900 && svdd != 1000)
|
||||
return -EINVAL;
|
||||
|
||||
svdd_tar = svdd;
|
||||
svdd_cur = get_serdes_volt();
|
||||
if (svdd_cur < 0)
|
||||
return -EINVAL;
|
||||
|
||||
debug("%s: current SVDD: %dmV; target SVDD: %dmV\n",
|
||||
__func__, svdd_cur, svdd_tar);
|
||||
if (svdd_cur == svdd_tar)
|
||||
return 0;
|
||||
|
||||
serdes1_base = (void *)CONFIG_SYS_FSL_SERDES_ADDR;
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
serdes2_base = (void *)serdes1_base + 0x10000;
|
||||
#endif
|
||||
|
||||
/* Put the all enabled lanes in reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes1_base->lane[i].gcr0);
|
||||
reg &= 0xFF9FFFFF;
|
||||
out_be32(&serdes1_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes2_base->lane[i].gcr0);
|
||||
reg &= 0xFF9FFFFF;
|
||||
out_be32(&serdes2_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Put the all enabled PLL in reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFBF;
|
||||
reg |= 0x10000000;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFF1F;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
}
|
||||
udelay(1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFBF;
|
||||
reg |= 0x10000000;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFF1F;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
}
|
||||
udelay(1);
|
||||
#endif
|
||||
|
||||
/* Put the Rx/Tx calibration into reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
reg = in_be32(&serdes1_base->srdstcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes1_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes1_base->srdsrcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes1_base->srdsrcalcr, reg);
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
reg = in_be32(&serdes2_base->srdstcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes2_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes2_base->srdsrcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes2_base->srdsrcalcr, reg);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If SVDD set failed, will not return directly, so that the
|
||||
* serdes lanes can complete reseting.
|
||||
*/
|
||||
ret = set_serdes_volt(svdd_tar);
|
||||
if (ret)
|
||||
printf("%s: Failed to set SVDD\n", __func__);
|
||||
|
||||
/* Wait for SVDD to stabilize */
|
||||
udelay(100);
|
||||
|
||||
/* For each PLL that’s not disabled via RCW */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x00000020;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x00000080;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
|
||||
/* Take the Rx/Tx calibration out of reset */
|
||||
if (!(cfg_tmp == 0x3 && i == 1)) {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes1_base->srdstcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes1_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes1_base->srdsrcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes1_base->srdsrcalcr, reg);
|
||||
}
|
||||
}
|
||||
udelay(1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x00000020;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x00000080;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
|
||||
/* Take the Rx/Tx calibration out of reset */
|
||||
if (!(cfg_tmp == 0x3 && i == 1)) {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes2_base->srdstcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes2_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes2_base->srdsrcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes2_base->srdsrcalcr, reg);
|
||||
}
|
||||
}
|
||||
udelay(1);
|
||||
|
||||
#endif
|
||||
|
||||
/* Wait for at lesat 625us to ensure the PLLs being reset are locked */
|
||||
udelay(800);
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
/* if the PLL is not locked, set RST_ERR */
|
||||
reg = in_be32(&serdes1_base->bank[i].pllcr0);
|
||||
if (!((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x20000000;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
} else {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFEF;
|
||||
reg |= 0x00000040;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].pllcr0);
|
||||
if (!((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x20000000;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
} else {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFEF;
|
||||
reg |= 0x00000040;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Take the all enabled lanes out of reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes1_base->lane[i].gcr0);
|
||||
reg |= 0x00600000;
|
||||
out_be32(&serdes1_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes2_base->lane[i].gcr0);
|
||||
reg |= 0x00600000;
|
||||
out_be32(&serdes2_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
/* For each PLL being reset, and achieved PLL lock set RST_DONE */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2; i++) {
|
||||
reg = in_be32(&serdes1_base->bank[i].pllcr0);
|
||||
if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x40000000;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2; i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].pllcr0);
|
||||
if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x40000000;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
serdes_init(FSL_SRDS_2,
|
||||
CONFIG_SYS_FSL_SERDES_ADDR,
|
||||
FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK,
|
||||
FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT,
|
||||
serdes2_prtcl_map);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
* Copyright 2019 NXP.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.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>
|
||||
#include "cpu.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);
|
||||
/* rcw_tmp is needed to get FMAN clock, or to get cluster group A
|
||||
* mux 2 clock for LS1043A/LS1046A.
|
||||
*/
|
||||
#if defined(CONFIG_SYS_DPAA_FMAN) || \
|
||||
defined(CONFIG_TARGET_LS1046ARDB) || \
|
||||
defined(CONFIG_TARGET_LS1043ARDB)
|
||||
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, 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;
|
||||
unsigned long cluster_clk;
|
||||
|
||||
sys_info->freq_systembus = sysclk;
|
||||
#ifndef CONFIG_CLUSTER_CLK_FREQ
|
||||
#define CONFIG_CLUSTER_CLK_FREQ CONFIG_SYS_CLK_FREQ
|
||||
#endif
|
||||
cluster_clk = CONFIG_CLUSTER_CLK_FREQ;
|
||||
|
||||
#ifdef CONFIG_DDR_CLK_FREQ
|
||||
sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
|
||||
#else
|
||||
sys_info->freq_ddrbus = sysclk;
|
||||
#endif
|
||||
|
||||
/* The freq_systembus is used to record frequency of platform PLL */
|
||||
sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
|
||||
|
||||
#ifdef CONFIG_ARCH_LS1012A
|
||||
sys_info->freq_ddrbus = 2 * sys_info->freq_systembus;
|
||||
#else
|
||||
sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_MASK;
|
||||
#endif
|
||||
|
||||
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] = cluster_clk * ratio[i];
|
||||
else
|
||||
freq_c_pll[i] = sys_info->freq_systembus * ratio[i];
|
||||
}
|
||||
|
||||
for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) {
|
||||
cluster = fsl_qoriq_core_to_cluster(cpu);
|
||||
u32 c_pll_sel = (in_be32(&clk->clkcsr[cluster].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 4:
|
||||
sys_info->freq_fman[0] = freq_c_pll[0] / 4;
|
||||
break;
|
||||
case 5:
|
||||
sys_info->freq_fman[0] = sys_info->freq_systembus;
|
||||
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
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
#define HWA_CGA_M2_CLK_SEL 0x00000007
|
||||
#define HWA_CGA_M2_CLK_SHIFT 0
|
||||
#if defined(CONFIG_TARGET_LS1046ARDB) || defined(CONFIG_TARGET_LS1043ARDB)
|
||||
rcw_tmp = in_be32(&gur->rcwsr[15]);
|
||||
switch ((rcw_tmp & HWA_CGA_M2_CLK_SEL) >> HWA_CGA_M2_CLK_SHIFT) {
|
||||
case 1:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1];
|
||||
break;
|
||||
#if defined(CONFIG_TARGET_LS1046ARDB)
|
||||
case 2:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1] / 2;
|
||||
break;
|
||||
#endif
|
||||
case 3:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1] / 3;
|
||||
break;
|
||||
#if defined(CONFIG_TARGET_LS1046ARDB)
|
||||
case 6:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[0] / 2;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("Error: Unknown peripheral clock select!\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_IFC)
|
||||
sys_info->freq_localbus = sys_info->freq_systembus /
|
||||
CONFIG_SYS_FSL_IFC_CLK_DIV;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
sys_info->freq_qman = (sys_info->freq_systembus /
|
||||
CONFIG_SYS_FSL_PCLK_DIV) /
|
||||
CONFIG_SYS_FSL_QMAN_CLK_DIV;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
unsigned long get_qman_freq(void)
|
||||
{
|
||||
struct sys_info sys_info;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
|
||||
return sys_info.freq_qman;
|
||||
}
|
||||
#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 / CONFIG_SYS_FSL_PCLK_DIV;
|
||||
gd->mem_clk = sys_info.freq_ddrbus;
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
#if defined(CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK)
|
||||
#if defined(CONFIG_TARGET_LS1046ARDB)
|
||||
gd->arch.sdhc_clk = sys_info.freq_cga_m2 / 2;
|
||||
#endif
|
||||
#if defined(CONFIG_TARGET_LS1043ARDB)
|
||||
gd->arch.sdhc_clk = sys_info.freq_cga_m2;
|
||||
#endif
|
||||
#if defined(CONFIG_TARGET_LS1012ARDB)
|
||||
gd->arch.sdhc_clk = sys_info.freq_systembus;
|
||||
#endif
|
||||
#else
|
||||
gd->arch.sdhc_clk = (sys_info.freq_systembus /
|
||||
CONFIG_SYS_FSL_PCLK_DIV) /
|
||||
CONFIG_SYS_FSL_SDHC_CLK_DIV;
|
||||
#endif
|
||||
#endif
|
||||
if (gd->cpu_clk != 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* get_bus_freq
|
||||
* return platform clock in Hz
|
||||
*********************************************/
|
||||
ulong get_bus_freq(ulong dummy)
|
||||
{
|
||||
if (!gd->bus_clk)
|
||||
get_clocks();
|
||||
|
||||
return gd->bus_clk;
|
||||
}
|
||||
|
||||
ulong get_ddr_freq(ulong dummy)
|
||||
{
|
||||
if (!gd->mem_clk)
|
||||
get_clocks();
|
||||
|
||||
return gd->mem_clk;
|
||||
}
|
||||
|
||||
int get_serial_clock(void)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_DUART_CLK_DIV;
|
||||
}
|
||||
|
||||
int get_i2c_freq(ulong dummy)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_I2C_CLK_DIV;
|
||||
}
|
||||
|
||||
int get_dspi_freq(ulong dummy)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_DSPI_CLK_DIV;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_LPUART
|
||||
int get_uart_freq(ulong dummy)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_LPUART_CLK_DIV;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_I2C_CLK:
|
||||
return get_i2c_freq(0);
|
||||
case MXC_DSPI_CLK:
|
||||
return get_dspi_freq(0);
|
||||
#ifdef CONFIG_FSL_LPUART
|
||||
case MXC_UART_CLK:
|
||||
return get_uart_freq(0);
|
||||
#endif
|
||||
default:
|
||||
printf("Unsupported clock\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+602
@@ -0,0 +1,602 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016-2018 NXP
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/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
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
static u8 serdes3_prtcl_map[SERDES_PRCTL_COUNT];
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
|
||||
#ifdef CONFIG_ARCH_LX2160A
|
||||
int xfi_dpmac[XFI14 + 1];
|
||||
int sgmii_dpmac[SGMII18 + 1];
|
||||
int a25gaui_dpmac[_25GE10 + 1];
|
||||
int xlaui_dpmac[_40GE2 + 1];
|
||||
int caui2_dpmac[_50GE2 + 1];
|
||||
int caui4_dpmac[_100GE2 + 1];
|
||||
#else
|
||||
int xfi_dpmac[XFI8 + 1];
|
||||
int sgmii_dpmac[SGMII16 + 1];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__weak void wriop_init_dpmac_qsgmii(int sd, int lane_prtcl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
*The return value of this func is the serdes protocol used.
|
||||
*Typically this function is called number of times depending
|
||||
*upon the number of serdes blocks in the Silicon.
|
||||
*Zero is used to denote that no serdes was enabled,
|
||||
*this is the case when golden RCW was used where DPAA2 bring was
|
||||
*intentionally removed to achieve boot to prompt
|
||||
*/
|
||||
|
||||
__weak int serdes_get_number(int serdes, int cfg)
|
||||
{
|
||||
return cfg;
|
||||
}
|
||||
|
||||
int is_serdes_configured(enum srds_prtcl device)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
if (!serdes1_prtcl_map[NONE])
|
||||
fsl_serdes_init();
|
||||
|
||||
ret |= serdes1_prtcl_map[device];
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
if (!serdes2_prtcl_map[NONE])
|
||||
fsl_serdes_init();
|
||||
|
||||
ret |= serdes2_prtcl_map[device];
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
if (!serdes3_prtcl_map[NONE])
|
||||
fsl_serdes_init();
|
||||
|
||||
ret |= serdes3_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 = 0;
|
||||
int i;
|
||||
|
||||
switch (sd) {
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
case FSL_SRDS_1:
|
||||
cfg = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS1_REGSR - 1]);
|
||||
cfg &= FSL_CHASSIS3_SRDS1_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS3_SRDS1_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
case FSL_SRDS_2:
|
||||
cfg = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS2_REGSR - 1]);
|
||||
cfg &= FSL_CHASSIS3_SRDS2_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS3_SRDS2_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
case NXP_SRDS_3:
|
||||
cfg = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS3_REGSR - 1]);
|
||||
cfg &= FSL_CHASSIS3_SRDS3_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS3_SRDS3_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("invalid SerDes%d\n", sd);
|
||||
break;
|
||||
}
|
||||
|
||||
cfg = serdes_get_number(sd, cfg);
|
||||
|
||||
/* 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 rcwsr, 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;
|
||||
|
||||
if (serdes_prtcl_map[NONE])
|
||||
return;
|
||||
|
||||
memset(serdes_prtcl_map, 0, sizeof(u8) * SERDES_PRCTL_COUNT);
|
||||
|
||||
cfg = gur_in32(&gur->rcwsr[rcwsr - 1]) & sd_prctl_mask;
|
||||
cfg >>= sd_prctl_shift;
|
||||
|
||||
cfg = serdes_get_number(sd, cfg);
|
||||
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;
|
||||
#if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
|
||||
#ifdef CONFIG_ARCH_LX2160A
|
||||
if (lane_prtcl >= XFI1 && lane_prtcl <= XFI14)
|
||||
wriop_init_dpmac(sd, xfi_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
if (lane_prtcl >= SGMII1 && lane_prtcl <= SGMII18)
|
||||
wriop_init_dpmac(sd, sgmii_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
if (lane_prtcl >= _25GE1 && lane_prtcl <= _25GE10)
|
||||
wriop_init_dpmac(sd, a25gaui_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
if (lane_prtcl >= _40GE1 && lane_prtcl <= _40GE2)
|
||||
wriop_init_dpmac(sd, xlaui_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
if (lane_prtcl >= _50GE1 && lane_prtcl <= _50GE2)
|
||||
wriop_init_dpmac(sd, caui2_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
if (lane_prtcl >= _100GE1 && lane_prtcl <= _100GE2)
|
||||
wriop_init_dpmac(sd, caui4_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
#else
|
||||
switch (lane_prtcl) {
|
||||
case QSGMII_A:
|
||||
case QSGMII_B:
|
||||
case QSGMII_C:
|
||||
case QSGMII_D:
|
||||
wriop_init_dpmac_qsgmii(sd, (int)lane_prtcl);
|
||||
break;
|
||||
default:
|
||||
if (lane_prtcl >= XFI1 && lane_prtcl <= XFI8)
|
||||
wriop_init_dpmac(sd,
|
||||
xfi_dpmac[lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
|
||||
if (lane_prtcl >= SGMII1 &&
|
||||
lane_prtcl <= SGMII16)
|
||||
wriop_init_dpmac(sd, sgmii_dpmac[
|
||||
lane_prtcl],
|
||||
(int)lane_prtcl);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the first element to indicate serdes has been initialized */
|
||||
serdes_prtcl_map[NONE] = 1;
|
||||
}
|
||||
|
||||
__weak int get_serdes_volt(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
__weak int set_serdes_volt(int svdd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define LNAGCR0_RT_RSTB 0x00600000
|
||||
|
||||
#define RSTCTL_RESET_MASK 0x000000E0
|
||||
|
||||
#define RSTCTL_RSTREQ 0x80000000
|
||||
#define RSTCTL_RST_DONE 0x40000000
|
||||
#define RSTCTL_RSTERR 0x20000000
|
||||
|
||||
#define RSTCTL_SDEN 0x00000020
|
||||
#define RSTCTL_SDRST_B 0x00000040
|
||||
#define RSTCTL_PLLRST_B 0x00000080
|
||||
|
||||
#define TCALCR_CALRST_B 0x08000000
|
||||
|
||||
struct serdes_prctl_info {
|
||||
u32 id;
|
||||
u32 mask;
|
||||
u32 shift;
|
||||
};
|
||||
|
||||
struct serdes_prctl_info srds_prctl_info[] = {
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
{.id = 1,
|
||||
.mask = FSL_CHASSIS3_SRDS1_PRTCL_MASK,
|
||||
.shift = FSL_CHASSIS3_SRDS1_PRTCL_SHIFT
|
||||
},
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
{.id = 2,
|
||||
.mask = FSL_CHASSIS3_SRDS2_PRTCL_MASK,
|
||||
.shift = FSL_CHASSIS3_SRDS2_PRTCL_SHIFT
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
{.id = 3,
|
||||
.mask = FSL_CHASSIS3_SRDS3_PRTCL_MASK,
|
||||
.shift = FSL_CHASSIS3_SRDS3_PRTCL_SHIFT
|
||||
},
|
||||
#endif
|
||||
{} /* NULL ENTRY */
|
||||
};
|
||||
|
||||
static int get_serdes_prctl_info_idx(u32 serdes_id)
|
||||
{
|
||||
int pos = 0;
|
||||
struct serdes_prctl_info *srds_info;
|
||||
|
||||
/* loop until NULL ENTRY defined by .id=0 */
|
||||
for (srds_info = srds_prctl_info; srds_info->id != 0;
|
||||
srds_info++, pos++) {
|
||||
if (srds_info->id == serdes_id)
|
||||
return pos;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void do_enabled_lanes_reset(u32 serdes_id, u32 cfg,
|
||||
struct ccsr_serdes __iomem *serdes_base,
|
||||
bool cmplt)
|
||||
{
|
||||
int i, pos;
|
||||
u32 cfg_tmp;
|
||||
|
||||
pos = get_serdes_prctl_info_idx(serdes_id);
|
||||
if (pos == -1) {
|
||||
printf("invalid serdes_id %d\n", serdes_id);
|
||||
return;
|
||||
}
|
||||
|
||||
cfg_tmp = cfg & srds_prctl_info[pos].mask;
|
||||
cfg_tmp >>= srds_prctl_info[pos].shift;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
if (cmplt)
|
||||
setbits_le32(&serdes_base->lane[i].gcr0,
|
||||
LNAGCR0_RT_RSTB);
|
||||
else
|
||||
clrbits_le32(&serdes_base->lane[i].gcr0,
|
||||
LNAGCR0_RT_RSTB);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_pll_reset(u32 cfg,
|
||||
struct ccsr_serdes __iomem *serdes_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2 && !(cfg & (0x1 << (1 - i))); i++) {
|
||||
clrbits_le32(&serdes_base->bank[i].rstctl,
|
||||
RSTCTL_RESET_MASK);
|
||||
udelay(1);
|
||||
|
||||
setbits_le32(&serdes_base->bank[i].rstctl,
|
||||
RSTCTL_RSTREQ);
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static void do_rx_tx_cal_reset(struct ccsr_serdes __iomem *serdes_base)
|
||||
{
|
||||
clrbits_le32(&serdes_base->srdstcalcr, TCALCR_CALRST_B);
|
||||
clrbits_le32(&serdes_base->srdstcalcr, TCALCR_CALRST_B);
|
||||
}
|
||||
|
||||
static void do_rx_tx_cal_reset_comp(u32 cfg, int i,
|
||||
struct ccsr_serdes __iomem *serdes_base)
|
||||
{
|
||||
if (!(cfg == 0x3 && i == 1)) {
|
||||
udelay(1);
|
||||
setbits_le32(&serdes_base->srdstcalcr, TCALCR_CALRST_B);
|
||||
setbits_le32(&serdes_base->srdstcalcr, TCALCR_CALRST_B);
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static void do_pll_reset_done(u32 cfg,
|
||||
struct ccsr_serdes __iomem *serdes_base)
|
||||
{
|
||||
int i;
|
||||
u32 reg = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
reg = in_le32(&serdes_base->bank[i].pllcr0);
|
||||
if (!(cfg & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
||||
setbits_le32(&serdes_base->bank[i].rstctl,
|
||||
RSTCTL_RST_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_serdes_enable(u32 cfg,
|
||||
struct ccsr_serdes __iomem *serdes_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2 && !(cfg & (0x1 << (1 - i))); i++) {
|
||||
setbits_le32(&serdes_base->bank[i].rstctl, RSTCTL_SDEN);
|
||||
udelay(1);
|
||||
|
||||
setbits_le32(&serdes_base->bank[i].rstctl, RSTCTL_PLLRST_B);
|
||||
udelay(1);
|
||||
/* Take the Rx/Tx calibration out of reset */
|
||||
do_rx_tx_cal_reset_comp(cfg, i, serdes_base);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_pll_lock(u32 cfg,
|
||||
struct ccsr_serdes __iomem *serdes_base)
|
||||
{
|
||||
int i;
|
||||
u32 reg = 0;
|
||||
|
||||
for (i = 0; i < 2 && !(cfg & (0x1 << (1 - i))); i++) {
|
||||
/* if the PLL is not locked, set RST_ERR */
|
||||
reg = in_le32(&serdes_base->bank[i].pllcr0);
|
||||
if (!((reg >> 23) & 0x1)) {
|
||||
setbits_le32(&serdes_base->bank[i].rstctl,
|
||||
RSTCTL_RSTERR);
|
||||
} else {
|
||||
udelay(1);
|
||||
setbits_le32(&serdes_base->bank[i].rstctl,
|
||||
RSTCTL_SDRST_B);
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int setup_serdes_volt(u32 svdd)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
struct ccsr_serdes __iomem *serdes1_base =
|
||||
(void *)CONFIG_SYS_FSL_LSCH3_SERDES_ADDR;
|
||||
u32 cfg_rcwsrds1 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS1_REGSR - 1]);
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
struct ccsr_serdes __iomem *serdes2_base =
|
||||
(void *)(CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + 0x10000);
|
||||
u32 cfg_rcwsrds2 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS2_REGSR - 1]);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
struct ccsr_serdes __iomem *serdes3_base =
|
||||
(void *)(CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + 0x20000);
|
||||
u32 cfg_rcwsrds3 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS3_REGSR - 1]);
|
||||
#endif
|
||||
u32 cfg_tmp;
|
||||
int svdd_cur, svdd_tar;
|
||||
int ret = 1;
|
||||
|
||||
/* Only support switch SVDD to 900mV */
|
||||
if (svdd != 900)
|
||||
return -EINVAL;
|
||||
|
||||
/* Scale up to the LTC resolution is 1/4096V */
|
||||
svdd = (svdd * 4096) / 1000;
|
||||
|
||||
svdd_tar = svdd;
|
||||
svdd_cur = get_serdes_volt();
|
||||
if (svdd_cur < 0)
|
||||
return -EINVAL;
|
||||
|
||||
debug("%s: current SVDD: %x; target SVDD: %x\n",
|
||||
__func__, svdd_cur, svdd_tar);
|
||||
if (svdd_cur == svdd_tar)
|
||||
return 0;
|
||||
|
||||
/* Put the all enabled lanes in reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
do_enabled_lanes_reset(1, cfg_rcwsrds1, serdes1_base, false);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
do_enabled_lanes_reset(2, cfg_rcwsrds2, serdes2_base, false);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
do_enabled_lanes_reset(3, cfg_rcwsrds3, serdes3_base, false);
|
||||
#endif
|
||||
|
||||
/* Put the all enabled PLL in reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcwsrds1 & 0x3;
|
||||
do_pll_reset(cfg_tmp, serdes1_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcwsrds1 & 0xC;
|
||||
cfg_tmp >>= 2;
|
||||
do_pll_reset(cfg_tmp, serdes2_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
cfg_tmp = cfg_rcwsrds3 & 0x30;
|
||||
cfg_tmp >>= 4;
|
||||
do_pll_reset(cfg_tmp, serdes3_base);
|
||||
#endif
|
||||
|
||||
/* Put the Rx/Tx calibration into reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
do_rx_tx_cal_reset(serdes1_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
do_rx_tx_cal_reset(serdes2_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
do_rx_tx_cal_reset(serdes3_base);
|
||||
#endif
|
||||
|
||||
ret = set_serdes_volt(svdd);
|
||||
if (ret < 0) {
|
||||
printf("could not change SVDD\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/* For each PLL that’s not disabled via RCW enable the SERDES */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcwsrds1 & 0x3;
|
||||
do_serdes_enable(cfg_tmp, serdes1_base);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcwsrds1 & 0xC;
|
||||
cfg_tmp >>= 2;
|
||||
do_serdes_enable(cfg_tmp, serdes2_base);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
cfg_tmp = cfg_rcwsrds3 & 0x30;
|
||||
cfg_tmp >>= 4;
|
||||
do_serdes_enable(cfg_tmp, serdes3_base);
|
||||
#endif
|
||||
|
||||
/* Wait for at at least 625us, ensure the PLLs being reset are locked */
|
||||
udelay(800);
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcwsrds1 & 0x3;
|
||||
do_pll_lock(cfg_tmp, serdes1_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcwsrds1 & 0xC;
|
||||
cfg_tmp >>= 2;
|
||||
do_pll_lock(cfg_tmp, serdes2_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
cfg_tmp = cfg_rcwsrds3 & 0x30;
|
||||
cfg_tmp >>= 4;
|
||||
do_pll_lock(cfg_tmp, serdes3_base);
|
||||
#endif
|
||||
|
||||
/* Take the all enabled lanes out of reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
do_enabled_lanes_reset(1, cfg_rcwsrds1, serdes1_base, true);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
do_enabled_lanes_reset(2, cfg_rcwsrds2, serdes2_base, true);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
do_enabled_lanes_reset(3, cfg_rcwsrds3, serdes3_base, true);
|
||||
#endif
|
||||
|
||||
/* For each PLL being reset, and achieved PLL lock set RST_DONE */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcwsrds1 & 0x3;
|
||||
do_pll_reset_done(cfg_tmp, serdes1_base);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcwsrds1 & 0xC;
|
||||
cfg_tmp >>= 2;
|
||||
do_pll_reset_done(cfg_tmp, serdes2_base);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
cfg_tmp = cfg_rcwsrds3 & 0x30;
|
||||
cfg_tmp >>= 4;
|
||||
do_pll_reset_done(cfg_tmp, serdes3_base);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fsl_serdes_init(void)
|
||||
{
|
||||
#if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
|
||||
int i , j;
|
||||
|
||||
#ifdef CONFIG_ARCH_LX2160A
|
||||
for (i = XFI1, j = 1; i <= XFI14; i++, j++)
|
||||
xfi_dpmac[i] = j;
|
||||
|
||||
for (i = SGMII1, j = 1; i <= SGMII18; i++, j++)
|
||||
sgmii_dpmac[i] = j;
|
||||
|
||||
for (i = _25GE1, j = 1; i <= _25GE10; i++, j++)
|
||||
a25gaui_dpmac[i] = j;
|
||||
|
||||
for (i = _40GE1, j = 1; i <= _40GE2; i++, j++)
|
||||
xlaui_dpmac[i] = j;
|
||||
|
||||
for (i = _50GE1, j = 1; i <= _50GE2; i++, j++)
|
||||
caui2_dpmac[i] = j;
|
||||
|
||||
for (i = _100GE1, j = 1; i <= _100GE2; i++, j++)
|
||||
caui4_dpmac[i] = j;
|
||||
#else
|
||||
for (i = XFI1, j = 1; i <= XFI8; i++, j++)
|
||||
xfi_dpmac[i] = j;
|
||||
|
||||
for (i = SGMII1, j = 1; i <= SGMII16; i++, j++)
|
||||
sgmii_dpmac[i] = j;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
serdes_init(FSL_SRDS_1,
|
||||
CONFIG_SYS_FSL_LSCH3_SERDES_ADDR,
|
||||
FSL_CHASSIS3_SRDS1_REGSR,
|
||||
FSL_CHASSIS3_SRDS1_PRTCL_MASK,
|
||||
FSL_CHASSIS3_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_SRDS2_REGSR,
|
||||
FSL_CHASSIS3_SRDS2_PRTCL_MASK,
|
||||
FSL_CHASSIS3_SRDS2_PRTCL_SHIFT,
|
||||
serdes2_prtcl_map);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NXP_SRDS_3
|
||||
serdes_init(NXP_SRDS_3,
|
||||
CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + NXP_SRDS_3 * 0x10000,
|
||||
FSL_CHASSIS3_SRDS3_REGSR,
|
||||
FSL_CHASSIS3_SRDS3_PRTCL_MASK,
|
||||
FSL_CHASSIS3_SRDS3_PRTCL_SHIFT,
|
||||
serdes3_prtcl_map);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014-2015, Freescale Semiconductor, Inc.
|
||||
* Copyright 2019 NXP Semiconductors
|
||||
*
|
||||
* Derived from arch/power/cpu/mpc85xx/speed.c
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <fsl_ifc.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch3.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);
|
||||
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;
|
||||
#if defined(CONFIG_ARCH_LS1028A) || defined(CONFIG_ARCH_LS1088A)
|
||||
uint rcw_tmp;
|
||||
#endif
|
||||
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;
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
sys_info->freq_ddrbus2 = CONFIG_DDR_CLK_FREQ;
|
||||
#endif
|
||||
#else
|
||||
sys_info->freq_ddrbus = sysclk;
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
sys_info->freq_ddrbus2 = sysclk;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The freq_systembus is used to record frequency of platform PLL */
|
||||
sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK;
|
||||
sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK;
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
if (soc_has_dp_ddr()) {
|
||||
sys_info->freq_ddrbus2 *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_MASK;
|
||||
} else {
|
||||
sys_info->freq_ddrbus2 = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
||||
sys_info->freq_localbus = sys_info->freq_systembus /
|
||||
CONFIG_SYS_FSL_IFC_CLK_DIV;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1028A) || defined(CONFIG_ARCH_LS1088A)
|
||||
#define HWA_CGA_M2_CLK_SEL 0x00380000
|
||||
#define HWA_CGA_M2_CLK_SHIFT 19
|
||||
rcw_tmp = in_le32(&gur->rcwsr[5]);
|
||||
switch ((rcw_tmp & HWA_CGA_M2_CLK_SEL) >> HWA_CGA_M2_CLK_SHIFT) {
|
||||
case 1:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1];
|
||||
break;
|
||||
case 2:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1] / 2;
|
||||
break;
|
||||
case 3:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1] / 3;
|
||||
break;
|
||||
case 4:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[1] / 4;
|
||||
break;
|
||||
case 6:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[0] / 2;
|
||||
break;
|
||||
case 7:
|
||||
sys_info->freq_cga_m2 = freq_c_pll[0] / 3;
|
||||
break;
|
||||
default:
|
||||
printf("Error: Unknown peripheral clock select!\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_LX2160A) || defined(CONFIG_ARCH_LS2080A)
|
||||
sys_info->freq_cga_m2 = sys_info->freq_systembus;
|
||||
#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 / CONFIG_SYS_FSL_PCLK_DIV;
|
||||
gd->mem_clk = sys_info.freq_ddrbus;
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
gd->arch.mem2_clk = sys_info.freq_ddrbus2;
|
||||
#endif
|
||||
#if defined(CONFIG_FSL_ESDHC)
|
||||
#if defined(CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK)
|
||||
#if defined(CONFIG_ARCH_LS1028A) || defined(CONFIG_ARCH_LX2160A)
|
||||
gd->arch.sdhc_clk = sys_info.freq_cga_m2 / 2;
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A)
|
||||
gd->arch.sdhc_clk = sys_info.freq_cga_m2;
|
||||
#endif
|
||||
#else
|
||||
gd->arch.sdhc_clk = gd->bus_clk / CONFIG_SYS_FSL_SDHC_CLK_DIV;
|
||||
#endif
|
||||
#endif /* defined(CONFIG_FSL_ESDHC) */
|
||||
|
||||
if (gd->cpu_clk != 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* get_bus_freq
|
||||
* return platform clock 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 controller 2 is on memory complext 1
|
||||
*/
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
if (ctrl_num >= 2)
|
||||
return gd->arch.mem2_clk;
|
||||
#endif
|
||||
|
||||
return gd->mem_clk;
|
||||
}
|
||||
|
||||
int get_i2c_freq(ulong dummy)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_I2C_CLK_DIV;
|
||||
}
|
||||
|
||||
int get_dspi_freq(ulong dummy)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_DSPI_CLK_DIV;
|
||||
}
|
||||
|
||||
int get_serial_clock(void)
|
||||
{
|
||||
return get_bus_freq(0) / CONFIG_SYS_FSL_DUART_CLK_DIV;
|
||||
}
|
||||
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_I2C_CLK:
|
||||
return get_i2c_freq(0);
|
||||
case MXC_DSPI_CLK:
|
||||
return get_dspi_freq(0);
|
||||
default:
|
||||
printf("Unsupported clock\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <fsl_fman.h>
|
||||
|
||||
static void set_icid(struct icid_id_table *tbl, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
if (tbl[i].le)
|
||||
out_le32((u32 *)(tbl[i].reg_addr), tbl[i].reg);
|
||||
else
|
||||
out_be32((u32 *)(tbl[i].reg_addr), tbl[i].reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
void set_fman_icids(struct fman_icid_id_table *tbl, int size)
|
||||
{
|
||||
int i;
|
||||
ccsr_fman_t *fm = (void *)CONFIG_SYS_FSL_FM1_ADDR;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
out_be32(&fm->fm_bmi_common.fmbm_ppid[tbl[i].port_id - 1],
|
||||
tbl[i].icid);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_icids(void)
|
||||
{
|
||||
/* setup general icid offsets */
|
||||
set_icid(icid_tbl, icid_tbl_sz);
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz);
|
||||
#endif
|
||||
}
|
||||
|
||||
int fdt_set_iommu_prop(void *blob, int off, int smmu_ph, u32 *ids, int num_ids)
|
||||
{
|
||||
int i, ret;
|
||||
u32 prop[8];
|
||||
|
||||
/*
|
||||
* Note: The "iommus" property definition mentions Stream IDs while
|
||||
* this code handles ICIDs. The current implementation assumes that
|
||||
* ICIDs and Stream IDs are equal.
|
||||
*/
|
||||
for (i = 0; i < num_ids; i++) {
|
||||
prop[i * 2] = cpu_to_fdt32(smmu_ph);
|
||||
prop[i * 2 + 1] = cpu_to_fdt32(ids[i]);
|
||||
}
|
||||
ret = fdt_setprop(blob, off, "iommus",
|
||||
prop, sizeof(u32) * num_ids * 2);
|
||||
if (ret) {
|
||||
printf("WARNING unable to set iommus: %s\n", fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_fixup_icid_tbl(void *blob, int smmu_ph,
|
||||
struct icid_id_table *tbl, int size)
|
||||
{
|
||||
int i, err, off;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (!tbl[i].compat)
|
||||
continue;
|
||||
|
||||
off = fdt_node_offset_by_compat_reg(blob,
|
||||
tbl[i].compat,
|
||||
tbl[i].compat_addr);
|
||||
if (off > 0) {
|
||||
err = fdt_set_iommu_prop(blob, off, smmu_ph,
|
||||
&tbl[i].id, 1);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
printf("WARNING could not find node %s: %s.\n",
|
||||
tbl[i].compat, fdt_strerror(off));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl,
|
||||
const int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (tbl[i].port_id == port_id)
|
||||
return tbl[i].icid;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void fdt_fixup_fman_port_icid_by_compat(void *blob, int smmu_ph,
|
||||
const char *compat)
|
||||
{
|
||||
int noff, len, icid;
|
||||
const u32 *prop;
|
||||
|
||||
noff = fdt_node_offset_by_compatible(blob, -1, compat);
|
||||
while (noff > 0) {
|
||||
prop = fdt_getprop(blob, noff, "cell-index", &len);
|
||||
if (!prop) {
|
||||
printf("WARNING missing cell-index for fman port\n");
|
||||
continue;
|
||||
}
|
||||
if (len != 4) {
|
||||
printf("WARNING bad cell-index size for fman port\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
icid = get_fman_port_icid(fdt32_to_cpu(*prop),
|
||||
fman_icid_tbl, fman_icid_tbl_sz);
|
||||
if (icid < 0) {
|
||||
printf("WARNING unknown ICID for fman port %d\n",
|
||||
*prop);
|
||||
continue;
|
||||
}
|
||||
|
||||
fdt_set_iommu_prop(blob, noff, smmu_ph, (u32 *)&icid, 1);
|
||||
|
||||
noff = fdt_node_offset_by_compatible(blob, noff, compat);
|
||||
}
|
||||
}
|
||||
|
||||
void fdt_fixup_fman_icids(void *blob, int smmu_ph)
|
||||
{
|
||||
static const char * const compats[] = {
|
||||
"fsl,fman-v3-port-oh",
|
||||
"fsl,fman-v3-port-rx",
|
||||
"fsl,fman-v3-port-tx",
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(compats); i++)
|
||||
fdt_fixup_fman_port_icid_by_compat(blob, smmu_ph, compats[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
int fdt_get_smmu_phandle(void *blob)
|
||||
{
|
||||
int noff, smmu_ph;
|
||||
|
||||
noff = fdt_node_offset_by_compatible(blob, -1, "arm,mmu-500");
|
||||
if (noff < 0) {
|
||||
printf("WARNING failed to get smmu node: %s\n",
|
||||
fdt_strerror(noff));
|
||||
return noff;
|
||||
}
|
||||
|
||||
smmu_ph = fdt_get_phandle(blob, noff);
|
||||
if (!smmu_ph) {
|
||||
smmu_ph = fdt_create_phandle(blob, noff);
|
||||
if (!smmu_ph) {
|
||||
printf("WARNING failed to get smmu phandle\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return smmu_ph;
|
||||
}
|
||||
|
||||
void fdt_fixup_icid(void *blob)
|
||||
{
|
||||
int smmu_ph;
|
||||
|
||||
smmu_ph = fdt_get_smmu_phandle(blob);
|
||||
if (smmu_ph < 0)
|
||||
return;
|
||||
|
||||
fdt_fixup_icid_tbl(blob, smmu_ph, icid_tbl, icid_tbl_sz);
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
fdt_fixup_fman_icids(blob, smmu_ph);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2014-2015 Freescale Semiconductor
|
||||
* Copyright 2019 NXP
|
||||
*
|
||||
* Extracted from armv8/start.S
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/gic.h>
|
||||
#include <asm/macro.h>
|
||||
#include <asm/arch-fsl-layerscape/soc.h>
|
||||
#ifdef CONFIG_MP
|
||||
#include <asm/arch/mp.h>
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch3.h>
|
||||
#endif
|
||||
#include <asm/u-boot.h>
|
||||
|
||||
/* Get GIC offset
|
||||
* For LS1043a rev1.0, GIC base address align with 4k.
|
||||
* For LS1043a rev1.1, if DCFG_GIC400_ALIGN[GIC_ADDR_BIT]
|
||||
* is set, GIC base address align with 4K, or else align
|
||||
* with 64k.
|
||||
* output:
|
||||
* x0: the base address of GICD
|
||||
* x1: the base address of GICC
|
||||
*/
|
||||
ENTRY(get_gic_offset)
|
||||
ldr x0, =GICD_BASE
|
||||
#ifdef CONFIG_GICV2
|
||||
ldr x1, =GICC_BASE
|
||||
#endif
|
||||
#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
|
||||
ldr x2, =DCFG_CCSR_SVR
|
||||
ldr w2, [x2]
|
||||
rev w2, w2
|
||||
lsr w3, w2, #16
|
||||
ldr w4, =SVR_DEV(SVR_LS1043A)
|
||||
cmp w3, w4
|
||||
b.ne 1f
|
||||
ands w2, w2, #0xff
|
||||
cmp w2, #REV1_0
|
||||
b.eq 1f
|
||||
ldr x2, =SCFG_GIC400_ALIGN
|
||||
ldr w2, [x2]
|
||||
rev w2, w2
|
||||
tbnz w2, #GIC_ADDR_BIT, 1f
|
||||
ldr x0, =GICD_BASE_64K
|
||||
#ifdef CONFIG_GICV2
|
||||
ldr x1, =GICC_BASE_64K
|
||||
#endif
|
||||
1:
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(get_gic_offset)
|
||||
|
||||
ENTRY(smp_kick_all_cpus)
|
||||
/* Kick secondary cpus up by SGI 0 interrupt */
|
||||
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
|
||||
mov x29, lr /* Save LR */
|
||||
bl get_gic_offset
|
||||
bl gic_kick_secondary_cpus
|
||||
mov lr, x29 /* Restore LR */
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(smp_kick_all_cpus)
|
||||
|
||||
|
||||
ENTRY(lowlevel_init)
|
||||
mov x29, lr /* Save LR */
|
||||
|
||||
/* unmask SError and abort */
|
||||
msr daifclr, #4
|
||||
|
||||
/* Set HCR_EL2[AMO] so SError @EL2 is taken */
|
||||
mrs x0, hcr_el2
|
||||
orr x0, x0, #0x20 /* AMO */
|
||||
msr hcr_el2, x0
|
||||
isb
|
||||
|
||||
switch_el x1, 1f, 100f, 100f /* skip if not in EL3 */
|
||||
1:
|
||||
|
||||
#if defined (CONFIG_SYS_FSL_HAS_CCN504)
|
||||
|
||||
/* Set Wuo bit for RN-I 20 */
|
||||
#ifdef CONFIG_ARCH_LS2080A
|
||||
ldr x0, =CCI_AUX_CONTROL_BASE(20)
|
||||
ldr x1, =0x00000010
|
||||
bl ccn504_set_aux
|
||||
|
||||
/*
|
||||
* Set forced-order mode in RNI-6, RNI-20
|
||||
* This is required for performance optimization on LS2088A
|
||||
* LS2080A family does not support setting forced-order mode,
|
||||
* so skip this operation for LS2080A family
|
||||
*/
|
||||
bl get_svr
|
||||
lsr w0, w0, #16
|
||||
ldr w1, =SVR_DEV(SVR_LS2080A)
|
||||
cmp w0, w1
|
||||
b.eq 1f
|
||||
|
||||
ldr x0, =CCI_AUX_CONTROL_BASE(6)
|
||||
ldr x1, =0x00000020
|
||||
bl ccn504_set_aux
|
||||
ldr x0, =CCI_AUX_CONTROL_BASE(20)
|
||||
ldr x1, =0x00000020
|
||||
bl ccn504_set_aux
|
||||
1:
|
||||
#endif
|
||||
|
||||
/* 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 /* CONFIG_SYS_FSL_HAS_CCN504 */
|
||||
|
||||
#ifdef SMMU_BASE
|
||||
/* 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]
|
||||
#endif
|
||||
|
||||
/* Initialize GIC Secure Bank Status */
|
||||
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
|
||||
branch_if_slave x0, 1f
|
||||
bl get_gic_offset
|
||||
bl gic_init_secure
|
||||
1:
|
||||
#ifdef CONFIG_GICV3
|
||||
ldr x0, =GICR_BASE
|
||||
bl gic_init_secure_percpu
|
||||
#elif defined(CONFIG_GICV2)
|
||||
bl get_gic_offset
|
||||
bl gic_init_secure_percpu
|
||||
#endif
|
||||
#endif
|
||||
|
||||
100:
|
||||
branch_if_master x0, x1, 2f
|
||||
|
||||
#if defined(CONFIG_MP) && defined(CONFIG_ARMV8_MULTIENTRY)
|
||||
ldr x0, =secondary_boot_func
|
||||
blr x0
|
||||
#endif
|
||||
|
||||
2:
|
||||
switch_el x1, 1f, 100f, 100f /* skip if not in EL3 */
|
||||
1:
|
||||
#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
|
||||
/*
|
||||
* LS2080 and its personalities does not support TZASC
|
||||
* So skip TZASC related operations
|
||||
*/
|
||||
bl get_svr
|
||||
lsr w0, w0, #16
|
||||
ldr w1, =SVR_DEV(SVR_LS2080A)
|
||||
cmp w0, w1
|
||||
b.eq 1f
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
.macro tzasc_prog, xreg
|
||||
|
||||
mov x12, TZASC1_BASE
|
||||
mov x16, #0x10000
|
||||
mul x14, \xreg, x16
|
||||
add x14, x14,x12
|
||||
mov x1, #0x8
|
||||
add x1, x1, x14
|
||||
|
||||
ldr w0, [x1] /* Filter 0 Gate Keeper Register */
|
||||
orr w0, w0, #1 << 0 /* Set open_request for Filter 0 */
|
||||
str w0, [x1]
|
||||
|
||||
mov x1, #0x110
|
||||
add x1, x1, x14
|
||||
|
||||
ldr w0, [x1] /* Region-0 Attributes Register */
|
||||
orr w0, w0, #1 << 31 /* Set Sec global write en, Bit[31] */
|
||||
orr w0, w0, #1 << 30 /* Set Sec global read en, Bit[30] */
|
||||
str w0, [x1]
|
||||
|
||||
mov x1, #0x114
|
||||
add x1, x1, x14
|
||||
|
||||
ldr w0, [x1] /* Region-0 Access Register */
|
||||
mov w0, #0xFFFFFFFF /* Set nsaid_wr_en and nsaid_rd_en */
|
||||
str w0, [x1]
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_FSL_TZASC_1
|
||||
mov x13, #0
|
||||
tzasc_prog x13
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_TZASC_2
|
||||
mov x13, #1
|
||||
tzasc_prog x13
|
||||
|
||||
#endif
|
||||
isb
|
||||
dsb sy
|
||||
#endif
|
||||
100:
|
||||
1:
|
||||
#ifdef CONFIG_ARCH_LS1046A
|
||||
switch_el x1, 1f, 100f, 100f /* skip if not in EL3 */
|
||||
1:
|
||||
/* Initialize the L2 RAM latency */
|
||||
mrs x1, S3_1_c11_c0_2
|
||||
mov x0, #0x1C7
|
||||
/* Clear L2 Tag RAM latency and L2 Data RAM latency */
|
||||
bic x1, x1, x0
|
||||
/* Set L2 data ram latency bits [2:0] */
|
||||
orr x1, x1, #0x2
|
||||
/* set L2 tag ram latency bits [8:6] */
|
||||
orr x1, x1, #0x80
|
||||
msr S3_1_c11_c0_2, x1
|
||||
isb
|
||||
100:
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_TFABOOT) && \
|
||||
(defined(CONFIG_FSL_LSCH2) && !defined(CONFIG_SPL_BUILD))
|
||||
bl fsl_ocram_init
|
||||
#endif
|
||||
|
||||
mov lr, x29 /* Restore LR */
|
||||
ret
|
||||
ENDPROC(lowlevel_init)
|
||||
|
||||
#if defined(CONFIG_FSL_LSCH2) && !defined(CONFIG_SPL_BUILD)
|
||||
ENTRY(fsl_ocram_init)
|
||||
mov x28, lr /* Save LR */
|
||||
bl fsl_clear_ocram
|
||||
bl fsl_ocram_clear_ecc_err
|
||||
mov lr, x28 /* Restore LR */
|
||||
ret
|
||||
ENDPROC(fsl_ocram_init)
|
||||
|
||||
ENTRY(fsl_clear_ocram)
|
||||
/* Clear OCRAM */
|
||||
ldr x0, =CONFIG_SYS_FSL_OCRAM_BASE
|
||||
ldr x1, =(CONFIG_SYS_FSL_OCRAM_BASE + CONFIG_SYS_FSL_OCRAM_SIZE)
|
||||
mov x2, #0
|
||||
clear_loop:
|
||||
str x2, [x0]
|
||||
add x0, x0, #8
|
||||
cmp x0, x1
|
||||
b.lo clear_loop
|
||||
ret
|
||||
ENDPROC(fsl_clear_ocram)
|
||||
|
||||
ENTRY(fsl_ocram_clear_ecc_err)
|
||||
/* OCRAM1/2 ECC status bit */
|
||||
mov w1, #0x60
|
||||
ldr x0, =DCSR_DCFG_SBEESR2
|
||||
str w1, [x0]
|
||||
ldr x0, =DCSR_DCFG_MBEESR2
|
||||
str w1, [x0]
|
||||
ret
|
||||
ENDPROC(fsl_ocram_init)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
.globl get_svr
|
||||
get_svr:
|
||||
ldr x1, =FSL_LSCH3_SVR
|
||||
ldr w0, [x1]
|
||||
ret
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_FSL_HAS_CCN504) || defined(CONFIG_SYS_FSL_HAS_CCN508)
|
||||
hnf_pstate_poll:
|
||||
/* x0 has the desired status, return only if operation succeed
|
||||
* clobber x1, x2, x6
|
||||
*/
|
||||
mov x1, x0
|
||||
mov w6, #8 /* HN-F node count */
|
||||
mov x0, #0x18
|
||||
movk x0, #0x420, lsl #16 /* HNF0_PSTATE_STATUS */
|
||||
1:
|
||||
ldr x2, [x0]
|
||||
cmp x2, x1 /* check status */
|
||||
b.eq 2f
|
||||
b 1b
|
||||
2:
|
||||
add x0, x0, #0x10000 /* move to next node */
|
||||
subs w6, w6, #1
|
||||
cbnz w6, 1b
|
||||
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_dcache)
|
||||
/*
|
||||
* Return status in x0
|
||||
* success 0
|
||||
*/
|
||||
mov x29, lr
|
||||
|
||||
dsb sy
|
||||
mov x0, #0x1 /* HNFPSTAT_SFONLY */
|
||||
bl hnf_set_pstate
|
||||
|
||||
mov x0, #0x4 /* SFONLY status */
|
||||
bl hnf_pstate_poll
|
||||
|
||||
dsb sy
|
||||
mov x0, #0x3 /* HNFPSTAT_FAM */
|
||||
bl hnf_set_pstate
|
||||
|
||||
mov x0, #0xc /* FAM status */
|
||||
bl hnf_pstate_poll
|
||||
|
||||
mov x0, #0
|
||||
mov lr, x29
|
||||
ret
|
||||
ENDPROC(__asm_flush_l3_dcache)
|
||||
#endif /* CONFIG_SYS_FSL_HAS_CCN504 */
|
||||
|
||||
#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)
|
||||
bl get_gic_offset
|
||||
mov x0, x1
|
||||
gic_wait_for_interrupt_m x0, w1
|
||||
#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:
|
||||
ldr x5, [x11, #24]
|
||||
cbz x5, 1f
|
||||
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
adr x4, secondary_switch_to_el1
|
||||
ldr x5, =ES_TO_AARCH64
|
||||
#else
|
||||
ldr x4, [x11]
|
||||
ldr x5, =ES_TO_AARCH32
|
||||
#endif
|
||||
bl secondary_switch_to_el2
|
||||
|
||||
1:
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
adr x4, secondary_switch_to_el1
|
||||
#else
|
||||
ldr x4, [x11]
|
||||
#endif
|
||||
ldr x5, =ES_TO_AARCH64
|
||||
bl secondary_switch_to_el2
|
||||
|
||||
ENDPROC(secondary_boot_func)
|
||||
|
||||
ENTRY(secondary_switch_to_el2)
|
||||
switch_el x6, 1f, 0f, 0f
|
||||
0: ret
|
||||
1: armv8_switch_to_el2_m x4, x5, x6
|
||||
ENDPROC(secondary_switch_to_el2)
|
||||
|
||||
ENTRY(secondary_switch_to_el1)
|
||||
mrs x0, mpidr_el1
|
||||
ubfm x1, x0, #8, #15
|
||||
ubfm x2, x0, #0, #1
|
||||
orr x10, x2, x1, lsl #2 /* x10 has LPID */
|
||||
|
||||
lsl x1, x10, #6
|
||||
ldr x0, =__spin_table
|
||||
/* physical address of this cpus spin table element */
|
||||
add x11, x1, x0
|
||||
|
||||
ldr x4, [x11]
|
||||
|
||||
ldr x5, [x11, #24]
|
||||
cbz x5, 2f
|
||||
|
||||
ldr x5, =ES_TO_AARCH32
|
||||
bl switch_to_el1
|
||||
|
||||
2: ldr x5, =ES_TO_AARCH64
|
||||
|
||||
switch_to_el1:
|
||||
switch_el x6, 0f, 1f, 0f
|
||||
0: ret
|
||||
1: armv8_switch_to_el1_m x4, x5, x6
|
||||
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
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#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[] = {
|
||||
{0x2208, {SGMII_2500_FM1_DTSEC1, SGMII_2500_FM1_DTSEC2, NONE, SATA1} },
|
||||
{0x0008, {NONE, NONE, NONE, SATA1} },
|
||||
{0x3508, {SGMII_FM1_DTSEC1, PCIE1, NONE, SATA1} },
|
||||
{0x3305, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, NONE, PCIE1} },
|
||||
{0x2205, {SGMII_2500_FM1_DTSEC1, SGMII_2500_FM1_DTSEC2, NONE, PCIE1} },
|
||||
{0x2305, {SGMII_2500_FM1_DTSEC1, SGMII_FM1_DTSEC2, NONE, PCIE1} },
|
||||
{0x9508, {TX_CLK, PCIE1, NONE, SATA1} },
|
||||
{0x3905, {SGMII_FM1_DTSEC1, TX_CLK, NONE, PCIE1} },
|
||||
{0x9305, {TX_CLK, SGMII_FM1_DTSEC2, NONE, PCIE1} },
|
||||
{}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch3.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_portals.h>
|
||||
|
||||
struct icid_id_table icid_tbl[] = {
|
||||
SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
|
||||
SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
|
||||
SET_SDHC_ICID(1, FSL_SDMMC_STREAM_ID),
|
||||
SET_SDHC_ICID(2, FSL_SDMMC2_STREAM_ID),
|
||||
SET_SATA_ICID(1, "fsl,ls1028a-ahci", FSL_SATA1_STREAM_ID),
|
||||
SET_EDMA_ICID(FSL_EDMA_STREAM_ID),
|
||||
SET_QDMA_ICID("fsl,ls1028a-qdma", FSL_DMA_STREAM_ID),
|
||||
SET_GPU_ICID("fsl,ls1028a-gpu", FSL_GPU_STREAM_ID),
|
||||
SET_DISPLAY_ICID(FSL_DISPLAY_STREAM_ID),
|
||||
#ifdef CONFIG_FSL_CAAM
|
||||
SET_SEC_JR_ICID_ENTRY(0, FSL_SEC_JR1_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(1, FSL_SEC_JR2_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(2, FSL_SEC_JR3_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(3, FSL_SEC_JR4_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
#endif
|
||||
};
|
||||
|
||||
int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
|
||||
@@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
|
||||
struct serdes_config {
|
||||
u32 protocol;
|
||||
u8 lanes[SRDS_MAX_LANES];
|
||||
u8 rcw_lanes[SRDS_MAX_LANES];
|
||||
};
|
||||
|
||||
static struct serdes_config serdes1_cfg_tbl[] = {
|
||||
/* SerDes 1 */
|
||||
{0xCC5B, {PCIE1, QSGMII_B, PCIE2, PCIE2} },
|
||||
{0xEB99, {SGMII1, SGMII1, PCIE2, SATA1} },
|
||||
{0xCC99, {SGMII1, SGMII1, PCIE2, PCIE2} },
|
||||
{0xBB99, {SGMII1, SGMII1, PCIE2, PCIE1} },
|
||||
{0x9999, {SGMII1, SGMII2, SGMII3, SGMII4} },
|
||||
{0xEBCC, {PCIE1, PCIE1, PCIE2, SATA1} },
|
||||
{0xCCCC, {PCIE1, PCIE1, PCIE2, PCIE2} },
|
||||
{0xDDDD, {PCIE1, PCIE1, PCIE1, PCIE1} },
|
||||
{0xE031, {SXGMII1, QXGMII2, NONE, SATA1} },
|
||||
{0xB991, {SXGMII1, SGMII1, SGMII2, PCIE1} },
|
||||
{0xBB31, {SXGMII1, QXGMII2, PCIE2, PCIE1} },
|
||||
{0xCC31, {SXGMII1, QXGMII2, PCIE2, PCIE2} },
|
||||
{0xBB51, {SXGMII1, QSGMII_B, PCIE2, PCIE1} },
|
||||
{0xBB38, {SGMII_T1, QXGMII2, PCIE2, PCIE1} },
|
||||
{0xCC38, {SGMII_T1, QXGMII2, PCIE2, PCIE2} },
|
||||
{0xBB58, {SGMII_T1, QSGMII_B, PCIE2, PCIE1} },
|
||||
{0xCC58, {SGMII_T1, QSGMII_B, PCIE2, PCIE2} },
|
||||
{0xCC8B, {PCIE1, SGMII_T1, PCIE2, PCIE2} },
|
||||
{0xEB58, {SGMII_T1, QSGMII_B, PCIE2, SATA1} },
|
||||
{0xEB8B, {PCIE1, SGMII_T1, PCIE2, SATA1} },
|
||||
{0xE8CC, {PCIE1, PCIE1, SGMII_T1, SATA1} },
|
||||
{}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch2.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_portals.h>
|
||||
#include <fsl_sec.h>
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
};
|
||||
#endif
|
||||
|
||||
struct icid_id_table icid_tbl[] = {
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
SET_QMAN_ICID(FSL_DPAA1_STREAM_ID_START),
|
||||
SET_BMAN_ICID(FSL_DPAA1_STREAM_ID_START + 1),
|
||||
#endif
|
||||
|
||||
SET_SDHC_ICID(FSL_SDHC_STREAM_ID),
|
||||
|
||||
SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
|
||||
SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
|
||||
SET_USB_ICID(3, "snps,dwc3", FSL_USB3_STREAM_ID),
|
||||
|
||||
SET_SATA_ICID("fsl,ls1043a-ahci", FSL_SATA_STREAM_ID),
|
||||
SET_QDMA_ICID("fsl,ls1043a-qdma", FSL_QDMA_STREAM_ID),
|
||||
SET_EDMA_ICID(FSL_EDMA_STREAM_ID),
|
||||
SET_ETR_ICID(FSL_ETR_STREAM_ID),
|
||||
SET_DEBUG_ICID(FSL_DEBUG_STREAM_ID),
|
||||
SET_QE_ICID(FSL_QE_STREAM_ID),
|
||||
#ifdef CONFIG_FSL_CAAM
|
||||
SET_SEC_QI_ICID(FSL_DPAA1_STREAM_ID_END),
|
||||
SET_SEC_JR_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 3),
|
||||
SET_SEC_JR_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 4),
|
||||
SET_SEC_JR_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 5),
|
||||
SET_SEC_JR_ICID_ENTRY(3, FSL_DPAA1_STREAM_ID_START + 6),
|
||||
SET_SEC_RTIC_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 7),
|
||||
SET_SEC_RTIC_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 8),
|
||||
SET_SEC_RTIC_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 9),
|
||||
SET_SEC_RTIC_ICID_ENTRY(3, FSL_DPAA1_STREAM_ID_START + 10),
|
||||
SET_SEC_DECO_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 11),
|
||||
SET_SEC_DECO_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 12),
|
||||
#endif
|
||||
};
|
||||
|
||||
int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
struct fman_icid_id_table fman_icid_tbl[] = {
|
||||
/* port id, icid */
|
||||
SET_FMAN_ICID_ENTRY(0x02, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x03, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x04, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x05, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x06, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x07, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x08, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x09, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0a, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0b, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0c, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0d, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x28, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x29, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2a, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2b, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2c, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2d, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x10, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x11, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x30, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x31, FSL_DPAA1_STREAM_ID_END),
|
||||
};
|
||||
|
||||
int fman_icid_tbl_sz = ARRAY_SIZE(fman_icid_tbl);
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2016 Freescale Semiconductor, Inc.
|
||||
* Author: Hongbo Zhang <hongbo.zhang@nxp.com>
|
||||
* This file implements LS102X platform PSCI SYSTEM-SUSPEND function
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/psci.h>
|
||||
|
||||
.pushsection ._secure.text, "ax"
|
||||
|
||||
.globl psci_version
|
||||
psci_version:
|
||||
ldr w0, =0x00010000 /* PSCI v1.0 */
|
||||
ret
|
||||
|
||||
.popsection
|
||||
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch2.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_portals.h>
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
|
||||
};
|
||||
#endif
|
||||
|
||||
struct icid_id_table icid_tbl[] = {
|
||||
#ifdef CONFIG_SYS_DPAA_QBMAN
|
||||
SET_QMAN_ICID(FSL_DPAA1_STREAM_ID_START),
|
||||
SET_BMAN_ICID(FSL_DPAA1_STREAM_ID_START + 1),
|
||||
#endif
|
||||
|
||||
SET_SDHC_ICID(FSL_SDHC_STREAM_ID),
|
||||
|
||||
SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
|
||||
SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
|
||||
SET_USB_ICID(3, "snps,dwc3", FSL_USB3_STREAM_ID),
|
||||
|
||||
SET_SATA_ICID("fsl,ls1046a-ahci", FSL_SATA_STREAM_ID),
|
||||
SET_QDMA_ICID("fsl,ls1046a-qdma", FSL_QDMA_STREAM_ID),
|
||||
SET_EDMA_ICID(FSL_EDMA_STREAM_ID),
|
||||
SET_ETR_ICID(FSL_ETR_STREAM_ID),
|
||||
SET_DEBUG_ICID(FSL_DEBUG_STREAM_ID),
|
||||
#ifdef CONFIG_FSL_CAAM
|
||||
SET_SEC_QI_ICID(FSL_DPAA1_STREAM_ID_END),
|
||||
SET_SEC_JR_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 3),
|
||||
SET_SEC_JR_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 4),
|
||||
SET_SEC_JR_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 5),
|
||||
SET_SEC_JR_ICID_ENTRY(3, FSL_DPAA1_STREAM_ID_START + 6),
|
||||
SET_SEC_RTIC_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 7),
|
||||
SET_SEC_RTIC_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 8),
|
||||
SET_SEC_RTIC_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 9),
|
||||
SET_SEC_RTIC_ICID_ENTRY(3, FSL_DPAA1_STREAM_ID_START + 10),
|
||||
SET_SEC_DECO_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 11),
|
||||
SET_SEC_DECO_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 12),
|
||||
SET_SEC_DECO_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 13),
|
||||
#endif
|
||||
};
|
||||
|
||||
int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
struct fman_icid_id_table fman_icid_tbl[] = {
|
||||
/* port id, icid */
|
||||
SET_FMAN_ICID_ENTRY(0x02, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x03, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x04, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x05, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x06, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x07, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x08, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x09, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0a, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0b, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0c, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x0d, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x28, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x29, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2a, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2b, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2c, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x2d, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x10, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x11, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x30, FSL_DPAA1_STREAM_ID_END),
|
||||
SET_FMAN_ICID_ENTRY(0x31, FSL_DPAA1_STREAM_ID_END),
|
||||
};
|
||||
|
||||
int fman_icid_tbl_sz = ARRAY_SIZE(fman_icid_tbl);
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#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 */
|
||||
{0x3333, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC5,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{0x1133, {XFI_FM1_MAC9, XFI_FM1_MAC10, SGMII_FM1_DTSEC5,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{0x1333, {XFI_FM1_MAC9, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC5,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{0x2333, {SGMII_2500_FM1_DTSEC9, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC5,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{0x2233, {SGMII_2500_FM1_DTSEC9, SGMII_2500_FM1_DTSEC10,
|
||||
SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} },
|
||||
{0x1040, {XFI_FM1_MAC9, NONE, QSGMII_FM1_A, NONE} },
|
||||
{0x2040, {SGMII_2500_FM1_DTSEC9, NONE, QSGMII_FM1_A, NONE} },
|
||||
{0x1163, {XFI_FM1_MAC9, XFI_FM1_MAC10, PCIE1, SGMII_FM1_DTSEC6} },
|
||||
{0x2263, {SGMII_2500_FM1_DTSEC9, SGMII_2500_FM1_DTSEC10, PCIE1,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{0x3363, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, PCIE1,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{0x2223, {SGMII_2500_FM1_DTSEC9, SGMII_2500_FM1_DTSEC10,
|
||||
SGMII_2500_FM1_DTSEC5, SGMII_FM1_DTSEC6} },
|
||||
{0x3040, {SGMII_FM1_DTSEC9, NONE, QSGMII_FM1_A, NONE} },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct serdes_config serdes2_cfg_tbl[] = {
|
||||
/* SerDes 2 */
|
||||
{0x8888, {PCIE1, PCIE1, PCIE1, PCIE1} },
|
||||
{0x5559, {PCIE1, PCIE2, PCIE3, SATA1} },
|
||||
{0x5577, {PCIE1, PCIE2, PCIE3, PCIE3} },
|
||||
{0x5506, {PCIE1, PCIE2, NONE, PCIE3} },
|
||||
{0x0506, {NONE, PCIE2, NONE, PCIE3} },
|
||||
{0x0559, {NONE, PCIE2, PCIE3, SATA1} },
|
||||
{0x5A59, {PCIE1, SGMII_FM1_DTSEC2, PCIE3, SATA1} },
|
||||
{0x5A06, {PCIE1, SGMII_FM1_DTSEC2, NONE, PCIE3} },
|
||||
{}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch3.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_portals.h>
|
||||
|
||||
struct icid_id_table icid_tbl[] = {
|
||||
SET_SDHC_ICID(1, FSL_SDMMC_STREAM_ID),
|
||||
SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
|
||||
SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
|
||||
SET_SATA_ICID(1, "fsl,ls1088a-ahci", FSL_SATA1_STREAM_ID),
|
||||
#ifdef CONFIG_FSL_CAAM
|
||||
SET_SEC_JR_ICID_ENTRY(0, FSL_SEC_JR1_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(1, FSL_SEC_JR2_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(2, FSL_SEC_JR3_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(3, FSL_SEC_JR4_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
#endif
|
||||
};
|
||||
|
||||
int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
|
||||
@@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2017 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
|
||||
struct serdes_config {
|
||||
u8 ip_protocol;
|
||||
u8 lanes[SRDS_MAX_LANES];
|
||||
u8 rcw_lanes[SRDS_MAX_LANES];
|
||||
};
|
||||
|
||||
static struct serdes_config serdes1_cfg_tbl[] = {
|
||||
/* SerDes 1 */
|
||||
{0x12, {SGMII3, SGMII7, SGMII1, SGMII2 }, {3, 3, 3, 3 } },
|
||||
{0x15, {SGMII3, SGMII7, XFI1, XFI2 }, {3, 3, 1, 1 } },
|
||||
{0x16, {SGMII3, SGMII7, SGMII1, XFI2 }, {3, 3, 3, 1 } },
|
||||
{0x17, {SGMII3, SGMII7, SGMII1, SGMII2 }, {3, 3, 3, 2 } },
|
||||
{0x18, {SGMII3, SGMII7, SGMII1, SGMII2 }, {3, 3, 2, 2 } },
|
||||
{0x19, {SGMII3, QSGMII_B, XFI1, XFI2}, {3, 4, 1, 1 } },
|
||||
{0x1A, {SGMII3, QSGMII_B, SGMII1, XFI2 }, {3, 4, 3, 1 } },
|
||||
{0x1B, {SGMII3, QSGMII_B, SGMII1, SGMII2 }, {3, 4, 3, 2 } },
|
||||
{0x1C, {SGMII3, QSGMII_B, SGMII1, SGMII2 }, {3, 4, 2, 2 } },
|
||||
{0x1D, {QSGMII_A, QSGMII_B, XFI1, XFI2 }, {4, 4, 1, 1 } },
|
||||
{0x1E, {QSGMII_A, QSGMII_B, SGMII1, XFI2 }, {4, 4, 3, 1 } },
|
||||
{0x1F, {QSGMII_A, QSGMII_B, SGMII1, SGMII2 }, {4, 4, 3, 2 } },
|
||||
{0x20, {QSGMII_A, QSGMII_B, SGMII1, SGMII2 }, {4, 4, 2, 2 } },
|
||||
{0x35, {SGMII3, QSGMII_B, SGMII1, SGMII2 }, {3, 4, 3, 3 } },
|
||||
{0x36, {QSGMII_A, QSGMII_B, SGMII1, SGMII2 }, {4, 4, 3, 3 } },
|
||||
{0x3A, {SGMII3, PCIE1, SGMII1, SGMII2 }, {3, 5, 3, 3 } },
|
||||
{}
|
||||
};
|
||||
static struct serdes_config serdes2_cfg_tbl[] = {
|
||||
/* SerDes 2 */
|
||||
{0x0C, {PCIE1, PCIE1, PCIE1, PCIE1 }, {8, 8, 8, 8 } },
|
||||
{0x0D, {PCIE1, PCIE2, PCIE3, SATA1 }, {5, 5, 5, 9 } },
|
||||
{0x0E, {PCIE1, PCIE1, PCIE2, SATA1 }, {7, 7, 6, 9 } },
|
||||
{0x13, {PCIE1, PCIE1, PCIE3, PCIE3 }, {7, 7, 7, 7 } },
|
||||
{0x14, {PCIE1, PCIE2, PCIE3, PCIE3 }, {5, 5, 7, 7 } },
|
||||
{0x3C, {NONE, PCIE2, NONE, PCIE3 }, {0, 5, 0, 6 } },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct serdes_config *serdes_cfg_tbl[] = {
|
||||
serdes1_cfg_tbl,
|
||||
serdes2_cfg_tbl,
|
||||
};
|
||||
|
||||
int serdes_get_number(int serdes, int cfg)
|
||||
{
|
||||
struct serdes_config *ptr;
|
||||
int i, j, index, lnk;
|
||||
int is_found, max_lane = SRDS_MAX_LANES;
|
||||
|
||||
if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
|
||||
return 0;
|
||||
|
||||
ptr = serdes_cfg_tbl[serdes];
|
||||
|
||||
while (ptr->ip_protocol) {
|
||||
is_found = 1;
|
||||
for (i = 0, j = max_lane - 1; i < max_lane; i++, j--) {
|
||||
lnk = cfg & (0xf << 4 * i);
|
||||
lnk = lnk >> (4 * i);
|
||||
|
||||
index = (serdes == FSL_SRDS_1) ? j : i;
|
||||
|
||||
if (ptr->rcw_lanes[index] == lnk && is_found)
|
||||
is_found = 1;
|
||||
else
|
||||
is_found = 0;
|
||||
}
|
||||
|
||||
if (is_found)
|
||||
return ptr->ip_protocol;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->ip_protocol) {
|
||||
if (ptr->ip_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->ip_protocol) {
|
||||
if (ptr->ip_protocol == prtcl)
|
||||
break;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (!ptr->ip_protocol)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
||||
if (ptr->lanes[i] != NONE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#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, {PCIE2, PCIE2, PCIE2, PCIE2, PCIE1, PCIE1, PCIE1, PCIE1 } },
|
||||
{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_D, QSGMII_C, QSGMII_B,
|
||||
QSGMII_A} },
|
||||
{0x35, {QSGMII_D, QSGMII_C, QSGMII_B, PCIE2, XFI4, XFI3, XFI2, XFI1 } },
|
||||
{0x39, {SGMII8, SGMII7, SGMII6, PCIE2, SGMII4, SGMII3, SGMII2,
|
||||
PCIE1 } },
|
||||
{0x3B, {XFI8, XFI7, XFI6, PCIE2, XFI4, XFI3, XFI2, PCIE1 } },
|
||||
{0x4B, {PCIE2, PCIE2, PCIE2, PCIE2, XFI4, XFI3, XFI2, XFI1 } },
|
||||
{0x4C, {XFI8, XFI7, XFI6, XFI5, PCIE1, PCIE1, PCIE1, PCIE1 } },
|
||||
{0x4D, {SGMII8, SGMII7, PCIE2, PCIE2, SGMII4, SGMII3, PCIE1, PCIE1 } },
|
||||
{}
|
||||
};
|
||||
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, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, PCIE4,
|
||||
PCIE4 } },
|
||||
{0x47, {PCIE3, SGMII10, SGMII11, SGMII12, PCIE4, SGMII14, SGMII15,
|
||||
SGMII16 } },
|
||||
{0x49, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1,
|
||||
SATA2 } },
|
||||
{0x4A, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1,
|
||||
SATA2 } },
|
||||
{0x51, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } },
|
||||
{0x57, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SGMII15, SGMII16 } },
|
||||
{}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch3.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_portals.h>
|
||||
|
||||
struct icid_id_table icid_tbl[] = {
|
||||
SET_SDHC_ICID(1, FSL_SDMMC_STREAM_ID),
|
||||
SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
|
||||
SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
|
||||
SET_SATA_ICID(1, "fsl,ls2080a-ahci", FSL_SATA1_STREAM_ID),
|
||||
SET_SATA_ICID(2, "fsl,ls2080a-ahci", FSL_SATA2_STREAM_ID),
|
||||
#ifdef CONFIG_FSL_CAAM
|
||||
SET_SEC_JR_ICID_ENTRY(0, FSL_SEC_JR1_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(1, FSL_SEC_JR2_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(2, FSL_SEC_JR3_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(3, FSL_SEC_JR4_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(4, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(5, FSL_SEC_STREAM_ID),
|
||||
#endif
|
||||
};
|
||||
|
||||
int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch-fsl-layerscape/immap_lsch3.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_portals.h>
|
||||
|
||||
struct icid_id_table icid_tbl[] = {
|
||||
SET_SDHC_ICID(1, FSL_SDMMC_STREAM_ID),
|
||||
SET_SDHC_ICID(2, FSL_SDMMC2_STREAM_ID),
|
||||
SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
|
||||
SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
|
||||
SET_SATA_ICID(1, "fsl,lx2160a-ahci", FSL_SATA1_STREAM_ID),
|
||||
SET_SATA_ICID(2, "fsl,lx2160a-ahci", FSL_SATA2_STREAM_ID),
|
||||
SET_SATA_ICID(3, "fsl,lx2160a-ahci", FSL_SATA3_STREAM_ID),
|
||||
SET_SATA_ICID(4, "fsl,lx2160a-ahci", FSL_SATA4_STREAM_ID),
|
||||
#ifdef CONFIG_FSL_CAAM
|
||||
SET_SEC_JR_ICID_ENTRY(0, FSL_SEC_JR1_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(1, FSL_SEC_JR2_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(2, FSL_SEC_JR3_STREAM_ID),
|
||||
SET_SEC_JR_ICID_ENTRY(3, FSL_SEC_JR4_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_RTIC_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(0, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(1, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(2, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(3, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(4, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(5, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(6, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(7, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(8, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(9, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(10, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(11, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(12, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(13, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(14, FSL_SEC_STREAM_ID),
|
||||
SET_SEC_DECO_ICID_ENTRY(15, FSL_SEC_STREAM_ID),
|
||||
#endif
|
||||
};
|
||||
|
||||
int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
|
||||
@@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
*/
|
||||
|
||||
#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 */
|
||||
{0x01, {PCIE2, PCIE2, PCIE2, PCIE2, PCIE1, PCIE1, PCIE1, PCIE1 } },
|
||||
{0x02, {PCIE2, PCIE2, PCIE2, PCIE2, SGMII6, SGMII5, SGMII4, SGMII3 } },
|
||||
{0x03, {PCIE2, PCIE2, PCIE2, PCIE2, XFI6, XFI5, XFI4,
|
||||
XFI3 } },
|
||||
{0x04, {SGMII10, SGMII9, SGMII8, SGMII7, SGMII6, SGMII5, SGMII4,
|
||||
SGMII3 } },
|
||||
{0x05, {XFI10, XFI9, XFI8, XFI7, PCIE1, PCIE1, PCIE1,
|
||||
PCIE1 } },
|
||||
{0x06, {SGMII10, SGMII9, SGMII8, SGMII7, SGMII6, SGMII5, XFI4,
|
||||
XFI3 } },
|
||||
{0x07, {SGMII10, SGMII9, SGMII8, SGMII7, XFI6, XFI5, XFI4,
|
||||
XFI3 } },
|
||||
{0x08, {XFI10, XFI9, XFI8, XFI7, XFI6, XFI5, XFI4, XFI3 } },
|
||||
{0x09, {SGMII10, SGMII9, SGMII8, PCIE2, SGMII6, SGMII5, SGMII4,
|
||||
PCIE1 } },
|
||||
{0x0A, {XFI10, XFI9, XFI8, PCIE2, XFI6, XFI5, XFI4, PCIE1 } },
|
||||
{0x0B, {SGMII10, SGMII9, PCIE2, PCIE2, SGMII6, SGMII5, PCIE1, PCIE1 } },
|
||||
{0x0C, {SGMII10, SGMII9, PCIE2, PCIE2, PCIE1, PCIE1, PCIE1, PCIE1 } },
|
||||
{0x0D, {_100GE2, _100GE2, _100GE2, _100GE2, _100GE1, _100GE1, _100GE1,
|
||||
_100GE1 } },
|
||||
{0x0E, {PCIE2, PCIE2, PCIE2, PCIE2, _100GE1, _100GE1, _100GE1,
|
||||
_100GE1 } },
|
||||
{0x0F, {PCIE2, PCIE2, PCIE2, PCIE2, _50GE2, _50GE2, _50GE1, _50GE1 } },
|
||||
{0x10, {PCIE2, PCIE2, PCIE2, PCIE2, _25GE6, _25GE5, _50GE1, _50GE1 } },
|
||||
{0x11, {PCIE2, PCIE2, PCIE2, PCIE2, _25GE6, _25GE5, _25GE4, _25GE3 } },
|
||||
{0x12, {XFI10, XFI9, XFI8, XFI7, _25GE6, _25GE5, XFI4,
|
||||
XFI3 } },
|
||||
{0x13, {_40GE2, _40GE2, _40GE2, _40GE2, _25GE6, _25GE5, XFI4, XFI3 } },
|
||||
{0x14, {_40GE2, _40GE2, _40GE2, _40GE2, _40GE1, _40GE1, _40GE1,
|
||||
_40GE1 } },
|
||||
{0x15, {_25GE10, _25GE9, PCIE2, PCIE2, _25GE6, _25GE5, _25GE4,
|
||||
_25GE3 } },
|
||||
{0x16, {XFI10, XFI9, PCIE2, PCIE2, XFI6, XFI5, XFI4, XFI3 } },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct serdes_config serdes2_cfg_tbl[] = {
|
||||
/* SerDes 2 */
|
||||
{0x01, {PCIE3, PCIE3, SATA1, SATA2, PCIE4, PCIE4, PCIE4, PCIE4 } },
|
||||
{0x02, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } },
|
||||
{0x03, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } },
|
||||
{0x04, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } },
|
||||
{0x05, {PCIE3, PCIE3, PCIE3, PCIE3, SATA3, SATA4, SATA1, SATA2 } },
|
||||
{0x06, {PCIE3, PCIE3, PCIE3, PCIE3, SGMII15, SGMII16, XFI13,
|
||||
XFI14 } },
|
||||
{0x07, {PCIE3, SGMII12, SGMII17, SGMII18, PCIE4, SGMII16, XFI13,
|
||||
XFI14 } },
|
||||
{0x08, {NONE, NONE, SATA1, SATA2, SATA3, SATA4, XFI13, XFI14 } },
|
||||
{0x09, {SGMII11, SGMII12, SGMII17, SGMII18, SGMII15, SGMII16, SGMII13,
|
||||
SGMII14} },
|
||||
{0x0A, {SGMII11, SGMII12, SGMII17, SGMII18, PCIE4, PCIE4, PCIE4,
|
||||
PCIE4 } },
|
||||
{0x0B, {PCIE3, SGMII12, SGMII17, SGMII18, PCIE4, SGMII16, SGMII13,
|
||||
SGMII14 } },
|
||||
{0x0C, {SGMII11, SGMII12, SGMII17, SGMII18, PCIE4, PCIE4, SATA1,
|
||||
SATA2 } },
|
||||
{0x0D, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SGMII13, SGMII14 } },
|
||||
{0x0E, {PCIE3, PCIE3, SGMII17, SGMII18, PCIE4, PCIE4, SGMII13,
|
||||
SGMII14 } },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct serdes_config serdes3_cfg_tbl[] = {
|
||||
/* SerDes 3 */
|
||||
{0x02, {PCIE5, PCIE5, PCIE5, PCIE5, PCIE5, PCIE5, PCIE5, PCIE5 } },
|
||||
{0x03, {PCIE5, PCIE5, PCIE5, PCIE5, PCIE6, PCIE6, PCIE6, PCIE6 } },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct serdes_config *serdes_cfg_tbl[] = {
|
||||
serdes1_cfg_tbl,
|
||||
serdes2_cfg_tbl,
|
||||
serdes3_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;
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/arch/mp.h>
|
||||
#include <asm/arch/soc.h>
|
||||
#include "cpu.h"
|
||||
#include <asm/arch-fsl-layerscape/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;
|
||||
}
|
||||
|
||||
void update_os_arch_secondary_cores(uint8_t os_arch)
|
||||
{
|
||||
u64 *table = get_spin_tbl_addr();
|
||||
int i;
|
||||
|
||||
for (i = 1; i < CONFIG_MAX_CPUS; i++) {
|
||||
if (os_arch == IH_ARCH_DEFAULT)
|
||||
table[i * WORDS_PER_SPIN_TABLE_ENTRY +
|
||||
SPIN_TABLE_ELEM_ARCH_COMP_IDX] = OS_ARCH_SAME;
|
||||
else
|
||||
table[i * WORDS_PER_SPIN_TABLE_ENTRY +
|
||||
SPIN_TABLE_ELEM_ARCH_COMP_IDX] = OS_ARCH_DIFF;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
void wake_secondary_core_n(int cluster, int core, int cluster_cores)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
|
||||
u32 mpidr = 0;
|
||||
|
||||
mpidr = ((cluster << 8) | core);
|
||||
/*
|
||||
* mpidr_el1 register value of core which needs to be released
|
||||
* is written to scratchrw[6] register
|
||||
*/
|
||||
gur_out32(&gur->scratchrw[6], mpidr);
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
rst->brrl |= 1 << ((cluster * cluster_cores) + core);
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
/*
|
||||
* scratchrw[6] register value is polled
|
||||
* when the value becomes zero, this means that this core is up
|
||||
* and running, next core can be released now
|
||||
*/
|
||||
while (gur_in32(&gur->scratchrw[6]) != 0)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
u32 svr, ver, cluster, type;
|
||||
int j = 0, cluster_cores = 0;
|
||||
#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);
|
||||
|
||||
svr = gur_in32(&gur->svr);
|
||||
ver = SVR_SOC_VER(svr);
|
||||
if (ver == SVR_LS2080A || ver == SVR_LS2085A) {
|
||||
gur_out32(&gur->scratchrw[6], 1);
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
rst->brrl = cores;
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
} else {
|
||||
/*
|
||||
* Release the cores out of reset one-at-a-time to avoid
|
||||
* power spikes
|
||||
*/
|
||||
i = 0;
|
||||
cluster = in_le32(&gur->tp_cluster[i].lower);
|
||||
for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
|
||||
type = initiator_type(cluster, j);
|
||||
if (type &&
|
||||
TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
|
||||
cluster_cores++;
|
||||
}
|
||||
|
||||
do {
|
||||
cluster = in_le32(&gur->tp_cluster[i].lower);
|
||||
for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
|
||||
type = initiator_type(cluster, j);
|
||||
if (type &&
|
||||
TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
|
||||
wake_secondary_core_n(i, j,
|
||||
cluster_cores);
|
||||
}
|
||||
i++;
|
||||
} while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
|
||||
}
|
||||
#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());
|
||||
}
|
||||
|
||||
static int is_pos_valid(unsigned int pos)
|
||||
{
|
||||
return !!((1 << pos) & cpu_pos_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(u32 nr)
|
||||
{
|
||||
puts("Feature is not implemented.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_disable(u32 nr)
|
||||
{
|
||||
puts("Feature is not implemented.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int core_to_pos(int nr)
|
||||
{
|
||||
u32 cores = cpu_pos_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_pos_valid(i)) {
|
||||
count++;
|
||||
if (count == nr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != nr)
|
||||
return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int cpu_status(u32 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(u32 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 */
|
||||
/*
|
||||
* When the first release command runs, all cores are set to go. Those
|
||||
* without a valid entry address will be trapped by "wfe". "sev" kicks
|
||||
* them off to check the address again. When set, they continue to run.
|
||||
*/
|
||||
asm volatile("sev");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 NXP Semiconductor, Inc.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <malloc.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
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
#include <fsl_validate.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_LS_PPA_FW_IN_NAND
|
||||
#include <nand.h>
|
||||
#elif defined(CONFIG_SYS_LS_PPA_FW_IN_MMC)
|
||||
#include <mmc.h>
|
||||
#endif
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int ppa_init(void)
|
||||
{
|
||||
unsigned int el = current_el();
|
||||
void *ppa_fit_addr;
|
||||
u32 *boot_loc_ptr_l, *boot_loc_ptr_h;
|
||||
u32 *loadable_l, *loadable_h;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
uintptr_t ppa_esbc_hdr = 0;
|
||||
uintptr_t ppa_img_addr = 0;
|
||||
#if defined(CONFIG_SYS_LS_PPA_FW_IN_MMC) || \
|
||||
defined(CONFIG_SYS_LS_PPA_FW_IN_NAND)
|
||||
void *ppa_hdr_ddr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Skip if running at lower exception level */
|
||||
if (el < 3) {
|
||||
debug("Skipping PPA init, running at EL%d\n", el);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_LS_PPA_FW_IN_XIP
|
||||
ppa_fit_addr = (void *)CONFIG_SYS_LS_PPA_FW_ADDR;
|
||||
debug("%s: PPA image load from XIP\n", __func__);
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
ppa_esbc_hdr = CONFIG_SYS_LS_PPA_ESBC_ADDR;
|
||||
#endif
|
||||
#else /* !CONFIG_SYS_LS_PPA_FW_IN_XIP */
|
||||
size_t fw_length, fdt_header_len = sizeof(struct fdt_header);
|
||||
|
||||
/* Copy PPA image from MMC/SD/NAND to allocated memory */
|
||||
#ifdef CONFIG_SYS_LS_PPA_FW_IN_MMC
|
||||
struct mmc *mmc;
|
||||
int dev = CONFIG_SYS_MMC_ENV_DEV;
|
||||
struct fdt_header *fitp;
|
||||
u32 cnt;
|
||||
u32 blk;
|
||||
|
||||
debug("%s: PPA image load from eMMC/SD\n", __func__);
|
||||
|
||||
ret = mmc_initialize(gd->bd);
|
||||
if (ret) {
|
||||
printf("%s: mmc_initialize() failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
mmc = find_mmc_device(dev);
|
||||
if (!mmc) {
|
||||
printf("PPA: MMC cannot find device for PPA firmware\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = mmc_init(mmc);
|
||||
if (ret) {
|
||||
printf("%s: mmc_init() failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fitp = malloc(roundup(fdt_header_len, 512));
|
||||
if (!fitp) {
|
||||
printf("PPA: malloc failed for FIT header(size 0x%zx)\n",
|
||||
roundup(fdt_header_len, 512));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
blk = CONFIG_SYS_LS_PPA_FW_ADDR / 512;
|
||||
cnt = DIV_ROUND_UP(fdt_header_len, 512);
|
||||
debug("%s: MMC read PPA FIT header: dev # %u, block # %u, count %u\n",
|
||||
__func__, dev, blk, cnt);
|
||||
ret = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, fitp);
|
||||
if (ret != cnt) {
|
||||
free(fitp);
|
||||
printf("MMC/SD read of PPA FIT header at offset 0x%x failed\n",
|
||||
CONFIG_SYS_LS_PPA_FW_ADDR);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = fdt_check_header(fitp);
|
||||
if (ret) {
|
||||
free(fitp);
|
||||
printf("%s: fdt_check_header() failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
ppa_hdr_ddr = malloc(CONFIG_LS_PPA_ESBC_HDR_SIZE);
|
||||
if (!ppa_hdr_ddr) {
|
||||
printf("PPA: malloc failed for PPA header\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
blk = CONFIG_SYS_LS_PPA_ESBC_ADDR >> 9;
|
||||
cnt = DIV_ROUND_UP(CONFIG_LS_PPA_ESBC_HDR_SIZE, 512);
|
||||
ret = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, ppa_hdr_ddr);
|
||||
if (ret != cnt) {
|
||||
free(ppa_hdr_ddr);
|
||||
printf("MMC/SD read of PPA header failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
debug("Read PPA header to 0x%p\n", ppa_hdr_ddr);
|
||||
|
||||
ppa_esbc_hdr = (uintptr_t)ppa_hdr_ddr;
|
||||
#endif
|
||||
|
||||
fw_length = fdt_totalsize(fitp);
|
||||
free(fitp);
|
||||
|
||||
fw_length = roundup(fw_length, 512);
|
||||
ppa_fit_addr = malloc(fw_length);
|
||||
if (!ppa_fit_addr) {
|
||||
printf("PPA: malloc failed for PPA image(size 0x%zx)\n",
|
||||
fw_length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
blk = CONFIG_SYS_LS_PPA_FW_ADDR / 512;
|
||||
cnt = DIV_ROUND_UP(fw_length, 512);
|
||||
debug("%s: MMC read PPA FIT image: dev # %u, block # %u, count %u\n",
|
||||
__func__, dev, blk, cnt);
|
||||
ret = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, ppa_fit_addr);
|
||||
if (ret != cnt) {
|
||||
free(ppa_fit_addr);
|
||||
printf("MMC/SD read of PPA FIT header at offset 0x%x failed\n",
|
||||
CONFIG_SYS_LS_PPA_FW_ADDR);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_SYS_LS_PPA_FW_IN_NAND)
|
||||
struct fdt_header fit;
|
||||
|
||||
debug("%s: PPA image load from NAND\n", __func__);
|
||||
|
||||
nand_init();
|
||||
ret = nand_read(get_nand_dev_by_index(0),
|
||||
(loff_t)CONFIG_SYS_LS_PPA_FW_ADDR,
|
||||
&fdt_header_len, (u_char *)&fit);
|
||||
if (ret == -EUCLEAN) {
|
||||
printf("NAND read of PPA FIT header at offset 0x%x failed\n",
|
||||
CONFIG_SYS_LS_PPA_FW_ADDR);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = fdt_check_header(&fit);
|
||||
if (ret) {
|
||||
printf("%s: fdt_check_header() failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
ppa_hdr_ddr = malloc(CONFIG_LS_PPA_ESBC_HDR_SIZE);
|
||||
if (!ppa_hdr_ddr) {
|
||||
printf("PPA: malloc failed for PPA header\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fw_length = CONFIG_LS_PPA_ESBC_HDR_SIZE;
|
||||
|
||||
ret = nand_read(get_nand_dev_by_index(0),
|
||||
(loff_t)CONFIG_SYS_LS_PPA_ESBC_ADDR,
|
||||
&fw_length, (u_char *)ppa_hdr_ddr);
|
||||
if (ret == -EUCLEAN) {
|
||||
free(ppa_hdr_ddr);
|
||||
printf("NAND read of PPA firmware at offset 0x%x failed\n",
|
||||
CONFIG_SYS_LS_PPA_FW_ADDR);
|
||||
return -EIO;
|
||||
}
|
||||
debug("Read PPA header to 0x%p\n", ppa_hdr_ddr);
|
||||
|
||||
ppa_esbc_hdr = (uintptr_t)ppa_hdr_ddr;
|
||||
#endif
|
||||
|
||||
fw_length = fdt_totalsize(&fit);
|
||||
|
||||
ppa_fit_addr = malloc(fw_length);
|
||||
if (!ppa_fit_addr) {
|
||||
printf("PPA: malloc failed for PPA image(size 0x%zx)\n",
|
||||
fw_length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = nand_read(get_nand_dev_by_index(0),
|
||||
(loff_t)CONFIG_SYS_LS_PPA_FW_ADDR,
|
||||
&fw_length, (u_char *)ppa_fit_addr);
|
||||
if (ret == -EUCLEAN) {
|
||||
free(ppa_fit_addr);
|
||||
printf("NAND read of PPA firmware at offset 0x%x failed\n",
|
||||
CONFIG_SYS_LS_PPA_FW_ADDR);
|
||||
return -EIO;
|
||||
}
|
||||
#else
|
||||
#error "No CONFIG_SYS_LS_PPA_FW_IN_xxx defined"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
ppa_img_addr = (uintptr_t)ppa_fit_addr;
|
||||
if (fsl_check_boot_mode_secure() != 0) {
|
||||
/*
|
||||
* In case of failure in validation, fsl_secboot_validate
|
||||
* would not return back in case of Production environment
|
||||
* with ITS=1. In Development environment (ITS=0 and
|
||||
* SB_EN=1), the function may return back in case of
|
||||
* non-fatal failures.
|
||||
*/
|
||||
ret = fsl_secboot_validate(ppa_esbc_hdr,
|
||||
PPA_KEY_HASH,
|
||||
&ppa_img_addr);
|
||||
if (ret != 0)
|
||||
printf("SEC firmware(s) validation failed\n");
|
||||
else
|
||||
printf("SEC firmware(s) validation Successful\n");
|
||||
}
|
||||
#if defined(CONFIG_SYS_LS_PPA_FW_IN_MMC) || \
|
||||
defined(CONFIG_SYS_LS_PPA_FW_IN_NAND)
|
||||
free(ppa_hdr_ddr);
|
||||
#endif
|
||||
#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;
|
||||
|
||||
/* Assign addresses to loadable ptrs */
|
||||
loadable_l = &gur->scratchrw[4];
|
||||
loadable_h = &gur->scratchrw[5];
|
||||
#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];
|
||||
|
||||
/* Assign addresses to loadable ptrs */
|
||||
loadable_l = &scfg->scratchrw[2];
|
||||
loadable_h = &scfg->scratchrw[3];
|
||||
#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,
|
||||
loadable_l, loadable_h);
|
||||
|
||||
#if defined(CONFIG_SYS_LS_PPA_FW_IN_MMC) || \
|
||||
defined(CONFIG_SYS_LS_PPA_FW_IN_NAND)
|
||||
free(ppa_fit_addr);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,874 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <env.h>
|
||||
#include <fsl_immap.h>
|
||||
#include <fsl_ifc.h>
|
||||
#include <init.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/soc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/arch-fsl-layerscape/config.h>
|
||||
#include <asm/arch-fsl-layerscape/ns_access.h>
|
||||
#include <asm/arch-fsl-layerscape/fsl_icid.h>
|
||||
#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
|
||||
#include <fsl_csu.h>
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_DDR
|
||||
#include <fsl_ddr_sdram.h>
|
||||
#include <fsl_ddr.h>
|
||||
#endif
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
#include <fsl_validate.h>
|
||||
#endif
|
||||
#include <fsl_immap.h>
|
||||
#ifdef CONFIG_TFABOOT
|
||||
#include <env_internal.h>
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
#endif
|
||||
|
||||
bool soc_has_dp_ddr(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 svr = gur_in32(&gur->svr);
|
||||
|
||||
/* LS2085A, LS2088A, LS2048A has DP_DDR */
|
||||
if ((SVR_SOC_VER(svr) == SVR_LS2085A) ||
|
||||
(SVR_SOC_VER(svr) == SVR_LS2088A) ||
|
||||
(SVR_SOC_VER(svr) == SVR_LS2048A))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool soc_has_aiop(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 svr = gur_in32(&gur->svr);
|
||||
|
||||
/* LS2085A has AIOP */
|
||||
if (SVR_SOC_VER(svr) == SVR_LS2085A)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void set_usb_txvreftune(u32 __iomem *scfg, u32 offset)
|
||||
{
|
||||
scfg_clrsetbits32(scfg + offset / 4,
|
||||
0xF << 6,
|
||||
SCFG_USB_TXVREFTUNE << 6);
|
||||
}
|
||||
|
||||
static void erratum_a009008(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009008
|
||||
u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A) || \
|
||||
defined(CONFIG_ARCH_LS1012A)
|
||||
set_usb_txvreftune(scfg, SCFG_USB3PRM1CR_USB1);
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
|
||||
set_usb_txvreftune(scfg, SCFG_USB3PRM1CR_USB2);
|
||||
set_usb_txvreftune(scfg, SCFG_USB3PRM1CR_USB3);
|
||||
#endif
|
||||
#elif defined(CONFIG_ARCH_LS2080A)
|
||||
set_usb_txvreftune(scfg, SCFG_USB3PRM1CR);
|
||||
#endif
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_A009008 */
|
||||
}
|
||||
|
||||
static inline void set_usb_sqrxtune(u32 __iomem *scfg, u32 offset)
|
||||
{
|
||||
scfg_clrbits32(scfg + offset / 4,
|
||||
SCFG_USB_SQRXTUNE_MASK << 23);
|
||||
}
|
||||
|
||||
static void erratum_a009798(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009798
|
||||
u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A) || \
|
||||
defined(CONFIG_ARCH_LS1012A)
|
||||
set_usb_sqrxtune(scfg, SCFG_USB3PRM1CR_USB1);
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
|
||||
set_usb_sqrxtune(scfg, SCFG_USB3PRM1CR_USB2);
|
||||
set_usb_sqrxtune(scfg, SCFG_USB3PRM1CR_USB3);
|
||||
#endif
|
||||
#elif defined(CONFIG_ARCH_LS2080A)
|
||||
set_usb_sqrxtune(scfg, SCFG_USB3PRM1CR);
|
||||
#endif
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_A009798 */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A) || \
|
||||
defined(CONFIG_ARCH_LS1012A)
|
||||
static inline void set_usb_pcstxswingfull(u32 __iomem *scfg, u32 offset)
|
||||
{
|
||||
scfg_clrsetbits32(scfg + offset / 4,
|
||||
0x7F << 9,
|
||||
SCFG_USB_PCSTXSWINGFULL << 9);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void erratum_a008997(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008997
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A) || \
|
||||
defined(CONFIG_ARCH_LS1012A)
|
||||
u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
|
||||
|
||||
set_usb_pcstxswingfull(scfg, SCFG_USB3PRM2CR_USB1);
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
|
||||
set_usb_pcstxswingfull(scfg, SCFG_USB3PRM2CR_USB2);
|
||||
set_usb_pcstxswingfull(scfg, SCFG_USB3PRM2CR_USB3);
|
||||
#endif
|
||||
#elif defined(CONFIG_ARCH_LS1028A)
|
||||
clrsetbits_le32(DCSR_BASE + DCSR_USB_IOCR1,
|
||||
0x7F << 11,
|
||||
DCSR_USB_PCSTXSWINGFULL << 11);
|
||||
#endif
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_A008997 */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A) || \
|
||||
defined(CONFIG_ARCH_LS1012A)
|
||||
|
||||
#define PROGRAM_USB_PHY_RX_OVRD_IN_HI(phy) \
|
||||
out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_1); \
|
||||
out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_2); \
|
||||
out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_3); \
|
||||
out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_4)
|
||||
|
||||
#elif defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A) || \
|
||||
defined(CONFIG_ARCH_LS1028A)
|
||||
|
||||
#define PROGRAM_USB_PHY_RX_OVRD_IN_HI(phy) \
|
||||
out_le16((phy) + DCSR_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_1); \
|
||||
out_le16((phy) + DCSR_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_2); \
|
||||
out_le16((phy) + DCSR_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_3); \
|
||||
out_le16((phy) + DCSR_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_4)
|
||||
|
||||
#endif
|
||||
|
||||
static void erratum_a009007(void)
|
||||
{
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A) || \
|
||||
defined(CONFIG_ARCH_LS1012A)
|
||||
void __iomem *usb_phy = (void __iomem *)SCFG_USB_PHY1;
|
||||
|
||||
PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy);
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
|
||||
usb_phy = (void __iomem *)SCFG_USB_PHY2;
|
||||
PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy);
|
||||
|
||||
usb_phy = (void __iomem *)SCFG_USB_PHY3;
|
||||
PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy);
|
||||
#endif
|
||||
#elif defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A) || \
|
||||
defined(CONFIG_ARCH_LS1028A)
|
||||
void __iomem *dcsr = (void __iomem *)DCSR_BASE;
|
||||
|
||||
PROGRAM_USB_PHY_RX_OVRD_IN_HI(dcsr + DCSR_USB_PHY1);
|
||||
PROGRAM_USB_PHY_RX_OVRD_IN_HI(dcsr + DCSR_USB_PHY2);
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_A009007 */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FSL_LSCH3)
|
||||
/*
|
||||
* This erratum requires setting a value to eddrtqcr1 to
|
||||
* optimal the DDR performance.
|
||||
*/
|
||||
static void erratum_a008336(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008336
|
||||
u32 *eddrtqcr1;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_DCSR_DDR_ADDR
|
||||
eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR_ADDR + 0x800;
|
||||
if (fsl_ddr_get_version(0) == 0x50200)
|
||||
out_le32(eddrtqcr1, 0x63b30002);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_DCSR_DDR2_ADDR
|
||||
eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR2_ADDR + 0x800;
|
||||
if (fsl_ddr_get_version(0) == 0x50200)
|
||||
out_le32(eddrtqcr1, 0x63b30002);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This erratum requires a register write before being Memory
|
||||
* controller 3 being enabled.
|
||||
*/
|
||||
static void erratum_a008514(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008514
|
||||
u32 *eddrtqcr1;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_DCSR_DDR3_ADDR
|
||||
eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR3_ADDR + 0x800;
|
||||
out_le32(eddrtqcr1, 0x63b20002);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009635
|
||||
#define PLATFORM_CYCLE_ENV_VAR "a009635_interval_val"
|
||||
|
||||
static unsigned long get_internval_val_mhz(void)
|
||||
{
|
||||
char *interval = env_get(PLATFORM_CYCLE_ENV_VAR);
|
||||
/*
|
||||
* interval is the number of platform cycles(MHz) between
|
||||
* wake up events generated by EPU.
|
||||
*/
|
||||
ulong interval_mhz = get_bus_freq(0) / (1000 * 1000);
|
||||
|
||||
if (interval)
|
||||
interval_mhz = simple_strtoul(interval, NULL, 10);
|
||||
|
||||
return interval_mhz;
|
||||
}
|
||||
|
||||
void erratum_a009635(void)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long interval_mhz = get_internval_val_mhz();
|
||||
|
||||
if (!interval_mhz)
|
||||
return;
|
||||
|
||||
val = in_le32(DCSR_CGACRE5);
|
||||
writel(val | 0x00000200, DCSR_CGACRE5);
|
||||
|
||||
val = in_le32(EPU_EPCMPR5);
|
||||
writel(interval_mhz, EPU_EPCMPR5);
|
||||
val = in_le32(EPU_EPCCR5);
|
||||
writel(val | 0x82820000, EPU_EPCCR5);
|
||||
val = in_le32(EPU_EPSMCR5);
|
||||
writel(val | 0x002f0000, EPU_EPSMCR5);
|
||||
val = in_le32(EPU_EPECR5);
|
||||
writel(val | 0x20000000, EPU_EPECR5);
|
||||
val = in_le32(EPU_EPGCR);
|
||||
writel(val | 0x80000000, EPU_EPGCR);
|
||||
}
|
||||
#endif /* CONFIG_SYS_FSL_ERRATUM_A009635 */
|
||||
|
||||
static void erratum_rcw_src(void)
|
||||
{
|
||||
#if defined(CONFIG_SPL) && defined(CONFIG_NAND_BOOT)
|
||||
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.
|
||||
*/
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009203
|
||||
static void erratum_a009203(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_I2C
|
||||
u8 __iomem *ptr;
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
|
||||
void bypass_smmu(void)
|
||||
{
|
||||
u32 val;
|
||||
val = (in_le32(SMMU_SCR0) | SCR0_CLIENTPD_MASK) & ~(SCR0_USFCFG_MASK);
|
||||
out_le32(SMMU_SCR0, val);
|
||||
val = (in_le32(SMMU_NSCR0) | SCR0_CLIENTPD_MASK) & ~(SCR0_USFCFG_MASK);
|
||||
out_le32(SMMU_NSCR0, val);
|
||||
}
|
||||
void fsl_lsch3_early_init_f(void)
|
||||
{
|
||||
erratum_rcw_src();
|
||||
#ifdef CONFIG_FSL_IFC
|
||||
init_early_memctl_regs(); /* tighten IFC timing */
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009203
|
||||
erratum_a009203();
|
||||
#endif
|
||||
erratum_a008514();
|
||||
erratum_a008336();
|
||||
erratum_a009008();
|
||||
erratum_a009798();
|
||||
erratum_a008997();
|
||||
erratum_a009007();
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
/* In case of Secure Boot, the IBR configures the SMMU
|
||||
* to allow only Secure transactions.
|
||||
* SMMU must be reset in bypass mode.
|
||||
* Set the ClientPD bit and Clear the USFCFG Bit
|
||||
*/
|
||||
if (fsl_check_boot_mode_secure() == 1)
|
||||
bypass_smmu();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1088A) || defined(CONFIG_ARCH_LS1028A) || \
|
||||
defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LX2160A)
|
||||
set_icids();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get VDD in the unit mV from voltage ID */
|
||||
int get_core_volt_from_fuse(void)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
int vdd;
|
||||
u32 fusesr;
|
||||
u8 vid;
|
||||
|
||||
/* get the voltage ID from fuse status register */
|
||||
fusesr = in_le32(&gur->dcfg_fusesr);
|
||||
debug("%s: fusesr = 0x%x\n", __func__, fusesr);
|
||||
vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
|
||||
FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
|
||||
if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
|
||||
vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
|
||||
FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
|
||||
}
|
||||
debug("%s: VID = 0x%x\n", __func__, vid);
|
||||
switch (vid) {
|
||||
case 0x00: /* VID isn't supported */
|
||||
vdd = -EINVAL;
|
||||
debug("%s: The VID feature is not supported\n", __func__);
|
||||
break;
|
||||
case 0x08: /* 0.9V silicon */
|
||||
vdd = 900;
|
||||
break;
|
||||
case 0x10: /* 1.0V silicon */
|
||||
vdd = 1000;
|
||||
break;
|
||||
default: /* Other core voltage */
|
||||
vdd = -EINVAL;
|
||||
debug("%s: The VID(%x) isn't supported\n", __func__, vid);
|
||||
break;
|
||||
}
|
||||
debug("%s: The required minimum volt of CORE is %dmV\n", __func__, vdd);
|
||||
|
||||
return vdd;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
|
||||
static void erratum_a009929(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009929
|
||||
struct ccsr_gur *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
|
||||
u32 __iomem *dcsr_cop_ccp = (void *)CONFIG_SYS_DCSR_COP_CCP_ADDR;
|
||||
u32 rstrqmr1 = gur_in32(&gur->rstrqmr1);
|
||||
|
||||
rstrqmr1 |= 0x00000400;
|
||||
gur_out32(&gur->rstrqmr1, rstrqmr1);
|
||||
writel(0x01000000, dcsr_cop_ccp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This erratum requires setting a value to eddrtqcr1 to optimal
|
||||
* the DDR performance. The eddrtqcr1 register is in SCFG space
|
||||
* of LS1043A and the offset is 0x157_020c.
|
||||
*/
|
||||
#if defined(CONFIG_SYS_FSL_ERRATUM_A009660) \
|
||||
&& defined(CONFIG_SYS_FSL_ERRATUM_A008514)
|
||||
#error A009660 and A008514 can not be both enabled.
|
||||
#endif
|
||||
|
||||
static void erratum_a009660(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009660
|
||||
u32 *eddrtqcr1 = (void *)CONFIG_SYS_FSL_SCFG_ADDR + 0x20c;
|
||||
out_be32(eddrtqcr1, 0x63b20042);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void erratum_a008850_early(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008850
|
||||
/* part 1 of 2 */
|
||||
struct ccsr_cci400 __iomem *cci = (void *)(CONFIG_SYS_IMMR +
|
||||
CONFIG_SYS_CCI400_OFFSET);
|
||||
struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
|
||||
/* Skip if running at lower exception level */
|
||||
if (current_el() < 3)
|
||||
return;
|
||||
|
||||
/* disables propagation of barrier transactions to DDRC from CCI400 */
|
||||
out_le32(&cci->ctrl_ord, CCI400_CTRLORD_TERM_BARRIER);
|
||||
|
||||
/* disable the re-ordering in DDRC */
|
||||
ddr_out32(&ddr->eor, DDR_EOR_RD_REOD_DIS | DDR_EOR_WD_REOD_DIS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void erratum_a008850_post(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008850
|
||||
/* part 2 of 2 */
|
||||
struct ccsr_cci400 __iomem *cci = (void *)(CONFIG_SYS_IMMR +
|
||||
CONFIG_SYS_CCI400_OFFSET);
|
||||
struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
u32 tmp;
|
||||
|
||||
/* Skip if running at lower exception level */
|
||||
if (current_el() < 3)
|
||||
return;
|
||||
|
||||
/* enable propagation of barrier transactions to DDRC from CCI400 */
|
||||
out_le32(&cci->ctrl_ord, CCI400_CTRLORD_EN_BARRIER);
|
||||
|
||||
/* enable the re-ordering in DDRC */
|
||||
tmp = ddr_in32(&ddr->eor);
|
||||
tmp &= ~(DDR_EOR_RD_REOD_DIS | DDR_EOR_WD_REOD_DIS);
|
||||
ddr_out32(&ddr->eor, tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A010315
|
||||
void erratum_a010315(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = PCIE1; i <= PCIE4; i++)
|
||||
if (!is_serdes_configured(i)) {
|
||||
debug("PCIe%d: disabled all R/W permission!\n", i);
|
||||
set_pcie_ns_access(i, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void erratum_a010539(void)
|
||||
{
|
||||
#if defined(CONFIG_SYS_FSL_ERRATUM_A010539) && defined(CONFIG_QSPI_BOOT)
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 porsr1;
|
||||
|
||||
porsr1 = in_be32(&gur->porsr1);
|
||||
porsr1 &= ~FSL_CHASSIS2_CCSR_PORSR1_RCW_MASK;
|
||||
out_be32((void *)(CONFIG_SYS_DCSR_DCFG_ADDR + DCFG_DCSR_PORCR1),
|
||||
porsr1);
|
||||
out_be32((void *)(CONFIG_SYS_FSL_SCFG_ADDR + 0x1a8), 0xffffffff);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get VDD in the unit mV from voltage ID */
|
||||
int get_core_volt_from_fuse(void)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
int vdd;
|
||||
u32 fusesr;
|
||||
u8 vid;
|
||||
|
||||
fusesr = in_be32(&gur->dcfg_fusesr);
|
||||
debug("%s: fusesr = 0x%x\n", __func__, fusesr);
|
||||
vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
|
||||
FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
|
||||
if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
|
||||
vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
|
||||
FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
|
||||
}
|
||||
debug("%s: VID = 0x%x\n", __func__, vid);
|
||||
switch (vid) {
|
||||
case 0x00: /* VID isn't supported */
|
||||
vdd = -EINVAL;
|
||||
debug("%s: The VID feature is not supported\n", __func__);
|
||||
break;
|
||||
case 0x08: /* 0.9V silicon */
|
||||
vdd = 900;
|
||||
break;
|
||||
case 0x10: /* 1.0V silicon */
|
||||
vdd = 1000;
|
||||
break;
|
||||
default: /* Other core voltage */
|
||||
vdd = -EINVAL;
|
||||
printf("%s: The VID(%x) isn't supported\n", __func__, vid);
|
||||
break;
|
||||
}
|
||||
debug("%s: The required minimum volt of CORE is %dmV\n", __func__, vdd);
|
||||
|
||||
return vdd;
|
||||
}
|
||||
|
||||
__weak int board_switch_core_volt(u32 vdd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_core_volt(u32 vdd)
|
||||
{
|
||||
return board_setup_core_volt(vdd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_DDR
|
||||
static void ddr_enable_0v9_volt(bool en)
|
||||
{
|
||||
struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
u32 tmp;
|
||||
|
||||
tmp = ddr_in32(&ddr->ddr_cdr1);
|
||||
|
||||
if (en)
|
||||
tmp |= DDR_CDR1_V0PT9_EN;
|
||||
else
|
||||
tmp &= ~DDR_CDR1_V0PT9_EN;
|
||||
|
||||
ddr_out32(&ddr->ddr_cdr1, tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
int setup_chip_volt(void)
|
||||
{
|
||||
int vdd;
|
||||
|
||||
vdd = get_core_volt_from_fuse();
|
||||
/* Nothing to do for silicons doesn't support VID */
|
||||
if (vdd < 0)
|
||||
return vdd;
|
||||
|
||||
if (setup_core_volt(vdd))
|
||||
printf("%s: Switch core VDD to %dmV failed\n", __func__, vdd);
|
||||
#ifdef CONFIG_SYS_HAS_SERDES
|
||||
if (setup_serdes_volt(vdd))
|
||||
printf("%s: Switch SVDD to %dmV failed\n", __func__, vdd);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_DDR
|
||||
if (vdd == 900)
|
||||
ddr_enable_0v9_volt(true);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_PFE
|
||||
void init_pfe_scfg_dcfg_regs(void)
|
||||
{
|
||||
struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
|
||||
u32 ecccr2;
|
||||
|
||||
out_be32(&scfg->pfeasbcr,
|
||||
in_be32(&scfg->pfeasbcr) | SCFG_PFEASBCR_AWCACHE0);
|
||||
out_be32(&scfg->pfebsbcr,
|
||||
in_be32(&scfg->pfebsbcr) | SCFG_PFEASBCR_AWCACHE0);
|
||||
|
||||
/* CCI-400 QoS settings for PFE */
|
||||
out_be32(&scfg->wr_qos1, (unsigned int)(SCFG_WR_QOS1_PFE1_QOS
|
||||
| SCFG_WR_QOS1_PFE2_QOS));
|
||||
out_be32(&scfg->rd_qos1, (unsigned int)(SCFG_RD_QOS1_PFE1_QOS
|
||||
| SCFG_RD_QOS1_PFE2_QOS));
|
||||
|
||||
ecccr2 = in_be32(CONFIG_SYS_DCSR_DCFG_ADDR + DCFG_DCSR_ECCCR2);
|
||||
out_be32((void *)CONFIG_SYS_DCSR_DCFG_ADDR + DCFG_DCSR_ECCCR2,
|
||||
ecccr2 | (unsigned int)DISABLE_PFE_ECC);
|
||||
}
|
||||
#endif
|
||||
|
||||
void fsl_lsch2_early_init_f(void)
|
||||
{
|
||||
struct ccsr_cci400 *cci = (struct ccsr_cci400 *)(CONFIG_SYS_IMMR +
|
||||
CONFIG_SYS_CCI400_OFFSET);
|
||||
struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
|
||||
#if defined(CONFIG_FSL_QSPI) && defined(CONFIG_TFABOOT)
|
||||
enum boot_src src;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
|
||||
enable_layerscape_ns_access();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_IFC
|
||||
init_early_memctl_regs(); /* tighten IFC timing */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_QSPI) && defined(CONFIG_TFABOOT)
|
||||
src = get_boot_src();
|
||||
if (src != BOOT_SOURCE_QSPI_NOR)
|
||||
out_be32(&scfg->qspi_cfg, SCFG_QSPI_CLKSEL);
|
||||
#else
|
||||
#if defined(CONFIG_FSL_QSPI) && !defined(CONFIG_QSPI_BOOT)
|
||||
out_be32(&scfg->qspi_cfg, SCFG_QSPI_CLKSEL);
|
||||
#endif
|
||||
#endif
|
||||
/* Make SEC reads and writes snoopable */
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
|
||||
setbits_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SECRDSNP |
|
||||
SCFG_SNPCNFGCR_SECWRSNP | SCFG_SNPCNFGCR_USB1RDSNP |
|
||||
SCFG_SNPCNFGCR_USB1WRSNP | SCFG_SNPCNFGCR_USB2RDSNP |
|
||||
SCFG_SNPCNFGCR_USB2WRSNP | SCFG_SNPCNFGCR_USB3RDSNP |
|
||||
SCFG_SNPCNFGCR_USB3WRSNP | SCFG_SNPCNFGCR_SATARDSNP |
|
||||
SCFG_SNPCNFGCR_SATAWRSNP);
|
||||
#else
|
||||
setbits_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SECRDSNP |
|
||||
SCFG_SNPCNFGCR_SECWRSNP |
|
||||
SCFG_SNPCNFGCR_SATARDSNP |
|
||||
SCFG_SNPCNFGCR_SATAWRSNP);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable snoop requests and DVM message requests for
|
||||
* Slave insterface S4 (A53 core cluster)
|
||||
*/
|
||||
if (current_el() == 3) {
|
||||
out_le32(&cci->slave[4].snoop_ctrl,
|
||||
CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Program Central Security Unit (CSU) to grant access
|
||||
* permission for USB 2.0 controller
|
||||
*/
|
||||
#if defined(CONFIG_ARCH_LS1012A) && defined(CONFIG_USB_EHCI_FSL)
|
||||
if (current_el() == 3)
|
||||
set_devices_ns_access(CSU_CSLX_USB_2, CSU_ALL_RW);
|
||||
#endif
|
||||
/* Erratum */
|
||||
erratum_a008850_early(); /* part 1 of 2 */
|
||||
erratum_a009929();
|
||||
erratum_a009660();
|
||||
erratum_a010539();
|
||||
erratum_a009008();
|
||||
erratum_a009798();
|
||||
erratum_a008997();
|
||||
erratum_a009007();
|
||||
|
||||
#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
|
||||
set_icids();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_QSPI_AHB_INIT
|
||||
/* Enable 4bytes address support and fast read */
|
||||
int qspi_ahb_init(void)
|
||||
{
|
||||
u32 *qspi_lut, lut_key, *qspi_key;
|
||||
|
||||
qspi_key = (void *)SYS_FSL_QSPI_ADDR + 0x300;
|
||||
qspi_lut = (void *)SYS_FSL_QSPI_ADDR + 0x310;
|
||||
|
||||
lut_key = in_be32(qspi_key);
|
||||
|
||||
if (lut_key == 0x5af05af0) {
|
||||
/* That means the register is BE */
|
||||
out_be32(qspi_key, 0x5af05af0);
|
||||
/* Unlock the lut table */
|
||||
out_be32(qspi_key + 1, 0x00000002);
|
||||
out_be32(qspi_lut, 0x0820040c);
|
||||
out_be32(qspi_lut + 1, 0x1c080c08);
|
||||
out_be32(qspi_lut + 2, 0x00002400);
|
||||
/* Lock the lut table */
|
||||
out_be32(qspi_key, 0x5af05af0);
|
||||
out_be32(qspi_key + 1, 0x00000001);
|
||||
} else {
|
||||
/* That means the register is LE */
|
||||
out_le32(qspi_key, 0x5af05af0);
|
||||
/* Unlock the lut table */
|
||||
out_le32(qspi_key + 1, 0x00000002);
|
||||
out_le32(qspi_lut, 0x0820040c);
|
||||
out_le32(qspi_lut + 1, 0x1c080c08);
|
||||
out_le32(qspi_lut + 2, 0x00002400);
|
||||
/* Lock the lut table */
|
||||
out_le32(qspi_key, 0x5af05af0);
|
||||
out_le32(qspi_key + 1, 0x00000001);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TFABOOT
|
||||
#define MAX_BOOTCMD_SIZE 512
|
||||
|
||||
int fsl_setenv_bootcmd(void)
|
||||
{
|
||||
int ret;
|
||||
enum boot_src src = get_boot_src();
|
||||
char bootcmd_str[MAX_BOOTCMD_SIZE];
|
||||
|
||||
switch (src) {
|
||||
#ifdef IFC_NOR_BOOTCOMMAND
|
||||
case BOOT_SOURCE_IFC_NOR:
|
||||
sprintf(bootcmd_str, IFC_NOR_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef QSPI_NOR_BOOTCOMMAND
|
||||
case BOOT_SOURCE_QSPI_NOR:
|
||||
sprintf(bootcmd_str, QSPI_NOR_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XSPI_NOR_BOOTCOMMAND
|
||||
case BOOT_SOURCE_XSPI_NOR:
|
||||
sprintf(bootcmd_str, XSPI_NOR_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IFC_NAND_BOOTCOMMAND
|
||||
case BOOT_SOURCE_IFC_NAND:
|
||||
sprintf(bootcmd_str, IFC_NAND_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef QSPI_NAND_BOOTCOMMAND
|
||||
case BOOT_SOURCE_QSPI_NAND:
|
||||
sprintf(bootcmd_str, QSPI_NAND_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XSPI_NAND_BOOTCOMMAND
|
||||
case BOOT_SOURCE_XSPI_NAND:
|
||||
sprintf(bootcmd_str, XSPI_NAND_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SD_BOOTCOMMAND
|
||||
case BOOT_SOURCE_SD_MMC:
|
||||
sprintf(bootcmd_str, SD_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SD2_BOOTCOMMAND
|
||||
case BOOT_SOURCE_SD_MMC2:
|
||||
sprintf(bootcmd_str, SD2_BOOTCOMMAND);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
#ifdef QSPI_NOR_BOOTCOMMAND
|
||||
sprintf(bootcmd_str, QSPI_NOR_BOOTCOMMAND);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
ret = env_set("bootcmd", bootcmd_str);
|
||||
if (ret) {
|
||||
printf("Failed to set bootcmd: ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsl_setenv_mcinitcmd(void)
|
||||
{
|
||||
int ret = 0;
|
||||
enum boot_src src = get_boot_src();
|
||||
|
||||
switch (src) {
|
||||
#ifdef IFC_MC_INIT_CMD
|
||||
case BOOT_SOURCE_IFC_NAND:
|
||||
case BOOT_SOURCE_IFC_NOR:
|
||||
ret = env_set("mcinitcmd", IFC_MC_INIT_CMD);
|
||||
break;
|
||||
#endif
|
||||
#ifdef QSPI_MC_INIT_CMD
|
||||
case BOOT_SOURCE_QSPI_NAND:
|
||||
case BOOT_SOURCE_QSPI_NOR:
|
||||
ret = env_set("mcinitcmd", QSPI_MC_INIT_CMD);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XSPI_MC_INIT_CMD
|
||||
case BOOT_SOURCE_XSPI_NAND:
|
||||
case BOOT_SOURCE_XSPI_NOR:
|
||||
ret = env_set("mcinitcmd", XSPI_MC_INIT_CMD);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SD_MC_INIT_CMD
|
||||
case BOOT_SOURCE_SD_MMC:
|
||||
ret = env_set("mcinitcmd", SD_MC_INIT_CMD);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SD2_MC_INIT_CMD
|
||||
case BOOT_SOURCE_SD_MMC2:
|
||||
ret = env_set("mcinitcmd", SD2_MC_INIT_CMD);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
#ifdef QSPI_MC_INIT_CMD
|
||||
ret = env_set("mcinitcmd", QSPI_MC_INIT_CMD);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
printf("Failed to set mcinitcmd: ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARD_LATE_INIT
|
||||
__weak int fsl_board_late_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int board_late_init(void)
|
||||
{
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
fsl_setenv_chain_of_trust();
|
||||
#endif
|
||||
#ifdef CONFIG_TFABOOT
|
||||
/*
|
||||
* check if gd->env_addr is default_environment; then setenv bootcmd
|
||||
* and mcinitcmd.
|
||||
*/
|
||||
#ifdef CONFIG_SYS_RELOC_GD_ENV_ADDR
|
||||
if (gd->env_addr == (ulong)&default_environment[0]) {
|
||||
#else
|
||||
if (gd->env_addr + gd->reloc_off == (ulong)&default_environment[0]) {
|
||||
#endif
|
||||
fsl_setenv_bootcmd();
|
||||
fsl_setenv_mcinitcmd();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the boot mode is secure, default environment is not present then
|
||||
* setenv command needs to be run by default
|
||||
*/
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
if ((fsl_check_boot_mode_secure() == 1)) {
|
||||
fsl_setenv_bootcmd();
|
||||
fsl_setenv_mcinitcmd();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_QSPI_AHB_INIT
|
||||
qspi_ahb_init();
|
||||
#endif
|
||||
|
||||
return fsl_board_late_init();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <env.h>
|
||||
#include <spl.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ifc.h>
|
||||
#include <i2c.h>
|
||||
#include <fsl_csu.h>
|
||||
#include <asm/arch/fdt.h>
|
||||
#include <asm/arch/ppa.h>
|
||||
#include <asm/arch/soc.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
|
||||
#ifdef CONFIG_QSPI_BOOT
|
||||
return BOOT_DEVICE_NOR;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
|
||||
void spl_board_init(void)
|
||||
{
|
||||
#if defined(CONFIG_NXP_ESBC) && defined(CONFIG_FSL_LSCH2)
|
||||
/*
|
||||
* In case of Secure Boot, the IBR configures the SMMU
|
||||
* to allow only Secure transactions.
|
||||
* SMMU must be reset in bypass mode.
|
||||
* Set the ClientPD bit and Clear the USFCFG Bit
|
||||
*/
|
||||
u32 val;
|
||||
val = (in_le32(SMMU_SCR0) | SCR0_CLIENTPD_MASK) & ~(SCR0_USFCFG_MASK);
|
||||
out_le32(SMMU_SCR0, val);
|
||||
val = (in_le32(SMMU_NSCR0) | SCR0_CLIENTPD_MASK) & ~(SCR0_USFCFG_MASK);
|
||||
out_le32(SMMU_NSCR0, val);
|
||||
#endif
|
||||
#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
|
||||
enable_layerscape_ns_access();
|
||||
#endif
|
||||
#ifdef CONFIG_SPL_FSL_LS_PPA
|
||||
ppa_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
icache_enable();
|
||||
/* Clear global data */
|
||||
memset((void *)gd, 0, sizeof(gd_t));
|
||||
board_early_init_f();
|
||||
timer_init();
|
||||
#ifdef CONFIG_ARCH_LS2080A
|
||||
env_init();
|
||||
#endif
|
||||
get_clocks();
|
||||
|
||||
preloader_console_init();
|
||||
spl_set_bd();
|
||||
|
||||
#ifdef CONFIG_SPL_I2C_SUPPORT
|
||||
i2c_init_all();
|
||||
#endif
|
||||
#ifdef CONFIG_VID
|
||||
init_func_vid();
|
||||
#endif
|
||||
dram_init();
|
||||
#ifdef CONFIG_SPL_FSL_LS_PPA
|
||||
#ifndef CONFIG_SYS_MEM_RESERVE_SECURE
|
||||
#error Need secure RAM for PPA
|
||||
#endif
|
||||
/*
|
||||
* Secure memory location is determined in dram_init_banksize().
|
||||
* gd->ram_size is deducted by the size of secure ram.
|
||||
*/
|
||||
dram_init_banksize();
|
||||
|
||||
/*
|
||||
* After dram_init_bank_size(), we know U-Boot only uses the first
|
||||
* memory bank regardless how big the memory is.
|
||||
*/
|
||||
gd->ram_top = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size;
|
||||
|
||||
/*
|
||||
* If PPA is loaded, U-Boot will resume running at EL2.
|
||||
* Cache and MMU will be enabled. Need a place for TLB.
|
||||
* U-Boot will be relocated to the end of available memory
|
||||
* in first bank. At this point, we cannot know how much
|
||||
* memory U-Boot uses. Put TLB table lower by SPL_TLB_SETBACK
|
||||
* to avoid overlapping. As soon as the RAM version U-Boot sets
|
||||
* up new MMU, this space is no longer needed.
|
||||
*/
|
||||
gd->ram_top -= SPL_TLB_SETBACK;
|
||||
gd->arch.tlb_size = PGTABLE_SIZE;
|
||||
gd->arch.tlb_addr = (gd->ram_top - gd->arch.tlb_size) & ~(0x10000 - 1);
|
||||
gd->arch.tlb_allocated = gd->arch.tlb_addr;
|
||||
#endif /* CONFIG_SPL_FSL_LS_PPA */
|
||||
#if defined(CONFIG_QSPI_AHB_INIT) && defined(CONFIG_QSPI_BOOT)
|
||||
qspi_ahb_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_OS_BOOT
|
||||
/*
|
||||
* Return
|
||||
* 0 if booting into OS is selected
|
||||
* 1 if booting into U-Boot is selected
|
||||
*/
|
||||
int spl_start_uboot(void)
|
||||
{
|
||||
env_init();
|
||||
if (env_get_yesno("boot_os") != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_SPL_OS_BOOT */
|
||||
#ifdef CONFIG_SPL_LOAD_FIT
|
||||
int board_fit_config_name_match(const char *name)
|
||||
{
|
||||
/* Just empty function now - can't decide what to choose */
|
||||
debug("%s: %s\n", __func__, name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
@@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/**
|
||||
* (C) Copyright 2014, Cavium Inc.
|
||||
* (C) Copyright 2017, Xilinx Inc.
|
||||
*
|
||||
**/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <version.h>
|
||||
#include <asm/macro.h>
|
||||
#include <asm/psci.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* Issue the hypervisor call
|
||||
*
|
||||
* x0~x7: input arguments
|
||||
* x0~x3: output arguments
|
||||
*/
|
||||
static void hvc_call(struct pt_regs *args)
|
||||
{
|
||||
asm volatile(
|
||||
"ldr x0, %0\n"
|
||||
"ldr x1, %1\n"
|
||||
"ldr x2, %2\n"
|
||||
"ldr x3, %3\n"
|
||||
"ldr x4, %4\n"
|
||||
"ldr x5, %5\n"
|
||||
"ldr x6, %6\n"
|
||||
"hvc #0\n"
|
||||
"str x0, %0\n"
|
||||
"str x1, %1\n"
|
||||
"str x2, %2\n"
|
||||
"str x3, %3\n"
|
||||
: "+m" (args->regs[0]), "+m" (args->regs[1]),
|
||||
"+m" (args->regs[2]), "+m" (args->regs[3])
|
||||
: "m" (args->regs[4]), "m" (args->regs[5]),
|
||||
"m" (args->regs[6])
|
||||
: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||
"x16", "x17");
|
||||
}
|
||||
|
||||
/*
|
||||
* void smc_call(arg0, arg1...arg7)
|
||||
*
|
||||
* issue the secure monitor call
|
||||
*
|
||||
* x0~x7: input arguments
|
||||
* x0~x3: output arguments
|
||||
*/
|
||||
|
||||
void smc_call(struct pt_regs *args)
|
||||
{
|
||||
asm volatile(
|
||||
"ldr x0, %0\n"
|
||||
"ldr x1, %1\n"
|
||||
"ldr x2, %2\n"
|
||||
"ldr x3, %3\n"
|
||||
"ldr x4, %4\n"
|
||||
"ldr x5, %5\n"
|
||||
"ldr x6, %6\n"
|
||||
"smc #0\n"
|
||||
"str x0, %0\n"
|
||||
"str x1, %1\n"
|
||||
"str x2, %2\n"
|
||||
"str x3, %3\n"
|
||||
: "+m" (args->regs[0]), "+m" (args->regs[1]),
|
||||
"+m" (args->regs[2]), "+m" (args->regs[3])
|
||||
: "m" (args->regs[4]), "m" (args->regs[5]),
|
||||
"m" (args->regs[6])
|
||||
: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||
"x16", "x17");
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, all systems we support run at least in EL2 and thus
|
||||
* trigger PSCI calls to EL3 using SMC. If anyone ever wants to
|
||||
* use PSCI on U-Boot running below a hypervisor, please detect
|
||||
* this and set the flag accordingly.
|
||||
*/
|
||||
static const bool use_smc_for_psci = true;
|
||||
|
||||
void __noreturn psci_system_reset(void)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
|
||||
regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
|
||||
|
||||
if (use_smc_for_psci)
|
||||
smc_call(®s);
|
||||
else
|
||||
hvc_call(®s);
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void __noreturn psci_system_off(void)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
|
||||
regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF;
|
||||
|
||||
if (use_smc_for_psci)
|
||||
smc_call(®s);
|
||||
else
|
||||
hvc_call(®s);
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <time.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Generic timer implementation of get_tbclk()
|
||||
*/
|
||||
unsigned long get_tbclk(void)
|
||||
{
|
||||
unsigned long cntfrq;
|
||||
asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq));
|
||||
return cntfrq;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008585
|
||||
/*
|
||||
* FSL erratum A-008585 says that the ARM generic timer counter "has the
|
||||
* potential to contain an erroneous value for a small number of core
|
||||
* clock cycles every time the timer value changes".
|
||||
* This sometimes leads to a consecutive counter read returning a lower
|
||||
* value than the previous one, thus reporting the time to go backwards.
|
||||
* The workaround is to read the counter twice and only return when the value
|
||||
* was the same in both reads.
|
||||
* Assumes that the CPU runs in much higher frequency than the timer.
|
||||
*/
|
||||
unsigned long timer_read_counter(void)
|
||||
{
|
||||
unsigned long cntpct;
|
||||
unsigned long temp;
|
||||
|
||||
isb();
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (temp));
|
||||
while (temp != cntpct) {
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (temp));
|
||||
}
|
||||
|
||||
return cntpct;
|
||||
}
|
||||
#elif CONFIG_SUNXI_A64_TIMER_ERRATUM
|
||||
/*
|
||||
* This erratum sometimes flips the lower 11 bits of the counter value
|
||||
* to all 0's or all 1's, leading to jumps forwards or backwards.
|
||||
* Backwards jumps might be interpreted all roll-overs and be treated as
|
||||
* huge jumps forward.
|
||||
* The workaround is to check whether the lower 11 bits of the counter are
|
||||
* all 0 or all 1, then discard this value and read again.
|
||||
* This occasionally discards valid values, but will catch all erroneous
|
||||
* reads and fixes the problem reliably. Also this mostly requires only a
|
||||
* single read, so does not have any significant overhead.
|
||||
* The algorithm was conceived by Samuel Holland.
|
||||
*/
|
||||
unsigned long timer_read_counter(void)
|
||||
{
|
||||
unsigned long cntpct;
|
||||
|
||||
isb();
|
||||
do {
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));
|
||||
} while (((cntpct + 1) & GENMASK(10, 0)) <= 1);
|
||||
|
||||
return cntpct;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* timer_read_counter() using the Arm Generic Timer (aka arch timer).
|
||||
*/
|
||||
unsigned long timer_read_counter(void)
|
||||
{
|
||||
unsigned long cntpct;
|
||||
|
||||
isb();
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));
|
||||
|
||||
return cntpct;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t get_ticks(void)
|
||||
{
|
||||
unsigned long ticks = timer_read_counter();
|
||||
|
||||
gd->arch.tbl = ticks;
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
unsigned long usec2ticks(unsigned long usec)
|
||||
{
|
||||
ulong ticks;
|
||||
if (usec < 1000)
|
||||
ticks = ((usec * (get_tbclk()/1000)) + 500) / 1000;
|
||||
else
|
||||
ticks = ((usec / 10) * (get_tbclk() / 100000));
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
ulong timer_get_boot_us(void)
|
||||
{
|
||||
u64 val = get_ticks() * 1000000;
|
||||
|
||||
return val / get_tbclk();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2015 Linaro
|
||||
# Peter Griffin <peter.griffin@linaro.org>
|
||||
|
||||
obj-y += pinmux.o
|
||||
@@ -0,0 +1,183 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2015 Linaro.
|
||||
* Peter Griffin <peter.griffin@linaro.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/pinmux.h>
|
||||
|
||||
struct hi6220_pinmux0_regs *pmx0 =
|
||||
(struct hi6220_pinmux0_regs *)HI6220_PINMUX0_BASE;
|
||||
|
||||
struct hi6220_pinmux1_regs *pmx1 =
|
||||
(struct hi6220_pinmux1_regs *)HI6220_PINMUX1_BASE;
|
||||
|
||||
static void hi6220_uart_config(int peripheral)
|
||||
{
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_UART0:
|
||||
writel(MUX_M0, &pmx0->iomg[48]); /* UART0_RXD */
|
||||
writel(MUX_M0, &pmx0->iomg[49]); /* UART0_TXD */
|
||||
|
||||
writel(DRIVE1_02MA | PULL_UP, &pmx1->iocfg[49]); /* UART0_RXD */
|
||||
writel(DRIVE1_02MA | PULL_UP, &pmx1->iocfg[50]); /* UART0_TXD */
|
||||
break;
|
||||
|
||||
case PERIPH_ID_UART1:
|
||||
writel(MUX_M0, &pmx0->iomg[50]); /* UART1_CTS_N */
|
||||
writel(MUX_M0, &pmx0->iomg[51]); /* UART1_RTS_N */
|
||||
writel(MUX_M0, &pmx0->iomg[52]); /* UART1_RXD */
|
||||
writel(MUX_M0, &pmx0->iomg[53]); /* UART1_TXD */
|
||||
|
||||
writel(DRIVE1_02MA | PULL_UP, &pmx1->iocfg[51]); /*UART1_CTS_N*/
|
||||
writel(DRIVE1_02MA | PULL_UP, &pmx1->iocfg[53]); /* UART1_RXD */
|
||||
writel(DRIVE1_02MA, &pmx1->iocfg[52]); /* UART1_RTS_N */
|
||||
writel(DRIVE1_02MA, &pmx1->iocfg[54]); /* UART1_TXD */
|
||||
break;
|
||||
|
||||
case PERIPH_ID_UART2:
|
||||
writel(MUX_M0, &pmx0->iomg[54]); /* UART2_CTS_N */
|
||||
writel(MUX_M0, &pmx0->iomg[55]); /* UART2_RTS_N */
|
||||
writel(MUX_M0, &pmx0->iomg[56]); /* UART2_RXD */
|
||||
writel(MUX_M0, &pmx0->iomg[57]); /* UART2_TXD */
|
||||
|
||||
writel(DRIVE1_02MA, &pmx1->iocfg[55]); /* UART2_CTS_N */
|
||||
writel(DRIVE1_02MA, &pmx1->iocfg[56]); /* UART2_RTS_N */
|
||||
writel(DRIVE1_02MA, &pmx1->iocfg[57]); /* UART2_RXD */
|
||||
writel(DRIVE1_02MA, &pmx1->iocfg[58]); /* UART2_TXD */
|
||||
break;
|
||||
|
||||
case PERIPH_ID_UART3:
|
||||
writel(MUX_M1, &pmx0->iomg[96]); /* UART3_CTS_N */
|
||||
writel(MUX_M1, &pmx0->iomg[97]); /* UART3_RTS_N */
|
||||
writel(MUX_M1, &pmx0->iomg[98]); /* UART3_RXD */
|
||||
writel(MUX_M1, &pmx0->iomg[99]); /* UART3_TXD */
|
||||
|
||||
/* UART3_TXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[100]);
|
||||
/* UART3_RTS_N */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[101]);
|
||||
/* UART3_RXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[102]);
|
||||
/* UART3_TXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[103]);
|
||||
break;
|
||||
|
||||
case PERIPH_ID_UART4:
|
||||
writel(MUX_M1, &pmx0->iomg[116]); /* UART4_CTS_N */
|
||||
writel(MUX_M1, &pmx0->iomg[117]); /* UART4_RTS_N */
|
||||
writel(MUX_M1, &pmx0->iomg[118]); /* UART4_RXD */
|
||||
writel(MUX_M1, &pmx0->iomg[119]); /* UART4_TXD */
|
||||
|
||||
/* UART4_CTS_N */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[120]);
|
||||
/* UART4_RTS_N */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[121]);
|
||||
/* UART4_RXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[122]);
|
||||
/* UART4_TXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[123]);
|
||||
break;
|
||||
case PERIPH_ID_UART5:
|
||||
writel(MUX_M1, &pmx0->iomg[114]); /* UART5_RXD */
|
||||
writel(MUX_M1, &pmx0->iomg[115]); /* UART5_TXD */
|
||||
|
||||
/* UART5_RXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[118]);
|
||||
/* UART5_TXD */
|
||||
writel(DRIVE1_02MA | PULL_DOWN, &pmx1->iocfg[119]);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("%s: invalid peripheral %d", __func__, peripheral);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int hi6220_mmc_config(int peripheral)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_SDMMC0:
|
||||
|
||||
/* eMMC pinmux config */
|
||||
writel(MUX_M0, &pmx0->iomg[64]); /* EMMC_CLK */
|
||||
writel(MUX_M0, &pmx0->iomg[65]); /* EMMC_CMD */
|
||||
writel(MUX_M0, &pmx0->iomg[66]); /* EMMC_DATA0 */
|
||||
writel(MUX_M0, &pmx0->iomg[67]); /* EMMC_DATA1 */
|
||||
writel(MUX_M0, &pmx0->iomg[68]); /* EMMC_DATA2 */
|
||||
writel(MUX_M0, &pmx0->iomg[69]); /* EMMC_DATA3 */
|
||||
writel(MUX_M0, &pmx0->iomg[70]); /* EMMC_DATA4 */
|
||||
writel(MUX_M0, &pmx0->iomg[71]); /* EMMC_DATA5 */
|
||||
writel(MUX_M0, &pmx0->iomg[72]); /* EMMC_DATA6 */
|
||||
writel(MUX_M0, &pmx0->iomg[73]); /* EMMC_DATA7 */
|
||||
|
||||
/*eMMC configure up/down/drive */
|
||||
writel(DRIVE1_08MA, &pmx1->iocfg[65]); /* EMMC_CLK */
|
||||
|
||||
tmp = DRIVE1_04MA | PULL_UP;
|
||||
writel(tmp, &pmx1->iocfg[65]); /* EMMC_CMD */
|
||||
writel(tmp, &pmx1->iocfg[66]); /* EMMC_DATA0 */
|
||||
writel(tmp, &pmx1->iocfg[67]); /* EMMC_DATA1 */
|
||||
writel(tmp, &pmx1->iocfg[68]); /* EMMC_DATA2 */
|
||||
writel(tmp, &pmx1->iocfg[69]); /* EMMC_DATA3 */
|
||||
writel(tmp, &pmx1->iocfg[70]); /* EMMC_DATA4 */
|
||||
writel(tmp, &pmx1->iocfg[71]); /* EMMC_DATA5 */
|
||||
writel(tmp, &pmx1->iocfg[72]); /* EMMC_DATA6 */
|
||||
writel(tmp, &pmx1->iocfg[73]); /* EMMC_DATA7 */
|
||||
|
||||
writel(DRIVE1_04MA, &pmx1->iocfg[73]); /* EMMC_RST_N */
|
||||
break;
|
||||
|
||||
case PERIPH_ID_SDMMC1:
|
||||
|
||||
writel(MUX_M0, &pmx0->iomg[3]); /* SD_CLK */
|
||||
writel(MUX_M0, &pmx0->iomg[4]); /* SD_CMD */
|
||||
writel(MUX_M0, &pmx0->iomg[5]); /* SD_DATA0 */
|
||||
writel(MUX_M0, &pmx0->iomg[6]); /* SD_DATA1 */
|
||||
writel(MUX_M0, &pmx0->iomg[7]); /* SD_DATA2 */
|
||||
writel(MUX_M0, &pmx0->iomg[8]); /* SD_DATA3 */
|
||||
|
||||
writel(DRIVE1_10MA | BIT(2), &pmx1->iocfg[3]); /*SD_CLK*/
|
||||
writel(DRIVE1_08MA | BIT(2), &pmx1->iocfg[4]); /*SD_CMD*/
|
||||
writel(DRIVE1_08MA | BIT(2), &pmx1->iocfg[5]); /*SD_DATA0*/
|
||||
writel(DRIVE1_08MA | BIT(2), &pmx1->iocfg[6]); /*SD_DATA1*/
|
||||
writel(DRIVE1_08MA | BIT(2), &pmx1->iocfg[7]); /*SD_DATA2*/
|
||||
writel(DRIVE1_08MA | BIT(2), &pmx1->iocfg[8]); /*SD_DATA3*/
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("%s: invalid peripheral %d", __func__, peripheral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hi6220_pinmux_config(int peripheral)
|
||||
{
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_UART0:
|
||||
case PERIPH_ID_UART1:
|
||||
case PERIPH_ID_UART2:
|
||||
case PERIPH_ID_UART3:
|
||||
hi6220_uart_config(peripheral);
|
||||
break;
|
||||
case PERIPH_ID_SDMMC0:
|
||||
case PERIPH_ID_SDMMC1:
|
||||
return hi6220_mmc_config(peripheral);
|
||||
default:
|
||||
debug("%s: invalid peripheral %d", __func__, peripheral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* (C) Copyright 2017 NVIDIA Corporation <www.nvidia.com>
|
||||
*
|
||||
* Derived from Linux kernel v4.14 files:
|
||||
*
|
||||
* arch/arm64/include/asm/assembler.h:
|
||||
* Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
|
||||
* Copyright (C) 1996-2000 Russell King
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
*
|
||||
* arch/arm64/kernel/head.S:
|
||||
* Based on arch/arm/kernel/head.S
|
||||
* Copyright (C) 1994-2002 Russell King
|
||||
* Copyright (C) 2003-2012 ARM Ltd.
|
||||
* Authors: Catalin Marinas <catalin.marinas@arm.com>
|
||||
* Will Deacon <will.deacon@arm.com>
|
||||
*
|
||||
* arch/arm64/kernel/image.h:
|
||||
* Copyright (C) 2014 ARM Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* There aren't any ELF relocations we can use to endian-swap values known only
|
||||
* at link time (e.g. the subtraction of two symbol addresses), so we must get
|
||||
* the linker to endian-swap certain values before emitting them.
|
||||
*
|
||||
* Note that, in order for this to work when building the ELF64 PIE executable
|
||||
* (for KASLR), these values should not be referenced via R_AARCH64_ABS64
|
||||
* relocations, since these are fixed up at runtime rather than at build time
|
||||
* when PIE is in effect. So we need to split them up in 32-bit high and low
|
||||
* words.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
#define DATA_LE32(data) \
|
||||
((((data) & 0x000000ff) << 24) | \
|
||||
(((data) & 0x0000ff00) << 8) | \
|
||||
(((data) & 0x00ff0000) >> 8) | \
|
||||
(((data) & 0xff000000) >> 24))
|
||||
#else
|
||||
#define DATA_LE32(data) ((data) & 0xffffffff)
|
||||
#endif
|
||||
|
||||
#define DEFINE_IMAGE_LE64(sym, data) \
|
||||
sym##_lo32 = DATA_LE32((data) & 0xffffffff); \
|
||||
sym##_hi32 = DATA_LE32((data) >> 32)
|
||||
|
||||
#define __MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define __CODE_DATA_SIZE (__bss_start - _start)
|
||||
#define __BSS_SIZE (__bss_end - __bss_start)
|
||||
#ifdef CONFIG_INIT_SP_RELATIVE
|
||||
#define __MAX_EXTRA_RAM_USAGE __MAX(__BSS_SIZE, CONFIG_SYS_INIT_SP_BSS_OFFSET)
|
||||
#else
|
||||
#define __MAX_EXTRA_RAM_USAGE __BSS_SIZE
|
||||
#endif
|
||||
#define __MEM_USAGE (__CODE_DATA_SIZE + __MAX_EXTRA_RAM_USAGE)
|
||||
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
#define __HEAD_FLAG_BE 1
|
||||
#else
|
||||
#define __HEAD_FLAG_BE 0
|
||||
#endif
|
||||
|
||||
#define __HEAD_FLAG_PAGE_SIZE 1 /* 4K hard-coded */
|
||||
|
||||
#define __HEAD_FLAG_PHYS_BASE 1
|
||||
|
||||
#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
|
||||
(__HEAD_FLAG_PAGE_SIZE << 1) | \
|
||||
(__HEAD_FLAG_PHYS_BASE << 3))
|
||||
|
||||
#define TEXT_OFFSET (CONFIG_SYS_TEXT_BASE - \
|
||||
CONFIG_LNX_KRNL_IMG_TEXT_OFFSET_BASE)
|
||||
|
||||
/*
|
||||
* These will output as part of the Image header, which should be little-endian
|
||||
* regardless of the endianness of the kernel. While constant values could be
|
||||
* endian swapped in head.S, all are done here for consistency.
|
||||
*/
|
||||
#define HEAD_SYMBOLS \
|
||||
DEFINE_IMAGE_LE64(_kernel_size_le, __MEM_USAGE); \
|
||||
DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \
|
||||
DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
|
||||
|
||||
HEAD_SYMBOLS
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* A lowlevel_init function that sets up the stack to call a C function to
|
||||
* perform further init.
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
ENTRY(lowlevel_init)
|
||||
/*
|
||||
* Setup a temporary stack. Global data is not available yet.
|
||||
*/
|
||||
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
|
||||
ldr w0, =CONFIG_SPL_STACK
|
||||
#else
|
||||
ldr w0, =CONFIG_SYS_INIT_SP_ADDR
|
||||
#endif
|
||||
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
|
||||
|
||||
/*
|
||||
* Save the old LR(passed in x29) and the current LR to stack
|
||||
*/
|
||||
stp x29, x30, [sp, #-16]!
|
||||
|
||||
/*
|
||||
* Call the very early init function. This should do only the
|
||||
* absolute bare minimum to get started. It should not:
|
||||
*
|
||||
* - set up DRAM
|
||||
* - use global_data
|
||||
* - clear BSS
|
||||
* - try to start a console
|
||||
*
|
||||
* For boards with SPL this should be empty since SPL can do all of
|
||||
* this init in the SPL board_init_f() function which is called
|
||||
* immediately after this.
|
||||
*/
|
||||
bl s_init
|
||||
ldp x29, x30, [sp]
|
||||
ret
|
||||
ENDPROC(lowlevel_init)
|
||||
@@ -0,0 +1,331 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2016 Freescale Semiconductor, Inc.
|
||||
* Author: Hongbo Zhang <hongbo.zhang@nxp.com>
|
||||
* This file implements LS102X platform PSCI SYSTEM-SUSPEND function
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/psci.h>
|
||||
#include <asm/secure.h>
|
||||
|
||||
/* Default PSCI function, return -1, Not Implemented */
|
||||
#define PSCI_DEFAULT(__fn) \
|
||||
ENTRY(__fn); \
|
||||
mov w0, #ARM_PSCI_RET_NI; \
|
||||
ret; \
|
||||
ENDPROC(__fn); \
|
||||
.weak __fn
|
||||
|
||||
/* PSCI function and ID table definition*/
|
||||
#define PSCI_TABLE(__id, __fn) \
|
||||
.quad __id; \
|
||||
.quad __fn
|
||||
|
||||
.pushsection ._secure.text, "ax"
|
||||
|
||||
/* 32 bits PSCI default functions */
|
||||
PSCI_DEFAULT(psci_version)
|
||||
PSCI_DEFAULT(psci_cpu_suspend)
|
||||
PSCI_DEFAULT(psci_cpu_off)
|
||||
PSCI_DEFAULT(psci_cpu_on)
|
||||
PSCI_DEFAULT(psci_affinity_info)
|
||||
PSCI_DEFAULT(psci_migrate)
|
||||
PSCI_DEFAULT(psci_migrate_info_type)
|
||||
PSCI_DEFAULT(psci_migrate_info_up_cpu)
|
||||
PSCI_DEFAULT(psci_system_off)
|
||||
PSCI_DEFAULT(psci_system_reset)
|
||||
PSCI_DEFAULT(psci_features)
|
||||
PSCI_DEFAULT(psci_cpu_freeze)
|
||||
PSCI_DEFAULT(psci_cpu_default_suspend)
|
||||
PSCI_DEFAULT(psci_node_hw_state)
|
||||
PSCI_DEFAULT(psci_system_suspend)
|
||||
PSCI_DEFAULT(psci_set_suspend_mode)
|
||||
PSCI_DEFAULT(psi_stat_residency)
|
||||
PSCI_DEFAULT(psci_stat_count)
|
||||
|
||||
.align 3
|
||||
_psci_32_table:
|
||||
PSCI_TABLE(ARM_PSCI_FN_CPU_SUSPEND, psci_cpu_suspend)
|
||||
PSCI_TABLE(ARM_PSCI_FN_CPU_OFF, psci_cpu_off)
|
||||
PSCI_TABLE(ARM_PSCI_FN_CPU_ON, psci_cpu_on)
|
||||
PSCI_TABLE(ARM_PSCI_FN_MIGRATE, psci_migrate)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_PSCI_VERSION, psci_version)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_SUSPEND, psci_cpu_suspend)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_OFF, psci_cpu_off)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_ON, psci_cpu_on)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_AFFINITY_INFO, psci_affinity_info)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE, psci_migrate)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE, psci_migrate_info_type)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_OFF, psci_system_off)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_RESET, psci_system_reset)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_PSCI_FEATURES, psci_features)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_FREEZE, psci_cpu_freeze)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_NODE_HW_STATE, psci_node_hw_state)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_SYSTEM_SUSPEND, psci_system_suspend)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_SET_SUSPEND_MODE, psci_set_suspend_mode)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_RESIDENCY, psi_stat_residency)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_COUNT, psci_stat_count)
|
||||
PSCI_TABLE(0, 0)
|
||||
|
||||
/* 64 bits PSCI default functions */
|
||||
PSCI_DEFAULT(psci_cpu_suspend_64)
|
||||
PSCI_DEFAULT(psci_cpu_on_64)
|
||||
PSCI_DEFAULT(psci_affinity_info_64)
|
||||
PSCI_DEFAULT(psci_migrate_64)
|
||||
PSCI_DEFAULT(psci_migrate_info_up_cpu_64)
|
||||
PSCI_DEFAULT(psci_cpu_default_suspend_64)
|
||||
PSCI_DEFAULT(psci_node_hw_state_64)
|
||||
PSCI_DEFAULT(psci_system_suspend_64)
|
||||
PSCI_DEFAULT(psci_stat_residency_64)
|
||||
PSCI_DEFAULT(psci_stat_count_64)
|
||||
|
||||
.align 3
|
||||
_psci_64_table:
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_SUSPEND, psci_cpu_suspend_64)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_ON, psci_cpu_on_64)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN64_AFFINITY_INFO, psci_affinity_info_64)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE, psci_migrate_64)
|
||||
PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu_64)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend_64)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN64_NODE_HW_STATE, psci_node_hw_state_64)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND, psci_system_suspend_64)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_RESIDENCY, psci_stat_residency_64)
|
||||
PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_COUNT, psci_stat_count_64)
|
||||
PSCI_TABLE(0, 0)
|
||||
|
||||
.macro psci_enter
|
||||
/* PSCI call is Fast Call(atomic), so mask DAIF */
|
||||
mrs x15, DAIF
|
||||
stp x15, xzr, [sp, #-16]!
|
||||
ldr x15, =0x3C0
|
||||
msr DAIF, x15
|
||||
/* SMC convention, x18 ~ x30 should be saved by callee */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
mrs x15, elr_el3
|
||||
stp x18, x15, [sp, #-16]!
|
||||
.endm
|
||||
|
||||
.macro psci_return
|
||||
/* restore registers */
|
||||
ldp x18, x15, [sp], #16
|
||||
msr elr_el3, x15
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
/* restore DAIF */
|
||||
ldp x15, xzr, [sp], #16
|
||||
msr DAIF, x15
|
||||
eret
|
||||
.endm
|
||||
|
||||
/* Caller must put PSCI function-ID table base in x9 */
|
||||
handle_psci:
|
||||
psci_enter
|
||||
1: ldr x10, [x9] /* Load PSCI function table */
|
||||
cbz x10, 3f /* If reach the end, bail out */
|
||||
cmp x10, x0
|
||||
b.eq 2f /* PSCI function found */
|
||||
add x9, x9, #16 /* If not match, try next entry */
|
||||
b 1b
|
||||
|
||||
2: ldr x11, [x9, #8] /* Load PSCI function */
|
||||
blr x11 /* Call PSCI function */
|
||||
psci_return
|
||||
|
||||
3: mov x0, #ARM_PSCI_RET_NI
|
||||
psci_return
|
||||
|
||||
/*
|
||||
* Handle SiP service functions defined in SiP service function table.
|
||||
* Use DECLARE_SECURE_SVC(_name, _id, _fn) to add platform specific SiP
|
||||
* service function into the SiP service function table.
|
||||
* SiP service function table is located in '._secure_svc_tbl_entries' section,
|
||||
* which is next to '._secure.text' section.
|
||||
*/
|
||||
handle_svc:
|
||||
adr x9, __secure_svc_tbl_start
|
||||
adr x10, __secure_svc_tbl_end
|
||||
subs x12, x10, x9 /* Get number of entries in table */
|
||||
b.eq 2f /* Make sure SiP function table is not empty */
|
||||
psci_enter
|
||||
1: ldr x10, [x9] /* Load SiP function table */
|
||||
ldr x11, [x9, #8]
|
||||
cmp w10, w0
|
||||
b.eq 2b /* SiP service function found */
|
||||
add x9, x9, #SECURE_SVC_TBL_OFFSET /* Move to next entry */
|
||||
subs x12, x12, #SECURE_SVC_TBL_OFFSET
|
||||
b.eq 3b /* If reach the end, bail out */
|
||||
b 1b
|
||||
2: ldr x0, =0xFFFFFFFF
|
||||
eret
|
||||
|
||||
handle_smc32:
|
||||
/* SMC function ID 0x84000000-0x8400001F: 32 bits PSCI */
|
||||
ldr w9, =0x8400001F
|
||||
cmp w0, w9
|
||||
b.gt handle_svc
|
||||
ldr w9, =0x84000000
|
||||
cmp w0, w9
|
||||
b.lt handle_svc
|
||||
|
||||
adr x9, _psci_32_table
|
||||
b handle_psci
|
||||
|
||||
handle_smc64:
|
||||
/* check SMC32 or SMC64 calls */
|
||||
ubfx x9, x0, #30, #1
|
||||
cbz x9, handle_smc32
|
||||
|
||||
/* SMC function ID 0xC4000000-0xC400001F: 64 bits PSCI */
|
||||
ldr x9, =0xC400001F
|
||||
cmp x0, x9
|
||||
b.gt handle_svc
|
||||
ldr x9, =0xC4000000
|
||||
cmp x0, x9
|
||||
b.lt handle_svc
|
||||
|
||||
adr x9, _psci_64_table
|
||||
b handle_psci
|
||||
|
||||
/*
|
||||
* Get CPU ID from MPIDR, suppose every cluster has same number of CPU cores,
|
||||
* Platform with asymmetric clusters should implement their own interface.
|
||||
* In case this function being called by other platform's C code, the ARM
|
||||
* Architecture Procedure Call Standard is considered, e.g. register X0 is
|
||||
* used for the return value, while in this PSCI environment, X0 usually holds
|
||||
* the SMC function identifier, so X0 should be saved by caller function.
|
||||
*/
|
||||
ENTRY(psci_get_cpu_id)
|
||||
#ifdef CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
|
||||
mrs x9, MPIDR_EL1
|
||||
ubfx x9, x9, #8, #8
|
||||
ldr x10, =CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
|
||||
mul x9, x10, x9
|
||||
#else
|
||||
mov x9, xzr
|
||||
#endif
|
||||
mrs x10, MPIDR_EL1
|
||||
ubfx x10, x10, #0, #8
|
||||
add x0, x10, x9
|
||||
ret
|
||||
ENDPROC(psci_get_cpu_id)
|
||||
.weak psci_get_cpu_id
|
||||
|
||||
/* CPU ID input in x0, stack top output in x0*/
|
||||
LENTRY(psci_get_cpu_stack_top)
|
||||
adr x9, __secure_stack_end
|
||||
lsl x0, x0, #ARM_PSCI_STACK_SHIFT
|
||||
sub x0, x9, x0
|
||||
ret
|
||||
ENDPROC(psci_get_cpu_stack_top)
|
||||
|
||||
unhandled_exception:
|
||||
b unhandled_exception /* simply dead loop */
|
||||
|
||||
handle_sync:
|
||||
mov x15, x30
|
||||
mov x14, x0
|
||||
|
||||
bl psci_get_cpu_id
|
||||
bl psci_get_cpu_stack_top
|
||||
mov x9, #1
|
||||
msr spsel, x9
|
||||
mov sp, x0
|
||||
|
||||
mov x0, x14
|
||||
mov x30, x15
|
||||
|
||||
mrs x9, esr_el3
|
||||
ubfx x9, x9, #26, #6
|
||||
cmp x9, #0x13
|
||||
b.eq handle_smc32
|
||||
cmp x9, #0x17
|
||||
b.eq handle_smc64
|
||||
|
||||
b unhandled_exception
|
||||
|
||||
#ifdef CONFIG_ARMV8_EA_EL3_FIRST
|
||||
/*
|
||||
* Override this function if custom error handling is
|
||||
* needed for asynchronous aborts
|
||||
*/
|
||||
ENTRY(plat_error_handler)
|
||||
ret
|
||||
ENDPROC(plat_error_handler)
|
||||
.weak plat_error_handler
|
||||
|
||||
handle_error:
|
||||
bl psci_get_cpu_id
|
||||
bl psci_get_cpu_stack_top
|
||||
mov x9, #1
|
||||
msr spsel, x9
|
||||
mov sp, x0
|
||||
|
||||
bl plat_error_handler /* Platform specific error handling */
|
||||
deadloop:
|
||||
b deadloop /* Never return */
|
||||
#endif
|
||||
|
||||
.align 11
|
||||
.globl el3_exception_vectors
|
||||
el3_exception_vectors:
|
||||
b unhandled_exception /* Sync, Current EL using SP0 */
|
||||
.align 7
|
||||
b unhandled_exception /* IRQ, Current EL using SP0 */
|
||||
.align 7
|
||||
b unhandled_exception /* FIQ, Current EL using SP0 */
|
||||
.align 7
|
||||
b unhandled_exception /* SError, Current EL using SP0 */
|
||||
.align 7
|
||||
b unhandled_exception /* Sync, Current EL using SPx */
|
||||
.align 7
|
||||
b unhandled_exception /* IRQ, Current EL using SPx */
|
||||
.align 7
|
||||
b unhandled_exception /* FIQ, Current EL using SPx */
|
||||
.align 7
|
||||
b unhandled_exception /* SError, Current EL using SPx */
|
||||
.align 7
|
||||
b handle_sync /* Sync, Lower EL using AArch64 */
|
||||
.align 7
|
||||
b unhandled_exception /* IRQ, Lower EL using AArch64 */
|
||||
.align 7
|
||||
b unhandled_exception /* FIQ, Lower EL using AArch64 */
|
||||
.align 7
|
||||
#ifdef CONFIG_ARMV8_EA_EL3_FIRST
|
||||
b handle_error /* SError, Lower EL using AArch64 */
|
||||
#else
|
||||
b unhandled_exception /* SError, Lower EL using AArch64 */
|
||||
#endif
|
||||
.align 7
|
||||
b unhandled_exception /* Sync, Lower EL using AArch32 */
|
||||
.align 7
|
||||
b unhandled_exception /* IRQ, Lower EL using AArch32 */
|
||||
.align 7
|
||||
b unhandled_exception /* FIQ, Lower EL using AArch32 */
|
||||
.align 7
|
||||
b unhandled_exception /* SError, Lower EL using AArch32 */
|
||||
|
||||
ENTRY(psci_setup_vectors)
|
||||
adr x0, el3_exception_vectors
|
||||
msr vbar_el3, x0
|
||||
ret
|
||||
ENDPROC(psci_setup_vectors)
|
||||
|
||||
ENTRY(psci_arch_init)
|
||||
ret
|
||||
ENDPROC(psci_arch_init)
|
||||
.weak psci_arch_init
|
||||
|
||||
.popsection
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2013-2016, Freescale Semiconductor, Inc.
|
||||
|
||||
obj-y += generic.o
|
||||
obj-y += cpu.o
|
||||
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2014-2016, Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/mc_me_regs.h>
|
||||
#include "cpu.h"
|
||||
|
||||
u32 cpu_mask(void)
|
||||
{
|
||||
return readl(MC_ME_CS);
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
|
||||
|
||||
#define S32V234_IRAM_BASE 0x3e800000UL
|
||||
#define S32V234_IRAM_SIZE 0x800000UL
|
||||
#define S32V234_DRAM_BASE1 0x80000000UL
|
||||
#define S32V234_DRAM_SIZE1 0x40000000UL
|
||||
#define S32V234_DRAM_BASE2 0xC0000000UL
|
||||
#define S32V234_DRAM_SIZE2 0x20000000UL
|
||||
#define S32V234_PERIPH_BASE 0x40000000UL
|
||||
#define S32V234_PERIPH_SIZE 0x40000000UL
|
||||
|
||||
static struct mm_region s32v234_mem_map[] = {
|
||||
{
|
||||
.virt = S32V234_IRAM_BASE,
|
||||
.phys = S32V234_IRAM_BASE,
|
||||
.size = S32V234_IRAM_SIZE,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_OUTER_SHARE
|
||||
}, {
|
||||
.virt = S32V234_DRAM_BASE1,
|
||||
.phys = S32V234_DRAM_BASE1,
|
||||
.size = S32V234_DRAM_SIZE1,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_OUTER_SHARE
|
||||
}, {
|
||||
.virt = S32V234_PERIPH_BASE,
|
||||
.phys = S32V234_PERIPH_BASE,
|
||||
.size = S32V234_PERIPH_SIZE,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
||||
PTE_BLOCK_NON_SHARE
|
||||
/* TODO: Do we need these? */
|
||||
/* | PTE_BLOCK_PXN | PTE_BLOCK_UXN */
|
||||
}, {
|
||||
.virt = S32V234_DRAM_BASE2,
|
||||
.phys = S32V234_DRAM_BASE2,
|
||||
.size = S32V234_DRAM_SIZE2,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL_NC) |
|
||||
PTE_BLOCK_OUTER_SHARE
|
||||
}, {
|
||||
/* List terminator */
|
||||
0,
|
||||
}
|
||||
};
|
||||
|
||||
struct mm_region *mem_map = s32v234_mem_map;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return the number of cores on this SOC.
|
||||
*/
|
||||
int cpu_numcores(void)
|
||||
{
|
||||
int numcores;
|
||||
u32 mask;
|
||||
|
||||
mask = cpu_mask();
|
||||
numcores = hweight32(cpu_mask());
|
||||
|
||||
/* Verify if M4 is deactivated */
|
||||
if (mask & 0x1)
|
||||
numcores--;
|
||||
|
||||
return numcores;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_EARLY_INIT_R)
|
||||
int arch_early_init_r(void)
|
||||
{
|
||||
int rv;
|
||||
asm volatile ("dsb sy");
|
||||
rv = fsl_s32v234_wake_seconday_cores();
|
||||
|
||||
if (rv)
|
||||
printf("Did not wake secondary cores\n");
|
||||
|
||||
asm volatile ("sev");
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ARCH_EARLY_INIT_R */
|
||||
@@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2014-2016, Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
u32 cpu_mask(void);
|
||||
int cpu_numcores(void);
|
||||
@@ -0,0 +1,349 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013-2016, Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/mc_cgm_regs.h>
|
||||
#include <asm/arch/mc_me_regs.h>
|
||||
#include <asm/arch/mc_rgm_regs.h>
|
||||
#include <netdev.h>
|
||||
#include <div64.h>
|
||||
#include <errno.h>
|
||||
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
struct mscm_ir *mscmir = (struct mscm_ir *)MSCM_BASE_ADDR;
|
||||
u32 cpu = readl(&mscmir->cpxtype);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static uintptr_t get_pllfreq(u32 pll, u32 refclk_freq, u32 plldv,
|
||||
u32 pllfd, u32 selected_output)
|
||||
{
|
||||
u32 vco = 0, plldv_prediv = 0, plldv_mfd = 0, pllfd_mfn = 0;
|
||||
u32 plldv_rfdphi_div = 0, fout = 0;
|
||||
u32 dfs_portn = 0, dfs_mfn = 0, dfs_mfi = 0;
|
||||
|
||||
if (selected_output > DFS_MAXNUMBER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
plldv_prediv =
|
||||
(plldv & PLLDIG_PLLDV_PREDIV_MASK) >> PLLDIG_PLLDV_PREDIV_OFFSET;
|
||||
plldv_mfd = (plldv & PLLDIG_PLLDV_MFD_MASK);
|
||||
|
||||
pllfd_mfn = (pllfd & PLLDIG_PLLFD_MFN_MASK);
|
||||
|
||||
plldv_prediv = plldv_prediv == 0 ? 1 : plldv_prediv;
|
||||
|
||||
/* The formula for VCO is from TR manual, rev. D */
|
||||
vco = refclk_freq / plldv_prediv * (plldv_mfd + pllfd_mfn / 20481);
|
||||
|
||||
if (selected_output != 0) {
|
||||
/* Determine the RFDPHI for PHI1 */
|
||||
plldv_rfdphi_div =
|
||||
(plldv & PLLDIG_PLLDV_RFDPHI1_MASK) >>
|
||||
PLLDIG_PLLDV_RFDPHI1_OFFSET;
|
||||
plldv_rfdphi_div = plldv_rfdphi_div == 0 ? 1 : plldv_rfdphi_div;
|
||||
if (pll == ARM_PLL || pll == ENET_PLL || pll == DDR_PLL) {
|
||||
dfs_portn =
|
||||
readl(DFS_DVPORTn(pll, selected_output - 1));
|
||||
dfs_mfi =
|
||||
(dfs_portn & DFS_DVPORTn_MFI_MASK) >>
|
||||
DFS_DVPORTn_MFI_OFFSET;
|
||||
dfs_mfn =
|
||||
(dfs_portn & DFS_DVPORTn_MFI_MASK) >>
|
||||
DFS_DVPORTn_MFI_OFFSET;
|
||||
fout = vco / (dfs_mfi + (dfs_mfn / 256));
|
||||
} else {
|
||||
fout = vco / plldv_rfdphi_div;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Determine the RFDPHI for PHI0 */
|
||||
plldv_rfdphi_div =
|
||||
(plldv & PLLDIG_PLLDV_RFDPHI_MASK) >>
|
||||
PLLDIG_PLLDV_RFDPHI_OFFSET;
|
||||
fout = vco / plldv_rfdphi_div;
|
||||
}
|
||||
|
||||
return fout;
|
||||
|
||||
}
|
||||
|
||||
/* Implemented for ARMPLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_LL */
|
||||
static uintptr_t decode_pll(enum pll_type pll, u32 refclk_freq,
|
||||
u32 selected_output)
|
||||
{
|
||||
u32 plldv, pllfd;
|
||||
|
||||
plldv = readl(PLLDIG_PLLDV(pll));
|
||||
pllfd = readl(PLLDIG_PLLFD(pll));
|
||||
|
||||
return get_pllfreq(pll, refclk_freq, plldv, pllfd, selected_output);
|
||||
}
|
||||
|
||||
static u32 get_mcu_main_clk(void)
|
||||
{
|
||||
u32 coreclk_div;
|
||||
u32 sysclk_sel;
|
||||
u32 freq = 0;
|
||||
|
||||
sysclk_sel = readl(CGM_SC_SS(MC_CGM1_BASE_ADDR)) & MC_CGM_SC_SEL_MASK;
|
||||
sysclk_sel >>= MC_CGM_SC_SEL_OFFSET;
|
||||
|
||||
coreclk_div =
|
||||
readl(CGM_SC_DCn(MC_CGM1_BASE_ADDR, 0)) & MC_CGM_SC_DCn_PREDIV_MASK;
|
||||
coreclk_div >>= MC_CGM_SC_DCn_PREDIV_OFFSET;
|
||||
coreclk_div += 1;
|
||||
|
||||
switch (sysclk_sel) {
|
||||
case MC_CGM_SC_SEL_FIRC:
|
||||
freq = FIRC_CLK_FREQ;
|
||||
break;
|
||||
case MC_CGM_SC_SEL_XOSC:
|
||||
freq = XOSC_CLK_FREQ;
|
||||
break;
|
||||
case MC_CGM_SC_SEL_ARMPLL:
|
||||
/* ARMPLL has as source XOSC and CORE_CLK has as input PHI0 */
|
||||
freq = decode_pll(ARM_PLL, XOSC_CLK_FREQ, 0);
|
||||
break;
|
||||
case MC_CGM_SC_SEL_CLKDISABLE:
|
||||
printf("Sysclk is disabled\n");
|
||||
break;
|
||||
default:
|
||||
printf("unsupported system clock select\n");
|
||||
}
|
||||
|
||||
return freq / coreclk_div;
|
||||
}
|
||||
|
||||
static u32 get_sys_clk(u32 number)
|
||||
{
|
||||
u32 sysclk_div, sysclk_div_number;
|
||||
u32 sysclk_sel;
|
||||
u32 freq = 0;
|
||||
|
||||
switch (number) {
|
||||
case 3:
|
||||
sysclk_div_number = 0;
|
||||
break;
|
||||
case 6:
|
||||
sysclk_div_number = 1;
|
||||
break;
|
||||
default:
|
||||
printf("unsupported system clock \n");
|
||||
return -1;
|
||||
}
|
||||
sysclk_sel = readl(CGM_SC_SS(MC_CGM0_BASE_ADDR)) & MC_CGM_SC_SEL_MASK;
|
||||
sysclk_sel >>= MC_CGM_SC_SEL_OFFSET;
|
||||
|
||||
sysclk_div =
|
||||
readl(CGM_SC_DCn(MC_CGM1_BASE_ADDR, sysclk_div_number)) &
|
||||
MC_CGM_SC_DCn_PREDIV_MASK;
|
||||
sysclk_div >>= MC_CGM_SC_DCn_PREDIV_OFFSET;
|
||||
sysclk_div += 1;
|
||||
|
||||
switch (sysclk_sel) {
|
||||
case MC_CGM_SC_SEL_FIRC:
|
||||
freq = FIRC_CLK_FREQ;
|
||||
break;
|
||||
case MC_CGM_SC_SEL_XOSC:
|
||||
freq = XOSC_CLK_FREQ;
|
||||
break;
|
||||
case MC_CGM_SC_SEL_ARMPLL:
|
||||
/* ARMPLL has as source XOSC and SYSn_CLK has as input DFS1 */
|
||||
freq = decode_pll(ARM_PLL, XOSC_CLK_FREQ, 1);
|
||||
break;
|
||||
case MC_CGM_SC_SEL_CLKDISABLE:
|
||||
printf("Sysclk is disabled\n");
|
||||
break;
|
||||
default:
|
||||
printf("unsupported system clock select\n");
|
||||
}
|
||||
|
||||
return freq / sysclk_div;
|
||||
}
|
||||
|
||||
static u32 get_peripherals_clk(void)
|
||||
{
|
||||
u32 aux5clk_div;
|
||||
u32 freq = 0;
|
||||
|
||||
aux5clk_div =
|
||||
readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 5, 0)) &
|
||||
MC_CGM_ACn_DCm_PREDIV_MASK;
|
||||
aux5clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
|
||||
aux5clk_div += 1;
|
||||
|
||||
freq = decode_pll(PERIPH_PLL, XOSC_CLK_FREQ, 0);
|
||||
|
||||
return freq / aux5clk_div;
|
||||
|
||||
}
|
||||
|
||||
static u32 get_uart_clk(void)
|
||||
{
|
||||
u32 auxclk3_div, auxclk3_sel, freq = 0;
|
||||
|
||||
auxclk3_sel =
|
||||
readl(CGM_ACn_SS(MC_CGM0_BASE_ADDR, 3)) & MC_CGM_ACn_SEL_MASK;
|
||||
auxclk3_sel >>= MC_CGM_ACn_SEL_OFFSET;
|
||||
|
||||
auxclk3_div =
|
||||
readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 3, 0)) &
|
||||
MC_CGM_ACn_DCm_PREDIV_MASK;
|
||||
auxclk3_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
|
||||
auxclk3_div += 1;
|
||||
|
||||
switch (auxclk3_sel) {
|
||||
case MC_CGM_ACn_SEL_FIRC:
|
||||
freq = FIRC_CLK_FREQ;
|
||||
break;
|
||||
case MC_CGM_ACn_SEL_XOSC:
|
||||
freq = XOSC_CLK_FREQ;
|
||||
break;
|
||||
case MC_CGM_ACn_SEL_PERPLLDIVX:
|
||||
freq = get_peripherals_clk() / 3;
|
||||
break;
|
||||
case MC_CGM_ACn_SEL_SYSCLK:
|
||||
freq = get_sys_clk(6);
|
||||
break;
|
||||
default:
|
||||
printf("unsupported system clock select\n");
|
||||
}
|
||||
|
||||
return freq / auxclk3_div;
|
||||
}
|
||||
|
||||
static u32 get_fec_clk(void)
|
||||
{
|
||||
u32 aux2clk_div;
|
||||
u32 freq = 0;
|
||||
|
||||
aux2clk_div =
|
||||
readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 2, 0)) &
|
||||
MC_CGM_ACn_DCm_PREDIV_MASK;
|
||||
aux2clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
|
||||
aux2clk_div += 1;
|
||||
|
||||
freq = decode_pll(ENET_PLL, XOSC_CLK_FREQ, 0);
|
||||
|
||||
return freq / aux2clk_div;
|
||||
}
|
||||
|
||||
static u32 get_usdhc_clk(void)
|
||||
{
|
||||
u32 aux15clk_div;
|
||||
u32 freq = 0;
|
||||
|
||||
aux15clk_div =
|
||||
readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 15, 0)) &
|
||||
MC_CGM_ACn_DCm_PREDIV_MASK;
|
||||
aux15clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
|
||||
aux15clk_div += 1;
|
||||
|
||||
freq = decode_pll(ENET_PLL, XOSC_CLK_FREQ, 4);
|
||||
|
||||
return freq / aux15clk_div;
|
||||
}
|
||||
|
||||
static u32 get_i2c_clk(void)
|
||||
{
|
||||
return get_peripherals_clk();
|
||||
}
|
||||
|
||||
/* return clocks in Hz */
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_ARM_CLK:
|
||||
return get_mcu_main_clk();
|
||||
case MXC_PERIPHERALS_CLK:
|
||||
return get_peripherals_clk();
|
||||
case MXC_UART_CLK:
|
||||
return get_uart_clk();
|
||||
case MXC_FEC_CLK:
|
||||
return get_fec_clk();
|
||||
case MXC_I2C_CLK:
|
||||
return get_i2c_clk();
|
||||
case MXC_USDHC_CLK:
|
||||
return get_usdhc_clk();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("Error: Unsupported function to read the frequency! \
|
||||
Please define it correctly!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Not yet implemented - int soc_clk_dump(); */
|
||||
|
||||
#if defined(CONFIG_DISPLAY_CPUINFO)
|
||||
static char *get_reset_cause(void)
|
||||
{
|
||||
u32 cause = readl(MC_RGM_BASE_ADDR + 0x300);
|
||||
|
||||
switch (cause) {
|
||||
case F_SWT4:
|
||||
return "WDOG";
|
||||
case F_JTAG:
|
||||
return "JTAG";
|
||||
case F_FCCU_SOFT:
|
||||
return "FCCU soft reaction";
|
||||
case F_FCCU_HARD:
|
||||
return "FCCU hard reaction";
|
||||
case F_SOFT_FUNC:
|
||||
return "Software Functional reset";
|
||||
case F_ST_DONE:
|
||||
return "Self Test done reset";
|
||||
case F_EXT_RST:
|
||||
return "External reset";
|
||||
default:
|
||||
return "unknown reset";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define SRC_SCR_SW_RST (1<<12)
|
||||
|
||||
void reset_cpu(ulong addr)
|
||||
{
|
||||
printf("Feature not supported.\n");
|
||||
};
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
printf("CPU: Freescale Treerunner S32V234 at %d MHz\n",
|
||||
mxc_get_clock(MXC_ARM_CLK) / 1000000);
|
||||
printf("Reset cause: %s\n", get_reset_cause());
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpu_eth_init(bd_t * bis)
|
||||
{
|
||||
int rc = -ENODEV;
|
||||
|
||||
#if defined(CONFIG_FEC_MXC)
|
||||
rc = fecmxc_initialize(bis);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int get_clocks(void)
|
||||
{
|
||||
#ifdef CONFIG_FSL_ESDHC_IMX
|
||||
gd->arch.sdhc_clk = mxc_get_clock(MXC_USDHC_CLK);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 NXP Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/macro.h>
|
||||
#include <asm/armv8/sec_firmware.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
extern void c_runtime_cpu_setup(void);
|
||||
|
||||
#define SEC_FIRMWARE_LOADED 0x1
|
||||
#define SEC_FIRMWARE_RUNNING 0x2
|
||||
#define SEC_FIRMWARE_ADDR_MASK (~0x3)
|
||||
/*
|
||||
* Secure firmware load addr
|
||||
* Flags used: 0x1 secure firmware has been loaded to secure memory
|
||||
* 0x2 secure firmware is running
|
||||
*/
|
||||
phys_addr_t sec_firmware_addr;
|
||||
|
||||
#ifndef SEC_FIRMWARE_FIT_IMAGE
|
||||
#define SEC_FIRMWARE_FIT_IMAGE "firmware"
|
||||
#endif
|
||||
#ifndef SEC_FIRMWARE_FIT_CNF_NAME
|
||||
#define SEC_FIRMWARE_FIT_CNF_NAME "config-1"
|
||||
#endif
|
||||
#ifndef SEC_FIRMWARE_TARGET_EL
|
||||
#define SEC_FIRMWARE_TARGET_EL 2
|
||||
#endif
|
||||
|
||||
static int sec_firmware_get_data(const void *sec_firmware_img,
|
||||
const void **data, size_t *size)
|
||||
{
|
||||
int conf_node_off, fw_node_off;
|
||||
char *conf_node_name = NULL;
|
||||
char *desc;
|
||||
int ret;
|
||||
|
||||
conf_node_name = SEC_FIRMWARE_FIT_CNF_NAME;
|
||||
|
||||
conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
|
||||
if (conf_node_off < 0) {
|
||||
printf("SEC Firmware: %s: no such config\n", conf_node_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
fw_node_off = fit_conf_get_prop_node(sec_firmware_img, conf_node_off,
|
||||
SEC_FIRMWARE_FIT_IMAGE);
|
||||
if (fw_node_off < 0) {
|
||||
printf("SEC Firmware: No '%s' in config\n",
|
||||
SEC_FIRMWARE_FIT_IMAGE);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
/* Verify secure firmware image */
|
||||
if (!(fit_image_verify(sec_firmware_img, fw_node_off))) {
|
||||
printf("SEC Firmware: Bad firmware image (bad CRC)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fit_image_get_data(sec_firmware_img, fw_node_off, data, size)) {
|
||||
printf("SEC Firmware: Can't get %s subimage data/size",
|
||||
SEC_FIRMWARE_FIT_IMAGE);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = fit_get_desc(sec_firmware_img, fw_node_off, &desc);
|
||||
if (ret)
|
||||
printf("SEC Firmware: Can't get description\n");
|
||||
else
|
||||
printf("%s\n", desc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* SEC Firmware FIT image parser checks if the image is in FIT
|
||||
* format, verifies integrity of the image and calculates raw
|
||||
* image address and size values.
|
||||
*
|
||||
* Returns 0 on success and a negative errno on error task fail.
|
||||
*/
|
||||
static int sec_firmware_parse_image(const void *sec_firmware_img,
|
||||
const void **raw_image_addr,
|
||||
size_t *raw_image_size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sec_firmware_get_data(sec_firmware_img, raw_image_addr,
|
||||
raw_image_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
debug("SEC Firmware: raw_image_addr = 0x%p, raw_image_size = 0x%lx\n",
|
||||
*raw_image_addr, *raw_image_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SEC Firmware FIT image parser to check if any loadable is
|
||||
* present. If present, verify integrity of the loadable and
|
||||
* copy loadable to address provided in (loadable_h, loadable_l).
|
||||
*
|
||||
* Returns 0 on success and a negative errno on error task fail.
|
||||
*/
|
||||
static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
|
||||
u32 *loadable_l, u32 *loadable_h)
|
||||
{
|
||||
phys_addr_t sec_firmware_loadable_addr = 0;
|
||||
int conf_node_off, ld_node_off, images;
|
||||
char *conf_node_name = NULL;
|
||||
const void *data;
|
||||
size_t size;
|
||||
ulong load;
|
||||
const char *name, *str, *type;
|
||||
int len;
|
||||
|
||||
conf_node_name = SEC_FIRMWARE_FIT_CNF_NAME;
|
||||
|
||||
conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
|
||||
if (conf_node_off < 0) {
|
||||
printf("SEC Firmware: %s: no such config\n", conf_node_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* find the node holding the images information */
|
||||
images = fdt_path_offset(sec_firmware_img, FIT_IMAGES_PATH);
|
||||
if (images < 0) {
|
||||
printf("%s: Cannot find /images node: %d\n", __func__, images);
|
||||
return -1;
|
||||
}
|
||||
|
||||
type = FIT_LOADABLE_PROP;
|
||||
|
||||
name = fdt_getprop(sec_firmware_img, conf_node_off, type, &len);
|
||||
if (!name) {
|
||||
/* Loadables not present */
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("SEC Firmware: '%s' present in config\n", type);
|
||||
|
||||
for (str = name; str && ((str - name) < len);
|
||||
str = strchr(str, '\0') + 1) {
|
||||
printf("%s: '%s'\n", type, str);
|
||||
ld_node_off = fdt_subnode_offset(sec_firmware_img, images, str);
|
||||
if (ld_node_off < 0) {
|
||||
printf("cannot find image node '%s': %d\n", str,
|
||||
ld_node_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Verify secure firmware image */
|
||||
if (!(fit_image_verify(sec_firmware_img, ld_node_off))) {
|
||||
printf("SEC Loadable: Bad loadable image (bad CRC)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fit_image_get_data(sec_firmware_img, ld_node_off,
|
||||
&data, &size)) {
|
||||
printf("SEC Loadable: Can't get subimage data/size");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Get load address, treated as load offset to secure memory */
|
||||
if (fit_image_get_load(sec_firmware_img, ld_node_off, &load)) {
|
||||
printf("SEC Loadable: Can't get subimage load");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Compute load address for loadable in secure memory */
|
||||
sec_firmware_loadable_addr = (sec_firmware_addr -
|
||||
gd->arch.tlb_size) + load;
|
||||
|
||||
/* Copy loadable to secure memory and flush dcache */
|
||||
debug("%s copied to address 0x%p\n",
|
||||
FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr);
|
||||
memcpy((void *)sec_firmware_loadable_addr, data, size);
|
||||
flush_dcache_range(sec_firmware_loadable_addr,
|
||||
sec_firmware_loadable_addr + size);
|
||||
|
||||
/* Populate loadable address only for Trusted OS */
|
||||
if (!strcmp(str, "trustedOS@1")) {
|
||||
/*
|
||||
* Populate address ptrs for loadable image with
|
||||
* loadbale addr
|
||||
*/
|
||||
out_le32(loadable_l, (sec_firmware_loadable_addr &
|
||||
WORD_MASK));
|
||||
out_le32(loadable_h, (sec_firmware_loadable_addr >>
|
||||
WORD_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sec_firmware_copy_image(const char *title,
|
||||
u64 image_addr, u32 image_size, u64 sec_firmware)
|
||||
{
|
||||
debug("%s copied to address 0x%p\n", title, (void *)sec_firmware);
|
||||
memcpy((void *)sec_firmware, (void *)image_addr, image_size);
|
||||
flush_dcache_range(sec_firmware, sec_firmware + image_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will parse the SEC Firmware image, and then load it
|
||||
* to secure memory. Also load any loadable if present along with SEC
|
||||
* Firmware image.
|
||||
*/
|
||||
static int sec_firmware_load_image(const void *sec_firmware_img,
|
||||
u32 *loadable_l, u32 *loadable_h)
|
||||
{
|
||||
const void *raw_image_addr;
|
||||
size_t raw_image_size = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The Excetpion Level must be EL3 to load and initialize
|
||||
* the SEC Firmware.
|
||||
*/
|
||||
if (current_el() != 3) {
|
||||
ret = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
|
||||
/*
|
||||
* The SEC Firmware must be stored in secure memory.
|
||||
* Append SEC Firmware to secure mmu table.
|
||||
*/
|
||||
if (!(gd->arch.secure_ram & MEM_RESERVE_SECURE_MAINTAINED)) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sec_firmware_addr = (gd->arch.secure_ram & MEM_RESERVE_SECURE_ADDR_MASK) +
|
||||
gd->arch.tlb_size;
|
||||
#else
|
||||
#error "The CONFIG_SYS_MEM_RESERVE_SECURE must be defined when enabled SEC Firmware support"
|
||||
#endif
|
||||
|
||||
/* Align SEC Firmware base address to 4K */
|
||||
sec_firmware_addr = (sec_firmware_addr + 0xfff) & ~0xfff;
|
||||
debug("SEC Firmware: Load address: 0x%llx\n",
|
||||
sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
|
||||
|
||||
ret = sec_firmware_parse_image(sec_firmware_img, &raw_image_addr,
|
||||
&raw_image_size);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* TODO:
|
||||
* Check if the end addr of SEC Firmware has been extend the secure
|
||||
* memory.
|
||||
*/
|
||||
|
||||
/* Copy the secure firmware to secure memory */
|
||||
ret = sec_firmware_copy_image("SEC Firmware", (u64)raw_image_addr,
|
||||
raw_image_size, sec_firmware_addr &
|
||||
SEC_FIRMWARE_ADDR_MASK);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Check if any loadable are present along with firmware image, if
|
||||
* present load them.
|
||||
*/
|
||||
ret = sec_firmware_check_copy_loadable(sec_firmware_img, loadable_l,
|
||||
loadable_h);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
sec_firmware_addr |= SEC_FIRMWARE_LOADED;
|
||||
debug("SEC Firmware: Entry point: 0x%llx\n",
|
||||
sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
printf("SEC Firmware: error (%d)\n", ret);
|
||||
sec_firmware_addr = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sec_firmware_entry(u32 *eret_hold_l, u32 *eret_hold_h)
|
||||
{
|
||||
const void *entry = (void *)(sec_firmware_addr &
|
||||
SEC_FIRMWARE_ADDR_MASK);
|
||||
|
||||
return _sec_firmware_entry(entry, eret_hold_l, eret_hold_h);
|
||||
}
|
||||
|
||||
/* Check the secure firmware FIT image */
|
||||
__weak bool sec_firmware_is_valid(const void *sec_firmware_img)
|
||||
{
|
||||
if (fdt_check_header(sec_firmware_img)) {
|
||||
printf("SEC Firmware: Bad firmware image (not a FIT image)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fit_check_format(sec_firmware_img)) {
|
||||
printf("SEC Firmware: Bad firmware image (bad FIT header)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SEC_FIRMWARE_ARMV8_PSCI
|
||||
/*
|
||||
* The PSCI_VERSION function is added from PSCI v0.2. When the PSCI
|
||||
* v0.1 received this function, the NOT_SUPPORTED (0xffff_ffff) error
|
||||
* number will be returned according to SMC Calling Conventions. But
|
||||
* when getting the NOT_SUPPORTED error number, we cannot ensure if
|
||||
* the PSCI version is v0.1 or other error occurred. So, PSCI v0.1
|
||||
* won't be supported by this framework.
|
||||
* And if the secure firmware isn't running, return NOT_SUPPORTED.
|
||||
*
|
||||
* The return value on success is PSCI version in format
|
||||
* major[31:16]:minor[15:0].
|
||||
*/
|
||||
unsigned int sec_firmware_support_psci_version(void)
|
||||
{
|
||||
if (current_el() == SEC_FIRMWARE_TARGET_EL)
|
||||
return _sec_firmware_support_psci_version();
|
||||
|
||||
return PSCI_INVALID_VER;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check with sec_firmware if it supports random number generation
|
||||
* via HW RNG
|
||||
*
|
||||
* The return value will be true if it is supported
|
||||
*/
|
||||
bool sec_firmware_support_hwrng(void)
|
||||
{
|
||||
#ifdef CONFIG_TFABOOT
|
||||
/* return true as TFA has one job ring reserved */
|
||||
return true;
|
||||
#endif
|
||||
if (sec_firmware_addr & SEC_FIRMWARE_RUNNING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* sec_firmware_get_random - Get a random number from SEC Firmware
|
||||
* @rand: random number buffer to be filled
|
||||
* @bytes: Number of bytes of random number to be supported
|
||||
* @eret: -1 in case of error, 0 for success
|
||||
*/
|
||||
int sec_firmware_get_random(uint8_t *rand, int bytes)
|
||||
{
|
||||
unsigned long long num;
|
||||
struct pt_regs regs;
|
||||
int param1;
|
||||
|
||||
if (!bytes || bytes > 8) {
|
||||
printf("Max Random bytes genration supported is 8\n");
|
||||
return -1;
|
||||
}
|
||||
#define SIP_RNG_64 0xC200FF11
|
||||
regs.regs[0] = SIP_RNG_64;
|
||||
|
||||
if (bytes <= 4)
|
||||
param1 = 0;
|
||||
else
|
||||
param1 = 1;
|
||||
regs.regs[1] = param1;
|
||||
|
||||
smc_call(®s);
|
||||
|
||||
if (regs.regs[0])
|
||||
return -1;
|
||||
|
||||
num = regs.regs[1];
|
||||
memcpy(rand, &num, bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sec_firmware_init - Initialize the SEC Firmware
|
||||
* @sec_firmware_img: the SEC Firmware image address
|
||||
* @eret_hold_l: the address to hold exception return address low
|
||||
* @eret_hold_h: the address to hold exception return address high
|
||||
* @loadable_l: the address to hold loadable address low
|
||||
* @loadable_h: the address to hold loadable address high
|
||||
*/
|
||||
int sec_firmware_init(const void *sec_firmware_img,
|
||||
u32 *eret_hold_l,
|
||||
u32 *eret_hold_h,
|
||||
u32 *loadable_l,
|
||||
u32 *loadable_h)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sec_firmware_is_valid(sec_firmware_img))
|
||||
return -EINVAL;
|
||||
|
||||
ret = sec_firmware_load_image(sec_firmware_img, loadable_l,
|
||||
loadable_h);
|
||||
if (ret) {
|
||||
printf("SEC Firmware: Failed to load image\n");
|
||||
return ret;
|
||||
} else if (sec_firmware_addr & SEC_FIRMWARE_LOADED) {
|
||||
ret = sec_firmware_entry(eret_hold_l, eret_hold_h);
|
||||
if (ret) {
|
||||
printf("SEC Firmware: Failed to initialize\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
debug("SEC Firmware: Return from SEC Firmware: current_el = %d\n",
|
||||
current_el());
|
||||
|
||||
/*
|
||||
* The PE will be turned into target EL when returned from
|
||||
* SEC Firmware.
|
||||
*/
|
||||
if (current_el() != SEC_FIRMWARE_TARGET_EL)
|
||||
return -EACCES;
|
||||
|
||||
sec_firmware_addr |= SEC_FIRMWARE_RUNNING;
|
||||
|
||||
/* Set exception table and enable caches if it isn't EL3 */
|
||||
if (current_el() != 3) {
|
||||
c_runtime_cpu_setup();
|
||||
enable_caches();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fdt_fix_kaslr - Add kalsr-seed node in Device tree
|
||||
* @fdt: Device tree
|
||||
* @eret: 0 in case of error, 1 for success
|
||||
*/
|
||||
int fdt_fixup_kaslr(void *fdt)
|
||||
{
|
||||
int nodeoffset;
|
||||
int err, ret = 0;
|
||||
u8 rand[8];
|
||||
|
||||
#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
|
||||
/* Check if random seed generation is supported */
|
||||
if (sec_firmware_support_hwrng() == false) {
|
||||
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = sec_firmware_get_random(rand, 8);
|
||||
if (ret < 0) {
|
||||
printf("WARNING: No random number to set kaslr-seed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = fdt_check_header(fdt);
|
||||
if (err < 0) {
|
||||
printf("fdt_chosen: %s\n", fdt_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find or create "/chosen" node. */
|
||||
nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
|
||||
if (nodeoffset < 0)
|
||||
return 0;
|
||||
|
||||
err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
|
||||
sizeof(rand));
|
||||
if (err < 0) {
|
||||
printf("WARNING: can't set kaslr-seed %s.\n",
|
||||
fdt_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
ret = 1;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2016 NXP Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
WEAK(_sec_firmware_entry)
|
||||
/*
|
||||
* x0: Secure Firmware entry point
|
||||
* x1: Exception return address Low
|
||||
* x2: Exception return address High
|
||||
*/
|
||||
|
||||
/* Save stack pointer for EL2 */
|
||||
mov x3, sp
|
||||
msr sp_el2, x3
|
||||
|
||||
/* Set exception return address hold pointer */
|
||||
adr x4, 1f
|
||||
mov x3, x4
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_ERET_ADDR_REVERT
|
||||
rev w3, w3
|
||||
#endif
|
||||
str w3, [x1]
|
||||
lsr x3, x4, #32
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_ERET_ADDR_REVERT
|
||||
rev w3, w3
|
||||
#endif
|
||||
str w3, [x2]
|
||||
|
||||
/* Call SEC monitor */
|
||||
br x0
|
||||
|
||||
1:
|
||||
mov x0, #0
|
||||
ret
|
||||
ENDPROC(_sec_firmware_entry)
|
||||
|
||||
#ifdef CONFIG_SEC_FIRMWARE_ARMV8_PSCI
|
||||
ENTRY(_sec_firmware_support_psci_version)
|
||||
mov x0, 0x84000000
|
||||
mov x1, 0x0
|
||||
mov x2, 0x0
|
||||
mov x3, 0x0
|
||||
smc #0
|
||||
ret
|
||||
ENDPROC(_sec_firmware_support_psci_version)
|
||||
|
||||
/*
|
||||
* Switch from AArch64 EL2 to AArch32 EL2
|
||||
* @param inputs:
|
||||
* x0: argument, zero
|
||||
* x1: machine nr
|
||||
* x2: fdt address
|
||||
* x3: input argument
|
||||
* x4: kernel entry point
|
||||
* @param outputs for secure firmware:
|
||||
* x0: function id
|
||||
* x1: kernel entry point
|
||||
* x2: machine nr
|
||||
* x3: fdt address
|
||||
*/
|
||||
ENTRY(armv8_el2_to_aarch32)
|
||||
mov x3, x2
|
||||
mov x2, x1
|
||||
mov x1, x4
|
||||
ldr x0, =0xc200ff17
|
||||
smc #0
|
||||
ret
|
||||
ENDPROC(armv8_el2_to_aarch32)
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015, Linaro Limited
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <generated/asm-offsets.h>
|
||||
|
||||
#ifdef CONFIG_EFI_LOADER
|
||||
.section .text.efi_runtime
|
||||
#endif
|
||||
|
||||
.macro SMCCC instr
|
||||
.cfi_startproc
|
||||
\instr #0
|
||||
ldr x4, [sp]
|
||||
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
|
||||
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
|
||||
ldr x4, [sp, #8]
|
||||
cbz x4, 1f /* no quirk structure */
|
||||
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
|
||||
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
|
||||
b.ne 1f
|
||||
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
|
||||
1: ret
|
||||
.cfi_endproc
|
||||
.endm
|
||||
|
||||
/*
|
||||
* void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
|
||||
* unsigned long a3, unsigned long a4, unsigned long a5,
|
||||
* unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
|
||||
* struct arm_smccc_quirk *quirk)
|
||||
*/
|
||||
ENTRY(__arm_smccc_smc)
|
||||
SMCCC smc
|
||||
ENDPROC(__arm_smccc_smc)
|
||||
|
||||
/*
|
||||
* void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
|
||||
* unsigned long a3, unsigned long a4, unsigned long a5,
|
||||
* unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
|
||||
* struct arm_smccc_quirk *quirk)
|
||||
*/
|
||||
ENTRY(__arm_smccc_hvc)
|
||||
SMCCC hvc
|
||||
ENDPROC(__arm_smccc_hvc)
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Socionext Inc.
|
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <asm/spin_table.h>
|
||||
|
||||
int spin_table_update_dt(void *fdt)
|
||||
{
|
||||
int cpus_offset, offset;
|
||||
const char *prop;
|
||||
int ret;
|
||||
unsigned long rsv_addr = (unsigned long)&spin_table_reserve_begin;
|
||||
unsigned long rsv_size = &spin_table_reserve_end -
|
||||
&spin_table_reserve_begin;
|
||||
|
||||
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||
if (cpus_offset < 0)
|
||||
return -ENODEV;
|
||||
|
||||
for (offset = fdt_first_subnode(fdt, cpus_offset);
|
||||
offset >= 0;
|
||||
offset = fdt_next_subnode(fdt, offset)) {
|
||||
prop = fdt_getprop(fdt, offset, "device_type", NULL);
|
||||
if (!prop || strcmp(prop, "cpu"))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* In the first loop, we check if every CPU node specifies
|
||||
* spin-table. Otherwise, just return successfully to not
|
||||
* disturb other methods, like psci.
|
||||
*/
|
||||
prop = fdt_getprop(fdt, offset, "enable-method", NULL);
|
||||
if (!prop || strcmp(prop, "spin-table"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (offset = fdt_first_subnode(fdt, cpus_offset);
|
||||
offset >= 0;
|
||||
offset = fdt_next_subnode(fdt, offset)) {
|
||||
prop = fdt_getprop(fdt, offset, "device_type", NULL);
|
||||
if (!prop || strcmp(prop, "cpu"))
|
||||
continue;
|
||||
|
||||
ret = fdt_setprop_u64(fdt, offset, "cpu-release-addr",
|
||||
(unsigned long)&spin_table_cpu_release_addr);
|
||||
if (ret)
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size);
|
||||
if (ret)
|
||||
return -ENOSPC;
|
||||
|
||||
printf(" Reserved memory region for spin-table: addr=%lx size=%lx\n",
|
||||
rsv_addr, rsv_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2016 Socionext Inc.
|
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
ENTRY(spin_table_secondary_jump)
|
||||
.globl spin_table_reserve_begin
|
||||
spin_table_reserve_begin:
|
||||
0: wfe
|
||||
ldr x0, spin_table_cpu_release_addr
|
||||
cbz x0, 0b
|
||||
br x0
|
||||
.globl spin_table_cpu_release_addr
|
||||
.align 3
|
||||
spin_table_cpu_release_addr:
|
||||
.quad 0
|
||||
.globl spin_table_reserve_end
|
||||
spin_table_reserve_end:
|
||||
ENDPROC(spin_table_secondary_jump)
|
||||
@@ -0,0 +1,374 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/macro.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Startup Code (reset vector)
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
#if defined(CONFIG_LINUX_KERNEL_IMAGE_HEADER)
|
||||
#include <asm/boot0-linux-kernel-header.h>
|
||||
#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
|
||||
/*
|
||||
* Various SoCs need something special and SoC-specific up front in
|
||||
* order to boot, allow them to set that in their boot0.h file and then
|
||||
* use it here.
|
||||
*/
|
||||
#include <asm/arch/boot0.h>
|
||||
#else
|
||||
b reset
|
||||
#endif
|
||||
|
||||
.align 3
|
||||
|
||||
.globl _TEXT_BASE
|
||||
_TEXT_BASE:
|
||||
.quad CONFIG_SYS_TEXT_BASE
|
||||
|
||||
/*
|
||||
* These are defined in the linker script.
|
||||
*/
|
||||
.globl _end_ofs
|
||||
_end_ofs:
|
||||
.quad _end - _start
|
||||
|
||||
.globl _bss_start_ofs
|
||||
_bss_start_ofs:
|
||||
.quad __bss_start - _start
|
||||
|
||||
.globl _bss_end_ofs
|
||||
_bss_end_ofs:
|
||||
.quad __bss_end - _start
|
||||
|
||||
reset:
|
||||
/* Allow the board to save important registers */
|
||||
b save_boot_params
|
||||
.globl save_boot_params_ret
|
||||
save_boot_params_ret:
|
||||
|
||||
#if CONFIG_POSITION_INDEPENDENT
|
||||
/*
|
||||
* Fix .rela.dyn relocations. This allows U-Boot to be loaded to and
|
||||
* executed at a different address than it was linked at.
|
||||
*/
|
||||
pie_fixup:
|
||||
adr x0, _start /* x0 <- Runtime value of _start */
|
||||
ldr x1, _TEXT_BASE /* x1 <- Linked value of _start */
|
||||
sub x9, x0, x1 /* x9 <- Run-vs-link offset */
|
||||
adr x2, __rel_dyn_start /* x2 <- Runtime &__rel_dyn_start */
|
||||
adr x3, __rel_dyn_end /* x3 <- Runtime &__rel_dyn_end */
|
||||
pie_fix_loop:
|
||||
ldp x0, x1, [x2], #16 /* (x0, x1) <- (Link location, fixup) */
|
||||
ldr x4, [x2], #8 /* x4 <- addend */
|
||||
cmp w1, #1027 /* relative fixup? */
|
||||
bne pie_skip_reloc
|
||||
/* relative fix: store addend plus offset at dest location */
|
||||
add x0, x0, x9
|
||||
add x4, x4, x9
|
||||
str x4, [x0]
|
||||
pie_skip_reloc:
|
||||
cmp x2, x3
|
||||
b.lo pie_fix_loop
|
||||
pie_fixup_done:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_RESET_SCTRL
|
||||
bl reset_sctrl
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARMV8_SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD)
|
||||
.macro set_vbar, regname, reg
|
||||
msr \regname, \reg
|
||||
.endm
|
||||
adr x0, vectors
|
||||
#else
|
||||
.macro set_vbar, regname, reg
|
||||
.endm
|
||||
#endif
|
||||
/*
|
||||
* Could be EL3/EL2/EL1, Initial State:
|
||||
* Little Endian, MMU Disabled, i/dCache Disabled
|
||||
*/
|
||||
switch_el x1, 3f, 2f, 1f
|
||||
3: set_vbar vbar_el3, x0
|
||||
mrs x0, scr_el3
|
||||
orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */
|
||||
msr scr_el3, x0
|
||||
msr cptr_el3, xzr /* Enable FP/SIMD */
|
||||
#ifdef COUNTER_FREQUENCY
|
||||
ldr x0, =COUNTER_FREQUENCY
|
||||
msr cntfrq_el0, x0 /* Initialize CNTFRQ */
|
||||
#endif
|
||||
b 0f
|
||||
2: set_vbar vbar_el2, x0
|
||||
mov x0, #0x33ff
|
||||
msr cptr_el2, x0 /* Enable FP/SIMD */
|
||||
b 0f
|
||||
1: set_vbar vbar_el1, x0
|
||||
mov x0, #3 << 20
|
||||
msr cpacr_el1, x0 /* Enable FP/SIMD */
|
||||
0:
|
||||
|
||||
/*
|
||||
* Enable SMPEN bit for coherency.
|
||||
* This register is not architectural but at the moment
|
||||
* this bit should be set for A53/A57/A72.
|
||||
*/
|
||||
#ifdef CONFIG_ARMV8_SET_SMPEN
|
||||
switch_el x1, 3f, 1f, 1f
|
||||
3:
|
||||
mrs x0, S3_1_c15_c2_1 /* cpuectlr_el1 */
|
||||
orr x0, x0, #0x40
|
||||
msr S3_1_c15_c2_1, x0
|
||||
1:
|
||||
#endif
|
||||
|
||||
/* Apply ARM core specific erratas */
|
||||
bl apply_core_errata
|
||||
|
||||
/*
|
||||
* Cache/BPB/TLB Invalidate
|
||||
* i-cache is invalidated before enabled in icache_enable()
|
||||
* tlb is invalidated before mmu is enabled in dcache_enable()
|
||||
* d-cache is invalidated before enabled in dcache_enable()
|
||||
*/
|
||||
|
||||
/* Processor specific initialization */
|
||||
bl lowlevel_init
|
||||
|
||||
#if defined(CONFIG_ARMV8_SPIN_TABLE) && !defined(CONFIG_SPL_BUILD)
|
||||
branch_if_master x0, x1, master_cpu
|
||||
b spin_table_secondary_jump
|
||||
/* never return */
|
||||
#elif defined(CONFIG_ARMV8_MULTIENTRY)
|
||||
branch_if_master x0, x1, master_cpu
|
||||
|
||||
/*
|
||||
* Slave CPUs
|
||||
*/
|
||||
slave_cpu:
|
||||
wfe
|
||||
ldr x1, =CPU_RELEASE_ADDR
|
||||
ldr x0, [x1]
|
||||
cbz x0, slave_cpu
|
||||
br x0 /* branch to the given address */
|
||||
#endif /* CONFIG_ARMV8_MULTIENTRY */
|
||||
master_cpu:
|
||||
bl _main
|
||||
|
||||
#ifdef CONFIG_SYS_RESET_SCTRL
|
||||
reset_sctrl:
|
||||
switch_el x1, 3f, 2f, 1f
|
||||
3:
|
||||
mrs x0, sctlr_el3
|
||||
b 0f
|
||||
2:
|
||||
mrs x0, sctlr_el2
|
||||
b 0f
|
||||
1:
|
||||
mrs x0, sctlr_el1
|
||||
|
||||
0:
|
||||
ldr x1, =0xfdfffffa
|
||||
and x0, x0, x1
|
||||
|
||||
switch_el x1, 6f, 5f, 4f
|
||||
6:
|
||||
msr sctlr_el3, x0
|
||||
b 7f
|
||||
5:
|
||||
msr sctlr_el2, x0
|
||||
b 7f
|
||||
4:
|
||||
msr sctlr_el1, x0
|
||||
|
||||
7:
|
||||
dsb sy
|
||||
isb
|
||||
b __asm_invalidate_tlb_all
|
||||
ret
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
WEAK(apply_core_errata)
|
||||
|
||||
mov x29, lr /* Save LR */
|
||||
/* For now, we support Cortex-A53, Cortex-A57 specific errata */
|
||||
|
||||
/* Check if we are running on a Cortex-A53 core */
|
||||
branch_if_a53_core x0, apply_a53_core_errata
|
||||
|
||||
/* Check if we are running on a Cortex-A57 core */
|
||||
branch_if_a57_core x0, apply_a57_core_errata
|
||||
0:
|
||||
mov lr, x29 /* Restore LR */
|
||||
ret
|
||||
|
||||
apply_a53_core_errata:
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_855873
|
||||
mrs x0, midr_el1
|
||||
tst x0, #(0xf << 20)
|
||||
b.ne 0b
|
||||
|
||||
mrs x0, midr_el1
|
||||
and x0, x0, #0xf
|
||||
cmp x0, #3
|
||||
b.lt 0b
|
||||
|
||||
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
|
||||
/* Enable data cache clean as data cache clean/invalidate */
|
||||
orr x0, x0, #1 << 44
|
||||
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
|
||||
#endif
|
||||
b 0b
|
||||
|
||||
apply_a57_core_errata:
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_828024
|
||||
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
|
||||
/* Disable non-allocate hint of w-b-n-a memory type */
|
||||
orr x0, x0, #1 << 49
|
||||
/* Disable write streaming no L1-allocate threshold */
|
||||
orr x0, x0, #3 << 25
|
||||
/* Disable write streaming no-allocate threshold */
|
||||
orr x0, x0, #3 << 27
|
||||
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_826974
|
||||
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
|
||||
/* Disable speculative load execution ahead of a DMB */
|
||||
orr x0, x0, #1 << 59
|
||||
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_833471
|
||||
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
|
||||
/* FPSCR write flush.
|
||||
* Note that in some cases where a flush is unnecessary this
|
||||
could impact performance. */
|
||||
orr x0, x0, #1 << 38
|
||||
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_829520
|
||||
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
|
||||
/* Disable Indirect Predictor bit will prevent this erratum
|
||||
from occurring
|
||||
* Note that in some cases where a flush is unnecessary this
|
||||
could impact performance. */
|
||||
orr x0, x0, #1 << 4
|
||||
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_833069
|
||||
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
|
||||
/* Disable Enable Invalidates of BTB bit */
|
||||
and x0, x0, #0xE
|
||||
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
|
||||
#endif
|
||||
b 0b
|
||||
ENDPROC(apply_core_errata)
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
WEAK(lowlevel_init)
|
||||
mov x29, lr /* Save LR */
|
||||
|
||||
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
|
||||
branch_if_slave x0, 1f
|
||||
ldr x0, =GICD_BASE
|
||||
bl gic_init_secure
|
||||
1:
|
||||
#if defined(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
|
||||
|
||||
#ifdef CONFIG_ARMV8_MULTIENTRY
|
||||
branch_if_master x0, x1, 2f
|
||||
|
||||
/*
|
||||
* Slave should wait for master clearing spin table.
|
||||
* This sync prevent salves observing incorrect
|
||||
* value of spin table and jumping to wrong place.
|
||||
*/
|
||||
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
|
||||
#ifdef CONFIG_GICV2
|
||||
ldr x0, =GICC_BASE
|
||||
#endif
|
||||
bl gic_wait_for_interrupt
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All slaves will enter EL2 and optionally EL1.
|
||||
*/
|
||||
adr x4, lowlevel_in_el2
|
||||
ldr x5, =ES_TO_AARCH64
|
||||
bl armv8_switch_to_el2
|
||||
|
||||
lowlevel_in_el2:
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
adr x4, lowlevel_in_el1
|
||||
ldr x5, =ES_TO_AARCH64
|
||||
bl armv8_switch_to_el1
|
||||
|
||||
lowlevel_in_el1:
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_ARMV8_MULTIENTRY */
|
||||
|
||||
2:
|
||||
mov lr, x29 /* Restore LR */
|
||||
ret
|
||||
ENDPROC(lowlevel_init)
|
||||
|
||||
WEAK(smp_kick_all_cpus)
|
||||
/* Kick secondary cpus up by SGI 0 interrupt */
|
||||
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
|
||||
ldr x0, =GICD_BASE
|
||||
b gic_kick_secondary_cpus
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(smp_kick_all_cpus)
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
ENTRY(c_runtime_cpu_setup)
|
||||
#if defined(CONFIG_ARMV8_SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD)
|
||||
/* Relocate vBAR */
|
||||
adr x0, vectors
|
||||
switch_el x1, 3f, 2f, 1f
|
||||
3: msr vbar_el3, x0
|
||||
b 0f
|
||||
2: msr vbar_el2, x0
|
||||
b 0f
|
||||
1: msr vbar_el1, x0
|
||||
0:
|
||||
#endif
|
||||
|
||||
ret
|
||||
ENDPROC(c_runtime_cpu_setup)
|
||||
|
||||
WEAK(save_boot_params)
|
||||
b save_boot_params_ret /* back to my caller */
|
||||
ENDPROC(save_boot_params)
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
/*
|
||||
* void __asm_invalidate_tlb_all(void)
|
||||
*
|
||||
* invalidate all tlb entries.
|
||||
*/
|
||||
.pushsection .text.__asm_invalidate_tlb_all, "ax"
|
||||
ENTRY(__asm_invalidate_tlb_all)
|
||||
switch_el x9, 3f, 2f, 1f
|
||||
3: tlbi alle3
|
||||
dsb sy
|
||||
isb
|
||||
b 0f
|
||||
2: tlbi alle2
|
||||
dsb sy
|
||||
isb
|
||||
b 0f
|
||||
1: tlbi vmalle1
|
||||
dsb sy
|
||||
isb
|
||||
0:
|
||||
ret
|
||||
ENDPROC(__asm_invalidate_tlb_all)
|
||||
.popsection
|
||||
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
.pushsection .text.armv8_switch_to_el2, "ax"
|
||||
ENTRY(armv8_switch_to_el2)
|
||||
switch_el x6, 1f, 0f, 0f
|
||||
0:
|
||||
cmp x5, #ES_TO_AARCH64
|
||||
b.eq 2f
|
||||
/*
|
||||
* When loading 32-bit kernel, it will jump
|
||||
* to secure firmware again, and never return.
|
||||
*/
|
||||
bl armv8_el2_to_aarch32
|
||||
2:
|
||||
/*
|
||||
* x4 is kernel entry point or switch_to_el1
|
||||
* if CONFIG_ARMV8_SWITCH_TO_EL1 is defined.
|
||||
* When running in EL2 now, jump to the
|
||||
* address saved in x4.
|
||||
*/
|
||||
br x4
|
||||
1: armv8_switch_to_el2_m x4, x5, x6
|
||||
ENDPROC(armv8_switch_to_el2)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.armv8_switch_to_el1, "ax"
|
||||
ENTRY(armv8_switch_to_el1)
|
||||
switch_el x6, 0f, 1f, 0f
|
||||
0:
|
||||
/* x4 is kernel entry point. When running in EL1
|
||||
* now, jump to the address saved in x4.
|
||||
*/
|
||||
br x4
|
||||
1: armv8_switch_to_el1_m x4, x5, x6
|
||||
ENDPROC(armv8_switch_to_el1)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.armv8_el2_to_aarch32, "ax"
|
||||
WEAK(armv8_el2_to_aarch32)
|
||||
ret
|
||||
ENDPROC(armv8_el2_to_aarch32)
|
||||
.popsection
|
||||
@@ -0,0 +1,78 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*/
|
||||
|
||||
MEMORY { .sram : ORIGIN = IMAGE_TEXT_BASE,
|
||||
LENGTH = IMAGE_MAX_SIZE }
|
||||
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
|
||||
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
. = ALIGN(8);
|
||||
*(.__image_copy_start)
|
||||
CPUDIR/start.o (.text*)
|
||||
*(.text*)
|
||||
} >.sram
|
||||
|
||||
.rodata : {
|
||||
. = ALIGN(8);
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
|
||||
} >.sram
|
||||
|
||||
.data : {
|
||||
. = ALIGN(8);
|
||||
*(.data*)
|
||||
} >.sram
|
||||
|
||||
.u_boot_list : {
|
||||
. = ALIGN(8);
|
||||
KEEP(*(SORT(.u_boot_list*)));
|
||||
} >.sram
|
||||
|
||||
.image_copy_end : {
|
||||
. = ALIGN(8);
|
||||
*(.__image_copy_end)
|
||||
} >.sram
|
||||
|
||||
.end : {
|
||||
. = ALIGN(8);
|
||||
*(.__end)
|
||||
} >.sram
|
||||
|
||||
_image_binary_end = .;
|
||||
|
||||
.bss_start (NOLOAD) : {
|
||||
. = ALIGN(8);
|
||||
KEEP(*(.__bss_start));
|
||||
} >.sdram
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
*(.bss*)
|
||||
. = ALIGN(8);
|
||||
} >.sdram
|
||||
|
||||
.bss_end (NOLOAD) : {
|
||||
KEEP(*(.__bss_end));
|
||||
} >.sdram
|
||||
|
||||
/DISCARD/ : { *(.dynsym) }
|
||||
/DISCARD/ : { *(.dynstr*) }
|
||||
/DISCARD/ : { *(.dynamic*) }
|
||||
/DISCARD/ : { *(.plt*) }
|
||||
/DISCARD/ : { *(.interp*) }
|
||||
/DISCARD/ : { *(.gnu*) }
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/psci.h>
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
#ifdef CONFIG_ARMV8_SECURE_BASE
|
||||
/DISCARD/ : { *(.rela._secure*) }
|
||||
#endif
|
||||
. = 0x00000000;
|
||||
|
||||
. = ALIGN(8);
|
||||
.text :
|
||||
{
|
||||
*(.__image_copy_start)
|
||||
CPUDIR/start.o (.text*)
|
||||
}
|
||||
|
||||
/* This needs to come before *(.text*) */
|
||||
.efi_runtime : {
|
||||
__efi_runtime_start = .;
|
||||
*(.text.efi_runtime*)
|
||||
*(.rodata.efi_runtime*)
|
||||
*(.data.efi_runtime*)
|
||||
__efi_runtime_stop = .;
|
||||
}
|
||||
|
||||
.text_rest :
|
||||
{
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARMV8_PSCI
|
||||
.__secure_start :
|
||||
#ifndef CONFIG_ARMV8_SECURE_BASE
|
||||
ALIGN(CONSTANT(COMMONPAGESIZE))
|
||||
#endif
|
||||
{
|
||||
KEEP(*(.__secure_start))
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARMV8_SECURE_BASE
|
||||
#define CONFIG_ARMV8_SECURE_BASE
|
||||
#define __ARMV8_PSCI_STACK_IN_RAM
|
||||
#endif
|
||||
.secure_text CONFIG_ARMV8_SECURE_BASE :
|
||||
AT(ADDR(.__secure_start) + SIZEOF(.__secure_start))
|
||||
{
|
||||
*(._secure.text)
|
||||
. = ALIGN(8);
|
||||
__secure_svc_tbl_start = .;
|
||||
KEEP(*(._secure_svc_tbl_entries))
|
||||
__secure_svc_tbl_end = .;
|
||||
}
|
||||
|
||||
.secure_data : AT(LOADADDR(.secure_text) + SIZEOF(.secure_text))
|
||||
{
|
||||
*(._secure.data)
|
||||
}
|
||||
|
||||
.secure_stack ALIGN(ADDR(.secure_data) + SIZEOF(.secure_data),
|
||||
CONSTANT(COMMONPAGESIZE)) (NOLOAD) :
|
||||
#ifdef __ARMV8_PSCI_STACK_IN_RAM
|
||||
AT(ADDR(.secure_stack))
|
||||
#else
|
||||
AT(LOADADDR(.secure_data) + SIZEOF(.secure_data))
|
||||
#endif
|
||||
{
|
||||
KEEP(*(.__secure_stack_start))
|
||||
|
||||
. = . + CONFIG_ARMV8_PSCI_NR_CPUS * ARM_PSCI_STACK_SIZE;
|
||||
|
||||
. = ALIGN(CONSTANT(COMMONPAGESIZE));
|
||||
|
||||
KEEP(*(.__secure_stack_end))
|
||||
}
|
||||
|
||||
#ifndef __ARMV8_PSCI_STACK_IN_RAM
|
||||
. = LOADADDR(.secure_stack);
|
||||
#endif
|
||||
|
||||
.__secure_end : AT(ADDR(.__secure_end)) {
|
||||
KEEP(*(.__secure_end))
|
||||
LONG(0x1d1071c); /* Must output something to reset LMA */
|
||||
}
|
||||
#endif
|
||||
|
||||
. = ALIGN(8);
|
||||
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
|
||||
|
||||
. = ALIGN(8);
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
. = ALIGN(8);
|
||||
|
||||
. = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
.u_boot_list : {
|
||||
KEEP(*(SORT(.u_boot_list*)));
|
||||
}
|
||||
|
||||
. = ALIGN(8);
|
||||
|
||||
.efi_runtime_rel : {
|
||||
__efi_runtime_rel_start = .;
|
||||
*(.rel*.efi_runtime)
|
||||
*(.rel*.efi_runtime.*)
|
||||
__efi_runtime_rel_stop = .;
|
||||
}
|
||||
|
||||
. = ALIGN(8);
|
||||
|
||||
.image_copy_end :
|
||||
{
|
||||
*(.__image_copy_end)
|
||||
}
|
||||
|
||||
. = ALIGN(8);
|
||||
|
||||
.rel_dyn_start :
|
||||
{
|
||||
*(.__rel_dyn_start)
|
||||
}
|
||||
|
||||
.rela.dyn : {
|
||||
*(.rela*)
|
||||
}
|
||||
|
||||
.rel_dyn_end :
|
||||
{
|
||||
*(.__rel_dyn_end)
|
||||
}
|
||||
|
||||
_end = .;
|
||||
|
||||
. = ALIGN(8);
|
||||
|
||||
.bss_start : {
|
||||
KEEP(*(.__bss_start));
|
||||
}
|
||||
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
. = ALIGN(8);
|
||||
}
|
||||
|
||||
.bss_end : {
|
||||
KEEP(*(.__bss_end));
|
||||
}
|
||||
|
||||
/DISCARD/ : { *(.dynsym) }
|
||||
/DISCARD/ : { *(.dynstr*) }
|
||||
/DISCARD/ : { *(.dynamic*) }
|
||||
/DISCARD/ : { *(.plt*) }
|
||||
/DISCARD/ : { *(.interp*) }
|
||||
/DISCARD/ : { *(.gnu*) }
|
||||
|
||||
#ifdef CONFIG_LINUX_KERNEL_IMAGE_HEADER
|
||||
#include "linux-kernel-image-header-vars.h"
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user