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 ...
Unified · Split
| @@ -47,7 +47,7 @@ examples: · 46 unmodified lines | ||
| 47 | 47 | - | |
| 48 | 48 | #include <dt-bindings/interrupt-controller/arm-gic.h> |
| 49 | 49 | |
| 50 | − cache-controller@1100000 { | |
| 50 | + system-cache-controller@1100000 { | |
| 51 | 51 | compatible = "qcom,sdm845-llcc"; |
| 52 | 52 | reg = <0x1100000 0x200000>, <0x1300000 0x50000> ; |
| 53 | 53 | reg-names = "llcc_base", "llcc_broadcast_base"; |
| @@ -1,148 +0,0 @@ | ||
| 1 | −Qualcomm RPM/RPMh Power domains | |
| 2 | − | |
| 3 | −For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh | |
| 4 | −which then translates it into a corresponding voltage on a rail | |
| 5 | − | |
| 6 | −Required Properties: | |
| 7 | − - compatible: Should be one of the following | |
| 8 | − * qcom,msm8976-rpmpd: RPM Power domain for the msm8976 family of SoC | |
| 9 | − * qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC | |
| 10 | − * qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC | |
| 11 | − * qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC | |
| 12 | − * qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC | |
| 13 | − - #power-domain-cells: number of cells in Power domain specifier | |
| 14 | − must be 1. | |
| 15 | − - operating-points-v2: Phandle to the OPP table for the Power domain. | |
| 16 | − Refer to Documentation/devicetree/bindings/power/power_domain.txt | |
| 17 | − and Documentation/devicetree/bindings/opp/opp.txt for more details | |
| 18 | − | |
| 19 | −Refer to <dt-bindings/power/qcom-rpmpd.h> for the level values for | |
| 20 | −various OPPs for different platforms as well as Power domain indexes | |
| 21 | − | |
| 22 | −Example: rpmh power domain controller and OPP table | |
| 23 | − | |
| 24 | −#include <dt-bindings/power/qcom-rpmhpd.h> | |
| 25 | − | |
| 26 | −opp-level values specified in the OPP tables for RPMh power domains | |
| 27 | −should use the RPMH_REGULATOR_LEVEL_* constants from | |
| 28 | −<dt-bindings/power/qcom-rpmhpd.h> | |
| 29 | − | |
| 30 | − rpmhpd: power-controller { | |
| 31 | − compatible = "qcom,sdm845-rpmhpd"; | |
| 32 | − #power-domain-cells = <1>; | |
| 33 | − operating-points-v2 = <&rpmhpd_opp_table>; | |
| 34 | − | |
| 35 | − rpmhpd_opp_table: opp-table { | |
| 36 | − compatible = "operating-points-v2"; | |
| 37 | − | |
| 38 | − rpmhpd_opp_ret: opp1 { | |
| 39 | − opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>; | |
| 40 | − }; | |
| 41 | − | |
| 42 | − rpmhpd_opp_min_svs: opp2 { | |
| 43 | − opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>; | |
| 44 | − }; | |
| 45 | − | |
| 46 | − rpmhpd_opp_low_svs: opp3 { | |
| 47 | − opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>; | |
| 48 | − }; | |
| 49 | − | |
| 50 | − rpmhpd_opp_svs: opp4 { | |
| 51 | − opp-level = <RPMH_REGULATOR_LEVEL_SVS>; | |
| 52 | − }; | |
| 53 | − | |
| 54 | − rpmhpd_opp_svs_l1: opp5 { | |
| 55 | − opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>; | |
| 56 | − }; | |
| 57 | − | |
| 58 | − rpmhpd_opp_nom: opp6 { | |
| 59 | − opp-level = <RPMH_REGULATOR_LEVEL_NOM>; | |
| 60 | − }; | |
| 61 | − | |
| 62 | − rpmhpd_opp_nom_l1: opp7 { | |
| 63 | − opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>; | |
| 64 | − }; | |
| 65 | − | |
| 66 | − rpmhpd_opp_nom_l2: opp8 { | |
| 67 | − opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>; | |
| 68 | − }; | |
| 69 | − | |
| 70 | − rpmhpd_opp_turbo: opp9 { | |
| 71 | − opp-level = <RPMH_REGULATOR_LEVEL_TURBO>; | |
| 72 | − }; | |
| 73 | − | |
| 74 | − rpmhpd_opp_turbo_l1: opp10 { | |
| 75 | − opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>; | |
| 76 | − }; | |
| 77 | − }; | |
| 78 | − }; | |
| 79 | − | |
| 80 | −Example: rpm power domain controller and OPP table | |
| 81 | − | |
| 82 | − rpmpd: power-controller { | |
| 83 | − compatible = "qcom,msm8996-rpmpd"; | |
| 84 | − #power-domain-cells = <1>; | |
| 85 | − operating-points-v2 = <&rpmpd_opp_table>; | |
| 86 | − | |
| 87 | − rpmpd_opp_table: opp-table { | |
| 88 | − compatible = "operating-points-v2"; | |
| 89 | − | |
| 90 | − rpmpd_opp_low: opp1 { | |
| 91 | − opp-level = <1>; | |
| 92 | − }; | |
| 93 | − | |
| 94 | − rpmpd_opp_ret: opp2 { | |
| 95 | − opp-level = <2>; | |
| 96 | − }; | |
| 97 | − | |
| 98 | − rpmpd_opp_svs: opp3 { | |
| 99 | − opp-level = <3>; | |
| 100 | − }; | |
| 101 | − | |
| 102 | − rpmpd_opp_normal: opp4 { | |
| 103 | − opp-level = <4>; | |
| 104 | − }; | |
| 105 | − | |
| 106 | − rpmpd_opp_high: opp5 { | |
| 107 | − opp-level = <5>; | |
| 108 | − }; | |
| 109 | − | |
| 110 | − rpmpd_opp_turbo: opp6 { | |
| 111 | − opp-level = <6>; | |
| 112 | − }; | |
| 113 | − }; | |
| 114 | − }; | |
| 115 | − | |
| 116 | −Example: Client/Consumer device using OPP table | |
| 117 | − | |
| 118 | − leaky-device0@12350000 { | |
| 119 | − compatible = "foo,i-leak-current"; | |
| 120 | − reg = <0x12350000 0x1000>; | |
| 121 | − power-domains = <&rpmhpd SDM845_MX>; | |
| 122 | − operating-points-v2 = <&leaky_opp_table>; | |
| 123 | − }; | |
| 124 | − | |
| 125 | − | |
| 126 | − leaky_opp_table: opp-table { | |
| 127 | − compatible = "operating-points-v2"; | |
| 128 | − | |
| 129 | − opp1 { | |
| 130 | − opp-hz = /bits/ 64 <144000>; | |
| 131 | − required-opps = <&rpmhpd_opp_low>; | |
| 132 | − }; | |
| 133 | − | |
| 134 | − opp2 { | |
| 135 | − opp-hz = /bits/ 64 <400000>; | |
| 136 | − required-opps = <&rpmhpd_opp_ret>; | |
| 137 | − }; | |
| 138 | − | |
| 139 | − opp3 { | |
| 140 | − opp-hz = /bits/ 64 <20000000>; | |
| 141 | − required-opps = <&rpmpd_opp_svs>; | |
| 142 | − }; | |
| 143 | − | |
| 144 | − opp4 { | |
| 145 | − opp-hz = /bits/ 64 <25000000>; | |
| 146 | − required-opps = <&rpmpd_opp_normal>; | |
| 147 | − }; | |
| 148 | − }; | |
| @@ -0,0 +1,170 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/power/qcom,rpmpd.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Qualcomm RPM/RPMh Power domains | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Rajendra Nayak <rnayak@codeaurora.org> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh | |
| 14 | + which then translates it into a corresponding voltage on a rail. | |
| 15 | + | |
| 16 | +properties: | |
| 17 | + compatible: | |
| 18 | + enum: | |
| 19 | + - qcom,msm8976-rpmpd | |
| 20 | + - qcom,msm8996-rpmpd | |
| 21 | + - qcom,msm8998-rpmpd | |
| 22 | + - qcom,qcs404-rpmpd | |
| 23 | + - qcom,sc7180-rpmhpd | |
| 24 | + - qcom,sdm845-rpmhpd | |
| 25 | + - qcom,sm8150-rpmhpd | |
| 26 | + | |
| 27 | + '#power-domain-cells': | |
| 28 | + const: 1 | |
| 29 | + | |
| 30 | + operating-points-v2: true | |
| 31 | + | |
| 32 | + opp-table: | |
| 33 | + type: object | |
| 34 | + | |
| 35 | +required: | |
| 36 | + - compatible | |
| 37 | + - '#power-domain-cells' | |
| 38 | + - operating-points-v2 | |
| 39 | + | |
| 40 | +additionalProperties: false | |
| 41 | + | |
| 42 | +examples: | |
| 43 | + - | | |
| 44 | + | |
| 45 | + // Example 1 (rpmh power domain controller and OPP table): | |
| 46 | + | |
| 47 | + #include <dt-bindings/power/qcom-rpmpd.h> | |
| 48 | + | |
| 49 | + rpmhpd: power-controller { | |
| 50 | + compatible = "qcom,sdm845-rpmhpd"; | |
| 51 | + #power-domain-cells = <1>; | |
| 52 | + operating-points-v2 = <&rpmhpd_opp_table>; | |
| 53 | + | |
| 54 | + rpmhpd_opp_table: opp-table { | |
| 55 | + compatible = "operating-points-v2"; | |
| 56 | + | |
| 57 | + rpmhpd_opp_ret: opp1 { | |
| 58 | + opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>; | |
| 59 | + }; | |
| 60 | + | |
| 61 | + rpmhpd_opp_min_svs: opp2 { | |
| 62 | + opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>; | |
| 63 | + }; | |
| 64 | + | |
| 65 | + rpmhpd_opp_low_svs: opp3 { | |
| 66 | + opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>; | |
| 67 | + }; | |
| 68 | + | |
| 69 | + rpmhpd_opp_svs: opp4 { | |
| 70 | + opp-level = <RPMH_REGULATOR_LEVEL_SVS>; | |
| 71 | + }; | |
| 72 | + | |
| 73 | + rpmhpd_opp_svs_l1: opp5 { | |
| 74 | + opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>; | |
| 75 | + }; | |
| 76 | + | |
| 77 | + rpmhpd_opp_nom: opp6 { | |
| 78 | + opp-level = <RPMH_REGULATOR_LEVEL_NOM>; | |
| 79 | + }; | |
| 80 | + | |
| 81 | + rpmhpd_opp_nom_l1: opp7 { | |
| 82 | + opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>; | |
| 83 | + }; | |
| 84 | + | |
| 85 | + rpmhpd_opp_nom_l2: opp8 { | |
| 86 | + opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>; | |
| 87 | + }; | |
| 88 | + | |
| 89 | + rpmhpd_opp_turbo: opp9 { | |
| 90 | + opp-level = <RPMH_REGULATOR_LEVEL_TURBO>; | |
| 91 | + }; | |
| 92 | + | |
| 93 | + rpmhpd_opp_turbo_l1: opp10 { | |
| 94 | + opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>; | |
| 95 | + }; | |
| 96 | + }; | |
| 97 | + }; | |
| 98 | + | |
| 99 | + - | | |
| 100 | + | |
| 101 | + // Example 2 (rpm power domain controller and OPP table): | |
| 102 | + | |
| 103 | + rpmpd: power-controller { | |
| 104 | + compatible = "qcom,msm8996-rpmpd"; | |
| 105 | + #power-domain-cells = <1>; | |
| 106 | + operating-points-v2 = <&rpmpd_opp_table>; | |
| 107 | + | |
| 108 | + rpmpd_opp_table: opp-table { | |
| 109 | + compatible = "operating-points-v2"; | |
| 110 | + | |
| 111 | + rpmpd_opp_low: opp1 { | |
| 112 | + opp-level = <1>; | |
| 113 | + }; | |
| 114 | + | |
| 115 | + rpmpd_opp_ret: opp2 { | |
| 116 | + opp-level = <2>; | |
| 117 | + }; | |
| 118 | + | |
| 119 | + rpmpd_opp_svs: opp3 { | |
| 120 | + opp-level = <3>; | |
| 121 | + }; | |
| 122 | + | |
| 123 | + rpmpd_opp_normal: opp4 { | |
| 124 | + opp-level = <4>; | |
| 125 | + }; | |
| 126 | + | |
| 127 | + rpmpd_opp_high: opp5 { | |
| 128 | + opp-level = <5>; | |
| 129 | + }; | |
| 130 | + | |
| 131 | + rpmpd_opp_turbo: opp6 { | |
| 132 | + opp-level = <6>; | |
| 133 | + }; | |
| 134 | + }; | |
| 135 | + }; | |
| 136 | + | |
| 137 | + - | | |
| 138 | + | |
| 139 | + // Example 3 (Client/Consumer device using OPP table): | |
| 140 | + | |
| 141 | + leaky-device0@12350000 { | |
| 142 | + compatible = "foo,i-leak-current"; | |
| 143 | + reg = <0x12350000 0x1000>; | |
| 144 | + power-domains = <&rpmhpd 0>; | |
| 145 | + operating-points-v2 = <&leaky_opp_table>; | |
| 146 | + }; | |
| 147 | + | |
| 148 | + leaky_opp_table: opp-table { | |
| 149 | + compatible = "operating-points-v2"; | |
| 150 | + opp1 { | |
| 151 | + opp-hz = /bits/ 64 <144000>; | |
| 152 | + required-opps = <&rpmhpd_opp_low>; | |
| 153 | + }; | |
| 154 | + | |
| 155 | + opp2 { | |
| 156 | + opp-hz = /bits/ 64 <400000>; | |
| 157 | + required-opps = <&rpmhpd_opp_ret>; | |
| 158 | + }; | |
| 159 | + | |
| 160 | + opp3 { | |
| 161 | + opp-hz = /bits/ 64 <20000000>; | |
| 162 | + required-opps = <&rpmpd_opp_svs>; | |
| 163 | + }; | |
| 164 | + | |
| 165 | + opp4 { | |
| 166 | + opp-hz = /bits/ 64 <25000000>; | |
| 167 | + required-opps = <&rpmpd_opp_normal>; | |
| 168 | + }; | |
| 169 | + }; | |
| 170 | +... | |
| @@ -239,14 +239,6 @@ config QCOM_SCM · 238 unmodified lines | ||
| 239 | 239 | depends on ARM || ARM64 |
| 240 | 240 | select RESET_CONTROLLER |
| 241 | 241 | |
| 242 | −config QCOM_SCM_32 | |
| 243 | − def_bool y | |
| 244 | − depends on QCOM_SCM && ARM | |
| 245 | − | |
| 246 | −config QCOM_SCM_64 | |
| 247 | − def_bool y | |
| 248 | − depends on QCOM_SCM && ARM64 | |
| 249 | − | |
| 250 | 242 | config QCOM_SCM_DOWNLOAD_MODE_DEFAULT |
| 251 | 243 | bool "Qualcomm download mode enabled by default" |
| 252 | 244 | depends on QCOM_SCM |
| @@ -17,10 +17,7 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o · 16 unmodified lines | ||
| 17 | 17 | obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o |
| 18 | 18 | obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o |
| 19 | 19 | obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o |
| 20 | −obj-$(CONFIG_QCOM_SCM) += qcom_scm.o | |
| 21 | −obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o | |
| 22 | −obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o | |
| 23 | −CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a | |
| 20 | +obj-$(CONFIG_QCOM_SCM) += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o | |
| 24 | 21 | obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o |
| 25 | 22 | obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o |
| 26 | 23 | obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o |
| @@ -1,671 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. | |
| 3 | − * Copyright (C) 2015 Linaro Ltd. | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include <linux/slab.h> | |
| 7 | −#include <linux/io.h> | |
| 8 | −#include <linux/module.h> | |
| 9 | −#include <linux/mutex.h> | |
| 10 | −#include <linux/errno.h> | |
| 11 | −#include <linux/err.h> | |
| 12 | −#include <linux/qcom_scm.h> | |
| 13 | −#include <linux/dma-mapping.h> | |
| 14 | − | |
| 15 | −#include "qcom_scm.h" | |
| 16 | − | |
| 17 | −#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00 | |
| 18 | −#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 | |
| 19 | −#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 | |
| 20 | −#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 | |
| 21 | − | |
| 22 | −#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 | |
| 23 | −#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 | |
| 24 | −#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 | |
| 25 | −#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 | |
| 26 | − | |
| 27 | −struct qcom_scm_entry { | |
| 28 | − int flag; | |
| 29 | − void *entry; | |
| 30 | −}; | |
| 31 | − | |
| 32 | −static struct qcom_scm_entry qcom_scm_wb[] = { | |
| 33 | − { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 }, | |
| 34 | − { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 }, | |
| 35 | − { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 }, | |
| 36 | − { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 }, | |
| 37 | −}; | |
| 38 | − | |
| 39 | −static DEFINE_MUTEX(qcom_scm_lock); | |
| 40 | − | |
| 41 | −/** | |
| 42 | − * struct qcom_scm_command - one SCM command buffer | |
| 43 | − * @len: total available memory for command and response | |
| 44 | − * @buf_offset: start of command buffer | |
| 45 | − * @resp_hdr_offset: start of response buffer | |
| 46 | − * @id: command to be executed | |
| 47 | − * @buf: buffer returned from qcom_scm_get_command_buffer() | |
| 48 | − * | |
| 49 | − * An SCM command is laid out in memory as follows: | |
| 50 | − * | |
| 51 | − * ------------------- <--- struct qcom_scm_command | |
| 52 | − * | command header | | |
| 53 | − * ------------------- <--- qcom_scm_get_command_buffer() | |
| 54 | − * | command buffer | | |
| 55 | − * ------------------- <--- struct qcom_scm_response and | |
| 56 | − * | response header | qcom_scm_command_to_response() | |
| 57 | − * ------------------- <--- qcom_scm_get_response_buffer() | |
| 58 | − * | response buffer | | |
| 59 | − * ------------------- | |
| 60 | − * | |
| 61 | − * There can be arbitrary padding between the headers and buffers so | |
| 62 | − * you should always use the appropriate qcom_scm_get_*_buffer() routines | |
| 63 | − * to access the buffers in a safe manner. | |
| 64 | − */ | |
| 65 | −struct qcom_scm_command { | |
| 66 | − __le32 len; | |
| 67 | − __le32 buf_offset; | |
| 68 | − __le32 resp_hdr_offset; | |
| 69 | − __le32 id; | |
| 70 | − __le32 buf[0]; | |
| 71 | −}; | |
| 72 | − | |
| 73 | −/** | |
| 74 | − * struct qcom_scm_response - one SCM response buffer | |
| 75 | − * @len: total available memory for response | |
| 76 | − * @buf_offset: start of response data relative to start of qcom_scm_response | |
| 77 | − * @is_complete: indicates if the command has finished processing | |
| 78 | − */ | |
| 79 | −struct qcom_scm_response { | |
| 80 | − __le32 len; | |
| 81 | − __le32 buf_offset; | |
| 82 | − __le32 is_complete; | |
| 83 | −}; | |
| 84 | − | |
| 85 | −/** | |
| 86 | − * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response | |
| 87 | − * @cmd: command | |
| 88 | − * | |
| 89 | − * Returns a pointer to a response for a command. | |
| 90 | − */ | |
| 91 | −static inline struct qcom_scm_response *qcom_scm_command_to_response( | |
| 92 | − const struct qcom_scm_command *cmd) | |
| 93 | −{ | |
| 94 | − return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); | |
| 95 | −} | |
| 96 | − | |
| 97 | −/** | |
| 98 | − * qcom_scm_get_command_buffer() - Get a pointer to a command buffer | |
| 99 | − * @cmd: command | |
| 100 | − * | |
| 101 | − * Returns a pointer to the command buffer of a command. | |
| 102 | − */ | |
| 103 | −static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd) | |
| 104 | −{ | |
| 105 | − return (void *)cmd->buf; | |
| 106 | −} | |
| 107 | − | |
| 108 | −/** | |
| 109 | − * qcom_scm_get_response_buffer() - Get a pointer to a response buffer | |
| 110 | − * @rsp: response | |
| 111 | − * | |
| 112 | − * Returns a pointer to a response buffer of a response. | |
| 113 | − */ | |
| 114 | −static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp) | |
| 115 | −{ | |
| 116 | − return (void *)rsp + le32_to_cpu(rsp->buf_offset); | |
| 117 | −} | |
| 118 | − | |
| 119 | −static u32 smc(u32 cmd_addr) | |
| 120 | −{ | |
| 121 | − int context_id; | |
| 122 | − register u32 r0 asm("r0") = 1; | |
| 123 | − register u32 r1 asm("r1") = (u32)&context_id; | |
| 124 | − register u32 r2 asm("r2") = cmd_addr; | |
| 125 | − do { | |
| 126 | − asm volatile( | |
| 127 | − __asmeq("%0", "r0") | |
| 128 | − __asmeq("%1", "r0") | |
| 129 | − __asmeq("%2", "r1") | |
| 130 | − __asmeq("%3", "r2") | |
| 131 | −#ifdef REQUIRES_SEC | |
| 132 | − ".arch_extension sec\n" | |
| 133 | −#endif | |
| 134 | − "smc #0 @ switch to secure world\n" | |
| 135 | − : "=r" (r0) | |
| 136 | − : "r" (r0), "r" (r1), "r" (r2) | |
| 137 | − : "r3", "r12"); | |
| 138 | − } while (r0 == QCOM_SCM_INTERRUPTED); | |
| 139 | − | |
| 140 | − return r0; | |
| 141 | −} | |
| 142 | − | |
| 143 | −/** | |
| 144 | − * qcom_scm_call() - Send an SCM command | |
| 145 | − * @dev: struct device | |
| 146 | − * @svc_id: service identifier | |
| 147 | − * @cmd_id: command identifier | |
| 148 | − * @cmd_buf: command buffer | |
| 149 | − * @cmd_len: length of the command buffer | |
| 150 | − * @resp_buf: response buffer | |
| 151 | − * @resp_len: length of the response buffer | |
| 152 | − * | |
| 153 | − * Sends a command to the SCM and waits for the command to finish processing. | |
| 154 | − * | |
| 155 | − * A note on cache maintenance: | |
| 156 | − * Note that any buffers that are expected to be accessed by the secure world | |
| 157 | − * must be flushed before invoking qcom_scm_call and invalidated in the cache | |
| 158 | − * immediately after qcom_scm_call returns. Cache maintenance on the command | |
| 159 | − * and response buffers is taken care of by qcom_scm_call; however, callers are | |
| 160 | − * responsible for any other cached buffers passed over to the secure world. | |
| 161 | − */ | |
| 162 | −static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, | |
| 163 | − const void *cmd_buf, size_t cmd_len, void *resp_buf, | |
| 164 | − size_t resp_len) | |
| 165 | −{ | |
| 166 | − int ret; | |
| 167 | − struct qcom_scm_command *cmd; | |
| 168 | − struct qcom_scm_response *rsp; | |
| 169 | − size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len; | |
| 170 | − dma_addr_t cmd_phys; | |
| 171 | − | |
| 172 | − cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); | |
| 173 | − if (!cmd) | |
| 174 | − return -ENOMEM; | |
| 175 | − | |
| 176 | − cmd->len = cpu_to_le32(alloc_len); | |
| 177 | − cmd->buf_offset = cpu_to_le32(sizeof(*cmd)); | |
| 178 | − cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len); | |
| 179 | − | |
| 180 | − cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); | |
| 181 | − if (cmd_buf) | |
| 182 | − memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len); | |
| 183 | − | |
| 184 | − rsp = qcom_scm_command_to_response(cmd); | |
| 185 | − | |
| 186 | − cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE); | |
| 187 | − if (dma_mapping_error(dev, cmd_phys)) { | |
| 188 | − kfree(cmd); | |
| 189 | − return -ENOMEM; | |
| 190 | − } | |
| 191 | − | |
| 192 | − mutex_lock(&qcom_scm_lock); | |
| 193 | − ret = smc(cmd_phys); | |
| 194 | − if (ret < 0) | |
| 195 | − ret = qcom_scm_remap_error(ret); | |
| 196 | − mutex_unlock(&qcom_scm_lock); | |
| 197 | − if (ret) | |
| 198 | − goto out; | |
| 199 | − | |
| 200 | − do { | |
| 201 | − dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len, | |
| 202 | − sizeof(*rsp), DMA_FROM_DEVICE); | |
| 203 | − } while (!rsp->is_complete); | |
| 204 | − | |
| 205 | − if (resp_buf) { | |
| 206 | − dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len + | |
| 207 | − le32_to_cpu(rsp->buf_offset), | |
| 208 | − resp_len, DMA_FROM_DEVICE); | |
| 209 | − memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), | |
| 210 | − resp_len); | |
| 211 | − } | |
| 212 | −out: | |
| 213 | − dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE); | |
| 214 | − kfree(cmd); | |
| 215 | − return ret; | |
| 216 | −} | |
| 217 | − | |
| 218 | −#define SCM_CLASS_REGISTER (0x2 << 8) | |
| 219 | −#define SCM_MASK_IRQS BIT(5) | |
| 220 | −#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \ | |
| 221 | − SCM_CLASS_REGISTER | \ | |
| 222 | − SCM_MASK_IRQS | \ | |
| 223 | − (n & 0xf)) | |
| 224 | − | |
| 225 | −/** | |
| 226 | − * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument | |
| 227 | − * @svc_id: service identifier | |
| 228 | − * @cmd_id: command identifier | |
| 229 | − * @arg1: first argument | |
| 230 | − * | |
| 231 | − * This shall only be used with commands that are guaranteed to be | |
| 232 | − * uninterruptable, atomic and SMP safe. | |
| 233 | − */ | |
| 234 | −static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) | |
| 235 | −{ | |
| 236 | − int context_id; | |
| 237 | − | |
| 238 | − register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1); | |
| 239 | − register u32 r1 asm("r1") = (u32)&context_id; | |
| 240 | − register u32 r2 asm("r2") = arg1; | |
| 241 | − | |
| 242 | − asm volatile( | |
| 243 | − __asmeq("%0", "r0") | |
| 244 | − __asmeq("%1", "r0") | |
| 245 | − __asmeq("%2", "r1") | |
| 246 | − __asmeq("%3", "r2") | |
| 247 | −#ifdef REQUIRES_SEC | |
| 248 | − ".arch_extension sec\n" | |
| 249 | −#endif | |
| 250 | − "smc #0 @ switch to secure world\n" | |
| 251 | − : "=r" (r0) | |
| 252 | − : "r" (r0), "r" (r1), "r" (r2) | |
| 253 | − : "r3", "r12"); | |
| 254 | − return r0; | |
| 255 | −} | |
| 256 | − | |
| 257 | −/** | |
| 258 | − * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments | |
| 259 | − * @svc_id: service identifier | |
| 260 | − * @cmd_id: command identifier | |
| 261 | − * @arg1: first argument | |
| 262 | − * @arg2: second argument | |
| 263 | − * | |
| 264 | − * This shall only be used with commands that are guaranteed to be | |
| 265 | − * uninterruptable, atomic and SMP safe. | |
| 266 | − */ | |
| 267 | −static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2) | |
| 268 | −{ | |
| 269 | − int context_id; | |
| 270 | − | |
| 271 | − register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2); | |
| 272 | − register u32 r1 asm("r1") = (u32)&context_id; | |
| 273 | − register u32 r2 asm("r2") = arg1; | |
| 274 | − register u32 r3 asm("r3") = arg2; | |
| 275 | − | |
| 276 | − asm volatile( | |
| 277 | − __asmeq("%0", "r0") | |
| 278 | − __asmeq("%1", "r0") | |
| 279 | − __asmeq("%2", "r1") | |
| 280 | − __asmeq("%3", "r2") | |
| 281 | − __asmeq("%4", "r3") | |
| 282 | −#ifdef REQUIRES_SEC | |
| 283 | − ".arch_extension sec\n" | |
| 284 | −#endif | |
| 285 | − "smc #0 @ switch to secure world\n" | |
| 286 | − : "=r" (r0) | |
| 287 | − : "r" (r0), "r" (r1), "r" (r2), "r" (r3) | |
| 288 | − : "r12"); | |
| 289 | − return r0; | |
| 290 | −} | |
| 291 | − | |
| 292 | −u32 qcom_scm_get_version(void) | |
| 293 | −{ | |
| 294 | − int context_id; | |
| 295 | − static u32 version = -1; | |
| 296 | − register u32 r0 asm("r0"); | |
| 297 | − register u32 r1 asm("r1"); | |
| 298 | − | |
| 299 | − if (version != -1) | |
| 300 | − return version; | |
| 301 | − | |
| 302 | − mutex_lock(&qcom_scm_lock); | |
| 303 | − | |
| 304 | − r0 = 0x1 << 8; | |
| 305 | − r1 = (u32)&context_id; | |
| 306 | − do { | |
| 307 | − asm volatile( | |
| 308 | − __asmeq("%0", "r0") | |
| 309 | − __asmeq("%1", "r1") | |
| 310 | − __asmeq("%2", "r0") | |
| 311 | − __asmeq("%3", "r1") | |
| 312 | −#ifdef REQUIRES_SEC | |
| 313 | − ".arch_extension sec\n" | |
| 314 | −#endif | |
| 315 | − "smc #0 @ switch to secure world\n" | |
| 316 | − : "=r" (r0), "=r" (r1) | |
| 317 | − : "r" (r0), "r" (r1) | |
| 318 | − : "r2", "r3", "r12"); | |
| 319 | − } while (r0 == QCOM_SCM_INTERRUPTED); | |
| 320 | − | |
| 321 | − version = r1; | |
| 322 | − mutex_unlock(&qcom_scm_lock); | |
| 323 | − | |
| 324 | − return version; | |
| 325 | −} | |
| 326 | −EXPORT_SYMBOL(qcom_scm_get_version); | |
| 327 | − | |
| 328 | −/** | |
| 329 | − * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus | |
| 330 | − * @entry: Entry point function for the cpus | |
| 331 | − * @cpus: The cpumask of cpus that will use the entry point | |
| 332 | − * | |
| 333 | − * Set the cold boot address of the cpus. Any cpu outside the supported | |
| 334 | − * range would be removed from the cpu present mask. | |
| 335 | − */ | |
| 336 | −int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |
| 337 | −{ | |
| 338 | − int flags = 0; | |
| 339 | − int cpu; | |
| 340 | − int scm_cb_flags[] = { | |
| 341 | − QCOM_SCM_FLAG_COLDBOOT_CPU0, | |
| 342 | − QCOM_SCM_FLAG_COLDBOOT_CPU1, | |
| 343 | − QCOM_SCM_FLAG_COLDBOOT_CPU2, | |
| 344 | − QCOM_SCM_FLAG_COLDBOOT_CPU3, | |
| 345 | − }; | |
| 346 | − | |
| 347 | − if (!cpus || (cpus && cpumask_empty(cpus))) | |
| 348 | − return -EINVAL; | |
| 349 | − | |
| 350 | − for_each_cpu(cpu, cpus) { | |
| 351 | − if (cpu < ARRAY_SIZE(scm_cb_flags)) | |
| 352 | − flags |= scm_cb_flags[cpu]; | |
| 353 | − else | |
| 354 | − set_cpu_present(cpu, false); | |
| 355 | − } | |
| 356 | − | |
| 357 | − return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, | |
| 358 | − flags, virt_to_phys(entry)); | |
| 359 | −} | |
| 360 | − | |
| 361 | −/** | |
| 362 | − * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus | |
| 363 | − * @entry: Entry point function for the cpus | |
| 364 | − * @cpus: The cpumask of cpus that will use the entry point | |
| 365 | − * | |
| 366 | − * Set the Linux entry point for the SCM to transfer control to when coming | |
| 367 | − * out of a power down. CPU power down may be executed on cpuidle or hotplug. | |
| 368 | − */ | |
| 369 | −int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, | |
| 370 | − const cpumask_t *cpus) | |
| 371 | −{ | |
| 372 | − int ret; | |
| 373 | − int flags = 0; | |
| 374 | − int cpu; | |
| 375 | − struct { | |
| 376 | − __le32 flags; | |
| 377 | − __le32 addr; | |
| 378 | − } cmd; | |
| 379 | − | |
| 380 | − /* | |
| 381 | − * Reassign only if we are switching from hotplug entry point | |
| 382 | − * to cpuidle entry point or vice versa. | |
| 383 | − */ | |
| 384 | − for_each_cpu(cpu, cpus) { | |
| 385 | − if (entry == qcom_scm_wb[cpu].entry) | |
| 386 | − continue; | |
| 387 | − flags |= qcom_scm_wb[cpu].flag; | |
| 388 | − } | |
| 389 | − | |
| 390 | − /* No change in entry function */ | |
| 391 | − if (!flags) | |
| 392 | − return 0; | |
| 393 | − | |
| 394 | − cmd.addr = cpu_to_le32(virt_to_phys(entry)); | |
| 395 | − cmd.flags = cpu_to_le32(flags); | |
| 396 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, | |
| 397 | − &cmd, sizeof(cmd), NULL, 0); | |
| 398 | − if (!ret) { | |
| 399 | − for_each_cpu(cpu, cpus) | |
| 400 | − qcom_scm_wb[cpu].entry = entry; | |
| 401 | − } | |
| 402 | − | |
| 403 | − return ret; | |
| 404 | −} | |
| 405 | − | |
| 406 | −/** | |
| 407 | − * qcom_scm_cpu_power_down() - Power down the cpu | |
| 408 | − * @flags - Flags to flush cache | |
| 409 | − * | |
| 410 | − * This is an end point to power down cpu. If there was a pending interrupt, | |
| 411 | − * the control would return from this function, otherwise, the cpu jumps to the | |
| 412 | − * warm boot entry point set for this cpu upon reset. | |
| 413 | − */ | |
| 414 | −void __qcom_scm_cpu_power_down(u32 flags) | |
| 415 | −{ | |
| 416 | − qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC, | |
| 417 | − flags & QCOM_SCM_FLUSH_FLAG_MASK); | |
| 418 | −} | |
| 419 | − | |
| 420 | −int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) | |
| 421 | −{ | |
| 422 | − int ret; | |
| 423 | − __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id); | |
| 424 | − __le32 ret_val = 0; | |
| 425 | − | |
| 426 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, | |
| 427 | − &svc_cmd, sizeof(svc_cmd), &ret_val, | |
| 428 | − sizeof(ret_val)); | |
| 429 | − if (ret) | |
| 430 | − return ret; | |
| 431 | − | |
| 432 | − return le32_to_cpu(ret_val); | |
| 433 | −} | |
| 434 | − | |
| 435 | −int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, | |
| 436 | − u32 req_cnt, u32 *resp) | |
| 437 | −{ | |
| 438 | − if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT) | |
| 439 | − return -ERANGE; | |
| 440 | − | |
| 441 | − return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, | |
| 442 | − req, req_cnt * sizeof(*req), resp, sizeof(*resp)); | |
| 443 | −} | |
| 444 | − | |
| 445 | −int __qcom_scm_ocmem_lock(struct device *dev, u32 id, u32 offset, u32 size, | |
| 446 | − u32 mode) | |
| 447 | −{ | |
| 448 | − struct ocmem_tz_lock { | |
| 449 | − __le32 id; | |
| 450 | − __le32 offset; | |
| 451 | − __le32 size; | |
| 452 | − __le32 mode; | |
| 453 | − } request; | |
| 454 | − | |
| 455 | − request.id = cpu_to_le32(id); | |
| 456 | − request.offset = cpu_to_le32(offset); | |
| 457 | − request.size = cpu_to_le32(size); | |
| 458 | − request.mode = cpu_to_le32(mode); | |
| 459 | − | |
| 460 | − return qcom_scm_call(dev, QCOM_SCM_OCMEM_SVC, QCOM_SCM_OCMEM_LOCK_CMD, | |
| 461 | − &request, sizeof(request), NULL, 0); | |
| 462 | −} | |
| 463 | − | |
| 464 | −int __qcom_scm_ocmem_unlock(struct device *dev, u32 id, u32 offset, u32 size) | |
| 465 | −{ | |
| 466 | − struct ocmem_tz_unlock { | |
| 467 | − __le32 id; | |
| 468 | − __le32 offset; | |
| 469 | − __le32 size; | |
| 470 | − } request; | |
| 471 | − | |
| 472 | − request.id = cpu_to_le32(id); | |
| 473 | − request.offset = cpu_to_le32(offset); | |
| 474 | − request.size = cpu_to_le32(size); | |
| 475 | − | |
| 476 | − return qcom_scm_call(dev, QCOM_SCM_OCMEM_SVC, QCOM_SCM_OCMEM_UNLOCK_CMD, | |
| 477 | − &request, sizeof(request), NULL, 0); | |
| 478 | −} | |
| 479 | − | |
| 480 | −void __qcom_scm_init(void) | |
| 481 | −{ | |
| 482 | −} | |
| 483 | − | |
| 484 | −bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) | |
| 485 | −{ | |
| 486 | − __le32 out; | |
| 487 | − __le32 in; | |
| 488 | − int ret; | |
| 489 | − | |
| 490 | − in = cpu_to_le32(peripheral); | |
| 491 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 492 | − QCOM_SCM_PAS_IS_SUPPORTED_CMD, | |
| 493 | − &in, sizeof(in), | |
| 494 | − &out, sizeof(out)); | |
| 495 | − | |
| 496 | − return ret ? false : !!out; | |
| 497 | −} | |
| 498 | − | |
| 499 | −int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, | |
| 500 | − dma_addr_t metadata_phys) | |
| 501 | −{ | |
| 502 | − __le32 scm_ret; | |
| 503 | − int ret; | |
| 504 | − struct { | |
| 505 | − __le32 proc; | |
| 506 | − __le32 image_addr; | |
| 507 | − } request; | |
| 508 | − | |
| 509 | − request.proc = cpu_to_le32(peripheral); | |
| 510 | − request.image_addr = cpu_to_le32(metadata_phys); | |
| 511 | − | |
| 512 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 513 | − QCOM_SCM_PAS_INIT_IMAGE_CMD, | |
| 514 | − &request, sizeof(request), | |
| 515 | − &scm_ret, sizeof(scm_ret)); | |
| 516 | − | |
| 517 | − return ret ? : le32_to_cpu(scm_ret); | |
| 518 | −} | |
| 519 | − | |
| 520 | −int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, | |
| 521 | − phys_addr_t addr, phys_addr_t size) | |
| 522 | −{ | |
| 523 | − __le32 scm_ret; | |
| 524 | − int ret; | |
| 525 | − struct { | |
| 526 | − __le32 proc; | |
| 527 | − __le32 addr; | |
| 528 | − __le32 len; | |
| 529 | − } request; | |
| 530 | − | |
| 531 | − request.proc = cpu_to_le32(peripheral); | |
| 532 | − request.addr = cpu_to_le32(addr); | |
| 533 | − request.len = cpu_to_le32(size); | |
| 534 | − | |
| 535 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 536 | − QCOM_SCM_PAS_MEM_SETUP_CMD, | |
| 537 | − &request, sizeof(request), | |
| 538 | − &scm_ret, sizeof(scm_ret)); | |
| 539 | − | |
| 540 | − return ret ? : le32_to_cpu(scm_ret); | |
| 541 | −} | |
| 542 | − | |
| 543 | −int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral) | |
| 544 | −{ | |
| 545 | − __le32 out; | |
| 546 | − __le32 in; | |
| 547 | − int ret; | |
| 548 | − | |
| 549 | − in = cpu_to_le32(peripheral); | |
| 550 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 551 | − QCOM_SCM_PAS_AUTH_AND_RESET_CMD, | |
| 552 | − &in, sizeof(in), | |
| 553 | − &out, sizeof(out)); | |
| 554 | − | |
| 555 | − return ret ? : le32_to_cpu(out); | |
| 556 | −} | |
| 557 | − | |
| 558 | −int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral) | |
| 559 | −{ | |
| 560 | − __le32 out; | |
| 561 | − __le32 in; | |
| 562 | − int ret; | |
| 563 | − | |
| 564 | − in = cpu_to_le32(peripheral); | |
| 565 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 566 | − QCOM_SCM_PAS_SHUTDOWN_CMD, | |
| 567 | − &in, sizeof(in), | |
| 568 | − &out, sizeof(out)); | |
| 569 | − | |
| 570 | − return ret ? : le32_to_cpu(out); | |
| 571 | −} | |
| 572 | − | |
| 573 | −int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) | |
| 574 | −{ | |
| 575 | − __le32 out; | |
| 576 | − __le32 in = cpu_to_le32(reset); | |
| 577 | − int ret; | |
| 578 | − | |
| 579 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, | |
| 580 | − &in, sizeof(in), | |
| 581 | − &out, sizeof(out)); | |
| 582 | − | |
| 583 | − return ret ? : le32_to_cpu(out); | |
| 584 | −} | |
| 585 | − | |
| 586 | −int __qcom_scm_set_dload_mode(struct device *dev, bool enable) | |
| 587 | −{ | |
| 588 | − return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE, | |
| 589 | − enable ? QCOM_SCM_SET_DLOAD_MODE : 0, 0); | |
| 590 | −} | |
| 591 | − | |
| 592 | −int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) | |
| 593 | −{ | |
| 594 | − struct { | |
| 595 | − __le32 state; | |
| 596 | − __le32 id; | |
| 597 | − } req; | |
| 598 | − __le32 scm_ret = 0; | |
| 599 | − int ret; | |
| 600 | − | |
| 601 | − req.state = cpu_to_le32(state); | |
| 602 | − req.id = cpu_to_le32(id); | |
| 603 | − | |
| 604 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE, | |
| 605 | − &req, sizeof(req), &scm_ret, sizeof(scm_ret)); | |
| 606 | − | |
| 607 | − return ret ? : le32_to_cpu(scm_ret); | |
| 608 | −} | |
| 609 | − | |
| 610 | −int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, | |
| 611 | − size_t mem_sz, phys_addr_t src, size_t src_sz, | |
| 612 | − phys_addr_t dest, size_t dest_sz) | |
| 613 | −{ | |
| 614 | − return -ENODEV; | |
| 615 | −} | |
| 616 | − | |
| 617 | −int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, | |
| 618 | − u32 spare) | |
| 619 | −{ | |
| 620 | − struct msm_scm_sec_cfg { | |
| 621 | − __le32 id; | |
| 622 | − __le32 ctx_bank_num; | |
| 623 | − } cfg; | |
| 624 | − int ret, scm_ret = 0; | |
| 625 | − | |
| 626 | − cfg.id = cpu_to_le32(device_id); | |
| 627 | − cfg.ctx_bank_num = cpu_to_le32(spare); | |
| 628 | − | |
| 629 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG, | |
| 630 | − &cfg, sizeof(cfg), &scm_ret, sizeof(scm_ret)); | |
| 631 | − | |
| 632 | − if (ret || scm_ret) | |
| 633 | − return ret ? ret : -EINVAL; | |
| 634 | − | |
| 635 | − return 0; | |
| 636 | −} | |
| 637 | − | |
| 638 | −int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, | |
| 639 | − size_t *size) | |
| 640 | −{ | |
| 641 | − return -ENODEV; | |
| 642 | −} | |
| 643 | − | |
| 644 | −int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, | |
| 645 | − u32 spare) | |
| 646 | −{ | |
| 647 | − return -ENODEV; | |
| 648 | −} | |
| 649 | − | |
| 650 | −int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, | |
| 651 | − unsigned int *val) | |
| 652 | −{ | |
| 653 | − int ret; | |
| 654 | − | |
| 655 | − ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr); | |
| 656 | − if (ret >= 0) | |
| 657 | − *val = ret; | |
| 658 | − | |
| 659 | − return ret < 0 ? ret : 0; | |
| 660 | −} | |
| 661 | − | |
| 662 | −int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) | |
| 663 | −{ | |
| 664 | − return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE, | |
| 665 | − addr, val); | |
| 666 | −} | |
| 667 | − | |
| 668 | −int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable) | |
| 669 | −{ | |
| 670 | − return -ENODEV; | |
| 671 | −} | |
| @@ -1,579 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* Copyright (c) 2015, The Linux Foundation. All rights reserved. | |
| 3 | − */ | |
| 4 | − | |
| 5 | −#include <linux/io.h> | |
| 6 | −#include <linux/errno.h> | |
| 7 | −#include <linux/delay.h> | |
| 8 | −#include <linux/mutex.h> | |
| 9 | −#include <linux/slab.h> | |
| 10 | −#include <linux/types.h> | |
| 11 | −#include <linux/qcom_scm.h> | |
| 12 | −#include <linux/arm-smccc.h> | |
| 13 | −#include <linux/dma-mapping.h> | |
| 14 | − | |
| 15 | −#include "qcom_scm.h" | |
| 16 | − | |
| 17 | −#define QCOM_SCM_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) | |
| 18 | − | |
| 19 | −#define MAX_QCOM_SCM_ARGS 10 | |
| 20 | −#define MAX_QCOM_SCM_RETS 3 | |
| 21 | − | |
| 22 | −enum qcom_scm_arg_types { | |
| 23 | − QCOM_SCM_VAL, | |
| 24 | − QCOM_SCM_RO, | |
| 25 | − QCOM_SCM_RW, | |
| 26 | − QCOM_SCM_BUFVAL, | |
| 27 | −}; | |
| 28 | − | |
| 29 | −#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\ | |
| 30 | − (((a) & 0x3) << 4) | \ | |
| 31 | − (((b) & 0x3) << 6) | \ | |
| 32 | − (((c) & 0x3) << 8) | \ | |
| 33 | − (((d) & 0x3) << 10) | \ | |
| 34 | − (((e) & 0x3) << 12) | \ | |
| 35 | − (((f) & 0x3) << 14) | \ | |
| 36 | − (((g) & 0x3) << 16) | \ | |
| 37 | − (((h) & 0x3) << 18) | \ | |
| 38 | − (((i) & 0x3) << 20) | \ | |
| 39 | − (((j) & 0x3) << 22) | \ | |
| 40 | − ((num) & 0xf)) | |
| 41 | − | |
| 42 | −#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
| 43 | − | |
| 44 | −/** | |
| 45 | − * struct qcom_scm_desc | |
| 46 | − * @arginfo: Metadata describing the arguments in args[] | |
| 47 | − * @args: The array of arguments for the secure syscall | |
| 48 | − * @res: The values returned by the secure syscall | |
| 49 | − */ | |
| 50 | −struct qcom_scm_desc { | |
| 51 | − u32 arginfo; | |
| 52 | − u64 args[MAX_QCOM_SCM_ARGS]; | |
| 53 | −}; | |
| 54 | − | |
| 55 | −static u64 qcom_smccc_convention = -1; | |
| 56 | −static DEFINE_MUTEX(qcom_scm_lock); | |
| 57 | − | |
| 58 | −#define QCOM_SCM_EBUSY_WAIT_MS 30 | |
| 59 | −#define QCOM_SCM_EBUSY_MAX_RETRY 20 | |
| 60 | − | |
| 61 | −#define N_EXT_QCOM_SCM_ARGS 7 | |
| 62 | −#define FIRST_EXT_ARG_IDX 3 | |
| 63 | −#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1) | |
| 64 | − | |
| 65 | −static void __qcom_scm_call_do(const struct qcom_scm_desc *desc, | |
| 66 | − struct arm_smccc_res *res, u32 fn_id, | |
| 67 | − u64 x5, u32 type) | |
| 68 | −{ | |
| 69 | − u64 cmd; | |
| 70 | − struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 }; | |
| 71 | − | |
| 72 | − cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention, | |
| 73 | − ARM_SMCCC_OWNER_SIP, fn_id); | |
| 74 | − | |
| 75 | − quirk.state.a6 = 0; | |
| 76 | − | |
| 77 | − do { | |
| 78 | − arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0], | |
| 79 | − desc->args[1], desc->args[2], x5, | |
| 80 | − quirk.state.a6, 0, res, &quirk); | |
| 81 | − | |
| 82 | − if (res->a0 == QCOM_SCM_INTERRUPTED) | |
| 83 | − cmd = res->a0; | |
| 84 | − | |
| 85 | − } while (res->a0 == QCOM_SCM_INTERRUPTED); | |
| 86 | −} | |
| 87 | − | |
| 88 | −static void qcom_scm_call_do(const struct qcom_scm_desc *desc, | |
| 89 | − struct arm_smccc_res *res, u32 fn_id, | |
| 90 | − u64 x5, bool atomic) | |
| 91 | −{ | |
| 92 | − int retry_count = 0; | |
| 93 | − | |
| 94 | − if (atomic) { | |
| 95 | − __qcom_scm_call_do(desc, res, fn_id, x5, ARM_SMCCC_FAST_CALL); | |
| 96 | − return; | |
| 97 | − } | |
| 98 | − | |
| 99 | − do { | |
| 100 | − mutex_lock(&qcom_scm_lock); | |
| 101 | − | |
| 102 | − __qcom_scm_call_do(desc, res, fn_id, x5, | |
| 103 | − ARM_SMCCC_STD_CALL); | |
| 104 | − | |
| 105 | − mutex_unlock(&qcom_scm_lock); | |
| 106 | − | |
| 107 | − if (res->a0 == QCOM_SCM_V2_EBUSY) { | |
| 108 | − if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) | |
| 109 | − break; | |
| 110 | − msleep(QCOM_SCM_EBUSY_WAIT_MS); | |
| 111 | − } | |
| 112 | − } while (res->a0 == QCOM_SCM_V2_EBUSY); | |
| 113 | −} | |
| 114 | − | |
| 115 | −static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, | |
| 116 | − const struct qcom_scm_desc *desc, | |
| 117 | − struct arm_smccc_res *res, bool atomic) | |
| 118 | −{ | |
| 119 | − int arglen = desc->arginfo & 0xf; | |
| 120 | − int i; | |
| 121 | − u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id); | |
| 122 | − u64 x5 = desc->args[FIRST_EXT_ARG_IDX]; | |
| 123 | − dma_addr_t args_phys = 0; | |
| 124 | − void *args_virt = NULL; | |
| 125 | − size_t alloc_len; | |
| 126 | − gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL; | |
| 127 | − | |
| 128 | − if (unlikely(arglen > N_REGISTER_ARGS)) { | |
| 129 | − alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64); | |
| 130 | − args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag); | |
| 131 | − | |
| 132 | − if (!args_virt) | |
| 133 | − return -ENOMEM; | |
| 134 | − | |
| 135 | − if (qcom_smccc_convention == ARM_SMCCC_SMC_32) { | |
| 136 | − __le32 *args = args_virt; | |
| 137 | − | |
| 138 | − for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++) | |
| 139 | − args[i] = cpu_to_le32(desc->args[i + | |
| 140 | − FIRST_EXT_ARG_IDX]); | |
| 141 | − } else { | |
| 142 | − __le64 *args = args_virt; | |
| 143 | − | |
| 144 | − for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++) | |
| 145 | − args[i] = cpu_to_le64(desc->args[i + | |
| 146 | − FIRST_EXT_ARG_IDX]); | |
| 147 | − } | |
| 148 | − | |
| 149 | − args_phys = dma_map_single(dev, args_virt, alloc_len, | |
| 150 | − DMA_TO_DEVICE); | |
| 151 | − | |
| 152 | − if (dma_mapping_error(dev, args_phys)) { | |
| 153 | − kfree(args_virt); | |
| 154 | − return -ENOMEM; | |
| 155 | − } | |
| 156 | − | |
| 157 | − x5 = args_phys; | |
| 158 | − } | |
| 159 | − | |
| 160 | − qcom_scm_call_do(desc, res, fn_id, x5, atomic); | |
| 161 | − | |
| 162 | − if (args_virt) { | |
| 163 | − dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE); | |
| 164 | − kfree(args_virt); | |
| 165 | − } | |
| 166 | − | |
| 167 | − if ((long)res->a0 < 0) | |
| 168 | − return qcom_scm_remap_error(res->a0); | |
| 169 | − | |
| 170 | − return 0; | |
| 171 | −} | |
| 172 | − | |
| 173 | −/** | |
| 174 | − * qcom_scm_call() - Invoke a syscall in the secure world | |
| 175 | − * @dev: device | |
| 176 | − * @svc_id: service identifier | |
| 177 | − * @cmd_id: command identifier | |
| 178 | − * @desc: Descriptor structure containing arguments and return values | |
| 179 | − * | |
| 180 | − * Sends a command to the SCM and waits for the command to finish processing. | |
| 181 | − * This should *only* be called in pre-emptible context. | |
| 182 | − */ | |
| 183 | −static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, | |
| 184 | − const struct qcom_scm_desc *desc, | |
| 185 | − struct arm_smccc_res *res) | |
| 186 | −{ | |
| 187 | − might_sleep(); | |
| 188 | − return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, false); | |
| 189 | −} | |
| 190 | − | |
| 191 | −/** | |
| 192 | − * qcom_scm_call_atomic() - atomic variation of qcom_scm_call() | |
| 193 | − * @dev: device | |
| 194 | − * @svc_id: service identifier | |
| 195 | − * @cmd_id: command identifier | |
| 196 | − * @desc: Descriptor structure containing arguments and return values | |
| 197 | − * @res: Structure containing results from SMC/HVC call | |
| 198 | − * | |
| 199 | − * Sends a command to the SCM and waits for the command to finish processing. | |
| 200 | − * This can be called in atomic context. | |
| 201 | − */ | |
| 202 | −static int qcom_scm_call_atomic(struct device *dev, u32 svc_id, u32 cmd_id, | |
| 203 | − const struct qcom_scm_desc *desc, | |
| 204 | − struct arm_smccc_res *res) | |
| 205 | −{ | |
| 206 | − return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, true); | |
| 207 | −} | |
| 208 | − | |
| 209 | −/** | |
| 210 | − * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus | |
| 211 | − * @entry: Entry point function for the cpus | |
| 212 | − * @cpus: The cpumask of cpus that will use the entry point | |
| 213 | − * | |
| 214 | − * Set the cold boot address of the cpus. Any cpu outside the supported | |
| 215 | − * range would be removed from the cpu present mask. | |
| 216 | − */ | |
| 217 | −int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |
| 218 | −{ | |
| 219 | − return -ENOTSUPP; | |
| 220 | −} | |
| 221 | − | |
| 222 | −/** | |
| 223 | − * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus | |
| 224 | − * @dev: Device pointer | |
| 225 | − * @entry: Entry point function for the cpus | |
| 226 | − * @cpus: The cpumask of cpus that will use the entry point | |
| 227 | − * | |
| 228 | − * Set the Linux entry point for the SCM to transfer control to when coming | |
| 229 | − * out of a power down. CPU power down may be executed on cpuidle or hotplug. | |
| 230 | − */ | |
| 231 | −int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, | |
| 232 | − const cpumask_t *cpus) | |
| 233 | −{ | |
| 234 | − return -ENOTSUPP; | |
| 235 | −} | |
| 236 | − | |
| 237 | −/** | |
| 238 | − * qcom_scm_cpu_power_down() - Power down the cpu | |
| 239 | − * @flags - Flags to flush cache | |
| 240 | − * | |
| 241 | − * This is an end point to power down cpu. If there was a pending interrupt, | |
| 242 | − * the control would return from this function, otherwise, the cpu jumps to the | |
| 243 | − * warm boot entry point set for this cpu upon reset. | |
| 244 | − */ | |
| 245 | −void __qcom_scm_cpu_power_down(u32 flags) | |
| 246 | −{ | |
| 247 | −} | |
| 248 | − | |
| 249 | −int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) | |
| 250 | −{ | |
| 251 | − int ret; | |
| 252 | − struct qcom_scm_desc desc = {0}; | |
| 253 | − struct arm_smccc_res res; | |
| 254 | − | |
| 255 | − desc.arginfo = QCOM_SCM_ARGS(1); | |
| 256 | − desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) | | |
| 257 | − (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT); | |
| 258 | − | |
| 259 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, | |
| 260 | − &desc, &res); | |
| 261 | − | |
| 262 | − return ret ? : res.a1; | |
| 263 | −} | |
| 264 | − | |
| 265 | −int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, | |
| 266 | − u32 req_cnt, u32 *resp) | |
| 267 | −{ | |
| 268 | − int ret; | |
| 269 | − struct qcom_scm_desc desc = {0}; | |
| 270 | − struct arm_smccc_res res; | |
| 271 | − | |
| 272 | − if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT) | |
| 273 | − return -ERANGE; | |
| 274 | − | |
| 275 | − desc.args[0] = req[0].addr; | |
| 276 | − desc.args[1] = req[0].val; | |
| 277 | − desc.args[2] = req[1].addr; | |
| 278 | − desc.args[3] = req[1].val; | |
| 279 | − desc.args[4] = req[2].addr; | |
| 280 | − desc.args[5] = req[2].val; | |
| 281 | − desc.args[6] = req[3].addr; | |
| 282 | − desc.args[7] = req[3].val; | |
| 283 | − desc.args[8] = req[4].addr; | |
| 284 | − desc.args[9] = req[4].val; | |
| 285 | − desc.arginfo = QCOM_SCM_ARGS(10); | |
| 286 | − | |
| 287 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc, | |
| 288 | − &res); | |
| 289 | − *resp = res.a1; | |
| 290 | − | |
| 291 | − return ret; | |
| 292 | −} | |
| 293 | − | |
| 294 | −int __qcom_scm_ocmem_lock(struct device *dev, uint32_t id, uint32_t offset, | |
| 295 | − uint32_t size, uint32_t mode) | |
| 296 | −{ | |
| 297 | − return -ENOTSUPP; | |
| 298 | −} | |
| 299 | − | |
| 300 | −int __qcom_scm_ocmem_unlock(struct device *dev, uint32_t id, uint32_t offset, | |
| 301 | − uint32_t size) | |
| 302 | −{ | |
| 303 | − return -ENOTSUPP; | |
| 304 | −} | |
| 305 | − | |
| 306 | −void __qcom_scm_init(void) | |
| 307 | −{ | |
| 308 | − u64 cmd; | |
| 309 | − struct arm_smccc_res res; | |
| 310 | − u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD); | |
| 311 | − | |
| 312 | − /* First try a SMC64 call */ | |
| 313 | − cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, | |
| 314 | − ARM_SMCCC_OWNER_SIP, function); | |
| 315 | − | |
| 316 | − arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)), | |
| 317 | − 0, 0, 0, 0, 0, &res); | |
| 318 | − | |
| 319 | − if (!res.a0 && res.a1) | |
| 320 | − qcom_smccc_convention = ARM_SMCCC_SMC_64; | |
| 321 | − else | |
| 322 | − qcom_smccc_convention = ARM_SMCCC_SMC_32; | |
| 323 | −} | |
| 324 | − | |
| 325 | −bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) | |
| 326 | −{ | |
| 327 | − int ret; | |
| 328 | − struct qcom_scm_desc desc = {0}; | |
| 329 | − struct arm_smccc_res res; | |
| 330 | − | |
| 331 | − desc.args[0] = peripheral; | |
| 332 | − desc.arginfo = QCOM_SCM_ARGS(1); | |
| 333 | − | |
| 334 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 335 | − QCOM_SCM_PAS_IS_SUPPORTED_CMD, | |
| 336 | − &desc, &res); | |
| 337 | − | |
| 338 | − return ret ? false : !!res.a1; | |
| 339 | −} | |
| 340 | − | |
| 341 | −int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, | |
| 342 | − dma_addr_t metadata_phys) | |
| 343 | −{ | |
| 344 | − int ret; | |
| 345 | − struct qcom_scm_desc desc = {0}; | |
| 346 | − struct arm_smccc_res res; | |
| 347 | − | |
| 348 | − desc.args[0] = peripheral; | |
| 349 | − desc.args[1] = metadata_phys; | |
| 350 | − desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW); | |
| 351 | − | |
| 352 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD, | |
| 353 | − &desc, &res); | |
| 354 | − | |
| 355 | − return ret ? : res.a1; | |
| 356 | −} | |
| 357 | − | |
| 358 | −int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, | |
| 359 | − phys_addr_t addr, phys_addr_t size) | |
| 360 | −{ | |
| 361 | − int ret; | |
| 362 | − struct qcom_scm_desc desc = {0}; | |
| 363 | − struct arm_smccc_res res; | |
| 364 | − | |
| 365 | − desc.args[0] = peripheral; | |
| 366 | − desc.args[1] = addr; | |
| 367 | − desc.args[2] = size; | |
| 368 | − desc.arginfo = QCOM_SCM_ARGS(3); | |
| 369 | − | |
| 370 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD, | |
| 371 | − &desc, &res); | |
| 372 | − | |
| 373 | − return ret ? : res.a1; | |
| 374 | −} | |
| 375 | − | |
| 376 | −int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral) | |
| 377 | −{ | |
| 378 | − int ret; | |
| 379 | − struct qcom_scm_desc desc = {0}; | |
| 380 | − struct arm_smccc_res res; | |
| 381 | − | |
| 382 | − desc.args[0] = peripheral; | |
| 383 | − desc.arginfo = QCOM_SCM_ARGS(1); | |
| 384 | − | |
| 385 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, | |
| 386 | − QCOM_SCM_PAS_AUTH_AND_RESET_CMD, | |
| 387 | − &desc, &res); | |
| 388 | − | |
| 389 | − return ret ? : res.a1; | |
| 390 | −} | |
| 391 | − | |
| 392 | −int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral) | |
| 393 | −{ | |
| 394 | − int ret; | |
| 395 | − struct qcom_scm_desc desc = {0}; | |
| 396 | − struct arm_smccc_res res; | |
| 397 | − | |
| 398 | − desc.args[0] = peripheral; | |
| 399 | − desc.arginfo = QCOM_SCM_ARGS(1); | |
| 400 | − | |
| 401 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD, | |
| 402 | − &desc, &res); | |
| 403 | − | |
| 404 | − return ret ? : res.a1; | |
| 405 | −} | |
| 406 | − | |
| 407 | −int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) | |
| 408 | −{ | |
| 409 | − struct qcom_scm_desc desc = {0}; | |
| 410 | − struct arm_smccc_res res; | |
| 411 | − int ret; | |
| 412 | − | |
| 413 | − desc.args[0] = reset; | |
| 414 | − desc.args[1] = 0; | |
| 415 | − desc.arginfo = QCOM_SCM_ARGS(2); | |
| 416 | − | |
| 417 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc, | |
| 418 | − &res); | |
| 419 | − | |
| 420 | − return ret ? : res.a1; | |
| 421 | −} | |
| 422 | − | |
| 423 | −int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) | |
| 424 | −{ | |
| 425 | − struct qcom_scm_desc desc = {0}; | |
| 426 | − struct arm_smccc_res res; | |
| 427 | − int ret; | |
| 428 | − | |
| 429 | − desc.args[0] = state; | |
| 430 | − desc.args[1] = id; | |
| 431 | − desc.arginfo = QCOM_SCM_ARGS(2); | |
| 432 | − | |
| 433 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE, | |
| 434 | − &desc, &res); | |
| 435 | − | |
| 436 | − return ret ? : res.a1; | |
| 437 | −} | |
| 438 | − | |
| 439 | −int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, | |
| 440 | − size_t mem_sz, phys_addr_t src, size_t src_sz, | |
| 441 | − phys_addr_t dest, size_t dest_sz) | |
| 442 | −{ | |
| 443 | − int ret; | |
| 444 | − struct qcom_scm_desc desc = {0}; | |
| 445 | − struct arm_smccc_res res; | |
| 446 | − | |
| 447 | − desc.args[0] = mem_region; | |
| 448 | − desc.args[1] = mem_sz; | |
| 449 | − desc.args[2] = src; | |
| 450 | − desc.args[3] = src_sz; | |
| 451 | − desc.args[4] = dest; | |
| 452 | − desc.args[5] = dest_sz; | |
| 453 | − desc.args[6] = 0; | |
| 454 | − | |
| 455 | − desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL, | |
| 456 | − QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO, | |
| 457 | − QCOM_SCM_VAL, QCOM_SCM_VAL); | |
| 458 | − | |
| 459 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, | |
| 460 | − QCOM_MEM_PROT_ASSIGN_ID, | |
| 461 | − &desc, &res); | |
| 462 | − | |
| 463 | − return ret ? : res.a1; | |
| 464 | −} | |
| 465 | − | |
| 466 | −int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) | |
| 467 | −{ | |
| 468 | − struct qcom_scm_desc desc = {0}; | |
| 469 | − struct arm_smccc_res res; | |
| 470 | − int ret; | |
| 471 | − | |
| 472 | − desc.args[0] = device_id; | |
| 473 | − desc.args[1] = spare; | |
| 474 | − desc.arginfo = QCOM_SCM_ARGS(2); | |
| 475 | − | |
| 476 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG, | |
| 477 | − &desc, &res); | |
| 478 | − | |
| 479 | − return ret ? : res.a1; | |
| 480 | −} | |
| 481 | − | |
| 482 | −int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, | |
| 483 | − size_t *size) | |
| 484 | −{ | |
| 485 | − struct qcom_scm_desc desc = {0}; | |
| 486 | − struct arm_smccc_res res; | |
| 487 | − int ret; | |
| 488 | − | |
| 489 | − desc.args[0] = spare; | |
| 490 | − desc.arginfo = QCOM_SCM_ARGS(1); | |
| 491 | − | |
| 492 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, | |
| 493 | − QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res); | |
| 494 | − | |
| 495 | − if (size) | |
| 496 | − *size = res.a1; | |
| 497 | − | |
| 498 | − return ret ? : res.a2; | |
| 499 | −} | |
| 500 | − | |
| 501 | −int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, | |
| 502 | − u32 spare) | |
| 503 | −{ | |
| 504 | − struct qcom_scm_desc desc = {0}; | |
| 505 | − struct arm_smccc_res res; | |
| 506 | − int ret; | |
| 507 | − | |
| 508 | − desc.args[0] = addr; | |
| 509 | − desc.args[1] = size; | |
| 510 | − desc.args[2] = spare; | |
| 511 | − desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, | |
| 512 | − QCOM_SCM_VAL); | |
| 513 | − | |
| 514 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, | |
| 515 | − QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res); | |
| 516 | − | |
| 517 | − /* the pg table has been initialized already, ignore the error */ | |
| 518 | − if (ret == -EPERM) | |
| 519 | − ret = 0; | |
| 520 | − | |
| 521 | − return ret; | |
| 522 | −} | |
| 523 | − | |
| 524 | −int __qcom_scm_set_dload_mode(struct device *dev, bool enable) | |
| 525 | −{ | |
| 526 | − struct qcom_scm_desc desc = {0}; | |
| 527 | − struct arm_smccc_res res; | |
| 528 | − | |
| 529 | − desc.args[0] = QCOM_SCM_SET_DLOAD_MODE; | |
| 530 | − desc.args[1] = enable ? QCOM_SCM_SET_DLOAD_MODE : 0; | |
| 531 | − desc.arginfo = QCOM_SCM_ARGS(2); | |
| 532 | − | |
| 533 | − return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE, | |
| 534 | − &desc, &res); | |
| 535 | −} | |
| 536 | − | |
| 537 | −int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, | |
| 538 | − unsigned int *val) | |
| 539 | −{ | |
| 540 | − struct qcom_scm_desc desc = {0}; | |
| 541 | − struct arm_smccc_res res; | |
| 542 | − int ret; | |
| 543 | − | |
| 544 | − desc.args[0] = addr; | |
| 545 | − desc.arginfo = QCOM_SCM_ARGS(1); | |
| 546 | − | |
| 547 | − ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, | |
| 548 | − &desc, &res); | |
| 549 | − if (ret >= 0) | |
| 550 | − *val = res.a1; | |
| 551 | − | |
| 552 | − return ret < 0 ? ret : 0; | |
| 553 | −} | |
| 554 | − | |
| 555 | −int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) | |
| 556 | −{ | |
| 557 | − struct qcom_scm_desc desc = {0}; | |
| 558 | − struct arm_smccc_res res; | |
| 559 | − | |
| 560 | − desc.args[0] = addr; | |
| 561 | − desc.args[1] = val; | |
| 562 | − desc.arginfo = QCOM_SCM_ARGS(2); | |
| 563 | − | |
| 564 | − return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE, | |
| 565 | − &desc, &res); | |
| 566 | −} | |
| 567 | − | |
| 568 | −int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en) | |
| 569 | −{ | |
| 570 | − struct qcom_scm_desc desc = {0}; | |
| 571 | − struct arm_smccc_res res; | |
| 572 | − | |
| 573 | − desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL; | |
| 574 | − desc.args[1] = en; | |
| 575 | − desc.arginfo = QCOM_SCM_ARGS(2); | |
| 576 | − | |
| 577 | − return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM, | |
| 578 | − QCOM_SCM_CONFIG_ERRATA1, &desc, &res); | |
| 579 | −} | |
| @@ -0,0 +1,242 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved. | |
| 3 | + * Copyright (C) 2015 Linaro Ltd. | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <linux/slab.h> | |
| 7 | +#include <linux/io.h> | |
| 8 | +#include <linux/module.h> | |
| 9 | +#include <linux/mutex.h> | |
| 10 | +#include <linux/errno.h> | |
| 11 | +#include <linux/err.h> | |
| 12 | +#include <linux/qcom_scm.h> | |
| 13 | +#include <linux/arm-smccc.h> | |
| 14 | +#include <linux/dma-mapping.h> | |
| 15 | + | |
| 16 | +#include "qcom_scm.h" | |
| 17 | + | |
| 18 | +static DEFINE_MUTEX(qcom_scm_lock); | |
| 19 | + | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * struct arm_smccc_args | |
| 23 | + * @args: The array of values used in registers in smc instruction | |
| 24 | + */ | |
| 25 | +struct arm_smccc_args { | |
| 26 | + unsigned long args[8]; | |
| 27 | +}; | |
| 28 | + | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * struct scm_legacy_command - one SCM command buffer | |
| 32 | + * @len: total available memory for command and response | |
| 33 | + * @buf_offset: start of command buffer | |
| 34 | + * @resp_hdr_offset: start of response buffer | |
| 35 | + * @id: command to be executed | |
| 36 | + * @buf: buffer returned from scm_legacy_get_command_buffer() | |
| 37 | + * | |
| 38 | + * An SCM command is laid out in memory as follows: | |
| 39 | + * | |
| 40 | + * ------------------- <--- struct scm_legacy_command | |
| 41 | + * | command header | | |
| 42 | + * ------------------- <--- scm_legacy_get_command_buffer() | |
| 43 | + * | command buffer | | |
| 44 | + * ------------------- <--- struct scm_legacy_response and | |
| 45 | + * | response header | scm_legacy_command_to_response() | |
| 46 | + * ------------------- <--- scm_legacy_get_response_buffer() | |
| 47 | + * | response buffer | | |
| 48 | + * ------------------- | |
| 49 | + * | |
| 50 | + * There can be arbitrary padding between the headers and buffers so | |
| 51 | + * you should always use the appropriate scm_legacy_get_*_buffer() routines | |
| 52 | + * to access the buffers in a safe manner. | |
| 53 | + */ | |
| 54 | +struct scm_legacy_command { | |
| 55 | + __le32 len; | |
| 56 | + __le32 buf_offset; | |
| 57 | + __le32 resp_hdr_offset; | |
| 58 | + __le32 id; | |
| 59 | + __le32 buf[0]; | |
| 60 | +}; | |
| 61 | + | |
| 62 | +/** | |
| 63 | + * struct scm_legacy_response - one SCM response buffer | |
| 64 | + * @len: total available memory for response | |
| 65 | + * @buf_offset: start of response data relative to start of scm_legacy_response | |
| 66 | + * @is_complete: indicates if the command has finished processing | |
| 67 | + */ | |
| 68 | +struct scm_legacy_response { | |
| 69 | + __le32 len; | |
| 70 | + __le32 buf_offset; | |
| 71 | + __le32 is_complete; | |
| 72 | +}; | |
| 73 | + | |
| 74 | +/** | |
| 75 | + * scm_legacy_command_to_response() - Get a pointer to a scm_legacy_response | |
| 76 | + * @cmd: command | |
| 77 | + * | |
| 78 | + * Returns a pointer to a response for a command. | |
| 79 | + */ | |
| 80 | +static inline struct scm_legacy_response *scm_legacy_command_to_response( | |
| 81 | + const struct scm_legacy_command *cmd) | |
| 82 | +{ | |
| 83 | + return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); | |
| 84 | +} | |
| 85 | + | |
| 86 | +/** | |
| 87 | + * scm_legacy_get_command_buffer() - Get a pointer to a command buffer | |
| 88 | + * @cmd: command | |
| 89 | + * | |
| 90 | + * Returns a pointer to the command buffer of a command. | |
| 91 | + */ | |
| 92 | +static inline void *scm_legacy_get_command_buffer( | |
| 93 | + const struct scm_legacy_command *cmd) | |
| 94 | +{ | |
| 95 | + return (void *)cmd->buf; | |
| 96 | +} | |
| 97 | + | |
| 98 | +/** | |
| 99 | + * scm_legacy_get_response_buffer() - Get a pointer to a response buffer | |
| 100 | + * @rsp: response | |
| 101 | + * | |
| 102 | + * Returns a pointer to a response buffer of a response. | |
| 103 | + */ | |
| 104 | +static inline void *scm_legacy_get_response_buffer( | |
| 105 | + const struct scm_legacy_response *rsp) | |
| 106 | +{ | |
| 107 | + return (void *)rsp + le32_to_cpu(rsp->buf_offset); | |
| 108 | +} | |
| 109 | + | |
| 110 | +static void __scm_legacy_do(const struct arm_smccc_args *smc, | |
| 111 | + struct arm_smccc_res *res) | |
| 112 | +{ | |
| 113 | + do { | |
| 114 | + arm_smccc_smc(smc->args[0], smc->args[1], smc->args[2], | |
| 115 | + smc->args[3], smc->args[4], smc->args[5], | |
| 116 | + smc->args[6], smc->args[7], res); | |
| 117 | + } while (res->a0 == QCOM_SCM_INTERRUPTED); | |
| 118 | +} | |
| 119 | + | |
| 120 | +/** | |
| 121 | + * qcom_scm_call() - Sends a command to the SCM and waits for the command to | |
| 122 | + * finish processing. | |
| 123 | + * | |
| 124 | + * A note on cache maintenance: | |
| 125 | + * Note that any buffers that are expected to be accessed by the secure world | |
| 126 | + * must be flushed before invoking qcom_scm_call and invalidated in the cache | |
| 127 | + * immediately after qcom_scm_call returns. Cache maintenance on the command | |
| 128 | + * and response buffers is taken care of by qcom_scm_call; however, callers are | |
| 129 | + * responsible for any other cached buffers passed over to the secure world. | |
| 130 | + */ | |
| 131 | +int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, | |
| 132 | + struct qcom_scm_res *res) | |
| 133 | +{ | |
| 134 | + u8 arglen = desc->arginfo & 0xf; | |
| 135 | + int ret = 0, context_id; | |
| 136 | + unsigned int i; | |
| 137 | + struct scm_legacy_command *cmd; | |
| 138 | + struct scm_legacy_response *rsp; | |
| 139 | + struct arm_smccc_args smc = {0}; | |
| 140 | + struct arm_smccc_res smc_res; | |
| 141 | + const size_t cmd_len = arglen * sizeof(__le32); | |
| 142 | + const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32); | |
| 143 | + size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len; | |
| 144 | + dma_addr_t cmd_phys; | |
| 145 | + __le32 *arg_buf; | |
| 146 | + const __le32 *res_buf; | |
| 147 | + | |
| 148 | + cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); | |
| 149 | + if (!cmd) | |
| 150 | + return -ENOMEM; | |
| 151 | + | |
| 152 | + cmd->len = cpu_to_le32(alloc_len); | |
| 153 | + cmd->buf_offset = cpu_to_le32(sizeof(*cmd)); | |
| 154 | + cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len); | |
| 155 | + cmd->id = cpu_to_le32(SCM_LEGACY_FNID(desc->svc, desc->cmd)); | |
| 156 | + | |
| 157 | + arg_buf = scm_legacy_get_command_buffer(cmd); | |
| 158 | + for (i = 0; i < arglen; i++) | |
| 159 | + arg_buf[i] = cpu_to_le32(desc->args[i]); | |
| 160 | + | |
| 161 | + rsp = scm_legacy_command_to_response(cmd); | |
| 162 | + | |
| 163 | + cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE); | |
| 164 | + if (dma_mapping_error(dev, cmd_phys)) { | |
| 165 | + kfree(cmd); | |
| 166 | + return -ENOMEM; | |
| 167 | + } | |
| 168 | + | |
| 169 | + smc.args[0] = 1; | |
| 170 | + smc.args[1] = (unsigned long)&context_id; | |
| 171 | + smc.args[2] = cmd_phys; | |
| 172 | + | |
| 173 | + mutex_lock(&qcom_scm_lock); | |
| 174 | + __scm_legacy_do(&smc, &smc_res); | |
| 175 | + if (smc_res.a0) | |
| 176 | + ret = qcom_scm_remap_error(smc_res.a0); | |
| 177 | + mutex_unlock(&qcom_scm_lock); | |
| 178 | + if (ret) | |
| 179 | + goto out; | |
| 180 | + | |
| 181 | + do { | |
| 182 | + dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len, | |
| 183 | + sizeof(*rsp), DMA_FROM_DEVICE); | |
| 184 | + } while (!rsp->is_complete); | |
| 185 | + | |
| 186 | + dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len + | |
| 187 | + le32_to_cpu(rsp->buf_offset), | |
| 188 | + resp_len, DMA_FROM_DEVICE); | |
| 189 | + | |
| 190 | + if (res) { | |
| 191 | + res_buf = scm_legacy_get_response_buffer(rsp); | |
| 192 | + for (i = 0; i < MAX_QCOM_SCM_RETS; i++) | |
| 193 | + res->result[i] = le32_to_cpu(res_buf[i]); | |
| 194 | + } | |
| 195 | +out: | |
| 196 | + dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE); | |
| 197 | + kfree(cmd); | |
| 198 | + return ret; | |
| 199 | +} | |
| 200 | + | |
| 201 | +#define SCM_LEGACY_ATOMIC_N_REG_ARGS 5 | |
| 202 | +#define SCM_LEGACY_ATOMIC_FIRST_REG_IDX 2 | |
| 203 | +#define SCM_LEGACY_CLASS_REGISTER (0x2 << 8) | |
| 204 | +#define SCM_LEGACY_MASK_IRQS BIT(5) | |
| 205 | +#define SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \ | |
| 206 | + ((SCM_LEGACY_FNID(svc, cmd) << 12) | \ | |
| 207 | + SCM_LEGACY_CLASS_REGISTER | \ | |
| 208 | + SCM_LEGACY_MASK_IRQS | \ | |
| 209 | + (n & 0xf)) | |
| 210 | + | |
| 211 | +/** | |
| 212 | + * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments | |
| 213 | + * and 3 return values | |
| 214 | + * @desc: SCM call descriptor containing arguments | |
| 215 | + * @res: SCM call return values | |
| 216 | + * | |
| 217 | + * This shall only be used with commands that are guaranteed to be | |
| 218 | + * uninterruptable, atomic and SMP safe. | |
| 219 | + */ | |
| 220 | +int scm_legacy_call_atomic(struct device *unused, | |
| 221 | + const struct qcom_scm_desc *desc, | |
| 222 | + struct qcom_scm_res *res) | |
| 223 | +{ | |
| 224 | + int context_id; | |
| 225 | + struct arm_smccc_res smc_res; | |
| 226 | + size_t arglen = desc->arginfo & 0xf; | |
| 227 | + | |
| 228 | + BUG_ON(arglen > SCM_LEGACY_ATOMIC_N_REG_ARGS); | |
| 229 | + | |
| 230 | + arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(desc->svc, desc->cmd, arglen), | |
| 231 | + (unsigned long)&context_id, | |
| 232 | + desc->args[0], desc->args[1], desc->args[2], | |
| 233 | + desc->args[3], desc->args[4], 0, &smc_res); | |
| 234 | + | |
| 235 | + if (res) { | |
| 236 | + res->result[0] = smc_res.a1; | |
| 237 | + res->result[1] = smc_res.a2; | |
| 238 | + res->result[2] = smc_res.a3; | |
| 239 | + } | |
| 240 | + | |
| 241 | + return smc_res.a0; | |
| 242 | +} | |
| @@ -0,0 +1,151 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#include <linux/io.h> | |
| 6 | +#include <linux/errno.h> | |
| 7 | +#include <linux/delay.h> | |
| 8 | +#include <linux/mutex.h> | |
| 9 | +#include <linux/slab.h> | |
| 10 | +#include <linux/types.h> | |
| 11 | +#include <linux/qcom_scm.h> | |
| 12 | +#include <linux/arm-smccc.h> | |
| 13 | +#include <linux/dma-mapping.h> | |
| 14 | + | |
| 15 | +#include "qcom_scm.h" | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * struct arm_smccc_args | |
| 19 | + * @args: The array of values used in registers in smc instruction | |
| 20 | + */ | |
| 21 | +struct arm_smccc_args { | |
| 22 | + unsigned long args[8]; | |
| 23 | +}; | |
| 24 | + | |
| 25 | +static DEFINE_MUTEX(qcom_scm_lock); | |
| 26 | + | |
| 27 | +#define QCOM_SCM_EBUSY_WAIT_MS 30 | |
| 28 | +#define QCOM_SCM_EBUSY_MAX_RETRY 20 | |
| 29 | + | |
| 30 | +#define SCM_SMC_N_REG_ARGS 4 | |
| 31 | +#define SCM_SMC_FIRST_EXT_IDX (SCM_SMC_N_REG_ARGS - 1) | |
| 32 | +#define SCM_SMC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SCM_SMC_N_REG_ARGS + 1) | |
| 33 | +#define SCM_SMC_FIRST_REG_IDX 2 | |
| 34 | +#define SCM_SMC_LAST_REG_IDX (SCM_SMC_FIRST_REG_IDX + SCM_SMC_N_REG_ARGS - 1) | |
| 35 | + | |
| 36 | +static void __scm_smc_do_quirk(const struct arm_smccc_args *smc, | |
| 37 | + struct arm_smccc_res *res) | |
| 38 | +{ | |
| 39 | + unsigned long a0 = smc->args[0]; | |
| 40 | + struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 }; | |
| 41 | + | |
| 42 | + quirk.state.a6 = 0; | |
| 43 | + | |
| 44 | + do { | |
| 45 | + arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2], | |
| 46 | + smc->args[3], smc->args[4], smc->args[5], | |
| 47 | + quirk.state.a6, smc->args[7], res, &quirk); | |
| 48 | + | |
| 49 | + if (res->a0 == QCOM_SCM_INTERRUPTED) | |
| 50 | + a0 = res->a0; | |
| 51 | + | |
| 52 | + } while (res->a0 == QCOM_SCM_INTERRUPTED); | |
| 53 | +} | |
| 54 | + | |
| 55 | +static void __scm_smc_do(const struct arm_smccc_args *smc, | |
| 56 | + struct arm_smccc_res *res, bool atomic) | |
| 57 | +{ | |
| 58 | + int retry_count = 0; | |
| 59 | + | |
| 60 | + if (atomic) { | |
| 61 | + __scm_smc_do_quirk(smc, res); | |
| 62 | + return; | |
| 63 | + } | |
| 64 | + | |
| 65 | + do { | |
| 66 | + mutex_lock(&qcom_scm_lock); | |
| 67 | + | |
| 68 | + __scm_smc_do_quirk(smc, res); | |
| 69 | + | |
| 70 | + mutex_unlock(&qcom_scm_lock); | |
| 71 | + | |
| 72 | + if (res->a0 == QCOM_SCM_V2_EBUSY) { | |
| 73 | + if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) | |
| 74 | + break; | |
| 75 | + msleep(QCOM_SCM_EBUSY_WAIT_MS); | |
| 76 | + } | |
| 77 | + } while (res->a0 == QCOM_SCM_V2_EBUSY); | |
| 78 | +} | |
| 79 | + | |
| 80 | +int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, | |
| 81 | + struct qcom_scm_res *res, bool atomic) | |
| 82 | +{ | |
| 83 | + int arglen = desc->arginfo & 0xf; | |
| 84 | + int i; | |
| 85 | + dma_addr_t args_phys = 0; | |
| 86 | + void *args_virt = NULL; | |
| 87 | + size_t alloc_len; | |
| 88 | + gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL; | |
| 89 | + u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL; | |
| 90 | + u32 qcom_smccc_convention = | |
| 91 | + (qcom_scm_convention == SMC_CONVENTION_ARM_32) ? | |
| 92 | + ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64; | |
| 93 | + struct arm_smccc_res smc_res; | |
| 94 | + struct arm_smccc_args smc = {0}; | |
| 95 | + | |
| 96 | + smc.args[0] = ARM_SMCCC_CALL_VAL( | |
| 97 | + smccc_call_type, | |
| 98 | + qcom_smccc_convention, | |
| 99 | + desc->owner, | |
| 100 | + SCM_SMC_FNID(desc->svc, desc->cmd)); | |
| 101 | + smc.args[1] = desc->arginfo; | |
| 102 | + for (i = 0; i < SCM_SMC_N_REG_ARGS; i++) | |
| 103 | + smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i]; | |
| 104 | + | |
| 105 | + if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) { | |
| 106 | + alloc_len = SCM_SMC_N_EXT_ARGS * sizeof(u64); | |
| 107 | + args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag); | |
| 108 | + | |
| 109 | + if (!args_virt) | |
| 110 | + return -ENOMEM; | |
| 111 | + | |
| 112 | + if (qcom_smccc_convention == ARM_SMCCC_SMC_32) { | |
| 113 | + __le32 *args = args_virt; | |
| 114 | + | |
| 115 | + for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++) | |
| 116 | + args[i] = cpu_to_le32(desc->args[i + | |
| 117 | + SCM_SMC_FIRST_EXT_IDX]); | |
| 118 | + } else { | |
| 119 | + __le64 *args = args_virt; | |
| 120 | + | |
| 121 | + for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++) | |
| 122 | + args[i] = cpu_to_le64(desc->args[i + | |
| 123 | + SCM_SMC_FIRST_EXT_IDX]); | |
| 124 | + } | |
| 125 | + | |
| 126 | + args_phys = dma_map_single(dev, args_virt, alloc_len, | |
| 127 | + DMA_TO_DEVICE); | |
| 128 | + | |
| 129 | + if (dma_mapping_error(dev, args_phys)) { | |
| 130 | + kfree(args_virt); | |
| 131 | + return -ENOMEM; | |
| 132 | + } | |
| 133 | + | |
| 134 | + smc.args[SCM_SMC_LAST_REG_IDX] = args_phys; | |
| 135 | + } | |
| 136 | + | |
| 137 | + __scm_smc_do(&smc, &smc_res, atomic); | |
| 138 | + | |
| 139 | + if (args_virt) { | |
| 140 | + dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE); | |
| 141 | + kfree(args_virt); | |
| 142 | + } | |
| 143 | + | |
| 144 | + if (res) { | |
| 145 | + res->result[0] = smc_res.a1; | |
| 146 | + res->result[1] = smc_res.a2; | |
| 147 | + res->result[2] = smc_res.a3; | |
| 148 | + } | |
| 149 | + | |
| 150 | + return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0; | |
| 151 | +} | |
| @@ -1,8 +1,5 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | −/* | |
| 3 | − * Qualcomm SCM driver | |
| 4 | − * | |
| 5 | − * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. | |
| 2 | +/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved. | |
| 6 | 3 | * Copyright (C) 2015 Linaro Ltd. |
| 7 | 4 | */ |
| 8 | 5 | #include <linux/platform_device.h> |
| @@ -19,6 +16,7 @@ · 10 unmodified lines | ||
| 19 | 16 | #include <linux/of_platform.h> |
| 20 | 17 | #include <linux/clk.h> |
| 21 | 18 | #include <linux/reset-controller.h> |
| 19 | +#include <linux/arm-smccc.h> | |
| 22 | 20 | |
| 23 | 21 | #include "qcom_scm.h" |
| 24 | 22 | |
| @@ -52,6 +50,35 @@ struct qcom_scm_mem_map_info { · 27 unmodified lines | ||
| 52 | 50 | __le64 mem_size; |
| 53 | 51 | }; |
| 54 | 52 | |
| 53 | +#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00 | |
| 54 | +#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 | |
| 55 | +#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 | |
| 56 | +#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 | |
| 57 | + | |
| 58 | +#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 | |
| 59 | +#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 | |
| 60 | +#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 | |
| 61 | +#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 | |
| 62 | + | |
| 63 | +struct qcom_scm_wb_entry { | |
| 64 | + int flag; | |
| 65 | + void *entry; | |
| 66 | +}; | |
| 67 | + | |
| 68 | +static struct qcom_scm_wb_entry qcom_scm_wb[] = { | |
| 69 | + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 }, | |
| 70 | + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 }, | |
| 71 | + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 }, | |
| 72 | + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 }, | |
| 73 | +}; | |
| 74 | + | |
| 75 | +static const char *qcom_scm_convention_names[] = { | |
| 76 | + [SMC_CONVENTION_UNKNOWN] = "unknown", | |
| 77 | + [SMC_CONVENTION_ARM_32] = "smc arm 32", | |
| 78 | + [SMC_CONVENTION_ARM_64] = "smc arm 64", | |
| 79 | + [SMC_CONVENTION_LEGACY] = "smc legacy", | |
| 80 | +}; | |
| 81 | + | |
| 55 | 82 | static struct qcom_scm *__scm; |
| 56 | 83 | |
| 57 | 84 | static int qcom_scm_clk_enable(void) |
| @@ -87,149 +114,308 @@ static void qcom_scm_clk_disable(void) · 29 unmodified lines | ||
| 87 | 114 | clk_disable_unprepare(__scm->bus_clk); |
| 88 | 115 | } |
| 89 | 116 | |
| 90 | −/** | |
| 91 | − * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus | |
| 92 | − * @entry: Entry point function for the cpus | |
| 93 | − * @cpus: The cpumask of cpus that will use the entry point | |
| 94 | − * | |
| 95 | − * Set the cold boot address of the cpus. Any cpu outside the supported | |
| 96 | − * range would be removed from the cpu present mask. | |
| 97 | − */ | |
| 98 | −int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |
| 117 | +static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, | |
| 118 | + u32 cmd_id); | |
| 119 | + | |
| 120 | +enum qcom_scm_convention qcom_scm_convention; | |
| 121 | +static bool has_queried __read_mostly; | |
| 122 | +static DEFINE_SPINLOCK(query_lock); | |
| 123 | + | |
| 124 | +static void __query_convention(void) | |
| 99 | 125 | { |
| 100 | − return __qcom_scm_set_cold_boot_addr(entry, cpus); | |
| 126 | + unsigned long flags; | |
| 127 | + struct qcom_scm_desc desc = { | |
| 128 | + .svc = QCOM_SCM_SVC_INFO, | |
| 129 | + .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL, | |
| 130 | + .args[0] = SCM_SMC_FNID(QCOM_SCM_SVC_INFO, | |
| 131 | + QCOM_SCM_INFO_IS_CALL_AVAIL) | | |
| 132 | + (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT), | |
| 133 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 134 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 135 | + }; | |
| 136 | + struct qcom_scm_res res; | |
| 137 | + int ret; | |
| 138 | + | |
| 139 | + spin_lock_irqsave(&query_lock, flags); | |
| 140 | + if (has_queried) | |
| 141 | + goto out; | |
| 142 | + | |
| 143 | + qcom_scm_convention = SMC_CONVENTION_ARM_64; | |
| 144 | + // Device isn't required as there is only one argument - no device | |
| 145 | + // needed to dma_map_single to secure world | |
| 146 | + ret = scm_smc_call(NULL, &desc, &res, true); | |
| 147 | + if (!ret && res.result[0] == 1) | |
| 148 | + goto out; | |
| 149 | + | |
| 150 | + qcom_scm_convention = SMC_CONVENTION_ARM_32; | |
| 151 | + ret = scm_smc_call(NULL, &desc, &res, true); | |
| 152 | + if (!ret && res.result[0] == 1) | |
| 153 | + goto out; | |
| 154 | + | |
| 155 | + qcom_scm_convention = SMC_CONVENTION_LEGACY; | |
| 156 | +out: | |
| 157 | + has_queried = true; | |
| 158 | + spin_unlock_irqrestore(&query_lock, flags); | |
| 159 | + pr_info("qcom_scm: convention: %s\n", | |
| 160 | + qcom_scm_convention_names[qcom_scm_convention]); | |
| 101 | 161 | } |
| 102 | −EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); | |
| 103 | 162 | |
| 104 | −/** | |
| 105 | − * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus | |
| 106 | − * @entry: Entry point function for the cpus | |
| 107 | − * @cpus: The cpumask of cpus that will use the entry point | |
| 108 | − * | |
| 109 | − * Set the Linux entry point for the SCM to transfer control to when coming | |
| 110 | − * out of a power down. CPU power down may be executed on cpuidle or hotplug. | |
| 111 | − */ | |
| 112 | −int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) | |
| 163 | +static inline enum qcom_scm_convention __get_convention(void) | |
| 113 | 164 | { |
| 114 | − return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus); | |
| 165 | + if (unlikely(!has_queried)) | |
| 166 | + __query_convention(); | |
| 167 | + return qcom_scm_convention; | |
| 115 | 168 | } |
| 116 | −EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); | |
| 117 | 169 | |
| 118 | 170 | /** |
| 119 | − * qcom_scm_cpu_power_down() - Power down the cpu | |
| 120 | − * @flags - Flags to flush cache | |
| 171 | + * qcom_scm_call() - Invoke a syscall in the secure world | |
| 172 | + * @dev: device | |
| 173 | + * @svc_id: service identifier | |
| 174 | + * @cmd_id: command identifier | |
| 175 | + * @desc: Descriptor structure containing arguments and return values | |
| 121 | 176 | * |
| 122 | − * This is an end point to power down cpu. If there was a pending interrupt, | |
| 123 | − * the control would return from this function, otherwise, the cpu jumps to the | |
| 124 | − * warm boot entry point set for this cpu upon reset. | |
| 177 | + * Sends a command to the SCM and waits for the command to finish processing. | |
| 178 | + * This should *only* be called in pre-emptible context. | |
| 125 | 179 | */ |
| 126 | −void qcom_scm_cpu_power_down(u32 flags) | |
| 180 | +static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc, | |
| 181 | + struct qcom_scm_res *res) | |
| 127 | 182 | { |
| 128 | − __qcom_scm_cpu_power_down(flags); | |
| 183 | + might_sleep(); | |
| 184 | + switch (__get_convention()) { | |
| 185 | + case SMC_CONVENTION_ARM_32: | |
| 186 | + case SMC_CONVENTION_ARM_64: | |
| 187 | + return scm_smc_call(dev, desc, res, false); | |
| 188 | + case SMC_CONVENTION_LEGACY: | |
| 189 | + return scm_legacy_call(dev, desc, res); | |
| 190 | + default: | |
| 191 | + pr_err("Unknown current SCM calling convention.\n"); | |
| 192 | + return -EINVAL; | |
| 193 | + } | |
| 129 | 194 | } |
| 130 | −EXPORT_SYMBOL(qcom_scm_cpu_power_down); | |
| 131 | 195 | |
| 132 | 196 | /** |
| 133 | − * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. | |
| 197 | + * qcom_scm_call_atomic() - atomic variation of qcom_scm_call() | |
| 198 | + * @dev: device | |
| 199 | + * @svc_id: service identifier | |
| 200 | + * @cmd_id: command identifier | |
| 201 | + * @desc: Descriptor structure containing arguments and return values | |
| 202 | + * @res: Structure containing results from SMC/HVC call | |
| 134 | 203 | * |
| 135 | − * Return true if HDCP is supported, false if not. | |
| 204 | + * Sends a command to the SCM and waits for the command to finish processing. | |
| 205 | + * This can be called in atomic context. | |
| 136 | 206 | */ |
| 137 | −bool qcom_scm_hdcp_available(void) | |
| 207 | +static int qcom_scm_call_atomic(struct device *dev, | |
| 208 | + const struct qcom_scm_desc *desc, | |
| 209 | + struct qcom_scm_res *res) | |
| 138 | 210 | { |
| 139 | − int ret = qcom_scm_clk_enable(); | |
| 140 | − | |
| 141 | − if (ret) | |
| 142 | − return ret; | |
| 211 | + switch (__get_convention()) { | |
| 212 | + case SMC_CONVENTION_ARM_32: | |
| 213 | + case SMC_CONVENTION_ARM_64: | |
| 214 | + return scm_smc_call(dev, desc, res, true); | |
| 215 | + case SMC_CONVENTION_LEGACY: | |
| 216 | + return scm_legacy_call_atomic(dev, desc, res); | |
| 217 | + default: | |
| 218 | + pr_err("Unknown current SCM calling convention.\n"); | |
| 219 | + return -EINVAL; | |
| 220 | + } | |
| 221 | +} | |
| 143 | 222 | |
| 144 | − ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP, | |
| 145 | − QCOM_SCM_CMD_HDCP); | |
| 223 | +static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, | |
| 224 | + u32 cmd_id) | |
| 225 | +{ | |
| 226 | + int ret; | |
| 227 | + struct qcom_scm_desc desc = { | |
| 228 | + .svc = QCOM_SCM_SVC_INFO, | |
| 229 | + .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL, | |
| 230 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 231 | + }; | |
| 232 | + struct qcom_scm_res res; | |
| 233 | + | |
| 234 | + desc.arginfo = QCOM_SCM_ARGS(1); | |
| 235 | + switch (__get_convention()) { | |
| 236 | + case SMC_CONVENTION_ARM_32: | |
| 237 | + case SMC_CONVENTION_ARM_64: | |
| 238 | + desc.args[0] = SCM_SMC_FNID(svc_id, cmd_id) | | |
| 239 | + (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT); | |
| 240 | + break; | |
| 241 | + case SMC_CONVENTION_LEGACY: | |
| 242 | + desc.args[0] = SCM_LEGACY_FNID(svc_id, cmd_id); | |
| 243 | + break; | |
| 244 | + default: | |
| 245 | + pr_err("Unknown SMC convention being used\n"); | |
| 246 | + return -EINVAL; | |
| 247 | + } | |
| 146 | 248 | |
| 147 | − qcom_scm_clk_disable(); | |
| 249 | + ret = qcom_scm_call(dev, &desc, &res); | |
| 148 | 250 | |
| 149 | − return ret > 0 ? true : false; | |
| 251 | + return ret ? : res.result[0]; | |
| 150 | 252 | } |
| 151 | −EXPORT_SYMBOL(qcom_scm_hdcp_available); | |
| 152 | 253 | |
| 153 | 254 | /** |
| 154 | − * qcom_scm_hdcp_req() - Send HDCP request. | |
| 155 | − * @req: HDCP request array | |
| 156 | − * @req_cnt: HDCP request array count | |
| 157 | − * @resp: response buffer passed to SCM | |
| 255 | + * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus | |
| 256 | + * @entry: Entry point function for the cpus | |
| 257 | + * @cpus: The cpumask of cpus that will use the entry point | |
| 158 | 258 | * |
| 159 | − * Write HDCP register(s) through SCM. | |
| 259 | + * Set the Linux entry point for the SCM to transfer control to when coming | |
| 260 | + * out of a power down. CPU power down may be executed on cpuidle or hotplug. | |
| 160 | 261 | */ |
| 161 | −int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) | |
| 262 | +int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) | |
| 162 | 263 | { |
| 163 | − int ret = qcom_scm_clk_enable(); | |
| 264 | + int ret; | |
| 265 | + int flags = 0; | |
| 266 | + int cpu; | |
| 267 | + struct qcom_scm_desc desc = { | |
| 268 | + .svc = QCOM_SCM_SVC_BOOT, | |
| 269 | + .cmd = QCOM_SCM_BOOT_SET_ADDR, | |
| 270 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 271 | + }; | |
| 164 | 272 | |
| 165 | − if (ret) | |
| 166 | − return ret; | |
| 273 | + /* | |
| 274 | + * Reassign only if we are switching from hotplug entry point | |
| 275 | + * to cpuidle entry point or vice versa. | |
| 276 | + */ | |
| 277 | + for_each_cpu(cpu, cpus) { | |
| 278 | + if (entry == qcom_scm_wb[cpu].entry) | |
| 279 | + continue; | |
| 280 | + flags |= qcom_scm_wb[cpu].flag; | |
| 281 | + } | |
| 282 | + | |
| 283 | + /* No change in entry function */ | |
| 284 | + if (!flags) | |
| 285 | + return 0; | |
| 286 | + | |
| 287 | + desc.args[0] = flags; | |
| 288 | + desc.args[1] = virt_to_phys(entry); | |
| 289 | + | |
| 290 | + ret = qcom_scm_call(__scm->dev, &desc, NULL); | |
| 291 | + if (!ret) { | |
| 292 | + for_each_cpu(cpu, cpus) | |
| 293 | + qcom_scm_wb[cpu].entry = entry; | |
| 294 | + } | |
| 167 | 295 | |
| 168 | − ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp); | |
| 169 | − qcom_scm_clk_disable(); | |
| 170 | 296 | return ret; |
| 171 | 297 | } |
| 172 | −EXPORT_SYMBOL(qcom_scm_hdcp_req); | |
| 298 | +EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); | |
| 173 | 299 | |
| 174 | 300 | /** |
| 175 | − * qcom_scm_pas_supported() - Check if the peripheral authentication service is | |
| 176 | − * available for the given peripherial | |
| 177 | − * @peripheral: peripheral id | |
| 301 | + * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus | |
| 302 | + * @entry: Entry point function for the cpus | |
| 303 | + * @cpus: The cpumask of cpus that will use the entry point | |
| 178 | 304 | * |
| 179 | − * Returns true if PAS is supported for this peripheral, otherwise false. | |
| 305 | + * Set the cold boot address of the cpus. Any cpu outside the supported | |
| 306 | + * range would be removed from the cpu present mask. | |
| 180 | 307 | */ |
| 181 | −bool qcom_scm_pas_supported(u32 peripheral) | |
| 308 | +int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |
| 182 | 309 | { |
| 183 | − int ret; | |
| 310 | + int flags = 0; | |
| 311 | + int cpu; | |
| 312 | + int scm_cb_flags[] = { | |
| 313 | + QCOM_SCM_FLAG_COLDBOOT_CPU0, | |
| 314 | + QCOM_SCM_FLAG_COLDBOOT_CPU1, | |
| 315 | + QCOM_SCM_FLAG_COLDBOOT_CPU2, | |
| 316 | + QCOM_SCM_FLAG_COLDBOOT_CPU3, | |
| 317 | + }; | |
| 318 | + struct qcom_scm_desc desc = { | |
| 319 | + .svc = QCOM_SCM_SVC_BOOT, | |
| 320 | + .cmd = QCOM_SCM_BOOT_SET_ADDR, | |
| 321 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 322 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 323 | + }; | |
| 324 | + | |
| 325 | + if (!cpus || (cpus && cpumask_empty(cpus))) | |
| 326 | + return -EINVAL; | |
| 184 | 327 | |
| 185 | − ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, | |
| 186 | − QCOM_SCM_PAS_IS_SUPPORTED_CMD); | |
| 187 | − if (ret <= 0) | |
| 188 | − return false; | |
| 328 | + for_each_cpu(cpu, cpus) { | |
| 329 | + if (cpu < ARRAY_SIZE(scm_cb_flags)) | |
| 330 | + flags |= scm_cb_flags[cpu]; | |
| 331 | + else | |
| 332 | + set_cpu_present(cpu, false); | |
| 333 | + } | |
| 334 | + | |
| 335 | + desc.args[0] = flags; | |
| 336 | + desc.args[1] = virt_to_phys(entry); | |
| 189 | 337 | |
| 190 | − return __qcom_scm_pas_supported(__scm->dev, peripheral); | |
| 338 | + return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL); | |
| 191 | 339 | } |
| 192 | −EXPORT_SYMBOL(qcom_scm_pas_supported); | |
| 340 | +EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); | |
| 193 | 341 | |
| 194 | 342 | /** |
| 195 | − * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available | |
| 343 | + * qcom_scm_cpu_power_down() - Power down the cpu | |
| 344 | + * @flags - Flags to flush cache | |
| 345 | + * | |
| 346 | + * This is an end point to power down cpu. If there was a pending interrupt, | |
| 347 | + * the control would return from this function, otherwise, the cpu jumps to the | |
| 348 | + * warm boot entry point set for this cpu upon reset. | |
| 196 | 349 | */ |
| 197 | −bool qcom_scm_ocmem_lock_available(void) | |
| 350 | +void qcom_scm_cpu_power_down(u32 flags) | |
| 198 | 351 | { |
| 199 | − return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_OCMEM_SVC, | |
| 200 | − QCOM_SCM_OCMEM_LOCK_CMD); | |
| 352 | + struct qcom_scm_desc desc = { | |
| 353 | + .svc = QCOM_SCM_SVC_BOOT, | |
| 354 | + .cmd = QCOM_SCM_BOOT_TERMINATE_PC, | |
| 355 | + .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK, | |
| 356 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 357 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 358 | + }; | |
| 359 | + | |
| 360 | + qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL); | |
| 201 | 361 | } |
| 202 | −EXPORT_SYMBOL(qcom_scm_ocmem_lock_available); | |
| 362 | +EXPORT_SYMBOL(qcom_scm_cpu_power_down); | |
| 203 | 363 | |
| 204 | −/** | |
| 205 | − * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM | |
| 206 | − * region to the specified initiator | |
| 207 | − * | |
| 208 | − * @id: tz initiator id | |
| 209 | − * @offset: OCMEM offset | |
| 210 | − * @size: OCMEM size | |
| 211 | − * @mode: access mode (WIDE/NARROW) | |
| 212 | − */ | |
| 213 | −int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size, | |
| 214 | − u32 mode) | |
| 364 | +int qcom_scm_set_remote_state(u32 state, u32 id) | |
| 215 | 365 | { |
| 216 | − return __qcom_scm_ocmem_lock(__scm->dev, id, offset, size, mode); | |
| 366 | + struct qcom_scm_desc desc = { | |
| 367 | + .svc = QCOM_SCM_SVC_BOOT, | |
| 368 | + .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE, | |
| 369 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 370 | + .args[0] = state, | |
| 371 | + .args[1] = id, | |
| 372 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 373 | + }; | |
| 374 | + struct qcom_scm_res res; | |
| 375 | + int ret; | |
| 376 | + | |
| 377 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 378 | + | |
| 379 | + return ret ? : res.result[0]; | |
| 217 | 380 | } |
| 218 | −EXPORT_SYMBOL(qcom_scm_ocmem_lock); | |
| 381 | +EXPORT_SYMBOL(qcom_scm_set_remote_state); | |
| 219 | 382 | |
| 220 | −/** | |
| 221 | − * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM | |
| 222 | − * region from the specified initiator | |
| 223 | − * | |
| 224 | − * @id: tz initiator id | |
| 225 | − * @offset: OCMEM offset | |
| 226 | − * @size: OCMEM size | |
| 227 | − */ | |
| 228 | −int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size) | |
| 383 | +static int __qcom_scm_set_dload_mode(struct device *dev, bool enable) | |
| 229 | 384 | { |
| 230 | − return __qcom_scm_ocmem_unlock(__scm->dev, id, offset, size); | |
| 385 | + struct qcom_scm_desc desc = { | |
| 386 | + .svc = QCOM_SCM_SVC_BOOT, | |
| 387 | + .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE, | |
| 388 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 389 | + .args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE, | |
| 390 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 391 | + }; | |
| 392 | + | |
| 393 | + desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0; | |
| 394 | + | |
| 395 | + return qcom_scm_call(__scm->dev, &desc, NULL); | |
| 396 | +} | |
| 397 | + | |
| 398 | +static void qcom_scm_set_download_mode(bool enable) | |
| 399 | +{ | |
| 400 | + bool avail; | |
| 401 | + int ret = 0; | |
| 402 | + | |
| 403 | + avail = __qcom_scm_is_call_available(__scm->dev, | |
| 404 | + QCOM_SCM_SVC_BOOT, | |
| 405 | + QCOM_SCM_BOOT_SET_DLOAD_MODE); | |
| 406 | + if (avail) { | |
| 407 | + ret = __qcom_scm_set_dload_mode(__scm->dev, enable); | |
| 408 | + } else if (__scm->dload_mode_addr) { | |
| 409 | + ret = qcom_scm_io_writel(__scm->dload_mode_addr, | |
| 410 | + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0); | |
| 411 | + } else { | |
| 412 | + dev_err(__scm->dev, | |
| 413 | + "No available mechanism for setting download mode\n"); | |
| 414 | + } | |
| 415 | + | |
| 416 | + if (ret) | |
| 417 | + dev_err(__scm->dev, "failed to set download mode: %d\n", ret); | |
| 231 | 418 | } |
| 232 | −EXPORT_SYMBOL(qcom_scm_ocmem_unlock); | |
| 233 | 419 | |
| 234 | 420 | /** |
| 235 | 421 | * qcom_scm_pas_init_image() - Initialize peripheral authentication service |
| @@ -248,6 +434,14 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) · 12 unmodified lines | ||
| 248 | 434 | dma_addr_t mdata_phys; |
| 249 | 435 | void *mdata_buf; |
| 250 | 436 | int ret; |
| 437 | + struct qcom_scm_desc desc = { | |
| 438 | + .svc = QCOM_SCM_SVC_PIL, | |
| 439 | + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE, | |
| 440 | + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW), | |
| 441 | + .args[0] = peripheral, | |
| 442 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 443 | + }; | |
| 444 | + struct qcom_scm_res res; | |
| 251 | 445 | |
| 252 | 446 | /* |
| 253 | 447 | * During the scm call memory protection will be enabled for the meta |
| @@ -266,14 +460,16 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) · 12 unmodified lines | ||
| 266 | 460 | if (ret) |
| 267 | 461 | goto free_metadata; |
| 268 | 462 | |
| 269 | − ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys); | |
| 463 | + desc.args[1] = mdata_phys; | |
| 464 | + | |
| 465 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 270 | 466 | |
| 271 | 467 | qcom_scm_clk_disable(); |
| 272 | 468 | |
| 273 | 469 | free_metadata: |
| 274 | 470 | dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); |
| 275 | 471 | |
| 276 | − return ret; | |
| 472 | + return ret ? : res.result[0]; | |
| 277 | 473 | } |
| 278 | 474 | EXPORT_SYMBOL(qcom_scm_pas_init_image); |
| 279 | 475 | |
| @@ -289,15 +485,25 @@ EXPORT_SYMBOL(qcom_scm_pas_init_image); · 9 unmodified lines | ||
| 289 | 485 | int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) |
| 290 | 486 | { |
| 291 | 487 | int ret; |
| 488 | + struct qcom_scm_desc desc = { | |
| 489 | + .svc = QCOM_SCM_SVC_PIL, | |
| 490 | + .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP, | |
| 491 | + .arginfo = QCOM_SCM_ARGS(3), | |
| 492 | + .args[0] = peripheral, | |
| 493 | + .args[1] = addr, | |
| 494 | + .args[2] = size, | |
| 495 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 496 | + }; | |
| 497 | + struct qcom_scm_res res; | |
| 292 | 498 | |
| 293 | 499 | ret = qcom_scm_clk_enable(); |
| 294 | 500 | if (ret) |
| 295 | 501 | return ret; |
| 296 | 502 | |
| 297 | − ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size); | |
| 503 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 298 | 504 | qcom_scm_clk_disable(); |
| 299 | 505 | |
| 300 | − return ret; | |
| 506 | + return ret ? : res.result[0]; | |
| 301 | 507 | } |
| 302 | 508 | EXPORT_SYMBOL(qcom_scm_pas_mem_setup); |
| 303 | 509 | |
| @@ -311,15 +517,23 @@ EXPORT_SYMBOL(qcom_scm_pas_mem_setup); · 7 unmodified lines | ||
| 311 | 517 | int qcom_scm_pas_auth_and_reset(u32 peripheral) |
| 312 | 518 | { |
| 313 | 519 | int ret; |
| 520 | + struct qcom_scm_desc desc = { | |
| 521 | + .svc = QCOM_SCM_SVC_PIL, | |
| 522 | + .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET, | |
| 523 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 524 | + .args[0] = peripheral, | |
| 525 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 526 | + }; | |
| 527 | + struct qcom_scm_res res; | |
| 314 | 528 | |
| 315 | 529 | ret = qcom_scm_clk_enable(); |
| 316 | 530 | if (ret) |
| 317 | 531 | return ret; |
| 318 | 532 | |
| 319 | − ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral); | |
| 533 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 320 | 534 | qcom_scm_clk_disable(); |
| 321 | 535 | |
| 322 | − return ret; | |
| 536 | + return ret ? : res.result[0]; | |
| 323 | 537 | } |
| 324 | 538 | EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); |
| 325 | 539 | |
| @@ -332,18 +546,75 @@ EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); · 6 unmodified lines | ||
| 332 | 546 | int qcom_scm_pas_shutdown(u32 peripheral) |
| 333 | 547 | { |
| 334 | 548 | int ret; |
| 549 | + struct qcom_scm_desc desc = { | |
| 550 | + .svc = QCOM_SCM_SVC_PIL, | |
| 551 | + .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN, | |
| 552 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 553 | + .args[0] = peripheral, | |
| 554 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 555 | + }; | |
| 556 | + struct qcom_scm_res res; | |
| 335 | 557 | |
| 336 | 558 | ret = qcom_scm_clk_enable(); |
| 337 | 559 | if (ret) |
| 338 | 560 | return ret; |
| 339 | 561 | |
| 340 | − ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral); | |
| 562 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 563 | + | |
| 341 | 564 | qcom_scm_clk_disable(); |
| 342 | 565 | |
| 343 | − return ret; | |
| 566 | + return ret ? : res.result[0]; | |
| 344 | 567 | } |
| 345 | 568 | EXPORT_SYMBOL(qcom_scm_pas_shutdown); |
| 346 | 569 | |
| 570 | +/** | |
| 571 | + * qcom_scm_pas_supported() - Check if the peripheral authentication service is | |
| 572 | + * available for the given peripherial | |
| 573 | + * @peripheral: peripheral id | |
| 574 | + * | |
| 575 | + * Returns true if PAS is supported for this peripheral, otherwise false. | |
| 576 | + */ | |
| 577 | +bool qcom_scm_pas_supported(u32 peripheral) | |
| 578 | +{ | |
| 579 | + int ret; | |
| 580 | + struct qcom_scm_desc desc = { | |
| 581 | + .svc = QCOM_SCM_SVC_PIL, | |
| 582 | + .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED, | |
| 583 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 584 | + .args[0] = peripheral, | |
| 585 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 586 | + }; | |
| 587 | + struct qcom_scm_res res; | |
| 588 | + | |
| 589 | + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, | |
| 590 | + QCOM_SCM_PIL_PAS_IS_SUPPORTED); | |
| 591 | + if (ret <= 0) | |
| 592 | + return false; | |
| 593 | + | |
| 594 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 595 | + | |
| 596 | + return ret ? false : !!res.result[0]; | |
| 597 | +} | |
| 598 | +EXPORT_SYMBOL(qcom_scm_pas_supported); | |
| 599 | + | |
| 600 | +static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) | |
| 601 | +{ | |
| 602 | + struct qcom_scm_desc desc = { | |
| 603 | + .svc = QCOM_SCM_SVC_PIL, | |
| 604 | + .cmd = QCOM_SCM_PIL_PAS_MSS_RESET, | |
| 605 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 606 | + .args[0] = reset, | |
| 607 | + .args[1] = 0, | |
| 608 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 609 | + }; | |
| 610 | + struct qcom_scm_res res; | |
| 611 | + int ret; | |
| 612 | + | |
| 613 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 614 | + | |
| 615 | + return ret ? : res.result[0]; | |
| 616 | +} | |
| 617 | + | |
| 347 | 618 | static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev, |
| 348 | 619 | unsigned long idx) |
| 349 | 620 | { |
| @@ -367,6 +638,43 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = { · 17 unmodified lines | ||
| 367 | 638 | .deassert = qcom_scm_pas_reset_deassert, |
| 368 | 639 | }; |
| 369 | 640 | |
| 641 | +int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) | |
| 642 | +{ | |
| 643 | + struct qcom_scm_desc desc = { | |
| 644 | + .svc = QCOM_SCM_SVC_IO, | |
| 645 | + .cmd = QCOM_SCM_IO_READ, | |
| 646 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 647 | + .args[0] = addr, | |
| 648 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 649 | + }; | |
| 650 | + struct qcom_scm_res res; | |
| 651 | + int ret; | |
| 652 | + | |
| 653 | + | |
| 654 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 655 | + if (ret >= 0) | |
| 656 | + *val = res.result[0]; | |
| 657 | + | |
| 658 | + return ret < 0 ? ret : 0; | |
| 659 | +} | |
| 660 | +EXPORT_SYMBOL(qcom_scm_io_readl); | |
| 661 | + | |
| 662 | +int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) | |
| 663 | +{ | |
| 664 | + struct qcom_scm_desc desc = { | |
| 665 | + .svc = QCOM_SCM_SVC_IO, | |
| 666 | + .cmd = QCOM_SCM_IO_WRITE, | |
| 667 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 668 | + .args[0] = addr, | |
| 669 | + .args[1] = val, | |
| 670 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 671 | + }; | |
| 672 | + | |
| 673 | + | |
| 674 | + return qcom_scm_call(__scm->dev, &desc, NULL); | |
| 675 | +} | |
| 676 | +EXPORT_SYMBOL(qcom_scm_io_writel); | |
| 677 | + | |
| 370 | 678 | /** |
| 371 | 679 | * qcom_scm_restore_sec_cfg_available() - Check if secure environment |
| 372 | 680 | * supports restore security config interface. |
| @@ -376,108 +684,106 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = { · 3 unmodified lines | ||
| 376 | 684 | bool qcom_scm_restore_sec_cfg_available(void) |
| 377 | 685 | { |
| 378 | 686 | return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP, |
| 379 | − QCOM_SCM_RESTORE_SEC_CFG); | |
| 687 | + QCOM_SCM_MP_RESTORE_SEC_CFG); | |
| 380 | 688 | } |
| 381 | 689 | EXPORT_SYMBOL(qcom_scm_restore_sec_cfg_available); |
| 382 | 690 | |
| 383 | 691 | int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) |
| 384 | 692 | { |
| 385 | − return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare); | |
| 386 | −} | |
| 387 | −EXPORT_SYMBOL(qcom_scm_restore_sec_cfg); | |
| 388 | − | |
| 389 | −int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) | |
| 390 | −{ | |
| 391 | − return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size); | |
| 392 | −} | |
| 393 | −EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size); | |
| 394 | − | |
| 395 | −int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) | |
| 396 | −{ | |
| 397 | − return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare); | |
| 398 | −} | |
| 399 | −EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); | |
| 693 | + struct qcom_scm_desc desc = { | |
| 694 | + .svc = QCOM_SCM_SVC_MP, | |
| 695 | + .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG, | |
| 696 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 697 | + .args[0] = device_id, | |
| 698 | + .args[1] = spare, | |
| 699 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 700 | + }; | |
| 701 | + struct qcom_scm_res res; | |
| 702 | + int ret; | |
| 400 | 703 | |
| 401 | −int qcom_scm_qsmmu500_wait_safe_toggle(bool en) | |
| 402 | −{ | |
| 403 | − return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en); | |
| 404 | −} | |
| 405 | −EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle); | |
| 704 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 406 | 705 | |
| 407 | −int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) | |
| 408 | −{ | |
| 409 | − return __qcom_scm_io_readl(__scm->dev, addr, val); | |
| 706 | + return ret ? : res.result[0]; | |
| 410 | 707 | } |
| 411 | −EXPORT_SYMBOL(qcom_scm_io_readl); | |
| 708 | +EXPORT_SYMBOL(qcom_scm_restore_sec_cfg); | |
| 412 | 709 | |
| 413 | −int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) | |
| 710 | +int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) | |
| 414 | 711 | { |
| 415 | − return __qcom_scm_io_writel(__scm->dev, addr, val); | |
| 416 | −} | |
| 417 | −EXPORT_SYMBOL(qcom_scm_io_writel); | |
| 712 | + struct qcom_scm_desc desc = { | |
| 713 | + .svc = QCOM_SCM_SVC_MP, | |
| 714 | + .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE, | |
| 715 | + .arginfo = QCOM_SCM_ARGS(1), | |
| 716 | + .args[0] = spare, | |
| 717 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 718 | + }; | |
| 719 | + struct qcom_scm_res res; | |
| 720 | + int ret; | |
| 418 | 721 | |
| 419 | −static void qcom_scm_set_download_mode(bool enable) | |
| 420 | −{ | |
| 421 | − bool avail; | |
| 422 | − int ret = 0; | |
| 722 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 423 | 723 | |
| 424 | − avail = __qcom_scm_is_call_available(__scm->dev, | |
| 425 | − QCOM_SCM_SVC_BOOT, | |
| 426 | − QCOM_SCM_SET_DLOAD_MODE); | |
| 427 | − if (avail) { | |
| 428 | − ret = __qcom_scm_set_dload_mode(__scm->dev, enable); | |
| 429 | − } else if (__scm->dload_mode_addr) { | |
| 430 | − ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr, | |
| 431 | − enable ? QCOM_SCM_SET_DLOAD_MODE : 0); | |
| 432 | − } else { | |
| 433 | − dev_err(__scm->dev, | |
| 434 | − "No available mechanism for setting download mode\n"); | |
| 435 | − } | |
| 724 | + if (size) | |
| 725 | + *size = res.result[0]; | |
| 436 | 726 | |
| 437 | − if (ret) | |
| 438 | − dev_err(__scm->dev, "failed to set download mode: %d\n", ret); | |
| 727 | + return ret ? : res.result[1]; | |
| 439 | 728 | } |
| 729 | +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size); | |
| 440 | 730 | |
| 441 | −static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) | |
| 731 | +int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) | |
| 442 | 732 | { |
| 443 | − struct device_node *tcsr; | |
| 444 | − struct device_node *np = dev->of_node; | |
| 445 | − struct resource res; | |
| 446 | − u32 offset; | |
| 733 | + struct qcom_scm_desc desc = { | |
| 734 | + .svc = QCOM_SCM_SVC_MP, | |
| 735 | + .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT, | |
| 736 | + .arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, | |
| 737 | + QCOM_SCM_VAL), | |
| 738 | + .args[0] = addr, | |
| 739 | + .args[1] = size, | |
| 740 | + .args[2] = spare, | |
| 741 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 742 | + }; | |
| 447 | 743 | int ret; |
| 448 | 744 | |
| 449 | − tcsr = of_parse_phandle(np, "qcom,dload-mode", 0); | |
| 450 | − if (!tcsr) | |
| 451 | − return 0; | |
| 452 | − | |
| 453 | − ret = of_address_to_resource(tcsr, 0, &res); | |
| 454 | − of_node_put(tcsr); | |
| 455 | − if (ret) | |
| 456 | − return ret; | |
| 457 | − | |
| 458 | − ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset); | |
| 459 | − if (ret < 0) | |
| 460 | − return ret; | |
| 745 | + desc.args[0] = addr; | |
| 746 | + desc.args[1] = size; | |
| 747 | + desc.args[2] = spare; | |
| 748 | + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, | |
| 749 | + QCOM_SCM_VAL); | |
| 461 | 750 | |
| 462 | − *addr = res.start + offset; | |
| 751 | + ret = qcom_scm_call(__scm->dev, &desc, NULL); | |
| 463 | 752 | |
| 464 | − return 0; | |
| 465 | −} | |
| 753 | + /* the pg table has been initialized already, ignore the error */ | |
| 754 | + if (ret == -EPERM) | |
| 755 | + ret = 0; | |
| 466 | 756 | |
| 467 | −/** | |
| 468 | − * qcom_scm_is_available() - Checks if SCM is available | |
| 469 | − */ | |
| 470 | −bool qcom_scm_is_available(void) | |
| 471 | −{ | |
| 472 | − return !!__scm; | |
| 757 | + return ret; | |
| 473 | 758 | } |
| 474 | −EXPORT_SYMBOL(qcom_scm_is_available); | |
| 759 | +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); | |
| 475 | 760 | |
| 476 | −int qcom_scm_set_remote_state(u32 state, u32 id) | |
| 761 | +static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, | |
| 762 | + size_t mem_sz, phys_addr_t src, size_t src_sz, | |
| 763 | + phys_addr_t dest, size_t dest_sz) | |
| 477 | 764 | { |
| 478 | − return __qcom_scm_set_remote_state(__scm->dev, state, id); | |
| 765 | + int ret; | |
| 766 | + struct qcom_scm_desc desc = { | |
| 767 | + .svc = QCOM_SCM_SVC_MP, | |
| 768 | + .cmd = QCOM_SCM_MP_ASSIGN, | |
| 769 | + .arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL, | |
| 770 | + QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO, | |
| 771 | + QCOM_SCM_VAL, QCOM_SCM_VAL), | |
| 772 | + .args[0] = mem_region, | |
| 773 | + .args[1] = mem_sz, | |
| 774 | + .args[2] = src, | |
| 775 | + .args[3] = src_sz, | |
| 776 | + .args[4] = dest, | |
| 777 | + .args[5] = dest_sz, | |
| 778 | + .args[6] = 0, | |
| 779 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 780 | + }; | |
| 781 | + struct qcom_scm_res res; | |
| 782 | + | |
| 783 | + ret = qcom_scm_call(dev, &desc, &res); | |
| 784 | + | |
| 785 | + return ret ? : res.result[0]; | |
| 479 | 786 | } |
| 480 | −EXPORT_SYMBOL(qcom_scm_set_remote_state); | |
| 481 | 787 | |
| 482 | 788 | /** |
| 483 | 789 | * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership |
| @@ -561,6 +867,184 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, · 77 unmodified lines | ||
| 561 | 867 | } |
| 562 | 868 | EXPORT_SYMBOL(qcom_scm_assign_mem); |
| 563 | 869 | |
| 870 | +/** | |
| 871 | + * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available | |
| 872 | + */ | |
| 873 | +bool qcom_scm_ocmem_lock_available(void) | |
| 874 | +{ | |
| 875 | + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_OCMEM, | |
| 876 | + QCOM_SCM_OCMEM_LOCK_CMD); | |
| 877 | +} | |
| 878 | +EXPORT_SYMBOL(qcom_scm_ocmem_lock_available); | |
| 879 | + | |
| 880 | +/** | |
| 881 | + * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM | |
| 882 | + * region to the specified initiator | |
| 883 | + * | |
| 884 | + * @id: tz initiator id | |
| 885 | + * @offset: OCMEM offset | |
| 886 | + * @size: OCMEM size | |
| 887 | + * @mode: access mode (WIDE/NARROW) | |
| 888 | + */ | |
| 889 | +int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size, | |
| 890 | + u32 mode) | |
| 891 | +{ | |
| 892 | + struct qcom_scm_desc desc = { | |
| 893 | + .svc = QCOM_SCM_SVC_OCMEM, | |
| 894 | + .cmd = QCOM_SCM_OCMEM_LOCK_CMD, | |
| 895 | + .args[0] = id, | |
| 896 | + .args[1] = offset, | |
| 897 | + .args[2] = size, | |
| 898 | + .args[3] = mode, | |
| 899 | + .arginfo = QCOM_SCM_ARGS(4), | |
| 900 | + }; | |
| 901 | + | |
| 902 | + return qcom_scm_call(__scm->dev, &desc, NULL); | |
| 903 | +} | |
| 904 | +EXPORT_SYMBOL(qcom_scm_ocmem_lock); | |
| 905 | + | |
| 906 | +/** | |
| 907 | + * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM | |
| 908 | + * region from the specified initiator | |
| 909 | + * | |
| 910 | + * @id: tz initiator id | |
| 911 | + * @offset: OCMEM offset | |
| 912 | + * @size: OCMEM size | |
| 913 | + */ | |
| 914 | +int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size) | |
| 915 | +{ | |
| 916 | + struct qcom_scm_desc desc = { | |
| 917 | + .svc = QCOM_SCM_SVC_OCMEM, | |
| 918 | + .cmd = QCOM_SCM_OCMEM_UNLOCK_CMD, | |
| 919 | + .args[0] = id, | |
| 920 | + .args[1] = offset, | |
| 921 | + .args[2] = size, | |
| 922 | + .arginfo = QCOM_SCM_ARGS(3), | |
| 923 | + }; | |
| 924 | + | |
| 925 | + return qcom_scm_call(__scm->dev, &desc, NULL); | |
| 926 | +} | |
| 927 | +EXPORT_SYMBOL(qcom_scm_ocmem_unlock); | |
| 928 | + | |
| 929 | +/** | |
| 930 | + * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. | |
| 931 | + * | |
| 932 | + * Return true if HDCP is supported, false if not. | |
| 933 | + */ | |
| 934 | +bool qcom_scm_hdcp_available(void) | |
| 935 | +{ | |
| 936 | + int ret = qcom_scm_clk_enable(); | |
| 937 | + | |
| 938 | + if (ret) | |
| 939 | + return ret; | |
| 940 | + | |
| 941 | + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP, | |
| 942 | + QCOM_SCM_HDCP_INVOKE); | |
| 943 | + | |
| 944 | + qcom_scm_clk_disable(); | |
| 945 | + | |
| 946 | + return ret > 0 ? true : false; | |
| 947 | +} | |
| 948 | +EXPORT_SYMBOL(qcom_scm_hdcp_available); | |
| 949 | + | |
| 950 | +/** | |
| 951 | + * qcom_scm_hdcp_req() - Send HDCP request. | |
| 952 | + * @req: HDCP request array | |
| 953 | + * @req_cnt: HDCP request array count | |
| 954 | + * @resp: response buffer passed to SCM | |
| 955 | + * | |
| 956 | + * Write HDCP register(s) through SCM. | |
| 957 | + */ | |
| 958 | +int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) | |
| 959 | +{ | |
| 960 | + int ret; | |
| 961 | + struct qcom_scm_desc desc = { | |
| 962 | + .svc = QCOM_SCM_SVC_HDCP, | |
| 963 | + .cmd = QCOM_SCM_HDCP_INVOKE, | |
| 964 | + .arginfo = QCOM_SCM_ARGS(10), | |
| 965 | + .args = { | |
| 966 | + req[0].addr, | |
| 967 | + req[0].val, | |
| 968 | + req[1].addr, | |
| 969 | + req[1].val, | |
| 970 | + req[2].addr, | |
| 971 | + req[2].val, | |
| 972 | + req[3].addr, | |
| 973 | + req[3].val, | |
| 974 | + req[4].addr, | |
| 975 | + req[4].val | |
| 976 | + }, | |
| 977 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 978 | + }; | |
| 979 | + struct qcom_scm_res res; | |
| 980 | + | |
| 981 | + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT) | |
| 982 | + return -ERANGE; | |
| 983 | + | |
| 984 | + ret = qcom_scm_clk_enable(); | |
| 985 | + if (ret) | |
| 986 | + return ret; | |
| 987 | + | |
| 988 | + ret = qcom_scm_call(__scm->dev, &desc, &res); | |
| 989 | + *resp = res.result[0]; | |
| 990 | + | |
| 991 | + qcom_scm_clk_disable(); | |
| 992 | + | |
| 993 | + return ret; | |
| 994 | +} | |
| 995 | +EXPORT_SYMBOL(qcom_scm_hdcp_req); | |
| 996 | + | |
| 997 | +int qcom_scm_qsmmu500_wait_safe_toggle(bool en) | |
| 998 | +{ | |
| 999 | + struct qcom_scm_desc desc = { | |
| 1000 | + .svc = QCOM_SCM_SVC_SMMU_PROGRAM, | |
| 1001 | + .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1, | |
| 1002 | + .arginfo = QCOM_SCM_ARGS(2), | |
| 1003 | + .args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL, | |
| 1004 | + .args[1] = en, | |
| 1005 | + .owner = ARM_SMCCC_OWNER_SIP, | |
| 1006 | + }; | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + return qcom_scm_call_atomic(__scm->dev, &desc, NULL); | |
| 1010 | +} | |
| 1011 | +EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle); | |
| 1012 | + | |
| 1013 | +static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) | |
| 1014 | +{ | |
| 1015 | + struct device_node *tcsr; | |
| 1016 | + struct device_node *np = dev->of_node; | |
| 1017 | + struct resource res; | |
| 1018 | + u32 offset; | |
| 1019 | + int ret; | |
| 1020 | + | |
| 1021 | + tcsr = of_parse_phandle(np, "qcom,dload-mode", 0); | |
| 1022 | + if (!tcsr) | |
| 1023 | + return 0; | |
| 1024 | + | |
| 1025 | + ret = of_address_to_resource(tcsr, 0, &res); | |
| 1026 | + of_node_put(tcsr); | |
| 1027 | + if (ret) | |
| 1028 | + return ret; | |
| 1029 | + | |
| 1030 | + ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset); | |
| 1031 | + if (ret < 0) | |
| 1032 | + return ret; | |
| 1033 | + | |
| 1034 | + *addr = res.start + offset; | |
| 1035 | + | |
| 1036 | + return 0; | |
| 1037 | +} | |
| 1038 | + | |
| 1039 | +/** | |
| 1040 | + * qcom_scm_is_available() - Checks if SCM is available | |
| 1041 | + */ | |
| 1042 | +bool qcom_scm_is_available(void) | |
| 1043 | +{ | |
| 1044 | + return !!__scm; | |
| 1045 | +} | |
| 1046 | +EXPORT_SYMBOL(qcom_scm_is_available); | |
| 1047 | + | |
| 564 | 1048 | static int qcom_scm_probe(struct platform_device *pdev) |
| 565 | 1049 | { |
| 566 | 1050 | struct qcom_scm *scm; |
| @@ -631,7 +1115,7 @@ static int qcom_scm_probe(struct platform_device *pdev) · 64 unmodified lines | ||
| 631 | 1115 | __scm = scm; |
| 632 | 1116 | __scm->dev = &pdev->dev; |
| 633 | 1117 | |
| 634 | − __qcom_scm_init(); | |
| 1118 | + __query_convention(); | |
| 635 | 1119 | |
| 636 | 1120 | /* |
| 637 | 1121 | * If requested enable "download mode", from this point on warmboot |
| @@ -1,71 +1,116 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | −/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. | |
| 2 | +/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved. | |
| 3 | 3 | */ |
| 4 | 4 | #ifndef __QCOM_SCM_INT_H |
| 5 | 5 | #define __QCOM_SCM_INT_H |
| 6 | 6 | |
| 7 | −#define QCOM_SCM_SVC_BOOT 0x1 | |
| 8 | −#define QCOM_SCM_BOOT_ADDR 0x1 | |
| 9 | −#define QCOM_SCM_SET_DLOAD_MODE 0x10 | |
| 10 | −#define QCOM_SCM_BOOT_ADDR_MC 0x11 | |
| 11 | −#define QCOM_SCM_SET_REMOTE_STATE 0xa | |
| 12 | −extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id); | |
| 13 | −extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable); | |
| 14 | − | |
| 15 | −#define QCOM_SCM_FLAG_HLOS 0x01 | |
| 16 | −#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02 | |
| 17 | −#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04 | |
| 18 | −extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, | |
| 19 | − const cpumask_t *cpus); | |
| 20 | −extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); | |
| 21 | − | |
| 22 | −#define QCOM_SCM_CMD_TERMINATE_PC 0x2 | |
| 7 | +enum qcom_scm_convention { | |
| 8 | + SMC_CONVENTION_UNKNOWN, | |
| 9 | + SMC_CONVENTION_LEGACY, | |
| 10 | + SMC_CONVENTION_ARM_32, | |
| 11 | + SMC_CONVENTION_ARM_64, | |
| 12 | +}; | |
| 13 | + | |
| 14 | +extern enum qcom_scm_convention qcom_scm_convention; | |
| 15 | + | |
| 16 | +#define MAX_QCOM_SCM_ARGS 10 | |
| 17 | +#define MAX_QCOM_SCM_RETS 3 | |
| 18 | + | |
| 19 | +enum qcom_scm_arg_types { | |
| 20 | + QCOM_SCM_VAL, | |
| 21 | + QCOM_SCM_RO, | |
| 22 | + QCOM_SCM_RW, | |
| 23 | + QCOM_SCM_BUFVAL, | |
| 24 | +}; | |
| 25 | + | |
| 26 | +#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\ | |
| 27 | + (((a) & 0x3) << 4) | \ | |
| 28 | + (((b) & 0x3) << 6) | \ | |
| 29 | + (((c) & 0x3) << 8) | \ | |
| 30 | + (((d) & 0x3) << 10) | \ | |
| 31 | + (((e) & 0x3) << 12) | \ | |
| 32 | + (((f) & 0x3) << 14) | \ | |
| 33 | + (((g) & 0x3) << 16) | \ | |
| 34 | + (((h) & 0x3) << 18) | \ | |
| 35 | + (((i) & 0x3) << 20) | \ | |
| 36 | + (((j) & 0x3) << 22) | \ | |
| 37 | + ((num) & 0xf)) | |
| 38 | + | |
| 39 | +#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
| 40 | + | |
| 41 | + | |
| 42 | +/** | |
| 43 | + * struct qcom_scm_desc | |
| 44 | + * @arginfo: Metadata describing the arguments in args[] | |
| 45 | + * @args: The array of arguments for the secure syscall | |
| 46 | + */ | |
| 47 | +struct qcom_scm_desc { | |
| 48 | + u32 svc; | |
| 49 | + u32 cmd; | |
| 50 | + u32 arginfo; | |
| 51 | + u64 args[MAX_QCOM_SCM_ARGS]; | |
| 52 | + u32 owner; | |
| 53 | +}; | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * struct qcom_scm_res | |
| 57 | + * @result: The values returned by the secure syscall | |
| 58 | + */ | |
| 59 | +struct qcom_scm_res { | |
| 60 | + u64 result[MAX_QCOM_SCM_RETS]; | |
| 61 | +}; | |
| 62 | + | |
| 63 | +#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) | |
| 64 | +extern int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, | |
| 65 | + struct qcom_scm_res *res, bool atomic); | |
| 66 | + | |
| 67 | +#define SCM_LEGACY_FNID(s, c) (((s) << 10) | ((c) & 0x3ff)) | |
| 68 | +extern int scm_legacy_call_atomic(struct device *dev, | |
| 69 | + const struct qcom_scm_desc *desc, | |
| 70 | + struct qcom_scm_res *res); | |
| 71 | +extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, | |
| 72 | + struct qcom_scm_res *res); | |
| 73 | + | |
| 74 | +#define QCOM_SCM_SVC_BOOT 0x01 | |
| 75 | +#define QCOM_SCM_BOOT_SET_ADDR 0x01 | |
| 76 | +#define QCOM_SCM_BOOT_TERMINATE_PC 0x02 | |
| 77 | +#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10 | |
| 78 | +#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a | |
| 23 | 79 | #define QCOM_SCM_FLUSH_FLAG_MASK 0x3 |
| 24 | −#define QCOM_SCM_CMD_CORE_HOTPLUGGED 0x10 | |
| 25 | −extern void __qcom_scm_cpu_power_down(u32 flags); | |
| 26 | 80 | |
| 27 | −#define QCOM_SCM_SVC_IO 0x5 | |
| 28 | −#define QCOM_SCM_IO_READ 0x1 | |
| 29 | −#define QCOM_SCM_IO_WRITE 0x2 | |
| 30 | −extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val); | |
| 31 | −extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val); | |
| 81 | +#define QCOM_SCM_SVC_PIL 0x02 | |
| 82 | +#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01 | |
| 83 | +#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02 | |
| 84 | +#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05 | |
| 85 | +#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06 | |
| 86 | +#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07 | |
| 87 | +#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a | |
| 88 | + | |
| 89 | +#define QCOM_SCM_SVC_IO 0x05 | |
| 90 | +#define QCOM_SCM_IO_READ 0x01 | |
| 91 | +#define QCOM_SCM_IO_WRITE 0x02 | |
| 92 | + | |
| 93 | +#define QCOM_SCM_SVC_INFO 0x06 | |
| 94 | +#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01 | |
| 32 | 95 | |
| 33 | −#define QCOM_SCM_SVC_INFO 0x6 | |
| 34 | −#define QCOM_IS_CALL_AVAIL_CMD 0x1 | |
| 35 | −extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, | |
| 36 | − u32 cmd_id); | |
| 96 | +#define QCOM_SCM_SVC_MP 0x0c | |
| 97 | +#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02 | |
| 98 | +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03 | |
| 99 | +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04 | |
| 100 | +#define QCOM_SCM_MP_ASSIGN 0x16 | |
| 101 | + | |
| 102 | +#define QCOM_SCM_SVC_OCMEM 0x0f | |
| 103 | +#define QCOM_SCM_OCMEM_LOCK_CMD 0x01 | |
| 104 | +#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x02 | |
| 37 | 105 | |
| 38 | 106 | #define QCOM_SCM_SVC_HDCP 0x11 |
| 39 | −#define QCOM_SCM_CMD_HDCP 0x01 | |
| 40 | −extern int __qcom_scm_hdcp_req(struct device *dev, | |
| 41 | − struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp); | |
| 107 | +#define QCOM_SCM_HDCP_INVOKE 0x01 | |
| 42 | 108 | |
| 43 | −extern void __qcom_scm_init(void); | |
| 109 | +#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 | |
| 110 | +#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03 | |
| 111 | +#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02 | |
| 44 | 112 | |
| 45 | −#define QCOM_SCM_OCMEM_SVC 0xf | |
| 46 | −#define QCOM_SCM_OCMEM_LOCK_CMD 0x1 | |
| 47 | −#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x2 | |
| 48 | − | |
| 49 | −extern int __qcom_scm_ocmem_lock(struct device *dev, u32 id, u32 offset, | |
| 50 | − u32 size, u32 mode); | |
| 51 | −extern int __qcom_scm_ocmem_unlock(struct device *dev, u32 id, u32 offset, | |
| 52 | − u32 size); | |
| 53 | − | |
| 54 | −#define QCOM_SCM_SVC_PIL 0x2 | |
| 55 | −#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1 | |
| 56 | −#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2 | |
| 57 | −#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5 | |
| 58 | −#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6 | |
| 59 | −#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7 | |
| 60 | −#define QCOM_SCM_PAS_MSS_RESET 0xa | |
| 61 | −extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral); | |
| 62 | −extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, | |
| 63 | − dma_addr_t metadata_phys); | |
| 64 | −extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, | |
| 65 | − phys_addr_t addr, phys_addr_t size); | |
| 66 | −extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral); | |
| 67 | −extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral); | |
| 68 | −extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset); | |
| 113 | +extern void __qcom_scm_init(void); | |
| 69 | 114 | |
| 70 | 115 | /* common error codes */ |
| 71 | 116 | #define QCOM_SCM_V2_EBUSY -12 |
| @@ -94,25 +139,4 @@ static inline int qcom_scm_remap_error(int err) · 22 unmodified lines | ||
| 94 | 139 | return -EINVAL; |
| 95 | 140 | } |
| 96 | 141 | |
| 97 | −#define QCOM_SCM_SVC_MP 0xc | |
| 98 | −#define QCOM_SCM_RESTORE_SEC_CFG 2 | |
| 99 | −extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, | |
| 100 | − u32 spare); | |
| 101 | −#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3 | |
| 102 | −#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4 | |
| 103 | −#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 | |
| 104 | −#define QCOM_SCM_CONFIG_ERRATA1 0x3 | |
| 105 | −#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2 | |
| 106 | −extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, | |
| 107 | − size_t *size); | |
| 108 | −extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, | |
| 109 | − u32 size, u32 spare); | |
| 110 | −extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, | |
| 111 | − bool enable); | |
| 112 | −#define QCOM_MEM_PROT_ASSIGN_ID 0x16 | |
| 113 | −extern int __qcom_scm_assign_mem(struct device *dev, | |
| 114 | − phys_addr_t mem_region, size_t mem_sz, | |
| 115 | − phys_addr_t src, size_t src_sz, | |
| 116 | − phys_addr_t dest, size_t dest_sz); | |
| 117 | − | |
| 118 | 142 | #endif |
| @@ -45,13 +45,13 @@ config QCOM_GLINK_SSR · 44 unmodified lines | ||
| 45 | 45 | neighboring subsystems going up or down. |
| 46 | 46 | |
| 47 | 47 | config QCOM_GSBI |
| 48 | − tristate "QCOM General Serial Bus Interface" | |
| 49 | − depends on ARCH_QCOM || COMPILE_TEST | |
| 50 | − select MFD_SYSCON | |
| 51 | − help | |
| 52 | − Say y here to enable GSBI support. The GSBI provides control | |
| 53 | − functions for connecting the underlying serial UART, SPI, and I2C | |
| 54 | − devices to the output pins. | |
| 48 | + tristate "QCOM General Serial Bus Interface" | |
| 49 | + depends on ARCH_QCOM || COMPILE_TEST | |
| 50 | + select MFD_SYSCON | |
| 51 | + help | |
| 52 | + Say y here to enable GSBI support. The GSBI provides control | |
| 53 | + functions for connecting the underlying serial UART, SPI, and I2C | |
| 54 | + devices to the output pins. | |
| 55 | 55 | |
| 56 | 56 | config QCOM_LLCC |
| 57 | 57 | tristate "Qualcomm Technologies, Inc. LLCC driver" |
| @@ -71,10 +71,10 @@ config QCOM_OCMEM · 13 unmodified lines | ||
| 71 | 71 | depends on ARCH_QCOM |
| 72 | 72 | select QCOM_SCM |
| 73 | 73 | help |
| 74 | − The On Chip Memory (OCMEM) allocator allows various clients to | |
| 75 | − allocate memory from OCMEM based on performance, latency and power | |
| 76 | − requirements. This is typically used by the GPU, camera/video, and | |
| 77 | − audio components on some Snapdragon SoCs. | |
| 74 | + The On Chip Memory (OCMEM) allocator allows various clients to | |
| 75 | + allocate memory from OCMEM based on performance, latency and power | |
| 76 | + requirements. This is typically used by the GPU, camera/video, and | |
| 77 | + audio components on some Snapdragon SoCs. | |
| 78 | 78 | |
| 79 | 79 | config QCOM_PM |
| 80 | 80 | bool "Qualcomm Power Management" |
| @@ -198,8 +198,8 @@ config QCOM_APR · 117 unmodified lines | ||
| 198 | 198 | depends on ARCH_QCOM || COMPILE_TEST |
| 199 | 199 | depends on RPMSG |
| 200 | 200 | help |
| 201 | − Enable APR IPC protocol support between | |
| 202 | − application processor and QDSP6. APR is | |
| 203 | − used by audio driver to configure QDSP6 | |
| 204 | − ASM, ADM and AFE modules. | |
| 201 | + Enable APR IPC protocol support between | |
| 202 | + application processor and QDSP6. APR is | |
| 203 | + used by audio driver to configure QDSP6 | |
| 204 | + ASM, ADM and AFE modules. | |
| 205 | 205 | endmenu |
| @@ -655,8 +655,12 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size, · 654 unmodified lines | ||
| 655 | 655 | |
| 656 | 656 | qmi->sock = qmi_sock_create(qmi, &qmi->sq); |
| 657 | 657 | if (IS_ERR(qmi->sock)) { |
| 658 | − pr_err("failed to create QMI socket\n"); | |
| 659 | − ret = PTR_ERR(qmi->sock); | |
| 658 | + if (PTR_ERR(qmi->sock) == -EAFNOSUPPORT) { | |
| 659 | + ret = -EPROBE_DEFER; | |
| 660 | + } else { | |
| 661 | + pr_err("failed to create QMI socket\n"); | |
| 662 | + ret = PTR_ERR(qmi->sock); | |
| 663 | + } | |
| 660 | 664 | goto err_destroy_wq; |
| 661 | 665 | } |
| 662 | 666 | |
| @@ -93,6 +93,7 @@ static struct rpmhpd sdm845_mx = { · 92 unmodified lines | ||
| 93 | 93 | |
| 94 | 94 | static struct rpmhpd sdm845_mx_ao = { |
| 95 | 95 | .pd = { .name = "mx_ao", }, |
| 96 | + .active_only = true, | |
| 96 | 97 | .peer = &sdm845_mx, |
| 97 | 98 | .res_name = "mx.lvl", |
| 98 | 99 | }; |
| @@ -107,6 +108,7 @@ static struct rpmhpd sdm845_cx = { · 8 unmodified lines | ||
| 107 | 108 | |
| 108 | 109 | static struct rpmhpd sdm845_cx_ao = { |
| 109 | 110 | .pd = { .name = "cx_ao", }, |
| 111 | + .active_only = true, | |
| 110 | 112 | .peer = &sdm845_cx, |
| 111 | 113 | .parent = &sdm845_mx_ao.pd, |
| 112 | 114 | .res_name = "cx.lvl", |
| @@ -129,8 +131,62 @@ static const struct rpmhpd_desc sdm845_desc = { · 16 unmodified lines | ||
| 129 | 131 | .num_pds = ARRAY_SIZE(sdm845_rpmhpds), |
| 130 | 132 | }; |
| 131 | 133 | |
| 134 | +/* SM8150 RPMH powerdomains */ | |
| 135 | + | |
| 136 | +static struct rpmhpd sm8150_mmcx_ao; | |
| 137 | +static struct rpmhpd sm8150_mmcx = { | |
| 138 | + .pd = { .name = "mmcx", }, | |
| 139 | + .peer = &sm8150_mmcx_ao, | |
| 140 | + .res_name = "mmcx.lvl", | |
| 141 | +}; | |
| 142 | + | |
| 143 | +static struct rpmhpd sm8150_mmcx_ao = { | |
| 144 | + .pd = { .name = "mmcx_ao", }, | |
| 145 | + .active_only = true, | |
| 146 | + .peer = &sm8150_mmcx, | |
| 147 | + .res_name = "mmcx.lvl", | |
| 148 | +}; | |
| 149 | + | |
| 150 | +static struct rpmhpd *sm8150_rpmhpds[] = { | |
| 151 | + [SM8150_MSS] = &sdm845_mss, | |
| 152 | + [SM8150_EBI] = &sdm845_ebi, | |
| 153 | + [SM8150_LMX] = &sdm845_lmx, | |
| 154 | + [SM8150_LCX] = &sdm845_lcx, | |
| 155 | + [SM8150_GFX] = &sdm845_gfx, | |
| 156 | + [SM8150_MX] = &sdm845_mx, | |
| 157 | + [SM8150_MX_AO] = &sdm845_mx_ao, | |
| 158 | + [SM8150_CX] = &sdm845_cx, | |
| 159 | + [SM8150_CX_AO] = &sdm845_cx_ao, | |
| 160 | + [SM8150_MMCX] = &sm8150_mmcx, | |
| 161 | + [SM8150_MMCX_AO] = &sm8150_mmcx_ao, | |
| 162 | +}; | |
| 163 | + | |
| 164 | +static const struct rpmhpd_desc sm8150_desc = { | |
| 165 | + .rpmhpds = sm8150_rpmhpds, | |
| 166 | + .num_pds = ARRAY_SIZE(sm8150_rpmhpds), | |
| 167 | +}; | |
| 168 | + | |
| 169 | +/* SC7180 RPMH powerdomains */ | |
| 170 | +static struct rpmhpd *sc7180_rpmhpds[] = { | |
| 171 | + [SC7180_CX] = &sdm845_cx, | |
| 172 | + [SC7180_CX_AO] = &sdm845_cx_ao, | |
| 173 | + [SC7180_GFX] = &sdm845_gfx, | |
| 174 | + [SC7180_MX] = &sdm845_mx, | |
| 175 | + [SC7180_MX_AO] = &sdm845_mx_ao, | |
| 176 | + [SC7180_LMX] = &sdm845_lmx, | |
| 177 | + [SC7180_LCX] = &sdm845_lcx, | |
| 178 | + [SC7180_MSS] = &sdm845_mss, | |
| 179 | +}; | |
| 180 | + | |
| 181 | +static const struct rpmhpd_desc sc7180_desc = { | |
| 182 | + .rpmhpds = sc7180_rpmhpds, | |
| 183 | + .num_pds = ARRAY_SIZE(sc7180_rpmhpds), | |
| 184 | +}; | |
| 185 | + | |
| 132 | 186 | static const struct of_device_id rpmhpd_match_table[] = { |
| 187 | + { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, | |
| 133 | 188 | { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, |
| 189 | + { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, | |
| 134 | 190 | { } |
| 135 | 191 | }; |
| 136 | 192 | |
| @@ -15,12 +15,36 @@ · 14 unmodified lines | ||
| 15 | 15 | #define SDM845_GFX 7 |
| 16 | 16 | #define SDM845_MSS 8 |
| 17 | 17 | |
| 18 | +/* SM8150 Power Domain Indexes */ | |
| 19 | +#define SM8150_MSS 0 | |
| 20 | +#define SM8150_EBI 1 | |
| 21 | +#define SM8150_LMX 2 | |
| 22 | +#define SM8150_LCX 3 | |
| 23 | +#define SM8150_GFX 4 | |
| 24 | +#define SM8150_MX 5 | |
| 25 | +#define SM8150_MX_AO 6 | |
| 26 | +#define SM8150_CX 7 | |
| 27 | +#define SM8150_CX_AO 8 | |
| 28 | +#define SM8150_MMCX 9 | |
| 29 | +#define SM8150_MMCX_AO 10 | |
| 30 | + | |
| 31 | +/* SC7180 Power Domain Indexes */ | |
| 32 | +#define SC7180_CX 0 | |
| 33 | +#define SC7180_CX_AO 1 | |
| 34 | +#define SC7180_GFX 2 | |
| 35 | +#define SC7180_MX 3 | |
| 36 | +#define SC7180_MX_AO 4 | |
| 37 | +#define SC7180_LMX 5 | |
| 38 | +#define SC7180_LCX 6 | |
| 39 | +#define SC7180_MSS 7 | |
| 40 | + | |
| 18 | 41 | /* SDM845 Power Domain performance levels */ |
| 19 | 42 | #define RPMH_REGULATOR_LEVEL_RETENTION 16 |
| 20 | 43 | #define RPMH_REGULATOR_LEVEL_MIN_SVS 48 |
| 21 | 44 | #define RPMH_REGULATOR_LEVEL_LOW_SVS 64 |
| 22 | 45 | #define RPMH_REGULATOR_LEVEL_SVS 128 |
| 23 | 46 | #define RPMH_REGULATOR_LEVEL_SVS_L1 192 |
| 47 | +#define RPMH_REGULATOR_LEVEL_SVS_L2 224 | |
| 24 | 48 | #define RPMH_REGULATOR_LEVEL_NOM 256 |
| 25 | 49 | #define RPMH_REGULATOR_LEVEL_NOM_L1 320 |
| 26 | 50 | #define RPMH_REGULATOR_LEVEL_NOM_L2 336 |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | −/* Copyright (c) 2010-2015, 2018, The Linux Foundation. All rights reserved. | |
| 2 | +/* Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved. | |
| 3 | 3 | * Copyright (C) 2015 Linaro Ltd. |
| 4 | 4 | */ |
| 5 | 5 | #ifndef __QCOM_SCM_H |
| @@ -55,77 +55,94 @@ enum qcom_scm_sec_dev_id { · 49 unmodified lines | ||
| 55 | 55 | #define QCOM_SCM_PERM_RWX (QCOM_SCM_PERM_RW | QCOM_SCM_PERM_EXEC) |
| 56 | 56 | |
| 57 | 57 | #if IS_ENABLED(CONFIG_QCOM_SCM) |
| 58 | +extern bool qcom_scm_is_available(void); | |
| 59 | + | |
| 58 | 60 | extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); |
| 59 | 61 | extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); |
| 60 | −extern bool qcom_scm_is_available(void); | |
| 61 | −extern bool qcom_scm_hdcp_available(void); | |
| 62 | −extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, | |
| 63 | − u32 *resp); | |
| 64 | −extern bool qcom_scm_ocmem_lock_available(void); | |
| 65 | −extern int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, | |
| 66 | − u32 size, u32 mode); | |
| 67 | −extern int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, | |
| 68 | − u32 size); | |
| 69 | −extern bool qcom_scm_pas_supported(u32 peripheral); | |
| 62 | +extern void qcom_scm_cpu_power_down(u32 flags); | |
| 63 | +extern int qcom_scm_set_remote_state(u32 state, u32 id); | |
| 64 | + | |
| 70 | 65 | extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, |
| 71 | 66 | size_t size); |
| 72 | 67 | extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, |
| 73 | 68 | phys_addr_t size); |
| 74 | 69 | extern int qcom_scm_pas_auth_and_reset(u32 peripheral); |
| 75 | 70 | extern int qcom_scm_pas_shutdown(u32 peripheral); |
| 76 | −extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, | |
| 77 | − unsigned int *src, | |
| 78 | − const struct qcom_scm_vmperm *newvm, | |
| 79 | − unsigned int dest_cnt); | |
| 80 | −extern void qcom_scm_cpu_power_down(u32 flags); | |
| 81 | −extern u32 qcom_scm_get_version(void); | |
| 82 | −extern int qcom_scm_set_remote_state(u32 state, u32 id); | |
| 71 | +extern bool qcom_scm_pas_supported(u32 peripheral); | |
| 72 | + | |
| 73 | +extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); | |
| 74 | +extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); | |
| 75 | + | |
| 83 | 76 | extern bool qcom_scm_restore_sec_cfg_available(void); |
| 84 | 77 | extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare); |
| 85 | 78 | extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size); |
| 86 | 79 | extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare); |
| 80 | +extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, | |
| 81 | + unsigned int *src, | |
| 82 | + const struct qcom_scm_vmperm *newvm, | |
| 83 | + unsigned int dest_cnt); | |
| 84 | + | |
| 85 | +extern bool qcom_scm_ocmem_lock_available(void); | |
| 86 | +extern int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, | |
| 87 | + u32 size, u32 mode); | |
| 88 | +extern int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, | |
| 89 | + u32 size); | |
| 90 | + | |
| 91 | +extern bool qcom_scm_hdcp_available(void); | |
| 92 | +extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, | |
| 93 | + u32 *resp); | |
| 94 | + | |
| 87 | 95 | extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en); |
| 88 | −extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); | |
| 89 | −extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); | |
| 90 | 96 | #else |
| 91 | 97 | |
| 92 | 98 | #include <linux/errno.h> |
| 93 | 99 | |
| 94 | −static inline | |
| 95 | −int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |
| 96 | −{ | |
| 97 | − return -ENODEV; | |
| 98 | −} | |
| 99 | −static inline | |
| 100 | −int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) | |
| 101 | −{ | |
| 102 | − return -ENODEV; | |
| 103 | −} | |
| 104 | 100 | static inline bool qcom_scm_is_available(void) { return false; } |
| 105 | −static inline bool qcom_scm_hdcp_available(void) { return false; } | |
| 106 | −static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, | |
| 107 | − u32 *resp) { return -ENODEV; } | |
| 108 | −static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; } | |
| 101 | + | |
| 102 | +static inline int qcom_scm_set_cold_boot_addr(void *entry, | |
| 103 | + const cpumask_t *cpus) { return -ENODEV; } | |
| 104 | +static inline int qcom_scm_set_warm_boot_addr(void *entry, | |
| 105 | + const cpumask_t *cpus) { return -ENODEV; } | |
| 106 | +static inline void qcom_scm_cpu_power_down(u32 flags) {} | |
| 107 | +static inline u32 qcom_scm_set_remote_state(u32 state,u32 id) | |
| 108 | + { return -ENODEV; } | |
| 109 | + | |
| 109 | 110 | static inline int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, |
| 110 | − size_t size) { return -ENODEV; } | |
| 111 | + size_t size) { return -ENODEV; } | |
| 111 | 112 | static inline int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, |
| 112 | − phys_addr_t size) { return -ENODEV; } | |
| 113 | −static inline int | |
| 114 | −qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; } | |
| 113 | + phys_addr_t size) { return -ENODEV; } | |
| 114 | +static inline int qcom_scm_pas_auth_and_reset(u32 peripheral) | |
| 115 | + { return -ENODEV; } | |
| 115 | 116 | static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; } |
| 117 | +static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; } | |
| 118 | + | |
| 119 | +static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) | |
| 120 | + { return -ENODEV; } | |
| 121 | +static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) | |
| 122 | + { return -ENODEV; } | |
| 123 | + | |
| 124 | +static inline bool qcom_scm_restore_sec_cfg_available(void) { return false; } | |
| 125 | +static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) | |
| 126 | + { return -ENODEV; } | |
| 127 | +static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) | |
| 128 | + { return -ENODEV; } | |
| 129 | +static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) | |
| 130 | + { return -ENODEV; } | |
| 116 | 131 | static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, |
| 117 | − unsigned int *src, | |
| 118 | − const struct qcom_scm_vmperm *newvm, | |
| 119 | − unsigned int dest_cnt) { return -ENODEV; } | |
| 120 | −static inline void qcom_scm_cpu_power_down(u32 flags) {} | |
| 121 | −static inline u32 qcom_scm_get_version(void) { return 0; } | |
| 122 | −static inline u32 | |
| 123 | −qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; } | |
| 124 | −static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; } | |
| 125 | −static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; } | |
| 126 | −static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; } | |
| 127 | −static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; } | |
| 128 | −static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; } | |
| 129 | −static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; } | |
| 132 | + unsigned int *src, const struct qcom_scm_vmperm *newvm, | |
| 133 | + unsigned int dest_cnt) { return -ENODEV; } | |
| 134 | + | |
| 135 | +static inline bool qcom_scm_ocmem_lock_available(void) { return false; } | |
| 136 | +static inline int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, | |
| 137 | + u32 size, u32 mode) { return -ENODEV; } | |
| 138 | +static inline int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, | |
| 139 | + u32 offset, u32 size) { return -ENODEV; } | |
| 140 | + | |
| 141 | +static inline bool qcom_scm_hdcp_available(void) { return false; } | |
| 142 | +static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, | |
| 143 | + u32 *resp) { return -ENODEV; } | |
| 144 | + | |
| 145 | +static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) | |
| 146 | + { return -ENODEV; } | |
| 130 | 147 | #endif |
| 131 | 148 | #endif |