summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/scm-boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom/scm-boot.c')
-rw-r--r--drivers/soc/qcom/scm-boot.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/soc/qcom/scm-boot.c b/drivers/soc/qcom/scm-boot.c
new file mode 100644
index 000000000000..369fb27ff447
--- /dev/null
+++ b/drivers/soc/qcom/scm-boot.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2010, 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/scm-boot.h>
+
+/*
+ * Set the cold/warm boot address for one of the CPU cores.
+ */
+int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
+{
+ struct {
+ u32 flags;
+ u32 addr;
+ } cmd;
+
+ cmd.addr = addr;
+ cmd.flags = flags;
+ return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR,
+ &cmd, sizeof(cmd), NULL, 0);
+}
+EXPORT_SYMBOL(scm_set_boot_addr);
+
+/**
+ * scm_set_boot_addr_mc - Set entry physical address for cpus
+ * @addr: 32bit physical address
+ * @aff0: Collective bitmask of the affinity-level-0 of the mpidr
+ * 1<<aff0_CPU0| 1<<aff0_CPU1....... | 1<<aff0_CPU32
+ * Supports maximum 32 cpus under any affinity level.
+ * @aff1: Collective bitmask of the affinity-level-1 of the mpidr
+ * @aff2: Collective bitmask of the affinity-level-2 of the mpidr
+ * @flags: Flag to differentiate between coldboot vs warmboot
+ */
+int scm_set_boot_addr_mc(phys_addr_t addr, u32 aff0,
+ u32 aff1, u32 aff2, u32 flags)
+{
+ struct {
+ u32 addr;
+ u32 aff0;
+ u32 aff1;
+ u32 aff2;
+ u32 reserved;
+ u32 flags;
+ } cmd;
+ struct scm_desc desc = {0};
+
+ if (!is_scm_armv8()) {
+ cmd.addr = addr;
+ cmd.aff0 = aff0;
+ cmd.aff1 = aff1;
+ cmd.aff2 = aff2;
+ /*
+ * Reserved for future chips with affinity level 3 effectively
+ * 1 << 0
+ */
+ cmd.reserved = ~0U;
+ cmd.flags = flags | SCM_FLAG_HLOS;
+ return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR_MC,
+ &cmd, sizeof(cmd), NULL, 0);
+ }
+
+ flags = flags | SCM_FLAG_HLOS;
+ desc.args[0] = addr;
+ desc.args[1] = aff0;
+ desc.args[2] = aff1;
+ desc.args[3] = aff2;
+ desc.args[4] = ~0ULL;
+ desc.args[5] = flags;
+ desc.arginfo = SCM_ARGS(6);
+
+ return scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, SCM_BOOT_ADDR_MC), &desc);
+}
+EXPORT_SYMBOL(scm_set_boot_addr_mc);
+
+/**
+ * scm_set_warm_boot_addr_mc_for_all -
+ * Set entry physical address for __all__ possible cpus
+ * This API passes all_set mask to secure-os and relies
+ * on secure-os to appropriately
+ * set the boot-address on the current system.
+ * @addr: 32bit physical address
+ */
+
+int scm_set_warm_boot_addr_mc_for_all(phys_addr_t addr)
+{
+ return scm_set_boot_addr_mc(addr, ~0U, ~0U, ~0U,
+ SCM_FLAG_WARMBOOT_MC);
+}
+EXPORT_SYMBOL(scm_set_warm_boot_addr_mc_for_all);
+
+/**
+ * scm_is_mc_boot_available -
+ * Checks if TZ supports the boot API for multi-cluster configuration
+ * Returns true if available and false otherwise
+ */
+int scm_is_mc_boot_available(void)
+{
+ return scm_is_call_available(SCM_SVC_BOOT, SCM_BOOT_ADDR_MC);
+}
+EXPORT_SYMBOL(scm_is_mc_boot_available);