Hi Alexander, Thanks your comments, > > > Hi Sandor, > > thanks for the update. > > Am Mittwoch, 10. Januar 2024, 02:08:45 CET schrieb Sandor Yu: > > Add a new DRM DisplayPort and HDMI bridge driver for Candence > MHDP8501 > > used in i.MX8MQ SOC. MHDP8501 could support HDMI or DisplayPort > > standards according embedded Firmware running in the uCPU. > > > > For iMX8MQ SOC, the DisplayPort/HDMI FW was loaded and activated by > > SOC's ROM code. Bootload binary included respective specific firmware > > is required. > > > > Driver will check display connector type and then load the > > corresponding driver. > > > > Signed-off-by: Sandor Yu <Sandor.yu@xxxxxxx> > > Tested-by: Alexander Stein <alexander.stein@xxxxxxxxxxxxxxx> > > --- > > v11->v12: > > - Replace DRM_INFO with dev_info or dev_warn. > > - Replace DRM_ERROR with dev_err. > > - Return ret when cdns_mhdp_dpcd_read failed in function > > cdns_dp_aux_transferi(). - Remove unused parmeter in function > > cdns_dp_get_msa_misc > > and use two separate variables for color space and bpc. > > - Add year 2024 to copyright. > > > > drivers/gpu/drm/bridge/cadence/Kconfig | 16 + > > drivers/gpu/drm/bridge/cadence/Makefile | 2 + > > .../drm/bridge/cadence/cdns-mhdp8501-core.c | 315 ++++++++ > > .../drm/bridge/cadence/cdns-mhdp8501-core.h | 365 +++++++++ > > .../gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c | 699 > ++++++++++++++++++ > > .../drm/bridge/cadence/cdns-mhdp8501-hdmi.c | 678 > +++++++++++++++++ > > 6 files changed, 2075 insertions(+) > > create mode 100644 > > drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c > > create mode 100644 > > drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.h > > create mode 100644 > drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c > > create mode 100644 > > drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c > > > > diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig > > b/drivers/gpu/drm/bridge/cadence/Kconfig index > > e0973339e9e33..45848e741f5f4 > > 100644 > > --- a/drivers/gpu/drm/bridge/cadence/Kconfig > > +++ b/drivers/gpu/drm/bridge/cadence/Kconfig > > @@ -51,3 +51,19 @@ config DRM_CDNS_MHDP8546_J721E > > initializes the J721E Display Port and sets up the > > clock and data muxes. > > endif > > + > > +config DRM_CDNS_MHDP8501 > > + tristate "Cadence MHDP8501 DP/HDMI bridge" > > + select DRM_KMS_HELPER > > + select DRM_PANEL_BRIDGE > > + select DRM_DISPLAY_DP_HELPER > > + select DRM_DISPLAY_HELPER > > + select CDNS_MHDP_HELPER > > + select DRM_CDNS_AUDIO > > + depends on OF > > + help > > + Support Cadence MHDP8501 DisplayPort/HDMI bridge. > > + Cadence MHDP8501 support one or more protocols, > > + including DisplayPort and HDMI. > > + To use the DP and HDMI drivers, their respective > > + specific firmware is required. > > diff --git a/drivers/gpu/drm/bridge/cadence/Makefile > > b/drivers/gpu/drm/bridge/cadence/Makefile index > > 087dc074820d7..02c1a9f3cf6fc 100644 > > --- a/drivers/gpu/drm/bridge/cadence/Makefile > > +++ b/drivers/gpu/drm/bridge/cadence/Makefile > > @@ -6,3 +6,5 @@ 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 > > +obj-$(CONFIG_DRM_CDNS_MHDP8501) += cdns-mhdp8501.o > cdns-mhdp8501-y := > > +cdns-mhdp8501-core.o cdns-mhdp8501-dp.o > > cdns-mhdp8501-hdmi.o diff --git > > a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c > > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c new file mode > > 100644 index 0000000000000..3080c7507a012 > > --- /dev/null > > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c > > @@ -0,0 +1,315 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +/* > > + * Cadence Display Port Interface (DP) driver > > + * > > + * Copyright (C) 2023, 2024 NXP Semiconductor, Inc. > > + * > > + */ > > +#include <drm/drm_of.h> > > +#include <drm/drm_print.h> > > +#include <linux/clk.h> > > +#include <linux/irq.h> > > +#include <linux/mutex.h> > > +#include <linux/of_device.h> > > Since commit d57d584ef69de ("of: Stop circularly including of_device.h and > of_platform.h") you to explicitly include linux/platform_device.h here. Please > compile against next tree. OK, I will check it on next tree. > > > +#include <linux/phy/phy.h> > > + > > +#include "cdns-mhdp8501-core.h" > > + > > [snip] > > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c > > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c new file mode > > 100644 index 0000000000000..6963c7143a3b0 > > --- /dev/null > > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c > > @@ -0,0 +1,699 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +/* > > + * Cadence MHDP8501 DisplayPort(DP) bridge driver > > + * > > + * Copyright (C) 2019-2024 NXP Semiconductor, Inc. > > + * > > + */ > > +#include <drm/drm_atomic_helper.h> > > +#include <drm/drm_edid.h> > > +#include <drm/drm_print.h> > > +#include <linux/phy/phy.h> > > +#include <linux/phy/phy-dp.h> > > + > > +#include "cdns-mhdp8501-core.h" > > + > > +#define LINK_TRAINING_TIMEOUT_MS 500 > > +#define LINK_TRAINING_RETRY_MS 20 > > + > > +ssize_t cdns_dp_aux_transfer(struct drm_dp_aux *aux, > > + struct drm_dp_aux_msg *msg) { > > + struct cdns_mhdp8501_device *mhdp = dev_get_drvdata(aux->dev); > > + bool native = msg->request & (DP_AUX_NATIVE_WRITE & > DP_AUX_NATIVE_READ); > > + int ret; > > + > > + /* Ignore address only message */ > > + if (!msg->size || !msg->buffer) { > > + msg->reply = native ? > > + DP_AUX_NATIVE_REPLY_ACK : > DP_AUX_I2C_REPLY_ACK; > > + return msg->size; > > + } > > + > > + if (!native) { > > + dev_err(mhdp->dev, "%s: only native messages > > + supported\n", > __func__); > > + return -EINVAL; > > + } > > + > > + /* msg sanity check */ > > + if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) { > > + dev_err(mhdp->dev, "%s: invalid msg: size(%zu), > request(%x)\n", > > + __func__, msg->size, (unsigned int)msg- > >request); > > + return -EINVAL; > > + } > > + > > + if (msg->request == DP_AUX_NATIVE_WRITE) { > > + const u8 *buf = msg->buffer; > > + int i; > > + > > + for (i = 0; i < msg->size; ++i) { > > + ret = cdns_mhdp_dpcd_write(&mhdp->base, > > + msg->address + > i, buf[i]); > > + if (ret < 0) { > > + dev_err(mhdp->dev, "Failed to write > DPCD\n"); > > + return ret; > > + } > > + } > > + msg->reply = DP_AUX_NATIVE_REPLY_ACK; > > + return msg->size; > > + } > > + > > + if (msg->request == DP_AUX_NATIVE_READ) { > > + ret = cdns_mhdp_dpcd_read(&mhdp->base, msg->address, > > + msg->buffer, msg->size); > > + if (ret < 0) > > + return ret; > > + msg->reply = DP_AUX_NATIVE_REPLY_ACK; > > + return msg->size; > > + } > > + return 0; > > +} > > + > > +int cdns_dp_aux_destroy(struct cdns_mhdp8501_device *mhdp) { > > + drm_dp_aux_unregister(&mhdp->dp.aux); > > + > > + return 0; > > +} > > + > > +static int cdns_dp_get_msa_misc(struct video_info *video) { > > + u32 msa_misc; > > + u8 color_space = 0; > > + u8 bpc = 0; > > + > > + switch (video->color_fmt) { > > + /* set YUV default color space conversion to BT601 */ > > + case DRM_COLOR_FORMAT_YCBCR444: > > + color_space = 6 + BT_601 * 8; > > + break; > > + case DRM_COLOR_FORMAT_YCBCR422: > > + color_space = 5 + BT_601 * 8; > > + break; > > + case DRM_COLOR_FORMAT_YCBCR420: > > + color_space = 5; > > + break; > > + case DRM_COLOR_FORMAT_RGB444: > > + default: > > + color_space = 0; > > + break; > > + }; > > + > > + switch (video->bpc) { > > + case 6: > > + bpc = 0; > > + break; > > + case 10: > > + bpc = 2; > > + break; > > + case 12: > > + bpc = 3; > > + break; > > + case 16: > > + bpc = 4; > > + break; > > + case 8: > > + default: > > + bpc = 1; > > + break; > > + }; > > + > > + msa_misc = (color_space << 1) | (bpc << 5); > > This looks much nicer, thanks. But please order them in descending shift > width: bpc first then color_space. > OK. > > + > > + return msa_misc; > > +} > > + > > [snip] > > +int cdns_dp_set_host_cap(struct cdns_mhdp8501_device *mhdp) > > This can be made static. OK. > > > +{ > > + u8 msg[8]; > > + int ret; > > + > > + msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate); > > + msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN; > > + msg[2] = VOLTAGE_LEVEL_2; > > + msg[3] = PRE_EMPHASIS_LEVEL_3; > > + msg[4] = PTS1 | PTS2 | PTS3 | PTS4; > > + msg[5] = FAST_LT_NOT_SUPPORT; > > + msg[6] = mhdp->lane_mapping; > > + msg[7] = ENHANCED; > > + > > + mutex_lock(&mhdp->mbox_mutex); > > + > > + ret = cdns_mhdp_mailbox_send(&mhdp->base, > MB_MODULE_ID_DP_TX, > > + DPTX_SET_HOST_CAPABILITIES, > > + sizeof(msg), msg); > > + > > + mutex_unlock(&mhdp->mbox_mutex); > > + > > + if (ret) > > + dev_err(mhdp->dev, "set host cap failed: %d\n", ret); > > + > > + return ret; > > +} > > [snip] > > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c > > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c new file mode > > 100644 index 0000000000000..ae21f7dfe5e94 > > --- /dev/null > > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c > > @@ -0,0 +1,678 @@ > > [snip] > > +bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, > > + const struct drm_display_mode > *mode, > > + struct drm_display_mode > *adjusted_mode) > > This can be made static. OK, thanks! Sandor > > Thanks and best regards, > Alexander > > > +{ > > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private; > > + struct video_info *video = &mhdp->video_info; > > + > > + /* The only currently supported format */ > > + video->bpc = 8; > > + video->color_fmt = DRM_COLOR_FORMAT_RGB444; > > + > > + return true; > > +} > > + > > +static enum drm_connector_status > > +cdns_hdmi_bridge_detect(struct drm_bridge *bridge) { > > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private; > > + > > + return cdns_mhdp8501_detect(mhdp); } > > + > > +static struct edid *cdns_hdmi_bridge_get_edid(struct drm_bridge *bridge, > > + struct drm_connector > *connector) > > +{ > > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private; > > + > > + return drm_do_get_edid(connector, cdns_hdmi_get_edid_block, > > +mhdp); } > > + > > +static void cdns_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, > > + struct drm_bridge_state > *old_state) > > +{ > > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private; > > + > > + mhdp->curr_conn = NULL; > > + > > + /* Mailbox protect for HDMI PHY access */ > > + mutex_lock(&mhdp->mbox_mutex); > > + phy_power_off(mhdp->phy); > > + mutex_unlock(&mhdp->mbox_mutex); } > > + > > +static void cdns_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, > > + struct drm_bridge_state > *old_state) > > +{ > > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private; > > + struct drm_atomic_state *state = old_state->base.state; > > + struct drm_connector *connector; > > + struct drm_crtc_state *crtc_state; > > + struct drm_connector_state *conn_state; > > + const struct drm_display_mode *mode; > > + > > + connector = drm_atomic_get_new_connector_for_encoder(state, > > + > bridge->encoder); > > + if (WARN_ON(!connector)) > > + return; > > + > > + mhdp->curr_conn = connector; > > + > > + conn_state = drm_atomic_get_new_connector_state(state, > connector); > > + if (WARN_ON(!conn_state)) > > + return; > > + > > + crtc_state = drm_atomic_get_new_crtc_state(state, > conn_state->crtc); > > + if (WARN_ON(!crtc_state)) > > + return; > > + > > + mode = &crtc_state->adjusted_mode; > > + dev_dbg(mhdp->dev, "Mode: %dx%dp%d\n", > > + mode->hdisplay, mode->vdisplay, mode->clock); > > + memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); > > + > > + cdns_hdmi_mode_set(mhdp); > > +} > > + > > +const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = { > > + .attach = cdns_hdmi_bridge_attach, > > + .detect = cdns_hdmi_bridge_detect, > > + .get_edid = cdns_hdmi_bridge_get_edid, > > + .mode_valid = cdns_hdmi_bridge_mode_valid, > > + .mode_fixup = cdns_hdmi_bridge_mode_fixup, > > + .atomic_enable = cdns_hdmi_bridge_atomic_enable, > > + .atomic_disable = cdns_hdmi_bridge_atomic_disable, > > + .atomic_duplicate_state = > drm_atomic_helper_bridge_duplicate_state, > > + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, > > + .atomic_reset = drm_atomic_helper_bridge_reset, }; > > > -- > TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany > Amtsgericht München, HRB 105018 > Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider > http://www.tq-/ > group.com%2F&data=05%7C02%7CSandor.yu%40nxp.com%7Cb23e376f27494 > 9cdb46c08dc17413d46%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0 > %7C638410816178929125%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjA > wMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7 > C%7C&sdata=tYc81WajNJAOmUvSD06cto0i%2FhVe%2BuLFxIeYm0uyMDM%3 > D&reserved=0 >