@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <linux/wait.h>
+#include <drm/bridge/cdns-mhdp-mailbox.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_hdcp_helper.h>
#include <drm/drm_atomic.h>
@@ -54,200 +55,6 @@
#include "cdns-mhdp8546-hdcp.h"
#include "cdns-mhdp8546-j721e.h"
-static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
-{
- int ret, empty;
-
- WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
-
- ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_EMPTY,
- empty, !empty, MAILBOX_RETRY_US,
- MAILBOX_TIMEOUT_US);
- if (ret < 0)
- return ret;
-
- return readl(mhdp->regs + CDNS_MAILBOX_RX_DATA) & 0xff;
-}
-
-static int cdns_mhdp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
-{
- int ret, full;
-
- WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
-
- ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_FULL,
- full, !full, MAILBOX_RETRY_US,
- MAILBOX_TIMEOUT_US);
- if (ret < 0)
- return ret;
-
- writel(val, mhdp->regs + CDNS_MAILBOX_TX_DATA);
-
- return 0;
-}
-
-static int cdns_mhdp_mailbox_recv_header(struct cdns_mhdp_device *mhdp,
- 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 = cdns_mhdp_mailbox_read(mhdp);
- if (ret < 0)
- return ret;
-
- header[i] = ret;
- }
-
- mbox_size = get_unaligned_be16(header + 2);
-
- if (opcode != header[0] || module_id != header[1] ||
- req_size != mbox_size) {
- /*
- * If the message in mailbox is not what we want, we need to
- * clear the mailbox by reading its contents.
- */
- for (i = 0; i < mbox_size; i++)
- if (cdns_mhdp_mailbox_read(mhdp) < 0)
- break;
-
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int cdns_mhdp_mailbox_recv_data(struct cdns_mhdp_device *mhdp,
- u8 *buff, u16 buff_size)
-{
- u32 i;
- int ret;
-
- for (i = 0; i < buff_size; i++) {
- ret = cdns_mhdp_mailbox_read(mhdp);
- if (ret < 0)
- return ret;
-
- buff[i] = ret;
- }
-
- return 0;
-}
-
-static int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, 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 = cdns_mhdp_mailbox_write(mhdp, header[i]);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < size; i++) {
- ret = cdns_mhdp_mailbox_write(mhdp, message[i]);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static
-int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr, u32 *value)
-{
- u8 msg[4], resp[8];
- int ret;
-
- put_unaligned_be32(addr, msg);
-
- mutex_lock(&mhdp->mbox_mutex);
-
- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
- GENERAL_REGISTER_READ,
- sizeof(msg), msg);
- if (ret)
- goto out;
-
- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_GENERAL,
- GENERAL_REGISTER_READ,
- sizeof(resp));
- if (ret)
- goto out;
-
- ret = cdns_mhdp_mailbox_recv_data(mhdp, resp, sizeof(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:
- mutex_unlock(&mhdp->mbox_mutex);
- if (ret) {
- dev_err(mhdp->dev, "Failed to read register\n");
- *value = 0;
- }
-
- return ret;
-}
-
-static
-int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val)
-{
- u8 msg[6];
- int ret;
-
- put_unaligned_be16(addr, msg);
- put_unaligned_be32(val, msg + 2);
-
- mutex_lock(&mhdp->mbox_mutex);
-
- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
- DPTX_WRITE_REGISTER, sizeof(msg), msg);
-
- mutex_unlock(&mhdp->mbox_mutex);
-
- return ret;
-}
-
-static
-int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
- u8 start_bit, u8 bits_no, u32 val)
-{
- u8 field[8];
- int ret;
-
- put_unaligned_be16(addr, field);
- field[2] = start_bit;
- field[3] = bits_no;
- put_unaligned_be32(val, field + 4);
-
- mutex_lock(&mhdp->mbox_mutex);
-
- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
- DPTX_WRITE_FIELD, sizeof(field), field);
-
- mutex_unlock(&mhdp->mbox_mutex);
-
- return ret;
-}
-
static
int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
u32 addr, u8 *data, u16 len)
@@ -212,7 +212,6 @@ struct phy;
#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
/* firmware and opcodes */
#define FW_NAME "cadence/mhdp8546.bin"
new file mode 100644
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence MHDP Firmware Access API function by Malibox.
+ *
+ * Copyright (C) 2022 NXP Semiconductor, Inc.
+ *
+ */
+#ifndef CDNS_MHDP_MAILBOX_H
+#define CDNS_MHDP_MAILBOX_H
+
+#include <asm/unaligned.h>
+#include <linux/iopoll.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_GENERAL 0x0A
+#define MB_MODULE_ID_DP_TX 0x01
+
+/* General Commands */
+#define GENERAL_REGISTER_WRITE 0x05
+#define GENERAL_REGISTER_READ 0x07
+
+/* DP TX Command */
+#define DPTX_WRITE_FIELD 0x08
+
+/* MHDP Firmware access functions by Mailbox */
+#define cdns_mhdp_mailbox_read(_mhdp) \
+({ \
+ int ret, empty, val; \
+\
+ WARN_ON(!mutex_is_locked(&(_mhdp)->mbox_mutex)); \
+\
+ do { \
+ ret = readx_poll_timeout(readl, (_mhdp)->regs + CDNS_MAILBOX_EMPTY, \
+ empty, !empty, MAILBOX_RETRY_US, \
+ MAILBOX_TIMEOUT_US); \
+ if (ret < 0) \
+ break; \
+\
+ val = readl((_mhdp)->regs + CDNS_MAILBOX_RX_DATA) & 0xff; \
+ } while (0); \
+\
+ (ret < 0) ? ret : val; \
+})
+
+#define cdns_mhdp_mailbox_write(_mhdp, _val) \
+({ \
+ int ret, full; \
+\
+ WARN_ON(!mutex_is_locked(&(_mhdp)->mbox_mutex)); \
+\
+ do { \
+ ret = readx_poll_timeout(readl, (_mhdp)->regs + CDNS_MAILBOX_FULL, \
+ full, !full, MAILBOX_RETRY_US, \
+ MAILBOX_TIMEOUT_US); \
+ if (ret < 0) \
+ break; \
+\
+ writel((_val), (_mhdp)->regs + CDNS_MAILBOX_TX_DATA); \
+ } while (0); \
+\
+ ret; \
+})
+
+#define cdns_mhdp_mailbox_recv_header(_mhdp, _module_id, _opcode, _req_size) \
+({ \
+ u32 mbox_size, i; \
+ u8 header[4]; \
+ int ret; \
+\
+ do { \
+ /* read the header of the message */ \
+ for (i = 0; i < sizeof(header); i++) { \
+ ret = cdns_mhdp_mailbox_read(_mhdp); \
+ if (ret < 0) \
+ break; \
+\
+ header[i] = ret; \
+ } \
+\
+ mbox_size = get_unaligned_be16(header + 2); \
+\
+ if ((_opcode) != header[0] || (_module_id) != header[1] || \
+ (_req_size) != mbox_size) { \
+ /* If the message in mailbox is not what we want, we need to
+ * clear the mailbox by reading its contents. */ \
+ for (i = 0; i < mbox_size; i++) \
+ if (cdns_mhdp_mailbox_read(_mhdp) < 0) \
+ break; \
+\
+ ret = -EINVAL; \
+ } \
+\
+ ret = 0; \
+\
+ } while (0); \
+\
+ ret; \
+})
+
+#define cdns_mhdp_mailbox_recv_data(_mhdp, _buff, _buff_size) \
+({ \
+ u32 i; \
+ int ret; \
+\
+ do { \
+ for (i = 0; i < (_buff_size); i++) { \
+ ret = cdns_mhdp_mailbox_read(_mhdp); \
+ if (ret < 0) \
+ break; \
+\
+ ((u8 *)_buff)[i] = ret; \
+ } \
+\
+ ret = 0; \
+\
+ } while (0); \
+\
+ ret; \
+})
+
+#define cdns_mhdp_mailbox_send(_mhdp, _module_id, _opcode, _size, _message) \
+({ \
+ u8 header[4]; \
+ int ret, i; \
+\
+ header[0] = _opcode; \
+ header[1] = _module_id; \
+ put_unaligned_be16(_size, header + 2); \
+\
+ do { \
+ for (i = 0; i < sizeof(header); i++) { \
+ ret = cdns_mhdp_mailbox_write(_mhdp, header[i]); \
+ if (ret < 0) \
+ break; \
+ } \
+\
+ for (i = 0; i < _size; i++) { \
+ ret = cdns_mhdp_mailbox_write(_mhdp, ((u8 *)_message)[i]); \
+ if (ret < 0) \
+ break;; \
+ } \
+ ret = 0; \
+ } while (0); \
+\
+ ret; \
+})
+
+#define cdns_mhdp_reg_read(_mhdp, _addr, _value) \
+({ \
+ u8 msg[4], resp[8]; \
+ int ret; \
+\
+ put_unaligned_be32(_addr, msg); \
+\
+ mutex_lock(&(_mhdp)->mbox_mutex); \
+\
+ do { \
+ ret = cdns_mhdp_mailbox_send(_mhdp, MB_MODULE_ID_GENERAL, \
+ GENERAL_REGISTER_READ, \
+ sizeof(msg), msg); \
+ if (ret < 0) \
+ break; \
+\
+ ret = cdns_mhdp_mailbox_recv_header(_mhdp, MB_MODULE_ID_GENERAL, \
+ GENERAL_REGISTER_READ, \
+ sizeof(resp)); \
+ if (ret < 0) \
+ break; \
+\
+ ret = cdns_mhdp_mailbox_recv_data(_mhdp, resp, sizeof(resp)); \
+ if (ret < 0) \
+ break; \
+\
+ /* Returned address value should be the same as requested */ \
+ if (memcmp(msg, resp, sizeof(msg))) { \
+ ret = -EINVAL; \
+ break; \
+ } \
+\
+ *((u32 *)_value) = get_unaligned_be32(resp + 4); \
+ ret = 0; \
+ } while (0); \
+\
+ mutex_unlock(&(_mhdp)->mbox_mutex); \
+ if (ret < 0) { \
+ dev_err((_mhdp)->dev, "Failed to read register\n"); \
+ *((u32 *)_value) = 0; \
+ } \
+\
+ ret; \
+})
+
+#define cdns_mhdp_reg_write(_mhdp, _addr, _val) \
+({ \
+ u8 msg[8]; \
+ int ret; \
+\
+ put_unaligned_be32(_addr, msg); \
+ put_unaligned_be32(_val, msg + 4); \
+\
+ mutex_lock(&(_mhdp)->mbox_mutex); \
+\
+ ret = cdns_mhdp_mailbox_send(_mhdp, MB_MODULE_ID_GENERAL, \
+ GENERAL_REGISTER_WRITE, sizeof(msg), msg); \
+\
+ mutex_unlock(&(_mhdp)->mbox_mutex); \
+\
+ ret; \
+})
+
+#define cdns_mhdp_reg_write_bit(_mhdp, _addr, _start_bit, _bits_no, _val) \
+({ \
+ u8 field[8]; \
+ int ret; \
+\
+ put_unaligned_be16(_addr, field); \
+ field[2] = _start_bit; \
+ field[3] = _bits_no; \
+ put_unaligned_be32(_val, field + 4); \
+\
+ mutex_lock(&(_mhdp)->mbox_mutex); \
+\
+ ret = cdns_mhdp_mailbox_send((_mhdp), MB_MODULE_ID_DP_TX, \
+ DPTX_WRITE_FIELD, sizeof(field), field); \
+\
+ mutex_unlock(&(_mhdp)->mbox_mutex); \
+\
+ ret; \
+})
+
+#endif