From patchwork Thu Dec 2 12:21:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Guo X-Patchwork-Id: 12652435 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9FBF9C433F5 for ; Thu, 2 Dec 2021 12:22:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1357969AbhLBMZ2 (ORCPT ); Thu, 2 Dec 2021 07:25:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35530 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358182AbhLBMZP (ORCPT ); Thu, 2 Dec 2021 07:25:15 -0500 Received: from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com [IPv6:2607:f8b0:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98424C0613F7 for ; Thu, 2 Dec 2021 04:21:50 -0800 (PST) Received: by mail-pl1-x62e.google.com with SMTP id b11so20079996pld.12 for ; Thu, 02 Dec 2021 04:21:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jM9EApcDDLI/s4BAHO7HR69hLfkrMUsostlIb7EIuxg=; b=U7/YUXtgHem9eXajI+v+rSaRM7u8XID5Tbk6B90kTtSQCXH83aJ75/XO5L5o62CLlW Z1BSR5Qc7BlGi3JlATqJ0dauoWKRgkK/5Mp+DFzEAUpQcn2z/uEMpo587id/byiDhWL2 U7+G/sAqhsFHuB5H+xadhszDaGT1Lm+xRaTjCZSHF95x6DSyd1rNN4nWv9WeCCoGcRQi Hqta+AMezDOGbKBCvbK4G8YhU4UY2ZEpEzEGGz7upPZ3z54ZLNzvTQsAbIIjDl4m5tgn hoUT0ycmK6rDCAdZgYpGEnLueKGQJcg/IB8P/rwkpxQGeSMqrHPpSrWYuAhwEju7a/0Z gcPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jM9EApcDDLI/s4BAHO7HR69hLfkrMUsostlIb7EIuxg=; b=OR/9fuFnQWm88O1bgwFH2ZqClUTVMf0SlP9J8b9LcaHrhsKSk2kPjDd7OfZaFN1Hsc UEGu6dXMPzjaEeI6F6bd9+AZ+oFuLSTw1CuZx/M7AcjQSEzmEcwMXbaZ+aYKtz0rZh8a 1ScwKFwaMUfm9eDI86FwhP0w+e7GiYUKxiiQt6nZQ/K98S/dhPKDt3jhgveq//vU5Ih4 t/5A08OfqnlO2pWmAXb2JfCiT9Ktt1OmcMRGWPnHEkiy48N9n1tUOiqEfheXFgJOARXH o+ZRquFD9jzdzjBTrcexfUF+hnz21pCI7MvQxlzsR6wnPFgdNZJf07XoVAAKvTFwZi5u I6fA== X-Gm-Message-State: AOAM530GhHdeMa3TCrJWV8x6aRk5JIj4jm/2vHo2kU0WjHRyBD5ZXjxE Qg15ZNlMP+aauefYsbJ48gKRRA== X-Google-Smtp-Source: ABdhPJzvJ9WrT4ikb15JxTPqXu4k1bO63dWrJr6KPRpZOUiAB9K6D2+bBnlUMYiPQvmtS9yDdyYljQ== X-Received: by 2002:a17:90b:3b44:: with SMTP id ot4mr5772191pjb.202.1638447710120; Thu, 02 Dec 2021 04:21:50 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id m15sm3608894pfk.186.2021.12.02.04.21.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Dec 2021 04:21:49 -0800 (PST) From: Shawn Guo To: Marc Zyngier , Thomas Gleixner Cc: Maulik Shah , Bjorn Andersson , Loic Poulain , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo , Florian Fainelli , Claudiu Beznea , Neil Armstrong Subject: [PATCH v3 1/3] irqchip: Pass platform_device pointer to init_cb Date: Thu, 2 Dec 2021 20:21:20 +0800 Message-Id: <20211202122122.23548-2-shawn.guo@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211202122122.23548-1-shawn.guo@linaro.org> References: <20211202122122.23548-1-shawn.guo@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org It makes sense to just pass device_node for callback in IRQCHIP_DECLARE case, but not so much for IRQCHIP_PLATFORM_DRIVER one, because platform_driver probe/init usually needs device pointer for various purposes, e.g. resource allocation, service request, device prefixed message output, etc. Create a new callback type irqchip_init_cb_t which takes platform_device pointer as parameter, and update the existing IRQCHIP_PLATFORM_DRIVER users accordingly. Cc: Florian Fainelli Cc: Claudiu Beznea Cc: Neil Armstrong Signed-off-by: Shawn Guo --- drivers/irqchip/irq-bcm7038-l1.c | 3 ++- drivers/irqchip/irq-bcm7120-l2.c | 10 ++++++---- drivers/irqchip/irq-brcmstb-l2.c | 10 ++++++---- drivers/irqchip/irq-mchp-eic.c | 4 +++- drivers/irqchip/irq-meson-gpio.c | 7 +++++-- drivers/irqchip/irqchip.c | 4 ++-- drivers/irqchip/qcom-pdc.c | 4 +++- include/linux/irqchip.h | 8 +++++++- 8 files changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index a62b96237b82..d52a598f73df 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -396,9 +396,10 @@ static const struct irq_domain_ops bcm7038_l1_domain_ops = { .map = bcm7038_l1_map, }; -static int __init bcm7038_l1_of_init(struct device_node *dn, +static int __init bcm7038_l1_of_init(struct platform_device *pdev, struct device_node *parent) { + struct device_node *dn = pdev->dev.of_node; struct bcm7038_l1_chip *intc; int idx, ret; diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index d80e67a6aad2..82a75eb11523 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -341,17 +341,19 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn, return ret; } -static int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, +static int __init bcm7120_l2_intc_probe_7120(struct platform_device *pdev, struct device_node *parent) { - return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, + return bcm7120_l2_intc_probe(pdev->dev.of_node, parent, + bcm7120_l2_intc_iomap_7120, "BCM7120 L2"); } -static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, +static int __init bcm7120_l2_intc_probe_3380(struct platform_device *pdev, struct device_node *parent) { - return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, + return bcm7120_l2_intc_probe(pdev->dev.of_node, parent, + bcm7120_l2_intc_iomap_3380, "BCM3380 L2"); } diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index e4efc08ac594..52886fbcea18 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -270,16 +270,18 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np, return ret; } -static int __init brcmstb_l2_edge_intc_of_init(struct device_node *np, +static int __init brcmstb_l2_edge_intc_of_init(struct platform_device *pdev, struct device_node *parent) { - return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init); + return brcmstb_l2_intc_of_init(pdev->dev.of_node, parent, + &l2_edge_intc_init); } -static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np, +static int __init brcmstb_l2_lvl_intc_of_init(struct platform_device *pdev, struct device_node *parent) { - return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); + return brcmstb_l2_intc_of_init(pdev->dev.of_node, parent, + &l2_lvl_intc_init); } IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2) diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index c726a19837d2..1ab34af841f6 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -199,8 +199,10 @@ static const struct irq_domain_ops mchp_eic_domain_ops = { .free = irq_domain_free_irqs_common, }; -static int mchp_eic_init(struct device_node *node, struct device_node *parent) +static int mchp_eic_init(struct platform_device *pdev, + struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *parent_domain = NULL; int ret, i; diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index d90ff0b92480..1c841189defa 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -436,7 +436,8 @@ static const struct irq_domain_ops meson_gpio_irq_domain_ops = { .translate = meson_gpio_irq_domain_translate, }; -static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_irq_controller *ctl) +static int meson_gpio_irq_parse_dt(struct device_node *node, + struct meson_gpio_irq_controller *ctl) { const struct of_device_id *match; int ret; @@ -462,8 +463,10 @@ static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_i return 0; } -static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *parent) +static int meson_gpio_irq_of_init(struct platform_device *pdev, + struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *domain, *parent_domain; struct meson_gpio_irq_controller *ctl; int ret; diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 3570f0a588c4..62e6dbc3c4d0 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -36,7 +36,7 @@ int platform_irqchip_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *par_np = of_irq_find_parent(np); - of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); + irqchip_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); if (!irq_init_cb) return -EINVAL; @@ -55,6 +55,6 @@ int platform_irqchip_probe(struct platform_device *pdev) if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) return -EPROBE_DEFER; - return irq_init_cb(np, par_np); + return irq_init_cb(pdev, par_np); } EXPORT_SYMBOL_GPL(platform_irqchip_probe); diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index 173e6520e06e..b66ac9dd46c3 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -359,8 +359,10 @@ static int pdc_setup_pin_mapping(struct device_node *np) return 0; } -static int qcom_pdc_init(struct device_node *node, struct device_node *parent) +static int qcom_pdc_init(struct platform_device *pdev, + struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain; int ret; diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index 3a091d0710ae..da33a21c0297 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -36,13 +36,19 @@ extern of_irq_init_cb_t typecheck_irq_init_cb; #define IRQCHIP_DECLARE(name, compat, fn) \ OF_DECLARE_2(irqchip, name, compat, typecheck_irq_init_cb(fn)) +typedef int (*irqchip_init_cb_t)(struct platform_device *, + struct device_node *); +extern irqchip_init_cb_t typecheck_irqchip_init_cb; +#define typecheck_irqchip_init_cb(fn) \ + (__typecheck(typecheck_irqchip_init_cb, &fn) ? fn : fn) + extern int platform_irqchip_probe(struct platform_device *pdev); #define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \ static const struct of_device_id drv_name##_irqchip_match_table[] = { #define IRQCHIP_MATCH(compat, fn) { .compatible = compat, \ - .data = typecheck_irq_init_cb(fn), }, + .data = typecheck_irqchip_init_cb(fn), }, #define IRQCHIP_PLATFORM_DRIVER_END(drv_name) \ {}, \ From patchwork Thu Dec 2 12:21:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Guo X-Patchwork-Id: 12652433 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B7A3DC433EF for ; Thu, 2 Dec 2021 12:22:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358046AbhLBMZ3 (ORCPT ); Thu, 2 Dec 2021 07:25:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358192AbhLBMZQ (ORCPT ); Thu, 2 Dec 2021 07:25:16 -0500 Received: from mail-pl1-x62a.google.com (mail-pl1-x62a.google.com [IPv6:2607:f8b0:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A0B1C0613FA for ; Thu, 2 Dec 2021 04:21:53 -0800 (PST) Received: by mail-pl1-x62a.google.com with SMTP id y7so20135107plp.0 for ; Thu, 02 Dec 2021 04:21:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RXntCnFaEu15rLId3/xepqIAwJ07mxfKidhEo2IC6sM=; b=IDZog2Aj9ymOUvZTrDhnO4TI4GKvzb0uPRslB4rapwq2iqDQEpd9XRf3WBK2A56ncG +a40DWq9uzKiTvmeOPXqQHVTcFGWI1hAOlUg5VKWJayvOiXYIzCobtEGqLytyXyHNs12 7+gFU5ekMQNTwWK3dQUWAqCuuaEEbHZYk2OFZ8uK30Cm5LsnU2BcbWlBptXQJ0BTtHTt /d3T/iudDP5qoS2naY29oWXnTWThaDEgd1b6uE5dgDdI+NJ182eq7ZEsm3GUhbZb7V/s +SIFHywFP43eL4txRKSwmIPASoykjjcjxDvhxv/NqyInFKW5InpIZ5c61mv/y4VHLxjq ZsbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RXntCnFaEu15rLId3/xepqIAwJ07mxfKidhEo2IC6sM=; b=OEdd6n6hI9GvdE2/3Qc86xNm6iHt2Rc+rzr1FA2Bi7XYBkXh/A9RdeQsDtiB4MiT9O tyGAGlrY7yw8m/V+70HtUbn6bd23wJxAWg0rIEkr2/zF2YrN7Ke5DpHivxKcldLcYv/3 fjqNvn4CLxU/AerJXn/vwb924V0bnm7U+GAbYdG9OQTXsb9+VyoPsDzs5+gfcnl5Dnzs hMcC+T8i7mkMj9V9uyCTbewW3nqg+/sx2E+kmld206uVff+qrfKZCC+yYAtv0bc6HFiW Nbx1dW4YjOHKah25OHOR+BTs2hhI7EOcL+YuFiAZ92e8d4/xRXg0MiKCZvlw50eoYRom K2fw== X-Gm-Message-State: AOAM530bVWJ9zaksmqESQuP2sLBFuWP8xezmOcy3n7Ozk1VHIa+sWlC0 TkKKTaLZiquluwjYWXzcFbkQ/A== X-Google-Smtp-Source: ABdhPJyBwBIRvIcq28MB98tASpBu8JrAk/Ww97FS+l9dyA2L7h41/yE8gDDdbl83I7oHUWvAFQgw3Q== X-Received: by 2002:a17:90b:4d0a:: with SMTP id mw10mr5675382pjb.89.1638447712913; Thu, 02 Dec 2021 04:21:52 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id m15sm3608894pfk.186.2021.12.02.04.21.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Dec 2021 04:21:52 -0800 (PST) From: Shawn Guo To: Marc Zyngier , Thomas Gleixner Cc: Maulik Shah , Bjorn Andersson , Loic Poulain , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v3 2/3] dt-bindings: interrupt-controller: Add Qualcomm MPM support Date: Thu, 2 Dec 2021 20:21:21 +0800 Message-Id: <20211202122122.23548-3-shawn.guo@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211202122122.23548-1-shawn.guo@linaro.org> References: <20211202122122.23548-1-shawn.guo@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org It adds DT binding support for Qualcomm MPM interrupt controller. Reviewed-by: Rob Herring Signed-off-by: Shawn Guo --- .../interrupt-controller/qcom,mpm.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml new file mode 100644 index 000000000000..22e87fe2eb8e --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/qcom,mpm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcom MPM Interrupt Controller + +maintainers: + - Shawn Guo + +description: + Qualcomm Technologies Inc. SoCs based on the RPM architecture have a + MSM Power Manager (MPM) that is in always-on domain. In addition to managing + resources during sleep, the hardware also has an interrupt controller that + monitors the interrupts when the system is asleep, wakes up the APSS when + one of these interrupts occur and replays it to GIC interrupt controller + after GIC becomes operational. + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +properties: + compatible: + items: + - const: qcom,qcm2290-mpm + + reg: + maxItems: 1 + description: + Specifies the base address and size of vMPM registers in RPM MSG RAM. + + interrupts: + maxItems: 1 + description: + Specify the IRQ used by RPM to wakeup APSS. + + mboxes: + maxItems: 1 + description: + Specify the mailbox used to notify RPM for writing vMPM registers. + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + description: + The first cell is the MPM pin number for the interrupt, and the second + is the trigger type. + +required: + - compatible + - reg + - interrupts + - mboxes + - interrupt-controller + - '#interrupt-cells' + +additionalProperties: false + +examples: + - | + #include + mpm: interrupt-controller@45f01b8 { + compatible = "qcom,qcm2290-mpm"; + interrupts = ; + reg = <0x45f01b8 0x1000>; + mboxes = <&apcs_glb 1>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + }; From patchwork Thu Dec 2 12:21:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Guo X-Patchwork-Id: 12652437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61F91C43217 for ; Thu, 2 Dec 2021 12:22:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358061AbhLBMZa (ORCPT ); Thu, 2 Dec 2021 07:25:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358208AbhLBMZS (ORCPT ); Thu, 2 Dec 2021 07:25:18 -0500 Received: from mail-pg1-x52f.google.com (mail-pg1-x52f.google.com [IPv6:2607:f8b0:4864:20::52f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 38EC6C061757 for ; Thu, 2 Dec 2021 04:21:56 -0800 (PST) Received: by mail-pg1-x52f.google.com with SMTP id 71so26868811pgb.4 for ; Thu, 02 Dec 2021 04:21:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=/6FhOx89QRBNuPh+FWrspQnEg8Nxq6jTr1Uu5b2NxbM=; b=ziCa9psd6biEDJqHLLpbbaldWDaaO6m7BdoKeb536rboFa5OPxOI9tjPiMnpprNRz7 IriE9R8DYLuFlGn81gbC7d9UIIIZsRL122ZeJqHWwULTB58BlemXOg+9Otna8jmhbvvt OjKksOjHWr46Wm2Ko4PHQBytZvHbpROO1kA9uxnyModVUx5YR4vttoSgy6TdTfixIOwN NLYe2TZD0AVgk2M98IoeZngz71axKZqsENnoQOpmockZLZiJy9nG8JY+XgZlQQC0Wz0n LcFiQstR5AhmeHjPXT57jb31/7KjQVlBwD/PaWfJbh4Cc7RIvpucI8KO63iw2dSRWLzE wF4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/6FhOx89QRBNuPh+FWrspQnEg8Nxq6jTr1Uu5b2NxbM=; b=I4HqD1WrfmnUlop+yvcLMCkOYX0iZbYMr4Hts7T0C8NyxzcbZabsVmeFkAlajEi9Q8 HYnRsKu5CEL7U1ggiCvFjuKhTRAv3U5QE3HLKDHWyj8qBdeNNhyDoMvE5UCK1ax0PyLN YvAWK+epzEvi5rhZMNT952MmrhGsCfCWDkVANer2e4ri4OVTMUQA4H0J4goB3FvZ6xJw ICsH1DdhkRbAvRrKV+S5LaarHmWOyNiB+v2yO6PhCM27SmUWHEGjPntLDKQngPlPlQk1 yfmZt8+SUI18KerxdBTu9bvkZyqmO+LHBCEt66wzRVr0lPGmqnfSrr2E8700HZtStzG7 zRPQ== X-Gm-Message-State: AOAM5300PJpxtsr+Nbv1UsJXafkNHjbgL9TQ2JurUnc/ihV/UexnKdRI kEG4/eR6h0MLPf5VD0RrrQWs6A== X-Google-Smtp-Source: ABdhPJwqVuDbCWlSmyU3BQLcE/AWRxIo3dNTfESxkuKgp878Gt2psPsgZVLa4h2fKBeQJzOx+2b3MQ== X-Received: by 2002:a63:da17:: with SMTP id c23mr9237788pgh.44.1638447715562; Thu, 02 Dec 2021 04:21:55 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id m15sm3608894pfk.186.2021.12.02.04.21.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Dec 2021 04:21:55 -0800 (PST) From: Shawn Guo To: Marc Zyngier , Thomas Gleixner Cc: Maulik Shah , Bjorn Andersson , Loic Poulain , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v3 3/3] irqchip: Add Qualcomm MPM controller driver Date: Thu, 2 Dec 2021 20:21:22 +0800 Message-Id: <20211202122122.23548-4-shawn.guo@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211202122122.23548-1-shawn.guo@linaro.org> References: <20211202122122.23548-1-shawn.guo@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Qualcomm SoCs based on the RPM architecture have a MSM Power Manager (MPM) in always-on domain. In addition to managing resources during sleep, the hardware also has an interrupt controller that monitors the interrupts when the system is asleep, wakes up the APSS when one of these interrupts occur and replays it to GIC after it becomes operational. It adds an irqchip driver for this interrupt controller, and here are some notes about it. - For given SoC, a fixed number of MPM pins are supported, e.g. 96 pins on QCM2290. Each of these MPM pins can be either a MPM_GIC pin or a MPM_GPIO pin. The mapping between MPM_GIC pin and GIC interrupt is defined by SoC, as well as the mapping between MPM_GPIO pin and GPIO number. The former mapping can be found as the SoC data in this MPM driver, while the latter can be found as the msm_gpio_wakeirq_map[] in TLMM driver. - All the register settings are done by APSS on an internal memory region called vMPM, and RPM will flush them into hardware after it receives a mailbox/IPC notification from APSS. - When SoC gets awake from sleep mode, the driver will receive an interrupt from RPM, so that it can replay interrupt for particular polarity. Signed-off-by: Shawn Guo Reported-by: kernel test robot --- drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/qcom-mpm.c | 481 +++++++++++++++++++++++++++++++++++++ 3 files changed, 490 insertions(+) create mode 100644 drivers/irqchip/qcom-mpm.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7038957f4a77..680d2fcf2686 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -430,6 +430,14 @@ config QCOM_PDC Power Domain Controller driver to manage and configure wakeup IRQs for Qualcomm Technologies Inc (QTI) mobile chips. +config QCOM_MPM + tristate "QCOM MPM" + depends on ARCH_QCOM + select IRQ_DOMAIN_HIERARCHY + help + MSM Power Manager driver to manage and configure wakeup + IRQs for Qualcomm Technologies Inc (QTI) mobile chips. + config CSKY_MPINTC bool depends on CSKY diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c1f611cbfbf8..0e2e10467e28 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o obj-$(CONFIG_NDS32) += irq-ativic32.o obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o +obj-$(CONFIG_QCOM_MPM) += qcom-mpm.o obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o diff --git a/drivers/irqchip/qcom-mpm.c b/drivers/irqchip/qcom-mpm.c new file mode 100644 index 000000000000..4a0dac2e2c6e --- /dev/null +++ b/drivers/irqchip/qcom-mpm.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, Linaro Limited + * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * vMPM register layout: + * + * 31 0 + * +--------------------------------+ + * | TIMER0 | 0x00 + * +--------------------------------+ + * | TIMER1 | 0x04 + * +--------------------------------+ + * | ENABLE0 | 0x08 + * +--------------------------------+ + * | ... | ... + * +--------------------------------+ + * | ENABLEn | + * +--------------------------------+ + * | FALLING_EDGE0 | + * +--------------------------------+ + * | ... | + * +--------------------------------+ + * | STATUSn | + * +--------------------------------+ + * + * n = DIV_ROUND_UP(pin_num, 32) + * + */ +#define MPM_REG_ENABLE 0 +#define MPM_REG_FALLING_EDGE 1 +#define MPM_REG_RISING_EDGE 2 +#define MPM_REG_POLARITY 3 +#define MPM_REG_STATUS 4 + +#define MPM_NO_PARENT_IRQ ~0UL + +/* MPM pin and its GIC hwirq */ +struct mpm_pin { + int pin; + irq_hw_number_t hwirq; +}; + +struct mpm_data { + unsigned int pin_num; + const struct mpm_pin *gic_pins; +}; + +struct qcom_mpm_priv { + void __iomem *base; + raw_spinlock_t lock; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + const struct mpm_data *data; + unsigned int reg_stride; + struct irq_domain *domain; + struct notifier_block pm_nb; + atomic_t cpus_in_pm; +}; + +static inline u32 +qcom_mpm_read(struct qcom_mpm_priv *priv, unsigned int reg, unsigned int index) +{ + unsigned int offset = (reg * priv->reg_stride + index + 2) * 4; + + return readl_relaxed(priv->base + offset); +} + +static inline void +qcom_mpm_write(struct qcom_mpm_priv *priv, unsigned int reg, + unsigned int index, u32 val) +{ + unsigned int offset = (reg * priv->reg_stride + index + 2) * 4; + + writel_relaxed(val, priv->base + offset); + + /* Ensure the write is completed */ + wmb(); +} + +static inline void qcom_mpm_enable_irq(struct irq_data *d, bool en) +{ + struct qcom_mpm_priv *priv = d->chip_data; + int pin = d->hwirq; + unsigned int index = pin / 32; + unsigned int shift = pin % 32; + u32 val; + + raw_spin_lock(&priv->lock); + + val = qcom_mpm_read(priv, MPM_REG_ENABLE, index); + if (en) + val |= BIT(shift); + else + val &= ~BIT(shift); + qcom_mpm_write(priv, MPM_REG_ENABLE, index, val); + + raw_spin_unlock(&priv->lock); +} + +static void qcom_mpm_mask(struct irq_data *d) +{ + qcom_mpm_enable_irq(d, false); + + if (d->parent_data) + irq_chip_mask_parent(d); +} + +static void qcom_mpm_unmask(struct irq_data *d) +{ + qcom_mpm_enable_irq(d, true); + + if (d->parent_data) + irq_chip_unmask_parent(d); +} + +static inline void +mpm_set_type(struct qcom_mpm_priv *priv, bool set, unsigned int reg, + unsigned int index, unsigned int shift) +{ + u32 val; + + raw_spin_lock(&priv->lock); + + val = qcom_mpm_read(priv, reg, index); + if (set) + val |= BIT(shift); + else + val &= ~BIT(shift); + qcom_mpm_write(priv, reg, index, val); + + raw_spin_unlock(&priv->lock); +} + +static int qcom_mpm_set_type(struct irq_data *d, unsigned int type) +{ + struct qcom_mpm_priv *priv = d->chip_data; + int pin = d->hwirq; + unsigned int index = pin / 32; + unsigned int shift = pin % 32; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + mpm_set_type(priv, !!(type & IRQ_TYPE_EDGE_RISING), + MPM_REG_RISING_EDGE, index, shift); + break; + case IRQ_TYPE_EDGE_FALLING: + mpm_set_type(priv, !!(type & IRQ_TYPE_EDGE_FALLING), + MPM_REG_FALLING_EDGE, index, shift); + break; + case IRQ_TYPE_LEVEL_HIGH: + mpm_set_type(priv, !!(type & IRQ_TYPE_LEVEL_HIGH), + MPM_REG_POLARITY, index, shift); + break; + } + + if (!d->parent_data) + return 0; + + if (type & IRQ_TYPE_EDGE_BOTH) + type = IRQ_TYPE_EDGE_RISING; + + if (type & IRQ_TYPE_LEVEL_MASK) + type = IRQ_TYPE_LEVEL_HIGH; + + return irq_chip_set_type_parent(d, type); +} + +static struct irq_chip qcom_mpm_chip = { + .name = "mpm", + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = qcom_mpm_mask, + .irq_unmask = qcom_mpm_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = qcom_mpm_set_type, + .irq_set_affinity = irq_chip_set_affinity_parent, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, +}; + +static irq_hw_number_t get_parent_hwirq(struct qcom_mpm_priv *priv, int pin) +{ + const struct mpm_pin *gic_pins = priv->data->gic_pins; + int i; + + for (i = 0; gic_pins[i].pin >= 0; i++) { + int p = gic_pins[i].pin; + + if (p < 0) + break; + + if (p == pin) + return gic_pins[i].hwirq; + } + + return MPM_NO_PARENT_IRQ; +} + +static int qcom_mpm_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct qcom_mpm_priv *priv = domain->host_data; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; + irq_hw_number_t parent_hwirq; + irq_hw_number_t hwirq; + unsigned int type; + int ret; + + ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &qcom_mpm_chip, priv); + if (ret) + return ret; + + parent_hwirq = get_parent_hwirq(priv, hwirq); + if (parent_hwirq == MPM_NO_PARENT_IRQ) + return irq_domain_disconnect_hierarchy(domain->parent, virq); + + if (type & IRQ_TYPE_EDGE_BOTH) + type = IRQ_TYPE_EDGE_RISING; + + if (type & IRQ_TYPE_LEVEL_MASK) + type = IRQ_TYPE_LEVEL_HIGH; + + parent_fwspec.fwnode = domain->parent->fwnode; + parent_fwspec.param_count = 3; + parent_fwspec.param[0] = 0; + parent_fwspec.param[1] = parent_hwirq; + parent_fwspec.param[2] = type; + + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); +} + +static const struct irq_domain_ops qcom_mpm_ops = { + .alloc = qcom_mpm_alloc, + .free = irq_domain_free_irqs_common, + .translate = irq_domain_translate_twocell, +}; + +/* Triggered by RPM when system resumes from deep sleep */ +static irqreturn_t qcom_mpm_handler(int irq, void *dev_id) +{ + struct qcom_mpm_priv *priv = dev_id; + unsigned long enable, pending; + int i, j; + + for (i = 0; i < priv->reg_stride; i++) { + enable = qcom_mpm_read(priv, MPM_REG_ENABLE, i); + pending = qcom_mpm_read(priv, MPM_REG_STATUS, i); + pending &= enable; + + for_each_set_bit(j, &pending, 32) { + unsigned int pin = 32 * i + j; + struct irq_desc *desc = + irq_resolve_mapping(priv->domain, pin); + struct irq_data *d = &desc->irq_data; + + if (!irqd_is_level_type(d)) + irq_set_irqchip_state(d->irq, + IRQCHIP_STATE_PENDING, true); + + } + } + + return IRQ_HANDLED; +} + +static int qcom_mpm_enter_sleep(struct qcom_mpm_priv *priv) +{ + int i, ret; + + for (i = 0; i < priv->reg_stride; i++) + qcom_mpm_write(priv, MPM_REG_STATUS, i, 0); + + /* Notify RPM to write vMPM into HW */ + ret = mbox_send_message(priv->mbox_chan, NULL); + if (ret < 0) + return ret; + + return 0; +} + +static int qcom_mpm_cpu_pm_callback(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct qcom_mpm_priv *priv = container_of(nb, struct qcom_mpm_priv, + pm_nb); + int ret = NOTIFY_OK; + int cpus_in_pm; + + switch (action) { + case CPU_PM_ENTER: + cpus_in_pm = atomic_inc_return(&priv->cpus_in_pm); + /* + * NOTE: comments for num_online_cpus() point out that it's + * only a snapshot so we need to be careful. It should be OK + * for us to use, though. It's important for us not to miss + * if we're the last CPU going down so it would only be a + * problem if a CPU went offline right after we did the check + * AND that CPU was not idle AND that CPU was the last non-idle + * CPU. That can't happen. CPUs would have to come out of idle + * before the CPU could go offline. + */ + if (cpus_in_pm < num_online_cpus()) + return NOTIFY_OK; + break; + case CPU_PM_ENTER_FAILED: + case CPU_PM_EXIT: + atomic_dec(&priv->cpus_in_pm); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } + + /* + * It's likely we're on the last CPU. Grab the lock and write MPM for + * sleep. Grabbing the lock means that if we race with another CPU + * coming up we are still guaranteed to be safe. + */ + if (raw_spin_trylock(&priv->lock)) { + if (qcom_mpm_enter_sleep(priv)) + ret = NOTIFY_BAD; + raw_spin_unlock(&priv->lock); + } else { + /* Another CPU must be up */ + return NOTIFY_OK; + } + + if (ret == NOTIFY_BAD) { + /* Double-check if we're here because someone else is up */ + if (cpus_in_pm < num_online_cpus()) + ret = NOTIFY_OK; + else + /* We won't be called w/ CPU_PM_ENTER_FAILED */ + atomic_dec(&priv->cpus_in_pm); + } + + return ret; +} + +static int qcom_mpm_init(struct platform_device *pdev, + struct device_node *parent, + const struct mpm_data *data) +{ + struct irq_domain *parent_domain; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct qcom_mpm_priv *priv; + unsigned int pin_num; + int irq; + int ret; + + if (!data) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = data; + pin_num = priv->data->pin_num; + priv->reg_stride = DIV_ROUND_UP(pin_num, 32); + + raw_spin_lock_init(&priv->lock); + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (!priv->base) + return PTR_ERR(priv->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + priv->mbox_client.dev = dev; + priv->mbox_chan = mbox_request_channel(&priv->mbox_client, 0); + if (IS_ERR(priv->mbox_chan)) { + ret = PTR_ERR(priv->mbox_chan); + dev_err(dev, "failed to acquire IPC channel: %d\n", ret); + return ret; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + dev_err(dev, "failed to find MPM parent domain\n"); + ret = -ENXIO; + goto free_mbox; + } + + priv->domain = irq_domain_create_hierarchy(parent_domain, + IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP, pin_num, + of_node_to_fwnode(np), &qcom_mpm_ops, priv); + if (!priv->domain) { + dev_err(dev, "failed to create MPM domain\n"); + ret = -ENOMEM; + goto free_mbox; + } + + irq_domain_update_bus_token(priv->domain, DOMAIN_BUS_WAKEUP); + + ret = devm_request_irq(dev, irq, qcom_mpm_handler, + IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, + "qcom_mpm", priv); + if (ret) { + dev_err(dev, "failed to request irq: %d\n", ret); + goto remove_domain; + } + + priv->pm_nb.notifier_call = qcom_mpm_cpu_pm_callback; + cpu_pm_register_notifier(&priv->pm_nb); + + dev_set_drvdata(dev, priv); + + return 0; + +remove_domain: + irq_domain_remove(priv->domain); +free_mbox: + mbox_free_channel(priv->mbox_chan); + return ret; +} + +/* + * The mapping between MPM_GIC pin and GIC SPI number on QCM2290. It's taken + * from downstream qcom-mpm-scuba.c with a little transform on the GIC + * SPI numbers (the second column). Due to the binding difference from + * the downstream, where GIC SPI numbering starts from 32, we expect the + * numbering starts from 0 here, and that's why we have the number minus 32 + * comparing to the downstream. + */ +const struct mpm_pin qcm2290_gic_pins[] = { + { 2, 275 }, /* tsens0_tsens_upper_lower_int */ + { 5, 296 }, /* lpass_irq_out_sdc */ + { 12, 422 }, /* b3_lfps_rxterm_irq */ + { 24, 79 }, /* bi_px_lpi_1_aoss_mx */ + { 86, 183 }, /* mpm_wake,spmi_m */ + { 90, 260 }, /* eud_p0_dpse_int_mx */ + { 91, 260 }, /* eud_p0_dmse_int_mx */ + { -1 }, +}; + +const struct mpm_data qcm2290_data = { + .pin_num = 96, + .gic_pins = qcm2290_gic_pins, +}; + +static int qcm2290_mpm_init(struct platform_device *pdev, + struct device_node *parent) +{ + return qcom_mpm_init(pdev, parent, &qcm2290_data); +} + +IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_mpm) +IRQCHIP_MATCH("qcom,qcm2290-mpm", qcm2290_mpm_init) +IRQCHIP_PLATFORM_DRIVER_END(qcom_mpm) +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Power Manager"); +MODULE_LICENSE("GPL v2");