From nobody Sun Jun 28 01:53:00 2026 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 95C2EC433F5 for ; Wed, 16 Feb 2022 13:28:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234309AbiBPN3E (ORCPT ); Wed, 16 Feb 2022 08:29:04 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:40914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234271AbiBPN27 (ORCPT ); Wed, 16 Feb 2022 08:28:59 -0500 Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10B791617E9 for ; Wed, 16 Feb 2022 05:28:48 -0800 (PST) Received: by mail-pf1-x430.google.com with SMTP id m22so2135334pfk.6 for ; Wed, 16 Feb 2022 05:28:48 -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=tARKrBf1+k+dk/y0+eGi6r+ZGZ/s9sGusak1bxU9rx0=; b=oRw5uoFIqszci3wJHVQoWSoHtxxhw/jfozwwgNBoAf3OTNakOtzqcGrCGDVTHnUgkM N9Ndz4eyrd6HVSaYr6A2ACuAEE3gfehc94fg9N61NXaX+mY6/x/pAAHqsKxTkP1vRr/B uMCluwzs38WJ4CfvRxF/Ee7iwMKVgHRmo4/JZf1LXcrnlVJLjqAgO4xTAcxymbRbFZtX abE7w6tzpHrvIjDIypQ8F1vcs3bIIF6+rsQdGbEh/vHUXNwv+JwRH3JQwG+MvVpP4/2h oJpU9kuF24noUO3pz8X/w7wfP2ryEHQW2g6PzD3y4n1Im7/4ihhhFQl8dLSDnpbNv3R6 QdHg== 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=tARKrBf1+k+dk/y0+eGi6r+ZGZ/s9sGusak1bxU9rx0=; b=f7xUq1T2fTCo06ZHPwpssvbvqK+cWb4SBAL8+dAbMytWcdsS44CjTVL2vLkJXY5Lwf rmVqCucDi5f3xJlsO+B+E4TucmvgsBe0DGltG369+tT+ss8edjJUmH4EIgX0wIN86c4v 1yEumTyAIYzHMakSymizHP/sa2g8m91oaUv3HekDO1LK+36p4Mvb1sNR0T0uxzAVhZjP el/nHzQDqXHhcqeo3ZvZP80Pxhfe+C4K3c5VJfEWCTo1FL73XvK1zL8RRVJwU/yhuAq7 1VA5WJ2FvHhl6sv1u/++8aoTcIRmo/RgrCfmO89ul+Ud/RbABDwXzc8gDKuF2H/XWCCQ M36Q== X-Gm-Message-State: AOAM530JtDLL9jWHWHvc7GvmofQDKQlbutUjbFgcYeq/tjxzFbPQtn17 n9L7hQQe1IL/5GDVzD7sa8VABw== X-Google-Smtp-Source: ABdhPJyUj+cZ79J/hrnelkzMVbiRfVIKVORSOhLePrdr/bNGnZcJycwgs1WIkvH0TS5BMaRztDoeWA== X-Received: by 2002:a63:215a:0:b0:372:9d20:5146 with SMTP id s26-20020a63215a000000b003729d205146mr2275147pgm.419.1645018127625; Wed, 16 Feb 2022 05:28:47 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id c68sm5431002pga.1.2022.02.16.05.28.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:28:47 -0800 (PST) From: Shawn Guo To: Marc Zyngier , Thomas Gleixner Cc: Maulik Shah , Bjorn Andersson , Lorenzo Pieralisi , Sudeep Holla , "Rafael J . Wysocki" , Daniel Lezcano , Rob Herring , devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v5 1/3] cpuidle: psci: Call cpu_cluster_pm_enter() on the last CPU Date: Wed, 16 Feb 2022 21:28:28 +0800 Message-Id: <20220216132830.32490-2-shawn.guo@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220216132830.32490-1-shawn.guo@linaro.org> References: <20220216132830.32490-1-shawn.guo@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Make a call to cpu_cluster_pm_enter() on the last CPU going to low power state (and cpu_cluster_pm_exit() on the firt CPU coming back), so that platforms can be notified to set up hardware for getting into the cluster low power state. Signed-off-by: Shawn Guo --- drivers/cpuidle/cpuidle-psci.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c index b51b5df08450..c748c1a7d7b1 100644 --- a/drivers/cpuidle/cpuidle-psci.c +++ b/drivers/cpuidle/cpuidle-psci.c @@ -37,6 +37,7 @@ struct psci_cpuidle_data { static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_d= ata); static DEFINE_PER_CPU(u32, domain_state); static bool psci_cpuidle_use_cpuhp; +static atomic_t cpus_in_idle; =20 void psci_set_domain_state(u32 state) { @@ -67,6 +68,14 @@ static int __psci_enter_domain_idle_state(struct cpuidle= _device *dev, if (ret) return -1; =20 + if (atomic_inc_return(&cpus_in_idle) =3D=3D num_online_cpus()) { + ret =3D cpu_cluster_pm_enter(); + if (ret) { + ret =3D -1; + goto dec_atomic; + } + } + /* Do runtime PM to manage a hierarchical CPU toplogy. */ rcu_irq_enter_irqson(); if (s2idle) @@ -88,6 +97,10 @@ static int __psci_enter_domain_idle_state(struct cpuidle= _device *dev, pm_runtime_get_sync(pd_dev); rcu_irq_exit_irqson(); =20 + if (atomic_read(&cpus_in_idle) =3D=3D num_online_cpus()) + cpu_cluster_pm_exit(); +dec_atomic: + atomic_dec(&cpus_in_idle); cpu_pm_exit(); =20 /* Clear the domain state to start fresh when back from idle. */ --=20 2.17.1 From nobody Sun Jun 28 01:53:00 2026 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 D5402C433EF for ; Wed, 16 Feb 2022 13:28:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234312AbiBPN3I (ORCPT ); Wed, 16 Feb 2022 08:29:08 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234267AbiBPN3F (ORCPT ); Wed, 16 Feb 2022 08:29:05 -0500 Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4A76516FDFF for ; Wed, 16 Feb 2022 05:28:52 -0800 (PST) Received: by mail-pl1-x632.google.com with SMTP id x4so2007562plb.4 for ; Wed, 16 Feb 2022 05:28:52 -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=s464YmEOgKVNHNX8tgctZT1MC7zN2ZI9MvD5gSlTKx8=; b=YLFDwiFsjtKH7a7ZWqkAAN4KsvB0qTzPFRfwq5p8SyLzZGdXctS/CwZkY6HaKtzGYP oqGphKYMIXVtLY72kHqaharaHRlaT7QWfm0cnRTl6RZP4J0VBTgotNX+j6F6i3QT1egR c0vYmpbmI9TTAlUwL42vjEB4Dg02gNkRRdtFwM7CA+VmtKOHFTOOMAI1vDXAmLQj0jIP QxiZXpY7ss20HdlSCff4g2GVc/HbSO7OlDewVKixYeLuQw5pi5jTaVEnCyqAuCczdbFJ 9TEUrmjcy/K30hwwEfZavOzbUgBZDPT+4L0ih71a61mZ/7ZxChYBGkEtI6yaIlAu3gzJ 9jkA== 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=s464YmEOgKVNHNX8tgctZT1MC7zN2ZI9MvD5gSlTKx8=; b=5DO+ez1uEhYlsZu3whjy2EMIkTH2O24wRG/V+jJmb83aWCJGpXenSIOE2h6Uj8WXOZ fqXUbAk2XB2Mva+OO7dWHLH2djL+iHoTTLCBZKjqWP9oD+D3NoMgG5PIYKsiJaNk6Ksh b06QBtmJ7Sb7Z1MCdKg2bsuG9uiIsHmZXXDKx2BoBr2agak9kbu+9SwfDjFLX4oiohIW a17Tlw+uaT4BVzzNVgTgRRc21r+ln4aa65nVLUNV7cT6Lz+qIQAlcSlbp7uNKjss8U2J SMQrsIqDBme6Zu7GyNtRaOinigewb7Klj5HJDMcF+AQJDDk6ZJBGbMgWV7jDFCFs54/d 7EaA== X-Gm-Message-State: AOAM531AoG71EmqrYJ1LZwT3pwg6ZuBNT1+2Py5JsaPFmGXaLSq9HT07 eSc2sok0zofzLyXNKGbiJYNhgg== X-Google-Smtp-Source: ABdhPJwZmzNMm/k6458FVvrVppd4t3q3/HGHH66dyyOJy1MNWV6JUNUNlZWKnwQrOGYxiXhxRw7Flw== X-Received: by 2002:a17:90a:a795:b0:1b9:2f9a:c049 with SMTP id f21-20020a17090aa79500b001b92f9ac049mr1759543pjq.240.1645018131712; Wed, 16 Feb 2022 05:28:51 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id c68sm5431002pga.1.2022.02.16.05.28.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:28:50 -0800 (PST) From: Shawn Guo To: Marc Zyngier , Thomas Gleixner Cc: Maulik Shah , Bjorn Andersson , Lorenzo Pieralisi , Sudeep Holla , "Rafael J . Wysocki" , Daniel Lezcano , Rob Herring , devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v5 2/3] dt-bindings: interrupt-controller: Add Qualcomm MPM support Date: Wed, 16 Feb 2022 21:28:29 +0800 Message-Id: <20220216132830.32490-3-shawn.guo@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220216132830.32490-1-shawn.guo@linaro.org> References: <20220216132830.32490-1-shawn.guo@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" It adds DT binding support for Qualcomm MPM interrupt controller. Reviewed-by: Rob Herring Signed-off-by: Shawn Guo --- .../interrupt-controller/qcom,mpm.yaml | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/= qcom,mpm.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,mp= m.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.ya= ml new file mode 100644 index 000000000000..374ef155f45c --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml @@ -0,0 +1,94 @@ +# 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 mana= ging + resources during sleep, the hardware also has an interrupt controller th= at + 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,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 seco= nd + is the trigger type. + + qcom,mpm-pin-count: + maxItems: 1 + description: + Specify the total MPM pin count that a SoC supports. + + qcom,mpm-pin-map: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: MPM pin number + - description: GIC SPI number for the MPM pin + +required: + - compatible + - reg + - interrupts + - mboxes + - interrupt-controller + - '#interrupt-cells' + - qcom,mpm-pin-count + - qcom,mpm-pin-map + +additionalProperties: false + +examples: + - | + #include + mpm: interrupt-controller@45f01b8 { + compatible =3D "qcom,qcm2290-mpm"; + interrupts =3D ; + reg =3D <0x45f01b8 0x1000>; + mboxes =3D <&apcs_glb 1>; + interrupt-controller; + #interrupt-cells =3D <2>; + interrupt-parent =3D <&intc>; + qcom,mpm-pin-count =3D <96>; + qcom,mpm-pin-map =3D <2 275>, + <5 296>, + <12 422>, + <24 79>, + <86 183>, + <90 260>, + <91 260>; + }; --=20 2.17.1 From nobody Sun Jun 28 01:53:00 2026 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 824F2C433EF for ; Wed, 16 Feb 2022 13:29:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233836AbiBPN3U (ORCPT ); Wed, 16 Feb 2022 08:29:20 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41454 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234330AbiBPN3M (ORCPT ); Wed, 16 Feb 2022 08:29:12 -0500 Received: from mail-pg1-x532.google.com (mail-pg1-x532.google.com [IPv6:2607:f8b0:4864:20::532]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D574F16EAA1 for ; Wed, 16 Feb 2022 05:28:56 -0800 (PST) Received: by mail-pg1-x532.google.com with SMTP id q132so2156446pgq.7 for ; Wed, 16 Feb 2022 05:28: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=Pkf5RyRv4TjCa25aN4iJ4g0kpEYRhMD0UlbOP1N34aQ=; b=S/R7ZLX+/SEvS5gX/f//zqWXoQ95QPioA3BIbOQfLAX0ArRH+8eQXwMeomcsdNiSJc CLyu/Kg7cssWUwXwe9CYE3MyczPj1WRLo1odDdpXbz2w4RpxBT9o6+HB94kEkYumz8bN 71T+EoMmFMd8cdyLqSLgr5et5qfQf4SMhb/TPhFJXE01JPGHNk9Nm1gEpEXZdw/lsmco 5i49xoIH+yJ26G91g6YL8HMGiVBTfltyHdDzYUMYwHDFZBVKy2NtZiae3dMBx154RN3D NiBgA/xrSqqfASQj6tTZ+mPRvObIEW7INhyJLKajCwYIOKLRbjC3VkmdkMc9S9qZM/tJ I/Jg== 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=Pkf5RyRv4TjCa25aN4iJ4g0kpEYRhMD0UlbOP1N34aQ=; b=Tilacr6up0rMjV5zurtl0iLyRhcFeZhsSGRHnPohNH+6VSe4UZlfFrSGUEZrAx6lIo 7kxUECnb1PSn9jXYlFB+s8tZkbJToCVz+lV33vdwxz9tTvUqag87sUvAxYUFdeExzK7Q FoIO0gZRPax3jsJNk28U5JJ9sR7+F7TRX0hXtXlRsokPfAnliLN60uIH/wBCpKlskmr3 ZRiGSJ369C/rFzUTxr8QucRHUetPz1RoDrBo6vDNyPpmannQp1jLzaOeX+/OyuXL8TzF txj1Ol6Gk/0SuyKLfpc5bKd0Gn82AqQ5C3Vkk2JPhTTSriQYDVpN8kjcvP82cdaeLQV7 g6Sw== X-Gm-Message-State: AOAM532CtcqJ4jxzIlfLUs/KKbBk8b/yAkjP2gkVFavckdXg6sXSTVQz a6AqM76Ocb8g54O8TdFxDWeAxA== X-Google-Smtp-Source: ABdhPJwjYBUeM0PLRh0MzFdrZ5T0u8MNxcL8h/Vuf50NYcrBrBhiesUQGJBjCbiwXH8ScJBa7PQs6g== X-Received: by 2002:a05:6a02:18b:b0:362:c8e4:d8f4 with SMTP id bj11-20020a056a02018b00b00362c8e4d8f4mr2311019pgb.86.1645018135992; Wed, 16 Feb 2022 05:28:55 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id c68sm5431002pga.1.2022.02.16.05.28.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:28:55 -0800 (PST) From: Shawn Guo To: Marc Zyngier , Thomas Gleixner Cc: Maulik Shah , Bjorn Andersson , Lorenzo Pieralisi , Sudeep Holla , "Rafael J . Wysocki" , Daniel Lezcano , Rob Herring , devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v5 3/3] irqchip: Add Qualcomm MPM controller driver Date: Wed, 16 Feb 2022 21:28:30 +0800 Message-Id: <20220216132830.32490-4-shawn.guo@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220216132830.32490-1-shawn.guo@linaro.org> References: <20220216132830.32490-1-shawn.guo@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 is retrieved from device tree, while the latter is defined in TLMM pinctrl driver. - Different from vendor driver that handles MPM_GIC and MPM_GPIO pin with separate irq_domain (and irq_chip), it handles both with a single irq_domain, and distinguishes them by checking parent IRQ, since only MPM_GIC pin has a parent GIC SPI number. - 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 --- drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/qcom-mpm.c | 440 +++++++++++++++++++++++++++++++++++++ 3 files changed, 449 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. =20 +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) +=3D irq-meson-gpio.o obj-$(CONFIG_GOLDFISH_PIC) +=3D irq-goldfish-pic.o obj-$(CONFIG_NDS32) +=3D irq-ativic32.o obj-$(CONFIG_QCOM_PDC) +=3D qcom-pdc.o +obj-$(CONFIG_QCOM_MPM) +=3D qcom-mpm.o obj-$(CONFIG_CSKY_MPINTC) +=3D irq-csky-mpintc.o obj-$(CONFIG_CSKY_APB_INTC) +=3D irq-csky-apb-intc.o obj-$(CONFIG_RISCV_INTC) +=3D irq-riscv-intc.o diff --git a/drivers/irqchip/qcom-mpm.c b/drivers/irqchip/qcom-mpm.c new file mode 100644 index 000000000000..06c2ed14635f --- /dev/null +++ b/drivers/irqchip/qcom-mpm.c @@ -0,0 +1,440 @@ +// 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 + +/* + * This is the driver for Qualcomm MPM (MSM Power Manager) interrupt contr= oller, + * which is commonly found on Qualcomm SoCs built on the RPM architecture. + * Sitting in always-on domain, MPM monitors the wakeup interrupts when So= C is + * asleep, and wakes up the AP when one of those interrupts occurs. This = driver + * doesn't directly access physical MPM registers though. Instead, the ac= cess + * is bridged via a piece of internal memory (SRAM) that is accessible to = both + * AP and RPM. This piece of memory is called 'vMPM' in the driver. + * + * When SoC is awake, the vMPM is owned by AP and the register setup by th= is + * driver all happens on vMPM. When AP is about to get power collapsed, t= he + * driver sends a mailbox notification to RPM, which will take over the vM= PM + * ownership and dump vMPM into physical MPM registers. On wakeup, AP is = woken + * up by a MPM pin/interrupt, and RPM will copy STATUS registers into vMPM. + * Then AP start owning vMPM again. + * + * vMPM register map: + * + * 31 0 + * +--------------------------------+ + * | TIMER0 | 0x00 + * +--------------------------------+ + * | TIMER1 | 0x04 + * +--------------------------------+ + * | ENABLE0 | 0x08 + * +--------------------------------+ + * | ... | ... + * +--------------------------------+ + * | ENABLEn | + * +--------------------------------+ + * | FALLING_EDGE0 | + * +--------------------------------+ + * | ... | + * +--------------------------------+ + * | STATUSn | + * +--------------------------------+ + * + * n =3D DIV_ROUND_UP(pin_cnt, 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 map to GIC hwirq */ +struct mpm_gic_map { + int pin; + irq_hw_number_t hwirq; +}; + +struct qcom_mpm_priv { + void __iomem *base; + raw_spinlock_t lock; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct mpm_gic_map *maps; + unsigned int map_cnt; + unsigned int reg_stride; + struct irq_domain *domain; + struct notifier_block pm_nb; +}; + +static u32 qcom_mpm_read(struct qcom_mpm_priv *priv, unsigned int reg, + unsigned int index) +{ + unsigned int offset =3D (reg * priv->reg_stride + index + 2) * 4; + + return readl_relaxed(priv->base + offset); +} + +static void qcom_mpm_write(struct qcom_mpm_priv *priv, unsigned int reg, + unsigned int index, u32 val) +{ + unsigned int offset =3D (reg * priv->reg_stride + index + 2) * 4; + + writel_relaxed(val, priv->base + offset); + + /* Ensure the write is completed */ + wmb(); +} + +static void qcom_mpm_enable_irq(struct irq_data *d, bool en) +{ + struct qcom_mpm_priv *priv =3D d->chip_data; + int pin =3D d->hwirq; + unsigned int index =3D pin / 32; + unsigned int shift =3D pin % 32; + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&priv->lock, flags); + + val =3D qcom_mpm_read(priv, MPM_REG_ENABLE, index); + if (en) + val |=3D BIT(shift); + else + val &=3D ~BIT(shift); + qcom_mpm_write(priv, MPM_REG_ENABLE, index, val); + + raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +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 void mpm_set_type(struct qcom_mpm_priv *priv, bool set, unsigned in= t reg, + unsigned int index, unsigned int shift) +{ + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&priv->lock, flags); + + val =3D qcom_mpm_read(priv, reg, index); + if (set) + val |=3D BIT(shift); + else + val &=3D ~BIT(shift); + qcom_mpm_write(priv, reg, index, val); + + raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +static int qcom_mpm_set_type(struct irq_data *d, unsigned int type) +{ + struct qcom_mpm_priv *priv =3D d->chip_data; + int pin =3D d->hwirq; + unsigned int index =3D pin / 32; + unsigned int shift =3D 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 =3D IRQ_TYPE_EDGE_RISING; + + if (type & IRQ_TYPE_LEVEL_MASK) + type =3D IRQ_TYPE_LEVEL_HIGH; + + return irq_chip_set_type_parent(d, type); +} + +static struct irq_chip qcom_mpm_chip =3D { + .name =3D "mpm", + .irq_eoi =3D irq_chip_eoi_parent, + .irq_mask =3D qcom_mpm_mask, + .irq_unmask =3D qcom_mpm_unmask, + .irq_retrigger =3D irq_chip_retrigger_hierarchy, + .irq_set_type =3D qcom_mpm_set_type, + .irq_set_affinity =3D irq_chip_set_affinity_parent, + .flags =3D IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, +}; + +static irq_hw_number_t get_parent_hwirq(struct qcom_mpm_priv *priv, int pi= n) +{ + const struct mpm_gic_map *maps =3D priv->maps; + int i; + + for (i =3D 0; i < priv->map_cnt; i++) { + if (maps[i].pin =3D=3D pin) + return maps[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 =3D domain->host_data; + struct irq_fwspec *fwspec =3D data; + struct irq_fwspec parent_fwspec; + irq_hw_number_t parent_hwirq; + irq_hw_number_t hwirq; + unsigned int type; + int ret; + + ret =3D irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + ret =3D irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &qcom_mpm_chip, priv); + if (ret) + return ret; + + parent_hwirq =3D get_parent_hwirq(priv, hwirq); + if (parent_hwirq =3D=3D MPM_NO_PARENT_IRQ) + return irq_domain_disconnect_hierarchy(domain->parent, virq); + + if (type & IRQ_TYPE_EDGE_BOTH) + type =3D IRQ_TYPE_EDGE_RISING; + + if (type & IRQ_TYPE_LEVEL_MASK) + type =3D IRQ_TYPE_LEVEL_HIGH; + + parent_fwspec.fwnode =3D domain->parent->fwnode; + parent_fwspec.param_count =3D 3; + parent_fwspec.param[0] =3D 0; + parent_fwspec.param[1] =3D parent_hwirq; + parent_fwspec.param[2] =3D type; + + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); +} + +static const struct irq_domain_ops qcom_mpm_ops =3D { + .alloc =3D qcom_mpm_alloc, + .free =3D irq_domain_free_irqs_common, + .translate =3D 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 =3D dev_id; + unsigned long enable, pending; + int i, j; + + for (i =3D 0; i < priv->reg_stride; i++) { + enable =3D qcom_mpm_read(priv, MPM_REG_ENABLE, i); + pending =3D qcom_mpm_read(priv, MPM_REG_STATUS, i); + pending &=3D enable; + + for_each_set_bit(j, &pending, 32) { + unsigned int pin =3D 32 * i + j; + struct irq_desc *desc =3D irq_resolve_mapping(priv->domain, pin); + struct irq_data *d =3D &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 =3D 0; i < priv->reg_stride; i++) + qcom_mpm_write(priv, MPM_REG_STATUS, i, 0); + + /* Notify RPM to write vMPM into HW */ + ret =3D 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 =3D container_of(nb, struct qcom_mpm_priv, + pm_nb); + int ret =3D NOTIFY_OK; + + switch (action) { + case CPU_CLUSTER_PM_ENTER: + if (qcom_mpm_enter_sleep(priv)) + ret =3D NOTIFY_BAD; + break; + default: + return NOTIFY_DONE; + } + + return ret; +} + +static int qcom_mpm_init(struct device_node *np, struct device_node *paren= t) +{ + struct platform_device *pdev =3D of_find_device_by_node(np); + struct device *dev =3D &pdev->dev; + struct irq_domain *parent_domain; + struct qcom_mpm_priv *priv; + unsigned int pin_cnt; + int i, irq; + int ret; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ret =3D of_property_read_u32(np, "qcom,mpm-pin-count", &pin_cnt); + if (ret) { + dev_err(dev, "failed to read qcom,mpm-pin-count: %d\n", ret); + return ret; + } + + priv->reg_stride =3D DIV_ROUND_UP(pin_cnt, 32); + + ret =3D of_property_count_u32_elems(np, "qcom,mpm-pin-map"); + if (ret < 0) { + dev_err(dev, "failed to read qcom,mpm-pin-map: %d\n", ret); + return ret; + } + + if (ret % 2) { + dev_err(dev, "invalid qcom,mpm-pin-map\n"); + return -EINVAL; + } + + priv->map_cnt =3D ret / 2; + priv->maps =3D devm_kcalloc(dev, priv->map_cnt, sizeof(*priv->maps), + GFP_KERNEL); + if (!priv->maps) + return -ENOMEM; + + for (i =3D 0; i < priv->map_cnt; i++) { + of_property_read_u32_index(np, "qcom,mpm-pin-map", i * 2, + &priv->maps[i].pin); + of_property_read_u32_index(np, "qcom,mpm-pin-map", i * 2 + 1, + (u32 *) &priv->maps[i].hwirq); + } + + raw_spin_lock_init(&priv->lock); + + priv->base =3D devm_platform_ioremap_resource(pdev, 0); + if (!priv->base) + return PTR_ERR(priv->base); + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + priv->mbox_client.dev =3D dev; + priv->mbox_chan =3D mbox_request_channel(&priv->mbox_client, 0); + if (IS_ERR(priv->mbox_chan)) { + ret =3D PTR_ERR(priv->mbox_chan); + dev_err(dev, "failed to acquire IPC channel: %d\n", ret); + return ret; + } + + parent_domain =3D irq_find_host(parent); + if (!parent_domain) { + dev_err(dev, "failed to find MPM parent domain\n"); + ret =3D -ENXIO; + goto free_mbox; + } + + priv->domain =3D irq_domain_create_hierarchy(parent_domain, + IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP, pin_cnt, + of_node_to_fwnode(np), &qcom_mpm_ops, priv); + if (!priv->domain) { + dev_err(dev, "failed to create MPM domain\n"); + ret =3D -ENOMEM; + goto free_mbox; + } + + irq_domain_update_bus_token(priv->domain, DOMAIN_BUS_WAKEUP); + + ret =3D 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 =3D 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; +} + +IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_mpm) +IRQCHIP_MATCH("qcom,mpm", qcom_mpm_init) +IRQCHIP_PLATFORM_DRIVER_END(qcom_mpm) +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Power Manager"); +MODULE_LICENSE("GPL v2"); --=20 2.17.1