From patchwork Tue Jul 23 11:27:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conor Dooley X-Patchwork-Id: 814046 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 524E8150984; Tue, 23 Jul 2024 11:28:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734108; cv=none; b=HyyitoCzTJsojspzhq96AiBeKHSAjHxJbcDRTkCrNP9B4Y8F7eapygQ57vNCqvVDAah5/v5SfYPvG6A+C8jBo8zGAp8EEi6kEYimGQ1xWUDAc9kvNeEY+7X8BBGBvFj/kLQaPe8XrLXM5cj9+NDow93cLwsZDvDwvfOd+UFAHbI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734108; c=relaxed/simple; bh=BY9RX9OmhdiwEixbfaIsfq/KameCCnfNFWrW+iwHgQc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rlFG9GmIOGLCST8klsXf9Dylz/5t1xZnbwR9uBQ7exjtrXsdEweYi3iZIKTjHoZ8Aiy3jXhkyPVon+RHLJol7JAkvljHUPpXc+uEm/mlCQJU7/19sR52yTdfIsWsxsZ855gvYVHAdA5PTzJQfgjcxKhqr0bUSboC6UDOA1OPR/M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=YZfqZm7Y; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="YZfqZm7Y" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1721734108; x=1753270108; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BY9RX9OmhdiwEixbfaIsfq/KameCCnfNFWrW+iwHgQc=; b=YZfqZm7YqfvoHtEFk+NcrHJW58dSBq3veWZaPF0Yufuwr66DAgG9nMEZ 9qQ8GPF74gMBZDAyigUM0RfD8DQ+k4G/KHklngGKMucuCY+50UKtGvx+2 RXE/gbGoLXllz3HFAfnnN1BQ4mjsycBdKFIuO3QCAFm5LYwx2i5HFHek6 KBjE9QYLutccK68w8TVsy96Mp56sk3sC4+mdDKRhruf8nvZhchs+pP0HT NxKRf8e6AZq/OARuLKZPZPnT7SXiHl6YbGZLaQqIkJhKi6lSn3i+pbgFb vwBf62TRpn/IZ6s3h+BB3FoCYmhErgjyud9IDNe+CR3HP8RZoNr3Zpknx A==; X-CSE-ConnectionGUID: S6DrTYNTSQStcH62wvxgTw== X-CSE-MsgGUID: jdFJGOP4SlSGNjM3ngZfIA== X-IronPort-AV: E=Sophos;i="6.09,230,1716274800"; d="scan'208";a="29574952" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Jul 2024 04:28:19 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Tue, 23 Jul 2024 04:28:02 -0700 Received: from wendy.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Tue, 23 Jul 2024 04:28:00 -0700 From: Conor Dooley To: CC: , , Marc Zyngier , Daire McNamara , "Linus Walleij" , Bartosz Golaszewski , "Rob Herring" , Krzysztof Kozlowski , "Thomas Gleixner" , Paul Walmsley , Palmer Dabbelt , , , Subject: [RFC v7 1/6] dt-bindings: gpio: fix microchip,mpfs-gpio interrupt descriptions Date: Tue, 23 Jul 2024 12:27:10 +0100 Message-ID: <20240723-trash-issuing-e2bdd55b764e@wendy> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240723-supervise-drown-d5d3b303e7fd@wendy> References: <20240723-supervise-drown-d5d3b303e7fd@wendy> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3445; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=BY9RX9OmhdiwEixbfaIsfq/KameCCnfNFWrW+iwHgQc=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGnzJ/cH1BazWMXpyim07n7hOkPoNHPk80lTHsj7HORz/Txn X3pfRykLgxgHg6yYIkvi7b4WqfV/XHY497yFmcPKBDKEgYtTACZydQ8jw5opU+9Y9M4u2LPv/8//zt 80r9z9cjhU3Vbv4iozjXpb8xsM//Qm2gm97fJ0+PxJ7UaT+zEJtsfXr+wySp17hnG/9710TSYA X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C The microchip,mpfs-gpio binding suffered greatly due to being written with a narrow minded view of the controller, and the interrupt bits ended up incorrect. It was mistakenly assumed that the interrupt configuration was set by platform firmware, based on the FPGA configuration, and that the GPIO DT nodes were the only way to really communicate interrupt configuration to software. Instead, the mux should be a device in its own right, and the GPIO controllers should be connected to it, rather than to the PLIC. Now that a binding exists for that mux, try to fix the misconceptions in the GPIO controller binding. Firstly, it's not possible for this controller to have fewer than 14 GPIOs, and thus 14 interrupts also. There are three controllers, with 14, 24 & 32 GPIOs each. The example is wacky too - it follows from the incorrect understanding that the GPIO controllers are connected to the PLIC directly. They are not however, with a mux sitting in between. Update the example to use the mux as a parent, and the interrupt numbers at the mux for GPIO2 as the example - rather than the strange looking, repeated <53>. Signed-off-by: Conor Dooley Reviewed-by: Krzysztof Kozlowski --- .../bindings/gpio/microchip,mpfs-gpio.yaml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/microchip,mpfs-gpio.yaml b/Documentation/devicetree/bindings/gpio/microchip,mpfs-gpio.yaml index d61569b3f15b2..eb7dbf1668285 100644 --- a/Documentation/devicetree/bindings/gpio/microchip,mpfs-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/microchip,mpfs-gpio.yaml @@ -22,7 +22,7 @@ properties: interrupts: description: Interrupt mapping, one per GPIO. Maximum 32 GPIOs. - minItems: 1 + minItems: 14 maxItems: 32 interrupt-controller: true @@ -39,9 +39,7 @@ properties: ngpios: description: The number of GPIOs available. - minimum: 1 - maximum: 32 - default: 32 + enum: [14, 24, 32] gpio-controller: true gpio-line-names: true @@ -81,6 +79,7 @@ required: - reg - "#gpio-cells" - gpio-controller + - ngpios - clocks additionalProperties: false @@ -91,18 +90,19 @@ examples: compatible = "microchip,mpfs-gpio"; reg = <0x20122000 0x1000>; clocks = <&clkcfg 25>; - interrupt-parent = <&plic>; + interrupt-parent = <&irqmux>; gpio-controller; #gpio-cells = <2>; + ngpios = <32>; interrupt-controller; - #interrupt-cells = <1>; - interrupts = <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>; + #interrupt-cells = <2>; + interrupts = <64>, <65>, <66>, <67>, + <68>, <69>, <70>, <71>, + <72>, <73>, <74>, <75>, + <76>, <77>, <78>, <79>, + <80>, <81>, <82>, <83>, + <84>, <85>, <86>, <87>, + <88>, <89>, <90>, <91>, + <92>, <93>, <94>, <95>; }; ... From patchwork Tue Jul 23 11:27:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conor Dooley X-Patchwork-Id: 814478 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3AB21509AC; Tue, 23 Jul 2024 11:28:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734109; cv=none; b=AF5KL1mEazwnQPKPKsX+NZ5rApllXHzdi9tU6RjOhR2hvaOPFeLKj+EoV0HUjvuOmk7gBuMK7on9MT0iwP6XC3VTeJ5CjHvROr2frJWrNIOtMp2T4B6XkZDh2oELG36UcgXiTVWLGJbC0zpFZjYHp/CtZy6H0PWsd0t2hB109NU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734109; c=relaxed/simple; bh=6aVvjVowW9Wu+EIEcex8bxj0klOHutOMqoPmSgWOOqw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NfT1Cy8gfxr8tXxertQXlkgvze2x/GnHyaNbCApPGeMIvYHEvStGFrn/7hO7F3cGsnAPxYQyvFVYzG04gd0Au+Wm36TV8ydN9QdmjeF/JIW31nBv35IvOG4oveQ/3gRXFO9NEGSX4M2rcHqOtNH/xxdDX2++yTrkPkgXBT77x40= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=njvcZ3Jv; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="njvcZ3Jv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1721734108; x=1753270108; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6aVvjVowW9Wu+EIEcex8bxj0klOHutOMqoPmSgWOOqw=; b=njvcZ3JveoGN0esFYNM2GgthPmWZ5wapA4wxtzZ9LkrlEb9ozEB0vQFE KdtojCQid7SUiDhONXIcqIW2uebeEWoe++VbjKNDVAi0kjCXoTIR2Aj8K xIaT846vTI575X/WlrMf6TxvzNxpWgB2SL5G02525sfvNQhRJNyXgMJx2 ny4PCWMp97GeoY2gi9or3yB7fErAYOAEWsWcRgtc5NFOM4Xzd1FAlvSig ZFw4oqiX8IUkwW+rRof/Xs+swdxPZicU8iDonDCnFdFSM5mjQHn7QelYe A/GlFN4P5Upo78CJ7SJkM1giaoYaZMgAMVpbxa/wSZ/WGtf1C9984ivue A==; X-CSE-ConnectionGUID: S6DrTYNTSQStcH62wvxgTw== X-CSE-MsgGUID: Oc+XHPzzQEGWFtnBlzp9Bg== X-IronPort-AV: E=Sophos;i="6.09,230,1716274800"; d="scan'208";a="29574953" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Jul 2024 04:28:19 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Tue, 23 Jul 2024 04:28:09 -0700 Received: from wendy.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Tue, 23 Jul 2024 04:28:06 -0700 From: Conor Dooley To: CC: , , Marc Zyngier , Daire McNamara , "Linus Walleij" , Bartosz Golaszewski , "Rob Herring" , Krzysztof Kozlowski , "Thomas Gleixner" , Paul Walmsley , Palmer Dabbelt , , , Subject: [RFC v7 2/6] dt-bindings: interrupt-controller: document PolarFire SoC's gpio interrupt mux Date: Tue, 23 Jul 2024 12:27:11 +0100 Message-ID: <20240723-uncouple-enforcer-7c48e4a4fefe@wendy> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240723-supervise-drown-d5d3b303e7fd@wendy> References: <20240723-supervise-drown-d5d3b303e7fd@wendy> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3570; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=6aVvjVowW9Wu+EIEcex8bxj0klOHutOMqoPmSgWOOqw=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGnzJ/fvPrujVDn3ikZUmUtEaYLhwiYpk0t3l5+crHYgY5vF kpxDHaUsDGIcDLJiiiyJt/tapNb/cdnh3PMWZg4rE8gQBi5OAZiIOCfDX/mTgiFaXoHfTtVwTftw3f vEqgXved/r/tBkPM8pHCy7kYXhf6TmyUvzXJ2iP/0XkWHd6y55TPLv87iVNS+0r3JPO3CjgQUA X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C On PolarFire SoC there are more GPIO interrupts than there are interrupt lines available on the PLIC, and a runtime configurable mux is used to decide which interrupts are assigned direct connections to the PLIC & which are relegated to sharing a line. This mux is, in our reference configuration, written by platform firmware during boot based on the FPGA's configuration. Signed-off-by: Conor Dooley --- .../microchip,mpfs-gpio-irq-mux.yaml | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/microchip,mpfs-gpio-irq-mux.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/microchip,mpfs-gpio-irq-mux.yaml b/Documentation/devicetree/bindings/interrupt-controller/microchip,mpfs-gpio-irq-mux.yaml new file mode 100644 index 0000000000000..89ed3a630eef3 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/microchip,mpfs-gpio-irq-mux.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/microchip,mpfs-gpio-irq-mux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip Polarfire SoC GPIO Interrupt Mux + +maintainers: + - Conor Dooley + +description: | + There are 3 GPIO controllers on this SoC, of which: + - GPIO controller 0 has 14 GPIOs + - GPIO controller 1 has 24 GPIOs + - GPIO controller 2 has 32 GPIOs + + All GPIOs are capable of generating interrupts, for a total of 70. + There are only 41 IRQs available however, so a configurable mux is used to + ensure all GPIOs can be used for interrupt generation. + 38 of the 41 interrupts are in what the documentation calls "direct mode", + as they provide an exclusive connection from a GPIO to the PLIC. + The 3 remaining interrupts are used to mux the interrupts which do not have + a exclusive connection, one for each GPIO controller. + +properties: + compatible: + const: microchip,mpfs-gpio-irq-mux + + reg: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 1 + + interrupts: + description: + The first 38 entries must be the "direct" interrupts, for exclusive + connections to the PLIC. The final 3 entries must be the + "non-direct"/muxed connections for each of GPIO controller 0, 1 & 2 + respectively. + maxItems: 41 + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +required: + - compatible + - reg + - interrupts + - "#interrupt-cells" + - interrupt-controller + +additionalProperties: false + +examples: + - | + irqmux: interrupt-controller@20002054 { + compatible = "microchip,mpfs-gpio-irq-mux"; + reg = <0x20002054 0x4>; + interrupt-parent = <&plic>; + interrupt-controller; + #interrupt-cells = <1>; + status = "okay"; + interrupts = <13>, <14>, <15>, <16>, + <17>, <18>, <19>, <20>, + <21>, <22>, <23>, <24>, + <25>, <26>, <27>, <28>, + <29>, <30>, <31>, <32>, + <33>, <34>, <35>, <36>, + <37>, <38>, <39>, <40>, + <41>, <42>, <43>, <44>, + <45>, <46>, <47>, <48>, + <49>, <50>, <51>, <52>, + <53>; + }; +... From patchwork Tue Jul 23 11:27:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conor Dooley X-Patchwork-Id: 814045 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C1B01514D0; Tue, 23 Jul 2024 11:28:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734111; cv=none; b=YlbByaesTomaRrrMSf8/yDn5ZP2gbubBb/mvFMLWah46tTXWh1pt/kvdMu1qp4FL87LVfZmCIbdm9uJ1xeRjdW/ABrT0kOfB9l34EtIhDPm82bzrUE1xLcWbAkTkUC4bF9SWpnqF5DKnRJwpkTuhPP1apdHVXRwLtq2QN72FvPU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734111; c=relaxed/simple; bh=CsrygMY0NxxMA3gHMzButnMVxrGDWdwJPdZ6u63oMS8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DuV4xqF8Mpf9ixFlWP/fCMnz5o0v31Ewy5+6NEzhtXxIEonZRa6OEvSkhJrQSFUBj6YtvDOklq3ogHo4KfI/wTSXlOHltOiBcxj5glLt9IQYFdazIlHaO9GKIVPGKSPzFtHbuGqtvEGC8+t9l5opiC99HBDfu0/TuwcF/1dOE2Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=w+FX9vVl; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="w+FX9vVl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1721734110; x=1753270110; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CsrygMY0NxxMA3gHMzButnMVxrGDWdwJPdZ6u63oMS8=; b=w+FX9vVluU9p8OaQydUUxuYho9naRY2ogPwR4UcWsDxw2KyY2958J/Rt RiWpdROFyWl1+u1u6QhgCPm9WEpDWvcXuOS3Gpc1VoJSiuzNA6SZCpRDh SpYz7IFLi6AlmVwTVb2ElzViOKZ83h986WsaqhfoA2a/pKiyXxkFEwyt1 IvuerPyAibvyin2wq7Y01CzbQfPlkb7cfRVNkJRx0yMrNmtddSbP6WjR9 eun0Y9SgaD3Hvh/DiVKCwSPFMJM+UkRgx7DGrcHC0DB4tugGzkTRA+UUY Ol0K55Ld+5unrQGhTlbKm9Px0nNfy8DfCf3NHS9tLo72lIf93RX5/E23j w==; X-CSE-ConnectionGUID: S6DrTYNTSQStcH62wvxgTw== X-CSE-MsgGUID: 5nh63x7SS/qg7QgYEfGAKA== X-IronPort-AV: E=Sophos;i="6.09,230,1716274800"; d="scan'208";a="29574955" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Jul 2024 04:28:20 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Tue, 23 Jul 2024 04:28:13 -0700 Received: from wendy.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Tue, 23 Jul 2024 04:28:10 -0700 From: Conor Dooley To: CC: , , Marc Zyngier , Daire McNamara , "Linus Walleij" , Bartosz Golaszewski , "Rob Herring" , Krzysztof Kozlowski , "Thomas Gleixner" , Paul Walmsley , Palmer Dabbelt , , , Subject: [RFC v7 3/6] irqchip: add mpfs gpio interrupt mux Date: Tue, 23 Jul 2024 12:27:12 +0100 Message-ID: <20240723-flatworm-cornflake-8023212f6584@wendy> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240723-supervise-drown-d5d3b303e7fd@wendy> References: <20240723-supervise-drown-d5d3b303e7fd@wendy> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=13683; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=CsrygMY0NxxMA3gHMzButnMVxrGDWdwJPdZ6u63oMS8=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGnzJ0/YdyXK+qTsivLef7LOVlJsNb2rrFV43p+9eHz+jFOu AbJVHaUsDGIcDLJiiiyJt/tapNb/cdnh3PMWZg4rE8gQBi5OAZhIrCfD/0p7+UzGbL7y+Au1m9YdK+ 94PEstYPl6n3nd8YXHdEVtpzMybBbw2f6JZcrnRx/n/HKdfnQHr3SZ1gmTmVMbi2/I2jHmswAA X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C On PolarFire SoC there are more GPIO interrupts than there are interrupt lines available on the PLIC, and a runtime configurable mux is used to decide which interrupts are assigned direct connections to the PLIC & which are relegated to sharing a line. This mux is, in our reference configuration, written by platform firmware during boot based on the FPGA's configuration. Add a driver so that Linux can figure out this mapping and correctly map the GPIO interrupts to their parents on the PLIC. Signed-off-by: Conor Dooley --- Please read my cover letter for the things I'm unsure of on the interrupt side. --- drivers/irqchip/Kconfig | 11 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-mpfs-mux.c | 333 +++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/irqchip/irq-mpfs-mux.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 14464716bacbb..2b951dbd559c7 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -706,6 +706,17 @@ config MCHP_EIC help Support for Microchip External Interrupt Controller. +config POLARFIRE_SOC_IRQ_MUX + bool "Microchip PolarFire SoC's GPIO IRQ Mux" + depends on ARCH_MICROCHIP_POLARFIRE + default y + help + Support for the interrupt mux on Polarfire SoC. It sits between + the GPIO controllers and the PLIC, as only 35 interrupts are shared + between 3 GPIO controllers with 32 interrupts each. Configuration of + the mux is done by the platform firmware, this driver is responsible + for reading that configuration and setting up correct routing. + config SUNPLUS_SP7021_INTC bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST default SOC_SP7021 diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index d9dc3d99aaa86..cf2f417c8d7fc 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -123,4 +123,5 @@ obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o +obj-$(CONFIG_POLARFIRE_SOC_IRQ_MUX) += irq-mpfs-mux.o obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o diff --git a/drivers/irqchip/irq-mpfs-mux.c b/drivers/irqchip/irq-mpfs-mux.c new file mode 100644 index 0000000000000..b093cae399700 --- /dev/null +++ b/drivers/irqchip/irq-mpfs-mux.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip PolarFire SoC (MPFS) GPIO IRQ MUX + * + * Author: Conor Dooley + */ + +#define pr_fmt(fmt) "mpfs-irq-mux: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPFS_MUX_NUM_IRQS 41 +#define MPFS_MUX_NUM_DIRECT_IRQS 38 +#define MPFS_MUX_NUM_NON_DIRECT_IRQS 3 +#define MPFS_MAX_IRQS_PER_GPIO 32 +#define MPFS_NUM_IRQS_GPIO0 14 +#define MPFS_NUM_IRQS_GPIO1 24 +#define MPFS_NUM_IRQS_GPIO2 32 +#define MPFS_NUM_IRQS_GPIO02_SHIFT 0 +#define MPFS_NUM_IRQS_GPIO1_SHIFT 14 + +/* + * There are 3 GPIO controllers on this SoC, of which: + * - GPIO controller 0 has 14 GPIOs + * - GPIO controller 1 has 24 GPIOs + * - GPIO controller 2 has 32 GPIOs + * + * All GPIOs are capable of generating interrupts, for a total of 70. + * There are only 41 IRQs available however, so a configurable mux is used to + * ensure all GPIOs can be used for interrupt generation. + * 38 of the 41 interrupts are in what the documentation calls "direct mode", + * as they provide an exclusive connection from a GPIO to the PLIC. + * The 3 remaining interrupts are used to mux the interrupts which do not have + * a exclusive connection, one for each GPIO controller. + * A register is used to set this configuration of this mux, depending on how + * the "MSS Configurator" (FPGA configuration tool) has set things up. + * This is done by the platform's firmware, so access from Linux is read-only. + * + * Documentation also refers to GPIO controller 0 & 1 as "pad" GPIO controllers + * and GPIO controller 2 as the "fabric" GPIO controller. Despite that wording, + * all 3 are "hard" peripherals. + * + * The mux has a single register, where bits 0 to 13 mux between GPIO controller + * 1's 14 GPIOs and GPIO controller 2's first 14 GPIOs. The remaining bits mux + * between the first 18 GPIOs of controller 1 and the last 18 GPIOS of + * controller 2. If a bit in the mux's control register is set, the + * corresponding interrupt line for GPIO controller 0 or 1 will be put in + * "non-direct" mode. If cleared, the "fabric" controller's will. + * + * Register layout: + * GPIO 1 interrupt line 17 | mux bit 31 | GPIO 2 interrupt line 31 + * ... | ... | ... + * ... | ... | ... + * GPIO 1 interrupt line 0 | mux bit 14 | GPIO 2 interrupt line 14 + * GPIO 0 interrupt line 13 | mux bit 13 | GPIO 2 interrupt line 13 + * ... | ... | ... + * ... | ... | ... + * GPIO 0 interrupt line 0 | mux bit 0 | GPIO 2 interrupt line 0 + * + * That leaves 6 exclusive, or "direct", interrupts remaining. These are + * used by GPIO controller 1's lines 18 to 23. + */ + +struct mpfs_irq_mux_bank_config { + u32 mask; + u8 shift; +}; + +static const struct mpfs_irq_mux_bank_config mpfs_irq_mux_bank_configs[3] = { + {GENMASK(MPFS_NUM_IRQS_GPIO0 - 1, 0), MPFS_NUM_IRQS_GPIO02_SHIFT}, + {GENMASK(MPFS_NUM_IRQS_GPIO1 - 1, 0), MPFS_NUM_IRQS_GPIO1_SHIFT}, + {GENMASK(MPFS_NUM_IRQS_GPIO2 - 1, 0), MPFS_NUM_IRQS_GPIO02_SHIFT}, +}; + +struct mpfs_irq_mux_irqchip { + struct irq_domain *domain; + int bank; + int irq; + u8 offset; +}; + +struct mpfs_irq_mux { + void __iomem *reg; + u32 mux_config; + struct mpfs_irq_mux_irqchip nondirect_irqchips[MPFS_MUX_NUM_NON_DIRECT_IRQS]; + int parent_irqs[MPFS_MUX_NUM_DIRECT_IRQS]; +}; + +/* + * There is no "control" hardware in this mux, and as such there is no ability + * to mask at this level. As the irq has been disconnected from the hierarchy, + * there's no parent irqchip from which to use mask functions either. + */ +static void mpfs_irq_mux_irq_mask(struct irq_data *d) {} +static void mpfs_irq_mux_irq_unmask(struct irq_data *d) {} + +static struct irq_chip mpfs_irq_mux_nondirect_irq_chip = { + .name = "MPFS GPIO Interrupt Mux", + .irq_mask = mpfs_irq_mux_irq_mask, + .irq_unmask = mpfs_irq_mux_irq_unmask, + .flags = IRQCHIP_IMMUTABLE, +}; + +static struct irq_chip mpfs_irq_mux_irq_chip = { + .name = "MPFS GPIO Interrupt Mux", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, + .flags = IRQCHIP_IMMUTABLE, +}; + +/* + * Returns an unsigned long, where a set bit indicates the corresponding + * interrupt is in non-direct/muxed mode for that bank/GPIO controller. + */ +static inline unsigned long mpfs_irq_mux_get_muxed_irqs(struct mpfs_irq_mux *priv, + unsigned int bank) +{ + unsigned long mux_config = priv->mux_config, muxed_irqs = -1; + struct mpfs_irq_mux_bank_config bank_config = mpfs_irq_mux_bank_configs[bank]; + + /* + * If a bit is set in the mux, GPIO the corresponding interrupt from + * controller 2 is direct and that controllers 0 or 1 is muxed. + * Invert the bits in the configuration register, so that set bits + * equate to non-direct mode, for GPIO controller 2. + */ + if (bank == 2u) + mux_config = ~mux_config; + + muxed_irqs &= bank_config.mask; + muxed_irqs &= mux_config >> bank_config.shift; + + return muxed_irqs; +} + +static void mpfs_irq_mux_nondirect_handler(struct irq_desc *desc) +{ + struct mpfs_irq_mux_irqchip *irqchip_data = irq_desc_get_handler_data(desc); + struct mpfs_irq_mux *priv = container_of(irqchip_data, struct mpfs_irq_mux, + nondirect_irqchips[irqchip_data->bank]); + unsigned long muxed_irqs; + int pos; + + chained_irq_enter(irq_desc_get_chip(desc), desc); + + muxed_irqs = mpfs_irq_mux_get_muxed_irqs(priv, irqchip_data->bank); + + for_each_set_bit(pos, &muxed_irqs, MPFS_MAX_IRQS_PER_GPIO) + generic_handle_domain_irq(irqchip_data->domain, irqchip_data->offset + pos); + + chained_irq_exit(irq_desc_get_chip(desc), desc); +} + +static bool mpfs_irq_mux_is_direct(struct mpfs_irq_mux *priv, struct irq_fwspec *fwspec) +{ + unsigned int bank, line; + u32 muxed_irqs; + + bank = fwspec->param[0] / MPFS_MAX_IRQS_PER_GPIO; + line = fwspec->param[0] % MPFS_MAX_IRQS_PER_GPIO; + + muxed_irqs = mpfs_irq_mux_get_muxed_irqs(priv, bank); + + if (BIT(line) & muxed_irqs) + return false; + + return true; +} + +static int mpfs_irq_mux_translate(struct irq_domain *d, struct irq_fwspec *fwspec, + unsigned long *out_hwirq, unsigned int *out_type) +{ + if (!is_of_node(fwspec->fwnode)) + return -EINVAL; + + return irq_domain_translate_onecell(d, fwspec, out_hwirq, out_type); +} + +static int mpfs_irq_mux_nondirect_alloc(struct irq_domain *d, unsigned int virq, + struct irq_fwspec *fwspec, struct mpfs_irq_mux *priv) +{ + unsigned int bank = fwspec->param[0] / MPFS_MAX_IRQS_PER_GPIO; + + if (bank > 2) + return -EINVAL; + + priv->nondirect_irqchips[bank].domain = d; + + irq_domain_set_hwirq_and_chip(d, virq, fwspec->param[0], + &mpfs_irq_mux_nondirect_irq_chip, priv); + irq_set_chained_handler_and_data(virq, handle_untracked_irq, + &priv->nondirect_irqchips[bank]); + + return irq_domain_disconnect_hierarchy(d->parent, virq); +} + +static int mpfs_irq_mux_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct mpfs_irq_mux *priv = d->host_data; + struct irq_fwspec *fwspec = arg; + struct irq_fwspec parent_fwspec; + unsigned int bank, line, irq; + + if (!mpfs_irq_mux_is_direct(priv, fwspec)) + return mpfs_irq_mux_nondirect_alloc(d, virq, fwspec, priv); + + bank = fwspec->param[0] / MPFS_MAX_IRQS_PER_GPIO; + line = fwspec->param[0] % MPFS_MAX_IRQS_PER_GPIO; + irq = line + mpfs_irq_mux_bank_configs[bank].shift; + + parent_fwspec.fwnode = d->parent->fwnode; + parent_fwspec.param[0] = priv->parent_irqs[irq]; + parent_fwspec.param_count = 1; + + irq_domain_set_hwirq_and_chip(d, virq, fwspec->param[0], &mpfs_irq_mux_irq_chip, priv); + + return irq_domain_alloc_irqs_parent(d, virq, 1, &parent_fwspec); +} + +static const struct irq_domain_ops mpfs_irq_mux_domain_ops = { + .translate = mpfs_irq_mux_translate, + .alloc = mpfs_irq_mux_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int mpfs_irq_mux_probe(struct platform_device *pdev) +{ + struct device_node *node, *parent; + struct device *dev = &pdev->dev; + struct mpfs_irq_mux *priv; + struct irq_domain *hier_domain, *parent_domain; + int i, ret = 0; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* + * This is clearly unacceptable - there's a significant re-write of + * the devicetree handling for this device required however to get + * rid of this. It'll be fixed for !RFC. + */ + node = to_of_node(dev->fwnode); + priv->reg = of_iomap(node, 0); + if (!priv->reg) { + ret = -ENODEV; + goto out_free_priv; + } + + priv->mux_config = readl(priv->reg); + + for (i = 0; i < MPFS_MUX_NUM_DIRECT_IRQS; i++) { + struct of_phandle_args parent_irq; + int ret; + + ret = of_irq_parse_one(node, i, &parent_irq); + if (ret) { + ret = -ENODEV; + goto out_unmap; + } + + /* + * The parent irqs are saved off for the first 38 interrupts + * from the devicetree entry so that they can be used in the + * domains alloc callback to allocate irqs from the parent irq + * chip directly. + */ + priv->parent_irqs[i] = parent_irq.args[0]; + } + + parent = of_irq_find_parent(node); + parent_domain = irq_find_host(parent); + hier_domain = irq_domain_add_hierarchy(parent_domain, 0, MPFS_MAX_IRQS_PER_GPIO * 3, + node, &mpfs_irq_mux_domain_ops, priv); + if (!hier_domain) { + dev_err(dev, "failed to add hierarchical domain\n"); + ret = -ENODEV; + goto out_unmap; + } + + /* + * The last 3 interrupts must be the non-direct/muxed ones, per + * the dt-binding. + */ + for (i = 0; i < MPFS_MUX_NUM_NON_DIRECT_IRQS; i++) { + int irq_index = i + MPFS_MUX_NUM_DIRECT_IRQS; + + priv->nondirect_irqchips[i].bank = i; + priv->nondirect_irqchips[i].irq = irq_of_parse_and_map(node, irq_index); + priv->nondirect_irqchips[i].offset = i * MPFS_MAX_IRQS_PER_GPIO; + irq_set_chained_handler_and_data(priv->nondirect_irqchips[i].irq, + mpfs_irq_mux_nondirect_handler, + &priv->nondirect_irqchips[i]); + } + + dev_dbg(dev, "mux configuration %x\n", priv->mux_config); + + return 0; + +out_unmap: + iounmap(priv->reg); + +out_free_priv: + kfree(priv); + + return ret; +} + +static const struct of_device_id mpfs_irq_mux_match[] = { + { .compatible = "microchip,mpfs-gpio-irq-mux" }, + +}; + +static struct platform_driver mpfs_irq_mux_driver = { + .driver = { + .name = "mpfs_irq_mux", + .of_match_table = mpfs_irq_mux_match, + }, + .probe = mpfs_irq_mux_probe, +}; +builtin_platform_driver(mpfs_irq_mux_driver); From patchwork Tue Jul 23 11:27:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conor Dooley X-Patchwork-Id: 814479 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 778A78287A; Tue, 23 Jul 2024 11:28:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734107; cv=none; b=s8dzDfkoJoU997SxbEfJxUsp2jNy6N7KYS1hpOXB/QhTVZcRAVyhsU3eJpJbCZs0neOdIs9Rd4sfgwmXb67g5iqu/ZB90LjGtXbD6fNSD+1c/rTAsS96yEP9O3iFujnx3/WrJUGDR3YrsWwa7KuqPkBwGD3ZQ8nIjmfGQIRmhfo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734107; c=relaxed/simple; bh=mwLzMK344LrlkXY++0l/Gj9MNq2rK0oWALq4fCAT0Wc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lxgMFdCB0BpHjsc0zyhiZSd0kA+KbMPnlS5rXhiubnZbzAu3hBrOGBOqHE737DEZJa0okvFL2xPclXvTrKb8KsL2KfoS/QGyzUkJfAd+D60iJ7nj7QmR4dM+o5EmmjQybKZ1+RljwKHkerRg2bXJqW0OQCBe4fgX0BRDQ3NCeic= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=1RcWvmNp; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="1RcWvmNp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1721734106; x=1753270106; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mwLzMK344LrlkXY++0l/Gj9MNq2rK0oWALq4fCAT0Wc=; b=1RcWvmNpazGxIZwmD3nsCzfiGaRvaYmTzmsBajZy0NfLhZI5L9/dOAda I/c9BQk9/XhQVY9fl/KiUU1YgsQP/fKvVBDsOwCWz7wiJe6CSZvr0l7LI sHmWE7wyLUVbptakMQ/81agyPzqmRQqeWzkxoJY8A8jWMz5ujhMbOcXaM 5IKjH8wStt3zJfLgBYWnFVzLQ6oPtv7hrL3Ln8LQxz/RVHqMNZ+9aDSLN MOM8Sn7tX7eNZJRWbWUEVYwcka9tQRwnqie9RxIehgXkkfeVKVAVfTHNa avfUG3mnXIYckC4kPhcgyRBSK54jtswucj9y9XysXNdRoLShqPN+h0GJU A==; X-CSE-ConnectionGUID: Bzp89j1bQnG7Qha2jIBWKQ== X-CSE-MsgGUID: 9Xz4Jg1zS/eGyBpnXKYMhQ== X-IronPort-AV: E=Sophos;i="6.09,230,1716274800"; d="scan'208";a="260469138" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa5.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Jul 2024 04:28:19 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Tue, 23 Jul 2024 04:28:16 -0700 Received: from wendy.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Tue, 23 Jul 2024 04:28:14 -0700 From: Conor Dooley To: CC: , , Marc Zyngier , Daire McNamara , "Linus Walleij" , Bartosz Golaszewski , "Rob Herring" , Krzysztof Kozlowski , "Thomas Gleixner" , Paul Walmsley , Palmer Dabbelt , , , , Lewis Hanly Subject: [RFC v7 4/6] gpio: mpfs: add polarfire soc gpio support Date: Tue, 23 Jul 2024 12:27:13 +0100 Message-ID: <20240723-underage-wheat-7dd65c2158e7@wendy> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240723-supervise-drown-d5d3b303e7fd@wendy> References: <20240723-supervise-drown-d5d3b303e7fd@wendy> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=11480; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=oRvlKxILF3owTWo7rBvagSB5lR8hjMzfhJvA3BN3F3o=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGnzJ09odPZe6X9rlmqfj8APvQbZhn2Fz1ZPF429MLFs7bnr u4OiO0pZGMQ4GGTFFFkSb/e1SK3/47LDuectzBxWJpAhDFycAjCRB22MDG33FgjbiGk8k56vsGrNJp Y/6QFvzk2cmZrM8y450liDKZ7hv6caf391p3jw85Mfd3G6BllcWxDdraKxv0EvJaBT6NcJNgA= X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C From: Lewis Hanly Add a driver to support the Polarfire SoC gpio controller Signed-off-by: Lewis Hanly Signed-off-by: Conor Dooley Reviewed-by: Linus Walleij --- Unchanged from last list submission, I'm looking for comments on the other patches in the series at the moment. --- drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-mpfs.c | 320 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 drivers/gpio/gpio-mpfs.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3dbddec070281..78fe494e3722c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -549,6 +549,13 @@ config GPIO_PL061 help Say yes here to support the PrimeCell PL061 GPIO device. +config GPIO_POLARFIRE_SOC + bool "Microchip FPGA GPIO support" + depends on OF_GPIO + select GPIOLIB_IRQCHIP + help + Say yes here to support the GPIO device on Microchip FPGAs. + config GPIO_PXA bool "PXA GPIO support" depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e2a53013780e5..dd6ba21bce76e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -132,6 +132,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o +obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c new file mode 100644 index 0000000000000..1ac0526ba1029 --- /dev/null +++ b/drivers/gpio/gpio-mpfs.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: (GPL-2.0) +/* + * Microchip PolarFire SoC (MPFS) GPIO controller driver + * + * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries + * + * Author: Lewis Hanly + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPFS_GPIO_CTRL(i) (0x4 * (i)) +#define MAX_NUM_GPIO 32 +#define MPFS_GPIO_EN_INT 3 +#define MPFS_GPIO_EN_OUT_BUF BIT(2) +#define MPFS_GPIO_EN_IN BIT(1) +#define MPFS_GPIO_EN_OUT BIT(0) + +#define MPFS_GPIO_TYPE_INT_EDGE_BOTH 0x80 +#define MPFS_GPIO_TYPE_INT_EDGE_NEG 0x60 +#define MPFS_GPIO_TYPE_INT_EDGE_POS 0x40 +#define MPFS_GPIO_TYPE_INT_LEVEL_LOW 0x20 +#define MPFS_GPIO_TYPE_INT_LEVEL_HIGH 0x00 +#define MPFS_GPIO_TYPE_INT_MASK GENMASK(7, 5) +#define MPFS_IRQ_REG 0x80 +#define MPFS_INP_REG 0x84 +#define MPFS_OUTP_REG 0x88 + +struct mpfs_gpio_chip { + void __iomem *base; + struct clk *clk; + raw_spinlock_t lock; + struct gpio_chip gc; +}; + +static void mpfs_gpio_assign_bit(void __iomem *addr, unsigned int bit_offset, bool value) +{ + unsigned long reg = readl(addr); + + __assign_bit(bit_offset, ®, value); + writel(reg, addr); +} + +static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + u32 gpio_cfg; + unsigned long flags; + + raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); + + gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + gpio_cfg |= MPFS_GPIO_EN_IN; + gpio_cfg &= ~(MPFS_GPIO_EN_OUT | MPFS_GPIO_EN_OUT_BUF); + writel(gpio_cfg, mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + + raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); + + return 0; +} + +static int mpfs_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio_index, int value) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + u32 gpio_cfg; + unsigned long flags; + + raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); + + gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + gpio_cfg |= MPFS_GPIO_EN_OUT | MPFS_GPIO_EN_OUT_BUF; + gpio_cfg &= ~MPFS_GPIO_EN_IN; + writel(gpio_cfg, mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_OUTP_REG, gpio_index, value); + + raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); + + return 0; +} + +static int mpfs_gpio_get_direction(struct gpio_chip *gc, + unsigned int gpio_index) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + u32 gpio_cfg; + + gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + if (gpio_cfg & MPFS_GPIO_EN_IN) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int mpfs_gpio_get(struct gpio_chip *gc, + unsigned int gpio_index) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + + return !!(readl(mpfs_gpio->base + MPFS_INP_REG) & BIT(gpio_index)); +} + +static void mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int value) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + unsigned long flags; + + raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); + + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_OUTP_REG, + gpio_index, value); + + raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); +} + +static int mpfs_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + int gpio_index = irqd_to_hwirq(data); + u32 interrupt_type; + u32 gpio_cfg; + unsigned long flags; + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_BOTH; + break; + case IRQ_TYPE_EDGE_FALLING: + interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_NEG; + break; + case IRQ_TYPE_EDGE_RISING: + interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_POS; + break; + case IRQ_TYPE_LEVEL_HIGH: + interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_LOW; + break; + } + + raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); + + gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + gpio_cfg &= ~MPFS_GPIO_TYPE_INT_MASK; + gpio_cfg |= interrupt_type; + writel(gpio_cfg, mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); + + raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); + + return 0; +} + +static void mpfs_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + int gpio_index = irqd_to_hwirq(data); + + gpiochip_enable_irq(gc, gpio_index); + mpfs_gpio_direction_input(gc, gpio_index); + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index), + MPFS_GPIO_EN_INT, 1); +} + +static void mpfs_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + int gpio_index = irqd_to_hwirq(data); + + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index), + MPFS_GPIO_EN_INT, 0); + gpiochip_disable_irq(gc, gpio_index); +} + +static const struct irq_chip mpfs_gpio_irqchip = { + .name = "mpfs", + .irq_set_type = mpfs_gpio_irq_set_type, + .irq_mask = mpfs_gpio_irq_mask, + .irq_unmask = mpfs_gpio_irq_unmask, + .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void mpfs_gpio_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct mpfs_gpio_chip *mpfs_gpio = + gpiochip_get_data(irq_desc_get_handler_data(desc)); + unsigned long status; + int offset; + + chained_irq_enter(irqchip, desc); + + status = readl(mpfs_gpio->base + MPFS_IRQ_REG); + for_each_set_bit(offset, &status, mpfs_gpio->gc.ngpio) { + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, offset, 1); + generic_handle_irq(irq_find_mapping(mpfs_gpio->gc.irq.domain, offset)); + } + + chained_irq_exit(irqchip, desc); +} + +static int mpfs_gpio_probe(struct platform_device *pdev) +{ + struct clk *clk; + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + struct mpfs_gpio_chip *mpfs_gpio; + struct gpio_irq_chip *girq; + int i, ret, ngpios, nirqs; + + mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL); + if (!mpfs_gpio) + return -ENOMEM; + + mpfs_gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mpfs_gpio->base)) + return dev_err_probe(dev, PTR_ERR(mpfs_gpio->base), "failed to ioremap memory resource\n"); + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "devm_clk_get failed\n"); + + ret = clk_prepare_enable(clk); + if (ret) + return dev_err_probe(dev, ret, "failed to enable clock\n"); + + mpfs_gpio->clk = clk; + + ngpios = MAX_NUM_GPIO; + device_property_read_u32(dev, "ngpios", &ngpios); + if (ngpios > MAX_NUM_GPIO) + ngpios = MAX_NUM_GPIO; + + raw_spin_lock_init(&mpfs_gpio->lock); + mpfs_gpio->gc.direction_input = mpfs_gpio_direction_input; + mpfs_gpio->gc.direction_output = mpfs_gpio_direction_output; + mpfs_gpio->gc.get_direction = mpfs_gpio_get_direction; + mpfs_gpio->gc.get = mpfs_gpio_get; + mpfs_gpio->gc.set = mpfs_gpio_set; + mpfs_gpio->gc.base = -1; + mpfs_gpio->gc.ngpio = ngpios; + mpfs_gpio->gc.label = dev_name(dev); + mpfs_gpio->gc.parent = dev; + mpfs_gpio->gc.owner = THIS_MODULE; + + nirqs = of_irq_count(node); + if (nirqs > MAX_NUM_GPIO) { + ret = -ENXIO; + goto cleanup_clock; + } + girq = &mpfs_gpio->gc.irq; + gpio_irq_chip_set_chip(girq, &mpfs_gpio_irqchip); + girq->handler = handle_simple_irq; + girq->parent_handler = mpfs_gpio_irq_handler; + girq->default_type = IRQ_TYPE_NONE; + girq->num_parents = nirqs; + girq->parents = devm_kcalloc(&pdev->dev, nirqs, + sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) { + ret = -ENOMEM; + goto cleanup_clock; + } + for (i = 0; i < nirqs; i++) + girq->parents[i] = platform_get_irq(pdev, i); + + ret = gpiochip_add_data(&mpfs_gpio->gc, mpfs_gpio); + if (ret) + goto cleanup_clock; + + platform_set_drvdata(pdev, mpfs_gpio); + + return 0; + +cleanup_clock: + clk_disable_unprepare(mpfs_gpio->clk); + return ret; +} + +static int mpfs_gpio_remove(struct platform_device *pdev) +{ + struct mpfs_gpio_chip *mpfs_gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&mpfs_gpio->gc); + clk_disable_unprepare(mpfs_gpio->clk); + + return 0; +} + +static const struct of_device_id mpfs_gpio_of_ids[] = { + { .compatible = "microchip,mpfs-gpio", }, + { /* end of list */ } +}; + +static struct platform_driver mpfs_gpio_driver = { + .probe = mpfs_gpio_probe, + .driver = { + .name = "microchip,mpfs-gpio", + .of_match_table = mpfs_gpio_of_ids, + }, + .remove = mpfs_gpio_remove, +}; +builtin_platform_driver(mpfs_gpio_driver); From patchwork Tue Jul 23 11:27:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conor Dooley X-Patchwork-Id: 814477 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 383B4154448; Tue, 23 Jul 2024 11:28:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734121; cv=none; b=fwBqa+KioVj70nHTwSO0JakxWThIdyDA3UUAsIF3TrP4dQuNsWOnqBjWhO/tJGoMqlQ2/yikAvyTDax45WRb6FTz+CXqiiclpG+8xEA+GeazyrblfcZuNZHomxMIjP7fz2ZOob5tcQYpg02GIYoJLzV+D0q+dTWR84mmsHz6Gz0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734121; c=relaxed/simple; bh=Ucm8XGSvUldvd/bc2uyFIRcCiSr1Ximdbh0xRa+hE+Q=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=fR2073eH7lrTyMIBhFRNYjH4PbrEjvy2rXH81TKbid8acuX59JhVTXDvKOIJpp33rWdLZnBnNxH8GR4ednOsYj3uPsf2g8uk7G2DX88vQ3aE0Ze0UWzjXSiOG4e0xxehUlehtjsY48j1kHbW8iTNj/wgt5ygD1CxA/f6hFaWWXo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=Caqxeobl; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="Caqxeobl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1721734119; x=1753270119; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Ucm8XGSvUldvd/bc2uyFIRcCiSr1Ximdbh0xRa+hE+Q=; b=CaqxeoblB1PLyj4ZQFtKRWqPLCL7QJPaPHi56kV8iy5JeUoRfL9grNxw 9tmKM55GuFZVm2MCYolc0SPMo4VDqnTn7hnY5Wcc8t3z7/+KOHCAjBCj/ HFbhdgN7wpkG+gVuB+SMcEivSomd0uJ7aVZaAH1D5Go7mBkFcXlS2LkoD 0sUd0hOZQ/av0Mcbvj0K6X054nrZ9Ul8KQ3wBo4IrtrcJe5YLJOFY5uU/ q3dzlrz4s2InqbBo3nZSuTBZ9bYvwc8M7zXX7laUswD4QLA9WiEgcdazs uyxNXcvdk1kIaAP/rnNsO2BZRd2gXsI/1SOcbSmoaj2DbfrJ+lwhPRG2v g==; X-CSE-ConnectionGUID: urgFf+kjT1Coy3E8dV+nGA== X-CSE-MsgGUID: NdOsJdXTT0q1UVuWrE8VRg== X-IronPort-AV: E=Sophos;i="6.09,230,1716274800"; d="scan'208";a="32335706" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Jul 2024 04:28:38 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Tue, 23 Jul 2024 04:28:20 -0700 Received: from wendy.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Tue, 23 Jul 2024 04:28:17 -0700 From: Conor Dooley To: CC: , , Marc Zyngier , Daire McNamara , "Linus Walleij" , Bartosz Golaszewski , "Rob Herring" , Krzysztof Kozlowski , "Thomas Gleixner" , Paul Walmsley , Palmer Dabbelt , , , Subject: [RFC v7 5/6] gpio: mpfs: pass gpio line number as irq data Date: Tue, 23 Jul 2024 12:27:14 +0100 Message-ID: <20240723-handoff-race-33160609553f@wendy> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240723-supervise-drown-d5d3b303e7fd@wendy> References: <20240723-supervise-drown-d5d3b303e7fd@wendy> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=6470; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=Ucm8XGSvUldvd/bc2uyFIRcCiSr1Ximdbh0xRa+hE+Q=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGnzJ0+YukcmPfZuz4P/5Vu65G/3V+9aXPHx6unjGh/ebMs0 1V1a11HKwiDGwSArpsiSeLuvRWr9H5cdzj1vYeawMoEMYeDiFICJGHMxMtzhkZ83zzDnwR3pvaeZvs m+uhDCftMndUVD27G855Gyhc8Z/kepmi0xObLx8d1Fa9ZX7bx0OF1W7SbfD3+PqXa1Jzo7TfkA X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C Since the interrupt mux is going to provide us a 1:1 mapping for interrupts, and it is no longer correct to hit all of the set bits in the interrupt handler, store the GPIO that "owns" an interrupt in its data pointer, so that we can determine which bit to clear. Signed-off-by: Conor Dooley --- This patch will need to be squashed, I've kept it apart for illustrative purposes. --- drivers/gpio/gpio-mpfs.c | 85 +++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c index 1ac0526ba1029..b92f094964822 100644 --- a/drivers/gpio/gpio-mpfs.c +++ b/drivers/gpio/gpio-mpfs.c @@ -43,6 +43,7 @@ struct mpfs_gpio_chip { struct clk *clk; raw_spinlock_t lock; struct gpio_chip gc; + u8 irq_data[MAX_NUM_GPIO]; }; static void mpfs_gpio_assign_bit(void __iomem *addr, unsigned int bit_offset, bool value) @@ -129,7 +130,7 @@ static int mpfs_gpio_irq_set_type(struct irq_data *data, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); - int gpio_index = irqd_to_hwirq(data); + int gpio_index = irqd_to_hwirq(data) % 32; u32 interrupt_type; u32 gpio_cfg; unsigned long flags; @@ -168,11 +169,10 @@ static void mpfs_gpio_irq_unmask(struct irq_data *data) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); - int gpio_index = irqd_to_hwirq(data); + int gpio_index = irqd_to_hwirq(data) % 32; gpiochip_enable_irq(gc, gpio_index); mpfs_gpio_direction_input(gc, gpio_index); - mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index), MPFS_GPIO_EN_INT, 1); } @@ -181,19 +181,18 @@ static void mpfs_gpio_irq_mask(struct irq_data *data) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); - int gpio_index = irqd_to_hwirq(data); + int gpio_index = irqd_to_hwirq(data) % 32; - mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index), MPFS_GPIO_EN_INT, 0); gpiochip_disable_irq(gc, gpio_index); } static const struct irq_chip mpfs_gpio_irqchip = { - .name = "mpfs", + .name = "MPFS GPIO", .irq_set_type = mpfs_gpio_irq_set_type, - .irq_mask = mpfs_gpio_irq_mask, - .irq_unmask = mpfs_gpio_irq_unmask, + .irq_mask = mpfs_gpio_irq_mask, + .irq_unmask = mpfs_gpio_irq_unmask, .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; @@ -201,18 +200,24 @@ static const struct irq_chip mpfs_gpio_irqchip = { static void mpfs_gpio_irq_handler(struct irq_desc *desc) { struct irq_chip *irqchip = irq_desc_get_chip(desc); - struct mpfs_gpio_chip *mpfs_gpio = - gpiochip_get_data(irq_desc_get_handler_data(desc)); + void *handler_data = irq_desc_get_handler_data(desc); + struct gpio_chip *gc = irq_data_get_irq_chip_data(&desc->irq_data); + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + u8 gpio_index = *((u8 *)handler_data); unsigned long status; - int offset; + + /* + * Since the parent may be a muxed/"non-direct" interrupt, this + * interrupt may not be for us. + */ + status = readl(mpfs_gpio->base + MPFS_IRQ_REG); + if (!(status & BIT(gpio_index))) + return; chained_irq_enter(irqchip, desc); - status = readl(mpfs_gpio->base + MPFS_IRQ_REG); - for_each_set_bit(offset, &status, mpfs_gpio->gc.ngpio) { - mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, offset, 1); - generic_handle_irq(irq_find_mapping(mpfs_gpio->gc.irq.domain, offset)); - } + generic_handle_irq(irq_find_mapping(mpfs_gpio->gc.irq.domain, gpio_index)); + mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); chained_irq_exit(irqchip, desc); } @@ -222,6 +227,7 @@ static int mpfs_gpio_probe(struct platform_device *pdev) struct clk *clk; struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; + void **irq_data = NULL; struct mpfs_gpio_chip *mpfs_gpio; struct gpio_irq_chip *girq; int i, ret, ngpios, nirqs; @@ -232,7 +238,8 @@ static int mpfs_gpio_probe(struct platform_device *pdev) mpfs_gpio->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mpfs_gpio->base)) - return dev_err_probe(dev, PTR_ERR(mpfs_gpio->base), "failed to ioremap memory resource\n"); + return dev_err_probe(dev, PTR_ERR(mpfs_gpio->base), + "failed to ioremap memory resource\n"); clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) @@ -266,20 +273,42 @@ static int mpfs_gpio_probe(struct platform_device *pdev) ret = -ENXIO; goto cleanup_clock; } + girq = &mpfs_gpio->gc.irq; - gpio_irq_chip_set_chip(girq, &mpfs_gpio_irqchip); - girq->handler = handle_simple_irq; - girq->parent_handler = mpfs_gpio_irq_handler; - girq->default_type = IRQ_TYPE_NONE; girq->num_parents = nirqs; - girq->parents = devm_kcalloc(&pdev->dev, nirqs, - sizeof(*girq->parents), GFP_KERNEL); - if (!girq->parents) { - ret = -ENOMEM; - goto cleanup_clock; + + if (girq->num_parents) { + gpio_irq_chip_set_chip(girq, &mpfs_gpio_irqchip); + girq->parent_handler = mpfs_gpio_irq_handler; + + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), GFP_KERNEL); + irq_data = devm_kmalloc_array(&pdev->dev, girq->num_parents, + sizeof(*irq_data), GFP_KERNEL); + + if (!girq->parents || !irq_data) { + ret = -ENOMEM; + goto cleanup_clock; + } + + for (i = 0; i < girq->num_parents; i++) { + ret = platform_get_irq(pdev, i); + if (ret < 0) + goto cleanup_clock; + + girq->parents[i] = ret; + mpfs_gpio->irq_data[i] = i; + irq_data[i] = &mpfs_gpio->irq_data[i]; + + irq_set_chip_data(ret, &mpfs_gpio->gc); + irq_set_handler(ret, handle_simple_irq); + } + + girq->parent_handler_data_array = irq_data; + girq->per_parent_data = true; + girq->handler = handle_simple_irq; + girq->default_type = IRQ_TYPE_NONE; } - for (i = 0; i < nirqs; i++) - girq->parents[i] = platform_get_irq(pdev, i); ret = gpiochip_add_data(&mpfs_gpio->gc, mpfs_gpio); if (ret) From patchwork Tue Jul 23 11:27:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conor Dooley X-Patchwork-Id: 814044 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DBC401514C0; Tue, 23 Jul 2024 11:28:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734131; cv=none; b=Y76TGB7H0voAH3apf7xJn7lsfbz8NyZcWpu0DjTzTIHWmP/a1JIsxbEcWDCFvisURZMfVBhtLsNm3eeZgHARW1skmmsf6VnvyXxH+edcJhZseaRDQQFPEl+DgEPwOxHsM3Es0juMp2/SDSOOErLhalLCn/3WOQZ5it4CtP/+7YA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721734131; c=relaxed/simple; bh=0BnMHbAdBH79ScPTvVNbtezh5vCswpZdpOoIuQ4RzEE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qSDdu6EoZ+OOPt8bbgqdUEVZp281HDhRLJ1M1HQjOX2zBB/4ghneenSMW0fP+c3zrnoIPnAT1YHyqKQV71zrHZHUoEttyeW+fTpIsVZB/hE/ihLHxTFfEBWClfgUr0/KRF1RFNln/eKl0QrhIJbkDn150xDABBFAyn+/K/2led8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=zwHqgf9u; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="zwHqgf9u" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1721734130; x=1753270130; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0BnMHbAdBH79ScPTvVNbtezh5vCswpZdpOoIuQ4RzEE=; b=zwHqgf9uOef8BKZyrBzU/K8FQIGXKQJrbpc7OhPviiHxitbc/RNIRdgS 9Yqw6K1QIVowthpM4Ua7NfR9tofhOo3n842gEENEIbmTL7HRYQ8Cj5ZtY dOXFBafC8OGoG55j30OdHpphrYUYprRRtyBABKvv03lvDxghKMQ3D7VYr 5frVuEbz0U3lCewOPJVPC3iXnhfNQFZUlN/SIzZBRKNZLgIVJLqzPpfAn 3sWDHiUW7YTrzR9aUENfxsgnOUlZ6XL8KhylWg/umM1Ip4ZzIo2CycB9m vxlX3niAGEmGQtjmldcw336OxvyUCXXaWv2JzQEWQRWYzlozcVmwWglqL A==; X-CSE-ConnectionGUID: ogbmHU+kQ5yxZ4OX2mUEtQ== X-CSE-MsgGUID: Y70jeUQRQ8adVIWl7jhXaw== X-IronPort-AV: E=Sophos;i="6.09,230,1716274800"; d="scan'208";a="29574987" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa3.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Jul 2024 04:28:49 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Tue, 23 Jul 2024 04:28:24 -0700 Received: from wendy.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Tue, 23 Jul 2024 04:28:21 -0700 From: Conor Dooley To: CC: , , Marc Zyngier , Daire McNamara , "Linus Walleij" , Bartosz Golaszewski , "Rob Herring" , Krzysztof Kozlowski , "Thomas Gleixner" , Paul Walmsley , Palmer Dabbelt , , , Subject: [RFC v7 6/6] riscv: dts: microchip: update gpio interrupts to better match the SoC Date: Tue, 23 Jul 2024 12:27:15 +0100 Message-ID: <20240723-framing-chaos-9f8e2df8889d@wendy> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240723-supervise-drown-d5d3b303e7fd@wendy> References: <20240723-supervise-drown-d5d3b303e7fd@wendy> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=5034; i=conor.dooley@microchip.com; h=from:subject:message-id; bh=0BnMHbAdBH79ScPTvVNbtezh5vCswpZdpOoIuQ4RzEE=; b=owGbwMvMwCFWscWwfUFT0iXG02pJDGnzJ0+c/rLzj6Ppc85Px9Je/mcOm3vjiVrjRbV1iqs22S4J sjB901HKwiDGwSArpsiSeLuvRWr9H5cdzj1vYeawMoEMYeDiFICJcJYw/C/J9V7+K11BZNH0Rcf1vT czOGzLV//19JlVpFygvVjf13BGhpOWzN8z95a/mrlzou3PjANBLCaiLZLJzdY+MxdZxjTo8AEA X-Developer-Key: i=conor.dooley@microchip.com; a=openpgp; fpr=F9ECA03CF54F12CD01F1655722E2C55B37CF380C There are 3 GPIO controllers on this SoC, of which: - GPIO controller 0 has 14 GPIOs - GPIO controller 1 has 24 GPIOs - GPIO controller 2 has 32 GPIOs All GPIOs are capable of generating interrupts, for a total of 70. There are only 41 IRQs available however, so a configurable mux is used to ensure all GPIOs can be used for interrupt generation. 38 of the 41 interrupts are in what the documentation calls "direct mode", as they provide an exclusive connection from a GPIO to the PLIC. The 3 remaining interrupts are used to mux the interrupts which do not have a exclusive connection, one for each GPIO controller. Setting of the mux should be done by the platform's firmware at boot, based on the output of the "MSS Configurator" (FPGA configuration tool). The microchip,mpfs-gpio binding suffered greatly due to being written with a narrow minded view of the controller, and the interrupt bits ended up incorrect. It was mistakenly assumed that the interrupt configuration was set by platform firmware, based on the FPGA configuration, and that the GPIO DT nodes were the only way to really communicate interrupt configuration to software. Instead, the mux should be a device in its own right, and the GPIO controllers should be connected to it, rather than to the PLIC. Now that a binding exists for that mux, fix the inaccurate description of the interrupt controller hierarchy. Signed-off-by: Conor Dooley --- .../boot/dts/microchip/mpfs-icicle-kit.dts | 8 --- arch/riscv/boot/dts/microchip/mpfs.dtsi | 50 +++++++++++++++++-- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts index f80df225f72b4..7a9822d2a8819 100644 --- a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts @@ -83,14 +83,6 @@ &core_pwm0 { }; &gpio2 { - interrupts = <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>, - <53>, <53>, <53>, <53>; status = "okay"; }; diff --git a/arch/riscv/boot/dts/microchip/mpfs.dtsi b/arch/riscv/boot/dts/microchip/mpfs.dtsi index 9883ca3554c50..e31e0aacb943b 100644 --- a/arch/riscv/boot/dts/microchip/mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/mpfs.dtsi @@ -465,39 +465,79 @@ mac1: ethernet@20112000 { status = "disabled"; }; - gpio0: gpio@20120000 { - compatible = "microchip,mpfs-gpio"; - reg = <0x0 0x20120000 0x0 0x1000>; + irqmux: interrupt-controller@20002054 { + compatible = "microchip,mpfs-gpio-irq-mux"; + reg = <0x0 0x20002054 0x0 0x4>; interrupt-parent = <&plic>; interrupt-controller; #interrupt-cells = <1>; + interrupts = <13>, <14>, <15>, <16>, + <17>, <18>, <19>, <20>, + <21>, <22>, <23>, <24>, + <25>, <26>, <27>, <28>, + <29>, <30>, <31>, <32>, + <33>, <34>, <35>, <36>, + <37>, <38>, <39>, <40>, + <41>, <42>, <43>, <44>, + <45>, <46>, <47>, <48>, + <49>, <50>, <51>, <52>, + <53>; + }; + + gpio0: gpio@20120000 { + compatible = "microchip,mpfs-gpio"; + reg = <0x0 0x20120000 0x0 0x1000>; + interrupt-parent = <&irqmux>; + interrupt-controller; + #interrupt-cells = <1>; + interrupts = <0>, <1>, <2>, <3>, + <4>, <5>, <6>, <7>, + <8>, <9>, <10>, <11>, + <12>, <13>; clocks = <&clkcfg CLK_GPIO0>; gpio-controller; #gpio-cells = <2>; + ngpios = <14>; status = "disabled"; }; gpio1: gpio@20121000 { compatible = "microchip,mpfs-gpio"; reg = <0x0 0x20121000 0x0 0x1000>; - interrupt-parent = <&plic>; + interrupt-parent = <&irqmux>; interrupt-controller; #interrupt-cells = <1>; + interrupts = <32>, <33>, <34>, <35>, + <36>, <37>, <38>, <39>, + <40>, <41>, <42>, <43>, + <44>, <45>, <46>, <47>, + <48>, <49>, <50>, <51>, + <52>, <53>, <54>, <55>; clocks = <&clkcfg CLK_GPIO1>; gpio-controller; #gpio-cells = <2>; + ngpios = <24>; status = "disabled"; }; gpio2: gpio@20122000 { compatible = "microchip,mpfs-gpio"; reg = <0x0 0x20122000 0x0 0x1000>; - interrupt-parent = <&plic>; + interrupt-parent = <&irqmux>; interrupt-controller; #interrupt-cells = <1>; + interrupts = <64>, <65>, <66>, <67>, + <68>, <69>, <70>, <71>, + <72>, <73>, <74>, <75>, + <76>, <77>, <78>, <79>, + <80>, <81>, <82>, <83>, + <84>, <85>, <86>, <87>, + <88>, <89>, <90>, <91>, + <92>, <93>, <94>, <95>; clocks = <&clkcfg CLK_GPIO2>; gpio-controller; #gpio-cells = <2>; + ngpios = <32>; status = "disabled"; };