mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
![Stephan Gerhold](/assets/img/avatar_default.png)
It looks like the old QCOM_SCM_BOOT_SET_ADDR API is broken on some MSM8916 firmware versions that implement the newer SMC32 calling convention. It just returns -EINVAL no matter which arguments are being passed. This does not cause any problems downstream because it first tries to use the new multi-cluster API replacement which is working fine. Implement support for the multi-cluster variant of the SCM call by attempting it first but still fallback to the old call in case of an error. Also, to be absolutely sure only use the multi-cluster variant with the SMC calling convention since older platforms should not need this. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Link: https://lore.kernel.org/r/20211201130505.257379-5-stephan@gerhold.net
161 lines
4.3 KiB
C
161 lines
4.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved.
|
|
*/
|
|
#ifndef __QCOM_SCM_INT_H
|
|
#define __QCOM_SCM_INT_H
|
|
|
|
enum qcom_scm_convention {
|
|
SMC_CONVENTION_UNKNOWN,
|
|
SMC_CONVENTION_LEGACY,
|
|
SMC_CONVENTION_ARM_32,
|
|
SMC_CONVENTION_ARM_64,
|
|
};
|
|
|
|
extern enum qcom_scm_convention qcom_scm_convention;
|
|
|
|
#define MAX_QCOM_SCM_ARGS 10
|
|
#define MAX_QCOM_SCM_RETS 3
|
|
|
|
enum qcom_scm_arg_types {
|
|
QCOM_SCM_VAL,
|
|
QCOM_SCM_RO,
|
|
QCOM_SCM_RW,
|
|
QCOM_SCM_BUFVAL,
|
|
};
|
|
|
|
#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
|
|
(((a) & 0x3) << 4) | \
|
|
(((b) & 0x3) << 6) | \
|
|
(((c) & 0x3) << 8) | \
|
|
(((d) & 0x3) << 10) | \
|
|
(((e) & 0x3) << 12) | \
|
|
(((f) & 0x3) << 14) | \
|
|
(((g) & 0x3) << 16) | \
|
|
(((h) & 0x3) << 18) | \
|
|
(((i) & 0x3) << 20) | \
|
|
(((j) & 0x3) << 22) | \
|
|
((num) & 0xf))
|
|
|
|
#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
|
|
|
|
/**
|
|
* struct qcom_scm_desc
|
|
* @arginfo: Metadata describing the arguments in args[]
|
|
* @args: The array of arguments for the secure syscall
|
|
*/
|
|
struct qcom_scm_desc {
|
|
u32 svc;
|
|
u32 cmd;
|
|
u32 arginfo;
|
|
u64 args[MAX_QCOM_SCM_ARGS];
|
|
u32 owner;
|
|
};
|
|
|
|
/**
|
|
* struct qcom_scm_res
|
|
* @result: The values returned by the secure syscall
|
|
*/
|
|
struct qcom_scm_res {
|
|
u64 result[MAX_QCOM_SCM_RETS];
|
|
};
|
|
|
|
#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
|
|
extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|
enum qcom_scm_convention qcom_convention,
|
|
struct qcom_scm_res *res, bool atomic);
|
|
#define scm_smc_call(dev, desc, res, atomic) \
|
|
__scm_smc_call((dev), (desc), qcom_scm_convention, (res), (atomic))
|
|
|
|
#define SCM_LEGACY_FNID(s, c) (((s) << 10) | ((c) & 0x3ff))
|
|
extern int scm_legacy_call_atomic(struct device *dev,
|
|
const struct qcom_scm_desc *desc,
|
|
struct qcom_scm_res *res);
|
|
extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|
struct qcom_scm_res *res);
|
|
|
|
#define QCOM_SCM_SVC_BOOT 0x01
|
|
#define QCOM_SCM_BOOT_SET_ADDR 0x01
|
|
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
|
|
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
|
|
#define QCOM_SCM_BOOT_SET_ADDR_MC 0x11
|
|
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
|
|
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
|
|
#define QCOM_SCM_BOOT_MAX_CPUS 4
|
|
#define QCOM_SCM_BOOT_MC_FLAG_AARCH64 BIT(0)
|
|
#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1)
|
|
#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2)
|
|
|
|
#define QCOM_SCM_SVC_PIL 0x02
|
|
#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
|
|
#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02
|
|
#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05
|
|
#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
|
|
#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
|
|
#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
|
|
|
|
#define QCOM_SCM_SVC_IO 0x05
|
|
#define QCOM_SCM_IO_READ 0x01
|
|
#define QCOM_SCM_IO_WRITE 0x02
|
|
|
|
#define QCOM_SCM_SVC_INFO 0x06
|
|
#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01
|
|
|
|
#define QCOM_SCM_SVC_MP 0x0c
|
|
#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
|
|
#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
|
|
#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
|
|
#define QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE 0x05
|
|
#define QCOM_SCM_MP_VIDEO_VAR 0x08
|
|
#define QCOM_SCM_MP_ASSIGN 0x16
|
|
|
|
#define QCOM_SCM_SVC_OCMEM 0x0f
|
|
#define QCOM_SCM_OCMEM_LOCK_CMD 0x01
|
|
#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x02
|
|
|
|
#define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */
|
|
#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
|
|
#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
|
|
|
|
#define QCOM_SCM_SVC_HDCP 0x11
|
|
#define QCOM_SCM_HDCP_INVOKE 0x01
|
|
|
|
#define QCOM_SCM_SVC_LMH 0x13
|
|
#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE 0x01
|
|
#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10
|
|
|
|
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
|
|
#define QCOM_SCM_SMMU_PT_FORMAT 0x01
|
|
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
|
|
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
|
|
|
|
extern void __qcom_scm_init(void);
|
|
|
|
/* common error codes */
|
|
#define QCOM_SCM_V2_EBUSY -12
|
|
#define QCOM_SCM_ENOMEM -5
|
|
#define QCOM_SCM_EOPNOTSUPP -4
|
|
#define QCOM_SCM_EINVAL_ADDR -3
|
|
#define QCOM_SCM_EINVAL_ARG -2
|
|
#define QCOM_SCM_ERROR -1
|
|
#define QCOM_SCM_INTERRUPTED 1
|
|
|
|
static inline int qcom_scm_remap_error(int err)
|
|
{
|
|
switch (err) {
|
|
case QCOM_SCM_ERROR:
|
|
return -EIO;
|
|
case QCOM_SCM_EINVAL_ADDR:
|
|
case QCOM_SCM_EINVAL_ARG:
|
|
return -EINVAL;
|
|
case QCOM_SCM_EOPNOTSUPP:
|
|
return -EOPNOTSUPP;
|
|
case QCOM_SCM_ENOMEM:
|
|
return -ENOMEM;
|
|
case QCOM_SCM_V2_EBUSY:
|
|
return -EBUSY;
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
|
|
#endif
|