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

Merge tag 'qcom-arm64-for-4.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/dt

Qualcomm ARM64 Updates for v4.19 - Part 2

* Add thermal nodes for MSM8996 and SDM845

* tag 'qcom-arm64-for-4.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux: (21 commits)
arm64: dts: sdm845: Add tsens nodes
arm64: dts: msm8996: thermal: Initialise via DT and add second controller
soc: qcom: rmtfs-mem: fix memleak in probe error paths
soc: qcom: llc-slice: Add missing MODULE_LICENSE()
drivers: qcom: rpmh: fix unwanted error check for get_tcs_of_type()
drivers: qcom: rpmh-rsc: fix the loop index check in get_req_from_tcs
firmware: qcom: scm: add a dummy qcom_scm_assign_mem()
drivers: qcom: rpmh-rsc: Check cmd_db_ready() to help children
drivers: qcom: rpmh-rsc: allow active requests from wake TCS
drivers: qcom: rpmh: add support for batch RPMH request
drivers: qcom: rpmh: allow requests to be sent asynchronously
drivers: qcom: rpmh: cache sleep/wake state requests
drivers: qcom: rpmh-rsc: allow invalidation of sleep/wake TCS
drivers: qcom: rpmh-rsc: write sleep/wake requests to TCS
drivers: qcom: rpmh: add RPMH helper functions
drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs
drivers: soc: Add LLCC driver
dt-bindings: Documentation for qcom, llcc
...

+2373 -13
+26
Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
··· 1 + == Introduction== 2 + 3 + LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, 4 + that can be shared by multiple clients. Clients here are different cores in the 5 + SOC, the idea is to minimize the local caches at the clients and migrate to 6 + common pool of memory. Cache memory is divided into partitions called slices 7 + which are assigned to clients. Clients can query the slice details, activate 8 + and deactivate them. 9 + 10 + Properties: 11 + - compatible: 12 + Usage: required 13 + Value type: <string> 14 + Definition: must be "qcom,sdm845-llcc" 15 + 16 + - reg: 17 + Usage: required 18 + Value Type: <prop-encoded-array> 19 + Definition: Start address and the the size of the register region. 20 + 21 + Example: 22 + 23 + cache-controller@1100000 { 24 + compatible = "qcom,sdm845-llcc"; 25 + reg = <0x1100000 0x250000>; 26 + };
+137
Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt
··· 1 + RPMH RSC: 2 + ------------ 3 + 4 + Resource Power Manager Hardened (RPMH) is the mechanism for communicating with 5 + the hardened resource accelerators on Qualcomm SoCs. Requests to the resources 6 + can be written to the Trigger Command Set (TCS) registers and using a (addr, 7 + val) pair and triggered. Messages in the TCS are then sent in sequence over an 8 + internal bus. 9 + 10 + The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity 11 + (Resource State Coordinator a.k.a RSC) that can handle multiple sleep and 12 + active/wake resource requests. Multiple such DRVs can exist in a SoC and can 13 + be written to from Linux. The structure of each DRV follows the same template 14 + with a few variations that are captured by the properties here. 15 + 16 + A TCS may be triggered from Linux or triggered by the F/W after all the CPUs 17 + have powered off to facilitate idle power saving. TCS could be classified as - 18 + 19 + ACTIVE /* Triggered by Linux */ 20 + SLEEP /* Triggered by F/W */ 21 + WAKE /* Triggered by F/W */ 22 + CONTROL /* Triggered by F/W */ 23 + 24 + The order in which they are described in the DT, should match the hardware 25 + configuration. 26 + 27 + Requests can be made for the state of a resource, when the subsystem is active 28 + or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state 29 + will be an aggregate of the sleep votes from each of those subsystems. Clients 30 + may request a sleep value for their shared resources in addition to the active 31 + mode requests. 32 + 33 + Properties: 34 + 35 + - compatible: 36 + Usage: required 37 + Value type: <string> 38 + Definition: Should be "qcom,rpmh-rsc". 39 + 40 + - reg: 41 + Usage: required 42 + Value type: <prop-encoded-array> 43 + Definition: The first register specifies the base address of the 44 + DRV(s). The number of DRVs in the dependent on the RSC. 45 + The tcs-offset specifies the start address of the 46 + TCS in the DRVs. 47 + 48 + - reg-names: 49 + Usage: required 50 + Value type: <string> 51 + Definition: Maps the register specified in the reg property. Must be 52 + "drv-0", "drv-1", "drv-2" etc and "tcs-offset". The 53 + 54 + - interrupts: 55 + Usage: required 56 + Value type: <prop-encoded-interrupt> 57 + Definition: The interrupt that trips when a message complete/response 58 + is received for this DRV from the accelerators. 59 + 60 + - qcom,drv-id: 61 + Usage: required 62 + Value type: <u32> 63 + Definition: The id of the DRV in the RSC block that will be used by 64 + this controller. 65 + 66 + - qcom,tcs-config: 67 + Usage: required 68 + Value type: <prop-encoded-array> 69 + Definition: The tuple defining the configuration of TCS. 70 + Must have 2 cells which describe each TCS type. 71 + <type number_of_tcs>. 72 + The order of the TCS must match the hardware 73 + configuration. 74 + - Cell #1 (TCS Type): TCS types to be specified - 75 + ACTIVE_TCS 76 + SLEEP_TCS 77 + WAKE_TCS 78 + CONTROL_TCS 79 + - Cell #2 (Number of TCS): <u32> 80 + 81 + - label: 82 + Usage: optional 83 + Value type: <string> 84 + Definition: Name for the RSC. The name would be used in trace logs. 85 + 86 + Drivers that want to use the RSC to communicate with RPMH must specify their 87 + bindings as child nodes of the RSC controllers they wish to communicate with. 88 + 89 + Example 1: 90 + 91 + For a TCS whose RSC base address is is 0x179C0000 and is at a DRV id of 2, the 92 + register offsets for DRV2 start at 0D00, the register calculations are like 93 + this - 94 + DRV0: 0x179C0000 95 + DRV2: 0x179C0000 + 0x10000 = 0x179D0000 96 + DRV2: 0x179C0000 + 0x10000 * 2 = 0x179E0000 97 + TCS-OFFSET: 0xD00 98 + 99 + apps_rsc: rsc@179c0000 { 100 + label = "apps_rsc"; 101 + compatible = "qcom,rpmh-rsc"; 102 + reg = <0x179c0000 0x10000>, 103 + <0x179d0000 0x10000>, 104 + <0x179e0000 0x10000>; 105 + reg-names = "drv-0", "drv-1", "drv-2"; 106 + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, 107 + <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, 108 + <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; 109 + qcom,tcs-offset = <0xd00>; 110 + qcom,drv-id = <2>; 111 + qcom,tcs-config = <ACTIVE_TCS 2>, 112 + <SLEEP_TCS 3>, 113 + <WAKE_TCS 3>, 114 + <CONTROL_TCS 1>; 115 + }; 116 + 117 + Example 2: 118 + 119 + For a TCS whose RSC base address is 0xAF20000 and is at DRV id of 0, the 120 + register offsets for DRV0 start at 01C00, the register calculations are like 121 + this - 122 + DRV0: 0xAF20000 123 + TCS-OFFSET: 0x1C00 124 + 125 + disp_rsc: rsc@af20000 { 126 + label = "disp_rsc"; 127 + compatible = "qcom,rpmh-rsc"; 128 + reg = <0xaf20000 0x10000>; 129 + reg-names = "drv-0"; 130 + interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>; 131 + qcom,tcs-offset = <0x1c00>; 132 + qcom,drv-id = <0>; 133 + qcom,tcs-config = <ACTIVE_TCS 0>, 134 + <SLEEP_TCS 1>, 135 + <WAKE_TCS 1>, 136 + <CONTROL_TCS 0>; 137 + };
+16 -6
arch/arm64/boot/dts/qcom/msm8996.dtsi
··· 377 377 reg = <0x740000 0x20000>; 378 378 }; 379 379 380 + tsens0: thermal-sensor@4a9000 { 381 + compatible = "qcom,msm8996-tsens"; 382 + reg = <0x4a9000 0x1000>, /* TM */ 383 + <0x4a8000 0x1000>; /* SROT */ 384 + #qcom,sensors = <13>; 385 + #thermal-sensor-cells = <1>; 386 + }; 387 + 388 + tsens1: thermal-sensor@4ad000 { 389 + compatible = "qcom,msm8996-tsens"; 390 + reg = <0x4ad000 0x1000>, /* TM */ 391 + <0x4ac000 0x1000>; /* SROT */ 392 + #qcom,sensors = <8>; 393 + #thermal-sensor-cells = <1>; 394 + }; 395 + 380 396 tcsr: syscon@7a0000 { 381 397 compatible = "qcom,tcsr-msm8996", "syscon"; 382 398 reg = <0x7a0000 0x18000>; ··· 473 457 #address-cells = <1>; 474 458 #size-cells = <0>; 475 459 status = "disabled"; 476 - }; 477 - 478 - tsens0: thermal-sensor@4a8000 { 479 - compatible = "qcom,msm8996-tsens"; 480 - reg = <0x4a8000 0x2000>; 481 - #thermal-sensor-cells = <1>; 482 460 }; 483 461 484 462 blsp2_uart1: serial@75b0000 {
+16
arch/arm64/boot/dts/qcom/sdm845.dtsi
··· 962 962 }; 963 963 }; 964 964 965 + tsens0: thermal-sensor@c263000 { 966 + compatible = "qcom,sdm845-tsens", "qcom,tsens-v2"; 967 + reg = <0xc263000 0x1ff>, /* TM */ 968 + <0xc222000 0x1ff>; /* SROT */ 969 + #qcom,sensors = <13>; 970 + #thermal-sensor-cells = <1>; 971 + }; 972 + 973 + tsens1: thermal-sensor@c265000 { 974 + compatible = "qcom,sdm845-tsens", "qcom,tsens-v2"; 975 + reg = <0xc265000 0x1ff>, /* TM */ 976 + <0xc223000 0x1ff>; /* SROT */ 977 + #qcom,sensors = <8>; 978 + #thermal-sensor-cells = <1>; 979 + }; 980 + 965 981 spmi_bus: spmi@c440000 { 966 982 compatible = "qcom,spmi-pmic-arb"; 967 983 reg = <0xc440000 0x1100>,
+27
drivers/soc/qcom/Kconfig
··· 40 40 functions for connecting the underlying serial UART, SPI, and I2C 41 41 devices to the output pins. 42 42 43 + config QCOM_LLCC 44 + tristate "Qualcomm Technologies, Inc. LLCC driver" 45 + depends on ARCH_QCOM 46 + help 47 + Qualcomm Technologies, Inc. platform specific 48 + Last Level Cache Controller(LLCC) driver. This provides interfaces 49 + to clients that use the LLCC. Say yes here to enable LLCC slice 50 + driver. 51 + 52 + config QCOM_SDM845_LLCC 53 + tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver" 54 + depends on QCOM_LLCC 55 + help 56 + Say yes here to enable the LLCC driver for SDM845. This provides 57 + data required to configure LLCC so that clients can start using the 58 + LLCC slices. 59 + 43 60 config QCOM_MDT_LOADER 44 61 tristate 45 62 select QCOM_SCM ··· 91 74 service and its clients. 92 75 93 76 Say y here if you intend to boot the modem remoteproc. 77 + 78 + config QCOM_RPMH 79 + bool "Qualcomm RPM-Hardened (RPMH) Communication" 80 + depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST 81 + help 82 + Support for communication with the hardened-RPM blocks in 83 + Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an 84 + internal bus to transmit state requests for shared resources. A set 85 + of hardware components aggregate requests for these resources and 86 + help apply the aggregated state on the resource. 94 87 95 88 config QCOM_SMEM 96 89 tristate "Qualcomm Shared Memory Manager (SMEM)"
+6
drivers/soc/qcom/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + CFLAGS_rpmh-rsc.o := -I$(src) 2 3 obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o 3 4 obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o 4 5 obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o ··· 9 8 obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o 10 9 qmi_helpers-y += qmi_encdec.o qmi_interface.o 11 10 obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o 11 + obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o 12 + qcom_rpmh-y += rpmh-rsc.o 13 + qcom_rpmh-y += rpmh.o 12 14 obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o 13 15 obj-$(CONFIG_QCOM_SMEM) += smem.o 14 16 obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o ··· 19 15 obj-$(CONFIG_QCOM_SMSM) += smsm.o 20 16 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o 21 17 obj-$(CONFIG_QCOM_APR) += apr.o 18 + obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o 19 + obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
+94
drivers/soc/qcom/llcc-sdm845.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 4 + * 5 + */ 6 + 7 + #include <linux/kernel.h> 8 + #include <linux/module.h> 9 + #include <linux/of.h> 10 + #include <linux/of_device.h> 11 + #include <linux/soc/qcom/llcc-qcom.h> 12 + 13 + /* 14 + * SCT(System Cache Table) entry contains of the following members: 15 + * usecase_id: Unique id for the client's use case 16 + * slice_id: llcc slice id for each client 17 + * max_cap: The maximum capacity of the cache slice provided in KB 18 + * priority: Priority of the client used to select victim line for replacement 19 + * fixed_size: Boolean indicating if the slice has a fixed capacity 20 + * bonus_ways: Bonus ways are additional ways to be used for any slice, 21 + * if client ends up using more than reserved cache ways. Bonus 22 + * ways are allocated only if they are not reserved for some 23 + * other client. 24 + * res_ways: Reserved ways for the cache slice, the reserved ways cannot 25 + * be used by any other client than the one its assigned to. 26 + * cache_mode: Each slice operates as a cache, this controls the mode of the 27 + * slice: normal or TCM(Tightly Coupled Memory) 28 + * probe_target_ways: Determines what ways to probe for access hit. When 29 + * configured to 1 only bonus and reserved ways are probed. 30 + * When configured to 0 all ways in llcc are probed. 31 + * dis_cap_alloc: Disable capacity based allocation for a client 32 + * retain_on_pc: If this bit is set and client has maintained active vote 33 + * then the ways assigned to this client are not flushed on power 34 + * collapse. 35 + * activate_on_init: Activate the slice immediately after the SCT is programmed 36 + */ 37 + #define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ 38 + { \ 39 + .usecase_id = uid, \ 40 + .slice_id = sid, \ 41 + .max_cap = mc, \ 42 + .priority = p, \ 43 + .fixed_size = fs, \ 44 + .bonus_ways = bway, \ 45 + .res_ways = rway, \ 46 + .cache_mode = cmod, \ 47 + .probe_target_ways = ptw, \ 48 + .dis_cap_alloc = dca, \ 49 + .retain_on_pc = rp, \ 50 + .activate_on_init = a, \ 51 + } 52 + 53 + static struct llcc_slice_config sdm845_data[] = { 54 + SCT_ENTRY(LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1), 55 + SCT_ENTRY(LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0), 56 + SCT_ENTRY(LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0), 57 + SCT_ENTRY(LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0), 58 + SCT_ENTRY(LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 59 + SCT_ENTRY(LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 60 + SCT_ENTRY(LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0), 61 + SCT_ENTRY(LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 62 + SCT_ENTRY(LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 63 + SCT_ENTRY(LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0), 64 + SCT_ENTRY(LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0), 65 + SCT_ENTRY(LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1), 66 + SCT_ENTRY(LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 67 + SCT_ENTRY(LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 68 + SCT_ENTRY(LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 69 + SCT_ENTRY(LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0), 70 + SCT_ENTRY(LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0), 71 + SCT_ENTRY(LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0), 72 + }; 73 + 74 + static int sdm845_qcom_llcc_probe(struct platform_device *pdev) 75 + { 76 + return qcom_llcc_probe(pdev, sdm845_data, ARRAY_SIZE(sdm845_data)); 77 + } 78 + 79 + static const struct of_device_id sdm845_qcom_llcc_of_match[] = { 80 + { .compatible = "qcom,sdm845-llcc", }, 81 + { } 82 + }; 83 + 84 + static struct platform_driver sdm845_qcom_llcc_driver = { 85 + .driver = { 86 + .name = "sdm845-llcc", 87 + .of_match_table = sdm845_qcom_llcc_of_match, 88 + }, 89 + .probe = sdm845_qcom_llcc_probe, 90 + }; 91 + module_platform_driver(sdm845_qcom_llcc_driver); 92 + 93 + MODULE_DESCRIPTION("QCOM sdm845 LLCC driver"); 94 + MODULE_LICENSE("GPL v2");
+338
drivers/soc/qcom/llcc-slice.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 4 + * 5 + */ 6 + 7 + #include <linux/bitmap.h> 8 + #include <linux/bitops.h> 9 + #include <linux/device.h> 10 + #include <linux/io.h> 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/mutex.h> 14 + #include <linux/of_device.h> 15 + #include <linux/regmap.h> 16 + #include <linux/slab.h> 17 + #include <linux/soc/qcom/llcc-qcom.h> 18 + 19 + #define ACTIVATE BIT(0) 20 + #define DEACTIVATE BIT(1) 21 + #define ACT_CTRL_OPCODE_ACTIVATE BIT(0) 22 + #define ACT_CTRL_OPCODE_DEACTIVATE BIT(1) 23 + #define ACT_CTRL_ACT_TRIG BIT(0) 24 + #define ACT_CTRL_OPCODE_SHIFT 0x01 25 + #define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02 26 + #define ATTR1_FIXED_SIZE_SHIFT 0x03 27 + #define ATTR1_PRIORITY_SHIFT 0x04 28 + #define ATTR1_MAX_CAP_SHIFT 0x10 29 + #define ATTR0_RES_WAYS_MASK GENMASK(11, 0) 30 + #define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16) 31 + #define ATTR0_BONUS_WAYS_SHIFT 0x10 32 + #define LLCC_STATUS_READ_DELAY 100 33 + 34 + #define CACHE_LINE_SIZE_SHIFT 6 35 + 36 + #define LLCC_COMMON_STATUS0 0x0003000c 37 + #define LLCC_LB_CNT_MASK GENMASK(31, 28) 38 + #define LLCC_LB_CNT_SHIFT 28 39 + 40 + #define MAX_CAP_TO_BYTES(n) (n * SZ_1K) 41 + #define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K) 42 + #define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K) 43 + #define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n) 44 + #define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n) 45 + 46 + #define BANK_OFFSET_STRIDE 0x80000 47 + 48 + static struct llcc_drv_data *drv_data; 49 + 50 + static const struct regmap_config llcc_regmap_config = { 51 + .reg_bits = 32, 52 + .reg_stride = 4, 53 + .val_bits = 32, 54 + .fast_io = true, 55 + }; 56 + 57 + /** 58 + * llcc_slice_getd - get llcc slice descriptor 59 + * @uid: usecase_id for the client 60 + * 61 + * A pointer to llcc slice descriptor will be returned on success and 62 + * and error pointer is returned on failure 63 + */ 64 + struct llcc_slice_desc *llcc_slice_getd(u32 uid) 65 + { 66 + const struct llcc_slice_config *cfg; 67 + struct llcc_slice_desc *desc; 68 + u32 sz, count; 69 + 70 + cfg = drv_data->cfg; 71 + sz = drv_data->cfg_size; 72 + 73 + for (count = 0; cfg && count < sz; count++, cfg++) 74 + if (cfg->usecase_id == uid) 75 + break; 76 + 77 + if (count == sz || !cfg) 78 + return ERR_PTR(-ENODEV); 79 + 80 + desc = kzalloc(sizeof(*desc), GFP_KERNEL); 81 + if (!desc) 82 + return ERR_PTR(-ENOMEM); 83 + 84 + desc->slice_id = cfg->slice_id; 85 + desc->slice_size = cfg->max_cap; 86 + 87 + return desc; 88 + } 89 + EXPORT_SYMBOL_GPL(llcc_slice_getd); 90 + 91 + /** 92 + * llcc_slice_putd - llcc slice descritpor 93 + * @desc: Pointer to llcc slice descriptor 94 + */ 95 + void llcc_slice_putd(struct llcc_slice_desc *desc) 96 + { 97 + kfree(desc); 98 + } 99 + EXPORT_SYMBOL_GPL(llcc_slice_putd); 100 + 101 + static int llcc_update_act_ctrl(u32 sid, 102 + u32 act_ctrl_reg_val, u32 status) 103 + { 104 + u32 act_ctrl_reg; 105 + u32 status_reg; 106 + u32 slice_status; 107 + int ret; 108 + 109 + act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); 110 + status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); 111 + 112 + /* Set the ACTIVE trigger */ 113 + act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; 114 + ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 115 + if (ret) 116 + return ret; 117 + 118 + /* Clear the ACTIVE trigger */ 119 + act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; 120 + ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 121 + if (ret) 122 + return ret; 123 + 124 + ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, 125 + slice_status, !(slice_status & status), 126 + 0, LLCC_STATUS_READ_DELAY); 127 + return ret; 128 + } 129 + 130 + /** 131 + * llcc_slice_activate - Activate the llcc slice 132 + * @desc: Pointer to llcc slice descriptor 133 + * 134 + * A value of zero will be returned on success and a negative errno will 135 + * be returned in error cases 136 + */ 137 + int llcc_slice_activate(struct llcc_slice_desc *desc) 138 + { 139 + int ret; 140 + u32 act_ctrl_val; 141 + 142 + mutex_lock(&drv_data->lock); 143 + if (test_bit(desc->slice_id, drv_data->bitmap)) { 144 + mutex_unlock(&drv_data->lock); 145 + return 0; 146 + } 147 + 148 + act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT; 149 + 150 + ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val, 151 + DEACTIVATE); 152 + if (ret) { 153 + mutex_unlock(&drv_data->lock); 154 + return ret; 155 + } 156 + 157 + __set_bit(desc->slice_id, drv_data->bitmap); 158 + mutex_unlock(&drv_data->lock); 159 + 160 + return ret; 161 + } 162 + EXPORT_SYMBOL_GPL(llcc_slice_activate); 163 + 164 + /** 165 + * llcc_slice_deactivate - Deactivate the llcc slice 166 + * @desc: Pointer to llcc slice descriptor 167 + * 168 + * A value of zero will be returned on success and a negative errno will 169 + * be returned in error cases 170 + */ 171 + int llcc_slice_deactivate(struct llcc_slice_desc *desc) 172 + { 173 + u32 act_ctrl_val; 174 + int ret; 175 + 176 + mutex_lock(&drv_data->lock); 177 + if (!test_bit(desc->slice_id, drv_data->bitmap)) { 178 + mutex_unlock(&drv_data->lock); 179 + return 0; 180 + } 181 + act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT; 182 + 183 + ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val, 184 + ACTIVATE); 185 + if (ret) { 186 + mutex_unlock(&drv_data->lock); 187 + return ret; 188 + } 189 + 190 + __clear_bit(desc->slice_id, drv_data->bitmap); 191 + mutex_unlock(&drv_data->lock); 192 + 193 + return ret; 194 + } 195 + EXPORT_SYMBOL_GPL(llcc_slice_deactivate); 196 + 197 + /** 198 + * llcc_get_slice_id - return the slice id 199 + * @desc: Pointer to llcc slice descriptor 200 + */ 201 + int llcc_get_slice_id(struct llcc_slice_desc *desc) 202 + { 203 + return desc->slice_id; 204 + } 205 + EXPORT_SYMBOL_GPL(llcc_get_slice_id); 206 + 207 + /** 208 + * llcc_get_slice_size - return the slice id 209 + * @desc: Pointer to llcc slice descriptor 210 + */ 211 + size_t llcc_get_slice_size(struct llcc_slice_desc *desc) 212 + { 213 + return desc->slice_size; 214 + } 215 + EXPORT_SYMBOL_GPL(llcc_get_slice_size); 216 + 217 + static int qcom_llcc_cfg_program(struct platform_device *pdev) 218 + { 219 + int i; 220 + u32 attr1_cfg; 221 + u32 attr0_cfg; 222 + u32 attr1_val; 223 + u32 attr0_val; 224 + u32 max_cap_cacheline; 225 + u32 sz; 226 + int ret; 227 + const struct llcc_slice_config *llcc_table; 228 + struct llcc_slice_desc desc; 229 + u32 bcast_off = drv_data->bcast_off; 230 + 231 + sz = drv_data->cfg_size; 232 + llcc_table = drv_data->cfg; 233 + 234 + for (i = 0; i < sz; i++) { 235 + attr1_cfg = bcast_off + 236 + LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); 237 + attr0_cfg = bcast_off + 238 + LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); 239 + 240 + attr1_val = llcc_table[i].cache_mode; 241 + attr1_val |= llcc_table[i].probe_target_ways << 242 + ATTR1_PROBE_TARGET_WAYS_SHIFT; 243 + attr1_val |= llcc_table[i].fixed_size << 244 + ATTR1_FIXED_SIZE_SHIFT; 245 + attr1_val |= llcc_table[i].priority << 246 + ATTR1_PRIORITY_SHIFT; 247 + 248 + max_cap_cacheline = MAX_CAP_TO_BYTES(llcc_table[i].max_cap); 249 + 250 + /* LLCC instances can vary for each target. 251 + * The SW writes to broadcast register which gets propagated 252 + * to each llcc instace (llcc0,.. llccN). 253 + * Since the size of the memory is divided equally amongst the 254 + * llcc instances, we need to configure the max cap accordingly. 255 + */ 256 + max_cap_cacheline = max_cap_cacheline / drv_data->num_banks; 257 + max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT; 258 + attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT; 259 + 260 + attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; 261 + attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; 262 + 263 + ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val); 264 + if (ret) 265 + return ret; 266 + ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); 267 + if (ret) 268 + return ret; 269 + if (llcc_table[i].activate_on_init) { 270 + desc.slice_id = llcc_table[i].slice_id; 271 + ret = llcc_slice_activate(&desc); 272 + } 273 + } 274 + return ret; 275 + } 276 + 277 + int qcom_llcc_probe(struct platform_device *pdev, 278 + const struct llcc_slice_config *llcc_cfg, u32 sz) 279 + { 280 + u32 num_banks; 281 + struct device *dev = &pdev->dev; 282 + struct resource *res; 283 + void __iomem *base; 284 + int ret, i; 285 + 286 + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); 287 + if (!drv_data) 288 + return -ENOMEM; 289 + 290 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 291 + base = devm_ioremap_resource(&pdev->dev, res); 292 + if (IS_ERR(base)) 293 + return PTR_ERR(base); 294 + 295 + drv_data->regmap = devm_regmap_init_mmio(dev, base, 296 + &llcc_regmap_config); 297 + if (IS_ERR(drv_data->regmap)) 298 + return PTR_ERR(drv_data->regmap); 299 + 300 + ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, 301 + &num_banks); 302 + if (ret) 303 + return ret; 304 + 305 + num_banks &= LLCC_LB_CNT_MASK; 306 + num_banks >>= LLCC_LB_CNT_SHIFT; 307 + drv_data->num_banks = num_banks; 308 + 309 + for (i = 0; i < sz; i++) 310 + if (llcc_cfg[i].slice_id > drv_data->max_slices) 311 + drv_data->max_slices = llcc_cfg[i].slice_id; 312 + 313 + drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32), 314 + GFP_KERNEL); 315 + if (!drv_data->offsets) 316 + return -ENOMEM; 317 + 318 + for (i = 0; i < num_banks; i++) 319 + drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; 320 + 321 + drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE; 322 + 323 + drv_data->bitmap = devm_kcalloc(dev, 324 + BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), 325 + GFP_KERNEL); 326 + if (!drv_data->bitmap) 327 + return -ENOMEM; 328 + 329 + drv_data->cfg = llcc_cfg; 330 + drv_data->cfg_size = sz; 331 + mutex_init(&drv_data->lock); 332 + platform_set_drvdata(pdev, drv_data); 333 + 334 + return qcom_llcc_cfg_program(pdev); 335 + } 336 + EXPORT_SYMBOL_GPL(qcom_llcc_probe); 337 + 338 + MODULE_LICENSE("GPL v2");
+1 -2
drivers/soc/qcom/rmtfs_mem.c
··· 184 184 device_initialize(&rmtfs_mem->dev); 185 185 rmtfs_mem->dev.parent = &pdev->dev; 186 186 rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups; 187 + rmtfs_mem->dev.release = qcom_rmtfs_mem_release_device; 187 188 188 189 rmtfs_mem->base = devm_memremap(&rmtfs_mem->dev, rmtfs_mem->addr, 189 190 rmtfs_mem->size, MEMREMAP_WC); ··· 206 205 dev_err(&pdev->dev, "failed to add cdev: %d\n", ret); 207 206 goto put_device; 208 207 } 209 - 210 - rmtfs_mem->dev.release = qcom_rmtfs_mem_release_device; 211 208 212 209 ret = of_property_read_u32(node, "qcom,vmid", &vmid); 213 210 if (ret < 0 && ret != -EINVAL) {
+114
drivers/soc/qcom/rpmh-internal.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + 7 + #ifndef __RPM_INTERNAL_H__ 8 + #define __RPM_INTERNAL_H__ 9 + 10 + #include <linux/bitmap.h> 11 + #include <soc/qcom/tcs.h> 12 + 13 + #define TCS_TYPE_NR 4 14 + #define MAX_CMDS_PER_TCS 16 15 + #define MAX_TCS_PER_TYPE 3 16 + #define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR) 17 + #define MAX_TCS_SLOTS (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE) 18 + 19 + struct rsc_drv; 20 + 21 + /** 22 + * struct tcs_group: group of Trigger Command Sets (TCS) to send state requests 23 + * to the controller 24 + * 25 + * @drv: the controller 26 + * @type: type of the TCS in this group - active, sleep, wake 27 + * @mask: mask of the TCSes relative to all the TCSes in the RSC 28 + * @offset: start of the TCS group relative to the TCSes in the RSC 29 + * @num_tcs: number of TCSes in this type 30 + * @ncpt: number of commands in each TCS 31 + * @lock: lock for synchronizing this TCS writes 32 + * @req: requests that are sent from the TCS 33 + * @cmd_cache: flattened cache of cmds in sleep/wake TCS 34 + * @slots: indicates which of @cmd_addr are occupied 35 + */ 36 + struct tcs_group { 37 + struct rsc_drv *drv; 38 + int type; 39 + u32 mask; 40 + u32 offset; 41 + int num_tcs; 42 + int ncpt; 43 + spinlock_t lock; 44 + const struct tcs_request *req[MAX_TCS_PER_TYPE]; 45 + u32 *cmd_cache; 46 + DECLARE_BITMAP(slots, MAX_TCS_SLOTS); 47 + }; 48 + 49 + /** 50 + * struct rpmh_request: the message to be sent to rpmh-rsc 51 + * 52 + * @msg: the request 53 + * @cmd: the payload that will be part of the @msg 54 + * @completion: triggered when request is done 55 + * @dev: the device making the request 56 + * @err: err return from the controller 57 + * @needs_free: check to free dynamically allocated request object 58 + */ 59 + struct rpmh_request { 60 + struct tcs_request msg; 61 + struct tcs_cmd cmd[MAX_RPMH_PAYLOAD]; 62 + struct completion *completion; 63 + const struct device *dev; 64 + int err; 65 + bool needs_free; 66 + }; 67 + 68 + /** 69 + * struct rpmh_ctrlr: our representation of the controller 70 + * 71 + * @cache: the list of cached requests 72 + * @cache_lock: synchronize access to the cache data 73 + * @dirty: was the cache updated since flush 74 + * @batch_cache: Cache sleep and wake requests sent as batch 75 + */ 76 + struct rpmh_ctrlr { 77 + struct list_head cache; 78 + spinlock_t cache_lock; 79 + bool dirty; 80 + struct list_head batch_cache; 81 + }; 82 + 83 + /** 84 + * struct rsc_drv: the Direct Resource Voter (DRV) of the 85 + * Resource State Coordinator controller (RSC) 86 + * 87 + * @name: controller identifier 88 + * @tcs_base: start address of the TCS registers in this controller 89 + * @id: instance id in the controller (Direct Resource Voter) 90 + * @num_tcs: number of TCSes in this DRV 91 + * @tcs: TCS groups 92 + * @tcs_in_use: s/w state of the TCS 93 + * @lock: synchronize state of the controller 94 + * @client: handle to the DRV's client. 95 + */ 96 + struct rsc_drv { 97 + const char *name; 98 + void __iomem *tcs_base; 99 + int id; 100 + int num_tcs; 101 + struct tcs_group tcs[TCS_TYPE_NR]; 102 + DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR); 103 + spinlock_t lock; 104 + struct rpmh_ctrlr client; 105 + }; 106 + 107 + int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg); 108 + int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, 109 + const struct tcs_request *msg); 110 + int rpmh_rsc_invalidate(struct rsc_drv *drv); 111 + 112 + void rpmh_tx_done(const struct tcs_request *msg, int r); 113 + 114 + #endif /* __RPM_INTERNAL_H__ */
+693
drivers/soc/qcom/rpmh-rsc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME 7 + 8 + #include <linux/atomic.h> 9 + #include <linux/delay.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/io.h> 12 + #include <linux/kernel.h> 13 + #include <linux/list.h> 14 + #include <linux/of.h> 15 + #include <linux/of_irq.h> 16 + #include <linux/of_platform.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/slab.h> 19 + #include <linux/spinlock.h> 20 + 21 + #include <soc/qcom/cmd-db.h> 22 + #include <soc/qcom/tcs.h> 23 + #include <dt-bindings/soc/qcom,rpmh-rsc.h> 24 + 25 + #include "rpmh-internal.h" 26 + 27 + #define CREATE_TRACE_POINTS 28 + #include "trace-rpmh.h" 29 + 30 + #define RSC_DRV_TCS_OFFSET 672 31 + #define RSC_DRV_CMD_OFFSET 20 32 + 33 + /* DRV Configuration Information Register */ 34 + #define DRV_PRNT_CHLD_CONFIG 0x0C 35 + #define DRV_NUM_TCS_MASK 0x3F 36 + #define DRV_NUM_TCS_SHIFT 6 37 + #define DRV_NCPT_MASK 0x1F 38 + #define DRV_NCPT_SHIFT 27 39 + 40 + /* Register offsets */ 41 + #define RSC_DRV_IRQ_ENABLE 0x00 42 + #define RSC_DRV_IRQ_STATUS 0x04 43 + #define RSC_DRV_IRQ_CLEAR 0x08 44 + #define RSC_DRV_CMD_WAIT_FOR_CMPL 0x10 45 + #define RSC_DRV_CONTROL 0x14 46 + #define RSC_DRV_STATUS 0x18 47 + #define RSC_DRV_CMD_ENABLE 0x1C 48 + #define RSC_DRV_CMD_MSGID 0x30 49 + #define RSC_DRV_CMD_ADDR 0x34 50 + #define RSC_DRV_CMD_DATA 0x38 51 + #define RSC_DRV_CMD_STATUS 0x3C 52 + #define RSC_DRV_CMD_RESP_DATA 0x40 53 + 54 + #define TCS_AMC_MODE_ENABLE BIT(16) 55 + #define TCS_AMC_MODE_TRIGGER BIT(24) 56 + 57 + /* TCS CMD register bit mask */ 58 + #define CMD_MSGID_LEN 8 59 + #define CMD_MSGID_RESP_REQ BIT(8) 60 + #define CMD_MSGID_WRITE BIT(16) 61 + #define CMD_STATUS_ISSUED BIT(8) 62 + #define CMD_STATUS_COMPL BIT(16) 63 + 64 + static u32 read_tcs_reg(struct rsc_drv *drv, int reg, int tcs_id, int cmd_id) 65 + { 66 + return readl_relaxed(drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id + 67 + RSC_DRV_CMD_OFFSET * cmd_id); 68 + } 69 + 70 + static void write_tcs_cmd(struct rsc_drv *drv, int reg, int tcs_id, int cmd_id, 71 + u32 data) 72 + { 73 + writel_relaxed(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id + 74 + RSC_DRV_CMD_OFFSET * cmd_id); 75 + } 76 + 77 + static void write_tcs_reg(struct rsc_drv *drv, int reg, int tcs_id, u32 data) 78 + { 79 + writel_relaxed(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id); 80 + } 81 + 82 + static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, int tcs_id, 83 + u32 data) 84 + { 85 + writel(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id); 86 + for (;;) { 87 + if (data == readl(drv->tcs_base + reg + 88 + RSC_DRV_TCS_OFFSET * tcs_id)) 89 + break; 90 + udelay(1); 91 + } 92 + } 93 + 94 + static bool tcs_is_free(struct rsc_drv *drv, int tcs_id) 95 + { 96 + return !test_bit(tcs_id, drv->tcs_in_use) && 97 + read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0); 98 + } 99 + 100 + static struct tcs_group *get_tcs_of_type(struct rsc_drv *drv, int type) 101 + { 102 + return &drv->tcs[type]; 103 + } 104 + 105 + static int tcs_invalidate(struct rsc_drv *drv, int type) 106 + { 107 + int m; 108 + struct tcs_group *tcs; 109 + 110 + tcs = get_tcs_of_type(drv, type); 111 + 112 + spin_lock(&tcs->lock); 113 + if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) { 114 + spin_unlock(&tcs->lock); 115 + return 0; 116 + } 117 + 118 + for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) { 119 + if (!tcs_is_free(drv, m)) { 120 + spin_unlock(&tcs->lock); 121 + return -EAGAIN; 122 + } 123 + write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); 124 + } 125 + bitmap_zero(tcs->slots, MAX_TCS_SLOTS); 126 + spin_unlock(&tcs->lock); 127 + 128 + return 0; 129 + } 130 + 131 + /** 132 + * rpmh_rsc_invalidate - Invalidate sleep and wake TCSes 133 + * 134 + * @drv: the RSC controller 135 + */ 136 + int rpmh_rsc_invalidate(struct rsc_drv *drv) 137 + { 138 + int ret; 139 + 140 + ret = tcs_invalidate(drv, SLEEP_TCS); 141 + if (!ret) 142 + ret = tcs_invalidate(drv, WAKE_TCS); 143 + 144 + return ret; 145 + } 146 + 147 + static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv, 148 + const struct tcs_request *msg) 149 + { 150 + int type, ret; 151 + struct tcs_group *tcs; 152 + 153 + switch (msg->state) { 154 + case RPMH_ACTIVE_ONLY_STATE: 155 + type = ACTIVE_TCS; 156 + break; 157 + case RPMH_WAKE_ONLY_STATE: 158 + type = WAKE_TCS; 159 + break; 160 + case RPMH_SLEEP_STATE: 161 + type = SLEEP_TCS; 162 + break; 163 + default: 164 + return ERR_PTR(-EINVAL); 165 + } 166 + 167 + /* 168 + * If we are making an active request on a RSC that does not have a 169 + * dedicated TCS for active state use, then re-purpose a wake TCS to 170 + * send active votes. 171 + * NOTE: The driver must be aware that this RSC does not have a 172 + * dedicated AMC, and therefore would invalidate the sleep and wake 173 + * TCSes before making an active state request. 174 + */ 175 + tcs = get_tcs_of_type(drv, type); 176 + if (msg->state == RPMH_ACTIVE_ONLY_STATE && !tcs->num_tcs) { 177 + tcs = get_tcs_of_type(drv, WAKE_TCS); 178 + if (tcs->num_tcs) { 179 + ret = rpmh_rsc_invalidate(drv); 180 + if (ret) 181 + return ERR_PTR(ret); 182 + } 183 + } 184 + 185 + return tcs; 186 + } 187 + 188 + static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv, 189 + int tcs_id) 190 + { 191 + struct tcs_group *tcs; 192 + int i; 193 + 194 + for (i = 0; i < TCS_TYPE_NR; i++) { 195 + tcs = &drv->tcs[i]; 196 + if (tcs->mask & BIT(tcs_id)) 197 + return tcs->req[tcs_id - tcs->offset]; 198 + } 199 + 200 + return NULL; 201 + } 202 + 203 + /** 204 + * tcs_tx_done: TX Done interrupt handler 205 + */ 206 + static irqreturn_t tcs_tx_done(int irq, void *p) 207 + { 208 + struct rsc_drv *drv = p; 209 + int i, j, err = 0; 210 + unsigned long irq_status; 211 + const struct tcs_request *req; 212 + struct tcs_cmd *cmd; 213 + 214 + irq_status = read_tcs_reg(drv, RSC_DRV_IRQ_STATUS, 0, 0); 215 + 216 + for_each_set_bit(i, &irq_status, BITS_PER_LONG) { 217 + req = get_req_from_tcs(drv, i); 218 + if (!req) { 219 + WARN_ON(1); 220 + goto skip; 221 + } 222 + 223 + err = 0; 224 + for (j = 0; j < req->num_cmds; j++) { 225 + u32 sts; 226 + 227 + cmd = &req->cmds[j]; 228 + sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, i, j); 229 + if (!(sts & CMD_STATUS_ISSUED) || 230 + ((req->wait_for_compl || cmd->wait) && 231 + !(sts & CMD_STATUS_COMPL))) { 232 + pr_err("Incomplete request: %s: addr=%#x data=%#x", 233 + drv->name, cmd->addr, cmd->data); 234 + err = -EIO; 235 + } 236 + } 237 + 238 + trace_rpmh_tx_done(drv, i, req, err); 239 + skip: 240 + /* Reclaim the TCS */ 241 + write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); 242 + write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i)); 243 + spin_lock(&drv->lock); 244 + clear_bit(i, drv->tcs_in_use); 245 + spin_unlock(&drv->lock); 246 + if (req) 247 + rpmh_tx_done(req, err); 248 + } 249 + 250 + return IRQ_HANDLED; 251 + } 252 + 253 + static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, 254 + const struct tcs_request *msg) 255 + { 256 + u32 msgid, cmd_msgid; 257 + u32 cmd_enable = 0; 258 + u32 cmd_complete; 259 + struct tcs_cmd *cmd; 260 + int i, j; 261 + 262 + cmd_msgid = CMD_MSGID_LEN; 263 + cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0; 264 + cmd_msgid |= CMD_MSGID_WRITE; 265 + 266 + cmd_complete = read_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0); 267 + 268 + for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) { 269 + cmd = &msg->cmds[i]; 270 + cmd_enable |= BIT(j); 271 + cmd_complete |= cmd->wait << j; 272 + msgid = cmd_msgid; 273 + msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0; 274 + 275 + write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid); 276 + write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr); 277 + write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data); 278 + trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd); 279 + } 280 + 281 + write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, cmd_complete); 282 + cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0); 283 + write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable); 284 + } 285 + 286 + static void __tcs_trigger(struct rsc_drv *drv, int tcs_id) 287 + { 288 + u32 enable; 289 + 290 + /* 291 + * HW req: Clear the DRV_CONTROL and enable TCS again 292 + * While clearing ensure that the AMC mode trigger is cleared 293 + * and then the mode enable is cleared. 294 + */ 295 + enable = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, 0); 296 + enable &= ~TCS_AMC_MODE_TRIGGER; 297 + write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable); 298 + enable &= ~TCS_AMC_MODE_ENABLE; 299 + write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable); 300 + 301 + /* Enable the AMC mode on the TCS and then trigger the TCS */ 302 + enable = TCS_AMC_MODE_ENABLE; 303 + write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable); 304 + enable |= TCS_AMC_MODE_TRIGGER; 305 + write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable); 306 + } 307 + 308 + static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs, 309 + const struct tcs_request *msg) 310 + { 311 + unsigned long curr_enabled; 312 + u32 addr; 313 + int i, j, k; 314 + int tcs_id = tcs->offset; 315 + 316 + for (i = 0; i < tcs->num_tcs; i++, tcs_id++) { 317 + if (tcs_is_free(drv, tcs_id)) 318 + continue; 319 + 320 + curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0); 321 + 322 + for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) { 323 + addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, j); 324 + for (k = 0; k < msg->num_cmds; k++) { 325 + if (addr == msg->cmds[k].addr) 326 + return -EBUSY; 327 + } 328 + } 329 + } 330 + 331 + return 0; 332 + } 333 + 334 + static int find_free_tcs(struct tcs_group *tcs) 335 + { 336 + int i; 337 + 338 + for (i = 0; i < tcs->num_tcs; i++) { 339 + if (tcs_is_free(tcs->drv, tcs->offset + i)) 340 + return tcs->offset + i; 341 + } 342 + 343 + return -EBUSY; 344 + } 345 + 346 + static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg) 347 + { 348 + struct tcs_group *tcs; 349 + int tcs_id; 350 + unsigned long flags; 351 + int ret; 352 + 353 + tcs = get_tcs_for_msg(drv, msg); 354 + if (IS_ERR(tcs)) 355 + return PTR_ERR(tcs); 356 + 357 + spin_lock_irqsave(&tcs->lock, flags); 358 + spin_lock(&drv->lock); 359 + /* 360 + * The h/w does not like if we send a request to the same address, 361 + * when one is already in-flight or being processed. 362 + */ 363 + ret = check_for_req_inflight(drv, tcs, msg); 364 + if (ret) { 365 + spin_unlock(&drv->lock); 366 + goto done_write; 367 + } 368 + 369 + tcs_id = find_free_tcs(tcs); 370 + if (tcs_id < 0) { 371 + ret = tcs_id; 372 + spin_unlock(&drv->lock); 373 + goto done_write; 374 + } 375 + 376 + tcs->req[tcs_id - tcs->offset] = msg; 377 + set_bit(tcs_id, drv->tcs_in_use); 378 + spin_unlock(&drv->lock); 379 + 380 + __tcs_buffer_write(drv, tcs_id, 0, msg); 381 + __tcs_trigger(drv, tcs_id); 382 + 383 + done_write: 384 + spin_unlock_irqrestore(&tcs->lock, flags); 385 + return ret; 386 + } 387 + 388 + /** 389 + * rpmh_rsc_send_data: Validate the incoming message and write to the 390 + * appropriate TCS block. 391 + * 392 + * @drv: the controller 393 + * @msg: the data to be sent 394 + * 395 + * Return: 0 on success, -EINVAL on error. 396 + * Note: This call blocks until a valid data is written to the TCS. 397 + */ 398 + int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) 399 + { 400 + int ret; 401 + 402 + if (!msg || !msg->cmds || !msg->num_cmds || 403 + msg->num_cmds > MAX_RPMH_PAYLOAD) { 404 + WARN_ON(1); 405 + return -EINVAL; 406 + } 407 + 408 + do { 409 + ret = tcs_write(drv, msg); 410 + if (ret == -EBUSY) { 411 + pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n", 412 + msg->cmds[0].addr); 413 + udelay(10); 414 + } 415 + } while (ret == -EBUSY); 416 + 417 + return ret; 418 + } 419 + 420 + static int find_match(const struct tcs_group *tcs, const struct tcs_cmd *cmd, 421 + int len) 422 + { 423 + int i, j; 424 + 425 + /* Check for already cached commands */ 426 + for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) { 427 + if (tcs->cmd_cache[i] != cmd[0].addr) 428 + continue; 429 + if (i + len >= tcs->num_tcs * tcs->ncpt) 430 + goto seq_err; 431 + for (j = 0; j < len; j++) { 432 + if (tcs->cmd_cache[i + j] != cmd[j].addr) 433 + goto seq_err; 434 + } 435 + return i; 436 + } 437 + 438 + return -ENODATA; 439 + 440 + seq_err: 441 + WARN(1, "Message does not match previous sequence.\n"); 442 + return -EINVAL; 443 + } 444 + 445 + static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, 446 + int *tcs_id, int *cmd_id) 447 + { 448 + int slot, offset; 449 + int i = 0; 450 + 451 + /* Find if we already have the msg in our TCS */ 452 + slot = find_match(tcs, msg->cmds, msg->num_cmds); 453 + if (slot >= 0) 454 + goto copy_data; 455 + 456 + /* Do over, until we can fit the full payload in a TCS */ 457 + do { 458 + slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS, 459 + i, msg->num_cmds, 0); 460 + if (slot == tcs->num_tcs * tcs->ncpt) 461 + return -ENOMEM; 462 + i += tcs->ncpt; 463 + } while (slot + msg->num_cmds - 1 >= i); 464 + 465 + copy_data: 466 + bitmap_set(tcs->slots, slot, msg->num_cmds); 467 + /* Copy the addresses of the resources over to the slots */ 468 + for (i = 0; i < msg->num_cmds; i++) 469 + tcs->cmd_cache[slot + i] = msg->cmds[i].addr; 470 + 471 + offset = slot / tcs->ncpt; 472 + *tcs_id = offset + tcs->offset; 473 + *cmd_id = slot % tcs->ncpt; 474 + 475 + return 0; 476 + } 477 + 478 + static int tcs_ctrl_write(struct rsc_drv *drv, const struct tcs_request *msg) 479 + { 480 + struct tcs_group *tcs; 481 + int tcs_id = 0, cmd_id = 0; 482 + unsigned long flags; 483 + int ret; 484 + 485 + tcs = get_tcs_for_msg(drv, msg); 486 + if (IS_ERR(tcs)) 487 + return PTR_ERR(tcs); 488 + 489 + spin_lock_irqsave(&tcs->lock, flags); 490 + /* find the TCS id and the command in the TCS to write to */ 491 + ret = find_slots(tcs, msg, &tcs_id, &cmd_id); 492 + if (!ret) 493 + __tcs_buffer_write(drv, tcs_id, cmd_id, msg); 494 + spin_unlock_irqrestore(&tcs->lock, flags); 495 + 496 + return ret; 497 + } 498 + 499 + /** 500 + * rpmh_rsc_write_ctrl_data: Write request to the controller 501 + * 502 + * @drv: the controller 503 + * @msg: the data to be written to the controller 504 + * 505 + * There is no response returned for writing the request to the controller. 506 + */ 507 + int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg) 508 + { 509 + if (!msg || !msg->cmds || !msg->num_cmds || 510 + msg->num_cmds > MAX_RPMH_PAYLOAD) { 511 + pr_err("Payload error\n"); 512 + return -EINVAL; 513 + } 514 + 515 + /* Data sent to this API will not be sent immediately */ 516 + if (msg->state == RPMH_ACTIVE_ONLY_STATE) 517 + return -EINVAL; 518 + 519 + return tcs_ctrl_write(drv, msg); 520 + } 521 + 522 + static int rpmh_probe_tcs_config(struct platform_device *pdev, 523 + struct rsc_drv *drv) 524 + { 525 + struct tcs_type_config { 526 + u32 type; 527 + u32 n; 528 + } tcs_cfg[TCS_TYPE_NR] = { { 0 } }; 529 + struct device_node *dn = pdev->dev.of_node; 530 + u32 config, max_tcs, ncpt, offset; 531 + int i, ret, n, st = 0; 532 + struct tcs_group *tcs; 533 + struct resource *res; 534 + void __iomem *base; 535 + char drv_id[10] = {0}; 536 + 537 + snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id); 538 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, drv_id); 539 + base = devm_ioremap_resource(&pdev->dev, res); 540 + if (IS_ERR(base)) 541 + return PTR_ERR(base); 542 + 543 + ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset); 544 + if (ret) 545 + return ret; 546 + drv->tcs_base = base + offset; 547 + 548 + config = readl_relaxed(base + DRV_PRNT_CHLD_CONFIG); 549 + 550 + max_tcs = config; 551 + max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id); 552 + max_tcs = max_tcs >> (DRV_NUM_TCS_SHIFT * drv->id); 553 + 554 + ncpt = config & (DRV_NCPT_MASK << DRV_NCPT_SHIFT); 555 + ncpt = ncpt >> DRV_NCPT_SHIFT; 556 + 557 + n = of_property_count_u32_elems(dn, "qcom,tcs-config"); 558 + if (n != 2 * TCS_TYPE_NR) 559 + return -EINVAL; 560 + 561 + for (i = 0; i < TCS_TYPE_NR; i++) { 562 + ret = of_property_read_u32_index(dn, "qcom,tcs-config", 563 + i * 2, &tcs_cfg[i].type); 564 + if (ret) 565 + return ret; 566 + if (tcs_cfg[i].type >= TCS_TYPE_NR) 567 + return -EINVAL; 568 + 569 + ret = of_property_read_u32_index(dn, "qcom,tcs-config", 570 + i * 2 + 1, &tcs_cfg[i].n); 571 + if (ret) 572 + return ret; 573 + if (tcs_cfg[i].n > MAX_TCS_PER_TYPE) 574 + return -EINVAL; 575 + } 576 + 577 + for (i = 0; i < TCS_TYPE_NR; i++) { 578 + tcs = &drv->tcs[tcs_cfg[i].type]; 579 + if (tcs->drv) 580 + return -EINVAL; 581 + tcs->drv = drv; 582 + tcs->type = tcs_cfg[i].type; 583 + tcs->num_tcs = tcs_cfg[i].n; 584 + tcs->ncpt = ncpt; 585 + spin_lock_init(&tcs->lock); 586 + 587 + if (!tcs->num_tcs || tcs->type == CONTROL_TCS) 588 + continue; 589 + 590 + if (st + tcs->num_tcs > max_tcs || 591 + st + tcs->num_tcs >= BITS_PER_BYTE * sizeof(tcs->mask)) 592 + return -EINVAL; 593 + 594 + tcs->mask = ((1 << tcs->num_tcs) - 1) << st; 595 + tcs->offset = st; 596 + st += tcs->num_tcs; 597 + 598 + /* 599 + * Allocate memory to cache sleep and wake requests to 600 + * avoid reading TCS register memory. 601 + */ 602 + if (tcs->type == ACTIVE_TCS) 603 + continue; 604 + 605 + tcs->cmd_cache = devm_kcalloc(&pdev->dev, 606 + tcs->num_tcs * ncpt, sizeof(u32), 607 + GFP_KERNEL); 608 + if (!tcs->cmd_cache) 609 + return -ENOMEM; 610 + } 611 + 612 + drv->num_tcs = st; 613 + 614 + return 0; 615 + } 616 + 617 + static int rpmh_rsc_probe(struct platform_device *pdev) 618 + { 619 + struct device_node *dn = pdev->dev.of_node; 620 + struct rsc_drv *drv; 621 + int ret, irq; 622 + 623 + /* 624 + * Even though RPMh doesn't directly use cmd-db, all of its children 625 + * do. To avoid adding this check to our children we'll do it now. 626 + */ 627 + ret = cmd_db_ready(); 628 + if (ret) { 629 + if (ret != -EPROBE_DEFER) 630 + dev_err(&pdev->dev, "Command DB not available (%d)\n", 631 + ret); 632 + return ret; 633 + } 634 + 635 + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); 636 + if (!drv) 637 + return -ENOMEM; 638 + 639 + ret = of_property_read_u32(dn, "qcom,drv-id", &drv->id); 640 + if (ret) 641 + return ret; 642 + 643 + drv->name = of_get_property(dn, "label", NULL); 644 + if (!drv->name) 645 + drv->name = dev_name(&pdev->dev); 646 + 647 + ret = rpmh_probe_tcs_config(pdev, drv); 648 + if (ret) 649 + return ret; 650 + 651 + spin_lock_init(&drv->lock); 652 + bitmap_zero(drv->tcs_in_use, MAX_TCS_NR); 653 + 654 + irq = platform_get_irq(pdev, drv->id); 655 + if (irq < 0) 656 + return irq; 657 + 658 + ret = devm_request_irq(&pdev->dev, irq, tcs_tx_done, 659 + IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, 660 + drv->name, drv); 661 + if (ret) 662 + return ret; 663 + 664 + /* Enable the active TCS to send requests immediately */ 665 + write_tcs_reg(drv, RSC_DRV_IRQ_ENABLE, 0, drv->tcs[ACTIVE_TCS].mask); 666 + 667 + spin_lock_init(&drv->client.cache_lock); 668 + INIT_LIST_HEAD(&drv->client.cache); 669 + INIT_LIST_HEAD(&drv->client.batch_cache); 670 + 671 + dev_set_drvdata(&pdev->dev, drv); 672 + 673 + return devm_of_platform_populate(&pdev->dev); 674 + } 675 + 676 + static const struct of_device_id rpmh_drv_match[] = { 677 + { .compatible = "qcom,rpmh-rsc", }, 678 + { } 679 + }; 680 + 681 + static struct platform_driver rpmh_driver = { 682 + .probe = rpmh_rsc_probe, 683 + .driver = { 684 + .name = "rpmh", 685 + .of_match_table = rpmh_drv_match, 686 + }, 687 + }; 688 + 689 + static int __init rpmh_driver_init(void) 690 + { 691 + return platform_driver_register(&rpmh_driver); 692 + } 693 + arch_initcall(rpmh_driver_init);
+513
drivers/soc/qcom/rpmh.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #include <linux/atomic.h> 7 + #include <linux/bug.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/jiffies.h> 10 + #include <linux/kernel.h> 11 + #include <linux/list.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/slab.h> 16 + #include <linux/spinlock.h> 17 + #include <linux/types.h> 18 + #include <linux/wait.h> 19 + 20 + #include <soc/qcom/rpmh.h> 21 + 22 + #include "rpmh-internal.h" 23 + 24 + #define RPMH_TIMEOUT_MS msecs_to_jiffies(10000) 25 + 26 + #define DEFINE_RPMH_MSG_ONSTACK(dev, s, q, name) \ 27 + struct rpmh_request name = { \ 28 + .msg = { \ 29 + .state = s, \ 30 + .cmds = name.cmd, \ 31 + .num_cmds = 0, \ 32 + .wait_for_compl = true, \ 33 + }, \ 34 + .cmd = { { 0 } }, \ 35 + .completion = q, \ 36 + .dev = dev, \ 37 + .needs_free = false, \ 38 + } 39 + 40 + #define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, client) 41 + 42 + /** 43 + * struct cache_req: the request object for caching 44 + * 45 + * @addr: the address of the resource 46 + * @sleep_val: the sleep vote 47 + * @wake_val: the wake vote 48 + * @list: linked list obj 49 + */ 50 + struct cache_req { 51 + u32 addr; 52 + u32 sleep_val; 53 + u32 wake_val; 54 + struct list_head list; 55 + }; 56 + 57 + /** 58 + * struct batch_cache_req - An entry in our batch catch 59 + * 60 + * @list: linked list obj 61 + * @count: number of messages 62 + * @rpm_msgs: the messages 63 + */ 64 + 65 + struct batch_cache_req { 66 + struct list_head list; 67 + int count; 68 + struct rpmh_request rpm_msgs[]; 69 + }; 70 + 71 + static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev) 72 + { 73 + struct rsc_drv *drv = dev_get_drvdata(dev->parent); 74 + 75 + return &drv->client; 76 + } 77 + 78 + void rpmh_tx_done(const struct tcs_request *msg, int r) 79 + { 80 + struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request, 81 + msg); 82 + struct completion *compl = rpm_msg->completion; 83 + 84 + rpm_msg->err = r; 85 + 86 + if (r) 87 + dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n", 88 + rpm_msg->msg.cmds[0].addr, r); 89 + 90 + if (!compl) 91 + goto exit; 92 + 93 + /* Signal the blocking thread we are done */ 94 + complete(compl); 95 + 96 + exit: 97 + if (rpm_msg->needs_free) 98 + kfree(rpm_msg); 99 + } 100 + 101 + static struct cache_req *__find_req(struct rpmh_ctrlr *ctrlr, u32 addr) 102 + { 103 + struct cache_req *p, *req = NULL; 104 + 105 + list_for_each_entry(p, &ctrlr->cache, list) { 106 + if (p->addr == addr) { 107 + req = p; 108 + break; 109 + } 110 + } 111 + 112 + return req; 113 + } 114 + 115 + static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr, 116 + enum rpmh_state state, 117 + struct tcs_cmd *cmd) 118 + { 119 + struct cache_req *req; 120 + unsigned long flags; 121 + 122 + spin_lock_irqsave(&ctrlr->cache_lock, flags); 123 + req = __find_req(ctrlr, cmd->addr); 124 + if (req) 125 + goto existing; 126 + 127 + req = kzalloc(sizeof(*req), GFP_ATOMIC); 128 + if (!req) { 129 + req = ERR_PTR(-ENOMEM); 130 + goto unlock; 131 + } 132 + 133 + req->addr = cmd->addr; 134 + req->sleep_val = req->wake_val = UINT_MAX; 135 + INIT_LIST_HEAD(&req->list); 136 + list_add_tail(&req->list, &ctrlr->cache); 137 + 138 + existing: 139 + switch (state) { 140 + case RPMH_ACTIVE_ONLY_STATE: 141 + if (req->sleep_val != UINT_MAX) 142 + req->wake_val = cmd->data; 143 + break; 144 + case RPMH_WAKE_ONLY_STATE: 145 + req->wake_val = cmd->data; 146 + break; 147 + case RPMH_SLEEP_STATE: 148 + req->sleep_val = cmd->data; 149 + break; 150 + default: 151 + break; 152 + } 153 + 154 + ctrlr->dirty = true; 155 + unlock: 156 + spin_unlock_irqrestore(&ctrlr->cache_lock, flags); 157 + 158 + return req; 159 + } 160 + 161 + /** 162 + * __rpmh_write: Cache and send the RPMH request 163 + * 164 + * @dev: The device making the request 165 + * @state: Active/Sleep request type 166 + * @rpm_msg: The data that needs to be sent (cmds). 167 + * 168 + * Cache the RPMH request and send if the state is ACTIVE_ONLY. 169 + * SLEEP/WAKE_ONLY requests are not sent to the controller at 170 + * this time. Use rpmh_flush() to send them to the controller. 171 + */ 172 + static int __rpmh_write(const struct device *dev, enum rpmh_state state, 173 + struct rpmh_request *rpm_msg) 174 + { 175 + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); 176 + int ret = -EINVAL; 177 + struct cache_req *req; 178 + int i; 179 + 180 + rpm_msg->msg.state = state; 181 + 182 + /* Cache the request in our store and link the payload */ 183 + for (i = 0; i < rpm_msg->msg.num_cmds; i++) { 184 + req = cache_rpm_request(ctrlr, state, &rpm_msg->msg.cmds[i]); 185 + if (IS_ERR(req)) 186 + return PTR_ERR(req); 187 + } 188 + 189 + rpm_msg->msg.state = state; 190 + 191 + if (state == RPMH_ACTIVE_ONLY_STATE) { 192 + WARN_ON(irqs_disabled()); 193 + ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg); 194 + } else { 195 + ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), 196 + &rpm_msg->msg); 197 + /* Clean up our call by spoofing tx_done */ 198 + rpmh_tx_done(&rpm_msg->msg, ret); 199 + } 200 + 201 + return ret; 202 + } 203 + 204 + static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state, 205 + const struct tcs_cmd *cmd, u32 n) 206 + { 207 + if (!cmd || !n || n > MAX_RPMH_PAYLOAD) 208 + return -EINVAL; 209 + 210 + memcpy(req->cmd, cmd, n * sizeof(*cmd)); 211 + 212 + req->msg.state = state; 213 + req->msg.cmds = req->cmd; 214 + req->msg.num_cmds = n; 215 + 216 + return 0; 217 + } 218 + 219 + /** 220 + * rpmh_write_async: Write a set of RPMH commands 221 + * 222 + * @dev: The device making the request 223 + * @state: Active/sleep set 224 + * @cmd: The payload data 225 + * @n: The number of elements in payload 226 + * 227 + * Write a set of RPMH commands, the order of commands is maintained 228 + * and will be sent as a single shot. 229 + */ 230 + int rpmh_write_async(const struct device *dev, enum rpmh_state state, 231 + const struct tcs_cmd *cmd, u32 n) 232 + { 233 + struct rpmh_request *rpm_msg; 234 + int ret; 235 + 236 + rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC); 237 + if (!rpm_msg) 238 + return -ENOMEM; 239 + rpm_msg->needs_free = true; 240 + 241 + ret = __fill_rpmh_msg(rpm_msg, state, cmd, n); 242 + if (ret) { 243 + kfree(rpm_msg); 244 + return ret; 245 + } 246 + 247 + return __rpmh_write(dev, state, rpm_msg); 248 + } 249 + EXPORT_SYMBOL(rpmh_write_async); 250 + 251 + /** 252 + * rpmh_write: Write a set of RPMH commands and block until response 253 + * 254 + * @rc: The RPMH handle got from rpmh_get_client 255 + * @state: Active/sleep set 256 + * @cmd: The payload data 257 + * @n: The number of elements in @cmd 258 + * 259 + * May sleep. Do not call from atomic contexts. 260 + */ 261 + int rpmh_write(const struct device *dev, enum rpmh_state state, 262 + const struct tcs_cmd *cmd, u32 n) 263 + { 264 + DECLARE_COMPLETION_ONSTACK(compl); 265 + DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg); 266 + int ret; 267 + 268 + if (!cmd || !n || n > MAX_RPMH_PAYLOAD) 269 + return -EINVAL; 270 + 271 + memcpy(rpm_msg.cmd, cmd, n * sizeof(*cmd)); 272 + rpm_msg.msg.num_cmds = n; 273 + 274 + ret = __rpmh_write(dev, state, &rpm_msg); 275 + if (ret) 276 + return ret; 277 + 278 + ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS); 279 + WARN_ON(!ret); 280 + return (ret > 0) ? 0 : -ETIMEDOUT; 281 + } 282 + EXPORT_SYMBOL(rpmh_write); 283 + 284 + static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req) 285 + { 286 + unsigned long flags; 287 + 288 + spin_lock_irqsave(&ctrlr->cache_lock, flags); 289 + list_add_tail(&req->list, &ctrlr->batch_cache); 290 + spin_unlock_irqrestore(&ctrlr->cache_lock, flags); 291 + } 292 + 293 + static int flush_batch(struct rpmh_ctrlr *ctrlr) 294 + { 295 + struct batch_cache_req *req; 296 + const struct rpmh_request *rpm_msg; 297 + unsigned long flags; 298 + int ret = 0; 299 + int i; 300 + 301 + /* Send Sleep/Wake requests to the controller, expect no response */ 302 + spin_lock_irqsave(&ctrlr->cache_lock, flags); 303 + list_for_each_entry(req, &ctrlr->batch_cache, list) { 304 + for (i = 0; i < req->count; i++) { 305 + rpm_msg = req->rpm_msgs + i; 306 + ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), 307 + &rpm_msg->msg); 308 + if (ret) 309 + break; 310 + } 311 + } 312 + spin_unlock_irqrestore(&ctrlr->cache_lock, flags); 313 + 314 + return ret; 315 + } 316 + 317 + static void invalidate_batch(struct rpmh_ctrlr *ctrlr) 318 + { 319 + struct batch_cache_req *req, *tmp; 320 + unsigned long flags; 321 + 322 + spin_lock_irqsave(&ctrlr->cache_lock, flags); 323 + list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list) 324 + kfree(req); 325 + INIT_LIST_HEAD(&ctrlr->batch_cache); 326 + spin_unlock_irqrestore(&ctrlr->cache_lock, flags); 327 + } 328 + 329 + /** 330 + * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the 331 + * batch to finish. 332 + * 333 + * @dev: the device making the request 334 + * @state: Active/sleep set 335 + * @cmd: The payload data 336 + * @n: The array of count of elements in each batch, 0 terminated. 337 + * 338 + * Write a request to the RSC controller without caching. If the request 339 + * state is ACTIVE, then the requests are treated as completion request 340 + * and sent to the controller immediately. The function waits until all the 341 + * commands are complete. If the request was to SLEEP or WAKE_ONLY, then the 342 + * request is sent as fire-n-forget and no ack is expected. 343 + * 344 + * May sleep. Do not call from atomic contexts for ACTIVE_ONLY requests. 345 + */ 346 + int rpmh_write_batch(const struct device *dev, enum rpmh_state state, 347 + const struct tcs_cmd *cmd, u32 *n) 348 + { 349 + struct batch_cache_req *req; 350 + struct rpmh_request *rpm_msgs; 351 + DECLARE_COMPLETION_ONSTACK(compl); 352 + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); 353 + unsigned long time_left; 354 + int count = 0; 355 + int ret, i, j; 356 + 357 + if (!cmd || !n) 358 + return -EINVAL; 359 + 360 + while (n[count] > 0) 361 + count++; 362 + if (!count) 363 + return -EINVAL; 364 + 365 + req = kzalloc(sizeof(*req) + count * sizeof(req->rpm_msgs[0]), 366 + GFP_ATOMIC); 367 + if (!req) 368 + return -ENOMEM; 369 + req->count = count; 370 + rpm_msgs = req->rpm_msgs; 371 + 372 + for (i = 0; i < count; i++) { 373 + __fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i]); 374 + cmd += n[i]; 375 + } 376 + 377 + if (state != RPMH_ACTIVE_ONLY_STATE) { 378 + cache_batch(ctrlr, req); 379 + return 0; 380 + } 381 + 382 + for (i = 0; i < count; i++) { 383 + rpm_msgs[i].completion = &compl; 384 + ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg); 385 + if (ret) { 386 + pr_err("Error(%d) sending RPMH message addr=%#x\n", 387 + ret, rpm_msgs[i].msg.cmds[0].addr); 388 + for (j = i; j < count; j++) 389 + rpmh_tx_done(&rpm_msgs[j].msg, ret); 390 + break; 391 + } 392 + } 393 + 394 + time_left = RPMH_TIMEOUT_MS; 395 + for (i = 0; i < count; i++) { 396 + time_left = wait_for_completion_timeout(&compl, time_left); 397 + if (!time_left) { 398 + /* 399 + * Better hope they never finish because they'll signal 400 + * the completion on our stack and that's bad once 401 + * we've returned from the function. 402 + */ 403 + WARN_ON(1); 404 + ret = -ETIMEDOUT; 405 + goto exit; 406 + } 407 + } 408 + 409 + exit: 410 + kfree(req); 411 + 412 + return ret; 413 + } 414 + EXPORT_SYMBOL(rpmh_write_batch); 415 + 416 + static int is_req_valid(struct cache_req *req) 417 + { 418 + return (req->sleep_val != UINT_MAX && 419 + req->wake_val != UINT_MAX && 420 + req->sleep_val != req->wake_val); 421 + } 422 + 423 + static int send_single(const struct device *dev, enum rpmh_state state, 424 + u32 addr, u32 data) 425 + { 426 + DEFINE_RPMH_MSG_ONSTACK(dev, state, NULL, rpm_msg); 427 + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); 428 + 429 + /* Wake sets are always complete and sleep sets are not */ 430 + rpm_msg.msg.wait_for_compl = (state == RPMH_WAKE_ONLY_STATE); 431 + rpm_msg.cmd[0].addr = addr; 432 + rpm_msg.cmd[0].data = data; 433 + rpm_msg.msg.num_cmds = 1; 434 + 435 + return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg); 436 + } 437 + 438 + /** 439 + * rpmh_flush: Flushes the buffered active and sleep sets to TCS 440 + * 441 + * @dev: The device making the request 442 + * 443 + * Return: -EBUSY if the controller is busy, probably waiting on a response 444 + * to a RPMH request sent earlier. 445 + * 446 + * This function is always called from the sleep code from the last CPU 447 + * that is powering down the entire system. Since no other RPMH API would be 448 + * executing at this time, it is safe to run lockless. 449 + */ 450 + int rpmh_flush(const struct device *dev) 451 + { 452 + struct cache_req *p; 453 + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); 454 + int ret; 455 + 456 + if (!ctrlr->dirty) { 457 + pr_debug("Skipping flush, TCS has latest data.\n"); 458 + return 0; 459 + } 460 + 461 + /* First flush the cached batch requests */ 462 + ret = flush_batch(ctrlr); 463 + if (ret) 464 + return ret; 465 + 466 + /* 467 + * Nobody else should be calling this function other than system PM, 468 + * hence we can run without locks. 469 + */ 470 + list_for_each_entry(p, &ctrlr->cache, list) { 471 + if (!is_req_valid(p)) { 472 + pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x", 473 + __func__, p->addr, p->sleep_val, p->wake_val); 474 + continue; 475 + } 476 + ret = send_single(dev, RPMH_SLEEP_STATE, p->addr, p->sleep_val); 477 + if (ret) 478 + return ret; 479 + ret = send_single(dev, RPMH_WAKE_ONLY_STATE, 480 + p->addr, p->wake_val); 481 + if (ret) 482 + return ret; 483 + } 484 + 485 + ctrlr->dirty = false; 486 + 487 + return 0; 488 + } 489 + EXPORT_SYMBOL(rpmh_flush); 490 + 491 + /** 492 + * rpmh_invalidate: Invalidate all sleep and active sets 493 + * sets. 494 + * 495 + * @dev: The device making the request 496 + * 497 + * Invalidate the sleep and active values in the TCS blocks. 498 + */ 499 + int rpmh_invalidate(const struct device *dev) 500 + { 501 + struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); 502 + int ret; 503 + 504 + invalidate_batch(ctrlr); 505 + ctrlr->dirty = true; 506 + 507 + do { 508 + ret = rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr)); 509 + } while (ret == -EAGAIN); 510 + 511 + return ret; 512 + } 513 + EXPORT_SYMBOL(rpmh_invalidate);
+5 -5
drivers/soc/qcom/smem.c
··· 364 364 end = phdr_to_last_uncached_entry(phdr); 365 365 cached = phdr_to_last_cached_entry(phdr); 366 366 367 - if (smem->global_partition) { 368 - dev_err(smem->dev, "Already found the global partition\n"); 369 - return -EINVAL; 370 - } 371 - 372 367 while (hdr < end) { 373 368 if (hdr->canary != SMEM_PRIVATE_CANARY) 374 369 goto bad_canary; ··· 730 735 u32 host0, host1, size; 731 736 bool found = false; 732 737 int i; 738 + 739 + if (smem->global_partition) { 740 + dev_err(smem->dev, "Already found the global partition\n"); 741 + return -EINVAL; 742 + } 733 743 734 744 ptable = qcom_smem_get_ptable(smem); 735 745 if (IS_ERR(ptable))
+82
drivers/soc/qcom/trace-rpmh.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #if !defined(_TRACE_RPMH_H) || defined(TRACE_HEADER_MULTI_READ) 7 + #define _TRACE_RPMH_H 8 + 9 + #undef TRACE_SYSTEM 10 + #define TRACE_SYSTEM rpmh 11 + 12 + #include <linux/tracepoint.h> 13 + #include "rpmh-internal.h" 14 + 15 + TRACE_EVENT(rpmh_tx_done, 16 + 17 + TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e), 18 + 19 + TP_ARGS(d, m, r, e), 20 + 21 + TP_STRUCT__entry( 22 + __string(name, d->name) 23 + __field(int, m) 24 + __field(u32, addr) 25 + __field(u32, data) 26 + __field(int, err) 27 + ), 28 + 29 + TP_fast_assign( 30 + __assign_str(name, d->name); 31 + __entry->m = m; 32 + __entry->addr = r->cmds[0].addr; 33 + __entry->data = r->cmds[0].data; 34 + __entry->err = e; 35 + ), 36 + 37 + TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d", 38 + __get_str(name), __entry->m, __entry->addr, __entry->data, 39 + __entry->err) 40 + ); 41 + 42 + TRACE_EVENT(rpmh_send_msg, 43 + 44 + TP_PROTO(struct rsc_drv *d, int m, int n, u32 h, 45 + const struct tcs_cmd *c), 46 + 47 + TP_ARGS(d, m, n, h, c), 48 + 49 + TP_STRUCT__entry( 50 + __string(name, d->name) 51 + __field(int, m) 52 + __field(int, n) 53 + __field(u32, hdr) 54 + __field(u32, addr) 55 + __field(u32, data) 56 + __field(bool, wait) 57 + ), 58 + 59 + TP_fast_assign( 60 + __assign_str(name, d->name); 61 + __entry->m = m; 62 + __entry->n = n; 63 + __entry->hdr = h; 64 + __entry->addr = c->addr; 65 + __entry->data = c->data; 66 + __entry->wait = c->wait; 67 + ), 68 + 69 + TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d", 70 + __get_str(name), __entry->m, __entry->n, __entry->hdr, 71 + __entry->addr, __entry->data, __entry->wait) 72 + ); 73 + 74 + #endif /* _TRACE_RPMH_H */ 75 + 76 + #undef TRACE_INCLUDE_PATH 77 + #define TRACE_INCLUDE_PATH . 78 + 79 + #undef TRACE_INCLUDE_FILE 80 + #define TRACE_INCLUDE_FILE trace-rpmh 81 + 82 + #include <trace/define_trace.h>
+14
include/dt-bindings/soc/qcom,rpmh-rsc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #ifndef __DT_QCOM_RPMH_RSC_H__ 7 + #define __DT_QCOM_RPMH_RSC_H__ 8 + 9 + #define SLEEP_TCS 0 10 + #define WAKE_TCS 1 11 + #define ACTIVE_TCS 2 12 + #define CONTROL_TCS 3 13 + 14 + #endif /* __DT_QCOM_RPMH_RSC_H__ */
+4
include/linux/qcom_scm.h
··· 87 87 static inline int 88 88 qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; } 89 89 static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; } 90 + static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, 91 + unsigned int *src, 92 + struct qcom_scm_vmperm *newvm, 93 + int dest_cnt) { return -ENODEV; } 90 94 static inline void qcom_scm_cpu_power_down(u32 flags) {} 91 95 static inline u32 qcom_scm_get_version(void) { return 0; } 92 96 static inline u32
+180
include/linux/soc/qcom/llcc-qcom.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 4 + * 5 + */ 6 + 7 + #include <linux/platform_device.h> 8 + #ifndef __LLCC_QCOM__ 9 + #define __LLCC_QCOM__ 10 + 11 + #define LLCC_CPUSS 1 12 + #define LLCC_VIDSC0 2 13 + #define LLCC_VIDSC1 3 14 + #define LLCC_ROTATOR 4 15 + #define LLCC_VOICE 5 16 + #define LLCC_AUDIO 6 17 + #define LLCC_MDMHPGRW 7 18 + #define LLCC_MDM 8 19 + #define LLCC_CMPT 10 20 + #define LLCC_GPUHTW 11 21 + #define LLCC_GPU 12 22 + #define LLCC_MMUHWT 13 23 + #define LLCC_CMPTDMA 15 24 + #define LLCC_DISP 16 25 + #define LLCC_VIDFW 17 26 + #define LLCC_MDMHPFX 20 27 + #define LLCC_MDMPNG 21 28 + #define LLCC_AUDHW 22 29 + 30 + /** 31 + * llcc_slice_desc - Cache slice descriptor 32 + * @slice_id: llcc slice id 33 + * @slice_size: Size allocated for the llcc slice 34 + */ 35 + struct llcc_slice_desc { 36 + u32 slice_id; 37 + size_t slice_size; 38 + }; 39 + 40 + /** 41 + * llcc_slice_config - Data associated with the llcc slice 42 + * @usecase_id: usecase id for which the llcc slice is used 43 + * @slice_id: llcc slice id assigned to each slice 44 + * @max_cap: maximum capacity of the llcc slice 45 + * @priority: priority of the llcc slice 46 + * @fixed_size: whether the llcc slice can grow beyond its size 47 + * @bonus_ways: bonus ways associated with llcc slice 48 + * @res_ways: reserved ways associated with llcc slice 49 + * @cache_mode: mode of the llcc slice 50 + * @probe_target_ways: Probe only reserved and bonus ways on a cache miss 51 + * @dis_cap_alloc: Disable capacity based allocation 52 + * @retain_on_pc: Retain through power collapse 53 + * @activate_on_init: activate the slice on init 54 + */ 55 + struct llcc_slice_config { 56 + u32 usecase_id; 57 + u32 slice_id; 58 + u32 max_cap; 59 + u32 priority; 60 + bool fixed_size; 61 + u32 bonus_ways; 62 + u32 res_ways; 63 + u32 cache_mode; 64 + u32 probe_target_ways; 65 + bool dis_cap_alloc; 66 + bool retain_on_pc; 67 + bool activate_on_init; 68 + }; 69 + 70 + /** 71 + * llcc_drv_data - Data associated with the llcc driver 72 + * @regmap: regmap associated with the llcc device 73 + * @cfg: pointer to the data structure for slice configuration 74 + * @lock: mutex associated with each slice 75 + * @cfg_size: size of the config data table 76 + * @max_slices: max slices as read from device tree 77 + * @bcast_off: Offset of the broadcast bank 78 + * @num_banks: Number of llcc banks 79 + * @bitmap: Bit map to track the active slice ids 80 + * @offsets: Pointer to the bank offsets array 81 + */ 82 + struct llcc_drv_data { 83 + struct regmap *regmap; 84 + const struct llcc_slice_config *cfg; 85 + struct mutex lock; 86 + u32 cfg_size; 87 + u32 max_slices; 88 + u32 bcast_off; 89 + u32 num_banks; 90 + unsigned long *bitmap; 91 + u32 *offsets; 92 + }; 93 + 94 + #if IS_ENABLED(CONFIG_QCOM_LLCC) 95 + /** 96 + * llcc_slice_getd - get llcc slice descriptor 97 + * @uid: usecase_id of the client 98 + */ 99 + struct llcc_slice_desc *llcc_slice_getd(u32 uid); 100 + 101 + /** 102 + * llcc_slice_putd - llcc slice descritpor 103 + * @desc: Pointer to llcc slice descriptor 104 + */ 105 + void llcc_slice_putd(struct llcc_slice_desc *desc); 106 + 107 + /** 108 + * llcc_get_slice_id - get slice id 109 + * @desc: Pointer to llcc slice descriptor 110 + */ 111 + int llcc_get_slice_id(struct llcc_slice_desc *desc); 112 + 113 + /** 114 + * llcc_get_slice_size - llcc slice size 115 + * @desc: Pointer to llcc slice descriptor 116 + */ 117 + size_t llcc_get_slice_size(struct llcc_slice_desc *desc); 118 + 119 + /** 120 + * llcc_slice_activate - Activate the llcc slice 121 + * @desc: Pointer to llcc slice descriptor 122 + */ 123 + int llcc_slice_activate(struct llcc_slice_desc *desc); 124 + 125 + /** 126 + * llcc_slice_deactivate - Deactivate the llcc slice 127 + * @desc: Pointer to llcc slice descriptor 128 + */ 129 + int llcc_slice_deactivate(struct llcc_slice_desc *desc); 130 + 131 + /** 132 + * qcom_llcc_probe - program the sct table 133 + * @pdev: platform device pointer 134 + * @table: soc sct table 135 + * @sz: Size of the config table 136 + */ 137 + int qcom_llcc_probe(struct platform_device *pdev, 138 + const struct llcc_slice_config *table, u32 sz); 139 + #else 140 + static inline struct llcc_slice_desc *llcc_slice_getd(u32 uid) 141 + { 142 + return NULL; 143 + } 144 + 145 + static inline void llcc_slice_putd(struct llcc_slice_desc *desc) 146 + { 147 + 148 + }; 149 + 150 + static inline int llcc_get_slice_id(struct llcc_slice_desc *desc) 151 + { 152 + return -EINVAL; 153 + } 154 + 155 + static inline size_t llcc_get_slice_size(struct llcc_slice_desc *desc) 156 + { 157 + return 0; 158 + } 159 + static inline int llcc_slice_activate(struct llcc_slice_desc *desc) 160 + { 161 + return -EINVAL; 162 + } 163 + 164 + static inline int llcc_slice_deactivate(struct llcc_slice_desc *desc) 165 + { 166 + return -EINVAL; 167 + } 168 + static inline int qcom_llcc_probe(struct platform_device *pdev, 169 + const struct llcc_slice_config *table, u32 sz) 170 + { 171 + return -ENODEV; 172 + } 173 + 174 + static inline int qcom_llcc_remove(struct platform_device *pdev) 175 + { 176 + return -ENODEV; 177 + } 178 + #endif 179 + 180 + #endif
+51
include/soc/qcom/rpmh.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #ifndef __SOC_QCOM_RPMH_H__ 7 + #define __SOC_QCOM_RPMH_H__ 8 + 9 + #include <soc/qcom/tcs.h> 10 + #include <linux/platform_device.h> 11 + 12 + 13 + #if IS_ENABLED(CONFIG_QCOM_RPMH) 14 + int rpmh_write(const struct device *dev, enum rpmh_state state, 15 + const struct tcs_cmd *cmd, u32 n); 16 + 17 + int rpmh_write_async(const struct device *dev, enum rpmh_state state, 18 + const struct tcs_cmd *cmd, u32 n); 19 + 20 + int rpmh_write_batch(const struct device *dev, enum rpmh_state state, 21 + const struct tcs_cmd *cmd, u32 *n); 22 + 23 + int rpmh_flush(const struct device *dev); 24 + 25 + int rpmh_invalidate(const struct device *dev); 26 + 27 + #else 28 + 29 + static inline int rpmh_write(const struct device *dev, enum rpmh_state state, 30 + const struct tcs_cmd *cmd, u32 n) 31 + { return -ENODEV; } 32 + 33 + static inline int rpmh_write_async(const struct device *dev, 34 + enum rpmh_state state, 35 + const struct tcs_cmd *cmd, u32 n) 36 + { return -ENODEV; } 37 + 38 + static inline int rpmh_write_batch(const struct device *dev, 39 + enum rpmh_state state, 40 + const struct tcs_cmd *cmd, u32 *n) 41 + { return -ENODEV; } 42 + 43 + static inline int rpmh_flush(const struct device *dev) 44 + { return -ENODEV; } 45 + 46 + static inline int rpmh_invalidate(const struct device *dev) 47 + { return -ENODEV; } 48 + 49 + #endif /* CONFIG_QCOM_RPMH */ 50 + 51 + #endif /* __SOC_QCOM_RPMH_H__ */
+56
include/soc/qcom/tcs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #ifndef __SOC_QCOM_TCS_H__ 7 + #define __SOC_QCOM_TCS_H__ 8 + 9 + #define MAX_RPMH_PAYLOAD 16 10 + 11 + /** 12 + * rpmh_state: state for the request 13 + * 14 + * RPMH_SLEEP_STATE: State of the resource when the processor subsystem 15 + * is powered down. There is no client using the 16 + * resource actively. 17 + * RPMH_WAKE_ONLY_STATE: Resume resource state to the value previously 18 + * requested before the processor was powered down. 19 + * RPMH_ACTIVE_ONLY_STATE: Active or AMC mode requests. Resource state 20 + * is aggregated immediately. 21 + */ 22 + enum rpmh_state { 23 + RPMH_SLEEP_STATE, 24 + RPMH_WAKE_ONLY_STATE, 25 + RPMH_ACTIVE_ONLY_STATE, 26 + }; 27 + 28 + /** 29 + * struct tcs_cmd: an individual request to RPMH. 30 + * 31 + * @addr: the address of the resource slv_id:18:16 | offset:0:15 32 + * @data: the resource state request 33 + * @wait: wait for this request to be complete before sending the next 34 + */ 35 + struct tcs_cmd { 36 + u32 addr; 37 + u32 data; 38 + u32 wait; 39 + }; 40 + 41 + /** 42 + * struct tcs_request: A set of tcs_cmds sent together in a TCS 43 + * 44 + * @state: state for the request. 45 + * @wait_for_compl: wait until we get a response from the h/w accelerator 46 + * @num_cmds: the number of @cmds in this request 47 + * @cmds: an array of tcs_cmds 48 + */ 49 + struct tcs_request { 50 + enum rpmh_state state; 51 + u32 wait_for_compl; 52 + u32 num_cmds; 53 + struct tcs_cmd *cmds; 54 + }; 55 + 56 + #endif /* __SOC_QCOM_TCS_H__ */