The driver communicates with the Neutron firmware via eight register-backed mailboxes. A subset of the mailbox registers are used to pass commands from driver to Neutron, while the rest are written by Neutron firmware with status/ack info.
Signed-off-by: Jiwei Fu <[email protected]> Signed-off-by: Ioana Ciocoi-Radulescu <[email protected]> --- drivers/accel/neutron/Makefile | 3 ++- drivers/accel/neutron/neutron_device.c | 4 +++ drivers/accel/neutron/neutron_mailbox.c | 47 +++++++++++++++++++++++++++++++++ drivers/accel/neutron/neutron_mailbox.h | 42 +++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/accel/neutron/Makefile b/drivers/accel/neutron/Makefile index d4298c7a8535..192ed896a9f9 100644 --- a/drivers/accel/neutron/Makefile +++ b/drivers/accel/neutron/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_DRM_ACCEL_NXP_NEUTRON) := neutron.o neutron-y := \ neutron_driver.o \ neutron_device.o \ - neutron_gem.o + neutron_gem.o \ + neutron_mailbox.o diff --git a/drivers/accel/neutron/neutron_device.c b/drivers/accel/neutron/neutron_device.c index 61b3c96b4996..e5c09105be99 100644 --- a/drivers/accel/neutron/neutron_device.c +++ b/drivers/accel/neutron/neutron_device.c @@ -7,6 +7,7 @@ #include <linux/iopoll.h> #include "neutron_device.h" +#include "neutron_mailbox.h" void neutron_enable_irq(struct neutron_device *ndev) { @@ -148,6 +149,9 @@ int neutron_boot(struct neutron_device *ndev) if (ret) return ret; + /* Prepare device to receive jobs */ + neutron_mbox_reset_state(ndev); + ndev->flags |= NEUTRON_BOOTED; return 0; diff --git a/drivers/accel/neutron/neutron_mailbox.c b/drivers/accel/neutron/neutron_mailbox.c new file mode 100644 index 000000000000..327ef2e8081d --- /dev/null +++ b/drivers/accel/neutron/neutron_mailbox.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright 2023, 2025-2026 NXP */ + +#include <linux/iopoll.h> + +#include "neutron_device.h" +#include "neutron_mailbox.h" + +#define NEUTRON_MBOX_FW_STATUS(dev) NEUTRON_REG(dev, MBOX0) +#define NEUTRON_MBOX_FW_ERRCODE(dev) NEUTRON_REG(dev, MBOX1) +#define NEUTRON_MBOX_CMD_ID(dev) NEUTRON_REG(dev, MBOX3) +#define NEUTRON_MBOX_CMD_ARG_BASE(dev) NEUTRON_REG(dev, MBOX4) +#define NEUTRON_MBOX_CMD_ARG(dev, i) (NEUTRON_MBOX_CMD_ARG_BASE(dev) + (i) * 4) + +int neutron_mbox_send_cmd(struct neutron_device *ndev, struct neutron_mbox_cmd *cmd) +{ + u32 status; + int i; + + /* Make sure Neutron is ready to receive commands */ + status = readl_relaxed(NEUTRON_MBOX_FW_STATUS(ndev)); + if (status != NEUTRON_FW_STATUS_RESET) + return -EBUSY; + + for (i = 0; i < NEUTRON_MBOX_MAX_CMD_ARGS; i++) + writel_relaxed(cmd->args[i], NEUTRON_MBOX_CMD_ARG(ndev, i)); + writel(cmd->id, NEUTRON_MBOX_CMD_ID(ndev)); + + return 0; +} + +int neutron_mbox_reset_state(struct neutron_device *ndev) +{ + u32 status; + + writel_relaxed(NEUTRON_CMD_RESET_STATE, NEUTRON_MBOX_CMD_ID(ndev)); + + return readl_poll_timeout(NEUTRON_MBOX_FW_STATUS(ndev), status, + status == NEUTRON_FW_STATUS_RESET, + 100, 100 * USEC_PER_MSEC); +} + +void neutron_mbox_read_state(struct neutron_device *ndev, struct neutron_mbox_state *state) +{ + state->status = readl_relaxed(NEUTRON_MBOX_FW_STATUS(ndev)); + state->err_code = readl_relaxed(NEUTRON_MBOX_FW_ERRCODE(ndev)); +} diff --git a/drivers/accel/neutron/neutron_mailbox.h b/drivers/accel/neutron/neutron_mailbox.h new file mode 100644 index 000000000000..4fe40a2f6a0c --- /dev/null +++ b/drivers/accel/neutron/neutron_mailbox.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright 2023, 2025-2026 NXP */ + +#ifndef __NEUTRON_MAILBOX_H__ +#define __NEUTRON_MAILBOX_H__ + +#include <linux/types.h> + +struct neutron_device; + +/* Device (firmware) status magic values */ +enum neutron_mbox_fwstat { + NEUTRON_FW_STATUS_RESET = 0, + NEUTRON_FW_STATUS_ACK = 0xA3, + NEUTRON_FW_STATUS_DONE = 0xAD0, +}; + +/* Firmware command opcodes */ +enum neutron_mbox_cmdid { + NEUTRON_CMD_INFERENCE = 0x269, + NEUTRON_CMD_RESET_STATE = 0x23637, +}; + +#define NEUTRON_MBOX_MAX_CMD_ARGS 4 + +/* Firmware command */ +struct neutron_mbox_cmd { + enum neutron_mbox_cmdid id; + u32 args[NEUTRON_MBOX_MAX_CMD_ARGS]; +}; + +/* Device state */ +struct neutron_mbox_state { + enum neutron_mbox_fwstat status; + u32 err_code; +}; + +int neutron_mbox_send_cmd(struct neutron_device *ndev, struct neutron_mbox_cmd *cmd); +void neutron_mbox_read_state(struct neutron_device *ndev, struct neutron_mbox_state *state); +int neutron_mbox_reset_state(struct neutron_device *ndev); + +#endif /* __NEUTRON_MAILBOX_H__ */ -- 2.34.1
