From nobody Wed Jun 24 01:07:21 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 C35D5C4332F for ; Wed, 23 Feb 2022 12:57:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240688AbiBWM5o (ORCPT ); Wed, 23 Feb 2022 07:57:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51792 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240670AbiBWM5m (ORCPT ); Wed, 23 Feb 2022 07:57:42 -0500 Received: from mail-pf1-x42f.google.com (mail-pf1-x42f.google.com [IPv6:2607:f8b0:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E755F9FFE for ; Wed, 23 Feb 2022 04:57:13 -0800 (PST) Received: by mail-pf1-x42f.google.com with SMTP id d17so15273951pfl.0 for ; Wed, 23 Feb 2022 04:57:13 -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 :mime-version:content-transfer-encoding; bh=9zjHo6BnE+LkvSb3drhMyymhfgiGeZ2qxQyNQtjreqM=; b=CNsXNq6GX/7wV0tQQjbzBvUkFpuR3GUyUnpFx34jzgdd5Fca/MULlkHlNnop9BE1H7 UzYtJoh0fjmwrJ7nPJWqTsMnuA09heFJZcOadyMiQnz0YGRZ/cBWaupEglqNi+YebIfG bOd1OHuu0t0wZKKTgcbhFCjlTiEy7o0wednqgj1ST/w7M17cUKSSQXfRpvdVVuqub/Sb ulNUDwC7lxJ4ocr5GGvujco3nau+SVz1RFQkaiugxQQbQchtOTC8nzH541e/vEwwKtGS vxVgnoH3bg3IHWaZTegO5vsd79ctl9MSUb4ZNp5ritfSZ0gc+b4dzihzzT3qXH53GrdP zrzA== 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:mime-version:content-transfer-encoding; bh=9zjHo6BnE+LkvSb3drhMyymhfgiGeZ2qxQyNQtjreqM=; b=LhjNUzBzxNsx1kfu+LMoYfu+oUGfqRQ6It9XtxcrWp9TLEM608c4gAhWBy6XRsT7qw Wi+LmFVAzZFz5MPUtQsAhNDEBvFUm8knE2vNQWMFqIPEZ1FqIAg7RXRFIUD1SYDl8b5L qaKE9wGOZksQIvcNUZqPRzv6sqOEduIl5aV7+h4bjFm7GX29HrvAVfS0vYIBl+vK+Vt6 UnX37gw57zImr8wBrvFB5zbKgV0jY1lloXrncxUIrRWeHyf0DzbJSiMsrB3oeDmJ0ZqK rNjiZdgcTWAqmPZL8F1mbo344jbCA9e8jgwx6ARMTs3WVsXxqXFq8kWzlq369NfFzE1y I9UA== X-Gm-Message-State: AOAM533MYWQD+Y4iCZkEnKiYKiJVRaZiWFWgpCCX4HJWQ6MB3803xEjf coo/HO8QoNftD/KaDh72CBvB+A== X-Google-Smtp-Source: ABdhPJyfMBO4QcCVfia/BemnU75mzGDNEqqptHIs/x1P4e0kISqh/l1AoaX/wM3QNabCIVs7Kj+0QQ== X-Received: by 2002:a63:531d:0:b0:365:5f0c:7cbb with SMTP id h29-20020a63531d000000b003655f0c7cbbmr23503993pgb.150.1645621033463; Wed, 23 Feb 2022 04:57:13 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id z23sm22136243pfj.87.2022.02.23.04.57.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Feb 2022 04:57:12 -0800 (PST) From: Shawn Guo To: Marc Zyngier , "Rafael J . Wysocki" Cc: Valentin Schneider , Sebastian Andrzej Siewior , Thomas Gleixner , Maulik Shah , Bjorn Andersson , Sudeep Holla , Ulf Hansson , Daniel Lezcano , Rob Herring , devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v6 1/3] PM: cpu: Add CPU_LAST_PM_ENTER and CPU_FIRST_PM_EXIT support Date: Wed, 23 Feb 2022 20:55:34 +0800 Message-Id: <20220223125536.230224-2-shawn.guo@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220223125536.230224-1-shawn.guo@linaro.org> References: <20220223125536.230224-1-shawn.guo@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" It becomes a common situation on some platforms that certain hardware setup needs to be done on the last standing cpu, and rpmh-rsc[1] is such an existing example. As figuring out the last standing cpu is really something generic, it adds CPU_LAST_PM_ENTER (and CPU_FIRST_PM_EXIT) event support to cpu_pm helper, so that individual driver can be notified when the last standing cpu is about to enter low power state. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree= /drivers/soc/qcom/rpmh-rsc.c?id=3Dv5.16#n773 Signed-off-by: Shawn Guo --- include/linux/cpu_pm.h | 15 +++++++++++++++ kernel/cpu_pm.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/linux/cpu_pm.h b/include/linux/cpu_pm.h index 552b8f9ea05e..153344307b7c 100644 --- a/include/linux/cpu_pm.h +++ b/include/linux/cpu_pm.h @@ -55,6 +55,21 @@ enum cpu_pm_event { =20 /* A cpu power domain is exiting a low power state */ CPU_CLUSTER_PM_EXIT, + + /* + * A cpu is entering a low power state after all other cpus + * in the system have entered the lower power state. + */ + CPU_LAST_PM_ENTER, + + /* The last cpu failed to enter a low power state */ + CPU_LAST_PM_ENTER_FAILED, + + /* + * A cpu is exiting a low power state before any other cpus + * in the system exits the low power state. + */ + CPU_FIRST_PM_EXIT, }; =20 #ifdef CONFIG_CPU_PM diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c index 246efc74e3f3..7c104446e1e9 100644 --- a/kernel/cpu_pm.c +++ b/kernel/cpu_pm.c @@ -26,6 +26,8 @@ static struct { .lock =3D __RAW_SPIN_LOCK_UNLOCKED(cpu_pm_notifier.lock), }; =20 +static atomic_t cpus_in_pm; + static int cpu_pm_notify(enum cpu_pm_event event) { int ret; @@ -116,7 +118,20 @@ EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier); */ int cpu_pm_enter(void) { - return cpu_pm_notify_robust(CPU_PM_ENTER, CPU_PM_ENTER_FAILED); + int ret; + + ret =3D cpu_pm_notify_robust(CPU_PM_ENTER, CPU_PM_ENTER_FAILED); + if (ret) + return ret; + + if (atomic_inc_return(&cpus_in_pm) =3D=3D num_online_cpus()) { + ret =3D cpu_pm_notify_robust(CPU_LAST_PM_ENTER, + CPU_LAST_PM_ENTER_FAILED); + if (ret) + return ret; + } + + return 0; } EXPORT_SYMBOL_GPL(cpu_pm_enter); =20 @@ -134,7 +149,21 @@ EXPORT_SYMBOL_GPL(cpu_pm_enter); */ int cpu_pm_exit(void) { - return cpu_pm_notify(CPU_PM_EXIT); + int ret; + + ret =3D cpu_pm_notify(CPU_PM_EXIT); + if (ret) + return ret; + + if (atomic_read(&cpus_in_pm) =3D=3D num_online_cpus()) { + ret =3D cpu_pm_notify(CPU_FIRST_PM_EXIT); + if (ret) + return ret; + } + + atomic_dec(&cpus_in_pm); + + return 0; } EXPORT_SYMBOL_GPL(cpu_pm_exit); =20 --=20 2.25.1 From nobody Wed Jun 24 01:07:21 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 F228FC433FE for ; Wed, 23 Feb 2022 12:59:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237583AbiBWM7w (ORCPT ); Wed, 23 Feb 2022 07:59:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52680 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240714AbiBWM5y (ORCPT ); Wed, 23 Feb 2022 07:57:54 -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 0B7F8E094 for ; Wed, 23 Feb 2022 04:57:19 -0800 (PST) Received: by mail-pl1-x632.google.com with SMTP id e13so901267plh.3 for ; Wed, 23 Feb 2022 04:57:19 -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 :mime-version:content-transfer-encoding; bh=Gpyd4vP7EgbsF/QazldQl0vAIMM6wCSjCpTQL1+8JT0=; b=E7V2nNWC+ebjB9OizOIDqcJ2x3xgHFzfgiXjJr0YRjP3kTrq96iaiKBZgb5Rm4X3EN Pd1am9duErfEAzbCmSx6GPhkF/wOey1bLlYOcFy3iEzJhRyhSXFAbSk5qm4C4KY7fAZq t2TMDuWRZMjJE6+VwbOPLG7LHh9WmoX5R3PNVRS/MrJskCHz51cL+fNZgWpH0GHbQAYv el1PzdOJO3UIcaGqNmOIphcffgw2JDQbhax52uO/5+IfD8/5HBwBFERuX2q252M2Zc/Y WVNePkii7LexIgRlSs9PWW4VSfDw9p04LbmeOV3iT0f1G6P7jTmPf0EHoWfAb6Dqf6Yo WRlw== 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:mime-version:content-transfer-encoding; bh=Gpyd4vP7EgbsF/QazldQl0vAIMM6wCSjCpTQL1+8JT0=; b=xN9P+bNunvmFYM4oG9rwnVkkrLlnQLTzV8E/Q/xlqrVaD4NOX9IUb66pnWcMiqbEiM cIAqaNXC5+w41t69NKNwziCOcsTBSmapwo26VQWZsV3ysbA8nCcApb3gSqliF4ygX/FD H4fK/qvnhmyVvBeu49tM28NCm1wbfdDFdkdhTk8kSnGhQ9vPp749l1ghxJnaxcPgTZyq /R3kL5L1xUUQV+aEbpEWE4Q3Bnha7E8giIeUGyVk/p8EjsY9PwZPNYDfRPcAjsPtIJCN SPE+NRwRT2LdjOyt+ELoGiloNdO/zvjczfoecUOAkwfZ+Ang+s/E02T5TJmVHSVN6K7d /p2A== X-Gm-Message-State: AOAM533DVFqgDrA5sqv0T3tYJ69t+YXoI84wglRc5I9WgwCl+Aqg4GUm fc+jLlf4kLKLroDi/IqdXtGKKw== X-Google-Smtp-Source: ABdhPJx6n9/CeWhHPrqJMfspDzJDPCGI1x0rvizUiWRysgrWf99/an1PBiJeX235MOAA0OC8/dgMPQ== X-Received: by 2002:a17:902:db04:b0:14c:f43b:e9df with SMTP id m4-20020a170902db0400b0014cf43be9dfmr27648150plx.76.1645621038420; Wed, 23 Feb 2022 04:57:18 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id z23sm22136243pfj.87.2022.02.23.04.57.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Feb 2022 04:57:17 -0800 (PST) From: Shawn Guo To: Marc Zyngier , "Rafael J . Wysocki" Cc: Valentin Schneider , Sebastian Andrzej Siewior , Thomas Gleixner , Maulik Shah , Bjorn Andersson , Sudeep Holla , Ulf Hansson , Daniel Lezcano , Rob Herring , devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo , Rob Herring Subject: [PATCH v6 2/3] dt-bindings: interrupt-controller: Add Qualcomm MPM support Date: Wed, 23 Feb 2022 20:55:35 +0800 Message-Id: <20220223125536.230224-3-shawn.guo@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220223125536.230224-1-shawn.guo@linaro.org> References: <20220223125536.230224-1-shawn.guo@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 | 96 +++++++++++++++++++ 1 file changed, 96 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..509d20c091af --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml @@ -0,0 +1,96 @@ +# 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: + description: + Specify the total MPM pin count that a SoC supports. + $ref: /schemas/types.yaml#/definitions/uint32 + + qcom,mpm-pin-map: + description: + A set of MPM pin numbers and the corresponding GIC SPIs. + $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,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.25.1 From nobody Wed Jun 24 01:07:21 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 AEDD6C433FE for ; Wed, 23 Feb 2022 12:57:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240731AbiBWM6N (ORCPT ); Wed, 23 Feb 2022 07:58:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52682 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240733AbiBWM55 (ORCPT ); Wed, 23 Feb 2022 07:57:57 -0500 Received: from mail-pg1-x529.google.com (mail-pg1-x529.google.com [IPv6:2607:f8b0:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16C0512A9E for ; Wed, 23 Feb 2022 04:57:24 -0800 (PST) Received: by mail-pg1-x529.google.com with SMTP id p23so19858678pgj.2 for ; Wed, 23 Feb 2022 04:57:24 -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 :mime-version:content-transfer-encoding; bh=K7Rr8/niGD4rtxLI5fSjQGfLtd7shjRvWSJcdBvDXf0=; b=OmW04qAeKTLK5gNfn+UMQOr6ani9SvibaggC2RhCbuJVbgWiZf8MtlvXa5U/qyKb2l DluXRDFPAAyG/eFlQZF29kuHl3X0NqvTwSJcbY+BnhLPHQUoCwlqBsrfhrWaIoOMokIL EMHvhaFHHZXfawbbvi3D1CQjhY/5gb/mmHU+Tlaetb9HmBrXGFyOhZZzWAXTPiVGepBZ 8iTGRcmZEWAjwjGAhrkaHIB+AZvM6Hd9QqDQlJxIvWP+jbu5nJz5yb5ywAUJjgTzBsWW Zvd+vT77az1Q9sfvQLy2vWX4vCqqxMcs9Yad8nwf3EJO8Ol1L3YpfHPLtpEiJGJ8XahV 6+xw== 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:mime-version:content-transfer-encoding; bh=K7Rr8/niGD4rtxLI5fSjQGfLtd7shjRvWSJcdBvDXf0=; b=xb0dOCjFHMd3ZfZmn7T2A1us4eLQYQX9jRO9PjpA7Q3K6eYUzpw2ES5BK5WaVj7g8s LwUWZ0ZvNdoP8W2/QVv7XOJbYz5miyyKBM1nV30gwV7ltzYq9z7ZyKfcnGhFJ5mugRRY Ddxu1jFZdpK+ZG9eBUqcqP/lL68JNvcnqqPtAgCSIp9VruaagFC9F++VfzXYac3M3qtD 6yuUMMxNL5WVReMBG8Z8NDggq8PHkZgJyqqF9ss1G1LH2xRd9pch0zwNz6N8rqPzEWdb rvrkqIQeRuIhg6ZnYlCRWBCUJlb9zsJfxJDvEgesyqUN5UJa4SaC7qJXVM5QmunqEPXN 4K3g== X-Gm-Message-State: AOAM531IVWveqdKHMwmCMy+XNoP1CUdzH0EWrZv+wVZe+5bf0z1htJM/ kuL7evSbOOHfzhXo7KlY36m8CzPtKC4Ppg== X-Google-Smtp-Source: ABdhPJy8radjQVdI9VlARhq2fTMR7N1XkSupEcw3vOErOyPzl6FDeQbZtIYj21PaXYURbcGpraoq2A== X-Received: by 2002:a62:7c11:0:b0:4e1:7ede:9ca9 with SMTP id x17-20020a627c11000000b004e17ede9ca9mr29669069pfc.84.1645621043429; Wed, 23 Feb 2022 04:57:23 -0800 (PST) Received: from localhost.localdomain (80.251.214.228.16clouds.com. [80.251.214.228]) by smtp.gmail.com with ESMTPSA id z23sm22136243pfj.87.2022.02.23.04.57.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Feb 2022 04:57:22 -0800 (PST) From: Shawn Guo To: Marc Zyngier , "Rafael J . Wysocki" Cc: Valentin Schneider , Sebastian Andrzej Siewior , Thomas Gleixner , Maulik Shah , Bjorn Andersson , Sudeep Holla , Ulf Hansson , Daniel Lezcano , Rob Herring , devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Shawn Guo Subject: [PATCH v6 3/3] irqchip: Add Qualcomm MPM controller driver Date: Wed, 23 Feb 2022 20:55:36 +0800 Message-Id: <20220223125536.230224-4-shawn.guo@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220223125536.230224-1-shawn.guo@linaro.org> References: <20220223125536.230224-1-shawn.guo@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 a couple of 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. - 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 | 439 +++++++++++++++++++++++++++++++++++++ 3 files changed, 448 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..8e142873a99a --- /dev/null +++ b/drivers/irqchip/qcom-mpm.c @@ -0,0 +1,439 @@ +// 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 + +/* 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, +}; + +struct mpm_gic_map *get_mpm_gic_map(struct qcom_mpm_priv *priv, int pin) +{ + 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]; + } + + return NULL; +} + +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; + struct mpm_gic_map *map; + 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; + + map =3D get_mpm_gic_map(priv, hwirq); + if (map =3D=3D NULL) + 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 map->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; + irqreturn_t ret =3D IRQ_NONE; + unsigned long flags; + int i, j; + + for (i =3D 0; i < priv->reg_stride; i++) { + raw_spin_lock_irqsave(&priv->lock, flags); + enable =3D qcom_mpm_read(priv, MPM_REG_ENABLE, i); + pending =3D qcom_mpm_read(priv, MPM_REG_STATUS, i); + pending &=3D enable; + raw_spin_unlock_irqrestore(&priv->lock, flags); + + 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); + ret =3D IRQ_HANDLED; + } + } + + return ret; +} + +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_LAST_PM_ENTER: + if (qcom_mpm_enter_sleep(priv)) + ret =3D NOTIFY_BAD; + break; + default: + ret =3D 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_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); + + 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.25.1