drivers: soc: add snapshot of scm driver

This is a snapshot of scm driver as of msm-4.4 commit <9d822a9489cceee5>
("Merge "ASoC: msm: set pointers to NULL after kfree")

CRs-Fixed: 1053664
Change-Id: I601d95e64756c6bb82a6799d259431af76edf528
Signed-off-by: Channagoud Kadabi <ckadabi@codeaurora.org>
[psodagud: Fixed most fot the warnings and written about
QCOM_SCM in Kconfig file]
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
tirimbino
Channagoud Kadabi 9 years ago committed by Prasad Sodagudi
parent a313e54567
commit e8a1ccf5e5
  1. 9
      drivers/soc/qcom/Kconfig
  2. 2
      drivers/soc/qcom/Makefile
  3. 111
      drivers/soc/qcom/scm-boot.c
  4. 1244
      drivers/soc/qcom/scm.c
  5. 65
      include/soc/qcom/scm-boot.h
  6. 237
      include/soc/qcom/scm.h
  7. 68
      include/trace/events/scm.h

@ -48,6 +48,15 @@ config QCOM_SMD_RPM
Say M here if you want to include support for the Qualcomm RPM as a
module. This will build a module called "qcom-smd-rpm".
config QCOM_SCM
bool "Secure Channel Manager (SCM) support"
default n
help
Say y here to enable Secure Channel Mananger(SCM) support for SoC.
SCM provides communication channel to communicate with secure
world(EL2 and EL3) by using smc call.
SCM driver provides the support for atomic scm calls also.
config QCOM_SMEM_STATE
bool

@ -7,3 +7,5 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o

@ -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);

File diff suppressed because it is too large Load Diff

@ -0,0 +1,65 @@
/* Copyright (c) 2010, 2012, 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.
*/
#ifndef __MACH_SCM_BOOT_H
#define __MACH_SCM_BOOT_H
#define SCM_BOOT_ADDR 0x1
#define SCM_FLAG_COLDBOOT_CPU1 0x01
#define SCM_FLAG_COLDBOOT_CPU2 0x08
#define SCM_FLAG_COLDBOOT_CPU3 0x20
#define SCM_FLAG_WARMBOOT_CPU1 0x02
#define SCM_FLAG_WARMBOOT_CPU0 0x04
#define SCM_FLAG_WARMBOOT_CPU2 0x10
#define SCM_FLAG_WARMBOOT_CPU3 0x40
/* Multicluster Variants */
#define SCM_BOOT_ADDR_MC 0x11
#define SCM_FLAG_COLDBOOT_MC 0x02
#define SCM_FLAG_WARMBOOT_MC 0x04
#ifdef CONFIG_ARM64
#define SCM_FLAG_HLOS 0x01
#else
#define SCM_FLAG_HLOS 0x0
#endif
#ifdef CONFIG_QCOM_SCM
int scm_set_boot_addr(phys_addr_t addr, unsigned int flags);
int scm_set_boot_addr_mc(phys_addr_t addr, u32 aff0,
u32 aff1, u32 aff2, u32 flags);
int scm_set_warm_boot_addr_mc_for_all(phys_addr_t addr);
int scm_is_mc_boot_available(void);
#else
static inline int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
{
WARN_ONCE(1, "CONFIG_QCOM_SCM disabled, SCM call will fail silently\n");
return 0;
}
static inline int scm_set_boot_addr_mc(phys_addr_t addr, u32 aff0,
u32 aff1, u32 aff2, u32 flags)
{
WARN_ONCE(1, "CONFIG_QCOM_SCM disabled, SCM call will fail silently\n");
return 0;
}
static inline int scm_set_warm_boot_addr_mc_for_all(phys_addr_t addr)
{
WARN_ONCE(1, "CONFIG_QCOM_SCM disabled, SCM call will fail silently\n");
return 0;
}
static inline int scm_is_mc_boot_available(void)
{
WARN_ONCE(1, "CONFIG_QCOM_SCM disabled, SCM call will fail silently\n");
return 0;
}
#endif
#endif

@ -0,0 +1,237 @@
/* Copyright (c) 2010-2016, 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.
*/
#ifndef __MACH_SCM_H
#define __MACH_SCM_H
#define SCM_SVC_BOOT 0x1
#define SCM_SVC_PIL 0x2
#define SCM_SVC_UTIL 0x3
#define SCM_SVC_TZ 0x4
#define SCM_SVC_IO 0x5
#define SCM_SVC_INFO 0x6
#define SCM_SVC_SSD 0x7
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
#define SCM_SVC_MP 0xC
#define SCM_SVC_DCVS 0xD
#define SCM_SVC_ES 0x10
#define SCM_SVC_HDCP 0x11
#define SCM_SVC_MDTP 0x12
#define SCM_SVC_LMH 0x13
#define SCM_SVC_SMMU_PROGRAM 0x15
#define SCM_SVC_QDSS 0x16
#define SCM_SVC_TZSCHEDULER 0xFC
#define SCM_FUSE_READ 0x7
#define SCM_CMD_HDCP 0x01
/* SCM Features */
#define SCM_SVC_SEC_CAMERA 0xD
#define DEFINE_SCM_BUFFER(__n) \
static char __n[PAGE_SIZE] __aligned(PAGE_SIZE)
#define SCM_BUFFER_SIZE(__buf) sizeof(__buf)
#define SCM_BUFFER_PHYS(__buf) virt_to_phys(__buf)
#define SCM_SIP_FNID(s, c) (((((s) & 0xFF) << 8) | ((c) & 0xFF)) | 0x02000000)
#define SCM_QSEEOS_FNID(s, c) (((((s) & 0xFF) << 8) | ((c) & 0xFF)) | \
0x32000000)
#define SCM_SVC_ID(s) (((s) & 0xFF00) >> 8)
#define MAX_SCM_ARGS 10
#define MAX_SCM_RETS 3
enum scm_arg_types {
SCM_VAL,
SCM_RO,
SCM_RW,
SCM_BUFVAL,
};
#define SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
(((a) & 0xff) << 4) | \
(((b) & 0xff) << 6) | \
(((c) & 0xff) << 8) | \
(((d) & 0xff) << 10) | \
(((e) & 0xff) << 12) | \
(((f) & 0xff) << 14) | \
(((g) & 0xff) << 16) | \
(((h) & 0xff) << 18) | \
(((i) & 0xff) << 20) | \
(((j) & 0xff) << 22) | \
(num & 0xffff))
#define SCM_ARGS(...) SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
/**
* struct scm_desc
* @arginfo: Metadata describing the arguments in args[]
* @args: The array of arguments for the secure syscall
* @ret: The values returned by the secure syscall
* @extra_arg_buf: The buffer containing extra arguments
(that don't fit in available registers)
* @x5: The 4rd argument to the secure syscall or physical address of
extra_arg_buf
*/
struct scm_desc {
u32 arginfo;
u64 args[MAX_SCM_ARGS];
u64 ret[MAX_SCM_RETS];
/* private */
void *extra_arg_buf;
u64 x5;
};
#ifdef CONFIG_QCOM_SCM
extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
void *resp_buf, size_t resp_len);
extern int scm_call2(u32 cmd_id, struct scm_desc *desc);
extern int scm_call2_atomic(u32 cmd_id, struct scm_desc *desc);
extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
size_t cmd_len, void *resp_buf, size_t resp_len,
void *scm_buf, size_t scm_buf_size);
extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
extern s32 scm_call_atomic1_1(u32 svc, u32 cmd, u32 arg1, u32 *ret1);
extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
extern s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3);
extern s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3,
u32 arg4, u32 *ret1, u32 *ret2);
extern s32 scm_call_atomic5_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3,
u32 arg4, u32 arg5, u32 *ret1, u32 *ret2, u32 *ret3);
#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF))
extern u32 scm_get_version(void);
extern int scm_is_call_available(u32 svc_id, u32 cmd_id);
extern int scm_get_feat_version(u32 feat);
extern bool is_scm_armv8(void);
extern int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret);
extern u32 scm_io_read(phys_addr_t address);
extern int scm_io_write(phys_addr_t address, u32 val);
extern bool scm_is_secure_device(void);
#define SCM_HDCP_MAX_REG 5
struct scm_hdcp_req {
u32 addr;
u32 val;
};
extern struct mutex scm_lmh_lock;
#else
static inline int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf,
size_t cmd_len, void *resp_buf, size_t resp_len)
{
return 0;
}
static inline int scm_call2(u32 cmd_id, struct scm_desc *desc)
{
return 0;
}
static inline int scm_call2_atomic(u32 cmd_id, struct scm_desc *desc)
{
return 0;
}
static inline int scm_call_noalloc(u32 svc_id, u32 cmd_id,
const void *cmd_buf, size_t cmd_len, void *resp_buf,
size_t resp_len, void *scm_buf, size_t scm_buf_size)
{
return 0;
}
static inline s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
{
return 0;
}
static inline s32 scm_call_atomic1_1(u32 svc, u32 cmd, u32 arg1, u32 *ret1)
{
return 0;
}
static inline s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
{
return 0;
}
static inline s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
u32 arg3)
{
return 0;
}
static inline s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
{
return 0;
}
static inline s32 scm_call_atomic5_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
u32 arg3, u32 arg4, u32 arg5, u32 *ret1, u32 *ret2, u32 *ret3)
{
return 0;
}
static inline u32 scm_get_version(void)
{
return 0;
}
static inline int scm_is_call_available(u32 svc_id, u32 cmd_id)
{
return 0;
}
static inline int scm_get_feat_version(u32 feat)
{
return 0;
}
static inline bool is_scm_armv8(void)
{
return true;
}
static inline int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret)
{
return 0;
}
static inline u32 scm_io_read(phys_addr_t address)
{
return 0;
}
static inline int scm_io_write(phys_addr_t address, u32 val)
{
return 0;
}
inline bool scm_is_secure_device(void)
{
return false;
}
#endif
#endif

@ -0,0 +1,68 @@
/* Copyright (c) 2016, 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.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM scm
#if !defined(_TRACE_SCM_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SCM_H
#include <linux/types.h>
#include <linux/tracepoint.h>
#include <soc/qcom/scm.h>
TRACE_EVENT(scm_call_start,
TP_PROTO(u64 x0, struct scm_desc *p),
TP_ARGS(x0, p),
TP_STRUCT__entry(
__field(u64, x0)
__field(u32, arginfo)
__array(u64, args, MAX_SCM_ARGS)
__field(u64, x5)
),
TP_fast_assign(
__entry->x0 = x0;
__entry->arginfo = p->arginfo;
memcpy(__entry->args, p->args, MAX_SCM_ARGS);
__entry->x5 = p->x5;
),
TP_printk("func id=%#llx (args: %#x, %#llx, %#llx, %#llx, %#llx)",
__entry->x0, __entry->arginfo, __entry->args[0],
__entry->args[1], __entry->args[2], __entry->x5)
);
TRACE_EVENT(scm_call_end,
TP_PROTO(struct scm_desc *p),
TP_ARGS(p),
TP_STRUCT__entry(
__array(u64, ret, MAX_SCM_RETS)
),
TP_fast_assign(
memcpy(__entry->ret, p->ret, MAX_SCM_RETS);
),
TP_printk("ret: %#llx, %#llx, %#llx",
__entry->ret[0], __entry->ret[1], __entry->ret[2])
);
#endif /* _TRACE_SCM_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
Loading…
Cancel
Save