> > On Tue, Oct 29, 2024 at 02:02:09PM +0800, Sandor Yu wrote: > > Mailbox access functions in MHDP8546 will be share to other MHDP > > driver and Cadence HDP-TX HDMI/DP PHY drivers. > > > > Create a new MHDP helper driver and move all mailbox access functions > into. > > According the mailbox access sequence and type of security. > > Six mailbox access API functions are introduced. > > Three APIs for non-secure mailbox access: > > - cdns_mhdp_mailbox_send() > > - cdns_mhdp_mailbox_send_recv() > > - cdns_mhdp_mailbox_send_recv_multi() > > The other three APIs 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 have been > > rewritten using those new API functions. > > > > The register read/write and DP DPCD read/write command functions are > > also included in this new helper driver. > > > > Function cdns_mhdp_reg_write() is renamed to cdns_mhdp_dp_reg_write(), > > because it use the DPTX command ID DPTX_WRITE_REGISTER. > > New cdns_mhdp_reg_write() is added with the general command ID > > GENERAL_REGISTER_WRITE. > > > > Signed-off-by: Sandor Yu <Sandor.yu@xxxxxxx> > > --- > > v17->v18: > > - Create three ordinary mailbox access APIs > > cdns_mhdp_mailbox_send > > cdns_mhdp_mailbox_send_recv > > cdns_mhdp_mailbox_send_recv_multi > > - Create three secure mailbox access APIs > > cdns_mhdp_secure_mailbox_send > > cdns_mhdp_secure_mailbox_send_recv > > cdns_mhdp_secure_mailbox_send_recv_multi > > - MHDP8546 DP and HDCP commands that need access mailbox are > rewrited > > with above 6 API functions. > > > > v16->v17: > > - Replaces the local mutex mbox_mutex with a global mutex > > mhdp_mailbox_mutex > > > > v12->v16: > > *No change. > > > > drivers/gpu/drm/bridge/cadence/Kconfig | 4 + > > drivers/gpu/drm/bridge/cadence/Makefile | 1 + > > .../gpu/drm/bridge/cadence/cdns-mhdp-helper.c | 414 > +++++++++++++++ > > .../drm/bridge/cadence/cdns-mhdp8546-core.c | 487 +++--------------- > > .../drm/bridge/cadence/cdns-mhdp8546-core.h | 47 +- > > .../drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 236 +-------- > > .../drm/bridge/cadence/cdns-mhdp8546-hdcp.h | 18 +- > > include/drm/bridge/cdns-mhdp-helper.h | 130 +++++ > > 8 files changed, 658 insertions(+), 679 deletions(-) create mode > > 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c > > create mode 100644 include/drm/bridge/cdns-mhdp-helper.h > > > > diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig > > b/drivers/gpu/drm/bridge/cadence/Kconfig > > index cced81633ddcd..e0973339e9e33 100644 > > --- a/drivers/gpu/drm/bridge/cadence/Kconfig > > +++ b/drivers/gpu/drm/bridge/cadence/Kconfig > > @@ -21,6 +21,9 @@ config DRM_CDNS_DSI_J721E > > the routing of the DSS DPI signal to the Cadence DSI. > > endif > > > > +config CDNS_MHDP_HELPER > > + tristate > > + > > I'm not sure if the placement for the helper is suitable. Especially if you want > to reuse the helper by some other subsystem. As far as I don't like it, maybe > drivers/soc is a better option. While PHY driver in drivers/phy/freescale also reuse the MHDP helper API, most of the code reuse happens in drivers/gpu/drm/bridge/cadence. I think it would be better to keep it in the current location because of this. > > > config DRM_CDNS_MHDP8546 > > tristate "Cadence DPI/DP bridge" > > select DRM_DISPLAY_DP_HELPER > > @@ -28,6 +31,7 @@ config DRM_CDNS_MHDP8546 > > select DRM_DISPLAY_HELPER > > select DRM_KMS_HELPER > > select DRM_PANEL_BRIDGE > > + select CDNS_MHDP_HELPER > > depends on OF > > help > > Support Cadence DPI to DP bridge. This is an internal diff > > --git a/drivers/gpu/drm/bridge/cadence/Makefile > > b/drivers/gpu/drm/bridge/cadence/Makefile > > index c95fd5b81d137..087dc074820d7 100644 > > --- a/drivers/gpu/drm/bridge/cadence/Makefile > > +++ b/drivers/gpu/drm/bridge/cadence/Makefile > > @@ -2,6 +2,7 @@ > > obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o cdns-dsi-y := > > cdns-dsi-core.o > > cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o > > +obj-$(CONFIG_CDNS_MHDP_HELPER) += cdns-mhdp-helper.o > > obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o > cdns-mhdp8546-y > > := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o > > cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += > > cdns-mhdp8546-j721e.o diff --git > > a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c > > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c > > new file mode 100644 > > index 0000000000000..f39228a78c7cb > > --- /dev/null > > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c > > @@ -0,0 +1,414 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +/* > > + * Copyright (C) 2023, 2024 NXP Semiconductor, Inc. > > + * > > + */ > > +#include <drm/bridge/cdns-mhdp-helper.h> #include > > +<linux/dev_printk.h> #include <linux/module.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 (opcode != header[0] || module_id != header[1] || > > + (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != > > + mbox_size)) { > > Could you please explain the second clause? This is a special case where the number of data received is not fixed. It needs to be parsed from the previous data, but there is a maximum limit. I will comment it. > > > + /* > > + * 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 (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; > > +} > > + > > Please add kerneldocs for all new API. It's obvious for the simple ones, but not > for the more complex functions. OK, I will add them. > > > +int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 > module_id, > > + u8 opcode, u16 size, u8 *message) { > > + int ret; > > + > > + mutex_lock(&mhdp_mailbox_mutex); > > guard(mutex)(&mhdp_mailbox_mutex); > > return mhdp_mailbox_send(...); > > Similar changes can be applied further on. OK. > > > + > > + ret = mhdp_mailbox_send(base->regs, module_id, opcode, size, > > + message); > > + > > + mutex_unlock(&mhdp_mailbox_mutex); > > + > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send); > > + > > +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; > > + > > + mutex_lock(&mhdp_mailbox_mutex); > > + > > + ret = mhdp_mailbox_send(base->regs, module_id, > > + opcode, msg_size, msg); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_header(base->regs, module_id, > > + opcode, resp_size); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_data(base->regs, resp, resp_size); > > +out: > > + mutex_unlock(&mhdp_mailbox_mutex); > > + > > + if (ret) > > + dev_err(base->dev, "ModuleID=%d, CMD=%d > failed: %d\n", > > + module_id, opcode, ret); > > Using guard() would allow you to use precise messages, e.g. failed to send, > failed to received header, failed to receive data. Yes, more precise messages will be added. > > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send_recv); > > + > > Like what is _multi? Why do you need to fetch into two separate buffers? > Can you fetch into one and then parse it accordingly? Please don't make the > API more complicated than necessary. > The majority of mailbox access commands can be implemented using the function cdns_mhdp_mailbox_send_recv() because the length of the response data is fixed based on the response type. However, there are three types of exceptions: Read operations: DPTX's DPTX_READ_DPCD and HDMITX's HDMI_TX_READ have variable response data lengths that depend on the caller's requirements. HDCPTX's HDCP_TRAN_IS_REC_ID_VALID: The response data length varies based on the type of connected HDCP receivers. Therefore, it's necessary to read a portion of the response data first, parse it, and then read the entire content. MHDP8546 link training DPTX_ADJUST_LT: The opcode for sending the message differs from the opcode for receiving the response. Considering these special cases, two new functions, cdns_mhdp_mailbox_send_recv_multi() and cdns_mhdp_secure_mailbox_send_recv_multi(), have been created to handle these specific scenarios. > > +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; > > + > > + mutex_lock(&mhdp_mailbox_mutex); > > + > > + ret = mhdp_mailbox_send(base->regs, module_id, > > + opcode, msg_size, msg); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_header(base->regs, module_id, > opcode_resp, > > + resp1_size + resp2_size); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_data(base->regs, resp1, resp1_size); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_data(base->regs, resp2, resp2_size); > > +out: > > + mutex_unlock(&mhdp_mailbox_mutex); > > + > > + if (ret) > > + dev_err(base->dev, "ModuleID=%d, MSG_CMD=%d > Resp_CMD=%d failed: %d\n", > > + module_id, opcode, opcode_resp, ret); > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send_recv_multi); > > + > > +/* > > + * Secure mailbox access functions: > > + * These functions handle secure mailbox communication, which differs > > + * from non-secure mailbox access. They use the secure address. > > + */ > > +int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_base *base, u8 > module_id, > > + u8 opcode, u16 size, u8 *message) { > > + int ret; > > + > > + mutex_lock(&mhdp_mailbox_mutex); > > + > > + ret = mhdp_mailbox_send(base->sapb_regs, module_id, opcode, > > + size, message); > > + > > + mutex_unlock(&mhdp_mailbox_mutex); > > + > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send); > > + > > +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; > > + > > + mutex_lock(&mhdp_mailbox_mutex); > > + > > + ret = mhdp_mailbox_send(base->sapb_regs, module_id, > > + opcode, msg_size, msg); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_header(base->sapb_regs, module_id, > > + opcode, resp_size); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_data(base->sapb_regs, resp, resp_size); > > +out: > > + mutex_unlock(&mhdp_mailbox_mutex); > > + > > + if (ret) > > + dev_err(base->dev, "ModuleID=%d, CMD=%d > failed: %d\n", > > + module_id, opcode, ret); > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send_recv); > > + > > +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; > > + > > + mutex_lock(&mhdp_mailbox_mutex); > > + > > + ret = mhdp_mailbox_send(base->sapb_regs, module_id, > > + opcode, msg_size, msg); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_header(base->sapb_regs, module_id, > > + opcode_resp, > > + resp1_size + resp2_size); > > + if (ret) > > + goto out; > > + > > + ret = mhdp_mailbox_recv_data(base->sapb_regs, resp1, > resp1_size); > > + if (ret) > > + goto out; > > + > > + if (module_id == MB_MODULE_ID_HDCP_TX && > > + opcode == HDCP_TRAN_IS_REC_ID_VALID) > > comment, please. OK. > > > + ret = mhdp_mailbox_recv_data(base->sapb_regs, resp2, 5 > * resp1[0]); > > + else > > + ret = mhdp_mailbox_recv_data(base->sapb_regs, resp2, > > +resp2_size); > > +out: > > + mutex_unlock(&mhdp_mailbox_mutex); > > + > > + if (ret) > > + dev_err(base->dev, "ModuleID=%d, CMD=%d > failed: %d\n", > > + module_id, opcode, ret); > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send_recv_multi); > > + > > +/* General read/write helper functions */ 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); > > + > > +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 */ > > +int cdns_mhdp_dp_reg_write(struct cdns_mhdp_base *base, u16 addr, > u32 > > +val) { > > + u8 msg[6]; > > + > > + put_unaligned_be16(addr, msg); > > + put_unaligned_be32(val, msg + 2); > > + > > + return cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX, > > + DPTX_WRITE_REGISTER, > sizeof(msg), > > +msg); } EXPORT_SYMBOL_GPL(cdns_mhdp_dp_reg_write); > > Please don't add API without a user. If the function is required in the following > patch, add it there. OK, cdns_mhdp_dp_reg_write() will be removed. B.R Sandor > > > + > > +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); > > + > > +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); > > + > > +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@xxxxxxx>"); > > +MODULE_LICENSE("GPL"); > > -- > With best wishes > Dmitry