* [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up
@ 2026-10-01 12:40 Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 01/15] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
` (14 more replies)
0 siblings, 15 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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, PL061 GPIO via gpio-regmap,
8250_dw UART quirks, ARCH_AMBARELLA, CV75 EVK DT, and MAINTAINERS.
The pinctrl binding and driver are already in the pinctrl tree. The
CV75 DT still describes that pin controller.
This series is sent together for review. Please take the GPIO
patches through the GPIO tree and provide an immutable branch
for the SoC tree. The remaining patches should be applied 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. The linear domain is
created with the PL061 private data and attached by gpio-regmap.
regmap-irq is 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
Assisted-by: LLM
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
Changes in v9:
- gpio-regmap: GPIO_REGMAP_QUIRK_SET_AFTER_DIR instead of
write_data_after_dir (Michael); put the flag in its own
group (Linus)
- gpio-regmap: drop gpio_regmap_get_chip() (Michael)
- gpio: pl061: create the irq domain with PL061 private data
before gpio_regmap_register() and let gpio-regmap attach it;
drop the gpio_chip irq helpers (Michael)
- gpio: pl061: GPIO_REGMAP_ADDR() for the direction register
(Michael)
- pinctrl: binding and driver applied by Linus Walleij; drop
them from this series (Linus)
- Cc Michael Walle <mwalle@kernel.org>
- collect Reviewed-by on the unchanged PL061 split patches
(Linus)
Link to v8: https://patch.msgid.link/20260921-cv75-v5-v8-0-282ff5d98dda@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
To: Long Zhao <longzhao@ambarella.com>
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: Michael Walle <mwalle@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 (15):
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: 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 GPIO_REGMAP_QUIRK_SET_AFTER_DIR
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
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/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 | 571 +++++++++++++--------
drivers/gpio/gpio-regmap.c | 15 +-
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 | 14 +
25 files changed, 1167 insertions(+), 210 deletions(-)
---
base-commit: 34cf6dafc47441dfb6b356a095b89c3585a93714
change-id: 20260818-cv75-v5-9e2039b349bc
Best regards,
--
Long Zhao <longzhao@ambarella.com>
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v9 01/15] dt-bindings: arm: add Ambarella CV75 platforms
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 02/15] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
` (13 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 02/15] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 01/15] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 03/15] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
` (12 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 03/15] dt-bindings: clock: add Ambarella CV75 RCT
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 01/15] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 02/15] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
` (11 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (2 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 03/15] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-01 19:23 ` Conor Dooley
2026-10-01 12:40 ` [PATCH v9 05/15] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart Long Zhao via B4 Relay
` (10 subsequent siblings)
14 siblings, 1 reply; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 05/15] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (3 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 06/15] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
` (9 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 06/15] clk: ambarella: add CV75 RCT clock controller
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (4 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 05/15] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-02 8:10 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 07/15] gpiolib: regmap: add GPIO_REGMAP_QUIRK_SET_AFTER_DIR Long Zhao via B4 Relay
` (8 subsequent siblings)
14 siblings, 1 reply; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 07/15] gpiolib: regmap: add GPIO_REGMAP_QUIRK_SET_AFTER_DIR
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (5 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 06/15] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-02 7:41 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 08/15] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
` (7 subsequent siblings)
14 siblings, 1 reply; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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 output writes while a line is still an input.
Add a behaviour flag so the output value is written after the direction
change. This is a legacy quirk. New hardware must not use it.
Signed-off-by: Long Zhao <longzhao@ambarella.com>
---
drivers/gpio/gpio-regmap.c | 15 +++++++++++++--
include/linux/gpio/regmap.h | 14 ++++++++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 51b4d69b8740..728bf3d90c48 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;
+ unsigned long quirks;
unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
@@ -271,9 +272,17 @@ static int gpio_regmap_direction_output(struct gpio_chip *chip,
return ret;
}
- gpio_regmap_set(chip, offset, value);
+ if (!(gpio->quirks & GPIO_REGMAP_QUIRK_SET_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;
+
+ if (gpio->quirks & GPIO_REGMAP_QUIRK_SET_AFTER_DIR)
+ gpio_regmap_set(chip, offset, value);
+
+ return 0;
}
void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
@@ -376,6 +385,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
config->fixed_direction_output, chip->ngpio);
}
+ gpio->quirks = config->quirks;
+
/* 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..e5a343512efb 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -3,6 +3,8 @@
#ifndef _LINUX_GPIO_REGMAP_H
#define _LINUX_GPIO_REGMAP_H
+#include <linux/bits.h>
+
struct device;
struct fwnode_handle;
struct gpio_regmap;
@@ -13,6 +15,14 @@ struct regmap;
#define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1))
#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
+/*
+ * Write the output value after the line is switched to output.
+ * Needed when hardware ignores output writes while the line is an input.
+ * This is a legacy quirk; new hardware must not use it. Direction changes
+ * will glitch.
+ */
+#define GPIO_REGMAP_QUIRK_SET_AFTER_DIR BIT(0)
+
/**
* struct gpio_regmap_config - Description of a generic regmap gpio_chip.
* @parent: The parent device
@@ -24,6 +34,7 @@ struct regmap;
* If not given, the name of the device is used.
* @ngpio: (Optional) Number of GPIOs
* @names: (Optional) Array of names for gpios
+ * @quirks: (Optional) Behaviour flags, OR of GPIO_REGMAP_QUIRK_*.
* @reg_dat_base: (Optional) (in) register base address
* @reg_set_base: (Optional) set register base address
* @reg_clr_base: (Optional) clear register base address
@@ -87,6 +98,9 @@ struct gpio_regmap_config {
int ngpio;
const char *const *names;
+ /* Regmap GPIO behaviour flags */
+ unsigned long quirks;
+
unsigned int reg_dat_base;
unsigned int reg_set_base;
unsigned int reg_clr_base;
--
2.34.1
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v9 08/15] gpio: pl061: convert register access to regmap
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (6 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 07/15] gpiolib: regmap: add GPIO_REGMAP_QUIRK_SET_AFTER_DIR Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-02 8:26 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 09/15] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
` (6 subsequent siblings)
14 siblings, 1 reply; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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.
Reviewed-by: Linus Walleij <linusw@kernel.org>
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 [flat|nested] 27+ messages in thread
* [PATCH v9 09/15] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (7 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 08/15] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-02 9:22 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 10/15] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
` (5 subsequent siblings)
14 siblings, 1 reply; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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.
Reviewed-by: Linus Walleij <linusw@kernel.org>
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 [flat|nested] 27+ messages in thread
* [PATCH v9 10/15] gpio: pl061: use cleanup helpers for locks
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (8 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 09/15] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
@ 2026-10-01 12:40 ` Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 11/15] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
` (4 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:40 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, Michael Walle, 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.
Reviewed-by: Linus Walleij <linusw@kernel.org>
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 [flat|nested] 27+ messages in thread
* [PATCH v9 11/15] gpio: pl061: switch data path to gpio-regmap
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (9 preceding siblings ...)
2026-10-01 12:40 ` [PATCH v9 10/15] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
@ 2026-10-01 12:41 ` Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 12/15] gpio: pl061: add Ambarella register-layout variant Long Zhao via B4 Relay
` (3 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:41 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, Michael Walle, 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>
Move get, set and direction onto gpio-regmap. ARM PL061 sets
GPIO_REGMAP_QUIRK_SET_AFTER_DIR so the output value is written
after the direction change.
Keep a custom irqchip and irq domain. Create the domain with
the PL061 private data and let gpio-regmap attach it.
Check the chained-handler regmap_read() return and always run
chained_irq_exit(). irq_type still ignores MMIO write returns.
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 | 505 ++++++++++++++++++++++++++--------------------
2 files changed, 288 insertions(+), 218 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..08d45f8923c2 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -12,171 +12,111 @@
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/init.h>
+#include <linux/err.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;
+ unsigned long quirks;
+ 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 device *dev;
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 unsigned int pl061_line_mask(struct pl061 *pl061, irq_hw_number_t hwirq)
{
- 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 BIT(hwirq % pl061->data->ngpio);
}
-static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
+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);
- unsigned int val = 0;
-
- regmap_read(pl061->regmap, BIT(offset + PL061_DATA_OFFSET), &val);
-
- return !!val;
-}
-
-static int pl061_set_value(struct gpio_chip *gc, unsigned int offset, int value)
-{
- 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 = irq_data_get_irq_chip_data(d);
+ 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)) {
- dev_err(gc->parent,
+ dev_err(pl061->dev,
"trying to configure line %d for both level and edge "
"detection, choose one!\n",
offset);
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;
@@ -191,7 +131,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
else
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_level_irq);
- dev_dbg(gc->parent, "line %d: IRQ on %s level\n",
+ dev_dbg(pl061->dev, "line %d: IRQ on %s level\n",
offset,
polarity ? "HIGH" : "LOW");
} else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
@@ -200,7 +140,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
/* Select both edges, setting this makes GPIOEV be ignored */
gpioibe |= bit;
irq_set_handler_locked(d, handle_edge_irq);
- dev_dbg(gc->parent, "line %d: IRQ on both edges\n", offset);
+ dev_dbg(pl061->dev, "line %d: IRQ on both edges\n", offset);
} else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
(trigger & IRQ_TYPE_EDGE_FALLING)) {
bool rising = trigger & IRQ_TYPE_EDGE_RISING;
@@ -215,7 +155,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
else
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_edge_irq);
- dev_dbg(gc->parent, "line %d: IRQ on %s edge\n",
+ dev_dbg(pl061->dev, "line %d: IRQ on %s edge\n",
offset,
rising ? "RISING" : "FALLING");
} else {
@@ -224,14 +164,15 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
gpioibe &= ~bit;
gpioiev &= ~bit;
irq_set_handler_locked(d, handle_bad_irq);
- dev_warn(gc->parent, "no trigger selected for line %d\n",
+ dev_warn(pl061->dev, "no trigger selected for line %d\n",
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,46 +181,40 @@ 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);
+ int offset, ret;
+ struct pl061 *pl061 = irq_desc_get_handler_data(desc);
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);
-
- guard(raw_spinlock)(&pl061->lock);
- regmap_update_bits(pl061->regmap, GPIOIE, mask, 0);
+ struct pl061 *pl061 = irq_data_get_irq_chip_data(d);
+ unsigned int mask = pl061_line_mask(pl061, irqd_to_hwirq(d));
- gpiochip_disable_irq(gc, d->hwirq);
+ regmap_update_bits(pl061->regmap, pl061->data->regs->ie, mask, 0);
}
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 = irq_data_get_irq_chip_data(d);
+ 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);
}
/**
@@ -292,29 +227,28 @@ 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 = irq_data_get_irq_chip_data(d);
+ 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 = irq_data_get_irq_chip_data(d);
return irq_set_irq_wake(pl061->parent_irq, state);
}
static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p)
{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct pl061 *pl061 = irq_data_get_irq_chip_data(data);
- seq_puts(p, dev_name(gc->parent));
+ seq_puts(p, dev_name(pl061->dev));
}
-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,
@@ -322,67 +256,187 @@ static const struct irq_chip pl061_irq_chip = {
.irq_set_wake = pl061_irq_set_wake,
.irq_print_chip = pl061_irq_print_chip,
.flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static int pl061_irq_domain_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct pl061 *pl061 = d->host_data;
+
+ irq_set_chip_data(virq, pl061);
+ 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,
+ .quirks = GPIO_REGMAP_QUIRK_SET_AFTER_DIR,
+ .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 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)
return -ENOMEM;
+ pl061->dev = dev;
+ pl061->data = data;
+
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;
+ if (irq) {
+ pl061->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
+ data->ngpio,
+ &pl061_irq_domain_ops,
+ pl061);
+ if (!pl061->irq_domain)
+ return -ENOMEM;
+ }
- 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 = GPIO_REGMAP_ADDR(regs->dir);
+ config.reg_mask_xlate = data->reg_mask_xlate;
+ config.quirks = data->quirks;
+ config.irq_domain = pl061->irq_domain;
+ config.drvdata = pl061;
+
+ gpio_regmap = devm_gpio_regmap_register(dev, &config);
+ if (IS_ERR(gpio_regmap)) {
+ if (pl061->irq_domain)
+ irq_domain_remove(pl061->irq_domain);
+ return PTR_ERR(gpio_regmap);
+ }
+
+ if (irq) {
+ 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, pl061);
+ }
amba_set_drvdata(adev, pl061);
dev_info(dev, "PL061 GPIO chip registered\n");
@@ -390,28 +444,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 +484,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 +513,7 @@ static const struct amba_id pl061_ids[] = {
{
.id = 0x00041061,
.mask = 0x000fffff,
+ .data = (void *)&pl061_arm,
},
{ 0, 0 },
};
--
2.34.1
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v9 12/15] gpio: pl061: add Ambarella register-layout variant
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (10 preceding siblings ...)
2026-10-01 12:41 ` [PATCH v9 11/15] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
@ 2026-10-01 12:41 ` Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
` (2 subsequent siblings)
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:41 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, Michael Walle, 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 08d45f8923c2..bbb9eeeb074a 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -38,6 +38,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;
@@ -318,6 +330,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,
@@ -329,6 +353,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,
@@ -339,6 +373,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,
@@ -348,6 +395,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;
@@ -515,6 +569,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 [flat|nested] 27+ messages in thread
* [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (11 preceding siblings ...)
2026-10-01 12:41 ` [PATCH v9 12/15] gpio: pl061: add Ambarella register-layout variant Long Zhao via B4 Relay
@ 2026-10-01 12:41 ` Long Zhao via B4 Relay
2026-10-01 12:52 ` Greg Kroah-Hartman
2026-10-01 12:41 ` [PATCH v9 14/15] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 15/15] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay
14 siblings, 1 reply; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:41 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 14/15] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (12 preceding siblings ...)
2026-10-01 12:41 ` [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
@ 2026-10-01 12:41 ` Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 15/15] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:41 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* [PATCH v9 15/15] MAINTAINERS: add ARM/AMBARELLA SoC support
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
` (13 preceding siblings ...)
2026-10-01 12:41 ` [PATCH v9 14/15] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
@ 2026-10-01 12:41 ` Long Zhao via B4 Relay
14 siblings, 0 replies; 27+ messages in thread
From: Long Zhao via B4 Relay @ 2026-10-01 12:41 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, Michael Walle, 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 [flat|nested] 27+ messages in thread
* Re: [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks
2026-10-01 12:41 ` [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
@ 2026-10-01 12:52 ` Greg Kroah-Hartman
2026-10-01 19:20 ` Linus Walleij
0 siblings, 1 reply; 27+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-01 12:52 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, Linus Walleij,
Bartosz Golaszewski, Michael Walle, 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 Thu, Oct 01, 2026 at 08:41:02PM +0800, Long Zhao via B4 Relay wrote:
> 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(+)
When you submit lots of different subsystem patches all in one series,
it's hard, if not impossible, for subsystem maintainers to take them :(
thanks,
greg k-h
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks
2026-10-01 12:52 ` Greg Kroah-Hartman
@ 2026-10-01 19:20 ` Linus Walleij
2026-10-02 2:17 ` zl020895
0 siblings, 1 reply; 27+ messages in thread
From: Linus Walleij @ 2026-10-01 19:20 UTC (permalink / raw)
To: Greg Kroah-Hartman
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, Michael Walle, 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 Thu, Oct 1, 2026 at 2:52 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Thu, Oct 01, 2026 at 08:41:02PM +0800, Long Zhao via B4 Relay wrote:
> > 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(+)
>
> When you submit lots of different subsystem patches all in one series,
> it's hard, if not impossible, for subsystem maintainers to take them :(
In my experience people do this in cases like this it is because they
essentially dump out their "bring-up" tree, the thing they have
booting on the hardware so they know the pieces work together.
Long: can you split it up in topic branches and work on e.g. the
serial driver on a separate branch?
A better way to test the whole set of patces is to just create a
mixdown branch where you merge all the topic branched into
one "test" branch, then you boot and test this before sending
out each branch separately.
Each topic branch can be versioned separately with b4.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant
2026-10-01 12:40 ` [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
@ 2026-10-01 19:23 ` Conor Dooley
2026-10-01 19:36 ` Linus Walleij
0 siblings, 1 reply; 27+ messages in thread
From: Conor Dooley @ 2026-10-01 19:23 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, Linus Walleij,
Bartosz Golaszewski, Michael Walle, 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
[-- Attachment #1: Type: text/plain, Size: 2457 bytes --]
On Thu, Oct 01, 2026 at 08:40:53PM +0800, Long Zhao via B4 Relay wrote:
> 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.
What has this got in common with the pl061 beyond using the PrimeCell
bus? Current reason for putting them together is a bit tenuous to me.
Cheers,
Conor.
>
> 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
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant
2026-10-01 19:23 ` Conor Dooley
@ 2026-10-01 19:36 ` Linus Walleij
2026-10-01 21:16 ` Conor Dooley
0 siblings, 1 reply; 27+ messages in thread
From: Linus Walleij @ 2026-10-01 19:36 UTC (permalink / raw)
To: Conor Dooley
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, Michael Walle, 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 Thu, Oct 1, 2026 at 9:23 PM Conor Dooley <conor@kernel.org> wrote:
> On Thu, Oct 01, 2026 at 08:40:53PM +0800, Long Zhao via B4 Relay wrote:
> > 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.
>
> What has this got in common with the pl061 beyond using the PrimeCell
> bus? Current reason for putting them together is a bit tenuous to me.
It was determined in early review that this is very clearly a modified
PL061 block. The basic registers are even named the same.
https://lore.kernel.org/linux-arm-kernel/CAD++jLk0LoOJk=TXin42AL3_z_7eVVkvMnYr1S8090C6A_B+dQ@mail.gmail.com/
PL061 is different and quirky and could not use gpio-mmio, while
with these changes to gpio-regmap it can handle its pecularities
and use a library which is a good thing on its own.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant
2026-10-01 19:36 ` Linus Walleij
@ 2026-10-01 21:16 ` Conor Dooley
0 siblings, 0 replies; 27+ messages in thread
From: Conor Dooley @ 2026-10-01 21:16 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, Michael Walle, 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
[-- Attachment #1: Type: text/plain, Size: 1470 bytes --]
On Thu, Oct 01, 2026 at 09:36:50PM +0200, Linus Walleij wrote:
> On Thu, Oct 1, 2026 at 9:23 PM Conor Dooley <conor@kernel.org> wrote:
> > On Thu, Oct 01, 2026 at 08:40:53PM +0800, Long Zhao via B4 Relay wrote:
> > > 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.
> >
> > What has this got in common with the pl061 beyond using the PrimeCell
> > bus? Current reason for putting them together is a bit tenuous to me.
>
> It was determined in early review that this is very clearly a modified
> PL061 block. The basic registers are even named the same.
> https://lore.kernel.org/linux-arm-kernel/CAD++jLk0LoOJk=TXin42AL3_z_7eVVkvMnYr1S8090C6A_B+dQ@mail.gmail.com/
Right. I think that'd be good to have in the commit message, because as
an outsider reading this it sounds like it could well be an entirely
different device.
With that explanation,
Acked-by: Conor Dooley <conor.dooley@microchip.com>
but as things stand,
pw-bot: changes-requested
Thanks,
Conor.
>
> PL061 is different and quirky and could not use gpio-mmio, while
> with these changes to gpio-regmap it can handle its pecularities
> and use a library which is a good thing on its own.
>
> Yours,
> Linus Walleij
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re:Re: [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks
2026-10-01 19:20 ` Linus Walleij
@ 2026-10-02 2:17 ` zl020895
2026-10-02 8:09 ` Jerome Brunet
0 siblings, 1 reply; 27+ messages in thread
From: zl020895 @ 2026-10-02 2:17 UTC (permalink / raw)
To: Linus Walleij
Cc: Greg Kroah-Hartman, 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, Michael Walle,
Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
Hi Greg, Linus,
Thanks.
This series follows the new-vendor, new-SoC process and is sent
as one set, so the new Kconfig symbol and the drivers that use it
land together.
If it has to be split, the GPIO patches and the UART patches can
go out as their own series. The SoC patches and the CV75 clock
driver should stay in one series: the clock Kconfig depends on
ARCH_AMBARELLA, which is added by the arm64 patch.
Would that split be acceptable for you?
Best regards,
Long Zhao
At 2026-10-02 03:20:51, "Linus Walleij" <linusw@kernel.org> wrote:
>On Thu, Oct 1, 2026 at 2:52 PM Greg Kroah-Hartman
><gregkh@linuxfoundation.org> wrote:
>> On Thu, Oct 01, 2026 at 08:41:02PM +0800, Long Zhao via B4 Relay wrote:
>
>> > 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(+)
>>
>> When you submit lots of different subsystem patches all in one series,
>> it's hard, if not impossible, for subsystem maintainers to take them :(
>
>In my experience people do this in cases like this it is because they
>essentially dump out their "bring-up" tree, the thing they have
>booting on the hardware so they know the pieces work together.
>
>Long: can you split it up in topic branches and work on e.g. the
>serial driver on a separate branch?
>
>A better way to test the whole set of patces is to just create a
>mixdown branch where you merge all the topic branched into
>one "test" branch, then you boot and test this before sending
>out each branch separately.
>
>Each topic branch can be versioned separately with b4.
>
>Yours,
>Linus Walleij
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 07/15] gpiolib: regmap: add GPIO_REGMAP_QUIRK_SET_AFTER_DIR
2026-10-01 12:40 ` [PATCH v9 07/15] gpiolib: regmap: add GPIO_REGMAP_QUIRK_SET_AFTER_DIR Long Zhao via B4 Relay
@ 2026-10-02 7:41 ` Andy Shevchenko
0 siblings, 0 replies; 27+ messages in thread
From: Andy Shevchenko @ 2026-10-02 7:41 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, Linus Walleij,
Bartosz Golaszewski, Michael Walle, Greg Kroah-Hartman,
Jiri Slaby, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Thu, Oct 01, 2026 at 08:40:56PM +0800, Long Zhao via B4 Relay wrote:
> Some controllers ignore output writes while a line is still an input.
> Add a behaviour flag so the output value is written after the direction
> change. This is a legacy quirk. New hardware must not use it.
A nit-pick below.
In general looks good to me.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
...
> struct gpio_regmap {
> unsigned int reg_clr_base;
> unsigned int reg_dir_in_base;
> unsigned int reg_dir_out_base;
> + unsigned long quirks;
I think I have told at some point that this location is not the best, I woul put it...
> unsigned long *fixed_direction_mask;
> unsigned long *fixed_direction_output;
...here, after the group of the direction related offsets and masks.
> - gpio_regmap_set(chip, offset, value);
> + if (!(gpio->quirks & GPIO_REGMAP_QUIRK_SET_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;
> +
> + if (gpio->quirks & GPIO_REGMAP_QUIRK_SET_AFTER_DIR)
> + gpio_regmap_set(chip, offset, value);
> +
> + return 0;
> }
...
> /**
> * struct gpio_regmap_config - Description of a generic regmap gpio_chip.
> * @parent: The parent device
> * @ngpio: (Optional) Number of GPIOs
> * @names: (Optional) Array of names for gpios
> + * @quirks: (Optional) Behaviour flags, OR of GPIO_REGMAP_QUIRK_*.
> * @reg_dat_base: (Optional) (in) register base address
> * @reg_set_base: (Optional) set register base address
> * @reg_clr_base: (Optional) clear register base address
> int ngpio;
> const char *const *names;
>
> + /* Regmap GPIO behaviour flags */
> + unsigned long quirks;
> +
> unsigned int reg_dat_base;
> unsigned int reg_set_base;
> unsigned int reg_clr_base;
I would follow the same location as it's in the above struct, id est after
unsigned long *fixed_direction_output;
member.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re:Re: [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks
2026-10-02 2:17 ` zl020895
@ 2026-10-02 8:09 ` Jerome Brunet
0 siblings, 0 replies; 27+ messages in thread
From: Jerome Brunet @ 2026-10-02 8:09 UTC (permalink / raw)
To: zl020895, Linus Walleij
Cc: Greg Kroah-Hartman, longzhao, Arnd Bergmann, Krzysztof Kozlowski,
Alexandre Belloni, soc, linux-arm-kernel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Bartosz Golaszewski, Michael Walle, Jiri Slaby,
Andy Shevchenko, Ilpo Järvinen, Catalin Marinas,
Will Deacon, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On ven. 02 oct. 2026 at 10:17, zl020895 <zl020895@163.com> wrote:
> Hi Greg, Linus,
>
> Thanks.
>
> This series follows the new-vendor, new-SoC process and is sent
> as one set, so the new Kconfig symbol and the drivers that use it
> land together.
What Greg and Linus say here is basically what I already suggested on
v6 [1]
Giving the whole context of a bring ups, mixing many trees, might be
nice at the RFC stage but then it makes a lot more difficult.
[1]: https://lore.kernel.org/all/1jld986j7m.fsf@starbuckisacylon.baylibre.com/
>
> If it has to be split, the GPIO patches and the UART patches can
> go out as their own series. The SoC patches and the CV75 clock
> driver should stay in one series: the clock Kconfig depends on
> ARCH_AMBARELLA, which is added by the arm64 patch.
>
> Would that split be acceptable for you?
>
I don't get why clock is any different here. Just state your
dependencies in the cover letter. `b4` can help you there as well.
> Best regards,
> Long Zhao
>
> At 2026-10-02 03:20:51, "Linus Walleij" <linusw@kernel.org> wrote:
>>On Thu, Oct 1, 2026 at 2:52 PM Greg Kroah-Hartman
>><gregkh@linuxfoundation.org> wrote:
>>> On Thu, Oct 01, 2026 at 08:41:02PM +0800, Long Zhao via B4 Relay wrote:
>>
>>> > 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(+)
>>>
>>> When you submit lots of different subsystem patches all in one series,
>>> it's hard, if not impossible, for subsystem maintainers to take them :(
>>
>>In my experience people do this in cases like this it is because they
>>essentially dump out their "bring-up" tree, the thing they have
>>booting on the hardware so they know the pieces work together.
>>
>>Long: can you split it up in topic branches and work on e.g. the
>>serial driver on a separate branch?
>>
>>A better way to test the whole set of patces is to just create a
>>mixdown branch where you merge all the topic branched into
>>one "test" branch, then you boot and test this before sending
>>out each branch separately.
>>
>>Each topic branch can be versioned separately with b4.
>>
>>Yours,
>>Linus Walleij
--
Jerome
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 06/15] clk: ambarella: add CV75 RCT clock controller
2026-10-01 12:40 ` [PATCH v9 06/15] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
@ 2026-10-02 8:10 ` Andy Shevchenko
0 siblings, 0 replies; 27+ messages in thread
From: Andy Shevchenko @ 2026-10-02 8:10 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, Linus Walleij,
Bartosz Golaszewski, Michael Walle, Greg Kroah-Hartman,
Jiri Slaby, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Thu, Oct 01, 2026 at 08:40:55PM +0800, Long Zhao via B4 Relay wrote:
> 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.
...
> +#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>
The latter one covers the former one.
> +#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>
...
> +struct cv75_pll_hw {
> + struct clk_hw hw;
> + u32 ctrl;
> + u32 frac;
> + u32 ctrl2;
This repeats twice in different data structures. Is the semantic the same in
both cases? If so, it might make sense to have a separate data structure for
these three and embed it as required.
> +};
...
> +struct cv75_pll {
> + const char *name;
> + struct cv75_pll_hw *hw;
> + unsigned long flags;
> + u32 ctrl;
> + u32 frac;
> + u32 ctrl2;
^^^ See above.
> + int id;
> +};
...
> +{
> + struct clk_parent_data parent_data = { .fw_name = "osc" };
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(cv75_plls); i++) {
for (unsigned int i = 0; i < ARRAY_SIZE(cv75_plls); i++) {
Same approach in the below code where similar cases appear.
> + 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_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);
Can it be done later, after memory allocation?
> + 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;
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 08/15] gpio: pl061: convert register access to regmap
2026-10-01 12:40 ` [PATCH v9 08/15] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
@ 2026-10-02 8:26 ` Andy Shevchenko
0 siblings, 0 replies; 27+ messages in thread
From: Andy Shevchenko @ 2026-10-02 8:26 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, Linus Walleij,
Bartosz Golaszewski, Michael Walle, Greg Kroah-Hartman,
Jiri Slaby, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Thu, Oct 01, 2026 at 08:40:57PM +0800, Long Zhao via B4 Relay wrote:
> 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.
...
> 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);
Why not returning an error?
> + if (gpiodir & BIT(offset))
> return GPIO_LINE_DIRECTION_OUT;
>
> return GPIO_LINE_DIRECTION_IN;
I believe this can use regmap_test_bits().
...
> 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);
_clear_bits()
> raw_spin_unlock_irqrestore(&pl061->lock, flags);
>
> return 0;
...
> 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);
_set_bits()
> + 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);
Ditto.
> raw_spin_unlock_irqrestore(&pl061->lock, flags);
>
> return 0;
...
> 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;
_test_bits()
> }
...
...and so on...
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v9 09/15] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH
2026-10-01 12:40 ` [PATCH v9 09/15] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
@ 2026-10-02 9:22 ` Andy Shevchenko
0 siblings, 0 replies; 27+ messages in thread
From: Andy Shevchenko @ 2026-10-02 9:22 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, Linus Walleij,
Bartosz Golaszewski, Michael Walle, Greg Kroah-Hartman,
Jiri Slaby, Ilpo Järvinen, Catalin Marinas, Will Deacon,
Long Zhao, Lee Jones, mfd, devicetree, linux-clk, linux-gpio,
linux-serial, linux-kernel
On Thu, Oct 01, 2026 at 08:40:58PM +0800, Long Zhao via B4 Relay wrote:
> Use the standard IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH helpers
> instead of open-coded edge and level comparisons.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2026-10-02 9:22 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-01 12:40 [PATCH v9 00/15] Ambarella CV75 SoC minimal bring-up Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 01/15] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 02/15] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 03/15] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 04/15] dt-bindings: gpio: pl061: add Ambarella CV75 variant Long Zhao via B4 Relay
2026-10-01 19:23 ` Conor Dooley
2026-10-01 19:36 ` Linus Walleij
2026-10-01 21:16 ` Conor Dooley
2026-10-01 12:40 ` [PATCH v9 05/15] dt-bindings: serial: snps-dw-apb-uart: add ambarella,cv75-uart Long Zhao via B4 Relay
2026-10-01 12:40 ` [PATCH v9 06/15] clk: ambarella: add CV75 RCT clock controller Long Zhao via B4 Relay
2026-10-02 8:10 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 07/15] gpiolib: regmap: add GPIO_REGMAP_QUIRK_SET_AFTER_DIR Long Zhao via B4 Relay
2026-10-02 7:41 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 08/15] gpio: pl061: convert register access to regmap Long Zhao via B4 Relay
2026-10-02 8:26 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 09/15] gpio: pl061: use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH Long Zhao via B4 Relay
2026-10-02 9:22 ` Andy Shevchenko
2026-10-01 12:40 ` [PATCH v9 10/15] gpio: pl061: use cleanup helpers for locks Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 11/15] gpio: pl061: switch data path to gpio-regmap Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 12/15] gpio: pl061: add Ambarella register-layout variant Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 13/15] serial: 8250_dw: add Ambarella CV75 quirks Long Zhao via B4 Relay
2026-10-01 12:52 ` Greg Kroah-Hartman
2026-10-01 19:20 ` Linus Walleij
2026-10-02 2:17 ` zl020895
2026-10-02 8:09 ` Jerome Brunet
2026-10-01 12:41 ` [PATCH v9 14/15] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
2026-10-01 12:41 ` [PATCH v9 15/15] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®