linux/drivers/firmware/qcom_scm-64.c
<<
>>
Prefs
   1/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
   2 *
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License version 2 and
   5 * only version 2 as published by the Free Software Foundation.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 */
  12
  13#include <linux/io.h>
  14#include <linux/errno.h>
  15#include <linux/delay.h>
  16#include <linux/mutex.h>
  17#include <linux/slab.h>
  18#include <linux/types.h>
  19#include <linux/qcom_scm.h>
  20#include <linux/arm-smccc.h>
  21#include <linux/dma-mapping.h>
  22
  23#include "qcom_scm.h"
  24
  25#define QCOM_SCM_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
  26
  27#define MAX_QCOM_SCM_ARGS 10
  28#define MAX_QCOM_SCM_RETS 3
  29
  30enum qcom_scm_arg_types {
  31        QCOM_SCM_VAL,
  32        QCOM_SCM_RO,
  33        QCOM_SCM_RW,
  34        QCOM_SCM_BUFVAL,
  35};
  36
  37#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
  38                           (((a) & 0x3) << 4) | \
  39                           (((b) & 0x3) << 6) | \
  40                           (((c) & 0x3) << 8) | \
  41                           (((d) & 0x3) << 10) | \
  42                           (((e) & 0x3) << 12) | \
  43                           (((f) & 0x3) << 14) | \
  44                           (((g) & 0x3) << 16) | \
  45                           (((h) & 0x3) << 18) | \
  46                           (((i) & 0x3) << 20) | \
  47                           (((j) & 0x3) << 22) | \
  48                           ((num) & 0xf))
  49
  50#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
  51
  52/**
  53 * struct qcom_scm_desc
  54 * @arginfo:    Metadata describing the arguments in args[]
  55 * @args:       The array of arguments for the secure syscall
  56 * @res:        The values returned by the secure syscall
  57 */
  58struct qcom_scm_desc {
  59        u32 arginfo;
  60        u64 args[MAX_QCOM_SCM_ARGS];
  61};
  62
  63static u64 qcom_smccc_convention = -1;
  64static DEFINE_MUTEX(qcom_scm_lock);
  65
  66#define QCOM_SCM_EBUSY_WAIT_MS 30
  67#define QCOM_SCM_EBUSY_MAX_RETRY 20
  68
  69#define N_EXT_QCOM_SCM_ARGS 7
  70#define FIRST_EXT_ARG_IDX 3
  71#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
  72
  73/**
  74 * qcom_scm_call() - Invoke a syscall in the secure world
  75 * @dev:        device
  76 * @svc_id:     service identifier
  77 * @cmd_id:     command identifier
  78 * @desc:       Descriptor structure containing arguments and return values
  79 *
  80 * Sends a command to the SCM and waits for the command to finish processing.
  81 * This should *only* be called in pre-emptible context.
  82*/
  83static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
  84                         const struct qcom_scm_desc *desc,
  85                         struct arm_smccc_res *res)
  86{
  87        int arglen = desc->arginfo & 0xf;
  88        int retry_count = 0, i;
  89        u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
  90        u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX];
  91        dma_addr_t args_phys = 0;
  92        void *args_virt = NULL;
  93        size_t alloc_len;
  94        struct arm_smccc_quirk quirk = {.id = ARM_SMCCC_QUIRK_QCOM_A6};
  95
  96        if (unlikely(arglen > N_REGISTER_ARGS)) {
  97                alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
  98                args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
  99
 100                if (!args_virt)
 101                        return -ENOMEM;
 102
 103                if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
 104                        __le32 *args = args_virt;
 105
 106                        for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
 107                                args[i] = cpu_to_le32(desc->args[i +
 108                                                      FIRST_EXT_ARG_IDX]);
 109                } else {
 110                        __le64 *args = args_virt;
 111
 112                        for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
 113                                args[i] = cpu_to_le64(desc->args[i +
 114                                                      FIRST_EXT_ARG_IDX]);
 115                }
 116
 117                args_phys = dma_map_single(dev, args_virt, alloc_len,
 118                                           DMA_TO_DEVICE);
 119
 120                if (dma_mapping_error(dev, args_phys)) {
 121                        kfree(args_virt);
 122                        return -ENOMEM;
 123                }
 124
 125                x5 = args_phys;
 126        }
 127
 128        do {
 129                mutex_lock(&qcom_scm_lock);
 130
 131                cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
 132                                         qcom_smccc_convention,
 133                                         ARM_SMCCC_OWNER_SIP, fn_id);
 134
 135                quirk.state.a6 = 0;
 136
 137                do {
 138                        arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
 139                                      desc->args[1], desc->args[2], x5,
 140                                      quirk.state.a6, 0, res, &quirk);
 141
 142                        if (res->a0 == QCOM_SCM_INTERRUPTED)
 143                                cmd = res->a0;
 144
 145                } while (res->a0 == QCOM_SCM_INTERRUPTED);
 146
 147                mutex_unlock(&qcom_scm_lock);
 148
 149                if (res->a0 == QCOM_SCM_V2_EBUSY) {
 150                        if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
 151                                break;
 152                        msleep(QCOM_SCM_EBUSY_WAIT_MS);
 153                }
 154        }  while (res->a0 == QCOM_SCM_V2_EBUSY);
 155
 156        if (args_virt) {
 157                dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
 158                kfree(args_virt);
 159        }
 160
 161        if (res->a0 < 0)
 162                return qcom_scm_remap_error(res->a0);
 163
 164        return 0;
 165}
 166
 167/**
 168 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
 169 * @entry: Entry point function for the cpus
 170 * @cpus: The cpumask of cpus that will use the entry point
 171 *
 172 * Set the cold boot address of the cpus. Any cpu outside the supported
 173 * range would be removed from the cpu present mask.
 174 */
 175int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
 176{
 177        return -ENOTSUPP;
 178}
 179
 180/**
 181 * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
 182 * @dev: Device pointer
 183 * @entry: Entry point function for the cpus
 184 * @cpus: The cpumask of cpus that will use the entry point
 185 *
 186 * Set the Linux entry point for the SCM to transfer control to when coming
 187 * out of a power down. CPU power down may be executed on cpuidle or hotplug.
 188 */
 189int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
 190                                  const cpumask_t *cpus)
 191{
 192        return -ENOTSUPP;
 193}
 194
 195/**
 196 * qcom_scm_cpu_power_down() - Power down the cpu
 197 * @flags - Flags to flush cache
 198 *
 199 * This is an end point to power down cpu. If there was a pending interrupt,
 200 * the control would return from this function, otherwise, the cpu jumps to the
 201 * warm boot entry point set for this cpu upon reset.
 202 */
 203void __qcom_scm_cpu_power_down(u32 flags)
 204{
 205}
 206
 207int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
 208{
 209        int ret;
 210        struct qcom_scm_desc desc = {0};
 211        struct arm_smccc_res res;
 212
 213        desc.arginfo = QCOM_SCM_ARGS(1);
 214        desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) |
 215                        (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
 216
 217        ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
 218                            &desc, &res);
 219
 220        return ret ? : res.a1;
 221}
 222
 223int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
 224                        u32 req_cnt, u32 *resp)
 225{
 226        int ret;
 227        struct qcom_scm_desc desc = {0};
 228        struct arm_smccc_res res;
 229
 230        if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
 231                return -ERANGE;
 232
 233        desc.args[0] = req[0].addr;
 234        desc.args[1] = req[0].val;
 235        desc.args[2] = req[1].addr;
 236        desc.args[3] = req[1].val;
 237        desc.args[4] = req[2].addr;
 238        desc.args[5] = req[2].val;
 239        desc.args[6] = req[3].addr;
 240        desc.args[7] = req[3].val;
 241        desc.args[8] = req[4].addr;
 242        desc.args[9] = req[4].val;
 243        desc.arginfo = QCOM_SCM_ARGS(10);
 244
 245        ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc,
 246                            &res);
 247        *resp = res.a1;
 248
 249        return ret;
 250}
 251
 252void __qcom_scm_init(void)
 253{
 254        u64 cmd;
 255        struct arm_smccc_res res;
 256        u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
 257
 258        /* First try a SMC64 call */
 259        cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
 260                                 ARM_SMCCC_OWNER_SIP, function);
 261
 262        arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
 263                      0, 0, 0, 0, 0, &res);
 264
 265        if (!res.a0 && res.a1)
 266                qcom_smccc_convention = ARM_SMCCC_SMC_64;
 267        else
 268                qcom_smccc_convention = ARM_SMCCC_SMC_32;
 269}
 270
 271bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
 272{
 273        int ret;
 274        struct qcom_scm_desc desc = {0};
 275        struct arm_smccc_res res;
 276
 277        desc.args[0] = peripheral;
 278        desc.arginfo = QCOM_SCM_ARGS(1);
 279
 280        ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
 281                                QCOM_SCM_PAS_IS_SUPPORTED_CMD,
 282                                &desc, &res);
 283
 284        return ret ? false : !!res.a1;
 285}
 286
 287int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
 288                              dma_addr_t metadata_phys)
 289{
 290        int ret;
 291        struct qcom_scm_desc desc = {0};
 292        struct arm_smccc_res res;
 293
 294        desc.args[0] = peripheral;
 295        desc.args[1] = metadata_phys;
 296        desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
 297
 298        ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
 299                                &desc, &res);
 300
 301        return ret ? : res.a1;
 302}
 303
 304int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
 305                              phys_addr_t addr, phys_addr_t size)
 306{
 307        int ret;
 308        struct qcom_scm_desc desc = {0};
 309        struct arm_smccc_res res;
 310
 311        desc.args[0] = peripheral;
 312        desc.args[1] = addr;
 313        desc.args[2] = size;
 314        desc.arginfo = QCOM_SCM_ARGS(3);
 315
 316        ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
 317                                &desc, &res);
 318
 319        return ret ? : res.a1;
 320}
 321
 322int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
 323{
 324        int ret;
 325        struct qcom_scm_desc desc = {0};
 326        struct arm_smccc_res res;
 327
 328        desc.args[0] = peripheral;
 329        desc.arginfo = QCOM_SCM_ARGS(1);
 330
 331        ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
 332                                QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
 333                                &desc, &res);
 334
 335        return ret ? : res.a1;
 336}
 337
 338int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
 339{
 340        int ret;
 341        struct qcom_scm_desc desc = {0};
 342        struct arm_smccc_res res;
 343
 344        desc.args[0] = peripheral;
 345        desc.arginfo = QCOM_SCM_ARGS(1);
 346
 347        ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
 348                        &desc, &res);
 349
 350        return ret ? : res.a1;
 351}
 352
 353int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
 354{
 355        struct qcom_scm_desc desc = {0};
 356        struct arm_smccc_res res;
 357        int ret;
 358
 359        desc.args[0] = reset;
 360        desc.args[1] = 0;
 361        desc.arginfo = QCOM_SCM_ARGS(2);
 362
 363        ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc,
 364                            &res);
 365
 366        return ret ? : res.a1;
 367}
 368
 369int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
 370{
 371        struct qcom_scm_desc desc = {0};
 372        struct arm_smccc_res res;
 373        int ret;
 374
 375        desc.args[0] = state;
 376        desc.args[1] = id;
 377        desc.arginfo = QCOM_SCM_ARGS(2);
 378
 379        ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
 380                            &desc, &res);
 381
 382        return ret ? : res.a1;
 383}
 384
 385int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
 386{
 387        struct qcom_scm_desc desc = {0};
 388        struct arm_smccc_res res;
 389        int ret;
 390
 391        desc.args[0] = device_id;
 392        desc.args[1] = spare;
 393        desc.arginfo = QCOM_SCM_ARGS(2);
 394
 395        ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG,
 396                            &desc, &res);
 397
 398        return ret ? : res.a1;
 399}
 400
 401int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
 402                                      size_t *size)
 403{
 404        struct qcom_scm_desc desc = {0};
 405        struct arm_smccc_res res;
 406        int ret;
 407
 408        desc.args[0] = spare;
 409        desc.arginfo = QCOM_SCM_ARGS(1);
 410
 411        ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
 412                            QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res);
 413
 414        if (size)
 415                *size = res.a1;
 416
 417        return ret ? : res.a2;
 418}
 419
 420int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
 421                                      u32 spare)
 422{
 423        struct qcom_scm_desc desc = {0};
 424        struct arm_smccc_res res;
 425        int ret;
 426
 427        desc.args[0] = addr;
 428        desc.args[1] = size;
 429        desc.args[2] = spare;
 430        desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
 431                                     QCOM_SCM_VAL);
 432
 433        ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
 434                            QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res);
 435
 436        /* the pg table has been initialized already, ignore the error */
 437        if (ret == -EPERM)
 438                ret = 0;
 439
 440        return ret;
 441}
 442