mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
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@yoga Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
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>;
|
||||
};
|
||||
};
|
||||
170
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
Normal file
170
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
Normal file
@@ -0,0 +1,170 @@
|
||||
# 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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
242
drivers/firmware/qcom_scm-legacy.c
Normal file
242
drivers/firmware/qcom_scm-legacy.c
Normal file
@@ -0,0 +1,242 @@
|
||||
// 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;
|
||||
}
|
||||
151
drivers/firmware/qcom_scm-smc.c
Normal file
151
drivers/firmware/qcom_scm-smc.c
Normal file
@@ -0,0 +1,151 @@
|
||||
// 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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +1,117 @@
|
||||
/* 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);
|
||||
enum qcom_scm_convention {
|
||||
SMC_CONVENTION_UNKNOWN,
|
||||
SMC_CONVENTION_LEGACY,
|
||||
SMC_CONVENTION_ARM_32,
|
||||
SMC_CONVENTION_ARM_64,
|
||||
};
|
||||
|
||||
#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);
|
||||
extern enum qcom_scm_convention qcom_scm_convention;
|
||||
|
||||
#define QCOM_SCM_CMD_TERMINATE_PC 0x2
|
||||
#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_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_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_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
|
||||
|
||||
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
|
||||
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
|
||||
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
|
||||
|
||||
extern void __qcom_scm_init(void);
|
||||
|
||||
#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);
|
||||
|
||||
/* common error codes */
|
||||
#define QCOM_SCM_V2_EBUSY -12
|
||||
#define QCOM_SCM_ENOMEM -5
|
||||
@@ -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
|
||||
|
||||
@@ -45,13 +45,13 @@ config QCOM_GLINK_SSR
|
||||
neighboring subsystems going up or down.
|
||||
|
||||
config QCOM_GSBI
|
||||
tristate "QCOM General Serial Bus Interface"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Say y here to enable GSBI support. The GSBI provides control
|
||||
functions for connecting the underlying serial UART, SPI, and I2C
|
||||
devices to the output pins.
|
||||
tristate "QCOM General Serial Bus Interface"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Say y here to enable GSBI support. The GSBI provides control
|
||||
functions for connecting the underlying serial UART, SPI, and I2C
|
||||
devices to the output pins.
|
||||
|
||||
config QCOM_LLCC
|
||||
tristate "Qualcomm Technologies, Inc. LLCC driver"
|
||||
@@ -71,10 +71,10 @@ config QCOM_OCMEM
|
||||
depends on ARCH_QCOM
|
||||
select QCOM_SCM
|
||||
help
|
||||
The On Chip Memory (OCMEM) allocator allows various clients to
|
||||
allocate memory from OCMEM based on performance, latency and power
|
||||
requirements. This is typically used by the GPU, camera/video, and
|
||||
audio components on some Snapdragon SoCs.
|
||||
The On Chip Memory (OCMEM) allocator allows various clients to
|
||||
allocate memory from OCMEM based on performance, latency and power
|
||||
requirements. This is typically used by the GPU, camera/video, and
|
||||
audio components on some Snapdragon SoCs.
|
||||
|
||||
config QCOM_PM
|
||||
bool "Qualcomm Power Management"
|
||||
@@ -198,8 +198,8 @@ config QCOM_APR
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on RPMSG
|
||||
help
|
||||
Enable APR IPC protocol support between
|
||||
application processor and QDSP6. APR is
|
||||
used by audio driver to configure QDSP6
|
||||
ASM, ADM and AFE modules.
|
||||
Enable APR IPC protocol support between
|
||||
application processor and QDSP6. APR is
|
||||
used by audio driver to configure QDSP6
|
||||
ASM, ADM and AFE modules.
|
||||
endmenu
|
||||
|
||||
@@ -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)) {
|
||||
pr_err("failed to create QMI socket\n");
|
||||
ret = PTR_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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* 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 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_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 dest_cnt) { 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 bool qcom_scm_pas_supported(u32 peripheral) { return false; }
|
||||
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_shutdown(u32 peripheral) { 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 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; }
|
||||
u32 *resp) { return -ENODEV; }
|
||||
|
||||
static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
|
||||
{ return -ENODEV; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user