GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -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);
@@ -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
}
@@ -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 thats 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;
}
@@ -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 thats 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(&regs);
else
hvc_call(&regs);
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(&regs);
else
hvc_call(&regs);
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(&regs);
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
}