From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.cyberchaos.dev (mail.cyberchaos.dev [195.39.247.168]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 981E71C84AB; Sat, 4 Jul 2026 20:14:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.39.247.168 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783196061; cv=none; b=QfVFTp9ZWsKpG2Ze2HwDwBAJYxwYBzH4iTymDwdkUmxG6XR02rvcwsgy1vTDbS5N87tDJMOPch7JaCvbyS+u6VEpMytqHYu2fpmLDsVzlxL6AoYV12heHDiC4BiY/O16XOJev9ex4QKng26fqdKurt1Jtz5vQAF8LTgtnNGvBVs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783196061; c=relaxed/simple; bh=UlhQyo/aPuYiS2Tlxmo9Wbnmve6jBrl7n+Uip0x8CYk=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=iDjbxm3RC81t+tm1Sp0xgaaGeORKWOvjk4x1wQPdI68jctkqDcUu5FlkA7nA6UGSW2X5JrVBnB9/mSa+8DXxcSpvt7AzhaOn2iZm4c7BVRWJXsDPUsnAY9V5L8b7NGUIF4pdP+O5yqz+zcJpTQZDZMyh9y1P67QWjbfaXlJ8QLw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cyberchaos.dev; spf=pass smtp.mailfrom=cyberchaos.dev; dkim=pass (1024-bit key) header.d=cyberchaos.dev header.i=@cyberchaos.dev header.b=ZRddKpF9; arc=none smtp.client-ip=195.39.247.168 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cyberchaos.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cyberchaos.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=cyberchaos.dev header.i=@cyberchaos.dev header.b="ZRddKpF9" Message-ID: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cyberchaos.dev; s=mail; t=1783196051; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zTHCAFgqF5udNYw2Cs627uyejZVVCfBgcdZnEEV1nXM=; b=ZRddKpF9VsyyvBZvDbSxuyrhWJ+rts7292GlHFbcB1MEi/sL2Vr1+DjtpBCeL/iQ2KQCmO 7bMMKBumRax9ZL+96GADMy6tZPI64/clER9GiwTYVz69nyvaHXa/3FsuPGKVi/F+uW2nOu yERIFKtybFZEgwKzJkHL6ed9Gxtf3Qs= Date: Sat, 4 Jul 2026 22:14:07 +0200 Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH 05/10] mailbox: apple: Add DockChannel FIFO controller To: michael.reeves077@gmail.com, 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@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, iommu@lists.linux.dev, linux-input@vger.kernel.org References: <20260630-apple-mtp-keyboard-final-v1-0-506d936a1707@gmail.com> <20260630-apple-mtp-keyboard-final-v1-5-506d936a1707@gmail.com> Content-Language: en-US From: Yureka Lilian In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-5-506d936a1707@gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 6/30/26 14:54, Michael Reeves via B4 Relay wrote: > From: Michael Reeves > > 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 > Signed-off-by: Hector Martin > Signed-off-by: Michael Reeves > --- > 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 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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); This must be writel_relaxed, as writeb_relaxed in this mmio region will cause an SError. This is why we have separate addresses putting 8-bits and 32-bits into the FIFO I guess. > + 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 "); > +MODULE_AUTHOR("Michael Reeves "); > +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 > + > +/** > + * 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_ */ >