[PATCH v22 1/8] soc: cadence: Create helper functions for Cadence MHDP

Laurentiu Palcu
2026-04-24T11:08:01Z

From: Sandor Yu <Sandor.yu@nxp.com>

Cadence MHDP IP includes a firmware. Driver and firmware communicate
through a mailbox. The basic mailbox access functions in this patch are
derived from the DRM bridge MHDP8546 driver. New mailbox access
functions have been created based on different mailbox return values and
security types, making them reusable across different MHDP driver
versions and SOCs.

These helper fucntions will be reused in both the DRM bridge driver
MDHP8501 and the i.MX8MQ HDPTX PHY driver.

Six mailbox access helper functions are introduced.
Three for non-secure mailbox access:
- cdns_mhdp_mailbox_send()
- cdns_mhdp_mailbox_send_recv()
- cdns_mhdp_mailbox_send_recv_multi()
The other three for secure mailbox access:
- cdns_mhdp_secure_mailbox_send()
- cdns_mhdp_secure_mailbox_send_recv()
- cdns_mhdp_secure_mailbox_send_recv_multi()

All MHDP commands that need to be passed through the mailbox
should be rewritten using these new helper functions.

The register read/write and DP DPCD read/write command functions
are also included in this new helper driver.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
Co-developed-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>

---
To: Parshuram Thombare <pthombar@cadence.com>
To: Swapnil Jakhade <sjakhade@cadence.com>
To: Dmitry Baryshkov <lumag@kernel.org>
To: Nikhil Devshatwar <nikhil.nd@ti.com>
To: Jayesh Choudhary <j-choudhary@ti.com>
---
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/cadence/Kconfig | 9 +
drivers/soc/cadence/Makefile | 3 +
drivers/soc/cadence/cdns-mhdp-helper.c | 611 +++++++++++++++++++++++++++++++++
include/soc/cadence/cdns-mhdp-helper.h | 143 ++++++++
6 files changed, 768 insertions(+)

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index a2d65adffb805..8f2114b9a6b7d 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -6,6 +6,7 @@ source "drivers/soc/apple/Kconfig"
source "drivers/soc/aspeed/Kconfig"
source "drivers/soc/atmel/Kconfig"
source "drivers/soc/bcm/Kconfig"
+source "drivers/soc/cadence/Kconfig"
source "drivers/soc/canaan/Kconfig"
source "drivers/soc/cirrus/Kconfig"
source "drivers/soc/fsl/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index c9e689080ceb7..33612ccdf5c47 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -7,6 +7,7 @@ obj-y += apple/
obj-y += aspeed/
obj-$(CONFIG_ARCH_AT91) += atmel/
obj-y += bcm/
+obj-y += cadence/
obj-$(CONFIG_ARCH_CANAAN) += canaan/
obj-$(CONFIG_EP93XX_SOC) += cirrus/
obj-$(CONFIG_ARCH_DOVE) += dove/
diff --git a/drivers/soc/cadence/Kconfig b/drivers/soc/cadence/Kconfig
new file mode 100644
index 0000000000000..d4a8e8e751882
--- /dev/null
+++ b/drivers/soc/cadence/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CDNS_MHDP_HELPER
+ tristate
+ help
+ Enable Cadence MHDP helpers for mailbox, HDMI and DP.
+ This driver provides a foundational layer of mailbox communication for
+ various Cadence MHDP IP implementations, such as HDMI and DisplayPort.
+
diff --git a/drivers/soc/cadence/Makefile b/drivers/soc/cadence/Makefile
new file mode 100644
index 0000000000000..a1f42e1936ca5
--- /dev/null
+++ b/drivers/soc/cadence/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_CDNS_MHDP_HELPER) += cdns-mhdp-helper.o
diff --git a/drivers/soc/cadence/cdns-mhdp-helper.c b/drivers/soc/cadence/cdns-mhdp-helper.c
new file mode 100644
index 0000000000000..5657e88131ba1
--- /dev/null
+++ b/drivers/soc/cadence/cdns-mhdp-helper.c
@@ -0,0 +1,611 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, 2024 NXP Semiconductor, Inc.
+ *
+ */
+#include <linux/dev_printk.h>
+#include <linux/module.h>
+#include <soc/cadence/cdns-mhdp-helper.h>
+
+/* Mailbox helper functions */
+static int mhdp_mailbox_read(struct cdns_mhdp_base *base)
+{
+ int ret, empty;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->regs + CDNS_MAILBOX_EMPTY,
+ empty, !empty, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ return readl(base->regs + CDNS_MAILBOX_RX_DATA) & 0xff;
+}
+
+static int mhdp_mailbox_write(struct cdns_mhdp_base *base, u8 val)
+{
+ int ret, full;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->regs + CDNS_MAILBOX_FULL,
+ full, !full, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ writel(val, base->regs + CDNS_MAILBOX_TX_DATA);
+
+ return 0;
+}
+
+static int mhdp_mailbox_read_secure(struct cdns_mhdp_base *base)
+{
+ int ret, empty;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->sapb_regs + CDNS_MAILBOX_EMPTY,
+ empty, !empty, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ return readl(base->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff;
+}
+
+static int mhdp_mailbox_write_secure(struct cdns_mhdp_base *base, u8 val)
+{
+ int ret, full;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->sapb_regs + CDNS_MAILBOX_FULL,
+ full, !full, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ writel(val, base->sapb_regs + CDNS_MAILBOX_TX_DATA);
+
+ return 0;
+}
+
+static int mhdp_mailbox_recv_header(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 req_size, bool secure)
+{
+ u32 mbox_size, i;
+ u8 header[4];
+ int ret;
+
+ /* read the header of the message */
+ for (i = 0; i < sizeof(header); i++) {
+ if (secure)
+ ret = mhdp_mailbox_read_secure(base);
+ else
+ ret = mhdp_mailbox_read(base);
+ if (ret < 0)
+ return ret;
+
+ header[i] = ret;
+ }
+
+ mbox_size = get_unaligned_be16(header + 2);
+
+ /*
+ * If the message in mailbox is not what we want, we need to
+ * clear the mailbox by reading its contents.
+ * Response data length for HDCP TX HDCP_TRAN_IS_REC_ID_VALID depend on
+ * case.
+ */
+ if (opcode != header[0] ||
+ module_id != header[1] ||
+ (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) {
+ for (i = 0; i < mbox_size; i++) {
+ if (secure)
+ ret = mhdp_mailbox_read_secure(base);
+ else
+ ret = mhdp_mailbox_read(base);
+ if (ret < 0)
+ break;
+ }
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mhdp_mailbox_recv_data(struct cdns_mhdp_base *base,
+ u8 *buff, u16 buff_size, bool secure)
+{
+ u32 i;
+ int ret;
+
+ for (i = 0; i < buff_size; i++) {
+ if (secure)
+ ret = mhdp_mailbox_read_secure(base);
+ else
+ ret = mhdp_mailbox_read(base);
+ if (ret < 0)
+ return ret;
+
+ buff[i] = ret;
+ }
+
+ return 0;
+}
+
+static int mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 module_id,
+ u8 opcode, u16 size, u8 *message, bool secure)
+{
+ u8 header[4];
+ int ret, i;
+
+ header[0] = opcode;
+ header[1] = module_id;
+ put_unaligned_be16(size, header + 2);
+
+ for (i = 0; i < sizeof(header); i++) {
+ if (secure)
+ ret = mhdp_mailbox_write_secure(base, header[i]);
+ else
+ ret = mhdp_mailbox_write(base, header[i]);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (secure)
+ ret = mhdp_mailbox_write_secure(base, message[i]);
+ else
+ ret = mhdp_mailbox_write(base, message[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns_mhdp_mailbox_send - Sends a message via the MHDP mailbox.
+ *
+ * This function sends a message via the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @size: Size of the message data.
+ * @message: Pointer to the message data.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 module_id,
+ u8 opcode, u16 size, u8 *message)
+{
+ guard(mutex)(&base->mailbox_mutex);
+
+ return mhdp_mailbox_send(base, module_id, opcode, size, message, false);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send);
+
+/**
+ * cdns_mhdp_mailbox_send_recv - Sends a message and receives a response.
+ *
+ * This function sends a message via the mailbox and then receives a response.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @resp_size: Size of the response buffer.
+ * @resp: Pointer to the response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode, resp_size, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv header failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp, resp_size, false);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv data failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send_recv);
+
+/**
+ * cdns_mhdp_mailbox_send_recv_multi - Sends a message and receives multiple
+ * responses.
+ *
+ * This function sends a message to a specified module via the MHDP mailbox and
+ * then receives multiple responses from the module.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @opcode_resp: Operation code of the response.
+ * @resp1_size: Size of the first response buffer.
+ * @resp1: Pointer to the first response buffer.
+ * @resp2_size: Size of the second response buffer.
+ * @resp2: Pointer to the second response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode_resp,
+ resp1_size + resp2_size, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv header failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp1, resp1_size, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data1 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp2, resp2_size, false);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data2 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send_recv_multi);
+
+/**
+ * cdns_mhdp_secure_mailbox_send - Sends a secure message via the mailbox.
+ *
+ * This function sends a secure message to a specified module via the MHDP
+ * mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @size: Size of the message data.
+ * @message: Pointer to the message data.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_base *base, u8 module_id,
+ u8 opcode, u16 size, u8 *message)
+{
+ guard(mutex)(&base->mailbox_mutex);
+
+ return mhdp_mailbox_send(base, module_id, opcode, size, message, true);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send);
+
+/**
+ * cdns_mhdp_secure_mailbox_send_recv - Sends a secure message and receives a
+ * response.
+ *
+ * This function sends a secure message to a specified module via the mailbox
+ * and then receives a response from the module.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @resp_size: Size of the response buffer.
+ * @resp: Pointer to the response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_secure_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode, resp_size, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv header failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp, resp_size, true);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv data failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send_recv);
+
+/**
+ * cdns_mhdp_secure_mailbox_send_recv_multi - Sends a secure message and
+ * receives multiple responses.
+ *
+ * This function sends a secure message to a specified module and receives
+ * multiple responses.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @opcode_resp: Operation code of the response.
+ * @resp1_size: Size of the first response buffer.
+ * @resp1: Pointer to the first response buffer.
+ * @resp2_size: Size of the second response buffer.
+ * @resp2: Pointer to the second response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_secure_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode_resp,
+ resp1_size + resp2_size, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv header failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp1, resp1_size, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data1 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ /*
+ * Response data length for HDCP TX HDCP_TRAN_IS_REC_ID_VALID depend on
+ * the number of HDCP receivers in resp1[0].
+ * 1 for regular case, more can be in repeater.
+ */
+ if (module_id == MB_MODULE_ID_HDCP_TX &&
+ opcode == HDCP_TRAN_IS_REC_ID_VALID)
+ ret = mhdp_mailbox_recv_data(base, resp2, 5 * resp1[0], true);
+ else
+ ret = mhdp_mailbox_recv_data(base, resp2, resp2_size, true);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data2 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send_recv_multi);
+
+/**
+ * cdns_mhdp_reg_read - Reads a general register value.
+ *
+ * This function reads the value from a general register
+ * using the mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the register to read.
+ * @value: Pointer to store the read value.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_reg_read(struct cdns_mhdp_base *base, u32 addr, u32 *value)
+{
+ u8 msg[4], resp[8];
+ int ret;
+
+ put_unaligned_be32(addr, msg);
+
+ ret = cdns_mhdp_mailbox_send_recv(base, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_READ,
+ sizeof(msg), msg, sizeof(resp), resp);
+ if (ret)
+ goto out;
+
+ /* Returned address value should be the same as requested */
+ if (memcmp(msg, resp, sizeof(msg))) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *value = get_unaligned_be32(resp + 4);
+out:
+ if (ret) {
+ dev_err(base->dev, "Failed to read register\n");
+ *value = 0;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_reg_read);
+
+/**
+ * cdns_mhdp_reg_write - Writes a value to a general register.
+ *
+ * This function writes a value to a general register using the mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the register to write to.
+ * @val: Value to write to the register.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_reg_write(struct cdns_mhdp_base *base, u32 addr, u32 val)
+{
+ u8 msg[8];
+
+ put_unaligned_be32(addr, msg);
+ put_unaligned_be32(val, msg + 4);
+
+ return cdns_mhdp_mailbox_send(base, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_WRITE,
+ sizeof(msg), msg);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_reg_write);
+
+/* DPTX helper functions */
+/**
+ * cdns_mhdp_dp_reg_write_bit - Writes a bit field to a DP register.
+ *
+ * This function writes a specific bit field within a DP register
+ * using the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the DP register.
+ * @start_bit: Starting bit position within the register.
+ * @bits_no: Number of bits to write.
+ * @val: Value to write to the bit field.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_dp_reg_write_bit(struct cdns_mhdp_base *base, u16 addr,
+ u8 start_bit, u8 bits_no, u32 val)
+{
+ u8 field[8];
+
+ put_unaligned_be16(addr, field);
+ field[2] = start_bit;
+ field[3] = bits_no;
+ put_unaligned_be32(val, field + 4);
+
+ return cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_FIELD, sizeof(field), field);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_dp_reg_write_bit);
+
+/**
+ * cdns_mhdp_dpcd_read - Reads data from a DPCD register.
+ *
+ * This function reads data from a specified DPCD register
+ * using the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the DPCD register to read.
+ * @data: Buffer to store the read data.
+ * @len: Length of the data to read.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_base *base,
+ u32 addr, u8 *data, u16 len)
+{
+ u8 msg[5], reg[5];
+
+ put_unaligned_be16(len, msg);
+ put_unaligned_be24(addr, msg + 2);
+
+ return cdns_mhdp_mailbox_send_recv_multi(base,
+ MB_MODULE_ID_DP_TX,
+ DPTX_READ_DPCD,
+ sizeof(msg), msg,
+ DPTX_READ_DPCD,
+ sizeof(reg), reg,
+ len, data);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_dpcd_read);
+
+/**
+ * cdns_mhdp_dpcd_write - Writes data to a DPCD register.
+ *
+ * This function writes data to a specified DPCD register
+ * using the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the DPCD register to write to.
+ * @value: Value to write to the register.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_base *base, u32 addr, u8 value)
+{
+ u8 msg[6], reg[5];
+ int ret;
+
+ put_unaligned_be16(1, msg);
+ put_unaligned_be24(addr, msg + 2);
+ msg[5] = value;
+
+ ret = cdns_mhdp_mailbox_send_recv(base, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_DPCD,
+ sizeof(msg), msg, sizeof(reg), reg);
+ if (ret) {
+ dev_err(base->dev, "dpcd write failed: %d\n", ret);
+ return ret;
+ }
+
+ if (addr != get_unaligned_be24(reg + 2)) {
+ dev_err(base->dev,
+ "Invalid response: expected address 0x%06x, got 0x%06x\n",
+ addr, get_unaligned_be24(reg + 2));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_dpcd_write);
+
+MODULE_DESCRIPTION("Cadence MHDP Helper driver");
+MODULE_AUTHOR("Sandor Yu <Sandor.yu@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/cadence/cdns-mhdp-helper.h b/include/soc/cadence/cdns-mhdp-helper.h
new file mode 100644
index 0000000000000..7e2ceb848fc2d
--- /dev/null
+++ b/include/soc/cadence/cdns-mhdp-helper.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023-2024 NXP Semiconductor, Inc.
+ */
+#ifndef __CDNS_MHDP_HELPER_H__
+#define __CDNS_MHDP_HELPER_H__
+
+#include <linux/iopoll.h>
+#include <linux/mutex.h>
+#include <linux/unaligned.h>
+
+/* mailbox regs offset */
+#define CDNS_MAILBOX_FULL 0x00008
+#define CDNS_MAILBOX_EMPTY 0x0000c
+#define CDNS_MAILBOX_TX_DATA 0x00010
+#define CDNS_MAILBOX_RX_DATA 0x00014
+
+#define MAILBOX_RETRY_US 1000
+#define MAILBOX_TIMEOUT_US 2000000
+
+/* Module ID Code */
+#define MB_MODULE_ID_DP_TX 0x01
+#define MB_MODULE_ID_HDMI_TX 0x03
+#define MB_MODULE_ID_HDCP_TX 0x07
+#define MB_MODULE_ID_HDCP_RX 0x08
+#define MB_MODULE_ID_HDCP_GENERAL 0x09
+#define MB_MODULE_ID_GENERAL 0x0A
+
+/* General Commands */
+#define GENERAL_MAIN_CONTROL 0x01
+#define GENERAL_TEST_ECHO 0x02
+#define GENERAL_BUS_SETTINGS 0x03
+#define GENERAL_TEST_ACCESS 0x04
+#define GENERAL_REGISTER_WRITE 0x05
+#define GENERAL_WRITE_FIELD 0x06
+#define GENERAL_REGISTER_READ 0x07
+#define GENERAL_GET_HPD_STATE 0x11
+
+/* DPTX Commands */
+#define DPTX_SET_POWER_MNG 0x00
+#define DPTX_SET_HOST_CAPABILITIES 0x01
+#define DPTX_GET_EDID 0x02
+#define DPTX_READ_DPCD 0x03
+#define DPTX_WRITE_DPCD 0x04
+#define DPTX_ENABLE_EVENT 0x05
+#define DPTX_WRITE_REGISTER 0x06
+#define DPTX_READ_REGISTER 0x07
+#define DPTX_WRITE_FIELD 0x08
+#define DPTX_TRAINING_CONTROL 0x09
+#define DPTX_READ_EVENT 0x0a
+#define DPTX_READ_LINK_STAT 0x0b
+#define DPTX_SET_VIDEO 0x0c
+#define DPTX_SET_AUDIO 0x0d
+#define DPTX_GET_LAST_AUX_STAUS 0x0e
+#define DPTX_SET_LINK_BREAK_POINT 0x0f
+#define DPTX_FORCE_LANES 0x10
+#define DPTX_HPD_STATE 0x11
+#define DPTX_ADJUST_LT 0x12
+
+/* HDMI TX Commands */
+#define HDMI_TX_READ 0x00
+#define HDMI_TX_WRITE 0x01
+#define HDMI_TX_UPDATE_READ 0x02
+#define HDMI_TX_EDID 0x03
+#define HDMI_TX_EVENTS 0x04
+#define HDMI_TX_HPD_STATUS 0x05
+
+/* HDCP TX Commands */
+#define HDCP_TRAN_CONFIGURATION 0x00
+#define HDCP2X_TX_SET_PUBLIC_KEY_PARAMS 0x01
+#define HDCP2X_TX_SET_DEBUG_RANDOM_NUMBERS 0x02
+#define HDCP2X_TX_RESPOND_KM 0x03
+#define HDCP1_TX_SEND_KEYS 0x04
+#define HDCP1_TX_SEND_RANDOM_AN 0x05
+#define HDCP_TRAN_STATUS_CHANGE 0x06
+#define HDCP2X_TX_IS_KM_STORED 0x07
+#define HDCP2X_TX_STORE_KM 0x08
+#define HDCP_TRAN_IS_REC_ID_VALID 0x09
+#define HDCP_TRAN_RESPOND_RECEIVER_ID_VALID 0x0a
+#define HDCP_TRAN_TEST_KEYS 0x0b
+#define HDCP2X_TX_SET_KM_KEY_PARAMS 0x0c
+#define HDCP_NUM_OF_SUPPORTED_MESSAGES 0x0d
+
+/**
+ * struct cdns_mhdp_base - Base structure for CDNS MHDP devices
+ * @dev: Pointer to the device structure
+ * @regs: Base address of the regular register space
+ * @sapb_regs: Base address of the secure APB register space
+ * @mailbox_mutex: Mutex to protect mailbox communications with firmware
+ *
+ * This structure contains the base resources needed for CDNS MHDP helper
+ * functions. Each device instance should have its own cdns_mhdp_base structure
+ * to ensure proper isolation of mailbox operations between multiple devices.
+ */
+struct cdns_mhdp_base {
+ struct device *dev;
+ void __iomem *regs;
+ void __iomem *sapb_regs;
+ struct mutex mailbox_mutex;
+};
+
+/* Mailbox helper functions */
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 size, u8 *message);
+int cdns_mhdp_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp);
+int cdns_mhdp_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2);
+
+/* Secure mailbox helper functions */
+int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 size, u8 *message);
+int cdns_mhdp_secure_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp);
+int cdns_mhdp_secure_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2);
+
+/* General commands helper functions */
+int cdns_mhdp_reg_read(struct cdns_mhdp_base *base, u32 addr, u32 *value);
+int cdns_mhdp_reg_write(struct cdns_mhdp_base *base, u32 addr, u32 val);
+
+/* DPTX commands helper functions */
+int cdns_mhdp_dp_reg_write_bit(struct cdns_mhdp_base *base, u16 addr,
+ u8 start_bit, u8 bits_no, u32 val);
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_base *base,
+ u32 addr, u8 *data, u16 len);
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_base *base, u32 addr, u8 value);
+
+#endif /* __CDNS_MHDP_HELPER_H__ */

--
2.51.0