aboutsummaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorTom Rini2016-11-25 17:39:54 -0500
committerTom Rini2016-11-25 17:39:54 -0500
commited77ccd014b4073c4d282028cfb22f8d1742fec1 (patch)
tree0d3cf0fd0e45bf10c7897a24f3560589f7740e20 /arch/arm
parent136179bec19f4bc84227cba138214ea392a723ea (diff)
parent020198b0c7d251cf6bde76024ecf0ee711860534 (diff)
Merge git://git.denx.de/u-boot-fsl-qoriq
Signed-off-by: Tom Rini <trini@konsulko.com> Conflicts: arch/arm/Kconfig
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig21
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/cpu.c13
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/cpu.h1
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/doc/README.qspi42
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc58
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S111
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c6
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/mp.c78
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/soc.c13
-rw-r--r--arch/arm/cpu/armv8/sec_firmware_asm.S23
-rw-r--r--arch/arm/cpu/armv8/start.S8
-rw-r--r--arch/arm/cpu/armv8/transition.S35
-rw-r--r--arch/arm/dts/Makefile4
-rw-r--r--arch/arm/dts/fsl-ls1046a-qds-lpuart.dts16
-rw-r--r--arch/arm/dts/fsl-ls1046a-qds.dtsi4
-rw-r--r--arch/arm/dts/fsl-ls1046a.dtsi54
-rw-r--r--arch/arm/dts/ls1021a-iot-duart.dts16
-rw-r--r--arch/arm/dts/ls1021a-iot.dtsi103
-rw-r--r--arch/arm/include/asm/arch-fsl-layerscape/config.h1
-rw-r--r--arch/arm/include/asm/arch-fsl-layerscape/cpu.h4
-rw-r--r--arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h9
-rw-r--r--arch/arm/include/asm/arch-fsl-layerscape/mp.h6
-rw-r--r--arch/arm/include/asm/arch-fsl-layerscape/soc.h12
-rw-r--r--arch/arm/include/asm/macro.h176
-rw-r--r--arch/arm/include/asm/system.h121
-rw-r--r--arch/arm/lib/bootm.c45
-rw-r--r--arch/arm/mach-exynos/Kconfig1
-rw-r--r--arch/arm/mach-exynos/soc.c18
-rw-r--r--arch/arm/mach-rmobile/lowlevel_init_gen3.S9
29 files changed, 901 insertions, 107 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index acd689beccc..e6263c05359 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -131,6 +131,12 @@ config ARCH_OMAP2
select CPU_V7
select SUPPORT_SPL
+config ARM64_SUPPORT_AARCH32
+ bool "ARM64 system support AArch32 execution state"
+ default y if ARM64 && !TARGET_THUNDERX_88XX
+ help
+ This ARM64 system supports AArch32 execution state.
+
choice
prompt "Target select"
default TARGET_HIKEY
@@ -750,6 +756,20 @@ config TARGET_LS1021ATWR
select ARCH_SUPPORT_PSCI
select LS1_DEEP_SLEEP
+config TARGET_LS1021AIOT
+ bool "Support ls1021aiot"
+ select CPU_V7
+ select CPU_V7_HAS_NONSEC
+ select CPU_V7_HAS_VIRT
+ select SUPPORT_SPL
+ select ARCH_LS1021A
+ select ARCH_SUPPORT_PSCI
+ help
+ Support for Freescale LS1021AIOT platform.
+ The LS1021A Freescale board (IOT) is a high-performance
+ development platform that supports the QorIQ LS1021A
+ Layerscape Architecture processor.
+
config TARGET_LS1043AQDS
bool "Support ls1043aqds"
select ARCH_LS1043A
@@ -951,6 +971,7 @@ source "board/freescale/ls2080ardb/Kconfig"
source "board/freescale/ls1021aqds/Kconfig"
source "board/freescale/ls1043aqds/Kconfig"
source "board/freescale/ls1021atwr/Kconfig"
+source "board/freescale/ls1021aiot/Kconfig"
source "board/freescale/ls1046aqds/Kconfig"
source "board/freescale/ls1043ardb/Kconfig"
source "board/freescale/ls1046ardb/Kconfig"
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index 0b516e37d70..d6ee54642d2 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -191,7 +191,7 @@ void enable_caches(void)
}
#endif
-static inline u32 initiator_type(u32 cluster, int init_id)
+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;
@@ -306,12 +306,14 @@ u32 fsl_qoriq_core_to_type(unsigned int core)
return -1; /* cannot identify the cluster */
}
+#ifndef CONFIG_FSL_LSCH3
uint get_svr(void)
{
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
return gur_in32(&gur->svr);
}
+#endif
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
@@ -431,6 +433,7 @@ int timer_init(void)
#endif
#ifdef CONFIG_LS2080A
u32 __iomem *pctbenr = (u32 *)FSL_PMU_PCTBENR_OFFSET;
+ u32 svr_dev_id;
#endif
#ifdef COUNTER_FREQUENCY_REAL
unsigned long cntfrq = COUNTER_FREQUENCY_REAL;
@@ -453,6 +456,14 @@ int timer_init(void)
* Register (PCTBENR), which allows the watchdog to operate.
*/
setbits_le32(pctbenr, 0xff);
+ /*
+ * For LS2080A SoC and its personalities, timer controller
+ * offset is different
+ */
+ svr_dev_id = get_svr() >> 16;
+ if (svr_dev_id == SVR_DEV_LS2080A)
+ cntcr = (u32 *)SYS_FSL_LS2080A_LS2085A_TIMER_ADDR;
+
#endif
/* Enable clock for timer
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.h b/arch/arm/cpu/armv8/fsl-layerscape/cpu.h
index 8072f3ca6a0..a05f8aad617 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.h
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.h
@@ -5,4 +5,5 @@
*/
int fsl_qoriq_core_to_cluster(unsigned int core);
+u32 initiator_type(u32 cluster, int init_id);
u32 cpu_mask(void);
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.qspi b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.qspi
new file mode 100644
index 00000000000..de86f4b3079
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.qspi
@@ -0,0 +1,42 @@
+QSPI Boot source support Overview
+-------------------
+ 1. LS1043A
+ LS1043AQDS
+ 2. LS2080A
+ LS2080AQDS
+ 3. LS1012A
+ LS1012AQDS
+ LS1012ARDB
+ 4. LS1046A
+ LS1046AQDS
+ LS1046ARDB
+
+Booting from QSPI
+-------------------
+Booting from QSPI requires two images, RCW and u-boot-dtb.bin.
+The difference between QSPI boot RCW image and NOR boot image is the PBI
+command sequence for setting the boot location pointer. It's should point
+to the address for u-boot in QSPI flash.
+
+RCW image should be written to the beginning of QSPI flash device.
+Example of using u-boot command
+
+=> sf probe 0:0
+SF: Detected S25FL256S_64K with page size 256 Bytes, erase size 64 KiB, total 32 MiB
+=> sf erase 0 +<size of rcw image>
+SF: 65536 bytes @ 0x0 Erased: OK
+=> sf write <rcw image in memory> 0 <size of rcw image>
+SF: 164 bytes @ 0x0 Written: OK
+
+To get the QSPI image, build u-boot with QSPI config, for example,
+<board_name>_qspi_defconfig. The image needed is u-boot-dtb.bin.
+The u-boot image should be written to 0x10000(but 0x1000 for LS1043A, LS2080A).
+
+=> sf probe 0:0
+SF: Detected S25FL256S_64K with page size 256 Bytes, erase size 64 KiB, total 32 MiB
+=> sf erase 10000 +<size of u-boot image>
+SF: 589824 bytes @ 0x10000 Erased: OK
+=> sf write <u-boot image in memory> 10000 <size of u-boot image>
+SF: 580966 bytes @ 0x10000 Written: OK
+
+With these two images in QSPI flash device, the board can boot from QSPI.
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
index f7b949aca22..c7496c02f57 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
+++ b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.soc
@@ -4,6 +4,7 @@ SoC overview
2. LS2080A
3. LS1012A
4. LS1046A
+ 5. LS2088A
LS1043A
---------
@@ -169,3 +170,60 @@ The LS1046A SoC includes the following function and features:
- Two DUARTs
- Integrated flash controller (IFC) supporting NAND and NOR flash
- QorIQ platform's trust architecture 2.1
+
+LS2088A
+--------
+The LS2088A integrated multicore processor combines eight ARM Cortex-A72
+processor cores with high-performance data path acceleration logic and network
+and peripheral bus interfaces required for networking, telecom/datacom,
+wireless infrastructure, and mil/aerospace applications.
+
+The LS2088A SoC includes the following function and features:
+
+ - Eight 64-bit ARM Cortex-A72 CPUs
+ - 1 MB platform cache with ECC
+ - Two 64-bit DDR4 SDRAM memory controllers with ECC and interleaving support
+ - One secondary 32-bit DDR4 SDRAM memory controller, intended for use by
+ the AIOP
+ - Data path acceleration architecture (DPAA2) incorporating acceleration for
+ the following functions:
+ - Packet parsing, classification, and distribution (WRIOP)
+ - Queue and Hardware buffer management for scheduling, packet sequencing, and
+ congestion management, buffer allocation and de-allocation (QBMan)
+ - Cryptography acceleration (SEC) at up to 10 Gbps
+ - RegEx pattern matching acceleration (PME) at up to 10 Gbps
+ - Decompression/compression acceleration (DCE) at up to 20 Gbps
+ - Accelerated I/O processing (AIOP) at up to 20 Gbps
+ - QDMA engine
+ - 16 SerDes lanes at up to 10.3125 GHz
+ - Ethernet interfaces
+ - Up to eight 10 Gbps Ethernet MACs
+ - Up to eight 1 / 2.5 Gbps Ethernet MACs
+ - High-speed peripheral interfaces
+ - Four PCIe 3.0 controllers, one supporting SR-IOV
+ - Additional peripheral interfaces
+ - Two serial ATA (SATA 3.0) controllers
+ - Two high-speed USB 3.0 controllers with integrated PHY
+ - Enhanced secure digital host controller (eSDXC/eMMC)
+ - Serial peripheral interface (SPI) controller
+ - Quad Serial Peripheral Interface (QSPI) Controller
+ - Four I2C controllers
+ - Two DUARTs
+ - Integrated flash controller (IFC 2.0) supporting NAND and NOR flash
+ - Support for hardware virtualization and partitioning enforcement
+ - QorIQ platform's trust architecture 3.0
+ - Service processor (SP) provides pre-boot initialization and secure-boot
+ capabilities
+
+LS2088A SoC has 3 more similar SoC personalities
+1)LS2048A, few difference w.r.t. LS2088A:
+ a) Four 64-bit ARM v8 Cortex-A72 CPUs
+
+2)LS2084A, few difference w.r.t. LS2088A:
+ a) No AIOP
+ b) No 32-bit DDR3 SDRAM memory
+ c) 5 * 1/10G + 5 *1G WRIOP
+ d) No L2 switch
+
+3)LS2044A, few difference w.r.t. LS2084A:
+ a) Four 64-bit ARM v8 Cortex-A72 CPUs
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
index 5700b1fb654..72f2c11baf6 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
+++ b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
@@ -13,6 +13,11 @@
#ifdef CONFIG_MP
#include <asm/arch/mp.h>
#endif
+#ifdef CONFIG_FSL_LSCH3
+#include <asm/arch-fsl-layerscape/immap_lsch3.h>
+#include <asm/arch-fsl-layerscape/soc.h>
+#endif
+#include <asm/u-boot.h>
ENTRY(lowlevel_init)
mov x29, lr /* Save LR */
@@ -137,6 +142,16 @@ ENTRY(lowlevel_init)
#endif
#ifdef CONFIG_FSL_TZASC_400
+ /*
+ * LS2080 and its personalities does not support TZASC
+ * So skip TZASC related operations
+ */
+ bl get_svr
+ lsr w0, w0, #16
+ ldr w1, =SVR_DEV_LS2080A
+ cmp w0, w1
+ b.eq 1f
+
/* Set TZASC so that:
* a. We use only Region0 whose global secure write/read is EN
* b. We use only Region0 whose NSAID write/read is EN
@@ -145,26 +160,26 @@ ENTRY(lowlevel_init)
* 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 w0, [x1] /* Filter 0 Gate Keeper Register */
+ orr w0, w0, #1 << 0 /* Set open_request for Filter 0 */
+ str w0, [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 w0, [x1] /* Filter 0 Gate Keeper Register */
+ orr w0, w0, #1 << 0 /* Set open_request for Filter 0 */
+ str w0, [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 w0, [x1] /* Region-0 Attributes Register */
+ orr w0, w0, #1 << 31 /* Set Sec global write en, Bit[31] */
+ orr w0, w0, #1 << 30 /* Set Sec global read en, Bit[30] */
+ str w0, [x1]
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 w0, [x1] /* Region-1 Attributes Register */
+ orr w0, w0, #1 << 31 /* Set Sec global write en, Bit[31] */
+ orr w0, w0, #1 << 30 /* Set Sec global read en, Bit[30] */
+ str w0, [x1]
ldr x1, =TZASC_REGION_ID_ACCESS_0(0)
ldr w0, [x1] /* Region-0 Access Register */
@@ -179,7 +194,7 @@ ENTRY(lowlevel_init)
isb
dsb sy
#endif
-
+1:
#ifdef CONFIG_ARCH_LS1046A
/* Initialize the L2 RAM latency */
mrs x1, S3_1_c11_c0_2
@@ -199,6 +214,12 @@ ENTRY(lowlevel_init)
ENDPROC(lowlevel_init)
#ifdef CONFIG_FSL_LSCH3
+ .globl get_svr
+get_svr:
+ ldr x1, =FSL_LSCH3_SVR
+ ldr w0, [x1]
+ ret
+
hnf_pstate_poll:
/* x0 has the desired status, return 0 for success, 1 for timeout
* clobber x1, x2, x3, x4, x6, x7
@@ -339,11 +360,6 @@ ENTRY(secondary_boot_func)
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]
@@ -356,19 +372,64 @@ slave_cpu:
tbz x1, #25, cpu_is_le
rev x0, x0 /* BE to LE conversion */
cpu_is_le:
- br x0 /* branch to the given address */
+ ldr x5, [x11, #24]
+ ldr x6, =IH_ARCH_DEFAULT
+ cmp x6, x5
+ b.eq 1f
+
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ adr x3, secondary_switch_to_el1
+ ldr x4, =ES_TO_AARCH64
+#else
+ ldr x3, [x11]
+ ldr x4, =ES_TO_AARCH32
+#endif
+ bl secondary_switch_to_el2
+
+1:
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ adr x3, secondary_switch_to_el1
+#else
+ ldr x3, [x11]
+#endif
+ ldr x4, =ES_TO_AARCH64
+ bl secondary_switch_to_el2
+
ENDPROC(secondary_boot_func)
ENTRY(secondary_switch_to_el2)
- switch_el x0, 1f, 0f, 0f
+ switch_el x5, 1f, 0f, 0f
0: ret
-1: armv8_switch_to_el2_m x0
+1: armv8_switch_to_el2_m x3, x4, x5
ENDPROC(secondary_switch_to_el2)
ENTRY(secondary_switch_to_el1)
- switch_el x0, 0f, 1f, 0f
+ mrs x0, mpidr_el1
+ ubfm x1, x0, #8, #15
+ ubfm x2, x0, #0, #1
+ orr x10, x2, x1, lsl #2 /* x10 has LPID */
+
+ lsl x1, x10, #6
+ ldr x0, =__spin_table
+ /* physical address of this cpus spin table element */
+ add x11, x1, x0
+
+ ldr x3, [x11]
+
+ ldr x5, [x11, #24]
+ ldr x6, =IH_ARCH_DEFAULT
+ cmp x6, x5
+ b.eq 2f
+
+ ldr x4, =ES_TO_AARCH32
+ bl switch_to_el1
+
+2: ldr x4, =ES_TO_AARCH64
+
+switch_to_el1:
+ switch_el x5, 0f, 1f, 0f
0: ret
-1: armv8_switch_to_el1_m x0, x1
+1: armv8_switch_to_el1_m x3, x4, x5
ENDPROC(secondary_switch_to_el1)
/* Ensure that the literals used by the secondary boot code are
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c
index eaa44a74c5b..67d605e38b1 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/ls2080a_serdes.c
@@ -34,6 +34,11 @@ static struct serdes_config serdes1_cfg_tbl[] = {
{0x33, {PCIE2, PCIE2, PCIE2, PCIE2, QSGMII_D, QSGMII_C, QSGMII_B,
QSGMII_A} },
{0x35, {QSGMII_D, QSGMII_C, QSGMII_B, PCIE2, XFI4, XFI3, XFI2, XFI1 } },
+ {0x39, {SGMII8, SGMII7, SGMII6, PCIE2, SGMII4, SGMII3, SGMII2,
+ PCIE1 } },
+ {0x4B, {PCIE2, PCIE2, PCIE2, PCIE2, XFI4, XFI3, XFI2, XFI1 } },
+ {0x4C, {XFI8, XFI7, XFI6, XFI5, PCIE1, PCIE1, PCIE1, PCIE1 } },
+ {0x4D, {SGMII8, SGMII7, PCIE2, PCIE2, SGMII4, SGMII3, PCIE1, PCIE1 } },
{}
};
static struct serdes_config serdes2_cfg_tbl[] = {
@@ -64,6 +69,7 @@ static struct serdes_config serdes2_cfg_tbl[] = {
SATA2 } },
{0x4A, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1,
SATA2 } },
+ {0x57, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SGMII15, SGMII16 } },
{}
};
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/mp.c b/arch/arm/cpu/armv8/fsl-layerscape/mp.c
index f607c3900ad..80fe1ade2e6 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/mp.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/mp.c
@@ -9,6 +9,8 @@
#include <asm/system.h>
#include <asm/arch/mp.h>
#include <asm/arch/soc.h>
+#include "cpu.h"
+#include <asm/arch-fsl-layerscape/soc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -22,11 +24,49 @@ phys_addr_t determine_mp_bootpg(void)
return (phys_addr_t)&secondary_boot_code;
}
+void update_os_arch_secondary_cores(uint8_t os_arch)
+{
+ u64 *table = get_spin_tbl_addr();
+ int i;
+
+ for (i = 1; i < CONFIG_MAX_CPUS; i++)
+ table[i * WORDS_PER_SPIN_TABLE_ENTRY +
+ SPIN_TABLE_ELEM_OS_ARCH_IDX] = os_arch;
+}
+
+#ifdef CONFIG_FSL_LSCH3
+void wake_secondary_core_n(int cluster, int core, int cluster_cores)
+{
+ struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+ struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
+ u32 mpidr = 0;
+
+ mpidr = ((cluster << 8) | core);
+ /*
+ * mpidr_el1 register value of core which needs to be released
+ * is written to scratchrw[6] register
+ */
+ gur_out32(&gur->scratchrw[6], mpidr);
+ asm volatile("dsb st" : : : "memory");
+ rst->brrl |= 1 << ((cluster * cluster_cores) + core);
+ asm volatile("dsb st" : : : "memory");
+ /*
+ * scratchrw[6] register value is polled
+ * when the value becomes zero, this means that this core is up
+ * and running, next core can be released now
+ */
+ while (gur_in32(&gur->scratchrw[6]) != 0)
+ ;
+}
+#endif
+
int fsl_layerscape_wake_seconday_cores(void)
{
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
#ifdef CONFIG_FSL_LSCH3
struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
+ u32 svr, ver, cluster, type;
+ int j = 0, cluster_cores = 0;
#elif defined(CONFIG_FSL_LSCH2)
struct ccsr_scfg __iomem *scfg = (void *)(CONFIG_SYS_FSL_SCFG_ADDR);
#endif
@@ -55,10 +95,40 @@ int fsl_layerscape_wake_seconday_cores(void)
#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");
+
+ svr = gur_in32(&gur->svr);
+ ver = SVR_SOC_VER(svr);
+ if (ver == SVR_LS2080A || ver == SVR_LS2085A) {
+ gur_out32(&gur->scratchrw[6], 1);
+ asm volatile("dsb st" : : : "memory");
+ rst->brrl = cores;
+ asm volatile("dsb st" : : : "memory");
+ } else {
+ /*
+ * Release the cores out of reset one-at-a-time to avoid
+ * power spikes
+ */
+ i = 0;
+ cluster = in_le32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ type = initiator_type(cluster, j);
+ if (type &&
+ TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
+ cluster_cores++;
+ }
+
+ do {
+ cluster = in_le32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ type = initiator_type(cluster, j);
+ if (type &&
+ TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
+ wake_secondary_core_n(i, j,
+ cluster_cores);
+ }
+ i++;
+ } while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
+ }
#elif defined(CONFIG_FSL_LSCH2)
scfg_out32(&scfg->scratchrw[0], (u32)(gd->relocaddr >> 32));
scfg_out32(&scfg->scratchrw[1], (u32)gd->relocaddr);
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
index d68eeba349a..6c4238707d1 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
@@ -31,8 +31,10 @@ 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)
+ /* LS2085A, LS2088A, LS2048A has DP_DDR */
+ if ((SVR_SOC_VER(svr) == SVR_LS2085A) ||
+ (SVR_SOC_VER(svr) == SVR_LS2088A) ||
+ (SVR_SOC_VER(svr) == SVR_LS2048A))
return true;
return false;
@@ -50,16 +52,16 @@ bool soc_has_aiop(void)
return false;
}
-#ifdef CONFIG_LS2080A
+#if defined(CONFIG_FSL_LSCH3)
/*
* This erratum requires setting a value to eddrtqcr1 to
* optimal the DDR performance.
*/
static void erratum_a008336(void)
{
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008336
u32 *eddrtqcr1;
-#ifdef CONFIG_SYS_FSL_ERRATUM_A008336
#ifdef CONFIG_SYS_FSL_DCSR_DDR_ADDR
eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR_ADDR + 0x800;
if (fsl_ddr_get_version(0) == 0x50200)
@@ -79,9 +81,9 @@ static void erratum_a008336(void)
*/
static void erratum_a008514(void)
{
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008514
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);
@@ -176,6 +178,7 @@ static void erratum_a009203(void)
#endif
#endif
}
+
void bypass_smmu(void)
{
u32 val;
diff --git a/arch/arm/cpu/armv8/sec_firmware_asm.S b/arch/arm/cpu/armv8/sec_firmware_asm.S
index 0c6a46249a2..1b39f1d3227 100644
--- a/arch/arm/cpu/armv8/sec_firmware_asm.S
+++ b/arch/arm/cpu/armv8/sec_firmware_asm.S
@@ -50,4 +50,27 @@ ENTRY(_sec_firmware_support_psci_version)
smc #0
ret
ENDPROC(_sec_firmware_support_psci_version)
+
+/*
+ * Switch from AArch64 EL2 to AArch32 EL2
+ * @param inputs:
+ * x0: argument, zero
+ * x1: machine nr
+ * x2: fdt address
+ * x3: kernel entry point
+ * @param outputs for secure firmware:
+ * x0: function id
+ * x1: kernel entry point
+ * x2: machine nr
+ * x3: fdt address
+*/
+ENTRY(armv8_el2_to_aarch32)
+ mov x0, x3
+ mov x3, x2
+ mov x2, x1
+ mov x1, x0
+ ldr x0, =0xc000ff04
+ smc #0
+ ret
+ENDPROC(armv8_el2_to_aarch32)
#endif
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index 19c771dba3a..4f5f6d8020f 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -251,9 +251,17 @@ WEAK(lowlevel_init)
/*
* All slaves will enter EL2 and optionally EL1.
*/
+ adr x3, lowlevel_in_el2
+ ldr x4, =ES_TO_AARCH64
bl armv8_switch_to_el2
+
+lowlevel_in_el2:
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ adr x3, lowlevel_in_el1
+ ldr x4, =ES_TO_AARCH64
bl armv8_switch_to_el1
+
+lowlevel_in_el1:
#endif
#endif /* CONFIG_ARMV8_MULTIENTRY */
diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S
index 253a39bd113..adb9f3566bf 100644
--- a/arch/arm/cpu/armv8/transition.S
+++ b/arch/arm/cpu/armv8/transition.S
@@ -11,13 +11,36 @@
#include <asm/macro.h>
ENTRY(armv8_switch_to_el2)
- switch_el x0, 1f, 0f, 0f
-0: ret
-1: armv8_switch_to_el2_m x0
+ switch_el x5, 1f, 0f, 0f
+0:
+ cmp x4, #ES_TO_AARCH64
+ b.eq 2f
+ /*
+ * When loading 32-bit kernel, it will jump
+ * to secure firmware again, and never return.
+ */
+ bl armv8_el2_to_aarch32
+2:
+ /*
+ * x3 is kernel entry point or switch_to_el1
+ * if CONFIG_ARMV8_SWITCH_TO_EL1 is defined.
+ * When running in EL2 now, jump to the
+ * address saved in x3.
+ */
+ br x3
+1: armv8_switch_to_el2_m x3, x4, x5
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
+ switch_el x5, 0f, 1f, 0f
+0:
+ /* x3 is kernel entry point. When running in EL1
+ * now, jump to the address saved in x3.
+ */
+ br x3
+1: armv8_switch_to_el1_m x3, x4, x5
ENDPROC(armv8_switch_to_el1)
+
+WEAK(armv8_el2_to_aarch32)
+ ret
+ENDPROC(armv8_el2_to_aarch32)
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 2c5b2f22c64..26f1e92ee4a 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -143,13 +143,15 @@ dtb-$(CONFIG_TARGET_STV0991) += stv0991.dtb
dtb-$(CONFIG_LS102XA) += ls1021a-qds-duart.dtb \
ls1021a-qds-lpuart.dtb \
- ls1021a-twr-duart.dtb ls1021a-twr-lpuart.dtb
+ ls1021a-twr-duart.dtb ls1021a-twr-lpuart.dtb \
+ ls1021a-iot-duart.dtb
dtb-$(CONFIG_FSL_LSCH3) += fsl-ls2080a-qds.dtb \
fsl-ls2080a-rdb.dtb
dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds-duart.dtb \
fsl-ls1043a-qds-lpuart.dtb \
fsl-ls1043a-rdb.dtb \
fsl-ls1046a-qds-duart.dtb \
+ fsl-ls1046a-qds-lpuart.dtb \
fsl-ls1046a-rdb.dtb \
fsl-ls1012a-qds.dtb \
fsl-ls1012a-rdb.dtb \
diff --git a/arch/arm/dts/fsl-ls1046a-qds-lpuart.dts b/arch/arm/dts/fsl-ls1046a-qds-lpuart.dts
new file mode 100644
index 00000000000..21243d07663
--- /dev/null
+++ b/arch/arm/dts/fsl-ls1046a-qds-lpuart.dts
@@ -0,0 +1,16 @@
+/*
+ * Device Tree file for Freescale Layerscape-1046A family SoC.
+ *
+ * Copyright (C) 2016, Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "fsl-ls1046a-qds.dtsi"
+
+/ {
+ chosen {
+ stdout-path = &lpuart0;
+ };
+};
diff --git a/arch/arm/dts/fsl-ls1046a-qds.dtsi b/arch/arm/dts/fsl-ls1046a-qds.dtsi
index c5122930fe1..a49ca08d888 100644
--- a/arch/arm/dts/fsl-ls1046a-qds.dtsi
+++ b/arch/arm/dts/fsl-ls1046a-qds.dtsi
@@ -75,3 +75,7 @@
&duart1 {
status = "okay";
};
+
+&lpuart0 {
+ status = "okay";
+};
diff --git a/arch/arm/dts/fsl-ls1046a.dtsi b/arch/arm/dts/fsl-ls1046a.dtsi
index 87dd9976d15..359a9d13bf8 100644
--- a/arch/arm/dts/fsl-ls1046a.dtsi
+++ b/arch/arm/dts/fsl-ls1046a.dtsi
@@ -151,6 +151,60 @@
clocks = <&clockgen 4 0>;
};
+ lpuart0: serial@2950000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2950000 0x0 0x1000>;
+ interrupts = <0 48 0x4>;
+ clocks = <&clockgen 4 0>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart1: serial@2960000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2960000 0x0 0x1000>;
+ interrupts = <0 49 0x4>;
+ clocks = <&clockgen 4 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart2: serial@2970000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2970000 0x0 0x1000>;
+ interrupts = <0 50 0x4>;
+ clocks = <&clockgen 4 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart3: serial@2980000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2980000 0x0 0x1000>;
+ interrupts = <0 51 0x4>;
+ clocks = <&clockgen 4 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart4: serial@2990000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2990000 0x0 0x1000>;
+ interrupts = <0 52 0x4>;
+ clocks = <&clockgen 4 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart5: serial@29a0000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x29a0000 0x0 0x1000>;
+ interrupts = <0 53 0x4>;
+ clocks = <&clockgen 4 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
qspi: quadspi@1550000 {
compatible = "fsl,vf610-qspi";
#address-cells = <1>;
diff --git a/arch/arm/dts/ls1021a-iot-duart.dts b/arch/arm/dts/ls1021a-iot-duart.dts
new file mode 100644
index 00000000000..62e4c670403
--- /dev/null
+++ b/arch/arm/dts/ls1021a-iot-duart.dts
@@ -0,0 +1,16 @@
+/*
+ * Freescale ls1021a IOT board device tree source
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ls1021a-iot.dtsi"
+
+/ {
+ chosen {
+ stdout-path = &uart0;
+ };
+};
diff --git a/arch/arm/dts/ls1021a-iot.dtsi b/arch/arm/dts/ls1021a-iot.dtsi
new file mode 100644
index 00000000000..1817c62c04c
--- /dev/null
+++ b/arch/arm/dts/ls1021a-iot.dtsi
@@ -0,0 +1,103 @@
+/*
+ * Freescale ls1021a IOT board device tree source
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+
+#include "ls1021a.dtsi"
+
+/ {
+ model = "LS1021A IOT Board";
+
+ aliases {
+ enet2_rgmii_phy = &rgmii_phy1;
+ enet0_sgmii_phy = &sgmii_phy2;
+ enet1_sgmii_phy = &sgmii_phy0;
+ spi0 = &qspi;
+ spi1 = &dspi1;
+ };
+};
+
+&qspi {
+ bus-num = <0>;
+ status = "okay";
+
+ qflash0: n25q128a13@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-flash";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ };
+};
+
+&dspi1 {
+ bus-num = <0>;
+ status = "okay";
+
+ dspiflash: at26df081a@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-flash";
+ spi-max-frequency = <16000000>;
+ spi-cpol;
+ spi-cpha;
+ reg = <0>;
+ };
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&ifc {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ /* NOR Flash on board */
+ ranges = <0x0 0x0 0x60000000 0x08000000>;
+ status = "okay";
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+};
+
+&lpuart0 {
+ status = "okay";
+};
+
+&mdio0 {
+ sgmii_phy0: ethernet-phy@0 {
+ reg = <0x0>;
+ };
+ rgmii_phy1: ethernet-phy@1 {
+ reg = <0x1>;
+ };
+ sgmii_phy2: ethernet-phy@2 {
+ reg = <0x2>;
+ };
+ tbi1: tbi-phy@1f {
+ reg = <0x1f>;
+ device_type = "tbi-phy";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/config.h b/arch/arm/include/asm/arch-fsl-layerscape/config.h
index 4201e0fbec4..6c3ba494f89 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/config.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/config.h
@@ -25,6 +25,7 @@
#ifndef L1_CACHE_BYTES
#define L1_CACHE_SHIFT 6
#define L1_CACHE_BYTES BIT(L1_CACHE_SHIFT)
+#define CONFIG_FSL_TZASC_400
#endif
#define CONFIG_SYS_FSL_OCRAM_BASE 0x18000000 /* initial RAM */
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h
index e2d96a1b781..a97be5c098a 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h
@@ -11,6 +11,10 @@ static struct cpu_type cpu_type_list[] = {
CPU_TYPE_ENTRY(LS2080A, LS2080A, 8),
CPU_TYPE_ENTRY(LS2085A, LS2085A, 8),
CPU_TYPE_ENTRY(LS2045A, LS2045A, 4),
+ CPU_TYPE_ENTRY(LS2088A, LS2088A, 8),
+ CPU_TYPE_ENTRY(LS2084A, LS2084A, 8),
+ CPU_TYPE_ENTRY(LS2048A, LS2048A, 4),
+ CPU_TYPE_ENTRY(LS2044A, LS2044A, 4),
CPU_TYPE_ENTRY(LS1043A, LS1043A, 4),
CPU_TYPE_ENTRY(LS1023A, LS1023A, 2),
CPU_TYPE_ENTRY(LS1046A, LS1046A, 4),
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
index 7acba2730aa..2df56f7a5b2 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
@@ -23,10 +23,12 @@
#define CONFIG_SYS_IFC_ADDR (CONFIG_SYS_IMMR + 0x01240000)
#define CONFIG_SYS_NS16550_COM1 (CONFIG_SYS_IMMR + 0x011C0500)
#define CONFIG_SYS_NS16550_COM2 (CONFIG_SYS_IMMR + 0x011C0600)
-#define CONFIG_SYS_FSL_TIMER_ADDR 0x023d0000
+#define SYS_FSL_LS2080A_LS2085A_TIMER_ADDR 0x023d0000
+#define CONFIG_SYS_FSL_TIMER_ADDR 0x023e0000
#define CONFIG_SYS_FSL_PMU_CLTBENR (CONFIG_SYS_FSL_PMU_ADDR + \
0x18A0)
#define FSL_PMU_PCTBENR_OFFSET (CONFIG_SYS_FSL_PMU_ADDR + 0x8A0)
+#define FSL_LSCH3_SVR (CONFIG_SYS_FSL_GUTS_ADDR + 0xA4)
#define CONFIG_SYS_FSL_WRIOP1_ADDR (CONFIG_SYS_IMMR + 0x7B80000)
#define CONFIG_SYS_FSL_WRIOP1_MDIO1 (CONFIG_SYS_FSL_WRIOP1_ADDR + 0x16000)
@@ -153,7 +155,7 @@
#define TP_CLUSTER_INIT_MASK 0x0000003f /* initiator mask */
#define TP_INIT_PER_CLUSTER 4
/* This is chassis generation 3 */
-
+#ifndef __ASSEMBLY__
struct sys_info {
unsigned long freq_processor[CONFIG_MAX_CPUS];
unsigned long freq_systembus;
@@ -317,6 +319,5 @@ struct ccsr_reset {
u32 ip_rev2; /* 0xbfc */
};
-uint get_svr(void);
-
+#endif /*__ASSEMBLY__*/
#endif /* __ARCH_FSL_LSCH3_IMMAP_H_ */
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/mp.h b/arch/arm/include/asm/arch-fsl-layerscape/mp.h
index f7306ff2667..d0832b54bc5 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/mp.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/mp.h
@@ -13,6 +13,7 @@
* uint64_t entry_addr;
* uint64_t status;
* uint64_t lpid;
+* uint64_t os_arch;
* };
* we pad this struct to 64 bytes so each entry is in its own cacheline
* the actual spin table is an array of these structures
@@ -20,6 +21,7 @@
#define SPIN_TABLE_ELEM_ENTRY_ADDR_IDX 0
#define SPIN_TABLE_ELEM_STATUS_IDX 1
#define SPIN_TABLE_ELEM_LPID_IDX 2
+#define SPIN_TABLE_ELEM_OS_ARCH_IDX 3
#define WORDS_PER_SPIN_TABLE_ENTRY 8 /* pad to 64 bytes */
#define SPIN_TABLE_ELEM_SIZE 64
@@ -36,4 +38,8 @@ void secondary_boot_func(void);
int is_core_online(u64 cpu_id);
u32 cpu_pos_mask(void);
#endif
+
+#define IH_ARCH_ARM 2 /* ARM */
+#define IH_ARCH_ARM64 22 /* ARM64 */
+
#endif /* _FSL_LAYERSCAPE_MP_H */
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/soc.h b/arch/arm/include/asm/arch-fsl-layerscape/soc.h
index 58e90d8d881..78363b602c7 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/soc.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/soc.h
@@ -30,7 +30,7 @@
#define pex_lut_in32(a) in_be32(a)
#define pex_lut_out32(a, v) out_be32(a, v)
#endif
-
+#ifndef __ASSEMBLY__
struct cpu_type {
char name[15];
u32 soc_ver;
@@ -39,7 +39,7 @@ struct cpu_type {
#define CPU_TYPE_ENTRY(n, v, nc) \
{ .name = #n, .soc_ver = SVR_##v, .num_cores = (nc)}
-
+#endif
#define SVR_WO_E 0xFFFFFE
#define SVR_LS1012A 0x870400
#define SVR_LS1043A 0x879200
@@ -50,6 +50,12 @@ struct cpu_type {
#define SVR_LS2080A 0x870110
#define SVR_LS2085A 0x870100
#define SVR_LS2040A 0x870130
+#define SVR_LS2088A 0x870900
+#define SVR_LS2084A 0x870910
+#define SVR_LS2048A 0x870920
+#define SVR_LS2044A 0x870930
+
+#define SVR_DEV_LS2080A 0x8701
#define SVR_MAJ(svr) (((svr) >> 4) & 0xf)
#define SVR_MIN(svr) (((svr) >> 0) & 0xf)
@@ -63,6 +69,7 @@ struct cpu_type {
#define AHCI_PORT_TRANS_CFG 0x08000029
#define AHCI_PORT_AXICC_CFG 0x3fffffff
+#ifndef __ASSEMBLY__
/* AHCI (sata) register map */
struct ccsr_ahci {
u32 res1[0xa4/4]; /* 0x0 - 0xa4 */
@@ -105,4 +112,5 @@ void erratum_a010315(void);
bool soc_has_dp_ddr(void);
bool soc_has_aiop(void);
+#endif
#endif /* _ASM_ARMV8_FSL_LAYERSCAPE_SOC_H_ */
diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
index 9bb0efa5ff0..2553e3e349c 100644
--- a/arch/arm/include/asm/macro.h
+++ b/arch/arm/include/asm/macro.h
@@ -8,6 +8,11 @@
#ifndef __ASM_ARM_MACRO_H__
#define __ASM_ARM_MACRO_H__
+
+#ifdef CONFIG_ARM64
+#include <asm/system.h>
+#endif
+
#ifdef __ASSEMBLY__
/*
@@ -135,13 +140,21 @@ lr .req x30
#endif
.endm
-.macro armv8_switch_to_el2_m, xreg1
- /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1 */
- mov \xreg1, #0x5b1
- msr scr_el3, \xreg1
+/*
+ * Switch from EL3 to EL2 for ARMv8
+ * @ep: kernel entry point
+ * @flag: The execution state flag for lower exception
+ * level, ES_TO_AARCH64 or ES_TO_AARCH32
+ * @tmp: temporary register
+ *
+ * For loading 32-bit OS, x1 is machine nr and x2 is ftaddr.
+ * For loading 64-bit OS, x0 is physical address to the FDT blob.
+ * They will be passed to the guest.
+ */
+.macro armv8_switch_to_el2_m, ep, flag, tmp
msr cptr_el3, xzr /* Disable coprocessor traps to EL3 */
- mov \xreg1, #0x33ff
- msr cptr_el2, \xreg1 /* Disable coprocessor traps to EL2 */
+ mov \tmp, #CPTR_EL2_RES1
+ msr cptr_el2, \tmp /* Disable coprocessor traps to EL2 */
/* Initialize Generic Timers */
msr cntvoff_el2, xzr
@@ -152,45 +165,90 @@ lr .req x30
* and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
* EE,WXN,I,SA,C,A,M to 0
*/
- mov \xreg1, #0x0830
- movk \xreg1, #0x30C5, lsl #16
- msr sctlr_el2, \xreg1
+ ldr \tmp, =(SCTLR_EL2_RES1 | SCTLR_EL2_EE_LE |\
+ SCTLR_EL2_WXN_DIS | SCTLR_EL2_ICACHE_DIS |\
+ SCTLR_EL2_SA_DIS | SCTLR_EL2_DCACHE_DIS |\
+ SCTLR_EL2_ALIGN_DIS | SCTLR_EL2_MMU_DIS)
+ msr sctlr_el2, \tmp
+
+ mov \tmp, sp
+ msr sp_el2, \tmp /* Migrate SP */
+ mrs \tmp, vbar_el3
+ msr vbar_el2, \tmp /* Migrate VBAR */
+
+ /* Check switch to AArch64 EL2 or AArch32 Hypervisor mode */
+ cmp \flag, #ES_TO_AARCH32
+ b.eq 1f
+
+ /*
+ * The next lower exception level is AArch64, 64bit EL2 | HCE |
+ * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
+ */
+ ldr \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
+ SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
+ SCR_EL3_NS_EN)
+ msr scr_el3, \tmp
/* Return to the EL2_SP2 mode from EL3 */
- mov \xreg1, sp
- msr sp_el2, \xreg1 /* Migrate SP */
- mrs \xreg1, vbar_el3
- msr vbar_el2, \xreg1 /* Migrate VBAR */
- mov \xreg1, #0x3c9
- msr spsr_el3, \xreg1 /* EL2_SP2 | D | A | I | F */
- msr elr_el3, lr
+ ldr \tmp, =(SPSR_EL_DEBUG_MASK | SPSR_EL_SERR_MASK |\
+ SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
+ SPSR_EL_M_AARCH64 | SPSR_EL_M_EL2H)
+ msr spsr_el3, \tmp
+ msr elr_el3, \ep
+ eret
+
+1:
+ /*
+ * The next lower exception level is AArch32, 32bit EL2 | HCE |
+ * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
+ */
+ ldr \tmp, =(SCR_EL3_RW_AARCH32 | SCR_EL3_HCE_EN |\
+ SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
+ SCR_EL3_NS_EN)
+ msr scr_el3, \tmp
+
+ /* Return to AArch32 Hypervisor mode */
+ ldr \tmp, =(SPSR_EL_END_LE | SPSR_EL_ASYN_MASK |\
+ SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
+ SPSR_EL_T_A32 | SPSR_EL_M_AARCH32 |\
+ SPSR_EL_M_HYP)
+ msr spsr_el3, \tmp
+ msr elr_el3, \ep
eret
.endm
-.macro armv8_switch_to_el1_m, xreg1, xreg2
+/*
+ * Switch from EL2 to EL1 for ARMv8
+ * @ep: kernel entry point
+ * @flag: The execution state flag for lower exception
+ * level, ES_TO_AARCH64 or ES_TO_AARCH32
+ * @tmp: temporary register
+ *
+ * For loading 32-bit OS, x1 is machine nr and x2 is ftaddr.
+ * For loading 64-bit OS, x0 is physical address to the FDT blob.
+ * They will be passed to the guest.
+ */
+.macro armv8_switch_to_el1_m, ep, flag, tmp
/* Initialize Generic Timers */
- mrs \xreg1, cnthctl_el2
- orr \xreg1, \xreg1, #0x3 /* Enable EL1 access to timers */
- msr cnthctl_el2, \xreg1
+ mrs \tmp, cnthctl_el2
+ /* Enable EL1 access to timers */
+ orr \tmp, \tmp, #(CNTHCTL_EL2_EL1PCEN_EN |\
+ CNTHCTL_EL2_EL1PCTEN_EN)
+ msr cnthctl_el2, \tmp
msr cntvoff_el2, xzr
/* Initilize MPID/MPIDR registers */
- mrs \xreg1, midr_el1
- mrs \xreg2, mpidr_el1
- msr vpidr_el2, \xreg1
- msr vmpidr_el2, \xreg2
+ mrs \tmp, midr_el1
+ msr vpidr_el2, \tmp
+ mrs \tmp, mpidr_el1
+ msr vmpidr_el2, \tmp
/* Disable coprocessor traps */
- mov \xreg1, #0x33ff
- msr cptr_el2, \xreg1 /* Disable coprocessor traps to EL2 */
+ mov \tmp, #CPTR_EL2_RES1
+ msr cptr_el2, \tmp /* Disable coprocessor traps to EL2 */
msr hstr_el2, xzr /* Disable coprocessor traps to EL2 */
- mov \xreg1, #3 << 20
- msr cpacr_el1, \xreg1 /* Enable FP/SIMD at EL1 */
-
- /* Initialize HCR_EL2 */
- mov \xreg1, #(1 << 31) /* 64bit EL1 */
- orr \xreg1, \xreg1, #(1 << 29) /* Disable HVC */
- msr hcr_el2, \xreg1
+ mov \tmp, #CPACR_EL1_FPEN_EN
+ msr cpacr_el1, \tmp /* Enable FP/SIMD at EL1 */
/* SCTLR_EL1 initialization
*
@@ -199,18 +257,50 @@ lr .req x30
* UCI,EE,EOE,WXN,nTWE,nTWI,UCT,DZE,I,UMA,SED,ITD,
* CP15BEN,SA0,SA,C,A,M to 0
*/
- mov \xreg1, #0x0800
- movk \xreg1, #0x30d0, lsl #16
- msr sctlr_el1, \xreg1
+ ldr \tmp, =(SCTLR_EL1_RES1 | SCTLR_EL1_UCI_DIS |\
+ SCTLR_EL1_EE_LE | SCTLR_EL1_WXN_DIS |\
+ SCTLR_EL1_NTWE_DIS | SCTLR_EL1_NTWI_DIS |\
+ SCTLR_EL1_UCT_DIS | SCTLR_EL1_DZE_DIS |\
+ SCTLR_EL1_ICACHE_DIS | SCTLR_EL1_UMA_DIS |\
+ SCTLR_EL1_SED_EN | SCTLR_EL1_ITD_EN |\
+ SCTLR_EL1_CP15BEN_DIS | SCTLR_EL1_SA0_DIS |\
+ SCTLR_EL1_SA_DIS | SCTLR_EL1_DCACHE_DIS |\
+ SCTLR_EL1_ALIGN_DIS | SCTLR_EL1_MMU_DIS)
+ msr sctlr_el1, \tmp
+
+ mov \tmp, sp
+ msr sp_el1, \tmp /* Migrate SP */
+ mrs \tmp, vbar_el2
+ msr vbar_el1, \tmp /* Migrate VBAR */
+
+ /* Check switch to AArch64 EL1 or AArch32 Supervisor mode */
+ cmp \flag, #ES_TO_AARCH32
+ b.eq 1f
+
+ /* Initialize HCR_EL2 */
+ ldr \tmp, =(HCR_EL2_RW_AARCH64 | HCR_EL2_HCD_DIS)
+ msr hcr_el2, \tmp
/* Return to the EL1_SP1 mode from EL2 */
- mov \xreg1, sp
- msr sp_el1, \xreg1 /* Migrate SP */
- mrs \xreg1, vbar_el2
- msr vbar_el1, \xreg1 /* Migrate VBAR */
- mov \xreg1, #0x3c5
- msr spsr_el2, \xreg1 /* EL1_SP1 | D | A | I | F */
- msr elr_el2, lr
+ ldr \tmp, =(SPSR_EL_DEBUG_MASK | SPSR_EL_SERR_MASK |\
+ SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
+ SPSR_EL_M_AARCH64 | SPSR_EL_M_EL1H)
+ msr spsr_el2, \tmp
+ msr elr_el2, \ep
+ eret
+
+1:
+ /* Initialize HCR_EL2 */
+ ldr \tmp, =(HCR_EL2_RW_AARCH32 | HCR_EL2_HCD_DIS)
+ msr hcr_el2, \tmp
+
+ /* Return to AArch32 Supervisor mode from EL2 */
+ ldr \tmp, =(SPSR_EL_END_LE | SPSR_EL_ASYN_MASK |\
+ SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
+ SPSR_EL_T_A32 | SPSR_EL_M_AARCH32 |\
+ SPSR_EL_M_SVC)
+ msr spsr_el2, \tmp
+ msr elr_el2, \ep
eret
.endm
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 574a0e775f3..01efc43657f 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -18,6 +18,95 @@
#define CR_WXN (1 << 19) /* Write Permision Imply XN */
#define CR_EE (1 << 25) /* Exception (Big) Endian */
+#define ES_TO_AARCH64 1
+#define ES_TO_AARCH32 0
+
+/*
+ * SCR_EL3 bits definitions
+ */
+#define SCR_EL3_RW_AARCH64 (1 << 10) /* Next lower level is AArch64 */
+#define SCR_EL3_RW_AARCH32 (0 << 10) /* Lower lowers level are AArch32 */
+#define SCR_EL3_HCE_EN (1 << 8) /* Hypervisor Call enable */
+#define SCR_EL3_SMD_DIS (1 << 7) /* Secure Monitor Call disable */
+#define SCR_EL3_RES1 (3 << 4) /* Reserved, RES1 */
+#define SCR_EL3_NS_EN (1 << 0) /* EL0 and EL1 in Non-scure state */
+
+/*
+ * SPSR_EL3/SPSR_EL2 bits definitions
+ */
+#define SPSR_EL_END_LE (0 << 9) /* Exception Little-endian */
+#define SPSR_EL_DEBUG_MASK (1 << 9) /* Debug exception masked */
+#define SPSR_EL_ASYN_MASK (1 << 8) /* Asynchronous data abort masked */
+#define SPSR_EL_SERR_MASK (1 << 8) /* System Error exception masked */
+#define SPSR_EL_IRQ_MASK (1 << 7) /* IRQ exception masked */
+#define SPSR_EL_FIQ_MASK (1 << 6) /* FIQ exception masked */
+#define SPSR_EL_T_A32 (0 << 5) /* AArch32 instruction set A32 */
+#define SPSR_EL_M_AARCH64 (0 << 4) /* Exception taken from AArch64 */
+#define SPSR_EL_M_AARCH32 (1 << 4) /* Exception taken from AArch32 */
+#define SPSR_EL_M_SVC (0x3) /* Exception taken from SVC mode */
+#define SPSR_EL_M_HYP (0xa) /* Exception taken from HYP mode */
+#define SPSR_EL_M_EL1H (5) /* Exception taken from EL1h mode */
+#define SPSR_EL_M_EL2H (9) /* Exception taken from EL2h mode */
+
+/*
+ * CPTR_EL2 bits definitions
+ */
+#define CPTR_EL2_RES1 (3 << 12 | 0x3ff) /* Reserved, RES1 */
+
+/*
+ * SCTLR_EL2 bits definitions
+ */
+#define SCTLR_EL2_RES1 (3 << 28 | 3 << 22 | 1 << 18 | 1 << 16 |\
+ 1 << 11 | 3 << 4) /* Reserved, RES1 */
+#define SCTLR_EL2_EE_LE (0 << 25) /* Exception Little-endian */
+#define SCTLR_EL2_WXN_DIS (0 << 19) /* Write permission is not XN */
+#define SCTLR_EL2_ICACHE_DIS (0 << 12) /* Instruction cache disabled */
+#define SCTLR_EL2_SA_DIS (0 << 3) /* Stack Alignment Check disabled */
+#define SCTLR_EL2_DCACHE_DIS (0 << 2) /* Data cache disabled */
+#define SCTLR_EL2_ALIGN_DIS (0 << 1) /* Alignment check disabled */
+#define SCTLR_EL2_MMU_DIS (0) /* MMU disabled */
+
+/*
+ * CNTHCTL_EL2 bits definitions
+ */
+#define CNTHCTL_EL2_EL1PCEN_EN (1 << 1) /* Physical timer regs accessible */
+#define CNTHCTL_EL2_EL1PCTEN_EN (1 << 0) /* Physical counter accessible */
+
+/*
+ * HCR_EL2 bits definitions
+ */
+#define HCR_EL2_RW_AARCH64 (1 << 31) /* EL1 is AArch64 */
+#define HCR_EL2_RW_AARCH32 (0 << 31) /* Lower levels are AArch32 */
+#define HCR_EL2_HCD_DIS (1 << 29) /* Hypervisor Call disabled */
+
+/*
+ * CPACR_EL1 bits definitions
+ */
+#define CPACR_EL1_FPEN_EN (3 << 20) /* SIMD and FP instruction enabled */
+
+/*
+ * SCTLR_EL1 bits definitions
+ */
+#define SCTLR_EL1_RES1 (3 << 28 | 3 << 22 | 1 << 20 |\
+ 1 << 11) /* Reserved, RES1 */
+#define SCTLR_EL1_UCI_DIS (0 << 26) /* Cache instruction disabled */
+#define SCTLR_EL1_EE_LE (0 << 25) /* Exception Little-endian */
+#define SCTLR_EL1_WXN_DIS (0 << 19) /* Write permission is not XN */
+#define SCTLR_EL1_NTWE_DIS (0 << 18) /* WFE instruction disabled */
+#define SCTLR_EL1_NTWI_DIS (0 << 16) /* WFI instruction disabled */
+#define SCTLR_EL1_UCT_DIS (0 << 15) /* CTR_EL0 access disabled */
+#define SCTLR_EL1_DZE_DIS (0 << 14) /* DC ZVA instruction disabled */
+#define SCTLR_EL1_ICACHE_DIS (0 << 12) /* Instruction cache disabled */
+#define SCTLR_EL1_UMA_DIS (0 << 9) /* User Mask Access disabled */
+#define SCTLR_EL1_SED_EN (0 << 8) /* SETEND instruction enabled */
+#define SCTLR_EL1_ITD_EN (0 << 7) /* IT instruction enabled */
+#define SCTLR_EL1_CP15BEN_DIS (0 << 5) /* CP15 barrier operation disabled */
+#define SCTLR_EL1_SA0_DIS (0 << 4) /* Stack Alignment EL0 disabled */
+#define SCTLR_EL1_SA_DIS (0 << 3) /* Stack Alignment EL1 disabled */
+#define SCTLR_EL1_DCACHE_DIS (0 << 2) /* Data cache disabled */
+#define SCTLR_EL1_ALIGN_DIS (0 << 1) /* Alignment check disabled */
+#define SCTLR_EL1_MMU_DIS (0) /* MMU disabled */
+
#ifndef __ASSEMBLY__
u64 get_page_table_size(void);
@@ -98,8 +187,36 @@ int __asm_flush_l3_dcache(void);
int __asm_invalidate_l3_icache(void);
void __asm_switch_ttbr(u64 new_ttbr);
-void armv8_switch_to_el2(void);
-void armv8_switch_to_el1(void);
+/*
+ * Switch from EL3 to EL2 for ARMv8
+ *
+ * @args: For loading 64-bit OS, fdt address.
+ * For loading 32-bit OS, zero.
+ * @mach_nr: For loading 64-bit OS, zero.
+ * For loading 32-bit OS, machine nr
+ * @fdt_addr: For loading 64-bit OS, zero.
+ * For loading 32-bit OS, fdt address.
+ * @entry_point: kernel entry point
+ * @es_flag: execution state flag, ES_TO_AARCH64 or ES_TO_AARCH32
+ */
+void armv8_switch_to_el2(u64 args, u64 mach_nr, u64 fdt_addr,
+ u64 entry_point, u64 es_flag);
+/*
+ * Switch from EL2 to EL1 for ARMv8
+ *
+ * @args: For loading 64-bit OS, fdt address.
+ * For loading 32-bit OS, zero.
+ * @mach_nr: For loading 64-bit OS, zero.
+ * For loading 32-bit OS, machine nr
+ * @fdt_addr: For loading 64-bit OS, zero.
+ * For loading 32-bit OS, fdt address.
+ * @entry_point: kernel entry point
+ * @es_flag: execution state flag, ES_TO_AARCH64 or ES_TO_AARCH32
+ */
+void armv8_switch_to_el1(u64 args, u64 mach_nr, u64 fdt_addr,
+ u64 entry_point, u64 es_flag);
+void armv8_el2_to_aarch32(u64 args, u64 mach_nr, u64 fdt_addr,
+ u64 entry_point);
void gic_init(void);
void gic_send_sgi(unsigned long sgino);
void wait_for_wakeup(void);
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index dedcd1e9a4b..35e6b06733b 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -200,10 +200,6 @@ static void do_nonsec_virt_switch(void)
{
smp_kick_all_cpus();
dcache_disable(); /* flush cache before swtiching to EL2 */
- armv8_switch_to_el2();
-#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
- armv8_switch_to_el1();
-#endif
}
#endif
@@ -280,6 +276,28 @@ bool armv7_boot_nonsec(void)
}
#endif
+#ifdef CONFIG_ARM64
+__weak void update_os_arch_secondary_cores(uint8_t os_arch)
+{
+}
+
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+static void switch_to_el1(void)
+{
+ if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
+ (images.os.arch == IH_ARCH_ARM))
+ armv8_switch_to_el1(0, (u64)gd->bd->bi_arch_number,
+ (u64)images.ft_addr,
+ (u64)images.ep,
+ ES_TO_AARCH32);
+ else
+ armv8_switch_to_el1((u64)images.ft_addr, 0, 0,
+ images.ep,
+ ES_TO_AARCH64);
+}
+#endif
+#endif
+
/* Subcommand: GO */
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
@@ -299,7 +317,24 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
if (!fake) {
do_nonsec_virt_switch();
- kernel_entry(images->ft_addr, NULL, NULL, NULL);
+
+ update_os_arch_secondary_cores(images->os.arch);
+
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ armv8_switch_to_el2((u64)images->ft_addr, 0, 0,
+ (u64)switch_to_el1, ES_TO_AARCH64);
+#else
+ if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
+ (images->os.arch == IH_ARCH_ARM))
+ armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
+ (u64)images->ft_addr,
+ (u64)images->ep,
+ ES_TO_AARCH32);
+ else
+ armv8_switch_to_el2((u64)images->ft_addr, 0, 0,
+ images->ep,
+ ES_TO_AARCH64);
+#endif
}
#else
unsigned long machid = gd->bd->bi_arch_number;
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index ce2a16f95b0..07118fc3df3 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -126,6 +126,7 @@ choice
config TARGET_ESPRESSO7420
bool "ESPRESSO7420 board"
select ARM64
+ select ARMV8_MULTIENTRY
select SUPPORT_SPL
select OF_CONTROL
select SPL_DISABLE_OF_CONTROL
diff --git a/arch/arm/mach-exynos/soc.c b/arch/arm/mach-exynos/soc.c
index f9c74686119..cf149ad1a8c 100644
--- a/arch/arm/mach-exynos/soc.c
+++ b/arch/arm/mach-exynos/soc.c
@@ -9,6 +9,16 @@
#include <asm/io.h>
#include <asm/system.h>
+#ifdef CONFIG_TARGET_ESPRESSO7420
+/*
+ * Exynos7420 uses CPU0 of Cluster-1 as boot CPU. Due to this, branch_if_master
+ * fails to identify as the boot CPU as the master CPU. As temporary workaround,
+ * setup the slave CPU boot address as "_main".
+ */
+extern void _main(void);
+void *secondary_boot_addr = (void *)_main;
+#endif /* CONFIG_TARGET_ESPRESSO7420 */
+
void reset_cpu(ulong addr)
{
#ifdef CONFIG_CPU_V7
@@ -23,11 +33,3 @@ void enable_caches(void)
dcache_enable();
}
#endif
-
-#ifdef CONFIG_ARM64
-void lowlevel_init(void)
-{
- armv8_switch_to_el2();
- armv8_switch_to_el1();
-}
-#endif
diff --git a/arch/arm/mach-rmobile/lowlevel_init_gen3.S b/arch/arm/mach-rmobile/lowlevel_init_gen3.S
index 88ff56ecbf8..11acce03957 100644
--- a/arch/arm/mach-rmobile/lowlevel_init_gen3.S
+++ b/arch/arm/mach-rmobile/lowlevel_init_gen3.S
@@ -61,11 +61,18 @@ ENTRY(lowlevel_init)
/*
* All slaves will enter EL2 and optionally EL1.
*/
+ adr x3, lowlevel_in_el2
+ ldr x4, =ES_TO_AARCH64
bl armv8_switch_to_el2
+
+lowlevel_in_el2:
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ adr x3, lowlevel_in_el1
+ ldr x4, =ES_TO_AARCH64
bl armv8_switch_to_el1
-#endif
+lowlevel_in_el1:
+#endif
#endif /* CONFIG_ARMV8_MULTIENTRY */
bl s_init