* [PATCH 0/2] mailbox: add Axiado AX3005 mailbox driver
@ 2026-07-30 4:36 Swark Yang
2026-07-30 4:36 ` [PATCH 1/2] dt-bindings: mailbox: add Axiado AX3005 mailbox Swark Yang
2026-07-30 4:36 ` [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
0 siblings, 2 replies; 5+ messages in thread
From: Swark Yang @ 2026-07-30 4:36 UTC (permalink / raw)
To: Krishnakumar Kesavan, Prasad Bolisetty, Jassi Brar, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Tzu-Hao Wei,
Karthikeyan Mitran
Cc: linux-kernel, devicetree, linux-arm-kernel, Swark Yang
The Axiado AX3005 SoC integrates a mailbox controller that provides
inter-processor communication channels between the host CPU and the
on-chip co-processor.
The controller exposes 16 fixed-function channels split into two
groups: 8 TX channels and 8 RX channels. Each channel has a
hardware FIFO and a control/status register, while TX and RX
channels reside in separate MMIO register regions.
Only the RX channels expose interrupts to the host CPU.
TX completion is detected by polling the FIFO empty status, so
txdone_poll is used instead of txdone_irq. RX delivery uses a
threaded IRQ per channel because draining a mailbox message word by
word is not appropriate in hard IRQ context.
The ax3005.dtsi mailbox node will follow in a separate patch once
the AX3005 devicetree series currently under review has been merged.
This series consists of:
1. dt-bindings: mailbox: add Axiado AX3005 mailbox
2. mailbox: add Axiado AX3005 mailbox driver
The corresponding MAINTAINERS entry is added incrementally by the
two patches: the binding path in patch 1 and the driver path in
patch 2.
Testing:
Tested on AX3005 using an out-of-tree MCTP-over-mailbox transport
driver, not yet submitted upstream, as the mailbox client. The test
exercised channel 0 for TX and channel 8 for RX.
Verified end to end by issuing a PLDM Firmware Update command from
OpenBMC over MCTP and routing it through this mailbox driver to the
on-chip coprocessor. The firmware update completed successfully,
and the resulting image passed verification.
Signed-off-by: Swark Yang <syang@axiado.com>
---
Swark Yang (2):
dt-bindings: mailbox: add Axiado AX3005 mailbox
mailbox: add Axiado AX3005 mailbox driver
.../bindings/mailbox/axiado,ax3005-mailbox.yaml | 98 ++++++
MAINTAINERS | 8 +
drivers/mailbox/Kconfig | 10 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/axiado-mailbox.c | 379 +++++++++++++++++++++
5 files changed, 497 insertions(+)
---
base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
change-id: 20260728-upstream-axiado-ax3005-mailbox-upstream-86feaa7edf49
Best regards,
--
Swark Yang <syang@axiado.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] dt-bindings: mailbox: add Axiado AX3005 mailbox
2026-07-30 4:36 [PATCH 0/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
@ 2026-07-30 4:36 ` Swark Yang
2026-07-30 5:59 ` Krzysztof Kozlowski
2026-07-30 4:36 ` [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
1 sibling, 1 reply; 5+ messages in thread
From: Swark Yang @ 2026-07-30 4:36 UTC (permalink / raw)
To: Krishnakumar Kesavan, Prasad Bolisetty, Jassi Brar, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Tzu-Hao Wei,
Karthikeyan Mitran
Cc: linux-kernel, devicetree, linux-arm-kernel, Swark Yang
Add a devicetree binding for the Axiado AX3005 mailbox controller.
The controller provides inter-processor communication channels
between the host CPU and the coprocessor, with separate TX and RX
register regions.
Add the corresponding MAINTAINERS entry covering the binding.
Signed-off-by: Swark Yang <syang@axiado.com>
---
.../bindings/mailbox/axiado,ax3005-mailbox.yaml | 98 ++++++++++++++++++++++
MAINTAINERS | 7 ++
2 files changed, 105 insertions(+)
diff --git a/Documentation/devicetree/bindings/mailbox/axiado,ax3005-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/axiado,ax3005-mailbox.yaml
new file mode 100644
index 000000000000..b4fab96356c1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/axiado,ax3005-mailbox.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mailbox/axiado,ax3005-mailbox.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Axiado AX3005 Mailbox Controller
+
+maintainers:
+ - Krishnakumar Kesavan <kkesavan@axiado.com>
+ - Prasad Bolisetty <pbolisetty@axiado.com>
+ - Swark Yang <syang@axiado.com>
+
+description: |
+ The Axiado mailbox controller provides inter-processor communication
+ channels between subsystems within the Axiado SoC. The hardware has
+ separate TX and RX register regions. Only the RX channels (channels 8-15)
+ generate interrupts; TX channels are purely poll/write-based.
+
+properties:
+ compatible:
+ const: axiado,ax3005-mailbox
+
+ reg:
+ items:
+ - description: TX mailbox register region
+ - description: RX mailbox register region
+
+ reg-names:
+ items:
+ - const: tx
+ - const: rx
+
+ interrupts:
+ description: |
+ One interrupt per RX channel. The hardware exposes eight RX interrupt
+ lines corresponding to channels 8 through 15.
+ minItems: 8
+ maxItems: 8
+
+ interrupt-names:
+ description: |
+ Named interrupt lines for each RX channel, from ch8 to ch15.
+ items:
+ - const: ch8
+ - const: ch9
+ - const: ch10
+ - const: ch11
+ - const: ch12
+ - const: ch13
+ - const: ch14
+ - const: ch15
+
+ "#mbox-cells":
+ description: |
+ Number of cells in a mailbox specifier. A single cell encodes the
+ channel index as seen by the client.
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - interrupt-names
+ - "#mbox-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ mailbox@330f2000 {
+ compatible = "axiado,ax3005-mailbox";
+ reg = <0x0 0x330f2000 0x0 0x2000>,
+ <0x0 0x331b0000 0x0 0x1000>;
+ reg-names = "tx", "rx";
+ /* Only RX channels (8-15) have IRQs */
+ interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15";
+ interrupt-parent = <&gic500>;
+ #mbox-cells = <1>;
+ status = "okay";
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index a674e36529f7..af6c3571c9f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4437,6 +4437,13 @@ F: Documentation/devicetree/bindings/phy/axiado,ax3000-emmc-phy.yaml
F: drivers/phy/axiado/Kconfig
F: drivers/phy/axiado/phy-axiado-emmc.c
+AXIADO MAILBOX DRIVER
+M: Krishnakumar Kesavan <kkesavan@axiado.com>
+M: Prasad Bolisetty <pbolisetty@axiado.com>
+M: Swark Yang <syang@axiado.com>
+S: Supported
+F: Documentation/devicetree/bindings/mailbox/axiado,ax3005-mailbox.yaml
+
AXI SPI ENGINE
M: Michael Hennerich <michael.hennerich@analog.com>
M: Nuno Sá <nuno.sa@analog.com>
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver
2026-07-30 4:36 [PATCH 0/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
2026-07-30 4:36 ` [PATCH 1/2] dt-bindings: mailbox: add Axiado AX3005 mailbox Swark Yang
@ 2026-07-30 4:36 ` Swark Yang
2026-07-30 4:48 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Swark Yang @ 2026-07-30 4:36 UTC (permalink / raw)
To: Krishnakumar Kesavan, Prasad Bolisetty, Jassi Brar, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Tzu-Hao Wei,
Karthikeyan Mitran
Cc: linux-kernel, devicetree, linux-arm-kernel, Swark Yang
Add a mailbox controller driver for the Axiado AX3005 SoC.
The controller provides communication channels between
the host CPU and the coprocessor.
The hardware provides 8 TX channels and 8 RX channels
through separate register regions. RX channels use
per-channel interrupts, while TX completion is detected by
polling the FIFO status.
Add the driver path to the existing Axiado mailbox entry in
MAINTAINERS.
Signed-off-by: Swark Yang <syang@axiado.com>
---
MAINTAINERS | 1 +
drivers/mailbox/Kconfig | 10 ++
drivers/mailbox/Makefile | 2 +
drivers/mailbox/axiado-mailbox.c | 379 +++++++++++++++++++++++++++++++++++++++
4 files changed, 392 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index af6c3571c9f2..80db69111889 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4443,6 +4443,7 @@ M: Prasad Bolisetty <pbolisetty@axiado.com>
M: Swark Yang <syang@axiado.com>
S: Supported
F: Documentation/devicetree/bindings/mailbox/axiado,ax3005-mailbox.yaml
+F: drivers/mailbox/axiado-mailbox.c
AXI SPI ENGINE
M: Michael Hennerich <michael.hennerich@analog.com>
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 3062ee352f78..ab869769e278 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -399,4 +399,14 @@ config RISCV_SBI_MPXY_MBOX
or HS-mode hypervisor). Say Y here, unless you are sure you do not
need this.
+config AXIADO_MAILBOX
+ tristate "Axiado mailbox driver"
+ depends on ARCH_AXIADO || COMPILE_TEST
+ depends on OF
+ help
+ Enable support for the Axiado mailbox controller. The driver provides
+ communication channels between the host CPU and the coprocessor on
+ Axiado SoCs.
+ If unsure, say N.
+
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 944d8ea39f34..45dc59bb3e7f 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -84,3 +84,5 @@ obj-$(CONFIG_CIX_MBOX) += cix-mailbox.o
obj-$(CONFIG_BCM74110_MAILBOX) += bcm74110-mailbox.o
obj-$(CONFIG_RISCV_SBI_MPXY_MBOX) += riscv-sbi-mpxy-mbox.o
+
+obj-$(CONFIG_AXIADO_MAILBOX) += axiado-mailbox.o
diff --git a/drivers/mailbox/axiado-mailbox.c b/drivers/mailbox/axiado-mailbox.c
new file mode 100644
index 000000000000..4f1daf394a27
--- /dev/null
+++ b/drivers/mailbox/axiado-mailbox.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021-2026 Axiado Corporation (or its affiliates).
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/mailbox_controller.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
+
+#define AXIADO_MBOX_TX_CHANS 8 /* 0-7 */
+#define AXIADO_MBOX_RX_CHANS 8 /* 8-15 */
+#define AXIADO_MBOX_CHAN_STRIDE 0x4
+#define AXIADO_MBOX_TX_REG_STRIDE 0x40
+#define AXIADO_MBOX_RX_REG_STRIDE 0x30
+#define AXIADO_MBOX_RX_POLL_US 10
+#define AXIADO_MBOX_RX_TIMEOUT_US 500
+
+/* Mailbox CSR bit definitions */
+#define AXIADO_MBOX_CSR_EMPTY BIT(0) /* 1 = FIFO empty; 0 = data available */
+#define AXIADO_MBOX_CSR_OVERFLOW BIT(2) /* write 1 to clear (W1C) */
+#define AXIADO_MBOX_CSR_UNDERFLOW BIT(3) /* write 1 to clear (W1C) */
+#define AXIADO_MBOX_CSR_FLUSH BIT(4) /* W1TRG flush; startup/shutdown */
+#define AXIADO_MBOX_CSR_LEVEL GENMASK(11, 5)
+
+#define AXIADO_MBOX_CSR_ERRORS (AXIADO_MBOX_CSR_OVERFLOW | \
+ AXIADO_MBOX_CSR_UNDERFLOW)
+
+struct axiado_mbox_data {
+ u8 num_chans;
+ u16 msg_size;
+};
+
+struct axiado_channel_data {
+ void __iomem *mbox_reg;
+ void __iomem *csr_reg;
+ void *rx_buffer;
+ u8 channel_num;
+ int irq;
+ struct mbox_chan *chan;
+ u16 chan_msg_size;
+ bool active;
+};
+
+/* mailbox side */
+struct axiado_mbox {
+ struct mbox_controller mbox;
+ const struct axiado_mbox_data *drv_data;
+ void __iomem *tx_base;
+ void __iomem *rx_base;
+};
+
+/*
+ * Checks OVERFLOW/UNDERFLOW, logs and W1C-clears them if set. Shared by the
+ * TX and RX paths; RX additionally flushes the FIFO afterwards to resync
+ * framing, which TX must not do since it could discard data the peer has
+ * not read yet.
+ */
+static bool axiado_mbox_clear_fifo_errors(struct axiado_channel_data *priv)
+{
+ struct device *dev = priv->chan->mbox->dev;
+ u32 errors;
+
+ errors = readl(priv->csr_reg) & AXIADO_MBOX_CSR_ERRORS;
+ if (!errors)
+ return false;
+
+ writel(errors, priv->csr_reg);
+
+ dev_warn_ratelimited(dev, "Channel %u FIFO error: %#x\n",
+ priv->channel_num, errors);
+
+ return true;
+}
+
+static int axiado_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+ struct axiado_mbox *mb = dev_get_drvdata(chan->mbox->dev);
+ struct axiado_channel_data *priv = chan->con_priv;
+ unsigned int idx = priv->channel_num;
+ u8 tail[sizeof(u32)] = { 0 };
+ const u8 *buf = data;
+ unsigned int tail_len;
+ unsigned int offset;
+ u32 msg_len;
+
+ if (priv->channel_num >= AXIADO_MBOX_TX_CHANS)
+ return -EINVAL;
+
+ if (!data)
+ return -EINVAL;
+
+ /*
+ * The Axiado mailbox message ABI stores the total message length,
+ * including this length word, as a little-endian byte count in the
+ * first word of every message.
+ */
+ msg_len = get_unaligned_le32(data);
+ if (msg_len < sizeof(u32) || msg_len > mb->drv_data->msg_size)
+ return -EINVAL;
+
+ /* Only touch the hardware after validating the message. */
+ axiado_mbox_clear_fifo_errors(priv);
+
+ if (!(readl(priv->csr_reg) & AXIADO_MBOX_CSR_EMPTY)) {
+ dev_warn(mb->mbox.dev, "Channel %u is busy\n", idx);
+ return -EBUSY;
+ }
+
+ for (offset = 0; offset + sizeof(u32) <= msg_len;
+ offset += sizeof(u32))
+ writel(get_unaligned_le32(buf + offset), priv->mbox_reg);
+
+ tail_len = msg_len - offset;
+ if (tail_len) {
+ memcpy(tail, buf + offset, tail_len);
+ writel(get_unaligned_le32(tail), priv->mbox_reg);
+ }
+
+ dev_dbg(mb->mbox.dev, "%s: Ch-%u sent\n", __func__, idx);
+
+ return 0;
+}
+
+static bool axiado_mbox_handle_rx_error(struct axiado_channel_data *priv)
+{
+ if (!axiado_mbox_clear_fifo_errors(priv))
+ return false;
+
+ /* Errors leave RX framing out of sync; flush and resync. */
+ writel(AXIADO_MBOX_CSR_FLUSH, priv->csr_reg);
+
+ return true;
+}
+
+static irqreturn_t axiado_rx_thread(int irq, void *dev_id)
+{
+ struct axiado_channel_data *priv = dev_id;
+ struct mbox_chan *chan = priv->chan;
+ u8 *buf = priv->rx_buffer;
+ unsigned int num_words;
+ unsigned int remaining;
+ unsigned int i;
+ u32 msg_len;
+ u32 word;
+ u32 csr;
+ int ret;
+
+ if (axiado_mbox_handle_rx_error(priv))
+ return IRQ_HANDLED;
+
+ csr = readl(priv->csr_reg);
+ if (csr & AXIADO_MBOX_CSR_EMPTY)
+ return IRQ_NONE;
+
+ /*
+ * The first word contains the total message length in bytes,
+ * including the length word itself.
+ */
+ word = readl(priv->mbox_reg);
+ msg_len = word;
+ put_unaligned_le32(word, buf);
+
+ if (msg_len < sizeof(u32) ||
+ msg_len > priv->chan_msg_size)
+ goto invalid_message;
+
+ num_words = DIV_ROUND_UP(msg_len, sizeof(u32));
+ remaining = num_words - 1;
+
+ /*
+ * The not-empty interrupt may occur as soon as the first DW enters
+ * the FIFO. Wait until all remaining DWs of this message arrive.
+ */
+ if (remaining) {
+ ret = readl_poll_timeout(priv->csr_reg, csr,
+ (csr & AXIADO_MBOX_CSR_ERRORS) ||
+ FIELD_GET(AXIADO_MBOX_CSR_LEVEL, csr) >=
+ remaining,
+ AXIADO_MBOX_RX_POLL_US,
+ AXIADO_MBOX_RX_TIMEOUT_US);
+ if (ret)
+ goto incomplete_message;
+
+ if (axiado_mbox_handle_rx_error(priv))
+ return IRQ_HANDLED;
+ }
+
+ for (i = 1; i < num_words; i++) {
+ word = readl(priv->mbox_reg);
+ put_unaligned_le32(word,
+ buf + i * sizeof(u32));
+ }
+
+ if (axiado_mbox_handle_rx_error(priv))
+ return IRQ_HANDLED;
+
+ if (READ_ONCE(priv->active))
+ mbox_chan_received_data(chan, priv->rx_buffer);
+
+ return IRQ_HANDLED;
+
+incomplete_message:
+ dev_warn_ratelimited(chan->mbox->dev,
+ "Channel %u received an incomplete message\n",
+ priv->channel_num);
+
+invalid_message:
+ writel(AXIADO_MBOX_CSR_FLUSH, priv->csr_reg);
+
+ return IRQ_HANDLED;
+}
+
+static int axiado_mbox_startup(struct mbox_chan *chan)
+{
+ struct axiado_channel_data *priv = chan->con_priv;
+
+ writel(AXIADO_MBOX_CSR_FLUSH, priv->csr_reg);
+ writel(AXIADO_MBOX_CSR_ERRORS, priv->csr_reg);
+ WRITE_ONCE(priv->active, true);
+
+ if (priv->channel_num >= AXIADO_MBOX_TX_CHANS)
+ enable_irq(priv->irq);
+
+ return 0;
+}
+
+static void axiado_mbox_shutdown(struct mbox_chan *chan)
+{
+ struct axiado_channel_data *priv = chan->con_priv;
+
+ WRITE_ONCE(priv->active, false);
+
+ if (priv->channel_num >= AXIADO_MBOX_TX_CHANS)
+ disable_irq(priv->irq);
+
+ writel(AXIADO_MBOX_CSR_FLUSH, priv->csr_reg);
+}
+
+static bool axiado_mbox_last_tx_done(struct mbox_chan *chan)
+{
+ struct axiado_channel_data *priv = chan->con_priv;
+
+ return !!(readl(priv->csr_reg) & AXIADO_MBOX_CSR_EMPTY);
+}
+
+static const struct mbox_chan_ops axiado_mbox_chan_ops = {
+ .send_data = axiado_mbox_send_data,
+ .startup = axiado_mbox_startup,
+ .shutdown = axiado_mbox_shutdown,
+ .last_tx_done = axiado_mbox_last_tx_done,
+};
+
+static int axiado_mbox_probe(struct platform_device *pdev)
+{
+ const struct axiado_mbox_data *drv_data;
+ struct axiado_channel_data *ch_data;
+ struct device *dev = &pdev->dev;
+ struct axiado_mbox *mb;
+ unsigned int irq_idx = 0;
+ unsigned int rx_chan;
+ unsigned int i;
+ int ret;
+
+ drv_data = device_get_match_data(dev);
+ if (!drv_data)
+ return -ENODEV;
+
+ mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL);
+ if (!mb)
+ return -ENOMEM;
+
+ mb->mbox.dev = dev;
+ mb->mbox.num_chans = drv_data->num_chans;
+
+ mb->mbox.chans = devm_kcalloc(&pdev->dev,
+ drv_data->num_chans,
+ sizeof(*mb->mbox.chans),
+ GFP_KERNEL);
+ if (!mb->mbox.chans)
+ return -ENOMEM;
+
+ mb->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx");
+ if (IS_ERR(mb->tx_base))
+ return PTR_ERR(mb->tx_base);
+
+ mb->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx");
+ if (IS_ERR(mb->rx_base))
+ return PTR_ERR(mb->rx_base);
+
+ ch_data = devm_kcalloc(&pdev->dev,
+ drv_data->num_chans,
+ sizeof(*ch_data),
+ GFP_KERNEL);
+ if (!ch_data)
+ return -ENOMEM;
+
+ for (i = 0; i < drv_data->num_chans; i++) {
+ ch_data[i].channel_num = i;
+ ch_data[i].chan = &mb->mbox.chans[i];
+ ch_data[i].chan_msg_size = drv_data->msg_size;
+
+ mb->mbox.chans[i].con_priv = &ch_data[i];
+
+ if (i < AXIADO_MBOX_TX_CHANS) {
+ ch_data[i].mbox_reg = mb->tx_base + (i * AXIADO_MBOX_CHAN_STRIDE);
+ ch_data[i].csr_reg = mb->tx_base + AXIADO_MBOX_TX_REG_STRIDE +
+ (i * AXIADO_MBOX_CHAN_STRIDE);
+ ch_data[i].irq = -1;
+ continue;
+ }
+
+ ch_data[i].rx_buffer = devm_kmalloc(dev, drv_data->msg_size,
+ GFP_KERNEL);
+ if (!ch_data[i].rx_buffer)
+ return -ENOMEM;
+
+ rx_chan = i - AXIADO_MBOX_TX_CHANS;
+ ch_data[i].mbox_reg = mb->rx_base +
+ (rx_chan * AXIADO_MBOX_CHAN_STRIDE);
+ ch_data[i].csr_reg = mb->rx_base + AXIADO_MBOX_RX_REG_STRIDE +
+ (rx_chan * AXIADO_MBOX_CHAN_STRIDE);
+ ch_data[i].irq = platform_get_irq(pdev, irq_idx++);
+ if (ch_data[i].irq < 0)
+ return dev_err_probe(dev, ch_data[i].irq,
+ "Failed to get IRQ for channel %u\n", i);
+
+ ret = devm_request_threaded_irq(dev, ch_data[i].irq, NULL,
+ axiado_rx_thread,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ dev_name(dev), &ch_data[i]);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to request IRQ for channel %u\n", i);
+
+ dev_dbg(dev, "RX chan %u -> irq %d\n", i, ch_data[i].irq);
+ }
+
+ platform_set_drvdata(pdev, mb);
+ mb->drv_data = drv_data;
+ mb->mbox.ops = &axiado_mbox_chan_ops;
+ mb->mbox.txdone_irq = false;
+ mb->mbox.txdone_poll = true;
+ mb->mbox.txpoll_period = 5;
+
+ return devm_mbox_controller_register(dev, &mb->mbox);
+}
+
+static const struct axiado_mbox_data axiado_drv_data = {
+ .num_chans = AXIADO_MBOX_TX_CHANS + AXIADO_MBOX_RX_CHANS,
+ .msg_size = 256,
+};
+
+static const struct of_device_id axiado_mbox_of_match[] = {
+ { .compatible = "axiado,ax3005-mailbox", .data = &axiado_drv_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, axiado_mbox_of_match);
+
+static struct platform_driver axiado_mbox_driver = {
+ .driver = {
+ .name = "axiado-mailbox",
+ .of_match_table = axiado_mbox_of_match,
+ },
+ .probe = axiado_mbox_probe,
+};
+module_platform_driver(axiado_mbox_driver);
+
+MODULE_AUTHOR("AXIADO CORPORATION");
+MODULE_DESCRIPTION("Axiado Mailbox driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver
2026-07-30 4:36 ` [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
@ 2026-07-30 4:48 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-30 4:48 UTC (permalink / raw)
To: Swark Yang; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The driver violates I/O accessors guidelines by using register accessors (writel/readl) instead of stream accessors (writesl/readsl) for bulk FIFO transfers.
--
--- Patch [2]: [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver ---
commit 49c49dbc503dbb9fb858d95d2747ac82a8d54442
Author: Swark Yang <syang@axiado.com>
mailbox: add Axiado AX3005 mailbox driver
Add a mailbox controller driver for the Axiado AX3005 SoC.
The controller provides communication channels between
the host CPU and the coprocessor.
> diff --git a/drivers/mailbox/axiado-mailbox.c b/drivers/mailbox/axiado-mailbox.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/mailbox/axiado-mailbox.c
[ ... ]
> +static int axiado_mbox_send_data(struct mbox_chan *chan, void *data)
> +{
[ ... ]
> + for (offset = 0; offset + sizeof(u32) <= msg_len;
> + offset += sizeof(u32))
> + writel(get_unaligned_le32(buf + offset), priv->mbox_reg);
> +
> + tail_len = msg_len - offset;
> + if (tail_len) {
> + memcpy(tail, buf + offset, tail_len);
> + writel(get_unaligned_le32(tail), priv->mbox_reg);
> + }
[Severity: Medium]
Does this code use the correct I/O accessors for FIFO transfers?
According to the I/O accessors guidelines, stream accessors like writesl()
should be used exclusively for FIFOs instead of register accessors like
writel().
While get_unaligned_le32() attempts to cancel out the endianness mapping,
using writel() in a loop introduces unnecessary per-access memory barriers.
Could this be updated to use writesl() for the bulk transfer?
[ ... ]
> +static irqreturn_t axiado_rx_thread(int irq, void *dev_id)
> +{
[ ... ]
> + for (i = 1; i < num_words; i++) {
> + word = readl(priv->mbox_reg);
> + put_unaligned_le32(word,
> + buf + i * sizeof(u32));
> + }
[Severity: Medium]
Similar to the transmit path in axiado_mbox_send_data(), should this loop
use readsl() instead of readl() for reading bulk data from the RX FIFO?
Replacing readl() with readsl() would align with the guidelines for FIFO
data streams and avoid the implicit memory barriers on each read access.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260729-upstream-axiado-ax3005-mailbox-upstream-v1-0-8961b7350338@axiado.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: mailbox: add Axiado AX3005 mailbox
2026-07-30 4:36 ` [PATCH 1/2] dt-bindings: mailbox: add Axiado AX3005 mailbox Swark Yang
@ 2026-07-30 5:59 ` Krzysztof Kozlowski
0 siblings, 0 replies; 5+ messages in thread
From: Krzysztof Kozlowski @ 2026-07-30 5:59 UTC (permalink / raw)
To: Swark Yang, Krishnakumar Kesavan, Prasad Bolisetty, Jassi Brar,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tzu-Hao Wei,
Karthikeyan Mitran
Cc: linux-kernel, devicetree, linux-arm-kernel
On 30/07/2026 06:36, Swark Yang wrote:
> + - Krishnakumar Kesavan <kkesavan@axiado.com>
> + - Prasad Bolisetty <pbolisetty@axiado.com>
> + - Swark Yang <syang@axiado.com>
> +
> +description: |
Do not need '|' unless you need to preserve formatting.
> + The Axiado mailbox controller provides inter-processor communication
> + channels between subsystems within the Axiado SoC. The hardware has
> + separate TX and RX register regions. Only the RX channels (channels 8-15)
> + generate interrupts; TX channels are purely poll/write-based.
> +
> +properties:
> + compatible:
> + const: axiado,ax3005-mailbox
> +
> + reg:
> + items:
> + - description: TX mailbox register region
> + - description: RX mailbox register region
> +
> + reg-names:
> + items:
> + - const: tx
> + - const: rx
> +
> + interrupts:
> + description: |
Do not need '|' unless you need to preserve formatting.
> + One interrupt per RX channel. The hardware exposes eight RX interrupt
> + lines corresponding to channels 8 through 15.
> + minItems: 8
Drop
> + reg-names = "tx", "rx";
> + /* Only RX channels (8-15) have IRQs */
> + interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "ch8", "ch9", "ch10", "ch11",
> + "ch12", "ch13", "ch14", "ch15";
> + interrupt-parent = <&gic500>;
> + #mbox-cells = <1>;
> + status = "okay";
Drop
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-30 5:59 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 4:36 [PATCH 0/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
2026-07-30 4:36 ` [PATCH 1/2] dt-bindings: mailbox: add Axiado AX3005 mailbox Swark Yang
2026-07-30 5:59 ` Krzysztof Kozlowski
2026-07-30 4:36 ` [PATCH 2/2] mailbox: add Axiado AX3005 mailbox driver Swark Yang
2026-07-30 4:48 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox