Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 10/10] arm64: dts: apple: Enable DockChannel HID on M2 and M3 laptops
From: Michael Reeves via B4 Relay @ 2026-06-30 12:54 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Jassi Brar, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Hector Martin,
	Joerg Roedel (AMD), Will Deacon, Robin Murphy, Dmitry Torokhov,
	Jiri Kosina, Benjamin Tissoires
  Cc: asahi, linux-arm-kernel, linux-kernel, devicetree, iommu,
	linux-input, Michael Reeves
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-0-506d936a1707@gmail.com>

From: Michael Reeves <michael.reeves077@gmail.com>

Enable the MTP mailbox, DART, DockChannel mailbox, and HID transport on
the M2 and M3 laptop device trees using this internal input path.

Add a keyboard alias and keyboard child node for each machine so the
transport can expose the internal keyboard.

Co-developed-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Michael Reeves <michael.reeves077@gmail.com>
---
 arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi | 25 +++++++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8112-j413.dts       | 20 ++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8112-j415.dts       | 20 ++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8112-j493.dts       | 22 +++++++++++++++++++++-
 arch/arm64/boot/dts/apple/t8122-j504.dts       | 22 ++++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8122-j613.dts       | 23 +++++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8122-j615.dts       | 23 +++++++++++++++++++++++
 7 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi
index 0e806d8ddf81..46ed5ea86242 100644
--- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi
@@ -16,6 +16,12 @@
 
 #include "t600x-j314-j316.dtsi"
 
+/ {
+	aliases {
+		keyboard = &keyboard;
+	};
+};
+
 &framebuffer0 {
 	power-domains = <&ps_disp0_cpu0>, <&ps_dptx_phy_ps>;
 };
@@ -43,3 +49,22 @@ &wifi0 {
 &bluetooth0 {
 	compatible = "pci14e4,5f72";
 };
+
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts
index 1a08a41f369b..1256e7cd9876 100644
--- a/arch/arm64/boot/dts/apple/t8112-j413.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j413.dts
@@ -20,6 +20,7 @@ / {
 
 	aliases {
 		bluetooth0 = &bluetooth0;
+		keyboard = &keyboard;
 		wifi0 = &wifi0;
 	};
 
@@ -91,3 +92,22 @@ &i2c4 {
 &fpwm1 {
 	status = "okay";
 };
+
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts
index e37c56d9fb4d..1db3500e991f 100644
--- a/arch/arm64/boot/dts/apple/t8112-j415.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j415.dts
@@ -20,6 +20,7 @@ / {
 
 	aliases {
 		bluetooth0 = &bluetooth0;
+		keyboard = &keyboard;
 		wifi0 = &wifi0;
 	};
 
@@ -91,3 +92,22 @@ &i2c4 {
 &fpwm1 {
 	status = "okay";
 };
+
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts
index ec116da3e4dd..5deb2dd9802a 100644
--- a/arch/arm64/boot/dts/apple/t8112-j493.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j493.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+ OR MIT
 /*
- * Apple MacBook Pro (13-inch, M1, 2022)
+ * Apple MacBook Pro (13-inch, M2, 2022)
  *
  * target-type: J493
  *
@@ -24,6 +24,7 @@ / {
 	 */
 	aliases {
 		bluetooth0 = &bluetooth0;
+		keyboard = &keyboard;
 		touchbar0 = &touchbar0;
 		wifi0 = &wifi0;
 	};
@@ -146,3 +147,22 @@ touchbar0: touchbar@0 {
 		touchscreen-inverted-y;
 	};
 };
+
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t8122-j504.dts b/arch/arm64/boot/dts/apple/t8122-j504.dts
index 464491b55b01..0d93ac72fff9 100644
--- a/arch/arm64/boot/dts/apple/t8122-j504.dts
+++ b/arch/arm64/boot/dts/apple/t8122-j504.dts
@@ -18,6 +18,10 @@ / {
 	compatible = "apple,j504", "apple,t8122", "apple,arm-platform";
 	model = "Apple MacBook Pro (14-inch, M3, 2023)";
 
+	aliases {
+		keyboard = &keyboard;
+	};
+
 	led-controller {
 		compatible = "pwm-leds";
 		led-0 {
@@ -35,3 +39,21 @@ &fpwm1 {
 	status = "okay";
 };
 
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t8122-j613.dts b/arch/arm64/boot/dts/apple/t8122-j613.dts
index 51894ea705e7..e77b1ad869eb 100644
--- a/arch/arm64/boot/dts/apple/t8122-j613.dts
+++ b/arch/arm64/boot/dts/apple/t8122-j613.dts
@@ -17,6 +17,10 @@ / {
 	compatible = "apple,j613", "apple,t8122", "apple,arm-platform";
 	model = "Apple MacBook Air (13-inch, M3, 2024)";
 
+	aliases {
+		keyboard = &keyboard;
+	};
+
 	led-controller {
 		compatible = "pwm-leds";
 		led-0 {
@@ -33,3 +37,22 @@ led-0 {
 &fpwm1 {
 	status = "okay";
 };
+
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};
diff --git a/arch/arm64/boot/dts/apple/t8122-j615.dts b/arch/arm64/boot/dts/apple/t8122-j615.dts
index 2a1970c1bc90..5da0021d40f8 100644
--- a/arch/arm64/boot/dts/apple/t8122-j615.dts
+++ b/arch/arm64/boot/dts/apple/t8122-j615.dts
@@ -17,6 +17,10 @@ / {
 	compatible = "apple,j615", "apple,t8122", "apple,arm-platform";
 	model = "Apple MacBook Air (15-inch, M3, 2024)";
 
+	aliases {
+		keyboard = &keyboard;
+	};
+
 	led-controller {
 		compatible = "pwm-leds";
 		led-0 {
@@ -33,3 +37,22 @@ led-0 {
 &fpwm1 {
 	status = "okay";
 };
+
+&mtp_mbox {
+	status = "okay";
+};
+
+&mtp_dart {
+	status = "okay";
+};
+
+&mtp_dockchannel {
+	status = "okay";
+};
+
+&mtp_hid {
+	status = "okay";
+
+	keyboard: keyboard {
+	};
+};

-- 
2.51.2




^ permalink raw reply related

* Re: [PATCH v11 0/6] gpio: siul2-s32g2: add initial GPIO driver
From: Khristine Andreea Barbulescu @ 2026-06-30 12:58 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Bartosz Golaszewski, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chester Lin, Matthias Brugger, Ghennadi Procopciuc,
	Larisa Grigore, Lee Jones, Shawn Guo, Sascha Hauer, Fabio Estevam,
	Dong Aisheng, Jacky Bai, Greg Kroah-Hartman, Rafael J. Wysocki,
	Srinivas Kandagatla, Alberto Ruiz, Christophe Lizzi, devicetree,
	Enric Balletbo, Eric Chanudet, imx, linux-arm-kernel, linux-gpio,
	linux-kernel, NXP S32 Linux Team, Pengutronix Kernel Team,
	Vincent Guittot
In-Reply-To: <CAD++jL=S6vEgSW=V4gu4z=RtuvASNFUiofJb0X+fGYMqNQT7vQ@mail.gmail.com>

On 6/30/2026 2:50 PM, Linus Walleij wrote:
> On Wed, Jun 10, 2026 at 2:21 PM Khristine Andreea Barbulescu
> <khristineandreea.barbulescu@oss.nxp.com> wrote:
> 
>> This patch series adds support for basic GPIO
>> operations using gpio-regmap.
> 
> Sorry for my confused comment on jun 10, these patches all go to the
> pinctrl subsystem so I should merge them.
> 
> Can you make a v12 based on v7.2-rc1 and I will apply them.
> Pick up ACKs!
> 
> I will not apply the device tree patch, this will need to be queued
> in the SoC tree.
> 
> Yours,
> Linus Walleij

Hi Linus,

v12 is now available. I've rebased the series on top of
v7.2-rc1 and collected the ACKs tags received in v11.

Best regards,
Khristine


^ permalink raw reply

* Re: [PATCH v2 1/9] time: Respect COMPAT_32BIT_TIME for old time type functions
From: Arnd Bergmann @ 2026-06-30 13:00 UTC (permalink / raw)
  To: Thomas Weißschuh, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Russell King, Catalin Marinas, Will Deacon, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy,
	Thomas Bogendoerfer, Vincenzo Frascino, John Stultz, Stephen Boyd,
	David S . Miller, Andreas Larsson
  Cc: linux-kernel, linux-arm-kernel, linuxppc-dev, linux-mips,
	linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-1-520d194640dd@linutronix.de>

On Tue, Jun 30, 2026, at 09:38, Thomas Weißschuh wrote:
> The "old" time types use 32-bit seconds which are not y2038-safe.
> Respect COMPAT_32BIT_TIME for functions using those types.
> time(), stime() and gettimeofday() are disabled completely.

Looks good, yes

> settimeofday() is kept as it is required to do the initial timewarping
> after boot. However the 'tv' argument will be rejected.

Not sure about this part, did we already discuss this last time?

I can see how keeping the timewarping functionality is the easy way
out, but completely disabling the settimeofday syscall the same
way we do on new architectures seems so much more consistent.

Note how scripts/syscall.tbl blocks sys_settimeofday on
architectures that don't set the time32 flag, which ideally
should match the COMPAT_32BIT_TIME option here.

     Arnd


^ permalink raw reply

* [PATCH v6 0/2] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5
From: Robin Murphy @ 2026-06-30 13:01 UTC (permalink / raw)
  To: will
  Cc: mark.rutland, linux-arm-kernel, linux-perf-users, zeev, blakgeof,
	avivb, ilkka

v5: lore.kernel.org/r/20260603150025.30980-1-avivb@amazon.com

Hi all,

I'm reposting Aviv's series partly for visibility, since the previous
versions were buried in a thread, but also to respin patch #1 - Aviv had
fixed up the bugs in my initial draft, but I also get reports against the
original commit on my branch, so I ended up taking a second look, and
deciding the improvement was worthwhile.

Thansk,
Robin.


Aviv Bakal (1):
  perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5

Robin Murphy (1):
  perf/arm-cmn: Move DTM index data out of hw_perf_event

 drivers/perf/arm-cmn.c | 123 ++++++++++++++++++++++++++++++-----------
 1 file changed, 92 insertions(+), 31 deletions(-)

-- 
2.54.0.dirty



^ permalink raw reply

* [PATCH v6 1/2] perf/arm-cmn: Move DTM index data out of hw_perf_event
From: Robin Murphy @ 2026-06-30 13:01 UTC (permalink / raw)
  To: will
  Cc: mark.rutland, linux-arm-kernel, linux-perf-users, zeev, blakgeof,
	avivb, ilkka
In-Reply-To: <cover.1782824005.git.robin.murphy@arm.com>

The amount of data we need to store all the per-DTM counter and
watchpoint allocations is already testing the limits of hw_perf_event,
and future CMNs are only likely to keep growing larger, so move these
arrays out to separate memory allocations. As part of that we can use
an explicit union for allocating cycle counters to dtc_cycles events,
which is arguably nicer anyway.

Reviewed-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

v6: Use bitmap functions consistently for cleaner allocation/zeroing

 drivers/perf/arm-cmn.c | 91 ++++++++++++++++++++++++++++--------------
 1 file changed, 61 insertions(+), 30 deletions(-)

diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 6e5cc4086a9e..9392838408ff 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -598,17 +598,14 @@ static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id) {}
 
 struct arm_cmn_hw_event {
 	struct arm_cmn_node *dn;
-	u64 dtm_idx[DIV_ROUND_UP(CMN_MAX_NODES_PER_EVENT * 2, 64)];
+	union {
+		unsigned long *dtm_idx;
+		int cc_idx;
+	};
+	unsigned long *wp_idx;
 	s8 dtc_idx[CMN_MAX_DTCS];
 	u8 num_dns;
 	u8 dtm_offset;
-
-	/*
-	 * WP config registers are divided to UP and DOWN events. We need to
-	 * keep to track only one of them.
-	 */
-	DECLARE_BITMAP(wp_idx, CMN_MAX_XPS);
-
 	bool wide_sel;
 	enum cmn_filter_select filter_sel;
 };
@@ -626,25 +623,44 @@ static struct arm_cmn_hw_event *to_cmn_hw(struct perf_event *event)
 	return (struct arm_cmn_hw_event *)&event->hw;
 }
 
-static void arm_cmn_set_index(u64 x[], unsigned int pos, unsigned int val)
+#define BPL2 (BITS_PER_LONG / 2)
+
+static void arm_cmn_set_dtm_idx(struct arm_cmn_hw_event *hw, unsigned int pos, unsigned int val)
 {
-	x[pos / 32] |= (u64)val << ((pos % 32) * 2);
+	hw->dtm_idx[pos / BPL2] |= (unsigned long)val << ((pos % BPL2) * 2);
 }
 
-static unsigned int arm_cmn_get_index(u64 x[], unsigned int pos)
+static unsigned int arm_cmn_get_dtm_idx(struct arm_cmn_hw_event *hw, unsigned int pos)
 {
-	return (x[pos / 32] >> ((pos % 32) * 2)) & 3;
+	return (hw->dtm_idx[pos / BPL2] >> ((pos % BPL2) * 2)) & 3;
 }
 
-static void arm_cmn_set_wp_idx(unsigned long *wp_idx, unsigned int pos, bool val)
+static unsigned long *arm_cmn_alloc_dtm_idx(void)
+{
+	return bitmap_zalloc(CMN_MAX_NODES_PER_EVENT * 2, GFP_KERNEL);
+}
+
+static void arm_cmn_set_wp_idx(struct arm_cmn_hw_event *hw, unsigned int pos, bool val)
 {
 	if (val)
-		set_bit(pos, wp_idx);
+		set_bit(pos, hw->wp_idx);
 }
 
-static unsigned int arm_cmn_get_wp_idx(unsigned long *wp_idx, unsigned int pos)
+static unsigned int arm_cmn_get_wp_idx(struct arm_cmn_hw_event *hw, unsigned int pos)
 {
-	return test_bit(pos, wp_idx);
+	return test_bit(pos, hw->wp_idx);
+}
+
+static unsigned long *arm_cmn_alloc_wp_idx(void)
+{
+	return bitmap_zalloc(CMN_MAX_XPS, GFP_KERNEL);
+}
+
+static void arm_cmn_clear_idx(struct arm_cmn_hw_event *hw)
+{
+	bitmap_zero(hw->dtm_idx, CMN_MAX_NODES_PER_EVENT * 2);
+	if (hw->wp_idx)
+		bitmap_zero(hw->wp_idx, CMN_MAX_XPS);
 }
 
 struct arm_cmn_event_attr {
@@ -1377,7 +1393,7 @@ static int arm_cmn_get_assigned_wp_idx(struct perf_event *event,
 				       struct arm_cmn_hw_event *hw,
 				       unsigned int pos)
 {
-	return CMN_EVENT_EVENTID(event) + arm_cmn_get_wp_idx(hw->wp_idx, pos);
+	return CMN_EVENT_EVENTID(event) + arm_cmn_get_wp_idx(hw, pos);
 }
 
 static void arm_cmn_claim_wp_idx(struct arm_cmn_dtm *dtm,
@@ -1388,7 +1404,7 @@ static void arm_cmn_claim_wp_idx(struct arm_cmn_dtm *dtm,
 	struct arm_cmn_hw_event *hw = to_cmn_hw(event);
 
 	dtm->wp_event[wp_idx] = hw->dtc_idx[dtc];
-	arm_cmn_set_wp_idx(hw->wp_idx, pos, wp_idx - CMN_EVENT_EVENTID(event));
+	arm_cmn_set_wp_idx(hw, pos, wp_idx - CMN_EVENT_EVENTID(event));
 }
 
 static u32 arm_cmn_wp_config(struct perf_event *event, int wp_idx)
@@ -1459,7 +1475,7 @@ static u64 arm_cmn_read_dtm(struct arm_cmn *cmn, struct arm_cmn_hw_event *hw,
 			dtm = &cmn->dtms[dn->dtm] + hw->dtm_offset;
 			reg = readq_relaxed(dtm->base + offset);
 		}
-		dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+		dtm_idx = arm_cmn_get_dtm_idx(hw, i);
 		count += (u16)(reg >> (dtm_idx * 16));
 	}
 	return count;
@@ -1506,7 +1522,7 @@ static void arm_cmn_event_read(struct perf_event *event)
 	unsigned long flags;
 
 	if (CMN_EVENT_TYPE(event) == CMN_TYPE_DTC) {
-		delta = arm_cmn_read_cc(cmn->dtc + hw->dtc_idx[0]);
+		delta = arm_cmn_read_cc(cmn->dtc + hw->cc_idx);
 		local64_add(delta, &event->count);
 		return;
 	}
@@ -1573,7 +1589,7 @@ static void arm_cmn_event_start(struct perf_event *event, int flags)
 	int i;
 
 	if (type == CMN_TYPE_DTC) {
-		struct arm_cmn_dtc *dtc = cmn->dtc + hw->dtc_idx[0];
+		struct arm_cmn_dtc *dtc = cmn->dtc + hw->cc_idx;
 
 		writel_relaxed(CMN_DT_DTC_CTL_DT_EN | CMN_DT_DTC_CTL_CG_DISABLE,
 			       dtc->base + CMN_DT_DTC_CTL);
@@ -1591,7 +1607,7 @@ static void arm_cmn_event_start(struct perf_event *event, int flags)
 			writeq_relaxed(mask, base + CMN_DTM_WPn_MASK(wp_idx));
 		}
 	} else for_each_hw_dn(hw, dn, i) {
-		int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+		int dtm_idx = arm_cmn_get_dtm_idx(hw, i);
 
 		arm_cmn_set_event_sel_lo(dn, dtm_idx, CMN_EVENT_EVENTID(event),
 					 hw->wide_sel);
@@ -1607,7 +1623,7 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
 	int i;
 
 	if (type == CMN_TYPE_DTC) {
-		struct arm_cmn_dtc *dtc = cmn->dtc + hw->dtc_idx[0];
+		struct arm_cmn_dtc *dtc = cmn->dtc + hw->cc_idx;
 
 		dtc->cc_active = false;
 		writel_relaxed(CMN_DT_DTC_CTL_DT_EN, dtc->base + CMN_DT_DTC_CTL);
@@ -1620,7 +1636,7 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
 			writeq_relaxed(~0ULL, base + CMN_DTM_WPn_VAL(wp_idx));
 		}
 	} else for_each_hw_dn(hw, dn, i) {
-		int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+		int dtm_idx = arm_cmn_get_dtm_idx(hw, i);
 
 		arm_cmn_set_event_sel_lo(dn, dtm_idx, 0, hw->wide_sel);
 	}
@@ -1764,6 +1780,14 @@ static enum cmn_filter_select arm_cmn_filter_sel(const struct arm_cmn *cmn,
 }
 
 
+static void arm_cmn_event_destroy(struct perf_event *event)
+{
+	struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+
+	bitmap_free(hw->dtm_idx);
+	bitmap_free(hw->wp_idx);
+}
+
 static int arm_cmn_event_init(struct perf_event *event)
 {
 	struct arm_cmn *cmn = to_cmn(event->pmu);
@@ -1788,6 +1812,11 @@ static int arm_cmn_event_init(struct perf_event *event)
 	if (type == CMN_TYPE_DTC)
 		return arm_cmn_validate_group(cmn, event);
 
+	event->destroy = arm_cmn_event_destroy;
+	hw->dtm_idx = arm_cmn_alloc_dtm_idx();
+	if (!hw->dtm_idx)
+		return -ENOMEM;
+
 	eventid = CMN_EVENT_EVENTID(event);
 	/* For watchpoints we need the actual XP node here */
 	if (type == CMN_TYPE_WP) {
@@ -1798,6 +1827,9 @@ static int arm_cmn_event_init(struct perf_event *event)
 		/* ...but the DTM may depend on which port we're watching */
 		if (cmn->multi_dtm)
 			hw->dtm_offset = CMN_EVENT_WP_DEV_SEL(event) / 2;
+		hw->wp_idx = arm_cmn_alloc_wp_idx();
+		if (!hw->wp_idx)
+			return -ENOMEM;
 	} else if (type == CMN_TYPE_XP &&
 		   (cmn->part == PART_CMN700 || cmn->part == PART_CMN_S3)) {
 		hw->wide_sel = true;
@@ -1848,7 +1880,7 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
 
 	while (i--) {
 		struct arm_cmn_dtm *dtm = &cmn->dtms[hw->dn[i].dtm] + hw->dtm_offset;
-		unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+		unsigned int dtm_idx = arm_cmn_get_dtm_idx(hw, i);
 
 		if (type == CMN_TYPE_WP) {
 			int wp_idx = arm_cmn_get_assigned_wp_idx(event, hw, i);
@@ -1862,8 +1894,7 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
 		dtm->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx);
 		writel_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG);
 	}
-	memset(hw->dtm_idx, 0, sizeof(hw->dtm_idx));
-	memset(hw->wp_idx, 0, sizeof(hw->wp_idx));
+	arm_cmn_clear_idx(hw);
 
 	for_each_hw_dtc_idx(hw, j, idx)
 		cmn->dtc[j].counters[idx] = NULL;
@@ -1883,7 +1914,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
 				return -ENOSPC;
 
 		cmn->dtc[i].cycles = event;
-		hw->dtc_idx[0] = i;
+		hw->cc_idx = i;
 
 		if (flags & PERF_EF_START)
 			arm_cmn_event_start(event, 0);
@@ -1948,7 +1979,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
 				goto free_dtms;
 		}
 
-		arm_cmn_set_index(hw->dtm_idx, i, dtm_idx);
+		arm_cmn_set_dtm_idx(hw, i, dtm_idx);
 
 		dtm->input_sel[dtm_idx] = input_sel;
 		shift = CMN__PMEVCNTn_GLOBAL_NUM_SHIFT(dtm_idx);
@@ -1981,7 +2012,7 @@ static void arm_cmn_event_del(struct perf_event *event, int flags)
 	arm_cmn_event_stop(event, PERF_EF_UPDATE);
 
 	if (type == CMN_TYPE_DTC)
-		cmn->dtc[hw->dtc_idx[0]].cycles = NULL;
+		cmn->dtc[hw->cc_idx].cycles = NULL;
 	else
 		arm_cmn_event_clear(cmn, event, hw->num_dns);
 }
-- 
2.54.0.dirty



^ permalink raw reply related

* [PATCH v6 2/2] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5
From: Robin Murphy @ 2026-06-30 13:01 UTC (permalink / raw)
  To: will
  Cc: mark.rutland, linux-arm-kernel, linux-perf-users, zeev, blakgeof,
	avivb, ilkka
In-Reply-To: <cover.1782824005.git.robin.murphy@arm.com>

From: Aviv Bakal <avivb@amazon.com>

Graviton5 uses a customised CMN-S3 implementation where certain
discovery registers report zeroed fields. Add the following workarounds:

 - Introduce a dedicated ACPI HID to identify the Graviton5 CMN variant.
 - Derive the DTC domain from the XP node ID, since the unit info
   register reports it as zero.
 - Set the DTC logical ID from the XP's logical ID, since the node info
   register's logical ID field is also zeroed.

Signed-off-by: Aviv Bakal <avivb@amazon.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

v6: No change

 drivers/perf/arm-cmn.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 9392838408ff..50402bc4a21d 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -31,7 +31,8 @@
 #define CMN_CHILD_NODE_ADDR		GENMASK(29, 0)
 #define CMN_CHILD_NODE_EXTERNAL		BIT(31)
 
-#define CMN_MAX_DIMENSION		12
+/* Some implementations use a mesh larger than the architectural max of 12 */
+#define CMN_MAX_DIMENSION		14
 #define CMN_MAX_XPS			(CMN_MAX_DIMENSION * CMN_MAX_DIMENSION)
 #define CMN_MAX_DTMS			(CMN_MAX_XPS + (CMN_MAX_DIMENSION - 1) * 4)
 
@@ -215,6 +216,8 @@ enum cmn_part {
 	PART_CMN700 = 0x43c,
 	PART_CI700 = 0x43a,
 	PART_CMN_S3 = 0x43e,
+	/* Synthetic part number, overridden to PART_CMN_S3 during discovery */
+	PART_GRAVITON5 = 0xa5,
 };
 
 /* CMN-600 r0px shouldn't exist in silicon, thankfully */
@@ -2253,6 +2256,18 @@ static unsigned int arm_cmn_dtc_domain(struct arm_cmn *cmn, void __iomem *xp_reg
 	return FIELD_GET(CMN_DTM_UNIT_INFO_DTC_DOMAIN, readl_relaxed(xp_region + offset));
 }
 
+static unsigned int arm_cmn_graviton5_dtc_domain(u16 xp_id)
+{
+	unsigned int x = (xp_id >> 7) & 0xf;
+	unsigned int y = (xp_id >> 3) & 0xf;
+
+	/*
+	 * The unit info register reads as zero; derive the DTC domain from
+	 * the XP's mesh coordinates over the 10x14 mesh.
+	 */
+	return (x / 5) + (y / 7) * 2;
+}
+
 static void arm_cmn_init_node_info(struct arm_cmn *cmn, u32 offset, struct arm_cmn_node *node)
 {
 	int level;
@@ -2298,6 +2313,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
 	u64 reg;
 	int i, j;
 	size_t sz;
+	bool graviton5_workaround = false;
 
 	arm_cmn_init_node_info(cmn, rgn_offset, &cfg);
 	if (cfg.type != CMN_TYPE_CFG)
@@ -2308,6 +2324,13 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
 	reg = readq_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_01);
 	part = FIELD_GET(CMN_CFGM_PID0_PART_0, reg);
 	part |= FIELD_GET(CMN_CFGM_PID1_PART_1, reg) << 8;
+
+	/* Graviton5 has a customised CMN-S3 which needs some fixups */
+	if (cmn->part == PART_GRAVITON5) {
+		cmn->part = PART_CMN_S3;
+		graviton5_workaround = true;
+	}
+
 	/* 600AE is close enough that it's not really worth more complexity */
 	if (part == PART_CMN600AE)
 		part = PART_CMN600;
@@ -2397,6 +2420,8 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
 
 		if (cmn->part == PART_CMN600)
 			xp->dtc = -1;
+		else if (graviton5_workaround)
+			xp->dtc = arm_cmn_graviton5_dtc_domain(xp->id);
 		else
 			xp->dtc = arm_cmn_dtc_domain(cmn, xp_region);
 
@@ -2475,6 +2500,10 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
 
 			switch (dn->type) {
 			case CMN_TYPE_DTC:
+				if (graviton5_workaround) {
+					/* Node info logical ID is zeroed; use the XP's */
+					dn->logid = xp->logid;
+				}
 				cmn->num_dtcs++;
 				dn++;
 				break;
@@ -2690,6 +2719,7 @@ static const struct acpi_device_id arm_cmn_acpi_match[] = {
 	{ "ARMHC650" },
 	{ "ARMHC700" },
 	{ "ARMHC003" },
+	{ "AMZN0070", PART_GRAVITON5 },
 	{}
 };
 MODULE_DEVICE_TABLE(acpi, arm_cmn_acpi_match);
-- 
2.54.0.dirty



^ permalink raw reply related

* [PATCH 09/10] arm64: dts: apple: Add MTP DockChannel HID nodes
From: Michael Reeves via B4 Relay @ 2026-06-30 12:54 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Jassi Brar, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Hector Martin,
	Joerg Roedel (AMD), Will Deacon, Robin Murphy, Dmitry Torokhov,
	Jiri Kosina, Benjamin Tissoires
  Cc: asahi, linux-arm-kernel, linux-kernel, devicetree, iommu,
	linux-input, Michael Reeves
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-0-506d936a1707@gmail.com>

From: Michael Reeves <michael.reeves077@gmail.com>

Add disabled MTP nodes for the Apple SoCs used by M2 and M3 systems.

Each instance describes the RTKit ASC mailbox, MTP DART, DockChannel
mailbox, and DockChannel HID client. Board files can enable them on
machines that route internal input through MTP.

Co-developed-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Michael Reeves <michael.reeves077@gmail.com>
---
 arch/arm64/boot/dts/apple/t602x-die0.dtsi | 46 ++++++++++++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8112.dtsi      | 46 ++++++++++++++++++++++++++++++
 arch/arm64/boot/dts/apple/t8122.dtsi      | 47 +++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+)

diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
index 8622ddea7b44..edc73682fd22 100644
--- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
@@ -150,6 +150,52 @@ pinctrl_smc: pinctrl@2a2820000 {
 				<AIC_IRQ 0 857 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
+	mtp_mbox: mbox@2a9408000 {
+		compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4";
+		reg = <0x2 0xa9408000 0x0 0x4000>;
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 0 693 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 0 694 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 0 695 IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_IRQ 0 696 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "send-empty", "send-not-empty",
+				  "recv-empty", "recv-not-empty";
+		#mbox-cells = <0>;
+		status = "disabled";
+	};
+
+	mtp_dart: iommu@2a9808000 {
+		compatible = "apple,t6020-dart", "apple,t8110-dart";
+		reg = <0x2 0xa9808000 0x0 0x4000>;
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 0 676 IRQ_TYPE_LEVEL_HIGH>;
+		#iommu-cells = <1>;
+		status = "disabled";
+	};
+
+	mtp_dockchannel: mailbox@2a9b14000 {
+		compatible = "apple,t6020-dockchannel", "apple,t8112-dockchannel";
+		reg = <0x2 0xa9b14000 0x0 0x4000>,
+		      <0x2 0xa9b30000 0x0 0x4000>,
+		      <0x2 0xa9b34000 0x0 0x4000>;
+		reg-names = "irq", "config", "data";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_IRQ 0 677 IRQ_TYPE_LEVEL_HIGH>;
+		#mbox-cells = <0>;
+		status = "disabled";
+	};
+
+	mtp_hid: hid@2a9400000 {
+		compatible = "apple,t6020-dockchannel-hid", "apple,t8112-dockchannel-hid";
+		reg = <0x2 0xa9400000 0x0 0x4000>,
+		      <0x2 0xa9c00000 0x0 0x100000>;
+		reg-names = "coproc-asc", "coproc-sram";
+		mboxes = <&mtp_mbox>, <&mtp_dockchannel>;
+		mbox-names = "asc", "dockchannel";
+		iommus = <&mtp_dart 1>;
+		status = "disabled";
+	};
+
 	sio_dart: iommu@39b008000 {
 		compatible = "apple,t6020-dart", "apple,t8110-dart";
 		reg = <0x3 0x9b008000 0x0 0x8000>;
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index 85c47422d4e8..8411828c0772 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -983,6 +983,52 @@ pinctrl_aop: pinctrl@24a820000 {
 				     <AIC_IRQ 307 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		mtp_mbox: mbox@24e408000 {
+			compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4";
+			reg = <0x2 0x4e408000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 864 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 865 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 866 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 867 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "send-empty", "send-not-empty",
+					  "recv-empty", "recv-not-empty";
+			#mbox-cells = <0>;
+			status = "disabled";
+		};
+
+		mtp_dart: iommu@24e808000 {
+			compatible = "apple,t8110-dart";
+			reg = <0x2 0x4e808000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 848 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
+
+		mtp_dockchannel: mailbox@24eb14000 {
+			compatible = "apple,t8112-dockchannel";
+			reg = <0x2 0x4eb14000 0x0 0x4000>,
+			      <0x2 0x4eb30000 0x0 0x4000>,
+			      <0x2 0x4eb34000 0x0 0x4000>;
+			reg-names = "irq", "config", "data";
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 850 IRQ_TYPE_LEVEL_HIGH>;
+			#mbox-cells = <0>;
+			status = "disabled";
+		};
+
+		mtp_hid: hid@24e400000 {
+			compatible = "apple,t8112-dockchannel-hid";
+			reg = <0x2 0x4e400000 0x0 0x4000>,
+			      <0x2 0x4ec00000 0x0 0x100000>;
+			reg-names = "coproc-asc", "coproc-sram";
+			mboxes = <&mtp_mbox>, <&mtp_dockchannel>;
+			mbox-names = "asc", "dockchannel";
+			iommus = <&mtp_dart 1>;
+			status = "disabled";
+		};
+
 		ans_mbox: mbox@277408000 {
 			compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4";
 			reg = <0x2 0x77408000 0x0 0x4000>;
diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi
index c6196225e96e..ec1f47d15ec9 100644
--- a/arch/arm64/boot/dts/apple/t8122.dtsi
+++ b/arch/arm64/boot/dts/apple/t8122.dtsi
@@ -438,6 +438,53 @@ pinctrl_aop: pinctrl@2f4824000 {
 				     <AIC_IRQ 351 IRQ_TYPE_LEVEL_HIGH>,
 				     <AIC_IRQ 352 IRQ_TYPE_LEVEL_HIGH>;
 		};
+
+		mtp_mbox: mbox@2fa408000 {
+			compatible = "apple,t8122-asc-mailbox", "apple,asc-mailbox-v4";
+			reg = <0x2 0xfa408000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 838 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 839 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 840 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 841 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "send-empty", "send-not-empty",
+					  "recv-empty", "recv-not-empty";
+			#mbox-cells = <0>;
+			status = "disabled";
+		};
+
+		mtp_dart: iommu@2fa808000 {
+			compatible = "apple,t8122-dart", "apple,t8110-dart";
+			reg = <0x2 0xfa808000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 822 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
+
+		mtp_dockchannel: mailbox@2fab14000 {
+			compatible = "apple,t8122-dockchannel", "apple,t8112-dockchannel";
+			reg = <0x2 0xfab14000 0x0 0x4000>,
+			      <0x2 0xfab30000 0x0 0x4000>,
+			      <0x2 0xfab34000 0x0 0x4000>;
+			reg-names = "irq", "config", "data";
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 824 IRQ_TYPE_LEVEL_HIGH>;
+			#mbox-cells = <0>;
+			status = "disabled";
+		};
+
+		mtp_hid: hid@2fa400000 {
+			compatible = "apple,t8122-dockchannel-hid",
+				     "apple,t8112-dockchannel-hid";
+			reg = <0x2 0xfa400000 0x0 0x4000>,
+			      <0x2 0xfac00000 0x0 0x100000>;
+			reg-names = "coproc-asc", "coproc-sram";
+			mboxes = <&mtp_mbox>, <&mtp_dockchannel>;
+			mbox-names = "asc", "dockchannel";
+			iommus = <&mtp_dart 1>;
+			status = "disabled";
+		};
 	};
 };
 

-- 
2.51.2




^ permalink raw reply related

* [PATCH] media: raspberrypi: rp1-cfe: acquire state_lock in cfe_start_streaming()
From: Tharit Tangkijwanichakul @ 2026-06-30 13:07 UTC (permalink / raw)
  To: tomi.valkeinen, kernel-list, mchehab, linux-media
  Cc: florian.fainelli, bcm-kernel-feedback-list, linux-rpi-kernel,
	linux-arm-kernel, linux-kernel, skhan, linux-kernel-mentees,
	Tharit Tangkijwanichakul

cfe_start_streaming() modifies shared device state without holding
state_lock. The driver exposes multiple video nodes backed by
a single cfe_device. While one node runs cfe_start_streaming(),
another node's cfe_buffer_queue() may read the node state via
test_all_nodes() under state_lock to decide whether to schedule a job.
Another case is when node->fs_count is read by the interrupt handler
in cfe_sof_isr().  Modifying this state without state_lock races
against those readers.

The counterpart cfe_stop_streaming() already takes state_lock around its
state modification. Fix cfe_start_streaming() to do the same.

Found by code inspection.

Fixes: 6edb685abb2a ("media: raspberrypi: Add support for RP1-CFE")
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@gmail.com>
---
 drivers/media/platform/raspberrypi/rp1-cfe/cfe.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
index 8375ed3e9..d8ea71830 100644
--- a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
@@ -1151,6 +1151,7 @@ static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count)
 	struct v4l2_subdev_state *state;
 	struct v4l2_subdev_route *route;
 	s64 link_freq;
+	unsigned long flags;
 	int ret;
 
 	cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
@@ -1184,9 +1185,11 @@ static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count)
 
 	state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd);
 
+	spin_lock_irqsave(&cfe->state_lock, flags);
 	clear_state(cfe, FS_INT | FE_INT, node->id);
 	set_state(cfe, NODE_STREAMING, node->id);
 	node->fs_count = 0;
+	spin_unlock_irqrestore(&cfe->state_lock, flags);
 
 	ret = cfe_start_channel(node);
 	if (ret)

base-commit: 06cb687a5132fcffe624c0070576ab852ac6b568
prerequisite-patch-id: 4c010e20cdeb611d14546bc729b513f959e25afd
-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH v4 3/4] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
From: Linus Walleij @ 2026-06-30 13:12 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: brgl, robh, krzk+dt, conor+dt, afaerber, mwalle,
	andriy.shevchenko, tychang, linux-gpio, devicetree, linux-kernel,
	linux-arm-kernel, linux-realtek-soc, cy.huang, stanley_chang,
	james.tai
In-Reply-To: <20260622092335.1166876-4-eleanor.lin@realtek.com>

Hi Yu-Chun,

thanks for your patch!

On Mon, Jun 22, 2026 at 10:33 AM Yu-Chun Lin <eleanor.lin@realtek.com> wrote:

> From: Tzuyi Chang <tychang@realtek.com>
>
> Add support for the GPIO controller found on Realtek DHC RTD1625 SoCs.
>
> Unlike the existing Realtek GPIO driver (drivers/gpio/gpio-rtd.c),
> which manages pins via shared bank registers, the RTD1625 introduces
> a per-pin register architecture. Each GPIO line now has its own
> dedicated 32-bit control register to manage configuration independently,
> including direction, output value, input value, interrupt enable, and
> debounce. Therefore, this distinct hardware design requires a separate
> driver.
>
> Additionally, the RTD1625 GPIO controller has a specific hardware quirk:
> it fires both 'assert' and 'de-assert' interrupts simultaneously on any
> edge toggle. To handle this, we utilize the polarity register to route
> the requested edge (rising/falling) to the 'assert' IRQ line. The driver
> then filters out the unwanted 'de-assert' interrupt in the IRQ handler
> and pre-clears edge interrupts to prevent interrupt storms caused by
> unhandled dropped interrupts.
>
> Interrupt support is optional for this device, matching the dt-bindings.
> If the interrupts property is not provided, the driver simply skips IRQ
> initialization and operates purely as a basic GPIO controller.
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Signed-off-by: Tzuyi Chang <tychang@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
(...)
> +static void rtd1625_gpio_irq_handle(struct irq_desc *desc)
> +{
> +       unsigned int (*get_reg_offset)(struct rtd1625_gpio *gpio, unsigned int offset);
> +       struct rtd1625_gpio *data = irq_desc_get_handler_data(desc);
> +       struct irq_domain *domain = data->gpio_chip.irq.domain;
> +       struct irq_chip *chip = irq_desc_get_chip(desc);
> +       unsigned int irq = irq_desc_get_irq(desc);
> +       unsigned long status;
> +       unsigned int reg_offset, i, j;
> +       unsigned int girq;

So this

> +       irq_hw_number_t hwirq;
> +       u32 irq_type;
> +
> +       if (irq == data->irqs[RTD1625_IRQ_ASSERT])
> +               get_reg_offset = &rtd1625_gpio_gpa_offset;
> +       else if (irq == data->irqs[RTD1625_IRQ_DEASSERT])
> +               get_reg_offset = &rtd1625_gpio_gpda_offset;
> +       else if (irq == data->irqs[2])
> +               get_reg_offset = &rtd1625_gpio_level_offset;
> +       else
> +               return;
> +
> +       chained_irq_enter(chip, desc);
> +
> +       for (i = 0; i < data->info->num_gpios; i += 32) {
> +               reg_offset = get_reg_offset(data, i);
> +               status = readl_relaxed(data->irq_base + reg_offset);
> +
> +               /*
> +                * Hardware quirk: The controller fires both "assert" and "de-assert"
> +                * interrupts simultaneously on any edge toggle.
> +                * We must pre-clear edge interrupts here. If we drop an unwanted
> +                * de-assert interrupt below, it will never reach the IRQ core
> +                * (generic_handle_domain_irq), meaning ->irq_ack() won't be called.
> +                * Failing to clear it here leads to an interrupt storm.
> +                */
> +               if (irq != data->irqs[RTD1625_IRQ_LEVEL])
> +                       writel_relaxed(status, data->irq_base + reg_offset);
> +
> +               for_each_set_bit(j, &status, 32) {
> +                       hwirq = i + j;
> +                       girq = irq_find_mapping(domain, hwirq);
> +                       irq_type = irq_get_trigger_type(girq);

Just
irq_type = irq_get_trigger_type(irq_find_mapping(domain, hwirq));

Drop the intermediate variable.

> +static void rtd1625_gpio_ack_irq(struct irq_data *d)
> +{
> +       struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
> +       irq_hw_number_t hwirq = irqd_to_hwirq(d);
> +       u32 irq_type = irqd_get_trigger_type(d);
> +       u32 bit_mask = BIT(hwirq % 32);

This is a clear sign that your GPIOs and IRQs should be three-cell
(bank and offset) since they clearly have one each a separate
status bit in this register.

> +static void rtd1625_gpio_enable_edge_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
> +{
> +       int gpda_reg_offset = rtd1625_gpio_gpda_offset(data, hwirq);
> +       int gpa_reg_offset = rtd1625_gpio_gpa_offset(data, hwirq);
> +       u32 clr_mask = BIT(hwirq % 32);

Same here.

> +static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd1625_gpio *data)
> +{
> +       struct gpio_irq_chip *irq_chip;

This is a super-confusing name for this variable.

It is called irq_chip but it's not struct irq_chip at all.

Call this girq like all other drivers.

Yours,
Linus Walleij


^ permalink raw reply

* RE: [PATCH v7 3/4] reset: cix: add sky1 audss auxiliary reset driver
From: Joakim  Zhang @ 2026-06-30 12:43 UTC (permalink / raw)
  To: Philipp Zabel, mturquette@baylibre.com, sboyd@kernel.org,
	bmasney@redhat.com, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org
  Cc: cix-kernel-upstream, linux-clk@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <90ecf77e16c17f0ac46b2996be58110fc01c2e08.camel@pengutronix.de>

Hi

> -----Original Message-----
> From: Philipp Zabel <p.zabel@pengutronix.de>
> Sent: Tuesday, June 30, 2026 5:38 PM
> To: Joakim Zhang <joakim.zhang@cixtech.com>; mturquette@baylibre.com;
> sboyd@kernel.org; bmasney@redhat.com; robh@kernel.org;
> krzk+dt@kernel.org; conor+dt@kernel.org
> Cc: cix-kernel-upstream <cix-kernel-upstream@cixtech.com>; linux-
> clk@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v7 3/4] reset: cix: add sky1 audss auxiliary reset driver
> 
> EXTERNAL EMAIL
> 
> CAUTION: Suspicious Email from unusual domain.
> 
> On Mo, 2026-06-29 at 17:14 +0800, joakim.zhang@cixtech.com wrote:
> > From: Joakim Zhang <joakim.zhang@cixtech.com>
> >
> > Add an auxiliary reset controller driver for the AUDSS CRU. Sixteen
> > software reset lines for audio subsystem peripherals are controlled
> > through one register in the CRU register map.
> >
> > The driver is created by the AUDSS clock platform driver and registers
> > the reset controller on the CRU device node.
> >
> > Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
> > ---
> >  drivers/reset/Kconfig            |  14 ++++
> >  drivers/reset/Makefile           |   1 +
> >  drivers/reset/reset-sky1-audss.c | 137
> > +++++++++++++++++++++++++++++++
> >  3 files changed, 152 insertions(+)
> >  create mode 100644 drivers/reset/reset-sky1-audss.c
> >
> > diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index
> > d009eb0849a3..f74859b292ae 100644
> > --- a/drivers/reset/Kconfig
> > +++ b/drivers/reset/Kconfig
> > @@ -300,6 +300,20 @@ config RESET_SKY1
> >       help
> >         This enables the reset controller for Cix Sky1.
> >
> > +config RESET_SKY1_AUDSS
> > +     tristate "Cix Sky1 Audio Subsystem reset controller"
> > +     depends on ARCH_CIX || COMPILE_TEST
> > +     select AUXILIARY_BUS
> > +     select REGMAP_MMIO
> 
> This driver doesn't need REGMAP_MMIO itself, it just inherits its parent's
> regmap.
Dropped.

Thanks,
Joakim

^ permalink raw reply

* [PATCH 05/10] mailbox: apple: Add DockChannel FIFO controller
From: Michael Reeves via B4 Relay @ 2026-06-30 12:54 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Jassi Brar, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Hector Martin,
	Joerg Roedel (AMD), Will Deacon, Robin Murphy, Dmitry Torokhov,
	Jiri Kosina, Benjamin Tissoires
  Cc: asahi, linux-arm-kernel, linux-kernel, devicetree, iommu,
	linux-input, Michael Reeves
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-0-506d936a1707@gmail.com>

From: Michael Reeves <michael.reeves077@gmail.com>

DockChannel is a hardware FIFO used by Apple coprocessors for
low-latency byte-stream communication with the AP.

Add a mailbox controller that preallocates RX storage, tracks IRQ
enable state in software, and reports TX completion from the TX-empty
interrupt.

Reject messages larger than the FIFO and return -EBUSY while the
previous message is still pending. This keeps the provider usable for
future small-message clients such as serial transports without a TX
worker.

Co-developed-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Michael Reeves <michael.reeves077@gmail.com>
---
 MAINTAINERS                               |   2 +
 drivers/mailbox/Kconfig                   |  12 +
 drivers/mailbox/Makefile                  |   2 +
 drivers/mailbox/apple-dockchannel.c       | 380 ++++++++++++++++++++++++++++++
 include/linux/mailbox/apple-dockchannel.h |  29 +++
 5 files changed, 425 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1f3c2cdb6e19..ed68452c0ad6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2628,6 +2628,7 @@ F:	drivers/input/touchscreen/apple_z2.c
 F:	drivers/iommu/apple-dart.c
 F:	drivers/iommu/io-pgtable-dart.c
 F:	drivers/irqchip/irq-apple-aic.c
+F:	drivers/mailbox/apple-dockchannel.c
 F:	drivers/mfd/macsmc.c
 F:	drivers/nvme/host/apple.c
 F:	drivers/nvmem/apple-efuses.c
@@ -2646,6 +2647,7 @@ F:	drivers/video/backlight/apple_dwi_bl.c
 F:	drivers/watchdog/apple_wdt.c
 F:	include/dt-bindings/interrupt-controller/apple-aic.h
 F:	include/dt-bindings/pinctrl/apple.h
+F:	include/linux/mailbox/apple-dockchannel.h
 F:	include/linux/mfd/macsmc.h
 F:	include/linux/soc/apple/*
 F:	include/uapi/drm/asahi_drm.h
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 3062ee352f78..f1af76d19f1e 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -36,6 +36,18 @@ config ARM_MHU_V3
 	  that provides different means of transports: supported extensions
 	  will be discovered and possibly managed at probe-time.
 
+config APPLE_DOCKCHANNEL
+	tristate "Apple DockChannel FIFO mailbox"
+	depends on ARCH_APPLE || COMPILE_TEST
+	depends on HAS_IOMEM
+	depends on OF
+	help
+	  DockChannel is a hardware FIFO used on Apple Silicon SoCs for
+	  communication between the application processor and co-processors.
+	  This driver exposes DockChannel FIFOs through the mailbox framework.
+
+	  Say Y here if you have an M2 or later Apple MacBook.
+
 config AST2700_MBOX
 	tristate "ASPEED AST2700 IPC driver"
 	depends on ARCH_ASPEED || COMPILE_TEST
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 944d8ea39f34..4f3405064269 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_ARM_MHU_V2)	+= arm_mhuv2.o
 
 obj-$(CONFIG_ARM_MHU_V3)	+= arm_mhuv3.o
 
+obj-$(CONFIG_APPLE_DOCKCHANNEL)	+= apple-dockchannel.o
+
 obj-$(CONFIG_AST2700_MBOX)	+= ast2700-mailbox.o
 
 obj-$(CONFIG_CV1800_MBOX)	+= cv1800-mailbox.o
diff --git a/drivers/mailbox/apple-dockchannel.c b/drivers/mailbox/apple-dockchannel.c
new file mode 100644
index 000000000000..bae183db1307
--- /dev/null
+++ b/drivers/mailbox/apple-dockchannel.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple DockChannel mailbox controller
+ *
+ * Copyright The Asahi Linux Contributors
+ *
+ * DockChannel is a byte FIFO used by Apple co-processors. This driver exposes a
+ * single FIFO pair as a Linux mailbox channel and moves payload bytes with PIO.
+ * There is no DMA involved, so relaxed MMIO accessors are sufficient for the
+ * FIFO accesses themselves.
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox/apple-dockchannel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/unaligned.h>
+
+#define APPLE_DOCKCHANNEL_FIFO_SIZE	0x800
+
+#define IRQ_MASK			0x0
+#define IRQ_FLAG			0x4
+
+#define IRQ_TX				BIT(2)
+#define IRQ_RX				BIT(3)
+
+#define CONFIG_TX_THRESH		0x0
+#define CONFIG_RX_THRESH		0x4
+
+#define DATA_TX8			0x4
+#define DATA_TX32			0x10
+#define DATA_TX_FREE			0x14
+#define DATA_RX8			0x1c
+#define DATA_RX32			0x28
+#define DATA_RX_COUNT			0x2c
+
+struct apple_dockchannel {
+	struct device *dev;
+	struct mbox_controller controller;
+	struct mbox_chan chan;
+
+	void __iomem *irq_base;
+	void __iomem *config_base;
+	void __iomem *data_base;
+	int irq;
+
+	spinlock_t lock; /* protects IRQ mask and TX state */
+	u32 irq_mask;
+
+	const u8 *tx_buf;
+	size_t tx_len;
+	size_t tx_pos;
+	bool tx_active;
+
+	u8 rx_buf[APPLE_DOCKCHANNEL_FIFO_SIZE];
+};
+
+static void apple_dockchannel_irq_update(struct apple_dockchannel *dc,
+					 u32 bits, bool enable)
+{
+	if (enable)
+		dc->irq_mask |= bits;
+	else
+		dc->irq_mask &= ~bits;
+	writel_relaxed(dc->irq_mask, dc->irq_base + IRQ_MASK);
+}
+
+static void apple_dockchannel_irq_enable(struct apple_dockchannel *dc, u32 bits)
+{
+	/*
+	 * IRQ_FLAG is write-to-clear. Clear stale latched flags before
+	 * unmasking so the next interrupt reflects current FIFO state.
+	 */
+	writel_relaxed(bits, dc->irq_base + IRQ_FLAG);
+	apple_dockchannel_irq_update(dc, bits, true);
+}
+
+static void apple_dockchannel_irq_disable(struct apple_dockchannel *dc, u32 bits)
+{
+	apple_dockchannel_irq_update(dc, bits, false);
+}
+
+static bool apple_dockchannel_tx_empty(struct apple_dockchannel *dc)
+{
+	return readl_relaxed(dc->data_base + DATA_TX_FREE) ==
+	       APPLE_DOCKCHANNEL_FIFO_SIZE;
+}
+
+static void apple_dockchannel_write_pending(struct apple_dockchannel *dc)
+{
+	size_t left = dc->tx_len - dc->tx_pos;
+	const u8 *p = dc->tx_buf + dc->tx_pos;
+
+	while (left) {
+		size_t avail;
+		size_t block;
+
+		avail = readl_relaxed(dc->data_base + DATA_TX_FREE);
+		if (!avail)
+			break;
+
+		block = min(left, avail);
+
+		while (block >= sizeof(u32)) {
+			writel_relaxed(get_unaligned_le32(p),
+				       dc->data_base + DATA_TX32);
+			p += sizeof(u32);
+			left -= sizeof(u32);
+			block -= sizeof(u32);
+		}
+
+		while (block) {
+			writeb_relaxed(*p++, dc->data_base + DATA_TX8);
+			left--;
+			block--;
+		}
+	}
+
+	dc->tx_pos = dc->tx_len - left;
+}
+
+static void apple_dockchannel_read(struct apple_dockchannel *dc, void *buf,
+				   size_t count)
+{
+	u8 *p = buf;
+	size_t left = count;
+
+	while (left >= sizeof(u32)) {
+		put_unaligned_le32(readl_relaxed(dc->data_base + DATA_RX32), p);
+		p += sizeof(u32);
+		left -= sizeof(u32);
+	}
+
+	while (left) {
+		/*
+		 * The byte FIFO register returns the byte in bits [15:8] on
+		 * these instances.
+		 */
+		*p++ = readl_relaxed(dc->data_base + DATA_RX8) >> 8;
+		left--;
+	}
+}
+
+static int apple_dockchannel_send_data(struct mbox_chan *chan, void *data)
+{
+	struct apple_dockchannel *dc = chan->con_priv;
+	struct apple_dockchannel_msg *msg = data;
+	unsigned long flags;
+
+	if (!msg || !msg->data || !msg->len)
+		return -EINVAL;
+
+	if (msg->len > APPLE_DOCKCHANNEL_FIFO_SIZE)
+		return -EMSGSIZE;
+
+	spin_lock_irqsave(&dc->lock, flags);
+
+	if (dc->tx_active || !apple_dockchannel_tx_empty(dc)) {
+		spin_unlock_irqrestore(&dc->lock, flags);
+		return -EBUSY;
+	}
+
+	dc->tx_buf = msg->data;
+	dc->tx_len = msg->len;
+	dc->tx_pos = 0;
+	dc->tx_active = true;
+
+	apple_dockchannel_write_pending(dc);
+	writel_relaxed(APPLE_DOCKCHANNEL_FIFO_SIZE,
+		       dc->config_base + CONFIG_TX_THRESH);
+	apple_dockchannel_irq_enable(dc, IRQ_TX);
+
+	spin_unlock_irqrestore(&dc->lock, flags);
+
+	return 0;
+}
+
+static int apple_dockchannel_startup(struct mbox_chan *chan)
+{
+	struct apple_dockchannel *dc = chan->con_priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dc->lock, flags);
+	/*
+	 * The mailbox framework has no per-client RX threshold. Use byte
+	 * granularity because UART-style DockChannel clients require it.
+	 */
+	writel_relaxed(1, dc->config_base + CONFIG_RX_THRESH);
+	apple_dockchannel_irq_enable(dc, IRQ_RX);
+	spin_unlock_irqrestore(&dc->lock, flags);
+
+	enable_irq(dc->irq);
+
+	return 0;
+}
+
+static void apple_dockchannel_shutdown(struct mbox_chan *chan)
+{
+	struct apple_dockchannel *dc = chan->con_priv;
+	unsigned long flags;
+
+	disable_irq(dc->irq);
+
+	spin_lock_irqsave(&dc->lock, flags);
+	apple_dockchannel_irq_disable(dc, IRQ_TX | IRQ_RX);
+	dc->tx_active = false;
+	spin_unlock_irqrestore(&dc->lock, flags);
+}
+
+static const struct mbox_chan_ops apple_dockchannel_mbox_ops = {
+	.send_data = apple_dockchannel_send_data,
+	.startup = apple_dockchannel_startup,
+	.shutdown = apple_dockchannel_shutdown,
+};
+
+static irqreturn_t apple_dockchannel_irq(int irq, void *data)
+{
+	struct apple_dockchannel *dc = data;
+	u32 flags;
+	u32 pending;
+	bool tx_done = false;
+
+	flags = readl_relaxed(dc->irq_base + IRQ_FLAG);
+
+	spin_lock(&dc->lock);
+
+	pending = flags & dc->irq_mask & (IRQ_TX | IRQ_RX);
+	if (!pending)
+		goto out_unlock_none;
+
+	if (pending & IRQ_TX) {
+		if (apple_dockchannel_tx_empty(dc)) {
+			apple_dockchannel_irq_disable(dc, IRQ_TX);
+			tx_done = dc->tx_active;
+			dc->tx_active = false;
+		} else {
+			pending &= ~IRQ_TX;
+		}
+	}
+
+	writel_relaxed(pending, dc->irq_base + IRQ_FLAG);
+
+	spin_unlock(&dc->lock);
+
+	if (tx_done)
+		mbox_chan_txdone(&dc->chan, 0);
+
+	if (pending & IRQ_RX)
+		return IRQ_WAKE_THREAD;
+
+	if (pending)
+		return IRQ_HANDLED;
+
+	return IRQ_NONE;
+
+out_unlock_none:
+	spin_unlock(&dc->lock);
+
+	if (flags & (IRQ_TX | IRQ_RX))
+		writel_relaxed(flags & (IRQ_TX | IRQ_RX),
+			       dc->irq_base + IRQ_FLAG);
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t apple_dockchannel_irq_thread(int irq, void *data)
+{
+	struct apple_dockchannel *dc = data;
+
+	for (;;) {
+		struct apple_dockchannel_msg msg;
+		size_t avail;
+
+		avail = readl_relaxed(dc->data_base + DATA_RX_COUNT);
+		if (!avail)
+			break;
+
+		avail = min_t(size_t, avail, APPLE_DOCKCHANNEL_FIFO_SIZE);
+
+		apple_dockchannel_read(dc, dc->rx_buf, avail);
+
+		msg.data = dc->rx_buf;
+		msg.len = avail;
+		mbox_chan_received_data(&dc->chan, &msg);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct mbox_chan *
+apple_dockchannel_of_xlate(struct mbox_controller *mbox,
+			   const struct of_phandle_args *spec)
+{
+	if (spec->args_count != 0)
+		return ERR_PTR(-EINVAL);
+
+	return &mbox->chans[0];
+}
+
+static int apple_dockchannel_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct apple_dockchannel *dc;
+	int ret;
+
+	dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
+	if (!dc)
+		return -ENOMEM;
+
+	dc->dev = dev;
+	spin_lock_init(&dc->lock);
+	platform_set_drvdata(pdev, dc);
+
+	dc->irq_base = devm_platform_ioremap_resource_byname(pdev, "irq");
+	if (IS_ERR(dc->irq_base))
+		return PTR_ERR(dc->irq_base);
+
+	dc->config_base = devm_platform_ioremap_resource_byname(pdev, "config");
+	if (IS_ERR(dc->config_base))
+		return PTR_ERR(dc->config_base);
+
+	dc->data_base = devm_platform_ioremap_resource_byname(pdev, "data");
+	if (IS_ERR(dc->data_base))
+		return PTR_ERR(dc->data_base);
+
+	writel_relaxed(0, dc->irq_base + IRQ_MASK);
+	writel_relaxed(~0, dc->irq_base + IRQ_FLAG);
+
+	dc->irq = platform_get_irq(pdev, 0);
+	if (dc->irq < 0)
+		return dc->irq;
+
+	ret = devm_request_threaded_irq(dev, dc->irq, apple_dockchannel_irq,
+					apple_dockchannel_irq_thread, IRQF_ONESHOT,
+					dev_name(dev), dc);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to request IRQ\n");
+
+	disable_irq(dc->irq);
+
+	dc->chan.con_priv = dc;
+	dc->controller.dev = dev;
+	dc->controller.ops = &apple_dockchannel_mbox_ops;
+	dc->controller.chans = &dc->chan;
+	dc->controller.num_chans = 1;
+	dc->controller.txdone_irq = true;
+	dc->controller.of_xlate = apple_dockchannel_of_xlate;
+
+	ret = devm_mbox_controller_register(dev, &dc->controller);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to register mailbox\n");
+
+	return 0;
+}
+
+static const struct of_device_id apple_dockchannel_of_match[] = {
+	{ .compatible = "apple,t8122-dockchannel" },
+	{ .compatible = "apple,t8112-dockchannel" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, apple_dockchannel_of_match);
+
+static struct platform_driver apple_dockchannel_driver = {
+	.driver = {
+		.name = "apple-dockchannel",
+		.of_match_table = apple_dockchannel_of_match,
+	},
+	.probe = apple_dockchannel_probe,
+};
+module_platform_driver(apple_dockchannel_driver);
+
+MODULE_DESCRIPTION("Apple DockChannel mailbox controller");
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
+MODULE_AUTHOR("Michael Reeves <michael.reeves077@gmail.com>");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/include/linux/mailbox/apple-dockchannel.h b/include/linux/mailbox/apple-dockchannel.h
new file mode 100644
index 000000000000..04d2fc44f12f
--- /dev/null
+++ b/include/linux/mailbox/apple-dockchannel.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Apple DockChannel mailbox message format.
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#ifndef _LINUX_MAILBOX_APPLE_DOCKCHANNEL_H_
+#define _LINUX_MAILBOX_APPLE_DOCKCHANNEL_H_
+
+#include <linux/types.h>
+
+/**
+ * struct apple_dockchannel_msg - DockChannel mailbox payload
+ * @data: Pointer to the byte stream payload
+ * @len: Number of payload bytes
+ *
+ * For TX, @data must remain valid until mbox_send_message() completes or the
+ * client receives tx_done in non-blocking mode.
+ *
+ * For RX, @data is owned by the controller and is valid only for the duration
+ * of the rx_callback.
+ */
+struct apple_dockchannel_msg {
+	void *data;
+	size_t len;
+};
+
+#endif /* _LINUX_MAILBOX_APPLE_DOCKCHANNEL_H_ */

-- 
2.51.2




^ permalink raw reply related

* Re: [PATCH v2 0/9] vDSO: Respect COMPAT_32BIT_TIME
From: Arnd Bergmann @ 2026-06-30 13:16 UTC (permalink / raw)
  To: Thomas Weißschuh, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Russell King, Catalin Marinas, Will Deacon, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy,
	Thomas Bogendoerfer, Vincenzo Frascino, John Stultz, Stephen Boyd,
	David S . Miller, Andreas Larsson
  Cc: linux-kernel, linux-arm-kernel, linuxppc-dev, linux-mips,
	linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

On Tue, Jun 30, 2026, at 09:38, Thomas Weißschuh wrote:
> If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
> provide any 32-bit time related functionality. This is the intended
> effect of the kconfig option and also the fallback system calls would
> also not be implemented.
>
> Currently the kconfig option does not affect the gettimeofday() syscall,
> so also keep that in the vDSO.
>
> I also tried to introduce some helpers to avoid much of the ifdeffery,
> but due to the high variance in the architecture-specific glue code
> these would need to handle they ended up being worse than the current
> proposal.
>
> As a side-effect this will make the self-tests more reliable,
> as there is now always a matching syscall available for each vDSO function.
>
> clock_gettime_time64() was only introduced in v6.19, so libc implementations

   ^ clock_getres_time64()

> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
> ---

Reviewed-by: Arnd Bergmann <arnd@arndb.de>

once we have consensus on my patch 1/9 comment. Thanks for
continuing this work!

      Arnd


^ permalink raw reply

* Re: [PATCH v4 1/4] dt-bindings: gpio: realtek: Add realtek,rtd1625-gpio
From: Linus Walleij @ 2026-06-30 13:17 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: brgl, robh, krzk+dt, conor+dt, afaerber, mwalle,
	andriy.shevchenko, tychang, linux-gpio, devicetree, linux-kernel,
	linux-arm-kernel, linux-realtek-soc, cy.huang, stanley_chang,
	james.tai, Krzysztof Kozlowski
In-Reply-To: <20260622092335.1166876-2-eleanor.lin@realtek.com>

Hi Yu-Chun,

thanks for your patch!

On Mon, Jun 22, 2026 at 10:33 AM Yu-Chun Lin <eleanor.lin@realtek.com> wrote:

> From: Tzuyi Chang <tychang@realtek.com>
>
> Add the device tree bindings for the Realtek DHC (Digital Home Center)
> RTD1625 GPIO controllers.
>
> The RTD1625 GPIO controller features a per-pin register architecture
> that differs significantly from previous generations. It utilizes
> separate register blocks for GPIO configuration and interrupt control.
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Tzuyi Chang <tychang@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
(...)

> +  interrupt-controller: true
> +
> +  "#interrupt-cells":
> +    const: 2
> +
> +  gpio-ranges: true
> +
> +  gpio-controller: true
> +
> +  "#gpio-cells":
> +    const: 2

After looking at the driver I must challenge this binding.

Your driver is full of (offset % 32) and even (offset % 32) *4 to just
work around the fact that the hardware inherently has 32-pin banks.

Instead of using twocell GPIO and irqs, just use threecell, interrupt-cells
and gpio-cells 3.

First cell is bank, second cell is offset inside each bank.

For Linux specifically there are helpers for dealing with this in gpiolib,
and further you will be able to use the GPIO_GENERIC library,
while this is beside the point for the binding itself.

Yours,
Linus Walleij


^ permalink raw reply

* Re: [PATCH rc v7 0/7] iommu/arm-smmu-v3: Fix device crash on kdump kernel
From: Mostafa Saleh @ 2026-06-30 13:17 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jgg, joro, praan, kees, baolu.lu, kevin.tian,
	miko.lenczewski, linux-arm-kernel, iommu, linux-kernel, stable,
	jamien
In-Reply-To: <cover.1782799827.git.nicolinc@nvidia.com>

On Mon, Jun 29, 2026 at 11:15:33PM -0700, Nicolin Chen wrote:
> When transitioning to a kdump kernel, the primary kernel might have crashed
> while endpoint devices were actively bus-mastering DMA. Currently, the SMMU
> driver aggressively resets the hardware during probe by clearing CR0_SMMUEN
> and setting the Global Bypass Attribute (GBPA) to ABORT.
> 
> In a kdump scenario, this aggressive reset is highly destructive:
> a) If GBPA is set to ABORT, in-flight DMA will be aborted, generating fatal
>    PCIe AER or SErrors that may panic the kdump kernel

Can you please clarify more on those errors, what conditions will
trigger that?
For example, patch 4 disables the EVTQ to avoid events as there might
be a lot, why are they not fatal also?

> b) If GBPA is set to BYPASS, in-flight DMA targeting some IOVAs will bypass
>    the SMMU and corrupt the physical memory at those 1:1 mapped IOVAs.
> 
> To safely absorb in-flight DMA, the kdump kernel must leave SMMUEN=1 intact
> and avoid modifying STRTAB_BASE. This allows HW to continue translating in-
> flight DMA using the crashed kernel's page tables until the endpoint device
> drivers probe and quiesce their respective hardware.
> 
> However, the ARM SMMUv3 architecture specification states that updating the
> SMMU_STRTAB_BASE register while SMMUEN == 1 is UNPREDICTABLE or ignored.
> 
> This leaves a kdump kernel no choice but to adopt the stream table from the
> crashed kernel.

In many cases the patches assume that the CDs/STE might be corrupted,
but still attempt to retrieve them with some validation
(log2size/split...)
However, the base address might be broken, TLBs state is unknown...

IMO, although that might improve the status quo, there are still
heuristics, in addition to noticeable complexity to transition the
stream tables. I wonder if FW can deal with AER in that case before
booting the kdump kernel.

Thanks,
Mostafa

> 
> In this series:
>  - Introduce an ARM_SMMU_OPT_KDUMP_ADOPT
>  - Skip SMMUEN and STRTAB_BASE resets in arm_smmu_device_reset()
>  - Skip EVENTQ/PRIQ setup including interrupts and their handlers
>  - Memremap the crashed kernel's stream tables into the kdump kernel [*]
>  - Defer any default domain attachment to retain STEs until device drivers
>    explicitly request it.
> 
> [*] For verification reasons, this series only fixes coherent SMMUs.
> 
> For non-ARM_SMMU_OPT_KDUMP_ADOPT cases, keep a status quo since the commit
> 3f54c447df34f ("iommu/arm-smmu-v3: Don't disable SMMU in kdump kernel"):
> full reset followed by driver-initiated reattach, potentially rejecting any
> in-flight DMA.
> 
> Note that the series requires Jason's work that was merged in v6.12: commit
> 85196f54743d ("iommu/arm-smmu-v3: Reorganize struct arm_smmu_strtab_cfg").
> I have a backported version that is verified with a v6.8 kernel. I can send
> if we see a strong need after this version is accepted.
> 
> This is on Github:
> https://github.com/nicolinc/iommufd/commits/smmuv3_kdump-v7
> 
> Changelog
> v7
>  * Rebase v7.2-rc1
>  * Add Reviewed-by from Pranjal
>  * Reword the linear stream table adoption comment
>  * Use dev_dbg for the stream table adoption message
>  * Document why the lazy L2 adoption uses devm_memremap()
>  * Drop redundant FEAT_COHERENCY checks in the adopt functions
>  * Use feature bit instead of STRTAB_BASE_CFG in adopt cleanup
>  * Skip CR0_ATSCHK update in adopt mode to retain the crashed policy
>  * Restore FEAT_2_LVL_STRTAB if the cleanup action fails to register
> v6
>  https://lore.kernel.org/all/cover.1779265413.git.nicolinc@nvidia.com/
>  * Rebase v7.1-rc3
>  * Add Reviewed-by from Jason
>  * Replace dma_addr_t with phys_addr_t
>  * Drop arm_smmu_kdump_phys_is_corrupted()
>  * Skip threaded IRQ handlers for EVTQ and PRIQ
>  * Bypass arm_smmu_rmr_install_bypass_ste() in kdump case
>  * Drop devm_ for adopt-time allocations; set up cleanup function via
>    devm_add_action_or_reset()
> v5
>  https://lore.kernel.org/all/cover.1778416609.git.nicolinc@nvidia.com/
>  * Add Reviewed-by from Kevin
>  * Drop READ_ONCE on lazy-attach L1 read
>  * Split "Skip EVTQ/PRIQ setup" into two patches
>  * Tighten kdump probe comment and dev_warn message
>  * Use MEM + BUSY in arm_smmu_kdump_phys_is_corrupted
> v4
>  https://lore.kernel.org/all/cover.1777446969.git.nicolinc@nvidia.com/
>  * Rebase v7.1-rc1
>  * s/arm_smmu_adopt/arm_smmu_kdump_adopt
>  * Revert alloc/memremap/fmt on fallback
>  * Reorder patches to avoid bisect regression
>  * Use IRQ_NONE for spurious evtq/priq entries
>  * Cap linear log2size by kdump's allocation bound
>  * Defer clearing FEAT_2_LVL_STRTAB on linear adopt
>  * Add arm_smmu_kdump_phys_is_corrupted() validation
>  * Defer l2 stream table memremap till master inserts
>  * Re-validate L1 desc on master insert with READ_ONCE
> v3
>  https://lore.kernel.org/all/cover.1777150307.git.nicolinc@nvidia.com/
>  * s/OPT_KDUMP/OPT_KDUMP_ADOPT
>  * Do not adopt if GERROR_SFM_ERR
>  * Retain CR0_ATSCHK beside CR0_SMMUEN
>  * Clear latched GERROR bits (e.g. CMDQ_ERR)
>  * Assert ARM_SMMU_FEAT_COHERENCY in adopt functions
>  * Add STE.Cfg check in arm_smmu_is_attach_deferred()
>  * Fix validations on return codes from devm_memremap()
>  * Sanitize crashed kernel register values in adopt functions
>  * Drop unnecessary l2ptrs guard in arm_smmu_is_attach_deferred()
>  * Don't enable PRIQ/EVTQ irqs and guard the irq functions for combined
>    irq cases
> v2
>  https://lore.kernel.org/all/cover.1776286352.git.nicolinc@nvidia.com/
>  * Add warning in non-coherent SMMU cases
>  * Keep eventq/priq disabled vs. enabling-and-disabling-later
>  * Check KDUMP option in the beginning of arm_smmu_device_reset()
>  * Validate STRTAB format matches HW capability instead of forcing flags
> v1:
>  https://lore.kernel.org/all/cover.1775763475.git.nicolinc@nvidia.com/
> 
> Nicolin Chen (7):
>   iommu/arm-smmu-v3: Add arm_smmu_kdump_adopt_strtab() for kdump
>   iommu/arm-smmu-v3: Implement is_attach_deferred() for kdump
>   iommu/arm-smmu-v3: Do not enable EVTQ/PRIQ interrupts in kdump kernel
>   iommu/arm-smmu-v3: Skip EVTQ/PRIQ setup in kdump kernel
>   iommu/arm-smmu-v3: Retain CR0_SMMUEN during kdump device reset
>   iommu/arm-smmu-v3: Skip RMR bypass for kdump adoption
>   iommu/arm-smmu-v3: Detect ARM_SMMU_OPT_KDUMP_ADOPT in probe()
> 
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |   1 +
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 467 ++++++++++++++++++--
>  2 files changed, 422 insertions(+), 46 deletions(-)
> 
> -- 
> 2.43.0
> 


^ permalink raw reply

* Re: [PATCH v3 2/7] gpio: regmap: add gpio_regmap_get_gpiochip() accessor
From: Linus Walleij @ 2026-06-30 13:21 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Michael Walle, Bartosz Golaszewski, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, afaerber@suse.com,
	wbg@kernel.org, mathieu.dubois-briand@bootlin.com,
	lars@metafoo.de, Michael.Hennerich@analog.com, jic23@kernel.org,
	nuno.sa@analog.com, andy@kernel.org, dlechner@baylibre.com,
	TY_Chang[張子逸], linux-gpio@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-realtek-soc@lists.infradead.org, linux-iio@vger.kernel.org,
	CY_Huang[黃鉦晏],
	Stanley Chang[昌育德],
	James Tai [戴志峰],
	Yu-Chun Lin [林祐君]
In-Reply-To: <ajkP4DHN4JPjr6yb@ashevche-desk.local>

On Mon, Jun 22, 2026 at 11:35 AM Andy Shevchenko
<andriy.shevchenko@intel.com> wrote:

> So, when we instantiate our own domain in regmap GPIO, we should have those
> callbacks be defined somewhere?

Domains are just translators, but if you create an irq chip it should
ideally have these callbacks.

Yours,
Linus Walleij


^ permalink raw reply

* Re: [PATCH 08/10] HID: apple: Add DockChannel HID transport driver
From: Yureka Lilian @ 2026-06-30 13:21 UTC (permalink / raw)
  To: michael.reeves077, Sven Peter, Janne Grunau, Neal Gompa,
	Jassi Brar, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Hector Martin, Joerg Roedel (AMD), Will Deacon, Robin Murphy,
	Dmitry Torokhov, Jiri Kosina, Benjamin Tissoires
  Cc: asahi, linux-arm-kernel, linux-kernel, devicetree, iommu,
	linux-input
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-8-506d936a1707@gmail.com>

On 6/30/26 14:54, Michael Reeves via B4 Relay wrote:
> From: Michael Reeves <michael.reeves077@gmail.com>
>
> Apple MTP exposes internal keyboard and trackpad interfaces over a HID
> transport carried by DockChannel.
>
> Add a transport driver that boots the MTP RTKit coprocessor, exchanges
> HID packets through the DockChannel mailbox, and registers child HID
> interfaces from devicetree.
>
> Co-developed-by: Hector Martin <marcan@marcan.st>
> Signed-off-by: Hector Martin <marcan@marcan.st>
> Signed-off-by: Michael Reeves <michael.reeves077@gmail.com>
> ---
>   MAINTAINERS                         |    1 +
>   drivers/hid/Kconfig                 |    2 +
>   drivers/hid/Makefile                |    2 +
>   drivers/hid/dockchannel/Kconfig     |   15 +
>   drivers/hid/dockchannel/Makefile    |    3 +
>   drivers/hid/dockchannel/apple-hid.c | 1130 +++++++++++++++++++++++++++++++++++
>   6 files changed, 1153 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ed68452c0ad6..0063276f0349 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2620,6 +2620,7 @@ F:	drivers/clk/clk-apple-nco.c
>   F:	drivers/cpufreq/apple-soc-cpufreq.c
>   F:	drivers/dma/apple-admac.c
>   F:	drivers/gpio/gpio-macsmc.c
> +F:	drivers/hid/dockchannel/
>   F:	drivers/hwmon/macsmc-hwmon.c
>   F:	drivers/pmdomain/apple/
>   F:	drivers/i2c/busses/i2c-pasemi-core.c
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index f9bcaeb66385..f27cda601ede 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -1488,6 +1488,8 @@ source "drivers/hid/surface-hid/Kconfig"
>   
>   source "drivers/hid/intel-thc-hid/Kconfig"
>   
> +source "drivers/hid/dockchannel/Kconfig"
> +
>   endif # HID
>   
>   # USB support may be used with HID disabled
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 23e6e3dd0c56..c9b4b1aff247 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -182,3 +182,5 @@ obj-$(CONFIG_AMD_SFH_HID)       += amd-sfh-hid/
>   obj-$(CONFIG_SURFACE_HID_CORE)  += surface-hid/
>   
>   obj-$(CONFIG_INTEL_THC_HID)     += intel-thc-hid/
> +
> +obj-$(CONFIG_APPLE_DOCKCHANNEL_HID)	+= dockchannel/
> diff --git a/drivers/hid/dockchannel/Kconfig b/drivers/hid/dockchannel/Kconfig
> new file mode 100644
> index 000000000000..fca09ef74403
> --- /dev/null
> +++ b/drivers/hid/dockchannel/Kconfig
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR MIT
> +
> +config APPLE_DOCKCHANNEL_HID
> +	tristate "HID over Apple DockChannel"
> +	depends on APPLE_DOCKCHANNEL
> +	depends on APPLE_RTKIT
> +	depends on HID
> +	depends on INPUT
> +	depends on OF
> +	help
> +	  This provides a HID transport layer over the Apple DockChannel
> +	  mailbox interface. It is required to support the internal keyboard
> +	  and trackpad on M2 and later MacBook models.
> +
> +	  Say Y here if you have an M2 or later Apple MacBook.
> diff --git a/drivers/hid/dockchannel/Makefile b/drivers/hid/dockchannel/Makefile
> new file mode 100644
> index 000000000000..d1a82aa57a69
> --- /dev/null
> +++ b/drivers/hid/dockchannel/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR MIT
> +
> +obj-$(CONFIG_APPLE_DOCKCHANNEL_HID)	+= apple-hid.o
> diff --git a/drivers/hid/dockchannel/apple-hid.c b/drivers/hid/dockchannel/apple-hid.c
> new file mode 100644
> index 000000000000..162fcfb5ab1c
> --- /dev/null
> +++ b/drivers/hid/dockchannel/apple-hid.c
> @@ -0,0 +1,1130 @@
> +// SPDX-License-Identifier: GPL-2.0-only OR MIT
> +/*
> + * Apple DockChannel HID transport driver
> + *
> + * Copyright The Asahi Linux Contributors
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/completion.h>
> +#include <linux/ctype.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/hid.h>
> +#include <linux/mailbox/apple-dockchannel.h>
> +#include <linux/mailbox_client.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/slab.h>
> +#include <linux/soc/apple/rtkit.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
> +#include <linux/unaligned.h>
> +#include <linux/workqueue.h>
> +
> +#define APPLE_ASC_CPU_CONTROL		0x44
> +#define APPLE_ASC_CPU_CONTROL_RUN	BIT(4)
> +
> +#define COMMAND_TIMEOUT_MS	1000
> +#define START_TIMEOUT_MS	2000
> +
> +#define MAX_INTERFACES		16
> +
> +#define DCHID_MAX_PAYLOAD	0xffff
> +#define DCHID_CHECKSUM_LEN	4
> +#define DCHID_RX_BUF_SIZE	(sizeof(struct dchid_hdr) + DCHID_MAX_PAYLOAD + \
> +				 DCHID_CHECKSUM_LEN)
> +
> +#define DCHID_CHANNEL_CMD	0x11
> +#define DCHID_CHANNEL_REPORT	0x12
> +#define DCHID_CHECKSUM_SEED	0xffffffff
> +
> +struct dchid_hdr {
> +	u8 hdr_len;
> +	u8 channel;
> +	__le16 length;
> +	u8 seq;
> +	u8 iface;
> +	__le16 pad;
> +} __packed;
> +
> +#define IFACE_COMM	0
> +
> +#define FLAGS_GROUP	GENMASK(7, 6)
> +#define FLAGS_REQ	GENMASK(5, 0)
> +
> +#define REQ_SET_REPORT	0
> +#define REQ_GET_REPORT	1
> +
> +struct dchid_subhdr {
> +	u8 flags;
> +	u8 unk;
> +	__le16 length;
> +	__le32 retcode;
> +} __packed;
> +
> +#define EVENT_INIT	0xf0
> +#define EVENT_READY	0xf1
> +
> +struct dchid_init_hdr {
> +	u8 type;
> +	u8 unk1;
> +	u8 unk2;
> +	u8 iface;
> +	char name[16];
> +	u8 more_packets;
> +	u8 unkpad;
> +} __packed;
> +
> +#define INIT_HID_DESCRIPTOR	0
> +#define INIT_TERMINATOR		2
> +#define INIT_PRODUCT_NAME	7
> +
> +#define CMD_RESET_INTERFACE	0x40
> +#define CMD_RESET_INTERFACE_SUB	1
> +#define CMD_ENABLE_INTERFACE	0xb4
> +
> +struct dchid_init_block_hdr {
> +	__le16 type;
> +	__le16 length;
> +} __packed;
> +
> +#define STM_REPORT_ID		0x10
> +#define STM_REPORT_SERIAL	0x11
> +
> +struct dchid_stm_id {
> +	u8 unk;
> +	__le16 vendor_id;
> +	__le16 product_id;
> +	__le16 version_number;
> +	u8 unk2;
> +	u8 unk3;
> +	u8 keyboard_type;
> +	u8 serial_length;
> +	/* Serial follows, but we grab it with a different report. */
> +} __packed;
> +
> +struct dchid_work {
> +	struct work_struct work;
> +	struct dchid_iface *iface;
> +
> +	struct dchid_hdr hdr;
> +	u8 data[];
> +};
> +
> +struct dchid_iface {
> +	struct dchid_dev *dchid;
> +	struct hid_device *hid;
> +	struct workqueue_struct *wq;
> +
> +	bool creating;
> +	struct work_struct create_work;
> +
> +	int index;
> +	const char *name;
> +	struct fwnode_handle *fwnode;
> +
> +	u8 tx_seq;
> +	bool deferred;
> +	bool starting;
> +	bool open;
> +	struct completion ready;
> +
> +	void *hid_desc;
> +	size_t hid_desc_len;
> +
> +	/* Lock for command submission state below */
> +	spinlock_t out_lock;
> +	u32 out_flags;
> +	int out_report;
> +	u32 retcode;
> +	void *resp_buf;
> +	size_t resp_size;
> +	struct completion out_complete;
> +};
> +
> +struct dchid_dev {
> +	struct device *dev;
> +	struct mbox_client dc_mbox_client;
> +	struct mbox_chan *dc_mbox;
> +
> +	struct apple_rtkit *rtk;
> +	void __iomem *asc_base;
> +	void __iomem *sram_base;
> +	struct resource sram_res;
> +
> +	bool id_ready;
> +	struct dchid_stm_id device_id;
> +	char serial[64];
> +
> +	u8 *rx_buf;
> +	size_t rx_len;
> +
> +	struct dchid_iface *comm;
> +	struct mutex ifaces_lock; /* protects ifaces array */
> +	struct dchid_iface *ifaces[MAX_INTERFACES];
> +
> +	/* Workqueue to asynchronously create HID devices */
> +	struct workqueue_struct *new_iface_wq;
> +};
> +
> +static void dchid_destroy_wq(void *data)
> +{
> +	struct workqueue_struct *wq = data;
> +
> +	destroy_workqueue(wq);
> +}
> +
> +static void dchid_fwnode_release(void *data)
> +{
> +	fwnode_handle_put(data);
> +}
> +
> +static void dchid_free_mbox(void *data)
> +{
> +	mbox_free_channel(data);
> +}
> +
> +static u32 dchid_checksum(const void *data, size_t len)
> +{
> +	const u8 *p = data;
> +	u32 sum = 0;
> +	int i;
> +
> +	while (len >= sizeof(u32)) {
> +		sum += get_unaligned_le32(p);
> +		p += sizeof(u32);
> +		len -= sizeof(u32);
> +	}
> +
> +	if (len) {
> +		u32 tmp = 0;
> +
> +		for (i = 0; i < len; i++)
> +			tmp |= p[i] << (i * 8);
> +		sum += tmp;
> +	}
> +
> +	return sum;
> +}
> +
> +static struct dchid_iface *
> +dchid_get_interface(struct dchid_dev *dchid, int index, const char *name)
> +{
> +	struct dchid_iface *iface;
> +	struct fwnode_handle *fwnode;
> +	int ret;
> +
> +	if (index >= MAX_INTERFACES) {
> +		dev_err(dchid->dev, "interface index %d out of range\n", index);
> +		return NULL;
> +	}
> +
> +	mutex_lock(&dchid->ifaces_lock);
> +	if (dchid->ifaces[index]) {
> +		iface = dchid->ifaces[index];
> +		mutex_unlock(&dchid->ifaces_lock);
> +		return iface;
> +	}
> +
> +	iface = devm_kzalloc(dchid->dev, sizeof(*iface), GFP_KERNEL);
> +	if (!iface) {
> +		mutex_unlock(&dchid->ifaces_lock);
> +		return NULL;
> +	}
> +
> +	iface->index = index;
> +	iface->name = devm_kstrdup(dchid->dev, name, GFP_KERNEL);
> +	if (!iface->name) {
> +		mutex_unlock(&dchid->ifaces_lock);
> +		return NULL;
> +	}
> +
> +	iface->dchid = dchid;
> +	iface->out_report = -1;
> +	init_completion(&iface->out_complete);
> +	init_completion(&iface->ready);
> +	spin_lock_init(&iface->out_lock);
> +
> +	iface->wq = alloc_ordered_workqueue("dchid-%s", 0, iface->name);
> +	if (!iface->wq) {
> +		mutex_unlock(&dchid->ifaces_lock);
> +		return NULL;
> +	}
> +
> +	ret = devm_add_action_or_reset(dchid->dev, dchid_destroy_wq, iface->wq);
> +	if (ret) {
> +		mutex_unlock(&dchid->ifaces_lock);
> +		return NULL;
> +	}
> +
> +	if (!strcmp(name, "comm")) {
> +		/* Comm is not a HID subdevice */
> +		dchid->ifaces[index] = iface;
> +		mutex_unlock(&dchid->ifaces_lock);
> +		return iface;
> +	}
> +
> +	fwnode = device_get_named_child_node(dchid->dev, name);
> +	if (fwnode) {
> +		iface->fwnode = fwnode;
> +		ret = devm_add_action_or_reset(dchid->dev, dchid_fwnode_release,
> +					       iface->fwnode);
> +		if (ret) {
> +			mutex_unlock(&dchid->ifaces_lock);
> +			return NULL;
> +		}
> +	} else {
> +		iface->fwnode = dev_fwnode(dchid->dev);
> +	}
> +
> +	dchid->ifaces[index] = iface;
> +	mutex_unlock(&dchid->ifaces_lock);
> +	return iface;
> +}
> +
> +static int dchid_send(struct dchid_iface *iface, u32 flags, const void *msg,
> +		      size_t size)
> +{
> +	struct dchid_dev *dchid = iface->dchid;
> +	size_t payload_padded = round_up(size, sizeof(u32));
> +	size_t total_len = sizeof(struct dchid_hdr) + sizeof(struct dchid_subhdr) +
> +			   payload_padded + DCHID_CHECKSUM_LEN;
> +	struct apple_dockchannel_msg dc_msg;
> +	struct dchid_hdr *hdr;
> +	struct dchid_subhdr *sub;
> +	u32 *checksum_ptr;
> +	u8 *buf;
> +	int ret;
> +
> +	if (total_len > DCHID_RX_BUF_SIZE)
> +		return -EINVAL;
> +
> +	buf = kzalloc(total_len, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	hdr = (struct dchid_hdr *)buf;
> +	sub = (struct dchid_subhdr *)(buf + sizeof(*hdr));
> +	checksum_ptr = (u32 *)(buf + total_len - DCHID_CHECKSUM_LEN);
> +
> +	hdr->hdr_len = sizeof(*hdr);
> +	hdr->channel = DCHID_CHANNEL_CMD;
> +	hdr->length = cpu_to_le16(payload_padded + sizeof(*sub));
> +	hdr->seq = iface->tx_seq;
> +	hdr->iface = iface->index;
> +
> +	sub->flags = (u8)flags;
> +	sub->length = cpu_to_le16(size);
> +
> +	memcpy(buf + sizeof(*hdr) + sizeof(*sub), msg, size);
> +
> +	*checksum_ptr = 0xffffffff - dchid_checksum(buf, total_len - DCHID_CHECKSUM_LEN);
> +
> +	dc_msg.data = buf;
> +	dc_msg.len = total_len;
> +	ret = mbox_send_message(dchid->dc_mbox, &dc_msg);
> +	kfree(buf);
> +
> +	return ret < 0 ? ret : 0;
> +}
> +
> +static int dchid_cmd(struct dchid_iface *iface, u32 type, u32 req,
> +		     void *data, size_t size, void *resp_buf, size_t resp_size)
> +{
> +	unsigned long flags;
> +	int ret;
> +	int report_id;
> +	bool timed_out = false;
> +	u32 out_flags;
> +
> +	if (size < 1)
> +		return -EINVAL;
> +
> +	report_id = *(u8 *)data;
> +	out_flags = FIELD_PREP(FLAGS_GROUP, type) | FIELD_PREP(FLAGS_REQ, req);
> +
> +	spin_lock_irqsave(&iface->out_lock, flags);
> +
> +	/* Only one command can be in flight per interface */
> +	if (WARN_ON(iface->out_report != -1)) {
> +		spin_unlock_irqrestore(&iface->out_lock, flags);
> +		return -EBUSY;
> +	}
> +
> +	iface->out_report = report_id;
> +	iface->out_flags = out_flags;
> +	iface->retcode = 0;
> +	iface->resp_buf = resp_buf;
> +	iface->resp_size = resp_size;
> +	reinit_completion(&iface->out_complete);
> +
> +	spin_unlock_irqrestore(&iface->out_lock, flags);
> +
> +	ret = dchid_send(iface, out_flags, data, size);
> +	if (ret < 0) {
> +		spin_lock_irqsave(&iface->out_lock, flags);
> +		iface->out_report = -1;
> +		iface->resp_buf = NULL;
> +		iface->resp_size = 0;
> +		spin_unlock_irqrestore(&iface->out_lock, flags);
> +		return ret;
> +	}
> +
> +	if (!wait_for_completion_timeout(&iface->out_complete,
> +					 msecs_to_jiffies(COMMAND_TIMEOUT_MS))) {
> +		dev_err(iface->dchid->dev, "command 0x%x to iface %d (%s) timed out\n",
> +			report_id, iface->index, iface->name);
> +		timed_out = true;
> +	}
> +
> +	spin_lock_irqsave(&iface->out_lock, flags);
> +
> +	if (timed_out && iface->out_report == report_id) {
> +		ret = -ETIMEDOUT;
> +	} else if (iface->retcode) {
> +		dev_err(iface->dchid->dev,
> +			"command 0x%x to iface %d (%s) failed with err 0x%x\n",
> +			report_id, iface->index, iface->name, iface->retcode);
> +		ret = -EIO;
> +	} else {
> +		ret = iface->resp_size;
> +	}
> +
> +	iface->tx_seq++;
> +	iface->out_report = -1;
> +	iface->resp_buf = NULL;
> +	iface->resp_size = 0;
> +	spin_unlock_irqrestore(&iface->out_lock, flags);
> +
> +	return ret;
> +}
> +
> +static int dchid_comm_cmd(struct dchid_dev *dchid, void *cmd, size_t size)
> +{
> +	return dchid_cmd(dchid->comm, HID_FEATURE_REPORT, REQ_SET_REPORT,
> +			 cmd, size, NULL, 0);
> +}
> +
> +static int dchid_enable_interface(struct dchid_iface *iface)
> +{
> +	u8 cmd[] = { CMD_ENABLE_INTERFACE, iface->index };
> +
> +	return dchid_comm_cmd(iface->dchid, cmd, sizeof(cmd));
> +}
> +
> +static int dchid_reset_interface(struct dchid_iface *iface, int state)
> +{
> +	u8 cmd[] = { CMD_RESET_INTERFACE, CMD_RESET_INTERFACE_SUB, iface->index,
> +		     (u8)state };
> +
> +	return dchid_comm_cmd(iface->dchid, cmd, sizeof(cmd));
> +}
> +
> +static int dchid_start_interface(struct dchid_iface *iface)
> +{
> +	if (iface->starting)
> +		return -EINPROGRESS;
> +
> +	dev_dbg(iface->dchid->dev, "starting interface %s\n", iface->name);
> +
> +	iface->starting = true;
> +	dchid_reset_interface(iface, 0);
> +	dchid_reset_interface(iface, 2);
> +
> +	return 0;
> +}
> +
> +static int dchid_start(struct hid_device *hdev)
> +{
> +	return 0;
> +}
> +
> +static int dchid_open(struct hid_device *hdev)
> +{
> +	struct dchid_iface *iface = hdev->driver_data;
> +	int ret;
> +
> +	if (!completion_done(&iface->ready)) {
> +		ret = dchid_start_interface(iface);
> +		if (ret < 0)
> +			return ret;
> +
> +		if (!wait_for_completion_timeout(&iface->ready,
> +						 msecs_to_jiffies(START_TIMEOUT_MS))) {
> +			dev_err(iface->dchid->dev, "iface %s start timed out\n",
> +				iface->name);
> +			return -ETIMEDOUT;
> +		}
> +	}
> +
> +	iface->open = true;
> +	return 0;
> +}
> +
> +static void dchid_close(struct hid_device *hdev)
> +{
> +	struct dchid_iface *iface = hdev->driver_data;
> +
> +	iface->open = false;
> +}
> +
> +static int dchid_parse(struct hid_device *hdev)
> +{
> +	struct dchid_iface *iface = hdev->driver_data;
> +
> +	return hid_parse_report(hdev, iface->hid_desc, iface->hid_desc_len);
> +}
> +
> +/* Note: buf excludes report number. */
> +static int dchid_get_report_cmd(struct dchid_iface *iface, u8 reportnum,
> +				void *buf, size_t len)
> +{
> +	int ret;
> +
> +	ret = dchid_cmd(iface, HID_FEATURE_REPORT, REQ_GET_REPORT, &reportnum, 1,
> +			buf, len);
> +
> +	return ret <= 0 ? ret : ret - 1;
> +}
> +
> +/* Note: buf includes report number. */
> +static int dchid_set_report(struct dchid_iface *iface, void *buf, size_t len)
> +{
> +	return dchid_cmd(iface, HID_OUTPUT_REPORT, REQ_SET_REPORT, buf, len,
> +			 NULL, 0);
> +}
> +
> +static int dchid_raw_request(struct hid_device *hdev, unsigned char reportnum,
> +			     __u8 *buf, size_t len, unsigned char rtype,
> +			     int reqtype)
> +{
> +	struct dchid_iface *iface = hdev->driver_data;
> +
> +	switch (reqtype) {
> +	case HID_REQ_GET_REPORT:
> +		if (len < 1)
> +			return -EINVAL;
> +
> +		buf[0] = reportnum;
> +		return dchid_cmd(iface, rtype, REQ_GET_REPORT, &reportnum, 1,
> +				 buf + 1, len - 1);
> +	case HID_REQ_SET_REPORT:
> +		return dchid_set_report(iface, buf, len);
> +	default:
> +		return -EIO;
> +	}
> +}
> +
> +static const struct hid_ll_driver dchid_ll = {
> +	.start = dchid_start,
> +	.open = dchid_open,
> +	.close = dchid_close,
> +	.parse = dchid_parse,
> +	.raw_request = dchid_raw_request,
> +};
> +
> +static void dchid_create_interface_work(struct work_struct *ws)
> +{
> +	struct dchid_iface *iface = container_of(ws, struct dchid_iface, create_work);
> +	struct dchid_dev *dchid = iface->dchid;
> +	struct hid_device *hid;
> +	char cap_name[16];
> +	int ret;
> +
> +	if (iface->hid) {
> +		dev_warn(dchid->dev, "interface %s already created\n", iface->name);
> +		goto done;
> +	}
> +
> +	ret = dchid_enable_interface(iface);
> +	if (ret < 0) {
> +		dev_warn(dchid->dev, "failed to enable %s: %d\n", iface->name, ret);
> +		goto done;
> +	}
> +
> +	iface->deferred = false;
> +
> +	hid = hid_allocate_device();
> +	if (IS_ERR(hid))
> +		goto done;
> +
> +	strscpy(cap_name, iface->name, sizeof(cap_name));
> +	if (cap_name[0])
> +		cap_name[0] = toupper(cap_name[0]);
> +	snprintf(hid->name, sizeof(hid->name), "Apple DockChannel %s", cap_name);
> +
> +	snprintf(hid->phys, sizeof(hid->phys), "%s.%d", dev_name(dchid->dev),
> +		 iface->index);
> +	strscpy(hid->uniq, dchid->serial, sizeof(hid->uniq));
If the keyboard appeared before stm, dchip->serial might be uninitialized.
> +
> +	hid->ll_driver = &dchid_ll;
> +	hid->bus = BUS_HOST;
> +	hid->vendor = le16_to_cpu(dchid->device_id.vendor_id);
> +	hid->product = le16_to_cpu(dchid->device_id.product_id);
> +	hid->version = le16_to_cpu(dchid->device_id.version_number);
> +	hid->type = HID_TYPE_OTHER;
> +	if (!strcmp(iface->name, "keyboard")) {
> +		u32 country_code;
> +
> +		hid->group = HID_GROUP_APPLE_DOCKCHANNEL;
> +
> +		/*
> +		 * The device provides no reliable way to get the keyboard
> +		 * country code, so board devicetrees provide it instead,
> +		 * filled by the bootloader.
> +		 */
> +		if (!fwnode_property_read_u32(iface->fwnode, "hid-country-code",
> +					      &country_code))
> +			hid->country = country_code;
> +	}
> +
> +	hid->dev.parent = iface->dchid->dev;
> +	hid->driver_data = iface;
> +	iface->hid = hid;
> +
> +	ret = hid_add_device(hid);
> +	if (ret < 0) {
> +		iface->hid = NULL;
> +		hid_destroy_device(hid);
> +		dev_warn(iface->dchid->dev, "failed to register HID device %s\n",
> +			 iface->name);
> +	}
> +
> +done:
> +	iface->creating = false;
> +}
> +
> +static int dchid_create_interface(struct dchid_iface *iface)
> +{
> +	if (iface->creating)
> +		return -EBUSY;
> +
> +	iface->creating = true;
> +	INIT_WORK(&iface->create_work, dchid_create_interface_work);
> +	return queue_work(iface->dchid->new_iface_wq, &iface->create_work);
> +}
> +
> +static void dchid_handle_descriptor(struct dchid_iface *iface, void *hid_desc,
> +				    size_t desc_len)
> +{
> +	u8 *rdesc;
> +	int i;
> +
> +	if (iface->hid)
> +		return;
> +
> +	rdesc = devm_kmemdup(iface->dchid->dev, hid_desc, desc_len,
> +			     GFP_KERNEL);
> +	if (!rdesc)
> +		return;
> +
> +	/* Fix up oversized report sizes in DockChannel report descriptors */
> +	if (desc_len >= 5) {
> +		for (i = 0; i <= (int)desc_len - 5; i++) {
> +			if (rdesc[i] == 0x76 && rdesc[i + 1] == 0x00 &&
> +			    rdesc[i + 2] == 0x40 && rdesc[i + 3] == 0x95) {
> +				u8 count = rdesc[i + 4];
> +
> +				if (count > 0 && count < 32) {
> +					dev_info(iface->dchid->dev,
> +						 "fixing up interface %s (%d) report size\n",
> +						 iface->name, iface->index);
> +					rdesc[i] = 0x75;
> +					rdesc[i + 1] = 0x08;
> +					rdesc[i + 2] = 0x96;
> +					rdesc[i + 3] = 0x00;
> +					rdesc[i + 4] = count * 8;
> +				}
> +			}
> +		}
> +	}
> +
> +	iface->hid_desc = rdesc;
> +	iface->hid_desc_len = desc_len;
> +}
> +
> +static void dchid_handle_ready(struct dchid_dev *dchid, void *data, size_t length)
> +{
> +	struct dchid_iface *iface;
> +	u8 *pkt = data;
> +	u8 index;
> +	int i;
> +	int ret;
> +
> +	if (length < 2)
> +		return;
> +
> +	index = pkt[1];
> +	if (index >= MAX_INTERFACES)
> +		return;
> +
> +	iface = dchid->ifaces[index];
> +	if (!iface)
> +		return;
> +
> +	dev_dbg(dchid->dev, "interface %s is now ready\n", iface->name);
> +	complete_all(&iface->ready);
> +
> +	/* When STM is ready, grab global device info */
> +	if (!strcmp(iface->name, "stm")) {
> +		ret = dchid_get_report_cmd(iface, STM_REPORT_ID, &dchid->device_id,
> +					   sizeof(dchid->device_id));
> +		if (ret < (int)sizeof(dchid->device_id)) {
> +			dev_warn(iface->dchid->dev, "failed to get device ID from STM\n");
> +			/* Fake it and keep going. Things might still work. */
> +			memset(&dchid->device_id, 0, sizeof(dchid->device_id));
> +		}
> +
> +		ret = dchid_get_report_cmd(iface, STM_REPORT_SERIAL, dchid->serial,
> +					   sizeof(dchid->serial) - 1);
> +		if (ret < 0) {
> +			dev_warn(iface->dchid->dev, "failed to get serial from STM\n");
> +			dchid->serial[0] = 0;
> +		}
> +
> +		dchid->id_ready = true;
> +		for (i = 0; i < MAX_INTERFACES; i++) {
> +			if (!dchid->ifaces[i] || !dchid->ifaces[i]->deferred)
> +				continue;
> +			dchid_create_interface(dchid->ifaces[i]);
> +		}
> +	}
> +}
> +
> +static void dchid_handle_init(struct dchid_dev *dchid, void *data, size_t length)
> +{
> +	struct dchid_init_hdr *hdr = data;
> +	struct dchid_init_block_hdr *blk;
> +	struct dchid_iface *iface;
> +	u8 *p = data;
> +
> +	if (length < sizeof(*hdr))
> +		return;
> +
> +	iface = dchid_get_interface(dchid, hdr->iface, hdr->name);
> +	if (!iface)
> +		return;
> +
> +	p += sizeof(*hdr);
> +	length -= sizeof(*hdr);
> +
> +	while (length >= sizeof(*blk)) {
> +		u16 blk_len;
> +
> +		blk = (struct dchid_init_block_hdr *)p;
> +		p += sizeof(*blk);
> +		length -= sizeof(*blk);
> +
> +		blk_len = le16_to_cpu(blk->length);
> +		if (blk_len > length)
> +			break;
> +
> +		switch (le16_to_cpu(blk->type)) {
> +		case INIT_HID_DESCRIPTOR:
> +			dchid_handle_descriptor(iface, p, blk_len);
> +			break;
> +		case INIT_PRODUCT_NAME:
> +			if (blk_len > 0 && p[blk_len - 1] != 0)
> +				dev_warn(dchid->dev, "unterminated product name for %s\n",
> +					 iface->name);
> +			break;
> +		}
> +
> +		p += blk_len;
> +		length -= blk_len;
> +
> +		if (le16_to_cpu(blk->type) == INIT_TERMINATOR)
> +			break;
> +	}
> +
> +	if (hdr->more_packets)
> +		return;
> +
> +	/*
> +	 * Prefer to enable STM first, since it provides device IDs. Some
> +	 * firmware versions do not expose STM, so let the keyboard start
> +	 * without it.
> +	 */
> +	if (iface->dchid->id_ready || !strcmp(iface->name, "stm") ||
> +	    !strcmp(iface->name, "keyboard"))

I specifically asked for a mechanism to let the keyboard probe even on 
devices which do not expose/have stm. Thanks for adding that!
However, I think this might need some more sophisticated mechanism to 
decide whether the stm is still going to appear after the keyboard, or 
not at all. I'm not sure if there is a way to tell this at this point, 
or we need to add a timeout for the stm to appearing, which needs to 
expire before we create the other interfaces with fake serials.

> +		dchid_create_interface(iface);
> +	else
> +		iface->deferred = true;
> +}
> +
> +static void dchid_handle_event(struct dchid_dev *dchid, void *data, size_t length)
> +{
> +	u8 *p = data;
> +
> +	if (!length)
> +		return;
> +
> +	switch (*p) {
> +	case EVENT_INIT:
> +		dchid_handle_init(dchid, data, length);
> +		break;
> +	case EVENT_READY:
> +		dchid_handle_ready(dchid, data, length);
> +		break;
> +	}
> +}
> +
> +static void dchid_handle_report(struct dchid_iface *iface, void *data, size_t length)
> +{
> +	if (!iface->hid || !iface->open)
> +		return;
> +
> +	hid_input_report(iface->hid, HID_INPUT_REPORT, data, length, 1);
> +}
> +
> +static void dchid_packet_work(struct work_struct *ws)
> +{
> +	struct dchid_work *work = container_of(ws, struct dchid_work, work);
> +	struct dchid_subhdr *shdr = (void *)work->data;
> +	struct dchid_dev *dchid = work->iface->dchid;
> +	u16 hdr_len = le16_to_cpu(work->hdr.length);
> +	u16 sub_len;
> +	int type;
> +	u8 *payload;
> +
> +	if (hdr_len < sizeof(*shdr)) {
> +		dev_err(dchid->dev, "bad subheader length\n");
> +		goto done;
> +	}
> +
> +	sub_len = le16_to_cpu(shdr->length);
> +	if (sub_len > hdr_len - sizeof(*shdr)) {
> +		dev_err(dchid->dev, "bad subheader length\n");
> +		goto done;
> +	}
> +
> +	type = FIELD_GET(FLAGS_GROUP, shdr->flags);
> +	payload = work->data + sizeof(*shdr);
> +
> +	switch (type) {
> +	case HID_INPUT_REPORT:
> +		if (work->hdr.iface == IFACE_COMM)
> +			dchid_handle_event(dchid, payload, sub_len);
> +		else
> +			dchid_handle_report(work->iface, payload, sub_len);
> +		break;
> +	}
> +
> +done:
> +	kfree(work);
> +}
> +
> +static void dchid_handle_ack(struct dchid_iface *iface, struct dchid_hdr *hdr,
> +			     void *data)
> +{
> +	struct dchid_subhdr *shdr = data;
> +	u8 *payload = data + sizeof(*shdr);
> +	u16 hdr_len = le16_to_cpu(hdr->length);
> +	u16 sub_len = le16_to_cpu(shdr->length);
> +	unsigned long flags;
> +	bool complete_cmd = false;
> +
> +	if (hdr_len < sizeof(*shdr) || sub_len > hdr_len - sizeof(*shdr) ||
> +	    sub_len < 1)
> +		return;
> +
> +	spin_lock_irqsave(&iface->out_lock, flags);
> +
> +	if (shdr->flags == iface->out_flags && iface->tx_seq == hdr->seq &&
> +	    iface->out_report == payload[0]) {
> +		if (iface->resp_buf && iface->resp_size)
> +			memcpy(iface->resp_buf, payload + 1,
> +			       min_t(size_t, sub_len - 1, iface->resp_size));
> +
> +		iface->resp_size = sub_len;
> +		iface->out_report = -1;
> +		iface->retcode = le32_to_cpu(shdr->retcode);
> +		complete_cmd = true;
> +	}
> +
> +	spin_unlock_irqrestore(&iface->out_lock, flags);
> +
> +	if (complete_cmd)
> +		complete(&iface->out_complete);
> +}
> +
> +static void dchid_process_packet(struct dchid_dev *dchid, struct dchid_hdr *hdr,
> +				 u8 *payload, size_t payload_len, u8 *packet,
> +				 size_t packet_len)
> +{
> +	struct dchid_work *work;
> +
> +	if (dchid_checksum(packet, packet_len) != DCHID_CHECKSUM_SEED) {
> +		dev_err_ratelimited(dchid->dev, "checksum error\n");
> +		return;
> +	}
> +
> +	if (payload_len < sizeof(struct dchid_subhdr))
> +		return;
> +
> +	if (hdr->iface >= MAX_INTERFACES || !dchid->ifaces[hdr->iface])
> +		return;
> +
> +	if (hdr->channel == DCHID_CHANNEL_CMD) {
> +		dchid_handle_ack(dchid->ifaces[hdr->iface], hdr, payload);
> +		return;
> +	}
> +
> +	if (hdr->channel != DCHID_CHANNEL_REPORT)
> +		return;
> +
> +	work = kzalloc(sizeof(*work) + payload_len, GFP_ATOMIC);
> +	if (!work)
> +		return;
> +
> +	work->hdr = *hdr;
> +	work->iface = dchid->ifaces[hdr->iface];
> +	memcpy(work->data, payload, payload_len);
> +	INIT_WORK(&work->work, dchid_packet_work);
> +
> +	queue_work(work->iface->wq, &work->work);
> +}
> +
> +static void dchid_consume_rx(struct dchid_dev *dchid)
> +{
> +	while (dchid->rx_len >= sizeof(struct dchid_hdr)) {
> +		struct dchid_hdr *hdr = (struct dchid_hdr *)dchid->rx_buf;
> +		size_t payload_len;
> +		size_t packet_len;
> +
> +		if (hdr->hdr_len != sizeof(*hdr)) {
> +			dev_err_ratelimited(dchid->dev, "bad header length %u\n",
> +					    hdr->hdr_len);
> +			dchid->rx_len = 0;
> +			return;
> +		}
> +
> +		payload_len = le16_to_cpu(hdr->length);
> +		packet_len = sizeof(*hdr) + payload_len + DCHID_CHECKSUM_LEN;
> +		if (packet_len > DCHID_RX_BUF_SIZE) {
> +			dev_err_ratelimited(dchid->dev, "oversized packet %zu\n",
> +					    packet_len);
> +			dchid->rx_len = 0;
> +			return;
> +		}
> +
> +		if (dchid->rx_len < packet_len)
> +			return;
> +
> +		dchid_process_packet(dchid, hdr, dchid->rx_buf + sizeof(*hdr),
> +				     payload_len, dchid->rx_buf, packet_len);
> +
> +		dchid->rx_len -= packet_len;
> +		memmove(dchid->rx_buf, dchid->rx_buf + packet_len, dchid->rx_len);
> +	}
> +}
> +
> +static void dchid_rx_callback(struct mbox_client *cl, void *mssg)
> +{
> +	struct dchid_dev *dchid = container_of(cl, struct dchid_dev, dc_mbox_client);
> +	struct apple_dockchannel_msg *msg = mssg;
> +
> +	if (!msg || !msg->data || !msg->len)
> +		return;
> +
> +	if (msg->len > DCHID_RX_BUF_SIZE - dchid->rx_len) {
> +		dev_err_ratelimited(dchid->dev, "RX buffer overflow\n");
> +		dchid->rx_len = 0;
> +		return;
> +	}
> +
> +	memcpy(dchid->rx_buf + dchid->rx_len, msg->data, msg->len);
> +	dchid->rx_len += msg->len;
> +
> +	dchid_consume_rx(dchid);
> +}
> +
> +static int dchid_rtkit_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr)
> +{
> +	struct dchid_dev *dchid = cookie;
> +	struct resource res = {
> +		.start = bfr->iova,
> +		.end = bfr->iova + bfr->size - 1,
> +		.name = "rtkit_map",
> +	};
> +
> +	if (!bfr->iova) {
> +		bfr->buffer = dma_alloc_coherent(dchid->dev, bfr->size,
> +						 &bfr->iova, GFP_KERNEL);
> +		if (!bfr->buffer)
> +			return -ENOMEM;
> +		return 0;
> +	}
> +
> +	if (!dchid->sram_res.start)
> +		return -EFAULT;
> +
> +	res.flags = dchid->sram_res.flags;
> +	if (res.end < res.start || !resource_contains(&dchid->sram_res, &res))
> +		return -EFAULT;
> +
> +	bfr->iomem = dchid->sram_base + (res.start - dchid->sram_res.start);
> +	bfr->is_mapped = true;
> +
> +	return 0;
> +}
> +
> +static void dchid_rtkit_shmem_destroy(void *cookie, struct apple_rtkit_shmem *bfr)
> +{
> +	struct dchid_dev *dchid = cookie;
> +
> +	if (bfr->buffer)
> +		dma_free_coherent(dchid->dev, bfr->size, bfr->buffer, bfr->iova);
> +}
> +
> +static const struct apple_rtkit_ops dchid_rtkit_ops = {
> +	.shmem_setup = dchid_rtkit_shmem_setup,
> +	.shmem_destroy = dchid_rtkit_shmem_destroy,
> +};
> +
> +static int dchid_map_helper_cpu(struct platform_device *pdev, struct dchid_dev *dchid)
> +{
> +	struct resource *res;
> +
> +	dchid->asc_base = devm_platform_ioremap_resource_byname(pdev, "coproc-asc");
> +	if (IS_ERR(dchid->asc_base))
> +		return PTR_ERR(dchid->asc_base);
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "coproc-sram");
> +	if (!res)
> +		return -EINVAL;
> +
> +	dchid->sram_res = *res;
> +
> +	dchid->sram_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(dchid->sram_base))
> +		return PTR_ERR(dchid->sram_base);
> +
> +	return 0;
> +}
> +
> +static int dchid_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct dchid_dev *dchid;
> +	int ret;
> +
> +	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(44));
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to set DMA mask\n");
> +
> +	dchid = devm_kzalloc(dev, sizeof(*dchid), GFP_KERNEL);
> +	if (!dchid)
> +		return -ENOMEM;
> +
> +	dchid->rx_buf = devm_kmalloc(dev, DCHID_RX_BUF_SIZE, GFP_KERNEL);
> +	if (!dchid->rx_buf)
> +		return -ENOMEM;
> +
> +	dchid->dev = dev;
> +	mutex_init(&dchid->ifaces_lock);
> +	platform_set_drvdata(pdev, dchid);
> +
> +	ret = dchid_map_helper_cpu(pdev, dchid);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to map helper CPU\n");
> +
> +	dchid->dc_mbox_client.dev = dev;
> +	dchid->dc_mbox_client.tx_block = true;
> +	dchid->dc_mbox_client.rx_callback = dchid_rx_callback;
> +
> +	dchid->dc_mbox = mbox_request_channel_byname(&dchid->dc_mbox_client,
> +						     "dockchannel");
> +	if (IS_ERR(dchid->dc_mbox))
> +		return dev_err_probe(dev, PTR_ERR(dchid->dc_mbox),
> +				     "failed to request DockChannel mailbox\n");
> +
> +	ret = devm_add_action_or_reset(dev, dchid_free_mbox, dchid->dc_mbox);
> +	if (ret)
> +		return ret;
> +
> +	dchid->rtk = devm_apple_rtkit_init(dev, dchid, "asc", 0, &dchid_rtkit_ops);
> +	if (IS_ERR(dchid->rtk))
> +		return dev_err_probe(dev, PTR_ERR(dchid->rtk), "failed to init RTKit\n");
> +
> +	writel_relaxed(APPLE_ASC_CPU_CONTROL_RUN,
> +		       dchid->asc_base + APPLE_ASC_CPU_CONTROL);
> +
> +	ret = apple_rtkit_wake(dchid->rtk);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to wake coprocessor\n");
> +
> +	dchid->new_iface_wq = alloc_ordered_workqueue("dchid-new", 0);
> +	if (!dchid->new_iface_wq)
> +		return dev_err_probe(dev, -ENOMEM, "failed to allocate workqueue\n");
> +
> +	ret = devm_add_action_or_reset(dev, dchid_destroy_wq, dchid->new_iface_wq);
> +	if (ret)
> +		return ret;
> +
> +	dchid->comm = dchid_get_interface(dchid, IFACE_COMM, "comm");
> +	if (!dchid->comm)
> +		return dev_err_probe(dev, -EIO, "failed to init comm interface\n");
> +
> +	return 0;
> +}
> +
> +static void dchid_remove(struct platform_device *pdev)
> +{
> +	struct dchid_dev *dchid = platform_get_drvdata(pdev);
> +	int i;
> +
> +	if (dchid->dc_mbox) {
> +		devm_release_action(&pdev->dev, dchid_free_mbox, dchid->dc_mbox);
> +		dchid->dc_mbox = NULL;
> +	}
> +
> +	if (dchid->rtk && apple_rtkit_is_running(dchid->rtk))
> +		apple_rtkit_quiesce(dchid->rtk);
> +
> +	if (dchid->asc_base)
> +		writel_relaxed(0, dchid->asc_base + APPLE_ASC_CPU_CONTROL);
> +
> +	for (i = 0; i < MAX_INTERFACES; i++) {
> +		struct dchid_iface *iface = dchid->ifaces[i];
> +
> +		if (!iface)
> +			continue;
> +
> +		cancel_work_sync(&iface->create_work);
> +		flush_workqueue(iface->wq);
> +
> +		if (iface->hid)
> +			hid_destroy_device(iface->hid);
> +	}
> +
> +	if (dchid->new_iface_wq)
> +		flush_workqueue(dchid->new_iface_wq);
> +}
> +
> +static const struct of_device_id dchid_of_match[] = {
> +	{ .compatible = "apple,t8122-dockchannel-hid" },
> +	{ .compatible = "apple,t8112-dockchannel-hid" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, dchid_of_match);
> +
> +static struct platform_driver dchid_platform_driver = {
> +	.driver = {
> +		.name = "dockchannel-hid",
> +		.of_match_table = dchid_of_match,
> +	},
> +	.probe = dchid_probe,
> +	.remove = dchid_remove,
> +};
> +module_platform_driver(dchid_platform_driver);
> +
> +MODULE_DESCRIPTION("Apple DockChannel HID transport driver");
> +MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
> +MODULE_AUTHOR("Michael Reeves <michael.reeves077@gmail.com>");
> +MODULE_LICENSE("Dual MIT/GPL");
>


^ permalink raw reply

* Re: [PATCH v5 0/5] Add support for AAEON SRG-IMX8P MCU
From: Thomas Perrot @ 2026-06-30 13:24 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: thomas.perrot, devicetree, linux-kernel, linux-gpio, imx,
	linux-arm-kernel, linux-watchdog, Thomas Petazzoni, Miquel Raynal,
	Krzysztof Kozlowski, Conor Dooley, Bartosz Golaszewski,
	Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Linus Walleij, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Jérémie Dautheribes, Wim Van Sebroeck,
	Lee Jones
In-Reply-To: <CAMRc=MdJJnRTOSEecqpX-EddJRAzWc_1a-cg3wrW8m0jR2Fihw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 884 bytes --]

Hello Bartosz,

On Tue, 2026-06-30 at 00:47 -0700, Bartosz Golaszewski wrote:
> On Mon, 29 Jun 2026 18:04:59 +0200, Thomas Perrot
> <thomas.perrot@bootlin.com> said:
> > Hello Guenter,
> > 
> > On Sat, 2026-04-11 at 17:12 -0700, Guenter Roeck wrote:
> > > snip
> > > 
> > > Sashiko has some interesting feedback that might be worth looking
> > > into.
> > > 
> > > https://sashiko.dev/#/patchset/20260408-dev-b4-aaeon-mcu-driver-v5-0-ad98bd481668%40bootlin.com
> > > 
> > 
> > Thanks for the pointer. I went through all findings and addressed
> > the
> >   valid ones in v6:
> > 
> 
> Did I miss anything? I don't see the v6 neither in my inbox nor on
> lore.

I just submitted it. I was waiting for the tests to finish.

Kind regards,
Thomas Perrot

> 
> Bart

-- 
Thomas Perrot, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply

* Re: [PATCH net-next v11 1/7] dt-bindings: phy: document the serdes PHY on sa8255p
From: Krzysztof Kozlowski @ 2026-06-30 13:24 UTC (permalink / raw)
  To: Vinod Koul, Geert Uytterhoeven
  Cc: Bartosz Golaszewski, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
	Alexandre Torgue, Giuseppe Cavallaro, Chen-Yu Tsai,
	Jernej Skrabec, Neil Armstrong, Kevin Hilman, Jerome Brunet,
	Shawn Guo, Fabio Estevam, Jan Petrous, s32, Mohd Ayaan Anwar,
	Romain Gantois, Magnus Damm, Maxime Ripard, Christophe Roullier,
	Radu Rendec, linux-arm-msm, devicetree, linux-kernel, netdev,
	linux-stm32, linux-arm-kernel, Drew Fustini, linux-sunxi,
	linux-amlogic, linux-mips, imx, linux-renesas-soc, linux-rockchip,
	sophgo, linux-riscv, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <akOZFIowVvprnAMf@vaman>

On 30/06/2026 12:23, Vinod Koul wrote:
> On 29-06-26, 16:51, Geert Uytterhoeven wrote:
>>> Russell King asked me to put the PHY logic for SCMI pm domains into the PHY
>>> driver instead of the MAC driver where it was previously. Instead of cramming
>>> both HLOS and firmware handling into the same driver, I figured it makes more
>>> sense to have a dedicated, cleaner driver as the two share very little code (if
>>> any).
>>
>> I think you are mixing up DT bindings and driver implementation?
> 
> Should the bindings change if we have different driver and firmware
> implementations? Isn't binding supposed to be agnostic of
> implementations..?


I did not follow earlier discussions, so I do not know Russell
arguments, but in general it's true that driver choices should not
influence binding decisions. IOW, you need to figure out which real
device is part of power domain and add the power-domains to that device
node (that device).


Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH 09/27] ASoC: codecs: idt821034: Use guard() for mutex locks
From: Mark Brown @ 2026-06-30 13:28 UTC (permalink / raw)
  To: Bui Duc Phuc
  Cc: Herve Codina, Takashi Iwai, Nick Li, Support Opensource,
	Liam Girdwood, Jaroslav Kysela, Srinivas Kandagatla,
	Charles Keepax, Richard Fitzgerald, Matthias Brugger,
	AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
	Sen Wang, Oder Chiou, Linus Walleij, Kuninori Morimoto,
	u.kleine-koenig, Zhang Yi, Marco Crivellari, Kees Cook,
	HyeongJun An, Arnd Bergmann, Qianfeng Rong, linux-sound,
	linux-kernel, patches, linux-mediatek, linux-arm-msm,
	linux-arm-kernel
In-Reply-To: <CAABR9nG5Wo1Wb+2_T6dR+6XTw8Vs9awSpQrSZ+k6=jp_ogoGCw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 386 bytes --]

On Tue, Jun 30, 2026 at 04:14:33PM +0700, Bui Duc Phuc wrote:
> On Tue, Jun 30, 2026 at 2:28 PM Herve Codina <herve.codina@bootlin.com> wrote:
> >
> > Hi,

Please delete unneeded context from mails when replying.  Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [PATCH 0/3] arm64: dts/net: stmmac: Add Agilex5 SoCDK TSN Config2 board support
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-30 13:31 UTC (permalink / raw)
  To: dinguyen, maxime.chevallier
  Cc: rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet, kuba,
	pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
	linux-kernel

From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>

The Intel SoCFPGA Agilex5 SoCDK TSN Config2 board uses a dual-port
Ethernet setup where gmac1 (TSN port) operates with different MAC-side
and PHY-side interface modes: GMII internally in the MAC, and RGMII
towards the PHY.

Russell King's commit de696c63c1dc ("net: stmmac: socfpga: convert to
use phy_interface") replaced mac_interface with phy_interface in
socfpga_get_plat_phymode(), correctly noting that no upstream DTS files
set the "mac-mode" property at the time. However, the Agilex5 SoCDK
TSN Config2 board requires mac-mode and phy-mode to differ, causing
ping failures when the MAC is configured with RGMII instead of GMII.

This series fixes the issue in three steps:

  Patch 1 (dt-bindings): Add the compatible string for the new board
  variant to Documentation/devicetree/bindings/arm/altera.yaml.

  Patch 2 (dts): Add the device tree source for the Agilex5 SoCDK
  TSN Config2 board, enabling gmac1 with mac-mode = "gmii" alongside
  the standard gmac2 port.

  Patch 3 (driver): Restore mac_interface support in dwmac-socfpga by
  reading the optional "mac-mode" DT property. When absent, it falls
  back to phy_interface, preserving existing behaviour for all other
  boards.

Note: Patches 1 and 2 target Dinh Nguyen's SoCFPGA tree
(git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git).
Patch 3 targets net-next.

Nazim Amirul (3):
  dt-bindings: arm: altera: Add Agilex5 SoCDK TSN Config2 board
  arm64: dts: socfpga: agilex5: Add SoCDK TSN Config2 board
  net: stmmac: dwmac-socfpga: Add mac-mode DT property support

 Documentation/devicetree/bindings/arm/altera.yaml            |   1 +
 arch/arm64/boot/dts/intel/Makefile                           |   9 +-
 arch/arm64/boot/dts/intel/socfpga_agilex5_socdk_tsn_cfg2.dts | 133 ++++++++++++++++++
 drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c          |  23 ++-
 4 files changed, 162 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex5_socdk_tsn_cfg2.dts

-- 
2.43.7



^ permalink raw reply

* [PATCH 1/3] dt-bindings: arm: altera: Add Agilex5 SoCDK TSN Config2 board board
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-30 13:31 UTC (permalink / raw)
  To: dinguyen, maxime.chevallier
  Cc: rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet, kuba,
	pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
	linux-kernel
In-Reply-To: <20260630133108.27244-1-muhammad.nazim.amirul.nazle.asmade@altera.com>

From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>

Add compatible string for the Intel SoCFPGA Agilex5 SoCDK TSN Config2
board variant, which uses a dual-port TSN configuration where gmac1
operates with different MAC-side (GMII) and PHY-side (RGMII) interface
modes.

Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
 Documentation/devicetree/bindings/arm/altera.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/altera.yaml b/Documentation/devicetree/bindings/arm/altera.yaml
index 3030cf46fe74..e431469a7175 100644
--- a/Documentation/devicetree/bindings/arm/altera.yaml
+++ b/Documentation/devicetree/bindings/arm/altera.yaml
@@ -114,6 +114,7 @@ properties:
               - intel,socfpga-agilex5-socdk-debug
               - intel,socfpga-agilex5-socdk-modular
               - intel,socfpga-agilex5-socdk-nand
+              - intel,socfpga-agilex5-socdk-tsn-cfg2
           - const: intel,socfpga-agilex5
 
       - description: Agilex72 boards
-- 
2.43.7



^ permalink raw reply related

* [PATCH 3/3] net: stmmac: dwmac-socfpga: Add mac-mode DT property support
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-30 13:31 UTC (permalink / raw)
  To: dinguyen, maxime.chevallier
  Cc: rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet, kuba,
	pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
	linux-kernel
In-Reply-To: <20260630133108.27244-1-muhammad.nazim.amirul.nazle.asmade@altera.com>

From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>

Russell King's commit de696c63c1dc ("net: stmmac: socfpga: convert to
use phy_interface") replaced mac_interface with phy_interface in
socfpga_get_plat_phymode(), noting that no upstream DTS files set the
"mac-mode" property, making the two values identical.

The Agilex5 SoCDK TSN Config2 board is an exception: its gmac1 TSN
port uses GMII internally in the MAC while the PHY-side interface is
RGMII, so mac-mode and phy-mode differ. Without restoring mac_interface
support, the MAC is configured with RGMII instead of GMII, causing
connectivity failures on this board.

Add socfpga_of_get_mac_mode() to read the optional "mac-mode" DT
property and store it in a new mac_interface field. When the property
is absent, mac_interface falls back to phy_interface, preserving
the existing behaviour for all other boards.

Fixes: de696c63c1dc ("net: stmmac: socfpga: convert to use phy_interface")
Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
 .../ethernet/stmicro/stmmac/dwmac-socfpga.c   | 23 ++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 1d7f0a57d288..6a6837c4a414 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -69,12 +69,30 @@ struct socfpga_dwmac {
 	void __iomem *tse_pcs_base;
 	void __iomem *sgmii_adapter_base;
 	bool f2h_ptp_ref_clk;
+	phy_interface_t mac_interface;
 	const struct socfpga_dwmac_ops *ops;
 };
 
+static int socfpga_of_get_mac_mode(struct device_node *np)
+{
+	const char *pm;
+	int err, i;
+
+	err = of_property_read_string(np, "mac-mode", &pm);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
+		if (!strcasecmp(pm, phy_modes(i)))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
 static phy_interface_t socfpga_get_plat_phymode(struct socfpga_dwmac *dwmac)
 {
-	return dwmac->plat_dat->phy_interface;
+	return dwmac->mac_interface;
 }
 
 static void socfpga_sgmii_config(struct socfpga_dwmac *dwmac, bool enable)
@@ -650,6 +668,9 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
 	plat_dat->pcs_exit = socfpga_dwmac_pcs_exit;
 	plat_dat->select_pcs = socfpga_dwmac_select_pcs;
 
+	ret = socfpga_of_get_mac_mode(pdev->dev.of_node);
+	dwmac->mac_interface = ret < 0 ? plat_dat->phy_interface : ret;
+
 	ops->setup_plat_dat(dwmac);
 
 	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
-- 
2.43.7



^ permalink raw reply related

* [PATCH 2/3] arm64: dts: socfpga: agilex5: Add SoCDK TSN Config2 board
From: muhammad.nazim.amirul.nazle.asmade @ 2026-06-30 13:31 UTC (permalink / raw)
  To: dinguyen, maxime.chevallier
  Cc: rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet, kuba,
	pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
	linux-kernel
In-Reply-To: <20260630133108.27244-1-muhammad.nazim.amirul.nazle.asmade@altera.com>

From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>

Add device tree for the Intel SoCFPGA Agilex5 SoCDK TSN Config2 board
variant. This configuration enables gmac1 as a TSN port alongside
the standard gmac2 Ethernet port.

The TSN port (gmac1) uses GMII internally in the MAC but connects to an
RGMII PHY. The mac-mode property is set to "gmii" to reflect the
MAC-side interface, while phy-mode is set to "rgmii" for the PHY-side
interface.

Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
 arch/arm64/boot/dts/intel/Makefile            |   3 +-
 .../intel/socfpga_agilex5_socdk_tsn_cfg2.dts  | 133 ++++++++++++++++++
 2 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex5_socdk_tsn_cfg2.dts

diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile
index 270c70fdf084..fc7ba2c6384b 100644
--- a/arch/arm64/boot/dts/intel/Makefile
+++ b/arch/arm64/boot/dts/intel/Makefile
@@ -4,10 +4,11 @@ dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_n6000.dtb \
 				socfpga_agilex_socdk_emmc.dtb \
 				socfpga_agilex_socdk_nand.dtb \
 				socfpga_agilex3_socdk.dtb \
-				socfpga_agilex5_socdk.dtb \
+			socfpga_agilex5_socdk.dtb \
 				socfpga_agilex5_socdk_013b.dtb \
 				socfpga_agilex5_socdk_modular.dtb \
 				socfpga_agilex5_socdk_nand.dtb \
+				socfpga_agilex5_socdk_tsn_cfg2.dtb \
 				socfpga_agilex72_socdk.dtb \
 				socfpga_agilex7m_socdk.dtb \
 				socfpga_n5x_socdk.dtb
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex5_socdk_tsn_cfg2.dts b/arch/arm64/boot/dts/intel/socfpga_agilex5_socdk_tsn_cfg2.dts
new file mode 100644
index 000000000000..f84f41a647ae
--- /dev/null
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex5_socdk_tsn_cfg2.dts
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+#include "socfpga_agilex5.dtsi"
+
+/ {
+	model = "SoCFPGA Agilex5 SoCDK TSN Config2";
+	compatible = "intel,socfpga-agilex5-socdk-tsn-cfg2", "intel,socfpga-agilex5";
+
+	aliases {
+		serial0 = &uart0;
+		ethernet1 = &gmac1;
+		ethernet2 = &gmac2;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-0 {
+			label = "hps_led0";
+			gpios = <&porta 11 GPIO_ACTIVE_HIGH>;
+		};
+
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		/* We expect the bootloader to fill in the reg */
+		reg = <0x0 0x80000000 0x0 0x0>;
+	};
+};
+
+&gpio0 {
+	status = "okay";
+};
+
+&gpio1 {
+	status = "okay";
+};
+
+/*
+ * gmac1 is the TSN port. The MAC operates in GMII mode internally
+ * while the PHY-side interface is RGMII, so mac-mode and phy-mode differ.
+ */
+&gmac1 {
+	status = "okay";
+	phy-mode = "rgmii"; /* TX/RX clock delays provided by Agilex5 I/O hardware */
+	mac-mode = "gmii";
+	phy-handle = <&emac1_phy0>;
+	max-frame-size = <9000>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+
+		emac1_phy0: ethernet-phy@0 {
+			reg = <0>;
+		};
+	};
+};
+
+&gmac2 {
+	status = "okay";
+	phy-mode = "rgmii"; /* TX/RX clock delays provided by Agilex5 I/O hardware */
+	phy-handle = <&emac2_phy0>;
+	max-frame-size = <9000>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+
+		emac2_phy0: ethernet-phy@0 {
+			reg = <0>;
+		};
+	};
+};
+
+&osc1 {
+	clock-frequency = <25000000>;
+};
+
+&qspi {
+	status = "okay";
+	flash@0 {
+		compatible = "micron,mt25qu02g", "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <100000000>;
+		m25p,fast-read;
+		cdns,read-delay = <2>;
+		cdns,tshsl-ns = <50>;
+		cdns,tsd2d-ns = <50>;
+		cdns,tchsh-ns = <4>;
+		cdns,tslch-ns = <4>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qspi_boot: partition@0 {
+				label = "u-boot";
+				reg = <0x0 0x04200000>;
+			};
+
+			root: partition@4200000 {
+				label = "root";
+				reg = <0x04200000 0x0be00000>;
+			};
+		};
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&usb0 {
+	status = "okay";
+	disable-over-current;
+};
+
+&watchdog0 {
+	status = "okay";
+};
-- 
2.43.7



^ permalink raw reply related

* Re: [PATCH v3] ARM: entry: expand comment in __switch_to
From: Mark Rutland @ 2026-06-30 13:38 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Russell King, Ard Biesheuvel, linux-arm-kernel
In-Reply-To: <20260630-comments-in-switch-to-v3-1-87a946a3fddd@kernel.org>

On Tue, Jun 30, 2026 at 11:38:55AM +0200, Linus Walleij wrote:
> From: Linus Walleij <linus.walleij@linaro.org>
> 
> As per discussion between the developers in the mail thread
> linked, expand the comment in __switch_to so that readers
> of the code understand what is going on.
> 
> Link: https://lore.kernel.org/linux-arm-kernel/ZxDh9biUbf9W8gNN@J2N7QTR9R3/
> Suggested-by: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> Acked-by: Mark Rutland <mark.rutland@arm.com>
> ---
> Changes in v3:
> - EDITME: describe what is new in this series revision.
> - EDITME: use bulletpoints and terse descriptions.
> - Link to v2: https://lore.kernel.org/r/20251216-comments-in-switch-to-v2-1-190d8741db14@kernel.org

Looks like you might have forgotten something here. ;)

This looks good to me, so I reckon you should drop it into Russell's
patch tracker:

  https://www.armlinux.org.uk/developer/patches/

Mark.

> 
> Changes in v2:
> - Rebased on v6.19-rc1
> - Link to v1: https://lore.kernel.org/r/20241028-comments-in-switch-to-v1-0-7280d09671a8@linaro.org
> ---
>  arch/arm/kernel/entry-armv.S | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index a3d050ce9b79..2d2ea3ca880c 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -557,9 +557,16 @@ ENTRY(__switch_to)
>  	ldmia	r4, {r4 - sl, fp, ip, lr}	@ Load all regs saved previously
>  #ifdef CONFIG_VMAP_STACK
>  	@
> -	@ Do a dummy read from the new stack while running from the old one so
> -	@ that we can rely on do_translation_fault() to fix up any stale PMD
> -	@ entries covering the vmalloc region.
> +	@ For a non-lazy mm switch, check_vmalloc_seq() has ensured that
> +	@ that the active mm's page tables have mappings for the prev
> +	@ task's stack and the next task's stack.
> +	@
> +	@ For a lazy mm switch the active mm's page tables have mappings
> +	@ for the prev task's stack but might not have mappings for the
> +	@ new task's stack. Do a dummy read from the new stack while
> +	@ running from the old stack so that we can rely on
> +	@ do_translation_fault() to populate missing PMD entries covering the
> +	@ new task's stack in the old task's page tables.
>  	@
>  	ldr	r2, [ip]
>  #ifdef CONFIG_KASAN_VMALLOC
> 
> ---
> base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
> change-id: 20241028-comments-in-switch-to-0e24480e8495
> 
> Best regards,
> --  
> Linus Walleij <linusw@kernel.org>
> 


^ permalink raw reply

* Re: [PATCH 07/10] HID: apple: Add support for DockChannel HID keyboards
From: Sasha Finkelstein @ 2026-06-30 13:41 UTC (permalink / raw)
  To: michael.reeves077
  Cc: Sven Peter, Janne Grunau, Neal Gompa, Jassi Brar, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Hector Martin,
	Joerg Roedel (AMD), Will Deacon, Robin Murphy, Dmitry Torokhov,
	Jiri Kosina, Benjamin Tissoires, asahi, linux-arm-kernel,
	linux-kernel, devicetree, iommu, linux-input
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-7-506d936a1707@gmail.com>


> On Jun 30, 2026, at 14:54, Michael Reeves via B4 Relay <devnull+michael.reeves077.gmail.com@kernel.org> wrote:
> 
> @@ -659,6 +669,7 @@ static void apple_battery_timer_tick(struct timer_list *t)
> /*
>  * MacBook JIS keyboard has wrong logical maximum
>  * Magic Keyboard JIS has wrong logical maximum
> + * Internal DockChannel keyboards can advertise oversized report sizes
>  */
> static const __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
> unsigned int *rsize)
> @@ -699,6 +710,27 @@ static const __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
> rdesc[3] = 0x06;
> }
> 
> + if (apple_is_dockchannel_keyboard(hdev) && *rsize >= 5) {
> + int i;
> +
> + for (i = 0; i <= *rsize - 5; i++) {
> + if (rdesc[i] == 0x76 && rdesc[i + 1] == 0x00 &&
> +    rdesc[i + 2] == 0x40 && rdesc[i + 3] == 0x95) {
> + u8 count = rdesc[i + 4];
> +
> + if (count > 0 && count < 32) {
> + hid_info(hdev,
> + "fixing up DockChannel report size\n");
> + rdesc[i] = 0x75;
> + rdesc[i + 1] = 0x08;
> + rdesc[i + 2] = 0x96;
> + rdesc[i + 3] = 0x00;
> + rdesc[i + 4] = count * 8;
> + }
> + }
> + }
> + }
> +
> return rdesc;
> }
> 

It looks like this section is duplicated in the following commit (8). 
Is that correct?




^ permalink raw reply


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