summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boards/ls1046ardb/board.c7
-rw-r--r--arch/arm/boards/ls1046ardb/lowlevel.c2
-rw-r--r--arch/arm/boards/tqmls1046a/board.c6
-rw-r--r--arch/arm/boards/tqmls1046a/lowlevel.c2
-rw-r--r--arch/arm/configs/layerscape_defconfig1
-rw-r--r--arch/arm/mach-layerscape/Kconfig13
-rw-r--r--arch/arm/mach-layerscape/Makefile1
-rw-r--r--arch/arm/mach-layerscape/include/mach/layerscape.h10
-rw-r--r--arch/arm/mach-layerscape/ppa-entry.S30
-rw-r--r--arch/arm/mach-layerscape/ppa.c118
-rw-r--r--firmware/Makefile2
11 files changed, 189 insertions, 3 deletions
diff --git a/arch/arm/boards/ls1046ardb/board.c b/arch/arm/boards/ls1046ardb/board.c
index 483040957e..0846df9fad 100644
--- a/arch/arm/boards/ls1046ardb/board.c
+++ b/arch/arm/boards/ls1046ardb/board.c
@@ -8,16 +8,21 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <asm/system.h>
+#include <mach/layerscape.h>
static int rdb_mem_init(void)
{
+ int ret;
+
if (!of_machine_is_compatible("fsl,ls1046a-rdb"))
return 0;
arm_add_mem_device("ram0", 0x80000000, 0x80000000);
arm_add_mem_device("ram1", 0x880000000, 3ULL * SZ_2G);
- printf("Current EL: %d\n", current_el());
+ ret = ls1046a_ppa_init(0x100000000 - SZ_64M, SZ_64M);
+ if (ret)
+ pr_err("Failed to initialize PPA firmware: %s\n", strerror(-ret));
return 0;
}
diff --git a/arch/arm/boards/ls1046ardb/lowlevel.c b/arch/arm/boards/ls1046ardb/lowlevel.c
index 0c95fbb035..0a30f05aa2 100644
--- a/arch/arm/boards/ls1046ardb/lowlevel.c
+++ b/arch/arm/boards/ls1046ardb/lowlevel.c
@@ -194,7 +194,7 @@ static noinline __noreturn void ls1046ardb_r_entry(unsigned long memsize)
if (memsize + membase >= 0x100000000)
memsize = 0x100000000 - membase;
- barebox_arm_entry(membase, 0x80000000 - SZ_1M * 67,
+ barebox_arm_entry(membase, 0x80000000 - SZ_64M,
__dtb_fsl_ls1046a_rdb_start);
}
diff --git a/arch/arm/boards/tqmls1046a/board.c b/arch/arm/boards/tqmls1046a/board.c
index 8cc4d73de5..028be890e0 100644
--- a/arch/arm/boards/tqmls1046a/board.c
+++ b/arch/arm/boards/tqmls1046a/board.c
@@ -15,11 +15,17 @@
static int tqmls1046a_mem_init(void)
{
+ int ret;
+
if (!of_machine_is_compatible("tqc,tqmls1046a"))
return 0;
arm_add_mem_device("ram0", 0x80000000, SZ_2G);
+ ret = ls1046a_ppa_init(0x100000000 - SZ_64M, SZ_64M);
+ if (ret)
+ pr_err("Failed to initialize PPA firmware: %s\n", strerror(-ret));
+
return 0;
}
mem_initcall(tqmls1046a_mem_init);
diff --git a/arch/arm/boards/tqmls1046a/lowlevel.c b/arch/arm/boards/tqmls1046a/lowlevel.c
index dc0e179694..f79f491ecc 100644
--- a/arch/arm/boards/tqmls1046a/lowlevel.c
+++ b/arch/arm/boards/tqmls1046a/lowlevel.c
@@ -243,7 +243,7 @@ static noinline __noreturn void tqmls1046a_r_entry(void)
unsigned long membase = LS1046A_DDR_SDRAM_BASE;
if (get_pc() >= membase)
- barebox_arm_entry(membase, 0x80000000,
+ barebox_arm_entry(membase, 0x80000000 - SZ_64M,
__dtb_fsl_tqmls1046a_mbls10xxa_start);
arm_cpu_lowlevel_init();
diff --git a/arch/arm/configs/layerscape_defconfig b/arch/arm/configs/layerscape_defconfig
index b81f375415..b36f1944ec 100644
--- a/arch/arm/configs/layerscape_defconfig
+++ b/arch/arm/configs/layerscape_defconfig
@@ -1,4 +1,5 @@
CONFIG_ARCH_LAYERSCAPE=y
+CONFIG_ARCH_LAYERSCAPE_PPA=y
CONFIG_MACH_LS1046ARDB=y
CONFIG_MACH_TQMLS1046A=y
CONFIG_MMU=y
diff --git a/arch/arm/mach-layerscape/Kconfig b/arch/arm/mach-layerscape/Kconfig
index 3a44f3fea1..139c63f66d 100644
--- a/arch/arm/mach-layerscape/Kconfig
+++ b/arch/arm/mach-layerscape/Kconfig
@@ -1,5 +1,18 @@
if ARCH_LAYERSCAPE
+config ARCH_LAYERSCAPE_PPA
+ bool "Include PPA firmware"
+ select ARM_PSCI_OF
+ select ARM_SMCCC
+ select FITIMAGE
+ bool
+ help
+ The "Primary Protected Application" (PPA) is a PSCI compliant firmware
+ distributed by NXP. It is needed to start the secondary cores on
+ Layerscape SoCs. Without it Linux will be started in EL3 and doesn't
+ work properly. The precompiled firmware images can be found here:
+ https://github.com/NXP/qoriq-ppa-binary
+
config ARCH_LS1046
select CPU_V8
select SYS_SUPPORTS_64BIT_KERNEL
diff --git a/arch/arm/mach-layerscape/Makefile b/arch/arm/mach-layerscape/Makefile
index 73cd61a7cf..8a814f9441 100644
--- a/arch/arm/mach-layerscape/Makefile
+++ b/arch/arm/mach-layerscape/Makefile
@@ -4,3 +4,4 @@ lwl-$(CONFIG_ARCH_LS1046) += lowlevel-ls1046a.o
obj-y += icid.o
obj-pbl-y += boot.o
pbl-y += xload-qspi.o xload.o
+obj-$(CONFIG_ARCH_LAYERSCAPE_PPA) += ppa.o ppa-entry.o
diff --git a/arch/arm/mach-layerscape/include/mach/layerscape.h b/arch/arm/mach-layerscape/include/mach/layerscape.h
index 3366e7f258..1f1da0f66e 100644
--- a/arch/arm/mach-layerscape/include/mach/layerscape.h
+++ b/arch/arm/mach-layerscape/include/mach/layerscape.h
@@ -6,4 +6,14 @@
enum bootsource ls1046_bootsource_get(void);
+#ifdef CONFIG_ARCH_LAYERSCAPE_PPA
+int ls1046a_ppa_init(resource_size_t ppa_start, resource_size_t ppa_size);
+#else
+static inline int ls1046a_ppa_init(resource_size_t ppa_start,
+ resource_size_t ppa_size)
+{
+ return -ENOSYS;
+}
+#endif
+
#endif /* __MACH_LAYERSCAPE_H */
diff --git a/arch/arm/mach-layerscape/ppa-entry.S b/arch/arm/mach-layerscape/ppa-entry.S
new file mode 100644
index 0000000000..18cfa6c37e
--- /dev/null
+++ b/arch/arm/mach-layerscape/ppa-entry.S
@@ -0,0 +1,30 @@
+#include <linux/linkage.h>
+
+.section .text.ppa_entry
+ENTRY(ppa_entry)
+ /*
+ * x0: Secure Firmware entry point
+ * x1: Exception return address Low
+ * x2: Exception return address High
+ */
+
+ /* Save stack pointer for EL2 */
+ mov x3, sp
+ msr sp_el2, x3
+
+ /* Set exception return address hold pointer */
+ adr x4, 1f
+ mov x3, x4
+ rev w3, w3
+ str w3, [x1]
+ lsr x3, x4, #32
+ rev w3, w3
+ str w3, [x2]
+
+ /* Call SEC monitor */
+ br x0
+
+1:
+ mov x0, #0
+ ret
+ENDPROC(ppa_entry)
diff --git a/arch/arm/mach-layerscape/ppa.c b/arch/arm/mach-layerscape/ppa.c
new file mode 100644
index 0000000000..6070451020
--- /dev/null
+++ b/arch/arm/mach-layerscape/ppa.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "ppa: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <firmware.h>
+#include <memory.h>
+#include <linux/sizes.h>
+#include <linux/arm-smccc.h>
+#include <asm/mmu.h>
+#include <soc/fsl/immap_lsch2.h>
+#include <asm/system.h>
+#include <image-fit.h>
+#include <asm/psci.h>
+#include <mach/layerscape.h>
+
+int ppa_entry(const void *, u32 *, u32 *);
+void dma_flush_range(void *ptr, size_t size);
+
+static int of_psci_do_fixup(struct device_node *root, void *unused)
+{
+ unsigned long psci_version;
+ struct arm_smccc_res res = {};
+
+ arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
+ psci_version = res.a0;
+
+ return of_psci_fixup(root, psci_version);
+}
+
+static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr)
+{
+ int ret;
+ u32 *boot_loc_ptr_l, *boot_loc_ptr_h;
+ struct ccsr_scfg __iomem *scfg = (void *)(LSCH2_SCFG_ADDR);
+ int el = current_el();
+ struct fit_handle *fit;
+ void *conf;
+ const void *buf;
+ unsigned long firmware_size;
+
+ if (el < 3) {
+ printf("EL%d, skip ppa init\n", el);
+ return 0;
+ }
+
+ boot_loc_ptr_l = &scfg->scratchrw[1];
+ boot_loc_ptr_h = &scfg->scratchrw[0];
+
+ fit = fit_open_buf(ppa, ppa_size, false, BOOTM_VERIFY_AVAILABLE);
+ if (IS_ERR(fit)) {
+ pr_err("Cannot open ppa FIT image: %s\n", strerrorp(fit));
+ return PTR_ERR(fit);
+ }
+
+ conf = fit_open_configuration(fit, NULL);
+ if (IS_ERR(conf)) {
+ pr_err("Cannot open default config in ppa FIT image: %s\n",
+ strerrorp(conf));
+ fit_close(fit);
+ return PTR_ERR(fit);
+ }
+
+
+ ret = fit_open_image(fit, conf, "firmware", &buf, &firmware_size);
+ if (ret) {
+ pr_err("Cannot open firmware image in ppa FIT image: %s\n",
+ strerror(-ret));
+ ret = PTR_ERR(fit);
+ goto err;
+ }
+
+ /* Copy the secure firmware to secure memory */
+ memcpy(sec_firmware_addr, buf, firmware_size);
+ dma_flush_range(sec_firmware_addr, ppa_size);
+
+ ret = ppa_entry(sec_firmware_addr, boot_loc_ptr_l, boot_loc_ptr_h);
+ if (ret) {
+ pr_err("Couldn't install PPA firmware: %s\n", strerror(-ret));
+ goto err;
+ }
+
+ pr_info("PPA firmware installed at 0x%p, now in EL%d\n",
+ sec_firmware_addr, current_el());
+
+ of_register_fixup(of_psci_do_fixup, NULL);
+err:
+ fit_close(fit);
+
+ return 0;
+}
+
+int ls1046a_ppa_init(resource_size_t ppa_start, resource_size_t ppa_size)
+{
+ resource_size_t ppa_end = ppa_start + ppa_size - 1;
+ struct resource *res;
+ void *ppa_fw;
+ size_t ppa_fw_size;
+ int ret;
+
+ res = request_sdram_region("ppa", ppa_start, ppa_size);
+ if (!res) {
+ pr_err("Cannot request SDRAM region %pa - %pa\n",
+ &ppa_start, &ppa_end);
+ return -EINVAL;
+ }
+
+ get_builtin_firmware(ppa_ls1046a_bin, &ppa_fw, &ppa_fw_size);
+
+ ret = ppa_init(ppa_fw, ppa_fw_size, (void *)ppa_start);
+ if (ret)
+ return ret;
+
+ of_add_reserve_entry(ppa_start, ppa_end);
+
+ return 0;
+}
diff --git a/firmware/Makefile b/firmware/Makefile
index 306c006e23..9581ee6116 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -13,6 +13,8 @@ firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx8mq-bl31.bin
firmware-$(CONFIG_DRIVER_NET_FSL_FMAN) += fsl_fman_ucode_ls1046_r1.0_106_4_18.bin
+firmware-$(CONFIG_ARCH_LAYERSCAPE_PPA) += ppa-ls1046a.bin
+
# Create $(fwabs) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a
# leading /, it's relative to $(srctree).
fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR))