* [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up
@ 2026-09-21 4:23 Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 01/18] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
` (18 more replies)
0 siblings, 19 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
This series adds minimal Ambarella CV75 support for early bring-up with
a serial console: DT bindings, RCT clocks, pinctrl, PL061 GPIO via
gpio-regmap, 8250_dw UART quirks, ARCH_AMBARELLA, CV75 EVK DT, and
MAINTAINERS.
This is a single unified series. Please apply via the SoC
tree; subsystem maintainers are Cc'd for their pieces.
GPIO data path uses gpio-regmap with two layouts (ARM PrimeCell and
Ambarella). IRQ stays a custom PL061 irqchip: a linear domain is
created after gpio_regmap_register(), attached with
gpiochip_irqchip_add_domain() via gpio_regmap_get_chip(), and the
chained handler uses gpio_chip as chip data. gpio-regmap girq and
regmap-irq are not used.
Verified with:
- scripts/checkpatch.pl --strict (0 errors)
- make dt_binding_check DT_SCHEMA_FILES=ambarella:pl061-gpio.yaml:syscon.yaml:snps-dw-apb-uart.yaml
- make CHECK_DTBS=y ambarella/cv75-evk.dtb
- arm64 build of new drivers/DTS
- CV75 EVK: console via 8250_dw (dw-apb-uart); GPIO edge IRQ
(gpio-hammer / gpio-event-mon) with CONFIG_PROVE_LOCKING after
use_raw_spinlock
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
Changes in v8:
- gpio: split v7 10/15 into 10/18 MMIO to regmap, 11/18 IRQ_TYPE_*
helpers, 12/18 cleanup.h guard(), 13/18 gpio-regmap + custom
irqchip, 14/18 Ambarella layout (Andy)
- gpio: keep gpio_regmap_get_chip(); drop the irq_domain attach
change in gpio-regmap (Andy)
- gpio-regmap: skip the pre-direction data write when write_data_after_dir
is set (Linus); still ignore gpio_regmap_set() returns (Andy)
- gpio: use_raw_spinlock so irq_ack() can run under the irq
descriptor lock (PROVE_LOCKING on CV75); irq_set_parent() for wake
- gpio: drop errno.h; -ENODATA; for_each_set_bit in PM; split virq
assignment; chained handler checks regmap_read (Andy)
- pinctrl: 15/18 PINCTRL_PINGROUP + per-pin alts; header uses
forward declarations; regmap_assign_bits / __assign_bit;
-ENOTSUPP; -ENODATA; devm_kasprintf_strarray (Andy)
- dt-bindings: gpio: 05/18 move allOf after required; explain why
CV75 is PrimeCell GPIO but not an arm,pl061 fallback, and why a
fixed arm,primecell-periphid is required (Krzysztof)
- serial: 16/18 keep snps,dw-apb-uart first; Andy and Ilpo R-b
- clk: drop mod_devicetable.h; use u16_fract (Andy, Uwe)
- collect lore tags on unchanged bindings (Linus, Krzysztof)
Link to v7: https://patch.msgid.link/20260915-cv75-v5-v7-0-3297d3fbc9c0@ambarella.com
Changes in v7:
- gpio: 10/15 convert ARM PL061 to gpio-regmap; 11/15 add Ambarella
layout with a second gpio_regmap config (Andy)
- gpio: 10/15 drop gpio-regmap girq; custom irqchip with a linear
domain, gpio_chip chip data, and a chained handler (Andy)
- gpio-regmap: 08/15 write_data_after_dir; 09/15 gpio_regmap_get_chip()
and quirk kerneldoc (Andy)
- dt-bindings: gpio: 05/15 $ref arm/primecell.yaml and
unevaluatedProperties (Rob)
- clk: fold the RCT driver into a single clk-cv75.c (Jerome)
- serial: 8250_dw startup only updates the up->ier shadow (Ilpo)
- collect lore tags on unchanged patches (Linus Reviewed-by; Krzysztof
Acked-by on the UART binding)
Link to v6:
https://lore.kernel.org/r/20260904-cv75-v5-v6-0-e918514cb3b1@ambarella.com
Changes in v6:
- gpio: convert gpio-pl061 data path to gpio-regmap; keep PL061 irqchip
(Andy, Linus). Add write_data_after_dir + girq helpers to gpio-regmap.
Ambarella layout uses JEP106 periphid 0x000e8061; no AFSEL clearing in
the GPIO driver; Ambarella skips unverified GPIO PM save/restore
- serial: restore 8250_dw Ambarella quirks from v3; drop standalone
8250_ambarella (Andy). Commit message clarifies Ambarella IP with a
DW-like register map needing only a thin quirk. Binding under
snps-dw-apb-uart; DT uses ambarella,cv75-uart + snps,dw-apb-uart with
reg-shift/reg-io-width
- clock/RCT: document #reset-cells (Krzysztof); soft-reset ID header and
reset provider deferred (no resets= consumers in this series)
- arm64/Kconfig: do not select ARM_PSCI / HAVE_ARM_ARCH_TIMER (Sashiko)
- pinctrl: no Ambarella suspend/resume claim without validated PM
Link to v5:
https://lore.kernel.org/r/20260818-cv75-v5-v5-0-7bbb12f0360f@ambarella.com
Link to v2:
https://lore.kernel.org/r/20260806-longzhao-upstream-cv75-v2-v2-0-6b09707c5fe9@ambarella.com
Link to v3-A:
https://lore.kernel.org/r/20260813-cv75-v3-a-v3-0-cfdd20b1b4dd@ambarella.com
Link to v3-B:
https://lore.kernel.org/r/20260813-cv75-v3-b-v3-0-1d82e18da09b@ambarella.com
Link to v3-C:
https://lore.kernel.org/r/20260813-cv75-v3-c-v3-0-9352b3fd6026@ambarella.com
Link to v4-B:
https://lore.kernel.org/r/20260814-cv75-v4-b-v4-0-622e63153d97@ambarella.com
To: Arnd Bergmann <arnd@arndb.de>
To: Krzysztof Kozlowski <krzk@kernel.org>
To: Alexandre Belloni <alexandre.belloni@bootlin.com>
To: soc@lists.linux.dev
To: linux-arm-kernel@lists.infradead.org
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Linus Walleij <linusw@kernel.org>
Cc: Bartosz Golaszewski <brgl@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jirislaby@kernel.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Long Zhao <zl020895@163.com>
Cc: Lee Jones <lee@kernel.org>
Cc: mfd@lists.linux.dev
Cc: devicetree@vger.kernel.org
Cc: linux-clk@vger.kernel.org
Cc: linux-gpio@vger.kernel.org
Cc: linux-serial@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Long Zhao (18):
dt-bindings: arm: add Ambarella CV75 platforms
dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad
dt-bindings: clock: add Ambarella CV75 RCT
dt-bindings: pinctrl: add Ambarella CV75 pinctrl
dt-bindings: gpio: pl061: add Ambarella CV75 variant
dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart
clk: ambarella: add CV75 RCT clock controller
gpiolib: regmap: add write_data_after_dir quirk
gpiolib: regmap: add gpio_regmap_get_chip()
gpio: pl061: convert register access to regmap
gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH
gpio: pl061: use cleanup helpers for locks
gpio: pl061: switch data path to gpio-regmap
gpio: pl061: add Ambarella register-layout variant
pinctrl: ambarella: add CV75 pin controller
serial: 8250_dw: add Ambarella CV75 quirks
arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT
MAINTAINERS: add ARM/AMBARELLA SoC support
.../devicetree/bindings/arm/ambarella.yaml | 24 +
.../bindings/clock/ambarella,cv75-rct.yaml | 64 +++
.../devicetree/bindings/gpio/pl061-gpio.yaml | 25 +-
Documentation/devicetree/bindings/mfd/syscon.yaml | 1 +
.../bindings/pinctrl/ambarella,cv75-pinctrl.yaml | 237 +++++++++
.../bindings/serial/snps-dw-apb-uart.yaml | 1 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 14 +
arch/arm64/Kconfig.platforms | 6 +
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 | 177 +++++++
arch/arm64/configs/defconfig | 1 +
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/ambarella/Kconfig | 9 +
drivers/clk/ambarella/Makefile | 3 +
drivers/clk/ambarella/clk-cv75.c | 365 +++++++++++++
drivers/gpio/Kconfig | 2 +
drivers/gpio/gpio-pl061.c | 551 ++++++++++++-------
drivers/gpio/gpio-regmap.c | 25 +-
drivers/pinctrl/Kconfig | 17 +
drivers/pinctrl/Makefile | 2 +
drivers/pinctrl/pinctrl-ambarella-cv75.c | 587 +++++++++++++++++++++
drivers/pinctrl/pinctrl-ambarella.c | 533 +++++++++++++++++++
drivers/pinctrl/pinctrl-ambarella.h | 40 ++
drivers/tty/serial/8250/8250_dw.c | 32 ++
include/dt-bindings/clock/ambarella,cv75-rct.h | 14 +
include/linux/amba/bus.h | 1 +
include/linux/gpio/regmap.h | 9 +
31 files changed, 2587 insertions(+), 191 deletions(-)
---
base-commit: 34cf6dafc47441dfb6b356a095b89c3585a93714
change-id: 20260818-cv75-v5-9e2039b349bc
Best regards,
--
Long Zhao <longzhao@ambarella.com>
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 01/18] dt-bindings: arm: add Ambarella CV75 platforms
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 02/18] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
` (17 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
From: Long Zhao <longzhao@ambarella.com>
Add the Ambarella vendor prefix and CV75 EVK board compatible for the
initial SoC bring-up.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
.../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/Documentation/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 <longzhao@ambarella.com>
+
+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/Documentation/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,.*":
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 02/18] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 01/18] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 03/18] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
` (16 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
From: Long Zhao <longzhao@ambarella.com>
Allow ambarella,cv75-sec-scratchpad as a syscon for the shared secure
scratchpad registers on CV75.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
Documentation/devicetree/bindings/mfd/syscon.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/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
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 03/18] dt-bindings: clock: add Ambarella CV75 RCT
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 01/18] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 02/18] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl Long Zhao via B4 Relay
` (15 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
From: Long Zhao <longzhao@ambarella.com>
Document the CV75 RCT clock controller and the clock ID header used by
DT consumers.
Document #reset-cells for the RCT reset-provider role. Soft-reset line
IDs and the reset provider driver are deferred; this series has no
resets= consumers.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
.../bindings/clock/ambarella,cv75-rct.yaml | 64 ++++++++++++++++++++++
include/dt-bindings/clock/ambarella,cv75-rct.h | 14 +++++
2 files changed, 78 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yaml b/Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yaml
new file mode 100644
index 000000000000..be89bd75f9e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ambarella,cv75-rct.yaml
@@ -0,0 +1,64 @@
+# 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 <longzhao@ambarella.com>
+
+description: |
+ The RCT (Reset and Clock Tree) block on the Ambarella CV75 SoC provides
+ PLLs, clock muxes, dividers and soft-reset controls 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-rct.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
+
+ "#reset-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - "#clock-cells"
+ - "#reset-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@ed080000 {
+ compatible = "ambarella,cv75-rct", "syscon";
+ reg = <0xed080000 0x1000>;
+ clocks = <&osc>;
+ clock-names = "osc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/include/dt-bindings/clock/ambarella,cv75-rct.h b/include/dt-bindings/clock/ambarella,cv75-rct.h
new file mode 100644
index 000000000000..b3e965b4ff2e
--- /dev/null
+++ b/include/dt-bindings/clock/ambarella,cv75-rct.h
@@ -0,0 +1,14 @@
+/* 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
+
+#define CV75_GCLK_UART0 0
+#define CV75_GCLK_CORE 1
+#define CV75_GCLK_AHB 2
+#define CV75_GCLK_APB 3
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (2 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 03/18] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-22 7:11 ` Linus Walleij
2026-10-01 7:03 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 05/18] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
` (14 subsequent siblings)
18 siblings, 2 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
From: Long Zhao <longzhao@ambarella.com>
Document the CV75 pin controller binding using generic function and
groups properties for pinmux configuration.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
.../bindings/pinctrl/ambarella,cv75-pinctrl.yaml | 237 +++++++++++++++++++++
1 file changed, 237 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.yaml
new file mode 100644
index 000000000000..ee464a0f80d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.yaml
@@ -0,0 +1,237 @@
+# 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 <longzhao@ambarella.com>
+
+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 group
+ 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
+ - 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
+ - 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 = "ambarella,cv75-pinctrl";
+ reg = <0xe4010000 0x1000>;
+ ambarella,drive-strength-syscon = <&rct>;
+ ambarella,pull-syscon = <&scratchpad>;
+
+ uart0-pins {
+ function = "uart0";
+ groups = "uart0";
+ bias-disable;
+ drive-strength = <8>;
+ };
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 05/18] dt-bindings: gpio: pl061: add Ambarella CV75 variant
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (3 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 06/18] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart Long Zhao via B4 Relay
` (13 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
The CV75 GPIO banks sit on the AMBA PrimeCell bus but are not
register-compatible with the ARM PL061. Each bank is 32-bit and 32
lines, with extra mask/enable registers, so arm,pl061 must not be used
as a fallback compatible.
The AMBA core matches the PL061 driver by PrimeCell ID, not by the DT
compatible string. These blocks do not implement the standard PL061 ID
(0x00041061) in the ID registers, so arm,primecell-periphid is required
and is fixed to 0x000e8061; the driver uses that ID to select the
Ambarella layout. gpio-ranges is required because each bank is a slice
of the SoC pinctrl pin space.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
.../devicetree/bindings/gpio/pl061-gpio.yaml | 25 +++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml b/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml
index 4d970e55104b..c22dd8a1d2c1 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
@@ -25,7 +27,9 @@ properties:
compatible:
items:
- - const: arm,pl061
+ - enum:
+ - ambarella,cv75-gpio
+ - arm,pl061
- const: arm,primecell
reg:
@@ -64,6 +68,21 @@ required:
- "#gpio-cells"
- gpio-controller
-additionalProperties: false
+allOf:
+ - $ref: /schemas/arm/primecell.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: ambarella,cv75-gpio
+ then:
+ properties:
+ arm,primecell-periphid:
+ const: 0x000e8061
+ required:
+ - arm,primecell-periphid
+ - gpio-ranges
+
+unevaluatedProperties: false
...
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 06/18] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (4 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 05/18] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 07/18] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
` (12 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
From: Long Zhao <longzhao@ambarella.com>
Add the Ambarella CV75 compatible string to the Synopsys DW APB UART
binding. The block is Ambarella IP with a DW-like register map, so it
is described as a DW APB UART variant.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index 49f51b002879..cec5c679f1a9 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -51,6 +51,7 @@ properties:
- const: renesas,rzn1-uart
- items:
- enum:
+ - ambarella,cv75-uart
- anlogic,dr1v90-uart
- brcm,bcm11351-dw-apb-uart
- brcm,bcm21664-dw-apb-uart
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 07/18] clk: ambarella: add CV75 RCT clock controller
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (5 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 06/18] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk Long Zhao via B4 Relay
` (11 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Add a table-driven CCF driver for the CV75 root clock tree. Register
the core PLL, AHB/APB fixed factors and UART0 composite clock, with
osc supplied via clk_parent_data.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/ambarella/Kconfig | 9 +
drivers/clk/ambarella/Makefile | 3 +
drivers/clk/ambarella/clk-cv75.c | 365 +++++++++++++++++++++++++++++++++++++++
5 files changed, 379 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.
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) += clk-xgene.o
# please keep this section sorted lexicographically by directory path name
obj-y += actions/
+obj-y += ambarella/
obj-y += analogbits/
obj-y += aspeed/
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
diff --git a/drivers/clk/ambarella/Kconfig b/drivers/clk/ambarella/Kconfig
new file mode 100644
index 000000000000..720eebdc5c9c
--- /dev/null
+++ b/drivers/clk/ambarella/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config CLK_AMBARELLA_CV75
+ bool "Ambarella CV75 RCT clock controller"
+ depends on ARCH_AMBARELLA || COMPILE_TEST
+ default ARCH_AMBARELLA
+ help
+ Say Y to enable the Ambarella CV75 RCT clock controller for
+ early bring-up clocks (core PLL, AHB, APB, UART0).
diff --git a/drivers/clk/ambarella/Makefile b/drivers/clk/ambarella/Makefile
new file mode 100644
index 000000000000..29555e452441
--- /dev/null
+++ b/drivers/clk/ambarella/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_CLK_AMBARELLA_CV75) += clk-cv75.o
diff --git a/drivers/clk/ambarella/clk-cv75.c b/drivers/clk/ambarella/clk-cv75.c
new file mode 100644
index 000000000000..4071dfd75659
--- /dev/null
+++ b/drivers/clk/ambarella/clk-cv75.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ambarella CV75 RCT clock controller
+ *
+ * Copyright (C) 2026 Ambarella, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk-provider.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <dt-bindings/clock/ambarella,cv75-rct.h>
+
+#define CV75_NUM_CLKS (CV75_GCLK_APB + 1)
+
+#define PLL_CTRL_BYPASS BIT(2)
+#define PLL_CTRL_FRAC_MODE BIT(3)
+#define PLL_CTRL_FORCE_RESET BIT(4)
+#define PLL_CTRL_POWER_DOWN BIT(5)
+#define PLL_CTRL_HALT_VCO BIT(6)
+#define PLL_CTRL_SDIV GENMASK(15, 12)
+#define PLL_CTRL_SOUT GENMASK(19, 16)
+#define PLL_CTRL_INTP GENMASK(30, 24)
+
+#define PLL_CTRL2_VCODIV_DIV2 BIT(8)
+#define PLL_CTRL2_FSDIV_DIV2 BIT(9)
+#define PLL_CTRL2_FSOUT_DIV2 BIT(11)
+#define PLL_CTRL2_BYPASS_HSDIV BIT(12)
+
+struct cv75_pll_hw {
+ struct clk_hw hw;
+ u32 ctrl;
+ u32 frac;
+ u32 ctrl2;
+};
+
+struct cv75_clk {
+ void __iomem *base;
+ spinlock_t lock;
+ struct cv75_pll_hw core;
+ struct cv75_pll_hw enet;
+ struct cv75_pll_hw sd;
+};
+
+struct cv75_pll {
+ const char *name;
+ struct cv75_pll_hw *hw;
+ unsigned long flags;
+ u32 ctrl;
+ u32 frac;
+ u32 ctrl2;
+ int id;
+};
+
+struct cv75_fixed_factor {
+ const char *name;
+ u32 id;
+ struct u16_fract ratio;
+};
+
+struct cv75_composite {
+ const char *name;
+ const struct clk_parent_data *parents;
+ unsigned long flags;
+ u32 id;
+ u16 mux_reg;
+ u16 div_reg;
+ u8 num_parents;
+ u8 mux_shift;
+ u8 mux_width;
+ u8 div_shift;
+ u8 div_width;
+};
+
+struct cv75_composite_hw {
+ struct clk_mux mux;
+ struct clk_divider div;
+ struct clk_gate gate;
+};
+
+static struct cv75_clk cv75_ccu;
+
+#define CV75_PLL(_id, _name, _ctrl, _frac, _ctrl2, _flags, _hw) { \
+ .name = _name, \
+ .hw = _hw, \
+ .flags = _flags, \
+ .ctrl = _ctrl, \
+ .frac = _frac, \
+ .ctrl2 = _ctrl2, \
+ .id = _id, \
+}
+
+static const struct cv75_pll cv75_plls[] = {
+ CV75_PLL(CV75_GCLK_CORE, "core", 0x000, 0x004, 0x100,
+ CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL, &cv75_ccu.core),
+ CV75_PLL(-1, "pll_enet", 0x520, 0x524, 0x528,
+ CLK_GET_RATE_NOCACHE, &cv75_ccu.enet),
+ CV75_PLL(-1, "pll_sd", 0x4ac, 0x4b0, 0x4b4,
+ CLK_GET_RATE_NOCACHE, &cv75_ccu.sd),
+};
+
+static const struct cv75_fixed_factor cv75_fixed_factors[] = {
+ { .id = CV75_GCLK_AHB, .name = "ahb", .ratio = { 1, 2 } },
+ { .id = CV75_GCLK_APB, .name = "apb", .ratio = { 1, 4 } },
+};
+
+static const struct clk_parent_data cv75_uart_parents[] = {
+ { .fw_name = "osc" },
+ { .hw = &cv75_ccu.core.hw },
+ { .hw = &cv75_ccu.enet.hw },
+ { .hw = &cv75_ccu.sd.hw },
+};
+
+#define CV75_COMPOSITE(_id, _name, _parents, _mreg, _mshift, _mwidth, \
+ _dreg, _dshift, _dwidth, _flags) \
+{ \
+ .id = _id, \
+ .name = _name, \
+ .parents = _parents, \
+ .num_parents = ARRAY_SIZE(_parents), \
+ .mux_reg = _mreg, \
+ .mux_shift = _mshift, \
+ .mux_width = _mwidth, \
+ .div_reg = _dreg, \
+ .div_shift = _dshift, \
+ .div_width = _dwidth, \
+ .flags = _flags, \
+}
+
+static const struct cv75_composite cv75_composites[] = {
+ CV75_COMPOSITE(CV75_GCLK_UART0, "uart0", cv75_uart_parents,
+ 0x1c8, 0, 2, 0x038, 0, 24,
+ CLK_SET_RATE_NO_REPARENT),
+};
+
+#define to_cv75_pll(_hw) container_of(_hw, struct cv75_pll_hw, hw)
+
+static unsigned long cv75_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cv75_pll_hw *pll = to_cv75_pll(hw);
+ u32 ctrl, ctrl2, frac_val;
+ u32 intp, sdiv, sout;
+ u32 vcodiv, fsdiv, fsout;
+ u64 vco, frac = 0;
+
+ ctrl = readl_relaxed(cv75_ccu.base + pll->ctrl);
+ if (ctrl & (PLL_CTRL_POWER_DOWN | PLL_CTRL_HALT_VCO | PLL_CTRL_FORCE_RESET))
+ return 0;
+
+ if (ctrl & PLL_CTRL_BYPASS)
+ return parent_rate;
+
+ ctrl2 = readl_relaxed(cv75_ccu.base + pll->ctrl2);
+ intp = FIELD_GET(PLL_CTRL_INTP, ctrl) + 1;
+ sdiv = FIELD_GET(PLL_CTRL_SDIV, ctrl) + 1;
+ sout = FIELD_GET(PLL_CTRL_SOUT, ctrl) + 1;
+ vcodiv = (ctrl2 & PLL_CTRL2_VCODIV_DIV2) ? 2 : 1;
+ fsdiv = (ctrl2 & PLL_CTRL2_FSDIV_DIV2) ? 2 : 1;
+ fsout = (ctrl2 & PLL_CTRL2_FSOUT_DIV2) ? 2 : 1;
+
+ vco = (u64)parent_rate * vcodiv * fsdiv * intp * sdiv;
+ if (ctrl & PLL_CTRL_FRAC_MODE) {
+ frac_val = readl_relaxed(cv75_ccu.base + pll->frac);
+ frac = mul_u64_u32_shr((u64)parent_rate * vcodiv * fsdiv * sdiv,
+ frac_val, 32);
+ vco += frac;
+ }
+
+ if (!(ctrl2 & PLL_CTRL2_BYPASS_HSDIV))
+ vco = div_u64(vco, (u64)vcodiv * fsout * sout);
+
+ return vco;
+}
+
+static const struct clk_ops cv75_pll_ops = {
+ .recalc_rate = cv75_pll_recalc_rate,
+};
+
+static int cv75_register_plls(struct device *dev,
+ struct clk_hw_onecell_data *data)
+{
+ struct clk_parent_data parent_data = { .fw_name = "osc" };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cv75_plls); i++) {
+ const struct cv75_pll *desc = &cv75_plls[i];
+ struct cv75_pll_hw *pll = desc->hw;
+ struct clk_init_data init = {};
+ int ret;
+
+ pll->ctrl = desc->ctrl;
+ pll->frac = desc->frac;
+ pll->ctrl2 = desc->ctrl2;
+
+ init.name = desc->name;
+ init.ops = &cv75_pll_ops;
+ init.parent_data = &parent_data;
+ init.num_parents = 1;
+ init.flags = desc->flags;
+ pll->hw.init = &init;
+
+ ret = devm_clk_hw_register(dev, &pll->hw);
+ if (ret)
+ return ret;
+
+ if (desc->id >= 0)
+ data->hws[desc->id] = &pll->hw;
+ }
+
+ return 0;
+}
+
+static int cv75_register_fixed_factors(struct device *dev,
+ struct clk_hw_onecell_data *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cv75_fixed_factors); i++) {
+ const struct cv75_fixed_factor *f = &cv75_fixed_factors[i];
+ struct clk_hw *hw;
+
+ hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, f->name,
+ &cv75_ccu.core.hw, 0,
+ f->ratio.numerator,
+ f->ratio.denominator);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ data->hws[f->id] = hw;
+ }
+
+ return 0;
+}
+
+static struct clk_hw *cv75_register_composite(struct device *dev,
+ const struct cv75_composite *c)
+{
+ const struct clk_ops *mux_ops = NULL, *div_ops = NULL, *gate_ops = NULL;
+ struct clk_hw *mux_hw = NULL, *div_hw = NULL, *gate_hw = NULL;
+ struct cv75_composite_hw *comp;
+
+ comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+ if (!comp)
+ return ERR_PTR(-ENOMEM);
+
+ if (c->mux_width) {
+ comp->mux.reg = cv75_ccu.base + c->mux_reg;
+ comp->mux.shift = c->mux_shift;
+ comp->mux.mask = GENMASK(c->mux_width - 1, 0);
+ comp->mux.lock = &cv75_ccu.lock;
+ mux_hw = &comp->mux.hw;
+ mux_ops = &clk_mux_ops;
+ }
+
+ if (c->div_width) {
+ comp->div.reg = cv75_ccu.base + c->div_reg;
+ comp->div.shift = c->div_shift;
+ comp->div.width = c->div_width;
+ comp->div.flags = CLK_DIVIDER_ONE_BASED;
+ comp->div.lock = &cv75_ccu.lock;
+ div_hw = &comp->div.hw;
+ div_ops = &clk_divider_ops;
+
+ comp->gate.reg = cv75_ccu.base + c->div_reg;
+ comp->gate.bit_idx = c->div_shift + c->div_width;
+ comp->gate.flags = CLK_GATE_SET_TO_DISABLE;
+ comp->gate.lock = &cv75_ccu.lock;
+ gate_hw = &comp->gate.hw;
+ gate_ops = &clk_gate_ops;
+ }
+
+ return devm_clk_hw_register_composite_pdata(dev, c->name, c->parents,
+ c->num_parents,
+ mux_hw, mux_ops,
+ div_hw, div_ops,
+ gate_hw, gate_ops, c->flags);
+}
+
+static int cv75_register_composites(struct device *dev,
+ struct clk_hw_onecell_data *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cv75_composites); i++) {
+ const struct cv75_composite *c = &cv75_composites[i];
+ struct clk_hw *hw;
+
+ hw = cv75_register_composite(dev, c);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ data->hws[c->id] = hw;
+ }
+
+ return 0;
+}
+
+static int cv75_rct_probe(struct platform_device *pdev)
+{
+ struct clk_hw_onecell_data *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ spin_lock_init(&cv75_ccu.lock);
+
+ cv75_ccu.base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(cv75_ccu.base))
+ return PTR_ERR(cv75_ccu.base);
+
+ data = devm_kzalloc(dev, struct_size(data, hws, CV75_NUM_CLKS), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ data->num = CV75_NUM_CLKS;
+
+ ret = cv75_register_plls(dev, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register plls\n");
+
+ ret = cv75_register_fixed_factors(dev, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register fixed factors\n");
+
+ ret = cv75_register_composites(dev, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register composites\n");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add clock provider\n");
+
+ return 0;
+}
+
+static const struct of_device_id cv75_rct_match[] = {
+ { .compatible = "ambarella,cv75-rct" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cv75_rct_match);
+
+static struct platform_driver cv75_rct_driver = {
+ .probe = cv75_rct_probe,
+ .driver = {
+ .name = "ambarella-cv75-rct",
+ .of_match_table = cv75_rct_match,
+ },
+};
+module_platform_driver(cv75_rct_driver);
+
+MODULE_AUTHOR("Cao Rongrong <rrcao@ambarella.com>");
+MODULE_DESCRIPTION("Ambarella CV75 RCT clock controller");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (6 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 07/18] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-22 7:17 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip() Long Zhao via B4 Relay
` (10 subsequent siblings)
18 siblings, 1 reply; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Some controllers ignore data-register writes while a line is still an
input. Optionally write the output value again after switching the
direction, matching the existing PL061 behaviour.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/gpio-regmap.c | 19 +++++++++++++++++--
include/linux/gpio/regmap.h | 8 ++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 51b4d69b8740..fbd4c753525a 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -31,6 +31,7 @@ struct gpio_regmap {
unsigned int reg_clr_base;
unsigned int reg_dir_in_base;
unsigned int reg_dir_out_base;
+ bool write_data_after_dir;
unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
@@ -271,9 +272,21 @@ static int gpio_regmap_direction_output(struct gpio_chip *chip,
return ret;
}
- gpio_regmap_set(chip, offset, value);
+ if (!gpio->write_data_after_dir)
+ gpio_regmap_set(chip, offset, value);
- return gpio_regmap_set_direction(chip, offset, true);
+ ret = gpio_regmap_set_direction(chip, offset, true);
+ if (ret)
+ return ret;
+
+ /*
+ * Some controllers ignore data-register writes while the line is
+ * still an input. Write the output value after switching direction.
+ */
+ if (gpio->write_data_after_dir)
+ gpio_regmap_set(chip, offset, value);
+
+ return 0;
}
void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
@@ -376,6 +389,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
config->fixed_direction_output, chip->ngpio);
}
+ gpio->write_data_after_dir = config->write_data_after_dir;
+
/* if not set, assume there is only one register */
gpio->ngpio_per_reg = config->ngpio_per_reg;
if (!gpio->ngpio_per_reg)
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index 06255756710d..d7ffc12b00a2 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -48,6 +48,13 @@ struct regmap;
* (Optional) Bitmap representing the fixed direction of
* the GPIO lines. Useful when there are GPIO lines with a
* fixed direction mixed together in the same register.
+ * @write_data_after_dir:
+ * (Optional) Write the output value again after
+ * switching a line to output in ->direction_output().
+ * Needed for hardware which ignores data register
+ * writes while the line is configured as an input.
+ * This is a legacy quirk (e.g. ARM PL061); new hardware
+ * must not use it. Direction changes will glitch.
* @drvdata: (Optional) Pointer to driver specific data which is
* not used by gpio-remap but is provided "as is" to the
* driver callback(s).
@@ -94,6 +101,7 @@ struct gpio_regmap_config {
unsigned int reg_dir_out_base;
int reg_stride;
int ngpio_per_reg;
+ bool write_data_after_dir;
struct irq_domain *irq_domain;
unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip()
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (7 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 10:35 ` Bartosz Golaszewski
2026-09-21 4:23 ` [PATCH v8 10/18] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
` (9 subsequent siblings)
18 siblings, 1 reply; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Let drivers that implement a custom irqchip retrieve the gpio_chip
after registration.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/gpio-regmap.c | 6 ++++++
include/linux/gpio/regmap.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index fbd4c753525a..21e0993b89e2 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -295,6 +295,12 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
}
EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
+struct gpio_chip *gpio_regmap_get_chip(struct gpio_regmap *gpio)
+{
+ return &gpio->gpio_chip;
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_get_chip);
+
/**
* gpio_regmap_register() - Register a generic regmap GPIO controller
* @config: configuration for gpio_regmap
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index d7ffc12b00a2..6bc00b9775a5 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -128,5 +128,6 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio);
struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
const struct gpio_regmap_config *config);
void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio);
+struct gpio_chip *gpio_regmap_get_chip(struct gpio_regmap *gpio);
#endif /* _LINUX_GPIO_REGMAP_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 10/18] gpio: pl061: convert register access to regmap
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (8 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip() Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 11/18] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
` (8 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Replace readb()/writeb() with a MMIO regmap while keeping the existing
gpio_chip and girq irqchip. Use a raw spinlock so irq_ack() can run
under the irq descriptor lock.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/Kconfig | 1 +
drivers/gpio/gpio-pl061.c | 134 ++++++++++++++++++++++++++++++----------------
2 files changed, 89 insertions(+), 46 deletions(-)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f03c05288376..2a1487bd1a94 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -583,6 +583,7 @@ config GPIO_PL061
depends on ARM_AMBA || COMPILE_TEST
select IRQ_DOMAIN
select GPIOLIB_IRQCHIP
+ select REGMAP_MMIO
help
Say yes here to support the PrimeCell PL061 GPIO device.
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 919cf86fd590..66aea0856bc4 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -19,9 +19,11 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/log2.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
+#include <linux/regmap.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -36,6 +38,7 @@
#define GPIOIC 0x41C
#define PL061_GPIO_NR 8
+#define PL061_DATA_OFFSET 2
struct pl061_context_save_regs {
u8 gpio_data;
@@ -49,18 +52,49 @@ struct pl061_context_save_regs {
struct pl061 {
raw_spinlock_t lock;
- void __iomem *base;
+ struct regmap *regmap;
struct gpio_chip gc;
int parent_irq;
struct pl061_context_save_regs csave_regs;
};
+static bool pl061_is_data_reg(unsigned int reg)
+{
+ return is_power_of_2(reg) &&
+ reg >= BIT(PL061_DATA_OFFSET) &&
+ reg <= BIT(PL061_DATA_OFFSET + PL061_GPIO_NR - 1);
+}
+
+static bool pl061_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case GPIOMIS:
+ case GPIOIC:
+ return true;
+ default:
+ return pl061_is_data_reg(reg);
+ }
+}
+
+static const struct regmap_config pl061_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .reg_stride = 4,
+ .max_register = GPIOIC,
+ .volatile_reg = pl061_volatile_reg,
+ .fast_io = true,
+ .use_raw_spinlock = true,
+};
+
static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
{
struct pl061 *pl061 = gpiochip_get_data(gc);
+ unsigned int gpiodir = 0;
- if (readb(pl061->base + GPIODIR) & BIT(offset))
+ regmap_read(pl061->regmap, GPIODIR, &gpiodir);
+
+ if (gpiodir & BIT(offset))
return GPIO_LINE_DIRECTION_OUT;
return GPIO_LINE_DIRECTION_IN;
@@ -70,12 +104,9 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061 *pl061 = gpiochip_get_data(gc);
unsigned long flags;
- unsigned char gpiodir;
raw_spin_lock_irqsave(&pl061->lock, flags);
- gpiodir = readb(pl061->base + GPIODIR);
- gpiodir &= ~(BIT(offset));
- writeb(gpiodir, pl061->base + GPIODIR);
+ regmap_update_bits(pl061->regmap, GPIODIR, BIT(offset), 0);
raw_spin_unlock_irqrestore(&pl061->lock, flags);
return 0;
@@ -86,19 +117,19 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
{
struct pl061 *pl061 = gpiochip_get_data(gc);
unsigned long flags;
- unsigned char gpiodir;
+ unsigned int mask = BIT(offset);
raw_spin_lock_irqsave(&pl061->lock, flags);
- writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
- gpiodir = readb(pl061->base + GPIODIR);
- gpiodir |= BIT(offset);
- writeb(gpiodir, pl061->base + GPIODIR);
+ regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
+ !!value << offset);
+ regmap_update_bits(pl061->regmap, GPIODIR, mask, mask);
/*
* 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)));
+ regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
+ !!value << offset);
raw_spin_unlock_irqrestore(&pl061->lock, flags);
return 0;
@@ -107,15 +138,19 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
{
struct pl061 *pl061 = gpiochip_get_data(gc);
+ unsigned int val = 0;
+
+ regmap_read(pl061->regmap, BIT(offset + PL061_DATA_OFFSET), &val);
- return !!readb(pl061->base + (BIT(offset + 2)));
+ return !!val;
}
static int pl061_set_value(struct gpio_chip *gc, unsigned int offset, int value)
{
struct pl061 *pl061 = gpiochip_get_data(gc);
- writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
+ regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
+ !!value << offset);
return 0;
}
@@ -126,8 +161,8 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
struct pl061 *pl061 = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(d);
unsigned long flags;
- u8 gpiois, gpioibe, gpioiev;
- u8 bit = BIT(offset);
+ unsigned int gpiois = 0, gpioibe = 0, gpioiev = 0;
+ unsigned int bit = BIT(offset);
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
@@ -145,9 +180,9 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
raw_spin_lock_irqsave(&pl061->lock, flags);
- gpioiev = readb(pl061->base + GPIOIEV);
- gpiois = readb(pl061->base + GPIOIS);
- gpioibe = readb(pl061->base + GPIOIBE);
+ regmap_read(pl061->regmap, GPIOIEV, &gpioiev);
+ regmap_read(pl061->regmap, GPIOIS, &gpiois);
+ regmap_read(pl061->regmap, GPIOIBE, &gpioibe);
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
@@ -199,9 +234,9 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
offset);
}
- writeb(gpiois, pl061->base + GPIOIS);
- writeb(gpioibe, pl061->base + GPIOIBE);
- writeb(gpioiev, pl061->base + GPIOIEV);
+ regmap_write(pl061->regmap, GPIOIS, gpiois);
+ regmap_write(pl061->regmap, GPIOIBE, gpioibe);
+ regmap_write(pl061->regmap, GPIOIEV, gpioiev);
raw_spin_unlock_irqrestore(&pl061->lock, flags);
@@ -211,6 +246,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
static void pl061_irq_handler(struct irq_desc *desc)
{
unsigned long pending;
+ unsigned int mis = 0;
int offset;
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct pl061 *pl061 = gpiochip_get_data(gc);
@@ -218,8 +254,9 @@ static void pl061_irq_handler(struct irq_desc *desc)
chained_irq_enter(irqchip, desc);
- pending = readb(pl061->base + GPIOMIS);
- if (pending) {
+ regmap_read(pl061->regmap, GPIOMIS, &mis);
+ if (mis) {
+ pending = mis;
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
generic_handle_domain_irq(gc->irq.domain,
offset);
@@ -233,11 +270,9 @@ static void pl061_irq_mask(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
- u8 gpioie;
raw_spin_lock(&pl061->lock);
- gpioie = readb(pl061->base + GPIOIE) & ~mask;
- writeb(gpioie, pl061->base + GPIOIE);
+ regmap_update_bits(pl061->regmap, GPIOIE, mask, 0);
raw_spin_unlock(&pl061->lock);
gpiochip_disable_irq(gc, d->hwirq);
@@ -248,13 +283,11 @@ static void pl061_irq_unmask(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
- u8 gpioie;
gpiochip_enable_irq(gc, d->hwirq);
raw_spin_lock(&pl061->lock);
- gpioie = readb(pl061->base + GPIOIE) | mask;
- writeb(gpioie, pl061->base + GPIOIE);
+ regmap_update_bits(pl061->regmap, GPIOIE, mask, mask);
raw_spin_unlock(&pl061->lock);
}
@@ -272,9 +305,7 @@ static void pl061_irq_ack(struct irq_data *d)
struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
- raw_spin_lock(&pl061->lock);
- writeb(mask, pl061->base + GPIOIC);
- raw_spin_unlock(&pl061->lock);
+ regmap_write(pl061->regmap, GPIOIC, mask);
}
static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
@@ -308,15 +339,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
struct device *dev = &adev->dev;
struct pl061 *pl061;
struct gpio_irq_chip *girq;
+ void __iomem *base;
int ret, irq;
pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
if (pl061 == NULL)
return -ENOMEM;
- pl061->base = devm_ioremap_resource(dev, &adev->res);
- if (IS_ERR(pl061->base))
- return PTR_ERR(pl061->base);
+ base = devm_ioremap_resource(dev, &adev->res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ pl061->regmap = devm_regmap_init_mmio(dev, base, &pl061_regmap_config);
+ if (IS_ERR(pl061->regmap))
+ return PTR_ERR(pl061->regmap);
raw_spin_lock_init(&pl061->lock);
pl061->gc.request = gpiochip_generic_request;
@@ -335,7 +371,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
- writeb(0, pl061->base + GPIOIE); /* disable irqs */
+ regmap_write(pl061->regmap, GPIOIE, 0); /* disable irqs */
irq = adev->irq[0];
if (!irq)
dev_warn(&adev->dev, "IRQ support disabled\n");
@@ -366,14 +402,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
static int pl061_suspend(struct device *dev)
{
struct pl061 *pl061 = dev_get_drvdata(dev);
+ unsigned int val = 0;
int offset;
pl061->csave_regs.gpio_data = 0;
- pl061->csave_regs.gpio_dir = readb(pl061->base + GPIODIR);
- pl061->csave_regs.gpio_is = readb(pl061->base + GPIOIS);
- pl061->csave_regs.gpio_ibe = readb(pl061->base + GPIOIBE);
- pl061->csave_regs.gpio_iev = readb(pl061->base + GPIOIEV);
- pl061->csave_regs.gpio_ie = readb(pl061->base + GPIOIE);
+ regmap_read(pl061->regmap, GPIODIR, &val);
+ pl061->csave_regs.gpio_dir = val;
+ regmap_read(pl061->regmap, GPIOIS, &val);
+ pl061->csave_regs.gpio_is = val;
+ regmap_read(pl061->regmap, GPIOIBE, &val);
+ pl061->csave_regs.gpio_ibe = val;
+ regmap_read(pl061->regmap, GPIOIEV, &val);
+ pl061->csave_regs.gpio_iev = val;
+ regmap_read(pl061->regmap, GPIOIE, &val);
+ pl061->csave_regs.gpio_ie = val;
for (offset = 0; offset < PL061_GPIO_NR; offset++) {
if (pl061->csave_regs.gpio_dir & (BIT(offset)))
@@ -398,10 +440,10 @@ static int pl061_resume(struct device *dev)
pl061_direction_input(&pl061->gc, offset);
}
- 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);
+ regmap_write(pl061->regmap, GPIOIS, pl061->csave_regs.gpio_is);
+ regmap_write(pl061->regmap, GPIOIBE, pl061->csave_regs.gpio_ibe);
+ regmap_write(pl061->regmap, GPIOIEV, pl061->csave_regs.gpio_iev);
+ regmap_write(pl061->regmap, GPIOIE, pl061->csave_regs.gpio_ie);
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 11/18] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (9 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 10/18] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-22 7:24 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 12/18] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
` (7 subsequent siblings)
18 siblings, 1 reply; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Use the standard IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH helpers
instead of open-coded edge and level comparisons.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/gpio-pl061.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 66aea0856bc4..2913daf46aff 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -167,9 +167,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
- if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
- (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
- {
+ if ((trigger & IRQ_TYPE_LEVEL_MASK) && (trigger & IRQ_TYPE_EDGE_BOTH)) {
dev_err(gc->parent,
"trying to configure line %d for both level and edge "
"detection, choose one!\n",
@@ -184,7 +182,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
regmap_read(pl061->regmap, GPIOIS, &gpiois);
regmap_read(pl061->regmap, GPIOIBE, &gpioibe);
- if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ if (trigger & IRQ_TYPE_LEVEL_MASK) {
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
/* Disable edge detection */
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 12/18] gpio: pl061: use cleanup helpers for locks
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (10 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 11/18] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-22 7:24 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 13/18] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
` (6 subsequent siblings)
18 siblings, 1 reply; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Convert raw_spinlock critical sections to guard() from cleanup.h.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/gpio-pl061.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 2913daf46aff..c821a5117eed 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -10,6 +10,7 @@
*/
#include <linux/amba/bus.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -103,11 +104,9 @@ static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061 *pl061 = gpiochip_get_data(gc);
- unsigned long flags;
- raw_spin_lock_irqsave(&pl061->lock, flags);
+ guard(raw_spinlock_irqsave)(&pl061->lock);
regmap_update_bits(pl061->regmap, GPIODIR, BIT(offset), 0);
- raw_spin_unlock_irqrestore(&pl061->lock, flags);
return 0;
}
@@ -116,10 +115,9 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct pl061 *pl061 = gpiochip_get_data(gc);
- unsigned long flags;
unsigned int mask = BIT(offset);
- raw_spin_lock_irqsave(&pl061->lock, flags);
+ guard(raw_spinlock_irqsave)(&pl061->lock);
regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
!!value << offset);
regmap_update_bits(pl061->regmap, GPIODIR, mask, mask);
@@ -130,7 +128,6 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
*/
regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
!!value << offset);
- raw_spin_unlock_irqrestore(&pl061->lock, flags);
return 0;
}
@@ -160,7 +157,6 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061 *pl061 = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(d);
- unsigned long flags;
unsigned int gpiois = 0, gpioibe = 0, gpioiev = 0;
unsigned int bit = BIT(offset);
@@ -176,7 +172,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
}
- raw_spin_lock_irqsave(&pl061->lock, flags);
+ guard(raw_spinlock_irqsave)(&pl061->lock);
regmap_read(pl061->regmap, GPIOIEV, &gpioiev);
regmap_read(pl061->regmap, GPIOIS, &gpiois);
@@ -236,7 +232,6 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
regmap_write(pl061->regmap, GPIOIBE, gpioibe);
regmap_write(pl061->regmap, GPIOIEV, gpioiev);
- raw_spin_unlock_irqrestore(&pl061->lock, flags);
return 0;
}
@@ -269,9 +264,8 @@ static void pl061_irq_mask(struct irq_data *d)
struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
- raw_spin_lock(&pl061->lock);
+ guard(raw_spinlock)(&pl061->lock);
regmap_update_bits(pl061->regmap, GPIOIE, mask, 0);
- raw_spin_unlock(&pl061->lock);
gpiochip_disable_irq(gc, d->hwirq);
}
@@ -284,9 +278,8 @@ static void pl061_irq_unmask(struct irq_data *d)
gpiochip_enable_irq(gc, d->hwirq);
- raw_spin_lock(&pl061->lock);
+ guard(raw_spinlock)(&pl061->lock);
regmap_update_bits(pl061->regmap, GPIOIE, mask, mask);
- raw_spin_unlock(&pl061->lock);
}
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 13/18] gpio: pl061: switch data path to gpio-regmap
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (11 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 12/18] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-22 7:25 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 14/18] gpio: pl061: add Ambarella register-layout variant Long Zhao via B4 Relay
` (5 subsequent siblings)
18 siblings, 1 reply; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Keep a custom irqchip and irq domain. The gpio_chip is owned by
gpio-regmap, so gpio_regmap_get_chip() is used to wire the domain.
Check the chained-handler regmap_read() return and always
run chained_irq_exit(). irq_type keeps the MMIO write style
and uses cleanup helpers from the previous patch.
irq_set_parent() nests the GPIO irq_desc under the AMBA parent
for irq_set_wake() and lockdep; checked with PROVE_LOCKING on CV75.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/Kconfig | 1 +
drivers/gpio/gpio-pl061.c | 485 +++++++++++++++++++++++++++-------------------
2 files changed, 287 insertions(+), 199 deletions(-)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 2a1487bd1a94..55a129836158 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -583,6 +583,7 @@ config GPIO_PL061
depends on ARM_AMBA || COMPILE_TEST
select IRQ_DOMAIN
select GPIOLIB_IRQCHIP
+ select GPIO_REGMAP
select REGMAP_MMIO
help
Say yes here to support the PrimeCell PL061 GPIO device.
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index c821a5117eed..604129a68948 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -12,155 +12,102 @@
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h>
-#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/gpio/driver.h>
-#include <linux/init.h>
+#include <linux/gpio/regmap.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
#include <linux/log2.h>
#include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
-#include <linux/slab.h>
#include <linux/spinlock.h>
-#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_DATA_OFFSET 2
-struct pl061_context_save_regs {
- u8 gpio_data;
- u8 gpio_dir;
- u8 gpio_is;
- u8 gpio_ibe;
- u8 gpio_iev;
- u8 gpio_ie;
+#define PL061_DIR 0x400
+#define PL061_IS 0x404
+#define PL061_IBE 0x408
+#define PL061_IEV 0x40c
+#define PL061_IE 0x410
+#define PL061_MIS 0x418
+#define PL061_IC 0x41c
+
+struct pl061_regs {
+ unsigned int dat;
+ unsigned int dir;
+ unsigned int is;
+ unsigned int ibe;
+ unsigned int iev;
+ unsigned int ie;
+ unsigned int mis;
+ unsigned int ic;
+ unsigned int mask;
+ unsigned int enable;
+};
+
+struct pl061_drvdata {
+ const struct regmap_config *regmap_config;
+ const struct pl061_regs *regs;
+ unsigned int ngpio;
+ bool write_data_after_dir;
+ bool clear_irq_on_type;
+ bool pm;
+ int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
+ unsigned int offset, unsigned int *reg,
+ unsigned int *mask);
};
struct pl061 {
raw_spinlock_t lock;
struct regmap *regmap;
- struct gpio_chip gc;
+ const struct pl061_drvdata *data;
+ struct irq_domain *irq_domain;
int parent_irq;
- struct pl061_context_save_regs csave_regs;
+ u32 saved_dat;
};
-static bool pl061_is_data_reg(unsigned int reg)
-{
- return is_power_of_2(reg) &&
- reg >= BIT(PL061_DATA_OFFSET) &&
- reg <= BIT(PL061_DATA_OFFSET + PL061_GPIO_NR - 1);
-}
-
-static bool pl061_volatile_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case GPIOMIS:
- case GPIOIC:
- return true;
- default:
- return pl061_is_data_reg(reg);
- }
-}
-
-static const struct regmap_config pl061_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .reg_stride = 4,
- .max_register = GPIOIC,
- .volatile_reg = pl061_volatile_reg,
- .fast_io = true,
- .use_raw_spinlock = true,
-};
-
-static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
-{
- struct pl061 *pl061 = gpiochip_get_data(gc);
- unsigned int gpiodir = 0;
-
- regmap_read(pl061->regmap, GPIODIR, &gpiodir);
-
- if (gpiodir & BIT(offset))
- return GPIO_LINE_DIRECTION_OUT;
-
- return GPIO_LINE_DIRECTION_IN;
-}
-
-static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
-{
- struct pl061 *pl061 = gpiochip_get_data(gc);
-
- guard(raw_spinlock_irqsave)(&pl061->lock);
- regmap_update_bits(pl061->regmap, GPIODIR, BIT(offset), 0);
-
- return 0;
-}
-
-static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
- int value)
+static struct pl061 *pl061_from_gpio_chip(struct gpio_chip *gc)
{
- struct pl061 *pl061 = gpiochip_get_data(gc);
- unsigned int mask = BIT(offset);
-
- guard(raw_spinlock_irqsave)(&pl061->lock);
- regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
- !!value << offset);
- regmap_update_bits(pl061->regmap, GPIODIR, mask, mask);
-
- /*
- * gpio value is set again, because pl061 doesn't allow to set value of
- * a gpio pin before configuring it in OUT mode.
- */
- regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
- !!value << offset);
-
- return 0;
+ return gpio_regmap_get_drvdata(gpiochip_get_data(gc));
}
-static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
+static unsigned int pl061_line_mask(struct pl061 *pl061, irq_hw_number_t hwirq)
{
- struct pl061 *pl061 = gpiochip_get_data(gc);
- unsigned int val = 0;
-
- regmap_read(pl061->regmap, BIT(offset + PL061_DATA_OFFSET), &val);
-
- return !!val;
+ return BIT(hwirq % pl061->data->ngpio);
}
-static int pl061_set_value(struct gpio_chip *gc, unsigned int offset, int value)
+static int pl061_arm_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
+ unsigned int offset, unsigned int *reg,
+ unsigned int *mask)
{
- struct pl061 *pl061 = gpiochip_get_data(gc);
-
- regmap_write(pl061->regmap, BIT(offset + PL061_DATA_OFFSET),
- !!value << offset);
+ if (base == 0)
+ *reg = BIT(offset + PL061_DATA_OFFSET);
+ else
+ *reg = base;
+ *mask = BIT(offset);
return 0;
}
-static int pl061_irq_type(struct irq_data *d, unsigned trigger)
+static int pl061_irq_type(struct irq_data *d, unsigned int trigger)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061 *pl061 = gpiochip_get_data(gc);
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
+ const struct pl061_regs *regs = pl061->data->regs;
int offset = irqd_to_hwirq(d);
unsigned int gpiois = 0, gpioibe = 0, gpioiev = 0;
unsigned int bit = BIT(offset);
- if (offset < 0 || offset >= PL061_GPIO_NR)
+ if (offset < 0 || offset >= pl061->data->ngpio)
return -EINVAL;
if ((trigger & IRQ_TYPE_LEVEL_MASK) && (trigger & IRQ_TYPE_EDGE_BOTH)) {
@@ -171,12 +118,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
return -EINVAL;
}
-
guard(raw_spinlock_irqsave)(&pl061->lock);
- regmap_read(pl061->regmap, GPIOIEV, &gpioiev);
- regmap_read(pl061->regmap, GPIOIS, &gpiois);
- regmap_read(pl061->regmap, GPIOIBE, &gpioibe);
+ regmap_read(pl061->regmap, regs->iev, &gpioiev);
+ regmap_read(pl061->regmap, regs->is, &gpiois);
+ regmap_read(pl061->regmap, regs->ibe, &gpioibe);
if (trigger & IRQ_TYPE_LEVEL_MASK) {
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
@@ -228,10 +174,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
offset);
}
- regmap_write(pl061->regmap, GPIOIS, gpiois);
- regmap_write(pl061->regmap, GPIOIBE, gpioibe);
- regmap_write(pl061->regmap, GPIOIEV, gpioiev);
-
+ regmap_write(pl061->regmap, regs->is, gpiois);
+ regmap_write(pl061->regmap, regs->ibe, gpioibe);
+ regmap_write(pl061->regmap, regs->iev, gpioiev);
+ if (pl061->data->clear_irq_on_type)
+ regmap_write(pl061->regmap, regs->ic, bit);
return 0;
}
@@ -240,32 +187,34 @@ static void pl061_irq_handler(struct irq_desc *desc)
{
unsigned long pending;
unsigned int mis = 0;
- int offset;
+ int offset, ret;
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct pl061 *pl061 = gpiochip_get_data(gc);
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc);
- regmap_read(pl061->regmap, GPIOMIS, &mis);
+ ret = regmap_read(pl061->regmap, pl061->data->regs->mis, &mis);
+ if (ret)
+ goto out;
+
if (mis) {
pending = mis;
- for_each_set_bit(offset, &pending, PL061_GPIO_NR)
- generic_handle_domain_irq(gc->irq.domain,
- offset);
+ for_each_set_bit(offset, &pending, pl061->data->ngpio)
+ generic_handle_domain_irq(pl061->irq_domain, offset);
}
+out:
chained_irq_exit(irqchip, desc);
}
static void pl061_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061 *pl061 = gpiochip_get_data(gc);
- u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
+ unsigned int mask = pl061_line_mask(pl061, irqd_to_hwirq(d));
- guard(raw_spinlock)(&pl061->lock);
- regmap_update_bits(pl061->regmap, GPIOIE, mask, 0);
+ regmap_update_bits(pl061->regmap, pl061->data->regs->ie, mask, 0);
gpiochip_disable_irq(gc, d->hwirq);
}
@@ -273,13 +222,12 @@ static void pl061_irq_mask(struct irq_data *d)
static void pl061_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061 *pl061 = gpiochip_get_data(gc);
- u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
+ unsigned int mask = pl061_line_mask(pl061, irqd_to_hwirq(d));
gpiochip_enable_irq(gc, d->hwirq);
- guard(raw_spinlock)(&pl061->lock);
- regmap_update_bits(pl061->regmap, GPIOIE, mask, mask);
+ regmap_update_bits(pl061->regmap, pl061->data->regs->ie, mask, mask);
}
/**
@@ -293,16 +241,16 @@ static void pl061_irq_unmask(struct irq_data *d)
static void pl061_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061 *pl061 = gpiochip_get_data(gc);
- u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
+ unsigned int mask = pl061_line_mask(pl061, irqd_to_hwirq(d));
- regmap_write(pl061->regmap, GPIOIC, mask);
+ regmap_write(pl061->regmap, pl061->data->regs->ic, mask);
}
static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct pl061 *pl061 = gpiochip_get_data(gc);
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
return irq_set_irq_wake(pl061->parent_irq, state);
}
@@ -314,7 +262,8 @@ static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p)
seq_puts(p, dev_name(gc->parent));
}
-static const struct irq_chip pl061_irq_chip = {
+static const struct irq_chip pl061_irqchip = {
+ .name = "pl061",
.irq_ack = pl061_irq_ack,
.irq_mask = pl061_irq_mask,
.irq_unmask = pl061_irq_unmask,
@@ -325,64 +274,187 @@ static const struct irq_chip pl061_irq_chip = {
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
+static int pl061_irq_domain_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct gpio_chip *gc = d->host_data;
+ struct pl061 *pl061 = pl061_from_gpio_chip(gc);
+
+ irq_set_chip_data(virq, gc);
+ irq_set_chip_and_handler(virq, &pl061_irqchip, handle_bad_irq);
+ irq_set_noprobe(virq);
+ irq_set_parent(virq, pl061->parent_irq);
+
+ return 0;
+}
+
+static void pl061_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
+{
+ irq_set_chip_and_handler(virq, NULL, NULL);
+ irq_set_chip_data(virq, NULL);
+}
+
+static const struct irq_domain_ops pl061_irq_domain_ops = {
+ .map = pl061_irq_domain_map,
+ .unmap = pl061_irq_domain_unmap,
+ .xlate = irq_domain_xlate_twothreecell,
+};
+
+static void pl061_remove_irq(void *data)
+{
+ struct pl061 *pl061 = data;
+
+ irq_set_chained_handler_and_data(pl061->parent_irq, NULL, NULL);
+
+ for (unsigned int i = 0; i < pl061->data->ngpio; i++) {
+ unsigned int virq;
+
+ virq = irq_find_mapping(pl061->irq_domain, i);
+ if (virq)
+ irq_dispose_mapping(virq);
+ }
+
+ irq_domain_remove(pl061->irq_domain);
+}
+
+static bool pl061_arm_is_data_reg(unsigned int reg)
+{
+ return reg >= BIT(PL061_DATA_OFFSET) &&
+ reg <= BIT(PL061_DATA_OFFSET + PL061_GPIO_NR - 1) &&
+ is_power_of_2(reg);
+}
+
+static bool pl061_arm_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PL061_MIS:
+ case PL061_IC:
+ return true;
+ default:
+ return pl061_arm_is_data_reg(reg);
+ }
+}
+
+static const struct regmap_config pl061_arm_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .reg_stride = 4,
+ .max_register = PL061_IC,
+ .volatile_reg = pl061_arm_volatile_reg,
+ .cache_type = REGCACHE_FLAT_S,
+ .fast_io = true,
+ .use_raw_spinlock = true,
+};
+
+static const struct pl061_regs pl061_arm_regs = {
+ .dir = PL061_DIR,
+ .is = PL061_IS,
+ .ibe = PL061_IBE,
+ .iev = PL061_IEV,
+ .ie = PL061_IE,
+ .mis = PL061_MIS,
+ .ic = PL061_IC,
+};
+
+static const struct pl061_drvdata pl061_arm = {
+ .regmap_config = &pl061_arm_regmap_config,
+ .regs = &pl061_arm_regs,
+ .ngpio = PL061_GPIO_NR,
+ .write_data_after_dir = true,
+ .pm = true,
+ .reg_mask_xlate = pl061_arm_reg_mask_xlate,
+};
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
+ const struct pl061_drvdata *data;
+ const struct pl061_regs *regs;
+ struct gpio_regmap_config config = {};
+ struct gpio_regmap *gpio_regmap;
+ struct gpio_chip *gc;
struct pl061 *pl061;
- struct gpio_irq_chip *girq;
void __iomem *base;
int ret, irq;
+ data = id->data;
+ if (!data)
+ return -ENODATA;
+
+ regs = data->regs;
+
pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
- if (pl061 == NULL)
+ if (!pl061)
return -ENOMEM;
+ pl061->data = data;
+ raw_spin_lock_init(&pl061->lock);
+
base = devm_ioremap_resource(dev, &adev->res);
if (IS_ERR(base))
return PTR_ERR(base);
- pl061->regmap = devm_regmap_init_mmio(dev, base, &pl061_regmap_config);
+ pl061->regmap = devm_regmap_init_mmio(dev, base, data->regmap_config);
if (IS_ERR(pl061->regmap))
return PTR_ERR(pl061->regmap);
- raw_spin_lock_init(&pl061->lock);
- pl061->gc.request = gpiochip_generic_request;
- pl061->gc.free = gpiochip_generic_free;
- pl061->gc.base = -1;
- pl061->gc.get_direction = pl061_get_direction;
- pl061->gc.direction_input = pl061_direction_input;
- pl061->gc.direction_output = pl061_direction_output;
- pl061->gc.get = pl061_get_value;
- pl061->gc.set = pl061_set_value;
- pl061->gc.ngpio = PL061_GPIO_NR;
- pl061->gc.label = dev_name(dev);
- pl061->gc.parent = dev;
- pl061->gc.owner = THIS_MODULE;
+ if (regs->enable) {
+ ret = regmap_write(pl061->regmap, regs->enable, ~0U);
+ if (ret)
+ return ret;
+ }
+ if (regs->mask) {
+ ret = regmap_write(pl061->regmap, regs->mask, ~0U);
+ if (ret)
+ return ret;
+ }
/*
* irq_chip support
*/
- regmap_write(pl061->regmap, GPIOIE, 0); /* disable irqs */
+ regmap_write(pl061->regmap, regs->ie, 0); /* disable irqs */
+
irq = adev->irq[0];
if (!irq)
- dev_warn(&adev->dev, "IRQ support disabled\n");
+ dev_warn(dev, "IRQ support disabled\n");
pl061->parent_irq = irq;
- girq = &pl061->gc.irq;
- gpio_irq_chip_set_chip(girq, &pl061_irq_chip);
- girq->parent_handler = pl061_irq_handler;
- girq->num_parents = 1;
- girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
- GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
- girq->parents[0] = irq;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_bad_irq;
-
- ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061);
- if (ret)
- return ret;
+ config.parent = dev;
+ config.regmap = pl061->regmap;
+ config.ngpio = data->ngpio;
+ config.reg_dat_base = GPIO_REGMAP_ADDR(regs->dat);
+ config.reg_set_base = GPIO_REGMAP_ADDR(regs->dat);
+ config.reg_dir_out_base = regs->dir;
+ config.reg_mask_xlate = data->reg_mask_xlate;
+ config.write_data_after_dir = data->write_data_after_dir;
+ config.drvdata = pl061;
+
+ gpio_regmap = devm_gpio_regmap_register(dev, &config);
+ if (IS_ERR(gpio_regmap))
+ return PTR_ERR(gpio_regmap);
+
+ gc = gpio_regmap_get_chip(gpio_regmap);
+
+ if (irq) {
+ pl061->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
+ data->ngpio,
+ &pl061_irq_domain_ops,
+ gc);
+ if (!pl061->irq_domain)
+ return -ENOMEM;
+
+ ret = gpiochip_irqchip_add_domain(gc, pl061->irq_domain);
+ if (ret) {
+ irq_domain_remove(pl061->irq_domain);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, pl061_remove_irq, pl061);
+ if (ret)
+ return ret;
+
+ irq_set_chained_handler_and_data(irq, pl061_irq_handler, gc);
+ }
amba_set_drvdata(adev, pl061);
dev_info(dev, "PL061 GPIO chip registered\n");
@@ -390,28 +462,38 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
}
+static void pl061_cache_ctrl_regs(struct pl061 *pl061, unsigned int *dir)
+{
+ const struct pl061_regs *regs = pl061->data->regs;
+ unsigned int val;
+
+ regmap_read(pl061->regmap, regs->dir, dir);
+ regmap_read(pl061->regmap, regs->is, &val);
+ regmap_read(pl061->regmap, regs->ibe, &val);
+ regmap_read(pl061->regmap, regs->iev, &val);
+ regmap_read(pl061->regmap, regs->ie, &val);
+}
+
static int pl061_suspend(struct device *dev)
{
struct pl061 *pl061 = dev_get_drvdata(dev);
- unsigned int val = 0;
- int offset;
-
- pl061->csave_regs.gpio_data = 0;
- regmap_read(pl061->regmap, GPIODIR, &val);
- pl061->csave_regs.gpio_dir = val;
- regmap_read(pl061->regmap, GPIOIS, &val);
- pl061->csave_regs.gpio_is = val;
- regmap_read(pl061->regmap, GPIOIBE, &val);
- pl061->csave_regs.gpio_ibe = val;
- regmap_read(pl061->regmap, GPIOIEV, &val);
- pl061->csave_regs.gpio_iev = val;
- regmap_read(pl061->regmap, GPIOIE, &val);
- pl061->csave_regs.gpio_ie = val;
-
- for (offset = 0; offset < PL061_GPIO_NR; offset++) {
- if (pl061->csave_regs.gpio_dir & (BIT(offset)))
- pl061->csave_regs.gpio_data |=
- pl061_get_value(&pl061->gc, offset) << offset;
+ unsigned long dir_mask;
+ unsigned int dir = 0, val;
+ unsigned int offset;
+
+ if (!pl061->data->pm)
+ return 0;
+
+ pl061_cache_ctrl_regs(pl061, &dir);
+
+ pl061->saved_dat = 0;
+ dir_mask = dir;
+ for_each_set_bit(offset, &dir_mask, pl061->data->ngpio) {
+ val = 0;
+ regmap_read_bypassed(pl061->regmap,
+ BIT(offset + PL061_DATA_OFFSET),
+ &val);
+ pl061->saved_dat |= val;
}
return 0;
@@ -420,23 +502,27 @@ static int pl061_suspend(struct device *dev)
static int pl061_resume(struct device *dev)
{
struct pl061 *pl061 = dev_get_drvdata(dev);
- int offset;
+ const struct pl061_regs *regs;
+ unsigned long dir_mask;
+ unsigned int dir = 0, offset;
- for (offset = 0; offset < PL061_GPIO_NR; offset++) {
- if (pl061->csave_regs.gpio_dir & (BIT(offset)))
- pl061_direction_output(&pl061->gc, offset,
- pl061->csave_regs.gpio_data &
- (BIT(offset)));
- else
- pl061_direction_input(&pl061->gc, offset);
- }
+ if (!pl061->data->pm)
+ return 0;
- regmap_write(pl061->regmap, GPIOIS, pl061->csave_regs.gpio_is);
- regmap_write(pl061->regmap, GPIOIBE, pl061->csave_regs.gpio_ibe);
- regmap_write(pl061->regmap, GPIOIEV, pl061->csave_regs.gpio_iev);
- regmap_write(pl061->regmap, GPIOIE, pl061->csave_regs.gpio_ie);
+ regs = pl061->data->regs;
- return 0;
+ regmap_read(pl061->regmap, regs->dir, &dir);
+
+ regcache_mark_dirty(pl061->regmap);
+ regcache_sync_region(pl061->regmap, regs->dir, regs->dir);
+
+ dir_mask = dir;
+ for_each_set_bit(offset, &dir_mask, pl061->data->ngpio)
+ regmap_write(pl061->regmap,
+ BIT(offset + PL061_DATA_OFFSET),
+ !!(pl061->saved_dat & BIT(offset)) << offset);
+
+ return regcache_sync_region(pl061->regmap, regs->is, regs->ie);
}
static DEFINE_SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
@@ -445,6 +531,7 @@ static const struct amba_id pl061_ids[] = {
{
.id = 0x00041061,
.mask = 0x000fffff,
+ .data = (void *)&pl061_arm,
},
{ 0, 0 },
};
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 14/18] gpio: pl061: add Ambarella register-layout variant
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (12 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 13/18] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller Long Zhao via B4 Relay
` (4 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Add a 32-bit, 32-line layout with DAT/DIR/IS/IBE/IEV/IE/MIS/IC plus
MASK and ENABLE. Probe unmasks the bank and enables the controller.
IRQ type changes also clear the pending bit. This derivative does not
need write-after-direction or system suspend save/restore.
Match the part with designer AMBA_VENDOR_AMBARELLA (JEP106 identity
0x68, bit 7 set) and part number 0x061.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/gpio-pl061.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/amba/bus.h | 1 +
2 files changed, 60 insertions(+)
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 604129a68948..fc7269837af4 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -39,6 +39,18 @@
#define PL061_MIS 0x418
#define PL061_IC 0x41c
+#define AMBARELLA_GPIO_NR 32
+#define AMBARELLA_DAT 0x00
+#define AMBARELLA_DIR 0x04
+#define AMBARELLA_IS 0x08
+#define AMBARELLA_IBE 0x0c
+#define AMBARELLA_IEV 0x10
+#define AMBARELLA_IE 0x14
+#define AMBARELLA_MIS 0x20
+#define AMBARELLA_IC 0x24
+#define AMBARELLA_MASK 0x28
+#define AMBARELLA_ENABLE 0x2c
+
struct pl061_regs {
unsigned int dat;
unsigned int dir;
@@ -335,6 +347,18 @@ static bool pl061_arm_volatile_reg(struct device *dev, unsigned int reg)
}
}
+static bool pl061_ambarella_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AMBARELLA_DAT:
+ case AMBARELLA_MIS:
+ case AMBARELLA_IC:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct regmap_config pl061_arm_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
@@ -346,6 +370,16 @@ static const struct regmap_config pl061_arm_regmap_config = {
.use_raw_spinlock = true,
};
+static const struct regmap_config pl061_ambarella_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = AMBARELLA_ENABLE,
+ .volatile_reg = pl061_ambarella_volatile_reg,
+ .fast_io = true,
+ .use_raw_spinlock = true,
+};
+
static const struct pl061_regs pl061_arm_regs = {
.dir = PL061_DIR,
.is = PL061_IS,
@@ -356,6 +390,19 @@ static const struct pl061_regs pl061_arm_regs = {
.ic = PL061_IC,
};
+static const struct pl061_regs pl061_ambarella_regs = {
+ .dat = AMBARELLA_DAT,
+ .dir = AMBARELLA_DIR,
+ .is = AMBARELLA_IS,
+ .ibe = AMBARELLA_IBE,
+ .iev = AMBARELLA_IEV,
+ .ie = AMBARELLA_IE,
+ .mis = AMBARELLA_MIS,
+ .ic = AMBARELLA_IC,
+ .mask = AMBARELLA_MASK,
+ .enable = AMBARELLA_ENABLE,
+};
+
static const struct pl061_drvdata pl061_arm = {
.regmap_config = &pl061_arm_regmap_config,
.regs = &pl061_arm_regs,
@@ -365,6 +412,13 @@ static const struct pl061_drvdata pl061_arm = {
.reg_mask_xlate = pl061_arm_reg_mask_xlate,
};
+static const struct pl061_drvdata pl061_ambarella = {
+ .regmap_config = &pl061_ambarella_regmap_config,
+ .regs = &pl061_ambarella_regs,
+ .ngpio = AMBARELLA_GPIO_NR,
+ .clear_irq_on_type = true,
+};
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -533,6 +587,11 @@ static const struct amba_id pl061_ids[] = {
.mask = 0x000fffff,
.data = (void *)&pl061_arm,
},
+ {
+ .id = (AMBA_VENDOR_AMBARELLA << 12) | 0x061,
+ .mask = 0x000fffff,
+ .data = (void *)&pl061_ambarella,
+ },
{ 0, 0 },
};
MODULE_DEVICE_TABLE(amba, pl061_ids);
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index 80a74cd2da7e..411533bfa61d 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -98,6 +98,7 @@ enum amba_vendor {
AMBA_VENDOR_ST = 0x80,
AMBA_VENDOR_QCOM = 0x51,
AMBA_VENDOR_LSI = 0xb6,
+ AMBA_VENDOR_AMBARELLA = 0xe8,
};
extern const struct bus_type amba_bustype;
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (13 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 14/18] gpio: pl061: add Ambarella register-layout variant Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-22 7:28 ` Linus Walleij
2026-10-01 7:05 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 16/18] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
` (3 subsequent siblings)
18 siblings, 2 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Add an Ambarella pinmux-only pinctrl driver with CV75 function/group
tables. GPIO is handled by the PL061 driver.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/pinctrl/Kconfig | 17 +
drivers/pinctrl/Makefile | 2 +
drivers/pinctrl/pinctrl-ambarella-cv75.c | 587 +++++++++++++++++++++++++++++++
drivers/pinctrl/pinctrl-ambarella.c | 533 ++++++++++++++++++++++++++++
drivers/pinctrl/pinctrl-ambarella.h | 40 +++
5 files changed, 1179 insertions(+)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c2cdd7b2c49b..08fbe3dc041b 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -37,6 +37,23 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+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 GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GPIOLIB
+ select GPIO_PL061
+ select MFD_SYSCON
+ select PINCONF
+ select PINMUX
+ help
+ Say Y here to enable the Ambarella pinmux/pinconf controller.
+ GPIO is provided by the PL061 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) += pinconf-generic.o
obj-$(CONFIG_GENERIC_PINCTRL) += pinctrl-generic.o
obj-$(CONFIG_OF) += devicetree.o
+obj-$(CONFIG_PINCTRL_AMB) += pinctrl-ambarella.o
+obj-$(CONFIG_PINCTRL_AMB) += pinctrl-ambarella-cv75.o
obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o
obj-$(CONFIG_PINCTRL_AMDISP) += pinctrl-amdisp.o
obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o
diff --git a/drivers/pinctrl/pinctrl-ambarella-cv75.c b/drivers/pinctrl/pinctrl-ambarella-cv75.c
new file mode 100644
index 000000000000..eb25fd94ece8
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ambarella-cv75.c
@@ -0,0 +1,587 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Ambarella CV75 pinctrl data
+ *
+ * Copyright (C) 2026, Ambarella, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/build_bug.h>
+#include <linux/types.h>
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-ambarella.h"
+
+#define CV75_EXPAND(...) __VA_ARGS__
+#define CV75_GROUP_PINS_ALTS(_name, _pin_list, _alt_list) \
+ static const unsigned int cv75_##_name##_pins[] = { CV75_EXPAND _pin_list }; \
+ static const u8 cv75_##_name##_alts[] = { CV75_EXPAND _alt_list }; \
+ static const struct pingroup cv75_##_name##_grp = \
+ PINCTRL_PINGROUP(#_name, cv75_##_name##_pins, \
+ ARRAY_SIZE(cv75_##_name##_pins)); \
+ static_assert(ARRAY_SIZE(cv75_##_name##_pins) == \
+ ARRAY_SIZE(cv75_##_name##_alts))
+
+#define CV75_GROUP(_name) \
+{ \
+ .grp = &cv75_##_name##_grp, \
+ .alts = cv75_##_name##_alts, \
+}
+
+#define CV75_FUNCTION(_name) \
+ PINCTRL_PINFUNCTION(#_name, cv75_##_name##_groups, ARRAY_SIZE(cv75_##_name##_groups))
+
+/* UART */
+CV75_GROUP_PINS_ALTS(uart0, (44, 45), (1, 1));
+CV75_GROUP_PINS_ALTS(uart1, (46, 47), (1, 1));
+CV75_GROUP_PINS_ALTS(uart1_flow, (48, 49), (1, 1));
+CV75_GROUP_PINS_ALTS(uart2_a, (46, 47), (2, 2));
+CV75_GROUP_PINS_ALTS(uart2_b, (50, 51), (2, 2));
+CV75_GROUP_PINS_ALTS(uart2_c, (66, 68), (2, 2));
+CV75_GROUP_PINS_ALTS(uart2_flow_a, (48, 49), (2, 2));
+CV75_GROUP_PINS_ALTS(uart2_flow_b, (65, 67), (3, 3));
+CV75_GROUP_PINS_ALTS(uart3_a, (70, 72), (3, 3));
+CV75_GROUP_PINS_ALTS(uart3_b, (80, 79), (3, 3));
+CV75_GROUP_PINS_ALTS(uart3_flow_a, (71, 69), (3, 3));
+CV75_GROUP_PINS_ALTS(uart3_flow_b, (81, 82), (3, 3));
+CV75_GROUP_PINS_ALTS(uart4_a, (29, 30), (3, 3));
+CV75_GROUP_PINS_ALTS(uart4_b, (76, 77), (3, 3));
+CV75_GROUP_PINS_ALTS(uart4_flow_a, (28, 31), (3, 3));
+CV75_GROUP_PINS_ALTS(uart4_flow_b, (74, 75), (3, 3));
+
+/* Flash */
+CV75_GROUP_PINS_ALTS(snand, (79, 80, 81, 82, 83, 84), (1, 1, 1, 1, 1, 1));
+CV75_GROUP_PINS_ALTS(spinor, (79, 80, 81, 82, 83, 84, 85),
+ (2, 2, 2, 2, 2, 2, 2));
+
+/* SD/MMC */
+CV75_GROUP_PINS_ALTS(sdmmc0_cd, (6), (1));
+CV75_GROUP_PINS_ALTS(sdmmc0_wp, (7), (1));
+CV75_GROUP_PINS_ALTS(sdmmc0_reset, (8), (1));
+CV75_GROUP_PINS_ALTS(sdmmc0_hs_sel, (93), (1));
+CV75_GROUP_PINS_ALTS(sdmmc0_1bit, (0, 4, 5), (1, 1, 1));
+CV75_GROUP_PINS_ALTS(sdmmc0_4bit, (0, 1, 2, 3, 4, 5), (1, 1, 1, 1, 1, 1));
+CV75_GROUP_PINS_ALTS(sdmmc1_cd, (15), (1));
+CV75_GROUP_PINS_ALTS(sdmmc1_wp, (16), (1));
+CV75_GROUP_PINS_ALTS(sdmmc1_reset, (17), (1));
+CV75_GROUP_PINS_ALTS(sdmmc1_hs_sel, (94), (1));
+CV75_GROUP_PINS_ALTS(sdmmc1_1bit, (9, 13, 14), (1, 1, 1));
+CV75_GROUP_PINS_ALTS(sdmmc1_4bit, (9, 10, 11, 12, 13, 14), (1, 1, 1, 1, 1, 1));
+
+/* Ethernet */
+CV75_GROUP_PINS_ALTS(enet_ext_osc_clk, (77), (1));
+CV75_GROUP_PINS_ALTS(enet_2nd_ref_clk_a, (78), (1));
+CV75_GROUP_PINS_ALTS(enet_2nd_ref_clk_b, (76), (2));
+CV75_GROUP_PINS_ALTS(enet0_ptp_pps_o, (74), (1));
+CV75_GROUP_PINS_ALTS(rgmii0, (62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76),
+ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
+CV75_GROUP_PINS_ALTS(rmii0, (62, 63, 64, 67, 68, 71, 72, 73, 75),
+ (1, 1, 1, 1, 1, 1, 1, 1, 2));
+
+/* I2C */
+CV75_GROUP_PINS_ALTS(i2c0_a, (67, 68), (2, 2));
+CV75_GROUP_PINS_ALTS(i2c0_b, (86, 87), (1, 1));
+CV75_GROUP_PINS_ALTS(i2c1_a, (22, 23), (2, 2));
+CV75_GROUP_PINS_ALTS(i2c1_b, (69, 70), (2, 2));
+CV75_GROUP_PINS_ALTS(i2c2, (88, 89), (1, 1));
+CV75_GROUP_PINS_ALTS(i2c3_a, (24, 25), (2, 2));
+CV75_GROUP_PINS_ALTS(i2c3_b, (48, 49), (3, 3));
+CV75_GROUP_PINS_ALTS(i2c3_c, (58, 59), (3, 3));
+CV75_GROUP_PINS_ALTS(i2cs_a, (19, 21), (2, 2));
+CV75_GROUP_PINS_ALTS(i2cs_b, (60, 61), (3, 3));
+CV75_GROUP_PINS_ALTS(i2cs_c, (71, 72), (2, 2));
+CV75_GROUP_PINS_ALTS(i2cs_d, (86, 87), (2, 2));
+
+/* CAN, IR, WDT */
+CV75_GROUP_PINS_ALTS(can0, (50, 51), (1, 1));
+CV75_GROUP_PINS_ALTS(can1, (52, 53), (1, 1));
+CV75_GROUP_PINS_ALTS(ir, (18), (1));
+CV75_GROUP_PINS_ALTS(wdt_a, (20), (2));
+CV75_GROUP_PINS_ALTS(wdt_b, (27), (3));
+CV75_GROUP_PINS_ALTS(wdt_c, (39), (2));
+CV75_GROUP_PINS_ALTS(wdt_d, (83), (3));
+CV75_GROUP_PINS_ALTS(wdt_e, (85), (4));
+CV75_GROUP_PINS_ALTS(wdt_f, (90), (1));
+
+/* I2S */
+CV75_GROUP_PINS_ALTS(i2s0, (54, 55, 56, 57), (1, 1, 1, 1));
+CV75_GROUP_PINS_ALTS(i2s1, (58, 59, 60, 61), (1, 1, 1, 1));
+CV75_GROUP_PINS_ALTS(dmic0, (54, 55), (2, 2));
+
+/* PWM */
+CV75_GROUP_PINS_ALTS(pwm0, (40), (1));
+CV75_GROUP_PINS_ALTS(pwm1, (41), (1));
+CV75_GROUP_PINS_ALTS(pwm2, (42), (1));
+CV75_GROUP_PINS_ALTS(pwm3, (43), (1));
+CV75_GROUP_PINS_ALTS(pwm4_a, (19), (3));
+CV75_GROUP_PINS_ALTS(pwm4_b, (32), (4));
+CV75_GROUP_PINS_ALTS(pwm5_a, (20), (3));
+CV75_GROUP_PINS_ALTS(pwm5_b, (33), (4));
+CV75_GROUP_PINS_ALTS(pwm6_a, (21), (3));
+CV75_GROUP_PINS_ALTS(pwm6_b, (34), (4));
+CV75_GROUP_PINS_ALTS(pwm7_a, (22), (3));
+CV75_GROUP_PINS_ALTS(pwm7_b, (35), (4));
+CV75_GROUP_PINS_ALTS(pwm8_a, (23), (3));
+CV75_GROUP_PINS_ALTS(pwm8_b, (36), (4));
+CV75_GROUP_PINS_ALTS(pwm9_a, (24), (3));
+CV75_GROUP_PINS_ALTS(pwm9_b, (37), (4));
+CV75_GROUP_PINS_ALTS(pwm10_a, (25), (3));
+CV75_GROUP_PINS_ALTS(pwm10_b, (38), (4));
+CV75_GROUP_PINS_ALTS(pwm11_a, (26), (3));
+CV75_GROUP_PINS_ALTS(pwm11_b, (39), (4));
+
+/* SPI */
+CV75_GROUP_PINS_ALTS(spi0, (19, 20, 21), (1, 1, 1));
+CV75_GROUP_PINS_ALTS(spi1, (24, 25, 26), (1, 1, 1));
+CV75_GROUP_PINS_ALTS(spi2, (28, 29, 30), (1, 1, 1));
+CV75_GROUP_PINS_ALTS(spi3_a, (32, 33, 34), (5, 5, 5));
+CV75_GROUP_PINS_ALTS(spi3_b, (40, 41, 43), (2, 2, 2));
+CV75_GROUP_PINS_ALTS(spi3_c, (58, 59, 60), (2, 2, 2));
+CV75_GROUP_PINS_ALTS(spi_slave_a, (24, 25, 26, 27), (4, 4, 4, 4));
+CV75_GROUP_PINS_ALTS(spi_slave_b, (28, 29, 30, 31), (2, 2, 2, 2));
+CV75_GROUP_PINS_ALTS(spi_slave_c, (36, 37, 38, 39), (5, 5, 5, 5));
+CV75_GROUP_PINS_ALTS(spi_slave_d, (50, 51, 52, 53), (3, 3, 3, 3));
+CV75_GROUP_PINS_ALTS(spi_slave_e, (81, 82, 83, 84), (4, 4, 4, 4));
+
+/* VIN master sync */
+CV75_GROUP_PINS_ALTS(vin_master_sync_a, (91, 92), (1, 1));
+CV75_GROUP_PINS_ALTS(vin_master_sync_b, (91, 92), (2, 2));
+CV75_GROUP_PINS_ALTS(vin_master_sync_c, (40, 41), (3, 3));
+CV75_GROUP_PINS_ALTS(vin_master_sync_d, (46, 47), (3, 3));
+CV75_GROUP_PINS_ALTS(vin_master_sync_e, (79, 80), (4, 4));
+CV75_GROUP_PINS_ALTS(vsync0, (32), (1));
+CV75_GROUP_PINS_ALTS(vsync1, (33), (1));
+CV75_GROUP_PINS_ALTS(vsync2, (34), (1));
+CV75_GROUP_PINS_ALTS(vsync3, (35), (1));
+CV75_GROUP_PINS_ALTS(hsync0, (36), (1));
+CV75_GROUP_PINS_ALTS(hsync1, (37), (1));
+
+static const struct amb_pinmux_group cv75_pin_groups[] = {
+ /* UART */
+ 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),
+ /* Flash */
+ CV75_GROUP(snand),
+ CV75_GROUP(spinor),
+ /* SD/MMC */
+ 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),
+ /* Ethernet */
+ 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),
+ /* I2C */
+ 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),
+ /* CAN, IR, WDT */
+ 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),
+ /* I2S */
+ CV75_GROUP(i2s0),
+ CV75_GROUP(i2s1),
+ CV75_GROUP(dmic0),
+ /* PWM */
+ 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),
+ /* SPI */
+ 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),
+ /* VIN master sync */
+ 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[] = {
+ "uart0",
+};
+
+static const char * const cv75_uart1_groups[] = {
+ "uart1",
+ "uart1_flow",
+};
+
+static const char * const cv75_uart2_groups[] = {
+ "uart2_a",
+ "uart2_b",
+ "uart2_c",
+ "uart2_flow_a",
+ "uart2_flow_b",
+};
+
+static const char * const cv75_uart3_groups[] = {
+ "uart3_a",
+ "uart3_b",
+ "uart3_flow_a",
+ "uart3_flow_b",
+};
+
+static const char * const cv75_uart4_groups[] = {
+ "uart4_a",
+ "uart4_b",
+ "uart4_flow_a",
+ "uart4_flow_b",
+};
+
+static const char * const cv75_snand_groups[] = {
+ "snand",
+};
+
+static const char * const cv75_spinor_groups[] = {
+ "spinor",
+};
+
+static const char * const cv75_sdmmc0_groups[] = {
+ "sdmmc0_cd",
+ "sdmmc0_wp",
+ "sdmmc0_reset",
+ "sdmmc0_hs_sel",
+ "sdmmc0_1bit",
+ "sdmmc0_4bit",
+};
+
+static const char * const cv75_sdmmc1_groups[] = {
+ "sdmmc1_cd",
+ "sdmmc1_wp",
+ "sdmmc1_reset",
+ "sdmmc1_hs_sel",
+ "sdmmc1_1bit",
+ "sdmmc1_4bit",
+};
+
+static const char * const cv75_enet0_groups[] = {
+ "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[] = {
+ "i2c0_a",
+ "i2c0_b",
+};
+
+static const char * const cv75_i2c1_groups[] = {
+ "i2c1_a",
+ "i2c1_b",
+};
+
+static const char * const cv75_i2c2_groups[] = {
+ "i2c2",
+};
+
+static const char * const cv75_i2c3_groups[] = {
+ "i2c3_a",
+ "i2c3_b",
+ "i2c3_c",
+};
+
+static const char * const cv75_i2cs_groups[] = {
+ "i2cs_a",
+ "i2cs_b",
+ "i2cs_c",
+ "i2cs_d",
+};
+
+static const char * const cv75_can0_groups[] = {
+ "can0",
+};
+
+static const char * const cv75_can1_groups[] = {
+ "can1",
+};
+
+static const char * const cv75_ir_groups[] = {
+ "ir",
+};
+
+static const char * const cv75_wdt_groups[] = {
+ "wdt_a",
+ "wdt_b",
+ "wdt_c",
+ "wdt_d",
+ "wdt_e",
+ "wdt_f",
+};
+
+static const char * const cv75_i2s0_groups[] = {
+ "i2s0",
+};
+
+static const char * const cv75_i2s1_groups[] = {
+ "i2s1",
+};
+
+static const char * const cv75_dmic0_groups[] = {
+ "dmic0",
+};
+
+static const char * const cv75_pwm0_groups[] = {
+ "pwm0",
+};
+
+static const char * const cv75_pwm1_groups[] = {
+ "pwm1",
+};
+
+static const char * const cv75_pwm2_groups[] = {
+ "pwm2",
+};
+
+static const char * const cv75_pwm3_groups[] = {
+ "pwm3",
+};
+
+static const char * const cv75_pwm4_groups[] = {
+ "pwm4_a",
+ "pwm4_b",
+};
+
+static const char * const cv75_pwm5_groups[] = {
+ "pwm5_a",
+ "pwm5_b",
+};
+
+static const char * const cv75_pwm6_groups[] = {
+ "pwm6_a",
+ "pwm6_b",
+};
+
+static const char * const cv75_pwm7_groups[] = {
+ "pwm7_a",
+ "pwm7_b",
+};
+
+static const char * const cv75_pwm8_groups[] = {
+ "pwm8_a",
+ "pwm8_b",
+};
+
+static const char * const cv75_pwm9_groups[] = {
+ "pwm9_a",
+ "pwm9_b",
+};
+
+static const char * const cv75_pwm10_groups[] = {
+ "pwm10_a",
+ "pwm10_b",
+};
+
+static const char * const cv75_pwm11_groups[] = {
+ "pwm11_a",
+ "pwm11_b",
+};
+
+static const char * const cv75_spi0_groups[] = {
+ "spi0",
+};
+
+static const char * const cv75_spi1_groups[] = {
+ "spi1",
+};
+
+static const char * const cv75_spi2_groups[] = {
+ "spi2",
+};
+
+static const char * const cv75_spi3_groups[] = {
+ "spi3_a",
+ "spi3_b",
+ "spi3_c",
+};
+
+static const char * const cv75_spi_slave_groups[] = {
+ "spi_slave_a",
+ "spi_slave_b",
+ "spi_slave_c",
+ "spi_slave_d",
+ "spi_slave_e",
+};
+
+static const char * const cv75_vin_master_sync_groups[] = {
+ "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[] = {
+ "vsync0",
+};
+
+static const char * const cv75_vsync1_groups[] = {
+ "vsync1",
+};
+
+static const char * const cv75_vsync2_groups[] = {
+ "vsync2",
+};
+
+static const char * const cv75_vsync3_groups[] = {
+ "vsync3",
+};
+
+static const char * const cv75_hsync0_groups[] = {
+ "hsync0",
+};
+
+static const char * const cv75_hsync1_groups[] = {
+ "hsync1",
+};
+
+static const struct pinfunction cv75_pin_functions[] = {
+ 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(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 = {
+ .groups = cv75_pin_groups,
+ .functions = cv75_pin_functions,
+ .ngroups = ARRAY_SIZE(cv75_pin_groups),
+ .nfunctions = ARRAY_SIZE(cv75_pin_functions),
+ .nr_banks = 3,
+ .npins = 96,
+ .ds0 = {
+ 0x314, 0x320, 0x32c,
+ },
+ .ds1 = {
+ 0x318, 0x324, 0x330,
+ },
+ .ds2 = {
+ 0x31c, 0x328, 0x334,
+ },
+ .pull_en = {
+ 0x60, 0x64, 0x68,
+ },
+ .pull_dir = {
+ 0x7c, 0x80, 0x84,
+ },
+ .have_ds2 = true,
+};
diff --git a/drivers/pinctrl/pinctrl-ambarella.c b/drivers/pinctrl/pinctrl-ambarella.c
new file mode 100644
index 000000000000..83afef6a123f
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ambarella.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl driver for Ambarella SoCs
+ *
+ * Copyright (C) 2012-2026, Ambarella, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string_helpers.h>
+#include <linux/types.h>
+
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "core.h"
+#include "pinmux.h"
+#include "pinctrl-ambarella.h"
+
+#define IOMUX_REG(bank, n) (((bank) * 0xc) + ((n) * 4))
+#define IOMUX_CTRL_SET 0xf0
+
+#define PINID_TO_BANK(p) ((p) >> 5)
+#define PINID_TO_OFFSET(p) ((p) & 0x1f)
+
+struct amb_pinctrl {
+ struct pinctrl_desc desc;
+ void __iomem *iomux_base;
+ struct regmap *ds_regmap;
+ struct regmap *pull_regmap;
+ const struct amb_pinctrl_data *data;
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ spinlock_t lock;
+};
+
+static const int amb_ds1_ma[] = { 2, 4, 8, 12 };
+static const int amb_ds2_ma[] = { 3, 4, 6, 8, 9, 12 };
+
+static const struct pinctrl_ops amb_pctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static void amb_iomux_commit(struct amb_pinctrl *ipc)
+{
+ writel(0x1, ipc->iomux_base + IOMUX_CTRL_SET);
+ writel(0x0, ipc->iomux_base + IOMUX_CTRL_SET);
+}
+
+static void amb_pinmux_set_altfunc(struct amb_pinctrl *ipc, u32 bank,
+ u32 offset, u32 altfunc)
+{
+ if (bank >= ipc->data->nr_banks)
+ return;
+
+ for (unsigned int i = 0; i < 3; i++) {
+ unsigned long data;
+
+ data = readl_relaxed(ipc->iomux_base + IOMUX_REG(bank, i));
+ __assign_bit(offset, &data, altfunc & BIT(i));
+ writel_relaxed(data, ipc->iomux_base + IOMUX_REG(bank, i));
+ }
+}
+
+static int amb_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int selector, unsigned int group)
+{
+ struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
+ struct group_desc *grp;
+ const u8 *alts;
+ unsigned long flags;
+
+ (void)selector;
+
+ grp = pinctrl_generic_get_group(pctldev, group);
+ if (!grp || !grp->data)
+ return -EINVAL;
+
+ alts = grp->data;
+
+ spin_lock_irqsave(&ipc->lock, flags);
+ for (unsigned int i = 0; i < grp->grp.npins; i++) {
+ unsigned int pin = grp->grp.pins[i];
+
+ amb_pinmux_set_altfunc(ipc, PINID_TO_BANK(pin),
+ PINID_TO_OFFSET(pin), alts[i]);
+ }
+ amb_iomux_commit(ipc);
+ spin_unlock_irqrestore(&ipc->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 *ipc = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long flags;
+
+ if (!range || !range->gc)
+ return -EINVAL;
+
+ if (pin >= ipc->data->npins)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ipc->lock, flags);
+ amb_pinmux_set_altfunc(ipc, PINID_TO_BANK(pin), PINID_TO_OFFSET(pin), 0);
+ amb_iomux_commit(ipc);
+ spin_unlock_irqrestore(&ipc->lock, flags);
+
+ return 0;
+}
+
+static const struct pinmux_ops amb_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = amb_pinmux_set_mux,
+ .gpio_request_enable = amb_pinmux_gpio_request_enable,
+ .strict = true,
+};
+
+static int amb_drive_strength_to_reg_ds1(u32 strength)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(amb_ds1_ma); i++) {
+ if (amb_ds1_ma[i] == strength)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int amb_drive_strength_to_reg_ds2(u32 strength)
+{
+ /* Hardware steps are 3, 4, 6, 8, 9, 12 mA; 5 and 7 are accepted aliases */
+ if (strength == 5)
+ strength = 4;
+ else if (strength == 7)
+ strength = 8;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(amb_ds2_ma); i++) {
+ if (amb_ds2_ma[i] == strength)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int amb_drive_strength_to_reg(const struct amb_pinctrl *ipc, u32 strength)
+{
+ if (ipc->data->have_ds2)
+ return amb_drive_strength_to_reg_ds2(strength);
+
+ return amb_drive_strength_to_reg_ds1(strength);
+}
+
+static int amb_reg_to_drive_strength(const struct amb_pinctrl *ipc, u32 ds)
+{
+ if (ipc->data->have_ds2) {
+ if (ds >= ARRAY_SIZE(amb_ds2_ma))
+ return -EINVAL;
+ return amb_ds2_ma[ds];
+ }
+
+ if (ds >= ARRAY_SIZE(amb_ds1_ma))
+ return -EINVAL;
+
+ return amb_ds1_ma[ds];
+}
+
+static int amb_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
+ u32 bank = PINID_TO_BANK(pin);
+ u32 offset = PINID_TO_OFFSET(pin);
+ unsigned int mask = BIT(offset);
+ int ret;
+
+ if (bank >= ipc->data->nr_banks)
+ return -EINVAL;
+
+ for (unsigned int i = 0; i < num_configs; i++) {
+ enum pin_config_param param = pinconf_to_config_param(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
+ int ds;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ ret = regmap_assign_bits(ipc->pull_regmap, ipc->data->pull_en[bank],
+ mask, false);
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ ret = regmap_assign_bits(ipc->pull_regmap, ipc->data->pull_dir[bank],
+ mask, param == PIN_CONFIG_BIAS_PULL_UP);
+ if (ret)
+ return ret;
+ ret = regmap_assign_bits(ipc->pull_regmap, ipc->data->pull_en[bank],
+ mask, true);
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ds = amb_drive_strength_to_reg(ipc, arg);
+ if (ds < 0)
+ return ds;
+ if (ipc->data->have_ds2) {
+ ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds0[bank],
+ mask, ds & BIT(0));
+ if (ret)
+ return ret;
+ ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds1[bank],
+ mask, ds & BIT(1));
+ if (ret)
+ return ret;
+ ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds2[bank],
+ mask, ds & BIT(2));
+ if (ret)
+ return ret;
+ } else {
+ ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds0[bank],
+ mask, ds & BIT(1));
+ if (ret)
+ return ret;
+ ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds1[bank],
+ mask, ds & BIT(0));
+ if (ret)
+ return ret;
+ }
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int amb_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (unsigned int i = 0; i < npins; i++) {
+ ret = amb_pinconf_set(pctldev, pins[i], configs, num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int amb_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 bank = PINID_TO_BANK(pin);
+ u32 offset = PINID_TO_OFFSET(pin);
+ u32 pull_en, pull_dir, ds0, ds1, ds2, ds;
+ bool en, dir, b0, b1, b2;
+ int ret, strength;
+
+ if (bank >= ipc->data->nr_banks)
+ return -EINVAL;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ ret = regmap_read(ipc->pull_regmap, ipc->data->pull_en[bank],
+ &pull_en);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(ipc->pull_regmap, ipc->data->pull_dir[bank],
+ &pull_dir);
+ if (ret)
+ return ret;
+
+ en = !!(pull_en & BIT(offset));
+ dir = !!(pull_dir & BIT(offset));
+
+ if (param == PIN_CONFIG_BIAS_DISABLE) {
+ if (en)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 0);
+ return 0;
+ }
+
+ if (!en)
+ return -EINVAL;
+ if (param == PIN_CONFIG_BIAS_PULL_UP && !dir)
+ return -EINVAL;
+ if (param == PIN_CONFIG_BIAS_PULL_DOWN && dir)
+ return -EINVAL;
+
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = regmap_read(ipc->ds_regmap, ipc->data->ds0[bank], &ds0);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(ipc->ds_regmap, ipc->data->ds1[bank], &ds1);
+ if (ret)
+ return ret;
+
+ b0 = !!(ds0 & BIT(offset));
+ b1 = !!(ds1 & BIT(offset));
+ if (ipc->data->have_ds2) {
+ ret = regmap_read(ipc->ds_regmap, ipc->data->ds2[bank],
+ &ds2);
+ if (ret)
+ return ret;
+
+ b2 = !!(ds2 & BIT(offset));
+ ds = (b2 << 2) | (b1 << 1) | b0;
+ } else {
+ ds = (b0 << 1) | b1;
+ }
+
+ strength = amb_reg_to_drive_strength(ipc, ds);
+ if (strength < 0)
+ return strength;
+
+ *config = pinconf_to_config_packed(param, strength);
+ return 0;
+
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static const struct pinconf_ops amb_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = amb_pinconf_get,
+ .pin_config_set = amb_pinconf_set,
+ .pin_config_group_set = amb_pinconf_group_set,
+};
+
+static int amb_pinctrl_add_groups(struct amb_pinctrl *ipc)
+{
+ const struct amb_pinctrl_data *data = ipc->data;
+
+ for (unsigned int i = 0; i < data->ngroups; i++) {
+ const struct amb_pinmux_group *g = &data->groups[i];
+ int ret;
+
+ if (!g->grp || !g->grp->name || !g->grp->pins ||
+ !g->grp->npins || !g->alts)
+ return -EINVAL;
+
+ for (unsigned int j = 0; j < g->grp->npins; j++) {
+ if (g->grp->pins[j] >= data->npins)
+ return -EINVAL;
+ }
+
+ ret = pinctrl_generic_add_group(ipc->pctl, g->grp->name,
+ g->grp->pins, g->grp->npins,
+ (void *)g->alts);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int amb_pinctrl_add_functions(struct amb_pinctrl *ipc)
+{
+ const struct amb_pinctrl_data *data = ipc->data;
+
+ for (unsigned int i = 0; i < data->nfunctions; i++) {
+ int ret;
+
+ ret = pinmux_generic_add_pinfunction(ipc->pctl,
+ &data->functions[i], NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int amb_pinctrl_register(struct amb_pinctrl *ipc)
+{
+ struct pinctrl_pin_desc *pindesc;
+ char **names;
+ int ret;
+
+ pindesc = devm_kcalloc(ipc->dev, ipc->data->npins, sizeof(*pindesc),
+ GFP_KERNEL);
+ if (!pindesc)
+ return -ENOMEM;
+
+ names = devm_kasprintf_strarray(ipc->dev, "io", ipc->data->npins);
+ if (!names)
+ return -ENOMEM;
+
+ for (unsigned int pin = 0; pin < ipc->data->npins; pin++) {
+ pindesc[pin].number = pin;
+ pindesc[pin].name = names[pin];
+ }
+
+ ipc->desc.name = dev_name(ipc->dev);
+ ipc->desc.pins = pindesc;
+ ipc->desc.npins = ipc->data->npins;
+ ipc->desc.pctlops = &amb_pctrl_ops;
+ ipc->desc.pmxops = &amb_pinmux_ops;
+ ipc->desc.confops = &amb_pinconf_ops;
+ ipc->desc.owner = THIS_MODULE;
+
+ ret = devm_pinctrl_register_and_init(ipc->dev, &ipc->desc, ipc, &ipc->pctl);
+ if (ret)
+ return ret;
+
+ ret = amb_pinctrl_add_groups(ipc);
+ if (ret)
+ return ret;
+
+ ret = amb_pinctrl_add_functions(ipc);
+ if (ret)
+ return ret;
+
+ return pinctrl_enable(ipc->pctl);
+}
+
+static int amb_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct amb_pinctrl *ipc;
+ int ret;
+
+ ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
+ if (!ipc)
+ return -ENOMEM;
+
+ ipc->dev = dev;
+ ipc->data = device_get_match_data(dev);
+ if (!ipc->data)
+ return dev_err_probe(dev, -ENODATA, "missing SoC data\n");
+
+ if (!ipc->data->nr_banks || ipc->data->nr_banks > AMBA_MAX_BANKS ||
+ !ipc->data->npins ||
+ !ipc->data->groups || !ipc->data->ngroups ||
+ !ipc->data->functions || !ipc->data->nfunctions)
+ return dev_err_probe(dev, -EINVAL, "invalid SoC data\n");
+
+ ipc->iomux_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ipc->iomux_base))
+ return PTR_ERR(ipc->iomux_base);
+
+ ipc->ds_regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev),
+ "ambarella,drive-strength-syscon");
+ if (IS_ERR(ipc->ds_regmap))
+ return dev_err_probe(dev, PTR_ERR(ipc->ds_regmap),
+ "missing drive-strength syscon\n");
+
+ ipc->pull_regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev),
+ "ambarella,pull-syscon");
+ if (IS_ERR(ipc->pull_regmap))
+ return dev_err_probe(dev, PTR_ERR(ipc->pull_regmap),
+ "missing pull syscon\n");
+
+ spin_lock_init(&ipc->lock);
+
+ ret = amb_pinctrl_register(ipc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register pinctrl\n");
+
+ platform_set_drvdata(pdev, ipc);
+
+ return 0;
+}
+
+static const struct of_device_id amb_pinctrl_dt_match[] = {
+ {
+ .compatible = "ambarella,cv75-pinctrl",
+ .data = &ambarella_cv75_pinctrl_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, amb_pinctrl_dt_match);
+
+static struct platform_driver amb_pinctrl_driver = {
+ .probe = amb_pinctrl_probe,
+ .driver = {
+ .name = "ambarella-pinctrl",
+ .of_match_table = amb_pinctrl_dt_match,
+ },
+};
+
+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 <rrcao@ambarella.com>");
+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..37e9c420662c
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ambarella.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Ambarella pinctrl SoC data
+ *
+ * Copyright (C) 2012-2026, Ambarella, Inc.
+ */
+
+#ifndef _PINCTRL_AMBARELLA_H
+#define _PINCTRL_AMBARELLA_H
+
+#include <linux/types.h>
+
+#define AMBA_MAX_BANKS 8
+
+struct pingroup;
+struct pinfunction;
+
+struct amb_pinmux_group {
+ const struct pingroup *grp;
+ const u8 *alts;
+};
+
+struct amb_pinctrl_data {
+ const struct amb_pinmux_group *groups;
+ const struct pinfunction *functions;
+ unsigned int ngroups;
+ unsigned int nfunctions;
+ unsigned int nr_banks;
+ unsigned int npins;
+ 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;
+};
+
+extern const struct amb_pinctrl_data ambarella_cv75_pinctrl_data;
+
+#endif /* _PINCTRL_AMBARELLA_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 16/18] serial: 8250_dw: add Ambarella CV75 quirks
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (14 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 17/18] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
` (2 subsequent siblings)
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
The Ambarella CV75 UART is Ambarella IP, not a Synopsys DesignWare
licensed block. At the register level it is close enough to DW APB UART
that a full custom UART driver is unnecessary: reuse 8250_dw with a
small platform quirk.
Quirks:
- keep IER ETOI (bit 5) set for RX timeout behaviour
- skip set_rate; baud clock is managed outside the UART block
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/tty/serial/8250/8250_dw.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 5fba913f3301..06f03e893346 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -43,6 +43,9 @@
#define RZN1_UART_xDMACR_8_WORD_BURST (2 << 1)
#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3)
+/* Ambarella IER: receive timeout interrupt enable */
+#define AMBARELLA_UART_IER_ETOI BIT(5)
+
/* Quirks */
#define DW_UART_QUIRK_OCTEON BIT(0)
#define DW_UART_QUIRK_ARMADA_38X BIT(1)
@@ -60,6 +63,7 @@
struct dw8250_platform_data {
u8 usr_reg;
+ u8 ier_mask;
u32 cpr_value;
unsigned int quirks;
};
@@ -572,6 +576,25 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
dw8250_writel_ext(up, RZN1_UART_RDMACR, val);
}
+static int dw8250_ier_mask_startup(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int ret;
+
+ ret = serial8250_do_startup(p);
+ if (ret)
+ return ret;
+
+ /*
+ * Ambarella keeps variant IER bits (e.g. ETOI) set for correct RX
+ * timeout behaviour.
+ */
+ up->ier |= d->pdata->ier_mask;
+
+ return 0;
+}
+
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
unsigned int quirks = data->pdata->quirks;
@@ -606,6 +629,8 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_in = dw8250_serial_in32;
data->uart_16550_compatible = true;
}
+ if (data->pdata->ier_mask)
+ p->startup = dw8250_ier_mask_startup;
}
static void dw8250_reset_control_assert(void *data)
@@ -879,6 +904,12 @@ static const struct dw8250_platform_data dw8250_intc10ee = {
.quirks = DW_UART_QUIRK_IER_KICK,
};
+static const struct dw8250_platform_data dw8250_ambarella_cv75_data = {
+ .usr_reg = DW_UART_USR,
+ .ier_mask = AMBARELLA_UART_IER_ETOI,
+ .quirks = DW_UART_QUIRK_SKIP_SET_RATE,
+};
+
static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = {
.usr_reg = DW_UART_USR,
.cpr_value = FIELD_PREP_CONST(DW_UART_CPR_ABP_DATA_WIDTH, 2) |
@@ -890,6 +921,7 @@ static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = {
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
+ { .compatible = "ambarella,cv75-uart", .data = &dw8250_ambarella_cv75_data },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
{ .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 17/18] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (15 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 16/18] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 18/18] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay
2026-09-21 10:31 ` [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Bartosz Golaszewski
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
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.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
arch/arm64/Kconfig.platforms | 6 +
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 | 177 +++++++++++++++++++++++++++++
arch/arm64/configs/defconfig | 1 +
6 files changed, 218 insertions(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index d2acfac73003..16d7e3a4c2d6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -26,6 +26,12 @@ config ARCH_SUNXI
help
This enables support for Allwinner sunxi based SoCs like the A64.
+config ARCH_AMBARELLA
+ bool "Ambarella SoC family"
+ 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 += airoha
subdir-y += allwinner
subdir-y += altera
subdir-y += amazon
+subdir-y += ambarella
subdir-y += amd
subdir-y += amlogic
subdir-y += apm
diff --git a/arch/arm64/boot/dts/ambarella/Makefile b/arch/arm64/boot/dts/ambarella/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) += cv75-evk.dtb
diff --git a/arch/arm64/boot/dts/ambarella/cv75-evk.dts b/arch/arm64/boot/dts/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 = "Ambarella CV75 EVK Board";
+ compatible = "ambarella,cv75-evk", "ambarella,cv75";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = &uart0;
+ };
+
+ memory@200000 {
+ device_type = "memory";
+ reg = <0x0 0x00200000 0x0 0x07e00000>;
+ };
+};
+
+&uart0 {
+ status = "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..c36b6af48237
--- /dev/null
+++ b/arch/arm64/boot/dts/ambarella/cv75.dtsi
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Ambarella CV75 SoC
+ *
+ * Boot peripheral: UART0 console.
+ * Clocks: a single ambarella,cv75-rct provider.
+ */
+
+#include <dt-bindings/clock/ambarella,cv75-rct.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "ambarella,cv75";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a76";
+ device_type = "cpu";
+ reg = <0x000>;
+ enable-method = "psci";
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a76";
+ device_type = "cpu";
+ reg = <0x100>;
+ enable-method = "psci";
+ };
+ };
+
+ osc: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc";
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ahb@ffe0000000 {
+ compatible = "simple-bus";
+ reg = <0xff 0xe0000000 0x0 0x01000000>;
+ ranges = <0xe0000000 0xff 0xe0000000 0x01000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ s_scratchpad_syscon: scratchpad@e002e000 {
+ compatible = "ambarella,cv75-sec-scratchpad", "syscon";
+ reg = <0xe002e000 0x1000>;
+ };
+ };
+
+ apb@ffe4000000 {
+ compatible = "simple-bus";
+ reg = <0xff 0xe4000000 0x0 0x01000000>;
+ ranges = <0xe4000000 0xff 0xe4000000 0x01000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ uart0: serial@e4000000 {
+ compatible = "ambarella,cv75-uart", "snps,dw-apb-uart";
+ reg = <0xe4000000 0x1000>;
+ clocks = <&rct CV75_GCLK_UART0>;
+ interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+
+ status = "disabled";
+ };
+
+ pinctrl: pinctrl@e4010000 {
+ compatible = "ambarella,cv75-pinctrl";
+ reg = <0xe4010000 0x1000>;
+ ambarella,drive-strength-syscon = <&rct>;
+ ambarella,pull-syscon = <&s_scratchpad_syscon>;
+
+ uart0_pins: uart0-pins {
+ function = "uart0";
+ groups = "uart0";
+ };
+ };
+
+ gpio0: gpio@e4013000 {
+ compatible = "ambarella,cv75-gpio", "arm,primecell";
+ reg = <0xe4013000 0x1000>;
+ clocks = <&rct CV75_GCLK_APB>;
+ clock-names = "apb_pclk";
+ interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 0 32>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ arm,primecell-periphid = <0x000e8061>;
+ };
+
+ gpio1: gpio@e4014000 {
+ compatible = "ambarella,cv75-gpio", "arm,primecell";
+ reg = <0xe4014000 0x1000>;
+ clocks = <&rct CV75_GCLK_APB>;
+ clock-names = "apb_pclk";
+ interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 32 32>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ arm,primecell-periphid = <0x000e8061>;
+ };
+
+ gpio2: gpio@e4015000 {
+ compatible = "ambarella,cv75-gpio", "arm,primecell";
+ reg = <0xe4015000 0x1000>;
+ clocks = <&rct CV75_GCLK_APB>;
+ clock-names = "apb_pclk";
+ interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 64 32>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ arm,primecell-periphid = <0x000e8061>;
+ };
+ };
+
+ rct: clock-controller@ffed080000 {
+ compatible = "ambarella,cv75-rct", "syscon";
+ reg = <0xff 0xed080000 0x0 0x1000>;
+ clocks = <&osc>;
+ clock-names = "osc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ assigned-clocks = <&rct CV75_GCLK_UART0>;
+ assigned-clock-parents = <&osc>;
+ assigned-clock-rates = <24000000>;
+ };
+
+ gic: interrupt-controller@fff0101000 {
+ compatible = "arm,gic-400";
+ reg = <0xff 0xf0101000 0x0 0x1000>,
+ <0xff 0xf0102000 0x0 0x2000>,
+ <0xff 0xf0104000 0x0 0x2000>,
+ <0xff 0xf0106000 0x0 0x2000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupts = <GIC_PPI 9
+ (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 12 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ad3bd3d9507b..454f07a6a6a6 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -36,6 +36,7 @@ CONFIG_CRASH_DUMP=y
CONFIG_ARCH_ACTIONS=y
CONFIG_ARCH_AIROHA=y
CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_AMBARELLA=y
CONFIG_ARCH_ALPINE=y
CONFIG_ARCH_APPLE=y
CONFIG_ARCH_ARTPEC=y
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v8 18/18] MAINTAINERS: add ARM/AMBARELLA SoC support
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (16 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 17/18] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
@ 2026-09-21 4:23 ` Long Zhao via B4 Relay
2026-09-21 10:31 ` [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Bartosz Golaszewski
18 siblings, 0 replies; 34+ messages in thread
From: Long Zhao via B4 Relay @ 2026-09-21 4:23 UTC (permalink / raw)
To: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
Cc: Long Zhao, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet, Linus Walleij,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
From: Long Zhao <longzhao@ambarella.com>
Add a maintainer entry covering Ambarella CV75 bindings, DTS and
related drivers.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
MAINTAINERS | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 803b60ad628f..59e5b32d7a02 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2502,6 +2502,20 @@ F: drivers/clocksource/asm9260_timer.c
F: drivers/rtc/rtc-asm9260.c
F: drivers/watchdog/asm9260_wdt.c
+ARM/AMBARELLA SOC SUPPORT
+M: Long Zhao <longzhao@ambarella.com>
+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: arch/arm64/boot/dts/ambarella/
+F: drivers/clk/ambarella/
+F: drivers/pinctrl/pinctrl-ambarella*
+F: include/dt-bindings/clock/ambarella,cv75-rct.h
+N: ambarella
+
ARM/AMD PENSANDO ARM64 ARCHITECTURE
M: Brad Larson <blarson@amd.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (17 preceding siblings ...)
2026-09-21 4:23 ` [PATCH v8 18/18] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay
@ 2026-09-21 10:31 ` Bartosz Golaszewski
2026-09-21 11:08 ` zl020895
18 siblings, 1 reply; 34+ messages in thread
From: Bartosz Golaszewski @ 2026-09-21 10:31 UTC (permalink / raw)
To: longzhao
Cc: Long Zhao via B4 Relay, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Jerome Brunet,
Linus Walleij, Bartosz Golaszewski, Greg Kroah-Hartman,
Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Long Zhao, Lee Jones, mfd, devicetree, linux-clk,
linux-gpio, linux-serial, linux-kernel, Krzysztof Kozlowski,
Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel
On Mon, 21 Sep 2026 06:23:19 +0200, Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> said:
> This series adds minimal Ambarella CV75 support for early bring-up with
> a serial console: DT bindings, RCT clocks, pinctrl, PL061 GPIO via
> gpio-regmap, 8250_dw UART quirks, ARCH_AMBARELLA, CV75 EVK DT, and
> MAINTAINERS.
>
> This is a single unified series. Please apply via the SoC
> tree; subsystem maintainers are Cc'd for their pieces.
>
As I said before: this brings in a lot of potentially conflicting code into
drivers/gpio/ so I'll need an immutable branch to pull or I can queue the GPIO
part myself and provide an immutable branch to other trees.
Bartosz
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip()
2026-09-21 4:23 ` [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip() Long Zhao via B4 Relay
@ 2026-09-21 10:35 ` Bartosz Golaszewski
2026-09-21 12:19 ` zl020895
0 siblings, 1 reply; 34+ messages in thread
From: Bartosz Golaszewski @ 2026-09-21 10:35 UTC (permalink / raw)
To: longzhao
Cc: Long Zhao via B4 Relay, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Jerome Brunet,
Linus Walleij, Bartosz Golaszewski, Greg Kroah-Hartman,
Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Long Zhao, Lee Jones, mfd, devicetree, linux-clk,
linux-gpio, linux-serial, linux-kernel, Arnd Bergmann,
Krzysztof Kozlowski, Alexandre Belloni, soc, linux-arm-kernel
On Mon, 21 Sep 2026 06:23:28 +0200, Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> said:
> From: Long Zhao <longzhao@ambarella.com>
>
> Let drivers that implement a custom irqchip retrieve the gpio_chip
> after registration.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
> ---
> drivers/gpio/gpio-regmap.c | 6 ++++++
> include/linux/gpio/regmap.h | 1 +
> 2 files changed, 7 insertions(+)
>
> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
> index fbd4c753525a..21e0993b89e2 100644
> --- a/drivers/gpio/gpio-regmap.c
> +++ b/drivers/gpio/gpio-regmap.c
> @@ -295,6 +295,12 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
> }
> EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
>
> +struct gpio_chip *gpio_regmap_get_chip(struct gpio_regmap *gpio)
> +{
> + return &gpio->gpio_chip;
> +}
> +EXPORT_SYMBOL_GPL(gpio_regmap_get_chip);
Please provide a kernel doc for all public APIs. It should explain that this
must not be used outside of a GPIO controller driver context.
Bart
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re:Re: [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up
2026-09-21 10:31 ` [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Bartosz Golaszewski
@ 2026-09-21 11:08 ` zl020895
0 siblings, 0 replies; 34+ messages in thread
From: zl020895 @ 2026-09-21 11:08 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: longzhao, Long Zhao via B4 Relay, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Jerome Brunet, Linus Walleij, Greg Kroah-Hartman,
Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski, Arnd Bergmann,
Krzysztof Kozlowski, Alexandre Belloni, soc, linux-arm-kernel
Thanks, Bart.
Please queue the GPIO patches yourself and provide an immutable
branch for the SoC tree.
The GPIO part is:
gpiolib: regmap: add write_data_after_dir quirk
gpiolib: regmap: add gpio_regmap_get_chip()
gpio: pl061: convert register access to regmap
gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH
gpio: pl061: use cleanup helpers for locks
gpio: pl061: switch data path to gpio-regmap
gpio: pl061: add Ambarella register-layout variant
I will send a follow-up for gpio_regmap_get_chip() with the missing
kernel-doc. The rest of the series (clk, pinctrl, UART, DT) can stay
with the SoC tree once that GPIO branch is available.
Best regards,
Long Zhao
At 2026-09-21 18:31:45, "Bartosz Golaszewski" <brgl@kernel.org> wrote:
>On Mon, 21 Sep 2026 06:23:19 +0200, Long Zhao via B4 Relay
><devnull+longzhao.ambarella.com@kernel.org> said:
>> This series adds minimal Ambarella CV75 support for early bring-up with
>> a serial console: DT bindings, RCT clocks, pinctrl, PL061 GPIO via
>> gpio-regmap, 8250_dw UART quirks, ARCH_AMBARELLA, CV75 EVK DT, and
>> MAINTAINERS.
>>
>> This is a single unified series. Please apply via the SoC
>> tree; subsystem maintainers are Cc'd for their pieces.
>>
>
>As I said before: this brings in a lot of potentially conflicting code into
>drivers/gpio/ so I'll need an immutable branch to pull or I can queue the GPIO
>part myself and provide an immutable branch to other trees.
>
>Bartosz
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re:Re: [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip()
2026-09-21 10:35 ` Bartosz Golaszewski
@ 2026-09-21 12:19 ` zl020895
2026-09-21 13:05 ` Bartosz Golaszewski
0 siblings, 1 reply; 34+ messages in thread
From: zl020895 @ 2026-09-21 12:19 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: longzhao, Long Zhao via B4 Relay, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Jerome Brunet, Linus Walleij, Greg Kroah-Hartman,
Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Arnd Bergmann, Krzysztof Kozlowski,
Alexandre Belloni, soc, linux-arm-kernel
Hi Bart,
Done, sent as a follow-up:
https://lore.kernel.org/all/20260921-gpio-doc-followup-v1-1-618738124f4c@ambarella.com/
Best regards,
Long Zhao
At 2026-09-21 18:35:08, "Bartosz Golaszewski" <brgl@kernel.org> wrote:
>On Mon, 21 Sep 2026 06:23:28 +0200, Long Zhao via B4 Relay
><devnull+longzhao.ambarella.com@kernel.org> said:
>> From: Long Zhao <longzhao@ambarella.com>
>>
>> Let drivers that implement a custom irqchip retrieve the gpio_chip
>> after registration.
>>
>> Signed-off-by: Long Zhao <longzhao@ambarella.com>
>> ---
>> drivers/gpio/gpio-regmap.c | 6 ++++++
>> include/linux/gpio/regmap.h | 1 +
>> 2 files changed, 7 insertions(+)
>>
>> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
>> index fbd4c753525a..21e0993b89e2 100644
>> --- a/drivers/gpio/gpio-regmap.c
>> +++ b/drivers/gpio/gpio-regmap.c
>> @@ -295,6 +295,12 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
>> }
>> EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
>>
>> +struct gpio_chip *gpio_regmap_get_chip(struct gpio_regmap *gpio)
>> +{
>> + return &gpio->gpio_chip;
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_regmap_get_chip);
>
>Please provide a kernel doc for all public APIs. It should explain that this
>must not be used outside of a GPIO controller driver context.
>
>Bart
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: Re:Re: [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip()
2026-09-21 12:19 ` zl020895
@ 2026-09-21 13:05 ` Bartosz Golaszewski
0 siblings, 0 replies; 34+ messages in thread
From: Bartosz Golaszewski @ 2026-09-21 13:05 UTC (permalink / raw)
To: zl020895
Cc: Bartosz Golaszewski, longzhao, Long Zhao via B4 Relay,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Jerome Brunet, Linus Walleij, Greg Kroah-Hartman,
Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Arnd Bergmann, Krzysztof Kozlowski,
Alexandre Belloni, soc, linux-arm-kernel, Michael Walle
On Mon, 21 Sep 2026 14:19:49 +0200, zl020895 <zl020895@163.com> said:
> Hi Bart,
>
> Done, sent as a follow-up:
> https://lore.kernel.org/all/20260921-gpio-doc-followup-v1-1-618738124f4c@ambarella.com/
>
No, don't send follow-ups before anything is picked up. Also: Michael Walle,
who's the maintainer for gpio-regmap was not Cc'ed on this so I'll wait for his
Ack or change requests.
Bart
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl
2026-09-21 4:23 ` [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl Long Zhao via B4 Relay
@ 2026-09-22 7:11 ` Linus Walleij
2026-09-22 8:28 ` zl020895
2026-10-01 7:03 ` Linus Walleij
1 sibling, 1 reply; 34+ messages in thread
From: Linus Walleij @ 2026-09-22 7:11 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
Hi Long,
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Document the CV75 pin controller binding using generic function and
> groups properties for pinmux configuration.
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
Is this something I should just apply to the pinctrl tree?
Same question about the driver.
I'm not sure you'll get all of the Ambarella in for v7.4 anyway
so what about putting some pieces in place to begin with?
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk
2026-09-21 4:23 ` [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk Long Zhao via B4 Relay
@ 2026-09-22 7:17 ` Linus Walleij
2026-09-22 8:45 ` zl020895
0 siblings, 1 reply; 34+ messages in thread
From: Linus Walleij @ 2026-09-22 7:17 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
Hi Long,
this is starting to look good!
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Some controllers ignore data-register writes while a line is still an
> input. Optionally write the output value again after switching the
> direction, matching the existing PL061 behaviour.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
(...)
> +++ b/include/linux/gpio/regmap.h
> @@ -48,6 +48,13 @@ struct regmap;
> * (Optional) Bitmap representing the fixed direction of
> * the GPIO lines. Useful when there are GPIO lines with a
> * fixed direction mixed together in the same register.
> + * @write_data_after_dir:
> + * (Optional) Write the output value again after
> + * switching a line to output in ->direction_output().
> + * Needed for hardware which ignores data register
> + * writes while the line is configured as an input.
> + * This is a legacy quirk (e.g. ARM PL061); new hardware
> + * must not use it. Direction changes will glitch.
> * @drvdata: (Optional) Pointer to driver specific data which is
> * not used by gpio-remap but is provided "as is" to the
> * driver callback(s).
> @@ -94,6 +101,7 @@ struct gpio_regmap_config {
> unsigned int reg_dir_out_base;
> int reg_stride;
> int ngpio_per_reg;
> + bool write_data_after_dir;
> struct irq_domain *irq_domain;
> unsigned long *fixed_direction_mask;
> unsigned long *fixed_direction_output;
1. You have put the kerneldoc in a completely different place in the order
of thing than where you put the flag in the struct.
2. Put a comment above the behaviour flags because there will
invariably be more of them! Something like:
/* Regmap GPIO behaviour flags */
3. Put a newline before & after the flags so they end up in a separate
section of the struct, so people know where to add them.
I would put them:
struct device *parent;
struct regmap *regmap;
struct fwnode_handle *fwnode;
const char *label;
int ngpio;
const char *const *names;
HERE
unsigned int reg_dat_base;
unsigned int reg_set_base;
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 11/18] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH
2026-09-21 4:23 ` [PATCH v8 11/18] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
@ 2026-09-22 7:24 ` Linus Walleij
0 siblings, 0 replies; 34+ messages in thread
From: Linus Walleij @ 2026-09-22 7:24 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Use the standard IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH helpers
> instead of open-coded edge and level comparisons.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 12/18] gpio: pl061: use cleanup helpers for locks
2026-09-21 4:23 ` [PATCH v8 12/18] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
@ 2026-09-22 7:24 ` Linus Walleij
0 siblings, 0 replies; 34+ messages in thread
From: Linus Walleij @ 2026-09-22 7:24 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Convert raw_spinlock critical sections to guard() from cleanup.h.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 13/18] gpio: pl061: switch data path to gpio-regmap
2026-09-21 4:23 ` [PATCH v8 13/18] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
@ 2026-09-22 7:25 ` Linus Walleij
0 siblings, 0 replies; 34+ messages in thread
From: Linus Walleij @ 2026-09-22 7:25 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Keep a custom irqchip and irq domain. The gpio_chip is owned by
> gpio-regmap, so gpio_regmap_get_chip() is used to wire the domain.
>
> Check the chained-handler regmap_read() return and always
> run chained_irq_exit(). irq_type keeps the MMIO write style
> and uses cleanup helpers from the previous patch.
>
> irq_set_parent() nests the GPIO irq_desc under the AMBA parent
> for irq_set_wake() and lockdep; checked with PROVE_LOCKING on CV75.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller
2026-09-21 4:23 ` [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller Long Zhao via B4 Relay
@ 2026-09-22 7:28 ` Linus Walleij
2026-10-01 7:05 ` Linus Walleij
1 sibling, 0 replies; 34+ messages in thread
From: Linus Walleij @ 2026-09-22 7:28 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Add an Ambarella pinmux-only pinctrl driver with CV75 function/group
> tables. GPIO is handled by the PL061 driver.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
I feel I could just apply this patch.
> + select GPIO_PL061
This doesn't matter so much, I can just assume this will appear in
the merge window.
If some bots complain it we can just ignore it.
Once the bindings are ACKed I will consider just apply the
bindings and this patch to the pinctrl tree.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re:Re: [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl
2026-09-22 7:11 ` Linus Walleij
@ 2026-09-22 8:28 ` zl020895
0 siblings, 0 replies; 34+ messages in thread
From: zl020895 @ 2026-09-22 8:28 UTC (permalink / raw)
To: Linus Walleij
Cc: longzhao, Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni,
soc, linux-arm-kernel, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Lee Jones, mfd, devicetree, linux-clk, linux-gpio, linux-serial,
linux-kernel, Krzysztof Kozlowski
Hi Linus,
Thank you.
"Putting some pieces in place to begin with" sounds like a good idea. What do I need to do next? I’m still new to this, thanks for your patience and guidance.
Best regards,
Long Zhao
At 2026-09-22 15:11:19, "Linus Walleij" <linusw@kernel.org> wrote:
>Hi Long,
>
>On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
><devnull+longzhao.ambarella.com@kernel.org> wrote:
>
>> From: Long Zhao <longzhao@ambarella.com>
>>
>> Document the CV75 pin controller binding using generic function and
>> groups properties for pinmux configuration.
>>
>> Reviewed-by: Linus Walleij <linusw@kernel.org>
>> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>> Signed-off-by: Long Zhao <longzhao@ambarella.com>
>
>Is this something I should just apply to the pinctrl tree?
>
>Same question about the driver.
>
>I'm not sure you'll get all of the Ambarella in for v7.4 anyway
>so what about putting some pieces in place to begin with?
>
>Yours,
>Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re:Re: [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk
2026-09-22 7:17 ` Linus Walleij
@ 2026-09-22 8:45 ` zl020895
0 siblings, 0 replies; 34+ messages in thread
From: zl020895 @ 2026-09-22 8:45 UTC (permalink / raw)
To: Linus Walleij
Cc: longzhao, Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni,
soc, linux-arm-kernel, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Lee Jones, mfd, devicetree, linux-clk, linux-gpio, linux-serial,
linux-kernel
Hi Linus,
Thanks for the review.
I will do in the next revision.
Best regards,
Long Zhao
At 2026-09-22 15:17:48, "Linus Walleij" <linusw@kernel.org> wrote:
>Hi Long,
>
>this is starting to look good!
>
>On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
><devnull+longzhao.ambarella.com@kernel.org> wrote:
>
>> From: Long Zhao <longzhao@ambarella.com>
>>
>> Some controllers ignore data-register writes while a line is still an
>> input. Optionally write the output value again after switching the
>> direction, matching the existing PL061 behaviour.
>>
>> Signed-off-by: Long Zhao <longzhao@ambarella.com>
>(...)
>
>> +++ b/include/linux/gpio/regmap.h
>> @@ -48,6 +48,13 @@ struct regmap;
>> * (Optional) Bitmap representing the fixed direction of
>> * the GPIO lines. Useful when there are GPIO lines with a
>> * fixed direction mixed together in the same register.
>> + * @write_data_after_dir:
>> + * (Optional) Write the output value again after
>> + * switching a line to output in ->direction_output().
>> + * Needed for hardware which ignores data register
>> + * writes while the line is configured as an input.
>> + * This is a legacy quirk (e.g. ARM PL061); new hardware
>> + * must not use it. Direction changes will glitch.
>> * @drvdata: (Optional) Pointer to driver specific data which is
>> * not used by gpio-remap but is provided "as is" to the
>> * driver callback(s).
>> @@ -94,6 +101,7 @@ struct gpio_regmap_config {
>> unsigned int reg_dir_out_base;
>> int reg_stride;
>> int ngpio_per_reg;
>> + bool write_data_after_dir;
>> struct irq_domain *irq_domain;
>> unsigned long *fixed_direction_mask;
>> unsigned long *fixed_direction_output;
>
>1. You have put the kerneldoc in a completely different place in the order
>of thing than where you put the flag in the struct.
>
>2. Put a comment above the behaviour flags because there will
>invariably be more of them! Something like:
>/* Regmap GPIO behaviour flags */
>
>3. Put a newline before & after the flags so they end up in a separate
>section of the struct, so people know where to add them.
>
>I would put them:
>
> struct device *parent;
> struct regmap *regmap;
> struct fwnode_handle *fwnode;
>
> const char *label;
> int ngpio;
> const char *const *names;
>
>HERE
>
> unsigned int reg_dat_base;
> unsigned int reg_set_base;
>
>Yours,
>Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl
2026-09-21 4:23 ` [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl Long Zhao via B4 Relay
2026-09-22 7:11 ` Linus Walleij
@ 2026-10-01 7:03 ` Linus Walleij
1 sibling, 0 replies; 34+ messages in thread
From: Linus Walleij @ 2026-10-01 7:03 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel, Krzysztof Kozlowski
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Document the CV75 pin controller binding using generic function and
> groups properties for pinmux configuration.
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
This patch 4/18 applied to the pinctrl tree.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller
2026-09-21 4:23 ` [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller Long Zhao via B4 Relay
2026-09-22 7:28 ` Linus Walleij
@ 2026-10-01 7:05 ` Linus Walleij
1 sibling, 0 replies; 34+ messages in thread
From: Linus Walleij @ 2026-10-01 7:05 UTC (permalink / raw)
To: longzhao
Cc: Arnd Bergmann, Krzysztof Kozlowski, Alexandre Belloni, soc,
linux-arm-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Jerome Brunet,
Bartosz Golaszewski, Greg Kroah-Hartman, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Mon, Sep 21, 2026 at 6:23 AM Long Zhao via B4 Relay
<devnull+longzhao.ambarella.com@kernel.org> wrote:
> From: Long Zhao <longzhao@ambarella.com>
>
> Add an Ambarella pinmux-only pinctrl driver with CV75 function/group
> tables. GPIO is handled by the PL061 driver.
>
> Signed-off-by: Long Zhao <longzhao@ambarella.com>
This patch 15/18 applied to the pinctrl tree.
It's on an immutable branch along with the bindings, so other
trees can pull it in if necessary. But I don't think it's necessary
because it looks like only run-time dependencies.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2026-10-01 7:05 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21 4:23 [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 01/18] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 02/18] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 03/18] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 04/18] dt-bindings: pinctrl: add Ambarella CV75 pinctrl Long Zhao via B4 Relay
2026-09-22 7:11 ` Linus Walleij
2026-09-22 8:28 ` zl020895
2026-10-01 7:03 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 05/18] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 06/18] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 07/18] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 08/18] gpiolib: regmap: add write_data_after_dir quirk Long Zhao via B4 Relay
2026-09-22 7:17 ` Linus Walleij
2026-09-22 8:45 ` zl020895
2026-09-21 4:23 ` [PATCH v8 09/18] gpiolib: regmap: add gpio_regmap_get_chip() Long Zhao via B4 Relay
2026-09-21 10:35 ` Bartosz Golaszewski
2026-09-21 12:19 ` zl020895
2026-09-21 13:05 ` Bartosz Golaszewski
2026-09-21 4:23 ` [PATCH v8 10/18] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 11/18] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
2026-09-22 7:24 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 12/18] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
2026-09-22 7:24 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 13/18] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
2026-09-22 7:25 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 14/18] gpio: pl061: add Ambarella register-layout variant Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 15/18] pinctrl: ambarella: add CV75 pin controller Long Zhao via B4 Relay
2026-09-22 7:28 ` Linus Walleij
2026-10-01 7:05 ` Linus Walleij
2026-09-21 4:23 ` [PATCH v8 16/18] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 17/18] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
2026-09-21 4:23 ` [PATCH v8 18/18] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay
2026-09-21 10:31 ` [PATCH v8 00/18] Ambarella CV75 SoC minimal bring-up Bartosz Golaszewski
2026-09-21 11:08 ` zl020895
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox