avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
6
u-boot/arch/arm/cpu/armv8/Kconfig
Normal file
6
u-boot/arch/arm/cpu/armv8/Kconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
if ARM64
|
||||
|
||||
config ARMV8_MULTIENTRY
|
||||
boolean "Enable multiple CPUs to enter into U-Boot"
|
||||
|
||||
endif
|
||||
22
u-boot/arch/arm/cpu/armv8/Makefile
Normal file
22
u-boot/arch/arm/cpu/armv8/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# (C) Copyright 2000-2003
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
extra-y := start.o
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += generic_timer.o
|
||||
obj-y += cache_v8.o
|
||||
obj-y += exceptions.o
|
||||
obj-y += cache.o
|
||||
obj-y += tlb.o
|
||||
obj-y += transition.o
|
||||
obj-y += fwcall.o
|
||||
|
||||
obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
|
||||
obj-$(CONFIG_S32V234) += s32v234/
|
||||
obj-$(CONFIG_ARCH_ZYNQMP) += zynqmp/
|
||||
obj-$(CONFIG_TARGET_HIKEY) += hisilicon/
|
||||
210
u-boot/arch/arm/cpu/armv8/cache.S
Normal file
210
u-boot/arch/arm/cpu/armv8/cache.S
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* This file is based on sample code from ARMv8 ARM.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#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
|
||||
*/
|
||||
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)
|
||||
|
||||
/*
|
||||
* void __asm_flush_dcache_all(int invalidate_only)
|
||||
*
|
||||
* x0: 0 clean & invalidate, 1 invalidate only
|
||||
*
|
||||
* flush or invalidate all data cache by SET/WAY.
|
||||
*/
|
||||
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)
|
||||
|
||||
ENTRY(__asm_flush_dcache_all)
|
||||
mov x0, #0
|
||||
b __asm_dcache_all
|
||||
ENDPROC(__asm_flush_dcache_all)
|
||||
|
||||
ENTRY(__asm_invalidate_dcache_all)
|
||||
mov x0, #0x1
|
||||
b __asm_dcache_all
|
||||
ENDPROC(__asm_invalidate_dcache_all)
|
||||
|
||||
/*
|
||||
* void __asm_flush_dcache_range(start, end)
|
||||
*
|
||||
* clean & invalidate data cache in the range
|
||||
*
|
||||
* x0: start address
|
||||
* x1: end address
|
||||
*/
|
||||
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)
|
||||
|
||||
/*
|
||||
* void __asm_invalidate_icache_all(void)
|
||||
*
|
||||
* invalidate all tlb entries.
|
||||
*/
|
||||
ENTRY(__asm_invalidate_icache_all)
|
||||
ic ialluis
|
||||
isb sy
|
||||
ret
|
||||
ENDPROC(__asm_invalidate_icache_all)
|
||||
|
||||
ENTRY(__asm_flush_l3_cache)
|
||||
mov x0, #0 /* return status as success */
|
||||
ret
|
||||
ENDPROC(__asm_flush_l3_cache)
|
||||
.weak __asm_flush_l3_cache
|
||||
|
||||
/*
|
||||
* void __asm_switch_ttbr(ulong new_ttbr)
|
||||
*
|
||||
* Safely switches to a new page table.
|
||||
*/
|
||||
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)
|
||||
658
u-boot/arch/arm/cpu/armv8/cache_v8.c
Normal file
658
u-boot/arch/arm/cpu/armv8/cache_v8.c
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* (C) Copyright 2016
|
||||
* Alexander Graf <agraf@suse.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_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
|
||||
*/
|
||||
|
||||
static 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].base + 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;
|
||||
}
|
||||
|
||||
/* Add one mm_region map entry to the page tables */
|
||||
static void add_map(struct mm_region *map)
|
||||
{
|
||||
u64 *pte;
|
||||
u64 addr = map->base;
|
||||
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(addr, 0);
|
||||
if (pte && (pte_type(pte) == PTE_TYPE_FAULT)) {
|
||||
debug("Creating table for addr 0x%llx\n", addr);
|
||||
new_table = create_table();
|
||||
set_pte_table(pte, new_table);
|
||||
}
|
||||
|
||||
for (level = 1; level < 4; level++) {
|
||||
pte = find_pte(addr, level);
|
||||
blocksize = 1ULL << level2shift(level);
|
||||
debug("Checking if pte fits for addr=%llx size=%llx "
|
||||
"blocksize=%llx\n", addr, size, blocksize);
|
||||
if (size >= blocksize && !(addr & (blocksize - 1))) {
|
||||
/* Page fits, create block PTE */
|
||||
debug("Setting PTE %p to block addr=%llx\n",
|
||||
pte, addr);
|
||||
*pte = addr | attrs;
|
||||
addr += blocksize;
|
||||
size -= blocksize;
|
||||
break;
|
||||
} else if ((pte_type(pte) == PTE_TYPE_FAULT)) {
|
||||
/* Page doesn't fit, create subpages */
|
||||
debug("Creating subtable for addr 0x%llx "
|
||||
"blksize=%llx\n", addr, blocksize);
|
||||
new_table = create_table();
|
||||
set_pte_table(pte, new_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);
|
||||
}
|
||||
|
||||
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->base;
|
||||
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;
|
||||
}
|
||||
|
||||
static void setup_pgtables(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* 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]);
|
||||
|
||||
/* Create the same thing once more for our emergency page table */
|
||||
create_table();
|
||||
}
|
||||
|
||||
static void setup_all_pgtables(void)
|
||||
{
|
||||
u64 tlb_addr = gd->arch.tlb_addr;
|
||||
|
||||
/* Reset the fill ptr */
|
||||
gd->arch.tlb_fillptr = tlb_addr;
|
||||
|
||||
/* Create normal system page tables */
|
||||
setup_pgtables();
|
||||
|
||||
/* Create emergency page tables */
|
||||
gd->arch.tlb_addr = gd->arch.tlb_fillptr;
|
||||
setup_pgtables();
|
||||
gd->arch.tlb_emerg = gd->arch.tlb_addr;
|
||||
gd->arch.tlb_addr = tlb_addr;
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_cache return status of timeout
|
||||
*/
|
||||
inline void flush_dcache_all(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm_flush_dcache_all();
|
||||
ret = __asm_flush_l3_cache();
|
||||
if (ret)
|
||||
debug("flushing dcache returns 0x%x\n", ret);
|
||||
else
|
||||
debug("flushing dcache successfully.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidates range in all levels of D-cache/unified cache
|
||||
*/
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
__asm_flush_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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static u64 set_one_region(u64 start, u64 size, u64 attrs, 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)) {
|
||||
*pte &= ~PMD_ATTRINDX_MASK;
|
||||
*pte |= attrs;
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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++) {
|
||||
r = set_one_region(start, size, attrs, 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);
|
||||
}
|
||||
|
||||
#else /* CONFIG_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_SYS_DCACHE_OFF */
|
||||
|
||||
#ifndef CONFIG_SYS_ICACHE_OFF
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
__asm_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();
|
||||
}
|
||||
|
||||
#else /* CONFIG_SYS_ICACHE_OFF */
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_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();
|
||||
}
|
||||
10
u-boot/arch/arm/cpu/armv8/config.mk
Normal file
10
u-boot/arch/arm/cpu/armv8/config.mk
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
PLATFORM_RELFLAGS += -fno-common -ffixed-x18
|
||||
|
||||
PF_NO_UNALIGNED := $(call cc-option, -mstrict-align)
|
||||
PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
|
||||
43
u-boot/arch/arm/cpu/armv8/cpu.c
Normal file
43
u-boot/arch/arm/cpu/armv8/cpu.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* (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>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
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;
|
||||
}
|
||||
146
u-boot/arch/arm/cpu/armv8/exceptions.S
Normal file
146
u-boot/arch/arm/cpu/armv8/exceptions.S
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/macro.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* Enter Exception.
|
||||
* This will save the processor state that is ELR/X0~X30
|
||||
* to the stack frame.
|
||||
*/
|
||||
.macro exception_entry
|
||||
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]!
|
||||
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]!
|
||||
|
||||
/* 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
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Exception vectors.
|
||||
*/
|
||||
.align 11
|
||||
.globl vectors
|
||||
vectors:
|
||||
.align 7
|
||||
b _do_bad_sync /* Current EL Synchronous Thread */
|
||||
|
||||
.align 7
|
||||
b _do_bad_irq /* Current EL IRQ Thread */
|
||||
|
||||
.align 7
|
||||
b _do_bad_fiq /* Current EL FIQ Thread */
|
||||
|
||||
.align 7
|
||||
b _do_bad_error /* Current EL Error Thread */
|
||||
|
||||
.align 7
|
||||
b _do_sync /* Current EL Synchronous Handler */
|
||||
|
||||
.align 7
|
||||
b _do_irq /* Current EL IRQ Handler */
|
||||
|
||||
.align 7
|
||||
b _do_fiq /* Current EL FIQ Handler */
|
||||
|
||||
.align 7
|
||||
b _do_error /* Current EL Error Handler */
|
||||
|
||||
|
||||
_do_bad_sync:
|
||||
exception_entry
|
||||
bl do_bad_sync
|
||||
b exception_exit
|
||||
|
||||
_do_bad_irq:
|
||||
exception_entry
|
||||
bl do_bad_irq
|
||||
b exception_exit
|
||||
|
||||
_do_bad_fiq:
|
||||
exception_entry
|
||||
bl do_bad_fiq
|
||||
b exception_exit
|
||||
|
||||
_do_bad_error:
|
||||
exception_entry
|
||||
bl do_bad_error
|
||||
b exception_exit
|
||||
|
||||
_do_sync:
|
||||
exception_entry
|
||||
bl do_sync
|
||||
b exception_exit
|
||||
|
||||
_do_irq:
|
||||
exception_entry
|
||||
bl do_irq
|
||||
b exception_exit
|
||||
|
||||
_do_fiq:
|
||||
exception_entry
|
||||
bl do_fiq
|
||||
b exception_exit
|
||||
|
||||
_do_error:
|
||||
exception_entry
|
||||
bl do_error
|
||||
b exception_exit
|
||||
|
||||
exception_exit:
|
||||
ldp x2, x0, [sp],#16
|
||||
switch_el x11, 3f, 2f, 1f
|
||||
3: msr elr_el3, x2
|
||||
b 0f
|
||||
2: msr elr_el2, x2
|
||||
b 0f
|
||||
1: msr elr_el1, x2
|
||||
0:
|
||||
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
|
||||
34
u-boot/arch/arm/cpu/armv8/fsl-layerscape/Makefile
Normal file
34
u-boot/arch/arm/cpu/armv8/fsl-layerscape/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright 2014-2015, Freescale Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += lowlevel.o
|
||||
obj-y += soc.o
|
||||
obj-$(CONFIG_MP) += mp.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += fdt.o
|
||||
obj-$(CONFIG_SPL) += spl.o
|
||||
|
||||
ifneq ($(CONFIG_FSL_LSCH3),)
|
||||
obj-y += fsl_lsch3_speed.o
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch3_serdes.o
|
||||
else
|
||||
ifneq ($(CONFIG_FSL_LSCH2),)
|
||||
obj-y += fsl_lsch2_speed.o
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch2_serdes.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_LS2080A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls2080a_serdes.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_LS1043A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1043a_serdes.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_LS1012A),)
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += ls1012a_serdes.o
|
||||
endif
|
||||
710
u-boot/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
Normal file
710
u-boot/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/soc.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/speed.h>
|
||||
#ifdef CONFIG_MP
|
||||
#include <asm/arch/mp.h>
|
||||
#endif
|
||||
#include <fm_eth.h>
|
||||
#include <fsl_debug_server.h>
|
||||
#include <fsl-mc/fsl_mc.h>
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
#include <fsl_esdhc.h>
|
||||
#endif
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct mm_region layerscape_mem_map[] = {
|
||||
{
|
||||
/* List terminator */
|
||||
0,
|
||||
}
|
||||
};
|
||||
struct mm_region *mem_map = layerscape_mem_map;
|
||||
|
||||
void cpu_name(char *name)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int i, svr, ver;
|
||||
|
||||
svr = gur_in32(&gur->svr);
|
||||
ver = SVR_SOC_VER(svr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++)
|
||||
if ((cpu_type_list[i].soc_ver & SVR_WO_E) == ver) {
|
||||
strcpy(name, cpu_type_list[i].name);
|
||||
|
||||
if (IS_E_PROCESSOR(svr))
|
||||
strcat(name, "E");
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(cpu_type_list))
|
||||
strcpy(name, "unknown");
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
static void set_pgtable_section(u64 *page_table, u64 index, u64 section,
|
||||
u64 memory_type, u64 attribute)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
value = section | PTE_TYPE_BLOCK | PTE_BLOCK_AF;
|
||||
value |= PMD_ATTRINDX(memory_type);
|
||||
value |= attribute;
|
||||
page_table[index] = value;
|
||||
}
|
||||
|
||||
static void set_pgtable_table(u64 *page_table, u64 index, u64 *table_addr)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
value = (u64)table_addr | PTE_TYPE_TABLE;
|
||||
page_table[index] = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the block entries according to the information of the table.
|
||||
*/
|
||||
static int set_block_entry(const struct sys_mmu_table *list,
|
||||
struct table_info *table)
|
||||
{
|
||||
u64 block_size = 0, block_shift = 0;
|
||||
u64 block_addr, index;
|
||||
int j;
|
||||
|
||||
if (table->entry_size == BLOCK_SIZE_L1) {
|
||||
block_size = BLOCK_SIZE_L1;
|
||||
block_shift = SECTION_SHIFT_L1;
|
||||
} else if (table->entry_size == BLOCK_SIZE_L2) {
|
||||
block_size = BLOCK_SIZE_L2;
|
||||
block_shift = SECTION_SHIFT_L2;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
block_addr = list->phys_addr;
|
||||
index = (list->virt_addr - table->table_base) >> block_shift;
|
||||
|
||||
for (j = 0; j < (list->size >> block_shift); j++) {
|
||||
set_pgtable_section(table->ptr,
|
||||
index,
|
||||
block_addr,
|
||||
list->memory_type,
|
||||
list->attribute);
|
||||
block_addr += block_size;
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the corresponding table entry for the list.
|
||||
*/
|
||||
static int find_table(const struct sys_mmu_table *list,
|
||||
struct table_info *table, u64 *level0_table)
|
||||
{
|
||||
u64 index = 0, level = 0;
|
||||
u64 *level_table = level0_table;
|
||||
u64 temp_base = 0, block_size = 0, block_shift = 0;
|
||||
|
||||
while (level < 3) {
|
||||
if (level == 0) {
|
||||
block_size = BLOCK_SIZE_L0;
|
||||
block_shift = SECTION_SHIFT_L0;
|
||||
} else if (level == 1) {
|
||||
block_size = BLOCK_SIZE_L1;
|
||||
block_shift = SECTION_SHIFT_L1;
|
||||
} else if (level == 2) {
|
||||
block_size = BLOCK_SIZE_L2;
|
||||
block_shift = SECTION_SHIFT_L2;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
while (list->virt_addr >= temp_base) {
|
||||
index++;
|
||||
temp_base += block_size;
|
||||
}
|
||||
|
||||
temp_base -= block_size;
|
||||
|
||||
if ((level_table[index - 1] & PTE_TYPE_MASK) ==
|
||||
PTE_TYPE_TABLE) {
|
||||
level_table = (u64 *)(level_table[index - 1] &
|
||||
~PTE_TYPE_MASK);
|
||||
level++;
|
||||
continue;
|
||||
} else {
|
||||
if (level == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((list->phys_addr + list->size) >
|
||||
(temp_base + block_size * NUM_OF_ENTRY))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Check the address and size of the list member is
|
||||
* aligned with the block size.
|
||||
*/
|
||||
if (((list->phys_addr & (block_size - 1)) != 0) ||
|
||||
((list->size & (block_size - 1)) != 0))
|
||||
return -EINVAL;
|
||||
|
||||
table->ptr = level_table;
|
||||
table->table_base = temp_base -
|
||||
((index - 1) << block_shift);
|
||||
table->entry_size = block_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* To start MMU before DDR is available, we create MMU table in SRAM.
|
||||
* The base address of SRAM is CONFIG_SYS_FSL_OCRAM_BASE. We use three
|
||||
* levels of translation tables here to cover 40-bit address space.
|
||||
* We use 4KB granule size, with 40 bits physical address, T0SZ=24
|
||||
* Level 0 IA[39], table address @0
|
||||
* Level 1 IA[38:30], table address @0x1000, 0x2000
|
||||
* Level 2 IA[29:21], table address @0x3000, 0x4000
|
||||
* Address above 0x5000 is free for other purpose.
|
||||
*/
|
||||
static inline void early_mmu_setup(void)
|
||||
{
|
||||
unsigned int el, i;
|
||||
u64 *level0_table = (u64 *)CONFIG_SYS_FSL_OCRAM_BASE;
|
||||
u64 *level1_table0 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x1000);
|
||||
u64 *level1_table1 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x2000);
|
||||
u64 *level2_table0 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x3000);
|
||||
u64 *level2_table1 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x4000);
|
||||
|
||||
struct table_info table = {level0_table, 0, BLOCK_SIZE_L0};
|
||||
|
||||
/* Invalidate all table entries */
|
||||
memset(level0_table, 0, 0x5000);
|
||||
|
||||
/* Fill in the table entries */
|
||||
set_pgtable_table(level0_table, 0, level1_table0);
|
||||
set_pgtable_table(level0_table, 1, level1_table1);
|
||||
set_pgtable_table(level1_table0, 0, level2_table0);
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
set_pgtable_table(level1_table0,
|
||||
CONFIG_SYS_FLASH_BASE >> SECTION_SHIFT_L1,
|
||||
level2_table1);
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
set_pgtable_table(level1_table0, 1, level2_table1);
|
||||
#endif
|
||||
/* Find the table and fill in the block entries */
|
||||
for (i = 0; i < ARRAY_SIZE(early_mmu_table); i++) {
|
||||
if (find_table(&early_mmu_table[i],
|
||||
&table, level0_table) == 0) {
|
||||
/*
|
||||
* If find_table() returns error, it cannot be dealt
|
||||
* with here. Breakpoint can be added for debugging.
|
||||
*/
|
||||
set_block_entry(&early_mmu_table[i], &table);
|
||||
/*
|
||||
* If set_block_entry() returns error, it cannot be
|
||||
* dealt with here too.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
el = current_el();
|
||||
|
||||
set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR,
|
||||
MEMORY_ATTRIBUTES);
|
||||
set_sctlr(get_sctlr() | CR_M);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
|
||||
/*
|
||||
* Called from final mmu setup. The phys_addr is new, non-existing
|
||||
* address. A new sub table is created @level2_table_secure to cover
|
||||
* size of CONFIG_SYS_MEM_RESERVE_SECURE memory.
|
||||
*/
|
||||
static inline int final_secure_ddr(u64 *level0_table,
|
||||
u64 *level2_table_secure,
|
||||
phys_addr_t phys_addr)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct table_info table = {};
|
||||
struct sys_mmu_table ddr_entry = {
|
||||
0, 0, BLOCK_SIZE_L1, MT_NORMAL,
|
||||
PTE_BLOCK_OUTER_SHARE | PTE_BLOCK_NS
|
||||
};
|
||||
u64 index;
|
||||
|
||||
/* Need to create a new table */
|
||||
ddr_entry.virt_addr = phys_addr & ~(BLOCK_SIZE_L1 - 1);
|
||||
ddr_entry.phys_addr = phys_addr & ~(BLOCK_SIZE_L1 - 1);
|
||||
ret = find_table(&ddr_entry, &table, level0_table);
|
||||
if (ret)
|
||||
return ret;
|
||||
index = (ddr_entry.virt_addr - table.table_base) >> SECTION_SHIFT_L1;
|
||||
set_pgtable_table(table.ptr, index, level2_table_secure);
|
||||
table.ptr = level2_table_secure;
|
||||
table.table_base = ddr_entry.virt_addr;
|
||||
table.entry_size = BLOCK_SIZE_L2;
|
||||
ret = set_block_entry(&ddr_entry, &table);
|
||||
if (ret) {
|
||||
printf("MMU error: could not fill non-secure ddr block entries\n");
|
||||
return ret;
|
||||
}
|
||||
ddr_entry.virt_addr = phys_addr;
|
||||
ddr_entry.phys_addr = phys_addr;
|
||||
ddr_entry.size = CONFIG_SYS_MEM_RESERVE_SECURE;
|
||||
ddr_entry.attribute = PTE_BLOCK_OUTER_SHARE;
|
||||
ret = find_table(&ddr_entry, &table, level0_table);
|
||||
if (ret) {
|
||||
printf("MMU error: could not find secure ddr table\n");
|
||||
return ret;
|
||||
}
|
||||
ret = set_block_entry(&ddr_entry, &table);
|
||||
if (ret)
|
||||
printf("MMU error: could not set secure ddr block entry\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The final tables look similar to early tables, but different in detail.
|
||||
* These tables are in DRAM. Sub tables are added to enable cache for
|
||||
* QBMan and OCRAM.
|
||||
*
|
||||
* Put the MMU table in secure memory if gd->secure_ram is valid.
|
||||
* OCRAM will be not used for this purpose so gd->secure_ram can't be 0.
|
||||
*
|
||||
* Level 1 table 0 contains 512 entries for each 1GB from 0 to 512GB.
|
||||
* Level 1 table 1 contains 512 entries for each 1GB from 512GB to 1TB.
|
||||
* Level 2 table 0 contains 512 entries for each 2MB from 0 to 1GB.
|
||||
*
|
||||
* For LSCH3:
|
||||
* Level 2 table 1 contains 512 entries for each 2MB from 32GB to 33GB.
|
||||
* For LSCH2:
|
||||
* Level 2 table 1 contains 512 entries for each 2MB from 1GB to 2GB.
|
||||
* Level 2 table 2 contains 512 entries for each 2MB from 20GB to 21GB.
|
||||
*/
|
||||
static inline void final_mmu_setup(void)
|
||||
{
|
||||
unsigned int el = current_el();
|
||||
unsigned int i;
|
||||
u64 *level0_table = (u64 *)gd->arch.tlb_addr;
|
||||
u64 *level1_table0;
|
||||
u64 *level1_table1;
|
||||
u64 *level2_table0;
|
||||
u64 *level2_table1;
|
||||
#ifdef CONFIG_FSL_LSCH2
|
||||
u64 *level2_table2;
|
||||
#endif
|
||||
struct table_info table = {NULL, 0, BLOCK_SIZE_L0};
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
|
||||
u64 *level2_table_secure;
|
||||
|
||||
if (el == 3) {
|
||||
/*
|
||||
* Only use gd->secure_ram if the address is recalculated
|
||||
* Align to 4KB for MMU table
|
||||
*/
|
||||
if (gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED)
|
||||
level0_table = (u64 *)(gd->secure_ram & ~0xfff);
|
||||
else
|
||||
printf("MMU warning: gd->secure_ram is not maintained, disabled.\n");
|
||||
}
|
||||
#endif
|
||||
level1_table0 = level0_table + 512;
|
||||
level1_table1 = level1_table0 + 512;
|
||||
level2_table0 = level1_table1 + 512;
|
||||
level2_table1 = level2_table0 + 512;
|
||||
#ifdef CONFIG_FSL_LSCH2
|
||||
level2_table2 = level2_table1 + 512;
|
||||
#endif
|
||||
table.ptr = level0_table;
|
||||
|
||||
/* Invalidate all table entries */
|
||||
memset(level0_table, 0, PGTABLE_SIZE);
|
||||
|
||||
/* Fill in the table entries */
|
||||
set_pgtable_table(level0_table, 0, level1_table0);
|
||||
set_pgtable_table(level0_table, 1, level1_table1);
|
||||
set_pgtable_table(level1_table0, 0, level2_table0);
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
set_pgtable_table(level1_table0,
|
||||
CONFIG_SYS_FSL_QBMAN_BASE >> SECTION_SHIFT_L1,
|
||||
level2_table1);
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
set_pgtable_table(level1_table0, 1, level2_table1);
|
||||
set_pgtable_table(level1_table0,
|
||||
CONFIG_SYS_FSL_QBMAN_BASE >> SECTION_SHIFT_L1,
|
||||
level2_table2);
|
||||
#endif
|
||||
|
||||
/* Find the table and fill in the block entries */
|
||||
for (i = 0; i < ARRAY_SIZE(final_mmu_table); i++) {
|
||||
if (find_table(&final_mmu_table[i],
|
||||
&table, level0_table) == 0) {
|
||||
if (set_block_entry(&final_mmu_table[i],
|
||||
&table) != 0) {
|
||||
printf("MMU error: could not set block entry for %p\n",
|
||||
&final_mmu_table[i]);
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("MMU error: could not find the table for %p\n",
|
||||
&final_mmu_table[i]);
|
||||
}
|
||||
}
|
||||
/* Set the secure memory to secure in MMU */
|
||||
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
|
||||
if (el == 3 && gd->secure_ram & MEM_RESERVE_SECURE_MAINTAINED) {
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
level2_table_secure = level2_table1 + 512;
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
level2_table_secure = level2_table2 + 512;
|
||||
#endif
|
||||
if (!final_secure_ddr(level0_table,
|
||||
level2_table_secure,
|
||||
gd->secure_ram & ~0x3)) {
|
||||
gd->secure_ram |= MEM_RESERVE_SECURE_SECURED;
|
||||
debug("Now MMU table is in secured memory at 0x%llx\n",
|
||||
gd->secure_ram & ~0x3);
|
||||
} else {
|
||||
printf("MMU warning: Failed to secure DDR\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* flush new MMU table */
|
||||
flush_dcache_range((ulong)level0_table,
|
||||
(ulong)level0_table + gd->arch.tlb_size);
|
||||
|
||||
/* point TTBR to the new table */
|
||||
set_ttbr_tcr_mair(el, (u64)level0_table, LAYERSCAPE_TCR_FINAL,
|
||||
MEMORY_ATTRIBUTES);
|
||||
/*
|
||||
* MMU is already enabled, just need to invalidate TLB to load the
|
||||
* new table. The new table is compatible with the current table, if
|
||||
* MMU somehow walks through the new table before invalidation TLB,
|
||||
* it still works. So we don't need to turn off MMU here.
|
||||
*/
|
||||
}
|
||||
|
||||
u64 get_page_table_size(void)
|
||||
{
|
||||
return 0x10000;
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
icache_enable();
|
||||
__asm_invalidate_dcache_all();
|
||||
__asm_invalidate_tlb_all();
|
||||
early_mmu_setup();
|
||||
set_sctlr(get_sctlr() | CR_C);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from lib/board.c.
|
||||
* It recreates MMU table in main memory. MMU and d-cache are enabled earlier.
|
||||
* There is no need to disable d-cache for this operation.
|
||||
*/
|
||||
void enable_caches(void)
|
||||
{
|
||||
final_mmu_setup();
|
||||
__asm_invalidate_tlb_all();
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline u32 initiator_type(u32 cluster, int init_id)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 idx = (cluster >> (init_id * 8)) & TP_CLUSTER_INIT_MASK;
|
||||
u32 type = 0;
|
||||
|
||||
type = gur_in32(&gur->tp_ityp[idx]);
|
||||
if (type & TP_ITYP_AV)
|
||||
return type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 cpu_mask(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
int i = 0, count = 0;
|
||||
u32 cluster, type, mask = 0;
|
||||
|
||||
do {
|
||||
int j;
|
||||
|
||||
cluster = gur_in32(&gur->tp_cluster[i].lower);
|
||||
for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
|
||||
type = initiator_type(cluster, j);
|
||||
if (type) {
|
||||
if (TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
|
||||
mask |= 1 << count;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while ((cluster & TP_CLUSTER_EOC) == 0x0);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of cores on this SOC.
|
||||
*/
|
||||
int cpu_numcores(void)
|
||||
{
|
||||
return hweight32(cpu_mask());
|
||||
}
|
||||
|
||||
int fsl_qoriq_core_to_cluster(unsigned int core)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur =
|
||||
(void __iomem *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
int i = 0, count = 0;
|
||||
u32 cluster;
|
||||
|
||||
do {
|
||||
int j;
|
||||
|
||||
cluster = gur_in32(&gur->tp_cluster[i].lower);
|
||||
for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
|
||||
if (initiator_type(cluster, j)) {
|
||||
if (count == core)
|
||||
return i;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while ((cluster & TP_CLUSTER_EOC) == 0x0);
|
||||
|
||||
return -1; /* cannot identify the cluster */
|
||||
}
|
||||
|
||||
u32 fsl_qoriq_core_to_type(unsigned int core)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur =
|
||||
(void __iomem *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
int i = 0, count = 0;
|
||||
u32 cluster, type;
|
||||
|
||||
do {
|
||||
int j;
|
||||
|
||||
cluster = gur_in32(&gur->tp_cluster[i].lower);
|
||||
for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
|
||||
type = initiator_type(cluster, j);
|
||||
if (type) {
|
||||
if (count == core)
|
||||
return type;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while ((cluster & TP_CLUSTER_EOC) == 0x0);
|
||||
|
||||
return -1; /* cannot identify the cluster */
|
||||
}
|
||||
|
||||
uint get_svr(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
|
||||
return gur_in32(&gur->svr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DISPLAY_CPUINFO
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
struct sys_info sysinfo;
|
||||
char buf[32];
|
||||
unsigned int i, core;
|
||||
u32 type, rcw, svr = gur_in32(&gur->svr);
|
||||
|
||||
puts("SoC: ");
|
||||
|
||||
cpu_name(buf);
|
||||
printf(" %s (0x%x)\n", buf, svr);
|
||||
memset((u8 *)buf, 0x00, ARRAY_SIZE(buf));
|
||||
get_sys_info(&sysinfo);
|
||||
puts("Clock Configuration:");
|
||||
for_each_cpu(i, core, cpu_numcores(), cpu_mask()) {
|
||||
if (!(i % 3))
|
||||
puts("\n ");
|
||||
type = TP_ITYP_VER(fsl_qoriq_core_to_type(core));
|
||||
printf("CPU%d(%s):%-4s MHz ", core,
|
||||
type == TY_ITYP_VER_A7 ? "A7 " :
|
||||
(type == TY_ITYP_VER_A53 ? "A53" :
|
||||
(type == TY_ITYP_VER_A57 ? "A57" : " ")),
|
||||
strmhz(buf, sysinfo.freq_processor[core]));
|
||||
}
|
||||
printf("\n Bus: %-4s MHz ",
|
||||
strmhz(buf, sysinfo.freq_systembus));
|
||||
printf("DDR: %-4s MT/s", strmhz(buf, sysinfo.freq_ddrbus));
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
printf(" FMAN: %-4s MHz", strmhz(buf, sysinfo.freq_fman[0]));
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
if (soc_has_dp_ddr()) {
|
||||
printf(" DP-DDR: %-4s MT/s",
|
||||
strmhz(buf, sysinfo.freq_ddrbus2));
|
||||
}
|
||||
#endif
|
||||
puts("\n");
|
||||
|
||||
/*
|
||||
* Display the RCW, so that no one gets confused as to what RCW
|
||||
* we're actually using for this boot.
|
||||
*/
|
||||
puts("Reset Configuration Word (RCW):");
|
||||
for (i = 0; i < ARRAY_SIZE(gur->rcwsr); i++) {
|
||||
rcw = gur_in32(&gur->rcwsr[i]);
|
||||
if ((i % 4) == 0)
|
||||
printf("\n %08x:", i * 4);
|
||||
printf(" %08x", rcw);
|
||||
}
|
||||
puts("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return fsl_esdhc_mmc_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpu_eth_init(bd_t *bis)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
#ifdef CONFIG_FSL_MC_ENET
|
||||
error = fsl_mc_ldpaa_init(bis);
|
||||
#endif
|
||||
#ifdef CONFIG_FMAN_ENET
|
||||
fm_standard_init(bis);
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
int arch_early_init_r(void)
|
||||
{
|
||||
#ifdef CONFIG_MP
|
||||
int rv = 1;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A009635
|
||||
erratum_a009635();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MP
|
||||
rv = fsl_layerscape_wake_seconday_cores();
|
||||
if (rv)
|
||||
printf("Did not wake secondary cores\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_HAS_SERDES
|
||||
fsl_serdes_init();
|
||||
#endif
|
||||
#ifdef CONFIG_FMAN_ENET
|
||||
fman_enet_init();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR;
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR;
|
||||
#endif
|
||||
#ifdef CONFIG_LS2080A
|
||||
u32 __iomem *pctbenr = (u32 *)FSL_PMU_PCTBENR_OFFSET;
|
||||
#endif
|
||||
#ifdef COUNTER_FREQUENCY_REAL
|
||||
unsigned long cntfrq = COUNTER_FREQUENCY_REAL;
|
||||
|
||||
/* Update with accurate clock frequency */
|
||||
asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
/* Enable timebase for all clusters.
|
||||
* It is safe to do so even some clusters are not enabled.
|
||||
*/
|
||||
out_le32(cltbenr, 0xf);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LS2080A
|
||||
/*
|
||||
* In certain Layerscape SoCs, the clock for each core's
|
||||
* has an enable bit in the PMU Physical Core Time Base Enable
|
||||
* Register (PCTBENR), which allows the watchdog to operate.
|
||||
*/
|
||||
setbits_le32(pctbenr, 0xff);
|
||||
#endif
|
||||
|
||||
/* Enable clock for timer
|
||||
* This is a global setting.
|
||||
*/
|
||||
out_le32(cntcr, 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset_cpu(ulong addr)
|
||||
{
|
||||
u32 __iomem *rstcr = (u32 *)CONFIG_SYS_FSL_RST_ADDR;
|
||||
u32 val;
|
||||
|
||||
/* Raise RESET_REQ_B */
|
||||
val = scfg_in32(rstcr);
|
||||
val |= 0x02;
|
||||
scfg_out32(rstcr, val);
|
||||
}
|
||||
|
||||
phys_size_t board_reserve_ram_top(phys_size_t ram_size)
|
||||
{
|
||||
phys_size_t ram_top = ram_size;
|
||||
|
||||
#ifdef CONFIG_SYS_MEM_TOP_HIDE
|
||||
#error CONFIG_SYS_MEM_TOP_HIDE not to be used together with this function
|
||||
#endif
|
||||
/* Carve the Debug Server private DRAM block from the end of DRAM */
|
||||
#ifdef CONFIG_FSL_DEBUG_SERVER
|
||||
ram_top -= debug_server_get_dram_block_size();
|
||||
#endif
|
||||
|
||||
/* Carve the MC private DRAM block from the end of DRAM */
|
||||
#ifdef CONFIG_FSL_MC_ENET
|
||||
ram_top -= mc_get_dram_block_size();
|
||||
ram_top &= ~(CONFIG_SYS_MC_RSV_MEM_ALIGN - 1);
|
||||
#endif
|
||||
|
||||
return ram_top;
|
||||
}
|
||||
8
u-boot/arch/arm/cpu/armv8/fsl-layerscape/cpu.h
Normal file
8
u-boot/arch/arm/cpu/armv8/fsl-layerscape/cpu.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright 2014-2015, Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
int fsl_qoriq_core_to_cluster(unsigned int core);
|
||||
u32 cpu_mask(void);
|
||||
10
u-boot/arch/arm/cpu/armv8/fsl-layerscape/doc/README.lsch2
Normal file
10
u-boot/arch/arm/cpu/armv8/fsl-layerscape/doc/README.lsch2
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2015 Freescale Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
Freescale LayerScape with Chassis Generation 2
|
||||
|
||||
This architecture supports Freescale ARMv8 SoCs with Chassis generation 2,
|
||||
for example LS1043A.
|
||||
354
u-boot/arch/arm/cpu/armv8/fsl-layerscape/doc/README.lsch3
Normal file
354
u-boot/arch/arm/cpu/armv8/fsl-layerscape/doc/README.lsch3
Normal file
@@ -0,0 +1,354 @@
|
||||
#
|
||||
# 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. 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 varible 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 QDS which uses
|
||||
NAND device with 2KB/page, block size 128KB.
|
||||
|
||||
1) CCSR 4-byte write to 0x00e00404, data=0x00000000
|
||||
2) CCSR 4-byte write to 0x00e00400, data=0x1800a000
|
||||
The above two commands set bootloc register to 0x00000000_1800a000 where
|
||||
the u-boot code will be running in OCRAM.
|
||||
|
||||
3) Block Copy: SRC=0x0107, SRC_ADDR=0x00020000, DEST_ADDR=0x1800a000,
|
||||
BLOCK_SIZE=0x00014000
|
||||
This command copies u-boot image from NAND device into OCRAM. The values need
|
||||
to adjust accordingly.
|
||||
|
||||
SRC should match the cfg_rcw_src, the reset config pins. It depends
|
||||
on the NAND device. See reference manual for cfg_rcw_src.
|
||||
SRC_ADDR is the offset of u-boot-with-spl.bin image in NAND device. In
|
||||
the example above, 128KB. For easy maintenance, we put it at
|
||||
the beginning of next block from RCW.
|
||||
DEST_ADDR is fixed at 0x1800a000, matching bootloc set above.
|
||||
BLOCK_SIZE is the size to be copied by PBI.
|
||||
|
||||
RCW image should be written to the beginning of NAND device. Example of using
|
||||
u-boot command
|
||||
|
||||
nand write <rcw image in memory> 0 <size of rcw image>
|
||||
|
||||
To form the NAND image, build u-boot with NAND config, for example,
|
||||
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 RDB boards,
|
||||
|
||||
1) CCSR 4-byte write to 0x00e00404, data=0x00000000
|
||||
2) CCSR 4-byte write to 0x00e00400, data=0x1800a000
|
||||
3) Block Copy: SRC=0x0119, SRC_ADDR=0x00080000, DEST_ADDR=0x1800a000,
|
||||
BLOCK_SIZE=0x00014000
|
||||
|
||||
nand write <rcw image in memory> 0 <size of rcw image>
|
||||
nand write <u-boot image in memory> 80000 <size of u-boot image>
|
||||
|
||||
Notice the difference from QDS is SRC, SRC_ADDR and the offset of u-boot image
|
||||
to match board NAND device with 4KB/page, block size 512KB.
|
||||
|
||||
MMU Translation Tables
|
||||
======================
|
||||
|
||||
(1) Early MMU Tables:
|
||||
|
||||
Level 0 Level 1 Level 2
|
||||
------------------ ------------------ ------------------
|
||||
| 0x00_0000_0000 | -----> | 0x00_0000_0000 | -----> | 0x00_0000_0000 |
|
||||
------------------ ------------------ ------------------
|
||||
| 0x80_0000_0000 | --| | 0x00_4000_0000 | | 0x00_0020_0000 |
|
||||
------------------ | ------------------ ------------------
|
||||
| invalid | | | 0x00_8000_0000 | | 0x00_0040_0000 |
|
||||
------------------ | ------------------ ------------------
|
||||
| | 0x00_c000_0000 | | 0x00_0060_0000 |
|
||||
| ------------------ ------------------
|
||||
| | 0x01_0000_0000 | | 0x00_0080_0000 |
|
||||
| ------------------ ------------------
|
||||
| ... ...
|
||||
| ------------------
|
||||
| | 0x05_8000_0000 | --|
|
||||
| ------------------ |
|
||||
| | 0x05_c000_0000 | |
|
||||
| ------------------ |
|
||||
| ... |
|
||||
| ------------------ | ------------------
|
||||
|--> | 0x80_0000_0000 | |-> | 0x00_3000_0000 |
|
||||
------------------ ------------------
|
||||
| 0x80_4000_0000 | | 0x00_3020_0000 |
|
||||
------------------ ------------------
|
||||
| 0x80_8000_0000 | | 0x00_3040_0000 |
|
||||
------------------ ------------------
|
||||
| 0x80_c000_0000 | | 0x00_3060_0000 |
|
||||
------------------ ------------------
|
||||
| 0x81_0000_0000 | | 0x00_3080_0000 |
|
||||
------------------ ------------------
|
||||
... ...
|
||||
|
||||
(2) Final MMU Tables:
|
||||
|
||||
Level 0 Level 1 Level 2
|
||||
------------------ ------------------ ------------------
|
||||
| 0x00_0000_0000 | -----> | 0x00_0000_0000 | -----> | 0x00_0000_0000 |
|
||||
------------------ ------------------ ------------------
|
||||
| 0x80_0000_0000 | --| | 0x00_4000_0000 | | 0x00_0020_0000 |
|
||||
------------------ | ------------------ ------------------
|
||||
| invalid | | | 0x00_8000_0000 | | 0x00_0040_0000 |
|
||||
------------------ | ------------------ ------------------
|
||||
| | 0x00_c000_0000 | | 0x00_0060_0000 |
|
||||
| ------------------ ------------------
|
||||
| | 0x01_0000_0000 | | 0x00_0080_0000 |
|
||||
| ------------------ ------------------
|
||||
| ... ...
|
||||
| ------------------
|
||||
| | 0x08_0000_0000 | --|
|
||||
| ------------------ |
|
||||
| | 0x08_4000_0000 | |
|
||||
| ------------------ |
|
||||
| ... |
|
||||
| ------------------ | ------------------
|
||||
|--> | 0x80_0000_0000 | |--> | 0x08_0000_0000 |
|
||||
------------------ ------------------
|
||||
| 0x80_4000_0000 | | 0x08_0020_0000 |
|
||||
------------------ ------------------
|
||||
| 0x80_8000_0000 | | 0x08_0040_0000 |
|
||||
------------------ ------------------
|
||||
| 0x80_c000_0000 | | 0x08_0060_0000 |
|
||||
------------------ ------------------
|
||||
| 0x81_0000_0000 | | 0x08_0080_0000 |
|
||||
------------------ ------------------
|
||||
... ...
|
||||
|
||||
|
||||
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
|
||||
129
u-boot/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
Normal file
129
u-boot/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
Normal file
@@ -0,0 +1,129 @@
|
||||
SoC overview
|
||||
|
||||
1. LS1043A
|
||||
2. LS2080A
|
||||
3. LS1012A
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
120
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
Normal file
120
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
#include <phy.h>
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
#include <asm/arch/fdt.h>
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
#include <fsl_esdhc.h>
|
||||
#endif
|
||||
#ifdef CONFIG_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>
|
||||
|
||||
int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc)
|
||||
{
|
||||
return fdt_setprop_string(blob, offset, "phy-connection-type",
|
||||
phy_string_for_interface(phyc));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MP
|
||||
void ft_fixup_cpu(void *blob)
|
||||
{
|
||||
int off;
|
||||
__maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr();
|
||||
fdt32_t *reg;
|
||||
int addr_cells;
|
||||
u64 val, core_id;
|
||||
size_t *boot_code_size = &(__secondary_boot_code_size);
|
||||
|
||||
off = fdt_path_offset(blob, "/cpus");
|
||||
if (off < 0) {
|
||||
puts("couldn't find /cpus node\n");
|
||||
return;
|
||||
}
|
||||
of_bus_default_count_cells(blob, off, &addr_cells, NULL);
|
||||
|
||||
off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
|
||||
while (off != -FDT_ERR_NOTFOUND) {
|
||||
reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
|
||||
if (reg) {
|
||||
core_id = of_read_number(reg, addr_cells);
|
||||
if (core_id == 0 || (is_core_online(core_id))) {
|
||||
val = spin_tbl_addr;
|
||||
val += id_to_core(core_id) *
|
||||
SPIN_TABLE_ELEM_SIZE;
|
||||
val = cpu_to_fdt64(val);
|
||||
fdt_setprop_string(blob, off, "enable-method",
|
||||
"spin-table");
|
||||
fdt_setprop(blob, off, "cpu-release-addr",
|
||||
&val, sizeof(val));
|
||||
} else {
|
||||
debug("skipping offline core\n");
|
||||
}
|
||||
} else {
|
||||
puts("Warning: found cpu node without reg property\n");
|
||||
}
|
||||
off = fdt_node_offset_by_prop_value(blob, off, "device_type",
|
||||
"cpu", 4);
|
||||
}
|
||||
|
||||
fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
|
||||
*boot_code_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ft_cpu_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
#ifdef CONFIG_FSL_LSCH2
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int svr = in_be32(&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;
|
||||
|
||||
sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
fdt_fixup_crypto_node(blob, sec_in32(&sec->secvid_ms));
|
||||
}
|
||||
#endif
|
||||
#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_compat_u32(blob, "fixed-clock",
|
||||
"clock-frequency", CONFIG_SYS_CLK_FREQ, 1);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
ft_pci_setup(blob, bd);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
fdt_fixup_esdhc(blob, bd);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
fdt_fixup_fman_firmware(blob);
|
||||
#endif
|
||||
}
|
||||
117
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
Normal file
117
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/soc.h>
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT];
|
||||
#endif
|
||||
|
||||
int is_serdes_configured(enum srds_prtcl device)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
ret |= serdes1_prtcl_map[device];
|
||||
#endif
|
||||
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 cfg = gur_in32(&gur->rcwsr[4]);
|
||||
int i;
|
||||
|
||||
switch (sd) {
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
case FSL_SRDS_1:
|
||||
cfg &= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("invalid SerDes%d\n", sd);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Is serdes enabled at all? */
|
||||
if (unlikely(cfg == 0))
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
||||
if (serdes_get_prtcl(sd, cfg, i) == device)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int get_serdes_protocol(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 cfg = gur_in32(&gur->rcwsr[4]) &
|
||||
FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
const char *serdes_clock_to_string(u32 clock)
|
||||
{
|
||||
switch (clock) {
|
||||
case SRDS_PLLCR0_RFCK_SEL_100:
|
||||
return "100";
|
||||
case SRDS_PLLCR0_RFCK_SEL_125:
|
||||
return "125";
|
||||
case SRDS_PLLCR0_RFCK_SEL_156_25:
|
||||
return "156.25";
|
||||
default:
|
||||
return "100";
|
||||
}
|
||||
}
|
||||
|
||||
void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
|
||||
u8 serdes_prtcl_map[SERDES_PRCTL_COUNT])
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 cfg;
|
||||
int lane;
|
||||
|
||||
memset(serdes_prtcl_map, 0, sizeof(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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
200
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c
Normal file
200
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/soc.h>
|
||||
#include <fsl_ifc.h>
|
||||
#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);
|
||||
#ifdef CONFIG_FSL_IFC
|
||||
struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL};
|
||||
u32 ccr;
|
||||
#endif
|
||||
#if (defined(CONFIG_FSL_ESDHC) &&\
|
||||
defined(CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK)) ||\
|
||||
defined(CONFIG_SYS_DPAA_FMAN)
|
||||
|
||||
u32 rcw_tmp;
|
||||
#endif
|
||||
struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_CLK_ADDR);
|
||||
unsigned int cpu;
|
||||
const u8 core_cplx_pll[8] = {
|
||||
[0] = 0, /* CC1 PPL / 1 */
|
||||
[1] = 0, /* CC1 PPL / 2 */
|
||||
[4] = 1, /* CC2 PPL / 1 */
|
||||
[5] = 1, /* CC2 PPL / 2 */
|
||||
};
|
||||
|
||||
const u8 core_cplx_pll_div[8] = {
|
||||
[0] = 1, /* CC1 PPL / 1 */
|
||||
[1] = 2, /* CC1 PPL / 2 */
|
||||
[4] = 1, /* CC2 PPL / 1 */
|
||||
[5] = 2, /* CC2 PPL / 2 */
|
||||
};
|
||||
|
||||
uint i, 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;
|
||||
|
||||
sys_info->freq_systembus = sysclk;
|
||||
#ifdef CONFIG_DDR_CLK_FREQ
|
||||
sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
|
||||
#else
|
||||
sys_info->freq_ddrbus = sysclk;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LS1012A
|
||||
sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
|
||||
#else
|
||||
sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
|
||||
sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_MASK;
|
||||
#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] = sysclk * 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];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LS1012A
|
||||
sys_info->freq_systembus = sys_info->freq_ddrbus / 2;
|
||||
sys_info->freq_ddrbus *= 2;
|
||||
#endif
|
||||
|
||||
#define HWA_CGA_M1_CLK_SEL 0xe0000000
|
||||
#define HWA_CGA_M1_CLK_SHIFT 29
|
||||
#ifdef CONFIG_SYS_DPAA_FMAN
|
||||
rcw_tmp = in_be32(&gur->rcwsr[7]);
|
||||
switch ((rcw_tmp & HWA_CGA_M1_CLK_SEL) >> HWA_CGA_M1_CLK_SHIFT) {
|
||||
case 2:
|
||||
sys_info->freq_fman[0] = freq_c_pll[0] / 2;
|
||||
break;
|
||||
case 3:
|
||||
sys_info->freq_fman[0] = freq_c_pll[0] / 3;
|
||||
break;
|
||||
case 6:
|
||||
sys_info->freq_fman[0] = freq_c_pll[1] / 2;
|
||||
break;
|
||||
case 7:
|
||||
sys_info->freq_fman[0] = freq_c_pll[1] / 3;
|
||||
break;
|
||||
default:
|
||||
printf("Error: Unknown FMan1 clock select!\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HWA_CGA_M2_CLK_SEL 0x00000007
|
||||
#define HWA_CGA_M2_CLK_SHIFT 0
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
|
||||
rcw_tmp = in_be32(&gur->rcwsr[15]);
|
||||
rcw_tmp = (rcw_tmp & HWA_CGA_M2_CLK_SEL) >> HWA_CGA_M2_CLK_SHIFT;
|
||||
sys_info->freq_sdhc = freq_c_pll[1] / rcw_tmp;
|
||||
#else
|
||||
sys_info->freq_sdhc = sys_info->freq_systembus;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_IFC)
|
||||
ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr);
|
||||
ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
|
||||
|
||||
sys_info->freq_localbus = sys_info->freq_systembus / ccr;
|
||||
#endif
|
||||
}
|
||||
|
||||
int get_clocks(void)
|
||||
{
|
||||
struct sys_info sys_info;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
gd->cpu_clk = sys_info.freq_processor[0];
|
||||
gd->bus_clk = sys_info.freq_systembus;
|
||||
gd->mem_clk = sys_info.freq_ddrbus;
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
gd->arch.sdhc_clk = sys_info.freq_sdhc;
|
||||
#endif
|
||||
|
||||
if (gd->cpu_clk != 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
ulong get_bus_freq(ulong dummy)
|
||||
{
|
||||
return gd->bus_clk;
|
||||
}
|
||||
|
||||
ulong get_ddr_freq(ulong dummy)
|
||||
{
|
||||
return gd->mem_clk;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
int get_sdhc_freq(ulong dummy)
|
||||
{
|
||||
return gd->arch.sdhc_clk;
|
||||
}
|
||||
#endif
|
||||
|
||||
int get_serial_clock(void)
|
||||
{
|
||||
return gd->bus_clk;
|
||||
}
|
||||
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_I2C_CLK:
|
||||
return get_bus_freq(0);
|
||||
#if defined(CONFIG_FSL_ESDHC)
|
||||
case MXC_ESDHC_CLK:
|
||||
return get_sdhc_freq(0);
|
||||
#endif
|
||||
case MXC_DSPI_CLK:
|
||||
return get_bus_freq(0);
|
||||
case MXC_UART_CLK:
|
||||
return get_bus_freq(0);
|
||||
default:
|
||||
printf("Unsupported clock\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
167
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c
Normal file
167
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/soc.h>
|
||||
#include <fsl-mc/ldpaa_wriop.h>
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT];
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_MC_ENET
|
||||
int xfi_dpmac[XFI8 + 1];
|
||||
int sgmii_dpmac[SGMII16 + 1];
|
||||
#endif
|
||||
|
||||
int is_serdes_configured(enum srds_prtcl device)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
ret |= serdes1_prtcl_map[device];
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
ret |= serdes2_prtcl_map[device];
|
||||
#endif
|
||||
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 cfg = gur_in32(&gur->rcwsr[28]);
|
||||
int i;
|
||||
|
||||
switch (sd) {
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
case FSL_SRDS_1:
|
||||
cfg &= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
case FSL_SRDS_2:
|
||||
cfg &= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK;
|
||||
cfg >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("invalid SerDes%d\n", sd);
|
||||
break;
|
||||
}
|
||||
/* Is serdes enabled at all? */
|
||||
if (cfg == 0)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
||||
if (serdes_get_prtcl(sd, cfg, i) == device)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
|
||||
u8 serdes_prtcl_map[SERDES_PRCTL_COUNT])
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 cfg;
|
||||
int lane;
|
||||
|
||||
memset(serdes_prtcl_map, 0, sizeof(u8) * SERDES_PRCTL_COUNT);
|
||||
|
||||
cfg = gur_in32(&gur->rcwsr[28]) & sd_prctl_mask;
|
||||
cfg >>= sd_prctl_shift;
|
||||
printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
|
||||
|
||||
if (!is_serdes_prtcl_valid(sd, cfg))
|
||||
printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
|
||||
|
||||
for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
|
||||
enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
|
||||
if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT))
|
||||
debug("Unknown SerDes lane protocol %d\n", lane_prtcl);
|
||||
else {
|
||||
serdes_prtcl_map[lane_prtcl] = 1;
|
||||
#ifdef CONFIG_FSL_MC_ENET
|
||||
switch (lane_prtcl) {
|
||||
case QSGMII_A:
|
||||
wriop_init_dpmac(sd, 5, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 6, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 7, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 8, (int)lane_prtcl);
|
||||
break;
|
||||
case QSGMII_B:
|
||||
wriop_init_dpmac(sd, 1, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 2, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 3, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 4, (int)lane_prtcl);
|
||||
break;
|
||||
case QSGMII_C:
|
||||
wriop_init_dpmac(sd, 13, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 14, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 15, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 16, (int)lane_prtcl);
|
||||
break;
|
||||
case QSGMII_D:
|
||||
wriop_init_dpmac(sd, 9, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 10, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 11, (int)lane_prtcl);
|
||||
wriop_init_dpmac(sd, 12, (int)lane_prtcl);
|
||||
break;
|
||||
default:
|
||||
if (lane_prtcl >= 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fsl_serdes_init(void)
|
||||
{
|
||||
#ifdef CONFIG_FSL_MC_ENET
|
||||
int i , j;
|
||||
|
||||
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
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
serdes_init(FSL_SRDS_1,
|
||||
CONFIG_SYS_FSL_LSCH3_SERDES_ADDR,
|
||||
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK,
|
||||
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT,
|
||||
serdes1_prtcl_map);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
serdes_init(FSL_SRDS_2,
|
||||
CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + FSL_SRDS_2 * 0x10000,
|
||||
FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK,
|
||||
FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT,
|
||||
serdes2_prtcl_map);
|
||||
#endif
|
||||
}
|
||||
204
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c
Normal file
204
u-boot/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2014-2015, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Derived from arch/power/cpu/mpc85xx/speed.c
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <fsl_ifc.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch-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);
|
||||
#ifdef CONFIG_FSL_IFC
|
||||
struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL};
|
||||
u32 ccr;
|
||||
#endif
|
||||
struct ccsr_clk_cluster_group __iomem *clk_grp[2] = {
|
||||
(void *)(CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR),
|
||||
(void *)(CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR)
|
||||
};
|
||||
struct ccsr_clk_ctrl __iomem *clk_ctrl =
|
||||
(void *)(CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR);
|
||||
unsigned int cpu;
|
||||
const u8 core_cplx_pll[16] = {
|
||||
[0] = 0, /* CC1 PPL / 1 */
|
||||
[1] = 0, /* CC1 PPL / 2 */
|
||||
[2] = 0, /* CC1 PPL / 4 */
|
||||
[4] = 1, /* CC2 PPL / 1 */
|
||||
[5] = 1, /* CC2 PPL / 2 */
|
||||
[6] = 1, /* CC2 PPL / 4 */
|
||||
[8] = 2, /* CC3 PPL / 1 */
|
||||
[9] = 2, /* CC3 PPL / 2 */
|
||||
[10] = 2, /* CC3 PPL / 4 */
|
||||
[12] = 3, /* CC4 PPL / 1 */
|
||||
[13] = 3, /* CC4 PPL / 2 */
|
||||
[14] = 3, /* CC4 PPL / 4 */
|
||||
};
|
||||
|
||||
const u8 core_cplx_pll_div[16] = {
|
||||
[0] = 1, /* CC1 PPL / 1 */
|
||||
[1] = 2, /* CC1 PPL / 2 */
|
||||
[2] = 4, /* CC1 PPL / 4 */
|
||||
[4] = 1, /* CC2 PPL / 1 */
|
||||
[5] = 2, /* CC2 PPL / 2 */
|
||||
[6] = 4, /* CC2 PPL / 4 */
|
||||
[8] = 1, /* CC3 PPL / 1 */
|
||||
[9] = 2, /* CC3 PPL / 2 */
|
||||
[10] = 4, /* CC3 PPL / 4 */
|
||||
[12] = 1, /* CC4 PPL / 1 */
|
||||
[13] = 2, /* CC4 PPL / 2 */
|
||||
[14] = 4, /* CC4 PPL / 4 */
|
||||
};
|
||||
|
||||
uint i, cluster;
|
||||
uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
|
||||
uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
|
||||
unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
|
||||
int cc_group[12] = CONFIG_SYS_FSL_CLUSTER_CLOCKS;
|
||||
u32 c_pll_sel, cplx_pll;
|
||||
void *offset;
|
||||
|
||||
sys_info->freq_systembus = sysclk;
|
||||
#ifdef CONFIG_DDR_CLK_FREQ
|
||||
sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
|
||||
#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
|
||||
|
||||
sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK;
|
||||
/* Platform clock is half of platform PLL */
|
||||
sys_info->freq_systembus /= 2;
|
||||
sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
|
||||
FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) &
|
||||
FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK;
|
||||
#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)
|
||||
ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr);
|
||||
ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
|
||||
|
||||
sys_info->freq_localbus = sys_info->freq_systembus / ccr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int get_clocks(void)
|
||||
{
|
||||
struct sys_info sys_info;
|
||||
get_sys_info(&sys_info);
|
||||
gd->cpu_clk = sys_info.freq_processor[0];
|
||||
gd->bus_clk = sys_info.freq_systembus;
|
||||
gd->mem_clk = sys_info.freq_ddrbus;
|
||||
#ifdef CONFIG_SYS_FSL_HAS_DP_DDR
|
||||
gd->arch.mem2_clk = sys_info.freq_ddrbus2;
|
||||
#endif
|
||||
#if defined(CONFIG_FSL_ESDHC)
|
||||
gd->arch.sdhc_clk = gd->bus_clk / 2;
|
||||
#endif /* defined(CONFIG_FSL_ESDHC) */
|
||||
|
||||
if (gd->cpu_clk != 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* get_bus_freq
|
||||
* return system bus freq in Hz
|
||||
*********************************************/
|
||||
ulong get_bus_freq(ulong dummy)
|
||||
{
|
||||
if (!gd->bus_clk)
|
||||
get_clocks();
|
||||
|
||||
return gd->bus_clk;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* get_ddr_freq
|
||||
* return ddr bus freq in Hz
|
||||
*********************************************/
|
||||
ulong get_ddr_freq(ulong ctrl_num)
|
||||
{
|
||||
if (!gd->mem_clk)
|
||||
get_clocks();
|
||||
|
||||
/*
|
||||
* DDR controller 0 & 1 are on memory complex 0
|
||||
* DDR 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;
|
||||
}
|
||||
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_I2C_CLK:
|
||||
return get_bus_freq(0) / 2;
|
||||
case MXC_DSPI_CLK:
|
||||
return get_bus_freq(0) / 2;
|
||||
default:
|
||||
printf("Unsupported clock\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
375
u-boot/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
Normal file
375
u-boot/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* (C) Copyright 2014-2015 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Extracted from armv8/start.S
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/gic.h>
|
||||
#include <asm/macro.h>
|
||||
#ifdef CONFIG_MP
|
||||
#include <asm/arch/mp.h>
|
||||
#endif
|
||||
|
||||
ENTRY(lowlevel_init)
|
||||
mov x29, lr /* Save LR */
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
|
||||
/* Set Wuo bit for RN-I 20 */
|
||||
#ifdef CONFIG_LS2080A
|
||||
ldr x0, =CCI_AUX_CONTROL_BASE(20)
|
||||
ldr x1, =0x00000010
|
||||
bl ccn504_set_aux
|
||||
#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
|
||||
|
||||
#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
|
||||
ldr x0, =GICD_BASE
|
||||
bl gic_init_secure
|
||||
1:
|
||||
#ifdef CONFIG_GICV3
|
||||
ldr x0, =GICR_BASE
|
||||
bl gic_init_secure_percpu
|
||||
#elif defined(CONFIG_GICV2)
|
||||
ldr x0, =GICD_BASE
|
||||
ldr x1, =GICC_BASE
|
||||
bl gic_init_secure_percpu
|
||||
#endif
|
||||
#endif
|
||||
|
||||
branch_if_master x0, x1, 2f
|
||||
|
||||
#if defined(CONFIG_MP) && defined(CONFIG_ARMV8_MULTIENTRY)
|
||||
ldr x0, =secondary_boot_func
|
||||
blr x0
|
||||
#endif
|
||||
|
||||
2:
|
||||
#ifdef CONFIG_FSL_TZPC_BP147
|
||||
/* Set Non Secure access for all devices protected via TZPC */
|
||||
ldr x1, =TZPCDECPROT_0_SET_BASE /* Decode Protection-0 Set Reg */
|
||||
orr w0, w0, #1 << 3 /* DCFG_RESET is accessible from NS world */
|
||||
str w0, [x1]
|
||||
|
||||
isb
|
||||
dsb sy
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_TZASC_400
|
||||
/* Set TZASC so that:
|
||||
* a. We use only Region0 whose global secure write/read is EN
|
||||
* b. We use only Region0 whose NSAID write/read is EN
|
||||
*
|
||||
* NOTE: As per the CCSR map doc, TZASC 3 and TZASC 4 are just
|
||||
* placeholders.
|
||||
*/
|
||||
ldr x1, =TZASC_GATE_KEEPER(0)
|
||||
ldr x0, [x1] /* Filter 0 Gate Keeper Register */
|
||||
orr x0, x0, #1 << 0 /* Set open_request for Filter 0 */
|
||||
str x0, [x1]
|
||||
|
||||
ldr x1, =TZASC_GATE_KEEPER(1)
|
||||
ldr x0, [x1] /* Filter 0 Gate Keeper Register */
|
||||
orr x0, x0, #1 << 0 /* Set open_request for Filter 0 */
|
||||
str x0, [x1]
|
||||
|
||||
ldr x1, =TZASC_REGION_ATTRIBUTES_0(0)
|
||||
ldr x0, [x1] /* Region-0 Attributes Register */
|
||||
orr x0, x0, #1 << 31 /* Set Sec global write en, Bit[31] */
|
||||
orr x0, x0, #1 << 30 /* Set Sec global read en, Bit[30] */
|
||||
str x0, [x1]
|
||||
|
||||
ldr x1, =TZASC_REGION_ATTRIBUTES_0(1)
|
||||
ldr x0, [x1] /* Region-1 Attributes Register */
|
||||
orr x0, x0, #1 << 31 /* Set Sec global write en, Bit[31] */
|
||||
orr x0, x0, #1 << 30 /* Set Sec global read en, Bit[30] */
|
||||
str x0, [x1]
|
||||
|
||||
ldr x1, =TZASC_REGION_ID_ACCESS_0(0)
|
||||
ldr w0, [x1] /* Region-0 Access Register */
|
||||
mov w0, #0xFFFFFFFF /* Set nsaid_wr_en and nsaid_rd_en */
|
||||
str w0, [x1]
|
||||
|
||||
ldr x1, =TZASC_REGION_ID_ACCESS_0(1)
|
||||
ldr w0, [x1] /* Region-1 Attributes Register */
|
||||
mov w0, #0xFFFFFFFF /* Set nsaid_wr_en and nsaid_rd_en */
|
||||
str w0, [x1]
|
||||
|
||||
isb
|
||||
dsb sy
|
||||
#endif
|
||||
mov lr, x29 /* Restore LR */
|
||||
ret
|
||||
ENDPROC(lowlevel_init)
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
hnf_pstate_poll:
|
||||
/* x0 has the desired status, return 0 for success, 1 for timeout
|
||||
* clobber x1, x2, x3, x4, x6, x7
|
||||
*/
|
||||
mov x1, x0
|
||||
mov x7, #0 /* flag for timeout */
|
||||
mrs x3, cntpct_el0 /* read timer */
|
||||
add x3, x3, #1200 /* timeout after 100 microseconds */
|
||||
mov x0, #0x18
|
||||
movk x0, #0x420, lsl #16 /* HNF0_PSTATE_STATUS */
|
||||
mov w6, #8 /* HN-F node count */
|
||||
1:
|
||||
ldr x2, [x0]
|
||||
cmp x2, x1 /* check status */
|
||||
b.eq 2f
|
||||
mrs x4, cntpct_el0
|
||||
cmp x4, x3
|
||||
b.ls 1b
|
||||
mov x7, #1 /* timeout */
|
||||
b 3f
|
||||
2:
|
||||
add x0, x0, #0x10000 /* move to next node */
|
||||
subs w6, w6, #1
|
||||
cbnz w6, 1b
|
||||
3:
|
||||
mov x0, x7
|
||||
ret
|
||||
|
||||
hnf_set_pstate:
|
||||
/* x0 has the desired state, clobber x1, x2, x6 */
|
||||
mov x1, x0
|
||||
/* power state to SFONLY */
|
||||
mov w6, #8 /* HN-F node count */
|
||||
mov x0, #0x10
|
||||
movk x0, #0x420, lsl #16 /* HNF0_PSTATE_REQ */
|
||||
1: /* set pstate to sfonly */
|
||||
ldr x2, [x0]
|
||||
and x2, x2, #0xfffffffffffffffc /* & HNFPSTAT_MASK */
|
||||
orr x2, x2, x1
|
||||
str x2, [x0]
|
||||
add x0, x0, #0x10000 /* move to next node */
|
||||
subs w6, w6, #1
|
||||
cbnz w6, 1b
|
||||
|
||||
ret
|
||||
|
||||
ENTRY(__asm_flush_l3_cache)
|
||||
/*
|
||||
* Return status in x0
|
||||
* success 0
|
||||
* tmeout 1 for setting SFONLY, 2 for FAM, 3 for both
|
||||
*/
|
||||
mov x29, lr
|
||||
mov x8, #0
|
||||
|
||||
dsb sy
|
||||
mov x0, #0x1 /* HNFPSTAT_SFONLY */
|
||||
bl hnf_set_pstate
|
||||
|
||||
mov x0, #0x4 /* SFONLY status */
|
||||
bl hnf_pstate_poll
|
||||
cbz x0, 1f
|
||||
mov x8, #1 /* timeout */
|
||||
1:
|
||||
dsb sy
|
||||
mov x0, #0x3 /* HNFPSTAT_FAM */
|
||||
bl hnf_set_pstate
|
||||
|
||||
mov x0, #0xc /* FAM status */
|
||||
bl hnf_pstate_poll
|
||||
cbz x0, 1f
|
||||
add x8, x8, #0x2
|
||||
1:
|
||||
mov x0, x8
|
||||
mov lr, x29
|
||||
ret
|
||||
ENDPROC(__asm_flush_l3_cache)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MP
|
||||
/* Keep literals not used by the secondary boot code outside it */
|
||||
.ltorg
|
||||
|
||||
/* Using 64 bit alignment since the spin table is accessed as data */
|
||||
.align 4
|
||||
.global secondary_boot_code
|
||||
/* Secondary Boot Code starts here */
|
||||
secondary_boot_code:
|
||||
.global __spin_table
|
||||
__spin_table:
|
||||
.space CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE
|
||||
|
||||
.align 2
|
||||
ENTRY(secondary_boot_func)
|
||||
/*
|
||||
* MPIDR_EL1 Fields:
|
||||
* MPIDR[1:0] = AFF0_CPUID <- Core ID (0,1)
|
||||
* MPIDR[7:2] = AFF0_RES
|
||||
* MPIDR[15:8] = AFF1_CLUSTERID <- Cluster ID (0,1,2,3)
|
||||
* MPIDR[23:16] = AFF2_CLUSTERID
|
||||
* MPIDR[24] = MT
|
||||
* MPIDR[29:25] = RES0
|
||||
* MPIDR[30] = U
|
||||
* MPIDR[31] = ME
|
||||
* MPIDR[39:32] = AFF3
|
||||
*
|
||||
* Linear Processor ID (LPID) calculation from MPIDR_EL1:
|
||||
* (We only use AFF0_CPUID and AFF1_CLUSTERID for now
|
||||
* until AFF2_CLUSTERID and AFF3 have non-zero values)
|
||||
*
|
||||
* LPID = MPIDR[15:8] | MPIDR[1:0]
|
||||
*/
|
||||
mrs x0, mpidr_el1
|
||||
ubfm x1, x0, #8, #15
|
||||
ubfm x2, x0, #0, #1
|
||||
orr x10, x2, x1, lsl #2 /* x10 has LPID */
|
||||
ubfm x9, x0, #0, #15 /* x9 contains MPIDR[15:0] */
|
||||
/*
|
||||
* offset of the spin table element for this core from start of spin
|
||||
* table (each elem is padded to 64 bytes)
|
||||
*/
|
||||
lsl x1, x10, #6
|
||||
ldr x0, =__spin_table
|
||||
/* physical address of this cpus spin table element */
|
||||
add x11, x1, x0
|
||||
|
||||
ldr x0, =__real_cntfrq
|
||||
ldr x0, [x0]
|
||||
msr cntfrq_el0, x0 /* set with real frequency */
|
||||
str x9, [x11, #16] /* LPID */
|
||||
mov x4, #1
|
||||
str x4, [x11, #8] /* STATUS */
|
||||
dsb sy
|
||||
#if defined(CONFIG_GICV3)
|
||||
gic_wait_for_interrupt_m x0
|
||||
#elif defined(CONFIG_GICV2)
|
||||
ldr x0, =GICC_BASE
|
||||
gic_wait_for_interrupt_m x0, w1
|
||||
#endif
|
||||
|
||||
bl secondary_switch_to_el2
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
bl secondary_switch_to_el1
|
||||
#endif
|
||||
|
||||
slave_cpu:
|
||||
wfe
|
||||
ldr x0, [x11]
|
||||
cbz x0, slave_cpu
|
||||
#ifndef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
mrs x1, sctlr_el2
|
||||
#else
|
||||
mrs x1, sctlr_el1
|
||||
#endif
|
||||
tbz x1, #25, cpu_is_le
|
||||
rev x0, x0 /* BE to LE conversion */
|
||||
cpu_is_le:
|
||||
br x0 /* branch to the given address */
|
||||
ENDPROC(secondary_boot_func)
|
||||
|
||||
ENTRY(secondary_switch_to_el2)
|
||||
switch_el x0, 1f, 0f, 0f
|
||||
0: ret
|
||||
1: armv8_switch_to_el2_m x0
|
||||
ENDPROC(secondary_switch_to_el2)
|
||||
|
||||
ENTRY(secondary_switch_to_el1)
|
||||
switch_el x0, 0f, 1f, 0f
|
||||
0: ret
|
||||
1: armv8_switch_to_el1_m x0, x1
|
||||
ENDPROC(secondary_switch_to_el1)
|
||||
|
||||
/* Ensure that the literals used by the secondary boot code are
|
||||
* assembled within it (this is required so that we can protect
|
||||
* this area with a single memreserve region
|
||||
*/
|
||||
.ltorg
|
||||
|
||||
/* 64 bit alignment for elements accessed as data */
|
||||
.align 4
|
||||
.global __real_cntfrq
|
||||
__real_cntfrq:
|
||||
.quad COUNTER_FREQUENCY
|
||||
.globl __secondary_boot_code_size
|
||||
.type __secondary_boot_code_size, %object
|
||||
/* Secondary Boot Code ends here */
|
||||
__secondary_boot_code_size:
|
||||
.quad .-secondary_boot_code
|
||||
#endif
|
||||
74
u-boot/arch/arm/cpu/armv8/fsl-layerscape/ls1012a_serdes.c
Normal file
74
u-boot/arch/arm/cpu/armv8/fsl-layerscape/ls1012a_serdes.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2016 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/immap_lsch2.h>
|
||||
|
||||
struct serdes_config {
|
||||
u32 protocol;
|
||||
u8 lanes[SRDS_MAX_LANES];
|
||||
};
|
||||
|
||||
static struct serdes_config serdes1_cfg_tbl[] = {
|
||||
{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;
|
||||
}
|
||||
86
u-boot/arch/arm/cpu/armv8/fsl-layerscape/ls1043a_serdes.c
Normal file
86
u-boot/arch/arm/cpu/armv8/fsl-layerscape/ls1043a_serdes.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/immap_lsch2.h>
|
||||
|
||||
struct serdes_config {
|
||||
u32 protocol;
|
||||
u8 lanes[SRDS_MAX_LANES];
|
||||
};
|
||||
|
||||
static struct serdes_config serdes1_cfg_tbl[] = {
|
||||
/* SerDes 1 */
|
||||
{0x1555, {XFI_FM1_MAC9, PCIE1, PCIE2, PCIE3} },
|
||||
{0x2555, {SGMII_2500_FM1_DTSEC9, PCIE1, PCIE2, PCIE3} },
|
||||
{0x4555, {QSGMII_FM1_A, PCIE1, PCIE2, PCIE3} },
|
||||
{0x4558, {QSGMII_FM1_A, PCIE1, PCIE2, SATA1} },
|
||||
{0x1355, {XFI_FM1_MAC9, SGMII_FM1_DTSEC2, PCIE2, PCIE3} },
|
||||
{0x2355, {SGMII_2500_FM1_DTSEC9, SGMII_FM1_DTSEC2, PCIE2, PCIE3} },
|
||||
{0x3335, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC5,
|
||||
PCIE3} },
|
||||
{0x3355, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, PCIE2, PCIE3} },
|
||||
{0x3358, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, PCIE2, SATA1} },
|
||||
{0x3555, {SGMII_FM1_DTSEC9, PCIE1, PCIE2, PCIE3} },
|
||||
{0x3558, {SGMII_FM1_DTSEC9, PCIE1, PCIE2, SATA1} },
|
||||
{0x7000, {PCIE1, PCIE1, PCIE1, PCIE1} },
|
||||
{0x9998, {PCIE1, PCIE2, PCIE3, SATA1} },
|
||||
{0x6058, {PCIE1, PCIE1, PCIE2, SATA1} },
|
||||
{0x1455, {XFI_FM1_MAC9, QSGMII_FM1_A, PCIE2, PCIE3} },
|
||||
{0x2455, {SGMII_2500_FM1_DTSEC9, QSGMII_FM1_A, PCIE2, PCIE3} },
|
||||
{0x2255, {SGMII_2500_FM1_DTSEC9, SGMII_2500_FM1_DTSEC2, PCIE2, PCIE3} },
|
||||
{0x3333, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC5,
|
||||
SGMII_FM1_DTSEC6} },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct serdes_config *serdes_cfg_tbl[] = {
|
||||
serdes1_cfg_tbl,
|
||||
};
|
||||
|
||||
enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane)
|
||||
{
|
||||
struct serdes_config *ptr;
|
||||
|
||||
if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
|
||||
return 0;
|
||||
|
||||
ptr = serdes_cfg_tbl[serdes];
|
||||
while (ptr->protocol) {
|
||||
if (ptr->protocol == cfg)
|
||||
return ptr->lanes[lane];
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_serdes_prtcl_valid(int serdes, u32 prtcl)
|
||||
{
|
||||
int i;
|
||||
struct serdes_config *ptr;
|
||||
|
||||
if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
|
||||
return 0;
|
||||
|
||||
ptr = serdes_cfg_tbl[serdes];
|
||||
while (ptr->protocol) {
|
||||
if (ptr->protocol == prtcl)
|
||||
break;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (!ptr->protocol)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
||||
if (ptr->lanes[i] != NONE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
116
u-boot/arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c
Normal file
116
u-boot/arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
|
||||
struct serdes_config {
|
||||
u8 protocol;
|
||||
u8 lanes[SRDS_MAX_LANES];
|
||||
};
|
||||
|
||||
static struct serdes_config serdes1_cfg_tbl[] = {
|
||||
/* SerDes 1 */
|
||||
{0x03, {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 } },
|
||||
{}
|
||||
};
|
||||
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 } },
|
||||
{}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
203
u-boot/arch/arm/cpu/armv8/fsl-layerscape/mp.c
Normal file
203
u-boot/arch/arm/cpu/armv8/fsl-layerscape/mp.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/arch/mp.h>
|
||||
#include <asm/arch/soc.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void *get_spin_tbl_addr(void)
|
||||
{
|
||||
return &__spin_table;
|
||||
}
|
||||
|
||||
phys_addr_t determine_mp_bootpg(void)
|
||||
{
|
||||
return (phys_addr_t)&secondary_boot_code;
|
||||
}
|
||||
|
||||
int fsl_layerscape_wake_seconday_cores(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR);
|
||||
#endif
|
||||
u32 cores, cpu_up_mask = 1;
|
||||
int i, timeout = 10;
|
||||
u64 *table = get_spin_tbl_addr();
|
||||
|
||||
#ifdef COUNTER_FREQUENCY_REAL
|
||||
/* update for secondary cores */
|
||||
__real_cntfrq = COUNTER_FREQUENCY_REAL;
|
||||
flush_dcache_range((unsigned long)&__real_cntfrq,
|
||||
(unsigned long)&__real_cntfrq + 8);
|
||||
#endif
|
||||
|
||||
cores = cpu_mask();
|
||||
/* Clear spin table so that secondary processors
|
||||
* observe the correct value after waking up from wfe.
|
||||
*/
|
||||
memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
|
||||
flush_dcache_range((unsigned long)table,
|
||||
(unsigned long)table +
|
||||
(CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
|
||||
|
||||
printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
|
||||
|
||||
#ifdef CONFIG_FSL_LSCH3
|
||||
gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
|
||||
gur_out32(&gur->bootlocptrl, (u32)gd->relocaddr);
|
||||
gur_out32(&gur->scratchrw[6], 1);
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
rst->brrl = cores;
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
scfg_out32(&scfg->scratchrw[0], (u32)(gd->relocaddr >> 32));
|
||||
scfg_out32(&scfg->scratchrw[1], (u32)gd->relocaddr);
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
gur_out32(&gur->brrl, cores);
|
||||
asm volatile("dsb st" : : : "memory");
|
||||
|
||||
/* Bootup online cores */
|
||||
scfg_out32(&scfg->corebcr, cores);
|
||||
#endif
|
||||
/* This is needed as a precautionary measure.
|
||||
* If some code before this has accidentally released the secondary
|
||||
* cores then the pre-bootloader code will trap them in a "wfe" unless
|
||||
* the scratchrw[6] is set. In this case we need a sev here to get these
|
||||
* cores moving again.
|
||||
*/
|
||||
asm volatile("sev");
|
||||
|
||||
while (timeout--) {
|
||||
flush_dcache_range((unsigned long)table, (unsigned long)table +
|
||||
CONFIG_MAX_CPUS * 64);
|
||||
for (i = 1; i < CONFIG_MAX_CPUS; i++) {
|
||||
if (table[i * WORDS_PER_SPIN_TABLE_ENTRY +
|
||||
SPIN_TABLE_ELEM_STATUS_IDX])
|
||||
cpu_up_mask |= 1 << i;
|
||||
}
|
||||
if (hweight32(cpu_up_mask) == hweight32(cores))
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if (timeout <= 0) {
|
||||
printf("Not all cores (0x%x) are up (0x%x)\n",
|
||||
cores, cpu_up_mask);
|
||||
return 1;
|
||||
}
|
||||
printf("All (%d) cores are up.\n", hweight32(cores));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_core_valid(unsigned int core)
|
||||
{
|
||||
return !!((1 << core) & cpu_mask());
|
||||
}
|
||||
|
||||
int is_core_online(u64 cpu_id)
|
||||
{
|
||||
u64 *table;
|
||||
int pos = id_to_core(cpu_id);
|
||||
table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY;
|
||||
return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1;
|
||||
}
|
||||
|
||||
int cpu_reset(int nr)
|
||||
{
|
||||
puts("Feature is not implemented.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_disable(int nr)
|
||||
{
|
||||
puts("Feature is not implemented.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int core_to_pos(int nr)
|
||||
{
|
||||
u32 cores = cpu_mask();
|
||||
int i, count = 0;
|
||||
|
||||
if (nr == 0) {
|
||||
return 0;
|
||||
} else if (nr >= hweight32(cores)) {
|
||||
puts("Not a valid core number.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
if (is_core_valid(i)) {
|
||||
count++;
|
||||
if (count == nr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int cpu_status(int nr)
|
||||
{
|
||||
u64 *table;
|
||||
int pos;
|
||||
|
||||
if (nr == 0) {
|
||||
table = (u64 *)get_spin_tbl_addr();
|
||||
printf("table base @ 0x%p\n", table);
|
||||
} else {
|
||||
pos = core_to_pos(nr);
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
table = (u64 *)get_spin_tbl_addr() + pos *
|
||||
WORDS_PER_SPIN_TABLE_ENTRY;
|
||||
printf("table @ 0x%p\n", table);
|
||||
printf(" addr - 0x%016llx\n",
|
||||
table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
|
||||
printf(" status - 0x%016llx\n",
|
||||
table[SPIN_TABLE_ELEM_STATUS_IDX]);
|
||||
printf(" lpid - 0x%016llx\n",
|
||||
table[SPIN_TABLE_ELEM_LPID_IDX]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_release(int nr, int argc, char * const argv[])
|
||||
{
|
||||
u64 boot_addr;
|
||||
u64 *table = (u64 *)get_spin_tbl_addr();
|
||||
int pos;
|
||||
|
||||
pos = core_to_pos(nr);
|
||||
if (pos <= 0)
|
||||
return -1;
|
||||
|
||||
table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
|
||||
boot_addr = simple_strtoull(argv[0], NULL, 16);
|
||||
table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr;
|
||||
flush_dcache_range((unsigned long)table,
|
||||
(unsigned long)table + SPIN_TABLE_ELEM_SIZE);
|
||||
asm volatile("dsb st");
|
||||
smp_kick_all_cpus(); /* only those with entry addr set will run */
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
343
u-boot/arch/arm/cpu/armv8/fsl-layerscape/soc.c
Normal file
343
u-boot/arch/arm/cpu/armv8/fsl-layerscape/soc.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fsl_ifc.h>
|
||||
#include <ahci.h>
|
||||
#include <scsi.h>
|
||||
#include <asm/arch/soc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/arch-fsl-layerscape/config.h>
|
||||
#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
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
bool soc_has_dp_ddr(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 svr = gur_in32(&gur->svr);
|
||||
|
||||
/* LS2085A has DP_DDR */
|
||||
if (SVR_SOC_VER(svr) == SVR_LS2085A)
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LS2080A
|
||||
/*
|
||||
* This erratum requires setting a value to eddrtqcr1 to
|
||||
* optimal the DDR performance.
|
||||
*/
|
||||
static void erratum_a008336(void)
|
||||
{
|
||||
u32 *eddrtqcr1;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008336
|
||||
#ifdef CONFIG_SYS_FSL_DCSR_DDR_ADDR
|
||||
eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR_ADDR + 0x800;
|
||||
out_le32(eddrtqcr1, 0x63b30002);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_DCSR_DDR2_ADDR
|
||||
eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR2_ADDR + 0x800;
|
||||
out_le32(eddrtqcr1, 0x63b30002);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This erratum requires a register write before being Memory
|
||||
* controller 3 being enabled.
|
||||
*/
|
||||
static void erratum_a008514(void)
|
||||
{
|
||||
u32 *eddrtqcr1;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008514
|
||||
#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 = getenv(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)
|
||||
u32 __iomem *dcfg_ccsr = (u32 __iomem *)DCFG_BASE;
|
||||
u32 __iomem *dcfg_dcsr = (u32 __iomem *)DCFG_DCSR_BASE;
|
||||
u32 val;
|
||||
|
||||
val = in_le32(dcfg_ccsr + DCFG_PORSR1 / 4);
|
||||
val &= ~DCFG_PORSR1_RCW_SRC;
|
||||
val |= DCFG_PORSR1_RCW_SRC_NOR;
|
||||
out_le32(dcfg_dcsr + DCFG_DCSR_PORCR1 / 4, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define I2C_DEBUG_REG 0x6
|
||||
#define I2C_GLITCH_EN 0x8
|
||||
/*
|
||||
* This erratum requires setting glitch_en bit to enable
|
||||
* digital glitch filter to improve clock stability.
|
||||
*/
|
||||
static void erratum_a009203(void)
|
||||
{
|
||||
u8 __iomem *ptr;
|
||||
#ifdef CONFIG_SYS_I2C
|
||||
#ifdef I2C1_BASE_ADDR
|
||||
ptr = (u8 __iomem *)(I2C1_BASE_ADDR + I2C_DEBUG_REG);
|
||||
|
||||
writeb(I2C_GLITCH_EN, ptr);
|
||||
#endif
|
||||
#ifdef I2C2_BASE_ADDR
|
||||
ptr = (u8 __iomem *)(I2C2_BASE_ADDR + I2C_DEBUG_REG);
|
||||
|
||||
writeb(I2C_GLITCH_EN, ptr);
|
||||
#endif
|
||||
#ifdef I2C3_BASE_ADDR
|
||||
ptr = (u8 __iomem *)(I2C3_BASE_ADDR + I2C_DEBUG_REG);
|
||||
|
||||
writeb(I2C_GLITCH_EN, ptr);
|
||||
#endif
|
||||
#ifdef I2C4_BASE_ADDR
|
||||
ptr = (u8 __iomem *)(I2C4_BASE_ADDR + I2C_DEBUG_REG);
|
||||
|
||||
writeb(I2C_GLITCH_EN, ptr);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
void 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();
|
||||
init_early_memctl_regs(); /* tighten IFC timing */
|
||||
erratum_a009203();
|
||||
erratum_a008514();
|
||||
erratum_a008336();
|
||||
#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
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCSI_AHCI_PLAT
|
||||
int sata_init(void)
|
||||
{
|
||||
struct ccsr_ahci __iomem *ccsr_ahci;
|
||||
|
||||
ccsr_ahci = (void *)CONFIG_SYS_SATA2;
|
||||
out_le32(&ccsr_ahci->ppcfg, AHCI_PORT_PHY_1_CFG);
|
||||
out_le32(&ccsr_ahci->ptc, AHCI_PORT_TRANS_CFG);
|
||||
|
||||
ccsr_ahci = (void *)CONFIG_SYS_SATA1;
|
||||
out_le32(&ccsr_ahci->ppcfg, AHCI_PORT_PHY_1_CFG);
|
||||
out_le32(&ccsr_ahci->ptc, AHCI_PORT_TRANS_CFG);
|
||||
|
||||
ahci_init((void __iomem *)CONFIG_SYS_SATA1);
|
||||
scsi_scan(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
#ifdef CONFIG_SCSI_AHCI_PLAT
|
||||
int sata_init(void)
|
||||
{
|
||||
struct ccsr_ahci __iomem *ccsr_ahci = (void *)CONFIG_SYS_SATA;
|
||||
|
||||
out_le32(&ccsr_ahci->ppcfg, AHCI_PORT_PHY_1_CFG);
|
||||
out_le32(&ccsr_ahci->pp2c, AHCI_PORT_PHY_2_CFG);
|
||||
out_le32(&ccsr_ahci->pp3c, AHCI_PORT_PHY_3_CFG);
|
||||
out_le32(&ccsr_ahci->ptc, AHCI_PORT_TRANS_CFG);
|
||||
|
||||
ahci_init((void __iomem *)CONFIG_SYS_SATA);
|
||||
scsi_scan(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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_CCI400_ADDR;
|
||||
struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
|
||||
/* 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_CCI400_ADDR;
|
||||
struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
|
||||
u32 tmp;
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
void fsl_lsch2_early_init_f(void)
|
||||
{
|
||||
struct ccsr_cci400 *cci = (struct ccsr_cci400 *)CONFIG_SYS_CCI400_ADDR;
|
||||
struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
|
||||
|
||||
#ifdef CONFIG_FSL_IFC
|
||||
init_early_memctl_regs(); /* tighten IFC timing */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_QSPI) && !defined(CONFIG_QSPI_BOOT)
|
||||
out_be32(&scfg->qspi_cfg, SCFG_QSPI_CLKSEL);
|
||||
#endif
|
||||
/* Make SEC reads and writes snoopable */
|
||||
setbits_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SECRDSNP |
|
||||
SCFG_SNPCNFGCR_SECWRSNP);
|
||||
|
||||
/*
|
||||
* Enable snoop requests and DVM message requests for
|
||||
* Slave insterface S4 (A53 core cluster)
|
||||
*/
|
||||
out_le32(&cci->slave[4].snoop_ctrl,
|
||||
CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
|
||||
|
||||
/* Erratum */
|
||||
erratum_a008850_early(); /* part 1 of 2 */
|
||||
erratum_a009929();
|
||||
erratum_a009660();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARD_LATE_INIT
|
||||
int board_late_init(void)
|
||||
{
|
||||
#ifdef CONFIG_SCSI_AHCI_PLAT
|
||||
sata_init();
|
||||
#endif
|
||||
#ifdef CONFIG_CHAIN_OF_TRUST
|
||||
fsl_setenv_chain_of_trust();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
74
u-boot/arch/arm/cpu/armv8/fsl-layerscape/spl.c
Normal file
74
u-boot/arch/arm/cpu/armv8/fsl-layerscape/spl.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <spl.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_ifc.h>
|
||||
#include <fsl_csu.h>
|
||||
#include <i2c.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
#ifdef CONFIG_SPL_MMC_SUPPORT
|
||||
return BOOT_DEVICE_MMC1;
|
||||
#endif
|
||||
#ifdef CONFIG_SPL_NAND_SUPPORT
|
||||
return BOOT_DEVICE_NAND;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 spl_boot_mode(const u32 boot_device)
|
||||
{
|
||||
switch (spl_boot_device()) {
|
||||
case BOOT_DEVICE_MMC1:
|
||||
#ifdef CONFIG_SPL_FAT_SUPPORT
|
||||
return MMCSD_MODE_FS;
|
||||
#else
|
||||
return MMCSD_MODE_RAW;
|
||||
#endif
|
||||
case BOOT_DEVICE_NAND:
|
||||
return 0;
|
||||
default:
|
||||
puts("spl: error: unsupported device\n");
|
||||
hang();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
/* Clear global data */
|
||||
memset((void *)gd, 0, sizeof(gd_t));
|
||||
#ifdef CONFIG_LS2080A
|
||||
arch_cpu_init();
|
||||
#endif
|
||||
board_early_init_f();
|
||||
timer_init();
|
||||
#ifdef CONFIG_LS2080A
|
||||
env_init();
|
||||
#endif
|
||||
get_clocks();
|
||||
|
||||
preloader_console_init();
|
||||
|
||||
#ifdef CONFIG_SPL_I2C_SUPPORT
|
||||
i2c_init_all();
|
||||
#endif
|
||||
dram_init();
|
||||
|
||||
/* Clear the BSS */
|
||||
memset(__bss_start, 0, __bss_end - __bss_start);
|
||||
|
||||
#ifdef CONFIG_LAYERSCAPE_NS_ACCESS
|
||||
enable_layerscape_ns_access();
|
||||
#endif
|
||||
board_init_r(NULL, 0);
|
||||
}
|
||||
#endif
|
||||
91
u-boot/arch/arm/cpu/armv8/fwcall.c
Normal file
91
u-boot/arch/arm/cpu/armv8/fwcall.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* (C) Copyright 2014, Cavium Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
**/
|
||||
|
||||
#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
|
||||
*/
|
||||
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"
|
||||
"ldr x7, %7\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]), "m" (args->regs[7])
|
||||
: "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");
|
||||
}
|
||||
|
||||
void __noreturn psci_system_reset(bool conduit_smc)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
|
||||
regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
|
||||
|
||||
if (conduit_smc)
|
||||
smc_call(®s);
|
||||
else
|
||||
hvc_call(®s);
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
53
u-boot/arch/arm/cpu/armv8/generic_timer.c
Normal file
53
u-boot/arch/arm/cpu/armv8/generic_timer.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* Generic timer implementation of get_tbclk()
|
||||
*/
|
||||
unsigned long get_tbclk(void)
|
||||
{
|
||||
unsigned long cntfrq;
|
||||
asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq));
|
||||
return cntfrq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic timer implementation of timer_read_counter()
|
||||
*/
|
||||
unsigned long timer_read_counter(void)
|
||||
{
|
||||
unsigned long cntpct;
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008585
|
||||
/* This erratum number needs to be confirmed to match ARM document */
|
||||
unsigned long temp;
|
||||
#endif
|
||||
isb();
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008585
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
return cntpct;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
8
u-boot/arch/arm/cpu/armv8/hisilicon/Makefile
Normal file
8
u-boot/arch/arm/cpu/armv8/hisilicon/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# (C) Copyright 2015 Linaro
|
||||
# Peter Griffin <peter.griffin@linaro.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += pinmux.o
|
||||
184
u-boot/arch/arm/cpu/armv8/hisilicon/pinmux.c
Normal file
184
u-boot/arch/arm/cpu/armv8/hisilicon/pinmux.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Linaro.
|
||||
* Peter Griffin <peter.griffin@linaro.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
8
u-boot/arch/arm/cpu/armv8/s32v234/Makefile
Normal file
8
u-boot/arch/arm/cpu/armv8/s32v234/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# (C) Copyright 2013-2016, Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += generic.o
|
||||
obj-y += cpu.o
|
||||
97
u-boot/arch/arm/cpu/armv8/s32v234/cpu.c
Normal file
97
u-boot/arch/arm/cpu/armv8/s32v234/cpu.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* (C) Copyright 2014-2016, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.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"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
u32 cpu_mask(void)
|
||||
{
|
||||
return readl(MC_ME_CS);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_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[] = {
|
||||
{
|
||||
.base = S32V234_IRAM_BASE,
|
||||
.size = S32V234_IRAM_SIZE,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_OUTER_SHARE
|
||||
}, {
|
||||
.base = S32V234_DRAM_BASE1,
|
||||
.size = S32V234_DRAM_SIZE1,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_OUTER_SHARE
|
||||
}, {
|
||||
.base = 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 */
|
||||
}, {
|
||||
.base = 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 */
|
||||
8
u-boot/arch/arm/cpu/armv8/s32v234/cpu.h
Normal file
8
u-boot/arch/arm/cpu/armv8/s32v234/cpu.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* (C) Copyright 2014-2016, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
u32 cpu_mask(void);
|
||||
int cpu_numcores(void);
|
||||
350
u-boot/arch/arm/cpu/armv8/s32v234/generic.c
Normal file
350
u-boot/arch/arm/cpu/armv8/s32v234/generic.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* (C) Copyright 2013-2016, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#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
|
||||
gd->arch.sdhc_clk = mxc_get_clock(MXC_USDHC_CLK);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
290
u-boot/arch/arm/cpu/armv8/start.S
Normal file
290
u-boot/arch/arm/cpu/armv8/start.S
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#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:
|
||||
b reset
|
||||
|
||||
#ifdef 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>
|
||||
ARM_SOC_BOOT0_HOOK
|
||||
#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:
|
||||
#ifdef CONFIG_SYS_RESET_SCTRL
|
||||
bl reset_sctrl
|
||||
#endif
|
||||
/*
|
||||
* Could be EL3/EL2/EL1, Initial State:
|
||||
* Little Endian, MMU Disabled, i/dCache Disabled
|
||||
*/
|
||||
adr x0, vectors
|
||||
switch_el x1, 3f, 2f, 1f
|
||||
3: msr 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: msr vbar_el2, x0
|
||||
mov x0, #0x33ff
|
||||
msr cptr_el2, x0 /* Enable FP/SIMD */
|
||||
b 0f
|
||||
1: msr vbar_el1, x0
|
||||
mov x0, #3 << 20
|
||||
msr cpacr_el1, x0 /* Enable FP/SIMD */
|
||||
0:
|
||||
|
||||
/* Enalbe SMPEN bit for coherency.
|
||||
* This register is not architectural but at the moment
|
||||
* this bit should be set for A53/A57/A72.
|
||||
*/
|
||||
mrs x0, S3_1_c15_c2_1 /* cpuactlr_el1 */
|
||||
orr x0, x0, #0x40
|
||||
msr S3_1_c15_c2_1, x0
|
||||
|
||||
/* 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
|
||||
|
||||
#ifdef 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 */
|
||||
master_cpu:
|
||||
/* On the master CPU */
|
||||
#endif /* CONFIG_ARMV8_MULTIENTRY */
|
||||
|
||||
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-A57 specific errata only */
|
||||
|
||||
/* 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_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.
|
||||
*/
|
||||
bl armv8_switch_to_el2
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
bl armv8_switch_to_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)
|
||||
/* 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:
|
||||
|
||||
ret
|
||||
ENDPROC(c_runtime_cpu_setup)
|
||||
33
u-boot/arch/arm/cpu/armv8/tlb.S
Normal file
33
u-boot/arch/arm/cpu/armv8/tlb.S
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
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)
|
||||
23
u-boot/arch/arm/cpu/armv8/transition.S
Normal file
23
u-boot/arch/arm/cpu/armv8/transition.S
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
ENTRY(armv8_switch_to_el2)
|
||||
switch_el x0, 1f, 0f, 0f
|
||||
0: ret
|
||||
1: armv8_switch_to_el2_m x0
|
||||
ENDPROC(armv8_switch_to_el2)
|
||||
|
||||
ENTRY(armv8_switch_to_el1)
|
||||
switch_el x0, 0f, 1f, 0f
|
||||
0: ret
|
||||
1: armv8_switch_to_el1_m x0, x1
|
||||
ENDPROC(armv8_switch_to_el1)
|
||||
79
u-boot/arch/arm/cpu/armv8/u-boot-spl.lds
Normal file
79
u-boot/arch/arm/cpu/armv8/u-boot-spl.lds
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* (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>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,
|
||||
LENGTH = CONFIG_SPL_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 : {
|
||||
. = ALIGN(8);
|
||||
KEEP(*(.__bss_start));
|
||||
} >.sdram
|
||||
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
. = ALIGN(8);
|
||||
} >.sdram
|
||||
|
||||
.bss_end : {
|
||||
KEEP(*(.__bss_end));
|
||||
} >.sdram
|
||||
|
||||
/DISCARD/ : { *(.dynsym) }
|
||||
/DISCARD/ : { *(.dynstr*) }
|
||||
/DISCARD/ : { *(.dynamic*) }
|
||||
/DISCARD/ : { *(.plt*) }
|
||||
/DISCARD/ : { *(.interp*) }
|
||||
/DISCARD/ : { *(.gnu*) }
|
||||
}
|
||||
105
u-boot/arch/arm/cpu/armv8/u-boot.lds
Normal file
105
u-boot/arch/arm/cpu/armv8/u-boot.lds
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00000000;
|
||||
|
||||
. = ALIGN(8);
|
||||
.text :
|
||||
{
|
||||
*(.__image_copy_start)
|
||||
CPUDIR/start.o (.text*)
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
. = 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 : {
|
||||
__efi_runtime_start = .;
|
||||
*(efi_runtime_text)
|
||||
*(efi_runtime_data)
|
||||
__efi_runtime_stop = .;
|
||||
}
|
||||
|
||||
.efi_runtime_rel : {
|
||||
__efi_runtime_rel_start = .;
|
||||
*(.relaefi_runtime_text)
|
||||
*(.relaefi_runtime_data)
|
||||
__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*) }
|
||||
}
|
||||
23
u-boot/arch/arm/cpu/armv8/zynqmp/Kconfig
Normal file
23
u-boot/arch/arm/cpu/armv8/zynqmp/Kconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
if ARCH_ZYNQMP
|
||||
|
||||
config SYS_BOARD
|
||||
default "zynqmp"
|
||||
|
||||
config SYS_VENDOR
|
||||
default "xilinx"
|
||||
|
||||
config SYS_SOC
|
||||
default "zynqmp"
|
||||
|
||||
config SYS_CONFIG_NAME
|
||||
string "Board configuration name"
|
||||
default "xilinx_zynqmp"
|
||||
help
|
||||
This option contains information about board configuration name.
|
||||
Based on this option include/configs/<CONFIG_SYS_CONFIG_NAME>.h header
|
||||
will be used for board configuration.
|
||||
|
||||
config ZYNQMP_USB
|
||||
bool "Configure ZynqMP USB"
|
||||
|
||||
endif
|
||||
12
u-boot/arch/arm/cpu/armv8/zynqmp/Makefile
Normal file
12
u-boot/arch/arm/cpu/armv8/zynqmp/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# (C) Copyright 2014 - 2015 Xilinx, Inc.
|
||||
# Michal Simek <michal.simek@xilinx.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += clk.o
|
||||
obj-y += cpu.o
|
||||
obj-$(CONFIG_MP) += mp.o
|
||||
obj-y += slcr.o
|
||||
obj-$(CONFIG_SPL_BUILD) += spl.o
|
||||
70
u-boot/arch/arm/cpu/armv8/zynqmp/clk.c
Normal file
70
u-boot/arch/arm/cpu/armv8/zynqmp/clk.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* (C) Copyright 2014 - 2015 Xilinx, Inc.
|
||||
* Michal Simek <michal.simek@xilinx.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
unsigned long get_uart_clk(int dev_id)
|
||||
{
|
||||
u32 ver = zynqmp_get_silicon_version();
|
||||
|
||||
switch (ver) {
|
||||
case ZYNQMP_CSU_VERSION_VELOCE:
|
||||
return 48000;
|
||||
case ZYNQMP_CSU_VERSION_EP108:
|
||||
return 25000000;
|
||||
case ZYNQMP_CSU_VERSION_QEMU:
|
||||
return 133000000;
|
||||
}
|
||||
|
||||
return 100000000;
|
||||
}
|
||||
|
||||
unsigned long zynqmp_get_system_timer_freq(void)
|
||||
{
|
||||
u32 ver = zynqmp_get_silicon_version();
|
||||
|
||||
switch (ver) {
|
||||
case ZYNQMP_CSU_VERSION_VELOCE:
|
||||
return 10000;
|
||||
case ZYNQMP_CSU_VERSION_EP108:
|
||||
return 4000000;
|
||||
case ZYNQMP_CSU_VERSION_QEMU:
|
||||
return 50000000;
|
||||
}
|
||||
|
||||
return 100000000;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CLOCKS
|
||||
/**
|
||||
* set_cpu_clk_info() - Initialize clock framework
|
||||
* Always returns zero.
|
||||
*
|
||||
* This function is called from common code after relocation and sets up the
|
||||
* clock framework. The framework must not be used before this function had been
|
||||
* called.
|
||||
*/
|
||||
int set_cpu_clk_info(void)
|
||||
{
|
||||
gd->cpu_clk = get_tbclk();
|
||||
|
||||
/* Support Veloce to show at least 1MHz via bdi */
|
||||
if (gd->cpu_clk > 1000000)
|
||||
gd->bd->bi_arm_freq = gd->cpu_clk / 1000000;
|
||||
else
|
||||
gd->bd->bi_arm_freq = 1;
|
||||
|
||||
gd->bd->bi_dsp_freq = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
99
u-boot/arch/arm/cpu/armv8/zynqmp/cpu.c
Normal file
99
u-boot/arch/arm/cpu/armv8/zynqmp/cpu.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* (C) Copyright 2014 - 2015 Xilinx, Inc.
|
||||
* Michal Simek <michal.simek@xilinx.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define ZYNQ_SILICON_VER_MASK 0xF000
|
||||
#define ZYNQ_SILICON_VER_SHIFT 12
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct mm_region zynqmp_mem_map[] = {
|
||||
{
|
||||
.base = 0x0UL,
|
||||
.size = 0x80000000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_INNER_SHARE
|
||||
}, {
|
||||
.base = 0x80000000UL,
|
||||
.size = 0x70000000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
||||
PTE_BLOCK_NON_SHARE |
|
||||
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
||||
}, {
|
||||
.base = 0xf8000000UL,
|
||||
.size = 0x07e00000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
||||
PTE_BLOCK_NON_SHARE |
|
||||
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
||||
}, {
|
||||
.base = 0xffe00000UL,
|
||||
.size = 0x00200000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_INNER_SHARE
|
||||
}, {
|
||||
.base = 0x400000000UL,
|
||||
.size = 0x200000000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
||||
PTE_BLOCK_NON_SHARE |
|
||||
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
||||
}, {
|
||||
.base = 0x600000000UL,
|
||||
.size = 0x800000000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
|
||||
PTE_BLOCK_INNER_SHARE
|
||||
}, {
|
||||
.base = 0xe00000000UL,
|
||||
.size = 0xf200000000UL,
|
||||
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
||||
PTE_BLOCK_NON_SHARE |
|
||||
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
||||
}, {
|
||||
/* List terminator */
|
||||
0,
|
||||
}
|
||||
};
|
||||
struct mm_region *mem_map = zynqmp_mem_map;
|
||||
|
||||
u64 get_page_table_size(void)
|
||||
{
|
||||
return 0x14000;
|
||||
}
|
||||
|
||||
static unsigned int zynqmp_get_silicon_version_secure(void)
|
||||
{
|
||||
u32 ver;
|
||||
|
||||
ver = readl(&csu_base->version);
|
||||
ver &= ZYNQMP_SILICON_VER_MASK;
|
||||
ver >>= ZYNQMP_SILICON_VER_SHIFT;
|
||||
|
||||
return ver;
|
||||
}
|
||||
|
||||
unsigned int zynqmp_get_silicon_version(void)
|
||||
{
|
||||
if (current_el() == 3)
|
||||
return zynqmp_get_silicon_version_secure();
|
||||
|
||||
gd->cpu_clk = get_tbclk();
|
||||
|
||||
switch (gd->cpu_clk) {
|
||||
case 0 ... 1000000:
|
||||
return ZYNQMP_CSU_VERSION_VELOCE;
|
||||
case 50000000:
|
||||
return ZYNQMP_CSU_VERSION_QEMU;
|
||||
case 4000000:
|
||||
return ZYNQMP_CSU_VERSION_EP108;
|
||||
}
|
||||
|
||||
return ZYNQMP_CSU_VERSION_SILICON;
|
||||
}
|
||||
269
u-boot/arch/arm/cpu/armv8/zynqmp/mp.c
Normal file
269
u-boot/arch/arm/cpu/armv8/zynqmp/mp.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* (C) Copyright 2014 - 2015 Xilinx, Inc.
|
||||
* Michal Simek <michal.simek@xilinx.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define LOCK 0
|
||||
#define SPLIT 1
|
||||
|
||||
#define HALT 0
|
||||
#define RELEASE 1
|
||||
|
||||
#define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF
|
||||
#define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000
|
||||
#define ZYNQMP_R5_LOVEC_ADDR 0x0
|
||||
#define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01
|
||||
#define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04
|
||||
#define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08
|
||||
#define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40
|
||||
#define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10
|
||||
|
||||
#define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04
|
||||
#define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01
|
||||
#define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02
|
||||
#define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000
|
||||
|
||||
#define ZYNQMP_TCM_START_ADDRESS 0xFFE00000
|
||||
#define ZYNQMP_TCM_BOTH_SIZE 0x40000
|
||||
|
||||
#define ZYNQMP_CORE_APU0 0
|
||||
#define ZYNQMP_CORE_APU3 3
|
||||
|
||||
#define ZYNQMP_MAX_CORES 6
|
||||
|
||||
int is_core_valid(unsigned int core)
|
||||
{
|
||||
if (core < ZYNQMP_MAX_CORES)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_reset(int nr)
|
||||
{
|
||||
puts("Feature is not implemented.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_r5_halt_mode(u8 halt, u8 mode)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(&rpu_base->rpu0_cfg);
|
||||
if (halt == HALT)
|
||||
tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
|
||||
else
|
||||
tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
|
||||
writel(tmp, &rpu_base->rpu0_cfg);
|
||||
|
||||
if (mode == LOCK) {
|
||||
tmp = readl(&rpu_base->rpu1_cfg);
|
||||
if (halt == HALT)
|
||||
tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
|
||||
else
|
||||
tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
|
||||
writel(tmp, &rpu_base->rpu1_cfg);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_r5_tcm_mode(u8 mode)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(&rpu_base->rpu_glbl_ctrl);
|
||||
if (mode == LOCK) {
|
||||
tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
|
||||
tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
|
||||
ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK;
|
||||
} else {
|
||||
tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
|
||||
tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
|
||||
ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK);
|
||||
}
|
||||
|
||||
writel(tmp, &rpu_base->rpu_glbl_ctrl);
|
||||
}
|
||||
|
||||
static void set_r5_reset(u8 mode)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(&crlapb_base->rst_lpd_top);
|
||||
tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
|
||||
ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
|
||||
|
||||
if (mode == LOCK)
|
||||
tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
|
||||
|
||||
writel(tmp, &crlapb_base->rst_lpd_top);
|
||||
}
|
||||
|
||||
static void release_r5_reset(u8 mode)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(&crlapb_base->rst_lpd_top);
|
||||
tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
|
||||
ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
|
||||
|
||||
if (mode == LOCK)
|
||||
tmp &= ~ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
|
||||
|
||||
writel(tmp, &crlapb_base->rst_lpd_top);
|
||||
}
|
||||
|
||||
static void enable_clock_r5(void)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(&crlapb_base->cpu_r5_ctrl);
|
||||
tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
|
||||
writel(tmp, &crlapb_base->cpu_r5_ctrl);
|
||||
|
||||
/* Give some delay for clock
|
||||
* to propogate */
|
||||
udelay(0x500);
|
||||
}
|
||||
|
||||
int cpu_disable(int nr)
|
||||
{
|
||||
if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
|
||||
u32 val = readl(&crfapb_base->rst_fpd_apu);
|
||||
val |= 1 << nr;
|
||||
writel(val, &crfapb_base->rst_fpd_apu);
|
||||
} else {
|
||||
set_r5_reset(LOCK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_status(int nr)
|
||||
{
|
||||
if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
|
||||
u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
|
||||
u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) +
|
||||
nr * 8);
|
||||
u32 val = readl(&crfapb_base->rst_fpd_apu);
|
||||
val &= 1 << nr;
|
||||
printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n",
|
||||
nr, val ? "OFF" : "ON" , addr_high, addr_low);
|
||||
} else {
|
||||
u32 val = readl(&crlapb_base->rst_lpd_top);
|
||||
val &= 1 << (nr - 4);
|
||||
printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_r5_start(u8 high)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(&rpu_base->rpu0_cfg);
|
||||
if (high)
|
||||
tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
|
||||
else
|
||||
tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
|
||||
writel(tmp, &rpu_base->rpu0_cfg);
|
||||
|
||||
tmp = readl(&rpu_base->rpu1_cfg);
|
||||
if (high)
|
||||
tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
|
||||
else
|
||||
tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
|
||||
writel(tmp, &rpu_base->rpu1_cfg);
|
||||
}
|
||||
|
||||
static void write_tcm_boot_trampoline(u32 boot_addr)
|
||||
{
|
||||
if (boot_addr) {
|
||||
/*
|
||||
* Boot trampoline is simple ASM code below.
|
||||
*
|
||||
* b over;
|
||||
* label:
|
||||
* .word 0
|
||||
* over: ldr r0, =label
|
||||
* ldr r1, [r0]
|
||||
* bx r1
|
||||
*/
|
||||
debug("Write boot trampoline for %x\n", boot_addr);
|
||||
writel(0xea000000, ZYNQMP_TCM_START_ADDRESS);
|
||||
writel(boot_addr, ZYNQMP_TCM_START_ADDRESS + 0x4);
|
||||
writel(0xe59f0004, ZYNQMP_TCM_START_ADDRESS + 0x8);
|
||||
writel(0xe5901000, ZYNQMP_TCM_START_ADDRESS + 0xc);
|
||||
writel(0xe12fff11, ZYNQMP_TCM_START_ADDRESS + 0x10);
|
||||
writel(0x00000004, ZYNQMP_TCM_START_ADDRESS + 0x14); // address for
|
||||
}
|
||||
}
|
||||
|
||||
int cpu_release(int nr, int argc, char * const argv[])
|
||||
{
|
||||
if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {
|
||||
u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
|
||||
/* HIGH */
|
||||
writel((u32)(boot_addr >> 32),
|
||||
((u8 *)&apu_base->rvbar_addr0_h) + nr * 8);
|
||||
/* LOW */
|
||||
writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK),
|
||||
((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
|
||||
|
||||
u32 val = readl(&crfapb_base->rst_fpd_apu);
|
||||
val &= ~(1 << nr);
|
||||
writel(val, &crfapb_base->rst_fpd_apu);
|
||||
} else {
|
||||
if (argc != 2) {
|
||||
printf("Invalid number of arguments to release.\n");
|
||||
printf("<addr> <mode>-Start addr lockstep or split\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 boot_addr = simple_strtoul(argv[0], NULL, 16);
|
||||
u32 boot_addr_uniq = 0;
|
||||
if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
|
||||
boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
|
||||
printf("Using TCM jump trampoline for address 0x%x\n",
|
||||
boot_addr);
|
||||
/* Save boot address for later usage */
|
||||
boot_addr_uniq = boot_addr;
|
||||
/*
|
||||
* R5 needs to start from LOVEC at TCM
|
||||
* OCM will be probably occupied by ATF
|
||||
*/
|
||||
boot_addr = ZYNQMP_R5_LOVEC_ADDR;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[1], "lockstep", 8)) {
|
||||
printf("R5 lockstep mode\n");
|
||||
set_r5_tcm_mode(LOCK);
|
||||
set_r5_halt_mode(HALT, LOCK);
|
||||
set_r5_start(boot_addr);
|
||||
enable_clock_r5();
|
||||
release_r5_reset(LOCK);
|
||||
write_tcm_boot_trampoline(boot_addr_uniq);
|
||||
set_r5_halt_mode(RELEASE, LOCK);
|
||||
} else if (!strncmp(argv[1], "split", 5)) {
|
||||
printf("R5 split mode\n");
|
||||
set_r5_tcm_mode(SPLIT);
|
||||
set_r5_halt_mode(HALT, SPLIT);
|
||||
enable_clock_r5();
|
||||
release_r5_reset(SPLIT);
|
||||
write_tcm_boot_trampoline(boot_addr_uniq);
|
||||
set_r5_halt_mode(RELEASE, SPLIT);
|
||||
} else {
|
||||
printf("Unsupported mode\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
63
u-boot/arch/arm/cpu/armv8/zynqmp/slcr.c
Normal file
63
u-boot/arch/arm/cpu/armv8/zynqmp/slcr.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* (C) Copyright 2014 - 2015 Xilinx, Inc.
|
||||
* Michal Simek <michal.simek@xilinx.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/arch/clk.h>
|
||||
|
||||
/*
|
||||
* zynq_slcr_mio_get_status - Get the status of MIO peripheral.
|
||||
*
|
||||
* @peri_name: Name of the peripheral for checking MIO status
|
||||
* @get_pins: Pointer to array of get pin for this peripheral
|
||||
* @num_pins: Number of pins for this peripheral
|
||||
* @mask: Mask value
|
||||
* @check_val: Required check value to get the status of periph
|
||||
*/
|
||||
struct zynq_slcr_mio_get_status {
|
||||
const char *peri_name;
|
||||
const int *get_pins;
|
||||
int num_pins;
|
||||
u32 mask;
|
||||
u32 check_val;
|
||||
};
|
||||
|
||||
static const struct zynq_slcr_mio_get_status mio_periphs[] = {
|
||||
};
|
||||
|
||||
/*
|
||||
* zynq_slcr_get_mio_pin_status - Get the MIO pin status of peripheral.
|
||||
*
|
||||
* @periph: Name of the peripheral
|
||||
*
|
||||
* Returns count to indicate the number of pins configured for the
|
||||
* given @periph.
|
||||
*/
|
||||
int zynq_slcr_get_mio_pin_status(const char *periph)
|
||||
{
|
||||
const struct zynq_slcr_mio_get_status *mio_ptr;
|
||||
int val, i, j;
|
||||
int mio = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mio_periphs); i++) {
|
||||
if (strcmp(periph, mio_periphs[i].peri_name) == 0) {
|
||||
mio_ptr = &mio_periphs[i];
|
||||
for (j = 0; j < mio_ptr->num_pins; j++) {
|
||||
val = readl(&slcr_base->mio_pin
|
||||
[mio_ptr->get_pins[j]]);
|
||||
if ((val & mio_ptr->mask) == mio_ptr->check_val)
|
||||
mio++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mio;
|
||||
}
|
||||
107
u-boot/arch/arm/cpu/armv8/zynqmp/spl.c
Normal file
107
u-boot/arch/arm/cpu/armv8/zynqmp/spl.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2015 - 2016 Xilinx, Inc.
|
||||
*
|
||||
* Michal Simek <michal.simek@xilinx.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <debug_uart.h>
|
||||
#include <spl.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/spl.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
psu_init();
|
||||
board_early_init_r();
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART
|
||||
/* Uart debug for sure */
|
||||
debug_uart_init();
|
||||
puts("Debug uart enabled\n"); /* or printch() */
|
||||
#endif
|
||||
/* Delay is required for clocks to be propagated */
|
||||
udelay(1000000);
|
||||
|
||||
/* Clear the BSS */
|
||||
memset(__bss_start, 0, __bss_end - __bss_start);
|
||||
|
||||
/* No need to call timer init - it is empty for ZynqMP */
|
||||
board_init_r(NULL, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BOARD_INIT
|
||||
void spl_board_init(void)
|
||||
{
|
||||
preloader_console_init();
|
||||
board_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
u32 reg = 0;
|
||||
u8 bootmode;
|
||||
|
||||
reg = readl(&crlapb_base->boot_mode);
|
||||
bootmode = reg & BOOT_MODES_MASK;
|
||||
|
||||
switch (bootmode) {
|
||||
case JTAG_MODE:
|
||||
return BOOT_DEVICE_RAM;
|
||||
#ifdef CONFIG_SPL_MMC_SUPPORT
|
||||
case EMMC_MODE:
|
||||
case SD_MODE:
|
||||
case SD_MODE1:
|
||||
return BOOT_DEVICE_MMC1;
|
||||
#endif
|
||||
default:
|
||||
printf("Invalid Boot Mode:0x%x\n", bootmode);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 spl_boot_mode(const u32 boot_device)
|
||||
{
|
||||
switch (spl_boot_device()) {
|
||||
case BOOT_DEVICE_RAM:
|
||||
return 0;
|
||||
case BOOT_DEVICE_MMC1:
|
||||
return MMCSD_MODE_FS;
|
||||
default:
|
||||
puts("spl: error: unsupported device\n");
|
||||
hang();
|
||||
}
|
||||
}
|
||||
|
||||
__weak void psu_init(void)
|
||||
{
|
||||
/*
|
||||
* This function is overridden by the one in
|
||||
* board/xilinx/zynqmp/(platform)/psu_init_gpl.c, if it exists.
|
||||
*/
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_OS_BOOT
|
||||
int spl_start_uboot(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user