summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-layerscape
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-03-06 14:34:52 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2019-05-13 13:58:06 +0200
commitab06d72a6ef8939831b8c0b1c412d9a11fc06889 (patch)
treeb015e4c8254ba8896be207947a55decf766daaf7 /arch/arm/mach-layerscape
parented251dc493215e1fa14e610b208059cdcb95e52e (diff)
downloadbarebox-ab06d72a6ef8939831b8c0b1c412d9a11fc06889.tar.gz
barebox-ab06d72a6ef8939831b8c0b1c412d9a11fc06889.tar.xz
ARM: Layerscape: Add PPA firmware support
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 on https://github.com/NXP/qoriq-ppa-binary and are not included in barebox. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-layerscape')
-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
5 files changed, 172 insertions, 0 deletions
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;
+}