Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'qcom-drivers-for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/drivers

Qualcomm ARM Based Driver Updates for v4.8

* Rework of SCM driver
* Add file patterns for Qualcomm Maintainers entry
* Add worker for wcnss_ctrl signaling
* Fixes for smp2p
* Update smem_state properties to match documentation
* Add SCM Peripheral Authentication service
* Expose SCM PAS command 10 as a reset controller

* tag 'qcom-drivers-for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux:
firmware: qcom: scm: Expose PAS command 10 as reset-controller
firmware: qcom: scm: Peripheral Authentication Service
soc: qcom: Update properties for smem state referencing
soc: qcom: smp2p: Drop io-accessors
soc: qcom: smp2p: Correct addressing of outgoing value
soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
firmware: qcom: scm: Add support for ARM64 SoCs
firmware: qcom: scm: Convert to streaming DMA APIS
firmware: qcom: scm: Generalize shared error map
firmware: qcom: scm: Use atomic SCM for cold boot
firmware: qcom: scm: Convert SCM to platform driver
MAINTAINERS: Add file patterns for qcom device tree bindings

Signed-off-by: Olof Johansson <olof@lixom.net>

+1012 -186
+2 -2
Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt
··· 68 68 Value type: <u32> 69 69 Definition: must be 2 - denoting the bit in the entry and IRQ flags 70 70 71 - - #qcom,state-cells: 71 + - #qcom,smem-state-cells: 72 72 Usage: required for outgoing entries 73 73 Value type: <u32> 74 74 Definition: must be 1 - denoting the bit in the entry ··· 92 92 wcnss_smp2p_out: master-kernel { 93 93 qcom,entry-name = "master-kernel"; 94 94 95 - #qcom,state-cells = <1>; 95 + #qcom,smem-state-cells = <1>; 96 96 }; 97 97 98 98 wcnss_smp2p_in: slave-kernel {
+2 -2
Documentation/devicetree/bindings/soc/qcom/qcom,smsm.txt
··· 51 51 Definition: specifies the offset, in words, of the first bit for this 52 52 entry 53 53 54 - - #qcom,state-cells: 54 + - #qcom,smem-state-cells: 55 55 Usage: required for local entry 56 56 Value type: <u32> 57 57 Definition: must be 1 - denotes bit number ··· 91 91 apps_smsm: apps@0 { 92 92 reg = <0>; 93 93 94 - #qcom,state-cells = <1>; 94 + #qcom,smem-state-cells = <1>; 95 95 }; 96 96 97 97 wcnss_smsm: wcnss@7 {
+1
MAINTAINERS
··· 1521 1521 L: linux-arm-msm@vger.kernel.org 1522 1522 L: linux-soc@vger.kernel.org 1523 1523 S: Maintained 1524 + F: Documentation/devicetree/bindings/soc/qcom/ 1524 1525 F: arch/arm/boot/dts/qcom-*.dts 1525 1526 F: arch/arm/boot/dts/qcom-*.dtsi 1526 1527 F: arch/arm/mach-qcom/
+1
drivers/firmware/Kconfig
··· 194 194 config QCOM_SCM 195 195 bool 196 196 depends on ARM || ARM64 197 + select RESET_CONTROLLER 197 198 198 199 config QCOM_SCM_32 199 200 def_bool y
+194 -133
drivers/firmware/qcom_scm-32.c
··· 23 23 #include <linux/errno.h> 24 24 #include <linux/err.h> 25 25 #include <linux/qcom_scm.h> 26 - 27 - #include <asm/cacheflush.h> 26 + #include <linux/dma-mapping.h> 28 27 29 28 #include "qcom_scm.h" 30 29 ··· 96 97 }; 97 98 98 99 /** 99 - * alloc_qcom_scm_command() - Allocate an SCM command 100 - * @cmd_size: size of the command buffer 101 - * @resp_size: size of the response buffer 102 - * 103 - * Allocate an SCM command, including enough room for the command 104 - * and response headers as well as the command and response buffers. 105 - * 106 - * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails. 107 - */ 108 - static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size) 109 - { 110 - struct qcom_scm_command *cmd; 111 - size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size + 112 - resp_size; 113 - u32 offset; 114 - 115 - cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); 116 - if (cmd) { 117 - cmd->len = cpu_to_le32(len); 118 - offset = offsetof(struct qcom_scm_command, buf); 119 - cmd->buf_offset = cpu_to_le32(offset); 120 - cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size); 121 - } 122 - return cmd; 123 - } 124 - 125 - /** 126 - * free_qcom_scm_command() - Free an SCM command 127 - * @cmd: command to free 128 - * 129 - * Free an SCM command. 130 - */ 131 - static inline void free_qcom_scm_command(struct qcom_scm_command *cmd) 132 - { 133 - kfree(cmd); 134 - } 135 - 136 - /** 137 100 * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response 138 101 * @cmd: command 139 102 * ··· 129 168 return (void *)rsp + le32_to_cpu(rsp->buf_offset); 130 169 } 131 170 132 - static int qcom_scm_remap_error(int err) 133 - { 134 - pr_err("qcom_scm_call failed with error code %d\n", err); 135 - switch (err) { 136 - case QCOM_SCM_ERROR: 137 - return -EIO; 138 - case QCOM_SCM_EINVAL_ADDR: 139 - case QCOM_SCM_EINVAL_ARG: 140 - return -EINVAL; 141 - case QCOM_SCM_EOPNOTSUPP: 142 - return -EOPNOTSUPP; 143 - case QCOM_SCM_ENOMEM: 144 - return -ENOMEM; 145 - } 146 - return -EINVAL; 147 - } 148 - 149 171 static u32 smc(u32 cmd_addr) 150 172 { 151 173 int context_id; ··· 153 209 return r0; 154 210 } 155 211 156 - static int __qcom_scm_call(const struct qcom_scm_command *cmd) 157 - { 158 - int ret; 159 - u32 cmd_addr = virt_to_phys(cmd); 160 - 161 - /* 162 - * Flush the command buffer so that the secure world sees 163 - * the correct data. 164 - */ 165 - secure_flush_area(cmd, cmd->len); 166 - 167 - ret = smc(cmd_addr); 168 - if (ret < 0) 169 - ret = qcom_scm_remap_error(ret); 170 - 171 - return ret; 172 - } 173 - 174 - static void qcom_scm_inv_range(unsigned long start, unsigned long end) 175 - { 176 - u32 cacheline_size, ctr; 177 - 178 - asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); 179 - cacheline_size = 4 << ((ctr >> 16) & 0xf); 180 - 181 - start = round_down(start, cacheline_size); 182 - end = round_up(end, cacheline_size); 183 - outer_inv_range(start, end); 184 - while (start < end) { 185 - asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) 186 - : "memory"); 187 - start += cacheline_size; 188 - } 189 - dsb(); 190 - isb(); 191 - } 192 - 193 212 /** 194 213 * qcom_scm_call() - Send an SCM command 214 + * @dev: struct device 195 215 * @svc_id: service identifier 196 216 * @cmd_id: command identifier 197 217 * @cmd_buf: command buffer ··· 172 264 * and response buffers is taken care of by qcom_scm_call; however, callers are 173 265 * responsible for any other cached buffers passed over to the secure world. 174 266 */ 175 - static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, 176 - size_t cmd_len, void *resp_buf, size_t resp_len) 267 + static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, 268 + const void *cmd_buf, size_t cmd_len, void *resp_buf, 269 + size_t resp_len) 177 270 { 178 271 int ret; 179 272 struct qcom_scm_command *cmd; 180 273 struct qcom_scm_response *rsp; 181 - unsigned long start, end; 274 + size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len; 275 + dma_addr_t cmd_phys; 182 276 183 - cmd = alloc_qcom_scm_command(cmd_len, resp_len); 277 + cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); 184 278 if (!cmd) 185 279 return -ENOMEM; 280 + 281 + cmd->len = cpu_to_le32(alloc_len); 282 + cmd->buf_offset = cpu_to_le32(sizeof(*cmd)); 283 + cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len); 186 284 187 285 cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); 188 286 if (cmd_buf) 189 287 memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len); 190 288 289 + rsp = qcom_scm_command_to_response(cmd); 290 + 291 + cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE); 292 + if (dma_mapping_error(dev, cmd_phys)) { 293 + kfree(cmd); 294 + return -ENOMEM; 295 + } 296 + 191 297 mutex_lock(&qcom_scm_lock); 192 - ret = __qcom_scm_call(cmd); 298 + ret = smc(cmd_phys); 299 + if (ret < 0) 300 + ret = qcom_scm_remap_error(ret); 193 301 mutex_unlock(&qcom_scm_lock); 194 302 if (ret) 195 303 goto out; 196 304 197 - rsp = qcom_scm_command_to_response(cmd); 198 - start = (unsigned long)rsp; 199 - 200 305 do { 201 - qcom_scm_inv_range(start, start + sizeof(*rsp)); 306 + dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len, 307 + sizeof(*rsp), DMA_FROM_DEVICE); 202 308 } while (!rsp->is_complete); 203 309 204 - end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len; 205 - qcom_scm_inv_range(start, end); 206 - 207 - if (resp_buf) 208 - memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len); 310 + if (resp_buf) { 311 + dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len + 312 + le32_to_cpu(rsp->buf_offset), 313 + resp_len, DMA_FROM_DEVICE); 314 + memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), 315 + resp_len); 316 + } 209 317 out: 210 - free_qcom_scm_command(cmd); 318 + dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE); 319 + kfree(cmd); 211 320 return ret; 212 321 } 213 322 ··· 267 342 return r0; 268 343 } 269 344 345 + /** 346 + * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments 347 + * @svc_id: service identifier 348 + * @cmd_id: command identifier 349 + * @arg1: first argument 350 + * @arg2: second argument 351 + * 352 + * This shall only be used with commands that are guaranteed to be 353 + * uninterruptable, atomic and SMP safe. 354 + */ 355 + static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2) 356 + { 357 + int context_id; 358 + 359 + register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2); 360 + register u32 r1 asm("r1") = (u32)&context_id; 361 + register u32 r2 asm("r2") = arg1; 362 + register u32 r3 asm("r3") = arg2; 363 + 364 + asm volatile( 365 + __asmeq("%0", "r0") 366 + __asmeq("%1", "r0") 367 + __asmeq("%2", "r1") 368 + __asmeq("%3", "r2") 369 + __asmeq("%4", "r3") 370 + #ifdef REQUIRES_SEC 371 + ".arch_extension sec\n" 372 + #endif 373 + "smc #0 @ switch to secure world\n" 374 + : "=r" (r0) 375 + : "r" (r0), "r" (r1), "r" (r2), "r" (r3) 376 + ); 377 + return r0; 378 + } 379 + 270 380 u32 qcom_scm_get_version(void) 271 381 { 272 382 int context_id; ··· 338 378 } 339 379 EXPORT_SYMBOL(qcom_scm_get_version); 340 380 341 - /* 342 - * Set the cold/warm boot address for one of the CPU cores. 343 - */ 344 - static int qcom_scm_set_boot_addr(u32 addr, int flags) 345 - { 346 - struct { 347 - __le32 flags; 348 - __le32 addr; 349 - } cmd; 350 - 351 - cmd.addr = cpu_to_le32(addr); 352 - cmd.flags = cpu_to_le32(flags); 353 - return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, 354 - &cmd, sizeof(cmd), NULL, 0); 355 - } 356 - 357 381 /** 358 382 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus 359 383 * @entry: Entry point function for the cpus ··· 367 423 set_cpu_present(cpu, false); 368 424 } 369 425 370 - return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); 426 + return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, 427 + flags, virt_to_phys(entry)); 371 428 } 372 429 373 430 /** ··· 379 434 * Set the Linux entry point for the SCM to transfer control to when coming 380 435 * out of a power down. CPU power down may be executed on cpuidle or hotplug. 381 436 */ 382 - int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 437 + int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, 438 + const cpumask_t *cpus) 383 439 { 384 440 int ret; 385 441 int flags = 0; 386 442 int cpu; 443 + struct { 444 + __le32 flags; 445 + __le32 addr; 446 + } cmd; 387 447 388 448 /* 389 449 * Reassign only if we are switching from hotplug entry point ··· 404 454 if (!flags) 405 455 return 0; 406 456 407 - ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags); 457 + cmd.addr = cpu_to_le32(virt_to_phys(entry)); 458 + cmd.flags = cpu_to_le32(flags); 459 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, 460 + &cmd, sizeof(cmd), NULL, 0); 408 461 if (!ret) { 409 462 for_each_cpu(cpu, cpus) 410 463 qcom_scm_wb[cpu].entry = entry; ··· 430 477 flags & QCOM_SCM_FLUSH_FLAG_MASK); 431 478 } 432 479 433 - int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id) 480 + int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) 434 481 { 435 482 int ret; 436 483 __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id); 437 484 __le32 ret_val = 0; 438 485 439 - ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd, 440 - sizeof(svc_cmd), &ret_val, sizeof(ret_val)); 486 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, 487 + &svc_cmd, sizeof(svc_cmd), &ret_val, 488 + sizeof(ret_val)); 441 489 if (ret) 442 490 return ret; 443 491 444 492 return le32_to_cpu(ret_val); 445 493 } 446 494 447 - int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) 495 + int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, 496 + u32 req_cnt, u32 *resp) 448 497 { 449 498 if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT) 450 499 return -ERANGE; 451 500 452 - return qcom_scm_call(QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, 501 + return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, 453 502 req, req_cnt * sizeof(*req), resp, sizeof(*resp)); 503 + } 504 + 505 + void __qcom_scm_init(void) 506 + { 507 + } 508 + 509 + bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) 510 + { 511 + __le32 out; 512 + __le32 in; 513 + int ret; 514 + 515 + in = cpu_to_le32(peripheral); 516 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 517 + QCOM_SCM_PAS_IS_SUPPORTED_CMD, 518 + &in, sizeof(in), 519 + &out, sizeof(out)); 520 + 521 + return ret ? false : !!out; 522 + } 523 + 524 + int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, 525 + dma_addr_t metadata_phys) 526 + { 527 + __le32 scm_ret; 528 + int ret; 529 + struct { 530 + __le32 proc; 531 + __le32 image_addr; 532 + } request; 533 + 534 + request.proc = cpu_to_le32(peripheral); 535 + request.image_addr = cpu_to_le32(metadata_phys); 536 + 537 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 538 + QCOM_SCM_PAS_INIT_IMAGE_CMD, 539 + &request, sizeof(request), 540 + &scm_ret, sizeof(scm_ret)); 541 + 542 + return ret ? : le32_to_cpu(scm_ret); 543 + } 544 + 545 + int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, 546 + phys_addr_t addr, phys_addr_t size) 547 + { 548 + __le32 scm_ret; 549 + int ret; 550 + struct { 551 + __le32 proc; 552 + __le32 addr; 553 + __le32 len; 554 + } request; 555 + 556 + request.proc = cpu_to_le32(peripheral); 557 + request.addr = cpu_to_le32(addr); 558 + request.len = cpu_to_le32(size); 559 + 560 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 561 + QCOM_SCM_PAS_MEM_SETUP_CMD, 562 + &request, sizeof(request), 563 + &scm_ret, sizeof(scm_ret)); 564 + 565 + return ret ? : le32_to_cpu(scm_ret); 566 + } 567 + 568 + int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral) 569 + { 570 + __le32 out; 571 + __le32 in; 572 + int ret; 573 + 574 + in = cpu_to_le32(peripheral); 575 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 576 + QCOM_SCM_PAS_AUTH_AND_RESET_CMD, 577 + &in, sizeof(in), 578 + &out, sizeof(out)); 579 + 580 + return ret ? : le32_to_cpu(out); 581 + } 582 + 583 + int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral) 584 + { 585 + __le32 out; 586 + __le32 in; 587 + int ret; 588 + 589 + in = cpu_to_le32(peripheral); 590 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 591 + QCOM_SCM_PAS_SHUTDOWN_CMD, 592 + &in, sizeof(in), 593 + &out, sizeof(out)); 594 + 595 + return ret ? : le32_to_cpu(out); 596 + } 597 + 598 + int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) 599 + { 600 + __le32 out; 601 + __le32 in = cpu_to_le32(reset); 602 + int ret; 603 + 604 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, 605 + &in, sizeof(in), 606 + &out, sizeof(out)); 607 + 608 + return ret ? : le32_to_cpu(out); 454 609 }
+302 -5
drivers/firmware/qcom_scm-64.c
··· 12 12 13 13 #include <linux/io.h> 14 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> 15 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 + 30 + enum 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 + */ 58 + struct qcom_scm_desc { 59 + u32 arginfo; 60 + u64 args[MAX_QCOM_SCM_ARGS]; 61 + }; 62 + 63 + static u64 qcom_smccc_convention = -1; 64 + static 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 + */ 83 + static 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 + 95 + if (unlikely(arglen > N_REGISTER_ARGS)) { 96 + alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64); 97 + args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); 98 + 99 + if (!args_virt) 100 + return -ENOMEM; 101 + 102 + if (qcom_smccc_convention == ARM_SMCCC_SMC_32) { 103 + __le32 *args = args_virt; 104 + 105 + for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++) 106 + args[i] = cpu_to_le32(desc->args[i + 107 + FIRST_EXT_ARG_IDX]); 108 + } else { 109 + __le64 *args = args_virt; 110 + 111 + for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++) 112 + args[i] = cpu_to_le64(desc->args[i + 113 + FIRST_EXT_ARG_IDX]); 114 + } 115 + 116 + args_phys = dma_map_single(dev, args_virt, alloc_len, 117 + DMA_TO_DEVICE); 118 + 119 + if (dma_mapping_error(dev, args_phys)) { 120 + kfree(args_virt); 121 + return -ENOMEM; 122 + } 123 + 124 + x5 = args_phys; 125 + } 126 + 127 + do { 128 + mutex_lock(&qcom_scm_lock); 129 + 130 + cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, 131 + qcom_smccc_convention, 132 + ARM_SMCCC_OWNER_SIP, fn_id); 133 + 134 + do { 135 + arm_smccc_smc(cmd, desc->arginfo, desc->args[0], 136 + desc->args[1], desc->args[2], x5, 0, 0, 137 + res); 138 + } while (res->a0 == QCOM_SCM_INTERRUPTED); 139 + 140 + mutex_unlock(&qcom_scm_lock); 141 + 142 + if (res->a0 == QCOM_SCM_V2_EBUSY) { 143 + if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) 144 + break; 145 + msleep(QCOM_SCM_EBUSY_WAIT_MS); 146 + } 147 + } while (res->a0 == QCOM_SCM_V2_EBUSY); 148 + 149 + if (args_virt) { 150 + dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE); 151 + kfree(args_virt); 152 + } 153 + 154 + if (res->a0 < 0) 155 + return qcom_scm_remap_error(res->a0); 156 + 157 + return 0; 158 + } 16 159 17 160 /** 18 161 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus ··· 172 29 173 30 /** 174 31 * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus 32 + * @dev: Device pointer 175 33 * @entry: Entry point function for the cpus 176 34 * @cpus: The cpumask of cpus that will use the entry point 177 35 * 178 36 * Set the Linux entry point for the SCM to transfer control to when coming 179 37 * out of a power down. CPU power down may be executed on cpuidle or hotplug. 180 38 */ 181 - int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 39 + int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, 40 + const cpumask_t *cpus) 182 41 { 183 42 return -ENOTSUPP; 184 43 } ··· 197 52 { 198 53 } 199 54 200 - int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id) 55 + int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) 201 56 { 202 - return -ENOTSUPP; 57 + int ret; 58 + struct qcom_scm_desc desc = {0}; 59 + struct arm_smccc_res res; 60 + 61 + desc.arginfo = QCOM_SCM_ARGS(1); 62 + desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) | 63 + (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT); 64 + 65 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, 66 + &desc, &res); 67 + 68 + return ret ? : res.a1; 203 69 } 204 70 205 - int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) 71 + int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, 72 + u32 req_cnt, u32 *resp) 206 73 { 207 - return -ENOTSUPP; 74 + int ret; 75 + struct qcom_scm_desc desc = {0}; 76 + struct arm_smccc_res res; 77 + 78 + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT) 79 + return -ERANGE; 80 + 81 + desc.args[0] = req[0].addr; 82 + desc.args[1] = req[0].val; 83 + desc.args[2] = req[1].addr; 84 + desc.args[3] = req[1].val; 85 + desc.args[4] = req[2].addr; 86 + desc.args[5] = req[2].val; 87 + desc.args[6] = req[3].addr; 88 + desc.args[7] = req[3].val; 89 + desc.args[8] = req[4].addr; 90 + desc.args[9] = req[4].val; 91 + desc.arginfo = QCOM_SCM_ARGS(10); 92 + 93 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc, 94 + &res); 95 + *resp = res.a1; 96 + 97 + return ret; 98 + } 99 + 100 + void __qcom_scm_init(void) 101 + { 102 + u64 cmd; 103 + struct arm_smccc_res res; 104 + u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD); 105 + 106 + /* First try a SMC64 call */ 107 + cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, 108 + ARM_SMCCC_OWNER_SIP, function); 109 + 110 + arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)), 111 + 0, 0, 0, 0, 0, &res); 112 + 113 + if (!res.a0 && res.a1) 114 + qcom_smccc_convention = ARM_SMCCC_SMC_64; 115 + else 116 + qcom_smccc_convention = ARM_SMCCC_SMC_32; 117 + } 118 + 119 + bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) 120 + { 121 + int ret; 122 + struct qcom_scm_desc desc = {0}; 123 + struct arm_smccc_res res; 124 + 125 + desc.args[0] = peripheral; 126 + desc.arginfo = QCOM_SCM_ARGS(1); 127 + 128 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 129 + QCOM_SCM_PAS_IS_SUPPORTED_CMD, 130 + &desc, &res); 131 + 132 + return ret ? false : !!res.a1; 133 + } 134 + 135 + int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, 136 + dma_addr_t metadata_phys) 137 + { 138 + int ret; 139 + struct qcom_scm_desc desc = {0}; 140 + struct arm_smccc_res res; 141 + 142 + desc.args[0] = peripheral; 143 + desc.args[1] = metadata_phys; 144 + desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW); 145 + 146 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD, 147 + &desc, &res); 148 + 149 + return ret ? : res.a1; 150 + } 151 + 152 + int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, 153 + phys_addr_t addr, phys_addr_t size) 154 + { 155 + int ret; 156 + struct qcom_scm_desc desc = {0}; 157 + struct arm_smccc_res res; 158 + 159 + desc.args[0] = peripheral; 160 + desc.args[1] = addr; 161 + desc.args[2] = size; 162 + desc.arginfo = QCOM_SCM_ARGS(3); 163 + 164 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD, 165 + &desc, &res); 166 + 167 + return ret ? : res.a1; 168 + } 169 + 170 + int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral) 171 + { 172 + int ret; 173 + struct qcom_scm_desc desc = {0}; 174 + struct arm_smccc_res res; 175 + 176 + desc.args[0] = peripheral; 177 + desc.arginfo = QCOM_SCM_ARGS(1); 178 + 179 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, 180 + QCOM_SCM_PAS_AUTH_AND_RESET_CMD, 181 + &desc, &res); 182 + 183 + return ret ? : res.a1; 184 + } 185 + 186 + int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral) 187 + { 188 + int ret; 189 + struct qcom_scm_desc desc = {0}; 190 + struct arm_smccc_res res; 191 + 192 + desc.args[0] = peripheral; 193 + desc.arginfo = QCOM_SCM_ARGS(1); 194 + 195 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD, 196 + &desc, &res); 197 + 198 + return ret ? : res.a1; 199 + } 200 + 201 + int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) 202 + { 203 + struct qcom_scm_desc desc = {0}; 204 + struct arm_smccc_res res; 205 + int ret; 206 + 207 + desc.args[0] = reset; 208 + desc.args[1] = 0; 209 + desc.arginfo = QCOM_SCM_ARGS(2); 210 + 211 + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc, 212 + &res); 213 + 214 + return ret ? : res.a1; 208 215 }
+334 -11
drivers/firmware/qcom_scm.c
··· 10 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 11 * GNU General Public License for more details. 12 12 * 13 - * You should have received a copy of the GNU General Public License 14 - * along with this program; if not, write to the Free Software 15 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 16 - * 02110-1301, USA. 17 13 */ 18 - 14 + #include <linux/platform_device.h> 15 + #include <linux/module.h> 19 16 #include <linux/cpumask.h> 20 17 #include <linux/export.h> 18 + #include <linux/dma-mapping.h> 21 19 #include <linux/types.h> 22 20 #include <linux/qcom_scm.h> 21 + #include <linux/of.h> 22 + #include <linux/of_platform.h> 23 + #include <linux/clk.h> 24 + #include <linux/reset-controller.h> 23 25 24 26 #include "qcom_scm.h" 27 + 28 + struct qcom_scm { 29 + struct device *dev; 30 + struct clk *core_clk; 31 + struct clk *iface_clk; 32 + struct clk *bus_clk; 33 + struct reset_controller_dev reset; 34 + }; 35 + 36 + static struct qcom_scm *__scm; 37 + 38 + static int qcom_scm_clk_enable(void) 39 + { 40 + int ret; 41 + 42 + ret = clk_prepare_enable(__scm->core_clk); 43 + if (ret) 44 + goto bail; 45 + 46 + ret = clk_prepare_enable(__scm->iface_clk); 47 + if (ret) 48 + goto disable_core; 49 + 50 + ret = clk_prepare_enable(__scm->bus_clk); 51 + if (ret) 52 + goto disable_iface; 53 + 54 + return 0; 55 + 56 + disable_iface: 57 + clk_disable_unprepare(__scm->iface_clk); 58 + disable_core: 59 + clk_disable_unprepare(__scm->core_clk); 60 + bail: 61 + return ret; 62 + } 63 + 64 + static void qcom_scm_clk_disable(void) 65 + { 66 + clk_disable_unprepare(__scm->core_clk); 67 + clk_disable_unprepare(__scm->iface_clk); 68 + clk_disable_unprepare(__scm->bus_clk); 69 + } 25 70 26 71 /** 27 72 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus ··· 92 47 */ 93 48 int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 94 49 { 95 - return __qcom_scm_set_warm_boot_addr(entry, cpus); 50 + return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus); 96 51 } 97 52 EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); 98 53 ··· 117 72 */ 118 73 bool qcom_scm_hdcp_available(void) 119 74 { 120 - int ret; 75 + int ret = qcom_scm_clk_enable(); 121 76 122 - ret = __qcom_scm_is_call_available(QCOM_SCM_SVC_HDCP, 123 - QCOM_SCM_CMD_HDCP); 77 + if (ret) 78 + return ret; 124 79 125 - return (ret > 0) ? true : false; 80 + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP, 81 + QCOM_SCM_CMD_HDCP); 82 + 83 + qcom_scm_clk_disable(); 84 + 85 + return ret > 0 ? true : false; 126 86 } 127 87 EXPORT_SYMBOL(qcom_scm_hdcp_available); 128 88 ··· 141 91 */ 142 92 int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) 143 93 { 144 - return __qcom_scm_hdcp_req(req, req_cnt, resp); 94 + int ret = qcom_scm_clk_enable(); 95 + 96 + if (ret) 97 + return ret; 98 + 99 + ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp); 100 + qcom_scm_clk_disable(); 101 + return ret; 145 102 } 146 103 EXPORT_SYMBOL(qcom_scm_hdcp_req); 104 + 105 + /** 106 + * qcom_scm_pas_supported() - Check if the peripheral authentication service is 107 + * available for the given peripherial 108 + * @peripheral: peripheral id 109 + * 110 + * Returns true if PAS is supported for this peripheral, otherwise false. 111 + */ 112 + bool qcom_scm_pas_supported(u32 peripheral) 113 + { 114 + int ret; 115 + 116 + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, 117 + QCOM_SCM_PAS_IS_SUPPORTED_CMD); 118 + if (ret <= 0) 119 + return false; 120 + 121 + return __qcom_scm_pas_supported(__scm->dev, peripheral); 122 + } 123 + EXPORT_SYMBOL(qcom_scm_pas_supported); 124 + 125 + /** 126 + * qcom_scm_pas_init_image() - Initialize peripheral authentication service 127 + * state machine for a given peripheral, using the 128 + * metadata 129 + * @peripheral: peripheral id 130 + * @metadata: pointer to memory containing ELF header, program header table 131 + * and optional blob of data used for authenticating the metadata 132 + * and the rest of the firmware 133 + * @size: size of the metadata 134 + * 135 + * Returns 0 on success. 136 + */ 137 + int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) 138 + { 139 + dma_addr_t mdata_phys; 140 + void *mdata_buf; 141 + int ret; 142 + 143 + /* 144 + * During the scm call memory protection will be enabled for the meta 145 + * data blob, so make sure it's physically contiguous, 4K aligned and 146 + * non-cachable to avoid XPU violations. 147 + */ 148 + mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, 149 + GFP_KERNEL); 150 + if (!mdata_buf) { 151 + dev_err(__scm->dev, "Allocation of metadata buffer failed.\n"); 152 + return -ENOMEM; 153 + } 154 + memcpy(mdata_buf, metadata, size); 155 + 156 + ret = qcom_scm_clk_enable(); 157 + if (ret) 158 + goto free_metadata; 159 + 160 + ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys); 161 + 162 + qcom_scm_clk_disable(); 163 + 164 + free_metadata: 165 + dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); 166 + 167 + return ret; 168 + } 169 + EXPORT_SYMBOL(qcom_scm_pas_init_image); 170 + 171 + /** 172 + * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral 173 + * for firmware loading 174 + * @peripheral: peripheral id 175 + * @addr: start address of memory area to prepare 176 + * @size: size of the memory area to prepare 177 + * 178 + * Returns 0 on success. 179 + */ 180 + int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) 181 + { 182 + int ret; 183 + 184 + ret = qcom_scm_clk_enable(); 185 + if (ret) 186 + return ret; 187 + 188 + ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size); 189 + qcom_scm_clk_disable(); 190 + 191 + return ret; 192 + } 193 + EXPORT_SYMBOL(qcom_scm_pas_mem_setup); 194 + 195 + /** 196 + * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware 197 + * and reset the remote processor 198 + * @peripheral: peripheral id 199 + * 200 + * Return 0 on success. 201 + */ 202 + int qcom_scm_pas_auth_and_reset(u32 peripheral) 203 + { 204 + int ret; 205 + 206 + ret = qcom_scm_clk_enable(); 207 + if (ret) 208 + return ret; 209 + 210 + ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral); 211 + qcom_scm_clk_disable(); 212 + 213 + return ret; 214 + } 215 + EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); 216 + 217 + /** 218 + * qcom_scm_pas_shutdown() - Shut down the remote processor 219 + * @peripheral: peripheral id 220 + * 221 + * Returns 0 on success. 222 + */ 223 + int qcom_scm_pas_shutdown(u32 peripheral) 224 + { 225 + int ret; 226 + 227 + ret = qcom_scm_clk_enable(); 228 + if (ret) 229 + return ret; 230 + 231 + ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral); 232 + qcom_scm_clk_disable(); 233 + 234 + return ret; 235 + } 236 + EXPORT_SYMBOL(qcom_scm_pas_shutdown); 237 + 238 + static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev, 239 + unsigned long idx) 240 + { 241 + if (idx != 0) 242 + return -EINVAL; 243 + 244 + return __qcom_scm_pas_mss_reset(__scm->dev, 1); 245 + } 246 + 247 + static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev, 248 + unsigned long idx) 249 + { 250 + if (idx != 0) 251 + return -EINVAL; 252 + 253 + return __qcom_scm_pas_mss_reset(__scm->dev, 0); 254 + } 255 + 256 + static const struct reset_control_ops qcom_scm_pas_reset_ops = { 257 + .assert = qcom_scm_pas_reset_assert, 258 + .deassert = qcom_scm_pas_reset_deassert, 259 + }; 260 + 261 + 262 + static int qcom_scm_probe(struct platform_device *pdev) 263 + { 264 + struct qcom_scm *scm; 265 + int ret; 266 + 267 + scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL); 268 + if (!scm) 269 + return -ENOMEM; 270 + 271 + scm->core_clk = devm_clk_get(&pdev->dev, "core"); 272 + if (IS_ERR(scm->core_clk)) { 273 + if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) 274 + return PTR_ERR(scm->core_clk); 275 + 276 + scm->core_clk = NULL; 277 + } 278 + 279 + if (of_device_is_compatible(pdev->dev.of_node, "qcom,scm")) { 280 + scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); 281 + if (IS_ERR(scm->iface_clk)) { 282 + if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) 283 + dev_err(&pdev->dev, "failed to acquire iface clk\n"); 284 + return PTR_ERR(scm->iface_clk); 285 + } 286 + 287 + scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); 288 + if (IS_ERR(scm->bus_clk)) { 289 + if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) 290 + dev_err(&pdev->dev, "failed to acquire bus clk\n"); 291 + return PTR_ERR(scm->bus_clk); 292 + } 293 + } 294 + 295 + scm->reset.ops = &qcom_scm_pas_reset_ops; 296 + scm->reset.nr_resets = 1; 297 + scm->reset.of_node = pdev->dev.of_node; 298 + reset_controller_register(&scm->reset); 299 + 300 + /* vote for max clk rate for highest performance */ 301 + ret = clk_set_rate(scm->core_clk, INT_MAX); 302 + if (ret) 303 + return ret; 304 + 305 + __scm = scm; 306 + __scm->dev = &pdev->dev; 307 + 308 + __qcom_scm_init(); 309 + 310 + return 0; 311 + } 312 + 313 + static const struct of_device_id qcom_scm_dt_match[] = { 314 + { .compatible = "qcom,scm-apq8064",}, 315 + { .compatible = "qcom,scm-msm8660",}, 316 + { .compatible = "qcom,scm-msm8960",}, 317 + { .compatible = "qcom,scm",}, 318 + {} 319 + }; 320 + 321 + MODULE_DEVICE_TABLE(of, qcom_scm_dt_match); 322 + 323 + static struct platform_driver qcom_scm_driver = { 324 + .driver = { 325 + .name = "qcom_scm", 326 + .of_match_table = qcom_scm_dt_match, 327 + }, 328 + .probe = qcom_scm_probe, 329 + }; 330 + 331 + static int __init qcom_scm_init(void) 332 + { 333 + struct device_node *np, *fw_np; 334 + int ret; 335 + 336 + fw_np = of_find_node_by_name(NULL, "firmware"); 337 + 338 + if (!fw_np) 339 + return -ENODEV; 340 + 341 + np = of_find_matching_node(fw_np, qcom_scm_dt_match); 342 + 343 + if (!np) { 344 + of_node_put(fw_np); 345 + return -ENODEV; 346 + } 347 + 348 + of_node_put(np); 349 + 350 + ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL); 351 + 352 + of_node_put(fw_np); 353 + 354 + if (ret) 355 + return ret; 356 + 357 + return platform_driver_register(&qcom_scm_driver); 358 + } 359 + 360 + arch_initcall(qcom_scm_init); 361 + 362 + static void __exit qcom_scm_exit(void) 363 + { 364 + platform_driver_unregister(&qcom_scm_driver); 365 + } 366 + module_exit(qcom_scm_exit); 367 + 368 + MODULE_DESCRIPTION("Qualcomm SCM driver"); 369 + MODULE_LICENSE("GPL v2");
+43 -4
drivers/firmware/qcom_scm.h
··· 19 19 #define QCOM_SCM_FLAG_HLOS 0x01 20 20 #define QCOM_SCM_FLAG_COLDBOOT_MC 0x02 21 21 #define QCOM_SCM_FLAG_WARMBOOT_MC 0x04 22 - extern int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); 22 + extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, 23 + const cpumask_t *cpus); 23 24 extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); 24 25 25 26 #define QCOM_SCM_CMD_TERMINATE_PC 0x2 ··· 30 29 31 30 #define QCOM_SCM_SVC_INFO 0x6 32 31 #define QCOM_IS_CALL_AVAIL_CMD 0x1 33 - extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id); 32 + extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, 33 + u32 cmd_id); 34 34 35 35 #define QCOM_SCM_SVC_HDCP 0x11 36 36 #define QCOM_SCM_CMD_HDCP 0x01 37 - extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, 38 - u32 *resp); 37 + extern int __qcom_scm_hdcp_req(struct device *dev, 38 + struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp); 39 + 40 + extern void __qcom_scm_init(void); 41 + 42 + #define QCOM_SCM_SVC_PIL 0x2 43 + #define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1 44 + #define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2 45 + #define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5 46 + #define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6 47 + #define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7 48 + #define QCOM_SCM_PAS_MSS_RESET 0xa 49 + extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral); 50 + extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, 51 + dma_addr_t metadata_phys); 52 + extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, 53 + phys_addr_t addr, phys_addr_t size); 54 + extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral); 55 + extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral); 56 + extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset); 39 57 40 58 /* common error codes */ 59 + #define QCOM_SCM_V2_EBUSY -12 41 60 #define QCOM_SCM_ENOMEM -5 42 61 #define QCOM_SCM_EOPNOTSUPP -4 43 62 #define QCOM_SCM_EINVAL_ADDR -3 44 63 #define QCOM_SCM_EINVAL_ARG -2 45 64 #define QCOM_SCM_ERROR -1 46 65 #define QCOM_SCM_INTERRUPTED 1 66 + 67 + static inline int qcom_scm_remap_error(int err) 68 + { 69 + switch (err) { 70 + case QCOM_SCM_ERROR: 71 + return -EIO; 72 + case QCOM_SCM_EINVAL_ADDR: 73 + case QCOM_SCM_EINVAL_ARG: 74 + return -EINVAL; 75 + case QCOM_SCM_EOPNOTSUPP: 76 + return -EOPNOTSUPP; 77 + case QCOM_SCM_ENOMEM: 78 + return -ENOMEM; 79 + case QCOM_SCM_V2_EBUSY: 80 + return -EBUSY; 81 + } 82 + return -EINVAL; 83 + } 47 84 48 85 #endif
+6 -6
drivers/soc/qcom/smem_state.c
··· 104 104 105 105 if (con_id) { 106 106 index = of_property_match_string(dev->of_node, 107 - "qcom,state-names", 107 + "qcom,smem-state-names", 108 108 con_id); 109 109 if (index < 0) { 110 - dev_err(dev, "missing qcom,state-names\n"); 110 + dev_err(dev, "missing qcom,smem-state-names\n"); 111 111 return ERR_PTR(index); 112 112 } 113 113 } 114 114 115 115 ret = of_parse_phandle_with_args(dev->of_node, 116 - "qcom,state", 117 - "#qcom,state-cells", 116 + "qcom,smem-states", 117 + "#qcom,smem-state-cells", 118 118 index, 119 119 &args); 120 120 if (ret) { 121 - dev_err(dev, "failed to parse qcom,state property\n"); 121 + dev_err(dev, "failed to parse qcom,smem-states property\n"); 122 122 return ERR_PTR(ret); 123 123 } 124 124 125 125 if (args.args_count != 1) { 126 - dev_err(dev, "invalid #qcom,state-cells\n"); 126 + dev_err(dev, "invalid #qcom,smem-state-cells\n"); 127 127 return ERR_PTR(-EINVAL); 128 128 } 129 129
+4 -3
drivers/soc/qcom/smp2p.c
··· 196 196 /* Match newly created entries */ 197 197 for (i = smp2p->valid_entries; i < in->valid_entries; i++) { 198 198 list_for_each_entry(entry, &smp2p->inbound, node) { 199 - memcpy_fromio(buf, in->entries[i].name, sizeof(buf)); 199 + memcpy(buf, in->entries[i].name, sizeof(buf)); 200 200 if (!strcmp(buf, entry->name)) { 201 201 entry->value = &in->entries[i].value; 202 202 break; ··· 343 343 344 344 /* Allocate an entry from the smem item */ 345 345 strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME); 346 - memcpy_toio(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME); 347 - out->valid_entries++; 346 + memcpy(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME); 348 347 349 348 /* Make the logical entry reference the physical value */ 350 349 entry->value = &out->entries[out->valid_entries].value; 350 + 351 + out->valid_entries++; 351 352 352 353 entry->state = qcom_smem_state_register(node, &smp2p_state_ops, entry); 353 354 if (IS_ERR(entry->state)) {
+1 -1
drivers/soc/qcom/smsm.c
··· 495 495 if (!smsm->hosts) 496 496 return -ENOMEM; 497 497 498 - local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,state-cells"); 498 + local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,smem-state-cells"); 499 499 if (!local_node) { 500 500 dev_err(&pdev->dev, "no state entry\n"); 501 501 return -EINVAL;
+106 -19
drivers/soc/qcom/wcnss_ctrl.c
··· 1 1 /* 2 + * Copyright (c) 2016, Linaro Ltd. 2 3 * Copyright (c) 2015, Sony Mobile Communications Inc. 3 4 * 4 5 * This program is free software; you can redistribute it and/or modify ··· 15 14 #include <linux/module.h> 16 15 #include <linux/slab.h> 17 16 #include <linux/soc/qcom/smd.h> 17 + #include <linux/io.h> 18 + #include <linux/of_platform.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/soc/qcom/wcnss_ctrl.h> 18 21 19 22 #define WCNSS_REQUEST_TIMEOUT (5 * HZ) 23 + #define WCNSS_CBC_TIMEOUT (10 * HZ) 24 + 25 + #define WCNSS_ACK_DONE_BOOTING 1 26 + #define WCNSS_ACK_COLD_BOOTING 2 20 27 21 28 #define NV_FRAGMENT_SIZE 3072 22 29 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" ··· 34 25 * @dev: device handle 35 26 * @channel: SMD channel handle 36 27 * @ack: completion for outstanding requests 28 + * @cbc: completion for cbc complete indication 37 29 * @ack_status: status of the outstanding request 38 - * @download_nv_work: worker for uploading nv binary 30 + * @probe_work: worker for uploading nv binary 39 31 */ 40 32 struct wcnss_ctrl { 41 33 struct device *dev; 42 34 struct qcom_smd_channel *channel; 43 35 44 36 struct completion ack; 37 + struct completion cbc; 45 38 int ack_status; 46 39 47 - struct work_struct download_nv_work; 40 + struct work_struct probe_work; 48 41 }; 49 42 50 43 /* message types */ ··· 59 48 WCNSS_UPLOAD_CAL_RESP, 60 49 WCNSS_DOWNLOAD_CAL_REQ, 61 50 WCNSS_DOWNLOAD_CAL_RESP, 51 + WCNSS_VBAT_LEVEL_IND, 52 + WCNSS_BUILD_VERSION_REQ, 53 + WCNSS_BUILD_VERSION_RESP, 54 + WCNSS_PM_CONFIG_REQ, 55 + WCNSS_CBC_COMPLETE_IND, 62 56 }; 63 57 64 58 /** ··· 144 128 version->major, version->minor, 145 129 version->version, version->revision); 146 130 147 - schedule_work(&wcnss->download_nv_work); 131 + complete(&wcnss->ack); 148 132 break; 149 133 case WCNSS_DOWNLOAD_NV_RESP: 150 134 if (count != sizeof(*nvresp)) { ··· 156 140 nvresp = data; 157 141 wcnss->ack_status = nvresp->status; 158 142 complete(&wcnss->ack); 143 + break; 144 + case WCNSS_CBC_COMPLETE_IND: 145 + dev_dbg(wcnss->dev, "cold boot complete\n"); 146 + complete(&wcnss->cbc); 159 147 break; 160 148 default: 161 149 dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); ··· 176 156 static int wcnss_request_version(struct wcnss_ctrl *wcnss) 177 157 { 178 158 struct wcnss_msg_hdr msg; 159 + int ret; 179 160 180 161 msg.type = WCNSS_VERSION_REQ; 181 162 msg.len = sizeof(msg); 163 + ret = qcom_smd_send(wcnss->channel, &msg, sizeof(msg)); 164 + if (ret < 0) 165 + return ret; 182 166 183 - return qcom_smd_send(wcnss->channel, &msg, sizeof(msg)); 167 + ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT); 168 + if (!ret) { 169 + dev_err(wcnss->dev, "timeout waiting for version response\n"); 170 + return -ETIMEDOUT; 171 + } 172 + 173 + return 0; 184 174 } 185 175 186 176 /** 187 177 * wcnss_download_nv() - send nv binary to WCNSS 188 - * @work: work struct to acquire wcnss context 178 + * @wcnss: wcnss_ctrl state handle 179 + * @expect_cbc: indicator to caller that an cbc event is expected 180 + * 181 + * Returns 0 on success. Negative errno on failure. 189 182 */ 190 - static void wcnss_download_nv(struct work_struct *work) 183 + static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) 191 184 { 192 - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work); 193 185 struct wcnss_download_nv_req *req; 194 186 const struct firmware *fw; 195 187 const void *data; ··· 210 178 211 179 req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); 212 180 if (!req) 213 - return; 181 + return -ENOMEM; 214 182 215 183 ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev); 216 - if (ret) { 184 + if (ret < 0) { 217 185 dev_err(wcnss->dev, "Failed to load nv file %s: %d\n", 218 186 NVBIN_FILE, ret); 219 187 goto free_req; ··· 239 207 memcpy(req->fragment, data, req->frag_size); 240 208 241 209 ret = qcom_smd_send(wcnss->channel, req, req->hdr.len); 242 - if (ret) { 210 + if (ret < 0) { 243 211 dev_err(wcnss->dev, "failed to send smd packet\n"); 244 212 goto release_fw; 245 213 } ··· 252 220 } while (left > 0); 253 221 254 222 ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT); 255 - if (!ret) 223 + if (!ret) { 256 224 dev_err(wcnss->dev, "timeout waiting for nv upload ack\n"); 257 - else if (wcnss->ack_status != 1) 258 - dev_err(wcnss->dev, "nv upload response failed err: %d\n", 259 - wcnss->ack_status); 225 + ret = -ETIMEDOUT; 226 + } else { 227 + *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING; 228 + ret = 0; 229 + } 260 230 261 231 release_fw: 262 232 release_firmware(fw); 263 233 free_req: 264 234 kfree(req); 235 + 236 + return ret; 237 + } 238 + 239 + /** 240 + * qcom_wcnss_open_channel() - open additional SMD channel to WCNSS 241 + * @wcnss: wcnss handle, retrieved from drvdata 242 + * @name: SMD channel name 243 + * @cb: callback to handle incoming data on the channel 244 + */ 245 + struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb) 246 + { 247 + struct wcnss_ctrl *_wcnss = wcnss; 248 + 249 + return qcom_smd_open_channel(_wcnss->channel, name, cb); 250 + } 251 + EXPORT_SYMBOL(qcom_wcnss_open_channel); 252 + 253 + static void wcnss_async_probe(struct work_struct *work) 254 + { 255 + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work); 256 + bool expect_cbc; 257 + int ret; 258 + 259 + ret = wcnss_request_version(wcnss); 260 + if (ret < 0) 261 + return; 262 + 263 + ret = wcnss_download_nv(wcnss, &expect_cbc); 264 + if (ret < 0) 265 + return; 266 + 267 + /* Wait for pending cold boot completion if indicated by the nv downloader */ 268 + if (expect_cbc) { 269 + ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT); 270 + if (!ret) 271 + dev_err(wcnss->dev, "expected cold boot completion\n"); 272 + } 273 + 274 + of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); 265 275 } 266 276 267 277 static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) ··· 318 244 wcnss->channel = sdev->channel; 319 245 320 246 init_completion(&wcnss->ack); 321 - INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv); 247 + init_completion(&wcnss->cbc); 248 + INIT_WORK(&wcnss->probe_work, wcnss_async_probe); 322 249 323 250 qcom_smd_set_drvdata(sdev->channel, wcnss); 251 + dev_set_drvdata(&sdev->dev, wcnss); 324 252 325 - return wcnss_request_version(wcnss); 253 + schedule_work(&wcnss->probe_work); 254 + 255 + return 0; 326 256 } 327 257 328 - static const struct qcom_smd_id wcnss_ctrl_smd_match[] = { 329 - { .name = "WCNSS_CTRL" }, 258 + static void wcnss_ctrl_remove(struct qcom_smd_device *sdev) 259 + { 260 + struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(sdev->channel); 261 + 262 + cancel_work_sync(&wcnss->probe_work); 263 + of_platform_depopulate(&sdev->dev); 264 + } 265 + 266 + static const struct of_device_id wcnss_ctrl_of_match[] = { 267 + { .compatible = "qcom,wcnss", }, 330 268 {} 331 269 }; 332 270 333 271 static struct qcom_smd_driver wcnss_ctrl_driver = { 334 272 .probe = wcnss_ctrl_probe, 273 + .remove = wcnss_ctrl_remove, 335 274 .callback = wcnss_ctrl_smd_callback, 336 - .smd_match_table = wcnss_ctrl_smd_match, 337 275 .driver = { 338 276 .name = "qcom_wcnss_ctrl", 339 277 .owner = THIS_MODULE, 278 + .of_match_table = wcnss_ctrl_of_match, 340 279 }, 341 280 }; 342 281
+8
include/linux/qcom_scm.h
··· 29 29 extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, 30 30 u32 *resp); 31 31 32 + extern bool qcom_scm_pas_supported(u32 peripheral); 33 + extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, 34 + size_t size); 35 + extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, 36 + phys_addr_t size); 37 + extern int qcom_scm_pas_auth_and_reset(u32 peripheral); 38 + extern int qcom_scm_pas_shutdown(u32 peripheral); 39 + 32 40 #define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 33 41 #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 34 42
+8
include/linux/soc/qcom/wcnss_ctrl.h
··· 1 + #ifndef __WCNSS_CTRL_H__ 2 + #define __WCNSS_CTRL_H__ 3 + 4 + #include <linux/soc/qcom/smd.h> 5 + 6 + struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb); 7 + 8 + #endif