From d0fe6491ddd2232e53d7fd8ee56e37d2c0a511be Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Sep 2021 11:21:08 -0700 Subject: dt-bindings: sram: Document qcom,rpm-msg-ram The Qualcomm SMEM binding always depended on a reference to a SRAM node of compatible "qcom,rpm-msg-ram", document this as part of the SRAM binding. The SRAM is consumed as a whole and not split up using subnodes, so properties related to this are not required. Signed-off-by: Bjorn Andersson Acked-by: Rob Herring Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20210930182111.57353-2-bjorn.andersson@linaro.org --- Documentation/devicetree/bindings/sram/sram.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml index 3eda5049d183..e3311b54db33 100644 --- a/Documentation/devicetree/bindings/sram/sram.yaml +++ b/Documentation/devicetree/bindings/sram/sram.yaml @@ -31,6 +31,7 @@ properties: - amlogic,meson-gxbb-sram - arm,juno-sram-ns - atmel,sama5d2-securam + - qcom,rpm-msg-ram - rockchip,rk3288-pmu-sram reg: @@ -135,7 +136,9 @@ if: properties: compatible: contains: - const: rockchip,rk3288-pmu-sram + enum: + - qcom,rpm-msg-ram + - rockchip,rk3288-pmu-sram else: required: -- cgit From 7a99e87e2e6bce689d77185c1a127b777b2b20f4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Sep 2021 11:21:09 -0700 Subject: dt-bindings: soc: smem: Make indirection optional In the olden days the Qualcomm shared memory (SMEM) region consisted of multiple chunks of memory, so SMEM was described as a standalone node with references to its various memory regions. But practically all modern Qualcomm platforms has a single reserved memory region used for SMEM. So rather than having to use two nodes to describe the one SMEM region, update the binding to allow the reserved-memory region alone to describe SMEM. The olden format is preserved as valid, as this is widely used already. Signed-off-by: Bjorn Andersson Reviewed-by: Rob Herring Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20210930182111.57353-3-bjorn.andersson@linaro.org --- .../devicetree/bindings/soc/qcom/qcom,smem.yaml | 34 +++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml index f7e17713b3d8..4149cf2b66be 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml @@ -10,14 +10,18 @@ maintainers: - Andy Gross - Bjorn Andersson -description: | - This binding describes the Qualcomm Shared Memory Manager, used to share data - between various subsystems and OSes in Qualcomm platforms. +description: + This binding describes the Qualcomm Shared Memory Manager, a region of + reserved-memory used to share data between various subsystems and OSes in + Qualcomm platforms. properties: compatible: const: qcom,smem + reg: + maxItems: 1 + memory-region: maxItems: 1 description: handle to memory reservation for main SMEM memory region. @@ -29,11 +33,19 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: handle to RPM message memory resource + no-map: true + required: - compatible - - memory-region - hwlocks +oneOf: + - required: + - reg + - no-map + - required: + - memory-region + additionalProperties: false examples: @@ -43,6 +55,20 @@ examples: #size-cells = <1>; ranges; + smem@fa00000 { + compatible = "qcom,smem"; + reg = <0xfa00000 0x200000>; + no-map; + + hwlocks = <&tcsr_mutex 3>; + }; + }; + - | + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + smem_region: smem@fa00000 { reg = <0xfa00000 0x200000>; no-map; -- cgit From b5af64fceb04dc298c5e69c517b4d83893ff060b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Sep 2021 11:21:10 -0700 Subject: soc: qcom: smem: Support reserved-memory description Practically all modern Qualcomm platforms has a single reserved-memory region for SMEM. So rather than having to describe SMEM in the form of a node with a reference to a reserved-memory node, allow the SMEM device to be instantiated directly from the reserved-memory node. The current means of falling back to dereferencing the "memory-region" is kept as a fallback, if it's determined that the SMEM node is a reserved-memory node. The "qcom,smem" compatible is added to the reserved_mem_matches list, to allow the reserved-memory device to be probed. In order to retain the readability of the code, the resolution of resources is split from the actual ioremapping. Signed-off-by: Bjorn Andersson Acked-by: Rob Herring Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20210930182111.57353-4-bjorn.andersson@linaro.org --- drivers/of/platform.c | 1 + drivers/soc/qcom/smem.c | 57 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 74afbb7a4f5e..19ba8e4d4f8d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate); static const struct of_device_id reserved_mem_matches[] = { { .compatible = "qcom,rmtfs-mem" }, { .compatible = "qcom,cmd-db" }, + { .compatible = "qcom,smem" }, { .compatible = "ramoops" }, { .compatible = "nvmem-rmem" }, {} diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 4fb5aeeb0843..c7e519bfdc8a 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -240,7 +241,7 @@ static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */ * @size: size of the memory region */ struct smem_region { - u32 aux_base; + phys_addr_t aux_base; void __iomem *virt_base; size_t size; }; @@ -499,7 +500,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, for (i = 0; i < smem->num_regions; i++) { region = &smem->regions[i]; - if (region->aux_base == aux_base || !aux_base) { + if ((u32)region->aux_base == aux_base || !aux_base) { if (size != NULL) *size = le32_to_cpu(entry->size); return region->virt_base + le32_to_cpu(entry->offset); @@ -664,7 +665,7 @@ phys_addr_t qcom_smem_virt_to_phys(void *p) if (p < region->virt_base + region->size) { u64 offset = p - region->virt_base; - return (phys_addr_t)region->aux_base + offset; + return region->aux_base + offset; } } @@ -863,12 +864,12 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) return 0; } -static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, - const char *name, int i) +static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name, + struct smem_region *region) { + struct device *dev = smem->dev; struct device_node *np; struct resource r; - resource_size_t size; int ret; np = of_parse_phandle(dev->of_node, name, 0); @@ -881,13 +882,9 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, of_node_put(np); if (ret) return ret; - size = resource_size(&r); - smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); - if (!smem->regions[i].virt_base) - return -ENOMEM; - smem->regions[i].aux_base = (u32)r.start; - smem->regions[i].size = size; + region->aux_base = r.start; + region->size = resource_size(&r); return 0; } @@ -895,12 +892,14 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, static int qcom_smem_probe(struct platform_device *pdev) { struct smem_header *header; + struct reserved_mem *rmem; struct qcom_smem *smem; size_t array_size; int num_regions; int hwlock_id; u32 version; int ret; + int i; num_regions = 1; if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) @@ -914,13 +913,35 @@ static int qcom_smem_probe(struct platform_device *pdev) smem->dev = &pdev->dev; smem->num_regions = num_regions; - ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0); - if (ret) - return ret; + rmem = of_reserved_mem_lookup(pdev->dev.of_node); + if (rmem) { + smem->regions[0].aux_base = rmem->base; + smem->regions[0].size = rmem->size; + } else { + /* + * Fall back to the memory-region reference, if we're not a + * reserved-memory node. + */ + ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]); + if (ret) + return ret; + } - if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev, - "qcom,rpm-msg-ram", 1))) - return ret; + if (num_regions > 1) { + ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]); + if (ret) + return ret; + } + + for (i = 0; i < num_regions; i++) { + smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev, + smem->regions[i].aux_base, + smem->regions[i].size); + if (!smem->regions[i].virt_base) { + dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base); + return -ENOMEM; + } + } header = smem->regions[0].virt_base; if (le32_to_cpu(header->initialized) != 1 || -- cgit From e3e56c050ab6e3f1bd811f0787f50709017543e4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 4 Oct 2021 20:37:32 -0700 Subject: soc: qcom: rpmhpd: Make power_on actually enable the domain The general expectation is that powering on a power-domain should make the power domain deliver some power, and if a specific performance state is needed further requests has to be made. But in contrast with other power-domain implementations (e.g. rpmpd) the RPMh does not have an interface to enable the power, so the driver has to vote for a particular corner (performance level) in rpmh_power_on(). But the corner is never initialized, so a typical request to simply enable the power domain would not actually turn on the hardware. Further more, when no more clients vote for a performance state (i.e. the aggregated vote is 0) the power domain would be turned off. Fix both of these issues by always voting for a corner with non-zero value, when the power domain is enabled. The tracking of the lowest non-zero corner is performed to handle the corner case if there's ever a domain with a non-zero lowest corner, in which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state() would be allowed to use this lowest corner. Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver") Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20211005033732.2284447-1-bjorn.andersson@linaro.org --- drivers/soc/qcom/rpmhpd.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index e280a8194725..0ca77ed22c6c 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -30,6 +30,7 @@ * @active_only: True if it represents an Active only peer * @corner: current corner * @active_corner: current active corner + * @enable_corner: lowest non-zero corner * @level: An array of level (vlvl) to corner (hlvl) mappings * derived from cmd-db * @level_count: Number of levels supported by the power domain. max @@ -47,6 +48,7 @@ struct rpmhpd { const bool active_only; unsigned int corner; unsigned int active_corner; + unsigned int enable_corner; u32 level[RPMH_ARC_MAX_LEVELS]; size_t level_count; bool enabled; @@ -401,13 +403,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner) static int rpmhpd_power_on(struct generic_pm_domain *domain) { struct rpmhpd *pd = domain_to_rpmhpd(domain); - int ret = 0; + unsigned int corner; + int ret; mutex_lock(&rpmhpd_lock); - if (pd->corner) - ret = rpmhpd_aggregate_corner(pd, pd->corner); - + corner = max(pd->corner, pd->enable_corner); + ret = rpmhpd_aggregate_corner(pd, corner); if (!ret) pd->enabled = true; @@ -452,6 +454,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain, i--; if (pd->enabled) { + /* Ensure that the domain isn't turn off */ + if (i < pd->enable_corner) + i = pd->enable_corner; + ret = rpmhpd_aggregate_corner(pd, i); if (ret) goto out; @@ -488,6 +494,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) for (i = 0; i < rpmhpd->level_count; i++) { rpmhpd->level[i] = buf[i]; + /* Remember the first corner with non-zero level */ + if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i]) + rpmhpd->enable_corner = i; + /* * The AUX data may be zero padded. These 0 valued entries at * the end of the map must be ignored. -- cgit From 2fae3ecc70405b72ea6c923b216d34547559d6a9 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 16 Oct 2021 22:06:07 +0300 Subject: soc: qcom: socinfo: add two missing PMIC IDs Add IDs for PMK8001 and PMI8996. They also fall in the list of 'duplicated' IDs, where the same index was used for multiple chips. Fixes: 7fda2b0bfbd9 ("soc: qcom: socinfo: import PMIC IDs from pmic-spmi") Signed-off-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211016190607.49866-1-dmitry.baryshkov@linaro.org --- drivers/soc/qcom/socinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 288897868435..bec6eb910cba 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -87,8 +87,8 @@ static const char *const pmic_models[] = { [15] = "PM8901", [16] = "PM8950/PM8027", [17] = "PMI8950/ISL9519", - [18] = "PM8921", - [19] = "PM8018", + [18] = "PMK8001/PM8921", + [19] = "PMI8996/PM8018", [20] = "PM8998/PM8015", [21] = "PMI8998/PM8014", [22] = "PM8821", -- cgit From ac3f1ee77cbed7f66932a10d091f653ca1ef8143 Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Wed, 13 Oct 2021 12:08:20 +0530 Subject: dt-bindings: Introduce QCOM Sleep stats bindings Add device binding documentation for Qualcomm Technologies, Inc. (QTI) Sleep stats driver. The driver is used for displaying Sleep statistic maintained by Always On Processor or Resource Power Manager. Cc: devicetree@vger.kernel.org Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Lina Iyer Signed-off-by: Maulik Shah Reviewed-by: Rob Herring Reviewed-by: Bjorn Andersson Reviewed-by: Stephen Boyd Tested-by: Shawn Guo Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1634107104-22197-2-git-send-email-mkshah@codeaurora.org --- .../devicetree/bindings/soc/qcom/qcom-stats.yaml | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml new file mode 100644 index 000000000000..99dff7d73b7e --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/qcom/qcom-stats.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. (QTI) Stats bindings + +maintainers: + - Maulik Shah + +description: + Always On Processor/Resource Power Manager maintains statistics of the SoC + sleep modes involving powering down of the rails and oscillator clock. + + Statistics includes SoC sleep mode type, number of times low power mode were + entered, time of last entry, time of last exit and accumulated sleep duration. + +properties: + compatible: + enum: + - qcom,rpmh-stats + - qcom,rpm-stats + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + # Example of rpmh sleep stats + - | + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0c3f0000 0x400>; + }; + # Example of rpm sleep stats + - | + sram@4690000 { + compatible = "qcom,rpm-stats"; + reg = <0x04690000 0x10000>; + }; +... -- cgit From 1d7724690344a264f8a567c9214aa65456d7566d Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Wed, 13 Oct 2021 12:08:21 +0530 Subject: soc: qcom: Add Sleep stats driver Let's add a driver to read the stats from remote processor and export to debugfs. The driver creates "qcom_sleep_stats" directory in debugfs and adds files for various low power mode available. Below is sample output with command cat /sys/kernel/debug/qcom_sleep_stats/ddr count = 0 Last Entered At = 0 Last Exited At = 0 Accumulated Duration = 0 Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Lina Iyer [mkshah: add subsystem sleep stats, create one file for each stat] Signed-off-by: Maulik Shah Tested-by: Shawn Guo Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1634107104-22197-3-git-send-email-mkshah@codeaurora.org --- drivers/soc/qcom/Kconfig | 10 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qcom_stats.c | 277 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 drivers/soc/qcom/qcom_stats.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index abfef201b94f..3cf3a6b41182 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -199,6 +199,16 @@ config QCOM_SPM to manage cores, L2 low power modes and to configure the internal Adaptive Voltage Scaler parameters, where supported. +config QCOM_STATS + tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver" + depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST + depends on QCOM_SMEM + help + Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read + the shared memory exported by the remote processor related to + various SoC level low power modes statistics and export to debugfs + interface. + config QCOM_WCNSS_CTRL tristate "Qualcomm WCNSS control driver" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 24514c722832..70d5de69fd7b 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o obj-$(CONFIG_QCOM_SPM) += spm.o +obj-$(CONFIG_QCOM_STATS) += qcom_stats.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_APR) += apr.o obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c new file mode 100644 index 000000000000..817505bd99b5 --- /dev/null +++ b/drivers/soc/qcom/qcom_stats.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define RPM_DYNAMIC_ADDR 0x14 +#define RPM_DYNAMIC_ADDR_MASK 0xFFFF + +#define STAT_TYPE_OFFSET 0x0 +#define COUNT_OFFSET 0x4 +#define LAST_ENTERED_AT_OFFSET 0x8 +#define LAST_EXITED_AT_OFFSET 0x10 +#define ACCUMULATED_OFFSET 0x18 +#define CLIENT_VOTES_OFFSET 0x1c + +struct subsystem_data { + const char *name; + u32 smem_item; + u32 pid; +}; + +static const struct subsystem_data subsystems[] = { + { "modem", 605, 1 }, + { "wpss", 605, 13 }, + { "adsp", 606, 2 }, + { "cdsp", 607, 5 }, + { "slpi", 608, 3 }, + { "gpu", 609, 0 }, + { "display", 610, 0 }, + { "adsp_island", 613, 2 }, + { "slpi_island", 613, 3 }, +}; + +struct stats_config { + size_t stats_offset; + size_t num_records; + bool appended_stats_avail; + bool dynamic_offset; + bool subsystem_stats_in_smem; +}; + +struct stats_data { + bool appended_stats_avail; + void __iomem *base; +}; + +struct sleep_stats { + u32 stat_type; + u32 count; + u64 last_entered_at; + u64 last_exited_at; + u64 accumulated; +}; + +struct appended_stats { + u32 client_votes; + u32 reserved[3]; +}; + +static void qcom_print_stats(struct seq_file *s, const struct sleep_stats *stat) +{ + u64 accumulated = stat->accumulated; + /* + * If a subsystem is in sleep when reading the sleep stats adjust + * the accumulated sleep duration to show actual sleep time. + */ + if (stat->last_entered_at > stat->last_exited_at) + accumulated += arch_timer_read_counter() - stat->last_entered_at; + + seq_printf(s, "Count: %u\n", stat->count); + seq_printf(s, "Last Entered At: %llu\n", stat->last_entered_at); + seq_printf(s, "Last Exited At: %llu\n", stat->last_exited_at); + seq_printf(s, "Accumulated Duration: %llu\n", accumulated); +} + +static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused) +{ + struct subsystem_data *subsystem = s->private; + struct sleep_stats *stat; + + /* Items are allocated lazily, so lookup pointer each time */ + stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL); + if (IS_ERR(stat)) + return -EIO; + + qcom_print_stats(s, stat); + + return 0; +} + +static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused) +{ + struct stats_data *d = s->private; + void __iomem *reg = d->base; + struct sleep_stats stat; + + memcpy_fromio(&stat, reg, sizeof(stat)); + qcom_print_stats(s, &stat); + + if (d->appended_stats_avail) { + struct appended_stats votes; + + memcpy_fromio(&votes, reg + CLIENT_VOTES_OFFSET, sizeof(votes)); + seq_printf(s, "Client Votes: %#x\n", votes.client_votes); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats); +DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats); + +static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg, + struct stats_data *d, + const struct stats_config *config) +{ + char stat_type[sizeof(u32) + 1] = {0}; + size_t stats_offset = config->stats_offset; + u32 offset = 0, type; + int i, j; + + /* + * On RPM targets, stats offset location is dynamic and changes from target + * to target and sometimes from build to build for same target. + * + * In such cases the dynamic address is present at 0x14 offset from base + * address in devicetree. The last 16bits indicates the stats_offset. + */ + if (config->dynamic_offset) { + stats_offset = readl(reg + RPM_DYNAMIC_ADDR); + stats_offset &= RPM_DYNAMIC_ADDR_MASK; + } + + for (i = 0; i < config->num_records; i++) { + d[i].base = reg + offset + stats_offset; + + /* + * Read the low power mode name and create debugfs file for it. + * The names read could be of below, + * (may change depending on low power mode supported). + * For rpmh-sleep-stats: "aosd", "cxsd" and "ddr". + * For rpm-sleep-stats: "vmin" and "vlow". + */ + type = readl(d[i].base); + for (j = 0; j < sizeof(u32); j++) { + stat_type[j] = type & 0xff; + type = type >> 8; + } + strim(stat_type); + debugfs_create_file(stat_type, 0400, root, &d[i], + &qcom_soc_sleep_stats_fops); + + offset += sizeof(struct sleep_stats); + if (d[i].appended_stats_avail) + offset += sizeof(struct appended_stats); + } +} + +static void qcom_create_subsystem_stat_files(struct dentry *root, + const struct stats_config *config) +{ + const struct sleep_stats *stat; + int i; + + if (!config->subsystem_stats_in_smem) + return; + + for (i = 0; i < ARRAY_SIZE(subsystems); i++) { + stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL); + if (IS_ERR(stat)) + continue; + + debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i], + &qcom_subsystem_sleep_stats_fops); + } +} + +static int qcom_stats_probe(struct platform_device *pdev) +{ + void __iomem *reg; + struct dentry *root; + const struct stats_config *config; + struct stats_data *d; + int i; + + config = device_get_match_data(&pdev->dev); + if (!config) + return -ENODEV; + + reg = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(reg)) + return -ENOMEM; + + d = devm_kcalloc(&pdev->dev, config->num_records, + sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + for (i = 0; i < config->num_records; i++) + d[i].appended_stats_avail = config->appended_stats_avail; + + root = debugfs_create_dir("qcom_stats", NULL); + + qcom_create_subsystem_stat_files(root, config); + qcom_create_soc_sleep_stat_files(root, reg, d, config); + + platform_set_drvdata(pdev, root); + + return 0; +} + +static int qcom_stats_remove(struct platform_device *pdev) +{ + struct dentry *root = platform_get_drvdata(pdev); + + debugfs_remove_recursive(root); + + return 0; +} + +static const struct stats_config rpm_data = { + .stats_offset = 0, + .num_records = 2, + .appended_stats_avail = true, + .dynamic_offset = true, + .subsystem_stats_in_smem = false, +}; + +static const struct stats_config rpmh_data = { + .stats_offset = 0x48, + .num_records = 3, + .appended_stats_avail = false, + .dynamic_offset = false, + .subsystem_stats_in_smem = true, +}; + +static const struct of_device_id qcom_stats_table[] = { + { .compatible = "qcom,rpm-stats", .data = &rpm_data }, + { .compatible = "qcom,rpmh-stats", .data = &rpmh_data }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_stats_table); + +static struct platform_driver qcom_stats = { + .probe = qcom_stats_probe, + .remove = qcom_stats_remove, + .driver = { + .name = "qcom_stats", + .of_match_table = qcom_stats_table, + }, +}; + +static int __init qcom_stats_init(void) +{ + return platform_driver_register(&qcom_stats); +} +late_initcall(qcom_stats_init); + +static void __exit qcom_stats_exit(void) +{ + platform_driver_unregister(&qcom_stats); +} +module_exit(qcom_stats_exit) + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. (QTI) Stats driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 85f755083b23b1ee59c96df80f148e6203bb078f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 5 Oct 2021 21:43:23 +0530 Subject: soc: qcom: smp2p: add feature negotiation and ssr ack feature support This patch adds feature negotiation and ssr ack feature between local host and remote processor. Local host can negotiate on common features supported with remote processor. When ssr ack feature bit is set, the remote processor will tell local host when it is reinitialized. All clients registered for falling edge interrupts will be notified when the smp2p entries are cleared for ssr. Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1633450403-21281-1-git-send-email-deesin@codeaurora.org --- drivers/soc/qcom/smp2p.c | 121 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 25 deletions(-) diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 38585a7edfe7..11b95113e38e 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -41,8 +41,11 @@ #define SMP2P_MAX_ENTRY_NAME 16 #define SMP2P_FEATURE_SSR_ACK 0x1 +#define SMP2P_FLAGS_RESTART_DONE_BIT 0 +#define SMP2P_FLAGS_RESTART_ACK_BIT 1 #define SMP2P_MAGIC 0x504d5324 +#define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK /** * struct smp2p_smem_item - in memory communication structure @@ -136,6 +139,10 @@ struct qcom_smp2p { unsigned valid_entries; + bool ssr_ack_enabled; + bool ssr_ack; + bool negotiation_done; + unsigned local_pid; unsigned remote_pid; @@ -163,22 +170,53 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) } } -/** - * qcom_smp2p_intr() - interrupt handler for incoming notifications - * @irq: unused - * @data: smp2p driver context - * - * Handle notifications from the remote side to handle newly allocated entries - * or any changes to the state bits of existing entries. - */ -static irqreturn_t qcom_smp2p_intr(int irq, void *data) +static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) +{ + struct smp2p_smem_item *in = smp2p->in; + bool restart; + + if (!smp2p->ssr_ack_enabled) + return false; + + restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); + + return restart != smp2p->ssr_ack; +} + +static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) +{ + struct smp2p_smem_item *out = smp2p->out; + u32 val; + + smp2p->ssr_ack = !smp2p->ssr_ack; + + val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT); + if (smp2p->ssr_ack) + val |= BIT(SMP2P_FLAGS_RESTART_ACK_BIT); + out->flags = val; + + qcom_smp2p_kick(smp2p); +} + +static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) +{ + struct smp2p_smem_item *out = smp2p->out; + struct smp2p_smem_item *in = smp2p->in; + + if (in->version == out->version) { + out->features &= in->features; + + if (out->features & SMP2P_FEATURE_SSR_ACK) + smp2p->ssr_ack_enabled = true; + + smp2p->negotiation_done = true; + } +} + +static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in; struct smp2p_entry *entry; - struct qcom_smp2p *smp2p = data; - unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND]; - unsigned pid = smp2p->remote_pid; - size_t size; int irq_pin; u32 status; char buf[SMP2P_MAX_ENTRY_NAME]; @@ -187,18 +225,6 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) in = smp2p->in; - /* Acquire smem item, if not already found */ - if (!in) { - in = qcom_smem_get(pid, smem_id, &size); - if (IS_ERR(in)) { - dev_err(smp2p->dev, - "Unable to acquire remote smp2p item\n"); - return IRQ_HANDLED; - } - - smp2p->in = in; - } - /* Match newly created entries */ for (i = smp2p->valid_entries; i < in->valid_entries; i++) { list_for_each_entry(entry, &smp2p->inbound, node) { @@ -237,7 +263,51 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) } } } +} + +/** + * qcom_smp2p_intr() - interrupt handler for incoming notifications + * @irq: unused + * @data: smp2p driver context + * + * Handle notifications from the remote side to handle newly allocated entries + * or any changes to the state bits of existing entries. + */ +static irqreturn_t qcom_smp2p_intr(int irq, void *data) +{ + struct smp2p_smem_item *in; + struct qcom_smp2p *smp2p = data; + unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; + unsigned int pid = smp2p->remote_pid; + bool ack_restart; + size_t size; + + in = smp2p->in; + + /* Acquire smem item, if not already found */ + if (!in) { + in = qcom_smem_get(pid, smem_id, &size); + if (IS_ERR(in)) { + dev_err(smp2p->dev, + "Unable to acquire remote smp2p item\n"); + goto out; + } + + smp2p->in = in; + } + + if (!smp2p->negotiation_done) + qcom_smp2p_negotiate(smp2p); + + if (smp2p->negotiation_done) { + ack_restart = qcom_smp2p_check_ssr(smp2p); + qcom_smp2p_notify_in(smp2p); + + if (ack_restart) + qcom_smp2p_do_ssr_ack(smp2p); + } +out: return IRQ_HANDLED; } @@ -393,6 +463,7 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) out->remote_pid = smp2p->remote_pid; out->total_entries = SMP2P_MAX_ENTRY; out->valid_entries = 0; + out->features = SMP2P_ALL_FEATURES; /* * Make sure the rest of the header is written before we validate the -- cgit From 38212b2a8a6fc4c3a6fa99d7445b833bedc9a67c Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 11 Oct 2021 13:00:14 -0700 Subject: firmware: qcom_scm: Fix error retval in __qcom_scm_is_call_available() Since __qcom_scm_is_call_available() returns bool, have it return false instead of -EINVAL if an invalid SMC convention is detected. This fixes the Smatch static checker warning: drivers/firmware/qcom_scm.c:255 __qcom_scm_is_call_available() warn: signedness bug returning '(-22)' Fixes: 9d11af8b06a8 ("firmware: qcom_scm: Make __qcom_scm_is_call_available() return bool") Reported-by: Dan Carpenter Signed-off-by: Guru Das Srinagesh Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1633982414-28347-1-git-send-email-quic_gurus@quicinc.com --- drivers/firmware/qcom_scm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index a861033616ee..7db8066b19fd 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -252,7 +252,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id, break; default: pr_err("Unknown SMC convention being used\n"); - return -EINVAL; + return false; } ret = qcom_scm_call(dev, &desc, &res); -- cgit From 87fd343c6e398e3a1d3368a4a8c9833dce0894ff Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 4 Oct 2021 19:40:25 -0700 Subject: soc: qcom: socinfo: Add PM8150C and SMB2351 models Add PM8150C and SMB2351 to the list of known PMIC models. Signed-off-by: Bjorn Andersson Reviewed-by: Bhupesh Sharma Link: https://lore.kernel.org/r/20211005024025.2037810-1-bjorn.andersson@linaro.org --- drivers/soc/qcom/socinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index bec6eb910cba..553554e7116e 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -102,6 +102,8 @@ static const char *const pmic_models[] = { [32] = "PM8150B", [33] = "PMK8002", [36] = "PM8009", + [38] = "PM8150C", + [41] = "SMB2351", }; #endif /* CONFIG_DEBUG_FS */ -- cgit From 93fcf45b16b56fe3b7843d84b6d9801d913ab58f Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 4 Oct 2021 22:49:50 +0200 Subject: dt-bindings: soc: qcom: spm: Document qcom,msm8916-saw2-v3.0-cpu Document the qcom,msm8916-saw2-v3.0-cpu compatible that is needed for cpuidle for MSM8916 on some devices with signed firmware which is only capable of booting ARM32 kernels without PSCI. Acked-by: Rob Herring Signed-off-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211004204955.21077-10-stephan@gerhold.net --- Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml index d68c002527fa..07d2d5398345 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml @@ -22,6 +22,7 @@ properties: - qcom,sdm660-silver-saw2-v4.1-l2 - qcom,msm8998-gold-saw2-v4.1-l2 - qcom,msm8998-silver-saw2-v4.1-l2 + - qcom,msm8916-saw2-v3.0-cpu - qcom,msm8226-saw2-v2.1-cpu - qcom,msm8974-saw2-v2.1-cpu - qcom,apq8084-saw2-v2.1-cpu -- cgit From 7f8adb19e97339d0b36ea98e61d8c455efd86874 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Mon, 4 Oct 2021 22:49:51 +0200 Subject: soc: qcom: spm: Add 8916 SPM register data Add SPM register information and initialization values for QCOM 8916 SoC. Link: https://lore.kernel.org/linux-arm-msm/1429314549-6730-5-git-send-email-lina.iyer@linaro.org/ Signed-off-by: Lina Iyer [stephan: rebase patch and fix conflicts] Signed-off-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211004204955.21077-11-stephan@gerhold.net --- drivers/soc/qcom/spm.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index 2961a89d929c..f831420b7fd4 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -67,6 +67,25 @@ static const struct spm_reg_data spm_reg_8998_silver_l2 = { .avs_limit = 0x4200420, }; +static const u16 spm_reg_offset_v3_0[SPM_REG_NR] = { + [SPM_REG_CFG] = 0x08, + [SPM_REG_SPM_CTL] = 0x30, + [SPM_REG_DLY] = 0x34, + [SPM_REG_SEQ_ENTRY] = 0x400, +}; + +/* SPM register data for 8916 */ +static const struct spm_reg_data spm_reg_8916_cpu = { + .reg_offset = spm_reg_offset_v3_0, + .spm_cfg = 0x1, + .spm_dly = 0x3C102800, + .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90, + 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B, + 0x80, 0x10, 0x26, 0x30, 0x0F }, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 5, +}; + static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = { [SPM_REG_CFG] = 0x08, [SPM_REG_SPM_CTL] = 0x30, @@ -176,6 +195,8 @@ static const struct of_device_id spm_match_table[] = { .data = &spm_reg_660_silver_l2 }, { .compatible = "qcom,msm8226-saw2-v2.1-cpu", .data = &spm_reg_8226_cpu }, + { .compatible = "qcom,msm8916-saw2-v3.0-cpu", + .data = &spm_reg_8916_cpu }, { .compatible = "qcom,msm8974-saw2-v2.1-cpu", .data = &spm_reg_8974_8084_cpu }, { .compatible = "qcom,msm8998-gold-saw2-v4.1-l2", -- cgit From 55845f46df0317fc7b06617ad21ebca08d72b668 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 4 Oct 2021 22:49:52 +0200 Subject: firmware: qcom: scm: Add support for MC boot address API It looks like the old QCOM_SCM_BOOT_SET_ADDR API is broken on some MSM8916 firmware versions that implement the newer SMC32 calling convention. It just returns -EINVAL no matter which arguments are being passed. This does not cause any problems downstream because it first tries to use the new multi-cluster API replacement which is working fine. Implement support for the multi-cluster variant of the SCM call by attempting it first but still fallback to the old call in case of an error. Also, to be absolutely sure only use the multi-cluster variant with the SMC calling convention since older platforms should not need this. Signed-off-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211004204955.21077-12-stephan@gerhold.net --- drivers/firmware/qcom_scm.c | 84 ++++++++++++++++++++++++++++++++++++--------- drivers/firmware/qcom_scm.h | 4 +++ 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 7db8066b19fd..7dd9e5e10f23 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -17,6 +17,8 @@ #include #include +#include + #include "qcom_scm.h" static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); @@ -260,15 +262,36 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id, return ret ? false : !!res.result[0]; } -/** - * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus - * @entry: Entry point function for the cpus - * @cpus: The cpumask of cpus that will use the entry point - * - * Set the Linux entry point for the SCM to transfer control to when coming - * out of a power down. CPU power down may be executed on cpuidle or hotplug. - */ -int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) +static int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus, + unsigned int flags) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_SET_ADDR_MC, + .owner = ARM_SMCCC_OWNER_SIP, + .arginfo = QCOM_SCM_ARGS(6), + }; + unsigned int cpu; + u64 map; + + /* Need a device for DMA of the additional arguments */ + if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY) + return -EOPNOTSUPP; + + desc.args[0] = virt_to_phys(entry); + for_each_cpu(cpu, cpus) { + map = cpu_logical_map(cpu); + desc.args[1] |= BIT(MPIDR_AFFINITY_LEVEL(map, 0)); + desc.args[2] |= BIT(MPIDR_AFFINITY_LEVEL(map, 1)); + desc.args[3] |= BIT(MPIDR_AFFINITY_LEVEL(map, 2)); + } + desc.args[4] = ~0ULL; /* Reserved for affinity level 3 */ + desc.args[5] = flags; + + return qcom_scm_call(__scm->dev, &desc, NULL); +} + +static int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) { int ret; int flags = 0; @@ -304,17 +327,28 @@ int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) return ret; } -EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); /** - * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus + * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus * @entry: Entry point function for the cpus * @cpus: The cpumask of cpus that will use the entry point * - * Set the cold boot address of the cpus. Any cpu outside the supported - * range would be removed from the cpu present mask. + * Set the Linux entry point for the SCM to transfer control to when coming + * out of a power down. CPU power down may be executed on cpuidle or hotplug. */ -int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) +int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) +{ + if (!cpus || cpumask_empty(cpus)) + return -EINVAL; + + if (__qcom_scm_set_boot_addr_mc(entry, cpus, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT)) + /* Fallback to old SCM call */ + return __qcom_scm_set_warm_boot_addr(entry, cpus); + return 0; +} +EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); + +static int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) { int flags = 0; int cpu; @@ -331,9 +365,6 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) .owner = ARM_SMCCC_OWNER_SIP, }; - if (!cpus || cpumask_empty(cpus)) - return -EINVAL; - for_each_cpu(cpu, cpus) { if (cpu < ARRAY_SIZE(scm_cb_flags)) flags |= scm_cb_flags[cpu]; @@ -346,6 +377,25 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL); } + +/** + * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus + * @entry: Entry point function for the cpus + * @cpus: The cpumask of cpus that will use the entry point + * + * Set the cold boot address of the cpus. Any cpu outside the supported + * range would be removed from the cpu present mask. + */ +int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) +{ + if (!cpus || cpumask_empty(cpus)) + return -EINVAL; + + if (__qcom_scm_set_boot_addr_mc(entry, cpus, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT)) + /* Fallback to old SCM call */ + return __qcom_scm_set_cold_boot_addr(entry, cpus); + return 0; +} EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); /** diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index d92156ceb3ac..2a6a87b75231 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -78,8 +78,12 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_BOOT_SET_ADDR 0x01 #define QCOM_SCM_BOOT_TERMINATE_PC 0x02 #define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10 +#define QCOM_SCM_BOOT_SET_ADDR_MC 0x11 #define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a #define QCOM_SCM_FLUSH_FLAG_MASK 0x3 +#define QCOM_SCM_BOOT_MC_FLAG_AARCH64 BIT(0) +#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1) +#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2) #define QCOM_SCM_SVC_PIL 0x02 #define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01 -- cgit From 87922aec8a269805aad7fd462c8959cda49ea9df Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 4 Oct 2021 22:49:49 +0200 Subject: ARM: qcom: Add qcom,msm8916-smp enable-method identical to MSM8226 Unfortunately, some MSM8916 devices have signed firmware without ARM64 and PSCI support and can therefore only boot ARM32 Linux. The ARM Cortex-A53 cores should be actually booted exactly like the Cortex-A7 cores on MSM8226, so just add an alias for the existing code. Signed-off-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211004204955.21077-9-stephan@gerhold.net --- arch/arm/mach-qcom/platsmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index 60496554c6dd..58a4228455ce 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -385,6 +385,7 @@ static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = { #endif }; CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops); +CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops); static const struct smp_operations qcom_smp_kpssv1_ops __initconst = { .smp_prepare_cpus = qcom_smp_prepare_cpus, -- cgit From 8e24a29620317012bf271d35692a5bab52831be1 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 4 Oct 2021 22:49:48 +0200 Subject: dt-bindings: arm: cpus: Document qcom,msm8916-smp enable-method Since MSM8916 is an ARM v8 64-bit SoC the CPU cores are normally booted using "psci" or "spin-table". Unfortunately, some devices come with signed 32-bit-only firmware without ARM64 and PSCI support. This setup is easy to support since it's very similar to older 32-bit only Qualcomm SoCs (e.g. MSM8226) and only requires adding a few new definitions to already existing drivers. Document the qcom,msm8916-smp enable-method. It is actually just an alias of qcom,msm8226-smp since it should be implemented identically. The enable-method is only valid on ARM32 and must not be used on ARM64. Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211004204955.21077-8-stephan@gerhold.net --- Documentation/devicetree/bindings/arm/cpus.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 6a1e3d455897..cd52f5c9b762 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -210,6 +210,8 @@ properties: - qcom,kpss-acc-v1 - qcom,kpss-acc-v2 - qcom,msm8226-smp + # Only valid on ARM 32-bit, see above for ARM v8 64-bit + - qcom,msm8916-smp - renesas,apmu - renesas,r9a06g032-smp - rockchip,rk3036-smp @@ -294,7 +296,8 @@ properties: Specifies the ACC* node associated with this CPU. Required for systems that have an "enable-method" property - value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2" or "qcom,msm8226-smp" + value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2", "qcom,msm8226-smp" or + "qcom,msm8916-smp". * arm/msm/qcom,kpss-acc.txt -- cgit From 086f52fdc8f7bd273d06a3de2adf65a063eb5392 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 20 Oct 2021 04:26:39 +0300 Subject: soc: qcom: rpmhpd: fix sm8350_mxc's peer domain The sm8350_mxc's domain description incorrectly references sm8150_mmcx_ao as a peer instead of sm8350_mxc_ao. Correct this typo. Fixes: 639c85628757 ("soc: qcom: rpmhpd: Add SM8350 power domains") Cc: Vinod Koul Signed-off-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211020012639.1183806-1-dmitry.baryshkov@linaro.org --- drivers/soc/qcom/rpmhpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 0ca77ed22c6c..1118345d8824 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -221,7 +221,7 @@ static const struct rpmhpd_desc sm8250_desc = { static struct rpmhpd sm8350_mxc_ao; static struct rpmhpd sm8350_mxc = { .pd = { .name = "mxc", }, - .peer = &sm8150_mmcx_ao, + .peer = &sm8350_mxc_ao, .res_name = "mxc.lvl", }; -- cgit From 62563bd99c7d7be269982b88173ad8938420d648 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Wed, 20 Oct 2021 14:19:13 +0530 Subject: soc: qcom: qcom_stats: Fix client votes offset Client votes starts at 0x20 offset. Correct the offset. Reported-and-suggested-by: Shawn Guo Fixes: 1d7724690344 ("soc: qcom: Add Sleep stats driver") Signed-off-by: Maulik Shah Reviewed-by: Shawn Guo Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1634719753-26064-1-git-send-email-mkshah@codeaurora.org --- drivers/soc/qcom/qcom_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 817505bd99b5..131d24caabf8 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -22,7 +22,7 @@ #define LAST_ENTERED_AT_OFFSET 0x8 #define LAST_EXITED_AT_OFFSET 0x10 #define ACCUMULATED_OFFSET 0x18 -#define CLIENT_VOTES_OFFSET 0x1c +#define CLIENT_VOTES_OFFSET 0x20 struct subsystem_data { const char *name; -- cgit From 72f1aa6205d84337b90b065f602a8fe190821781 Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Thu, 14 Oct 2021 04:30:17 -0400 Subject: soc: qcom: apr: Add of_node_put() before return Fix following coccicheck warning: ./drivers/soc/qcom/apr.c:485:1-23: WARNING: Function for_each_child_of_node should have of_node_put() before return Early exits from for_each_child_of_node should decrement the node reference counter. Fixes: 834735662602 ("soc: qcom: apr: Add avs/audio tracking functionality") Signed-off-by: Wan Jiabing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211014083017.19714-1-wanjiabing@vivo.com --- drivers/soc/qcom/apr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 8a9bfbcd4bb9..82ca12c9328a 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -492,12 +492,14 @@ static int of_apr_add_pd_lookups(struct device *dev) 1, &service_path); if (ret < 0) { dev_err(dev, "pdr service path missing: %d\n", ret); + of_node_put(node); return ret; } pds = pdr_add_lookup(apr->pdr, service_name, service_path); if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds)); + of_node_put(node); return PTR_ERR(pds); } } -- cgit From e1b391e9712db4880394e727ae623b96ee18d618 Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Thu, 14 Oct 2021 02:23:49 -0400 Subject: soc: qcom: smp2p: Add of_node_put() before goto Fix following coccicheck warning: ./drivers/soc/qcom/smp2p.c:501:1-33: WARNING: Function for_each_available_child_of_node should have of_node_put() before goto Early exits from for_each_available_child_of_node should decrement the node reference counter. Signed-off-by: Wan Jiabing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211014062350.8942-1-wanjiabing@vivo.com --- drivers/soc/qcom/smp2p.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 11b95113e38e..4a157240f419 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -573,6 +573,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev) entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; + of_node_put(node); goto unwind_interfaces; } @@ -580,19 +581,25 @@ static int qcom_smp2p_probe(struct platform_device *pdev) spin_lock_init(&entry->lock); ret = of_property_read_string(node, "qcom,entry-name", &entry->name); - if (ret < 0) + if (ret < 0) { + of_node_put(node); goto unwind_interfaces; + } if (of_property_read_bool(node, "interrupt-controller")) { ret = qcom_smp2p_inbound_entry(smp2p, entry, node); - if (ret < 0) + if (ret < 0) { + of_node_put(node); goto unwind_interfaces; + } list_add(&entry->node, &smp2p->inbound); } else { ret = qcom_smp2p_outbound_entry(smp2p, entry, node); - if (ret < 0) + if (ret < 0) { + of_node_put(node); goto unwind_interfaces; + } list_add(&entry->node, &smp2p->outbound); } -- cgit From c50031f03dfe1c1462f326973ddc5f0db839fb68 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sun, 24 Oct 2021 19:58:16 -0700 Subject: firmware: qcom: scm: Don't break compile test on non-ARM platforms The introduction of __qcom_scm_set_boot_addr_mc() relies on cpu_logical_map() and MPIDR_AFFINITY_LEVEL() from smp_plat.h, but only ARM and ARM64 has this include file, so the introduction of this dependency broke compile testing on e.g. x86_64. Make the inclusion of smp_plat.h and the affected function depend on ARM || ARM64 to allow the code to still be compiled. Fixes: 55845f46df03 ("firmware: qcom: scm: Add support for MC boot address API") Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211025025816.2937465-1-bjorn.andersson@linaro.org --- drivers/firmware/qcom_scm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 7dd9e5e10f23..11464f6502be 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -17,7 +17,9 @@ #include #include +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) #include +#endif #include "qcom_scm.h" @@ -262,6 +264,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id, return ret ? false : !!res.result[0]; } +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) static int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus, unsigned int flags) { @@ -290,6 +293,13 @@ static int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus, return qcom_scm_call(__scm->dev, &desc, NULL); } +#else +static inline int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus, + unsigned int flags) +{ + return -EINVAL; +} +#endif static int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) { -- cgit