Commit 333505a4 authored by Olof Johansson's avatar Olof Johansson

Merge tag 'qcom-drivers-for-5.6' of...

Merge tag 'qcom-drivers-for-5.6' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers

Qualcomm driver updates for v5.6

* SCM major refactoring and cleanup
* Properly flag active only power domains as active only
* Add SC7180 and SM8150 RPMH power domains
* Return EPROBE_DEFER from QMI if packet family is not yet available

* tag 'qcom-drivers-for-5.6' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (27 commits)
  firmware: qcom_scm: Dynamically support SMCCC and legacy conventions
  firmware: qcom_scm: Remove thin wrappers
  firmware: qcom_scm: Order functions, definitions by service/command
  firmware: qcom_scm-32: Add device argument to atomic calls
  firmware: qcom_scm-32: Create common legacy atomic call
  firmware: qcom_scm-32: Move SMCCC register filling to qcom_scm_call
  firmware: qcom_scm-32: Use qcom_scm_desc in non-atomic calls
  firmware: qcom_scm-32: Add funcnum IDs
  firmware: qcom_scm-32: Use SMC arch wrappers
  firmware: qcom_scm-64: Improve SMC convention detection
  firmware: qcom_scm-64: Move SMC register filling to qcom_scm_call_smccc
  firmware: qcom_scm-64: Add SCM results struct
  firmware: qcom_scm-64: Move svc/cmd/owner into qcom_scm_desc
  firmware: qcom_scm-64: Make SMC macros less magical
  firmware: qcom_scm: Remove unused qcom_scm_get_version
  firmware: qcom_scm: Apply consistent naming scheme to command IDs
  firmware: qcom_scm: Rename macros and structures
  soc: qcom: rpmhpd: Set 'active_only' for active only power domains
  firmware: scm: Add stubs for OCMEM and restore_sec_cfg_available
  dt-bindings: power: rpmpd: Convert rpmpd bindings to yaml
  ...

Link: https://lore.kernel.org/r/20200113204405.GD3325@yogaSigned-off-by: default avatarOlof Johansson <olof@lixom.net>
parents a9e3e12f 9a434cee
......@@ -47,7 +47,7 @@ examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
cache-controller@1100000 {
system-cache-controller@1100000 {
compatible = "qcom,sdm845-llcc";
reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
reg-names = "llcc_base", "llcc_broadcast_base";
......
Qualcomm RPM/RPMh Power domains
For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh
which then translates it into a corresponding voltage on a rail
Required Properties:
- compatible: Should be one of the following
* qcom,msm8976-rpmpd: RPM Power domain for the msm8976 family of SoC
* qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC
* qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC
* qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC
* qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC
- #power-domain-cells: number of cells in Power domain specifier
must be 1.
- operating-points-v2: Phandle to the OPP table for the Power domain.
Refer to Documentation/devicetree/bindings/power/power_domain.txt
and Documentation/devicetree/bindings/opp/opp.txt for more details
Refer to <dt-bindings/power/qcom-rpmpd.h> for the level values for
various OPPs for different platforms as well as Power domain indexes
Example: rpmh power domain controller and OPP table
#include <dt-bindings/power/qcom-rpmhpd.h>
opp-level values specified in the OPP tables for RPMh power domains
should use the RPMH_REGULATOR_LEVEL_* constants from
<dt-bindings/power/qcom-rpmhpd.h>
rpmhpd: power-controller {
compatible = "qcom,sdm845-rpmhpd";
#power-domain-cells = <1>;
operating-points-v2 = <&rpmhpd_opp_table>;
rpmhpd_opp_table: opp-table {
compatible = "operating-points-v2";
rpmhpd_opp_ret: opp1 {
opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
};
rpmhpd_opp_min_svs: opp2 {
opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
};
rpmhpd_opp_low_svs: opp3 {
opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
};
rpmhpd_opp_svs: opp4 {
opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
};
rpmhpd_opp_svs_l1: opp5 {
opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
};
rpmhpd_opp_nom: opp6 {
opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
};
rpmhpd_opp_nom_l1: opp7 {
opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
};
rpmhpd_opp_nom_l2: opp8 {
opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
};
rpmhpd_opp_turbo: opp9 {
opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
};
rpmhpd_opp_turbo_l1: opp10 {
opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
};
};
};
Example: rpm power domain controller and OPP table
rpmpd: power-controller {
compatible = "qcom,msm8996-rpmpd";
#power-domain-cells = <1>;
operating-points-v2 = <&rpmpd_opp_table>;
rpmpd_opp_table: opp-table {
compatible = "operating-points-v2";
rpmpd_opp_low: opp1 {
opp-level = <1>;
};
rpmpd_opp_ret: opp2 {
opp-level = <2>;
};
rpmpd_opp_svs: opp3 {
opp-level = <3>;
};
rpmpd_opp_normal: opp4 {
opp-level = <4>;
};
rpmpd_opp_high: opp5 {
opp-level = <5>;
};
rpmpd_opp_turbo: opp6 {
opp-level = <6>;
};
};
};
Example: Client/Consumer device using OPP table
leaky-device0@12350000 {
compatible = "foo,i-leak-current";
reg = <0x12350000 0x1000>;
power-domains = <&rpmhpd SDM845_MX>;
operating-points-v2 = <&leaky_opp_table>;
};
leaky_opp_table: opp-table {
compatible = "operating-points-v2";
opp1 {
opp-hz = /bits/ 64 <144000>;
required-opps = <&rpmhpd_opp_low>;
};
opp2 {
opp-hz = /bits/ 64 <400000>;
required-opps = <&rpmhpd_opp_ret>;
};
opp3 {
opp-hz = /bits/ 64 <20000000>;
required-opps = <&rpmpd_opp_svs>;
};
opp4 {
opp-hz = /bits/ 64 <25000000>;
required-opps = <&rpmpd_opp_normal>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/qcom,rpmpd.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm RPM/RPMh Power domains
maintainers:
- Rajendra Nayak <rnayak@codeaurora.org>
description:
For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh
which then translates it into a corresponding voltage on a rail.
properties:
compatible:
enum:
- qcom,msm8976-rpmpd
- qcom,msm8996-rpmpd
- qcom,msm8998-rpmpd
- qcom,qcs404-rpmpd
- qcom,sc7180-rpmhpd
- qcom,sdm845-rpmhpd
- qcom,sm8150-rpmhpd
'#power-domain-cells':
const: 1
operating-points-v2: true
opp-table:
type: object
required:
- compatible
- '#power-domain-cells'
- operating-points-v2
additionalProperties: false
examples:
- |
// Example 1 (rpmh power domain controller and OPP table):
#include <dt-bindings/power/qcom-rpmpd.h>
rpmhpd: power-controller {
compatible = "qcom,sdm845-rpmhpd";
#power-domain-cells = <1>;
operating-points-v2 = <&rpmhpd_opp_table>;
rpmhpd_opp_table: opp-table {
compatible = "operating-points-v2";
rpmhpd_opp_ret: opp1 {
opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
};
rpmhpd_opp_min_svs: opp2 {
opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
};
rpmhpd_opp_low_svs: opp3 {
opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
};
rpmhpd_opp_svs: opp4 {
opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
};
rpmhpd_opp_svs_l1: opp5 {
opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
};
rpmhpd_opp_nom: opp6 {
opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
};
rpmhpd_opp_nom_l1: opp7 {
opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
};
rpmhpd_opp_nom_l2: opp8 {
opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
};
rpmhpd_opp_turbo: opp9 {
opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
};
rpmhpd_opp_turbo_l1: opp10 {
opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
};
};
};
- |
// Example 2 (rpm power domain controller and OPP table):
rpmpd: power-controller {
compatible = "qcom,msm8996-rpmpd";
#power-domain-cells = <1>;
operating-points-v2 = <&rpmpd_opp_table>;
rpmpd_opp_table: opp-table {
compatible = "operating-points-v2";
rpmpd_opp_low: opp1 {
opp-level = <1>;
};
rpmpd_opp_ret: opp2 {
opp-level = <2>;
};
rpmpd_opp_svs: opp3 {
opp-level = <3>;
};
rpmpd_opp_normal: opp4 {
opp-level = <4>;
};
rpmpd_opp_high: opp5 {
opp-level = <5>;
};
rpmpd_opp_turbo: opp6 {
opp-level = <6>;
};
};
};
- |
// Example 3 (Client/Consumer device using OPP table):
leaky-device0@12350000 {
compatible = "foo,i-leak-current";
reg = <0x12350000 0x1000>;
power-domains = <&rpmhpd 0>;
operating-points-v2 = <&leaky_opp_table>;
};
leaky_opp_table: opp-table {
compatible = "operating-points-v2";
opp1 {
opp-hz = /bits/ 64 <144000>;
required-opps = <&rpmhpd_opp_low>;
};
opp2 {
opp-hz = /bits/ 64 <400000>;
required-opps = <&rpmhpd_opp_ret>;
};
opp3 {
opp-hz = /bits/ 64 <20000000>;
required-opps = <&rpmpd_opp_svs>;
};
opp4 {
opp-hz = /bits/ 64 <25000000>;
required-opps = <&rpmpd_opp_normal>;
};
};
...
......@@ -239,14 +239,6 @@ config QCOM_SCM
depends on ARM || ARM64
select RESET_CONTROLLER
config QCOM_SCM_32
def_bool y
depends on QCOM_SCM && ARM
config QCOM_SCM_64
def_bool y
depends on QCOM_SCM && ARM64
config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
bool "Qualcomm download mode enabled by default"
depends on QCOM_SCM
......
......@@ -17,10 +17,7 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*/
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
#include "qcom_scm.h"
static DEFINE_MUTEX(qcom_scm_lock);
/**
* struct arm_smccc_args
* @args: The array of values used in registers in smc instruction
*/
struct arm_smccc_args {
unsigned long args[8];
};
/**
* struct scm_legacy_command - one SCM command buffer
* @len: total available memory for command and response
* @buf_offset: start of command buffer
* @resp_hdr_offset: start of response buffer
* @id: command to be executed
* @buf: buffer returned from scm_legacy_get_command_buffer()
*
* An SCM command is laid out in memory as follows:
*
* ------------------- <--- struct scm_legacy_command
* | command header |
* ------------------- <--- scm_legacy_get_command_buffer()
* | command buffer |
* ------------------- <--- struct scm_legacy_response and
* | response header | scm_legacy_command_to_response()
* ------------------- <--- scm_legacy_get_response_buffer()
* | response buffer |
* -------------------
*
* There can be arbitrary padding between the headers and buffers so
* you should always use the appropriate scm_legacy_get_*_buffer() routines
* to access the buffers in a safe manner.
*/
struct scm_legacy_command {
__le32 len;
__le32 buf_offset;
__le32 resp_hdr_offset;
__le32 id;
__le32 buf[0];
};
/**
* struct scm_legacy_response - one SCM response buffer
* @len: total available memory for response
* @buf_offset: start of response data relative to start of scm_legacy_response
* @is_complete: indicates if the command has finished processing
*/
struct scm_legacy_response {
__le32 len;
__le32 buf_offset;
__le32 is_complete;
};
/**
* scm_legacy_command_to_response() - Get a pointer to a scm_legacy_response
* @cmd: command
*
* Returns a pointer to a response for a command.
*/
static inline struct scm_legacy_response *scm_legacy_command_to_response(
const struct scm_legacy_command *cmd)
{
return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
}
/**
* scm_legacy_get_command_buffer() - Get a pointer to a command buffer
* @cmd: command
*
* Returns a pointer to the command buffer of a command.
*/
static inline void *scm_legacy_get_command_buffer(
const struct scm_legacy_command *cmd)
{
return (void *)cmd->buf;
}
/**
* scm_legacy_get_response_buffer() - Get a pointer to a response buffer
* @rsp: response
*
* Returns a pointer to a response buffer of a response.
*/
static inline void *scm_legacy_get_response_buffer(
const struct scm_legacy_response *rsp)
{
return (void *)rsp + le32_to_cpu(rsp->buf_offset);
}
static void __scm_legacy_do(const struct arm_smccc_args *smc,
struct arm_smccc_res *res)
{
do {
arm_smccc_smc(smc->args[0], smc->args[1], smc->args[2],
smc->args[3], smc->args[4], smc->args[5],
smc->args[6], smc->args[7], res);
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}
/**
* qcom_scm_call() - Sends a command to the SCM and waits for the command to
* finish processing.
*
* A note on cache maintenance:
* Note that any buffers that are expected to be accessed by the secure world
* must be flushed before invoking qcom_scm_call and invalidated in the cache
* immediately after qcom_scm_call returns. Cache maintenance on the command
* and response buffers is taken care of by qcom_scm_call; however, callers are
* responsible for any other cached buffers passed over to the secure world.
*/
int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
struct qcom_scm_res *res)
{
u8 arglen = desc->arginfo & 0xf;
int ret = 0, context_id;
unsigned int i;
struct scm_legacy_command *cmd;
struct scm_legacy_response *rsp;
struct arm_smccc_args smc = {0};
struct arm_smccc_res smc_res;
const size_t cmd_len = arglen * sizeof(__le32);
const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
dma_addr_t cmd_phys;
__le32 *arg_buf;
const __le32 *res_buf;
cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
cmd->len = cpu_to_le32(alloc_len);
cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
cmd->id = cpu_to_le32(SCM_LEGACY_FNID(desc->svc, desc->cmd));
arg_buf = scm_legacy_get_command_buffer(cmd);
for (i = 0; i < arglen; i++)
arg_buf[i] = cpu_to_le32(desc->args[i]);
rsp = scm_legacy_command_to_response(cmd);
cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, cmd_phys)) {
kfree(cmd);
return -ENOMEM;
}
smc.args[0] = 1;
smc.args[1] = (unsigned long)&context_id;
smc.args[2] = cmd_phys;
mutex_lock(&qcom_scm_lock);
__scm_legacy_do(&smc, &smc_res);
if (smc_res.a0)
ret = qcom_scm_remap_error(smc_res.a0);
mutex_unlock(&qcom_scm_lock);
if (ret)
goto out;
do {
dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
sizeof(*rsp), DMA_FROM_DEVICE);
} while (!rsp->is_complete);
dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
le32_to_cpu(rsp->buf_offset),
resp_len, DMA_FROM_DEVICE);
if (res) {
res_buf = scm_legacy_get_response_buffer(rsp);
for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
res->result[i] = le32_to_cpu(res_buf[i]);
}
out:
dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
kfree(cmd);
return ret;
}
#define SCM_LEGACY_ATOMIC_N_REG_ARGS 5
#define SCM_LEGACY_ATOMIC_FIRST_REG_IDX 2
#define SCM_LEGACY_CLASS_REGISTER (0x2 << 8)
#define SCM_LEGACY_MASK_IRQS BIT(5)
#define SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \
((SCM_LEGACY_FNID(svc, cmd) << 12) | \
SCM_LEGACY_CLASS_REGISTER | \
SCM_LEGACY_MASK_IRQS | \
(n & 0xf))
/**
* qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments
* and 3 return values
* @desc: SCM call descriptor containing arguments
* @res: SCM call return values
*
* This shall only be used with commands that are guaranteed to be
* uninterruptable, atomic and SMP safe.
*/
int scm_legacy_call_atomic(struct device *unused,
const struct qcom_scm_desc *desc,
struct qcom_scm_res *res)
{
int context_id;
struct arm_smccc_res smc_res;
size_t arglen = desc->arginfo & 0xf;
BUG_ON(arglen > SCM_LEGACY_ATOMIC_N_REG_ARGS);
arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(desc->svc, desc->cmd, arglen),
(unsigned long)&context_id,
desc->args[0], desc->args[1], desc->args[2],
desc->args[3], desc->args[4], 0, &smc_res);
if (res) {
res->result[0] = smc_res.a1;
res->result[1] = smc_res.a2;
res->result[2] = smc_res.a3;
}
return smc_res.a0;
}
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
*/
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
#include "qcom_scm.h"
/**
* struct arm_smccc_args
* @args: The array of values used in registers in smc instruction
*/
struct arm_smccc_args {
unsigned long args[8];
};
static DEFINE_MUTEX(qcom_scm_lock);
#define QCOM_SCM_EBUSY_WAIT_MS 30
#define QCOM_SCM_EBUSY_MAX_RETRY 20
#define SCM_SMC_N_REG_ARGS 4
#define SCM_SMC_FIRST_EXT_IDX (SCM_SMC_N_REG_ARGS - 1)
#define SCM_SMC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SCM_SMC_N_REG_ARGS + 1)
#define SCM_SMC_FIRST_REG_IDX 2
#define SCM_SMC_LAST_REG_IDX (SCM_SMC_FIRST_REG_IDX + SCM_SMC_N_REG_ARGS - 1)
static void __scm_smc_do_quirk(const struct arm_smccc_args *smc,
struct arm_smccc_res *res)
{
unsigned long a0 = smc->args[0];
struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
quirk.state.a6 = 0;
do {
arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2],
smc->args[3], smc->args[4], smc->args[5],
quirk.state.a6, smc->args[7], res, &quirk);
if (res->a0 == QCOM_SCM_INTERRUPTED)
a0 = res->a0;
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}
static void __scm_smc_do(const struct arm_smccc_args *smc,
struct arm_smccc_res *res, bool atomic)
{
int retry_count = 0;
if (atomic) {
__scm_smc_do_quirk(smc, res);
return;
}
do {
mutex_lock(&qcom_scm_lock);
__scm_smc_do_quirk(smc, res);
mutex_unlock(&qcom_scm_lock);
if (res->a0 == QCOM_SCM_V2_EBUSY) {
if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
break;
msleep(QCOM_SCM_EBUSY_WAIT_MS);
}
} while (res->a0 == QCOM_SCM_V2_EBUSY);
}
int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
struct qcom_scm_res *res, bool atomic)
{
int arglen = desc->arginfo & 0xf;
int i;
dma_addr_t args_phys = 0;
void *args_virt = NULL;
size_t alloc_len;
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
u32 qcom_smccc_convention =
(qcom_scm_convention == SMC_CONVENTION_ARM_32) ?
ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64;
struct arm_smccc_res smc_res;
struct arm_smccc_args smc = {0};
smc.args[0] = ARM_SMCCC_CALL_VAL(
smccc_call_type,
qcom_smccc_convention,
desc->owner,
SCM_SMC_FNID(desc->svc, desc->cmd));
smc.args[1] = desc->arginfo;
for (i = 0; i < SCM_SMC_N_REG_ARGS; i++)
smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i];
if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) {
alloc_len = SCM_SMC_N_EXT_ARGS * sizeof(u64);
args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
if (!args_virt)
return -ENOMEM;
if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
__le32 *args = args_virt;
for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
args[i] = cpu_to_le32(desc->args[i +
SCM_SMC_FIRST_EXT_IDX]);
} else {
__le64 *args = args_virt;
for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
args[i] = cpu_to_le64(desc->args[i +
SCM_SMC_FIRST_EXT_IDX]);
}
args_phys = dma_map_single(dev, args_virt, alloc_len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, args_phys)) {
kfree(args_virt);
return -ENOMEM;
}
smc.args[SCM_SMC_LAST_REG_IDX] = args_phys;
}
__scm_smc_do(&smc, &smc_res, atomic);
if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
kfree(args_virt);
}
if (res) {
res->result[0] = smc_res.a1;
res->result[1] = smc_res.a2;
res->result[2] = smc_res.a3;
}
return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0;
}
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved.
*/
#ifndef __QCOM_SCM_INT_H
#define __QCOM_SCM_INT_H
#define QCOM_SCM_SVC_BOOT 0x1
#define QCOM_SCM_BOOT_ADDR 0x1
#define QCOM_SCM_SET_DLOAD_MODE 0x10
#define QCOM_SCM_BOOT_ADDR_MC 0x11
#define QCOM_SCM_SET_REMOTE_STATE 0xa
extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
#define QCOM_SCM_FLAG_HLOS 0x01
#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04
extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus);
extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
#define QCOM_SCM_CMD_TERMINATE_PC 0x2
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,
struct qcom_scm_res *res, bool 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_REMOTE_STATE 0x0a
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
#define QCOM_SCM_CMD_CORE_HOTPLUGGED 0x10
extern void __qcom_scm_cpu_power_down(u32 flags);
#define QCOM_SCM_SVC_IO 0x5
#define QCOM_SCM_IO_READ 0x1
#define QCOM_SCM_IO_WRITE 0x2
extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val);
extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);
#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_ASSIGN 0x16
#define QCOM_SCM_SVC_INFO 0x6
#define QCOM_IS_CALL_AVAIL_CMD 0x1
extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
u32 cmd_id);
#define QCOM_SCM_SVC_OCMEM 0x0f
#define QCOM_SCM_OCMEM_LOCK_CMD 0x01
#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x02
#define QCOM_SCM_SVC_HDCP 0x11
#define QCOM_SCM_CMD_HDCP 0x01
extern int __qcom_scm_hdcp_req(struct device *dev,
struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
#define QCOM_SCM_HDCP_INVOKE 0x01
extern void __qcom_scm_init(void);
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
#define QCOM_SCM_OCMEM_SVC 0xf
#define QCOM_SCM_OCMEM_LOCK_CMD 0x1
#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x2
extern int __qcom_scm_ocmem_lock(struct device *dev, u32 id, u32 offset,
u32 size, u32 mode);
extern int __qcom_scm_ocmem_unlock(struct device *dev, u32 id, u32 offset,
u32 size);
#define QCOM_SCM_SVC_PIL 0x2
#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1
#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2
#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5
#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6
#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7
#define QCOM_SCM_PAS_MSS_RESET 0xa
extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys);
extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
phys_addr_t addr, phys_addr_t size);
extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
extern void __qcom_scm_init(void);
/* common error codes */
#define QCOM_SCM_V2_EBUSY -12
......@@ -94,25 +139,4 @@ static inline int qcom_scm_remap_error(int err)
return -EINVAL;
}
#define QCOM_SCM_SVC_MP 0xc
#define QCOM_SCM_RESTORE_SEC_CFG 2
extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
u32 spare);
#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3
#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
#define QCOM_SCM_CONFIG_ERRATA1 0x3
#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2
extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
size_t *size);
extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
u32 size, u32 spare);
extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
bool enable);
#define QCOM_MEM_PROT_ASSIGN_ID 0x16
extern int __qcom_scm_assign_mem(struct device *dev,
phys_addr_t mem_region, size_t mem_sz,
phys_addr_t src, size_t src_sz,
phys_addr_t dest, size_t dest_sz);
#endif
......@@ -655,8 +655,12 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size,
qmi->sock = qmi_sock_create(qmi, &qmi->sq);
if (IS_ERR(qmi->sock)) {
if (PTR_ERR(qmi->sock) == -EAFNOSUPPORT) {
ret = -EPROBE_DEFER;
} else {
pr_err("failed to create QMI socket\n");
ret = PTR_ERR(qmi->sock);
}
goto err_destroy_wq;
}
......
......@@ -93,6 +93,7 @@ static struct rpmhpd sdm845_mx = {
static struct rpmhpd sdm845_mx_ao = {
.pd = { .name = "mx_ao", },
.active_only = true,
.peer = &sdm845_mx,
.res_name = "mx.lvl",
};
......@@ -107,6 +108,7 @@ static struct rpmhpd sdm845_cx = {
static struct rpmhpd sdm845_cx_ao = {
.pd = { .name = "cx_ao", },
.active_only = true,
.peer = &sdm845_cx,
.parent = &sdm845_mx_ao.pd,
.res_name = "cx.lvl",
......@@ -129,8 +131,62 @@ static const struct rpmhpd_desc sdm845_desc = {
.num_pds = ARRAY_SIZE(sdm845_rpmhpds),
};
/* SM8150 RPMH powerdomains */
static struct rpmhpd sm8150_mmcx_ao;
static struct rpmhpd sm8150_mmcx = {
.pd = { .name = "mmcx", },
.peer = &sm8150_mmcx_ao,
.res_name = "mmcx.lvl",
};
static struct rpmhpd sm8150_mmcx_ao = {
.pd = { .name = "mmcx_ao", },
.active_only = true,
.peer = &sm8150_mmcx,
.res_name = "mmcx.lvl",
};
static struct rpmhpd *sm8150_rpmhpds[] = {
[SM8150_MSS] = &sdm845_mss,
[SM8150_EBI] = &sdm845_ebi,
[SM8150_LMX] = &sdm845_lmx,
[SM8150_LCX] = &sdm845_lcx,
[SM8150_GFX] = &sdm845_gfx,
[SM8150_MX] = &sdm845_mx,
[SM8150_MX_AO] = &sdm845_mx_ao,
[SM8150_CX] = &sdm845_cx,
[SM8150_CX_AO] = &sdm845_cx_ao,
[SM8150_MMCX] = &sm8150_mmcx,
[SM8150_MMCX_AO] = &sm8150_mmcx_ao,
};
static const struct rpmhpd_desc sm8150_desc = {
.rpmhpds = sm8150_rpmhpds,
.num_pds = ARRAY_SIZE(sm8150_rpmhpds),
};
/* SC7180 RPMH powerdomains */
static struct rpmhpd *sc7180_rpmhpds[] = {
[SC7180_CX] = &sdm845_cx,
[SC7180_CX_AO] = &sdm845_cx_ao,
[SC7180_GFX] = &sdm845_gfx,
[SC7180_MX] = &sdm845_mx,
[SC7180_MX_AO] = &sdm845_mx_ao,
[SC7180_LMX] = &sdm845_lmx,
[SC7180_LCX] = &sdm845_lcx,
[SC7180_MSS] = &sdm845_mss,
};
static const struct rpmhpd_desc sc7180_desc = {
.rpmhpds = sc7180_rpmhpds,
.num_pds = ARRAY_SIZE(sc7180_rpmhpds),
};
static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
{ .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },
{ }
};
......
......@@ -15,12 +15,36 @@
#define SDM845_GFX 7
#define SDM845_MSS 8
/* SM8150 Power Domain Indexes */
#define SM8150_MSS 0
#define SM8150_EBI 1
#define SM8150_LMX 2
#define SM8150_LCX 3
#define SM8150_GFX 4
#define SM8150_MX 5
#define SM8150_MX_AO 6
#define SM8150_CX 7
#define SM8150_CX_AO 8
#define SM8150_MMCX 9
#define SM8150_MMCX_AO 10
/* SC7180 Power Domain Indexes */
#define SC7180_CX 0
#define SC7180_CX_AO 1
#define SC7180_GFX 2
#define SC7180_MX 3
#define SC7180_MX_AO 4
#define SC7180_LMX 5
#define SC7180_LCX 6
#define SC7180_MSS 7
/* SDM845 Power Domain performance levels */
#define RPMH_REGULATOR_LEVEL_RETENTION 16
#define RPMH_REGULATOR_LEVEL_MIN_SVS 48
#define RPMH_REGULATOR_LEVEL_LOW_SVS 64
#define RPMH_REGULATOR_LEVEL_SVS 128
#define RPMH_REGULATOR_LEVEL_SVS_L1 192
#define RPMH_REGULATOR_LEVEL_SVS_L2 224
#define RPMH_REGULATOR_LEVEL_NOM 256
#define RPMH_REGULATOR_LEVEL_NOM_L1 320
#define RPMH_REGULATOR_LEVEL_NOM_L2 336
......
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2010-2015, 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*/
#ifndef __QCOM_SCM_H
......@@ -55,77 +55,94 @@ enum qcom_scm_sec_dev_id {
#define QCOM_SCM_PERM_RWX (QCOM_SCM_PERM_RW | QCOM_SCM_PERM_EXEC)
#if IS_ENABLED(CONFIG_QCOM_SCM)
extern bool qcom_scm_is_available(void);
extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
extern bool qcom_scm_is_available(void);
extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
extern bool qcom_scm_ocmem_lock_available(void);
extern int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size, u32 mode);
extern int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size);
extern bool qcom_scm_pas_supported(u32 peripheral);
extern void qcom_scm_cpu_power_down(u32 flags);
extern int qcom_scm_set_remote_state(u32 state, u32 id);
extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size);
extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size);
extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
extern int qcom_scm_pas_shutdown(u32 peripheral);
extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src,
const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt);
extern void qcom_scm_cpu_power_down(u32 flags);
extern u32 qcom_scm_get_version(void);
extern int qcom_scm_set_remote_state(u32 state, u32 id);
extern bool qcom_scm_pas_supported(u32 peripheral);
extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
extern bool qcom_scm_restore_sec_cfg_available(void);
extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src,
const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt);
extern bool qcom_scm_ocmem_lock_available(void);
extern int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size, u32 mode);
extern int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size);
extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
#else
#include <linux/errno.h>
static inline
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
{
return -ENODEV;
}
static inline
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
{
return -ENODEV;
}
static inline bool qcom_scm_is_available(void) { return false; }
static inline bool qcom_scm_hdcp_available(void) { return false; }
static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp) { return -ENODEV; }
static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; }
static inline int qcom_scm_set_cold_boot_addr(void *entry,
const cpumask_t *cpus) { return -ENODEV; }
static inline int qcom_scm_set_warm_boot_addr(void *entry,
const cpumask_t *cpus) { return -ENODEV; }
static inline void qcom_scm_cpu_power_down(u32 flags) {}
static inline u32 qcom_scm_set_remote_state(u32 state,u32 id)
{ return -ENODEV; }
static inline int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size) { return -ENODEV; }
static inline int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size) { return -ENODEV; }
static inline int
qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
static inline int qcom_scm_pas_auth_and_reset(u32 peripheral)
{ return -ENODEV; }
static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; }
static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
{ return -ENODEV; }
static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
{ return -ENODEV; }
static inline bool qcom_scm_restore_sec_cfg_available(void) { return false; }
static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
{ return -ENODEV; }
static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
{ return -ENODEV; }
static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
{ return -ENODEV; }
static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src,
const struct qcom_scm_vmperm *newvm,
unsigned int *src, const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt) { return -ENODEV; }
static inline void qcom_scm_cpu_power_down(u32 flags) {}
static inline u32 qcom_scm_get_version(void) { return 0; }
static inline u32
qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; }
static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; }
static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; }
static inline bool qcom_scm_ocmem_lock_available(void) { return false; }
static inline int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size, u32 mode) { return -ENODEV; }
static inline int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id,
u32 offset, u32 size) { return -ENODEV; }
static inline bool qcom_scm_hdcp_available(void) { return false; }
static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp) { return -ENODEV; }
static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
{ return -ENODEV; }
#endif
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment