From 8c75d585b931ac874fbe4ee5a8f1811d20c2817f Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Tue, 31 Aug 2021 20:00:27 +0530 Subject: [PATCH 01/40] soc: qcom: aoss: Expose send for generic usecase Not all upcoming usecases will have an interface to allow the aoss driver to hook onto. Expose the send api and create a get function to enable drivers to send their own messages to aoss. Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1630420228-31075-2-git-send-email-deesin@codeaurora.org --- drivers/soc/qcom/qcom_aoss.c | 54 +++++++++++++++++++++++++++++- include/linux/soc/qcom/qcom_aoss.h | 38 +++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 include/linux/soc/qcom/qcom_aoss.h diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 536c3e4114fb..bb336cc8df6f 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -8,10 +8,12 @@ #include #include #include +#include #include #include #include #include +#include #define QMP_DESC_MAGIC 0x0 #define QMP_DESC_VERSION 0x4 @@ -223,11 +225,14 @@ static bool qmp_message_empty(struct qmp *qmp) * * Return: 0 on success, negative errno on failure */ -static int qmp_send(struct qmp *qmp, const void *data, size_t len) +int qmp_send(struct qmp *qmp, const void *data, size_t len) { long time_left; int ret; + if (WARN_ON(IS_ERR_OR_NULL(qmp) || !data)) + return -EINVAL; + if (WARN_ON(len + sizeof(u32) > qmp->size)) return -EINVAL; @@ -261,6 +266,7 @@ static int qmp_send(struct qmp *qmp, const void *data, size_t len) return ret; } +EXPORT_SYMBOL(qmp_send); static int qmp_qdss_clk_prepare(struct clk_hw *hw) { @@ -519,6 +525,51 @@ static void qmp_cooling_devices_remove(struct qmp *qmp) thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev); } +/** + * qmp_get() - get a qmp handle from a device + * @dev: client device pointer + * + * Return: handle to qmp device on success, ERR_PTR() on failure + */ +struct qmp *qmp_get(struct device *dev) +{ + struct platform_device *pdev; + struct device_node *np; + struct qmp *qmp; + + if (!dev || !dev->of_node) + return ERR_PTR(-EINVAL); + + np = of_parse_phandle(dev->of_node, "qcom,qmp", 0); + if (!np) + return ERR_PTR(-ENODEV); + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) + return ERR_PTR(-EINVAL); + + qmp = platform_get_drvdata(pdev); + + return qmp ? qmp : ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL(qmp_get); + +/** + * qmp_put() - release a qmp handle + * @qmp: qmp handle obtained from qmp_get() + */ +void qmp_put(struct qmp *qmp) +{ + /* + * Match get_device() inside of_find_device_by_node() in + * qmp_get() + */ + if (!IS_ERR_OR_NULL(qmp)) + put_device(qmp->dev); +} +EXPORT_SYMBOL(qmp_put); + static int qmp_probe(struct platform_device *pdev) { struct resource *res; @@ -615,6 +666,7 @@ static struct platform_driver qmp_driver = { .driver = { .name = "qcom_aoss_qmp", .of_match_table = qmp_dt_match, + .suppress_bind_attrs = true, }, .probe = qmp_probe, .remove = qmp_remove, diff --git a/include/linux/soc/qcom/qcom_aoss.h b/include/linux/soc/qcom/qcom_aoss.h new file mode 100644 index 000000000000..3c2a82e606f8 --- /dev/null +++ b/include/linux/soc/qcom/qcom_aoss.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef __QCOM_AOSS_H__ +#define __QCOM_AOSS_H__ + +#include +#include + +struct qmp; + +#if IS_ENABLED(CONFIG_QCOM_AOSS_QMP) + +int qmp_send(struct qmp *qmp, const void *data, size_t len); +struct qmp *qmp_get(struct device *dev); +void qmp_put(struct qmp *qmp); + +#else + +static inline int qmp_send(struct qmp *qmp, const void *data, size_t len) +{ + return -ENODEV; +} + +static inline struct qmp *qmp_get(struct device *dev) +{ + return ERR_PTR(-ENODEV); +} + +static inline void qmp_put(struct qmp *qmp) +{ +} + +#endif + +#endif From c2b854b03adf325056f57f1aa239440c4e9c7c56 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 20 Aug 2021 22:31:02 +0200 Subject: [PATCH 02/40] soc: qcom: rpmhpd: Add SM6350 Add the power domains exposed by RPMH in the Qualcomm SM6350 platform. Acked-by: AngeloGioacchino Del Regno Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20210820203105.229764-4-konrad.dybcio@somainline.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/rpmhpd.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index fa209b479ab3..e280a8194725 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -147,6 +147,21 @@ static const struct rpmhpd_desc sdx55_desc = { .num_pds = ARRAY_SIZE(sdx55_rpmhpds), }; +/* SM6350 RPMH powerdomains */ +static struct rpmhpd *sm6350_rpmhpds[] = { + [SM6350_CX] = &sdm845_cx, + [SM6350_GFX] = &sdm845_gfx, + [SM6350_LCX] = &sdm845_lcx, + [SM6350_LMX] = &sdm845_lmx, + [SM6350_MSS] = &sdm845_mss, + [SM6350_MX] = &sdm845_mx, +}; + +static const struct rpmhpd_desc sm6350_desc = { + .rpmhpds = sm6350_rpmhpds, + .num_pds = ARRAY_SIZE(sm6350_rpmhpds), +}; + /* SM8150 RPMH powerdomains */ static struct rpmhpd sm8150_mmcx_ao; @@ -297,6 +312,7 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, + { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc }, { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc }, From 1f7b2b6327ffd16d8704bfbf0c28b6bdb6ece39f Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 20 Aug 2021 22:31:04 +0200 Subject: [PATCH 03/40] soc: qcom: llcc: Add configuration data for SM6350 Add LLCC configuration data for SM6350 SoC. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20210820203105.229764-6-konrad.dybcio@somainline.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 15a36dcab990..fb471cc4066b 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -142,6 +142,16 @@ static const struct llcc_slice_config sdm845_data[] = { { LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0 }, }; +static const struct llcc_slice_config sm6350_data[] = { + { LLCC_CPUSS, 1, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1 }, + { LLCC_MDM, 8, 512, 2, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_GPUHTW, 11, 256, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_GPU, 12, 512, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_MDMPNG, 21, 768, 0, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_NPU, 23, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, +}; + static const struct llcc_slice_config sm8150_data[] = { { LLCC_CPUSS, 1, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 1 }, { LLCC_VIDSC0, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, @@ -203,6 +213,11 @@ static const struct qcom_llcc_config sdm845_cfg = { .need_llcc_cfg = false, }; +static const struct qcom_llcc_config sm6350_cfg = { + .sct_data = sm6350_data, + .size = ARRAY_SIZE(sm6350_data), +}; + static const struct qcom_llcc_config sm8150_cfg = { .sct_data = sm8150_data, .size = ARRAY_SIZE(sm8150_data), @@ -626,6 +641,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg }, { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg }, { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg }, + { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg }, { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, { } From 2b9575d47841daa69f6c102e8534bf862b098606 Mon Sep 17 00:00:00 2001 From: Bartosz Dudziak Date: Sun, 6 Jun 2021 22:16:11 +0200 Subject: [PATCH 04/40] dt-bindings: arm: Add SMP enable-method for MSM8226 Add binding in enable-method property for MSM8226 SoC SMP support. Signed-off-by: Bartosz Dudziak Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210606201612.100752-2-bartosz.dudziak@snejp.pl Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/arm/cpus.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 9a2432a88074..6a1e3d455897 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -209,6 +209,7 @@ properties: - qcom,gcc-msm8660 - qcom,kpss-acc-v1 - qcom,kpss-acc-v2 + - qcom,msm8226-smp - renesas,apmu - renesas,r9a06g032-smp - rockchip,rk3036-smp @@ -293,7 +294,7 @@ properties: Specifies the ACC* node associated with this CPU. Required for systems that have an "enable-method" property - value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2" + value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2" or "qcom,msm8226-smp" * arm/msm/qcom,kpss-acc.txt From 7a010c3c64e2edd22f17e1165f43ba0a40904182 Mon Sep 17 00:00:00 2001 From: Bartosz Dudziak Date: Sun, 6 Jun 2021 22:16:12 +0200 Subject: [PATCH 05/40] arm: qcom: Add SMP support for MSM8226 Implement support for Cortex-A7 CPU release sequence in MSM8226 SoC. Signed-off-by: Bartosz Dudziak Reviewed-by: Stephan Gerhold Link: https://lore.kernel.org/r/20210606201612.100752-3-bartosz.dudziak@snejp.pl Signed-off-by: Bjorn Andersson --- arch/arm/mach-qcom/platsmp.c | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index 630a038f4513..60496554c6dd 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -29,6 +29,7 @@ #define COREPOR_RST BIT(5) #define CORE_RST BIT(4) #define L2DT_SLP BIT(3) +#define CORE_MEM_CLAMP BIT(1) #define CLAMP BIT(0) #define APC_PWR_GATE_CTL 0x14 @@ -75,6 +76,62 @@ static int scss_release_secondary(unsigned int cpu) return 0; } +static int cortex_a7_release_secondary(unsigned int cpu) +{ + int ret = 0; + void __iomem *reg; + struct device_node *cpu_node, *acc_node; + u32 reg_val; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (!cpu_node) + return -ENODEV; + + acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0); + if (!acc_node) { + ret = -ENODEV; + goto out_acc; + } + + reg = of_iomap(acc_node, 0); + if (!reg) { + ret = -ENOMEM; + goto out_acc_map; + } + + /* Put the CPU into reset. */ + reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + + /* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */ + writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL); + /* Wait for the BHS to settle */ + udelay(2); + + reg_val &= ~CORE_MEM_CLAMP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + reg_val |= L2DT_SLP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + udelay(2); + + reg_val = (reg_val | BIT(17)) & ~CLAMP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + udelay(2); + + /* Release CPU out of reset and bring it to life. */ + reg_val &= ~(CORE_RST | COREPOR_RST); + writel(reg_val, reg + APCS_CPU_PWR_CTL); + reg_val |= CORE_PWRD_UP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + + iounmap(reg); +out_acc_map: + of_node_put(acc_node); +out_acc: + of_node_put(cpu_node); + return ret; +} + static int kpssv1_release_secondary(unsigned int cpu) { int ret = 0; @@ -281,6 +338,11 @@ static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle) return qcom_boot_secondary(cpu, scss_release_secondary); } +static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + return qcom_boot_secondary(cpu, cortex_a7_release_secondary); +} + static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle) { return qcom_boot_secondary(cpu, kpssv1_release_secondary); @@ -315,6 +377,15 @@ static const struct smp_operations smp_msm8660_ops __initconst = { }; CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops); +static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = { + .smp_prepare_cpus = qcom_smp_prepare_cpus, + .smp_boot_secondary = cortex_a7_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = qcom_cpu_die, +#endif +}; +CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops); + static const struct smp_operations qcom_smp_kpssv1_ops __initconst = { .smp_prepare_cpus = qcom_smp_prepare_cpus, .smp_boot_secondary = kpssv1_boot_secondary, From b03543067a88879169ebfdfdb36d9e8e827eeb6d Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sun, 12 Sep 2021 01:26:57 +0200 Subject: [PATCH 06/40] dt-bindings: firmware: scm: Add compatible for msm8226 Add devicetree compatible for SCM present in msm8226 platform. Signed-off-by: Luca Weiss Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210911232707.259615-4-luca@z3ntu.xyz --- Documentation/devicetree/bindings/firmware/qcom,scm.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index a7333ad938d2..5a90e84b8dcf 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -13,6 +13,7 @@ Required properties: * "qcom,scm-ipq806x" * "qcom,scm-ipq8074" * "qcom,scm-mdm9607" + * "qcom,scm-msm8226" * "qcom,scm-msm8660" * "qcom,scm-msm8916" * "qcom,scm-msm8960" From 60f3692b5f0b3e1df3ccc07c28758379052d0ab6 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 29 Jul 2021 17:56:05 +0200 Subject: [PATCH 07/40] cpuidle: qcom_spm: Detach state machine from main SPM handling In commit a871be6b8eee ("cpuidle: Convert Qualcomm SPM driver to a generic CPUidle driver") the SPM driver has been converted to a generic CPUidle driver: that was mainly made to simplify the driver and that was a great accomplishment; Though, at that time, this driver was only applicable to ARM 32-bit SoCs, lacking logic about the handling of newer generation SAW. In preparation for the enablement of SPM features on AArch64/ARM64, split the cpuidle-qcom-spm driver in two: the CPUIdle related state machine (currently used only on ARM SoCs) stays there, while the SPM communication handling lands back in soc/qcom/spm.c and also making sure to not discard the simplifications that were introduced in the aforementioned commit. Since now the "two drivers" are split, the SCM dependency in the main SPM handling is gone and for this reason it was also possible to move the SPM initialization early: this will also make sure that whenever the SAW CPUIdle driver is getting initialized, the SPM driver will be ready to do the job. Please note that the anticipation of the SPM initialization was also done to optimize the boot times on platforms that have their CPU/L2 idle states managed by other means (such as PSCI), while needing SAW initialization for other purposes, like AVS control. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Stephan Gerhold Tested-by: Stephan Gerhold Acked-by: Daniel Lezcano Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210729155609.608159-2-angelogioacchino.delregno@somainline.org --- drivers/cpuidle/Kconfig.arm | 1 + drivers/cpuidle/cpuidle-qcom-spm.c | 326 +++++++---------------------- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/spm.c | 216 +++++++++++++++++++ include/soc/qcom/spm.h | 41 ++++ 6 files changed, 340 insertions(+), 254 deletions(-) create mode 100644 drivers/soc/qcom/spm.c create mode 100644 include/soc/qcom/spm.h diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 334f83e56120..8a02213c8391 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -112,6 +112,7 @@ config ARM_QCOM_SPM_CPUIDLE select CPU_IDLE_MULTIPLE_DRIVERS select DT_IDLE_STATES select QCOM_SCM + select QCOM_SPM help Select this to enable cpuidle for Qualcomm processors. The Subsystem Power Manager (SPM) controls low power modes for the diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index c0e7971da2da..01e77913a414 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -18,158 +18,18 @@ #include #include #include +#include #include #include #include "dt_idle_states.h" -#define MAX_PMIC_DATA 2 -#define MAX_SEQ_DATA 64 -#define SPM_CTL_INDEX 0x7f -#define SPM_CTL_INDEX_SHIFT 4 -#define SPM_CTL_EN BIT(0) - -enum pm_sleep_mode { - PM_SLEEP_MODE_STBY, - PM_SLEEP_MODE_RET, - PM_SLEEP_MODE_SPC, - PM_SLEEP_MODE_PC, - PM_SLEEP_MODE_NR, -}; - -enum spm_reg { - SPM_REG_CFG, - SPM_REG_SPM_CTL, - SPM_REG_DLY, - SPM_REG_PMIC_DLY, - SPM_REG_PMIC_DATA_0, - SPM_REG_PMIC_DATA_1, - SPM_REG_VCTL, - SPM_REG_SEQ_ENTRY, - SPM_REG_SPM_STS, - SPM_REG_PMIC_STS, - SPM_REG_NR, -}; - -struct spm_reg_data { - const u8 *reg_offset; - u32 spm_cfg; - u32 spm_dly; - u32 pmic_dly; - u32 pmic_data[MAX_PMIC_DATA]; - u8 seq[MAX_SEQ_DATA]; - u8 start_index[PM_SLEEP_MODE_NR]; -}; - -struct spm_driver_data { +struct cpuidle_qcom_spm_data { struct cpuidle_driver cpuidle_driver; - void __iomem *reg_base; - const struct spm_reg_data *reg_data; + struct spm_driver_data *spm; }; -static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = { - [SPM_REG_CFG] = 0x08, - [SPM_REG_SPM_CTL] = 0x30, - [SPM_REG_DLY] = 0x34, - [SPM_REG_SEQ_ENTRY] = 0x80, -}; - -/* SPM register data for 8974, 8084 */ -static const struct spm_reg_data spm_reg_8974_8084_cpu = { - .reg_offset = spm_reg_offset_v2_1, - .spm_cfg = 0x1, - .spm_dly = 0x3C102800, - .seq = { 0x03, 0x0B, 0x0F, 0x00, 0x20, 0x80, 0x10, 0xE8, 0x5B, 0x03, - 0x3B, 0xE8, 0x5B, 0x82, 0x10, 0x0B, 0x30, 0x06, 0x26, 0x30, - 0x0F }, - .start_index[PM_SLEEP_MODE_STBY] = 0, - .start_index[PM_SLEEP_MODE_SPC] = 3, -}; - -/* SPM register data for 8226 */ -static const struct spm_reg_data spm_reg_8226_cpu = { - .reg_offset = spm_reg_offset_v2_1, - .spm_cfg = 0x0, - .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 u8 spm_reg_offset_v1_1[SPM_REG_NR] = { - [SPM_REG_CFG] = 0x08, - [SPM_REG_SPM_CTL] = 0x20, - [SPM_REG_PMIC_DLY] = 0x24, - [SPM_REG_PMIC_DATA_0] = 0x28, - [SPM_REG_PMIC_DATA_1] = 0x2C, - [SPM_REG_SEQ_ENTRY] = 0x80, -}; - -/* SPM register data for 8064 */ -static const struct spm_reg_data spm_reg_8064_cpu = { - .reg_offset = spm_reg_offset_v1_1, - .spm_cfg = 0x1F, - .pmic_dly = 0x02020004, - .pmic_data[0] = 0x0084009C, - .pmic_data[1] = 0x00A4001C, - .seq = { 0x03, 0x0F, 0x00, 0x24, 0x54, 0x10, 0x09, 0x03, 0x01, - 0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F }, - .start_index[PM_SLEEP_MODE_STBY] = 0, - .start_index[PM_SLEEP_MODE_SPC] = 2, -}; - -static inline void spm_register_write(struct spm_driver_data *drv, - enum spm_reg reg, u32 val) -{ - if (drv->reg_data->reg_offset[reg]) - writel_relaxed(val, drv->reg_base + - drv->reg_data->reg_offset[reg]); -} - -/* Ensure a guaranteed write, before return */ -static inline void spm_register_write_sync(struct spm_driver_data *drv, - enum spm_reg reg, u32 val) -{ - u32 ret; - - if (!drv->reg_data->reg_offset[reg]) - return; - - do { - writel_relaxed(val, drv->reg_base + - drv->reg_data->reg_offset[reg]); - ret = readl_relaxed(drv->reg_base + - drv->reg_data->reg_offset[reg]); - if (ret == val) - break; - cpu_relax(); - } while (1); -} - -static inline u32 spm_register_read(struct spm_driver_data *drv, - enum spm_reg reg) -{ - return readl_relaxed(drv->reg_base + drv->reg_data->reg_offset[reg]); -} - -static void spm_set_low_power_mode(struct spm_driver_data *drv, - enum pm_sleep_mode mode) -{ - u32 start_index; - u32 ctl_val; - - start_index = drv->reg_data->start_index[mode]; - - ctl_val = spm_register_read(drv, SPM_REG_SPM_CTL); - ctl_val &= ~(SPM_CTL_INDEX << SPM_CTL_INDEX_SHIFT); - ctl_val |= start_index << SPM_CTL_INDEX_SHIFT; - ctl_val |= SPM_CTL_EN; - spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val); -} - static int qcom_pm_collapse(unsigned long int unused) { qcom_scm_cpu_power_down(QCOM_SCM_CPU_PWR_DOWN_L2_ON); @@ -201,10 +61,10 @@ static int qcom_cpu_spc(struct spm_driver_data *drv) static int spm_enter_idle_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { - struct spm_driver_data *data = container_of(drv, struct spm_driver_data, - cpuidle_driver); + struct cpuidle_qcom_spm_data *data = container_of(drv, struct cpuidle_qcom_spm_data, + cpuidle_driver); - return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data); + return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data->spm); } static struct cpuidle_driver qcom_spm_idle_driver = { @@ -225,134 +85,92 @@ static const struct of_device_id qcom_idle_state_match[] = { { }, }; -static int spm_cpuidle_init(struct cpuidle_driver *drv, int cpu) +static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu) { + struct platform_device *pdev = NULL; + struct device_node *cpu_node, *saw_node; + struct cpuidle_qcom_spm_data *data = NULL; int ret; - memcpy(drv, &qcom_spm_idle_driver, sizeof(*drv)); - drv->cpumask = (struct cpumask *)cpumask_of(cpu); + cpu_node = of_cpu_device_node_get(cpu); + if (!cpu_node) + return -ENODEV; - /* Parse idle states from device tree */ - ret = dt_init_idle_driver(drv, qcom_idle_state_match, 1); + saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); + if (!saw_node) + return -ENODEV; + + pdev = of_find_device_by_node(saw_node); + of_node_put(saw_node); + of_node_put(cpu_node); + if (!pdev) + return -ENODEV; + + data = devm_kzalloc(cpuidle_dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->spm = dev_get_drvdata(&pdev->dev); + if (!data->spm) + return -EINVAL; + + data->cpuidle_driver = qcom_spm_idle_driver; + data->cpuidle_driver.cpumask = (struct cpumask *)cpumask_of(cpu); + + ret = dt_init_idle_driver(&data->cpuidle_driver, + qcom_idle_state_match, 1); if (ret <= 0) return ret ? : -ENODEV; - /* We have atleast one power down mode */ - return qcom_scm_set_warm_boot_addr(cpu_resume_arm, drv->cpumask); + ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm, cpumask_of(cpu)); + if (ret) + return ret; + + return cpuidle_register(&data->cpuidle_driver, NULL); } -static struct spm_driver_data *spm_get_drv(struct platform_device *pdev, - int *spm_cpu) +static int spm_cpuidle_drv_probe(struct platform_device *pdev) { - struct spm_driver_data *drv = NULL; - struct device_node *cpu_node, *saw_node; - int cpu; - bool found = 0; - - for_each_possible_cpu(cpu) { - cpu_node = of_cpu_device_node_get(cpu); - if (!cpu_node) - continue; - saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); - found = (saw_node == pdev->dev.of_node); - of_node_put(saw_node); - of_node_put(cpu_node); - if (found) - break; - } - - if (found) { - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); - if (drv) - *spm_cpu = cpu; - } - - return drv; -} - -static const struct of_device_id spm_match_table[] = { - { .compatible = "qcom,msm8226-saw2-v2.1-cpu", - .data = &spm_reg_8226_cpu }, - { .compatible = "qcom,msm8974-saw2-v2.1-cpu", - .data = &spm_reg_8974_8084_cpu }, - { .compatible = "qcom,apq8084-saw2-v2.1-cpu", - .data = &spm_reg_8974_8084_cpu }, - { .compatible = "qcom,apq8064-saw2-v1.1-cpu", - .data = &spm_reg_8064_cpu }, - { }, -}; - -static int spm_dev_probe(struct platform_device *pdev) -{ - struct spm_driver_data *drv; - struct resource *res; - const struct of_device_id *match_id; - void __iomem *addr; int cpu, ret; if (!qcom_scm_is_available()) return -EPROBE_DEFER; - drv = spm_get_drv(pdev, &cpu); - if (!drv) - return -EINVAL; - platform_set_drvdata(pdev, drv); + for_each_possible_cpu(cpu) { + ret = spm_cpuidle_register(&pdev->dev, cpu); + if (ret && ret != -ENODEV) { + dev_err(&pdev->dev, + "Cannot register for CPU%d: %d\n", cpu, ret); + } + } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drv->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(drv->reg_base)) - return PTR_ERR(drv->reg_base); - - match_id = of_match_node(spm_match_table, pdev->dev.of_node); - if (!match_id) - return -ENODEV; - - drv->reg_data = match_id->data; - - ret = spm_cpuidle_init(&drv->cpuidle_driver, cpu); - if (ret) - return ret; - - /* Write the SPM sequences first.. */ - addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY]; - __iowrite32_copy(addr, drv->reg_data->seq, - ARRAY_SIZE(drv->reg_data->seq) / 4); - - /* - * ..and then the control registers. - * On some SoC if the control registers are written first and if the - * CPU was held in reset, the reset signal could trigger the SPM state - * machine, before the sequences are completely written. - */ - spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg); - spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly); - spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly); - spm_register_write(drv, SPM_REG_PMIC_DATA_0, - drv->reg_data->pmic_data[0]); - spm_register_write(drv, SPM_REG_PMIC_DATA_1, - drv->reg_data->pmic_data[1]); - - /* Set up Standby as the default low power mode */ - spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); - - return cpuidle_register(&drv->cpuidle_driver, NULL); -} - -static int spm_dev_remove(struct platform_device *pdev) -{ - struct spm_driver_data *drv = platform_get_drvdata(pdev); - - cpuidle_unregister(&drv->cpuidle_driver); return 0; } -static struct platform_driver spm_driver = { - .probe = spm_dev_probe, - .remove = spm_dev_remove, +static struct platform_driver spm_cpuidle_driver = { + .probe = spm_cpuidle_drv_probe, .driver = { - .name = "saw", - .of_match_table = spm_match_table, + .name = "qcom-spm-cpuidle", + .suppress_bind_attrs = true, }, }; -builtin_platform_driver(spm_driver); +static int __init qcom_spm_cpuidle_init(void) +{ + struct platform_device *pdev; + int ret; + + ret = platform_driver_register(&spm_cpuidle_driver); + if (ret) + return ret; + + pdev = platform_device_register_simple("qcom-spm-cpuidle", + -1, NULL, 0); + if (IS_ERR(pdev)) { + platform_driver_unregister(&spm_cpuidle_driver); + return PTR_ERR(pdev); + } + + return 0; +} +device_initcall(qcom_spm_cpuidle_init); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 79b568f82a1c..fe3c486ae32d 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -190,6 +190,15 @@ config QCOM_SOCINFO Say yes here to support the Qualcomm socinfo driver, providing information about the SoC to user space. +config QCOM_SPM + tristate "Qualcomm Subsystem Power Manager (SPM)" + depends on ARCH_QCOM + select QCOM_SCM + help + Enable the support for the Qualcomm Subsystem Power Manager, used + to manage cores, L2 low power modes and to configure the internal + Adaptive Voltage Scaler parameters, where supported. + 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 ad675a6593d0..24514c722832 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o 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_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_APR) += apr.o obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c new file mode 100644 index 000000000000..ef20607877de --- /dev/null +++ b/drivers/soc/qcom/spm.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2015, Linaro Ltd. + * + * SAW power controller driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPM_CTL_INDEX 0x7f +#define SPM_CTL_INDEX_SHIFT 4 +#define SPM_CTL_EN BIT(0) + +enum spm_reg { + SPM_REG_CFG, + SPM_REG_SPM_CTL, + SPM_REG_DLY, + SPM_REG_PMIC_DLY, + SPM_REG_PMIC_DATA_0, + SPM_REG_PMIC_DATA_1, + SPM_REG_VCTL, + SPM_REG_SEQ_ENTRY, + SPM_REG_SPM_STS, + SPM_REG_PMIC_STS, + SPM_REG_NR, +}; + +static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = { + [SPM_REG_CFG] = 0x08, + [SPM_REG_SPM_CTL] = 0x30, + [SPM_REG_DLY] = 0x34, + [SPM_REG_SEQ_ENTRY] = 0x80, +}; + +/* SPM register data for 8974, 8084 */ +static const struct spm_reg_data spm_reg_8974_8084_cpu = { + .reg_offset = spm_reg_offset_v2_1, + .spm_cfg = 0x1, + .spm_dly = 0x3C102800, + .seq = { 0x03, 0x0B, 0x0F, 0x00, 0x20, 0x80, 0x10, 0xE8, 0x5B, 0x03, + 0x3B, 0xE8, 0x5B, 0x82, 0x10, 0x0B, 0x30, 0x06, 0x26, 0x30, + 0x0F }, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 3, +}; + +/* SPM register data for 8226 */ +static const struct spm_reg_data spm_reg_8226_cpu = { + .reg_offset = spm_reg_offset_v2_1, + .spm_cfg = 0x0, + .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 u8 spm_reg_offset_v1_1[SPM_REG_NR] = { + [SPM_REG_CFG] = 0x08, + [SPM_REG_SPM_CTL] = 0x20, + [SPM_REG_PMIC_DLY] = 0x24, + [SPM_REG_PMIC_DATA_0] = 0x28, + [SPM_REG_PMIC_DATA_1] = 0x2C, + [SPM_REG_SEQ_ENTRY] = 0x80, +}; + +/* SPM register data for 8064 */ +static const struct spm_reg_data spm_reg_8064_cpu = { + .reg_offset = spm_reg_offset_v1_1, + .spm_cfg = 0x1F, + .pmic_dly = 0x02020004, + .pmic_data[0] = 0x0084009C, + .pmic_data[1] = 0x00A4001C, + .seq = { 0x03, 0x0F, 0x00, 0x24, 0x54, 0x10, 0x09, 0x03, 0x01, + 0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F }, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 2, +}; + +static inline void spm_register_write(struct spm_driver_data *drv, + enum spm_reg reg, u32 val) +{ + if (drv->reg_data->reg_offset[reg]) + writel_relaxed(val, drv->reg_base + + drv->reg_data->reg_offset[reg]); +} + +/* Ensure a guaranteed write, before return */ +static inline void spm_register_write_sync(struct spm_driver_data *drv, + enum spm_reg reg, u32 val) +{ + u32 ret; + + if (!drv->reg_data->reg_offset[reg]) + return; + + do { + writel_relaxed(val, drv->reg_base + + drv->reg_data->reg_offset[reg]); + ret = readl_relaxed(drv->reg_base + + drv->reg_data->reg_offset[reg]); + if (ret == val) + break; + cpu_relax(); + } while (1); +} + +static inline u32 spm_register_read(struct spm_driver_data *drv, + enum spm_reg reg) +{ + return readl_relaxed(drv->reg_base + drv->reg_data->reg_offset[reg]); +} + +void spm_set_low_power_mode(struct spm_driver_data *drv, + enum pm_sleep_mode mode) +{ + u32 start_index; + u32 ctl_val; + + start_index = drv->reg_data->start_index[mode]; + + ctl_val = spm_register_read(drv, SPM_REG_SPM_CTL); + ctl_val &= ~(SPM_CTL_INDEX << SPM_CTL_INDEX_SHIFT); + ctl_val |= start_index << SPM_CTL_INDEX_SHIFT; + ctl_val |= SPM_CTL_EN; + spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val); +} + +static const struct of_device_id spm_match_table[] = { + { .compatible = "qcom,msm8226-saw2-v2.1-cpu", + .data = &spm_reg_8226_cpu }, + { .compatible = "qcom,msm8974-saw2-v2.1-cpu", + .data = &spm_reg_8974_8084_cpu }, + { .compatible = "qcom,apq8084-saw2-v2.1-cpu", + .data = &spm_reg_8974_8084_cpu }, + { .compatible = "qcom,apq8064-saw2-v1.1-cpu", + .data = &spm_reg_8064_cpu }, + { }, +}; +MODULE_DEVICE_TABLE(of, spm_match_table); + +static int spm_dev_probe(struct platform_device *pdev) +{ + const struct of_device_id *match_id; + struct spm_driver_data *drv; + struct resource *res; + void __iomem *addr; + + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); + if (!drv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + drv->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(drv->reg_base)) + return PTR_ERR(drv->reg_base); + + match_id = of_match_node(spm_match_table, pdev->dev.of_node); + if (!match_id) + return -ENODEV; + + drv->reg_data = match_id->data; + platform_set_drvdata(pdev, drv); + + /* Write the SPM sequences first.. */ + addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY]; + __iowrite32_copy(addr, drv->reg_data->seq, + ARRAY_SIZE(drv->reg_data->seq) / 4); + + /* + * ..and then the control registers. + * On some SoC if the control registers are written first and if the + * CPU was held in reset, the reset signal could trigger the SPM state + * machine, before the sequences are completely written. + */ + spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg); + spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly); + spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly); + spm_register_write(drv, SPM_REG_PMIC_DATA_0, + drv->reg_data->pmic_data[0]); + spm_register_write(drv, SPM_REG_PMIC_DATA_1, + drv->reg_data->pmic_data[1]); + + /* Set up Standby as the default low power mode */ + spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); + + return 0; +} + +static struct platform_driver spm_driver = { + .probe = spm_dev_probe, + .driver = { + .name = "qcom_spm", + .of_match_table = spm_match_table, + }, +}; + +static int __init qcom_spm_init(void) +{ + return platform_driver_register(&spm_driver); +} +arch_initcall(qcom_spm_init); + +MODULE_LICENSE("GPL v2"); diff --git a/include/soc/qcom/spm.h b/include/soc/qcom/spm.h new file mode 100644 index 000000000000..4c7e5ac2583d --- /dev/null +++ b/include/soc/qcom/spm.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2015, Linaro Ltd. + */ + +#ifndef __SPM_H__ +#define __SPM_H__ + +#include + +#define MAX_PMIC_DATA 2 +#define MAX_SEQ_DATA 64 + +enum pm_sleep_mode { + PM_SLEEP_MODE_STBY, + PM_SLEEP_MODE_RET, + PM_SLEEP_MODE_SPC, + PM_SLEEP_MODE_PC, + PM_SLEEP_MODE_NR, +}; + +struct spm_reg_data { + const u8 *reg_offset; + u32 spm_cfg; + u32 spm_dly; + u32 pmic_dly; + u32 pmic_data[MAX_PMIC_DATA]; + u8 seq[MAX_SEQ_DATA]; + u8 start_index[PM_SLEEP_MODE_NR]; +}; + +struct spm_driver_data { + void __iomem *reg_base; + const struct spm_reg_data *reg_data; +}; + +void spm_set_low_power_mode(struct spm_driver_data *drv, + enum pm_sleep_mode mode); + +#endif /* __SPM_H__ */ From f8881c5d2fcb24b5b10b0d462e5fa0bbe9014af5 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 29 Jul 2021 17:56:06 +0200 Subject: [PATCH 08/40] dt-bindings: soc: qcom: Add devicetree binding for QCOM SPM Add devicetree binding for Qualcomm Subsystem Power Manager (SPM). Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210729155609.608159-3-angelogioacchino.delregno@somainline.org --- .../bindings/soc/qcom/qcom,spm.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml new file mode 100644 index 000000000000..507216100e3f --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/qcom/qcom,spm.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm Subsystem Power Manager binding + +maintainers: + - Andy Gross + - Bjorn Andersson + +description: | + This binding describes the Qualcomm Subsystem Power Manager, used to control + the peripheral logic surrounding the application cores in Qualcomm platforms. + +properties: + compatible: + items: + - enum: + - qcom,msm8226-saw2-v2.1-cpu + - qcom,msm8974-saw2-v2.1-cpu + - qcom,apq8084-saw2-v2.1-cpu + - qcom,apq8064-saw2-v1.1-cpu + - const: qcom,saw2 + + reg: + description: Base address and size of the SPM register region + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "qcom,kryo"; + device_type = "cpu"; + enable-method = "qcom,kpss-acc-v2"; + qcom,saw = <&saw0>; + reg = <0x0>; + operating-points-v2 = <&cpu_opp_table>; + }; + }; + + saw0: power-manager@f9089000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9089000 0x1000>; + }; + +... From 13e72c3e22611915f9a71a513b640e064a403e78 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 29 Jul 2021 17:56:07 +0200 Subject: [PATCH 09/40] soc: qcom: spm: Implement support for SAWv4.1, SDM630/660 L2 AVS Implement the support for SAW v4.1, used in at least MSM8998, SDM630, SDM660 and APQ variants and, while at it, also add the configuration for the SDM630/660 Silver and Gold cluster L2 Adaptive Voltage Scaler: this is also one of the prerequisites to allow the OSM controller to perform DCVS. Please note that despite there are various "versions" of these values downstream, these are the only ones that are perfectly stable on the entire set of tested devices. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210729155609.608159-4-angelogioacchino.delregno@somainline.org --- drivers/soc/qcom/spm.c | 32 +++++++++++++++++++++++++++++--- include/soc/qcom/spm.h | 4 +++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index ef20607877de..fb8de9dcfee7 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -33,10 +33,29 @@ enum spm_reg { SPM_REG_SEQ_ENTRY, SPM_REG_SPM_STS, SPM_REG_PMIC_STS, + SPM_REG_AVS_CTL, + SPM_REG_AVS_LIMIT, SPM_REG_NR, }; -static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = { +static const u16 spm_reg_offset_v4_1[SPM_REG_NR] = { + [SPM_REG_AVS_CTL] = 0x904, + [SPM_REG_AVS_LIMIT] = 0x908, +}; + +static const struct spm_reg_data spm_reg_660_gold_l2 = { + .reg_offset = spm_reg_offset_v4_1, + .avs_ctl = 0x1010031, + .avs_limit = 0x4580458, +}; + +static const struct spm_reg_data spm_reg_660_silver_l2 = { + .reg_offset = spm_reg_offset_v4_1, + .avs_ctl = 0x101c031, + .avs_limit = 0x4580458, +}; + +static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = { [SPM_REG_CFG] = 0x08, [SPM_REG_SPM_CTL] = 0x30, [SPM_REG_DLY] = 0x34, @@ -67,7 +86,7 @@ static const struct spm_reg_data spm_reg_8226_cpu = { .start_index[PM_SLEEP_MODE_SPC] = 5, }; -static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = { +static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = { [SPM_REG_CFG] = 0x08, [SPM_REG_SPM_CTL] = 0x20, [SPM_REG_PMIC_DLY] = 0x24, @@ -139,6 +158,10 @@ void spm_set_low_power_mode(struct spm_driver_data *drv, } static const struct of_device_id spm_match_table[] = { + { .compatible = "qcom,sdm660-gold-saw2-v4.1-l2", + .data = &spm_reg_660_gold_l2 }, + { .compatible = "qcom,sdm660-silver-saw2-v4.1-l2", + .data = &spm_reg_660_silver_l2 }, { .compatible = "qcom,msm8226-saw2-v2.1-cpu", .data = &spm_reg_8226_cpu }, { .compatible = "qcom,msm8974-saw2-v2.1-cpu", @@ -185,6 +208,8 @@ static int spm_dev_probe(struct platform_device *pdev) * CPU was held in reset, the reset signal could trigger the SPM state * machine, before the sequences are completely written. */ + spm_register_write(drv, SPM_REG_AVS_CTL, drv->reg_data->avs_ctl); + spm_register_write(drv, SPM_REG_AVS_LIMIT, drv->reg_data->avs_limit); spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg); spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly); spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly); @@ -194,7 +219,8 @@ static int spm_dev_probe(struct platform_device *pdev) drv->reg_data->pmic_data[1]); /* Set up Standby as the default low power mode */ - spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); + if (drv->reg_data->reg_offset[SPM_REG_SPM_CTL]) + spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); return 0; } diff --git a/include/soc/qcom/spm.h b/include/soc/qcom/spm.h index 4c7e5ac2583d..4951f9d8b0bd 100644 --- a/include/soc/qcom/spm.h +++ b/include/soc/qcom/spm.h @@ -21,11 +21,13 @@ enum pm_sleep_mode { }; struct spm_reg_data { - const u8 *reg_offset; + const u16 *reg_offset; u32 spm_cfg; u32 spm_dly; u32 pmic_dly; u32 pmic_data[MAX_PMIC_DATA]; + u32 avs_ctl; + u32 avs_limit; u8 seq[MAX_SEQ_DATA]; u8 start_index[PM_SLEEP_MODE_NR]; }; From e48e6fb9ebdf90a290933712621319cf2cfcb777 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 29 Jul 2021 17:56:08 +0200 Subject: [PATCH 10/40] soc: qcom: spm: Add compatible for MSM8998 SAWv4.1 L2 Add the SAWv4.1 parameters for MSM8998's Gold and Silver clusters. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210729155609.608159-5-angelogioacchino.delregno@somainline.org --- drivers/soc/qcom/spm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index fb8de9dcfee7..2961a89d929c 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -55,6 +55,18 @@ static const struct spm_reg_data spm_reg_660_silver_l2 = { .avs_limit = 0x4580458, }; +static const struct spm_reg_data spm_reg_8998_gold_l2 = { + .reg_offset = spm_reg_offset_v4_1, + .avs_ctl = 0x1010031, + .avs_limit = 0x4700470, +}; + +static const struct spm_reg_data spm_reg_8998_silver_l2 = { + .reg_offset = spm_reg_offset_v4_1, + .avs_ctl = 0x1010031, + .avs_limit = 0x4200420, +}; + static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = { [SPM_REG_CFG] = 0x08, [SPM_REG_SPM_CTL] = 0x30, @@ -166,6 +178,10 @@ static const struct of_device_id spm_match_table[] = { .data = &spm_reg_8226_cpu }, { .compatible = "qcom,msm8974-saw2-v2.1-cpu", .data = &spm_reg_8974_8084_cpu }, + { .compatible = "qcom,msm8998-gold-saw2-v4.1-l2", + .data = &spm_reg_8998_gold_l2 }, + { .compatible = "qcom,msm8998-silver-saw2-v4.1-l2", + .data = &spm_reg_8998_silver_l2 }, { .compatible = "qcom,apq8084-saw2-v2.1-cpu", .data = &spm_reg_8974_8084_cpu }, { .compatible = "qcom,apq8064-saw2-v1.1-cpu", From 926576172d7111f8230fc6cb346b95250b607ab7 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 29 Jul 2021 17:56:09 +0200 Subject: [PATCH 11/40] dt-bindings: soc: qcom: spm: Document SDM660 and MSM8998 compatibles The driver was updated to add SAW2 v4.1 support for new SoCs: document the new compatibles. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210729155609.608159-6-angelogioacchino.delregno@somainline.org --- .../bindings/soc/qcom/qcom,spm.yaml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml index 507216100e3f..d68c002527fa 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml @@ -18,6 +18,10 @@ properties: compatible: items: - enum: + - qcom,sdm660-gold-saw2-v4.1-l2 + - qcom,sdm660-silver-saw2-v4.1-l2 + - qcom,msm8998-gold-saw2-v4.1-l2 + - qcom,msm8998-silver-saw2-v4.1-l2 - qcom,msm8226-saw2-v2.1-cpu - qcom,msm8974-saw2-v2.1-cpu - qcom,apq8084-saw2-v2.1-cpu @@ -36,6 +40,8 @@ additionalProperties: false examples: - | + + /* Example 1: SoC using SAW2 and kpss-acc-v2 CPUIdle */ cpus { #address-cells = <1>; #size-cells = <0>; @@ -55,4 +61,20 @@ examples: reg = <0xf9089000 0x1000>; }; + - | + + /* + * Example 2: New-gen multi cluster SoC using SAW only for L2; + * This does not require any cpuidle driver, nor any cpu phandle. + */ + power-manager@17812000 { + compatible = "qcom,msm8998-gold-saw2-v4.1-l2", "qcom,saw2"; + reg = <0x17812000 0x1000>; + }; + + power-manager@17912000 { + compatible = "qcom,msm8998-silver-saw2-v4.1-l2", "qcom,saw2"; + reg = <0x17912000 0x1000>; + }; + ... From 96c42812f798c5e48d55cd6fc2101ce99af19608 Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Wed, 25 Aug 2021 22:29:42 +0530 Subject: [PATCH 12/40] dt-bindings: soc: qcom: smd-rpm: Add compatible for MSM8953 SoC Document compatible for MSM8953 SoC. Signed-off-by: Vladimir Lypak Signed-off-by: Adam Skladowski Signed-off-by: Sireesh Kodali Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210825165943.19415-1-sireeshkodali1@gmail.com --- Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index cc3fe5ed7421..77963b86b714 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -34,6 +34,7 @@ properties: - qcom,rpm-ipq6018 - qcom,rpm-msm8226 - qcom,rpm-msm8916 + - qcom,rpm-msm8953 - qcom,rpm-msm8974 - qcom,rpm-msm8976 - qcom,rpm-msm8996 @@ -57,6 +58,7 @@ if: - qcom,rpm-apq8084 - qcom,rpm-msm8916 - qcom,rpm-msm8974 + - qcom,rpm-msm8953 then: required: - qcom,smd-channels From e972a290b03f83eb06c70610eaed7b0984babde7 Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Wed, 25 Aug 2021 22:31:51 +0530 Subject: [PATCH 13/40] soc: qcom: smd-rpm: Add compatible for MSM8953 SoC Add a compatible for MSM8953 Signed-off-by: Vladimir Lypak Signed-off-by: Adam Skladowski Signed-off-by: Sireesh Kodali Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210825170151.19698-1-sireeshkodali1@gmail.com --- drivers/soc/qcom/smd-rpm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index dfdd4f20f5fd..fb4896d7a9a7 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -236,6 +236,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-msm8226" }, { .compatible = "qcom,rpm-msm8916" }, { .compatible = "qcom,rpm-msm8936" }, + { .compatible = "qcom,rpm-msm8953" }, { .compatible = "qcom,rpm-msm8974" }, { .compatible = "qcom,rpm-msm8976" }, { .compatible = "qcom,rpm-msm8994" }, From cdb6f6044aeaed0dce066a780aee9bc6f3dd4fab Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Wed, 25 Aug 2021 22:32:32 +0530 Subject: [PATCH 14/40] dt-bindings: power: rpmpd: Add MSM8953 to rpmpd binding Add compatible and constants for the power domains exposed by the RPM in the Qualcomm MSM8953 platform. Signed-off-by: Vladimir Lypak Signed-off-by: Adam Skladowski Signed-off-by: Sireesh Kodali Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210825170233.19859-1-sireeshkodali1@gmail.com --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 1 + include/dt-bindings/power/qcom-rpmpd.h | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 239f37881cae..996ddd360de9 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -19,6 +19,7 @@ properties: - qcom,mdm9607-rpmpd - qcom,msm8916-rpmpd - qcom,msm8939-rpmpd + - qcom,msm8953-rpmpd - qcom,msm8976-rpmpd - qcom,msm8994-rpmpd - qcom,msm8996-rpmpd diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index 4533dbbf9937..f367cf6fedf3 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -133,6 +133,15 @@ #define MSM8916_VDDMX 3 #define MSM8916_VDDMX_AO 4 +/* MSM8953 Power Domain Indexes */ +#define MSM8953_VDDMD 0 +#define MSM8953_VDDMD_AO 1 +#define MSM8953_VDDCX 2 +#define MSM8953_VDDCX_AO 3 +#define MSM8953_VDDCX_VFL 4 +#define MSM8953_VDDMX 5 +#define MSM8953_VDDMX_AO 6 + /* MSM8976 Power Domain Indexes */ #define MSM8976_VDDCX 0 #define MSM8976_VDDCX_AO 1 From e7ec00eafe944e7a4d02918517aa31c2c3b6c48a Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Wed, 25 Aug 2021 22:32:51 +0530 Subject: [PATCH 15/40] soc: qcom: rpmpd: Add power domains for MSM8953 Add support for MSM8953 power domains. Signed-off-by: Vladimir Lypak Signed-off-by: Adam Skladowski Signed-off-by: Sireesh Kodali Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210825170252.20137-1-sireeshkodali1@gmail.com --- drivers/soc/qcom/rpmpd.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index dbf494e92574..4f69fb9b2e0e 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -185,6 +185,29 @@ static const struct rpmpd_desc msm8916_desc = { .max_state = MAX_CORNER_RPMPD_STATE, }; +/* msm8953 RPM Power Domains */ +DEFINE_RPMPD_PAIR(msm8953, vddmd, vddmd_ao, SMPA, LEVEL, 1); +DEFINE_RPMPD_PAIR(msm8953, vddcx, vddcx_ao, SMPA, LEVEL, 2); +DEFINE_RPMPD_PAIR(msm8953, vddmx, vddmx_ao, SMPA, LEVEL, 7); + +DEFINE_RPMPD_VFL(msm8953, vddcx_vfl, SMPA, 2); + +static struct rpmpd *msm8953_rpmpds[] = { + [MSM8953_VDDMD] = &msm8953_vddmd, + [MSM8953_VDDMD_AO] = &msm8953_vddmd_ao, + [MSM8953_VDDCX] = &msm8953_vddcx, + [MSM8953_VDDCX_AO] = &msm8953_vddcx_ao, + [MSM8953_VDDCX_VFL] = &msm8953_vddcx_vfl, + [MSM8953_VDDMX] = &msm8953_vddmx, + [MSM8953_VDDMX_AO] = &msm8953_vddmx_ao, +}; + +static const struct rpmpd_desc msm8953_desc = { + .rpmpds = msm8953_rpmpds, + .num_pds = ARRAY_SIZE(msm8953_rpmpds), + .max_state = RPM_SMD_LEVEL_TURBO, +}; + /* msm8976 RPM Power Domains */ DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2); DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6); @@ -377,6 +400,7 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc }, { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, + { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc }, { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, From aa88e34f2bfdb7516510b0d154eaa6c0a9b284cb Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sun, 5 Sep 2021 19:11:31 +0200 Subject: [PATCH 16/40] soc: qcom: socinfo: Add IPQ8074 family ID-s IPQ8074 family SoC ID-s are missing, so lets add them based on the downstream driver. Signed-off-by: Robert Marko Reviewed-by: Kathiravan T Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210905171131.660885-1-robimarko@gmail.com --- drivers/soc/qcom/socinfo.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 9faf48302f4b..288897868435 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -281,19 +281,31 @@ static const struct soc_id soc_id[] = { { 319, "APQ8098" }, { 321, "SDM845" }, { 322, "MDM9206" }, + { 323, "IPQ8074" }, { 324, "SDA660" }, { 325, "SDM658" }, { 326, "SDA658" }, { 327, "SDA630" }, { 338, "SDM450" }, { 341, "SDA845" }, + { 342, "IPQ8072" }, + { 343, "IPQ8076" }, + { 344, "IPQ8078" }, { 345, "SDM636" }, { 346, "SDA636" }, { 349, "SDM632" }, { 350, "SDA632" }, { 351, "SDA450" }, { 356, "SM8250" }, + { 375, "IPQ8070" }, + { 376, "IPQ8071" }, + { 389, "IPQ8072A" }, + { 390, "IPQ8074A" }, + { 391, "IPQ8076A" }, + { 392, "IPQ8078A" }, { 394, "SM6125" }, + { 395, "IPQ8070A" }, + { 396, "IPQ8071A" }, { 402, "IPQ6018" }, { 403, "IPQ6028" }, { 421, "IPQ6000" }, From 0e6fda9c65634e1f6f4a18fd1c48acf0af761deb Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 16:02:11 +0800 Subject: [PATCH 17/40] PM: AVS: qcom-cpr: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210908080216.1301-1-caihuoqing@baidu.com --- drivers/soc/qcom/cpr.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index 4ce8e816154f..1d818a8ba208 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -1614,7 +1614,6 @@ static void cpr_debugfs_init(struct cpr_drv *drv) static int cpr_probe(struct platform_device *pdev) { - struct resource *res; struct device *dev = &pdev->dev; struct cpr_drv *drv; int irq, ret; @@ -1648,8 +1647,7 @@ static int cpr_probe(struct platform_device *pdev) if (IS_ERR(drv->tcsr)) return PTR_ERR(drv->tcsr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drv->base = devm_ioremap_resource(dev, res); + drv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(drv->base)) return PTR_ERR(drv->base); From 172037b12be46aee55dae3ae4f8468a2dbd5eaa3 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 16:02:12 +0800 Subject: [PATCH 18/40] soc: qcom: ocmem: Make use of the helper function devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210908080216.1301-2-caihuoqing@baidu.com --- drivers/soc/qcom/ocmem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index f1875dc31ae2..d2dacbbaafbd 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -300,7 +300,6 @@ static int ocmem_dev_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; unsigned long reg, region_size; int i, j, ret, num_banks; - struct resource *res; struct ocmem *ocmem; if (!qcom_scm_is_available()) @@ -321,8 +320,7 @@ static int ocmem_dev_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); - ocmem->mmio = devm_ioremap_resource(&pdev->dev, res); + ocmem->mmio = devm_platform_ioremap_resource_byname(pdev, "ctrl"); if (IS_ERR(ocmem->mmio)) { dev_err(&pdev->dev, "Failed to ioremap ocmem_ctrl resource\n"); return PTR_ERR(ocmem->mmio); From d21dc0be36bbe8d424a956f6594c3f2b9f7884a6 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 16:02:13 +0800 Subject: [PATCH 19/40] soc: qcom: geni: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210908080216.1301-3-caihuoqing@baidu.com --- drivers/soc/qcom/qcom-geni-se.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 7d649d2cf31e..28a8c0dda66c 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -871,7 +871,6 @@ EXPORT_SYMBOL(geni_icc_disable); static int geni_se_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; struct geni_wrapper *wrapper; int ret; @@ -880,8 +879,7 @@ static int geni_se_probe(struct platform_device *pdev) return -ENOMEM; wrapper->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wrapper->base = devm_ioremap_resource(dev, res); + wrapper->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wrapper->base)) return PTR_ERR(wrapper->base); From c318dcbcccd35a033e7bd79ba51004d2daeb4acb Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 16:02:14 +0800 Subject: [PATCH 20/40] soc: qcom: aoss: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210908080216.1301-4-caihuoqing@baidu.com --- drivers/soc/qcom/qcom_aoss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 536c3e4114fb..c42b80ee3920 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -521,7 +521,6 @@ static void qmp_cooling_devices_remove(struct qmp *qmp) static int qmp_probe(struct platform_device *pdev) { - struct resource *res; struct qmp *qmp; int irq; int ret; @@ -534,8 +533,7 @@ static int qmp_probe(struct platform_device *pdev) init_waitqueue_head(&qmp->event); mutex_init(&qmp->tx_lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - qmp->msgram = devm_ioremap_resource(&pdev->dev, res); + qmp->msgram = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(qmp->msgram)) return PTR_ERR(qmp->msgram); From eb242d57aa6f93b702b15c40682f2775049c467d Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 16:02:15 +0800 Subject: [PATCH 21/40] soc: qcom: gsbi: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210908080216.1301-5-caihuoqing@baidu.com --- drivers/soc/qcom/qcom_gsbi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index 304afc223a58..290bdefbf28a 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -127,7 +127,6 @@ static int gsbi_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct device_node *tcsr_node; const struct of_device_id *match; - struct resource *res; void __iomem *base; struct gsbi_info *gsbi; int i, ret; @@ -139,8 +138,7 @@ static int gsbi_probe(struct platform_device *pdev) if (!gsbi) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From f69a91e376695ae6048934c92f6b7eea6c51cd86 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 8 Sep 2021 16:02:16 +0800 Subject: [PATCH 22/40] soc: qcom: rpmh-rsc: Make use of the helper function devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210908080216.1301-6-caihuoqing@baidu.com --- drivers/soc/qcom/rpmh-rsc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index e749a2b285d8..3a12a482f6b2 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -910,7 +910,6 @@ static int rpmh_rsc_probe(struct platform_device *pdev) { struct device_node *dn = pdev->dev.of_node; struct rsc_drv *drv; - struct resource *res; char drv_id[10] = {0}; int ret, irq; u32 solver_config; @@ -941,8 +940,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev) drv->name = dev_name(&pdev->dev); snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, drv_id); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource_byname(pdev, drv_id); if (IS_ERR(base)) return PTR_ERR(base); From 26bc7a6a0beed882032aa7c945e44d7e82887073 Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sun, 8 Aug 2021 14:50:10 +0200 Subject: [PATCH 23/40] soc: qcom: pdr: Prefer strscpy over strcpy strcpy() performs no bounds checking on the destination buffer. This could result in linear overflows beyond the end of the buffer, leading to all kinds of misbehaviors. The safe replacement is strscpy(). This is a previous step in the path to remove the strcpy() function entirely from the kernel. Signed-off-by: Len Baker Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210808125012.4715-2-len.baker@gmx.com --- drivers/soc/qcom/pdr_interface.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c index 915d5bc3d46e..fc580a3c4336 100644 --- a/drivers/soc/qcom/pdr_interface.c +++ b/drivers/soc/qcom/pdr_interface.c @@ -131,7 +131,7 @@ static int pdr_register_listener(struct pdr_handle *pdr, return ret; req.enable = enable; - strcpy(req.service_path, pds->service_path); + strscpy(req.service_path, pds->service_path, sizeof(req.service_path)); ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr, &txn, SERVREG_REGISTER_LISTENER_REQ, @@ -257,7 +257,7 @@ static int pdr_send_indack_msg(struct pdr_handle *pdr, struct pdr_service *pds, return ret; req.transaction_id = tid; - strcpy(req.service_path, pds->service_path); + strscpy(req.service_path, pds->service_path, sizeof(req.service_path)); ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr, &txn, SERVREG_SET_ACK_REQ, @@ -406,7 +406,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) return -ENOMEM; /* Prepare req message */ - strcpy(req.service_name, pds->service_name); + strscpy(req.service_name, pds->service_name, sizeof(req.service_name)); req.domain_offset_valid = true; req.domain_offset = 0; @@ -531,8 +531,8 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, return ERR_PTR(-ENOMEM); pds->service = SERVREG_NOTIFIER_SERVICE; - strcpy(pds->service_name, service_name); - strcpy(pds->service_path, service_path); + strscpy(pds->service_name, service_name, sizeof(pds->service_name)); + strscpy(pds->service_path, service_path, sizeof(pds->service_path)); pds->need_locator_lookup = true; mutex_lock(&pdr->list_lock); @@ -587,7 +587,7 @@ int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds) break; /* Prepare req message */ - strcpy(req.service_path, pds->service_path); + strscpy(req.service_path, pds->service_path, sizeof(req.service_path)); addr = pds->addr; break; } From 0fdeecf9e33053f9c1629000682bc4d864242061 Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Tue, 10 Aug 2021 16:44:39 +0000 Subject: [PATCH 24/40] dt-bindings: firmware: qcom-scm: Document msm8953 bindings SCM driver on MSM8953 requires 3 clocks. Signed-off-by: Vladimir Lypak Signed-off-by: Sireesh Kodali Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210810164347.45578-4-sireeshkodali@protonmail.com --- Documentation/devicetree/bindings/firmware/qcom,scm.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index 5a90e84b8dcf..d7e3cda8924e 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -16,6 +16,7 @@ Required properties: * "qcom,scm-msm8226" * "qcom,scm-msm8660" * "qcom,scm-msm8916" + * "qcom,scm-msm8953" * "qcom,scm-msm8960" * "qcom,scm-msm8974" * "qcom,scm-msm8994" @@ -34,7 +35,7 @@ Required properties: * core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and "qcom,scm-msm8960" * core, iface and bus clocks required for "qcom,scm-apq8084", - "qcom,scm-msm8916" and "qcom,scm-msm8974" + "qcom,scm-msm8916", "qcom,scm-msm8953" and "qcom,scm-msm8974" - clock-names: Must contain "core" for the core clock, "iface" for the interface clock and "bus" for the bus clock per the requirements of the compatible. - qcom,dload-mode: phandle to the TCSR hardware block and offset of the From bca4392a1aa1cedc7153d975ca551d23a965b1bb Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Tue, 10 Aug 2021 16:44:48 +0000 Subject: [PATCH 25/40] firmware: qcom_scm: Add compatible for MSM8953 SoC Add compatible for SCM on MSM8953. Signed-off-by: Vladimir Lypak Signed-off-by: Sireesh Kodali Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210810164347.45578-5-sireeshkodali@protonmail.com --- drivers/firmware/qcom_scm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 2ee97bab7440..a861033616ee 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1348,6 +1348,10 @@ static const struct of_device_id qcom_scm_dt_match[] = { SCM_HAS_IFACE_CLK | SCM_HAS_BUS_CLK) }, + { .compatible = "qcom,scm-msm8953", .data = (void *)(SCM_HAS_CORE_CLK | + SCM_HAS_IFACE_CLK | + SCM_HAS_BUS_CLK) + }, { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK | SCM_HAS_IFACE_CLK | SCM_HAS_BUS_CLK) From b624c15088cb3e009785b4ad3984a9d6d1b7cea6 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 14 Sep 2021 09:53:48 +0800 Subject: [PATCH 26/40] dt-bindings: soc: qcom: smd-rpm: Add QCM2290 compatible Add compatible for the RPM on Qualcomm QCM2290 SoC. Signed-off-by: Shawn Guo Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210914015349.29295-2-shawn.guo@linaro.org --- Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index 77963b86b714..b32457c2fc0b 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -42,6 +42,7 @@ properties: - qcom,rpm-sdm660 - qcom,rpm-sm6115 - qcom,rpm-sm6125 + - qcom,rpm-qcm2290 - qcom,rpm-qcs404 qcom,smd-channels: From 3e035cbd445f98760d828154b25f3c55f577d299 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 14 Sep 2021 09:53:49 +0800 Subject: [PATCH 27/40] soc: qcom: smd-rpm: Add QCM2290 compatible Add compatible for QCM2290 SoC support. Signed-off-by: Shawn Guo Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210914015349.29295-3-shawn.guo@linaro.org --- drivers/soc/qcom/smd-rpm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index fb4896d7a9a7..30dda1af63c8 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -245,6 +245,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-sdm660" }, { .compatible = "qcom,rpm-sm6115" }, { .compatible = "qcom,rpm-sm6125" }, + { .compatible = "qcom,rpm-qcm2290" }, { .compatible = "qcom,rpm-qcs404" }, {} }; From 3a461009e195c3c17f6af73da310b886991309fd Mon Sep 17 00:00:00 2001 From: Naina Mehta Date: Tue, 21 Sep 2021 11:29:42 +0530 Subject: [PATCH 28/40] soc: qcom: llcc: Disable MMUHWT retention Disable MMUHWT retention for SC7280 as done for other platforms to avoid more power burn. Fixes: f6a07be63301 ("soc: qcom: llcc: Add configuration data for SC7280") Signed-off-by: Naina Mehta Signed-off-by: Sai Prakash Ranjan Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210921055942.30600-1-saiprakash.ranjan@codeaurora.org --- drivers/soc/qcom/llcc-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index fb471cc4066b..6bf2f1d1f2c5 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -115,7 +115,7 @@ static const struct llcc_slice_config sc7280_data[] = { { LLCC_CMPT, 10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, { LLCC_GPUHTW, 11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, { LLCC_GPU, 12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 1, 0}, + { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0}, { LLCC_MDMPNG, 21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, { LLCC_WLHW, 24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, { LLCC_MODPE, 29, 64, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, From 069f01fac33b2506c36aa73b604b16b23f7d8e90 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 20 Aug 2021 22:31:00 +0200 Subject: [PATCH 29/40] dt-bindings: soc: qcom: aoss: Add SM6350 compatible Add SM6350 AOSS QMP compatible to the list of possible bindings. Signed-off-by: Konrad Dybcio Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210820203105.229764-2-konrad.dybcio@somainline.org --- Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 93e4b737ee1b..1904612fad85 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -30,6 +30,7 @@ properties: - qcom,sc7280-aoss-qmp - qcom,sc8180x-aoss-qmp - qcom,sdm845-aoss-qmp + - qcom,sm6350-aoss-qmp - qcom,sm8150-aoss-qmp - qcom,sm8250-aoss-qmp - qcom,sm8350-aoss-qmp From 92dde3279df9fd11b4a10cf6c7d01525c3d373ea Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 20 Aug 2021 22:31:01 +0200 Subject: [PATCH 30/40] dt-bindings: power: rpmpd: Add SM6350 to rpmpd binding Add compatible and constants for the power domains exposed by the RPMH in the Qualcomm SM6350 platform. Acked-by: AngeloGioacchino Del Regno Signed-off-by: Konrad Dybcio Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210820203105.229764-3-konrad.dybcio@somainline.org --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 1 + include/dt-bindings/power/qcom-rpmpd.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 996ddd360de9..e810480e3eb7 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -32,6 +32,7 @@ properties: - qcom,sdm845-rpmhpd - qcom,sdx55-rpmhpd - qcom,sm6115-rpmpd + - qcom,sm6350-rpmhpd - qcom,sm8150-rpmhpd - qcom,sm8250-rpmhpd - qcom,sm8350-rpmhpd diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index f367cf6fedf3..960f7976a807 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -20,6 +20,14 @@ #define SDX55_MX 1 #define SDX55_CX 2 +/* SM6350 Power Domain Indexes */ +#define SM6350_CX 0 +#define SM6350_GFX 1 +#define SM6350_LCX 2 +#define SM6350_LMX 3 +#define SM6350_MSS 4 +#define SM6350_MX 5 + /* SM8150 Power Domain Indexes */ #define SM8150_MSS 0 #define SM8150_EBI 1 From 1a561c521ba901ac86acaf698e79ad6ecedbec2b Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Tue, 21 Sep 2021 16:04:27 +0530 Subject: [PATCH 31/40] soc: qcom: smp2p: Add wakeup capability to SMP2P IRQ Remote susbsystems notify fatal crash through smp2p interrupt. When remoteproc crashes it can cause soc to come out of low power state and may not allow again to enter in low power state until crash is handled. Mark smp2p interrupt wakeup capable so that interrupt handler is executed and remoteproc crash can be handled in system resume path. This patch marks interrupt wakeup capable but keeps wakeup disabled by default. User space can enable it based on its requirement for wakeup from suspend. Signed-off-by: Deepak Kumar Singh Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1632220467-27410-1-git-send-email-deesin@codeaurora.org --- drivers/soc/qcom/smp2p.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 2df488333be9..38585a7edfe7 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -538,9 +539,26 @@ static int qcom_smp2p_probe(struct platform_device *pdev) goto unwind_interfaces; } + /* + * Treat smp2p interrupt as wakeup source, but keep it disabled + * by default. User space can decide enabling it depending on its + * use cases. For example if remoteproc crashes and device wants + * to handle it immediatedly (e.g. to not miss phone calls) it can + * enable wakeup source from user space, while other devices which + * do not have proper autosleep feature may want to handle it with + * other wakeup events (e.g. Power button) instead waking up immediately. + */ + device_set_wakeup_capable(&pdev->dev, true); + + ret = dev_pm_set_wake_irq(&pdev->dev, irq); + if (ret) + goto set_wake_irq_fail; return 0; +set_wake_irq_fail: + dev_pm_clear_wake_irq(&pdev->dev); + unwind_interfaces: list_for_each_entry(entry, &smp2p->inbound, node) irq_domain_remove(entry->domain); @@ -565,6 +583,8 @@ static int qcom_smp2p_remove(struct platform_device *pdev) struct qcom_smp2p *smp2p = platform_get_drvdata(pdev); struct smp2p_entry *entry; + dev_pm_clear_wake_irq(&pdev->dev); + list_for_each_entry(entry, &smp2p->inbound, node) irq_domain_remove(entry->domain); From a4fe5159038f22604e9ef3a8c38b680db4456138 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:18 +0530 Subject: [PATCH 32/40] dt-bindings: soc: qcom: aoss: Drop the load state power-domain The power-domains exposed by AOSS QMP node are used to notify the Always on Subsystem (AOSS) that a particular co-processor is up/down. These co-processors enter low-power modes independent to that of the application processor and their states are expected to remain unaltered across system suspend/resume cycles. To achieve this behavior let's drop the load power-domain and replace them with generic qmp_send interface instead. Signed-off-by: Sibi Sankar Reviewed-by: Matthias Kaehlcke Reviewed-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-2-git-send-email-sibis@codeaurora.org --- .../devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 1904612fad85..e2e173dfada7 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -19,8 +19,7 @@ description: The AOSS side channel exposes control over a set of resources, used to control a set of debug related clocks and to affect the low power state of resources - related to the secondary subsystems. These resources are exposed as a set of - power-domains. + related to the secondary subsystems. properties: compatible: @@ -58,13 +57,6 @@ properties: description: The single clock represents the QDSS clock. - "#power-domain-cells": - const: 1 - description: | - The provided power-domains are: - CDSP state (0), LPASS state (1), modem state (2), SLPI - state (3), SPSS state (4) and Venus state (5). - required: - compatible - reg @@ -102,7 +94,6 @@ examples: mboxes = <&apss_shared 0>; #clock-cells = <0>; - #power-domain-cells = <1>; cx_cdev: cx { #cooling-cells = <2>; From 99512191f4f1dd4e0ad92e6f61ffe4d8a22aa3ba Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:28 +0530 Subject: [PATCH 33/40] soc: qcom: aoss: Drop power domain support Strip out the load state power-domain support from the driver since the low power mode signalling for the co-processors is now accessible through the direct qmp message send interface. Signed-off-by: Sibi Sankar Reviewed-by: Matthias Kaehlcke Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-12-git-send-email-sibis@codeaurora.org --- drivers/soc/qcom/qcom_aoss.c | 107 ----------------------------------- 1 file changed, 107 deletions(-) diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index aac36f0b58e4..34acf58bbb0d 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2019, Linaro Ltd */ -#include #include #include #include @@ -10,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -66,7 +64,6 @@ struct qmp_cooling_device { * @event: wait_queue for synchronization with the IRQ * @tx_lock: provides synchronization between multiple callers of qmp_send() * @qdss_clk: QDSS clock hw struct - * @pd_data: genpd data * @cooling_devs: thermal cooling devices */ struct qmp { @@ -84,17 +81,9 @@ struct qmp { struct mutex tx_lock; struct clk_hw qdss_clk; - struct genpd_onecell_data pd_data; struct qmp_cooling_device *cooling_devs; }; -struct qmp_pd { - struct qmp *qmp; - struct generic_pm_domain pd; -}; - -#define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd) - static void qmp_kick(struct qmp *qmp) { mbox_send_message(qmp->mbox_chan, NULL); @@ -320,95 +309,6 @@ static void qmp_qdss_clk_remove(struct qmp *qmp) clk_hw_unregister(&qmp->qdss_clk); } -static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable) -{ - char buf[QMP_MSG_LEN] = {}; - - snprintf(buf, sizeof(buf), - "{class: image, res: load_state, name: %s, val: %s}", - res->pd.name, enable ? "on" : "off"); - return qmp_send(res->qmp, buf, sizeof(buf)); -} - -static int qmp_pd_power_on(struct generic_pm_domain *domain) -{ - return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true); -} - -static int qmp_pd_power_off(struct generic_pm_domain *domain) -{ - return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false); -} - -static const char * const sdm845_resources[] = { - [AOSS_QMP_LS_CDSP] = "cdsp", - [AOSS_QMP_LS_LPASS] = "adsp", - [AOSS_QMP_LS_MODEM] = "modem", - [AOSS_QMP_LS_SLPI] = "slpi", - [AOSS_QMP_LS_SPSS] = "spss", - [AOSS_QMP_LS_VENUS] = "venus", -}; - -static int qmp_pd_add(struct qmp *qmp) -{ - struct genpd_onecell_data *data = &qmp->pd_data; - struct device *dev = qmp->dev; - struct qmp_pd *res; - size_t num = ARRAY_SIZE(sdm845_resources); - int ret; - int i; - - res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL); - if (!res) - return -ENOMEM; - - data->domains = devm_kcalloc(dev, num, sizeof(*data->domains), - GFP_KERNEL); - if (!data->domains) - return -ENOMEM; - - for (i = 0; i < num; i++) { - res[i].qmp = qmp; - res[i].pd.name = sdm845_resources[i]; - res[i].pd.power_on = qmp_pd_power_on; - res[i].pd.power_off = qmp_pd_power_off; - - ret = pm_genpd_init(&res[i].pd, NULL, true); - if (ret < 0) { - dev_err(dev, "failed to init genpd\n"); - goto unroll_genpds; - } - - data->domains[i] = &res[i].pd; - } - - data->num_domains = i; - - ret = of_genpd_add_provider_onecell(dev->of_node, data); - if (ret < 0) - goto unroll_genpds; - - return 0; - -unroll_genpds: - for (i--; i >= 0; i--) - pm_genpd_remove(data->domains[i]); - - return ret; -} - -static void qmp_pd_remove(struct qmp *qmp) -{ - struct genpd_onecell_data *data = &qmp->pd_data; - struct device *dev = qmp->dev; - int i; - - of_genpd_del_provider(dev->of_node); - - for (i = 0; i < data->num_domains; i++) - pm_genpd_remove(data->domains[i]); -} - static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { @@ -612,10 +512,6 @@ static int qmp_probe(struct platform_device *pdev) if (ret) goto err_close_qmp; - ret = qmp_pd_add(qmp); - if (ret) - goto err_remove_qdss_clk; - ret = qmp_cooling_devices_register(qmp); if (ret) dev_err(&pdev->dev, "failed to register aoss cooling devices\n"); @@ -624,8 +520,6 @@ static int qmp_probe(struct platform_device *pdev) return 0; -err_remove_qdss_clk: - qmp_qdss_clk_remove(qmp); err_close_qmp: qmp_close(qmp); err_free_mbox: @@ -639,7 +533,6 @@ static int qmp_remove(struct platform_device *pdev) struct qmp *qmp = platform_get_drvdata(pdev); qmp_qdss_clk_remove(qmp); - qmp_pd_remove(qmp); qmp_cooling_devices_remove(qmp); qmp_close(qmp); From ec908595825ce84fb40e94a68b378f13c65076af Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:29 +0530 Subject: [PATCH 34/40] dt-bindings: msm/dp: Remove aoss-qmp header Remove the unused aoss-qmp header from the list of includes. Signed-off-by: Sibi Sankar Acked-by: Rob Herring Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-13-git-send-email-sibis@codeaurora.org --- Documentation/devicetree/bindings/display/msm/dp-controller.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index 64d8d9e5e47a..d89b3c510c27 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -95,7 +95,6 @@ examples: - | #include #include - #include #include displayport-controller@ae90000 { From e603577231d4d041eceeaf23c25935df5d008798 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:30 +0530 Subject: [PATCH 35/40] dt-bindings: soc: qcom: aoss: Delete unused power-domain definitions Delete unused power-domain definitions exposed by AOSS QMP. Signed-off-by: Sibi Sankar Reviewed-by: Stephen Boyd Acked-by: Rob Herring Reviewed-by: Matthias Kaehlcke Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-14-git-send-email-sibis@codeaurora.org --- include/dt-bindings/power/qcom-aoss-qmp.h | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 include/dt-bindings/power/qcom-aoss-qmp.h diff --git a/include/dt-bindings/power/qcom-aoss-qmp.h b/include/dt-bindings/power/qcom-aoss-qmp.h deleted file mode 100644 index ec336d31dee4..000000000000 --- a/include/dt-bindings/power/qcom-aoss-qmp.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2018, Linaro Ltd. */ - -#ifndef __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H -#define __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H - -#define AOSS_QMP_LS_CDSP 0 -#define AOSS_QMP_LS_LPASS 1 -#define AOSS_QMP_LS_MODEM 2 -#define AOSS_QMP_LS_SLPI 3 -#define AOSS_QMP_LS_SPSS 4 -#define AOSS_QMP_LS_VENUS 5 - -#endif From 985f62a9a13175217978a797cd8f1f26216b2c87 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Sep 2021 14:55:38 +0100 Subject: [PATCH 36/40] soc: dt-bindings: qcom: apr: convert to yaml Convert APR bindings to yaml format so that we could add new bindings support. All the dsp services bindings are now part of apr bindings instead of adding them to audio bindings. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210927135559.738-2-srinivas.kandagatla@linaro.org --- .../devicetree/bindings/soc/qcom/qcom,apr.txt | 134 ----------------- .../bindings/soc/qcom/qcom,apr.yaml | 135 ++++++++++++++++++ 2 files changed, 135 insertions(+), 134 deletions(-) delete mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt deleted file mode 100644 index 2e2f6dc351c0..000000000000 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt +++ /dev/null @@ -1,134 +0,0 @@ -Qualcomm APR (Asynchronous Packet Router) binding - -This binding describes the Qualcomm APR. APR is a IPC protocol for -communication between Application processor and QDSP. APR is mainly -used for audio/voice services on the QDSP. - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,apr-v", example "qcom,apr-v2" - -- qcom,apr-domain - Usage: required - Value type: - Definition: Destination processor ID. - Possible values are : - 1 - APR simulator - 2 - PC - 3 - MODEM - 4 - ADSP - 5 - APPS - 6 - MODEM2 - 7 - APPS2 - -= APR SERVICES -Each subnode of the APR node represents service tied to this apr. The name -of the nodes are not important. The properties of these nodes are defined -by the individual bindings for the specific service -- All APR services MUST contain the following property: - -- reg - Usage: required - Value type: - Definition: APR Service ID - Possible values are : - 3 - DSP Core Service - 4 - Audio Front End Service. - 5 - Voice Stream Manager Service. - 6 - Voice processing manager. - 7 - Audio Stream Manager Service. - 8 - Audio Device Manager Service. - 9 - Multimode voice manager. - 10 - Core voice stream. - 11 - Core voice processor. - 12 - Ultrasound stream manager. - 13 - Listen stream manager. - -- qcom,protection-domain - Usage: optional - Value type: - Definition: Must list the protection domain service name and path - that the particular apr service has a dependency on. - Possible values are : - "avs/audio", "msm/adsp/audio_pd". - "kernel/elf_loader", "msm/modem/wlan_pd". - "tms/servreg", "msm/adsp/audio_pd". - "tms/servreg", "msm/modem/wlan_pd". - "tms/servreg", "msm/slpi/sensor_pd". - -= EXAMPLE -The following example represents a QDSP based sound card on a MSM8996 device -which uses apr as communication between Apps and QDSP. - - apr { - compatible = "qcom,apr-v2"; - qcom,apr-domain = ; - - apr-service@3 { - compatible = "qcom,q6core"; - reg = ; - }; - - apr-service@4 { - compatible = "qcom,q6afe"; - reg = ; - - dais { - #sound-dai-cells = <1>; - dai@1 { - reg = ; - }; - }; - }; - - apr-service@7 { - compatible = "qcom,q6asm"; - reg = ; - ... - }; - - apr-service@8 { - compatible = "qcom,q6adm"; - reg = ; - ... - }; - }; - -= EXAMPLE 2 -The following example represents a QDSP based sound card with protection domain -dependencies specified. Here some of the apr services are dependent on services -running on protection domain hosted on ADSP/SLPI remote processors while others -have no such dependency. - - apr { - compatible = "qcom,apr-v2"; - qcom,glink-channels = "apr_audio_svc"; - qcom,apr-domain = ; - - apr-service@3 { - compatible = "qcom,q6core"; - reg = ; - }; - - q6afe: apr-service@4 { - compatible = "qcom,q6afe"; - reg = ; - qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; - ... - }; - - q6asm: apr-service@7 { - compatible = "qcom,q6asm"; - reg = ; - qcom,protection-domain = "tms/servreg", "msm/slpi/sensor_pd"; - ... - }; - - q6adm: apr-service@8 { - compatible = "qcom,q6adm"; - reg = ; - qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; - ... - }; - }; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml new file mode 100644 index 000000000000..a52b955b8b39 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/qcom/qcom,apr.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm APR (Asynchronous Packet Router) binding + +maintainers: + - Srinivas Kandagatla + +description: | + This binding describes the Qualcomm APR, APR is a IPC protocol for + communication between Application processor and QDSP. APR is mainly + used for audio/voice services on the QDSP. + +properties: + compatible: + enum: + - qcom,apr-v2 + + qcom,apr-domain: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 3, 4, 5, 6, 7] + description: + Selects the processor domain for apr + 1 = APR simulator + 2 = PC Domain + 3 = Modem Domain + 4 = ADSP Domain + 5 = Application processor Domain + 6 = Modem2 Domain + 7 = Application Processor2 Domain + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +#APR Services +patternProperties: + "^service@[3-9a-d]$": + type: object + description: + APR node's client devices use subnodes for desired static port services. + + properties: + compatible: + enum: + - qcom,q6core + - qcom,q6asm + - qcom,q6afe + - qcom,q6adm + + reg: + minimum: 3 + maximum: 13 + description: + APR Service ID + 3 = DSP Core Service + 4 = Audio Front End Service. + 5 = Voice Stream Manager Service. + 6 = Voice processing manager. + 7 = Audio Stream Manager Service. + 8 = Audio Device Manager Service. + 9 = Multimode voice manager. + 10 = Core voice stream. + 11 = Core voice processor. + 12 = Ultrasound stream manager. + 13 = Listen stream manager. + + qcom,protection-domain: + $ref: /schemas/types.yaml#/definitions/string-array + description: protection domain service name and path for apr service + possible values are + "avs/audio", "msm/adsp/audio_pd". + "kernel/elf_loader", "msm/modem/wlan_pd". + "tms/servreg", "msm/adsp/audio_pd". + "tms/servreg", "msm/modem/wlan_pd". + "tms/servreg", "msm/slpi/sensor_pd". + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + patternProperties: + "^.*@[0-9a-f]+$": + type: object + description: + Service based devices like clock controllers or digital audio interfaces. + + additionalProperties: false + +required: + - compatible + - qcom,apr-domain + +additionalProperties: false + +examples: + - | + #include + apr { + compatible = "qcom,apr-v2"; + qcom,apr-domain = ; + #address-cells = <1>; + #size-cells = <0>; + + q6core: service@3 { + compatible = "qcom,q6core"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + }; + + q6afe: service@4 { + compatible = "qcom,q6afe"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + }; + + q6asm: service@7 { + compatible = "qcom,q6asm"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + }; + + q6adm: service@8 { + compatible = "qcom,q6adm"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + }; + }; From 1ff63d5465d0b0bf4e69562096b2d3ec9ff1a116 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Sep 2021 14:55:39 +0100 Subject: [PATCH 37/40] soc: dt-bindings: qcom: apr: deprecate qcom,apr-domain property replace usage of qcom,apr-domain property with qcom,domain property so that bindings and driver can be reused. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210927135559.738-3-srinivas.kandagatla@linaro.org --- .../bindings/soc/qcom/qcom,apr.yaml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml index a52b955b8b39..bfe04fca8aa3 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -31,6 +31,21 @@ properties: 5 = Application processor Domain 6 = Modem2 Domain 7 = Application Processor2 Domain + deprecated: true + + qcom,domain: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 7 + description: + Selects the processor domain for apr + 1 = APR simulator + 2 = PC Domain + 3 = Modem Domain + 4 = ADSP Domain + 5 = Application processor Domain + 6 = Modem2 Domain + 7 = Application Processor2 Domain '#address-cells': const: 1 @@ -96,7 +111,7 @@ patternProperties: required: - compatible - - qcom,apr-domain + - qcom,domain additionalProperties: false @@ -105,7 +120,7 @@ examples: #include apr { compatible = "qcom,apr-v2"; - qcom,apr-domain = ; + qcom,domain = ; #address-cells = <1>; #size-cells = <0>; From 99139b80c1b3d73026ed8be2de42c52e2976ab64 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Sep 2021 14:55:40 +0100 Subject: [PATCH 38/40] soc: qcom: apr: make code more reuseable APR and other packet routers like GPR are pretty much same and interact with other drivers in similar way. Ex: GPR ports can be considered as APR services, only difference is they are allocated dynamically. Other difference is packet layout, which should not matter with the apis abstracted. Apart from this the rest of the functionality is pretty much identical across APR and GPR. Make the apr code more reusable by abstracting it service level, rather than device level so that we do not need to write new drivers for other new packet routers like GPR. This patch is in preparation to add GPR support to this driver. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210927135559.738-4-srinivas.kandagatla@linaro.org --- drivers/soc/qcom/apr.c | 129 +++++++++++++++++++++-------------- include/linux/soc/qcom/apr.h | 12 +++- 2 files changed, 90 insertions(+), 51 deletions(-) diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 475a57b435b2..bfad71e540ad 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -15,13 +15,18 @@ #include #include -struct apr { +enum { + PR_TYPE_APR = 0, +}; + +struct packet_router { struct rpmsg_endpoint *ch; struct device *dev; spinlock_t svcs_lock; spinlock_t rx_lock; struct idr svcs_idr; int dest_domain_id; + int type; struct pdr_handle *pdr; struct workqueue_struct *rxwq; struct work_struct rx_work; @@ -44,21 +49,21 @@ struct apr_rx_buf { */ int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt) { - struct apr *apr = dev_get_drvdata(adev->dev.parent); + struct packet_router *apr = dev_get_drvdata(adev->dev.parent); struct apr_hdr *hdr; unsigned long flags; int ret; - spin_lock_irqsave(&adev->lock, flags); + spin_lock_irqsave(&adev->svc.lock, flags); hdr = &pkt->hdr; hdr->src_domain = APR_DOMAIN_APPS; - hdr->src_svc = adev->svc_id; + hdr->src_svc = adev->svc.id; hdr->dest_domain = adev->domain_id; - hdr->dest_svc = adev->svc_id; + hdr->dest_svc = adev->svc.id; ret = rpmsg_trysend(apr->ch, pkt, hdr->pkt_size); - spin_unlock_irqrestore(&adev->lock, flags); + spin_unlock_irqrestore(&adev->svc.lock, flags); return ret ? ret : hdr->pkt_size; } @@ -74,7 +79,7 @@ static void apr_dev_release(struct device *dev) static int apr_callback(struct rpmsg_device *rpdev, void *buf, int len, void *priv, u32 addr) { - struct apr *apr = dev_get_drvdata(&rpdev->dev); + struct packet_router *apr = dev_get_drvdata(&rpdev->dev); struct apr_rx_buf *abuf; unsigned long flags; @@ -100,11 +105,11 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, return 0; } - -static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf) +static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf) { uint16_t hdr_size, msg_type, ver, svc_id; - struct apr_device *svc = NULL; + struct pkt_router_svc *svc; + struct apr_device *adev; struct apr_driver *adrv = NULL; struct apr_resp_pkt resp; struct apr_hdr *hdr; @@ -145,12 +150,15 @@ static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf) svc_id = hdr->dest_svc; spin_lock_irqsave(&apr->svcs_lock, flags); svc = idr_find(&apr->svcs_idr, svc_id); - if (svc && svc->dev.driver) - adrv = to_apr_driver(svc->dev.driver); + if (svc && svc->dev->driver) { + adev = svc_to_apr_device(svc); + adrv = to_apr_driver(adev->dev.driver); + } spin_unlock_irqrestore(&apr->svcs_lock, flags); - if (!adrv) { - dev_err(apr->dev, "APR: service is not registered\n"); + if (!adrv || !adev) { + dev_err(apr->dev, "APR: service is not registered (%d)\n", + svc_id); return -EINVAL; } @@ -164,20 +172,26 @@ static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf) if (resp.payload_size > 0) resp.payload = buf + hdr_size; - adrv->callback(svc, &resp); + adrv->callback(adev, &resp); return 0; } static void apr_rxwq(struct work_struct *work) { - struct apr *apr = container_of(work, struct apr, rx_work); + struct packet_router *apr = container_of(work, struct packet_router, rx_work); struct apr_rx_buf *abuf, *b; unsigned long flags; if (!list_empty(&apr->rx_list)) { list_for_each_entry_safe(abuf, b, &apr->rx_list, node) { - apr_do_rx_callback(apr, abuf); + switch (apr->type) { + case PR_TYPE_APR: + apr_do_rx_callback(apr, abuf); + break; + default: + break; + } spin_lock_irqsave(&apr->rx_lock, flags); list_del(&abuf->node); spin_unlock_irqrestore(&apr->rx_lock, flags); @@ -201,7 +215,7 @@ static int apr_device_match(struct device *dev, struct device_driver *drv) while (id->domain_id != 0 || id->svc_id != 0) { if (id->domain_id == adev->domain_id && - id->svc_id == adev->svc_id) + id->svc_id == adev->svc.id) return 1; id++; } @@ -221,14 +235,14 @@ static void apr_device_remove(struct device *dev) { struct apr_device *adev = to_apr_device(dev); struct apr_driver *adrv; - struct apr *apr = dev_get_drvdata(adev->dev.parent); + struct packet_router *apr = dev_get_drvdata(adev->dev.parent); if (dev->driver) { adrv = to_apr_driver(dev->driver); if (adrv->remove) adrv->remove(adev); spin_lock(&apr->svcs_lock); - idr_remove(&apr->svcs_idr, adev->svc_id); + idr_remove(&apr->svcs_idr, adev->svc.id); spin_unlock(&apr->svcs_lock); } } @@ -255,28 +269,39 @@ struct bus_type aprbus = { EXPORT_SYMBOL_GPL(aprbus); static int apr_add_device(struct device *dev, struct device_node *np, - const struct apr_device_id *id) + u32 svc_id, u32 domain_id) { - struct apr *apr = dev_get_drvdata(dev); + struct packet_router *apr = dev_get_drvdata(dev); struct apr_device *adev = NULL; + struct pkt_router_svc *svc; int ret; adev = kzalloc(sizeof(*adev), GFP_KERNEL); if (!adev) return -ENOMEM; - spin_lock_init(&adev->lock); + adev->svc_id = svc_id; + svc = &adev->svc; + + svc->id = svc_id; + svc->pr = apr; + svc->priv = adev; + svc->dev = dev; + spin_lock_init(&svc->lock); + + adev->domain_id = domain_id; - adev->svc_id = id->svc_id; - adev->domain_id = id->domain_id; - adev->version = id->svc_version; if (np) snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np); - else - strscpy(adev->name, id->name, APR_NAME_SIZE); - dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, - id->domain_id, id->svc_id); + switch (apr->type) { + case PR_TYPE_APR: + dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, + domain_id, svc_id); + break; + default: + break; + } adev->dev.bus = &aprbus; adev->dev.parent = dev; @@ -285,8 +310,7 @@ static int apr_add_device(struct device *dev, struct device_node *np, adev->dev.driver = NULL; spin_lock(&apr->svcs_lock); - idr_alloc(&apr->svcs_idr, adev, id->svc_id, - id->svc_id + 1, GFP_ATOMIC); + idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC); spin_unlock(&apr->svcs_lock); of_property_read_string_index(np, "qcom,protection-domain", @@ -306,7 +330,7 @@ static int apr_add_device(struct device *dev, struct device_node *np, static int of_apr_add_pd_lookups(struct device *dev) { const char *service_name, *service_path; - struct apr *apr = dev_get_drvdata(dev); + struct packet_router *apr = dev_get_drvdata(dev); struct device_node *node; struct pdr_service *pds; int ret; @@ -336,13 +360,14 @@ static int of_apr_add_pd_lookups(struct device *dev) static void of_register_apr_devices(struct device *dev, const char *svc_path) { - struct apr *apr = dev_get_drvdata(dev); + struct packet_router *apr = dev_get_drvdata(dev); struct device_node *node; const char *service_path; int ret; for_each_child_of_node(dev->of_node, node) { - struct apr_device_id id = { {0} }; + u32 svc_id; + u32 domain_id; /* * This function is called with svc_path NULL during @@ -372,13 +397,13 @@ static void of_register_apr_devices(struct device *dev, const char *svc_path) continue; } - if (of_property_read_u32(node, "reg", &id.svc_id)) + if (of_property_read_u32(node, "reg", &svc_id)) continue; - id.domain_id = apr->dest_domain_id; + domain_id = apr->dest_domain_id; - if (apr_add_device(dev, node, &id)) - dev_err(dev, "Failed to add apr %d svc\n", id.svc_id); + if (apr_add_device(dev, node, svc_id, domain_id)) + dev_err(dev, "Failed to add apr %d svc\n", svc_id); } } @@ -398,7 +423,7 @@ static int apr_remove_device(struct device *dev, void *svc_path) static void apr_pd_status(int state, char *svc_path, void *priv) { - struct apr *apr = (struct apr *)priv; + struct packet_router *apr = (struct packet_router *)priv; switch (state) { case SERVREG_SERVICE_STATE_UP: @@ -413,16 +438,20 @@ static void apr_pd_status(int state, char *svc_path, void *priv) static int apr_probe(struct rpmsg_device *rpdev) { struct device *dev = &rpdev->dev; - struct apr *apr; + struct packet_router *apr; int ret; apr = devm_kzalloc(dev, sizeof(*apr), GFP_KERNEL); if (!apr) return -ENOMEM; - ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id); + ret = of_property_read_u32(dev->of_node, "qcom,domain", &apr->dest_domain_id); + if (ret) /* try deprecated apr-domain property */ + ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", + &apr->dest_domain_id); + apr->type = PR_TYPE_APR; if (ret) { - dev_err(dev, "APR Domain ID not specified in DT\n"); + dev_err(dev, "Domain ID not specified in DT\n"); return ret; } @@ -465,7 +494,7 @@ destroy_wq: static void apr_remove(struct rpmsg_device *rpdev) { - struct apr *apr = dev_get_drvdata(&rpdev->dev); + struct packet_router *apr = dev_get_drvdata(&rpdev->dev); pdr_handle_release(apr->pdr); device_for_each_child(&rpdev->dev, NULL, apr_remove_device); @@ -502,20 +531,20 @@ void apr_driver_unregister(struct apr_driver *drv) } EXPORT_SYMBOL_GPL(apr_driver_unregister); -static const struct of_device_id apr_of_match[] = { +static const struct of_device_id pkt_router_of_match[] = { { .compatible = "qcom,apr"}, { .compatible = "qcom,apr-v2"}, {} }; -MODULE_DEVICE_TABLE(of, apr_of_match); +MODULE_DEVICE_TABLE(of, pkt_router_of_match); -static struct rpmsg_driver apr_driver = { +static struct rpmsg_driver packet_router_driver = { .probe = apr_probe, .remove = apr_remove, .callback = apr_callback, .drv = { .name = "qcom,apr", - .of_match_table = apr_of_match, + .of_match_table = pkt_router_of_match, }, }; @@ -525,7 +554,7 @@ static int __init apr_init(void) ret = bus_register(&aprbus); if (!ret) - ret = register_rpmsg_driver(&apr_driver); + ret = register_rpmsg_driver(&packet_router_driver); else bus_unregister(&aprbus); @@ -535,7 +564,7 @@ static int __init apr_init(void) static void __exit apr_exit(void) { bus_unregister(&aprbus); - unregister_rpmsg_driver(&apr_driver); + unregister_rpmsg_driver(&packet_router_driver); } subsys_initcall(apr_init); diff --git a/include/linux/soc/qcom/apr.h b/include/linux/soc/qcom/apr.h index 137f9f2ac4c3..7bca213a3f83 100644 --- a/include/linux/soc/qcom/apr.h +++ b/include/linux/soc/qcom/apr.h @@ -79,6 +79,15 @@ struct apr_resp_pkt { #define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF) #define APR_SVC_MINOR_VERSION(v) (v & 0xFF) +struct packet_router; +struct pkt_router_svc { + struct device *dev; + struct packet_router *pr; + spinlock_t lock; + int id; + void *priv; +}; + struct apr_device { struct device dev; uint16_t svc_id; @@ -86,11 +95,12 @@ struct apr_device { uint32_t version; char name[APR_NAME_SIZE]; const char *service_path; - spinlock_t lock; + struct pkt_router_svc svc; struct list_head node; }; #define to_apr_device(d) container_of(d, struct apr_device, dev) +#define svc_to_apr_device(d) container_of(d, struct apr_device, svc) struct apr_driver { int (*probe)(struct apr_device *sl); From 974c6faf7667e551d202712470ca210c14ca249d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Sep 2021 14:55:41 +0100 Subject: [PATCH 39/40] soc: dt-bindings: qcom: add gpr bindings Qualcomm Generic Packet router aka GPR is the IPC mechanism found in AudioReach next generation signal processing framework to perform command and response messages between various processors. GPR has concepts of static and dynamic port, all static services like APM (Audio Processing Manager), PRM (Proxy resource manager) have fixed port numbers where as dynamic services like graphs have dynamic port numbers which are allocated at runtime. All GPR packet messages will have source and destination domain and port along with opcode and payload. This support is added using existing APR driver to reuse most of the code. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210927135559.738-5-srinivas.kandagatla@linaro.org --- .../bindings/soc/qcom/qcom,apr.yaml | 41 +++++++++++++++---- include/dt-bindings/soc/qcom,gpr.h | 19 +++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 include/dt-bindings/soc/qcom,gpr.h diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml index bfe04fca8aa3..028c5d105adb 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -4,20 +4,21 @@ $id: "http://devicetree.org/schemas/soc/qcom/qcom,apr.yaml#" $schema: "http://devicetree.org/meta-schemas/core.yaml#" -title: Qualcomm APR (Asynchronous Packet Router) binding +title: Qualcomm APR/GPR (Asynchronous/Generic Packet Router) binding maintainers: - Srinivas Kandagatla description: | - This binding describes the Qualcomm APR, APR is a IPC protocol for - communication between Application processor and QDSP. APR is mainly + This binding describes the Qualcomm APR/GPR, APR/GPR is a IPC protocol for + communication between Application processor and QDSP. APR/GPR is mainly used for audio/voice services on the QDSP. properties: compatible: enum: - qcom,apr-v2 + - qcom,gpr qcom,apr-domain: $ref: /schemas/types.yaml#/definitions/uint32 @@ -46,6 +47,10 @@ properties: 5 = Application processor Domain 6 = Modem2 Domain 7 = Application Processor2 Domain + Selects the processor domain for gpr + 1 = Modem Domain + 2 = Audio DSP Domain + 3 = Application Processor Domain '#address-cells': const: 1 @@ -53,12 +58,12 @@ properties: '#size-cells': const: 0 -#APR Services +#APR/GPR Services patternProperties: - "^service@[3-9a-d]$": + "^service@[1-9a-d]$": type: object description: - APR node's client devices use subnodes for desired static port services. + APR/GPR node's client devices use subnodes for desired static port services. properties: compatible: @@ -67,9 +72,11 @@ patternProperties: - qcom,q6asm - qcom,q6afe - qcom,q6adm + - qcom,q6apm + - qcom,q6prm reg: - minimum: 3 + minimum: 1 maximum: 13 description: APR Service ID @@ -84,6 +91,11 @@ patternProperties: 11 = Core voice processor. 12 = Ultrasound stream manager. 13 = Listen stream manager. + GPR Service ID + 1 = Audio Process Manager Service + 2 = Proxy Resource Manager Service. + 3 = AMDB Service. + 4 = Voice processing manager. qcom,protection-domain: $ref: /schemas/types.yaml#/definitions/string-array @@ -148,3 +160,18 @@ examples: qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; }; }; + + - | + #include + gpr { + compatible = "qcom,gpr"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + + service@1 { + compatible = "qcom,q6apm"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + }; + }; diff --git a/include/dt-bindings/soc/qcom,gpr.h b/include/dt-bindings/soc/qcom,gpr.h new file mode 100644 index 000000000000..3107da59319c --- /dev/null +++ b/include/dt-bindings/soc/qcom,gpr.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + +#ifndef __DT_BINDINGS_QCOM_GPR_H +#define __DT_BINDINGS_QCOM_GPR_H + +/* DOMAINS */ + +#define GPR_DOMAIN_ID_MODEM 1 +#define GPR_DOMAIN_ID_ADSP 2 +#define GPR_DOMAIN_ID_APPS 3 + +/* Static Services */ + +#define GPR_APM_MODULE_IID 1 +#define GPR_PRM_MODULE_IID 2 +#define GPR_AMDB_MODULE_IID 3 +#define GPR_VCPM_MODULE_IID 4 + +#endif /* __DT_BINDINGS_QCOM_GPR_H */ From ec1471a898cca38af6b8956a83ebc1297214546f Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Sep 2021 14:55:42 +0100 Subject: [PATCH 40/40] soc: qcom: apr: Add GPR support Qualcomm Generic Packet router aka GPR is the IPC mechanism found in AudioReach next generation signal processing framework to perform command and response messages between various processors. GPR has concepts of static and dynamic port, all static services like APM (Audio Processing Manager), PRM (Proxy resource manager) have fixed port numbers where as dynamic services like graphs have dynamic port numbers which are allocated at runtime. All GPR packet messages will have source and destination domain and port along with opcode and payload. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210927135559.738-6-srinivas.kandagatla@linaro.org --- drivers/soc/qcom/Kconfig | 2 +- drivers/soc/qcom/apr.c | 166 +++++++++++++++++++++++++++++++++-- include/linux/soc/qcom/apr.h | 58 ++++++++++++ 3 files changed, 219 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 79b568f82a1c..bfa2ab5772cf 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -199,7 +199,7 @@ config QCOM_WCNSS_CTRL firmware to a newly booted WCNSS chip. config QCOM_APR - tristate "Qualcomm APR Bus (Asynchronous Packet Router)" + tristate "Qualcomm APR/GPR Bus (Asynchronous/Generic Packet Router)" depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG depends on NET diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index bfad71e540ad..8a9bfbcd4bb9 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -17,8 +17,13 @@ enum { PR_TYPE_APR = 0, + PR_TYPE_GPR, }; +/* Some random values tbh which does not collide with static modules */ +#define GPR_DYNAMIC_PORT_START 0x10000000 +#define GPR_DYNAMIC_PORT_END 0x20000000 + struct packet_router { struct rpmsg_endpoint *ch; struct device *dev; @@ -69,6 +74,83 @@ int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt) } EXPORT_SYMBOL_GPL(apr_send_pkt); +void gpr_free_port(gpr_port_t *port) +{ + struct packet_router *gpr = port->pr; + unsigned long flags; + + spin_lock_irqsave(&gpr->svcs_lock, flags); + idr_remove(&gpr->svcs_idr, port->id); + spin_unlock_irqrestore(&gpr->svcs_lock, flags); + + kfree(port); +} +EXPORT_SYMBOL_GPL(gpr_free_port); + +gpr_port_t *gpr_alloc_port(struct apr_device *gdev, struct device *dev, + gpr_port_cb cb, void *priv) +{ + struct packet_router *pr = dev_get_drvdata(gdev->dev.parent); + gpr_port_t *port; + struct pkt_router_svc *svc; + int id; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + svc = port; + svc->callback = cb; + svc->pr = pr; + svc->priv = priv; + svc->dev = dev; + spin_lock_init(&svc->lock); + + spin_lock(&pr->svcs_lock); + id = idr_alloc_cyclic(&pr->svcs_idr, svc, GPR_DYNAMIC_PORT_START, + GPR_DYNAMIC_PORT_END, GFP_ATOMIC); + if (id < 0) { + dev_err(dev, "Unable to allocate dynamic GPR src port\n"); + kfree(port); + spin_unlock(&pr->svcs_lock); + return ERR_PTR(id); + } + + svc->id = id; + spin_unlock(&pr->svcs_lock); + + return port; +} +EXPORT_SYMBOL_GPL(gpr_alloc_port); + +static int pkt_router_send_svc_pkt(struct pkt_router_svc *svc, struct gpr_pkt *pkt) +{ + struct packet_router *pr = svc->pr; + struct gpr_hdr *hdr; + unsigned long flags; + int ret; + + hdr = &pkt->hdr; + + spin_lock_irqsave(&svc->lock, flags); + ret = rpmsg_trysend(pr->ch, pkt, hdr->pkt_size); + spin_unlock_irqrestore(&svc->lock, flags); + + return ret ? ret : hdr->pkt_size; +} + +int gpr_send_pkt(struct apr_device *gdev, struct gpr_pkt *pkt) +{ + return pkt_router_send_svc_pkt(&gdev->svc, pkt); +} +EXPORT_SYMBOL_GPL(gpr_send_pkt); + +int gpr_send_port_pkt(gpr_port_t *port, struct gpr_pkt *pkt) +{ + return pkt_router_send_svc_pkt(port, pkt); +} +EXPORT_SYMBOL_GPL(gpr_send_port_pkt); + static void apr_dev_release(struct device *dev) { struct apr_device *adev = to_apr_device(dev); @@ -177,6 +259,59 @@ static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf return 0; } +static int gpr_do_rx_callback(struct packet_router *gpr, struct apr_rx_buf *abuf) +{ + uint16_t hdr_size, ver; + struct pkt_router_svc *svc = NULL; + struct gpr_resp_pkt resp; + struct gpr_hdr *hdr; + unsigned long flags; + void *buf = abuf->buf; + int len = abuf->len; + + hdr = buf; + ver = hdr->version; + if (ver > GPR_PKT_VER + 1) + return -EINVAL; + + hdr_size = hdr->hdr_size; + if (hdr_size < GPR_PKT_HEADER_WORD_SIZE) { + dev_err(gpr->dev, "GPR: Wrong hdr size:%d\n", hdr_size); + return -EINVAL; + } + + if (hdr->pkt_size < GPR_PKT_HEADER_BYTE_SIZE || hdr->pkt_size != len) { + dev_err(gpr->dev, "GPR: Wrong packet size\n"); + return -EINVAL; + } + + resp.hdr = *hdr; + resp.payload_size = hdr->pkt_size - (hdr_size * 4); + + /* + * NOTE: hdr_size is not same as GPR_HDR_SIZE as remote can include + * optional headers in to gpr_hdr which should be ignored + */ + if (resp.payload_size > 0) + resp.payload = buf + (hdr_size * 4); + + + spin_lock_irqsave(&gpr->svcs_lock, flags); + svc = idr_find(&gpr->svcs_idr, hdr->dest_port); + spin_unlock_irqrestore(&gpr->svcs_lock, flags); + + if (!svc) { + dev_err(gpr->dev, "GPR: Port(%x) is not registered\n", + hdr->dest_port); + return -EINVAL; + } + + if (svc->callback) + svc->callback(&resp, svc->priv, 0); + + return 0; +} + static void apr_rxwq(struct work_struct *work) { struct packet_router *apr = container_of(work, struct packet_router, rx_work); @@ -189,6 +324,9 @@ static void apr_rxwq(struct work_struct *work) case PR_TYPE_APR: apr_do_rx_callback(apr, abuf); break; + case PR_TYPE_GPR: + gpr_do_rx_callback(apr, abuf); + break; default: break; } @@ -227,8 +365,13 @@ static int apr_device_probe(struct device *dev) { struct apr_device *adev = to_apr_device(dev); struct apr_driver *adrv = to_apr_driver(dev->driver); + int ret; - return adrv->probe(adev); + ret = adrv->probe(adev); + if (!ret) + adev->svc.callback = adrv->gpr_callback; + + return ret; } static void apr_device_remove(struct device *dev) @@ -299,6 +442,10 @@ static int apr_add_device(struct device *dev, struct device_node *np, dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, domain_id, svc_id); break; + case PR_TYPE_GPR: + dev_set_name(&adev->dev, "gprsvc:%s:%x:%x", adev->name, + domain_id, svc_id); + break; default: break; } @@ -316,7 +463,7 @@ static int apr_add_device(struct device *dev, struct device_node *np, of_property_read_string_index(np, "qcom,protection-domain", 1, &adev->service_path); - dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev)); + dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev)); ret = device_register(&adev->dev); if (ret) { @@ -446,10 +593,16 @@ static int apr_probe(struct rpmsg_device *rpdev) return -ENOMEM; ret = of_property_read_u32(dev->of_node, "qcom,domain", &apr->dest_domain_id); - if (ret) /* try deprecated apr-domain property */ - ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", - &apr->dest_domain_id); - apr->type = PR_TYPE_APR; + + if (of_device_is_compatible(dev->of_node, "qcom,gpr")) { + apr->type = PR_TYPE_GPR; + } else { + if (ret) /* try deprecated apr-domain property */ + ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", + &apr->dest_domain_id); + apr->type = PR_TYPE_APR; + } + if (ret) { dev_err(dev, "Domain ID not specified in DT\n"); return ret; @@ -534,6 +687,7 @@ EXPORT_SYMBOL_GPL(apr_driver_unregister); static const struct of_device_id pkt_router_of_match[] = { { .compatible = "qcom,apr"}, { .compatible = "qcom,apr-v2"}, + { .compatible = "qcom,gpr"}, {} }; MODULE_DEVICE_TABLE(of, pkt_router_of_match); diff --git a/include/linux/soc/qcom/apr.h b/include/linux/soc/qcom/apr.h index 7bca213a3f83..23c5b30f3511 100644 --- a/include/linux/soc/qcom/apr.h +++ b/include/linux/soc/qcom/apr.h @@ -7,6 +7,7 @@ #include #include #include +#include extern struct bus_type aprbus; @@ -75,19 +76,65 @@ struct apr_resp_pkt { int payload_size; }; +struct gpr_hdr { + uint32_t version:4; + uint32_t hdr_size:4; + uint32_t pkt_size:24; + uint32_t dest_domain:8; + uint32_t src_domain:8; + uint32_t reserved:16; + uint32_t src_port; + uint32_t dest_port; + uint32_t token; + uint32_t opcode; +} __packed; + +struct gpr_pkt { + struct gpr_hdr hdr; + uint32_t payload[]; +}; + +struct gpr_resp_pkt { + struct gpr_hdr hdr; + void *payload; + int payload_size; +}; + +#define GPR_HDR_SIZE sizeof(struct gpr_hdr) +#define GPR_PKT_VER 0x0 +#define GPR_PKT_HEADER_WORD_SIZE ((sizeof(struct gpr_pkt) + 3) >> 2) +#define GPR_PKT_HEADER_BYTE_SIZE (GPR_PKT_HEADER_WORD_SIZE << 2) + +#define GPR_BASIC_RSP_RESULT 0x02001005 + +struct gpr_ibasic_rsp_result_t { + uint32_t opcode; + uint32_t status; +}; + +#define GPR_BASIC_EVT_ACCEPTED 0x02001006 + +struct gpr_ibasic_rsp_accepted_t { + uint32_t opcode; +}; + /* Bits 0 to 15 -- Minor version, Bits 16 to 31 -- Major version */ #define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF) #define APR_SVC_MINOR_VERSION(v) (v & 0xFF) +typedef int (*gpr_port_cb) (struct gpr_resp_pkt *d, void *priv, int op); struct packet_router; struct pkt_router_svc { struct device *dev; + gpr_port_cb callback; struct packet_router *pr; spinlock_t lock; int id; void *priv; }; +typedef struct pkt_router_svc gpr_port_t; + struct apr_device { struct device dev; uint16_t svc_id; @@ -99,6 +146,8 @@ struct apr_device { struct list_head node; }; +typedef struct apr_device gpr_device_t; + #define to_apr_device(d) container_of(d, struct apr_device, dev) #define svc_to_apr_device(d) container_of(d, struct apr_device, svc) @@ -107,10 +156,12 @@ struct apr_driver { int (*remove)(struct apr_device *sl); int (*callback)(struct apr_device *a, struct apr_resp_pkt *d); + int (*gpr_callback)(struct gpr_resp_pkt *d, void *data, int op); struct device_driver driver; const struct apr_device_id *id_table; }; +typedef struct apr_driver gpr_driver_t; #define to_apr_driver(d) container_of(d, struct apr_driver, driver) /* @@ -133,7 +184,14 @@ void apr_driver_unregister(struct apr_driver *drv); #define module_apr_driver(__apr_driver) \ module_driver(__apr_driver, apr_driver_register, \ apr_driver_unregister) +#define module_gpr_driver(__gpr_driver) module_apr_driver(__gpr_driver) int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt); +gpr_port_t *gpr_alloc_port(gpr_device_t *gdev, struct device *dev, + gpr_port_cb cb, void *priv); +void gpr_free_port(gpr_port_t *port); +int gpr_send_port_pkt(gpr_port_t *port, struct gpr_pkt *pkt); +int gpr_send_pkt(gpr_device_t *gdev, struct gpr_pkt *pkt); + #endif /* __QCOM_APR_H_ */