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

Merge tag 'qcom-drivers-for-5.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers

More Qualcomm driver updates for v5.16

This introduces the Qualcomm "sleep stats" driver, which aids the
efforts of bringing various Qualcomm platforms into low power mode.

The SMP2P driver gains support for negotiating the "SSR" feature, which
is used to better synchronize some corner cases that might appear as the
remoteproc is recovering from a crash.

The socinfo driver learns about a few new PMICs.

SMEM is updated so that it's possible to put the compatible property
directly in the reserved-memory node, to avoid having to have a separate
node just pointing to the memory-region.

Lastly it fixes some bugs in smp2p, apr, rpmhpd drivers, notably
avoiding the issue where powering on a power-domain using rpmhpd while
keeping the performance_state at 0 is a nop

* tag 'qcom-drivers-for-5.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux:
firmware: qcom: scm: Don't break compile test on non-ARM platforms
soc: qcom: smp2p: Add of_node_put() before goto
soc: qcom: apr: Add of_node_put() before return
soc: qcom: qcom_stats: Fix client votes offset
soc: qcom: rpmhpd: fix sm8350_mxc's peer domain
dt-bindings: arm: cpus: Document qcom,msm8916-smp enable-method
ARM: qcom: Add qcom,msm8916-smp enable-method identical to MSM8226
firmware: qcom: scm: Add support for MC boot address API
soc: qcom: spm: Add 8916 SPM register data
dt-bindings: soc: qcom: spm: Document qcom,msm8916-saw2-v3.0-cpu
soc: qcom: socinfo: Add PM8150C and SMB2351 models
firmware: qcom_scm: Fix error retval in __qcom_scm_is_call_available()
soc: qcom: smp2p: add feature negotiation and ssr ack feature support
soc: qcom: Add Sleep stats driver
dt-bindings: Introduce QCOM Sleep stats bindings
soc: qcom: socinfo: add two missing PMIC IDs
soc: qcom: rpmhpd: Make power_on actually enable the domain
soc: qcom: smem: Support reserved-memory description
dt-bindings: soc: smem: Make indirection optional
dt-bindings: sram: Document qcom,rpm-msg-ram

Link: https://lore.kernel.org/r/20211026140706.1205989-1-bjorn.andersson@linaro.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+645 -77
+4 -1
Documentation/devicetree/bindings/arm/cpus.yaml
··· 210 210 - qcom,kpss-acc-v1 211 211 - qcom,kpss-acc-v2 212 212 - qcom,msm8226-smp 213 + # Only valid on ARM 32-bit, see above for ARM v8 64-bit 214 + - qcom,msm8916-smp 213 215 - renesas,apmu 214 216 - renesas,r9a06g032-smp 215 217 - rockchip,rk3036-smp ··· 296 294 Specifies the ACC* node associated with this CPU. 297 295 298 296 Required for systems that have an "enable-method" property 299 - value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2" or "qcom,msm8226-smp" 297 + value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2", "qcom,msm8226-smp" or 298 + "qcom,msm8916-smp". 300 299 301 300 * arm/msm/qcom,kpss-acc.txt 302 301
+30 -4
Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml
··· 10 10 - Andy Gross <agross@kernel.org> 11 11 - Bjorn Andersson <bjorn.andersson@linaro.org> 12 12 13 - description: | 14 - This binding describes the Qualcomm Shared Memory Manager, used to share data 15 - between various subsystems and OSes in Qualcomm platforms. 13 + description: 14 + This binding describes the Qualcomm Shared Memory Manager, a region of 15 + reserved-memory used to share data between various subsystems and OSes in 16 + Qualcomm platforms. 16 17 17 18 properties: 18 19 compatible: 19 20 const: qcom,smem 21 + 22 + reg: 23 + maxItems: 1 20 24 21 25 memory-region: 22 26 maxItems: 1 ··· 33 29 $ref: /schemas/types.yaml#/definitions/phandle 34 30 description: handle to RPM message memory resource 35 31 32 + no-map: true 33 + 36 34 required: 37 35 - compatible 38 - - memory-region 39 36 - hwlocks 37 + 38 + oneOf: 39 + - required: 40 + - reg 41 + - no-map 42 + - required: 43 + - memory-region 40 44 41 45 additionalProperties: false 42 46 43 47 examples: 48 + - | 49 + reserved-memory { 50 + #address-cells = <1>; 51 + #size-cells = <1>; 52 + ranges; 53 + 54 + smem@fa00000 { 55 + compatible = "qcom,smem"; 56 + reg = <0xfa00000 0x200000>; 57 + no-map; 58 + 59 + hwlocks = <&tcsr_mutex 3>; 60 + }; 61 + }; 44 62 - | 45 63 reserved-memory { 46 64 #address-cells = <1>;
+1
Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
··· 22 22 - qcom,sdm660-silver-saw2-v4.1-l2 23 23 - qcom,msm8998-gold-saw2-v4.1-l2 24 24 - qcom,msm8998-silver-saw2-v4.1-l2 25 + - qcom,msm8916-saw2-v3.0-cpu 25 26 - qcom,msm8226-saw2-v2.1-cpu 26 27 - qcom,msm8974-saw2-v2.1-cpu 27 28 - qcom,apq8084-saw2-v2.1-cpu
+47
Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/soc/qcom/qcom-stats.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Qualcomm Technologies, Inc. (QTI) Stats bindings 8 + 9 + maintainers: 10 + - Maulik Shah <mkshah@codeaurora.org> 11 + 12 + description: 13 + Always On Processor/Resource Power Manager maintains statistics of the SoC 14 + sleep modes involving powering down of the rails and oscillator clock. 15 + 16 + Statistics includes SoC sleep mode type, number of times low power mode were 17 + entered, time of last entry, time of last exit and accumulated sleep duration. 18 + 19 + properties: 20 + compatible: 21 + enum: 22 + - qcom,rpmh-stats 23 + - qcom,rpm-stats 24 + 25 + reg: 26 + maxItems: 1 27 + 28 + required: 29 + - compatible 30 + - reg 31 + 32 + additionalProperties: false 33 + 34 + examples: 35 + # Example of rpmh sleep stats 36 + - | 37 + sram@c3f0000 { 38 + compatible = "qcom,rpmh-stats"; 39 + reg = <0x0c3f0000 0x400>; 40 + }; 41 + # Example of rpm sleep stats 42 + - | 43 + sram@4690000 { 44 + compatible = "qcom,rpm-stats"; 45 + reg = <0x04690000 0x10000>; 46 + }; 47 + ...
+4 -1
Documentation/devicetree/bindings/sram/sram.yaml
··· 31 31 - amlogic,meson-gxbb-sram 32 32 - arm,juno-sram-ns 33 33 - atmel,sama5d2-securam 34 + - qcom,rpm-msg-ram 34 35 - rockchip,rk3288-pmu-sram 35 36 36 37 reg: ··· 136 135 properties: 137 136 compatible: 138 137 contains: 139 - const: rockchip,rk3288-pmu-sram 138 + enum: 139 + - qcom,rpm-msg-ram 140 + - rockchip,rk3288-pmu-sram 140 141 141 142 else: 142 143 required:
+1
arch/arm/mach-qcom/platsmp.c
··· 385 385 #endif 386 386 }; 387 387 CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops); 388 + CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops); 388 389 389 390 static const struct smp_operations qcom_smp_kpssv1_ops __initconst = { 390 391 .smp_prepare_cpus = qcom_smp_prepare_cpus,
+78 -18
drivers/firmware/qcom_scm.c
··· 17 17 #include <linux/reset-controller.h> 18 18 #include <linux/arm-smccc.h> 19 19 20 + #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) 21 + #include <asm/smp_plat.h> 22 + #endif 23 + 20 24 #include "qcom_scm.h" 21 25 22 26 static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); ··· 256 252 break; 257 253 default: 258 254 pr_err("Unknown SMC convention being used\n"); 259 - return -EINVAL; 255 + return false; 260 256 } 261 257 262 258 ret = qcom_scm_call(dev, &desc, &res); ··· 264 260 return ret ? false : !!res.result[0]; 265 261 } 266 262 267 - /** 268 - * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus 269 - * @entry: Entry point function for the cpus 270 - * @cpus: The cpumask of cpus that will use the entry point 271 - * 272 - * Set the Linux entry point for the SCM to transfer control to when coming 273 - * out of a power down. CPU power down may be executed on cpuidle or hotplug. 274 - */ 275 - int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 263 + #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) 264 + static int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus, 265 + unsigned int flags) 266 + { 267 + struct qcom_scm_desc desc = { 268 + .svc = QCOM_SCM_SVC_BOOT, 269 + .cmd = QCOM_SCM_BOOT_SET_ADDR_MC, 270 + .owner = ARM_SMCCC_OWNER_SIP, 271 + .arginfo = QCOM_SCM_ARGS(6), 272 + }; 273 + unsigned int cpu; 274 + u64 map; 275 + 276 + /* Need a device for DMA of the additional arguments */ 277 + if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY) 278 + return -EOPNOTSUPP; 279 + 280 + desc.args[0] = virt_to_phys(entry); 281 + for_each_cpu(cpu, cpus) { 282 + map = cpu_logical_map(cpu); 283 + desc.args[1] |= BIT(MPIDR_AFFINITY_LEVEL(map, 0)); 284 + desc.args[2] |= BIT(MPIDR_AFFINITY_LEVEL(map, 1)); 285 + desc.args[3] |= BIT(MPIDR_AFFINITY_LEVEL(map, 2)); 286 + } 287 + desc.args[4] = ~0ULL; /* Reserved for affinity level 3 */ 288 + desc.args[5] = flags; 289 + 290 + return qcom_scm_call(__scm->dev, &desc, NULL); 291 + } 292 + #else 293 + static inline int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus, 294 + unsigned int flags) 295 + { 296 + return -EINVAL; 297 + } 298 + #endif 299 + 300 + static int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 276 301 { 277 302 int ret; 278 303 int flags = 0; ··· 337 304 338 305 return ret; 339 306 } 340 - EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); 341 307 342 308 /** 343 - * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus 309 + * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus 344 310 * @entry: Entry point function for the cpus 345 311 * @cpus: The cpumask of cpus that will use the entry point 346 312 * 347 - * Set the cold boot address of the cpus. Any cpu outside the supported 348 - * range would be removed from the cpu present mask. 313 + * Set the Linux entry point for the SCM to transfer control to when coming 314 + * out of a power down. CPU power down may be executed on cpuidle or hotplug. 349 315 */ 350 - int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) 316 + int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 317 + { 318 + if (!cpus || cpumask_empty(cpus)) 319 + return -EINVAL; 320 + 321 + if (__qcom_scm_set_boot_addr_mc(entry, cpus, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT)) 322 + /* Fallback to old SCM call */ 323 + return __qcom_scm_set_warm_boot_addr(entry, cpus); 324 + return 0; 325 + } 326 + EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); 327 + 328 + static int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) 351 329 { 352 330 int flags = 0; 353 331 int cpu; ··· 375 331 .owner = ARM_SMCCC_OWNER_SIP, 376 332 }; 377 333 378 - if (!cpus || cpumask_empty(cpus)) 379 - return -EINVAL; 380 - 381 334 for_each_cpu(cpu, cpus) { 382 335 if (cpu < ARRAY_SIZE(scm_cb_flags)) 383 336 flags |= scm_cb_flags[cpu]; ··· 386 345 desc.args[1] = virt_to_phys(entry); 387 346 388 347 return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL); 348 + } 349 + 350 + /** 351 + * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus 352 + * @entry: Entry point function for the cpus 353 + * @cpus: The cpumask of cpus that will use the entry point 354 + * 355 + * Set the cold boot address of the cpus. Any cpu outside the supported 356 + * range would be removed from the cpu present mask. 357 + */ 358 + int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) 359 + { 360 + if (!cpus || cpumask_empty(cpus)) 361 + return -EINVAL; 362 + 363 + if (__qcom_scm_set_boot_addr_mc(entry, cpus, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT)) 364 + /* Fallback to old SCM call */ 365 + return __qcom_scm_set_cold_boot_addr(entry, cpus); 366 + return 0; 389 367 } 390 368 EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); 391 369
+4
drivers/firmware/qcom_scm.h
··· 78 78 #define QCOM_SCM_BOOT_SET_ADDR 0x01 79 79 #define QCOM_SCM_BOOT_TERMINATE_PC 0x02 80 80 #define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10 81 + #define QCOM_SCM_BOOT_SET_ADDR_MC 0x11 81 82 #define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a 82 83 #define QCOM_SCM_FLUSH_FLAG_MASK 0x3 84 + #define QCOM_SCM_BOOT_MC_FLAG_AARCH64 BIT(0) 85 + #define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1) 86 + #define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2) 83 87 84 88 #define QCOM_SCM_SVC_PIL 0x02 85 89 #define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
+1
drivers/of/platform.c
··· 509 509 static const struct of_device_id reserved_mem_matches[] = { 510 510 { .compatible = "qcom,rmtfs-mem" }, 511 511 { .compatible = "qcom,cmd-db" }, 512 + { .compatible = "qcom,smem" }, 512 513 { .compatible = "ramoops" }, 513 514 { .compatible = "nvmem-rmem" }, 514 515 {}
+10
drivers/soc/qcom/Kconfig
··· 199 199 to manage cores, L2 low power modes and to configure the internal 200 200 Adaptive Voltage Scaler parameters, where supported. 201 201 202 + config QCOM_STATS 203 + tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver" 204 + depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST 205 + depends on QCOM_SMEM 206 + help 207 + Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read 208 + the shared memory exported by the remote processor related to 209 + various SoC level low power modes statistics and export to debugfs 210 + interface. 211 + 202 212 config QCOM_WCNSS_CTRL 203 213 tristate "Qualcomm WCNSS control driver" 204 214 depends on ARCH_QCOM || COMPILE_TEST
+1
drivers/soc/qcom/Makefile
··· 21 21 obj-$(CONFIG_QCOM_SMSM) += smsm.o 22 22 obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o 23 23 obj-$(CONFIG_QCOM_SPM) += spm.o 24 + obj-$(CONFIG_QCOM_STATS) += qcom_stats.o 24 25 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o 25 26 obj-$(CONFIG_QCOM_APR) += apr.o 26 27 obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
+2
drivers/soc/qcom/apr.c
··· 492 492 1, &service_path); 493 493 if (ret < 0) { 494 494 dev_err(dev, "pdr service path missing: %d\n", ret); 495 + of_node_put(node); 495 496 return ret; 496 497 } 497 498 498 499 pds = pdr_add_lookup(apr->pdr, service_name, service_path); 499 500 if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { 500 501 dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds)); 502 + of_node_put(node); 501 503 return PTR_ERR(pds); 502 504 } 503 505 }
+277
drivers/soc/qcom/qcom_stats.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #include <linux/debugfs.h> 7 + #include <linux/device.h> 8 + #include <linux/io.h> 9 + #include <linux/module.h> 10 + #include <linux/of.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/seq_file.h> 13 + 14 + #include <linux/soc/qcom/smem.h> 15 + #include <clocksource/arm_arch_timer.h> 16 + 17 + #define RPM_DYNAMIC_ADDR 0x14 18 + #define RPM_DYNAMIC_ADDR_MASK 0xFFFF 19 + 20 + #define STAT_TYPE_OFFSET 0x0 21 + #define COUNT_OFFSET 0x4 22 + #define LAST_ENTERED_AT_OFFSET 0x8 23 + #define LAST_EXITED_AT_OFFSET 0x10 24 + #define ACCUMULATED_OFFSET 0x18 25 + #define CLIENT_VOTES_OFFSET 0x20 26 + 27 + struct subsystem_data { 28 + const char *name; 29 + u32 smem_item; 30 + u32 pid; 31 + }; 32 + 33 + static const struct subsystem_data subsystems[] = { 34 + { "modem", 605, 1 }, 35 + { "wpss", 605, 13 }, 36 + { "adsp", 606, 2 }, 37 + { "cdsp", 607, 5 }, 38 + { "slpi", 608, 3 }, 39 + { "gpu", 609, 0 }, 40 + { "display", 610, 0 }, 41 + { "adsp_island", 613, 2 }, 42 + { "slpi_island", 613, 3 }, 43 + }; 44 + 45 + struct stats_config { 46 + size_t stats_offset; 47 + size_t num_records; 48 + bool appended_stats_avail; 49 + bool dynamic_offset; 50 + bool subsystem_stats_in_smem; 51 + }; 52 + 53 + struct stats_data { 54 + bool appended_stats_avail; 55 + void __iomem *base; 56 + }; 57 + 58 + struct sleep_stats { 59 + u32 stat_type; 60 + u32 count; 61 + u64 last_entered_at; 62 + u64 last_exited_at; 63 + u64 accumulated; 64 + }; 65 + 66 + struct appended_stats { 67 + u32 client_votes; 68 + u32 reserved[3]; 69 + }; 70 + 71 + static void qcom_print_stats(struct seq_file *s, const struct sleep_stats *stat) 72 + { 73 + u64 accumulated = stat->accumulated; 74 + /* 75 + * If a subsystem is in sleep when reading the sleep stats adjust 76 + * the accumulated sleep duration to show actual sleep time. 77 + */ 78 + if (stat->last_entered_at > stat->last_exited_at) 79 + accumulated += arch_timer_read_counter() - stat->last_entered_at; 80 + 81 + seq_printf(s, "Count: %u\n", stat->count); 82 + seq_printf(s, "Last Entered At: %llu\n", stat->last_entered_at); 83 + seq_printf(s, "Last Exited At: %llu\n", stat->last_exited_at); 84 + seq_printf(s, "Accumulated Duration: %llu\n", accumulated); 85 + } 86 + 87 + static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused) 88 + { 89 + struct subsystem_data *subsystem = s->private; 90 + struct sleep_stats *stat; 91 + 92 + /* Items are allocated lazily, so lookup pointer each time */ 93 + stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL); 94 + if (IS_ERR(stat)) 95 + return -EIO; 96 + 97 + qcom_print_stats(s, stat); 98 + 99 + return 0; 100 + } 101 + 102 + static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused) 103 + { 104 + struct stats_data *d = s->private; 105 + void __iomem *reg = d->base; 106 + struct sleep_stats stat; 107 + 108 + memcpy_fromio(&stat, reg, sizeof(stat)); 109 + qcom_print_stats(s, &stat); 110 + 111 + if (d->appended_stats_avail) { 112 + struct appended_stats votes; 113 + 114 + memcpy_fromio(&votes, reg + CLIENT_VOTES_OFFSET, sizeof(votes)); 115 + seq_printf(s, "Client Votes: %#x\n", votes.client_votes); 116 + } 117 + 118 + return 0; 119 + } 120 + 121 + DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats); 122 + DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats); 123 + 124 + static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg, 125 + struct stats_data *d, 126 + const struct stats_config *config) 127 + { 128 + char stat_type[sizeof(u32) + 1] = {0}; 129 + size_t stats_offset = config->stats_offset; 130 + u32 offset = 0, type; 131 + int i, j; 132 + 133 + /* 134 + * On RPM targets, stats offset location is dynamic and changes from target 135 + * to target and sometimes from build to build for same target. 136 + * 137 + * In such cases the dynamic address is present at 0x14 offset from base 138 + * address in devicetree. The last 16bits indicates the stats_offset. 139 + */ 140 + if (config->dynamic_offset) { 141 + stats_offset = readl(reg + RPM_DYNAMIC_ADDR); 142 + stats_offset &= RPM_DYNAMIC_ADDR_MASK; 143 + } 144 + 145 + for (i = 0; i < config->num_records; i++) { 146 + d[i].base = reg + offset + stats_offset; 147 + 148 + /* 149 + * Read the low power mode name and create debugfs file for it. 150 + * The names read could be of below, 151 + * (may change depending on low power mode supported). 152 + * For rpmh-sleep-stats: "aosd", "cxsd" and "ddr". 153 + * For rpm-sleep-stats: "vmin" and "vlow". 154 + */ 155 + type = readl(d[i].base); 156 + for (j = 0; j < sizeof(u32); j++) { 157 + stat_type[j] = type & 0xff; 158 + type = type >> 8; 159 + } 160 + strim(stat_type); 161 + debugfs_create_file(stat_type, 0400, root, &d[i], 162 + &qcom_soc_sleep_stats_fops); 163 + 164 + offset += sizeof(struct sleep_stats); 165 + if (d[i].appended_stats_avail) 166 + offset += sizeof(struct appended_stats); 167 + } 168 + } 169 + 170 + static void qcom_create_subsystem_stat_files(struct dentry *root, 171 + const struct stats_config *config) 172 + { 173 + const struct sleep_stats *stat; 174 + int i; 175 + 176 + if (!config->subsystem_stats_in_smem) 177 + return; 178 + 179 + for (i = 0; i < ARRAY_SIZE(subsystems); i++) { 180 + stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL); 181 + if (IS_ERR(stat)) 182 + continue; 183 + 184 + debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i], 185 + &qcom_subsystem_sleep_stats_fops); 186 + } 187 + } 188 + 189 + static int qcom_stats_probe(struct platform_device *pdev) 190 + { 191 + void __iomem *reg; 192 + struct dentry *root; 193 + const struct stats_config *config; 194 + struct stats_data *d; 195 + int i; 196 + 197 + config = device_get_match_data(&pdev->dev); 198 + if (!config) 199 + return -ENODEV; 200 + 201 + reg = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 202 + if (IS_ERR(reg)) 203 + return -ENOMEM; 204 + 205 + d = devm_kcalloc(&pdev->dev, config->num_records, 206 + sizeof(*d), GFP_KERNEL); 207 + if (!d) 208 + return -ENOMEM; 209 + 210 + for (i = 0; i < config->num_records; i++) 211 + d[i].appended_stats_avail = config->appended_stats_avail; 212 + 213 + root = debugfs_create_dir("qcom_stats", NULL); 214 + 215 + qcom_create_subsystem_stat_files(root, config); 216 + qcom_create_soc_sleep_stat_files(root, reg, d, config); 217 + 218 + platform_set_drvdata(pdev, root); 219 + 220 + return 0; 221 + } 222 + 223 + static int qcom_stats_remove(struct platform_device *pdev) 224 + { 225 + struct dentry *root = platform_get_drvdata(pdev); 226 + 227 + debugfs_remove_recursive(root); 228 + 229 + return 0; 230 + } 231 + 232 + static const struct stats_config rpm_data = { 233 + .stats_offset = 0, 234 + .num_records = 2, 235 + .appended_stats_avail = true, 236 + .dynamic_offset = true, 237 + .subsystem_stats_in_smem = false, 238 + }; 239 + 240 + static const struct stats_config rpmh_data = { 241 + .stats_offset = 0x48, 242 + .num_records = 3, 243 + .appended_stats_avail = false, 244 + .dynamic_offset = false, 245 + .subsystem_stats_in_smem = true, 246 + }; 247 + 248 + static const struct of_device_id qcom_stats_table[] = { 249 + { .compatible = "qcom,rpm-stats", .data = &rpm_data }, 250 + { .compatible = "qcom,rpmh-stats", .data = &rpmh_data }, 251 + { } 252 + }; 253 + MODULE_DEVICE_TABLE(of, qcom_stats_table); 254 + 255 + static struct platform_driver qcom_stats = { 256 + .probe = qcom_stats_probe, 257 + .remove = qcom_stats_remove, 258 + .driver = { 259 + .name = "qcom_stats", 260 + .of_match_table = qcom_stats_table, 261 + }, 262 + }; 263 + 264 + static int __init qcom_stats_init(void) 265 + { 266 + return platform_driver_register(&qcom_stats); 267 + } 268 + late_initcall(qcom_stats_init); 269 + 270 + static void __exit qcom_stats_exit(void) 271 + { 272 + platform_driver_unregister(&qcom_stats); 273 + } 274 + module_exit(qcom_stats_exit) 275 + 276 + MODULE_DESCRIPTION("Qualcomm Technologies, Inc. (QTI) Stats driver"); 277 + MODULE_LICENSE("GPL v2");
+15 -5
drivers/soc/qcom/rpmhpd.c
··· 30 30 * @active_only: True if it represents an Active only peer 31 31 * @corner: current corner 32 32 * @active_corner: current active corner 33 + * @enable_corner: lowest non-zero corner 33 34 * @level: An array of level (vlvl) to corner (hlvl) mappings 34 35 * derived from cmd-db 35 36 * @level_count: Number of levels supported by the power domain. max ··· 48 47 const bool active_only; 49 48 unsigned int corner; 50 49 unsigned int active_corner; 50 + unsigned int enable_corner; 51 51 u32 level[RPMH_ARC_MAX_LEVELS]; 52 52 size_t level_count; 53 53 bool enabled; ··· 221 219 static struct rpmhpd sm8350_mxc_ao; 222 220 static struct rpmhpd sm8350_mxc = { 223 221 .pd = { .name = "mxc", }, 224 - .peer = &sm8150_mmcx_ao, 222 + .peer = &sm8350_mxc_ao, 225 223 .res_name = "mxc.lvl", 226 224 }; 227 225 ··· 403 401 static int rpmhpd_power_on(struct generic_pm_domain *domain) 404 402 { 405 403 struct rpmhpd *pd = domain_to_rpmhpd(domain); 406 - int ret = 0; 404 + unsigned int corner; 405 + int ret; 407 406 408 407 mutex_lock(&rpmhpd_lock); 409 408 410 - if (pd->corner) 411 - ret = rpmhpd_aggregate_corner(pd, pd->corner); 412 - 409 + corner = max(pd->corner, pd->enable_corner); 410 + ret = rpmhpd_aggregate_corner(pd, corner); 413 411 if (!ret) 414 412 pd->enabled = true; 415 413 ··· 454 452 i--; 455 453 456 454 if (pd->enabled) { 455 + /* Ensure that the domain isn't turn off */ 456 + if (i < pd->enable_corner) 457 + i = pd->enable_corner; 458 + 457 459 ret = rpmhpd_aggregate_corner(pd, i); 458 460 if (ret) 459 461 goto out; ··· 493 487 494 488 for (i = 0; i < rpmhpd->level_count; i++) { 495 489 rpmhpd->level[i] = buf[i]; 490 + 491 + /* Remember the first corner with non-zero level */ 492 + if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i]) 493 + rpmhpd->enable_corner = i; 496 494 497 495 /* 498 496 * The AUX data may be zero padded. These 0 valued entries at
+39 -18
drivers/soc/qcom/smem.c
··· 9 9 #include <linux/module.h> 10 10 #include <linux/of.h> 11 11 #include <linux/of_address.h> 12 + #include <linux/of_reserved_mem.h> 12 13 #include <linux/platform_device.h> 13 14 #include <linux/sizes.h> 14 15 #include <linux/slab.h> ··· 241 240 * @size: size of the memory region 242 241 */ 243 242 struct smem_region { 244 - u32 aux_base; 243 + phys_addr_t aux_base; 245 244 void __iomem *virt_base; 246 245 size_t size; 247 246 }; ··· 500 499 for (i = 0; i < smem->num_regions; i++) { 501 500 region = &smem->regions[i]; 502 501 503 - if (region->aux_base == aux_base || !aux_base) { 502 + if ((u32)region->aux_base == aux_base || !aux_base) { 504 503 if (size != NULL) 505 504 *size = le32_to_cpu(entry->size); 506 505 return region->virt_base + le32_to_cpu(entry->offset); ··· 665 664 if (p < region->virt_base + region->size) { 666 665 u64 offset = p - region->virt_base; 667 666 668 - return (phys_addr_t)region->aux_base + offset; 667 + return region->aux_base + offset; 669 668 } 670 669 } 671 670 ··· 864 863 return 0; 865 864 } 866 865 867 - static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, 868 - const char *name, int i) 866 + static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name, 867 + struct smem_region *region) 869 868 { 869 + struct device *dev = smem->dev; 870 870 struct device_node *np; 871 871 struct resource r; 872 - resource_size_t size; 873 872 int ret; 874 873 875 874 np = of_parse_phandle(dev->of_node, name, 0); ··· 882 881 of_node_put(np); 883 882 if (ret) 884 883 return ret; 885 - size = resource_size(&r); 886 884 887 - smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); 888 - if (!smem->regions[i].virt_base) 889 - return -ENOMEM; 890 - smem->regions[i].aux_base = (u32)r.start; 891 - smem->regions[i].size = size; 885 + region->aux_base = r.start; 886 + region->size = resource_size(&r); 892 887 893 888 return 0; 894 889 } ··· 892 895 static int qcom_smem_probe(struct platform_device *pdev) 893 896 { 894 897 struct smem_header *header; 898 + struct reserved_mem *rmem; 895 899 struct qcom_smem *smem; 896 900 size_t array_size; 897 901 int num_regions; 898 902 int hwlock_id; 899 903 u32 version; 900 904 int ret; 905 + int i; 901 906 902 907 num_regions = 1; 903 908 if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) ··· 913 914 smem->dev = &pdev->dev; 914 915 smem->num_regions = num_regions; 915 916 916 - ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0); 917 - if (ret) 918 - return ret; 917 + rmem = of_reserved_mem_lookup(pdev->dev.of_node); 918 + if (rmem) { 919 + smem->regions[0].aux_base = rmem->base; 920 + smem->regions[0].size = rmem->size; 921 + } else { 922 + /* 923 + * Fall back to the memory-region reference, if we're not a 924 + * reserved-memory node. 925 + */ 926 + ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]); 927 + if (ret) 928 + return ret; 929 + } 919 930 920 - if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev, 921 - "qcom,rpm-msg-ram", 1))) 922 - return ret; 931 + if (num_regions > 1) { 932 + ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]); 933 + if (ret) 934 + return ret; 935 + } 936 + 937 + for (i = 0; i < num_regions; i++) { 938 + smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev, 939 + smem->regions[i].aux_base, 940 + smem->regions[i].size); 941 + if (!smem->regions[i].virt_base) { 942 + dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base); 943 + return -ENOMEM; 944 + } 945 + } 923 946 924 947 header = smem->regions[0].virt_base; 925 948 if (le32_to_cpu(header->initialized) != 1 ||
+106 -28
drivers/soc/qcom/smp2p.c
··· 41 41 #define SMP2P_MAX_ENTRY_NAME 16 42 42 43 43 #define SMP2P_FEATURE_SSR_ACK 0x1 44 + #define SMP2P_FLAGS_RESTART_DONE_BIT 0 45 + #define SMP2P_FLAGS_RESTART_ACK_BIT 1 44 46 45 47 #define SMP2P_MAGIC 0x504d5324 48 + #define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK 46 49 47 50 /** 48 51 * struct smp2p_smem_item - in memory communication structure ··· 139 136 140 137 unsigned valid_entries; 141 138 139 + bool ssr_ack_enabled; 140 + bool ssr_ack; 141 + bool negotiation_done; 142 + 142 143 unsigned local_pid; 143 144 unsigned remote_pid; 144 145 ··· 170 163 } 171 164 } 172 165 173 - /** 174 - * qcom_smp2p_intr() - interrupt handler for incoming notifications 175 - * @irq: unused 176 - * @data: smp2p driver context 177 - * 178 - * Handle notifications from the remote side to handle newly allocated entries 179 - * or any changes to the state bits of existing entries. 180 - */ 181 - static irqreturn_t qcom_smp2p_intr(int irq, void *data) 166 + static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) 167 + { 168 + struct smp2p_smem_item *in = smp2p->in; 169 + bool restart; 170 + 171 + if (!smp2p->ssr_ack_enabled) 172 + return false; 173 + 174 + restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); 175 + 176 + return restart != smp2p->ssr_ack; 177 + } 178 + 179 + static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) 180 + { 181 + struct smp2p_smem_item *out = smp2p->out; 182 + u32 val; 183 + 184 + smp2p->ssr_ack = !smp2p->ssr_ack; 185 + 186 + val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT); 187 + if (smp2p->ssr_ack) 188 + val |= BIT(SMP2P_FLAGS_RESTART_ACK_BIT); 189 + out->flags = val; 190 + 191 + qcom_smp2p_kick(smp2p); 192 + } 193 + 194 + static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) 195 + { 196 + struct smp2p_smem_item *out = smp2p->out; 197 + struct smp2p_smem_item *in = smp2p->in; 198 + 199 + if (in->version == out->version) { 200 + out->features &= in->features; 201 + 202 + if (out->features & SMP2P_FEATURE_SSR_ACK) 203 + smp2p->ssr_ack_enabled = true; 204 + 205 + smp2p->negotiation_done = true; 206 + } 207 + } 208 + 209 + static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) 182 210 { 183 211 struct smp2p_smem_item *in; 184 212 struct smp2p_entry *entry; 185 - struct qcom_smp2p *smp2p = data; 186 - unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND]; 187 - unsigned pid = smp2p->remote_pid; 188 - size_t size; 189 213 int irq_pin; 190 214 u32 status; 191 215 char buf[SMP2P_MAX_ENTRY_NAME]; ··· 224 186 int i; 225 187 226 188 in = smp2p->in; 227 - 228 - /* Acquire smem item, if not already found */ 229 - if (!in) { 230 - in = qcom_smem_get(pid, smem_id, &size); 231 - if (IS_ERR(in)) { 232 - dev_err(smp2p->dev, 233 - "Unable to acquire remote smp2p item\n"); 234 - return IRQ_HANDLED; 235 - } 236 - 237 - smp2p->in = in; 238 - } 239 189 240 190 /* Match newly created entries */ 241 191 for (i = smp2p->valid_entries; i < in->valid_entries; i++) { ··· 263 237 } 264 238 } 265 239 } 240 + } 266 241 242 + /** 243 + * qcom_smp2p_intr() - interrupt handler for incoming notifications 244 + * @irq: unused 245 + * @data: smp2p driver context 246 + * 247 + * Handle notifications from the remote side to handle newly allocated entries 248 + * or any changes to the state bits of existing entries. 249 + */ 250 + static irqreturn_t qcom_smp2p_intr(int irq, void *data) 251 + { 252 + struct smp2p_smem_item *in; 253 + struct qcom_smp2p *smp2p = data; 254 + unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; 255 + unsigned int pid = smp2p->remote_pid; 256 + bool ack_restart; 257 + size_t size; 258 + 259 + in = smp2p->in; 260 + 261 + /* Acquire smem item, if not already found */ 262 + if (!in) { 263 + in = qcom_smem_get(pid, smem_id, &size); 264 + if (IS_ERR(in)) { 265 + dev_err(smp2p->dev, 266 + "Unable to acquire remote smp2p item\n"); 267 + goto out; 268 + } 269 + 270 + smp2p->in = in; 271 + } 272 + 273 + if (!smp2p->negotiation_done) 274 + qcom_smp2p_negotiate(smp2p); 275 + 276 + if (smp2p->negotiation_done) { 277 + ack_restart = qcom_smp2p_check_ssr(smp2p); 278 + qcom_smp2p_notify_in(smp2p); 279 + 280 + if (ack_restart) 281 + qcom_smp2p_do_ssr_ack(smp2p); 282 + } 283 + 284 + out: 267 285 return IRQ_HANDLED; 268 286 } 269 287 ··· 463 393 out->remote_pid = smp2p->remote_pid; 464 394 out->total_entries = SMP2P_MAX_ENTRY; 465 395 out->valid_entries = 0; 396 + out->features = SMP2P_ALL_FEATURES; 466 397 467 398 /* 468 399 * Make sure the rest of the header is written before we validate the ··· 573 502 entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); 574 503 if (!entry) { 575 504 ret = -ENOMEM; 505 + of_node_put(node); 576 506 goto unwind_interfaces; 577 507 } 578 508 ··· 581 509 spin_lock_init(&entry->lock); 582 510 583 511 ret = of_property_read_string(node, "qcom,entry-name", &entry->name); 584 - if (ret < 0) 512 + if (ret < 0) { 513 + of_node_put(node); 585 514 goto unwind_interfaces; 515 + } 586 516 587 517 if (of_property_read_bool(node, "interrupt-controller")) { 588 518 ret = qcom_smp2p_inbound_entry(smp2p, entry, node); 589 - if (ret < 0) 519 + if (ret < 0) { 520 + of_node_put(node); 590 521 goto unwind_interfaces; 522 + } 591 523 592 524 list_add(&entry->node, &smp2p->inbound); 593 525 } else { 594 526 ret = qcom_smp2p_outbound_entry(smp2p, entry, node); 595 - if (ret < 0) 527 + if (ret < 0) { 528 + of_node_put(node); 596 529 goto unwind_interfaces; 530 + } 597 531 598 532 list_add(&entry->node, &smp2p->outbound); 599 533 }
+4 -2
drivers/soc/qcom/socinfo.c
··· 87 87 [15] = "PM8901", 88 88 [16] = "PM8950/PM8027", 89 89 [17] = "PMI8950/ISL9519", 90 - [18] = "PM8921", 91 - [19] = "PM8018", 90 + [18] = "PMK8001/PM8921", 91 + [19] = "PMI8996/PM8018", 92 92 [20] = "PM8998/PM8015", 93 93 [21] = "PMI8998/PM8014", 94 94 [22] = "PM8821", ··· 102 102 [32] = "PM8150B", 103 103 [33] = "PMK8002", 104 104 [36] = "PM8009", 105 + [38] = "PM8150C", 106 + [41] = "SMB2351", 105 107 }; 106 108 #endif /* CONFIG_DEBUG_FS */ 107 109
+21
drivers/soc/qcom/spm.c
··· 67 67 .avs_limit = 0x4200420, 68 68 }; 69 69 70 + static const u16 spm_reg_offset_v3_0[SPM_REG_NR] = { 71 + [SPM_REG_CFG] = 0x08, 72 + [SPM_REG_SPM_CTL] = 0x30, 73 + [SPM_REG_DLY] = 0x34, 74 + [SPM_REG_SEQ_ENTRY] = 0x400, 75 + }; 76 + 77 + /* SPM register data for 8916 */ 78 + static const struct spm_reg_data spm_reg_8916_cpu = { 79 + .reg_offset = spm_reg_offset_v3_0, 80 + .spm_cfg = 0x1, 81 + .spm_dly = 0x3C102800, 82 + .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90, 83 + 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B, 84 + 0x80, 0x10, 0x26, 0x30, 0x0F }, 85 + .start_index[PM_SLEEP_MODE_STBY] = 0, 86 + .start_index[PM_SLEEP_MODE_SPC] = 5, 87 + }; 88 + 70 89 static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = { 71 90 [SPM_REG_CFG] = 0x08, 72 91 [SPM_REG_SPM_CTL] = 0x30, ··· 195 176 .data = &spm_reg_660_silver_l2 }, 196 177 { .compatible = "qcom,msm8226-saw2-v2.1-cpu", 197 178 .data = &spm_reg_8226_cpu }, 179 + { .compatible = "qcom,msm8916-saw2-v3.0-cpu", 180 + .data = &spm_reg_8916_cpu }, 198 181 { .compatible = "qcom,msm8974-saw2-v2.1-cpu", 199 182 .data = &spm_reg_8974_8084_cpu }, 200 183 { .compatible = "qcom,msm8998-gold-saw2-v4.1-l2",