From nobody Mon Sep 28 19:23:44 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 DB701451998; Tue, 18 Aug 2026 10:32:13 +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=1787049133; cv=none; b=AmA342sPUByr9i/eLJcRmJGIFzxDsl/NTt6vkfQbdEQTSziy/MMvMzntsW7e/E0xcVAegK51HRNYQPM+L90jidxOyWJZgId3onnzBXlmzCh+oE0ZpeSWKOwh85zR0tMwke/ehQUPsHV/2SfcR0ToqW7JCmejcCX5aKX0AjfU5cQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049133; c=relaxed/simple; bh=bBo2EYuFMiPEg5+TDMdIErdYoSUfwyw/F22EJeOZDYA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AWVbvW7Frt72Hz28BFJvz/J2QI2molfQPcLBPuezEFxfDy7JJlnwzSs+4U1cAR+QO3Yguklpz9k7fEZ3gkK1bbYvvflEK0Lv+9gXh2VmkgGs1fzQhql4m0TW3wvaZjYlBUMY7kS4KUZSjtQKDAWmvpj8yuo19Z26scC6MxuiYUM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ovy2wBG6; 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="ovy2wBG6" Received: by smtp.kernel.org (Postfix) with ESMTPS id 7A2F9C2BCF4; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049133; bh=bBo2EYuFMiPEg5+TDMdIErdYoSUfwyw/F22EJeOZDYA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ovy2wBG6n+e8GxlX8WxuggwW8b5Wzhtx+iWNpbolmc+MKpXrlVuOtC1KRDeS9m3cr tYlgc1Ixct12hsUifIbaQbvGVvase6OKcaKQ8mjDyw1dlbv9h5T08+8aOLfPisR4Mb 8w8ol0e9kD7fEjoWvHJOHxaIX2P0KsMG5jxd2UIdxSaTGAiP0j+Arl/ajWtarWgKQm PuF5IYtjecrmW7ks5UROxEOLFH/dcoNTSg0JVgemsXCtoZg3JHgt0+CrL2//N97MeK ZYOPmwL93JTBtpPGSkI+JjmzOHbvj5CUN08PeiSl2igAQYhYT+3REcgwgPa3dk56kV fddf/NerJCdUg== 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 585DEC5DF7E; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:15 +0800 Subject: [PATCH v5 01/12] dt-bindings: arm: add Ambarella CV75 platforms 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: <20260818-cv75-v5-v5-1-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao , Krzysztof Kozlowski X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=1828; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=YCSbMKhFe2paSe+SbS/++piT5GFUx/NTLE9tewoMf1g=; b=7zS5JX+qYMav0URq9+fkE+H6aGnT83L6d9WznSLatR9efeE6dfU171Rtot4QnRUxUI0wHm7BP azprhVfRdAXCR67Ee9u9CdAxFXWaQ7o8pf+ub3XCwzCLjXM+wck511p X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Add the Ambarella vendor prefix and CV75 EVK board compatible for the initial SoC bring-up. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Long Zhao --- .../devicetree/bindings/arm/ambarella.yaml | 24 ++++++++++++++++++= ++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 ++ 2 files changed, 26 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/ambarella.yaml b/Documen= tation/devicetree/bindings/arm/ambarella.yaml new file mode 100644 index 000000000000..72946e94fa76 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/ambarella.yaml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/ambarella.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ambarella SoC platforms + +maintainers: + - Long Zhao + +properties: + $nodename: + const: "/" + + compatible: + oneOf: + - description: Ambarella CV75 boards + items: + - enum: + - ambarella,cv75-evk + - const: ambarella,cv75 + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Docum= entation/devicetree/bindings/vendor-prefixes.yaml index 85a27937832e..f48aa6dabbe9 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -112,6 +112,8 @@ patternProperties: description: Amarula Solutions "^amazon,.*": description: Amazon.com, Inc. + "^ambarella,.*": + description: Ambarella, Inc. "^amcc,.*": description: Applied Micro Circuits Corporation (APM, formally AMCC) "^amd,.*": --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 DF4BB4519A2; Tue, 18 Aug 2026 10:32:13 +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=1787049133; cv=none; b=A92BlnSpMS995ejndMSSkB3Ew8U6W/b8xUCt7W4P+B2P5fIjUsosLmbiTMhTOyMvvTDH1sVjmccmyB0n7PbDYFoO63SxnvBZOZ5WXDJBbALzBq4yEEz4Brdm5EXWDPth0SvHhSZs+KVPolafAlykpHQqI+p78r/vVqOXBFk7cjY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049133; c=relaxed/simple; bh=QVo13gwqTD4KZzt9imrEAhoQPNNjElG0xmVDlRWUyNI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qWYqclODrINSgLGR8ANc1KG0gUSYO8KIGYdq3jEGYkgyJv1dnvHCCB/tX8dM5MqgxLMN4F6QTFUh+sEI5EvWVfVqA7lO5TcXLIpKCfS2RZYGh9kH1cC3oTaA3sFZng0lFPJh+9rqp8houIX+j5EBeuxyhHrYmTfaiL6oUCBzjJA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lnN+DjGH; 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="lnN+DjGH" Received: by smtp.kernel.org (Postfix) with ESMTPS id 9277EC2BCFA; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049133; bh=QVo13gwqTD4KZzt9imrEAhoQPNNjElG0xmVDlRWUyNI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=lnN+DjGHeo2tlc9vycESrAeCBLVQTWq34Njnvezg9CzWCbnonP3YdFTEXOlZTeByR zzadrpuPzV7YWHtK4mhkBh3gfV9rd+XJkJHGeXrAmEaJ5Mpxr0D/tIe39cSZ2Vkq+h f7GqjXbhgVb3KuivP/easo1L2Nr6F8LZzafUCA/WolDufpmfwjj9o1wODX6j7Lkh5Y A2XbrsiyGx3Ze60XRvr7xG15qTKlwc3faQq+Kjh0RiT2DvqZkPbks0uwsZACybJfxi t5LDBsW/8CBsVTdfjnR4XMY65yP2xMLvmqR7N4z6gNJg+3/CvK1ZPfyTyWK5bj68fq CyCi4w/kyjKMQ== 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 7156DC5DF80; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:16 +0800 Subject: [PATCH v5 02/12] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad 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: <20260818-cv75-v5-v5-2-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=864; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=UZUyXXBBt/U6PUqQu+CGVwiN2KK9z5EYeOVD1g3SxZg=; b=T8yD7k5AUqFRlxCE8adl8w66UEPKZlmwNFkLbqgX9QAVa/6oT3PaPWQtmP1u4FbMy7fjOmrHQ gK9z87jqEUICI07g5YRbWrqdiPaZHBed4IEaJhQQnJwBc2vYstg5t3W X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Allow ambarella,cv75-sec-scratchpad as a syscon for the shared secure scratchpad registers on CV75. Signed-off-by: Long Zhao --- Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentat= ion/devicetree/bindings/mfd/syscon.yaml index fe882d3f828b..9ebf702c06f1 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -32,6 +32,7 @@ properties: - allwinner,sun50i-a64-system-controller - altr,l3regs - altr,sdr-ctl + - ambarella,cv75-sec-scratchpad - amd,pensando-elba-syscon - amlogic,meson-mx-assist - amlogic,meson-mx-bootrom --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 E25064519AD; Tue, 18 Aug 2026 10:32:13 +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=1787049134; cv=none; b=WAMK4lkMp3Is8CBkibWI5wjRYGf4bsY1Je4tSqZtXV6WPioL3N5AB5QSFEVyNeBcHYAuPpri/objUxINxEim1JuwhpUX0o/DSPdIEs43X9XECN6XWSfyB92B51kKX7prggZXPyvMrhBfka0c7DIzr1kwZqG0wX5XQwFpJuff4qs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=8kmXgMn7RPN9j9Jy9UOQa6siDtddsJcy9fJ+5E1nz2k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FDjPTkYJc7uFsmRe2YJM2+FQF5R/K2/xZHURU0R2aBioL5gv6s39fxXxC7ajTJcCtapj2v+o4ADHe51b5M01UZl41iaFH56QgF5ovnQtJ6aLjqSFjo2KRwUImEVnndOWGUfJjEbDV1ptgvL7UsNFFbJuh4XfamOSs4hhxjCe1dY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=d7hlcV7q; 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="d7hlcV7q" Received: by smtp.kernel.org (Postfix) with ESMTPS id A314BC2BCFB; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049133; bh=8kmXgMn7RPN9j9Jy9UOQa6siDtddsJcy9fJ+5E1nz2k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=d7hlcV7qh1C9Zlu6p9j2r0LEu4/yFtH5BfZx8xE5ZzFWJ0mm8N1efoD151U5T/Lq6 GT0Q7Q2yS60HFyOYAjgfbmtAPJjQp6Gvbv73Mk7F8FgnvIdMzv0LBgOHwGXYszZWMk Y++nOMT37eS8o8WoJPoD5iudbpS/D51h+ZD8d1X/SCX3NrmXoSXslUF5rVMZZb9PbE IrVrryimvRO29HhA75yBQ60SS0n+H/bHauxNgboORIQMrPXmr+aA0vCu6dL1Zl3TD/ Z/yh06+hRuQxuGWRrL/ZOXSTiU9FBREauzG8qLV34o725gC1Ih9S2L2tO7wLVKX40R B+N9OswQ/AXPg== 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 87A2AC5DF83; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:17 +0800 Subject: [PATCH v5 03/12] dt-bindings: clock: add Ambarella CV75 RCT 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: <20260818-cv75-v5-v5-3-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=2831; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=V/+hOnSzFSfW8h7vb5mU8wEcrovus3c1ZYvtQiEoZ8M=; b=1L9RzEZpAKZpbuE1EZVlaJ604mA6VtWntg5JCP8Rhm6MWZdE0JW3z43uEuTH1cwtS0XxbPUvA aWZqdUcvDKWCa58iV/FqZnZQ0lyieXXzk8z42eNT25wWrFJaiCnnOgI X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Document the CV75 RCT clock controller and the clock ID header used by DT consumers. This initial binding describes only the clock-provider functionality. Reset-controller support is outside scope of this series, so #reset-cells property is intentionally omitted. Signed-off-by: Long Zhao --- .../bindings/clock/ambarella,cv75-rct.yaml | 58 ++++++++++++++++++= ++++ include/dt-bindings/clock/ambarella,cv75-rct.h | 15 ++++++ 2 files changed, 73 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yam= l b/Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yaml new file mode 100644 index 000000000000..eb5956fc32bc --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ambarella,cv75-rct.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ambarella CV75 RCT Clock Controller + +maintainers: + - Long Zhao + +description: | + The RCT (Reset and Clock Tree) block on the Ambarella CV75 SoC provides + PLLs, clock muxes and dividers for on-chip peripherals. + + The same register region is also exposed as a syscon for other SoC + blocks (e.g. pin drive-strength), hence the "syscon" compatible. + + Clock indices are defined in include/dt-bindings/clock/ambarella,cv75-rc= t.h. + +properties: + + compatible: + items: + - const: ambarella,cv75-rct + - const: syscon + + reg: + maxItems: 1 + + clocks: + description: Reference crystal oscillator (typically 24 MHz) + maxItems: 1 + + clock-names: + const: osc + + "#clock-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - "#clock-cells" + +additionalProperties: false + +examples: + - | + clock-controller@ed080000 { + compatible =3D "ambarella,cv75-rct", "syscon"; + reg =3D <0xed080000 0x1000>; + clocks =3D <&osc>; + clock-names =3D "osc"; + #clock-cells =3D <1>; + }; diff --git a/include/dt-bindings/clock/ambarella,cv75-rct.h b/include/dt-bi= ndings/clock/ambarella,cv75-rct.h new file mode 100644 index 000000000000..0a6e946c9108 --- /dev/null +++ b/include/dt-bindings/clock/ambarella,cv75-rct.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (C) 2026 Ambarella, Inc. + */ + +#ifndef _DT_BINDINGS_CLOCK_AMBARELLA_CV75_RCT_H +#define _DT_BINDINGS_CLOCK_AMBARELLA_CV75_RCT_H + +/* Boot / bus clocks */ +#define CV75_GCLK_UART0 0 +#define CV75_GCLK_CORE 1 +#define CV75_GCLK_AHB 2 +#define CV75_GCLK_APB 3 + +#endif --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 017E74519BA; Tue, 18 Aug 2026 10:32:13 +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=1787049134; cv=none; b=ruDvei69uLnC5lgrYtgyrWHgGwxvQJ8x3gPkLcQLK+EA2hcLe+7dEPSGSYRG5Ilpw+CYQthkqNkKUgG6TyFvCk9ypxgqR3C29/8Mr+K4vXF5kDh8kTOHkSKQIZusu1Rw9ei4eKcRYd7hDGHYaFclqev6LDp/llOx+eHsG8d0mQE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=hp7bqmHn9P6jHYwnNUYIruS99llCyau/ChCTrkE9I+E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VBZsW6leWIYAZjV9dR7nyfu8l/YvYzX9xN4oU8P9Fj9pbUM6vDcWzR1yKTkMktVylrwN5GabAfe4SO64HvZ1Q2oc7fi/GjDFTiV0mjhjDn7fSftldgQeHNE42mEjYGHNhhTaLRBClX/kYz72AfsbgXxEyHAHOIBWTTcMdfEgsYA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ayZJa1sV; 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="ayZJa1sV" Received: by smtp.kernel.org (Postfix) with ESMTPS id B49FCC2BCFD; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049133; bh=hp7bqmHn9P6jHYwnNUYIruS99llCyau/ChCTrkE9I+E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ayZJa1sVH7++0TDFW9aoodDYU6rdAbzkf4zDqLPqxB14Gvf+E1hkBbZCwXlQxA0g8 d/cqkhqkrCg7idKhrZ8T+E7ClPgbT/DnydVFo6152Vl4nrM+vxj6lwuLBr4QhwNBL0 RZ4jeV+HJkn0ylpRBCDb6B9hxiD/6pd89uxL+w+P6r2rbtStD7p3nmzFeSWWcGDArr Gg63P3aoexDRuItczcnDFBs/H0A90vps2MQrFP7kZYHu3iQ5S+2daURmFaBjNsgqa/ cbyjWHxMiF16l+a+riRZAEn4frC/1BNCpO7faceOuEZ3mXQsr+vDpzkuzZG0eW22sW OydMv0infh7Rw== 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 9D225C5DF81; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:18 +0800 Subject: [PATCH v5 04/12] dt-bindings: pinctrl: add Ambarella CV75 pinctrl 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: <20260818-cv75-v5-v5-4-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=6330; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=XEvKncSGovDF7OgNkB6DKQG+ZkDy9YW2XQhMlWM+4n0=; b=h0FnNS20H56ST+R+dRfD5UAzzGYH0JEd8Or/5lM0Na4qx2C7nEvIIvStg13h1naJHobLAF/AF uZh/eJHD9QZBVWpx9A5orZvK3lxDnL1ANHOdlepSP7cT+s9rcZpktTG X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Document the CV75 pin controller binding using generic function and groups properties for pinmux configuration. Signed-off-by: Long Zhao --- .../bindings/pinctrl/ambarella,cv75-pinctrl.yaml | 239 +++++++++++++++++= ++++ 1 file changed, 239 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinct= rl.yaml b/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.= yaml new file mode 100644 index 000000000000..34054bc56c3b --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.yaml @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/ambarella,cv75-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ambarella CV75 Pin Controller + +maintainers: + - Long Zhao + +description: + The Ambarella CV75 pin controller configures pin multiplexing, bias and + drive strength for the main GPIO banks. Pin groups and their mux settings + are defined by the pin controller driver and selected by function and gr= oup + names. + +allOf: + - $ref: pinctrl.yaml# + +properties: + compatible: + const: ambarella,cv75-pinctrl + + reg: + maxItems: 1 + description: IOMUX registers + + ambarella,drive-strength-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: RCT syscon containing the drive-strength registers. + + ambarella,pull-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: Secure scratchpad syscon containing the pull registers. + +patternProperties: + "^[a-z0-9-]+-pins$": + type: object + allOf: + - $ref: pinmux-node.yaml# + - $ref: pincfg-node.yaml# + additionalProperties: false + + properties: + function: + enum: + - can0 + - can1 + - clk_au + - dmic0 + - enet0 + - hsync0 + - hsync1 + - i2c0 + - i2c1 + - i2c2 + - i2c3 + - i2cs + - i2s0 + - i2s1 + - ir + - pwm0 + - pwm1 + - pwm2 + - pwm3 + - pwm4 + - pwm5 + - pwm6 + - pwm7 + - pwm8 + - pwm9 + - pwm10 + - pwm11 + - sdmmc0 + - sdmmc1 + - snand + - spi0 + - spi1 + - spi2 + - spi3 + - spi_slave + - spinor + - uart0 + - uart1 + - uart2 + - uart3 + - uart4 + - vin_master_sync + - vsync0 + - vsync1 + - vsync2 + - vsync3 + - wdt + + groups: + items: + enum: + - can0 + - can1 + - clk_au + - dmic0 + - enet_2nd_ref_clk_a + - enet_2nd_ref_clk_b + - enet_ext_osc_clk + - enet0_ptp_pps_o + - hsync0 + - hsync1 + - i2c0_a + - i2c0_b + - i2c1_a + - i2c1_b + - i2c2 + - i2c3_a + - i2c3_b + - i2c3_c + - i2cs_a + - i2cs_b + - i2cs_c + - i2cs_d + - i2s0 + - i2s1 + - ir + - pwm0 + - pwm1 + - pwm2 + - pwm3 + - pwm4_a + - pwm4_b + - pwm5_a + - pwm5_b + - pwm6_a + - pwm6_b + - pwm7_a + - pwm7_b + - pwm8_a + - pwm8_b + - pwm9_a + - pwm9_b + - pwm10_a + - pwm10_b + - pwm11_a + - pwm11_b + - rgmii0 + - rmii0 + - sdmmc0_1bit + - sdmmc0_4bit + - sdmmc0_cd + - sdmmc0_hs_sel + - sdmmc0_reset + - sdmmc0_wp + - sdmmc1_1bit + - sdmmc1_4bit + - sdmmc1_cd + - sdmmc1_hs_sel + - sdmmc1_reset + - sdmmc1_wp + - snand + - spi0 + - spi1 + - spi2 + - spi3_a + - spi3_b + - spi3_c + - spi_slave_a + - spi_slave_b + - spi_slave_c + - spi_slave_d + - spi_slave_e + - spinor + - uart0 + - uart1 + - uart1_flow + - uart2_a + - uart2_b + - uart2_c + - uart2_flow_a + - uart2_flow_b + - uart3_a + - uart3_b + - uart3_flow_a + - uart3_flow_b + - uart4_a + - uart4_b + - uart4_flow_a + - uart4_flow_b + - vin_master_sync_a + - vin_master_sync_b + - vin_master_sync_c + - vin_master_sync_d + - vin_master_sync_e + - vsync0 + - vsync1 + - vsync2 + - vsync3 + - wdt_a + - wdt_b + - wdt_c + - wdt_d + - wdt_e + - wdt_f + minItems: 1 + maxItems: 6 + uniqueItems: true + + bias-disable: true + bias-pull-down: true + bias-pull-up: true + + drive-strength: + enum: [3, 4, 5, 6, 7, 8, 9, 12] + + required: + - function + - groups + +required: + - compatible + - reg + - ambarella,drive-strength-syscon + - ambarella,pull-syscon + +unevaluatedProperties: false + +examples: + - | + pinctrl: pinctrl@e4010000 { + compatible =3D "ambarella,cv75-pinctrl"; + reg =3D <0xe4010000 0x1000>; + ambarella,drive-strength-syscon =3D <&rct>; + ambarella,pull-syscon =3D <&scratchpad>; + + uart0-pins { + function =3D "uart0"; + groups =3D "uart0"; + bias-disable; + drive-strength =3D <8>; + }; + }; --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 2D560456E12; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=QwYbrfPe8iqPr8EAfLLB6/+8odiZkdNNCl4QxNTOD0UAo8fuwaR97t4rdSUSpym5CnEDTQBj+LSsKrv8O176PWfb4xgGHC0Dq4I6eYHXLya/6YtBNDyNXDW7hKRZIz9Xf+pHnYS6ena17jKzyS0/5lTQOm9DP/3gvX6Ys08jOoM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=jEcPzTS2r9CRkRuHf/bP0CLeDxdimN8/GXo8Hz0PSGQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=d56ISHha7m9/m0xejhOhqP45wsRd6F5YWZI1ucpppVGw1oa0UWYzSqiB5ODbdLDoYEZlnbCXJkLlWhWTDBBhX6nk0mX2DmfxXbcYHdQEioqLzzDyaKGaeVS5Ty8ZndQPHnR9Uvi4l0r07JU+TJ5G1BCvP2h4kq72UCEgxHN72S0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lmMsA0G5; 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="lmMsA0G5" Received: by smtp.kernel.org (Postfix) with ESMTPS id CFF09C4AF0C; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049133; bh=jEcPzTS2r9CRkRuHf/bP0CLeDxdimN8/GXo8Hz0PSGQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=lmMsA0G5Q8oZQVCxvjBSavux2XN9pcMMQ2yqJxzorr/srtzEr08xBhf2s1phw7p9N 1lSf6a+ws2OUAND5BAN/taHWwfCFNSwxTA+bg/qlZsIJ6vPy6GXbMSfmYxNLJBzEuK 2W5Yki/1O278pIdNJurvJwo8T2XmaZkRGnf5sFIu0d5WvPAi8A588Qw6TpMh5CiZLv okFtuLZkENaKtOEEHNnMrpx6OOXxVkDIHHDulgXNI/CZCd7xnt6O9H4FnHT9XSFQEY UYP/b/8Lcp+ePUGbwiU0YjFNo+JW0iEfW/c9MVIMkpba+dfUsxzHmaj5H64I++tjKK w6hMzwavt2KQQ== 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 B495CC5DF84; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:19 +0800 Subject: [PATCH v5 05/12] dt-bindings: gpio: pl061: add Ambarella CV75 variant 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: <20260818-cv75-v5-v5-5-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=1941; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=Pngr7p+U3E/qWLbm7iUMOUjiAHv8IZUzMpz2/ZKNyVk=; b=ERm6YliqAyLiRYZMFDvJ/vS+LdTq7UeN8oTFIqiNI6KrdZKYs66DOsVTYT6sbgYEBuqfZgS2r 3YpxPbqjO7WDEs0T54oSFzodxcJSxS/ZKO7XsH4b7e6RewM+4nGHJOa X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Document the Ambarella CV75 GPIO bank compatible and the synthetic arm,primecell-periphid used with the PL061 binding. Signed-off-by: Long Zhao --- .../devicetree/bindings/gpio/pl061-gpio.yaml | 35 ++++++++++++++++++= +--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml b/Docum= entation/devicetree/bindings/gpio/pl061-gpio.yaml index 4d970e55104b..414f8d4a3976 100644 --- a/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml @@ -15,7 +15,9 @@ select: properties: compatible: contains: - const: arm,pl061 + enum: + - arm,pl061 + - ambarella,cv75-gpio required: - compatible =20 @@ -24,9 +26,20 @@ properties: pattern: "^gpio@[0-9a-f]+$" =20 compatible: - items: - - const: arm,pl061 - - const: arm,primecell + oneOf: + - items: + - const: arm,pl061 + - const: arm,primecell + - items: + - const: ambarella,cv75-gpio + - const: arm,primecell + + arm,primecell-periphid: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Value to override the hardware PrimeCell peripheral ID. Ambarella + variants use a synthetic ID retaining the PL061 part number because + the hardware has no discoverable ID or assigned designer ID. =20 reg: maxItems: 1 @@ -57,6 +70,20 @@ properties: minItems: 1 maxItems: 8 =20 +allOf: + - if: + properties: + compatible: + contains: + const: ambarella,cv75-gpio + then: + properties: + arm,primecell-periphid: + const: 0x00000061 + required: + - arm,primecell-periphid + - gpio-ranges + required: - compatible - reg --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 519FD45DF6E; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=GeAXdINSu4e8wxjFCTw6/wBvtMwJWfrcEYfTAqGAuFMm3nFIEHVEuLrZeCdwpWrUWbj0nYsrPpqGXd6RCffSjF9fhhyo+WzFl6sIN5NhyL1SiyB2+BdIfYgbOJ/W2UMMJj023T2Chsw6aFFKogZl4GqQdkCgphcKbgbiM9+531E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=XE7Jze2pWOY+XLVEZ5GthHvKEoJMO8iLYBrsfeT5fUs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fFP0LyWoMdzZxrSCe9wdufi4riypdaitEPDkp06pHcJdEmt5PdjtGxnQs/hwKljLHwAFW8jjDvtJnFPFL+UvQ6qE8eXxzyPabWjnHRYhvl0/XUygVhV0JsxrsCzkrKGQsqioveTm8uLrDq5jbIs2KiNjCzLsUpoimecmmLePuZI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kcmtxsBB; 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="kcmtxsBB" Received: by smtp.kernel.org (Postfix) with ESMTPS id E4727C32781; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=XE7Jze2pWOY+XLVEZ5GthHvKEoJMO8iLYBrsfeT5fUs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=kcmtxsBBiEst7E+Mh78eRH4cxVf0bQPPMYZyThjxUW0nSeltxVbnc4+fo2hsAE8l4 VW3JUjl8HSOWOdaG6rC6E8WnXABuUnZq57dgD3+HsLx7luEF7UHck477nIgQGbqv1b 6j91dqY0IZKYkV8KViC4moGmVAeVSKFc9olgoy3o8O/SYpI9oj7FpvhU+ZbvEfOmBL zrLjO3MxxC4fjmThTvl5JmwHC9aPRVUsd72CVBG3DTJt6DAGDLp9ytH13PhNPZRlo/ KLxvvF/7GtUZMIOqwvqtH7Wqf3EkYbHlGqw8kvR6kUWJzhB7JGUVJhrNntcr/KeA6p b2ZE5bz42KFYQ== 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 CB559C5DF7E; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:20 +0800 Subject: [PATCH v5 06/12] dt-bindings: serial: add Ambarella CV75 UART 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: <20260818-cv75-v5-v5-6-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=1828; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=5fvXIv4VkCf1t6ZAmNKnU3A6+aTT4MQ6fcD192SSaH0=; b=mUjLxTDt6GYIBD1VZ0ihH3mBXE05YBuVvYwKtwJk/oVtF8hBC5N1AYZD8QCXF8h3B/hzS3JiS x6XHFYANljODgynMMLC6EQ5Y8ffoS6SlvUxp4Q01qVPH85Nn14H0XGu X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Document the Ambarella CV75 on-chip UART controller binding for early console bring-up. The binding requires a single RCT clock input and fixed 32-bit register access via reg-shift and reg-io-width. Signed-off-by: Long Zhao Reviewed-by: Linus Walleij --- .../bindings/serial/ambarella,cv75-uart.yaml | 56 ++++++++++++++++++= ++++ 1 file changed, 56 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/ambarella,cv75-uart.y= aml b/Documentation/devicetree/bindings/serial/ambarella,cv75-uart.yaml new file mode 100644 index 000000000000..223c84bf460d --- /dev/null +++ b/Documentation/devicetree/bindings/serial/ambarella,cv75-uart.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/ambarella,cv75-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ambarella CV75 UART + +maintainers: + - Long Zhao + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: ambarella,cv75-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + reg-shift: + const: 2 + + reg-io-width: + const: 4 + +required: + - compatible + - reg + - interrupts + - clocks + - reg-shift + - reg-io-width + +unevaluatedProperties: false + +examples: + - | + #include + #include + + serial@e4000000 { + compatible =3D "ambarella,cv75-uart"; + reg =3D <0xe4000000 0x1000>; + clocks =3D <&rct CV75_GCLK_UART0>; + interrupts =3D ; + reg-shift =3D <2>; + reg-io-width =3D <4>; + }; --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 53E2145DF72; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=Lll+9uv4IS0UBmEJHE/AJ1ixGENOHmgObSFBHaiTdO1cWlucziz84oVgcKzSn4ty1f3D2cWOfPnXZP7BRKDeITzxjXQNCSLIRIbD50lC3iv6JbFcif67oPvlFXm98CR1kpoJpQXzfca+g5XPb28bNTYW1GBDTkWwCgUMnvKcDLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=edTv7X3JOk9qEQcpt1/dcTxfRtJqMC+ETPomdGA3JtQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HxXUXunxU4Ju7GZY/TkWWcu8zK5vi6D82jQCCYaOrMBq8e8wMnf0VZL5p+PjMrstxHMcBgXXaiwsaazn+qwWPAA2ixukLl3vlDNjyR/l7vJcUHohb1TVP61LUiVAN/cIBowkvH/wUkcYoT3TEKIuO1vJr+hhJ63DefqmWBVmv+k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=b/HwhvI8; 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="b/HwhvI8" Received: by smtp.kernel.org (Postfix) with ESMTPS id 078B5C19425; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=edTv7X3JOk9qEQcpt1/dcTxfRtJqMC+ETPomdGA3JtQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=b/HwhvI8qYJ6tuHLn3t4S5zp21KRjlIcnxwnlw47sG5ZIlx94wauyOWacZVF5OsMf /LhImmpFHnR42Gv4xZCBlFLxjeht2g4YDa5da8i3u76Cp5aPzudAdLNAk9L7gIHuEd 5f6lGVTk9U6lDY9FAUZbbqCgz1vw3wJiCqQcMR2U8VkATqJH11m85YkPOlO3ol3IrF KEAycTN2t14ifN6AlNjdqfPxTeBeIaQ9Eb+ShfYnmrsCyvsggnx1MNnYSTMuJxc9bA cSIT3bnLpdQsHx9TkVrNRsPpel76Vyc68iry8Set43TBm+O1ZTWusiXUZ5xrpDghoF dnrTfJMBxgnkw== 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 E8952C5DF80; Tue, 18 Aug 2026 10:32:13 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:21 +0800 Subject: [PATCH v5 07/12] clk: ambarella: add CV75 CCU 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: <20260818-cv75-v5-v5-7-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=34322; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=7/+Ndc7aTjKBO/IbA27ppYExNXma8eY3yTC1fYvWtrs=; b=EtajKiJr5MuZekdQW9E5VAxvHPPZbr5w2pfHepE1/Ph9DIeXNa8UZoYaTIg69nTXBRRGa1n7R RKC+inAeSkAChe7KOC4Rs1WtG1dueuP63A7FCQY2uMLlDkMeKkftwze X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Add the Ambarella CV75 clock driver covering the core PLL and the UART0 / AHB / APB clocks needed for early console bring-up. Signed-off-by: Long Zhao --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ambarella/Kconfig | 13 ++ drivers/clk/ambarella/Makefile | 6 + drivers/clk/ambarella/ccu-cv75.c | 296 +++++++++++++++++++++++++ drivers/clk/ambarella/ccu_common.c | 60 +++++ drivers/clk/ambarella/ccu_common.h | 25 +++ drivers/clk/ambarella/ccu_mux_div.c | 234 ++++++++++++++++++++ drivers/clk/ambarella/ccu_mux_div.h | 35 +++ drivers/clk/ambarella/ccu_pll.c | 421 ++++++++++++++++++++++++++++++++= ++++ drivers/clk/ambarella/ccu_pll.h | 70 ++++++ 11 files changed, 1162 insertions(+) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1717ce75a907..fbbf4963716c 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -506,6 +506,7 @@ config COMMON_CLK_RPMI the RISC-V platform management interface (RPMI) specification. =20 source "drivers/clk/actions/Kconfig" +source "drivers/clk/ambarella/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/aspeed/Kconfig" source "drivers/clk/bcm/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index cc108a75a900..30d823ee606f 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) +=3D clk-xgene.o =20 # please keep this section sorted lexicographically by directory path name obj-y +=3D actions/ +obj-y +=3D ambarella/ obj-y +=3D analogbits/ obj-y +=3D aspeed/ obj-$(CONFIG_COMMON_CLK_AT91) +=3D at91/ diff --git a/drivers/clk/ambarella/Kconfig b/drivers/clk/ambarella/Kconfig new file mode 100644 index 000000000000..d79bb4bd6df5 --- /dev/null +++ b/drivers/clk/ambarella/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config CLK_AMBARELLA_CV75 + bool "Ambarella CV75 RCT clock controller" + depends on ARCH_AMBARELLA || COMPILE_TEST + select CLK_AMBARELLA_CCU + default ARCH_AMBARELLA + help + Say Y to enable the Ambarella CV75 RCT clock controller. + +config CLK_AMBARELLA_CCU + bool + select REGMAP_MMIO diff --git a/drivers/clk/ambarella/Makefile b/drivers/clk/ambarella/Makefile new file mode 100644 index 000000000000..36e96326ea97 --- /dev/null +++ b/drivers/clk/ambarella/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for ambarella specific clk +# + +obj-$(CONFIG_CLK_AMBARELLA_CCU) +=3D ccu_common.o ccu_mux_div.o ccu_pll.o +obj-$(CONFIG_CLK_AMBARELLA_CV75) +=3D ccu-cv75.o diff --git a/drivers/clk/ambarella/ccu-cv75.c b/drivers/clk/ambarella/ccu-c= v75.c new file mode 100644 index 000000000000..d682da3cf28d --- /dev/null +++ b/drivers/clk/ambarella/ccu-cv75.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Ambarella, Inc. + * + * CV75 RCT clock controller for boot clocks. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "ccu_common.h" +#include "ccu_mux_div.h" +#include "ccu_pll.h" + +enum amb_cv75_clk_type { + AMB_CV75_CLK_FIXED_RATE, + AMB_CV75_CLK_FIXED_FACTOR, + AMB_CV75_CLK_PLL, + AMB_CV75_CLK_DIV, + AMB_CV75_CLK_MUX_DIV, +}; + +enum amb_cv75_clk_ref { + AMB_CV75_CLK_REF_OSC =3D -1, + AMB_CV75_CLK_REF_DUMMY =3D -2, +}; + +/* PLL version for CV75 (ambarella,clkpll-v1 in vendor DTS) */ +static const struct amb_pll_soc_data cv75_pll_soc_data =3D { + .pll_version =3D 1, + .fsout_mask =3D CTRL2_FSOUT_DIV2, + .fsout_val =3D CTRL2_FSOUT_DIV2, + .fsdiv_mask =3D CTRL2_FSDIV_DIV2, + .fsdiv_val =3D CTRL2_FSDIV_DIV2, + .vcodiv_mask =3D CTRL2_VCODIV_DIV2, + .vcodiv_val =3D CTRL2_VCODIV_DIV2, + .vco_max_mhz =3D 2600UL, + .vco_min_mhz =3D 850UL, + .vco_range =3D { 1800UL, 1400UL, 1100UL, 0UL }, +}; + +struct amb_cv75_clk_desc { + int id; + enum amb_cv75_clk_type type; + const char *name; + int parent; + + union { + struct { + unsigned long rate; + } fixed_rate; + struct { + unsigned long flags; + unsigned int mult; + unsigned int div; + } fixed_factor; + struct { + u32 reg_offset[REG_NUM]; + const struct amb_pll_soc_data *soc_data; + } pll; + struct { + u32 reg; + u32 shift; + u32 width; + u32 flags; + u32 fix_divider; + } div; + struct amb_mux_div_desc mux_div; + }; +}; + +static const struct amb_cv75_clk_desc cv75_clks[] =3D { + { + .id =3D AMB_CV75_CLK_REF_DUMMY, + .type =3D AMB_CV75_CLK_FIXED_RATE, + .name =3D "dummy", + .fixed_rate.rate =3D 0, + }, + { + .id =3D CV75_GCLK_CORE, + .type =3D AMB_CV75_CLK_PLL, + .name =3D "core", + .parent =3D AMB_CV75_CLK_REF_OSC, + .pll =3D { + .reg_offset =3D { + 0x000, 0x004, 0x100, + 0x104, 0x000, 0x000, + }, + .soc_data =3D &cv75_pll_soc_data, + }, + }, + { + .id =3D CV75_GCLK_AHB, + .type =3D AMB_CV75_CLK_FIXED_FACTOR, + .name =3D "ahb", + .parent =3D CV75_GCLK_CORE, + .fixed_factor =3D { + .flags =3D 0, + .mult =3D 1, + .div =3D 2, + }, + }, + { + .id =3D CV75_GCLK_APB, + .type =3D AMB_CV75_CLK_FIXED_FACTOR, + .name =3D "apb", + .parent =3D CV75_GCLK_CORE, + .fixed_factor =3D { + .flags =3D 0, + .mult =3D 1, + .div =3D 4, + }, + }, + { + .id =3D CV75_GCLK_UART0, + .type =3D AMB_CV75_CLK_MUX_DIV, + .name =3D "uart0", + .mux_div =3D { + .name =3D "uart0", + .parents =3D (const int[]) { + AMB_CV75_CLK_REF_OSC, CV75_GCLK_CORE, + AMB_CV75_CLK_REF_DUMMY, AMB_CV75_CLK_REF_DUMMY, + }, + .num_parents =3D 4, + .mux_reg =3D 0x1c8, + .mux_shift =3D 0, + .mux_mask =3D 0x3, + .div_reg =3D 0x038, + .div_shift =3D 0, + .div_width =3D 24, + .div_flags =3D CLK_DIVIDER_ONE_BASED, + .fix_divider =3D 1, + }, + }, +}; + +static struct clk_hw *amb_cv75_get_parent(struct amb_ccu *ccu, + struct clk_hw *osc, + struct clk_hw *dummy, + int parent) +{ + if (parent =3D=3D AMB_CV75_CLK_REF_OSC) + return osc; + if (parent =3D=3D AMB_CV75_CLK_REF_DUMMY) + return dummy; + + if (parent < 0 || parent >=3D ccu->data->num) + return ERR_PTR(-EINVAL); + + if (!ccu->data->hws[parent]) + return ERR_PTR(-EPROBE_DEFER); + + return ccu->data->hws[parent]; +} + +static struct clk_hw *amb_cv75_register_mux_div(struct device *dev, + struct amb_ccu *ccu, + const struct amb_cv75_clk_desc *desc, + struct clk_hw *osc, + struct clk_hw *dummy) +{ + const struct amb_mux_div_desc *md =3D &desc->mux_div; + struct clk_parent_data *pdata; + struct clk_hw *parent; + u8 i; + + pdata =3D devm_kcalloc(dev, md->num_parents, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + for (i =3D 0; i < md->num_parents; i++) { + if (md->parents[i] =3D=3D AMB_CV75_CLK_REF_OSC) { + pdata[i].fw_name =3D "osc"; + continue; + } + + parent =3D amb_cv75_get_parent(ccu, osc, dummy, md->parents[i]); + if (IS_ERR(parent)) + return parent; + + pdata[i].hw =3D parent; + } + + return amb_mux_div_register(dev, ccu->map, md, pdata); +} + +static struct clk_hw *amb_cv75_register_clk(struct device *dev, + struct amb_ccu *ccu, + const struct amb_cv75_clk_desc *desc, + struct clk_hw *osc, + struct clk_hw *dummy) +{ + struct amb_pll_desc pll_desc; + struct clk_hw *parent; + + switch (desc->type) { + case AMB_CV75_CLK_FIXED_RATE: + return devm_clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, + desc->fixed_rate.rate); + case AMB_CV75_CLK_FIXED_FACTOR: + parent =3D amb_cv75_get_parent(ccu, osc, dummy, desc->parent); + if (IS_ERR(parent)) + return parent; + + return devm_clk_hw_register_fixed_factor_parent_hw(dev, + desc->name, parent, + desc->fixed_factor.flags, + desc->fixed_factor.mult, + desc->fixed_factor.div); + case AMB_CV75_CLK_PLL: + parent =3D amb_cv75_get_parent(ccu, osc, dummy, desc->parent); + if (IS_ERR(parent)) + return parent; + + pll_desc.name =3D desc->name; + pll_desc.parent =3D parent; + memcpy((void *)pll_desc.reg_offset, desc->pll.reg_offset, + sizeof(pll_desc.reg_offset)); + pll_desc.soc_data =3D desc->pll.soc_data; + pll_desc.frac_mode =3D false; + + return amb_pll_register(dev, ccu->map, &pll_desc); + case AMB_CV75_CLK_DIV: + parent =3D amb_cv75_get_parent(ccu, osc, dummy, desc->parent); + if (IS_ERR(parent)) + return parent; + + return amb_div_register(dev, ccu->map, desc->name, parent, + desc->div.reg, desc->div.shift, + desc->div.width, desc->div.flags, + desc->div.fix_divider); + case AMB_CV75_CLK_MUX_DIV: + return amb_cv75_register_mux_div(dev, ccu, desc, osc, dummy); + default: + return ERR_PTR(-EINVAL); + } +} + +static int amb_cv75_rct_probe(struct platform_device *pdev) +{ + struct amb_ccu *ccu; + struct clk *osc_clk; + struct clk_hw *osc, *dummy =3D NULL, *hw; + int i; + + ccu =3D amb_ccu_init(pdev, ARRAY_SIZE(cv75_clks)); + if (IS_ERR(ccu)) + return PTR_ERR(ccu); + + osc_clk =3D devm_clk_get(&pdev->dev, "osc"); + if (IS_ERR(osc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(osc_clk), + "missing osc clock\n"); + osc =3D __clk_get_hw(osc_clk); + + for (i =3D 0; i < ARRAY_SIZE(cv75_clks); i++) { + hw =3D amb_cv75_register_clk(&pdev->dev, ccu, &cv75_clks[i], + osc, dummy); + if (IS_ERR(hw)) + return dev_err_probe(&pdev->dev, PTR_ERR(hw), + "failed to register %s\n", + cv75_clks[i].name); + + if (cv75_clks[i].id =3D=3D AMB_CV75_CLK_REF_DUMMY) + dummy =3D hw; + else + ccu->data->hws[cv75_clks[i].id] =3D hw; + } + + return amb_ccu_register(ccu); +} + +static const struct of_device_id amb_cv75_rct_match[] =3D { + { .compatible =3D "ambarella,cv75-rct" }, + { } +}; +MODULE_DEVICE_TABLE(of, amb_cv75_rct_match); + +static struct platform_driver amb_cv75_rct_driver =3D { + .probe =3D amb_cv75_rct_probe, + .driver =3D { + .name =3D "ambarella-cv75-rct", + .of_match_table =3D amb_cv75_rct_match, + }, +}; +module_platform_driver(amb_cv75_rct_driver); + +MODULE_AUTHOR("Ambarella Inc."); +MODULE_DESCRIPTION("Ambarella CV75 RCT clock controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/ambarella/ccu_common.c b/drivers/clk/ambarella/ccu= _common.c new file mode 100644 index 000000000000..78587c5f2ce1 --- /dev/null +++ b/drivers/clk/ambarella/ccu_common.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Ambarella, Inc. + */ + +#include +#include +#include +#include +#include + +#include "ccu_common.h" + +static const struct regmap_config amb_rct_regmap_config =3D { + .reg_bits =3D 32, + .val_bits =3D 32, + .reg_stride =3D 4, + .max_register =3D AMB_RCT_REG_SIZE - 4, +}; + +struct amb_ccu *amb_ccu_init(struct platform_device *pdev, + unsigned int num_clks) +{ + struct amb_ccu *ccu; + void __iomem *base; + + if (!num_clks) + return ERR_PTR(-EINVAL); + + ccu =3D devm_kzalloc(&pdev->dev, sizeof(*ccu), GFP_KERNEL); + if (!ccu) + return ERR_PTR(-ENOMEM); + + ccu->dev =3D &pdev->dev; + + ccu->data =3D devm_kzalloc(&pdev->dev, + struct_size(ccu->data, hws, num_clks), + GFP_KERNEL); + if (!ccu->data) + return ERR_PTR(-ENOMEM); + + ccu->data->num =3D num_clks; + + base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return ERR_CAST(base); + + ccu->map =3D devm_regmap_init_mmio(&pdev->dev, base, + &amb_rct_regmap_config); + if (IS_ERR(ccu->map)) + return ERR_CAST(ccu->map); + + return ccu; +} + +int amb_ccu_register(struct amb_ccu *ccu) +{ + return devm_of_clk_add_hw_provider(ccu->dev, of_clk_hw_onecell_get, + ccu->data); +} diff --git a/drivers/clk/ambarella/ccu_common.h b/drivers/clk/ambarella/ccu= _common.h new file mode 100644 index 000000000000..f2bf9d1f06d7 --- /dev/null +++ b/drivers/clk/ambarella/ccu_common.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Ambarella, Inc. + */ + +#ifndef __CCU_COMMON_H +#define __CCU_COMMON_H + +#include +#include +#include + +#define AMB_RCT_REG_SIZE 0x1000 + +struct amb_ccu { + struct device *dev; + struct regmap *map; + struct clk_hw_onecell_data *data; +}; + +struct amb_ccu *amb_ccu_init(struct platform_device *pdev, + unsigned int num_clks); +int amb_ccu_register(struct amb_ccu *ccu); + +#endif diff --git a/drivers/clk/ambarella/ccu_mux_div.c b/drivers/clk/ambarella/cc= u_mux_div.c new file mode 100644 index 000000000000..d5259bc347e4 --- /dev/null +++ b/drivers/clk/ambarella/ccu_mux_div.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Ambarella, Inc. + * + * Regmap-backed mux + divider, derived from the vendor composite-clock dr= iver. + */ + +#include +#include +#include +#include + +#include "ccu_mux_div.h" + +struct amb_mux { + struct clk_hw hw; + struct regmap *map; + u32 offset; + u32 mask; + u32 shift; +}; + +struct amb_div { + struct clk_hw hw; + struct regmap *map; + u32 offset; + u32 shift; + u32 width; + u32 flags; + u32 fix_divider; +}; + +#define to_amb_mux(_hw) container_of(_hw, struct amb_mux, hw) +#define to_amb_div(_hw) container_of(_hw, struct amb_div, hw) + +static u8 amb_mux_get_parent(struct clk_hw *hw) +{ + struct amb_mux *mux =3D to_amb_mux(hw); + u32 val; + + regmap_read(mux->map, mux->offset, &val); + val >>=3D mux->shift; + val &=3D mux->mask; + + return val; +} + +static int amb_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct amb_mux *mux =3D to_amb_mux(hw); + + return regmap_update_bits(mux->map, mux->offset, + mux->mask << mux->shift, + index << mux->shift); +} + +static const struct clk_ops amb_mux_ops =3D { + .get_parent =3D amb_mux_get_parent, + .set_parent =3D amb_mux_set_parent, +}; + +static unsigned long amb_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct amb_div *div =3D to_amb_div(hw); + unsigned long rate; + u32 val; + + regmap_read(div->map, div->offset, &val); + + /* Divider reset/disable bit sits above the field at shift+width. */ + if (val & (BIT(div->width) << div->shift)) + return 0; + + val >>=3D div->shift; + val &=3D clk_div_mask(div->width); + + rate =3D divider_recalc_rate(hw, parent_rate, val, NULL, + div->flags, div->width); + if (div->fix_divider) + rate =3D div_u64(rate, div->fix_divider); + + return rate; +} + +static int amb_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct amb_div *div =3D to_amb_div(hw); + struct clk_rate_request scaled =3D *req; + int ret; + + if (!req->rate && (div->flags & CLK_DIVIDER_ONE_BASED)) + return 0; + + if (div->fix_divider) { + scaled.rate =3D min(req->rate, + ULONG_MAX / div->fix_divider) * + div->fix_divider; + scaled.min_rate =3D min(req->min_rate, + ULONG_MAX / div->fix_divider) * + div->fix_divider; + scaled.max_rate =3D min(req->max_rate, + ULONG_MAX / div->fix_divider) * + div->fix_divider; + } + + ret =3D divider_determine_rate(hw, &scaled, NULL, div->width, + div->flags); + if (ret) + return ret; + + req->rate =3D scaled.rate; + req->best_parent_rate =3D scaled.best_parent_rate; + req->best_parent_hw =3D scaled.best_parent_hw; + if (div->fix_divider) + req->rate =3D div_u64(req->rate, div->fix_divider); + + return 0; +} + +static int amb_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct amb_div *div =3D to_amb_div(hw); + int val, mask; + + if (div->fix_divider) + rate *=3D div->fix_divider; + + if (!rate) { + /* Assert the reset/disable bit above the divider field. */ + val =3D BIT(div->width); + mask =3D clk_div_mask(div->width + 1); + } else { + val =3D divider_get_val(rate, parent_rate, NULL, + div->width, div->flags); + if (val < 0) + return val; + + /* + * Include the disable bit in the mask so a later non-zero + * set_rate clears a previous rate=3D=3D0 disable assert. + */ + mask =3D clk_div_mask(div->width + 1); + } + + regmap_update_bits(div->map, div->offset, mask << div->shift, + val << div->shift); + + /* + * Non-ONE_BASED dividers use bit 0 as a write-enable strobe. Skip the + * pulse when shift =3D=3D 0 so we do not corrupt the divider field itsel= f. + */ + if (!(div->flags & CLK_DIVIDER_ONE_BASED) && div->shift) { + regmap_update_bits(div->map, div->offset, BIT(0), BIT(0)); + regmap_update_bits(div->map, div->offset, BIT(0), 0); + } + + return 0; +} + +static const struct clk_ops amb_div_ops =3D { + .recalc_rate =3D amb_div_recalc_rate, + .determine_rate =3D amb_div_determine_rate, + .set_rate =3D amb_div_set_rate, +}; + +struct clk_hw *amb_div_register(struct device *dev, struct regmap *map, + const char *name, const struct clk_hw *parent, + u32 div_reg, u32 div_shift, u32 div_width, + u32 div_flags, u32 fix_divider) +{ + struct amb_div *div; + struct clk_init_data init =3D {}; + int ret; + + div =3D devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + div->map =3D map; + div->offset =3D div_reg; + div->shift =3D div_shift; + div->width =3D div_width; + div->flags =3D div_flags; + div->fix_divider =3D fix_divider; + + init.name =3D name; + init.ops =3D &amb_div_ops; + init.parent_hws =3D &parent; + init.num_parents =3D 1; + + div->hw.init =3D &init; + + ret =3D devm_clk_hw_register(dev, &div->hw); + if (ret) + return ERR_PTR(ret); + + return &div->hw; +} + +struct clk_hw *amb_mux_div_register(struct device *dev, struct regmap *map, + const struct amb_mux_div_desc *desc, + const struct clk_parent_data *parent_data) +{ + struct amb_mux *mux; + struct amb_div *div; + + mux =3D devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + div =3D devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!mux || !div) + return ERR_PTR(-ENOMEM); + + mux->map =3D map; + mux->offset =3D desc->mux_reg; + mux->shift =3D desc->mux_shift; + mux->mask =3D desc->mux_mask; + + div->map =3D map; + div->offset =3D desc->div_reg; + div->shift =3D desc->div_shift; + div->width =3D desc->div_width; + div->flags =3D desc->div_flags; + div->fix_divider =3D desc->fix_divider; + + return devm_clk_hw_register_composite_pdata(dev, desc->name, + parent_data, + desc->num_parents, + &mux->hw, &amb_mux_ops, + &div->hw, &amb_div_ops, + NULL, NULL, + CLK_SET_RATE_NO_REPARENT); +} diff --git a/drivers/clk/ambarella/ccu_mux_div.h b/drivers/clk/ambarella/cc= u_mux_div.h new file mode 100644 index 000000000000..abaefff1201a --- /dev/null +++ b/drivers/clk/ambarella/ccu_mux_div.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Ambarella, Inc. + */ + +#ifndef __CCU_MUX_DIV_H +#define __CCU_MUX_DIV_H + +#include +#include + +struct amb_mux_div_desc { + const char *name; + const int *parents; + u8 num_parents; + u32 mux_reg; + u32 mux_shift; + u32 mux_mask; + u32 div_reg; + u32 div_shift; + u32 div_width; + u32 div_flags; + u32 fix_divider; +}; + +struct clk_hw *amb_mux_div_register(struct device *dev, struct regmap *map, + const struct amb_mux_div_desc *desc, + const struct clk_parent_data *parent_data); + +struct clk_hw *amb_div_register(struct device *dev, struct regmap *map, + const char *name, const struct clk_hw *parent, + u32 div_reg, u32 div_shift, u32 div_width, + u32 div_flags, u32 fix_divider); + +#endif diff --git a/drivers/clk/ambarella/ccu_pll.c b/drivers/clk/ambarella/ccu_pl= l.c new file mode 100644 index 000000000000..76452003bb0d --- /dev/null +++ b/drivers/clk/ambarella/ccu_pll.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Ambarella, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ccu_pll.h" + +#define AMB_PLL_MAX_SOUT 16UL +#define AMB_PLL_MAX_SDIV 16UL + +struct amb_pll { + struct clk_hw hw; + struct regmap *map; + u32 reg_offset[REG_NUM]; + const struct amb_pll_soc_data *soc_data; + u32 fix_divider; + bool frac_mode; +}; + +#define to_amb_pll(_hw) container_of(_hw, struct amb_pll, hw) + +static void amb_pll_write_enable(struct regmap *map, u32 offset, u32 val) +{ + regmap_write(map, offset, val); + regmap_write(map, offset, val | CTRL_WRITE_ENABLE); + regmap_write(map, offset, val); +} + +static unsigned long amb_pll_calc_vco(struct amb_pll *pll, + unsigned long parent_rate) +{ + const struct amb_pll_soc_data *soc_data =3D pll->soc_data; + u32 *reg =3D pll->reg_offset; + u32 pre_scaler =3D 1; + u32 ctrl_val, ctrl2_val =3D 0, frac_val; + u32 intp, sdiv, vcodiv, fsdiv; + u64 frac =3D 0, vco; + + if (reg[PRES_OFFSET]) { + regmap_read(pll->map, reg[PRES_OFFSET], &pre_scaler); + pre_scaler =3D (pre_scaler >> 4) + 1; + } + + regmap_read(pll->map, reg[CTRL_OFFSET], &ctrl_val); + intp =3D ((ctrl_val >> 24) & 0x7f) + 1; + sdiv =3D ((ctrl_val >> 12) & 0xf) + 1; + + if (soc_data->pll_version >=3D 2) { + vcodiv =3D (ctrl_val & soc_data->vcodiv_mask) =3D=3D + soc_data->vcodiv_val ? 2 : 1; + fsdiv =3D (ctrl_val & soc_data->fsdiv_mask) =3D=3D + soc_data->fsdiv_val ? 2 : 1; + } else { + regmap_read(pll->map, reg[CTRL2_OFFSET], &ctrl2_val); + vcodiv =3D (ctrl2_val & soc_data->vcodiv_mask) =3D=3D + soc_data->vcodiv_val ? 2 : 1; + fsdiv =3D (ctrl2_val & soc_data->fsdiv_mask) =3D=3D + soc_data->fsdiv_val ? 2 : 1; + } + + vco =3D (u64)parent_rate * vcodiv * fsdiv * intp * sdiv; + vco =3D div_u64(vco, pre_scaler); + + if (ctrl_val & CTRL_FRAC_MODE) { + regmap_read(pll->map, reg[FRAC_OFFSET], &frac_val); + frac =3D (u64)parent_rate * vcodiv * fsdiv * sdiv * frac_val; + frac =3D div_u64(frac, pre_scaler) >> 32; + } + + return vco + frac; +} + +static unsigned long amb_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct amb_pll *pll =3D to_amb_pll(hw); + const struct amb_pll_soc_data *soc_data =3D pll->soc_data; + u32 *reg =3D pll->reg_offset; + u32 pre_scaler =3D 1, post_scaler =3D 1; + u32 ctrl_val, ctrl2_val =3D 0; + u32 vcodiv, fsout, sout; + u64 rate; + + regmap_read(pll->map, reg[CTRL_OFFSET], &ctrl_val); + if (ctrl_val & (CTRL_POWER_DOWN | CTRL_HALT_VCO | CTRL_FORCE_RESET)) + return 0; + + if (reg[PRES_OFFSET]) { + regmap_read(pll->map, reg[PRES_OFFSET], &pre_scaler); + pre_scaler =3D (pre_scaler >> 4) + 1; + } + + if (reg[POST_OFFSET]) { + regmap_read(pll->map, reg[POST_OFFSET], &post_scaler); + post_scaler =3D (post_scaler >> 4) + 1; + } + + if (ctrl_val & CTRL_BYPASS) + return parent_rate / pre_scaler / post_scaler; + + if (soc_data->pll_version >=3D 2) { + vcodiv =3D (ctrl_val & soc_data->vcodiv_mask) =3D=3D + soc_data->vcodiv_val ? 2 : 1; + fsout =3D (ctrl_val & soc_data->fsout_mask) =3D=3D + soc_data->fsout_val ? 2 : 1; + } else { + regmap_read(pll->map, reg[CTRL2_OFFSET], &ctrl2_val); + vcodiv =3D (ctrl2_val & soc_data->vcodiv_mask) =3D=3D + soc_data->vcodiv_val ? 2 : 1; + fsout =3D (ctrl2_val & soc_data->fsout_mask) =3D=3D + soc_data->fsout_val ? 2 : 1; + } + + sout =3D ((ctrl_val >> 16) & 0xf) + 1; + rate =3D amb_pll_calc_vco(pll, parent_rate); + + if (soc_data->pll_version >=3D 2) { + if (!(ctrl_val & CTRL_BYPASS_HSDIV)) + rate =3D div_u64(rate, vcodiv * fsout * sout); + } else { + if (!(ctrl2_val & CTRL2_BYPASS_HSDIV)) + rate =3D div_u64(rate, vcodiv * fsout * sout); + } + + rate =3D div_u64(rate, pll->fix_divider * post_scaler); + + return rate; +} + +static int amb_pll_calc_params(struct amb_pll *pll, unsigned long rate, + unsigned long parent_rate, u32 ctrl2_val, + u32 *intp, u32 *sdiv, u32 *sout, + u32 *vcodiv, u32 *fsdiv, u32 *fsout) +{ + const struct amb_pll_soc_data *soc_data =3D pll->soc_data; + unsigned long max_numerator, max_denominator; + unsigned long intp_ul, sout_ul, rate_tmp, parent_scaled; + u32 ctrl_val; + + if (!parent_rate) + return -EINVAL; + + *sdiv =3D 1; + + if (soc_data->pll_version >=3D 2) { + ctrl_val =3D 0; + *vcodiv =3D (ctrl_val & soc_data->vcodiv_mask) =3D=3D + soc_data->vcodiv_val ? 2 : 1; + *fsdiv =3D (ctrl_val & soc_data->fsdiv_mask) =3D=3D + soc_data->fsdiv_val ? 2 : 1; + *fsout =3D (ctrl_val & soc_data->fsout_mask) =3D=3D + soc_data->fsout_val ? 2 : 1; + } else { + *vcodiv =3D (ctrl2_val & soc_data->vcodiv_mask) =3D=3D + soc_data->vcodiv_val ? 2 : 1; + *fsdiv =3D (ctrl2_val & soc_data->fsdiv_mask) =3D=3D + soc_data->fsdiv_val ? 2 : 1; + *fsout =3D (ctrl2_val & soc_data->fsout_mask) =3D=3D + soc_data->fsout_val ? 2 : 1; + } + + if (rate < parent_rate) + return -EINVAL; + + max_numerator =3D soc_data->vco_max_mhz; + max_numerator =3D div_u64(max_numerator * 1000000ULL, parent_rate); + max_numerator =3D div_u64(max_numerator, *vcodiv * *fsdiv); + max_numerator =3D min(128UL, max_numerator); + if (!max_numerator) + return -EINVAL; + + /* + * Approximate intp/sout against the fsdiv/fsout-scaled parent so the + * initial guess matches the hardware frequency equation. + */ + max_denominator =3D AMB_PLL_MAX_SOUT; + parent_scaled =3D parent_rate * *fsdiv / *fsout; + if (!parent_scaled) + return -EINVAL; + rate_tmp =3D rate; + rational_best_approximation(rate_tmp, parent_scaled, max_numerator, + max_denominator, &intp_ul, &sout_ul); + + while (parent_rate * *fsdiv * intp_ul * *sdiv / *fsout / sout_ul > + rate) { + unsigned long resolution =3D parent_scaled / AMB_PLL_MAX_SOUT; + + /* Avoid an infinite loop when parent_rate < AMB_PLL_MAX_SOUT. */ + if (!resolution) + resolution =3D 1; + + if (rate_tmp <=3D resolution) + return -EINVAL; + + rate_tmp -=3D resolution; + rational_best_approximation(rate_tmp, parent_scaled, + max_numerator, max_denominator, + &intp_ul, &sout_ul); + } + + while (parent_rate / 1000000 * *vcodiv * *fsdiv * intp_ul * *sdiv < + soc_data->vco_min_mhz) { + if (sout_ul > 8 || intp_ul > 64) + break; + + intp_ul *=3D 2; + sout_ul *=3D 2; + } + + if (intp_ul > max_numerator || sout_ul > max_denominator || + *sdiv > AMB_PLL_MAX_SDIV) + return -EINVAL; + + *intp =3D intp_ul; + *sout =3D sout_ul; + + return 0; +} + +static int amb_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct amb_pll *pll =3D to_amb_pll(hw); + const struct amb_pll_soc_data *soc_data =3D pll->soc_data; + u32 ctrl2_val =3D 0; + u32 intp, sdiv, sout, vcodiv, fsdiv, fsout; + unsigned long rate; + u64 rounded; + int ret; + + if (!req->best_parent_rate) + return -EINVAL; + + if (!req->rate || pll->frac_mode) + return 0; + + if (req->rate > ULONG_MAX / pll->fix_divider) + return -ERANGE; + + rate =3D req->rate * pll->fix_divider; + if (soc_data->ctrl2_val) + ctrl2_val =3D soc_data->ctrl2_val; + else + regmap_read(pll->map, pll->reg_offset[CTRL2_OFFSET], + &ctrl2_val); + + ret =3D amb_pll_calc_params(pll, rate, req->best_parent_rate, + ctrl2_val, &intp, &sdiv, &sout, &vcodiv, + &fsdiv, &fsout); + if (ret) + return ret; + + rounded =3D (u64)req->best_parent_rate * fsdiv * intp * sdiv; + rounded =3D div64_u64(rounded, (u64)fsout * sout); + rounded =3D div64_u64(rounded, pll->fix_divider); + if (rounded < req->min_rate || rounded > req->max_rate) + return -EINVAL; + + req->rate =3D rounded; + + return 0; +} + +static int amb_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct amb_pll *pll =3D to_amb_pll(hw); + const struct amb_pll_soc_data *soc_data =3D pll->soc_data; + u32 *reg =3D pll->reg_offset; + u32 ctrl_val, ctrl2_val =3D 0, ctrl3_val, frac_val =3D 0; + u32 intp, sdiv, sout, vcodiv, fsdiv, fsout; + unsigned long old_rate, new_rate, rate_tmp; + int ret; + + if (!rate) { + regmap_read(pll->map, reg[CTRL_OFFSET], &ctrl_val); + ctrl_val |=3D CTRL_POWER_DOWN | CTRL_HALT_VCO; + amb_pll_write_enable(pll->map, reg[CTRL_OFFSET], ctrl_val); + return 0; + } + + if (!parent_rate) + return -EINVAL; + + rate *=3D pll->fix_divider; + + if (soc_data->ctrl2_val) + ctrl2_val =3D soc_data->ctrl2_val; + else + regmap_read(pll->map, reg[CTRL2_OFFSET], &ctrl2_val); + + ret =3D amb_pll_calc_params(pll, rate, parent_rate, ctrl2_val, + &intp, &sdiv, &sout, &vcodiv, &fsdiv, + &fsout); + if (ret) + return ret; + + if (soc_data->ctrl2_val) + regmap_write(pll->map, reg[CTRL2_OFFSET], soc_data->ctrl2_val); + + ctrl_val =3D ((intp - 1) & 0x7f) << 24; + ctrl_val |=3D ((sdiv - 1) & 0xf) << 12; + ctrl_val |=3D ((sout - 1) & 0xf) << 16; + if (soc_data->pll_version >=3D 2) { + ctrl_val |=3D vcodiv =3D=3D 2 ? soc_data->vcodiv_val : 0; + ctrl_val |=3D fsdiv =3D=3D 2 ? soc_data->fsdiv_val : 0; + ctrl_val |=3D fsout =3D=3D 2 ? soc_data->fsout_val : 0; + } + + regmap_write(pll->map, reg[CTRL_OFFSET], ctrl_val); + regmap_write(pll->map, reg[FRAC_OFFSET], 0); + + old_rate =3D amb_pll_recalc_rate(hw, parent_rate) * pll->fix_divider; + rate_tmp =3D old_rate > rate ? 0 : rate - old_rate; + if (rate_tmp && pll->frac_mode) { + u64 dividend, divider; + + dividend =3D (u64)rate_tmp * sout * fsout; + dividend <<=3D 32; + divider =3D (u64)sdiv * fsdiv * parent_rate; + frac_val =3D DIV64_U64_ROUND_CLOSEST(dividend, divider); + regmap_write(pll->map, reg[FRAC_OFFSET], frac_val); + ctrl_val |=3D CTRL_FRAC_MODE; + } + + if (soc_data->pll_version >=3D 2) { + ctrl3_val =3D soc_data->ctrl3_val; + regmap_write(pll->map, reg[CTRL3_OFFSET], + ctrl3_val | CTRL3_VCO_CLAMP); + regmap_write(pll->map, reg[CTRL_OFFSET], + ctrl_val | CTRL_FORCE_RESET); + ndelay(100); + regmap_write(pll->map, reg[CTRL_OFFSET], + ctrl_val & ~CTRL_FORCE_RESET); + ndelay(100); + regmap_write(pll->map, reg[CTRL3_OFFSET], + ctrl3_val & ~CTRL3_VCO_CLAMP); + } else { + u32 fvco_mhz, range; + + fvco_mhz =3D amb_pll_calc_vco(pll, parent_rate) / 1000000UL; + for (range =3D 0; range < ARRAY_SIZE(soc_data->vco_range); + range++) { + if (fvco_mhz > soc_data->vco_range[range]) + break; + } + if (range =3D=3D ARRAY_SIZE(soc_data->vco_range)) + range =3D 0; + else + range =3D ARRAY_SIZE(soc_data->vco_range) - range - 1; + + regmap_read(pll->map, reg[CTRL3_OFFSET], &ctrl3_val); + ctrl3_val &=3D ~CTRL3_VCO_RANGE_MASK; + ctrl3_val |=3D range << 1; + regmap_write(pll->map, reg[CTRL3_OFFSET], ctrl3_val); + + if (frac_val) { + ctrl_val |=3D CTRL_FORCE_RESET; + amb_pll_write_enable(pll->map, reg[CTRL_OFFSET], + ctrl_val); + } + + ctrl_val &=3D ~CTRL_FORCE_RESET; + amb_pll_write_enable(pll->map, reg[CTRL_OFFSET], ctrl_val); + } + + new_rate =3D amb_pll_recalc_rate(hw, parent_rate); + rate_tmp =3D rate / pll->fix_divider; + if (max(new_rate, rate_tmp) - min(new_rate, rate_tmp) > 10) + pr_warn("%s: requested %lu, got %lu\n", clk_hw_get_name(hw), + rate_tmp, new_rate); + + return 0; +} + +static const struct clk_ops amb_pll_ops =3D { + .recalc_rate =3D amb_pll_recalc_rate, + .determine_rate =3D amb_pll_determine_rate, + .set_rate =3D amb_pll_set_rate, +}; + +struct clk_hw *amb_pll_register(struct device *dev, struct regmap *map, + const struct amb_pll_desc *desc) +{ + struct amb_pll *pll; + struct clk_init_data init =3D {}; + const struct clk_hw *parent =3D desc->parent; + int ret; + + pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->map =3D map; + memcpy(pll->reg_offset, desc->reg_offset, sizeof(pll->reg_offset)); + pll->soc_data =3D desc->soc_data; + pll->fix_divider =3D 1; + pll->frac_mode =3D desc->frac_mode; + + init.name =3D desc->name; + init.ops =3D &amb_pll_ops; + init.flags =3D CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL; + init.parent_hws =3D &parent; + init.num_parents =3D 1; + + pll->hw.init =3D &init; + + ret =3D devm_clk_hw_register(dev, &pll->hw); + if (ret) + return ERR_PTR(ret); + + return &pll->hw; +} diff --git a/drivers/clk/ambarella/ccu_pll.h b/drivers/clk/ambarella/ccu_pl= l.h new file mode 100644 index 000000000000..b9e453e9debf --- /dev/null +++ b/drivers/clk/ambarella/ccu_pll.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Ambarella, Inc. + */ + +#ifndef __CCU_PLL_H +#define __CCU_PLL_H + +#include +#include +#include +#include +#include + +enum { + CTRL_OFFSET =3D 0, + FRAC_OFFSET, + CTRL2_OFFSET, + CTRL3_OFFSET, + PRES_OFFSET, + POST_OFFSET, + REG_NUM, +}; + +#define CTRL_BYPASS BIT(2) +#define CTRL_WRITE_ENABLE BIT(0) +#define CTRL_FRAC_MODE BIT(3) +#define CTRL_FORCE_RESET BIT(4) +#define CTRL_POWER_DOWN BIT(5) +#define CTRL_HALT_VCO BIT(6) +#define CTRL_VCODIV_DIV2 BIT(8) +#define CTRL_FSDIV_DIV2 BIT(9) +#define CTRL_FSOUT_DIV2 BIT(10) +#define CTRL_BYPASS_HSDIV BIT(11) + +#define CTRL2_VCODIV_DIV2 BIT(8) +#define CTRL2_FSDIV_DIV2 BIT(9) +#define CTRL2_FSOUT_DIV2 BIT(11) +#define CTRL2_BYPASS_HSDIV BIT(12) + +#define CTRL3_VCO_RANGE_MASK 0x6 +#define CTRL3_VCO_CLAMP 0x8 + +struct amb_pll_soc_data { + u32 pll_version; + u32 fsout_mask; + u32 fsout_val; + u32 fsdiv_mask; + u32 fsdiv_val; + u32 vcodiv_mask; + u32 vcodiv_val; + u32 vco_max_mhz; + u32 vco_min_mhz; + u32 vco_range[4]; + u32 ctrl2_val; + u32 ctrl3_val; +}; + +struct amb_pll_desc { + const char *name; + const struct clk_hw *parent; + const u32 reg_offset[REG_NUM]; + const struct amb_pll_soc_data *soc_data; + bool frac_mode; +}; + +struct clk_hw *amb_pll_register(struct device *dev, struct regmap *map, + const struct amb_pll_desc *desc); + +#endif --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 89B07463B61; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=tSQ58IGa6Zkb4DBsLIn8VUWK9pf6wPklBfez6kL65/MwySs2ReuVu/SXZ1jJ/rFn/vE2xawJiN1s8asM/O64cg1i8nLIj1z5kCQo4eFoA94ms30Xyil3peE2lVBsYu6jPUBz+05+/8fGWdWXAoIvWpmturgwENIsUVVnGdFnJEc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=xwi9V5iaJMkLR+Qjk51IHow4x0qp4btcOqKjgTxfqUU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Zg8qm8WoagVO81JlY3K5UElwa6L7pYFNtzQyK/bn+xnUeJYeD50mbJq94xu1lBklv7tBovZ1vt0sAdTuI0k02l+ryyk74auYSpRoppodU/xsR4r77sd7sMYwgxoMfVuTfpH3eoWjzAqNM/qEJhDZNp1cTExt7wSh0RHh3GwjcgI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CogGTq6W; 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="CogGTq6W" Received: by smtp.kernel.org (Postfix) with ESMTPS id 26A5CC4AF17; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=xwi9V5iaJMkLR+Qjk51IHow4x0qp4btcOqKjgTxfqUU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=CogGTq6WhOH8ZlrIosSAlVs6ByLwYvpYvpst7SPyv9Ga7cu0ZweOjb3EaDKwfyp7e LtilCo8YVHuW8rz7XtHqcNPeruL4RHndEHm/bohlCX99iqoCQRHARtzJJP4pYDMaX3 tHh3Mc6umI9kV2ouvzeSFqH2r9dTMMLuFFhNqfdsXcCuFjg5jgxyDFifS8ME5+4dHM qL0T4Q1gcYt3c6fPqqxTsNE2cQ1jF3Jdko3rvOo4wQPDtiuLmO84FdnPpjPHOyIzj5 wV1jCUQiNvQGHi4sqI093hXzlvP6deeRnQa3fhIR4QtHKOLMTIVao+WciaFVkPVqJ9 ovx6jlklsETyQ== 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 10100C5DF70; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:22 +0800 Subject: [PATCH v5 08/12] gpio: pl061: add Ambarella CV75 register layout variant 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: <20260818-cv75-v5-v5-8-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=16722; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=RHmyh9z9T6Amp9QXuHxV5eF7JSTRQdSfnmES5eTRyA0=; b=C7M6vwIFkxdB51F9f2NgTcCech9PLDKwUaXajZbVN5YzmRY6l1+8afJVd8InINvtCp5cYHH18 nUzZPyErfwxDPwfMZ8LxgOV6dWTwUBB6BnWpljTCB5zB+61ztqZ5IFQ X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Extend gpio-pl061 with a per-variant register layout so the Ambarella CV75 GPIO banks can reuse the PL061 driver instead of a duplicate. Signed-off-by: Long Zhao --- drivers/gpio/gpio-pl061.c | 314 ++++++++++++++++++++++++++++++++++++------= ---- 1 file changed, 246 insertions(+), 68 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 919cf86fd590..7002ddbc9713 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -26,41 +26,107 @@ #include #include =20 -#define GPIODIR 0x400 -#define GPIOIS 0x404 -#define GPIOIBE 0x408 -#define GPIOIEV 0x40C -#define GPIOIE 0x410 -#define GPIORIS 0x414 -#define GPIOMIS 0x418 -#define GPIOIC 0x41C - #define PL061_GPIO_NR 8 +#define PL061_REG_NONE U32_MAX +#define PL061_AMBARELLA_PERIPH_ID 0x00000061 + +struct pl061_variant_data { + u32 data; + u32 dir; + u32 is; + u32 ibe; + u32 iev; + u32 ie; + u32 ris; + u32 mis; + u32 ic; + u32 afsel; + u32 mask; + u32 enable; + unsigned int ngpio; + bool access_32bit; + bool masked_data_address; + bool write_data_after_dir; + bool clear_irq_on_type; +}; =20 struct pl061_context_save_regs { - u8 gpio_data; - u8 gpio_dir; - u8 gpio_is; - u8 gpio_ibe; - u8 gpio_iev; - u8 gpio_ie; + u32 gpio_data; + u32 gpio_dir; + u32 gpio_is; + u32 gpio_ibe; + u32 gpio_iev; + u32 gpio_ie; + u32 gpio_afsel; + u32 gpio_mask; }; =20 struct pl061 { raw_spinlock_t lock; =20 void __iomem *base; + const struct pl061_variant_data *variant; struct gpio_chip gc; int parent_irq; =20 struct pl061_context_save_regs csave_regs; }; =20 +static u32 pl061_read(struct pl061 *pl061, u32 offset) +{ + if (pl061->variant->access_32bit) + return readl_relaxed(pl061->base + offset); + + return readb_relaxed(pl061->base + offset); +} + +static void pl061_write(struct pl061 *pl061, u32 value, u32 offset) +{ + if (pl061->variant->access_32bit) + writel_relaxed(value, pl061->base + offset); + else + writeb_relaxed(value, pl061->base + offset); +} + +static int pl061_get_data(struct pl061 *pl061, unsigned int offset) +{ + if (pl061->variant->masked_data_address) + return !!readb_relaxed(pl061->base + BIT(offset + 2)); + + pl061_write(pl061, BIT(offset), pl061->variant->mask); + return !!(pl061_read(pl061, pl061->variant->data) & BIT(offset)); +} + +static void pl061_set_data(struct pl061 *pl061, unsigned int offset, int v= alue) +{ + if (pl061->variant->masked_data_address) { + writeb_relaxed(!!value << offset, + pl061->base + BIT(offset + 2)); + return; + } + + pl061_write(pl061, BIT(offset), pl061->variant->mask); + pl061_write(pl061, value ? BIT(offset) : 0, pl061->variant->data); +} + +static void pl061_claim_gpio(struct pl061 *pl061, unsigned int offset) +{ + u32 afsel; + + if (pl061->variant->afsel =3D=3D PL061_REG_NONE) + return; + + afsel =3D pl061_read(pl061, pl061->variant->afsel); + if (afsel & BIT(offset)) + pl061_write(pl061, afsel & ~BIT(offset), + pl061->variant->afsel); +} + static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) { struct pl061 *pl061 =3D gpiochip_get_data(gc); =20 - if (readb(pl061->base + GPIODIR) & BIT(offset)) + if (pl061_read(pl061, pl061->variant->dir) & BIT(offset)) return GPIO_LINE_DIRECTION_OUT; =20 return GPIO_LINE_DIRECTION_IN; @@ -70,12 +136,13 @@ static int pl061_direction_input(struct gpio_chip *gc,= unsigned offset) { struct pl061 *pl061 =3D gpiochip_get_data(gc); unsigned long flags; - unsigned char gpiodir; + u32 gpiodir; =20 raw_spin_lock_irqsave(&pl061->lock, flags); - gpiodir =3D readb(pl061->base + GPIODIR); + gpiodir =3D pl061_read(pl061, pl061->variant->dir); gpiodir &=3D ~(BIT(offset)); - writeb(gpiodir, pl061->base + GPIODIR); + pl061_write(pl061, gpiodir, pl061->variant->dir); + pl061_claim_gpio(pl061, offset); raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; @@ -86,19 +153,21 @@ static int pl061_direction_output(struct gpio_chip *gc= , unsigned offset, { struct pl061 *pl061 =3D gpiochip_get_data(gc); unsigned long flags; - unsigned char gpiodir; + u32 gpiodir; =20 raw_spin_lock_irqsave(&pl061->lock, flags); - writeb(!!value << offset, pl061->base + (BIT(offset + 2))); - gpiodir =3D readb(pl061->base + GPIODIR); + pl061_set_data(pl061, offset, value); + gpiodir =3D pl061_read(pl061, pl061->variant->dir); gpiodir |=3D BIT(offset); - writeb(gpiodir, pl061->base + GPIODIR); + pl061_write(pl061, gpiodir, pl061->variant->dir); =20 /* * gpio value is set again, because pl061 doesn't allow to set value of * a gpio pin before configuring it in OUT mode. */ - writeb(!!value << offset, pl061->base + (BIT(offset + 2))); + if (pl061->variant->write_data_after_dir) + pl061_set_data(pl061, offset, value); + pl061_claim_gpio(pl061, offset); raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; @@ -107,15 +176,24 @@ static int pl061_direction_output(struct gpio_chip *g= c, unsigned offset, static int pl061_get_value(struct gpio_chip *gc, unsigned offset) { struct pl061 *pl061 =3D gpiochip_get_data(gc); + unsigned long flags; + int value; =20 - return !!readb(pl061->base + (BIT(offset + 2))); + raw_spin_lock_irqsave(&pl061->lock, flags); + value =3D pl061_get_data(pl061, offset); + raw_spin_unlock_irqrestore(&pl061->lock, flags); + + return value; } =20 static int pl061_set_value(struct gpio_chip *gc, unsigned int offset, int = value) { struct pl061 *pl061 =3D gpiochip_get_data(gc); + unsigned long flags; =20 - writeb(!!value << offset, pl061->base + (BIT(offset + 2))); + raw_spin_lock_irqsave(&pl061->lock, flags); + pl061_set_data(pl061, offset, value); + raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; } @@ -126,15 +204,14 @@ static int pl061_irq_type(struct irq_data *d, unsigne= d trigger) struct pl061 *pl061 =3D gpiochip_get_data(gc); int offset =3D irqd_to_hwirq(d); unsigned long flags; - u8 gpiois, gpioibe, gpioiev; - u8 bit =3D BIT(offset); + u32 gpiois, gpioibe, gpioiev; + u32 bit =3D BIT(offset); =20 - if (offset < 0 || offset >=3D PL061_GPIO_NR) + if (offset < 0 || offset >=3D gc->ngpio) return -EINVAL; =20 if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) && - (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) - { + (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) { dev_err(gc->parent, "trying to configure line %d for both level and edge " "detection, choose one!\n", @@ -142,12 +219,11 @@ static int pl061_irq_type(struct irq_data *d, unsigne= d trigger) return -EINVAL; } =20 - raw_spin_lock_irqsave(&pl061->lock, flags); =20 - gpioiev =3D readb(pl061->base + GPIOIEV); - gpiois =3D readb(pl061->base + GPIOIS); - gpioibe =3D readb(pl061->base + GPIOIBE); + gpioiev =3D pl061_read(pl061, pl061->variant->iev); + gpiois =3D pl061_read(pl061, pl061->variant->is); + gpioibe =3D pl061_read(pl061, pl061->variant->ibe); =20 if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { bool polarity =3D trigger & IRQ_TYPE_LEVEL_HIGH; @@ -199,9 +275,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned= trigger) offset); } =20 - writeb(gpiois, pl061->base + GPIOIS); - writeb(gpioibe, pl061->base + GPIOIBE); - writeb(gpioiev, pl061->base + GPIOIEV); + pl061_write(pl061, gpiois, pl061->variant->is); + pl061_write(pl061, gpioibe, pl061->variant->ibe); + pl061_write(pl061, gpioiev, pl061->variant->iev); + if (pl061->variant->clear_irq_on_type) + pl061_write(pl061, bit, pl061->variant->ic); =20 raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 @@ -218,9 +296,9 @@ static void pl061_irq_handler(struct irq_desc *desc) =20 chained_irq_enter(irqchip, desc); =20 - pending =3D readb(pl061->base + GPIOMIS); + pending =3D pl061_read(pl061, pl061->variant->mis); if (pending) { - for_each_set_bit(offset, &pending, PL061_GPIO_NR) + for_each_set_bit(offset, &pending, gc->ngpio) generic_handle_domain_irq(gc->irq.domain, offset); } @@ -232,12 +310,12 @@ static void pl061_irq_mask(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); struct pl061 *pl061 =3D gpiochip_get_data(gc); - u8 mask =3D BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); - u8 gpioie; + u32 mask =3D BIT(irqd_to_hwirq(d)); + u32 gpioie; =20 raw_spin_lock(&pl061->lock); - gpioie =3D readb(pl061->base + GPIOIE) & ~mask; - writeb(gpioie, pl061->base + GPIOIE); + gpioie =3D pl061_read(pl061, pl061->variant->ie) & ~mask; + pl061_write(pl061, gpioie, pl061->variant->ie); raw_spin_unlock(&pl061->lock); =20 gpiochip_disable_irq(gc, d->hwirq); @@ -247,14 +325,14 @@ static void pl061_irq_unmask(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); struct pl061 *pl061 =3D gpiochip_get_data(gc); - u8 mask =3D BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); - u8 gpioie; + u32 mask =3D BIT(irqd_to_hwirq(d)); + u32 gpioie; =20 gpiochip_enable_irq(gc, d->hwirq); =20 raw_spin_lock(&pl061->lock); - gpioie =3D readb(pl061->base + GPIOIE) | mask; - writeb(gpioie, pl061->base + GPIOIE); + gpioie =3D pl061_read(pl061, pl061->variant->ie) | mask; + pl061_write(pl061, gpioie, pl061->variant->ie); raw_spin_unlock(&pl061->lock); } =20 @@ -270,10 +348,10 @@ static void pl061_irq_ack(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); struct pl061 *pl061 =3D gpiochip_get_data(gc); - u8 mask =3D BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); + u32 mask =3D BIT(irqd_to_hwirq(d)); =20 raw_spin_lock(&pl061->lock); - writeb(mask, pl061->base + GPIOIC); + pl061_write(pl061, mask, pl061->variant->ic); raw_spin_unlock(&pl061->lock); } =20 @@ -292,6 +370,24 @@ static void pl061_irq_print_chip(struct irq_data *data= , struct seq_file *p) seq_puts(p, dev_name(gc->parent)); } =20 +static int pl061_irq_request_resources(struct irq_data *d) +{ + struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); + struct pl061 *pl061 =3D gpiochip_get_data(gc); + unsigned long flags; + int ret; + + ret =3D gpiochip_irq_reqres(d); + if (ret) + return ret; + + raw_spin_lock_irqsave(&pl061->lock, flags); + pl061_claim_gpio(pl061, irqd_to_hwirq(d)); + raw_spin_unlock_irqrestore(&pl061->lock, flags); + + return 0; +} + static const struct irq_chip pl061_irq_chip =3D { .irq_ack =3D pl061_irq_ack, .irq_mask =3D pl061_irq_mask, @@ -299,8 +395,9 @@ static const struct irq_chip pl061_irq_chip =3D { .irq_set_type =3D pl061_irq_type, .irq_set_wake =3D pl061_irq_set_wake, .irq_print_chip =3D pl061_irq_print_chip, + .irq_request_resources =3D pl061_irq_request_resources, + .irq_release_resources =3D gpiochip_irq_relres, .flags =3D IRQCHIP_IMMUTABLE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, }; =20 static int pl061_probe(struct amba_device *adev, const struct amba_id *id) @@ -314,6 +411,10 @@ static int pl061_probe(struct amba_device *adev, const= struct amba_id *id) if (pl061 =3D=3D NULL) return -ENOMEM; =20 + pl061->variant =3D id->data; + if (!pl061->variant) + return dev_err_probe(dev, -EINVAL, "missing variant data\n"); + pl061->base =3D devm_ioremap_resource(dev, &adev->res); if (IS_ERR(pl061->base)) return PTR_ERR(pl061->base); @@ -327,7 +428,7 @@ static int pl061_probe(struct amba_device *adev, const = struct amba_id *id) pl061->gc.direction_output =3D pl061_direction_output; pl061->gc.get =3D pl061_get_value; pl061->gc.set =3D pl061_set_value; - pl061->gc.ngpio =3D PL061_GPIO_NR; + pl061->gc.ngpio =3D pl061->variant->ngpio; pl061->gc.label =3D dev_name(dev); pl061->gc.parent =3D dev; pl061->gc.owner =3D THIS_MODULE; @@ -335,7 +436,12 @@ static int pl061_probe(struct amba_device *adev, const= struct amba_id *id) /* * irq_chip support */ - writeb(0, pl061->base + GPIOIE); /* disable irqs */ + pl061_write(pl061, 0, pl061->variant->ie); /* disable irqs */ + if (pl061->variant->enable !=3D PL061_REG_NONE) + pl061_write(pl061, GENMASK(pl061->gc.ngpio - 1, 0), + pl061->variant->enable); + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061_write(pl061, 0, pl061->variant->mask); irq =3D adev->irq[0]; if (!irq) dev_warn(&adev->dev, "IRQ support disabled\n"); @@ -366,20 +472,37 @@ static int pl061_probe(struct amba_device *adev, cons= t struct amba_id *id) static int pl061_suspend(struct device *dev) { struct pl061 *pl061 =3D dev_get_drvdata(dev); + unsigned long flags; int offset; =20 + raw_spin_lock_irqsave(&pl061->lock, flags); pl061->csave_regs.gpio_data =3D 0; - pl061->csave_regs.gpio_dir =3D readb(pl061->base + GPIODIR); - pl061->csave_regs.gpio_is =3D readb(pl061->base + GPIOIS); - pl061->csave_regs.gpio_ibe =3D readb(pl061->base + GPIOIBE); - pl061->csave_regs.gpio_iev =3D readb(pl061->base + GPIOIEV); - pl061->csave_regs.gpio_ie =3D readb(pl061->base + GPIOIE); - - for (offset =3D 0; offset < PL061_GPIO_NR; offset++) { - if (pl061->csave_regs.gpio_dir & (BIT(offset))) - pl061->csave_regs.gpio_data |=3D - pl061_get_value(&pl061->gc, offset) << offset; + pl061->csave_regs.gpio_dir =3D + pl061_read(pl061, pl061->variant->dir); + pl061->csave_regs.gpio_is =3D + pl061_read(pl061, pl061->variant->is); + pl061->csave_regs.gpio_ibe =3D + pl061_read(pl061, pl061->variant->ibe); + pl061->csave_regs.gpio_iev =3D + pl061_read(pl061, pl061->variant->iev); + pl061->csave_regs.gpio_ie =3D + pl061_read(pl061, pl061->variant->ie); + if (pl061->variant->afsel !=3D PL061_REG_NONE) + pl061->csave_regs.gpio_afsel =3D + pl061_read(pl061, pl061->variant->afsel); + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061->csave_regs.gpio_mask =3D + pl061_read(pl061, pl061->variant->mask); + + for (offset =3D 0; offset < pl061->gc.ngpio; offset++) { + if ((pl061->csave_regs.gpio_dir & BIT(offset)) && + pl061_get_data(pl061, offset)) + pl061->csave_regs.gpio_data |=3D BIT(offset); } + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061_write(pl061, pl061->csave_regs.gpio_mask, + pl061->variant->mask); + raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; } @@ -389,7 +512,7 @@ static int pl061_resume(struct device *dev) struct pl061 *pl061 =3D dev_get_drvdata(dev); int offset; =20 - for (offset =3D 0; offset < PL061_GPIO_NR; offset++) { + for (offset =3D 0; offset < pl061->gc.ngpio; offset++) { if (pl061->csave_regs.gpio_dir & (BIT(offset))) pl061_direction_output(&pl061->gc, offset, pl061->csave_regs.gpio_data & @@ -398,20 +521,75 @@ static int pl061_resume(struct device *dev) pl061_direction_input(&pl061->gc, offset); } =20 - writeb(pl061->csave_regs.gpio_is, pl061->base + GPIOIS); - writeb(pl061->csave_regs.gpio_ibe, pl061->base + GPIOIBE); - writeb(pl061->csave_regs.gpio_iev, pl061->base + GPIOIEV); - writeb(pl061->csave_regs.gpio_ie, pl061->base + GPIOIE); + pl061_write(pl061, pl061->csave_regs.gpio_is, + pl061->variant->is); + pl061_write(pl061, pl061->csave_regs.gpio_ibe, + pl061->variant->ibe); + pl061_write(pl061, pl061->csave_regs.gpio_iev, + pl061->variant->iev); + pl061_write(pl061, pl061->csave_regs.gpio_ie, + pl061->variant->ie); + if (pl061->variant->afsel !=3D PL061_REG_NONE) + pl061_write(pl061, pl061->csave_regs.gpio_afsel, + pl061->variant->afsel); + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061_write(pl061, pl061->csave_regs.gpio_mask, + pl061->variant->mask); + if (pl061->variant->enable !=3D PL061_REG_NONE) + pl061_write(pl061, GENMASK(pl061->gc.ngpio - 1, 0), + pl061->variant->enable); =20 return 0; } =20 static DEFINE_SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_res= ume); =20 +static struct pl061_variant_data pl061_arm =3D { + .data =3D 0x000, + .dir =3D 0x400, + .is =3D 0x404, + .ibe =3D 0x408, + .iev =3D 0x40c, + .ie =3D 0x410, + .ris =3D 0x414, + .mis =3D 0x418, + .ic =3D 0x41c, + .afsel =3D PL061_REG_NONE, + .mask =3D PL061_REG_NONE, + .enable =3D PL061_REG_NONE, + .ngpio =3D PL061_GPIO_NR, + .masked_data_address =3D true, + .write_data_after_dir =3D true, +}; + +static struct pl061_variant_data pl061_ambarella =3D { + .data =3D 0x00, + .dir =3D 0x04, + .is =3D 0x08, + .ibe =3D 0x0c, + .iev =3D 0x10, + .ie =3D 0x14, + .afsel =3D 0x18, + .ris =3D 0x1c, + .mis =3D 0x20, + .ic =3D 0x24, + .mask =3D 0x28, + .enable =3D 0x2c, + .ngpio =3D 32, + .access_32bit =3D true, + .clear_irq_on_type =3D true, +}; + static const struct amba_id pl061_ids[] =3D { { .id =3D 0x00041061, .mask =3D 0x000fffff, + .data =3D &pl061_arm, + }, + { + .id =3D PL061_AMBARELLA_PERIPH_ID, + .mask =3D 0xffffffff, + .data =3D &pl061_ambarella, }, { 0, 0 }, }; --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 61C1A45DF76; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=bGix/ad1UqyKdREaNBQ6gSnXqZwN+TD7dTWB33Ovm0ENbYRQHlvAfStyPJQ3TysPKDHTe7vEasEcJ1sszfIOwyuuKQR8UBEYqPOANTZq3FJiBaq2JdtaNf5JixVJ+fwDgLN8wvcxlUi5qkUnkgfLHCGzus40eMQGUCkp6vj0Tp4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=gs20gpz4jlCr1qs5BBbTD9T75AyKDEN+GUkDquXORAg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=igtu/mC1JN7aMnLHqEhKw23+sdRk/3wrHcI39FoVpdYJEAhCvIo3FuaU6xS0DgtxURtrIA/U+D6azG1vcPIuyGXGiPROypt5H8gGaLHjI5t87gxOLMj9htx/VRHubQGUssF7mlOI1ocbXsT21z9LjzUlMN00pD4V6vd4rp/7PFQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HEWskDOb; 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="HEWskDOb" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3F4F0C2BCF4; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=gs20gpz4jlCr1qs5BBbTD9T75AyKDEN+GUkDquXORAg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=HEWskDOb879bBTg7jj5ah+FXdeYqUTw/GthQ+MkkLEMuVw3VtrZtw/Eoi/HRr2Sdg 74Gp3smA35tzwHaXeUMLR1EbDz+ys06aP65nbnw8JizVx8J1+V6Mw2zbiu2iPMCOEF z6qXeJB1sTRjRWKTAqtYBIzuNrGnErLjbzb08TEaO//L5pKXotXI7H18dCSvLCky4R biCYn5pTYZC1ToIXHJ2fv1VqfuYHCfD2wgTcXOcCNpvHXstMtY7j8rjCmDAuhfqJDz ZZG3ps0AtCuhvVEjfmoQsHkoPq8ejRrTuPp9j6pXQnKSBxuRG2585/50Fm/o8HHvix lFegtdFMXx1sQ== 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 2B461C5DF81; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:23 +0800 Subject: [PATCH v5 09/12] pinctrl: ambarella: add CV75 pin 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: <20260818-cv75-v5-v5-9-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=46166; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=y8xGRspu7e782wZgrt/0WZrJLc0/H/F+o5WId22LrWY=; b=G7rjkxLh4I1OHGvx7BvdCjh8z/Q1fbepDk199uwHfLgPCck6OvkoSWMBUvAHwJjfUy3g4JcLO Nu8XC1Y038VDsXn16YpqBa6tAq1E9xNOkf24xoXIiYD/hIEVWdoOLli X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Add an Ambarella pinmux-only pinctrl driver with CV75 function/group tables. GPIO is handled by the PL061 driver. Signed-off-by: Long Zhao --- drivers/pinctrl/Kconfig | 15 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/pinctrl-ambarella-cv75.c | 561 ++++++++++++++++++++ drivers/pinctrl/pinctrl-ambarella.c | 863 +++++++++++++++++++++++++++= ++++ drivers/pinctrl/pinctrl-ambarella.h | 50 ++ 5 files changed, 1491 insertions(+) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c2cdd7b2c49b..da423792b5fa 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -37,6 +37,21 @@ config DEBUG_PINCTRL help Say Y here to add some extra checks and diagnostics to PINCTRL calls. =20 +config PINCTRL_AMB + bool "Ambarella pin controller support" + depends on ARCH_AMBARELLA || COMPILE_TEST + depends on HAS_IOMEM + default y if ARCH_AMBARELLA + select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + select GPIO_PL061 + select MFD_SYSCON + select PINCONF + select PINMUX + help + Say Y here to enable the Ambarella pin controller driver. + config PINCTRL_AMD bool "AMD GPIO pin control" depends on HAS_IOMEM diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index a35d71135abf..ce0825f4fc1b 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -10,6 +10,8 @@ obj-$(CONFIG_GENERIC_PINCONF) +=3D pinconf-generic.o obj-$(CONFIG_GENERIC_PINCTRL) +=3D pinctrl-generic.o obj-$(CONFIG_OF) +=3D devicetree.o =20 +obj-$(CONFIG_PINCTRL_AMB) +=3D pinctrl-ambarella.o +obj-$(CONFIG_PINCTRL_AMB) +=3D pinctrl-ambarella-cv75.o obj-$(CONFIG_PINCTRL_AMD) +=3D pinctrl-amd.o obj-$(CONFIG_PINCTRL_AMDISP) +=3D pinctrl-amdisp.o obj-$(CONFIG_PINCTRL_APPLE_GPIO) +=3D pinctrl-apple-gpio.o diff --git a/drivers/pinctrl/pinctrl-ambarella-cv75.c b/drivers/pinctrl/pin= ctrl-ambarella-cv75.c new file mode 100644 index 000000000000..e617f0717b31 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ambarella-cv75.c @@ -0,0 +1,561 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Ambarella CV75 pinctrl data + * + * Copyright (C) 2026, Ambarella, Inc. + */ + +#include + +#include "pinctrl-ambarella.h" + +#define CV75_PINMUX_GROUP(_name, ...) \ + static const u32 cv75_##_name##_pinmux[] =3D { __VA_ARGS__ } + +#define CV75_GROUP(_name) \ + { \ + .name =3D #_name, \ + .pinmux =3D cv75_##_name##_pinmux, \ + .num_pins =3D ARRAY_SIZE(cv75_##_name##_pinmux), \ + } + +#define CV75_FUNCTION(_name) \ + { \ + .name =3D #_name, \ + .groups =3D cv75_##_name##_groups, \ + .num_groups =3D ARRAY_SIZE(cv75_##_name##_groups), \ + } + +/* UART */ +CV75_PINMUX_GROUP(uart0, AMBA_PINMUX(44, 1), AMBA_PINMUX(45, 1)); +CV75_PINMUX_GROUP(uart1, AMBA_PINMUX(46, 1), AMBA_PINMUX(47, 1)); +CV75_PINMUX_GROUP(uart1_flow, AMBA_PINMUX(48, 1), AMBA_PINMUX(49, 1)); +CV75_PINMUX_GROUP(uart2_a, AMBA_PINMUX(46, 2), AMBA_PINMUX(47, 2)); +CV75_PINMUX_GROUP(uart2_b, AMBA_PINMUX(50, 2), AMBA_PINMUX(51, 2)); +CV75_PINMUX_GROUP(uart2_c, AMBA_PINMUX(66, 2), AMBA_PINMUX(68, 2)); +CV75_PINMUX_GROUP(uart2_flow_a, AMBA_PINMUX(48, 2), AMBA_PINMUX(49, 2)); +CV75_PINMUX_GROUP(uart2_flow_b, AMBA_PINMUX(65, 3), AMBA_PINMUX(67, 3)); +CV75_PINMUX_GROUP(uart3_a, AMBA_PINMUX(70, 3), AMBA_PINMUX(72, 3)); +CV75_PINMUX_GROUP(uart3_b, AMBA_PINMUX(80, 3), AMBA_PINMUX(79, 3)); +CV75_PINMUX_GROUP(uart3_flow_a, AMBA_PINMUX(71, 3), AMBA_PINMUX(69, 3)); +CV75_PINMUX_GROUP(uart3_flow_b, AMBA_PINMUX(81, 3), AMBA_PINMUX(82, 3)); +CV75_PINMUX_GROUP(uart4_a, AMBA_PINMUX(29, 3), AMBA_PINMUX(30, 3)); +CV75_PINMUX_GROUP(uart4_b, AMBA_PINMUX(76, 3), AMBA_PINMUX(77, 3)); +CV75_PINMUX_GROUP(uart4_flow_a, AMBA_PINMUX(28, 3), AMBA_PINMUX(31, 3)); +CV75_PINMUX_GROUP(uart4_flow_b, AMBA_PINMUX(74, 3), AMBA_PINMUX(75, 3)); + +/* Flash */ +CV75_PINMUX_GROUP(snand, AMBA_PINMUX(79, 1), AMBA_PINMUX(80, 1), + AMBA_PINMUX(81, 1), AMBA_PINMUX(82, 1), + AMBA_PINMUX(83, 1), AMBA_PINMUX(84, 1)); +CV75_PINMUX_GROUP(spinor, AMBA_PINMUX(79, 2), AMBA_PINMUX(80, 2), + AMBA_PINMUX(81, 2), AMBA_PINMUX(82, 2), + AMBA_PINMUX(83, 2), AMBA_PINMUX(84, 2), + AMBA_PINMUX(85, 2)); + +/* SD/MMC */ +CV75_PINMUX_GROUP(sdmmc0_cd, AMBA_PINMUX(6, 1)); +CV75_PINMUX_GROUP(sdmmc0_wp, AMBA_PINMUX(7, 1)); +CV75_PINMUX_GROUP(sdmmc0_reset, AMBA_PINMUX(8, 1)); +CV75_PINMUX_GROUP(sdmmc0_hs_sel, AMBA_PINMUX(93, 1)); +CV75_PINMUX_GROUP(sdmmc0_1bit, AMBA_PINMUX(0, 1), AMBA_PINMUX(4, 1), + AMBA_PINMUX(5, 1)); +CV75_PINMUX_GROUP(sdmmc0_4bit, AMBA_PINMUX(0, 1), AMBA_PINMUX(1, 1), + AMBA_PINMUX(2, 1), AMBA_PINMUX(3, 1), + AMBA_PINMUX(4, 1), AMBA_PINMUX(5, 1)); +CV75_PINMUX_GROUP(sdmmc1_cd, AMBA_PINMUX(15, 1)); +CV75_PINMUX_GROUP(sdmmc1_wp, AMBA_PINMUX(16, 1)); +CV75_PINMUX_GROUP(sdmmc1_reset, AMBA_PINMUX(17, 1)); +CV75_PINMUX_GROUP(sdmmc1_hs_sel, AMBA_PINMUX(94, 1)); +CV75_PINMUX_GROUP(sdmmc1_1bit, AMBA_PINMUX(9, 1), AMBA_PINMUX(13, 1), + AMBA_PINMUX(14, 1)); +CV75_PINMUX_GROUP(sdmmc1_4bit, AMBA_PINMUX(9, 1), AMBA_PINMUX(10, 1), + AMBA_PINMUX(11, 1), AMBA_PINMUX(12, 1), + AMBA_PINMUX(13, 1), AMBA_PINMUX(14, 1)); + +/* Ethernet */ +CV75_PINMUX_GROUP(enet_ext_osc_clk, AMBA_PINMUX(77, 1)); +CV75_PINMUX_GROUP(enet_2nd_ref_clk_a, AMBA_PINMUX(78, 1)); +CV75_PINMUX_GROUP(enet_2nd_ref_clk_b, AMBA_PINMUX(76, 2)); +CV75_PINMUX_GROUP(enet0_ptp_pps_o, AMBA_PINMUX(74, 1)); +CV75_PINMUX_GROUP(rgmii0, AMBA_PINMUX(62, 1), AMBA_PINMUX(63, 1), + AMBA_PINMUX(64, 1), AMBA_PINMUX(65, 1), + AMBA_PINMUX(66, 1), AMBA_PINMUX(67, 1), + AMBA_PINMUX(68, 1), AMBA_PINMUX(69, 1), + AMBA_PINMUX(70, 1), AMBA_PINMUX(71, 1), + AMBA_PINMUX(72, 1), AMBA_PINMUX(73, 1), + AMBA_PINMUX(75, 1), AMBA_PINMUX(76, 1)); +CV75_PINMUX_GROUP(rmii0, AMBA_PINMUX(62, 1), AMBA_PINMUX(63, 1), + AMBA_PINMUX(64, 1), AMBA_PINMUX(67, 1), + AMBA_PINMUX(68, 1), AMBA_PINMUX(71, 1), + AMBA_PINMUX(72, 1), AMBA_PINMUX(73, 1), + AMBA_PINMUX(75, 2)); + +/* I2C */ +CV75_PINMUX_GROUP(i2c0_a, AMBA_PINMUX(67, 2), AMBA_PINMUX(68, 2)); +CV75_PINMUX_GROUP(i2c0_b, AMBA_PINMUX(86, 1), AMBA_PINMUX(87, 1)); +CV75_PINMUX_GROUP(i2c1_a, AMBA_PINMUX(22, 2), AMBA_PINMUX(23, 2)); +CV75_PINMUX_GROUP(i2c1_b, AMBA_PINMUX(69, 2), AMBA_PINMUX(70, 2)); +CV75_PINMUX_GROUP(i2c2, AMBA_PINMUX(88, 1), AMBA_PINMUX(89, 1)); +CV75_PINMUX_GROUP(i2c3_a, AMBA_PINMUX(24, 2), AMBA_PINMUX(25, 2)); +CV75_PINMUX_GROUP(i2c3_b, AMBA_PINMUX(48, 3), AMBA_PINMUX(49, 3)); +CV75_PINMUX_GROUP(i2c3_c, AMBA_PINMUX(58, 3), AMBA_PINMUX(59, 3)); +CV75_PINMUX_GROUP(i2cs_a, AMBA_PINMUX(19, 2), AMBA_PINMUX(21, 2)); +CV75_PINMUX_GROUP(i2cs_b, AMBA_PINMUX(60, 3), AMBA_PINMUX(61, 3)); +CV75_PINMUX_GROUP(i2cs_c, AMBA_PINMUX(71, 2), AMBA_PINMUX(72, 2)); +CV75_PINMUX_GROUP(i2cs_d, AMBA_PINMUX(86, 2), AMBA_PINMUX(87, 2)); + +/* CAN, IR, WDT */ +CV75_PINMUX_GROUP(can0, AMBA_PINMUX(50, 1), AMBA_PINMUX(51, 1)); +CV75_PINMUX_GROUP(can1, AMBA_PINMUX(52, 1), AMBA_PINMUX(53, 1)); +CV75_PINMUX_GROUP(ir, AMBA_PINMUX(18, 1)); +CV75_PINMUX_GROUP(wdt_a, AMBA_PINMUX(20, 2)); +CV75_PINMUX_GROUP(wdt_b, AMBA_PINMUX(27, 3)); +CV75_PINMUX_GROUP(wdt_c, AMBA_PINMUX(39, 2)); +CV75_PINMUX_GROUP(wdt_d, AMBA_PINMUX(83, 3)); +CV75_PINMUX_GROUP(wdt_e, AMBA_PINMUX(85, 4)); +CV75_PINMUX_GROUP(wdt_f, AMBA_PINMUX(90, 1)); + +/* I2S */ +CV75_PINMUX_GROUP(i2s0, AMBA_PINMUX(54, 1), AMBA_PINMUX(55, 1), + AMBA_PINMUX(56, 1), AMBA_PINMUX(57, 1)); +CV75_PINMUX_GROUP(i2s1, AMBA_PINMUX(58, 1), AMBA_PINMUX(59, 1), + AMBA_PINMUX(60, 1), AMBA_PINMUX(61, 1)); +CV75_PINMUX_GROUP(clk_au, AMBA_PINMUX(96, 1)); +CV75_PINMUX_GROUP(dmic0, AMBA_PINMUX(54, 2), AMBA_PINMUX(55, 2)); + +/* PWM */ +CV75_PINMUX_GROUP(pwm0, AMBA_PINMUX(40, 1)); +CV75_PINMUX_GROUP(pwm1, AMBA_PINMUX(41, 1)); +CV75_PINMUX_GROUP(pwm2, AMBA_PINMUX(42, 1)); +CV75_PINMUX_GROUP(pwm3, AMBA_PINMUX(43, 1)); +CV75_PINMUX_GROUP(pwm4_a, AMBA_PINMUX(19, 3)); +CV75_PINMUX_GROUP(pwm4_b, AMBA_PINMUX(32, 4)); +CV75_PINMUX_GROUP(pwm5_a, AMBA_PINMUX(20, 3)); +CV75_PINMUX_GROUP(pwm5_b, AMBA_PINMUX(33, 4)); +CV75_PINMUX_GROUP(pwm6_a, AMBA_PINMUX(21, 3)); +CV75_PINMUX_GROUP(pwm6_b, AMBA_PINMUX(34, 4)); +CV75_PINMUX_GROUP(pwm7_a, AMBA_PINMUX(22, 3)); +CV75_PINMUX_GROUP(pwm7_b, AMBA_PINMUX(35, 4)); +CV75_PINMUX_GROUP(pwm8_a, AMBA_PINMUX(23, 3)); +CV75_PINMUX_GROUP(pwm8_b, AMBA_PINMUX(36, 4)); +CV75_PINMUX_GROUP(pwm9_a, AMBA_PINMUX(24, 3)); +CV75_PINMUX_GROUP(pwm9_b, AMBA_PINMUX(37, 4)); +CV75_PINMUX_GROUP(pwm10_a, AMBA_PINMUX(25, 3)); +CV75_PINMUX_GROUP(pwm10_b, AMBA_PINMUX(38, 4)); +CV75_PINMUX_GROUP(pwm11_a, AMBA_PINMUX(26, 3)); +CV75_PINMUX_GROUP(pwm11_b, AMBA_PINMUX(39, 4)); + +/* SPI */ +CV75_PINMUX_GROUP(spi0, AMBA_PINMUX(19, 1), AMBA_PINMUX(20, 1), + AMBA_PINMUX(21, 1)); +CV75_PINMUX_GROUP(spi1, AMBA_PINMUX(24, 1), AMBA_PINMUX(25, 1), + AMBA_PINMUX(26, 1)); +CV75_PINMUX_GROUP(spi2, AMBA_PINMUX(28, 1), AMBA_PINMUX(29, 1), + AMBA_PINMUX(30, 1)); +CV75_PINMUX_GROUP(spi3_a, AMBA_PINMUX(32, 5), AMBA_PINMUX(33, 5), + AMBA_PINMUX(34, 5)); +CV75_PINMUX_GROUP(spi3_b, AMBA_PINMUX(40, 2), AMBA_PINMUX(41, 2), + AMBA_PINMUX(43, 2)); +CV75_PINMUX_GROUP(spi3_c, AMBA_PINMUX(58, 2), AMBA_PINMUX(59, 2), + AMBA_PINMUX(60, 2)); +CV75_PINMUX_GROUP(spi_slave_a, AMBA_PINMUX(24, 4), AMBA_PINMUX(25, 4), + AMBA_PINMUX(26, 4), AMBA_PINMUX(27, 4)); +CV75_PINMUX_GROUP(spi_slave_b, AMBA_PINMUX(28, 2), AMBA_PINMUX(29, 2), + AMBA_PINMUX(30, 2), AMBA_PINMUX(31, 2)); +CV75_PINMUX_GROUP(spi_slave_c, AMBA_PINMUX(36, 5), AMBA_PINMUX(37, 5), + AMBA_PINMUX(38, 5), AMBA_PINMUX(39, 5)); +CV75_PINMUX_GROUP(spi_slave_d, AMBA_PINMUX(50, 3), AMBA_PINMUX(51, 3), + AMBA_PINMUX(52, 3), AMBA_PINMUX(53, 3)); +CV75_PINMUX_GROUP(spi_slave_e, AMBA_PINMUX(81, 4), AMBA_PINMUX(82, 4), + AMBA_PINMUX(83, 4), AMBA_PINMUX(84, 4)); + +/* VIN master sync */ +CV75_PINMUX_GROUP(vin_master_sync_a, AMBA_PINMUX(91, 1), + AMBA_PINMUX(92, 1)); +CV75_PINMUX_GROUP(vin_master_sync_b, AMBA_PINMUX(91, 2), + AMBA_PINMUX(92, 2)); +CV75_PINMUX_GROUP(vin_master_sync_c, AMBA_PINMUX(40, 3), + AMBA_PINMUX(41, 3)); +CV75_PINMUX_GROUP(vin_master_sync_d, AMBA_PINMUX(46, 3), + AMBA_PINMUX(47, 3)); +CV75_PINMUX_GROUP(vin_master_sync_e, AMBA_PINMUX(79, 4), + AMBA_PINMUX(80, 4)); +CV75_PINMUX_GROUP(vsync0, AMBA_PINMUX(32, 1)); +CV75_PINMUX_GROUP(vsync1, AMBA_PINMUX(33, 1)); +CV75_PINMUX_GROUP(vsync2, AMBA_PINMUX(34, 1)); +CV75_PINMUX_GROUP(vsync3, AMBA_PINMUX(35, 1)); +CV75_PINMUX_GROUP(hsync0, AMBA_PINMUX(36, 1)); +CV75_PINMUX_GROUP(hsync1, AMBA_PINMUX(37, 1)); + +static const struct ambpin_group_desc cv75_pin_groups[] =3D { + CV75_GROUP(uart0), + CV75_GROUP(uart1), CV75_GROUP(uart1_flow), + CV75_GROUP(uart2_a), CV75_GROUP(uart2_b), CV75_GROUP(uart2_c), + CV75_GROUP(uart2_flow_a), CV75_GROUP(uart2_flow_b), + CV75_GROUP(uart3_a), CV75_GROUP(uart3_b), + CV75_GROUP(uart3_flow_a), CV75_GROUP(uart3_flow_b), + CV75_GROUP(uart4_a), CV75_GROUP(uart4_b), + CV75_GROUP(uart4_flow_a), CV75_GROUP(uart4_flow_b), + CV75_GROUP(snand), CV75_GROUP(spinor), + CV75_GROUP(sdmmc0_cd), CV75_GROUP(sdmmc0_wp), + CV75_GROUP(sdmmc0_reset), CV75_GROUP(sdmmc0_hs_sel), + CV75_GROUP(sdmmc0_1bit), CV75_GROUP(sdmmc0_4bit), + CV75_GROUP(sdmmc1_cd), CV75_GROUP(sdmmc1_wp), + CV75_GROUP(sdmmc1_reset), CV75_GROUP(sdmmc1_hs_sel), + CV75_GROUP(sdmmc1_1bit), CV75_GROUP(sdmmc1_4bit), + CV75_GROUP(enet_ext_osc_clk), CV75_GROUP(enet_2nd_ref_clk_a), + CV75_GROUP(enet_2nd_ref_clk_b), CV75_GROUP(enet0_ptp_pps_o), + CV75_GROUP(rgmii0), CV75_GROUP(rmii0), + CV75_GROUP(i2c0_a), CV75_GROUP(i2c0_b), + CV75_GROUP(i2c1_a), CV75_GROUP(i2c1_b), CV75_GROUP(i2c2), + CV75_GROUP(i2c3_a), CV75_GROUP(i2c3_b), CV75_GROUP(i2c3_c), + CV75_GROUP(i2cs_a), CV75_GROUP(i2cs_b), + CV75_GROUP(i2cs_c), CV75_GROUP(i2cs_d), + CV75_GROUP(can0), CV75_GROUP(can1), CV75_GROUP(ir), + CV75_GROUP(wdt_a), CV75_GROUP(wdt_b), CV75_GROUP(wdt_c), + CV75_GROUP(wdt_d), CV75_GROUP(wdt_e), CV75_GROUP(wdt_f), + CV75_GROUP(i2s0), CV75_GROUP(i2s1), + CV75_GROUP(clk_au), CV75_GROUP(dmic0), + CV75_GROUP(pwm0), CV75_GROUP(pwm1), + CV75_GROUP(pwm2), CV75_GROUP(pwm3), + CV75_GROUP(pwm4_a), CV75_GROUP(pwm4_b), + CV75_GROUP(pwm5_a), CV75_GROUP(pwm5_b), + CV75_GROUP(pwm6_a), CV75_GROUP(pwm6_b), + CV75_GROUP(pwm7_a), CV75_GROUP(pwm7_b), + CV75_GROUP(pwm8_a), CV75_GROUP(pwm8_b), + CV75_GROUP(pwm9_a), CV75_GROUP(pwm9_b), + CV75_GROUP(pwm10_a), CV75_GROUP(pwm10_b), + CV75_GROUP(pwm11_a), CV75_GROUP(pwm11_b), + CV75_GROUP(spi0), CV75_GROUP(spi1), CV75_GROUP(spi2), + CV75_GROUP(spi3_a), CV75_GROUP(spi3_b), CV75_GROUP(spi3_c), + CV75_GROUP(spi_slave_a), CV75_GROUP(spi_slave_b), + CV75_GROUP(spi_slave_c), CV75_GROUP(spi_slave_d), + CV75_GROUP(spi_slave_e), + CV75_GROUP(vin_master_sync_a), CV75_GROUP(vin_master_sync_b), + CV75_GROUP(vin_master_sync_c), CV75_GROUP(vin_master_sync_d), + CV75_GROUP(vin_master_sync_e), + CV75_GROUP(vsync0), CV75_GROUP(vsync1), + CV75_GROUP(vsync2), CV75_GROUP(vsync3), + CV75_GROUP(hsync0), CV75_GROUP(hsync1), +}; + +static const char * const cv75_uart0_groups[] =3D { + "uart0", +}; + +static const char * const cv75_uart1_groups[] =3D { + "uart1", + "uart1_flow", +}; + +static const char * const cv75_uart2_groups[] =3D { + "uart2_a", + "uart2_b", + "uart2_c", + "uart2_flow_a", + "uart2_flow_b", +}; + +static const char * const cv75_uart3_groups[] =3D { + "uart3_a", + "uart3_b", + "uart3_flow_a", + "uart3_flow_b", +}; + +static const char * const cv75_uart4_groups[] =3D { + "uart4_a", + "uart4_b", + "uart4_flow_a", + "uart4_flow_b", +}; + +static const char * const cv75_snand_groups[] =3D { + "snand", +}; + +static const char * const cv75_spinor_groups[] =3D { + "spinor", +}; + +static const char * const cv75_sdmmc0_groups[] =3D { + "sdmmc0_cd", + "sdmmc0_wp", + "sdmmc0_reset", + "sdmmc0_hs_sel", + "sdmmc0_1bit", + "sdmmc0_4bit", +}; + +static const char * const cv75_sdmmc1_groups[] =3D { + "sdmmc1_cd", + "sdmmc1_wp", + "sdmmc1_reset", + "sdmmc1_hs_sel", + "sdmmc1_1bit", + "sdmmc1_4bit", +}; + +static const char * const cv75_enet0_groups[] =3D { + "enet_ext_osc_clk", + "enet_2nd_ref_clk_a", + "enet_2nd_ref_clk_b", + "enet0_ptp_pps_o", + "rgmii0", + "rmii0", +}; + +static const char * const cv75_i2c0_groups[] =3D { + "i2c0_a", + "i2c0_b", +}; + +static const char * const cv75_i2c1_groups[] =3D { + "i2c1_a", + "i2c1_b", +}; + +static const char * const cv75_i2c2_groups[] =3D { + "i2c2", +}; + +static const char * const cv75_i2c3_groups[] =3D { + "i2c3_a", + "i2c3_b", + "i2c3_c", +}; + +static const char * const cv75_i2cs_groups[] =3D { + "i2cs_a", + "i2cs_b", + "i2cs_c", + "i2cs_d", +}; + +static const char * const cv75_can0_groups[] =3D { + "can0", +}; + +static const char * const cv75_can1_groups[] =3D { + "can1", +}; + +static const char * const cv75_ir_groups[] =3D { + "ir", +}; + +static const char * const cv75_wdt_groups[] =3D { + "wdt_a", + "wdt_b", + "wdt_c", + "wdt_d", + "wdt_e", + "wdt_f", +}; + +static const char * const cv75_i2s0_groups[] =3D { + "i2s0", +}; + +static const char * const cv75_i2s1_groups[] =3D { + "i2s1", +}; + +static const char * const cv75_clk_au_groups[] =3D { + "clk_au", +}; + +static const char * const cv75_dmic0_groups[] =3D { + "dmic0", +}; + +static const char * const cv75_pwm0_groups[] =3D { + "pwm0", +}; + +static const char * const cv75_pwm1_groups[] =3D { + "pwm1", +}; + +static const char * const cv75_pwm2_groups[] =3D { + "pwm2", +}; + +static const char * const cv75_pwm3_groups[] =3D { + "pwm3", +}; + +static const char * const cv75_pwm4_groups[] =3D { + "pwm4_a", + "pwm4_b", +}; + +static const char * const cv75_pwm5_groups[] =3D { + "pwm5_a", + "pwm5_b", +}; + +static const char * const cv75_pwm6_groups[] =3D { + "pwm6_a", + "pwm6_b", +}; + +static const char * const cv75_pwm7_groups[] =3D { + "pwm7_a", + "pwm7_b", +}; + +static const char * const cv75_pwm8_groups[] =3D { + "pwm8_a", + "pwm8_b", +}; + +static const char * const cv75_pwm9_groups[] =3D { + "pwm9_a", + "pwm9_b", +}; + +static const char * const cv75_pwm10_groups[] =3D { + "pwm10_a", + "pwm10_b", +}; + +static const char * const cv75_pwm11_groups[] =3D { + "pwm11_a", + "pwm11_b", +}; + +static const char * const cv75_spi0_groups[] =3D { + "spi0", +}; + +static const char * const cv75_spi1_groups[] =3D { + "spi1", +}; + +static const char * const cv75_spi2_groups[] =3D { + "spi2", +}; + +static const char * const cv75_spi3_groups[] =3D { + "spi3_a", + "spi3_b", + "spi3_c", +}; + +static const char * const cv75_spi_slave_groups[] =3D { + "spi_slave_a", + "spi_slave_b", + "spi_slave_c", + "spi_slave_d", + "spi_slave_e", +}; + +static const char * const cv75_vin_master_sync_groups[] =3D { + "vin_master_sync_a", + "vin_master_sync_b", + "vin_master_sync_c", + "vin_master_sync_d", + "vin_master_sync_e", +}; + +static const char * const cv75_vsync0_groups[] =3D { + "vsync0", +}; + +static const char * const cv75_vsync1_groups[] =3D { + "vsync1", +}; + +static const char * const cv75_vsync2_groups[] =3D { + "vsync2", +}; + +static const char * const cv75_vsync3_groups[] =3D { + "vsync3", +}; + +static const char * const cv75_hsync0_groups[] =3D { + "hsync0", +}; + +static const char * const cv75_hsync1_groups[] =3D { + "hsync1", +}; + +static const struct ambpin_function cv75_pin_functions[] =3D { + CV75_FUNCTION(uart0), + CV75_FUNCTION(uart1), + CV75_FUNCTION(uart2), + CV75_FUNCTION(uart3), + CV75_FUNCTION(uart4), + CV75_FUNCTION(snand), + CV75_FUNCTION(spinor), + CV75_FUNCTION(sdmmc0), + CV75_FUNCTION(sdmmc1), + CV75_FUNCTION(enet0), + CV75_FUNCTION(i2c0), + CV75_FUNCTION(i2c1), + CV75_FUNCTION(i2c2), + CV75_FUNCTION(i2c3), + CV75_FUNCTION(i2cs), + CV75_FUNCTION(can0), + CV75_FUNCTION(can1), + CV75_FUNCTION(ir), + CV75_FUNCTION(wdt), + CV75_FUNCTION(i2s0), + CV75_FUNCTION(i2s1), + CV75_FUNCTION(clk_au), + CV75_FUNCTION(dmic0), + CV75_FUNCTION(pwm0), + CV75_FUNCTION(pwm1), + CV75_FUNCTION(pwm2), + CV75_FUNCTION(pwm3), + CV75_FUNCTION(pwm4), + CV75_FUNCTION(pwm5), + CV75_FUNCTION(pwm6), + CV75_FUNCTION(pwm7), + CV75_FUNCTION(pwm8), + CV75_FUNCTION(pwm9), + CV75_FUNCTION(pwm10), + CV75_FUNCTION(pwm11), + CV75_FUNCTION(spi0), + CV75_FUNCTION(spi1), + CV75_FUNCTION(spi2), + CV75_FUNCTION(spi3), + CV75_FUNCTION(spi_slave), + CV75_FUNCTION(vin_master_sync), + CV75_FUNCTION(vsync0), + CV75_FUNCTION(vsync1), + CV75_FUNCTION(vsync2), + CV75_FUNCTION(vsync3), + CV75_FUNCTION(hsync0), + CV75_FUNCTION(hsync1), +}; + +const struct amb_pinctrl_data ambarella_cv75_pinctrl_data =3D { + .ds0 =3D { + 0x314, 0x320, 0x32c, + }, + .ds1 =3D { + 0x318, 0x324, 0x330, + }, + .ds2 =3D { + 0x31c, 0x328, 0x334, + }, + .pull_en =3D { + 0x60, 0x64, 0x68, + }, + .pull_dir =3D { + 0x7c, 0x80, 0x84, + }, + .have_ds2 =3D true, + .clk_au_dedicated_pin =3D 96, + .nr_banks =3D 3, + .npins =3D 97, + .groups =3D cv75_pin_groups, + .nr_groups =3D ARRAY_SIZE(cv75_pin_groups), + .functions =3D cv75_pin_functions, + .nr_functions =3D ARRAY_SIZE(cv75_pin_functions), +}; diff --git a/drivers/pinctrl/pinctrl-ambarella.c b/drivers/pinctrl/pinctrl-= ambarella.c new file mode 100644 index 000000000000..f9146d365c3c --- /dev/null +++ b/drivers/pinctrl/pinctrl-ambarella.c @@ -0,0 +1,863 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Pinctrl driver for Ambarella SoCs + * + * History: + * 2013/12/18 - [Cao Rongrong] created file + * + * Copyright (C) 2012-2026, Ambarella, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinconf.h" +#include "pinctrl-ambarella.h" + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D*/ + +#define IOMUX_OFFSET(bank, n) (((bank) * 0xc) + ((n) * 4)) +#define IOMUX_CTRL_SET_OFFSET 0xf0 + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D*/ + +#define AMBA_MAX_PINS (AMBA_MAX_BANKS * 32) + +#define PINID_TO_BANK(p) ((p) >> 5) +#define PINID_TO_OFFSET(p) ((p) & 0x1f) + +struct amb_pinctrl_pm_state { + u32 iomux[3]; + u32 pull[2]; + u32 ds[3]; +}; + +struct ambpin_group { + const char *name; + const u32 *pinmux; + unsigned int *pins; + unsigned int num_pins; +}; + +struct amb_pinctrl_soc_data { + struct device *dev; + const struct amb_pinctrl_data *data; + void __iomem *iomux_base; + struct regmap *ds_regmap; + struct regmap *pull_regmap; + unsigned int npins; + unsigned long used[BITS_TO_LONGS(AMBA_MAX_PINS)]; + raw_spinlock_t lock; + + struct pinctrl_dev *pctl; + + const struct ambpin_function *functions; + unsigned int nr_functions; + struct ambpin_group *groups; + unsigned int nr_groups; + + struct amb_pinctrl_pm_state pm[AMBA_MAX_BANKS]; +}; + +/* check if the selector is a valid pin group selector */ +static int amb_get_group_count(struct pinctrl_dev *pctldev) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->nr_groups; +} + +/* return the name of the group selected by the group selector */ +static const char *amb_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->groups[selector].name; +} + +/* return the pin numbers associated with the specified group */ +static int amb_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *num_pins) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + *pins =3D soc->groups[selector].pins; + *num_pins =3D soc->groups[selector].num_pins; + + return 0; +} + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static void amb_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + seq_printf(s, " %s", pinctrl_dev_get_devname(pctldev)); +} +#endif + +/* list of pinctrl callbacks for the pinctrl core */ +static const struct pinctrl_ops amb_pctrl_ops =3D { + .get_groups_count =3D amb_get_group_count, + .get_group_name =3D amb_get_group_name, + .get_group_pins =3D amb_get_group_pins, +#if IS_ENABLED(CONFIG_DEBUG_FS) + .pin_dbg_show =3D amb_pin_dbg_show, +#endif + .dt_node_to_map =3D pinconf_generic_dt_node_to_map_all, + .dt_free_map =3D pinconf_generic_dt_free_map, +}; + +/* check if the selector is a valid pin function selector */ +static int amb_pinmux_request(struct pinctrl_dev *pctldev, unsigned int pi= n) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + if (test_and_set_bit(pin, soc->used)) + return -EBUSY; + + return 0; +} + +/* check if the selector is a valid pin function selector */ +static int amb_pinmux_free(struct pinctrl_dev *pctldev, unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + clear_bit(pin, soc->used); + + return 0; +} + +/* check if the selector is a valid pin function selector */ +static int amb_pinmux_get_fcount(struct pinctrl_dev *pctldev) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->nr_functions; +} + +/* return the name of the pin function specified */ +static const char *amb_pinmux_get_fname(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->functions[selector].name; +} + +/* return the groups associated for the specified function selector */ +static int amb_pinmux_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + *groups =3D soc->functions[selector].groups; + *num_groups =3D soc->functions[selector].num_groups; + + return 0; +} + +static bool amb_iomux_accessible(const struct amb_pinctrl_soc_data *soc) +{ + return soc->data->hsm_domain_id =3D=3D 0; +} + +static void amb_iomux_commit(struct amb_pinctrl_soc_data *soc) +{ + if (!amb_iomux_accessible(soc)) + return; + + writel_relaxed(0x1, soc->iomux_base + IOMUX_CTRL_SET_OFFSET); + writel_relaxed(0x0, soc->iomux_base + IOMUX_CTRL_SET_OFFSET); +} + +static void amb_iomux_save_bank(struct amb_pinctrl_soc_data *soc, u32 bank) +{ + if (!amb_iomux_accessible(soc) || bank >=3D AMBA_MAX_BANKS) + return; + + soc->pm[bank].iomux[0] =3D + readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, 0)); + soc->pm[bank].iomux[1] =3D + readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, 1)); + soc->pm[bank].iomux[2] =3D + readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, 2)); +} + +static void amb_iomux_restore_bank(struct amb_pinctrl_soc_data *soc, u32 b= ank) +{ + if (!amb_iomux_accessible(soc) || bank >=3D AMBA_MAX_BANKS) + return; + + writel_relaxed(soc->pm[bank].iomux[0], + soc->iomux_base + IOMUX_OFFSET(bank, 0)); + writel_relaxed(soc->pm[bank].iomux[1], + soc->iomux_base + IOMUX_OFFSET(bank, 1)); + writel_relaxed(soc->pm[bank].iomux[2], + soc->iomux_base + IOMUX_OFFSET(bank, 2)); +} + +static void amb_pinmux_set_altfunc(struct amb_pinctrl_soc_data *soc, + u32 bank, u32 offset, u32 altfunc) +{ + u32 i, data; + + if (!amb_iomux_accessible(soc)) + return; + + for (i =3D 0; i < 3; i++) { + data =3D readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, i)); + data &=3D ~BIT(offset); + data |=3D ((altfunc >> i) & 1U) << offset; + writel_relaxed(data, soc->iomux_base + IOMUX_OFFSET(bank, i)); + } +} + +/* enable a specified pinmux by writing to registers */ +static int amb_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned int group) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + const struct ambpin_group *grp; + u32 i, pin, alt, bank, offset; + unsigned long flags; + + grp =3D &soc->groups[group]; + + raw_spin_lock_irqsave(&soc->lock, flags); + for (i =3D 0; i < grp->num_pins; i++) { + pin =3D AMBA_PINMUX_TO_PIN(grp->pinmux[i]); + alt =3D AMBA_PINMUX_TO_ALT(grp->pinmux[i]); + bank =3D PINID_TO_BANK(pin); + offset =3D PINID_TO_OFFSET(pin); + amb_pinmux_set_altfunc(soc, bank, offset, alt); + } + /* One commit after the whole group is programmed. */ + amb_iomux_commit(soc); + raw_spin_unlock_irqrestore(&soc->lock, flags); + + return 0; +} + +static int amb_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + u32 bank, offset; + unsigned long flags; + + if (!range || !range->gc) { + dev_err(soc->dev, "invalid range: %p\n", range); + return -EINVAL; + } + + if (test_and_set_bit(pin, soc->used)) + return -EBUSY; + + bank =3D PINID_TO_BANK(pin); + offset =3D PINID_TO_OFFSET(pin); + + raw_spin_lock_irqsave(&soc->lock, flags); + amb_pinmux_set_altfunc(soc, bank, offset, 0); + amb_iomux_commit(soc); + raw_spin_unlock_irqrestore(&soc->lock, flags); + + return 0; +} + +static void amb_pinmux_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(soc->dev, "disable pin %u as GPIO\n", pin); + /* Set the pin to some default state, GPIO is usually default */ + + clear_bit(pin, soc->used); +} + +/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ +static const struct pinmux_ops amb_pinmux_ops =3D { + .request =3D amb_pinmux_request, + .free =3D amb_pinmux_free, + .get_functions_count =3D amb_pinmux_get_fcount, + .get_function_name =3D amb_pinmux_get_fname, + .get_function_groups =3D amb_pinmux_get_groups, + .set_mux =3D amb_pinmux_set_mux, + .gpio_request_enable =3D amb_pinmux_gpio_request_enable, + .gpio_disable_free =3D amb_pinmux_gpio_disable_free, +}; + +static int amb_drive_strength_to_reg(struct amb_pinctrl_soc_data *soc, + u32 strength) +{ + if (soc->data->have_ds2) { + switch (strength) { + case 3: + return 0; + case 4: + case 5: + return 1; + case 6: + return 2; + case 7: + case 8: + return 3; + case 9: + return 4; + case 12: + return 5; + default: + return -EINVAL; + } + } + + switch (strength) { + case 2: + return 0; + case 4: + return 1; + case 8: + return 2; + case 12: + return 3; + default: + return -EINVAL; + } +} + +static int amb_reg_to_drive_strength(struct amb_pinctrl_soc_data *soc, u32= ds) +{ + static const int ds2_ma[] =3D { 3, 4, 6, 8, 9, 12 }; + static const int ds_ma[] =3D { 2, 4, 8, 12 }; + + if (soc->data->have_ds2) { + if (ds >=3D ARRAY_SIZE(ds2_ma)) + return -EINVAL; + + return ds2_ma[ds]; + } + + if (ds >=3D ARRAY_SIZE(ds_ma)) + return -EINVAL; + + return ds_ma[ds]; +} + +/* set the pin config settings for a specified pin */ +static int amb_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + u32 i, bank, offset; + unsigned long config; + enum pin_config_param param; + u32 arg; + int ds; + + bank =3D PINID_TO_BANK(pin); + if (bank >=3D soc->data->nr_banks) + return -EINVAL; + + offset =3D PINID_TO_OFFSET(pin); + + for (i =3D 0; i < num_configs; i++) { + config =3D configs[i]; + param =3D pinconf_to_config_param(config); + arg =3D pinconf_to_config_argument(config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + regmap_update_bits(soc->pull_regmap, + soc->data->pull_en[bank], BIT(offset), 0); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + regmap_update_bits(soc->pull_regmap, soc->data->pull_dir[bank], + BIT(offset), + (param =3D=3D PIN_CONFIG_BIAS_PULL_UP) ? + BIT(offset) : 0); + regmap_update_bits(soc->pull_regmap, soc->data->pull_en[bank], + BIT(offset), BIT(offset)); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ds =3D amb_drive_strength_to_reg(soc, arg); + if (ds < 0) + return ds; + if (soc->data->have_ds2) { + regmap_update_bits(soc->ds_regmap, + soc->data->ds0[bank], BIT(offset), + (ds & BIT(0)) ? BIT(offset) : 0); + regmap_update_bits(soc->ds_regmap, + soc->data->ds1[bank], BIT(offset), + (ds & BIT(1)) ? BIT(offset) : 0); + regmap_update_bits(soc->ds_regmap, + soc->data->ds2[bank], BIT(offset), + (ds & BIT(2)) ? BIT(offset) : 0); + } else { + regmap_update_bits(soc->ds_regmap, + soc->data->ds0[bank], BIT(offset), + (ds & BIT(1)) ? BIT(offset) : 0); + regmap_update_bits(soc->ds_regmap, + soc->data->ds1[bank], BIT(offset), + (ds & BIT(0)) ? BIT(offset) : 0); + } + break; + default: + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int amb_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + const struct ambpin_group *grp =3D &soc->groups[selector]; + int ret; + u32 i; + + for (i =3D 0; i < grp->num_pins; i++) { + ret =3D amb_pinconf_set(pctldev, grp->pins[i], configs, + num_configs); + if (ret) + return ret; + } + + return 0; +} + +/* get the pin config settings for a specified pin */ +static int amb_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param =3D pinconf_to_config_param(*config); + u32 bank, offset, pull_en, pull_dir, ds0, ds1, ds2, ds; + int ret, strength; + + bank =3D PINID_TO_BANK(pin); + if (bank >=3D soc->data->nr_banks) + return -EINVAL; + + offset =3D PINID_TO_OFFSET(pin); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + ret =3D regmap_read(soc->pull_regmap, soc->data->pull_en[bank], + &pull_en); + if (ret) + return ret; + + ret =3D regmap_read(soc->pull_regmap, soc->data->pull_dir[bank], + &pull_dir); + if (ret) + return ret; + + pull_en =3D (pull_en >> offset) & 1; + pull_dir =3D (pull_dir >> offset) & 1; + + if (param =3D=3D PIN_CONFIG_BIAS_DISABLE) { + if (pull_en) + return -EINVAL; + *config =3D pinconf_to_config_packed(param, 0); + return 0; + } + + if (!pull_en) + return -EINVAL; + if (param =3D=3D PIN_CONFIG_BIAS_PULL_UP && !pull_dir) + return -EINVAL; + if (param =3D=3D PIN_CONFIG_BIAS_PULL_DOWN && pull_dir) + return -EINVAL; + + *config =3D pinconf_to_config_packed(param, 1); + return 0; + + case PIN_CONFIG_DRIVE_STRENGTH: + ret =3D regmap_read(soc->ds_regmap, soc->data->ds0[bank], &ds0); + if (ret) + return ret; + + ret =3D regmap_read(soc->ds_regmap, soc->data->ds1[bank], &ds1); + if (ret) + return ret; + + ds0 =3D (ds0 >> offset) & 1; + ds1 =3D (ds1 >> offset) & 1; + if (soc->data->have_ds2) { + ret =3D regmap_read(soc->ds_regmap, soc->data->ds2[bank], &ds2); + if (ret) + return ret; + + ds2 =3D (ds2 >> offset) & 1; + ds =3D (ds2 << 2) | (ds1 << 1) | ds0; + } else { + ds =3D (ds0 << 1) | ds1; + } + + strength =3D amb_reg_to_drive_strength(soc, ds); + if (strength < 0) + return strength; + + *config =3D pinconf_to_config_packed(param, strength); + return 0; + + default: + return -EOPNOTSUPP; + } +} + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static void amb_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + u32 pull_en, pull_dir, ds0, ds1, ds2 =3D 0, ds; + u32 bank, offset; + int strength, ret; + + bank =3D PINID_TO_BANK(pin); + if (bank >=3D soc->data->nr_banks) { + seq_puts(s, " (no pinconf)"); + return; + } + + offset =3D PINID_TO_OFFSET(pin); + + ret =3D regmap_read(soc->pull_regmap, soc->data->pull_en[bank], + &pull_en); + if (ret) { + seq_puts(s, " pull: "); + return; + } + ret =3D regmap_read(soc->pull_regmap, soc->data->pull_dir[bank], + &pull_dir); + if (ret) { + seq_puts(s, " pull: "); + return; + } + pull_en =3D (pull_en >> offset) & 1; + pull_dir =3D (pull_dir >> offset) & 1; + seq_printf(s, " pull: %s,", + pull_en ? (pull_dir ? "up" : "down") : "disable"); + + ret =3D regmap_read(soc->ds_regmap, soc->data->ds0[bank], &ds0); + if (ret) { + seq_puts(s, " drive-strength: "); + return; + } + ret =3D regmap_read(soc->ds_regmap, soc->data->ds1[bank], &ds1); + if (ret) { + seq_puts(s, " drive-strength: "); + return; + } + ds0 =3D (ds0 >> offset) & 1; + ds1 =3D (ds1 >> offset) & 1; + if (soc->data->have_ds2) { + ret =3D regmap_read(soc->ds_regmap, soc->data->ds2[bank], &ds2); + if (ret) { + seq_puts(s, " drive-strength: "); + return; + } + ds2 =3D (ds2 >> offset) & 1; + ds =3D (ds2 << 2) | (ds1 << 1) | ds0; + } else { + ds =3D (ds0 << 1) | ds1; + } + + strength =3D amb_reg_to_drive_strength(soc, ds); + if (strength < 0) + seq_puts(s, " drive-strength: invalid"); + else + seq_printf(s, " drive-strength: %dmA", strength); +} +#endif + +/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code = */ +static const struct pinconf_ops amb_pinconf_ops =3D { + .is_generic =3D true, + .pin_config_get =3D amb_pinconf_get, + .pin_config_set =3D amb_pinconf_set, + .pin_config_group_set =3D amb_pinconf_group_set, +#if IS_ENABLED(CONFIG_DEBUG_FS) + .pin_config_dbg_show =3D amb_pinconf_dbg_show, +#endif +}; + +/* register the pinctrl interface with the pinctrl subsystem */ +static int amb_pinctrl_register(struct amb_pinctrl_soc_data *soc) +{ + struct pinctrl_pin_desc *pindesc; + struct pinctrl_desc *amb_pinctrl_desc; + unsigned int pin; + + /* dynamically populate the pin number and pin name for pindesc */ + pindesc =3D devm_kcalloc(soc->dev, soc->npins, sizeof(*pindesc), + GFP_KERNEL); + if (!pindesc) + return -ENOMEM; + + for (pin =3D 0; pin < soc->npins; pin++) { + pindesc[pin].number =3D pin; + pindesc[pin].name =3D devm_kasprintf(soc->dev, GFP_KERNEL, + "io%u", pin); + if (!pindesc[pin].name) + return -ENOMEM; + } + + amb_pinctrl_desc =3D devm_kzalloc(soc->dev, sizeof(*amb_pinctrl_desc), GF= P_KERNEL); + if (!amb_pinctrl_desc) + return -ENOMEM; + + amb_pinctrl_desc->name =3D dev_name(soc->dev); + amb_pinctrl_desc->pins =3D pindesc; + amb_pinctrl_desc->npins =3D soc->npins; + amb_pinctrl_desc->pctlops =3D &amb_pctrl_ops; + amb_pinctrl_desc->pmxops =3D &amb_pinmux_ops; + amb_pinctrl_desc->confops =3D &amb_pinconf_ops; + amb_pinctrl_desc->owner =3D THIS_MODULE; + + soc->pctl =3D devm_pinctrl_register(soc->dev, amb_pinctrl_desc, soc); + if (IS_ERR(soc->pctl)) { + dev_err(soc->dev, "could not register pinctrl driver\n"); + return PTR_ERR(soc->pctl); + } + + return 0; +} + +static int amb_pinctrl_probe(struct platform_device *pdev) +{ + struct amb_pinctrl_soc_data *soc; + struct device_node *np; + unsigned int *group_pins; + unsigned int group, group_pin; + size_t nr_group_pins =3D 0; + int rval; + + soc =3D devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL); + if (!soc) + return -ENOMEM; + + soc->dev =3D &pdev->dev; + soc->data =3D of_device_get_match_data(&pdev->dev); + if (!soc->data) + return dev_err_probe(&pdev->dev, -EINVAL, "missing soc data"); + if (!soc->data->nr_banks || + soc->data->nr_banks > AMBA_MAX_BANKS || + !soc->data->npins || + soc->data->npins > AMBA_MAX_PINS || + soc->data->nr_banks * 32 > soc->data->npins || + soc->data->clk_au_dedicated_pin >=3D soc->data->npins || + PINID_TO_BANK(soc->data->clk_au_dedicated_pin) >=3D AMBA_MAX_BANKS) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid bank or pin count\n"); + + soc->npins =3D soc->data->npins; + + np =3D pdev->dev.of_node; + soc->iomux_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(soc->iomux_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(soc->iomux_base), + "couldn't get iomux reg"); + + soc->ds_regmap =3D syscon_regmap_lookup_by_phandle(np, "ambarella,drive-s= trength-syscon"); + if (IS_ERR(soc->ds_regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(soc->ds_regmap), + "couldn't get drive-strength regmap"); + + soc->pull_regmap =3D syscon_regmap_lookup_by_phandle(np, "ambarella,pull-= syscon"); + if (IS_ERR(soc->pull_regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(soc->pull_regmap), + "couldn't get pull regmap"); + + soc->nr_groups =3D soc->data->nr_groups; + soc->functions =3D soc->data->functions; + soc->nr_functions =3D soc->data->nr_functions; + if (!soc->data->groups || !soc->nr_groups || + !soc->functions || !soc->nr_functions) + return dev_err_probe(&pdev->dev, -EINVAL, + "missing pin groups or functions\n"); + + soc->groups =3D devm_kcalloc(&pdev->dev, soc->nr_groups, + sizeof(*soc->groups), GFP_KERNEL); + if (!soc->groups) + return -ENOMEM; + + for (group =3D 0; group < soc->nr_groups; group++) { + const struct ambpin_group_desc *desc =3D + &soc->data->groups[group]; + + if (!desc->name || !desc->pinmux || !desc->num_pins) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid pin group %u\n", group); + + nr_group_pins +=3D desc->num_pins; + } + + group_pins =3D devm_kcalloc(&pdev->dev, nr_group_pins, + sizeof(*group_pins), GFP_KERNEL); + if (!group_pins) + return -ENOMEM; + + for (group =3D 0; group < soc->nr_groups; group++) { + const struct ambpin_group_desc *desc =3D + &soc->data->groups[group]; + struct ambpin_group *grp =3D &soc->groups[group]; + + grp->name =3D desc->name; + grp->pinmux =3D desc->pinmux; + grp->pins =3D group_pins; + grp->num_pins =3D desc->num_pins; + for (group_pin =3D 0; + group_pin < grp->num_pins; + group_pin++) { + u32 pinmux =3D grp->pinmux[group_pin]; + unsigned int pin =3D AMBA_PINMUX_TO_PIN(pinmux); + unsigned int alt =3D AMBA_PINMUX_TO_ALT(pinmux); + + if (pin >=3D soc->npins || alt > 7) + return dev_err_probe(&pdev->dev, -EINVAL, + "group %s has invalid pinmux %#x\n", + grp->name, pinmux); + + grp->pins[group_pin] =3D pin; + } + group_pins +=3D grp->num_pins; + } + + raw_spin_lock_init(&soc->lock); + + /* Mark all pins unavailable, then clear pins that exist. */ + bitmap_fill(soc->used, AMBA_MAX_PINS); + bitmap_clear(soc->used, 0, soc->data->nr_banks * 32); + clear_bit(soc->data->clk_au_dedicated_pin, soc->used); + + rval =3D amb_pinctrl_register(soc); + if (rval) + return dev_err_probe(&pdev->dev, rval, "pinctrl register failed!"); + + platform_set_drvdata(pdev, soc); + dev_info(&pdev->dev, "Ambarella pinctrl driver registered"); + + return 0; +} + +static int amb_pinctrl_suspend(struct device *dev) +{ + struct amb_pinctrl_soc_data *soc =3D dev_get_drvdata(dev); + u32 bank, dedicated =3D soc->data->clk_au_dedicated_pin; + + for (bank =3D 0; bank < soc->data->nr_banks; bank++) { + regmap_read(soc->pull_regmap, soc->data->pull_en[bank], + &soc->pm[bank].pull[0]); + regmap_read(soc->pull_regmap, soc->data->pull_dir[bank], + &soc->pm[bank].pull[1]); + + regmap_read(soc->ds_regmap, soc->data->ds0[bank], + &soc->pm[bank].ds[0]); + regmap_read(soc->ds_regmap, soc->data->ds1[bank], + &soc->pm[bank].ds[1]); + if (soc->data->have_ds2) + regmap_read(soc->ds_regmap, soc->data->ds2[bank], + &soc->pm[bank].ds[2]); + + amb_iomux_save_bank(soc, bank); + } + + if (dedicated >=3D soc->data->nr_banks * 32) + amb_iomux_save_bank(soc, PINID_TO_BANK(dedicated)); + + return 0; +} + +static int amb_pinctrl_resume(struct device *dev) +{ + struct amb_pinctrl_soc_data *soc =3D dev_get_drvdata(dev); + u32 bank, dedicated =3D soc->data->clk_au_dedicated_pin; + + for (bank =3D 0; bank < soc->data->nr_banks; bank++) + amb_iomux_restore_bank(soc, bank); + + if (dedicated >=3D soc->data->nr_banks * 32) + amb_iomux_restore_bank(soc, PINID_TO_BANK(dedicated)); + + /* Ensure restored IOMUX writes land before the commit strobe. */ + wmb(); + amb_iomux_commit(soc); + + for (bank =3D 0; bank < soc->data->nr_banks; bank++) { + regmap_write(soc->ds_regmap, soc->data->ds0[bank], + soc->pm[bank].ds[0]); + regmap_write(soc->ds_regmap, soc->data->ds1[bank], + soc->pm[bank].ds[1]); + if (soc->data->have_ds2) + regmap_write(soc->ds_regmap, soc->data->ds2[bank], + soc->pm[bank].ds[2]); + + regmap_write(soc->pull_regmap, soc->data->pull_dir[bank], + soc->pm[bank].pull[1]); + regmap_write(soc->pull_regmap, soc->data->pull_en[bank], + soc->pm[bank].pull[0]); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(amb_pinctrl_pm_ops, + amb_pinctrl_suspend, + amb_pinctrl_resume); + +static const struct of_device_id amb_pinctrl_dt_match[] =3D { + { + .compatible =3D "ambarella,cv75-pinctrl", + .data =3D &ambarella_cv75_pinctrl_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, amb_pinctrl_dt_match); + +static struct platform_driver amb_pinctrl_driver =3D { + .probe =3D amb_pinctrl_probe, + .driver =3D { + .name =3D "ambarella-pinctrl", + .of_match_table =3D of_match_ptr(amb_pinctrl_dt_match), + .pm =3D pm_sleep_ptr(&amb_pinctrl_pm_ops), + }, +}; + +static int __init amb_pinctrl_drv_register(void) +{ + return platform_driver_register(&amb_pinctrl_driver); +} +arch_initcall(amb_pinctrl_drv_register); + +MODULE_AUTHOR("Cao Rongrong "); +MODULE_DESCRIPTION("Ambarella SoC pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-ambarella.h b/drivers/pinctrl/pinctrl-= ambarella.h new file mode 100644 index 000000000000..094639627131 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ambarella.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Ambarella pinctrl common data definitions + * + * Copyright (C) 2012-2026, Ambarella, Inc. + */ + +#ifndef _PINCTRL_AMBARELLA_H +#define _PINCTRL_AMBARELLA_H + +#include + +#define AMBA_MAX_BANKS 8 + +#define AMBA_PINMUX(pin, alt) (((alt) << 12) | (pin)) +#define AMBA_PINMUX_TO_PIN(mux) ((mux) & 0xfff) +#define AMBA_PINMUX_TO_ALT(mux) (((mux) >> 12) & 0xf) + +struct ambpin_group_desc { + const char *name; + const u32 *pinmux; + unsigned int num_pins; +}; + +struct ambpin_function { + const char *name; + const char * const *groups; + unsigned int num_groups; +}; + +struct amb_pinctrl_data { + unsigned int ds0[AMBA_MAX_BANKS]; + unsigned int ds1[AMBA_MAX_BANKS]; + unsigned int ds2[AMBA_MAX_BANKS]; + unsigned int pull_en[AMBA_MAX_BANKS]; + unsigned int pull_dir[AMBA_MAX_BANKS]; + bool have_ds2; + u32 hsm_domain_id; + u32 clk_au_dedicated_pin; + unsigned int nr_banks; + unsigned int npins; + const struct ambpin_group_desc *groups; + unsigned int nr_groups; + const struct ambpin_function *functions; + unsigned int nr_functions; +}; + +extern const struct amb_pinctrl_data ambarella_cv75_pinctrl_data; + +#endif /* _PINCTRL_AMBARELLA_H */ --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 816AD45FFDF; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=scSGyEvFm7i6kVIaxkcEI3dgaWENFoIzRj25ZzaNj1HVb+0uDXWY9P0o/9czsMEzwIKxMhFjCBGfqgzRlBcK2fgz4BY4yyaIXT4KlKr9iH71VQatT13icml+m7TWg6Yht2a1j8HAUkCGIifCYpIGHkslX7Wk2f+Tt9Ta+AJlNUw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=i+FUfbs5rlgTTWag8fNMv7qbV7TUuvFcadcDdAMLsh8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fktWPrufipTqHq1iKhKUxtiOB/iVfKP5Ap6V4jUsPjzL/+sXFCkbgle7ldHNd3OLy3I8M03m11q61Kimx8tUUozWehYEQGzVh2hWYHiJ+CkJMPJ3+5g2UNQ0l6CvxMr3VrdxdA3UnOi1//JOg6NroGIHzOq+lg86YENvnVy8wGg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DpBJ6ntA; 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="DpBJ6ntA" Received: by smtp.kernel.org (Postfix) with ESMTPS id 590BFC2BCFF; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=i+FUfbs5rlgTTWag8fNMv7qbV7TUuvFcadcDdAMLsh8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=DpBJ6ntAzZHKzeV3hW1188boj/B4FgPnWW9qPkirb5cjsegT0Fwywn61qRcR3t2F8 e7XiAwMvmWMWf9QojojIiMBwMNh7d3l9epmyWcaFCRI8Q6HEWuJSj2UAFUHucK0B97 P+pI4bG/T0Wl3KDWQ85/rdvpNO7Tos2rN2pnLktIR8UAxQhC2BItx333ipYBXWVMuF R+gSWX5UP0bjpwWmX5LiZD3+gZEdYz0Kx626gizkriL5gP66DRpH31H4oRasYvIrG8 ir6UkE3jP69+vUjEgCfkU4Oe5/QPTnpszIHnq5ek3fEegZSuF9uC/aHAUwIBLOiLrD dTQEnPNCKnzMg== 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 4476DC5DF70; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:24 +0800 Subject: [PATCH v5 10/12] serial: 8250: add Ambarella UART 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: <20260818-cv75-v5-v5-10-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=10410; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=EOzZgfZ/lCbDgs1qmo/SpdoPp8b/Dsi10/sjSRwB0l0=; b=Pvl7qAMl+Y0rFBUMsE7GO1ptJ+7qw4/XeUZLnJawQLDeHW2XKJyKZ7n4Yw1E/5evSJJNkF32Z 4U+EWeqPmnzCzC7sqI3POCqNvmZhbf+aYMJ553emjMQnzmk0KlGvm4G X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Add an 8250 platform driver for Ambarella CV75 instead of claiming snps,dw-apb-uart compatibility. Signed-off-by: Long Zhao --- drivers/tty/serial/8250/8250_ambarella.c | 312 +++++++++++++++++++++++++++= ++++ drivers/tty/serial/8250/Kconfig | 9 + drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 322 insertions(+) diff --git a/drivers/tty/serial/8250/8250_ambarella.c b/drivers/tty/serial/= 8250/8250_ambarella.c new file mode 100644 index 000000000000..951355e19fa2 --- /dev/null +++ b/drivers/tty/serial/8250/8250_ambarella.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Serial port driver for Ambarella UART + * + * Copyright (C) 2026 Ambarella, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +#define AMBARELLA_UART_IER_ETOI BIT(5) +#define AMBARELLA_UART_USR 0x1f +#define AMBARELLA_UART_USR_BUSY BIT(0) +#define AMBARELLA_UART_IIR_IID GENMASK(3, 0) +#define AMBARELLA_UART_IIR_STATUS GENMASK(5, 0) + +struct ambarella_uart_soc_data { + unsigned int fifo_size; +}; + +struct ambarella_uart { + int line; + struct clk *clk; + const struct ambarella_uart_soc_data *soc_data; + bool in_idle; +}; + +static void ambarella_idle_exit(struct uart_port *p) +{ + struct ambarella_uart *data =3D p->private_data; + struct uart_8250_port *up =3D up_to_u8250p(p); + + if (up->capabilities & UART_CAP_FIFO) + writel(up->fcr, p->membase + (UART_FCR << p->regshift)); + writel(up->mcr, p->membase + (UART_MCR << p->regshift)); + writel(up->ier, p->membase + (UART_IER << p->regshift)); + + data->in_idle =3D false; +} + +static int ambarella_idle_enter(struct uart_port *p) +{ + struct ambarella_uart *data =3D p->private_data; + struct uart_8250_port *up =3D up_to_u8250p(p); + unsigned int status; + int retries =3D 4; + + lockdep_assert_held_once(&p->lock); + + data->in_idle =3D true; + writel(0, p->membase + (UART_IER << p->regshift)); + + serial8250_fifo_wait_for_lsr_thre(up, p->fifosize); + ndelay(p->frame_time); + writel(up->mcr | UART_MCR_LOOP, + p->membase + (UART_MCR << p->regshift)); + + do { + serial8250_clear_fifos(up); + if (!(readl(p->membase + + (AMBARELLA_UART_USR << p->regshift)) & + AMBARELLA_UART_USR_BUSY)) + break; + ndelay(p->frame_time); + } while (--retries); + + status =3D serial_lsr_in(up); + if (status & UART_LSR_DR) { + readl(p->membase + (UART_RX << p->regshift)); + up->lsr_saved_flags =3D 0; + } + + if (readl(p->membase + (AMBARELLA_UART_USR << p->regshift)) & + AMBARELLA_UART_USR_BUSY) { + ambarella_idle_exit(p); + return -EBUSY; + } + + return 0; +} + +static void ambarella_serial_out(struct uart_port *p, unsigned int offset, + u32 value) +{ + struct ambarella_uart *data =3D p->private_data; + u32 lcr; + + if (offset !=3D UART_LCR || !data || data->in_idle) { + writel(value, p->membase + (offset << p->regshift)); + return; + } + + lcr =3D readl(p->membase + (UART_LCR << p->regshift)); + if (lcr =3D=3D value) + return; + + writel(value, p->membase + (UART_LCR << p->regshift)); + lcr =3D readl(p->membase + (UART_LCR << p->regshift)); + if ((lcr & ~UART_LCR_SPAR) =3D=3D (value & ~UART_LCR_SPAR)) + return; + + if (ambarella_idle_enter(p)) + return; + + writel(value, p->membase + (UART_LCR << p->regshift)); + ambarella_idle_exit(p); +} + +static u32 ambarella_serial_in(struct uart_port *p, unsigned int offset) +{ + return readl(p->membase + (offset << p->regshift)); +} + +static int ambarella_handle_irq(struct uart_port *p) +{ + struct uart_8250_port *up =3D up_to_u8250p(p); + unsigned int iir =3D serial_port_in(p, UART_IIR); + bool rx_timeout =3D (iir & AMBARELLA_UART_IIR_STATUS) =3D=3D + UART_IIR_RX_TIMEOUT; + unsigned int status; + + guard(uart_port_lock_check_sysrq_irqsave)(p); + + switch (FIELD_GET(AMBARELLA_UART_IIR_IID, iir)) { + case UART_IIR_NO_INT: + return 0; + case UART_IIR_BUSY: + serial_port_in(p, AMBARELLA_UART_USR); + return 1; + } + + if (rx_timeout) { + status =3D serial_lsr_in(up); + if (!(status & (UART_LSR_DR | UART_LSR_BI))) + serial_port_in(p, UART_RX); + } + + serial8250_handle_irq_locked(p, iir); + return 1; +} + +static void ambarella_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + struct uart_8250_port *up =3D up_to_u8250p(p); + + if (ambarella_idle_enter(p)) + return; + + serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB); + if (serial_port_in(p, UART_LCR) & UART_LCR_DLAB) + serial_dl_write(up, quot); + serial_port_out(p, UART_LCR, up->lcr); + + ambarella_idle_exit(p); +} + +static int ambarella_startup(struct uart_port *port) +{ + struct uart_8250_port *up =3D up_to_u8250p(port); + int ret; + + ret =3D serial8250_do_startup(port); + if (ret) + return ret; + + up->ier |=3D AMBARELLA_UART_IER_ETOI; + serial_port_out(port, UART_IER, up->ier); + + return 0; +} + +static int ambarella_uart_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct ambarella_uart *data; + struct uart_8250_port uart =3D {}; + struct resource *regs; + u32 reg_io_width =3D 4; + u32 reg_shift =3D 2; + int irq, ret; + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + regs =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return dev_err_probe(dev, -EINVAL, "missing registers\n"); + + data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->soc_data =3D device_get_match_data(dev); + if (!data->soc_data) + return -EINVAL; + + data->clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(data->clk)) + return dev_err_probe(dev, PTR_ERR(data->clk), + "unable to get clock\n"); + + uart.port.dev =3D dev; + uart.port.mapbase =3D regs->start; + uart.port.mapsize =3D resource_size(regs); + uart.port.membase =3D devm_ioremap(dev, regs->start, + resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + + uart.port.irq =3D irq; + uart.port.type =3D PORT_16550A; + uart.port.flags =3D UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; + uart.port.startup =3D ambarella_startup; + uart.port.handle_irq =3D ambarella_handle_irq; + uart.port.set_divisor =3D ambarella_set_divisor; + uart.port.uartclk =3D clk_get_rate(data->clk); + if (!uart.port.uartclk) + return dev_err_probe(dev, -EINVAL, "clock rate not defined\n"); + + uart.port.fifosize =3D data->soc_data->fifo_size; + uart.port.private_data =3D data; + uart.capabilities =3D UART_CAP_FIFO | UART_CAP_NOTEMT | UART_CAP_AFE; + + of_property_read_u32(dev->of_node, "reg-shift", ®_shift); + of_property_read_u32(dev->of_node, "reg-io-width", ®_io_width); + uart.port.regshift =3D reg_shift; + + switch (reg_io_width) { + case 4: + uart.port.iotype =3D UPIO_MEM32; + uart.port.serial_in =3D ambarella_serial_in; + uart.port.serial_out =3D ambarella_serial_out; + break; + default: + return dev_err_probe(dev, -EINVAL, + "unsupported reg-io-width %u\n", + reg_io_width); + } + + ret =3D serial8250_register_8250_port(&uart); + if (ret < 0) + return dev_err_probe(dev, ret, "unable to register 8250 port\n"); + + data->line =3D ret; + platform_set_drvdata(pdev, data); + return 0; +} + +static void ambarella_uart_remove(struct platform_device *pdev) +{ + struct ambarella_uart *data =3D platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); +} + +static const struct ambarella_uart_soc_data cv75_uart_data =3D { + .fifo_size =3D 64, +}; + +static const struct of_device_id ambarella_uart_dt_ids[] =3D { + { + .compatible =3D "ambarella,cv75-uart", + .data =3D &cv75_uart_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ambarella_uart_dt_ids); + +static struct platform_driver ambarella_uart_platform_driver =3D { + .driver =3D { + .name =3D "8250-ambarella", + .of_match_table =3D ambarella_uart_dt_ids, + }, + .probe =3D ambarella_uart_probe, + .remove =3D ambarella_uart_remove, +}; + +module_platform_driver(ambarella_uart_platform_driver); + +static int __init ambarella_early_setup(struct earlycon_device *device, + const char *options) +{ + struct uart_port *port =3D &device->port; + + if (!port->membase) + return -ENODEV; + + port->iotype =3D UPIO_MEM32; + port->regshift =3D 2; + port->serial_in =3D ambarella_serial_in; + port->serial_out =3D ambarella_serial_out; + + return early_serial8250_setup(device, options); +} + +OF_EARLYCON_DECLARE(ambarella, "ambarella,cv75-uart", ambarella_early_setu= p); + +MODULE_IMPORT_NS("SERIAL_8250"); +MODULE_AUTHOR("Long Zhao "); +MODULE_DESCRIPTION("Ambarella UART driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kcon= fig index fc3e58d62233..523c55be3227 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -337,6 +337,15 @@ config SERIAL_8250_ACORN system, say Y to this option. The driver can handle 1, 2, or 3 port cards. If unsure, say N. =20 +config SERIAL_8250_AMBARELLA + tristate "Ambarella UART support" + depends on SERIAL_8250 && HAVE_CLK + depends on ARCH_AMBARELLA || COMPILE_TEST + default y if ARCH_AMBARELLA + help + Support for the on-chip UART found on Ambarella SoCs. + If unsure, say N. + config SERIAL_8250_BCM2835AUX tristate "BCM2835 auxiliar mini UART support" depends on ARCH_BCM2835 || COMPILE_TEST diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Mak= efile index 6d21402b4435..601d9e2589fe 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SERIAL_8250_CONSOLE) +=3D 8250_early.o =20 obj-$(CONFIG_SERIAL_8250_ACCENT) +=3D 8250_accent.o obj-$(CONFIG_SERIAL_8250_ACORN) +=3D 8250_acorn.o +obj-$(CONFIG_SERIAL_8250_AMBARELLA) +=3D 8250_ambarella.o obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) +=3D 8250_aspeed_vuart.o obj-$(CONFIG_SERIAL_8250_BCM2835AUX) +=3D 8250_bcm2835aux.o obj-$(CONFIG_SERIAL_8250_BCM7271) +=3D 8250_bcm7271.o --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 94738463B74; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=oC2ZJp3spczaV6zH+u6kteRCXe8SP4tU5ggQD7q8yn5L9iJS1Uy+d0o97wd7mHjwAzUZxPOwvYCLrOxWH631bfZKBC2brr+GdeWmvgP3w6+9ycipIjxjmoqXjNc2fE7lVuqewu2K3J8LYBf6kHF9GLTE0JR7YGIo0Nuf0ghjVGs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=tICu1kyhW6ciLBQrYgOgEDijSYbYwL7txSJb0cxx7wI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=foS4zzOroxMTcSYOzNZuqAvcVy+ukClRrIrt339KdLwEqRT3KKWxA9R9HSf9fNUdxqU+ULmzIJ7QgeJUmEayLsX5e7lqFjbJ6L363r7CksKzllMraBMY5N5VEnk+7pUoew8IDwf7nEIIeuKEM2LBlJgIw+hyHF1Ce9qWLjCdBGY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XCggO56r; 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="XCggO56r" Received: by smtp.kernel.org (Postfix) with ESMTPS id 716A7C2BCFA; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=tICu1kyhW6ciLBQrYgOgEDijSYbYwL7txSJb0cxx7wI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=XCggO56rLefYkLZxt338eDp+nxd6r27UQn+zgjAojugWeUxI6ASTSBtMR2sGs1BBm 441RWJMBMxKCkjM2loHm7n3mYTRdpVV/2FHOlB9YMkuGDR4++iY6lhtl9FNJ2+Fi/0 Iq5Gh0pyYj1x1PgMs0ZdC1YjoAd/4o3147B+hmhJVqkiooQ4q8lUsAbKmkIjxzLgP6 H3BgyY7WhQRn1d8aSzg/LQIrz749aHD4nFXctbh66aWdPPQs4R+LEO41+oY/JGm5cX olfIEugGWijnwXLDwVHhD04FOJp3mOCiHaAIcxnvpPv8Qkbef0MIL+T6goIPesqTaL ejePVEU9ntY4g== 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 5D750C5DF81; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:25 +0800 Subject: [PATCH v5 11/12] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT 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: <20260818-cv75-v5-v5-11-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=8330; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=IpNrjrrLhNL6j9beNqn3g0g/0+e1YQ5b0+ZAZpgVVg4=; b=E6xncZh3d3ihAc1k6GLnYxEVrI56nkcf430XoEdkWisRIUbRsKMs8ow4ecJllXPgfHTdTQUak 15feqe7gCC2C9uQ0cdOHuNkQkh0xCGeD03SM1HN5M0m+qAMS9IdA9ux X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Enable ARCH_AMBARELLA and add a minimal CV75 SoC / EVK device tree for console bring-up with the RCT clocks, UART, pinctrl and GPIO banks. Signed-off-by: Long Zhao --- arch/arm64/Kconfig.platforms | 8 ++ arch/arm64/boot/dts/Makefile | 1 + arch/arm64/boot/dts/ambarella/Makefile | 3 + arch/arm64/boot/dts/ambarella/cv75-evk.dts | 30 +++++ arch/arm64/boot/dts/ambarella/cv75.dtsi | 176 +++++++++++++++++++++++++= ++++ arch/arm64/configs/defconfig | 2 + 6 files changed, 220 insertions(+) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index d2acfac73003..cb05eff267a8 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -26,6 +26,14 @@ config ARCH_SUNXI help This enables support for Allwinner sunxi based SoCs like the A64. =20 +config ARCH_AMBARELLA + bool "Ambarella SoC family" + select ARM_PSCI + select HAVE_ARM_ARCH_TIMER + select PINCTRL + help + This enables support for the ARM64 based Ambarella SoCs like CV75. + config ARCH_ALPINE bool "Annapurna Labs Alpine platform" select ALPINE_MSI if PCI diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index fc726b215f12..f1709eb5d915 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -4,6 +4,7 @@ subdir-y +=3D airoha subdir-y +=3D allwinner subdir-y +=3D altera subdir-y +=3D amazon +subdir-y +=3D ambarella subdir-y +=3D amd subdir-y +=3D amlogic subdir-y +=3D apm diff --git a/arch/arm64/boot/dts/ambarella/Makefile b/arch/arm64/boot/dts/a= mbarella/Makefile new file mode 100644 index 000000000000..ddca3d7b18cc --- /dev/null +++ b/arch/arm64/boot/dts/ambarella/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +dtb-$(CONFIG_ARCH_AMBARELLA) +=3D cv75-evk.dtb diff --git a/arch/arm64/boot/dts/ambarella/cv75-evk.dts b/arch/arm64/boot/d= ts/ambarella/cv75-evk.dts new file mode 100644 index 000000000000..42a0fe24b83b --- /dev/null +++ b/arch/arm64/boot/dts/ambarella/cv75-evk.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Ambarella CV75 EVK board + */ + +/dts-v1/; + +#include "cv75.dtsi" + +/ { + model =3D "Ambarella CV75 EVK Board"; + compatible =3D "ambarella,cv75-evk", "ambarella,cv75"; + + aliases { + serial0 =3D &uart0; + }; + + chosen { + stdout-path =3D &uart0; + }; + + memory@200000 { + device_type =3D "memory"; + reg =3D <0x0 0x00200000 0x0 0x07e00000>; + }; +}; + +&uart0 { + status =3D "okay"; +}; diff --git a/arch/arm64/boot/dts/ambarella/cv75.dtsi b/arch/arm64/boot/dts/= ambarella/cv75.dtsi new file mode 100644 index 000000000000..3b7948954968 --- /dev/null +++ b/arch/arm64/boot/dts/ambarella/cv75.dtsi @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Ambarella CV75 SoC + * + * Boot peripheral: UART0 console. + * Clocks: a single ambarella,cv75-rct provider. + */ + +#include +#include + +/ { + compatible =3D "ambarella,cv75"; + interrupt-parent =3D <&gic>; + #address-cells =3D <2>; + #size-cells =3D <2>; + + cpus { + #address-cells =3D <1>; + #size-cells =3D <0>; + + cpu@0 { + compatible =3D "arm,cortex-a76"; + device_type =3D "cpu"; + reg =3D <0x000>; + enable-method =3D "psci"; + }; + + cpu@1 { + compatible =3D "arm,cortex-a76"; + device_type =3D "cpu"; + reg =3D <0x100>; + enable-method =3D "psci"; + }; + }; + + osc: oscillator { + compatible =3D "fixed-clock"; + #clock-cells =3D <0>; + clock-frequency =3D <24000000>; + clock-output-names =3D "osc"; + }; + + psci { + compatible =3D "arm,psci-0.2"; + method =3D "smc"; + }; + + soc { + compatible =3D "simple-bus"; + #address-cells =3D <2>; + #size-cells =3D <2>; + ranges; + + ahb@ffe0000000 { + compatible =3D "simple-bus"; + reg =3D <0xff 0xe0000000 0x0 0x01000000>; + ranges =3D <0xe0000000 0xff 0xe0000000 0x01000000>; + #address-cells =3D <1>; + #size-cells =3D <1>; + + s_scratchpad_syscon: scratchpad@e002e000 { + compatible =3D "ambarella,cv75-sec-scratchpad", "syscon"; + reg =3D <0xe002e000 0x1000>; + }; + }; + + apb@ffe4000000 { + compatible =3D "simple-bus"; + reg =3D <0xff 0xe4000000 0x0 0x01000000>; + ranges =3D <0xe4000000 0xff 0xe4000000 0x01000000>; + #address-cells =3D <1>; + #size-cells =3D <1>; + + uart0: serial@e4000000 { + compatible =3D "ambarella,cv75-uart"; + reg =3D <0xe4000000 0x1000>; + clocks =3D <&rct CV75_GCLK_UART0>; + interrupts =3D ; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&uart0_pins>; + reg-io-width =3D <4>; + reg-shift =3D <2>; + + status =3D "disabled"; + }; + + pinctrl: pinctrl@e4010000 { + compatible =3D "ambarella,cv75-pinctrl"; + reg =3D <0xe4010000 0x1000>; + ambarella,drive-strength-syscon =3D <&rct>; + ambarella,pull-syscon =3D <&s_scratchpad_syscon>; + + uart0_pins: uart0-pins { + function =3D "uart0"; + groups =3D "uart0"; + }; + }; + + gpio0: gpio@e4013000 { + compatible =3D "ambarella,cv75-gpio", "arm,primecell"; + reg =3D <0xe4013000 0x1000>; + clocks =3D <&rct CV75_GCLK_APB>; + clock-names =3D "apb_pclk"; + interrupts =3D ; + gpio-controller; + #gpio-cells =3D <2>; + gpio-ranges =3D <&pinctrl 0 0 32>; + interrupt-controller; + #interrupt-cells =3D <2>; + arm,primecell-periphid =3D <0x00000061>; + }; + + gpio1: gpio@e4014000 { + compatible =3D "ambarella,cv75-gpio", "arm,primecell"; + reg =3D <0xe4014000 0x1000>; + clocks =3D <&rct CV75_GCLK_APB>; + clock-names =3D "apb_pclk"; + interrupts =3D ; + gpio-controller; + #gpio-cells =3D <2>; + gpio-ranges =3D <&pinctrl 0 32 32>; + interrupt-controller; + #interrupt-cells =3D <2>; + arm,primecell-periphid =3D <0x00000061>; + }; + + gpio2: gpio@e4015000 { + compatible =3D "ambarella,cv75-gpio", "arm,primecell"; + reg =3D <0xe4015000 0x1000>; + clocks =3D <&rct CV75_GCLK_APB>; + clock-names =3D "apb_pclk"; + interrupts =3D ; + gpio-controller; + #gpio-cells =3D <2>; + gpio-ranges =3D <&pinctrl 0 64 32>; + interrupt-controller; + #interrupt-cells =3D <2>; + arm,primecell-periphid =3D <0x00000061>; + }; + }; + + rct: clock-controller@ffed080000 { + compatible =3D "ambarella,cv75-rct", "syscon"; + reg =3D <0xff 0xed080000 0x0 0x1000>; + clocks =3D <&osc>; + clock-names =3D "osc"; + #clock-cells =3D <1>; + assigned-clocks =3D <&rct CV75_GCLK_UART0>; + assigned-clock-parents =3D <&osc>; + assigned-clock-rates =3D <24000000>; + }; + + gic: interrupt-controller@fff0101000 { + compatible =3D "arm,gic-400"; + reg =3D <0xff 0xf0101000 0x0 0x1000>, + <0xff 0xf0102000 0x0 0x2000>, + <0xff 0xf0104000 0x0 0x2000>, + <0xff 0xf0106000 0x0 0x2000>; + interrupt-controller; + #interrupt-cells =3D <3>; + #address-cells =3D <0>; + interrupts =3D ; + }; + }; + + timer { + compatible =3D "arm,armv8-timer"; + interrupts =3D , + , + , + , + ; + }; +}; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index ad3bd3d9507b..ae5bcc6c9fc7 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -36,6 +36,7 @@ CONFIG_CRASH_DUMP=3Dy CONFIG_ARCH_ACTIONS=3Dy CONFIG_ARCH_AIROHA=3Dy CONFIG_ARCH_SUNXI=3Dy +CONFIG_ARCH_AMBARELLA=3Dy CONFIG_ARCH_ALPINE=3Dy CONFIG_ARCH_APPLE=3Dy CONFIG_ARCH_ARTPEC=3Dy @@ -560,6 +561,7 @@ CONFIG_SERIAL_8250_CONSOLE=3Dy CONFIG_SERIAL_8250_NR_UARTS=3D8 CONFIG_SERIAL_8250_EXTENDED=3Dy CONFIG_SERIAL_8250_SHARE_IRQ=3Dy +CONFIG_SERIAL_8250_AMBARELLA=3Dy CONFIG_SERIAL_8250_BCM2835AUX=3Dy CONFIG_SERIAL_8250_DW=3Dy CONFIG_SERIAL_8250_EM=3Dy --=20 2.34.1 From nobody Mon Sep 28 19:23:44 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 B59224582C3; Tue, 18 Aug 2026 10:32:14 +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=1787049134; cv=none; b=fChP88hyykiK7WHdqPWqCN41u2qdR3O1OK/RqkphFyitLAF5ZREq1zHiYQdvRgjkRAWWOlfJ5DlKh5bjqn+RlgYzLwNny83p4t8FUWAyoe6eS88XBDWx0pjltu9KzJrURYZCmJ9+cN/4MPXU4FzNdq0RLHVBDy1Kdy7F9XeqcGE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787049134; c=relaxed/simple; bh=Bb36BfGeVG00O5acHqEedqkrcVnPEN+C2tMnqCVjfps=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=o4sIWGgTpVETvNTwodqQgv1LzhteZpmpWTFHgE4L8sJYB5WkwQXK7BmXXK42m0iQC8pDObG+ECLP9KcJhY5b0SCDtvdzirAxMQoIGlQ1dSu83moDMciESD59q1xCqrPB/M9jHz6ntTbhDq0F39Ur5rKzkIS4hKgBzlOzkGcC/eo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cxEGbg9a; 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="cxEGbg9a" Received: by smtp.kernel.org (Postfix) with ESMTPS id 91965C2BD00; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1787049134; bh=Bb36BfGeVG00O5acHqEedqkrcVnPEN+C2tMnqCVjfps=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=cxEGbg9akGWhslNkUnpvGOYgjYFvlG8RUICRl72778pTxnW3tnuZxyB4KoSOaeWRb qiKkjCk6xyzajQt0crSTGwE7HfoNwmhCn2QF/yPf6OZcuJ0R0ry6mwGx9y9RspM+ow B3lL4rZxD0Tmq/e4iqwV2QupyHpLlTQ0rghEjdVtNWPJM70+5vr9vsM9P4FhwvsmSj vsaJrHHybEGw5cs5KZ1jBHj9Gf+KPe91JusBO+zRl6PcKIlKYGxX7yaHZKQlKdRvrl H5XSv+eGMA6zYbMVBG7GUE1leWbYOEUcfz1YMJwKLcY5utPuFDWhx1pbB8U+5Yo1gL 1lQYTelHwxd3A== 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 7B3B0C5DF70; Tue, 18 Aug 2026 10:32:14 +0000 (UTC) From: Long Zhao via B4 Relay Date: Tue, 18 Aug 2026 18:31:26 +0800 Subject: [PATCH v5 12/12] MAINTAINERS: add ARM/AMBARELLA SoC support 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: <20260818-cv75-v5-v5-12-7bbb12f0360f@ambarella.com> References: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> In-Reply-To: <20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com> To: Arnd Bergmann , Krzysztof Kozlowski , Alexandre Belloni , soc@lists.linux.dev, linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Turquette , Stephen Boyd , Linus Walleij , Bartosz Golaszewski , Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko , Catalin Marinas , Will Deacon , devicetree@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney , Lee Jones , mfd@lists.linux.dev, Long Zhao , Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787049131; l=1312; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=qRk4o9fqrbJ/RTe53ZqQZzJC7nitoycd8NIbTSpQATc=; b=22jZKHSk4JLzNo9O8aGxR1ZHXYovNN3EMRSWAxCkRINCuJDf+fH7BEi0M1am6EfDNoaT9CyzQ GaOtRr7cdbOCbblt/GRQZFAws6QRfB1pNBOAALqZOdSrlL4fz1xTMEJ X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Add a maintainer entry covering Ambarella CV75 bindings, DTS and related drivers. Signed-off-by: Long Zhao --- MAINTAINERS | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 803b60ad628f..4352a2dc1e3d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2502,6 +2502,22 @@ F: drivers/clocksource/asm9260_timer.c F: drivers/rtc/rtc-asm9260.c F: drivers/watchdog/asm9260_wdt.c =20 +ARM/AMBARELLA SOC SUPPORT +M: Long Zhao +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: devicetree@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/arm/ambarella.yaml +F: Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yaml +F: Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.yaml +F: Documentation/devicetree/bindings/serial/ambarella,cv75-uart.yaml +F: arch/arm64/boot/dts/ambarella/ +F: drivers/clk/ambarella/ +F: drivers/pinctrl/pinctrl-ambarella* +F: drivers/tty/serial/8250/8250_ambarella.c +F: include/dt-bindings/clock/ambarella,cv75-rct.h +N: ambarella + ARM/AMD PENSANDO ARM64 ARCHITECTURE M: Brad Larson L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) --=20 2.34.1