ARM Sunxi Platform Development
 help / color / mirror / Atom feed
* [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse
@ 2026-10-12 10:08 Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 01/11] dt-bindings: clock: sun4i-a10-ccu: add Allwinner B288 Pablo Mazzini
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
  Cc: Pablo Mazzini, Andre Przywara, devicetree, linux-arm-kernel,
	linux-clk, linux-gpio, linux-i2c, linux-kernel, linux-rtc,
	linux-sunxi, linux-watchdog

The Allwinner B288 (sun8iw10p1) is a dual Cortex-A7 SoC used in e-book
readers. This series adds the CCU and pin controller drivers, the RTC,
I2C, NMI and watchdog compatibles, the SoC .dtsi, and one board: the
PocketBook Verse (PB629), a 6" reader.

The B288 is closest to the A64: most of its PLLs are bit-identical.
The clock and pin descriptions come from Allwinner's BSP, cross-checked
against ccu-sun50i-a64.c. Tested on a PB629, boots to userspace.

The pin controller relies on "pinctrl: sunxi: dt: number the IRQ banks
from the first one that has IRQs" for correct PIO interrupt mapping.

Changes since v3:
  - CCU: reference parents with clk_parent_data and clk_hw pointers,
    as newer sunxi-ng drivers do; add the audio PLL's sigma-delta
    settings, as on the A64; fix the PLL_24M rate and parent the PLLs
    to it.
  - RTC: register the 32 kHz clocks, reusing the A23 data (Sashiko).
  - DTS: take osc32k from the RTC, as on the A64.
  - DTS: allow the eMMC up to 150 MHz, as on the A523.

Changes since v2:
  - Drop the MMC binding patch, applied by Ulf.
  - Rebase onto sunxi/for-next.
  - Constrain the RTC clock outputs and pinctrl interrupts in the
    bindings (Sashiko).
  - Add a B288 watchdog compatible (Andre).
  - DTS: drop the memory node, the arch timer workaround and the
    sunxi.c entry; add disable-wp and the eMMC 1.8V modes; DLDO1 no
    longer always-on; mainline pin function names (Andre).

Changes since v1:
  - Add this cover letter.
  - Drop both new bindings; add the compatibles to the existing
    allwinner,sun4i-a10-{ccu,pinctrl}.yaml instead.
  - Rewrite the pinctrl driver in the DT-provided pinmux style.

Pablo Mazzini (11):
  dt-bindings: clock: sun4i-a10-ccu: add Allwinner B288
  clk: sunxi-ng: add Allwinner B288 CCU driver
  dt-bindings: pinctrl: sun4i-a10: add Allwinner B288
  pinctrl: sunxi: add Allwinner B288 pin controller driver
  dt-bindings: rtc: sun6i-a31: add Allwinner B288
  rtc: sun6i: add Allwinner B288 compatible
  dt-bindings: i2c: mv64xxx: add Allwinner B288
  dt-bindings: interrupt-controller: add Allwinner B288 NMI
  dt-bindings: watchdog: sun4i-a10-wdt: add Allwinner B288
  dt-bindings: arm: sunxi: add PocketBook Verse
  ARM: dts: allwinner: add B288 and the PocketBook Verse

 .../devicetree/bindings/arm/sunxi.yaml        |   5 +
 .../clock/allwinner,sun4i-a10-ccu.yaml        |   1 +
 .../bindings/i2c/marvell,mv64xxx-i2c.yaml     |   1 +
 .../allwinner,sun7i-a20-sc-nmi.yaml           |   1 +
 .../pinctrl/allwinner,sun4i-a10-pinctrl.yaml  |  22 +
 .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml |   3 +
 .../watchdog/allwinner,sun4i-a10-wdt.yaml     |   1 +
 arch/arm/boot/dts/allwinner/Makefile          |   1 +
 .../allwinner/sun8i-b288-pocketbook-verse.dts | 114 +++
 arch/arm/boot/dts/allwinner/sun8i-b288.dtsi   | 292 +++++++
 drivers/clk/sunxi-ng/Kconfig                  |   5 +
 drivers/clk/sunxi-ng/Makefile                 |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-b288.c         | 749 ++++++++++++++++++
 drivers/clk/sunxi-ng/ccu-sun8i-b288.h         |  10 +
 drivers/pinctrl/sunxi/Kconfig                 |  10 +
 drivers/pinctrl/sunxi/Makefile                |   1 +
 drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c    |  49 ++
 drivers/rtc/rtc-sun6i.c                       |   5 +
 include/dt-bindings/clock/sun8i-b288-ccu.h    |  82 ++
 include/dt-bindings/reset/sun8i-b288-ccu.h    |  45 ++
 20 files changed, 1398 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-b288-pocketbook-verse.dts
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-b288.dtsi
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-b288.c
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-b288.h
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
 create mode 100644 include/dt-bindings/clock/sun8i-b288-ccu.h
 create mode 100644 include/dt-bindings/reset/sun8i-b288-ccu.h

-- 
2.52.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 01/11] dt-bindings: clock: sun4i-a10-ccu: add Allwinner B288
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver Pablo Mazzini
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Brian Masney, Chen-Yu Tsai, Conor Dooley, Jernej Skrabec,
	Jerome Brunet, Krzysztof Kozlowski, Maxime Ripard, Philipp Zabel,
	Rob Herring, Samuel Holland, Stephen Boyd
  Cc: Pablo Mazzini, Krzysztof Kozlowski, Andre Przywara, devicetree,
	linux-arm-kernel, linux-clk, linux-kernel, linux-sunxi

The B288 (sun8iw10p1) is a dual Cortex-A7 SoC used in e-book readers.
Its CCU needs only the two oscillator inputs, so it fits the existing
schema without changes.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
 .../clock/allwinner,sun4i-a10-ccu.yaml        |  1 +
 include/dt-bindings/clock/sun8i-b288-ccu.h    | 82 +++++++++++++++++++
 include/dt-bindings/reset/sun8i-b288-ccu.h    | 45 ++++++++++
 3 files changed, 128 insertions(+)
 create mode 100644 include/dt-bindings/clock/sun8i-b288-ccu.h
 create mode 100644 include/dt-bindings/reset/sun8i-b288-ccu.h

diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
index 1690b9d99c3d..cc3f62d3554c 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
@@ -28,6 +28,7 @@ properties:
       - allwinner,sun8i-a33-ccu
       - allwinner,sun8i-a83t-ccu
       - allwinner,sun8i-a83t-r-ccu
+      - allwinner,sun8i-b288-ccu
       - allwinner,sun8i-h3-ccu
       - allwinner,sun8i-h3-r-ccu
       - allwinner,sun8i-r40-ccu
diff --git a/include/dt-bindings/clock/sun8i-b288-ccu.h b/include/dt-bindings/clock/sun8i-b288-ccu.h
new file mode 100644
index 000000000000..c9b9eaf979ad
--- /dev/null
+++ b/include/dt-bindings/clock/sun8i-b288-ccu.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+#ifndef _DT_BINDINGS_CLK_SUN8I_B288_H_
+#define _DT_BINDINGS_CLK_SUN8I_B288_H_
+
+#define CLK_PLL_CPUX	0
+#define CLK_PLL_AUDIO_BASE	1
+#define CLK_PLL_VIDEO0	2
+#define CLK_PLL_DDR0	3
+#define CLK_PLL_PERIPH0	4
+#define CLK_PLL_VIDEO1	5
+#define CLK_PLL_24M	6
+#define CLK_PLL_PERIPH1	7
+#define CLK_PLL_DE	8
+#define CLK_PLL_DDR1	9
+
+#define CLK_PLL_PERIPH0_2X	10
+#define CLK_PLL_PERIPH1_2X	11
+#define CLK_CPUX	12
+#define CLK_AXI	13
+#define CLK_CPUAPB	14
+#define CLK_AHB1	15
+#define CLK_APB1	16
+#define CLK_APB2	17
+
+#define CLK_NAND	18
+#define CLK_MMC0	19
+#define CLK_MMC1	20
+#define CLK_MMC2	21
+#define CLK_MMC3	22
+#define CLK_SPI0	23
+#define CLK_SPI1	24
+#define CLK_SPI2	25
+#define CLK_DRAM	26
+#define CLK_DE	27
+#define CLK_EE	28
+#define CLK_EDMA	29
+#define CLK_TCON0	30
+#define CLK_MBUS	31
+
+#define CLK_BUS_THS	32
+#define CLK_BUS_NAND	33
+#define CLK_BUS_SDMMC0_BUS	34
+#define CLK_BUS_SDMMC1_BUS	35
+#define CLK_BUS_SDMMC2_BUS	36
+#define CLK_BUS_SDMMC3_BUS	37
+#define CLK_BUS_SPI0	38
+#define CLK_BUS_SPI1	39
+#define CLK_BUS_SPI2	40
+#define CLK_BUS_I2S0	41
+#define CLK_BUS_I2S1	42
+#define CLK_BUS_SPDIF	43
+#define CLK_BUS_DSD	44
+#define CLK_BUS_DMIC	45
+#define CLK_BUS_USBOHCI0	46
+#define CLK_BUS_USBEHCI0	47
+#define CLK_BUS_USBOTG	48
+#define CLK_BUS_DE	49
+#define CLK_BUS_EE	50
+#define CLK_BUS_TCON0	51
+#define CLK_BUS_CSI	52
+#define CLK_BUS_ADDA	53
+#define CLK_BUS_SDRAM	54
+#define CLK_BUS_PSRAM	55
+#define CLK_BUS_DMA	56
+#define CLK_BUS_UART0	57
+#define CLK_BUS_UART1	58
+#define CLK_BUS_UART2	59
+#define CLK_BUS_UART3	60
+#define CLK_BUS_UART4	61
+#define CLK_BUS_UART5	62
+#define CLK_BUS_TWI0	63
+#define CLK_BUS_TWI1	64
+#define CLK_BUS_TWI2	65
+#define CLK_BUS_PIO	66
+#define CLK_BUS_GPADC	67
+#define CLK_BUS_KEYADC	68
+#define CLK_MMC0_SAMPLE	69
+#define CLK_MMC0_OUTPUT	70
+#define CLK_MMC1_SAMPLE	71
+#define CLK_MMC1_OUTPUT	72
+
+#endif
diff --git a/include/dt-bindings/reset/sun8i-b288-ccu.h b/include/dt-bindings/reset/sun8i-b288-ccu.h
new file mode 100644
index 000000000000..675145654548
--- /dev/null
+++ b/include/dt-bindings/reset/sun8i-b288-ccu.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+#ifndef _DT_BINDINGS_RST_SUN8I_B288_H_
+#define _DT_BINDINGS_RST_SUN8I_B288_H_
+
+#define RST_BUS_THS	0
+#define RST_BUS_NAND	1
+#define RST_BUS_MMC0	2
+#define RST_BUS_MMC1	3
+#define RST_BUS_MMC2	4
+#define RST_BUS_MMC3	5
+#define RST_BUS_SPI0	6
+#define RST_BUS_SPI1	7
+#define RST_BUS_SPI2	8
+#define RST_BUS_I2S0	9
+#define RST_BUS_I2S1	10
+#define RST_BUS_SPDIF	11
+#define RST_BUS_DSD	12
+#define RST_BUS_DMIC	13
+#define RST_USBPHY0	14
+#define RST_BUS_OHCI0	15
+#define RST_BUS_EHCI0	16
+#define RST_BUS_OTG	17
+#define RST_BUS_DE	18
+#define RST_BUS_EE	19
+#define RST_BUS_TCON0	20
+#define RST_BUS_CSI	21
+#define RST_BUS_ADDA	22
+#define RST_BUS_WLAN	23
+#define RST_MBUS	24
+#define RST_BUS_DRAM	25
+#define RST_BUS_PSRAM	26
+#define RST_BUS_DMA	27
+#define RST_BUS_UART0	28
+#define RST_BUS_UART1	29
+#define RST_BUS_UART2	30
+#define RST_BUS_UART3	31
+#define RST_BUS_UART4	32
+#define RST_BUS_UART5	33
+#define RST_BUS_I2C0	34
+#define RST_BUS_I2C1	35
+#define RST_BUS_I2C2	36
+#define RST_BUS_GPADC	37
+#define RST_BUS_KEYADC	38
+
+#endif
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 01/11] dt-bindings: clock: sun4i-a10-ccu: add Allwinner B288 Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:21   ` sashiko-bot
  2026-10-12 10:08 ` [PATCH v4 03/11] dt-bindings: pinctrl: sun4i-a10: add Allwinner B288 Pablo Mazzini
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Brian Masney, Chen-Yu Tsai, Jernej Skrabec, Jerome Brunet,
	Samuel Holland, Stephen Boyd
  Cc: Pablo Mazzini, Andre Przywara, linux-arm-kernel, linux-clk,
	linux-kernel, linux-sunxi

Covers the PLLs, the CPU/AHB/APB tree, the module clocks and the bus
gates and resets.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
---
 drivers/clk/sunxi-ng/Kconfig          |   5 +
 drivers/clk/sunxi-ng/Makefile         |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-b288.c | 749 ++++++++++++++++++++++++++
 drivers/clk/sunxi-ng/ccu-sun8i-b288.h |  10 +
 4 files changed, 765 insertions(+)
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-b288.c
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-b288.h

diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 6af2d020e03e..5bdfb8574794 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -88,6 +88,11 @@ config SUN6I_RTC_CCU
 	default ARCH_SUNXI
 	depends on MACH_SUN8I || ARM64 || RISCV || COMPILE_TEST
 
+config SUN8I_B288_CCU
+	tristate "Support for the Allwinner B288 CCU"
+	default ARCH_SUNXI
+	depends on MACH_SUN8I || COMPILE_TEST
+
 config SUN8I_A23_CCU
 	tristate "Support for the Allwinner A23 CCU"
 	default ARCH_SUNXI
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index a1c4087d7241..dcc377a09ccc 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SUN4I_A10_CCU)	+= sun4i-a10-ccu.o
 obj-$(CONFIG_SUN5I_CCU)		+= sun5i-ccu.o
 obj-$(CONFIG_SUN6I_A31_CCU)	+= sun6i-a31-ccu.o
 obj-$(CONFIG_SUN6I_RTC_CCU)	+= sun6i-rtc-ccu.o
+obj-$(CONFIG_SUN8I_B288_CCU)	+= ccu-sun8i-b288.o
 obj-$(CONFIG_SUN8I_A23_CCU)	+= sun8i-a23-ccu.o
 obj-$(CONFIG_SUN8I_A33_CCU)	+= sun8i-a33-ccu.o
 obj-$(CONFIG_SUN8I_A83T_CCU)	+= sun8i-a83t-ccu.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-b288.c b/drivers/clk/sunxi-ng/ccu-sun8i-b288.c
new file mode 100644
index 000000000000..c53afd6f9af9
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-b288.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock Control Unit driver for the Allwinner B288 (sun8iw10p1).
+ *
+ * Closely related to the A64; most of its PLLs are bit-identical.
+ * Transcribed from the BSP clk-sun8iw10.{c,h} and cross-checked against
+ * ccu-sun50i-a64.c; divergences are called out inline.
+ *
+ * The audio clock tree (i2s/spdif/dsd/dmic/adda) is not implemented.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_mult.h"
+#include "ccu_nk.h"
+#include "ccu_nkmp.h"
+#include "ccu_nm.h"
+#include "ccu_phase.h"
+#include "ccu_sdm.h"
+
+#include "ccu-sun8i-b288.h"
+
+/*
+ * PLL_24M @ 0x034 -- B288 only. It feeds the PLLs 24 MHz whatever the
+ * crystal: it converts a 26 MHz one and is bypassed with a 24 MHz one.
+ */
+static struct clk_fixed_rate pll_24m_clk = {
+	.fixed_rate	= 24000000,
+	.hw.init	= CLK_HW_INIT_FW_NAME("pll-24m", "hosc",
+					      &clk_fixed_rate_ops, 0),
+};
+
+static const struct clk_hw *pll_24m_hws[] = { &pll_24m_clk.hw };
+
+/*
+ * PLL_CPU @ 0x000 -- N[12:8] K[5:4] M[1:0] P[17:16], gate 31, lock 28.
+ * Identical to sun50i-a64.
+ */
+static struct ccu_nkmp pll_cpux_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 5),
+	.k		= _SUNXI_CCU_MULT(4, 2),
+	.m		= _SUNXI_CCU_DIV(0, 2),
+	.p		= _SUNXI_CCU_DIV_MAX(16, 2, 4),
+	.common		= {
+		.reg		= 0x000,
+		.hw.init	= CLK_HW_INIT_HWS("pll-cpux", pll_24m_hws,
+						  &ccu_nkmp_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/*
+ * PLL_AUDIO @ 0x008 -- N[14:8] M[4:0] P[19:16], gate 31, lock 28, with
+ * sigma-delta modulation for the audio rates, as on the A64 and H3. P is
+ * forced to 1 at probe, so the rates are exact.
+ */
+#define SUN8I_B288_PLL_AUDIO_REG	0x008
+
+static struct ccu_sdm_setting pll_audio_sdm_table[] = {
+	{ .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 },
+	{ .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 },
+};
+
+static struct ccu_nm pll_audio_base_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 7),
+	.m		= _SUNXI_CCU_DIV(0, 5),
+	.sdm		= _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24),
+					 0x284, BIT(31)),
+	.common		= {
+		.reg		= SUN8I_B288_PLL_AUDIO_REG,
+		.features	= CCU_FEATURE_SIGMA_DELTA_MOD,
+		.hw.init	= CLK_HW_INIT_HWS("pll-audio-base", pll_24m_hws,
+						  &ccu_nm_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/* PLL_VIDEO0 @ 0x010 -- identical to sun50i-a64. */
+static struct ccu_nm pll_video0_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 7),
+	.m		= _SUNXI_CCU_DIV(0, 4),
+	.frac		= _SUNXI_CCU_FRAC(BIT(24), BIT(25), 270000000, 297000000),
+	.common		= {
+		.reg		= 0x010,
+		.features	= CCU_FEATURE_FRACTIONAL,
+		.hw.init	= CLK_HW_INIT_HWS("pll-video0", pll_24m_hws,
+						  &ccu_nm_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/*
+ * PLL_DDR0 @ 0x020 -- N[14:8] M[1:0]. Unlike the A64 there is no K,
+ * and N is 7 bits wide.
+ */
+static struct ccu_nm pll_ddr0_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 7),
+	.m		= _SUNXI_CCU_DIV(0, 2),
+	.common		= {
+		.reg		= 0x020,
+		.hw.init	= CLK_HW_INIT_HWS("pll-ddr0", pll_24m_hws,
+						  &ccu_nm_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/* PLL_PERIPH0 @ 0x028 -- identical to sun50i-a64, incl. fixed post-div 2. */
+static struct ccu_nk pll_periph0_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 5),
+	.k		= _SUNXI_CCU_MULT_MIN(4, 2, 2),
+	.fixed_post_div	= 2,
+	.common		= {
+		.reg		= 0x028,
+		.features	= CCU_FEATURE_FIXED_POSTDIV,
+		.hw.init	= CLK_HW_INIT_HWS("pll-periph0", pll_24m_hws,
+						  &ccu_nk_ops, 0),
+	},
+};
+
+/* PLL_VIDEO1 @ 0x030 -- same layout as PLL_VIDEO0. */
+static struct ccu_nm pll_video1_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 7),
+	.m		= _SUNXI_CCU_DIV(0, 4),
+	.frac		= _SUNXI_CCU_FRAC(BIT(24), BIT(25), 270000000, 297000000),
+	.common		= {
+		.reg		= 0x030,
+		.features	= CCU_FEATURE_FRACTIONAL,
+		.hw.init	= CLK_HW_INIT_HWS("pll-video1", pll_24m_hws,
+						  &ccu_nm_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/* PLL_PERIPH1 @ 0x044 -- identical to sun50i-a64. */
+static struct ccu_nk pll_periph1_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 5),
+	.k		= _SUNXI_CCU_MULT_MIN(4, 2, 2),
+	.fixed_post_div	= 2,
+	.common		= {
+		.reg		= 0x044,
+		.features	= CCU_FEATURE_FIXED_POSTDIV,
+		.hw.init	= CLK_HW_INIT_HWS("pll-periph1", pll_24m_hws,
+						  &ccu_nk_ops, 0),
+	},
+};
+
+/* PLL_DE @ 0x048 -- identical to sun50i-a64. */
+static struct ccu_nm pll_de_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 7),
+	.m		= _SUNXI_CCU_DIV(0, 4),
+	.frac		= _SUNXI_CCU_FRAC(BIT(24), BIT(25), 270000000, 297000000),
+	.common		= {
+		.reg		= 0x048,
+		.features	= CCU_FEATURE_FRACTIONAL,
+		.hw.init	= CLK_HW_INIT_HWS("pll-de", pll_24m_hws,
+						  &ccu_nm_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/* PLL_DDR1 @ 0x04c -- B288 only. Same layout; this is the one feeding DRAM. */
+static struct ccu_nm pll_ddr1_clk = {
+	.enable		= BIT(31),
+	.lock		= BIT(28),
+	.n		= _SUNXI_CCU_MULT(8, 7),
+	.m		= _SUNXI_CCU_DIV(0, 2),
+	.common		= {
+		.reg		= 0x04c,
+		.hw.init	= CLK_HW_INIT_HWS("pll-ddr1", pll_24m_hws,
+						  &ccu_nm_ops,
+						  CLK_SET_RATE_UNGATE),
+	},
+};
+
+/*
+ * pll_periph{0,1} carry a fixed /2 post-divider, so the 2x clocks are the
+ * raw outputs.
+ */
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+			   &pll_periph0_clk.common.hw,
+			   1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+			   &pll_periph1_clk.common.hw,
+			   1, 2, 0);
+
+/*
+ * CPU_CFG @ 0x050 -- mux[17:16], CPUAPB divider [9:8], AXI divider [1:0].
+ * Same layout as the H3 and the A64.
+ */
+static const struct clk_parent_data cpux_parents[] = {
+	{ .fw_name = "losc" },
+	{ .fw_name = "hosc" },
+	{ .hw = &pll_cpux_clk.common.hw },
+	{ .hw = &pll_cpux_clk.common.hw },
+};
+
+static SUNXI_CCU_MUX_DATA(cpux_clk, "cpux", cpux_parents,
+			  0x050, 16, 2, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *cpux_hws[] = { &cpux_clk.common.hw };
+static SUNXI_CCU_M_HWS(axi_clk, "axi", cpux_hws, 0x050, 0, 2, 0);
+static SUNXI_CCU_M_HWS(cpuapb_clk, "cpuapb", cpux_hws, 0x050, 8, 2, 0);
+
+/*
+ * AHB1_CFG @ 0x054 -- mux[13:12], AHB1 P2 divider [5:4], PLL_PERIPH0-only
+ * pre-divider [7:6], APB1 divider [9:8].
+ */
+static const struct clk_parent_data ahb1_parents[] = {
+	{ .fw_name = "losc" },
+	{ .fw_name = "hosc" },
+	{ .hw = &axi_clk.common.hw },
+	{ .hw = &pll_periph0_clk.common.hw },
+};
+
+static const struct ccu_mux_var_prediv ahb1_predivs[] = {
+	{ .index = 3, .shift = 6, .width = 2 },
+};
+
+static struct ccu_div ahb1_clk = {
+	.div		= _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
+
+	.mux		= {
+		.shift	= 12,
+		.width	= 2,
+
+		.var_predivs	= ahb1_predivs,
+		.n_var_predivs	= ARRAY_SIZE(ahb1_predivs),
+	},
+
+	.common		= {
+		.reg		= 0x054,
+		.features	= CCU_FEATURE_VARIABLE_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("ahb1",
+							   ahb1_parents,
+							   &ccu_div_ops,
+							   0),
+	},
+};
+
+static struct clk_div_table apb1_div_table[] = {
+	{ .val = 0, .div = 2 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ .val = 3, .div = 8 },
+	{ /* Sentinel */ },
+};
+
+static SUNXI_CCU_DIV_TABLE_HW(apb1_clk, "apb1", &ahb1_clk.common.hw,
+			      0x054, 8, 2, apb1_div_table, 0);
+
+/*
+ * APB2_CFG @ 0x058 -- M[4:0] P[17:16] mux[25:24]. The divider matches the
+ * H3, but mux index 2 selects PLL_24M here rather than PLL_PERIPH0_2X.
+ */
+static const struct clk_parent_data apb2_parents[] = {
+	{ .fw_name = "losc" },
+	{ .fw_name = "hosc" },
+	{ .hw = &pll_24m_clk.hw },
+	{ .hw = &pll_periph0_2x_clk.hw },
+};
+
+static SUNXI_CCU_MP_DATA_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058,
+				  0, 5,		/* M */
+				  16, 2,	/* P */
+				  24, 2,	/* mux */
+				  0);
+
+static const struct clk_parent_data mod0_parents[] = {
+	{ .fw_name = "hosc" },
+	{ .hw = &pll_periph0_2x_clk.hw },
+	{ .hw = &pll_periph1_2x_clk.hw },
+};
+
+static const struct clk_parent_data de_parents[] = {
+	{ .hw = &pll_periph0_2x_clk.hw },
+	{ .hw = &pll_de_clk.common.hw },
+};
+
+static const struct clk_parent_data tcon0_parents[] = {
+	{ .hw = &pll_video0_clk.common.hw },
+	{ .hw = &pll_video1_clk.common.hw },
+};
+
+static const struct clk_parent_data mbus_parents[] = {
+	{ .fw_name = "hosc" },
+	{ .hw = &pll_periph0_2x_clk.hw },
+	{ .hw = &pll_ddr0_clk.common.hw },
+	{ .hw = &pll_ddr1_clk.common.hw },
+};
+
+static const struct clk_parent_data dram_parents[] = {
+	{ .hw = &pll_ddr0_clk.common.hw },
+	{ .hw = &pll_ddr1_clk.common.hw },
+	{ .hw = &pll_periph0_2x_clk.hw },
+};
+
+/* NAND_CFG @ 0x080 -- M[3:0] P[17:16] mux[25:24] gate 31 */
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(nand_clk, "nand", mod0_parents, 0x080,
+				       0, 4,		/* M */
+				       16, 2,	/* P */
+				       24, 2,	/* mux */
+				       BIT(31),	/* gate */
+				       0);
+
+/*
+ * SD{0..3}_CFG @ 0x088/0x08c/0x090/0x094 -- same layout as NAND.
+ * mmc0/mmc1 use the old timing mode: no post-divider, and they need the
+ * sample and output phase clocks. mmc2/mmc3 halve the clock internally.
+ */
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_parents, 0x088,
+				       0, 4,		/* M */
+				       16, 2,	/* P */
+				       24, 2,	/* mux */
+				       BIT(31),	/* gate */
+				       0);
+static struct ccu_phase mmc0_sample_clk = {
+	.shift	= 20,
+	.width	= 3,
+	.common	= {
+		.reg		= 0x088,
+		.hw.init	= CLK_HW_INIT_HW("mmc0_sample", &mmc0_clk.common.hw,
+						 &ccu_phase_ops, 0),
+	},
+};
+
+static struct ccu_phase mmc0_output_clk = {
+	.shift	= 8,
+	.width	= 3,
+	.common	= {
+		.reg		= 0x088,
+		.hw.init	= CLK_HW_INIT_HW("mmc0_output", &mmc0_clk.common.hw,
+						 &ccu_phase_ops, 0),
+	},
+};
+
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_parents, 0x08c,
+				       0, 4,		/* M */
+				       16, 2,	/* P */
+				       24, 2,	/* mux */
+				       BIT(31),	/* gate */
+				       0);
+static struct ccu_phase mmc1_sample_clk = {
+	.shift	= 20,
+	.width	= 3,
+	.common	= {
+		.reg		= 0x08c,
+		.hw.init	= CLK_HW_INIT_HW("mmc1_sample", &mmc1_clk.common.hw,
+						 &ccu_phase_ops, 0),
+	},
+};
+
+static struct ccu_phase mmc1_output_clk = {
+	.shift	= 8,
+	.width	= 3,
+	.common	= {
+		.reg		= 0x08c,
+		.hw.init	= CLK_HW_INIT_HW("mmc1_output", &mmc1_clk.common.hw,
+						 &ccu_phase_ops, 0),
+	},
+};
+
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mod0_parents,
+					       0x090, 0, 4, 16, 2, 24, 2,
+					       BIT(31), 2, 0);
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(mmc3_clk, "mmc3", mod0_parents,
+					       0x094, 0, 4, 16, 2, 24, 2,
+					       BIT(31), 2, 0);
+
+/* SPI{0..2}_CFG @ 0x0a0/0x0a4/0x0a8 -- same layout as NAND. */
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi0_clk, "spi0", mod0_parents, 0x0a0,
+				       0, 4, 16, 2, 24, 2, BIT(31), 0);
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi1_clk, "spi1", mod0_parents, 0x0a4,
+				       0, 4, 16, 2, 24, 2, BIT(31), 0);
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi2_clk, "spi2", mod0_parents, 0x0a8,
+				       0, 4, 16, 2, 24, 2, BIT(31), 0);
+
+/* DRAM_CFG @ 0x0f4 -- M[1:0] mux[21:20] gate 31 */
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(dram_clk, "dram", dram_parents, 0x0f4,
+				      0, 2,		/* M */
+				      20, 2,		/* mux */
+				      BIT(31),	/* gate */
+				      CLK_IS_CRITICAL);
+
+/* DE_CFG @ 0x104, EE_CFG @ 0x108, EDMA_CFG @ 0x10c -- M[3:0] mux[26:24] gate 31 */
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(de_clk, "de", de_parents, 0x104,
+				      0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ee_clk, "ee", de_parents, 0x108,
+				      0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(edma_clk, "edma", de_parents, 0x10c,
+				      0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+/* TCON_CFG @ 0x118 -- mux[26:24] gate 31, no divider */
+static SUNXI_CCU_MUX_DATA_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, 0x118,
+				    24, 3,		/* mux */
+				    BIT(31),		/* gate */
+				    CLK_SET_RATE_PARENT);
+
+/* MBUS_CFG @ 0x15c -- M[2:0] mux[25:24] gate 31 */
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x15c,
+				      0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL);
+
+static const struct clk_hw *ahb1_hws[] = { &ahb1_clk.common.hw };
+static const struct clk_hw *apb1_hws[] = { &apb1_clk.common.hw };
+static const struct clk_hw *apb2_hws[] = { &apb2_clk.common.hw };
+
+static SUNXI_CCU_GATE_HWS(bus_ths_clk, "bus-ths", apb1_hws,
+			  0x068, BIT(8), 0);
+static SUNXI_CCU_GATE_HWS(bus_nand_clk, "bus-nand", ahb1_hws,
+			  0x060, BIT(13), 0);
+static SUNXI_CCU_GATE_HWS(bus_sdmmc0_bus_clk, "bus-sdmmc0-bus", ahb1_hws,
+			  0x060, BIT(8), 0);
+static SUNXI_CCU_GATE_HWS(bus_sdmmc1_bus_clk, "bus-sdmmc1-bus", ahb1_hws,
+			  0x060, BIT(9), 0);
+static SUNXI_CCU_GATE_HWS(bus_sdmmc2_bus_clk, "bus-sdmmc2-bus", ahb1_hws,
+			  0x060, BIT(10), 0);
+static SUNXI_CCU_GATE_HWS(bus_sdmmc3_bus_clk, "bus-sdmmc3-bus", ahb1_hws,
+			  0x060, BIT(11), 0);
+static SUNXI_CCU_GATE_HWS(bus_spi0_clk, "bus-spi0", ahb1_hws,
+			  0x060, BIT(20), 0);
+static SUNXI_CCU_GATE_HWS(bus_spi1_clk, "bus-spi1", ahb1_hws,
+			  0x060, BIT(21), 0);
+static SUNXI_CCU_GATE_HWS(bus_spi2_clk, "bus-spi2", ahb1_hws,
+			  0x060, BIT(22), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2s0_clk, "bus-i2s0", apb1_hws,
+			  0x068, BIT(12), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2s1_clk, "bus-i2s1", apb1_hws,
+			  0x068, BIT(13), 0);
+static SUNXI_CCU_GATE_HWS(bus_spdif_clk, "bus-spdif", apb1_hws,
+			  0x068, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_dsd_clk, "bus-dsd", apb1_hws,
+			  0x068, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(bus_dmic_clk, "bus-dmic", apb1_hws,
+			  0x068, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(bus_usbohci0_clk, "bus-usbohci0", ahb1_hws,
+			  0x060, BIT(29), 0);
+static SUNXI_CCU_GATE_HWS(bus_usbehci0_clk, "bus-usbehci0", ahb1_hws,
+			  0x060, BIT(26), 0);
+static SUNXI_CCU_GATE_HWS(bus_usbotg_clk, "bus-usbotg", ahb1_hws,
+			  0x060, BIT(24), 0);
+static SUNXI_CCU_GATE_HWS(bus_de_clk, "bus-de", ahb1_hws,
+			  0x064, BIT(12), 0);
+static SUNXI_CCU_GATE_HWS(bus_ee_clk, "bus-ee", ahb1_hws,
+			  0x064, BIT(13), 0);
+static SUNXI_CCU_GATE_HWS(bus_tcon0_clk, "bus-tcon0", ahb1_hws,
+			  0x064, BIT(4), 0);
+/* csi_s, csi_m and csi_misc share one bus gate, as on the A64. */
+static SUNXI_CCU_GATE_HWS(bus_csi_clk, "bus-csi", ahb1_hws,
+			  0x064, BIT(8), 0);
+static SUNXI_CCU_GATE_HWS(bus_adda_clk, "bus-adda", apb1_hws,
+			  0x068, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_sdram_clk, "bus-sdram", ahb1_hws,
+			  0x060, BIT(14), 0);
+static SUNXI_CCU_GATE_HWS(bus_psram_clk, "bus-psram", ahb1_hws,
+			  0x060, BIT(15), 0);
+static SUNXI_CCU_GATE_HWS(bus_dma_clk, "bus-dma", ahb1_hws,
+			  0x060, BIT(6), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart0_clk, "bus-uart0", apb2_hws,
+			  0x06c, BIT(16), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart1_clk, "bus-uart1", apb2_hws,
+			  0x06c, BIT(17), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart2_clk, "bus-uart2", apb2_hws,
+			  0x06c, BIT(18), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart3_clk, "bus-uart3", apb2_hws,
+			  0x06c, BIT(19), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart4_clk, "bus-uart4", apb2_hws,
+			  0x06c, BIT(20), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart5_clk, "bus-uart5", apb2_hws,
+			  0x06c, BIT(21), 0);
+static SUNXI_CCU_GATE_HWS(bus_twi0_clk, "bus-twi0", apb2_hws,
+			  0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_twi1_clk, "bus-twi1", apb2_hws,
+			  0x06c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_twi2_clk, "bus-twi2", apb2_hws,
+			  0x06c, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(bus_pio_clk, "bus-pio", apb1_hws,
+			  0x068, BIT(5), 0);
+static SUNXI_CCU_GATE_HWS(bus_gpadc_clk, "bus-gpadc", apb1_hws,
+			  0x068, BIT(10), 0);
+static SUNXI_CCU_GATE_HWS(bus_keyadc_clk, "bus-keyadc", apb1_hws,
+			  0x068, BIT(9), 0);
+/* losc_out is the RTC's osc32k-out */
+
+static const struct ccu_reset_map sun8i_b288_ccu_resets[] = {
+	[RST_BUS_THS]	= { 0x2d0, BIT(8) },
+	[RST_BUS_NAND]	= { 0x2c0, BIT(13) },
+	[RST_BUS_MMC0]	= { 0x2c0, BIT(8) },
+	[RST_BUS_MMC1]	= { 0x2c0, BIT(9) },
+	[RST_BUS_MMC2]	= { 0x2c0, BIT(10) },
+	[RST_BUS_MMC3]	= { 0x2c0, BIT(11) },
+	[RST_BUS_SPI0]	= { 0x2c0, BIT(20) },
+	[RST_BUS_SPI1]	= { 0x2c0, BIT(21) },
+	[RST_BUS_SPI2]	= { 0x2c0, BIT(22) },
+	[RST_BUS_I2S0]	= { 0x2d0, BIT(12) },
+	[RST_BUS_I2S1]	= { 0x2d0, BIT(13) },
+	[RST_BUS_SPDIF]	= { 0x2d0, BIT(1) },
+	[RST_BUS_DSD]	= { 0x2d0, BIT(2) },
+	[RST_BUS_DMIC]	= { 0x2d0, BIT(3) },
+	[RST_USBPHY0]	= { 0x0cc, BIT(0) },
+	[RST_BUS_OHCI0]	= { 0x2c0, BIT(29) },
+	[RST_BUS_EHCI0]	= { 0x2c0, BIT(26) },
+	[RST_BUS_OTG]	= { 0x2c0, BIT(24) },
+	[RST_BUS_DE]	= { 0x2c4, BIT(12) },
+	[RST_BUS_EE]	= { 0x2c4, BIT(13) },
+	[RST_BUS_TCON0]	= { 0x2c4, BIT(4) },
+	[RST_BUS_CSI]	= { 0x2c4, BIT(8) },
+	[RST_BUS_ADDA]	= { 0x2d0, BIT(0) },
+	[RST_BUS_WLAN]	= { 0x2c4, BIT(1) },
+	[RST_MBUS]	= { 0x0fc, BIT(31) },
+	[RST_BUS_DRAM]	= { 0x2c0, BIT(14) },
+	[RST_BUS_PSRAM]	= { 0x2c0, BIT(15) },
+	[RST_BUS_DMA]	= { 0x2c0, BIT(6) },
+	[RST_BUS_UART0]	= { 0x2d8, BIT(16) },
+	[RST_BUS_UART1]	= { 0x2d8, BIT(17) },
+	[RST_BUS_UART2]	= { 0x2d8, BIT(18) },
+	[RST_BUS_UART3]	= { 0x2d8, BIT(19) },
+	[RST_BUS_UART4]	= { 0x2d8, BIT(20) },
+	[RST_BUS_UART5]	= { 0x2d8, BIT(21) },
+	[RST_BUS_I2C0]	= { 0x2d8, BIT(0) },
+	[RST_BUS_I2C1]	= { 0x2d8, BIT(1) },
+	[RST_BUS_I2C2]	= { 0x2d8, BIT(2) },
+	[RST_BUS_GPADC]	= { 0x2d0, BIT(10) },
+	[RST_BUS_KEYADC]	= { 0x2d0, BIT(9) },
+};
+
+static struct ccu_common *sun8i_b288_ccu_clks[] = {
+	&pll_cpux_clk.common,
+	&pll_audio_base_clk.common,
+	&pll_video0_clk.common,
+	&pll_ddr0_clk.common,
+	&pll_periph0_clk.common,
+	&pll_video1_clk.common,
+	&pll_periph1_clk.common,
+	&pll_de_clk.common,
+	&pll_ddr1_clk.common,
+	&cpux_clk.common,
+	&axi_clk.common,
+	&cpuapb_clk.common,
+	&ahb1_clk.common,
+	&apb1_clk.common,
+	&apb2_clk.common,
+	&nand_clk.common,
+	&mmc0_clk.common,
+	&mmc0_sample_clk.common,
+	&mmc0_output_clk.common,
+	&mmc1_clk.common,
+	&mmc1_sample_clk.common,
+	&mmc1_output_clk.common,
+	&mmc2_clk.common,
+	&mmc3_clk.common,
+	&spi0_clk.common,
+	&spi1_clk.common,
+	&spi2_clk.common,
+	&dram_clk.common,
+	&de_clk.common,
+	&ee_clk.common,
+	&edma_clk.common,
+	&tcon0_clk.common,
+	&mbus_clk.common,
+	&bus_ths_clk.common,
+	&bus_nand_clk.common,
+	&bus_sdmmc0_bus_clk.common,
+	&bus_sdmmc1_bus_clk.common,
+	&bus_sdmmc2_bus_clk.common,
+	&bus_sdmmc3_bus_clk.common,
+	&bus_spi0_clk.common,
+	&bus_spi1_clk.common,
+	&bus_spi2_clk.common,
+	&bus_i2s0_clk.common,
+	&bus_i2s1_clk.common,
+	&bus_spdif_clk.common,
+	&bus_dsd_clk.common,
+	&bus_dmic_clk.common,
+	&bus_usbohci0_clk.common,
+	&bus_usbehci0_clk.common,
+	&bus_usbotg_clk.common,
+	&bus_de_clk.common,
+	&bus_ee_clk.common,
+	&bus_tcon0_clk.common,
+	&bus_csi_clk.common,
+	&bus_adda_clk.common,
+	&bus_sdram_clk.common,
+	&bus_psram_clk.common,
+	&bus_dma_clk.common,
+	&bus_uart0_clk.common,
+	&bus_uart1_clk.common,
+	&bus_uart2_clk.common,
+	&bus_uart3_clk.common,
+	&bus_uart4_clk.common,
+	&bus_uart5_clk.common,
+	&bus_twi0_clk.common,
+	&bus_twi1_clk.common,
+	&bus_twi2_clk.common,
+	&bus_pio_clk.common,
+	&bus_gpadc_clk.common,
+	&bus_keyadc_clk.common,
+};
+
+static struct clk_hw_onecell_data sun8i_b288_hw_clks = {
+	.hws	= {
+		[CLK_PLL_CPUX]		= &pll_cpux_clk.common.hw,
+		[CLK_PLL_AUDIO_BASE]	= &pll_audio_base_clk.common.hw,
+		[CLK_PLL_VIDEO0]	= &pll_video0_clk.common.hw,
+		[CLK_PLL_DDR0]		= &pll_ddr0_clk.common.hw,
+		[CLK_PLL_PERIPH0]	= &pll_periph0_clk.common.hw,
+		[CLK_PLL_VIDEO1]	= &pll_video1_clk.common.hw,
+		[CLK_PLL_24M]		= &pll_24m_clk.hw,
+		[CLK_PLL_PERIPH1]	= &pll_periph1_clk.common.hw,
+		[CLK_PLL_DE]		= &pll_de_clk.common.hw,
+		[CLK_PLL_DDR1]		= &pll_ddr1_clk.common.hw,
+		[CLK_PLL_PERIPH0_2X]	= &pll_periph0_2x_clk.hw,
+		[CLK_PLL_PERIPH1_2X]	= &pll_periph1_2x_clk.hw,
+		[CLK_CPUX]	= &cpux_clk.common.hw,
+		[CLK_AXI]	= &axi_clk.common.hw,
+		[CLK_CPUAPB]	= &cpuapb_clk.common.hw,
+		[CLK_AHB1]	= &ahb1_clk.common.hw,
+		[CLK_APB1]	= &apb1_clk.common.hw,
+		[CLK_APB2]	= &apb2_clk.common.hw,
+		[CLK_NAND]	= &nand_clk.common.hw,
+		[CLK_MMC0]	= &mmc0_clk.common.hw,
+		[CLK_MMC0_SAMPLE]	= &mmc0_sample_clk.common.hw,
+		[CLK_MMC0_OUTPUT]	= &mmc0_output_clk.common.hw,
+		[CLK_MMC1]	= &mmc1_clk.common.hw,
+		[CLK_MMC1_SAMPLE]	= &mmc1_sample_clk.common.hw,
+		[CLK_MMC1_OUTPUT]	= &mmc1_output_clk.common.hw,
+		[CLK_MMC2]	= &mmc2_clk.common.hw,
+		[CLK_MMC3]	= &mmc3_clk.common.hw,
+		[CLK_SPI0]	= &spi0_clk.common.hw,
+		[CLK_SPI1]	= &spi1_clk.common.hw,
+		[CLK_SPI2]	= &spi2_clk.common.hw,
+		[CLK_DRAM]	= &dram_clk.common.hw,
+		[CLK_DE]	= &de_clk.common.hw,
+		[CLK_EE]	= &ee_clk.common.hw,
+		[CLK_EDMA]	= &edma_clk.common.hw,
+		[CLK_TCON0]	= &tcon0_clk.common.hw,
+		[CLK_MBUS]	= &mbus_clk.common.hw,
+		[CLK_BUS_THS]	= &bus_ths_clk.common.hw,
+		[CLK_BUS_NAND]	= &bus_nand_clk.common.hw,
+		[CLK_BUS_SDMMC0_BUS]	= &bus_sdmmc0_bus_clk.common.hw,
+		[CLK_BUS_SDMMC1_BUS]	= &bus_sdmmc1_bus_clk.common.hw,
+		[CLK_BUS_SDMMC2_BUS]	= &bus_sdmmc2_bus_clk.common.hw,
+		[CLK_BUS_SDMMC3_BUS]	= &bus_sdmmc3_bus_clk.common.hw,
+		[CLK_BUS_SPI0]	= &bus_spi0_clk.common.hw,
+		[CLK_BUS_SPI1]	= &bus_spi1_clk.common.hw,
+		[CLK_BUS_SPI2]	= &bus_spi2_clk.common.hw,
+		[CLK_BUS_I2S0]	= &bus_i2s0_clk.common.hw,
+		[CLK_BUS_I2S1]	= &bus_i2s1_clk.common.hw,
+		[CLK_BUS_SPDIF]	= &bus_spdif_clk.common.hw,
+		[CLK_BUS_DSD]	= &bus_dsd_clk.common.hw,
+		[CLK_BUS_DMIC]	= &bus_dmic_clk.common.hw,
+		[CLK_BUS_USBOHCI0]	= &bus_usbohci0_clk.common.hw,
+		[CLK_BUS_USBEHCI0]	= &bus_usbehci0_clk.common.hw,
+		[CLK_BUS_USBOTG]	= &bus_usbotg_clk.common.hw,
+		[CLK_BUS_DE]	= &bus_de_clk.common.hw,
+		[CLK_BUS_EE]	= &bus_ee_clk.common.hw,
+		[CLK_BUS_TCON0]	= &bus_tcon0_clk.common.hw,
+		[CLK_BUS_CSI]		= &bus_csi_clk.common.hw,
+		[CLK_BUS_ADDA]	= &bus_adda_clk.common.hw,
+		[CLK_BUS_SDRAM]	= &bus_sdram_clk.common.hw,
+		[CLK_BUS_PSRAM]	= &bus_psram_clk.common.hw,
+		[CLK_BUS_DMA]	= &bus_dma_clk.common.hw,
+		[CLK_BUS_UART0]	= &bus_uart0_clk.common.hw,
+		[CLK_BUS_UART1]	= &bus_uart1_clk.common.hw,
+		[CLK_BUS_UART2]	= &bus_uart2_clk.common.hw,
+		[CLK_BUS_UART3]	= &bus_uart3_clk.common.hw,
+		[CLK_BUS_UART4]	= &bus_uart4_clk.common.hw,
+		[CLK_BUS_UART5]	= &bus_uart5_clk.common.hw,
+		[CLK_BUS_TWI0]	= &bus_twi0_clk.common.hw,
+		[CLK_BUS_TWI1]	= &bus_twi1_clk.common.hw,
+		[CLK_BUS_TWI2]	= &bus_twi2_clk.common.hw,
+		[CLK_BUS_PIO]	= &bus_pio_clk.common.hw,
+		[CLK_BUS_GPADC]	= &bus_gpadc_clk.common.hw,
+		[CLK_BUS_KEYADC]	= &bus_keyadc_clk.common.hw,
+	},
+	.num	= CLK_NUMBER,
+};
+
+static const struct sunxi_ccu_desc sun8i_b288_ccu_desc = {
+	.ccu_clks	= sun8i_b288_ccu_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun8i_b288_ccu_clks),
+
+	.hw_clks	= &sun8i_b288_hw_clks,
+
+	.resets		= sun8i_b288_ccu_resets,
+	.num_resets	= ARRAY_SIZE(sun8i_b288_ccu_resets),
+
+};
+
+static int sun8i_b288_ccu_probe(struct platform_device *pdev)
+{
+	void __iomem *reg;
+	u32 val;
+
+	reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(reg))
+		return PTR_ERR(reg);
+
+	/* Force the PLL-Audio-1x divider to 1 */
+	val = readl(reg + SUN8I_B288_PLL_AUDIO_REG);
+	val &= ~GENMASK(19, 16);
+	writel(val, reg + SUN8I_B288_PLL_AUDIO_REG);
+
+	return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_b288_ccu_desc);
+}
+
+static const struct of_device_id sun8i_b288_ccu_ids[] = {
+	{ .compatible = "allwinner,sun8i-b288-ccu" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun8i_b288_ccu_ids);
+
+static struct platform_driver sun8i_b288_ccu_driver = {
+	.probe	= sun8i_b288_ccu_probe,
+	.driver	= {
+		.name			= "sun8i-b288-ccu",
+		.suppress_bind_attrs	= true,
+		.of_match_table		= sun8i_b288_ccu_ids,
+	},
+};
+module_platform_driver(sun8i_b288_ccu_driver);
+
+MODULE_IMPORT_NS("SUNXI_CCU");
+MODULE_DESCRIPTION("Allwinner B288 (sun8iw10p1) CCU driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-b288.h b/drivers/clk/sunxi-ng/ccu-sun8i-b288.h
new file mode 100644
index 000000000000..805df2d6d99c
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-b288.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _CCU_SUN8I_B288_H_
+#define _CCU_SUN8I_B288_H_
+
+#include <dt-bindings/clock/sun8i-b288-ccu.h>
+#include <dt-bindings/reset/sun8i-b288-ccu.h>
+
+#define CLK_NUMBER		(CLK_MMC1_OUTPUT + 1)
+
+#endif /* _CCU_SUN8I_B288_H_ */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 03/11] dt-bindings: pinctrl: sun4i-a10: add Allwinner B288
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 01/11] dt-bindings: clock: sun4i-a10-ccu: add Allwinner B288 Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver Pablo Mazzini
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Conor Dooley, Jernej Skrabec, Krzysztof Kozlowski,
	Linus Walleij, Maxime Ripard, Rob Herring, Samuel Holland
  Cc: Pablo Mazzini, Andre Przywara, devicetree, linux-arm-kernel,
	linux-gpio, linux-kernel, linux-sunxi

The B288 driver takes its mux values from the DT, so allwinner,pinmux
becomes an allowed property here, required for this compatible only.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
---
 .../pinctrl/allwinner,sun4i-a10-pinctrl.yaml  | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
index 45b7a0b6c626..b1f093d218f5 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
@@ -39,6 +39,7 @@ properties:
       - allwinner,sun8i-a33-pinctrl
       - allwinner,sun8i-a83t-pinctrl
       - allwinner,sun8i-a83t-r-pinctrl
+      - allwinner,sun8i-b288-pinctrl
       - allwinner,sun8i-h3-pinctrl
       - allwinner,sun8i-h3-r-pinctrl
       - allwinner,sun8i-r40-pinctrl
@@ -120,6 +121,15 @@ patternProperties:
         $ref: /schemas/types.yaml#/definitions/uint32
         enum: [10, 20, 30, 40]
 
+      allwinner,pinmux:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        description:
+          Pinmux selector value, for each pin. Only used by SoCs whose
+          driver takes the mux values from the DT instead of an in-driver
+          table. Almost every time this value is the same for all pins, so
+          any array shorter than the number of pins will repeat the last
+          value, to allow just specifying a single cell, for all cells.
+
     required:
       - pins
       - function
@@ -144,6 +154,17 @@ allOf:
   # warnings.
 
   - $ref: pinctrl.yaml#
+
+  - if:
+      properties:
+        compatible:
+          const: allwinner,sun8i-b288-pinctrl
+
+    then:
+      patternProperties:
+        "^([rs]-)?(([a-z0-9]{3,}|[a-oq-z0-9][a-z0-9]*?)?-)+?(p[a-ilm][0-9]*?-)??pins?$":
+          required:
+            - allwinner,pinmux
   - if:
       not:
         properties:
@@ -222,6 +243,7 @@ allOf:
           enum:
             - allwinner,sun6i-a31-pinctrl
             - allwinner,sun6i-a31s-pinctrl
+            - allwinner,sun8i-b288-pinctrl
             - allwinner,sun50i-h6-pinctrl
 
     then:
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (2 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 03/11] dt-bindings: pinctrl: sun4i-a10: add Allwinner B288 Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:29   ` sashiko-bot
  2026-10-12 10:08 ` [PATCH v4 05/11] dt-bindings: rtc: sun6i-a31: add Allwinner B288 Pablo Mazzini
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Jernej Skrabec, Linus Walleij, Samuel Holland
  Cc: Pablo Mazzini, Andre Przywara, linux-arm-kernel, linux-gpio,
	linux-kernel, linux-sunxi

80 pins across ports B, C, D, F and G; the mux values come from the DT.
Port C has no external interrupts. PH0 is BSP FPGA-only and omitted.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
---
 drivers/pinctrl/sunxi/Kconfig              | 10 +++++
 drivers/pinctrl/sunxi/Makefile             |  1 +
 drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c | 49 ++++++++++++++++++++++
 3 files changed, 60 insertions(+)
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c

diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index dc62eba96348..a08186133090 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -56,6 +56,16 @@ config PINCTRL_SUN8I_A23_R
 	default MACH_SUN8I
 	select PINCTRL_SUNXI
 
+config PINCTRL_SUN8I_B288
+	bool "Support for the Allwinner B288 PIO"
+	default MACH_SUN8I
+	select PINCTRL_SUNXI
+	help
+	  Say Y here to enable pin controller and GPIO support for the
+	  Allwinner B288 (sun8iw10p1) SoC, as used in e-book readers such
+	  as the PocketBook Verse. This covers ports B, C, D, F and G,
+	  including the four banks of external interrupt capable pins.
+
 config PINCTRL_SUN8I_H3
 	bool "Support for the Allwinner H3 PIO"
 	default MACH_SUN8I
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index 951b3f1e4b4f..5129c0f19f3e 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_PINCTRL_SUN50I_A100)	+= pinctrl-sun50i-a100.o
 obj-$(CONFIG_PINCTRL_SUN50I_A100_R)	+= pinctrl-sun50i-a100-r.o
 obj-$(CONFIG_PINCTRL_SUN8I_A83T)	+= pinctrl-sun8i-a83t.o
 obj-$(CONFIG_PINCTRL_SUN8I_A83T_R)	+= pinctrl-sun8i-a83t-r.o
+obj-$(CONFIG_PINCTRL_SUN8I_B288)	+= pinctrl-sun8i-b288.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3)		+= pinctrl-sun8i-h3.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3_R)	+= pinctrl-sun8i-h3-r.o
 obj-$(CONFIG_PINCTRL_SUN8I_V3S)		+= pinctrl-sun8i-v3s.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
new file mode 100644
index 000000000000..f973c2b3f2eb
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Allwinner B288 (sun8iw10p1) SoC pinctrl driver.
+ *
+ * Bank sizes and the interrupt mux derived from Allwinner's BSP driver
+ * pinctrl-sun8iw10p1.c, which is:
+ * Copyright (C) 2014 Jackie Hwang <huangshr@allwinnertech.com>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+/* PH0 exists only on the BSP's FPGA platform and is omitted. */
+static const u8 b288_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] =
+/*	  PA  PB  PC  PD  PE  PF  PG */
+	{  0, 17, 15, 29,  0,  7, 12 };
+
+static const u8 b288_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
+/*	  PA  PB  PC  PD  PE  PF  PG */
+	{  0,  6,  0,  6,  0,  6,  6 };
+
+static struct sunxi_pinctrl_desc b288_pinctrl_data = {
+	.irq_banks	= 4,
+};
+
+static int b288_pinctrl_probe(struct platform_device *pdev)
+{
+	return sunxi_pinctrl_dt_table_init(pdev, b288_nr_bank_pins,
+					   b288_irq_bank_muxes,
+					   &b288_pinctrl_data, 0);
+}
+
+static const struct of_device_id b288_pinctrl_match[] = {
+	{ .compatible = "allwinner,sun8i-b288-pinctrl", },
+	{}
+};
+
+static struct platform_driver b288_pinctrl_driver = {
+	.probe	= b288_pinctrl_probe,
+	.driver	= {
+		.name		= "sun8i-b288-pinctrl",
+		.of_match_table	= b288_pinctrl_match,
+	},
+};
+builtin_platform_driver(b288_pinctrl_driver);
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 05/11] dt-bindings: rtc: sun6i-a31: add Allwinner B288
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (3 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:15   ` sashiko-bot
  2026-10-12 10:08 ` [PATCH v4 06/11] rtc: sun6i: add Allwinner B288 compatible Pablo Mazzini
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Alexandre Belloni, Chen-Yu Tsai, Conor Dooley, Jernej Skrabec,
	Krzysztof Kozlowski, Maxime Ripard, Rob Herring, Samuel Holland
  Cc: Pablo Mazzini, Andre Przywara, devicetree, linux-arm-kernel,
	linux-kernel, linux-rtc, linux-sunxi

The B288 RTC wires one alarm interrupt, not two.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
---
 .../devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml       | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
index f2b91186ed37..ebe35f893f8c 100644
--- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
@@ -19,6 +19,7 @@ properties:
       - enum:
           - allwinner,sun6i-a31-rtc
           - allwinner,sun8i-a23-rtc
+          - allwinner,sun8i-b288-rtc
           - allwinner,sun8i-h3-rtc
           - allwinner,sun8i-r40-rtc
           - allwinner,sun8i-v3-rtc
@@ -82,6 +83,7 @@ allOf:
           contains:
             enum:
               - allwinner,sun8i-a23-rtc
+              - allwinner,sun8i-b288-rtc
               - allwinner,sun8i-r40-rtc
               - allwinner,sun8i-v3-rtc
 
@@ -162,6 +164,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - allwinner,sun8i-b288-rtc
               - allwinner,sun8i-r40-rtc
               - allwinner,sun50i-h616-rtc
               - allwinner,sun50i-r329-rtc
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 06/11] rtc: sun6i: add Allwinner B288 compatible
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (4 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 05/11] dt-bindings: rtc: sun6i-a31: add Allwinner B288 Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:19   ` sashiko-bot
  2026-10-12 10:08 ` [PATCH v4 08/11] dt-bindings: interrupt-controller: add Allwinner B288 NMI Pablo Mazzini
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Alexandre Belloni, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
  Cc: Pablo Mazzini, Andre Przywara, linux-arm-kernel, linux-kernel,
	linux-rtc, linux-sunxi

The 32 kHz clocks are the same as the A23's. Only one alarm interrupt
is wired, which is all the driver uses.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
---
 drivers/rtc/rtc-sun6i.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index 7fc60880e409..05004e80ac08 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -350,6 +350,10 @@ static void __init sun8i_a23_rtc_clk_init(struct device_node *node)
 CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
 		      sun8i_a23_rtc_clk_init);
 
+/* The B288 RTC clocks are the same as the A23's */
+CLK_OF_DECLARE_DRIVER(sun8i_b288_rtc_clk, "allwinner,sun8i-b288-rtc",
+		      sun8i_a23_rtc_clk_init);
+
 static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
 	.rc_osc_rate = 16000000,
 	.fixed_prescaler = 32,
@@ -859,6 +863,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
 static const struct of_device_id sun6i_rtc_dt_ids[] = {
 	{ .compatible = "allwinner,sun6i-a31-rtc" },
 	{ .compatible = "allwinner,sun8i-a23-rtc" },
+	{ .compatible = "allwinner,sun8i-b288-rtc" },
 	{ .compatible = "allwinner,sun8i-h3-rtc" },
 	{ .compatible = "allwinner,sun8i-r40-rtc" },
 	{ .compatible = "allwinner,sun8i-v3-rtc" },
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 08/11] dt-bindings: interrupt-controller: add Allwinner B288 NMI
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (5 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 06/11] rtc: sun6i: add Allwinner B288 compatible Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 09/11] dt-bindings: watchdog: sun4i-a10-wdt: add Allwinner B288 Pablo Mazzini
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Conor Dooley, Jernej Skrabec, Krzysztof Kozlowski,
	Maxime Ripard, Radu Rendec, Rob Herring, Samuel Holland,
	Thomas Gleixner
  Cc: Pablo Mazzini, Krzysztof Kozlowski, Andre Przywara, devicetree,
	linux-arm-kernel, linux-kernel, linux-sunxi

Same register layout as the sun9i-a80 NMI, like the V3s.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
 .../interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml         | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
index bb9273ec2457..179e7842bf46 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
@@ -29,6 +29,7 @@ properties:
       - const: allwinner,sun55i-a523-nmi
       - items:
           - enum:
+              - allwinner,sun8i-b288-nmi
               - allwinner,sun8i-v3s-nmi
               - allwinner,sun50i-a100-nmi
               - allwinner,sun50i-h616-nmi
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 09/11] dt-bindings: watchdog: sun4i-a10-wdt: add Allwinner B288
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (6 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 08/11] dt-bindings: interrupt-controller: add Allwinner B288 NMI Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 10/11] dt-bindings: arm: sunxi: add PocketBook Verse Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 11/11] ARM: dts: allwinner: add B288 and the " Pablo Mazzini
  9 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Conor Dooley, Guenter Roeck, Jernej Skrabec,
	Krzysztof Kozlowski, Maxime Ripard, Rob Herring, Samuel Holland,
	Wim Van Sebroeck
  Cc: Pablo Mazzini, Andre Przywara, devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi, linux-watchdog

Same watchdog as the A31, which it falls back to.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
---
 .../devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml
index b35ac03d5172..b70a6b45a33d 100644
--- a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml
@@ -20,6 +20,7 @@ properties:
       - const: allwinner,sun6i-a31-wdt
       - items:
           - enum:
+              - allwinner,sun8i-b288-wdt
               - allwinner,sun50i-a64-wdt
               - allwinner,sun50i-a100-wdt
               - allwinner,sun50i-h6-wdt
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 10/11] dt-bindings: arm: sunxi: add PocketBook Verse
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (7 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 09/11] dt-bindings: watchdog: sun4i-a10-wdt: add Allwinner B288 Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  2026-10-12 10:08 ` [PATCH v4 11/11] ARM: dts: allwinner: add B288 and the " Pablo Mazzini
  9 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Conor Dooley, Jernej Skrabec, Krzysztof Kozlowski,
	Maxime Ripard, Rob Herring, Samuel Holland
  Cc: Pablo Mazzini, Krzysztof Kozlowski, Andre Przywara, devicetree,
	linux-arm-kernel, linux-kernel, linux-sunxi

A 6" e-book reader built around the Allwinner B288.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/sunxi.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
index 28437c47ac01..fa34786f0652 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.yaml
+++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
@@ -811,6 +811,11 @@ properties:
           - const: pocketbook,614-plus
           - const: allwinner,sun5i-a13
 
+      - description: PocketBook Verse (PB629)
+        items:
+          - const: pocketbook,verse
+          - const: allwinner,sun8i-b288
+
       - description: Point of View Protab2-IPS9
         items:
           - const: pov,protab2-ips9
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 11/11] ARM: dts: allwinner: add B288 and the PocketBook Verse
  2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
                   ` (8 preceding siblings ...)
  2026-10-12 10:08 ` [PATCH v4 10/11] dt-bindings: arm: sunxi: add PocketBook Verse Pablo Mazzini
@ 2026-10-12 10:08 ` Pablo Mazzini
  9 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-12 10:08 UTC (permalink / raw)
  To: Chen-Yu Tsai, Conor Dooley, Jernej Skrabec, Krzysztof Kozlowski,
	Rob Herring, Samuel Holland
  Cc: Pablo Mazzini, Andre Przywara, devicetree, linux-arm-kernel,
	linux-kernel, linux-sunxi

Add the B288 SoC .dtsi and the PocketBook Verse (PB629) board.

Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>
---
 arch/arm/boot/dts/allwinner/Makefile          |   1 +
 .../allwinner/sun8i-b288-pocketbook-verse.dts | 114 +++++++
 arch/arm/boot/dts/allwinner/sun8i-b288.dtsi   | 292 ++++++++++++++++++
 3 files changed, 407 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-b288-pocketbook-verse.dts
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-b288.dtsi

diff --git a/arch/arm/boot/dts/allwinner/Makefile b/arch/arm/boot/dts/allwinner/Makefile
index 75b2b6a2f7a6..2dfdc01e4825 100644
--- a/arch/arm/boot/dts/allwinner/Makefile
+++ b/arch/arm/boot/dts/allwinner/Makefile
@@ -227,6 +227,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-a83t-bananapi-m3.dtb \
 	sun8i-a83t-cubietruck-plus.dtb \
 	sun8i-a83t-tbs-a711.dtb \
+	sun8i-b288-pocketbook-verse.dtb \
 	sun8i-h2-plus-bananapi-m2-zero.dtb \
 	sun8i-h2-plus-libretech-all-h3-cc.dtb \
 	sun8i-h2-plus-orangepi-r1.dtb \
diff --git a/arch/arm/boot/dts/allwinner/sun8i-b288-pocketbook-verse.dts b/arch/arm/boot/dts/allwinner/sun8i-b288-pocketbook-verse.dts
new file mode 100644
index 000000000000..a60cbb638019
--- /dev/null
+++ b/arch/arm/boot/dts/allwinner/sun8i-b288-pocketbook-verse.dts
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * PocketBook Verse (PB629), an Allwinner B288 based e-reader.
+ */
+
+/dts-v1/;
+#include "sun8i-b288.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "PocketBook Verse";
+	compatible = "pocketbook,verse", "allwinner,sun8i-b288";
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pb_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	vmmc-supply = <&reg_dldo2>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;	/* PF6 */
+	disable-wp;
+	status = "okay";
+};
+
+&mmc3 {
+	vmmc-supply = <&reg_dcdc1>;
+	vqmmc-supply = <&reg_dldo1>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	mmc-ddr-1_8v;
+	mmc-hs200-1_8v;
+	status = "okay";
+};
+
+&pio {
+	vcc-pc-supply = <&reg_dldo1>;
+	vcc-pd-supply = <&reg_dldo1>;
+};
+
+&i2c0 {
+	status = "okay";
+
+	axp22x: pmic@34 {
+		/* labelled AXP227 */
+		compatible = "x-powers,axp221";
+		reg = <0x34>;
+		interrupt-parent = <&nmi_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+#include "axp22x.dtsi"
+
+&reg_dcdc1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "vcc-io";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1260000>;
+	regulator-max-microvolt = <1260000>;
+	regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc4 {
+	regulator-always-on;
+	regulator-min-microvolt = <1100000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1350000>;
+	regulator-max-microvolt = <1350000>;
+	regulator-name = "vcc-dram";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
+&reg_dldo1 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vcc-pc";
+};
+
+&reg_dldo2 {
+	/* microSD slot */
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-sdcv";
+};
diff --git a/arch/arm/boot/dts/allwinner/sun8i-b288.dtsi b/arch/arm/boot/dts/allwinner/sun8i-b288.dtsi
new file mode 100644
index 000000000000..53832ea9dc01
--- /dev/null
+++ b/arch/arm/boot/dts/allwinner/sun8i-b288.dtsi
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Allwinner B288 (sun8iw10p1) SoC
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
+#include <dt-bindings/clock/sun8i-b288-ccu.h>
+#include <dt-bindings/reset/sun8i-b288-ccu.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&gic>;
+
+	osc24M: osc24M-clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <24000000>;
+		clock-output-names = "osc24M";
+	};
+
+	osc32k: osc32k-clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+		clock-output-names = "ext-osc32k";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <0>;
+			clocks = <&ccu CLK_CPUX>;
+			clock-names = "cpu";
+		};
+
+		cpu1: cpu@1 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <1>;
+			clocks = <&ccu CLK_CPUX>;
+			clock-names = "cpu";
+		};
+	};
+
+	timer {
+		compatible = "arm,armv7-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)>;
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		nmi_intc: interrupt-controller@1c000d0 {
+			compatible = "allwinner,sun8i-b288-nmi",
+				     "allwinner,sun9i-a80-nmi";
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			reg = <0x01c000d0 0x0c>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		/*
+		 * mmc0 is a v4p1x controller, so it runs in the old timing
+		 * mode and needs the sample and output phase clocks.
+		 */
+		mmc0: mmc@1c0f000 {
+			compatible = "allwinner,sun8i-b288-mmc",
+				     "allwinner,sun7i-a20-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ccu CLK_BUS_SDMMC0_BUS>,
+				 <&ccu CLK_MMC0>,
+				 <&ccu CLK_MMC0_OUTPUT>,
+				 <&ccu CLK_MMC0_SAMPLE>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&ccu RST_BUS_MMC0>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc0_pins>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		mmc3: mmc@1c12000 {
+			compatible = "allwinner,sun8i-b288-emmc",
+				     "allwinner,sun50i-a64-emmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&ccu CLK_BUS_SDMMC3_BUS>, <&ccu CLK_MMC3>;
+			clock-names = "ahb", "mmc";
+			resets = <&ccu RST_BUS_MMC3>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc3_pins>;
+			max-frequency = <150000000>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		/* mmc2 @0x01c11000 is an unsupported SDHCI-style controller. */
+
+		ccu: clock-controller@1c20000 {
+			compatible = "allwinner,sun8i-b288-ccu";
+			reg = <0x01c20000 0x400>;
+			clocks = <&osc24M>, <&rtc CLK_OSC32K>;
+			clock-names = "hosc", "losc";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		rtc: rtc@1c20400 {
+			compatible = "allwinner,sun8i-b288-rtc";
+			reg = <0x01c20400 0x400>;
+			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+			clock-output-names = "osc32k", "osc32k-out";
+			clocks = <&osc32k>;
+			#clock-cells = <1>;
+		};
+
+		pio: pinctrl@1c20800 {
+			compatible = "allwinner,sun8i-b288-pinctrl";
+			reg = <0x01c20800 0x400>;
+			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc CLK_OSC32K>;
+			clock-names = "apb", "hosc", "losc";
+			gpio-controller;
+			#gpio-cells = <3>;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+
+			mmc0_pins: mmc0-pins {
+				pins = "PF0", "PF1", "PF2",
+				       "PF3", "PF4", "PF5";
+				function = "mmc0";
+				allwinner,pinmux = <2>;
+				drive-strength = <30>;
+				bias-pull-up;
+			};
+
+			i2c0_pins: i2c0-pins {
+				pins = "PB6", "PB7";
+				function = "i2c0";
+				allwinner,pinmux = <2>;
+			};
+
+			mmc3_pins: mmc3-pins {
+				pins = "PC1", "PC4", "PC5", "PC6",
+				       "PC7", "PC8", "PC9", "PC10",
+				       "PC11", "PC12", "PC13", "PC14";
+				function = "mmc3";
+				allwinner,pinmux = <5>;
+				drive-strength = <40>;
+				bias-pull-up;
+			};
+
+			uart0_pb_pins: uart0-pb-pins {
+				pins = "PB4", "PB5";
+				function = "uart0";
+				allwinner,pinmux = <2>;
+			};
+		};
+
+		wdt: watchdog@1c20ca0 {
+			compatible = "allwinner,sun8i-b288-wdt",
+				     "allwinner,sun6i-a31-wdt";
+			reg = <0x01c20ca0 0x20>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&osc24M>;
+		};
+
+		uart0: serial@1c28000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28000 0x400>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART0>;
+			resets = <&ccu RST_BUS_UART0>;
+			status = "disabled";
+		};
+
+		uart1: serial@1c28400 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28400 0x400>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART1>;
+			resets = <&ccu RST_BUS_UART1>;
+			status = "disabled";
+		};
+
+		uart2: serial@1c28800 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28800 0x400>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART2>;
+			resets = <&ccu RST_BUS_UART2>;
+			status = "disabled";
+		};
+
+		uart3: serial@1c28c00 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28c00 0x400>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART3>;
+			resets = <&ccu RST_BUS_UART3>;
+			status = "disabled";
+		};
+
+		uart4: serial@1c29000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c29000 0x400>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART4>;
+			resets = <&ccu RST_BUS_UART4>;
+			status = "disabled";
+		};
+
+		i2c0: i2c@1c2ac00 {
+			compatible = "allwinner,sun8i-b288-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2ac00 0x400>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TWI0>;
+			resets = <&ccu RST_BUS_I2C0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c1: i2c@1c2b000 {
+			compatible = "allwinner,sun8i-b288-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b000 0x400>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TWI1>;
+			resets = <&ccu RST_BUS_I2C1>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c2: i2c@1c2b400 {
+			compatible = "allwinner,sun8i-b288-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b400 0x400>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TWI2>;
+			resets = <&ccu RST_BUS_I2C2>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		gic: interrupt-controller@1c81000 {
+			compatible = "arm,gic-400";
+			reg = <0x01c81000 0x1000>,
+			      <0x01c82000 0x2000>,
+			      <0x01c84000 0x2000>,
+			      <0x01c86000 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+		};
+	};
+};
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 05/11] dt-bindings: rtc: sun6i-a31: add Allwinner B288
  2026-10-12 10:08 ` [PATCH v4 05/11] dt-bindings: rtc: sun6i-a31: add Allwinner B288 Pablo Mazzini
@ 2026-10-12 10:15   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-12 10:15 UTC (permalink / raw)
  To: Pablo Mazzini
  Cc: Alexandre Belloni, robh, devicetree, linux-sunxi, conor+dt,
	linux-rtc

> The B288 RTC wires one alarm interrupt, not two.
> 
> Signed-off-by: Pablo Mazzini <pmazzini@gmail.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261012100816.331033-1-pmazzini@gmail.com?part=5


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 06/11] rtc: sun6i: add Allwinner B288 compatible
  2026-10-12 10:08 ` [PATCH v4 06/11] rtc: sun6i: add Allwinner B288 compatible Pablo Mazzini
@ 2026-10-12 10:19   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-12 10:19 UTC (permalink / raw)
  To: Pablo Mazzini; +Cc: Alexandre Belloni, linux-sunxi, linux-rtc

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] rtc: sun6i: missing ERR_PTR check causes crash in probe on clk_register failure
- [Medium] rtc: sun6i: resource leak of losc clock on initialization error path
- [Low] rtc: sun6i: memory leak of rtc structure in sun6i_rtc_clk_init error path
--

commit 903d00f6b5cb6afede9ad6ad5fca01853d776ce4
Author: Pablo Mazzini <pmazzini@gmail.com>
Subject: rtc: sun6i: add Allwinner B288 compatible

This commit adds support for the Allwinner B288 RTC by reusing the A23
clock configuration. It maps the new compatible string
allwinner,sun8i-b288-rtc to the existing initialization functions.

> diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
> index 7fc60880e4094..05004e80ac089 100644
> --- a/drivers/rtc/rtc-sun6i.c
> +++ b/drivers/rtc/rtc-sun6i.c
> @@ -350,6 +350,10 @@ static void __init sun8i_a23_rtc_clk_init(struct device_node *node)
>  CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
>  		      sun8i_a23_rtc_clk_init);
>  
> +/* The B288 RTC clocks are the same as the A23's */
> +CLK_OF_DECLARE_DRIVER(sun8i_b288_rtc_clk, "allwinner,sun8i-b288-rtc",
> +		      sun8i_a23_rtc_clk_init);
> +

[Severity: High]
Does adding this compatible string expose an issue in the error handling
of sun6i_rtc_clk_init on registration failure?

If clk_register fails for rtc->losc, the function returns an error
pointer and jumps to the err_register label. Since the global sun6i_rtc
pointer is already assigned to the allocated rtc struct earlier:

sun6i_rtc_clk_init()
    /* Yes, I know, this is ugly. */
    sun6i_rtc = rtc;
    ...
    rtc->losc = clk_register(NULL, &rtc->hw);
    if (IS_ERR(rtc->losc)) {
        pr_crit("Couldn't register the LOSC clock\n");
        goto err_register;
    }

The probe function sun6i_rtc_probe later fetches this dangling pointer:

sun6i_rtc_probe()
    struct sun6i_rtc_dev *chip = sun6i_rtc;
    ...
    clk_prepare_enable(chip->losc);

Can this lead to a kernel panic when clk_prepare_enable attempts to
dereference the error pointer stored in chip->losc?

[Severity: Medium]
Additionally, if clk_register succeeds for rtc->losc but a later clock
registration fails, triggering the jump to err_register, does this
cleanup path leak the rtc->losc clock?

sun6i_rtc_clk_init()
err_register:
    clk_hw_unregister_fixed_rate(rtc->int_osc);
err:
    kfree(clk_data);

The err_register path unregisters rtc->int_osc but appears to omit
calling clk_unregister(rtc->losc).

[Severity: Low]
Does the err cleanup path also leak the dynamically allocated rtc
structure?

sun6i_rtc_clk_init()
    rtc = kzalloc_obj(*rtc);
    ...
err:
    kfree(clk_data);

The error path frees clk_data but seems to omit freeing the allocated
rtc structure.

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261012100816.331033-1-pmazzini@gmail.com?part=6

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver
  2026-10-12 10:08 ` [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver Pablo Mazzini
@ 2026-10-12 10:21   ` sashiko-bot
  2026-10-13 15:07     ` Pablo Mazzini
  0 siblings, 1 reply; 17+ messages in thread
From: sashiko-bot @ 2026-10-12 10:21 UTC (permalink / raw)
  To: Pablo Mazzini; +Cc: linux-clk, linux-sunxi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] clk: sunxi-ng: missing parent index table for tcon0_clk
--

commit 3f9c552550550b015864167770907fa314ac3239
Author: Pablo Mazzini <pmazzini@gmail.com>

clk: sunxi-ng: add Allwinner B288 CCU driver

This commit introduces the Allwinner B288 CCU driver, covering the PLLs,
the CPU/AHB/APB tree, module clocks, bus gates, and resets. The driver
is noted to be closely related to the A64 CCU.

> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-b288.c b/drivers/clk/sunxi-ng/ccu-sun8i-b288.c
> new file mode 100644
> index 0000000000000..c53afd6f9af98
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-b288.c

[ ... ]

> +/* DE_CFG @ 0x104, EE_CFG @ 0x108, EDMA_CFG @ 0x10c -- M[3:0] mux[26:24] gate 31 */
> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(de_clk, "de", de_parents, 0x104,
> +				      0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ee_clk, "ee", de_parents, 0x108,
> +				      0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(edma_clk, "edma", de_parents, 0x10c,
> +				      0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
> +
> +/* TCON_CFG @ 0x118 -- mux[26:24] gate 31, no divider */
> +static SUNXI_CCU_MUX_DATA_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, 0x118,
> +				    24, 3,		/* mux */
> +				    BIT(31),		/* gate */
> +				    CLK_SET_RATE_PARENT);

[Severity: Medium]
Does the B288 hardware actually use a 1:1 index mapping (0 and 1) for this
TCON mux?

The closely related A64 SoC uses a {0, 2} index mapping for its TCON PLLs.
Because SUNXI_CCU_MUX_DATA_WITH_GATE defaults to a 1:1 mapping, if a display
driver requests to use pll_video1 for the TCON, the CCU driver will write
index 1 to the mux register. If the hardware maps the second parent to index
2 instead of 1, this will result in incorrect clock parent selection and could
break video output.

If a custom mapping is needed, it might be slightly tricky to define since the
ccu_mux.h framework currently lacks a SUNXI_CCU_MUX_DATA_TABLE_WITH_GATE
macro to combine a table with clk_parent_data.

> +
> +/* MBUS_CFG @ 0x15c -- M[2:0] mux[25:24] gate 31 */
> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x15c,
> +				      0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261012100816.331033-1-pmazzini@gmail.com?part=2

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver
  2026-10-12 10:08 ` [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver Pablo Mazzini
@ 2026-10-12 10:29   ` sashiko-bot
  2026-10-13 15:38     ` Pablo Mazzini
  0 siblings, 1 reply; 17+ messages in thread
From: sashiko-bot @ 2026-10-12 10:29 UTC (permalink / raw)
  To: Pablo Mazzini; +Cc: linux-sunxi, linux-gpio

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] pinctrl: sunxi: out-of-bounds write in irq_array when Bank 0 has 0 pins
- [High] pinctrl: sunxi: Missing irq_bank_map breaks B288 IRQ offsets and domain size
- [High] pinctrl: sunxi: probe deferral crash due to npins accumulation
--

commit 6057aa70ee139132fe0176fd6bf4d482c87bdc64
Author: Pablo Mazzini <pmazzini@gmail.com>

pinctrl: sunxi: add Allwinner B288 pin controller driver

This commit adds a new pin controller driver for the Allwinner B288 SoC,
supporting 80 pins across ports B, C, D, F, and G. It uses DT-provided
mux values and specifies 4 banks of external interrupts.

> diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
> new file mode 100644
> index 0000000000000..f973c2b3f2eba
> --- /dev/null
> +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
> @@ -0,0 +1,49 @@
[ ... ]
> +/* PH0 exists only on the BSP's FPGA platform and is omitted. */
> +static const u8 b288_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] =
> +/*	  PA  PB  PC  PD  PE  PF  PG */
> +	{  0, 17, 15, 29,  0,  7, 12 };

[Severity: High]
Since Bank 0 (PA) has 0 pins, does this cause an out-of-bounds write in
the core sunxi pinctrl driver?

In drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c:prepare_function_table(),
last_bank and irq_bank are initialized to 0. When processing PB (bank 1),
the condition (bank > last_bank) evaluates to true (1 > 0), causing irq_bank
to erroneously increment to 1.

This shifts the logical IRQ bank indices for PB, PD, PF, and PG to
1, 2, 3, and 4 instead of 0, 1, 2, and 3.

Later, sunxi_pinctrl_build_state() configures the interrupts:

    int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
    pctl->irq_array[irqnum] = pin->pin.number;

For PG (irqbank 4), irqnum will be between 128 and 139. However, irq_array
is allocated for exactly 4 banks (128 elements) in
sunxi_pinctrl_init_with_flags(), which would result in an out-of-bounds
write past the end of the array.

> +
> +static const u8 b288_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
> +/*	  PA  PB  PC  PD  PE  PF  PG */
> +	{  0,  6,  0,  6,  0,  6,  6 };
> +
> +static struct sunxi_pinctrl_desc b288_pinctrl_data = {
> +	.irq_banks	= 4,
> +};

[Severity: High]
Does omitting the irq_bank_map array break external interrupts?

Without an irq_bank_map, drivers/pinctrl/sunxi/pinctrl-sunxi.h:
sunxi_irq_hw_bank_num() returns the sequential logical irqbank indices.

Because the irq_bank offset is already shifted to 1, 2, 3, and 4, these
logical indices will be used as physical hardware bank offsets.

This incorrectly maps PD, PF, and PG to hardware banks 2, 3, and 4 instead
of their actual hardware indices 3, 5, and 6.

Additionally, because PG receives irqbank 4, its out_hwirq is calculated
as 4 * 32 + irqnum (>= 128), which exceeds the bounds of the 128-entry
IRQ domain created during probe.

> +
> +static int b288_pinctrl_probe(struct platform_device *pdev)
> +{
> +	return sunxi_pinctrl_dt_table_init(pdev, b288_nr_bank_pins,
> +					   b288_irq_bank_muxes,
> +					   &b288_pinctrl_data, 0);
> +}

[Severity: High]
Could this lead to a kernel panic during a probe deferral?

The driver passes the static b288_pinctrl_data descriptor to
sunxi_pinctrl_dt_table_init(), which calls init_pins_table() and
accumulates the total pin count:

    desc->npins += pins_per_bank[i];

If the driver probe defers, desc->npins will double on the next attempt
(from 80 to 160) because the static descriptor is reused.

The pins array is then allocated for 160 elements, but only the first 80
will have their .pin.name populated.

During DT parsing in fill_pin_function(), if an unrecognized pin name is
encountered, the search loops over the oversized array and evaluates:

    if (!strcmp(pins[pin].pin.name, name))
        break;

Iterating past index 79 would call strcmp() with a NULL pointer for
.pin.name, causing a panic.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261012100816.331033-1-pmazzini@gmail.com?part=4

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver
  2026-10-12 10:21   ` sashiko-bot
@ 2026-10-13 15:07     ` Pablo Mazzini
  0 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-13 15:07 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: linux-clk, linux-sunxi

The B288 has pll-video0 and pll-video1 at TCON0 mux values 0 and 1, so
the plain mapping is right.

BSP: https://github.com/pocketbook/kernel-b288/blob/e30bb2ed149410ef2d3245ea01192833d44c4e46/drivers/clk/sunxi/clk-sun8iw10.c#L468
Wiki: https://linux-sunxi.org/B288/Clocks

On Mon, Oct 12, 2026 at 11:21 AM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] clk: sunxi-ng: missing parent index table for tcon0_clk
> --
>
> commit 3f9c552550550b015864167770907fa314ac3239
> Author: Pablo Mazzini <pmazzini@gmail.com>
>
> clk: sunxi-ng: add Allwinner B288 CCU driver
>
> This commit introduces the Allwinner B288 CCU driver, covering the PLLs,
> the CPU/AHB/APB tree, module clocks, bus gates, and resets. The driver
> is noted to be closely related to the A64 CCU.
>
> > diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-b288.c b/drivers/clk/sunxi-ng/ccu-sun8i-b288.c
> > new file mode 100644
> > index 0000000000000..c53afd6f9af98
> > --- /dev/null
> > +++ b/drivers/clk/sunxi-ng/ccu-sun8i-b288.c
>
> [ ... ]
>
> > +/* DE_CFG @ 0x104, EE_CFG @ 0x108, EDMA_CFG @ 0x10c -- M[3:0] mux[26:24] gate 31 */
> > +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(de_clk, "de", de_parents, 0x104,
> > +                                   0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
> > +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ee_clk, "ee", de_parents, 0x108,
> > +                                   0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
> > +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(edma_clk, "edma", de_parents, 0x10c,
> > +                                   0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
> > +
> > +/* TCON_CFG @ 0x118 -- mux[26:24] gate 31, no divider */
> > +static SUNXI_CCU_MUX_DATA_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, 0x118,
> > +                                 24, 3,              /* mux */
> > +                                 BIT(31),            /* gate */
> > +                                 CLK_SET_RATE_PARENT);
>
> [Severity: Medium]
> Does the B288 hardware actually use a 1:1 index mapping (0 and 1) for this
> TCON mux?
>
> The closely related A64 SoC uses a {0, 2} index mapping for its TCON PLLs.
> Because SUNXI_CCU_MUX_DATA_WITH_GATE defaults to a 1:1 mapping, if a display
> driver requests to use pll_video1 for the TCON, the CCU driver will write
> index 1 to the mux register. If the hardware maps the second parent to index
> 2 instead of 1, this will result in incorrect clock parent selection and could
> break video output.
>
> If a custom mapping is needed, it might be slightly tricky to define since the
> ccu_mux.h framework currently lacks a SUNXI_CCU_MUX_DATA_TABLE_WITH_GATE
> macro to combine a table with clk_parent_data.
>
> > +
> > +/* MBUS_CFG @ 0x15c -- M[2:0] mux[25:24] gate 31 */
> > +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x15c,
> > +                                   0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL);
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20261012100816.331033-1-pmazzini@gmail.com?part=2

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver
  2026-10-12 10:29   ` sashiko-bot
@ 2026-10-13 15:38     ` Pablo Mazzini
  0 siblings, 0 replies; 17+ messages in thread
From: Pablo Mazzini @ 2026-10-13 15:38 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: linux-sunxi, linux-gpio

The first two come from the IRQ bank numbering in
prepare_function_table(), which this patch depends on [1]. Andre plans
to send a fix after -rc1 [2].

The third is fixed by "pinctrl: sunxi: dt: do not accumulate npins
across probe attempts" [3], which Linus has applied.

[1] https://lore.kernel.org/linux-sunxi/20260929203634.32998-1-pmazzini@gmail.com/
[2] https://lore.kernel.org/r/20261004225724.0b821e9c@ryzen.lan
[3] https://lore.kernel.org/r/20261007060107.62221-1-pmazzini@gmail.com

On Mon, Oct 12, 2026 at 11:29 AM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] pinctrl: sunxi: out-of-bounds write in irq_array when Bank 0 has 0 pins
> - [High] pinctrl: sunxi: Missing irq_bank_map breaks B288 IRQ offsets and domain size
> - [High] pinctrl: sunxi: probe deferral crash due to npins accumulation
> --
>
> commit 6057aa70ee139132fe0176fd6bf4d482c87bdc64
> Author: Pablo Mazzini <pmazzini@gmail.com>
>
> pinctrl: sunxi: add Allwinner B288 pin controller driver
>
> This commit adds a new pin controller driver for the Allwinner B288 SoC,
> supporting 80 pins across ports B, C, D, F, and G. It uses DT-provided
> mux values and specifies 4 banks of external interrupts.
>
> > diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
> > new file mode 100644
> > index 0000000000000..f973c2b3f2eba
> > --- /dev/null
> > +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-b288.c
> > @@ -0,0 +1,49 @@
> [ ... ]
> > +/* PH0 exists only on the BSP's FPGA platform and is omitted. */
> > +static const u8 b288_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] =
> > +/*     PA  PB  PC  PD  PE  PF  PG */
> > +     {  0, 17, 15, 29,  0,  7, 12 };
>
> [Severity: High]
> Since Bank 0 (PA) has 0 pins, does this cause an out-of-bounds write in
> the core sunxi pinctrl driver?
>
> In drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c:prepare_function_table(),
> last_bank and irq_bank are initialized to 0. When processing PB (bank 1),
> the condition (bank > last_bank) evaluates to true (1 > 0), causing irq_bank
> to erroneously increment to 1.
>
> This shifts the logical IRQ bank indices for PB, PD, PF, and PG to
> 1, 2, 3, and 4 instead of 0, 1, 2, and 3.
>
> Later, sunxi_pinctrl_build_state() configures the interrupts:
>
>     int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
>     pctl->irq_array[irqnum] = pin->pin.number;
>
> For PG (irqbank 4), irqnum will be between 128 and 139. However, irq_array
> is allocated for exactly 4 banks (128 elements) in
> sunxi_pinctrl_init_with_flags(), which would result in an out-of-bounds
> write past the end of the array.
>
> > +
> > +static const u8 b288_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
> > +/*     PA  PB  PC  PD  PE  PF  PG */
> > +     {  0,  6,  0,  6,  0,  6,  6 };
> > +
> > +static struct sunxi_pinctrl_desc b288_pinctrl_data = {
> > +     .irq_banks      = 4,
> > +};
>
> [Severity: High]
> Does omitting the irq_bank_map array break external interrupts?
>
> Without an irq_bank_map, drivers/pinctrl/sunxi/pinctrl-sunxi.h:
> sunxi_irq_hw_bank_num() returns the sequential logical irqbank indices.
>
> Because the irq_bank offset is already shifted to 1, 2, 3, and 4, these
> logical indices will be used as physical hardware bank offsets.
>
> This incorrectly maps PD, PF, and PG to hardware banks 2, 3, and 4 instead
> of their actual hardware indices 3, 5, and 6.
>
> Additionally, because PG receives irqbank 4, its out_hwirq is calculated
> as 4 * 32 + irqnum (>= 128), which exceeds the bounds of the 128-entry
> IRQ domain created during probe.
>
> > +
> > +static int b288_pinctrl_probe(struct platform_device *pdev)
> > +{
> > +     return sunxi_pinctrl_dt_table_init(pdev, b288_nr_bank_pins,
> > +                                        b288_irq_bank_muxes,
> > +                                        &b288_pinctrl_data, 0);
> > +}
>
> [Severity: High]
> Could this lead to a kernel panic during a probe deferral?
>
> The driver passes the static b288_pinctrl_data descriptor to
> sunxi_pinctrl_dt_table_init(), which calls init_pins_table() and
> accumulates the total pin count:
>
>     desc->npins += pins_per_bank[i];
>
> If the driver probe defers, desc->npins will double on the next attempt
> (from 80 to 160) because the static descriptor is reused.
>
> The pins array is then allocated for 160 elements, but only the first 80
> will have their .pin.name populated.
>
> During DT parsing in fill_pin_function(), if an unrecognized pin name is
> encountered, the search loops over the oversized array and evaluates:
>
>     if (!strcmp(pins[pin].pin.name, name))
>         break;
>
> Iterating past index 79 would call strcmp() with a NULL pointer for
> .pin.name, causing a panic.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20261012100816.331033-1-pmazzini@gmail.com?part=4

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-10-13 15:38 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-12 10:08 [PATCH v4 00/11] ARM: sunxi: add Allwinner B288 and the PocketBook Verse Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 01/11] dt-bindings: clock: sun4i-a10-ccu: add Allwinner B288 Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 02/11] clk: sunxi-ng: add Allwinner B288 CCU driver Pablo Mazzini
2026-10-12 10:21   ` sashiko-bot
2026-10-13 15:07     ` Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 03/11] dt-bindings: pinctrl: sun4i-a10: add Allwinner B288 Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 04/11] pinctrl: sunxi: add Allwinner B288 pin controller driver Pablo Mazzini
2026-10-12 10:29   ` sashiko-bot
2026-10-13 15:38     ` Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 05/11] dt-bindings: rtc: sun6i-a31: add Allwinner B288 Pablo Mazzini
2026-10-12 10:15   ` sashiko-bot
2026-10-12 10:08 ` [PATCH v4 06/11] rtc: sun6i: add Allwinner B288 compatible Pablo Mazzini
2026-10-12 10:19   ` sashiko-bot
2026-10-12 10:08 ` [PATCH v4 08/11] dt-bindings: interrupt-controller: add Allwinner B288 NMI Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 09/11] dt-bindings: watchdog: sun4i-a10-wdt: add Allwinner B288 Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 10/11] dt-bindings: arm: sunxi: add PocketBook Verse Pablo Mazzini
2026-10-12 10:08 ` [PATCH v4 11/11] ARM: dts: allwinner: add B288 and the " Pablo Mazzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox