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...@nxp.com>
---
v19->v20:
- new patch in v20.
  The patch split from Patch #1 in v19 and move to a new folder 
drivers/soc/cadence

 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 | 565 +++++++++++++++++++++++++
 include/soc/cadence/cdns-mhdp-helper.h | 129 ++++++
 6 files changed, 708 insertions(+)
 create mode 100644 drivers/soc/cadence/Kconfig
 create mode 100644 drivers/soc/cadence/Makefile
 create mode 100644 drivers/soc/cadence/cdns-mhdp-helper.c
 create mode 100644 include/soc/cadence/cdns-mhdp-helper.h

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 6a8daeb8c4b96..f6c18114b2d68 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 2037a8695cb28..a5fa4f4d15321 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..b668790660fa5
--- /dev/null
+++ b/drivers/soc/cadence/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CDNS_MHDP_HELPER
+       tristate "Cadence MHDP Helper driver"
+       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..f74b4cae134a2
--- /dev/null
+++ b/drivers/soc/cadence/cdns-mhdp-helper.c
@@ -0,0 +1,565 @@
+// 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>
+
+/* Protects mailbox communications with the firmware */
+static DEFINE_MUTEX(mhdp_mailbox_mutex);
+
+/* Mailbox helper functions */
+static int mhdp_mailbox_read(void __iomem *regs)
+{
+       int ret, empty;
+
+       WARN_ON(!mutex_is_locked(&mhdp_mailbox_mutex));
+
+       ret = readx_poll_timeout(readl, regs + CDNS_MAILBOX_EMPTY,
+                                empty, !empty, MAILBOX_RETRY_US,
+                                MAILBOX_TIMEOUT_US);
+       if (ret < 0)
+               return ret;
+
+       return readl(regs + CDNS_MAILBOX_RX_DATA) & 0xff;
+}
+
+static int mhdp_mailbox_write(void __iomem *regs, u8 val)
+{
+       int ret, full;
+
+       WARN_ON(!mutex_is_locked(&mhdp_mailbox_mutex));
+
+       ret = readx_poll_timeout(readl, regs + CDNS_MAILBOX_FULL,
+                                full, !full, MAILBOX_RETRY_US,
+                                MAILBOX_TIMEOUT_US);
+       if (ret < 0)
+               return ret;
+
+       writel(val, regs + CDNS_MAILBOX_TX_DATA);
+
+       return 0;
+}
+
+static int mhdp_mailbox_recv_header(void __iomem *regs,
+                                   u8 module_id, u8 opcode,
+                                   u16 req_size)
+{
+       u32 mbox_size, i;
+       u8 header[4];
+       int ret;
+
+       /* read the header of the message */
+       for (i = 0; i < sizeof(header); i++) {
+               ret = mhdp_mailbox_read(regs);
+               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 (mhdp_mailbox_read(regs) < 0)
+                               break;
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mhdp_mailbox_recv_data(void __iomem *regs,
+                                 u8 *buff, u16 buff_size)
+{
+       u32 i;
+       int ret;
+
+       for (i = 0; i < buff_size; i++) {
+               ret = mhdp_mailbox_read(regs);
+               if (ret < 0)
+                       return ret;
+
+               buff[i] = ret;
+       }
+
+       return 0;
+}
+
+static int mhdp_mailbox_send(void __iomem *regs, u8 module_id,
+                            u8 opcode, u16 size, u8 *message)
+{
+       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++) {
+               ret = mhdp_mailbox_write(regs, header[i]);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < size; i++) {
+               ret = mhdp_mailbox_write(regs, 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)(&mhdp_mailbox_mutex);
+
+       return mhdp_mailbox_send(base->regs, module_id, opcode, size, message);
+}
+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)(&mhdp_mailbox_mutex);
+
+       ret = mhdp_mailbox_send(base->regs, module_id,
+                               opcode, msg_size, msg);
+       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->regs, module_id,
+                                      opcode, resp_size);
+       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->regs, resp, resp_size);
+       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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param module_id: ID of the module to send the message to.
+ * @param opcode: Operation code of the message.
+ * @param msg_size: Size of the message data.
+ * @param msg: Pointer to the message data.
+ * @param opcode_resp: Operation code of the response.
+ * @param resp1_size: Size of the first response buffer.
+ * @param resp1: Pointer to the first response buffer.
+ * @param resp2_size: Size of the second response buffer.
+ * @param 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)(&mhdp_mailbox_mutex);
+
+       ret = mhdp_mailbox_send(base->regs, module_id,
+                               opcode, msg_size, msg);
+       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->regs, module_id, opcode_resp,
+                                      resp1_size + resp2_size);
+       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->regs, resp1, resp1_size);
+       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->regs, resp2, resp2_size);
+       if (ret)
+               dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data1 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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param module_id: ID of the module to send the message to.
+ * @param opcode: Operation code of the message.
+ * @param size: Size of the message data.
+ * @param 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)(&mhdp_mailbox_mutex);
+
+       return mhdp_mailbox_send(base->sapb_regs, module_id, opcode, size, 
message);
+}
+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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param module_id: ID of the module to send the message to.
+ * @param opcode: Operation code of the message.
+ * @param msg_size: Size of the message data.
+ * @param msg: Pointer to the message data.
+ * @param resp_size: Size of the response buffer.
+ * @param 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)(&mhdp_mailbox_mutex);
+
+       ret = mhdp_mailbox_send(base->sapb_regs, module_id,
+                               opcode, msg_size, msg);
+       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->sapb_regs, module_id,
+                                      opcode, resp_size);
+       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->sapb_regs, resp, resp_size);
+       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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param module_id: ID of the module to send the message to.
+ * @param opcode: Operation code of the message.
+ * @param msg_size: Size of the message data.
+ * @param msg: Pointer to the message data.
+ * @param opcode_resp: Operation code of the response.
+ * @param resp1_size: Size of the first response buffer.
+ * @param resp1: Pointer to the first response buffer.
+ * @param resp2_size: Size of the second response buffer.
+ * @param 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)(&mhdp_mailbox_mutex);
+
+       ret = mhdp_mailbox_send(base->sapb_regs, module_id,
+                               opcode, msg_size, msg);
+       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->sapb_regs, module_id,
+                                      opcode_resp,
+                                      resp1_size + resp2_size);
+       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->sapb_regs, resp1, resp1_size);
+       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->sapb_regs, resp2, 5 * 
resp1[0]);
+       else
+               ret = mhdp_mailbox_recv_data(base->sapb_regs, resp2, 
resp2_size);
+       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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param addr: Address of the register to read.
+ * @param 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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param addr: Address of the register to write to.
+ * @param 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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param addr: Address of the DP register.
+ * @param start_bit: Starting bit position within the register.
+ * @param bits_no: Number of bits to write.
+ * @param 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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param addr: Address of the DPCD register to read.
+ * @param data: Buffer to store the read data.
+ * @param 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.
+ *
+ * @param base: Pointer to the CDNS MHDP base structure.
+ * @param addr: Address of the DPCD register to write to.
+ * @param 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...@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..25b9737de615f
--- /dev/null
+++ b/include/soc/cadence/cdns-mhdp-helper.h
@@ -0,0 +1,129 @@
+/* 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/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    0x09
+#define HDCP_TRAN_TEST_KEYS                    0x0a
+#define HDCP2X_TX_SET_KM_KEY_PARAMS            0x0b
+#define HDCP_NUM_OF_SUPPORTED_MESSAGES         0x0c
+
+struct cdns_mhdp_base {
+       struct device *dev;
+       void __iomem *regs;
+       void __iomem *sapb_regs;
+};
+
+/* 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.34.1

Reply via email to