From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D16FD27A907; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; cv=none; b=U5ukK8W9cW/OqIU78rg3yOtbw4Y+oLlF26WbFoGF0HgoabYyS6w3LoI9ON2k+DB/VhAZ4Sbz3eCJB1wgYS9Dv3KLbC51Rxoi7NkS+oaepB56hwkz1oyivG8mdaj9Ra3Z6LnUZVE7Kv196UVHOROVUvdfr3VjNf1DD2xwe3mQpIE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; c=relaxed/simple; bh=uWHJNFEDwNhxfzEsQVN+MYBNDHqcBjEugM8Y0dLDGg0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=l+Uvif0LDbwxOt39EcvhcUOF4To5DGUgRc4Bqym1S6W8AQiWAkOHuf/gtCZrFu64JejMWm4M89EtWHzTQaET13Qy6x2afX/hQ1w1wJAC5zWNo+Uh4OByH/WU5yLxCowVnRCFV8rTiVIrAPFesnCFaPjiAnl81790WqGObIhuHvc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=schp2qo4; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="schp2qo4" Received: by smtp.kernel.org (Postfix) with ESMTPS id 38042C2BCF5; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=uWHJNFEDwNhxfzEsQVN+MYBNDHqcBjEugM8Y0dLDGg0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=schp2qo4nsd55MUrHUMuKXxyW9TuDXBWJ1LlwS/L8Mz5q3jwRR7E//FwIdaXZs6dx o2Lmom99rm6bGVNbMt3HWnU8TFPTHfeVxKC5XAWXfx9bEhvco9eUKIswjho9II1VEf skt/Z1H3xEln5aZNyNbnIHIDI/A8iIPRIFoHWJD69rzd4dhlGExDLqlkx6/Wf/3rv4 lW/5MK768/ZyHhu20W7G0hx3lu9ZRppRiTgmJEjhcSZa9zKeIDx/AOWB3TOS9khmVR Qz4tqmB+GbbrUz0zTvdc/stOZQr4zqWkvSmK4TivHi1tTVSOB2bDjfhfVcYM5AR60D GmlKAGYGJUS3Q== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 171CCC5AC80; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:10 +0800 Subject: [PATCH v2 01/17] dt-bindings: display: spacemit: add K3 Saturn DPU controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-1-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=4691; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=BmFVX9AQPaf/054idrgE6KVKK1IoNznGkA+GRXEpG9M=; b=/yT1v9ef3dtpOxKhsnKQ6uDojXxRxTguGnrCGEHMzwSEdtLmy/6hQaxRTrGavkrSIIhV91ENi Keu/o38CU+fDXhx68dbKaDqN0e5YjIYpM1GaAE80y4Kp71TuxHmZXYS X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang Document the Saturn display processing unit found on the SpacemiT K3 SoC. The K3 instantiates two of them, one per display path. They share a compatible: an instance differs only in which register window, interrupt, clock and reset lines it takes. Reviewed-by: Rob Herring (Arm) Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - add Reviewed-by: Rob Herring (Arm) --- .../display/spacemit/spacemit,k3-saturn-dpu.yaml | 132 +++++++++++++++++= ++++ 1 file changed, 132 insertions(+) diff --git a/Documentation/devicetree/bindings/display/spacemit/spacemit,k3= -saturn-dpu.yaml b/Documentation/devicetree/bindings/display/spacemit/space= mit,k3-saturn-dpu.yaml new file mode 100644 index 0000000000000..97ea9da4b68e4 --- /dev/null +++ b/Documentation/devicetree/bindings/display/spacemit/spacemit,k3-saturn= -dpu.yaml @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/spacemit/spacemit,k3-saturn-dpu= .yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K3 Saturn Display Processing Unit + +maintainers: + - Cody Kang + +description: + The Saturn DPU is the display processing unit of the SpacemiT K3 SoC. It + composes the display planes and drives the timing for one display path. = Its + output goes to a DisplayPort or embedded DisplayPort controller. The K3 = has + two instances. + +properties: + compatible: + const: spacemit,k3-saturn-dpu + + reg: + maxItems: 1 + + interrupts: + items: + - description: Online (live display) compose path. + - description: Offline (writeback) compose path. + + interrupt-names: + items: + - const: online + - const: offline + + clocks: + items: + - description: Pixel clock. + - description: Memory clock for the compose pipeline. + - description: AXI bus clock. + - description: DSI escape clock. + - description: DSC clock. + + clock-names: + items: + - const: pxclk + - const: mclk + - const: aclk + - const: escclk + - const: dscclk + + resets: + items: + - description: Memory clock domain. + - description: LCD domain, shared with the downstream controller. + - description: DSI escape clock domain. + - description: AXI clock domain. + - description: DSC domain. + + reset-names: + items: + - const: mclk + - const: lcd + - const: esc + - const: aclk + - const: dsc + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Video output to the DisplayPort or eDP controller. + + required: + - port@0 + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - resets + - reset-names + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + + soc { + #address-cells =3D <2>; + #size-cells =3D <2>; + + dpu@c0340000 { + compatible =3D "spacemit,k3-saturn-dpu"; + reg =3D <0x0 0xc0340000 0x0 0x54000>; + interrupts =3D <90 IRQ_TYPE_LEVEL_HIGH>, + <89 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names =3D "online", "offline"; + clocks =3D <&syscon_apmu CLK_APMU_LCD_PXCLK>, + <&syscon_apmu CLK_APMU_LCD_MCLK>, + <&syscon_apmu CLK_APMU_DPU_ACLK>, + <&syscon_apmu CLK_APMU_DSI_ESC>, + <&syscon_apmu CLK_APMU_LCD_DSC>; + clock-names =3D "pxclk", "mclk", "aclk", "escclk", "dscclk"; + resets =3D <&syscon_apmu RESET_APMU_LCD_MCLK>, + <&syscon_apmu RESET_APMU_LCD>, + <&syscon_apmu RESET_APMU_DSI_ESC>, + <&syscon_apmu RESET_APMU_DPU_ACLK>, + <&syscon_apmu RESET_APMU_LCD_DSCCLK>; + reset-names =3D "mclk", "lcd", "esc", "aclk", "dsc"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + endpoint { + remote-endpoint =3D <&edp0_in>; + }; + }; + }; + }; + }; --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D112526A1CF; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; cv=none; b=llubU7hirfiysryaqhOUqNPm32/HCbYbhJD+3VCXN6mMy1D4VwB5tCSYU6q6/+XeTpmKol5t7uX/xTfRzW6nQunqbRs1fgbwHcQZlgYjHm5fMJZgpTkIiG+dbtggwvfaqhb2e8BFv+0tpSOoYpPpkdgUCj+Sno7gNN6VqtOTFck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; c=relaxed/simple; bh=GaC5ILihit460FZxqqZmeMPb77gx2K+GWLRT410+nv4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jAlxiNBBl6zFaGKb/Oh9yOW+TsDYv9aMxC8VssBoA2UWicrQtPMLwK5A8nw7elTjCLkdd2Cehr/YYuJR4vXMbrTM/joWBnDxLL8BONHIHAqzKM5VQ6kCvepyZfUM7AuQiMDKaUDqL4GRXzxS6meFa/vnaOo0D3GJeeQHBlhtMT0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GcIXoyPp; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GcIXoyPp" Received: by smtp.kernel.org (Postfix) with ESMTPS id 4E136C2BCF6; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=GaC5ILihit460FZxqqZmeMPb77gx2K+GWLRT410+nv4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=GcIXoyPpYACOoXPXTmVO8AjW4kZ9Tx1khHigfSWz9aGhg45hz3wmTHdkcr/Ni7r6W arwA0XWL2A0//RJn18w6dXRp5w5nPAPEaZG5aOHqymcCvDVGQ0F+t6cFkjSGmy+Rro Qp+zuZDHR+YgvvUb0rbp3ov7VffdJzaHNYQbL52fe3ZX8zBnjkujrDlObsGRhXnLRY sjB/2BXSpJWX+aM1qGuFH3fNw1GVRO2/2WK++jzLheeKX+acmzzC0NPZO7zX4ZF/K5 UY3DccriQ1PVu5Ksp6YHHYIEH91DJ9YoOaWuPfedk2tQH7AVIxSMBx36T4G1k3yvnV crGTh7HWz5x6w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2B793C5AD68; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:11 +0800 Subject: [PATCH v2 02/17] dt-bindings: phy: add SpacemiT K3 Innosilicon DP PHY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-2-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=2433; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=XomvK7OQWB2BpQ6NfJVtgaEE/SQQ/w/1buDPgY2JWZE=; b=OS0Mdz446kIKQUNz8sGws3u9JiiUbHKzMIA2ZX5KN9NECBOZFp2U87rcrgLZkoSyxKZTxfjVD I2sF9J1v23OD9WYP68abUdwsWu2fYWGq5R4NAtsNt0jx212CFwm5Kkx X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang The SpacemiT K3 DisplayPort controller drives its four transmit lanes through an integrated Innosilicon DP PHY, one PHY per controller. Add a binding so the controller can reference its transmit PHY and the pixel clock the PHY's PLL sources. The PHY's registers are interleaved with its parent controller's inside one MMIO window, so it owns neither a reg nor a reset and is modelled as a child of the controller. It exposes its PLL-generated pixel clock through #clock-cells, so the APMU pixel-clock mux can select it as a parent through the clock framework. Reviewed-by: Rob Herring (Arm) Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - add Reviewed-by: Rob Herring (Arm) --- .../bindings/phy/spacemit,k3-inno-dp-phy.yaml | 48 ++++++++++++++++++= ++++ 1 file changed, 48 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/spacemit,k3-inno-dp-phy.= yaml b/Documentation/devicetree/bindings/phy/spacemit,k3-inno-dp-phy.yaml new file mode 100644 index 0000000000000..f8f1ef3729511 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/spacemit,k3-inno-dp-phy.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/spacemit,k3-inno-dp-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K3 Innosilicon DisplayPort PHY + +maintainers: + - Cody Kang + +description: + Innosilicon four-lane DisplayPort transmit PHY integrated in the SpacemiT + K3 SoC, one per DisplayPort controller. Its registers are interleaved wi= th + the controller's own inside a single register window, so it is described= as + a child of the controller and owns neither a reg nor a reset. + + The PHY provides the pixel clock its PLL generates, which the APMU + pixel-clock mux takes as one of its inputs. + +properties: + compatible: + const: spacemit,k3-inno-dp-phy + + "#phy-cells": + const: 0 + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + +required: + - compatible + - "#phy-cells" + - "#clock-cells" + +additionalProperties: false + +examples: + - | + phy { + compatible =3D "spacemit,k3-inno-dp-phy"; + #phy-cells =3D <0>; + #clock-cells =3D <0>; + clock-output-names =3D "edp0_pll_pxclk"; + }; --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 99EEC2417D9; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281321; cv=none; b=Qr7E1WvAZHV8QmN2ZBFM8IMBlZrN01JW6qCGPtbtHTTQIa06HDQvpHy3HA6LKpOB6M8yXLF0Qqy1aiZqqRaERMMXNg9KuUIZUyuCaU2Ifux7IEAC79isdVjeD0YujRUHpaTem16s93zHwfmZdCAaHc7bIxt2zqvjG0Hbj8w/6H8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281321; c=relaxed/simple; bh=9peFgrnHqlLJn8Ue7sGrY5PiSn7KpFqxvAykcmftCp8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Q+AW2JnfcwWhHmaXAbSwhlS2uvhN8mHPPuRXwdCNvIxikk8xUPACgJwik5RdkCtRob6NSOk5THPw8sSHeV+Vus6OTjqpp9qFLptghlfF0QDucAp3mSBOFHHYu1HDKBIE9OWjqz7smkO1K4g3qSSCLC4TBInPZSuipDvEQzLWWaU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VaDtLmzB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VaDtLmzB" Received: by smtp.kernel.org (Postfix) with ESMTPS id 62849C2BD05; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=9peFgrnHqlLJn8Ue7sGrY5PiSn7KpFqxvAykcmftCp8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=VaDtLmzBLiMCHaK7iB/0prE+fswjBrAjperEeS8++CktfySTSqr1icijjETkqoUd+ e8qWZiF60I32xao/6FPEhKpubjodK5H4nCbone3/+HnfNquDIyH2T+kdHPJSyyWBS1 Og66F/uEoP7t9rBnChSfL1UR+Gk878Hl6Wxiwz82/i5AmENeW1eZYOtvAkIYoRmZ/t srsWcj/V/kepMtegRPxRI5I2lJHEWiyD9NSLzD2vr0Uf9aEqCyQzrt7jyXjWZQOSNA jSi2c4Q0kU0JwmICxOGB/NdOynyLrjnxVv0+dh7+OuwEMh118TxZ1fj9BM32B0Dt20 yqgM1+jN6bmDA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43741C5AD2C; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:12 +0800 Subject: [PATCH v2 03/17] dt-bindings: display: spacemit: add K3 Innosilicon DP/eDP controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-3-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=4802; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=VkHwjITfjJFDv2SvE3j5UStndtyWrAWLVP3FHNwGNeE=; b=llT07l7DIsiM1lHB9+w0LQewfBUC5/hb1VcZ0hJjSrb8Ow6g31WJRK2i5vaKmSyMD124koK0Q K6KHDPcB+R9D74X0khdGbM21yXzK69ex/5hgwdfO70l2URTSLWsPGkr X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang Both K3 instances are the same IP and share one compatible; which one behaves as eDP is decided by what its downstream port is wired to, not by which register window it sits in, so the binding does not distinguish them. Reviewed-by: Rob Herring (Arm) Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - make port@1 required (Rob Herring) - add Reviewed-by: Rob Herring (Arm) --- .../display/spacemit/spacemit,k3-inno-dp.yaml | 141 +++++++++++++++++= ++++ 1 file changed, 141 insertions(+) diff --git a/Documentation/devicetree/bindings/display/spacemit/spacemit,k3= -inno-dp.yaml b/Documentation/devicetree/bindings/display/spacemit/spacemit= ,k3-inno-dp.yaml new file mode 100644 index 0000000000000..491d25730da9f --- /dev/null +++ b/Documentation/devicetree/bindings/display/spacemit/spacemit,k3-inno-d= p.yaml @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/spacemit/spacemit,k3-inno-dp.ya= ml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K3 Innosilicon DisplayPort / embedded DisplayPort Controll= er + +maintainers: + - Cody Kang + +description: + Innosilicon DisplayPort transmit controller integrated in the SpacemiT K3 + SoC. The K3 has two instances of the same block sharing one compatible; + each acts as embedded or external DisplayPort depending on whether its + output port drives a panel or a connector. + +properties: + compatible: + const: spacemit,k3-inno-dp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: Link and hot-plug events. + + clocks: + items: + - description: Pixel clock for the controller. + - description: + Pixel clock generated by the DP PHY PLL; the pixel clock above is + parented onto it in use. + + clock-names: + items: + - const: pxclk + - const: pll + + resets: + maxItems: 1 + description: Controller-wide reset signal. + + phys: + maxItems: 1 + description: Phandle to the K3 Innosilicon DP PHY. + + phy-names: + items: + - const: dp + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Video input from the DPU. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Output to the panel or to the DisplayPort connector. + + required: + - port@0 + - port@1 + + aux-bus: + $ref: /schemas/display/dp-aux-bus.yaml# + description: + The DisplayPort AUX bus. Present when the output drives an embedded + panel, which is described as a child of this node and identifies its= elf + over AUX. Absent when the output is a connector. + + phy: + $ref: /schemas/phy/spacemit,k3-inno-dp-phy.yaml# + description: + The DisplayPort PHY. Its registers live inside this controller's + register window, so it is described here as a child node. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - phys + - phy-names + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + + soc { + #address-cells =3D <2>; + #size-cells =3D <2>; + + edp@cac84000 { + compatible =3D "spacemit,k3-inno-dp"; + reg =3D <0x0 0xcac84000 0x0 0x4000>; + interrupts =3D <132 IRQ_TYPE_LEVEL_HIGH>; + clocks =3D <&syscon_apmu CLK_APMU_EDP0_PXCLK>, <&edp0_phy>; + clock-names =3D "pxclk", "pll"; + resets =3D <&syscon_apmu RESET_APMU_EDP0>; + phys =3D <&edp0_phy>; + phy-names =3D "dp"; + + edp0_phy: phy { + compatible =3D "spacemit,k3-inno-dp-phy"; + #phy-cells =3D <0>; + #clock-cells =3D <0>; + clock-output-names =3D "edp0_pll_pxclk"; + }; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + endpoint { + remote-endpoint =3D <&dpu0_out>; + }; + }; + + port@1 { + reg =3D <1>; + endpoint { + remote-endpoint =3D <&panel_in>; + }; + }; + }; + }; + }; --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D586D2BD58A; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; cv=none; b=BU9M61lGazNUfCXMWnUl/zIom1eHvV3SlEOkQfl2qPi8eKpNdgFnPrz+GGc+2ZxnK9L3/pRfysp+F7NYdstU27n/Xa0+ByPcpLVqBiRFEZnzbpVYwvKm0+mBuF5XF2MksTDL1iXWk2mgCu8NQOEXsFqyfYFxIB5iz3N/aW/0UhA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; c=relaxed/simple; bh=4OU6Od8el7QzsKN2rqPzw6rTUFmkgSbklP0M50hiEXw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bcuDDFZDFKxMMrlxO5Rfe69BDnoRWSGnq26S8GdsP8xMl50nNIxLzKCfXqiFkL7zC1OdBFF0MRrD6RjeoxbX/EiPUWpIU0FBs7ZaXHlpF3vhwTnRnDDhW8lkKcoeE179lg7MBhXsm2J3N1VOixTGBZE9Mx8hM71s+MArqiuWu3c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K+m6ZLjK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="K+m6ZLjK" Received: by smtp.kernel.org (Postfix) with ESMTPS id 79245C2BD01; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=4OU6Od8el7QzsKN2rqPzw6rTUFmkgSbklP0M50hiEXw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=K+m6ZLjKe1Jn7Ok0Exl2WTg03ARqZvJK25znyWryDMYsDLTpRBLQnGI1eWdIndTr7 w2CaJYPHgKRUL6FVM/BQCFVnse02D+Ewv1CwAz/iFit3c69xcqExsHPTerW35jmSwQ RGy9b0asT+0oggCTkGFzYiorSj3b0W853GUirj5yZpBE2VDxFhysqzOgujblD2j3At dhkcf7PF0rJBkH+yZ7csduGnM/0ePfTMrIXpih564RJzF2Y8FbM3wDsKEg4OZV9zio Sp8uCT1GjnwfxaIEqRMUUu4Et0aU3VcUC9NyPMaf7stHw5oqq3aRGPOoPN2We6P2Qd 8p6K/FobUzBPw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60B26C5AD6A; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:13 +0800 Subject: [PATCH v2 04/17] dt-bindings: soc: spacemit: allow eDP/DP PHY PLL pixel clocks on K3 APMU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-4-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=1913; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=XIXdh8tM1nuisKWRso6HNY0wYA1fsQzlAJKbSvbCocs=; b=ZL1gtNAJ4clzcCfAX4wu5YkJYSmn8UV14NVeaPo5RRhKJCeJA0cgvPk+y1y+V0zqhhft+IuII HXqR64HqL3tDmZ+AnT4xjeisv3x891Vekpy0Vs56fjQPZA9o3Vf8Iu2 X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang The APMU's eDP pixel-clock muxes select the DP PHY PLLs as parents, so the K3 syscon takes two clock inputs the other variants do not have. Gate them behind the K3 compatible instead of widening the shared clock list, so a non-K3 syscon cannot silently accept clocks it has no mux for. Signed-off-by: Cody Kang Reviewed-by: Rob Herring (Arm) Tested-by: Ze Huang --- v2: - drop the redundant minItems: 4; four is already the minimum (Rob Herring) --- .../bindings/soc/spacemit/spacemit,k1-syscon.yaml | 21 +++++++++++++++++= +++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/spacemit/spacemit,k1-sys= con.yaml b/Documentation/devicetree/bindings/soc/spacemit/spacemit,k1-sysco= n.yaml index d3a7c93c3c54f..a6ef456fe14be 100644 --- a/Documentation/devicetree/bindings/soc/spacemit/spacemit,k1-syscon.yaml +++ b/Documentation/devicetree/bindings/soc/spacemit/spacemit,k1-syscon.yaml @@ -31,14 +31,18 @@ properties: maxItems: 1 =20 clocks: - maxItems: 4 + minItems: 4 + maxItems: 6 =20 clock-names: + minItems: 4 items: - const: osc - const: vctcxo_1m - const: vctcxo_3m - const: vctcxo_24m + - const: edp0_pll_pxclk + - const: edp1_pll_pxclk =20 "#clock-cells": const: 1 @@ -95,6 +99,21 @@ allOf: - clocks - clock-names - "#clock-cells" + # Only the K3 APMU exposes the two eDP/DP PHY PLL pixel clocks as extra + # inputs (parents of its eDP pixel-clock muxes); every other variant has + # the four base oscillator inputs only. + - if: + not: + properties: + compatible: + contains: + const: spacemit,k3-syscon-apmu + then: + properties: + clocks: + maxItems: 4 + clock-names: + maxItems: 4 =20 additionalProperties: false =20 --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 89D7C29A31C; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281321; cv=none; b=oDigLiHHvuL8Cpju/tcmCOQBn8PMXahp/cPSr5bedos+1baCnFQSbL3VVbha+OB9rV3XXi7+t0BF6Yq3zc11Imt29iTNxZekwWV/7o6U0quKNEWf2D270RmCWj297PJLPoiePeTp7CDvAeiHdNcfVTB1UVUOCaZ8RXU0QHMOzYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281321; c=relaxed/simple; bh=8IMEYD3n6yT8ZSbC1ZnVI+oSqA0c5prW8Yu3yOGSG30=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=m7QsQ+cTL0DBt9bhecWtGSxzCE+dNJND3bWbOWJkbIO/+SIZdJMgbivPgYw+TDkefP1YsnbRQjG9hNWwA2ib3BYMxegH1ht4Fb63k1YkKttobX5MRdl5f/tJskTYNeeIUtI7l91MmL54A5+DeWsloHpZngbtWKgQRQbo60FMbJU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oIZbW8Wr; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oIZbW8Wr" Received: by smtp.kernel.org (Postfix) with ESMTPS id 93F15C2BCFA; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=8IMEYD3n6yT8ZSbC1ZnVI+oSqA0c5prW8Yu3yOGSG30=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=oIZbW8WrItwMHYpdn4Hf75VXs8fnpDhQ4NwjdheyknMEB7eCP75ZPWyM9XuR1VplY TAmnGznDsqF/i0SZiPkfTaKe4MhMe8szqIMKJu1oFkKWTVD2v/Sz+8mAKbGkytlFUZ +p2RpRHBmhnEQki9bfDyxcN0+zOOgIskLr4qjZPfBXm41wpsGGYLCMxcCc9fDiD/0a B7Fo5A6/jgLWPykW8uKmRoSi23bT+WLaTOrNb8zgpKxXW5YdWwrQERcZnOwGgIRLWh U8fAEvbA6WhTK7tM1NbW1d26BZficW/R167rR5sIYu9bSx29VWl7Te1DMja0fLDlLf WXP7ckvNCXWqQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7EA62C5AD68; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:14 +0800 Subject: [PATCH v2 05/17] phy: spacemit: add Innosilicon DP TX PHY driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-5-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=32412; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=eiAZGYRnjMdS7Ttf5CCg6aP5MonclwmGSHwFKFiDmik=; b=NS2m4pt67V1TljSXyH7wKHLFQEhYRgyXvoH1SBFoywEwznBiv15Yct3ffYLnPU0dp2RYPLa6B ZHeX5fwwuX4ApI76mnc8FOL5P9RsSav3S6ofOLotVQ6LCvb29x7W1tD X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang The PHY's registers are interleaved into its parent DP controller's MMIO window rather than a window of its own, so it probes as a child of the controller, carries no reg or reset, and reaches its registers through the controller's regmap. It registers its pixel PLL as a clock provider. That lets the display controller ask for a mode's pixel rate through clk_set_rate(), and it lets the APMU pixel-clock mux parent to the PHY through the clock framework. Without it the controller and PHY would have to know each other's registers. Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - drop the mod_devicetable.h include (Uwe Kleine-Koenig) - unwind the lanes and pixel PLL on the power_on lock-timeout paths (Sashiko) - document why power_off keeps the MPLL up: it feeds the 16 MHz AUX reference, and AUX must survive link drops (Sashiko) - register the PHY and clock providers last in probe (Sashiko) --- drivers/phy/spacemit/Kconfig | 13 + drivers/phy/spacemit/Makefile | 1 + drivers/phy/spacemit/phy-k3-inno-dp.c | 967 ++++++++++++++++++++++++++++++= ++++ 3 files changed, 981 insertions(+) diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig index 50b0005acf663..098f33998f732 100644 --- a/drivers/phy/spacemit/Kconfig +++ b/drivers/phy/spacemit/Kconfig @@ -23,3 +23,16 @@ config PHY_SPACEMIT_K1_USB2 help Enable this to support K1 USB 2.0 PHY driver. This driver takes care of enabling and clock setup and will be used by K1 udc/ehci/otg/xhci drive= r. + +config PHY_SPACEMIT_K3_INNO_DP + tristate "SpacemiT K3 Innosilicon DisplayPort PHY driver" + depends on (ARCH_SPACEMIT || COMPILE_TEST) && OF + depends on COMMON_CLK + select GENERIC_PHY + select REGMAP + help + Enable support for the Innosilicon DisplayPort transmit PHY + integrated in the SpacemiT K3 SoC. The PHY shares its MMIO window + with its parent DP/eDP controller (drivers/gpu/drm/spacemit/) and + exposes lane / rate / vswing / pre-emphasis control through the + generic PHY framework. diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile index a821a21d61422..960c5827f5e5f 100644 --- a/drivers/phy/spacemit/Makefile +++ b/drivers/phy/spacemit/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) +=3D phy-k1-pcie.o obj-$(CONFIG_PHY_SPACEMIT_K1_USB2) +=3D phy-k1-usb2.o +obj-$(CONFIG_PHY_SPACEMIT_K3_INNO_DP) +=3D phy-k3-inno-dp.o diff --git a/drivers/phy/spacemit/phy-k3-inno-dp.c b/drivers/phy/spacemit/p= hy-k3-inno-dp.c new file mode 100644 index 0000000000000..42ebfc347b84b --- /dev/null +++ b/drivers/phy/spacemit/phy-k3-inno-dp.c @@ -0,0 +1,967 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SpacemiT K3 Innosilicon DisplayPort PHY driver. + * + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Offsets are into the parent controller's MMIO window */ +#define DPTX_PHY_CTRL 0x0100 +#define DPTX_PHY_CTRL_XMIT_EN GENMASK(20, 17) +#define DPTX_PHY_CTRL_NUM_LANES GENMASK(6, 5) +#define DPTX_PHY_CTRL_RATE GENMASK(1, 0) + +/* One 6-bit slot per lane; only the low 4 bits of each slot are used. */ +#define DPTX_PHY_LANE_TRIM 0x0104 +#define DPTX_PHY_LANE_BITS_PER 6 +#define DPTX_PHY_LANE_FIELD_MASK 0xf /* preemp[1:0] | vswing[1:0] */ +#define DPTX_PHY_LANE_VSWING_SHIFT 2 /* within the lane field */ + +/* MPLL is the link PLL (lane rate) */ +#define DPTX_ANA_MPLL 0x0180 +#define DPTX_ANA_MPLL_FBDIV_LBIT GENMASK(31, 24) +#define DPTX_ANA_MPLL_FBDIV_HBIT GENMASK(19, 16) +#define DPTX_ANA_MPLL_PREDIV GENMASK(13, 8) +#define DPTX_ANA_MPLL_LOCKED BIT(7) +#define DPTX_ANA_MPLL_DACPD BIT(5) +#define DPTX_ANA_MPLL_DSMPD BIT(4) +#define DPTX_ANA_MPLL_PD BIT(0) + +#define DPTX_ANA_MPLL_FRAC 0x0184 +#define DPTX_ANA_MPLL_FRAC_LBIT GENMASK(23, 16) +#define DPTX_ANA_MPLL_FRAC_MBIT GENMASK(15, 8) +#define DPTX_ANA_MPLL_FRAC_HBIT GENMASK(7, 0) + +#define DPTX_ANA_MPLL_DIV 0x0188 +#define DPTX_ANA_MPLL_VCOCLK_DIV8_EN BIT(16) +#define DPTX_ANA_MPLL_POSTDIVEN BIT(11) +#define DPTX_ANA_MPLL_POSTDIV GENMASK(10, 8) + +/* PREPLL is the pixel PLL exposed as a clock. */ +#define DPTX_ANA_PREPLL 0x0190 +#define DPTX_ANA_PREPLL_FBDIV2_LBIT GENMASK(31, 24) +#define DPTX_ANA_PREPLL_FBDIV2_HBIT GENMASK(19, 16) +#define DPTX_ANA_PREPLL_PREDIV GENMASK(13, 8) +#define DPTX_ANA_PREPLL_LOCKED BIT(7) +#define DPTX_ANA_PREPLL_DACPD BIT(5) +#define DPTX_ANA_PREPLL_DSMPD BIT(4) +#define DPTX_ANA_PREPLL_PCLK_NORMAL BIT(1) +#define DPTX_ANA_PREPLL_PD BIT(0) + +#define DPTX_ANA_PREPLL_DIV 0x0194 +#define DPTX_ANA_PREPLL_PRECLK_DIVM GENMASK(17, 16) +#define DPTX_ANA_PREPLL_PRECLK_DIVAUX GENMASK(12, 8) + +#define DPTX_ANA_PREPLL_CTRL 0x0198 +#define DPTX_ANA_PREPLL_PCLKDIV5_EN BIT(31) +#define DPTX_ANA_PREPLL_PCLK_DIVAUX GENMASK(28, 24) +#define DPTX_ANA_PREPLL_LOCK_BYPEN BIT(17) +#define DPTX_ANA_PREPLL_HDMI_EN BIT(9) +#define DPTX_ANA_PREPLL_DP_EN BIT(8) + +#define DPTX_ANA_PREPLL_FRAC 0x019c +#define DPTX_ANA_PREPLL_FRAC2_LBIT GENMASK(23, 16) +#define DPTX_ANA_PREPLL_FRAC2_MBIT GENMASK(15, 8) +#define DPTX_ANA_PREPLL_FRAC2_HBIT GENMASK(7, 0) + +#define DPTX_ANA_TX_CTRL 0x01a0 +#define DPTX_ANA_MPLL_CLKDIV_16M GENMASK(13, 8) + +/* PRECLK_DIVM register value -> divide factor */ +static const u8 k3_inno_dp_divm_factors[] =3D { 1, 2, 3, 5 }; + +#define DPTX_VCO_MIN_KHZ 1000000 +#define DPTX_VCO_MAX_KHZ 3000000 +#define DPTX_PLL_FRAC_MOD (1 << 24) +#define DPTX_PLL_ERR_TOLERANCE 10 + +struct k3_inno_dp_phy { + struct device *dev; + struct regmap *regmap; + struct phy *phy; + u8 lanes; /* tracks last set_lanes */ + + struct clk_hw pxclk_hw; /* the PREPLL's pixel clock */ + unsigned long pxclk_rate; /* last programmed PREPLL rate */ + u32 ref_clk_khz; /* PLL reference */ +}; + +static int k3_inno_dp_phy_power_on(struct phy *phy) +{ + struct k3_inno_dp_phy *p =3D phy_get_drvdata(phy); + u32 lane_en; + u32 val; + int ret; + + switch (p->lanes) { + case 1: + lane_en =3D 0x1; + break; + case 2: + lane_en =3D 0x3; + break; + case 4: + default: + lane_en =3D 0xf; + break; + } + + ret =3D regmap_write_bits(p->regmap, DPTX_ANA_MPLL, DPTX_ANA_MPLL_PD, 0); + if (ret) + return ret; + ret =3D regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, + DPTX_ANA_PREPLL_PD, 0); + if (ret) + return ret; + usleep_range(2000, 4000); + + ret =3D regmap_write_bits(p->regmap, DPTX_PHY_CTRL, + DPTX_PHY_CTRL_XMIT_EN, + FIELD_PREP(DPTX_PHY_CTRL_XMIT_EN, lane_en)); + if (ret) + return ret; + usleep_range(2000, 4000); + + ret =3D regmap_read_poll_timeout(p->regmap, DPTX_ANA_MPLL, val, + val & DPTX_ANA_MPLL_LOCKED, + 2000, 10 * 1000); + if (ret) { + dev_err(p->dev, "DP PHY core PLL lock timed out\n"); + goto err_power_down; + } + + ret =3D regmap_read_poll_timeout(p->regmap, DPTX_ANA_PREPLL, val, + val & DPTX_ANA_PREPLL_LOCKED, + 2000, 10 * 1000); + if (ret) { + dev_err(p->dev, "DP PHY pixel PLL lock timed out\n"); + goto err_power_down; + } + + return 0; + + /* + * The PHY core does not call power_off after a failed power_on, so + * park what power_off parks. Not the MPLL: see power_off. + */ +err_power_down: + regmap_write_bits(p->regmap, DPTX_PHY_CTRL, DPTX_PHY_CTRL_XMIT_EN, 0); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_PD, + DPTX_ANA_PREPLL_PD); + return ret; +} + +/* + * Asymmetric with power_on on purpose: the MPLL stays up because it also + * feeds the 16 MHz AUX reference (DPTX_ANA_MPLL_CLKDIV_16M), and AUX must + * keep working while the link is down (EDID, DPCD, panel detection). The + * controller parks the PHY through here on every link drop, including + * right after bind. + */ +static int k3_inno_dp_phy_power_off(struct phy *phy) +{ + struct k3_inno_dp_phy *p =3D phy_get_drvdata(phy); + + regmap_write_bits(p->regmap, DPTX_PHY_CTRL, DPTX_PHY_CTRL_XMIT_EN, 0); + usleep_range(2000, 4000); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_PD, + DPTX_ANA_PREPLL_PD); + usleep_range(2000, 4000); + + return 0; +} + +static int k3_inno_dp_phy_set_lanes(struct k3_inno_dp_phy *p, u8 lanes) +{ + u32 val; + int ret; + + switch (lanes) { + case 1: + val =3D 0; + break; + case 2: + val =3D 1; + break; + case 4: + val =3D 2; + break; + default: + return -EINVAL; + } + + ret =3D regmap_write_bits(p->regmap, DPTX_PHY_CTRL, + DPTX_PHY_CTRL_NUM_LANES, + FIELD_PREP(DPTX_PHY_CTRL_NUM_LANES, val)); + if (ret) + return ret; + + p->lanes =3D lanes; + return 0; +} + +struct k3_inno_dp_mpll_cfg { + unsigned int link_rate; /* Mbps per lane */ + u8 prediv; + u16 fbdiv; + u32 frac; + u8 postdiv; + u8 postdiv_en; + u8 frac_pd; + u8 vcoclk_div8_en; + u8 clk_16mdiv; +}; + +static const struct k3_inno_dp_mpll_cfg k3_inno_dp_mpll_cfgs[] =3D { + { + .link_rate =3D 1620, + .prediv =3D 0x02, + .fbdiv =3D 0x87, + .frac =3D 0, + .postdiv =3D 0, + .postdiv_en =3D 1, + .frac_pd =3D 0x3, + .vcoclk_div8_en =3D 1, + .clk_16mdiv =3D 12, + }, { + .link_rate =3D 2700, + .prediv =3D 0x02, + .fbdiv =3D 0xe1, + .frac =3D 0, + .postdiv =3D 0, + .postdiv_en =3D 1, + .frac_pd =3D 0x3, + .vcoclk_div8_en =3D 1, + .clk_16mdiv =3D 21, + }, { + .link_rate =3D 5400, + .prediv =3D 0x02, + .fbdiv =3D 0xe1, + .frac =3D 0, + .postdiv =3D 0, + .postdiv_en =3D 0, + .frac_pd =3D 0x3, + .vcoclk_div8_en =3D 0, + .clk_16mdiv =3D 42, + }, +}; + +static void k3_inno_dp_phy_program_mpll(struct k3_inno_dp_phy *p, + const struct k3_inno_dp_mpll_cfg *cfg) +{ + struct regmap *rm =3D p->regmap; + + /* + * Shared with an unwired HDMI path: select DP first, otherwise the + * PLLs still lock but nothing reaches the lanes and AUX times out. + */ + regmap_write_bits(rm, DPTX_ANA_PREPLL_CTRL, DPTX_ANA_PREPLL_DP_EN, + DPTX_ANA_PREPLL_DP_EN); + regmap_write_bits(rm, DPTX_ANA_PREPLL_CTRL, DPTX_ANA_PREPLL_HDMI_EN, 0); + + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_PD, + FIELD_PREP(DPTX_ANA_MPLL_PD, 1)); + usleep_range(2000, 4000); + + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_PREDIV, + FIELD_PREP(DPTX_ANA_MPLL_PREDIV, cfg->prediv)); + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_FBDIV_LBIT, + FIELD_PREP(DPTX_ANA_MPLL_FBDIV_LBIT, cfg->fbdiv & 0xff)); + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_FBDIV_HBIT, + FIELD_PREP(DPTX_ANA_MPLL_FBDIV_HBIT, (cfg->fbdiv >> 8) & 0xf)); + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_DACPD, + FIELD_PREP(DPTX_ANA_MPLL_DACPD, (cfg->frac_pd >> 1) & 0x1)); + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_DSMPD, + FIELD_PREP(DPTX_ANA_MPLL_DSMPD, cfg->frac_pd & 0x1)); + + regmap_write_bits(rm, DPTX_ANA_MPLL_FRAC, DPTX_ANA_MPLL_FRAC_LBIT, + FIELD_PREP(DPTX_ANA_MPLL_FRAC_LBIT, cfg->frac & 0xff)); + regmap_write_bits(rm, DPTX_ANA_MPLL_FRAC, DPTX_ANA_MPLL_FRAC_MBIT, + FIELD_PREP(DPTX_ANA_MPLL_FRAC_MBIT, (cfg->frac >> 8) & 0xff)); + regmap_write_bits(rm, DPTX_ANA_MPLL_FRAC, DPTX_ANA_MPLL_FRAC_HBIT, + FIELD_PREP(DPTX_ANA_MPLL_FRAC_HBIT, (cfg->frac >> 16) & 0xff)); + + regmap_write_bits(rm, DPTX_ANA_MPLL_DIV, DPTX_ANA_MPLL_POSTDIV, + FIELD_PREP(DPTX_ANA_MPLL_POSTDIV, cfg->postdiv)); + regmap_write_bits(rm, DPTX_ANA_MPLL_DIV, DPTX_ANA_MPLL_POSTDIVEN, + FIELD_PREP(DPTX_ANA_MPLL_POSTDIVEN, cfg->postdiv_en)); + regmap_write_bits(rm, DPTX_ANA_MPLL_DIV, DPTX_ANA_MPLL_VCOCLK_DIV8_EN, + FIELD_PREP(DPTX_ANA_MPLL_VCOCLK_DIV8_EN, cfg->vcoclk_div8_en)); + + regmap_write_bits(rm, DPTX_ANA_TX_CTRL, DPTX_ANA_MPLL_CLKDIV_16M, + FIELD_PREP(DPTX_ANA_MPLL_CLKDIV_16M, cfg->clk_16mdiv)); + + regmap_write_bits(rm, DPTX_ANA_PREPLL_CTRL, DPTX_ANA_PREPLL_LOCK_BYPEN, + FIELD_PREP(DPTX_ANA_PREPLL_LOCK_BYPEN, 1)); + + regmap_write_bits(rm, DPTX_ANA_MPLL, DPTX_ANA_MPLL_PD, + FIELD_PREP(DPTX_ANA_MPLL_PD, 0)); + usleep_range(2000, 4000); +} + +static int k3_inno_dp_phy_set_rate(struct k3_inno_dp_phy *p, + unsigned int link_rate) +{ + const struct k3_inno_dp_mpll_cfg *cfg =3D NULL; + unsigned int i; + u32 sel; + + switch (link_rate) { + case 1620: + sel =3D 0; + break; + case 2700: + sel =3D 1; + break; + case 5400: + sel =3D 2; + break; + default: + return -EINVAL; + } + + for (i =3D 0; i < ARRAY_SIZE(k3_inno_dp_mpll_cfgs); i++) { + if (k3_inno_dp_mpll_cfgs[i].link_rate =3D=3D link_rate) { + cfg =3D &k3_inno_dp_mpll_cfgs[i]; + break; + } + } + if (!cfg) + return -EINVAL; + + k3_inno_dp_phy_program_mpll(p, cfg); + + return regmap_write_bits(p->regmap, DPTX_PHY_CTRL, + DPTX_PHY_CTRL_RATE, + FIELD_PREP(DPTX_PHY_CTRL_RATE, sel)); +} + +static int k3_inno_dp_phy_set_voltages(struct k3_inno_dp_phy *p, + struct phy_configure_opts_dp *opts) +{ + u8 lane; + int ret; + + for (lane =3D 0; lane < opts->lanes; lane++) { + unsigned int shift =3D lane * DPTX_PHY_LANE_BITS_PER; + u32 mask =3D DPTX_PHY_LANE_FIELD_MASK << shift; + u32 val =3D (((opts->voltage[lane] & 0x3) << DPTX_PHY_LANE_VSWING_SHIFT= ) | + (opts->pre[lane] & 0x3)) << shift; + + ret =3D regmap_write_bits(p->regmap, DPTX_PHY_LANE_TRIM, mask, + val); + if (ret) + return ret; + } + + return 0; +} + +static int k3_inno_dp_phy_configure(struct phy *phy, + union phy_configure_opts *opts) +{ + struct k3_inno_dp_phy *p =3D phy_get_drvdata(phy); + int ret; + + if (opts->dp.set_lanes) { + ret =3D k3_inno_dp_phy_set_lanes(p, opts->dp.lanes); + if (ret) + return ret; + } + + if (opts->dp.set_rate) { + ret =3D k3_inno_dp_phy_set_rate(p, opts->dp.link_rate); + if (ret) + return ret; + } + + if (opts->dp.set_voltages) { + ret =3D k3_inno_dp_phy_set_voltages(p, &opts->dp); + if (ret) + return ret; + } + + return 0; +} + +static u32 k3_inno_dp_div64(u64 *n, u32 base) +{ + return do_div(*n, base); +} + +static int k3_inno_dp_better_cfg(bool new_valid, bool new_is_int, u8 new_p= re, u32 new_vco, + bool best_valid, bool best_is_int, u8 best_pre, u32 best_vco) +{ + if (!new_valid) + return 0; + if (!best_valid) + return 1; + + if (new_is_int && !best_is_int) + return 1; + if (!new_is_int && best_is_int) + return 0; + + if (new_pre < best_pre) + return 1; + if (new_pre > best_pre) + return 0; + + if (new_vco > best_vco) + return 1; + + return 0; +} + +struct k3_inno_dp_prepll_cfg { + u32 target_pclk_khz; + u32 vco_freq_khz; + u8 prediv; + u16 fbdiv; + u32 frac_pd; + u32 frac; + u8 div5_en; + u8 divm; + u8 divaux; + u8 divp; + u32 actual_pclk_khz; + bool valid; +}; + +static const struct k3_inno_dp_prepll_cfg k3_inno_dp_prepll_cfgs[] =3D { + { 614400, 2460000, 0x05, 512, 0x3, 0x0, 0x0, 0x1, 0x01, 0x1, 614400, tru= e }, + { 594000, 2376000, 0x01, 99, 0x3, 0x0, 0x0, 0x1, 0x01, 0x1, 594000, tru= e }, + { 551040, 2760000, 0x05, 574, 0x3, 0x0, 0x1, 0x0, 0x00, 0x0, 551040, tru= e }, + { 533250, 2130000, 0x08, 711, 0x3, 0x0, 0x0, 0x1, 0x01, 0x1, 533250, tru= e }, + { 443250, 1770000, 0x08, 591, 0x3, 0x0, 0x0, 0x1, 0x01, 0x1, 443250, tru= e }, + { 375000, 3000000, 0x01, 125, 0x3, 0x0, 0x0, 0x0, 0x04, 0x1, 375000, tru= e }, + { 372000, 2980000, 0x01, 124, 0x3, 0x0, 0x0, 0x0, 0x04, 0x1, 372000, tru= e }, + { 348500, 2790000, 0x06, 697, 0x3, 0x0, 0x0, 0x0, 0x04, 0x1, 348500, tru= e }, + { 307200, 1540000, 0x01, 64, 0x3, 0x0, 0x1, 0x0, 0x00, 0x0, 307200, tru= e }, + { 297000, 2376000, 0x01, 99, 0x3, 0x0, 0x0, 0x0, 0x04, 0x1, 297000, tru= e }, + { 280000, 1680000, 0x01, 70, 0x3, 0x0, 0x0, 0x2, 0x01, 0x1, 280000, tru= e }, + { 277440, 2770000, 0x05, 578, 0x3, 0x0, 0x0, 0x3, 0x01, 0x1, 277440, tru= e }, + { 245760, 2457600, 0x05, 512, 0x3, 0x0, 0x0, 0x3, 0x01, 0x1, 245760, tru= e }, + { 241500, 1932000, 0x02, 161, 0x3, 0x0, 0x0, 0x0, 0x04, 0x1, 241500, tru= e }, + { 236000, 2830000, 0x01, 118, 0x3, 0x0, 0x0, 0x0, 0x06, 0x1, 236000, tru= e }, + { 204800, 2048000, 0x03, 256, 0x3, 0x0, 0x0, 0x3, 0x01, 0x1, 204800, tru= e }, + { 193250, 2320000, 0x08, 773, 0x3, 0x0, 0x0, 0x0, 0x06, 0x1, 193250, tru= e }, + { 189000, 1510000, 0x01, 63, 0x3, 0x0, 0x0, 0x0, 0x04, 0x1, 189000, tru= e }, + { 187500, 3000000, 0x01, 125, 0x3, 0x0, 0x0, 0x0, 0x08, 0x1, 187500, tru= e }, + { 162000, 2592000, 0x01, 108, 0x3, 0x0, 0x0, 0x0, 0x08, 0x1, 162000, tru= e }, + { 156000, 2810000, 0x01, 117, 0x3, 0x0, 0x0, 0x0, 0x09, 0x1, 156000, tru= e }, + { 150000, 3000000, 0x01, 125, 0x3, 0x0, 0x0, 0x0, 0x0a, 0x1, 150000, tru= e }, + { 148500, 2376000, 0x01, 99, 0x3, 0x0, 0x0, 0x0, 0x08, 0x1, 148500, tru= e }, + { 146000, 1750000, 0x01, 73, 0x3, 0x0, 0x0, 0x0, 0x06, 0x1, 146000, tru= e }, + { 142860, 2860000, 0x14, 2381, 0x3, 0x0, 0x0, 0x0, 0x0a, 0x1, 142860, tru= e }, + { 140000, 2520000, 0x01, 105, 0x3, 0x0, 0x0, 0x0, 0x09, 0x1, 140000, tru= e }, + { 138500, 2220000, 0x03, 277, 0x3, 0x0, 0x0, 0x0, 0x08, 0x1, 138500, tru= e }, + { 122000, 2930000, 0x01, 122, 0x3, 0x0, 0x0, 0x0, 0x0c, 0x1, 122000, tru= e }, + { 121750, 2920000, 0x04, 487, 0x3, 0x0, 0x0, 0x0, 0x0c, 0x1, 121750, tru= e }, + { 108000, 2810000, 0x01, 117, 0x3, 0x0, 0x0, 0x0, 0x0d, 0x1, 108000, tru= e }, + { 106500, 1700000, 0x01, 71, 0x3, 0x0, 0x0, 0x0, 0x08, 0x1, 106500, tru= e }, + { 83500, 2000000, 0x02, 167, 0x3, 0x0, 0x0, 0x0, 0x0c, 0x1, 83500, tru= e }, + { 79500, 2540000, 0x01, 106, 0x3, 0x0, 0x0, 0x0, 0x10, 0x1, 79500, tru= e }, + { 75000, 3000000, 0x01, 125, 0x3, 0x0, 0x0, 0x0, 0x14, 0x1, 75000, tru= e }, + { 74250, 2376000, 0x01, 99, 0x3, 0x0, 0x0, 0x0, 0x10, 0x1, 74250, tru= e }, + { 65000, 1560000, 0x01, 65, 0x3, 0x0, 0x0, 0x0, 0x0c, 0x1, 65000, tru= e }, + { 40000, 2880000, 0x01, 120, 0x3, 0x0, 0x0, 0x0, 0x12, 0x2, 40000, tru= e }, + { 27000, 2810000, 0x01, 117, 0x3, 0x0, 0x0, 0x0, 0x1a, 0x2, 27000, tru= e }, + { 25600, 2300000, 0x01, 96, 0x3, 0x0, 0x0, 0x0, 0x0f, 0x3, 25600, tru= e }, + { 25200, 2520000, 0x01, 105, 0x3, 0x0, 0x0, 0x0, 0x19, 0x2, 25200, tru= e }, +}; + +static u64 k3_inno_dp_abs_diff(u64 a, u64 b) +{ + return (a > b) ? (a - b) : (b - a); +} + +static u32 k3_inno_dp_pll_rate_khz(u8 pre, u16 fb, u32 frac, + u32 ref_clk_khz, u32 total_div) +{ + u64 vco_hz; + u64 ref_hz =3D (u64)ref_clk_khz * 1000; + u64 int_part; + u64 frac_part; + + /* Integer part: (Ref * FB) / Pre */ + int_part =3D ref_hz * fb; + int_part +=3D (pre / 2); + k3_inno_dp_div64(&int_part, pre); + + /* Fractional part: (Ref * Frac) / (Pre * 2^24) */ + frac_part =3D ref_hz * frac; + + frac_part +=3D (pre / 2); + k3_inno_dp_div64(&frac_part, pre); + + frac_part +=3D (DPTX_PLL_FRAC_MOD / 2); + k3_inno_dp_div64(&frac_part, DPTX_PLL_FRAC_MOD); + + vco_hz =3D int_part + frac_part; + + /* Final Rate =3D VCO / total_div */ + vco_hz +=3D (total_div / 2); + k3_inno_dp_div64(&vco_hz, total_div); + + vco_hz +=3D 500; + k3_inno_dp_div64(&vco_hz, 1000); + + return (u32)vco_hz; +} + +static int k3_inno_dp_prepll_div_total(const struct k3_inno_dp_prepll_cfg = *cfg, + u32 *div_total) +{ + if (!cfg || !div_total || !cfg->valid) + return -EINVAL; + + /* div5_en fixes div_total at 5; divp is unused on this path */ + if (cfg->div5_en) { + *div_total =3D 5; + return 0; + } + + if (!cfg->divp) + return -EINVAL; + + if (cfg->divaux =3D=3D 1) { + if (cfg->divm >=3D ARRAY_SIZE(k3_inno_dp_divm_factors)) + return -EINVAL; + + *div_total =3D 2 * k3_inno_dp_divm_factors[cfg->divm] * cfg->divp; + return 0; + } + + if (cfg->divaux < 2) + return -EINVAL; + + *div_total =3D 2 * cfg->divaux * cfg->divp; + return 0; +} + +static bool k3_inno_dp_prepll_cfg_matches(const struct k3_inno_dp_prepll_c= fg *cfg, + u32 target_pclk_khz, + u32 ref_clk_khz) +{ + u32 div_total; + u32 actual_pclk_khz; + + if (k3_inno_dp_prepll_div_total(cfg, &div_total)) + return false; + + actual_pclk_khz =3D k3_inno_dp_pll_rate_khz(cfg->prediv, cfg->fbdiv, + cfg->frac, ref_clk_khz, + div_total); + + if (cfg->actual_pclk_khz && + k3_inno_dp_abs_diff(actual_pclk_khz, + cfg->actual_pclk_khz) > DPTX_PLL_ERR_TOLERANCE) + return false; + + return k3_inno_dp_abs_diff(actual_pclk_khz, + target_pclk_khz) <=3D DPTX_PLL_ERR_TOLERANCE; +} + +static const struct k3_inno_dp_prepll_cfg *k3_inno_dp_find_prepll_cfg(u32 = pclk_khz, + u32 ref_clk_khz) +{ + const struct k3_inno_dp_prepll_cfg *best_match =3D NULL; + u32 min_diff =3D 0xFFFFFFFF; + int num_configs =3D ARRAY_SIZE(k3_inno_dp_prepll_cfgs); + + for (int i =3D 0; i < num_configs; i++) { + u32 current_target =3D k3_inno_dp_prepll_cfgs[i].target_pclk_khz; + u32 diff =3D k3_inno_dp_abs_diff(pclk_khz, current_target); + + if (diff =3D=3D 0 && k3_inno_dp_prepll_cfg_matches(&k3_inno_dp_prepll_cf= gs[i], + pclk_khz, ref_clk_khz)) { + return &k3_inno_dp_prepll_cfgs[i]; + } + + if ((pclk_khz / 100) =3D=3D (current_target / 100) && + k3_inno_dp_prepll_cfg_matches(&k3_inno_dp_prepll_cfgs[i], + pclk_khz, ref_clk_khz)) { + return &k3_inno_dp_prepll_cfgs[i]; + } + + if (diff < min_diff && diff < 500 && + k3_inno_dp_prepll_cfg_matches(&k3_inno_dp_prepll_cfgs[i], + pclk_khz, ref_clk_khz)) { + min_diff =3D diff; + best_match =3D &k3_inno_dp_prepll_cfgs[i]; + } + } + + return best_match; +} + +static int k3_inno_dp_solve_frac(u32 target_vco_khz, u32 ref_clk_khz, + u8 *best_pre, u16 *best_fb, u32 *best_frac) +{ + u64 min_err =3D ~0ULL; + int found =3D 0; + bool best_is_int =3D false; + int pre; + + for (pre =3D 1; pre <=3D 63; pre++) { + u64 ref_clk_hz =3D (u64)ref_clk_khz * 1000; + u64 target_vco_hz =3D (u64)target_vco_khz * 1000; + + /* + * Calculate required multiplier: Mult =3D (TargetVCO * Pre) / Ref + */ + u64 num =3D target_vco_hz * pre; + u64 den =3D ref_clk_hz; + u64 remainder; + u64 fb_val; + u64 frac_val; + u64 actual_vco; + u64 diff; + bool current_is_int; + + fb_val =3D num; + remainder =3D k3_inno_dp_div64(&fb_val, (u32)den); + + if (fb_val > 4095) + continue; + + /* Frac =3D (Remainder * 2^24 + Ref/2) / Ref */ + frac_val =3D remainder * DPTX_PLL_FRAC_MOD; + frac_val +=3D (den / 2); + k3_inno_dp_div64(&frac_val, (u32)den); + + if (frac_val > 0xFFFFFF) + frac_val =3D 0xFFFFFF; + + /* VCO =3D (Ref * FB / Pre) + (Ref * Frac / (Pre * 2^24)) */ + { + u64 vco_int, vco_frac; + + vco_int =3D ref_clk_hz * fb_val; + k3_inno_dp_div64(&vco_int, pre); + vco_frac =3D ref_clk_hz * frac_val; + k3_inno_dp_div64(&vco_frac, pre); + k3_inno_dp_div64(&vco_frac, DPTX_PLL_FRAC_MOD); + + actual_vco =3D vco_int + vco_frac; + } + + diff =3D k3_inno_dp_abs_diff(actual_vco, target_vco_hz); + current_is_int =3D (frac_val =3D=3D 0); + + if (diff < min_err) { + min_err =3D diff; + *best_pre =3D pre; + *best_fb =3D (u16)fb_val; + *best_frac =3D (u32)frac_val; + best_is_int =3D current_is_int; + found =3D 1; + } else if (diff =3D=3D min_err) { + if (current_is_int && !best_is_int) { + *best_pre =3D pre; + *best_fb =3D (u16)fb_val; + *best_frac =3D (u32)frac_val; + best_is_int =3D true; + found =3D 1; + } + } + } + + return found ? 0 : -EINVAL; +} + +/* divaux must be 1 for the DivM path and > 1 for the DivAux path. */ +static void k3_inno_dp_try_prepll(u32 target_pclk_khz, u32 ref_clk_khz, + u32 div_total, u8 div5_en, u8 divaux, + u8 divm, u8 divp, + struct k3_inno_dp_prepll_cfg *best) +{ + struct k3_inno_dp_prepll_cfg curr =3D {0}; + u32 target_vco =3D target_pclk_khz * div_total; + u32 actual_pclk; + u32 frac; + u16 fb; + u8 pre; + + if (target_vco < DPTX_VCO_MIN_KHZ || target_vco > DPTX_VCO_MAX_KHZ) + return; + + if (k3_inno_dp_solve_frac(target_vco, ref_clk_khz, &pre, &fb, &frac)) + return; + + actual_pclk =3D k3_inno_dp_pll_rate_khz(pre, fb, frac, ref_clk_khz, + div_total); + if (k3_inno_dp_abs_diff(actual_pclk, target_pclk_khz) > DPTX_PLL_ERR_TOLE= RANCE) + return; + + curr.valid =3D true; + curr.vco_freq_khz =3D target_vco; + curr.actual_pclk_khz =3D actual_pclk; + curr.prediv =3D pre; + curr.fbdiv =3D fb; + curr.frac =3D frac; + curr.frac_pd =3D (frac =3D=3D 0) ? 3 : 0; + curr.div5_en =3D div5_en; + curr.divaux =3D divaux; + curr.divm =3D divm; + curr.divp =3D divp; + + if (k3_inno_dp_better_cfg(curr.valid, curr.frac =3D=3D 0, curr.prediv, + curr.vco_freq_khz, best->valid, + best->frac =3D=3D 0, best->prediv, + best->vco_freq_khz)) + *best =3D curr; +} + +static int k3_inno_dp_solve_prepll(u32 target_pclk_khz, u32 ref_clk_khz, + struct k3_inno_dp_prepll_cfg *cfg) +{ + struct k3_inno_dp_prepll_cfg best =3D {0}; + int pclk_div; + int i; + + /* Strategy 1: Div5 path (VCO =3D PCLK * 5) */ + k3_inno_dp_try_prepll(target_pclk_khz, ref_clk_khz, 5, 1, 0, 0, 0, + &best); + + for (pclk_div =3D 1; pclk_div <=3D 31; pclk_div++) { + /* Strategy 2: DivM path */ + for (i =3D 0; i < ARRAY_SIZE(k3_inno_dp_divm_factors); i++) + k3_inno_dp_try_prepll(target_pclk_khz, ref_clk_khz, + 2 * k3_inno_dp_divm_factors[i] * pclk_div, 0, 1, + i, pclk_div, &best); + + /* Strategy 3: DivAux path */ + for (i =3D 2; i <=3D 31; i++) + k3_inno_dp_try_prepll(target_pclk_khz, ref_clk_khz, + 2 * i * pclk_div, + 0, i, 0, pclk_div, &best); + } + + if (!best.valid) + return -EINVAL; + + *cfg =3D best; + return 0; +} + +static void k3_inno_dp_program_prepll(struct k3_inno_dp_phy *p, + const struct k3_inno_dp_prepll_cfg *cfg) +{ + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_PD, + FIELD_PREP(DPTX_ANA_PREPLL_PD, 1)); + usleep_range(2000, 4000); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_PREDIV, + FIELD_PREP(DPTX_ANA_PREPLL_PREDIV, cfg->prediv)); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, + DPTX_ANA_PREPLL_FBDIV2_LBIT, + FIELD_PREP(DPTX_ANA_PREPLL_FBDIV2_LBIT, cfg->fbdiv & 0xFF)); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, + DPTX_ANA_PREPLL_FBDIV2_HBIT, + FIELD_PREP(DPTX_ANA_PREPLL_FBDIV2_HBIT, (cfg->fbdiv >> 8) & 0xF)); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_DACPD, + FIELD_PREP(DPTX_ANA_PREPLL_DACPD, (cfg->frac_pd >> 1) & 0x1)); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_DSMPD, + FIELD_PREP(DPTX_ANA_PREPLL_DSMPD, cfg->frac_pd & 0x1)); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_FRAC, + DPTX_ANA_PREPLL_FRAC2_LBIT, + FIELD_PREP(DPTX_ANA_PREPLL_FRAC2_LBIT, cfg->frac & 0xFF)); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_FRAC, + DPTX_ANA_PREPLL_FRAC2_MBIT, + FIELD_PREP(DPTX_ANA_PREPLL_FRAC2_MBIT, (cfg->frac >> 8) & 0xFF)); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_FRAC, + DPTX_ANA_PREPLL_FRAC2_HBIT, + FIELD_PREP(DPTX_ANA_PREPLL_FRAC2_HBIT, (cfg->frac >> 16) & 0xFF)); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_DIV, + DPTX_ANA_PREPLL_PRECLK_DIVM, + FIELD_PREP(DPTX_ANA_PREPLL_PRECLK_DIVM, cfg->divm)); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_DIV, + DPTX_ANA_PREPLL_PRECLK_DIVAUX, + FIELD_PREP(DPTX_ANA_PREPLL_PRECLK_DIVAUX, cfg->divaux)); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_CTRL, + DPTX_ANA_PREPLL_PCLKDIV5_EN, + FIELD_PREP(DPTX_ANA_PREPLL_PCLKDIV5_EN, cfg->div5_en)); + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL_CTRL, + DPTX_ANA_PREPLL_PCLK_DIVAUX, + FIELD_PREP(DPTX_ANA_PREPLL_PCLK_DIVAUX, cfg->divp)); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, + DPTX_ANA_PREPLL_PCLK_NORMAL, + FIELD_PREP(DPTX_ANA_PREPLL_PCLK_NORMAL, 1)); + usleep_range(2000, 4000); + + regmap_write_bits(p->regmap, DPTX_ANA_PREPLL, DPTX_ANA_PREPLL_PD, + FIELD_PREP(DPTX_ANA_PREPLL_PD, 0)); + usleep_range(2000, 4000); +} + +#define to_k3_inno_dp_phy_clk(_hw) \ + container_of(_hw, struct k3_inno_dp_phy, pxclk_hw) + +static unsigned long k3_inno_dp_pxclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct k3_inno_dp_phy *p =3D to_k3_inno_dp_phy_clk(hw); + + return p->pxclk_rate; +} + +static int k3_inno_dp_pxclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct k3_inno_dp_phy *p =3D to_k3_inno_dp_phy_clk(hw); + const struct k3_inno_dp_prepll_cfg *cfg; + struct k3_inno_dp_prepll_cfg solved; + u32 khz =3D div_u64(req->rate, 1000); + int ret; + + cfg =3D k3_inno_dp_find_prepll_cfg(khz, p->ref_clk_khz); + if (cfg) { + req->rate =3D (unsigned long)cfg->actual_pclk_khz * 1000; + return 0; + } + + ret =3D k3_inno_dp_solve_prepll(khz, p->ref_clk_khz, &solved); + if (ret) + return ret; + + req->rate =3D (unsigned long)solved.actual_pclk_khz * 1000; + + return 0; +} + +static int k3_inno_dp_pxclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct k3_inno_dp_phy *p =3D to_k3_inno_dp_phy_clk(hw); + const struct k3_inno_dp_prepll_cfg *cfg; + struct k3_inno_dp_prepll_cfg solved; + u32 khz =3D div_u64(rate, 1000); + int ret; + + cfg =3D k3_inno_dp_find_prepll_cfg(khz, p->ref_clk_khz); + if (!cfg) { + ret =3D k3_inno_dp_solve_prepll(khz, p->ref_clk_khz, &solved); + if (ret) { + dev_err(p->dev, "no PLL setting for %lu Hz\n", rate); + return ret; + } + cfg =3D &solved; + } + + k3_inno_dp_program_prepll(p, cfg); + p->pxclk_rate =3D (unsigned long)cfg->actual_pclk_khz * 1000; + + return 0; +} + +static const struct clk_ops k3_inno_dp_pxclk_ops =3D { + .recalc_rate =3D k3_inno_dp_pxclk_recalc_rate, + .determine_rate =3D k3_inno_dp_pxclk_determine_rate, + .set_rate =3D k3_inno_dp_pxclk_set_rate, +}; + +static const struct phy_ops k3_inno_dp_phy_ops =3D { + .power_on =3D k3_inno_dp_phy_power_on, + .power_off =3D k3_inno_dp_phy_power_off, + .configure =3D k3_inno_dp_phy_configure, + .owner =3D THIS_MODULE, +}; + +static int k3_inno_dp_phy_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct k3_inno_dp_phy *p; + struct phy_provider *provider; + struct clk_init_data init =3D {}; + int ret; + + p =3D devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->dev =3D dev; + + p->regmap =3D dev_get_regmap(dev->parent, "dp"); + if (!p->regmap) + return dev_err_probe(dev, -ENODEV, + "parent DP regmap not available\n"); + + p->phy =3D devm_phy_create(dev, dev->of_node, &k3_inno_dp_phy_ops); + if (IS_ERR(p->phy)) + return dev_err_probe(dev, PTR_ERR(p->phy), + "failed to create DP PHY\n"); + + phy_set_drvdata(p->phy, p); + + /* PHY takes a 24 MHz reference clock */ + p->ref_clk_khz =3D 24000; + + /* The APMU pixel-clock mux references this clock by name. */ + of_property_read_string(dev->of_node, "clock-output-names", &init.name); + if (!init.name) + init.name =3D dev_name(dev); + init.ops =3D &k3_inno_dp_pxclk_ops; + init.parent_names =3D NULL; + init.num_parents =3D 0; + init.flags =3D 0; + p->pxclk_hw.init =3D &init; + + ret =3D devm_clk_hw_register(dev, &p->pxclk_hw); + if (ret) + return dev_err_probe(dev, ret, + "failed to register pixel clock\n"); + + ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &p->pxclk_hw); + if (ret) + return dev_err_probe(dev, ret, + "failed to add pixel clock provider\n"); + + /* Providers last: nothing may resolve a half-initialized PHY. */ + provider =3D devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) + return dev_err_probe(dev, PTR_ERR(provider), + "failed to register PHY provider\n"); + + return 0; +} + +static const struct of_device_id k3_inno_dp_phy_of_match[] =3D { + { .compatible =3D "spacemit,k3-inno-dp-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, k3_inno_dp_phy_of_match); + +static struct platform_driver k3_inno_dp_phy_driver =3D { + .probe =3D k3_inno_dp_phy_probe, + .driver =3D { + .name =3D "spacemit-k3-inno-dp-phy", + .of_match_table =3D k3_inno_dp_phy_of_match, + }, +}; +module_platform_driver(k3_inno_dp_phy_driver); + +MODULE_DESCRIPTION("SpacemiT K3 Innosilicon DisplayPort PHY driver"); +MODULE_AUTHOR("Cody Kang "); +MODULE_LICENSE("GPL"); --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D3A4029D281; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; cv=none; b=n8HaTjpFE6uXE0veK8tEXhSm24ALFHqzLpAdTAbP/8C4fqQhIRw93v6mEjoqsQFRk7qF4sUBRziY6u+N50TJg1AwxOl8IYhjOiIr4Ta6jw51T3GJxyxO523nKysjxxp39qLjpX6HnfS3Vk4Og13EtO8U360Oe5VCdkSxKjr4A1U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; c=relaxed/simple; bh=nXtZ+nvKaPR4e0kxD9q85O5p2VolIkFyzikHh79h080=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EsPYGc3EBE9D59vWWUnGuS5/hTHjfxDoRM2lf5Dd9jrd5qrcrPquUwPk4iSZoAq5CWfcDFIAn22ehfdgVOiM3y12s0aoJhqSzMd2trDmuVkms0eAHwRy3ZINNXs73nt6xkjxe1NoWM9BkS0rJ45qwa//Igl53iZWrkORSZ2RWqU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qTdGEthN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qTdGEthN" Received: by smtp.kernel.org (Postfix) with ESMTPS id B175AC2BCFF; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=nXtZ+nvKaPR4e0kxD9q85O5p2VolIkFyzikHh79h080=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=qTdGEthNlU8qe5IRz89KZmVGOEP0kg1eOi852bW8zlZGKYJV4iw45nfE5/WRRBJNq PL8xW9/1ffIT8zNLNdxmuCYjtjAlsmtGlq5n7Mq7gHwqGeccGPLIVt4nSRHnCkjS9p NgrsnWZ+HHfUDAUoS1pZUMutut2XZf6jhz7Qz8Dv/vRRaIL3PclGe8DSxZ/ldfiK6x 2xrUTlDUZ4EdJjhcFzOM54IlQcqCLDFT+A+mZTbP4OpdcowCsG6jtvFmTByH0U20Pt 73AJ+aMyu7nVwc35qBC4HPNXJc6FlewCJp8G9Ge1MGlGJZsis1qhfI0t0Ulkeq9EcD GW2wS78bZNTXQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CD0EC5AD4E; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:15 +0800 Subject: [PATCH v2 06/17] clk: spacemit: k3: parent eDP/DP pixel clock to the PHY PLL Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-6-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=1278; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=D1thhdzY/CUbnE8bdXM4DECedWsXa83klc5ru7yhZ0s=; b=t5kel38scVDrqSR6I6QlaT5Kh7e5XdYnVTYNum0UHMpsnvDt0sw3pzA0Qg2TIlztsR6bFhv5A +h5NzE+El8zBKumOLKjq8GGpCGYDxmzBk3yE/RecsFcVIsFzRru/9Cl X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang The APMU eDP/DP pixel-clock muxes were parented to a placeholder, because their real parents (the DP PHY PLLs) did not exist as clocks yet. They do now, so point each mux at its PLL and let the pixel clock reach the controller through the clock framework. Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - no change --- drivers/clk/spacemit/ccu-k3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/spacemit/ccu-k3.c b/drivers/clk/spacemit/ccu-k3.c index cb0c4277f72a8..afbbbd797826d 100644 --- a/drivers/clk/spacemit/ccu-k3.c +++ b/drivers/clk/spacemit/ccu-k3.c @@ -937,13 +937,13 @@ CCU_MUX_DIV_GATE_FC_DEFINE(ufs_aclk, ufs_aclk_parents= , APMU_UFS_CLK_RES_CTRL, 5, =20 static const struct clk_parent_data edp0_pclk_parents[] =3D { CCU_PARENT_HW(lcd_pxclk), - CCU_PARENT_NAME(external_clk), + CCU_PARENT_NAME(edp0_pll_pxclk), }; CCU_MUX_GATE_DEFINE(edp0_pxclk, edp0_pclk_parents, APMU_LCD_EDP_CTRL, 2, 1= , BIT(1), 0); =20 static const struct clk_parent_data edp1_pclk_parents[] =3D { CCU_PARENT_HW(dsi4ln2_lcd_pxclk), - CCU_PARENT_NAME(external_clk), + CCU_PARENT_NAME(edp1_pll_pxclk), }; CCU_MUX_GATE_DEFINE(edp1_pxclk, edp1_pclk_parents, APMU_LCD_EDP_CTRL, 18, = 1, BIT(17), 0); =20 --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 842AF2C15A5; Sun, 9 Aug 2026 13:15:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; cv=none; b=bYRMBwBVQuVgR5MCvODDcLxwtB4cGAeAp5NQVd1T8ov7yrS9e1Y537ZAusPkFol8xI692u/Yg4dFjFvVhbfFqWZuME0HAzRKae7r5qWxL8nkhttPIQRrTfzKM8p74IvUhiXc6g6trCQGwnTZ+4Nw5+OXmzRGXv+zLI9a13FYloE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; c=relaxed/simple; bh=oZycql2vzyaWbFLy9ZkxW92kJxpsO8SmZihnBgmDb5w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=t/jRBktUqFKGlqA5DHM2r9LpRfVBqKiEN5VyAXCj5m4xTCWnEIBoAW1Umy0fLWLil1pchhPN4f4hlMBYCdNZPIMusbQty1N4bV1A7KqXq5Z/LVJ2aifCq9xXgOrbj6fi2aB5nzla8bEGDtiRwHPKhx+VMoj+Lrdfj+KO85g/1O8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gkiYGdnv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gkiYGdnv" Received: by smtp.kernel.org (Postfix) with ESMTPS id CC585C2BCFB; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281320; bh=oZycql2vzyaWbFLy9ZkxW92kJxpsO8SmZihnBgmDb5w=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=gkiYGdnv5Mx6DlLzGD+MnbT3W+23PMaB3Z5gRkWsn7/b9S9RSTm8hpUsBag7JYnCl wlzhuwpbrhfVKbfRQASjXaHtQWR3lCBCsQUeL7Psh+b5SjrruNWYL9g6BskE3JFoG6 LBkS8EQb3ykznzk8PRZMe6hctVnAaBUkYbXdLZ8V3Cs7UivZvrnd/ssaSuigC69y+q p0aE2FmOA+sM2fwu3/IHlQfS7Hoqt3psDUTYXTy6MLMGrzSHIHjKvbBY+DaHD0n30V iDKVM5ASud8b41A54H8FGaR8vkbvLxFcqLPQiivXE0X0mlDYD0E/RpJvOMXEccNDBu KMdOsbQteNPJw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6419C5AD7B; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:16 +0800 Subject: [PATCH v2 07/17] drm/spacemit: add Saturn DPU register model Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-7-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=19513; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=MpoXAydP67++lySrVEJU/OikaOtSDUt5x364GZNXI7M=; b=goRN61zCJfUm3mzh6YyIh0URBSJDjXIMUi7UA79yzMllLgnDB2sDsccC5ZJOYBIfnRl2yCydv WLeElbbO3OlBSAeTZpD79mucOtlbj9pnvw5h4OqwjjZHqULCiatWBiU X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang The Saturn display processing unit is programmed through a set of register blocks (composer, RDMA, timing generator, cmdlist engine, display MMU) laid out identically in both SoC instances. Add the block address map, the per-field word offset and mask tables consumed by the field accessors, the interrupt bit layout and the compositor and output-format ID encodings. The address map describes the whole IP block on purpose, including blocks the driver does not touch; the field tables carry the fields the driver programs, with each block's full word count kept as its NWORDS extent. Consumers arrive with the following patches; the driver only becomes buildable once the final patch adds the Kconfig and Makefile glue. Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - no change --- drivers/gpu/drm/spacemit/dpu/saturn_regs/dpu_int.h | 25 ++ .../gpu/drm/spacemit/dpu/saturn_regs/reg_map_hee.h | 64 +++++ .../drm/spacemit/dpu/saturn_regs/saturn_fields.h | 298 +++++++++++++++++= ++++ drivers/gpu/drm/spacemit/spacemit_dpu_ids.h | 22 ++ 4 files changed, 409 insertions(+) diff --git a/drivers/gpu/drm/spacemit/dpu/saturn_regs/dpu_int.h b/drivers/g= pu/drm/spacemit/dpu/saturn_regs/dpu_int.h new file mode 100644 index 0000000000000..2c7fa00ba31e9 --- /dev/null +++ b/drivers/gpu/drm/spacemit/dpu/saturn_regs/dpu_int.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#ifndef DPU_INT_REG_H +#define DPU_INT_REG_H + +#include + +#define DPU_INT_CMDLIST_CH_FRM_CFG_DONE_MASK (0xff) +#define DPU_INT_CMDLIST_CH_FRM_CFG_DONE (DPU_INT_CMDLIST_CH_FRM_CFG_DONE_= MASK << 11) +#define DPU_INT_FRM_TIMING_UNFLOW BIT(8) +#define DPU_INT_CFG_RDY_CLR BIT(5) +#define DPU_INT_FRM_TIMING_CFG_LINE BIT(4) +#define DPU_INT_FRM_TIMING_CFG_EOF (BIT(2) | BIT(3)) +#define DPU_INT_FRM_TIMING_EOF BIT(1) +#define DPU_INT_FRM_TIMING_VSYNC BIT(0) +#define DPU_REST_INT_BITS (DPU_INT_FRM_TIMING_CFG_EOF | \ + DPU_INT_FRM_TIMING_CFG_LINE | \ + DPU_INT_FRM_TIMING_EOF | \ + DPU_INT_CMDLIST_CH_FRM_CFG_DONE) + +#endif diff --git a/drivers/gpu/drm/spacemit/dpu/saturn_regs/reg_map_hee.h b/drive= rs/gpu/drm/spacemit/dpu/saturn_regs/reg_map_hee.h new file mode 100644 index 0000000000000..9490021cdb918 --- /dev/null +++ b/drivers/gpu/drm/spacemit/dpu/saturn_regs/reg_map_hee.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#ifndef _SATURN_REG_MAP_hee_H_ +#define _SATURN_REG_MAP_hee_H_ + +#include "dpu_int.h" + +/* Base address, then bit definitions */ + +#define DPU_TOP_BASE_ADDR 0x0 +#define DPU_CTRL_BASE_ADDR 0x3c0 /* dpu_ctl_top start address */ +#define CMDLIST_BASE_ADDR 0x500 +#define DPU_INT_BASE_ADDR 0x700 + +#define DPU_ONLINE_IRQ_MSK (3 * 4) +#define DPU_ONLINE_IRQ_STS (12 * 4) + +#define DMA_TOP_BASE_ADDR (RDMA0_BASE_ADDR + 0x280) + +#define RDMA0_BASE_ADDR (0x00001000) +#define RDMA1_BASE_ADDR (RDMA0_BASE_ADDR + 0x1000) +#define RDMA2_BASE_ADDR (RDMA0_BASE_ADDR + 0xa000) +#define RDMA3_BASE_ADDR (RDMA0_BASE_ADDR + 0xb000) + +#define MMU_BASE_ADDR (0x1100) +#define MMU_TOP_BASE_ADDR (MMU_BASE_ADDR + 0x100) + +#define TBU0_ADDR 0x1100 +#define TBU1_ADDR 0x1180 +#define TBU2_ADDR 0x2100 +#define TBU3_ADDR 0x2180 +#define TBU4_ADDR 0xb100 +#define TBU5_ADDR 0xb180 +#define TBU6_ADDR 0xc100 +#define TBU7_ADDR 0xc180 + +#define CMP0_BASE_ADDR 0x00018000 +#define CMP1_BASE_ADDR (CMP0_BASE_ADDR + 0x18000) +#define CMP2_BASE_ADDR (CMP0_BASE_ADDR + 0x30000) + +#define PREPIPE_SCAL0_BASE_ADDR 0x14000 +#define PREPIPE_SCAL1_BASE_ADDR 0x14400 +#define PREPIPE_SCAL2_BASE_ADDR 0x14800 +#define PREPIPE_SCAL3_BASE_ADDR 0x14c00 + +#define POST_PIPE_ADDR (CMP1_BASE_ADDR + 0x300) + +#define EE_ADDR (CMP1_BASE_ADDR + 0xd00) + +#define DPU_SCENE_CTL_BASE_ADDR (0x300) +#define DPU_SCENE_CTL_SIZE 0x40 +#define DPU_SCENE_CTL_ADDR(i) (DPU_SCENE_CTL_BASE_ADDR + (i) * DPU_SCENE_C= TL_SIZE) + +#define TMG0_BASE_ADDR (0x00051000 + 0x200) + +#define CMDLIST_CH_Y 0x188 +#define CMDLIST_CH_START_CMPS_Y 0x90 +#define CMDLIST_CFG_READY 0x34 + +#endif diff --git a/drivers/gpu/drm/spacemit/dpu/saturn_regs/saturn_fields.h b/dri= vers/gpu/drm/spacemit/dpu/saturn_regs/saturn_fields.h new file mode 100644 index 0000000000000..f745dfdaa83de --- /dev/null +++ b/drivers/gpu/drm/spacemit/dpu/saturn_regs/saturn_fields.h @@ -0,0 +1,298 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + * Saturn DPU register field map: word offset and mask per field, consumed= by + * the dpu_write()/dpu_read() accessors. + */ + +#ifndef SATURN_FIELDS_H +#define SATURN_FIELDS_H + +#include + +/* CMDLIST_REG: 128 x 32-bit registers */ +#define CMDLIST_REG__NWORDS 128 +#define CMDLIST_REG__cmdlist_reg_0__cmdlist_ch_start_addrl_WORD(i) (0 + (i= )) +#define CMDLIST_REG__cmdlist_reg_0__cmdlist_ch_start_addrl_MASK GENMASK(31= , 4) +#define CMDLIST_REG__cmdlist_reg_16__cmdlist_ch_start_addrh_WORD(i) (16 + = (i)) +#define CMDLIST_REG__cmdlist_reg_16__cmdlist_ch_start_addrh_MASK GENMASK(5= , 0) +#define CMDLIST_REG__cmdlist_reg_48__cmdlist_ch_y_first_WORD(i) (48 + (i)) +#define CMDLIST_REG__cmdlist_reg_48__cmdlist_ch_y_first_MASK GENMASK(24, 1= 2) + +/* CMPS_X_REG: 146 x 32-bit registers */ +#define CMPS_X_REG__NWORDS 146 +#define CMPS_X_REG__module_enable_WORD 0 +#define CMPS_X_REG__module_enable_MASK GENMASK(0, 0) +#define CMPS_X_REG__dst_w_WORD 1 +#define CMPS_X_REG__dst_w_MASK GENMASK(15, 0) +#define CMPS_X_REG__dst_h_WORD 1 +#define CMPS_X_REG__dst_h_MASK GENMASK(31, 16) +#define CMPS_X_REG__bg_color_r_WORD 2 +#define CMPS_X_REG__bg_color_r_MASK GENMASK(9, 0) +#define CMPS_X_REG__bg_color_g_WORD 3 +#define CMPS_X_REG__bg_color_g_MASK GENMASK(9, 0) +#define CMPS_X_REG__bg_color_b_WORD 4 +#define CMPS_X_REG__bg_color_b_MASK GENMASK(9, 0) +#define CMPS_X_REG__bg_color_a_WORD 5 +#define CMPS_X_REG__bg_color_a_MASK GENMASK(7, 0) +#define CMPS_X_REG__layer00_area_left_WORD 8 +#define CMPS_X_REG__layer00_area_left_MASK GENMASK(15, 0) +#define CMPS_X_REG__layer00_area_right_WORD 8 +#define CMPS_X_REG__layer00_area_right_MASK GENMASK(31, 16) +#define CMPS_X_REG__layer00_area_top_WORD 9 +#define CMPS_X_REG__layer00_area_top_MASK GENMASK(15, 0) +#define CMPS_X_REG__layer00_area_bottom_WORD 9 +#define CMPS_X_REG__layer00_area_bottom_MASK GENMASK(31, 16) +#define CMPS_X_REG__layer00_solid_color_r_WORD 10 +#define CMPS_X_REG__layer00_solid_color_r_MASK GENMASK(9, 0) +#define CMPS_X_REG__layer00_solid_color_g_WORD 11 +#define CMPS_X_REG__layer00_solid_color_g_MASK GENMASK(9, 0) +#define CMPS_X_REG__layer00_solid_color_b_WORD 12 +#define CMPS_X_REG__layer00_solid_color_b_MASK GENMASK(9, 0) +#define CMPS_X_REG__layer00_solid_color_a_WORD 13 +#define CMPS_X_REG__layer00_solid_color_a_MASK GENMASK(7, 0) +#define CMPS_X_REG__layer00_blend_mode_WORD 13 +#define CMPS_X_REG__layer00_blend_mode_MASK GENMASK(15, 14) +#define CMPS_X_REG__layer00_colorkey_en_WORD 13 +#define CMPS_X_REG__layer00_colorkey_en_MASK GENMASK(18, 18) +#define CMPS_X_REG__layer00_en_WORD 14 +#define CMPS_X_REG__layer00_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer00_blend_sel_WORD 14 +#define CMPS_X_REG__layer00_blend_sel_MASK GENMASK(2, 1) +#define CMPS_X_REG__layer00_solid_en_WORD 14 +#define CMPS_X_REG__layer00_solid_en_MASK GENMASK(3, 3) +#define CMPS_X_REG__layer00_dma_id_WORD 14 +#define CMPS_X_REG__layer00_dma_id_MASK GENMASK(7, 4) +#define CMPS_X_REG__layer00_layer_alpha_WORD 14 +#define CMPS_X_REG__layer00_layer_alpha_MASK GENMASK(15, 8) +#define CMPS_X_REG__layer00_alpha_ratio_WORD 14 +#define CMPS_X_REG__layer00_alpha_ratio_MASK GENMASK(23, 16) +#define CMPS_X_REG__layer01_en_WORD 21 +#define CMPS_X_REG__layer01_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer02_en_WORD 28 +#define CMPS_X_REG__layer02_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer03_en_WORD 35 +#define CMPS_X_REG__layer03_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer04_en_WORD 42 +#define CMPS_X_REG__layer04_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer05_en_WORD 49 +#define CMPS_X_REG__layer05_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer06_en_WORD 56 +#define CMPS_X_REG__layer06_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer07_en_WORD 63 +#define CMPS_X_REG__layer07_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer08_en_WORD 70 +#define CMPS_X_REG__layer08_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer09_en_WORD 77 +#define CMPS_X_REG__layer09_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer10_en_WORD 84 +#define CMPS_X_REG__layer10_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer11_en_WORD 91 +#define CMPS_X_REG__layer11_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer12_en_WORD 98 +#define CMPS_X_REG__layer12_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer13_en_WORD 105 +#define CMPS_X_REG__layer13_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer14_en_WORD 112 +#define CMPS_X_REG__layer14_en_MASK GENMASK(0, 0) +#define CMPS_X_REG__layer15_en_WORD 119 +#define CMPS_X_REG__layer15_en_MASK GENMASK(0, 0) + +/* DMA_TOP_REG: 25 x 32-bit registers */ +#define DMA_TOP_REG__NWORDS 25 +#define DMA_TOP_REG__image_rr_ratio_WORD 1 +#define DMA_TOP_REG__image_rr_ratio_MASK GENMASK(7, 0) +#define DMA_TOP_REG__pixel_num_th_WORD 1 +#define DMA_TOP_REG__pixel_num_th_MASK GENMASK(14, 9) +#define DMA_TOP_REG__rdma_timeout_limit_WORD 2 +#define DMA_TOP_REG__rdma_timeout_limit_MASK GENMASK(15, 0) +#define DMA_TOP_REG__wdma_timeout_limit_WORD 2 +#define DMA_TOP_REG__wdma_timeout_limit_MASK GENMASK(31, 16) + +/* DPU_CTL_REG: 15 x 32-bit registers */ +#define DPU_CTL_REG__NWORDS 15 +#define DPU_CTL_REG__nml_rch_en_WORD 0 +#define DPU_CTL_REG__nml_rch_en_MASK GENMASK(9, 0) +#define DPU_CTL_REG__nml_scl_en_WORD 0 +#define DPU_CTL_REG__nml_scl_en_MASK GENMASK(13, 10) +#define DPU_CTL_REG__nml_outctl_en_WORD 0 +#define DPU_CTL_REG__nml_outctl_en_MASK GENMASK(18, 18) +#define DPU_CTL_REG__nml_frm_timing_en_WORD 0 +#define DPU_CTL_REG__nml_frm_timing_en_MASK GENMASK(25, 23) +#define DPU_CTL_REG__both_cfg_rdy_WORD 2 +#define DPU_CTL_REG__both_cfg_rdy_MASK GENMASK(0, 0) +#define DPU_CTL_REG__video_mod_WORD 3 +#define DPU_CTL_REG__video_mod_MASK GENMASK(0, 0) +#define DPU_CTL_REG__dbg_mod_WORD 3 +#define DPU_CTL_REG__dbg_mod_MASK GENMASK(1, 1) +#define DPU_CTL_REG__timing_inter0_WORD 3 +#define DPU_CTL_REG__timing_inter0_MASK GENMASK(7, 2) +#define DPU_CTL_REG__timing_inter1_WORD 3 +#define DPU_CTL_REG__timing_inter1_MASK GENMASK(13, 8) +#define DPU_CTL_REG__sw_start_WORD 4 +#define DPU_CTL_REG__sw_start_MASK GENMASK(0, 0) +#define DPU_CTL_REG__nml_rch_vrt_reuse_WORD 7 +#define DPU_CTL_REG__nml_rch_vrt_reuse_MASK GENMASK(9, 0) + +/* DPU_CTL_TOP_REG: 53 x 32-bit registers */ +#define DPU_CTL_TOP_REG__NWORDS 53 +#define DPU_CTL_TOP_REG__dpu_ctl_top_reg_0__cmdlist_rch_en_WORD(i) (0 + (i= )) +#define DPU_CTL_TOP_REG__dpu_ctl_top_reg_0__cmdlist_rch_en_MASK GENMASK(0,= 0) +#define DPU_CTL_TOP_REG__dpu_ctl_top_reg_10__cmdlist_cmps_other_en_WORD(i)= (10 + (i)) +#define DPU_CTL_TOP_REG__dpu_ctl_top_reg_10__cmdlist_cmps_other_en_MASK GE= NMASK(0, 0) +#define DPU_CTL_TOP_REG__dpu_ctl_top_reg_10__cmdlist_cmps_top_en_WORD(i) (= 10 + (i)) +#define DPU_CTL_TOP_REG__dpu_ctl_top_reg_10__cmdlist_cmps_top_en_MASK GENM= ASK(1, 1) + +/* DPU_INTP_REG: 50 x 32-bit registers */ +#define DPU_INTP_REG__NWORDS 50 + +/* EE_REG: 51 x 32-bit registers */ +#define EE_REG__NWORDS 51 +#define EE_REG__m_benable_WORD 0 +#define EE_REG__m_benable_MASK GENMASK(0, 0) + +/* MMU_TBU_REG: 21 x 32-bit registers */ +#define MMU_TBU_REG__NWORDS 21 +#define MMU_TBU_REG__tbu_base_addr0_low_WORD 1 +#define MMU_TBU_REG__tbu_base_addr0_low_MASK GENMASK(31, 0) +#define MMU_TBU_REG__tbu_base_addr0_high_WORD 2 +#define MMU_TBU_REG__tbu_base_addr0_high_MASK GENMASK(11, 0) +#define MMU_TBU_REG__tbu_base_addr1_low_WORD 3 +#define MMU_TBU_REG__tbu_base_addr1_low_MASK GENMASK(31, 0) +#define MMU_TBU_REG__tbu_base_addr1_high_WORD 4 +#define MMU_TBU_REG__tbu_base_addr1_high_MASK GENMASK(11, 0) +#define MMU_TBU_REG__tbu_base_addr2_low_WORD 5 +#define MMU_TBU_REG__tbu_base_addr2_low_MASK GENMASK(31, 0) +#define MMU_TBU_REG__tbu_base_addr2_high_WORD 6 +#define MMU_TBU_REG__tbu_base_addr2_high_MASK GENMASK(11, 0) +#define MMU_TBU_REG__tbu_va0_WORD 7 +#define MMU_TBU_REG__tbu_va0_MASK GENMASK(31, 0) +#define MMU_TBU_REG__tbu_va1_WORD 8 +#define MMU_TBU_REG__tbu_va1_MASK GENMASK(31, 0) +#define MMU_TBU_REG__tbu_va2_WORD 9 +#define MMU_TBU_REG__tbu_va2_MASK GENMASK(31, 0) +#define MMU_TBU_REG__tbu_size0_WORD 10 +#define MMU_TBU_REG__tbu_size0_MASK GENMASK(15, 0) +#define MMU_TBU_REG__tbu_size1_WORD 11 +#define MMU_TBU_REG__tbu_size1_MASK GENMASK(15, 0) +#define MMU_TBU_REG__tbu_size2_WORD 12 +#define MMU_TBU_REG__tbu_size2_MASK GENMASK(15, 0) +#define MMU_TBU_REG__vsync_update_en_WORD 13 +#define MMU_TBU_REG__vsync_update_en_MASK GENMASK(1, 1) + +/* MMU_TOP_REG: 23 x 32-bit registers */ +#define MMU_TOP_REG__NWORDS 23 +#define MMU_TOP_REG__rdma_timelimit_WORD 0 +#define MMU_TOP_REG__rdma_timelimit_MASK GENMASK(31, 16) +#define MMU_TOP_REG__sram0_tlb_axi_port_sel_WORD 1 +#define MMU_TOP_REG__sram0_tlb_axi_port_sel_MASK GENMASK(1, 0) +#define MMU_TOP_REG__sram1_tlb_axi_port_sel_WORD 1 +#define MMU_TOP_REG__sram1_tlb_axi_port_sel_MASK GENMASK(3, 2) +#define MMU_TOP_REG__dmac0_rd_outs_num_WORD 2 +#define MMU_TOP_REG__dmac0_rd_outs_num_MASK GENMASK(7, 0) +#define MMU_TOP_REG__dmac1_rd_outs_num_WORD 3 +#define MMU_TOP_REG__dmac1_rd_outs_num_MASK GENMASK(7, 0) + +/* POSTPIPE_REG: 50 x 32-bit registers */ +#define POSTPIPE_REG__NWORDS 50 +#define POSTPIPE_REG__m_inwidth_WORD 13 +#define POSTPIPE_REG__m_inwidth_MASK GENMASK(15, 0) +#define POSTPIPE_REG__m_inheight_WORD 13 +#define POSTPIPE_REG__m_inheight_MASK GENMASK(31, 16) + +/* RDMA_PATH_X_REG: 60 x 32-bit registers */ +#define RDMA_PATH_X_REG__NWORDS 60 +#define RDMA_PATH_X_REG__layer_mode_WORD 0 +#define RDMA_PATH_X_REG__layer_mode_MASK GENMASK(1, 0) +#define RDMA_PATH_X_REG__layer_cmpsr_id_WORD 0 +#define RDMA_PATH_X_REG__layer_cmpsr_id_MASK GENMASK(15, 13) +#define RDMA_PATH_X_REG__is_two_layers_WORD 1 +#define RDMA_PATH_X_REG__is_two_layers_MASK GENMASK(0, 0) +#define RDMA_PATH_X_REG__is_offline_WORD 1 +#define RDMA_PATH_X_REG__is_offline_MASK GENMASK(1, 1) +#define RDMA_PATH_X_REG__base_addr0_low_ly0_WORD 9 +#define RDMA_PATH_X_REG__base_addr0_low_ly0_MASK GENMASK(31, 0) +#define RDMA_PATH_X_REG__base_addr0_high_ly0_WORD 10 +#define RDMA_PATH_X_REG__base_addr0_high_ly0_MASK GENMASK(1, 0) +#define RDMA_PATH_X_REG__base_addr1_low_ly0_WORD 11 +#define RDMA_PATH_X_REG__base_addr1_low_ly0_MASK GENMASK(31, 0) +#define RDMA_PATH_X_REG__base_addr1_high_ly0_WORD 12 +#define RDMA_PATH_X_REG__base_addr1_high_ly0_MASK GENMASK(1, 0) +#define RDMA_PATH_X_REG__base_addr2_low_ly0_WORD 13 +#define RDMA_PATH_X_REG__base_addr2_low_ly0_MASK GENMASK(31, 0) +#define RDMA_PATH_X_REG__base_addr2_high_ly0_WORD 14 +#define RDMA_PATH_X_REG__base_addr2_high_ly0_MASK GENMASK(1, 0) +#define RDMA_PATH_X_REG__rdma_stride0_layer0_WORD 15 +#define RDMA_PATH_X_REG__rdma_stride0_layer0_MASK GENMASK(15, 0) +#define RDMA_PATH_X_REG__rdma_stride1_layer0_WORD 15 +#define RDMA_PATH_X_REG__rdma_stride1_layer0_MASK GENMASK(31, 16) +#define RDMA_PATH_X_REG__img_width_ly0_WORD 16 +#define RDMA_PATH_X_REG__img_width_ly0_MASK GENMASK(15, 0) +#define RDMA_PATH_X_REG__img_height_ly0_WORD 16 +#define RDMA_PATH_X_REG__img_height_ly0_MASK GENMASK(31, 16) +#define RDMA_PATH_X_REG__bbox_start_x_ly0_WORD 17 +#define RDMA_PATH_X_REG__bbox_start_x_ly0_MASK GENMASK(15, 0) +#define RDMA_PATH_X_REG__bbox_start_y_ly0_WORD 17 +#define RDMA_PATH_X_REG__bbox_start_y_ly0_MASK GENMASK(31, 16) +#define RDMA_PATH_X_REG__bbox_end_x_ly0_WORD 18 +#define RDMA_PATH_X_REG__bbox_end_x_ly0_MASK GENMASK(15, 0) +#define RDMA_PATH_X_REG__bbox_end_y_ly0_WORD 18 +#define RDMA_PATH_X_REG__bbox_end_y_ly0_MASK GENMASK(31, 16) +#define RDMA_PATH_X_REG__pixel_format_WORD 29 +#define RDMA_PATH_X_REG__pixel_format_MASK GENMASK(5, 0) +#define RDMA_PATH_X_REG__uv_swap_WORD 29 +#define RDMA_PATH_X_REG__uv_swap_MASK GENMASK(6, 6) +#define RDMA_PATH_X_REG__rot_mode_ly0_WORD 29 +#define RDMA_PATH_X_REG__rot_mode_ly0_MASK GENMASK(10, 8) + +/* TMG_REG: 30 x 32-bit registers */ +#define TMG_REG__NWORDS 30 +#define TMG_REG__split_en_WORD 0 +#define TMG_REG__split_en_MASK GENMASK(0, 0) +#define TMG_REG__cmd_screen_WORD 0 +#define TMG_REG__cmd_screen_MASK GENMASK(1, 1) +#define TMG_REG__fm_timing_en_WORD 0 +#define TMG_REG__fm_timing_en_MASK GENMASK(2, 2) +#define TMG_REG__cmd_wait_en_WORD 0 +#define TMG_REG__cmd_wait_en_MASK GENMASK(3, 3) +#define TMG_REG__cmd_wait_te_WORD 0 +#define TMG_REG__cmd_wait_te_MASK GENMASK(4, 4) +#define TMG_REG__disp_ready_man_en_WORD 0 +#define TMG_REG__disp_ready_man_en_MASK GENMASK(5, 5) +#define TMG_REG__hsp_WORD 0 +#define TMG_REG__hsp_MASK GENMASK(7, 7) +#define TMG_REG__vsp_WORD 0 +#define TMG_REG__vsp_MASK GENMASK(8, 8) +#define TMG_REG__user_WORD 2 +#define TMG_REG__user_MASK GENMASK(15, 12) +#define TMG_REG__hfp_WORD 3 +#define TMG_REG__hfp_MASK GENMASK(27, 16) +#define TMG_REG__hsync_width_WORD 4 +#define TMG_REG__hsync_width_MASK GENMASK(9, 0) +#define TMG_REG__hbp_WORD 4 +#define TMG_REG__hbp_MASK GENMASK(27, 16) +#define TMG_REG__vfp_WORD 5 +#define TMG_REG__vfp_MASK GENMASK(15, 0) +#define TMG_REG__vsync_width_WORD 5 +#define TMG_REG__vsync_width_MASK GENMASK(25, 16) +#define TMG_REG__vbp_WORD 6 +#define TMG_REG__vbp_MASK GENMASK(11, 0) +#define TMG_REG__h_active_WORD 6 +#define TMG_REG__h_active_MASK GENMASK(29, 16) +#define TMG_REG__v_active_WORD 7 +#define TMG_REG__v_active_MASK GENMASK(13, 0) +#define TMG_REG__background_r_WORD 9 +#define TMG_REG__background_r_MASK GENMASK(11, 0) +#define TMG_REG__background_g_WORD 9 +#define TMG_REG__background_g_MASK GENMASK(27, 16) +#define TMG_REG__background_b_WORD 10 +#define TMG_REG__background_b_MASK GENMASK(11, 0) +#define TMG_REG__eof_1st_ln_dly_num_WORD 11 +#define TMG_REG__eof_1st_ln_dly_num_MASK GENMASK(15, 0) +#define TMG_REG__eof_2nd_ln_dly_num_WORD 11 +#define TMG_REG__eof_2nd_ln_dly_num_MASK GENMASK(31, 16) +#define TMG_REG__sof_pre_ln_num_WORD 14 +#define TMG_REG__sof_pre_ln_num_MASK GENMASK(16, 0) + +#endif /* SATURN_FIELDS_H */ diff --git a/drivers/gpu/drm/spacemit/spacemit_dpu_ids.h b/drivers/gpu/drm/= spacemit/spacemit_dpu_ids.h new file mode 100644 index 0000000000000..41014dda927b9 --- /dev/null +++ b/drivers/gpu/drm/spacemit/spacemit_dpu_ids.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + */ + +#ifndef _SPACEMIT_DPU_IDS_H_ +#define _SPACEMIT_DPU_IDS_H_ + +/* Saturn online compositor instance ids (hardware IRQ-table indices). */ +#define COMPOSER0 0 +#define COMPOSER1 1 +#define COMPOSER2 2 +#define COMPOSER3 3 + +/* DPU output-format field encoding (dpuctrl out-format register). */ +#define OUTFMT_RGB121212 0 +#define OUTFMT_RGB101010 1 +#define OUTFMT_RGB888 2 +#define OUTFMT_RGB666 12 +#define OUTFMT_RGB565 13 + +#endif /* _SPACEMIT_DPU_IDS_H_ */ --=20 2.43.0 From nobody Tue Sep 29 09:46:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D3BCA29E10F; Sun, 9 Aug 2026 13:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; cv=none; b=TWGLcO8gWD4myfW2dRPs6PZ8cxthJmyjc2NiBx9L2lnAxizaOa4/ZUuODAEiB9A09iMLfEBQJ+rSiHBrXdnCXOvOyDOHHhuQ7FQC/6PJfNCk2A1LCGpXQDEH8Q8OH2ZQqbgVrlDqBzVSo8YtBC/ssINGgwW+Fc4IRyIr66v4I0Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786281322; c=relaxed/simple; bh=d3hk7S6cwDtGRjhxnqeKNqNv2dECeNGKbwrhSJcNI94=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uYQmekxSsxAeu1pFniMpWejAO1OnD3iUBHVnRGBvjQlaFfPW+CsIyTQEI5tf8BqYj3hroCFSanVFwLFkFpwWhdGxrJl6u4pgSuVXf/GpsVSYhYY6ga7mr8YD7uqEeyHIaKIQ3tuGe4/pnx3iLgZhBE466X85yULGAiQNXOJG5CA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CvIoeumx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CvIoeumx" Received: by smtp.kernel.org (Postfix) with ESMTPS id EC775C2BD00; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786281321; bh=d3hk7S6cwDtGRjhxnqeKNqNv2dECeNGKbwrhSJcNI94=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=CvIoeumxnyIvQynPJkYtSy2NpC7axHdV3huqZhYzbZWmL2dBjMyMF7wO+m69uMRUT TMyrUSJejRLvm1GVZlt8c9MWgwNu0S1+SMkST5/mfcK/sPHg9K0ChBG+aO2/s9dG8n caXGDSK8Q/3KmN/0nSlgfyTDZzxrF1dUoBwb4IN/gxEVmNgjeLgJYL6fFNjo6RV3rI ZN1lJI8Ey/2LkVl7dlwpd7ao1m1XJ/AQHodEbNuK/QpOGJ/BtXTjtnwnPfA5eL+X/i +vfAT/4FXmBJy8JoqfPRHiY4DginlU8uMASY3PDU79I8X6nmJEuZiDoqxF3ZnaAHOt VBgO8ZQHzx54w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D522AC5AD68; Sun, 9 Aug 2026 13:15:20 +0000 (UTC) From: Cody Kang via B4 Relay Date: Sun, 09 Aug 2026 21:14:17 +0800 Subject: [PATCH v2 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260809-k3-display-v2-8-327d7910bf71@gmail.com> References: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> In-Reply-To: <20260809-k3-display-v2-0-327d7910bf71@gmail.com> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Vinod Koul , Neil Armstrong , Haylen Chu , Michael Turquette , Stephen Boyd , Brian Masney , Philipp Zabel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Yao Zi , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Guodong Xu Cc: dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, linux-clk@vger.kernel.org, Cody Kang X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786281298; l=45314; i=codykang.hk@gmail.com; s=codykang; h=from:subject:message-id; bh=0aA0Vkq4JndUPsyOa8h984LQsYZfoTg6AN4cbfpx1t4=; b=8ZYqSpu8xSWQxP3XeIP9vS9kVZrvZaxNhTMWUKqESK4ucGTIuXMVEBoK+0DrjiiUQi1aRZ8MR PWS9dfsOUHrDJQVuea9NM4TbVpV9qNrfMzhsBrlV3hil2bqkvtt/B7z X-Developer-Key: i=codykang.hk@gmail.com; a=ed25519; pk=Osn6/cs9Su/mHHw4P19cmVc3v2FMQfiWahjsN0vEkuk= X-Endpoint-Received: by B4 Relay for codykang.hk@gmail.com/codykang with auth_id=895 X-Original-From: Cody Kang Reply-To: codykang.hk@gmail.com From: Cody Kang Register programming of the Saturn DPU is batched: the driver builds per-module register lists in memory and the hardware command-list engine replays them at frame boundaries, while scanout buffers are mapped through the DPU's private address translation unit (DMMU) rather than scanned out by physical address. Add the shared driver types, the MMIO field accessors, the trace events, the command-list builder and the DMMU table code. Some DPU configuration registers are write-only, so a read-modify-write would corrupt neighbouring fields; byte- and halfword-aligned fields are therefore written at their native width instead. Signed-off-by: Cody Kang Tested-by: Ze Huang --- v2: - hold the DPU reset lines as one reset_control_bulk_data pipe_resets[5] array in spacemit_drm_private and drop the pointers duplicated into struct spacemit_crtc (Philipp Zabel) - drop the INT_VSYNC_UPDATE enum member; it never had an irq_list[] mapping and the register model has no such status bit (Sashiko) - drop the unreachable multi-planar arms in spacemit_dmmu_map(); every advertised format is single-planar (Sashiko) - drop the unused cmdlist parameter from the crtc_cmdlist op (Sashiko) --- drivers/gpu/drm/spacemit/dpu/dpu_saturn.h | 35 +++ drivers/gpu/drm/spacemit/dpu/dpu_trace.h | 350 ++++++++++++++++++++++++= ++++ drivers/gpu/drm/spacemit/spacemit_cmdlist.c | 304 ++++++++++++++++++++++++ drivers/gpu/drm/spacemit/spacemit_cmdlist.h | 146 ++++++++++++ drivers/gpu/drm/spacemit/spacemit_crtc.h | 246 +++++++++++++++++++ drivers/gpu/drm/spacemit/spacemit_dmmu.c | 80 +++++++ drivers/gpu/drm/spacemit/spacemit_dmmu.h | 40 ++++ drivers/gpu/drm/spacemit/spacemit_dpu_reg.h | 108 +++++++++ drivers/gpu/drm/spacemit/spacemit_drm.h | 61 +++++ 9 files changed, 1370 insertions(+) diff --git a/drivers/gpu/drm/spacemit/dpu/dpu_saturn.h b/drivers/gpu/drm/sp= acemit/dpu/dpu_saturn.h new file mode 100644 index 0000000000000..22d77d56eca1a --- /dev/null +++ b/drivers/gpu/drm/spacemit/dpu/dpu_saturn.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#ifndef _DPU_SATURN_H_ +#define _DPU_SATURN_H_ + +#include "../spacemit_crtc.h" + +struct dpu_format_id { + u32 format; /* DRM fourcc */ + u8 id; + u8 bpp; /* bits per pixel */ +}; + +#define SPACEMIT_DPU_INVALID_FORMAT_ID 0xff + +enum format_features { + FORMAT_RGB =3D BIT(0), +}; + +struct spacemit_hw_rdma { + u16 formats; +}; + +int dpu_parse_clocks(struct device *dev, struct dpu_clk_context *clk_ctx); +u8 spacemit_plane_hw_get_format_id(u32 format); +u32 saturn_conf_dpuctrl_rdma(struct spacemit_crtc *a_crtc); +extern const struct spacemit_hw_device k3_saturn_dpu; +void saturn_enable_irq_mask(struct spacemit_crtc *a_crtc, bool enable, + u32 offset, u32 mask); +void spacemit_cfg_rdy_timer_handler(struct timer_list *t); +#endif diff --git a/drivers/gpu/drm/spacemit/dpu/dpu_trace.h b/drivers/gpu/drm/spa= cemit/dpu/dpu_trace.h new file mode 100644 index 0000000000000..abfe34a67a4bd --- /dev/null +++ b/drivers/gpu/drm/spacemit/dpu/dpu_trace.h @@ -0,0 +1,350 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM spacemit_dpu + +#if !defined(_DPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _DPU_TRACE_H_ + +#include +#include +#include + +#include "dpu_saturn.h" + +TRACE_EVENT(drm_display_mode_info, + TP_PROTO(struct drm_display_mode *mode), + TP_ARGS(mode), + TP_STRUCT__entry( + __field(u16, hdisplay) + __field(u16, hbp) + __field(u16, hfp) + __field(u16, hsync) + __field(u16, vdisplay) + __field(u16, vbp) + __field(u16, vfp) + __field(u16, vsync) + ), + TP_fast_assign( + __entry->hdisplay =3D mode->hdisplay; + __entry->hbp =3D mode->htotal - mode->hsync_end; + __entry->hfp =3D mode->hsync_start - mode->hdisplay; + __entry->hsync =3D mode->hsync_end - mode->hsync_start; + __entry->vdisplay =3D mode->vdisplay; + __entry->vbp =3D mode->vtotal - mode->vsync_end; + __entry->vfp =3D mode->vsync_start - mode->vdisplay; + __entry->vsync =3D mode->vsync_end - mode->vsync_start; + ), + TP_printk("drm_display_mode: hdisplay=3D%d vdisplay=3D%d hsync=3D%d vsync= =3D%d hbp=3D%d hfp=3D%d vbp=3D%d vfp=3D%d", + __entry->hdisplay, __entry->vdisplay, __entry->hsync, __entry->vsync, + __entry->hbp, __entry->hfp, __entry->vbp, __entry->vfp + ) +); + +TRACE_EVENT(dpu_plane_info, + TP_PROTO(struct drm_plane_state *state, struct drm_framebuffer *fb, + u32 rdma_id, u32 alpha, u32 rotation), + TP_ARGS(state, fb, rdma_id, alpha, rotation), + TP_STRUCT__entry( + __field(u32, rdma_id) + __field(u32, src_w) + __field(u32, src_h) + __field(u32, src_x) + __field(u32, src_y) + __field(u32, crtc_w) + __field(u32, crtc_h) + __field(u32, crtc_x) + __field(u32, crtc_y) + __field(u32, width) + __field(u32, height) + __field(u32, format) + __field(u32, blend_mode) + __field(u32, alpha) + __field(u32, zpos) + __field(u32, rotation) + ), + TP_fast_assign( + __entry->rdma_id =3D rdma_id; + __entry->src_w =3D state->src_w >> 16; + __entry->src_h =3D state->src_h >> 16; + __entry->src_x =3D state->src_x >> 16; + __entry->src_y =3D state->src_y >> 16; + __entry->crtc_w =3D state->crtc_w; + __entry->crtc_h =3D state->crtc_h; + __entry->crtc_x =3D state->crtc_x; + __entry->crtc_y =3D state->crtc_y; + __entry->width =3D fb->width; + __entry->height =3D fb->height; + __entry->format =3D fb->format->format; + __entry->blend_mode =3D state->pixel_blend_mode; + __entry->alpha =3D alpha; + __entry->zpos =3D state->zpos; + __entry->rotation =3D rotation; + ), + TP_printk("rdma_id=3D%d src: w=3D%d h=3D%d x=3D%d y=3D%d crtc: w=3D%d h= =3D%d x=3D%d y=3D%d width=3D%d height=3D%d fmt=3D0x%x blend=3D%d alpha=3D%d= zpos=3D%d rot=3D%d", + __entry->rdma_id, __entry->src_w, + __entry->src_h, __entry->src_x, + __entry->src_y, __entry->crtc_w, + __entry->crtc_h, __entry->crtc_x, + __entry->crtc_y, __entry->width, + __entry->height, __entry->format, + __entry->blend_mode, __entry->alpha, + __entry->zpos, __entry->rotation) +); + +DECLARE_EVENT_CLASS(dpu_status_template, + TP_PROTO(const char *name, int status), + TP_ARGS(name, status), + TP_STRUCT__entry( + __string(name_str, name) + __field(int, status) + ), + TP_fast_assign( + __assign_str(name_str); + __entry->status =3D status; + ), + TP_printk("%s: 0x%x", + __get_str(name_str), __entry->status) +); + +DEFINE_EVENT(dpu_status_template, dpuctrl, + TP_PROTO(const char *name, int status), + TP_ARGS(name, status) +); +DEFINE_EVENT(dpu_status_template, spacemit_plane_update_hw_channel, + TP_PROTO(const char *name, int status), + TP_ARGS(name, status) +); +DEFINE_EVENT(dpu_status_template, saturn_irq_enable, + TP_PROTO(const char *name, int status), + TP_ARGS(name, status) +); +DEFINE_EVENT(dpu_status_template, saturn_enable_vsync, + TP_PROTO(const char *name, int status), + TP_ARGS(name, status) +); +DEFINE_EVENT(dpu_status_template, dpu_isr_status, + TP_PROTO(const char *name, int status), + TP_ARGS(name, status) +); + +DECLARE_EVENT_CLASS(dpu_uint64_t_data_template, + TP_PROTO(const char *name, u64 data), + TP_ARGS(name, data), + TP_STRUCT__entry( + __string(name_str, name) + __field(u64, data) + ), + TP_fast_assign( + __assign_str(name_str); + __entry->data =3D data; + ), + TP_printk("%s: %lld", + __get_str(name_str), __entry->data) +); + +DEFINE_EVENT(dpu_uint64_t_data_template, u64_data, + TP_PROTO(const char *name, u64 data), + TP_ARGS(name, data) +); + +TRACE_EVENT(spacemit_dpu_reg_write, + TP_PROTO(u32 data, u32 base, const char *name), + TP_ARGS(data, base, name), + TP_STRUCT__entry( + __field(u32, data) + __field(u32, base) + __string(name_str, name) + ), + TP_fast_assign( + __entry->data =3D data; + __entry->base =3D base; + __assign_str(name_str); + ), + TP_printk("dpu write 0x%x to addr 0x%x field %s", + __entry->data, __entry->base, __get_str(name_str)) +); + +TRACE_EVENT(spacemit_plane_disable_hw_channel, + TP_PROTO(u32 layer_id, u32 rdma_id), + TP_ARGS(layer_id, rdma_id), + TP_STRUCT__entry( + __field(u32, layer_id) + __field(u32, rdma_id) + ), + TP_fast_assign( + __entry->layer_id =3D layer_id; + __entry->rdma_id =3D rdma_id; + ), + TP_printk("layer_id:%d rdma_id:%d", + __entry->layer_id, __entry->rdma_id) +); + +DECLARE_EVENT_CLASS(dpu_func_template, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id), + TP_STRUCT__entry( + __field(u32, dev_id) + ), + TP_fast_assign( + __entry->dev_id =3D dev_id; + ), + TP_printk("dev_id=3D%d", __entry->dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_check, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_update, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_duplicate_state, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_destroy_state, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_plane_init, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, dpu_enable_clocks, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, dpu_disable_clocks, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, dpu_uninit, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, dpu_isr, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, dpu_run, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_enable, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_disable, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_check, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_begin, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_flush, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_enable_vblank, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_disable_vblank, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_run, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_init, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, spacemit_crtc_uninit, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DEFINE_EVENT(dpu_func_template, saturn_ctrl_cfg_ready_timer, + TP_PROTO(u32 dev_id), + TP_ARGS(dev_id) +); +DECLARE_EVENT_CLASS(dpu_ctrl_template, + TP_PROTO(int id, int enable), + TP_ARGS(id, enable), + TP_STRUCT__entry( + __field(u32, id) + __field(u32, enable) + ), + TP_fast_assign( + __entry->id =3D id; + __entry->enable =3D enable; + ), + TP_printk("id=3D%d enable:%d", + __entry->id, __entry->enable) +); +DEFINE_EVENT(dpu_ctrl_template, saturn_ctrl_cfg_ready, + TP_PROTO(int id, int enable), + TP_ARGS(id, enable) +); + +DEFINE_EVENT(dpu_ctrl_template, saturn_ctrl_sw_start, + TP_PROTO(int id, int enable), + TP_ARGS(id, enable) +); + +TRACE_EVENT(plat_cmdlist_dump_node, + TP_PROTO(char *dump), + TP_ARGS(dump), + TP_STRUCT__entry( + __string(dump_str, dump) + ), + TP_fast_assign( + __assign_str(dump_str); + ), + TP_printk("%s", __get_str(dump_str)) +); + +TRACE_EVENT(cmdlist_dump_node, + TP_PROTO(char *type, int rdma_id, u8 dev_id, int zpos, u16 nod_len), + TP_ARGS(type, rdma_id, dev_id, zpos, nod_len), + TP_STRUCT__entry( + __string(type_str, type) + __field(int, rdma_id) + __field(u8, dev_id) + __field(int, zpos) + __field(u16, nod_len) + ), + TP_fast_assign( + __assign_str(type_str); + __entry->rdma_id =3D rdma_id; + __entry->dev_id =3D dev_id; + __entry->zpos =3D zpos; + __entry->nod_len =3D nod_len; + ), + TP_printk("cmdlist[%s]: rdma_id:%d crtc:%d zpos:%d rows:%d", + __get_str(type_str), + __entry->rdma_id, + __entry->dev_id, + __entry->zpos, + __entry->nod_len) +); +#endif /* _DPU_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_FILE +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/spacemit/dpu/ + +#define TRACE_INCLUDE_FILE dpu_trace +#include diff --git a/drivers/gpu/drm/spacemit/spacemit_cmdlist.c b/drivers/gpu/drm/= spacemit/spacemit_cmdlist.c new file mode 100644 index 0000000000000..f4f14eaa12a0f --- /dev/null +++ b/drivers/gpu/drm/spacemit/spacemit_cmdlist.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "spacemit_cmdlist.h" +#include "spacemit_crtc.h" +#include "spacemit_dpu_reg.h" +#include "spacemit_drm.h" +#include "dpu/dpu_saturn.h" +#include "dpu/dpu_trace.h" + +struct spacemit_plane_state *cl_to_spacemit_pstate(const struct cmdlist *c= l) +{ + return container_of(cl, struct spacemit_plane_state, cl); +} + +struct spacemit_crtc_state *cl_to_spacemit_cstate(const struct cmdlist *cl) +{ + return container_of(cl, struct spacemit_crtc_state, cl); +} + +struct cmdlist *plane_to_cl(struct drm_plane *plane) +{ + struct spacemit_plane_state *spacemit_pstate =3D + to_spacemit_plane_state(plane->state); + + return &spacemit_pstate->cl; +} + +struct cmdlist *crtc_to_cl(struct drm_crtc *crtc) +{ + struct spacemit_crtc_state *spacemit_cstate =3D + to_spacemit_crtc_state(crtc->state); + + return &spacemit_cstate->cl; +} + +static void cmdlist_dump_node(struct cmdlist *cl) +{ + struct spacemit_drm_private *priv; + struct spacemit_hw_device *hwdev; + struct spacemit_crtc *a_crtc; + char *type; + int zpos =3D -1, rdma_id =3D -1; + + if (!cl) + return; + + if (cl->type =3D=3D CMDLIST_PLANE) { + struct spacemit_plane_state *spacemit_pstate =3D + cl_to_spacemit_pstate(cl); + + a_crtc =3D to_spacemit_crtc(spacemit_pstate->state.crtc); + rdma_id =3D spacemit_pstate->rdma_id; + zpos =3D (int)(spacemit_pstate->state.zpos); + type =3D "RDMA"; + } else if (cl->type =3D=3D CMDLIST_CRTC) { + struct spacemit_crtc_state *spacemit_cstate =3D + cl_to_spacemit_cstate(cl); + + a_crtc =3D to_spacemit_crtc(spacemit_cstate->base.crtc); + type =3D "CRTC"; + } else { + return; + } + + trace_cmdlist_dump_node(type, rdma_id, a_crtc->dev_id, zpos, + cl->nod_len); + + priv =3D a_crtc->crtc.dev->dev_private; + hwdev =3D priv->hwdev; + hwdev->cmdlist_dump_node(cl); +} + +void cmdlist_regs_packing(struct cmdlist *cl, enum cmdlist_mode_type mod, + struct cmdlist_regs *cl_regs) +{ + struct spacemit_crtc *a_crtc; + struct spacemit_drm_private *priv; + struct spacemit_hw_device *hwdev; + u32 *reg_base; + int i; + u32 index; + + if (!cl_regs) + return; + + if (cl->type =3D=3D CMDLIST_PLANE) { + struct spacemit_plane_state *spacemit_pstate =3D + cl_to_spacemit_pstate(cl); + + a_crtc =3D to_spacemit_crtc(spacemit_pstate->state.crtc); + + drm_dbg(a_crtc->crtc.dev, "rch_id =3D %d, ch_y =3D %u\n", + spacemit_pstate->rdma_id, + spacemit_pstate->state.crtc_y); + } else if (cl->type =3D=3D CMDLIST_CRTC) { + struct spacemit_crtc_state *spacemit_cstate =3D + cl_to_spacemit_cstate(cl); + + a_crtc =3D to_spacemit_crtc(spacemit_cstate->base.crtc); + } else { + WARN_ONCE(1, "unsupported cmdlist type %d\n", cl->type); + return; + } + + priv =3D a_crtc->crtc.dev->dev_private; + hwdev =3D priv->hwdev; + reg_base =3D cl_regs->module; + + cl->mode_mask |=3D mod; + + /* + * Without the atomic_check() buffer the staged register writes vanish. + */ + if (drm_WARN_ON(a_crtc->crtc.dev, !cl->va)) + return; + + for (i =3D 0; i < cl_regs->size;) { + u32 value[CMDLIST_ROW_REGS] =3D {0x0}; + u32 offset, strobe =3D 0; + u8 regs_in_row =3D 0; + + if (cl_regs->flags[i]) { + offset =3D cl_regs->base + i * sizeof(u32); + for (u8 j =3D 0; j < CMDLIST_ROW_REGS; j++) { + index =3D i + j; + if (likely(index < cl_regs->size)) { + if (cl_regs->flags[index]) { + value[j] =3D reg_base[index]; + regs_in_row++; + strobe |=3D CMDLIST_REG_STROBE(j); + } + } else { + break; + } + } + hwdev->cmdlist_fill_data_row(cl, strobe, offset, value); + /* + * the row covers the whole window; a shorter stride + * would revisit covered words as duplicate rows + */ + i +=3D CMDLIST_ROW_REGS; + cl->nod_len++; + } else { + i++; + } + } + + drm_dbg(a_crtc->crtc.dev, "row_num =3D %d\n", cl->nod_len); +} + +void cmdlist_sort_by_group(struct drm_crtc *crtc) +{ + struct cmdlist *first_cl; + struct cmdlist *last_cl; + struct cmdlist *p; + struct cmdlist *prev; + struct drm_plane *plane; + struct spacemit_crtc_rdma *rdmas =3D + to_spacemit_crtc_state(crtc->state)->rdmas; + struct spacemit_drm_private *priv =3D crtc->dev->dev_private; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct spacemit_plane_state *spacemit_pstate =3D + to_spacemit_plane_state(plane->state); + u32 rdma_id =3D spacemit_pstate->rdma_id; + + first_cl =3D &spacemit_pstate->cl; + if (!first_cl->va) + continue; + + last_cl =3D first_cl; + last_cl->next =3D NULL; + + rdmas[rdma_id].in_use =3D true; + if (priv->cmdlist_groups[rdma_id]) { + p =3D priv->cmdlist_groups[rdma_id]; + prev =3D NULL; + while (p) { + if (cl_to_spacemit_pstate(p)->state.crtc_y < + spacemit_pstate->state.crtc_y) { + prev =3D p; + p =3D p->next; + } else { + break; + } + } + if (!prev) { + priv->cmdlist_groups[rdma_id] =3D first_cl; + last_cl->next =3D p; + } else { + prev->next =3D first_cl; + last_cl->next =3D p; + } + } else { + priv->cmdlist_groups[rdma_id] =3D first_cl; + } + } +} + +void cmdlist_atomic_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + int i; + struct cmdlist *cur_cl, *first_cl; + struct spacemit_crtc *a_crtc =3D NULL; + u32 chy, addrl, addrh; + struct spacemit_drm_private *priv =3D crtc->dev->dev_private; + struct spacemit_hw_device *hwdev =3D priv->hwdev; + struct spacemit_crtc_rdma *cur_rdmas =3D + to_spacemit_crtc_state(crtc->state)->rdmas; + struct spacemit_crtc_rdma *old_rdmas =3D + to_spacemit_crtc_state(old_state)->rdmas; + + a_crtc =3D to_spacemit_crtc(crtc); + + for (i =3D 0; i < hwdev->rdma_nums; i++) { + if (old_rdmas[i].in_use) + hwdev->enable_cmdlist(a_crtc, hwdev, i, false); + + if (cur_rdmas[i].in_use) { + drm_dbg(crtc->dev, "cmdlist group =3D %d\n", i); + cur_cl =3D priv->cmdlist_groups[i]; + first_cl =3D cur_cl; + while (cur_cl) { + hwdev->cmdlist_fill_conf_row(cur_cl, hwdev, + CMDLIST_CMP_INVALID); + cmdlist_dump_node(cur_cl); + cur_cl =3D cur_cl->next; + } + chy =3D cl_to_spacemit_pstate(first_cl)->state.crtc_y; + addrl =3D (lower_32_bits(priv->cmdlist_groups[i]->pa) & + CMDLIST_ADDRL_ALIGN_MASK) >> CMDLIST_ADDRL_ALIGN_BITS; + + addrh =3D upper_32_bits(priv->cmdlist_groups[i]->pa); + hwdev->cfg_cmdlist(hwdev, i, chy, addrl, addrh); + hwdev->enable_cmdlist(a_crtc, hwdev, i, true); + priv->cmdlist_groups[i] =3D NULL; + } + } +} + +void crtc_cmdlist_sort_by_group(struct spacemit_crtc *a_crtc) +{ + struct cmdlist *first_cl; + struct cmdlist *last_cl; + struct drm_crtc *crtc =3D &a_crtc->crtc; + struct spacemit_drm_private *priv =3D crtc->dev->dev_private; + struct spacemit_hw_device *hwdev =3D priv->hwdev; + struct drm_crtc_state *crtc_state =3D a_crtc->crtc.state; + struct spacemit_crtc_state *spacemit_crtc_state =3D + to_spacemit_crtc_state(crtc_state); + u8 crtc_id =3D drm_crtc_index(crtc); + + first_cl =3D &spacemit_crtc_state->cl; + last_cl =3D first_cl; + last_cl->next =3D NULL; + priv->cmdlist_groups[hwdev->rdma_nums + crtc_id] =3D first_cl; +} + +void crtc_cmdlist_atomic_commit(struct spacemit_crtc *a_crtc) +{ + struct cmdlist *cur_cl; + struct drm_crtc *crtc =3D &a_crtc->crtc; + struct spacemit_drm_private *priv =3D crtc->dev->dev_private; + struct spacemit_hw_device *hwdev =3D priv->hwdev; + u8 crtc_id =3D drm_crtc_index(crtc); + u8 dev_id =3D a_crtc->dev_id; + + drm_dbg(crtc->dev, "cmdlist group =3D %d\n", + hwdev->rdma_nums + crtc_id); + cur_cl =3D priv->cmdlist_groups[hwdev->rdma_nums + crtc_id]; + while (cur_cl) { + hwdev->cmdlist_fill_conf_row(cur_cl, hwdev, dev_id); + cmdlist_dump_node(cur_cl); + cur_cl =3D cur_cl->next; + } + hwdev->crtc_cmdlist(hwdev, priv, crtc_id, dev_id); +} + +/* Called from atomic_check(), where -ENOMEM is still an answer. */ +int spacemit_cmdlist_alloc(struct device *dev, struct cmdlist *cl) +{ + if (cl->va) + return 0; + + cl->size =3D PER_CMDLIST_SIZE; + cl->va =3D dma_alloc_coherent(dev, cl->size, &cl->pa, + GFP_KERNEL | __GFP_ZERO); + if (!cl->va) + return -ENOMEM; + + return 0; +} diff --git a/drivers/gpu/drm/spacemit/spacemit_cmdlist.h b/drivers/gpu/drm/= spacemit/spacemit_cmdlist.h new file mode 100644 index 0000000000000..d5acdbeb3b0e7 --- /dev/null +++ b/drivers/gpu/drm/spacemit/spacemit_cmdlist.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#ifndef _SATURN_FW_CMDLIST_H_ +#define _SATURN_FW_CMDLIST_H_ + +#include +#include +#include +#include + +struct spacemit_crtc; +struct spacemit_plane_state; + +#define PER_CMDLIST_SIZE 4096 +#define CMDLIST_ROW_REGS (3) +#define CMDLIST_CMP_INVALID (0xff) +/* poison for the per-cmdlist compose sentinels, never written to hw */ +#define CMDLIST_SENTINEL_POISON 0xDEADBEEF + +/** + * enum cmdlist_type - what surface owns a cmdlist instance + * @CMDLIST_PLANE: Per-plane RDMA register batches. + * @CMDLIST_CRTC: Compose-side batches submitted on every flush. + */ +enum cmdlist_type { + CMDLIST_PLANE =3D 1, + CMDLIST_CRTC, +}; + +/** + * struct cmdlist - A DMA-backed batch of register writes replayed at CFG_= RDY + * @nod_len: Number of register-write rows currently filled. + * @size: Capacity of the DMA buffer in bytes. + * @mode_mask: cmdlist_mode_type sources; gates which rows are pulled. + * @va: Kernel virtual address of the DMA buffer. + * @pa: DMA address programmed into the cmdlist base register. + * @next: Cmdlists in submission order; the CRTC-level one comes last. + * @type: Originating surface; see &enum cmdlist_type. + * @rch_start_cmps_y: Compositor-Y start sentinel. + * @cmdlist_ch_y_other: Companion sentinel to @rch_start_cmps_y. + */ +struct cmdlist { + u16 nod_len; + u32 size; + u32 mode_mask; + void *va; + dma_addr_t pa; + struct cmdlist *next; + u8 type; + u32 rch_start_cmps_y; + u32 cmdlist_ch_y_other; +}; + +enum cmdlist_mode_type { + CMDLIST_MOD_RDMA =3D BIT(0), + CMDLIST_MOD_COMP =3D BIT(3), + CMDLIST_MOD_DMMU =3D BIT(6), +}; + +#define CMDLIST_REG_STROBE(index) (0xf << ((index) * 4)) + +#define CMDLIST_ADDRL_ALIGN_BITS (4) /* From cmdlist_reg_0[]= in CMDLIST_REG */ +#define CMDLIST_ADDRL_ALIGN_MASK \ + ((u32)(~(BIT(CMDLIST_ADDRL_ALIGN_BITS) - 1))) +/* NULL on failure is safe: every consumer falls back to direct MMIO. */ +#define alloc_cmdlist_regs(module_name) \ +({ \ + struct cmdlist_regs *cl =3D kzalloc(sizeof(*cl), GFP_KERNEL); \ + if (cl) { \ + cl->size =3D module_name##__NWORDS; \ + cl->module =3D kzalloc(4 * module_name##__NWORDS, GFP_KERNEL); \ + cl->flags =3D kzalloc(module_name##__NWORDS, GFP_KERNEL); \ + if (!cl->module || !cl->flags) { \ + kfree(cl->module); \ + kfree(cl->flags); \ + kfree(cl); \ + cl =3D NULL; \ + } \ + } \ + cl; \ +}) + +#define free_cmdlist_regs(cl_p) \ +do { \ + struct cmdlist_regs *cl =3D (cl_p); \ + if (cl) { \ + kfree(cl->module); \ + kfree(cl->flags); \ + kfree(cl); \ + } \ +} while (0) + +/* + * First touch seeds the word from a live MMIO read: only register blocks = that + * read back what was written may be routed through cmdlist. + */ +#define cmdlist_write_reg(hwdev, module_name, module_base, field, data, cl= _regs) \ +do { \ + struct cmdlist_regs *cl_p =3D (cl_regs); \ + u32 *__words =3D cl_p->module; \ + const unsigned int __w =3D dpu_field_word(module_name, field); \ + if (cl_p->flags[__w] =3D=3D 0) { \ + __words[__w] =3D readl((hwdev)->base + (module_base) + 4 * __w); \ + cl_p->base =3D (module_base); \ + cl_p->flags[__w] =3D 1; \ + } \ + __words[__w] &=3D ~dpu_field_mask(module_name, field); \ + __words[__w] |=3D FIELD_PREP(dpu_field_mask(module_name, field), \ + (u32)(data)); \ +} while (0) + +/* Raw whole-word variant (the value32[] call sites); no seeding needed. */ +#define cmdlist_write_word(module_base, word, data, cl_regs) \ +do { \ + struct cmdlist_regs *cl_p =3D (cl_regs); \ + u32 *__words =3D cl_p->module; \ + cl_p->base =3D (module_base); \ + cl_p->flags[(word)] =3D 1; \ + __words[(word)] =3D (u32)(data); \ +} while (0) + +struct cmdlist_regs { + u32 base; + u16 size; + u32 *module; + u8 *flags; +}; + +void cmdlist_regs_packing(struct cmdlist *cl, enum cmdlist_mode_type mod, + struct cmdlist_regs *cl_regs); +void cmdlist_sort_by_group(struct drm_crtc *crtc); +void cmdlist_atomic_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); +struct spacemit_plane_state *cl_to_spacemit_pstate(const struct cmdlist *c= l); +void crtc_cmdlist_sort_by_group(struct spacemit_crtc *a_crtc); +void crtc_cmdlist_atomic_commit(struct spacemit_crtc *a_crtc); +struct spacemit_crtc_state *cl_to_spacemit_cstate(const struct cmdlist *cl= ); +int spacemit_cmdlist_alloc(struct device *dev, struct cmdlist *cl); +struct cmdlist *plane_to_cl(struct drm_plane *plane); +struct cmdlist *crtc_to_cl(struct drm_crtc *crtc); + +#endif /* _SATURN_FW_CMDLIST_H_ */ diff --git a/drivers/gpu/drm/spacemit/spacemit_crtc.h b/drivers/gpu/drm/spa= cemit/spacemit_crtc.h new file mode 100644 index 0000000000000..7c03102414d00 --- /dev/null +++ b/drivers/gpu/drm/spacemit/spacemit_crtc.h @@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025-2026 SpacemiT Co., Ltd. + * + */ + +#ifndef _SPACEMIT_CRTC_H_ +#define _SPACEMIT_CRTC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include