Message ID | cover.1704785836.git.Sandor.yu@nxp.com |
---|---|
Headers | show |
Series | Initial support Cadence MHDP8501(HDMI/DP) for i.MX8MQ | expand |
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@nxp.com> > Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com> > --- > 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. > +#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. > + > + return msa_misc; > +} > + > [snip] > +int cdns_dp_set_host_cap(struct cdns_mhdp8501_device *mhdp) This can be made static. > +{ > + 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. 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, > +};
Hi Sandor, thanks for the update. Am Mittwoch, 10. Januar 2024, 02:08:48 CET schrieb Sandor Yu: > Add Cadence HDP-TX HDMI PHY driver for i.MX8MQ. > > Cadence HDP-TX PHY could be put in either DP mode or > HDMI mode base on the configuration chosen. > HDMI PHY mode is configurated in the driver. > > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com> > Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com> > --- > v11->v12: > - Adjust clk disable order. > - Return error code to replace -1 for function wait_for_ack(). > - Use bool for variable pclk_in. > - Add year 2024 to copyright. > > drivers/phy/freescale/Kconfig | 10 + > drivers/phy/freescale/Makefile | 1 + > drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c | 959 ++++++++++++++++++++ > 3 files changed, 970 insertions(+) > create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c > > diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig > index c39709fd700ac..14f47b7cc77ab 100644 > --- a/drivers/phy/freescale/Kconfig > +++ b/drivers/phy/freescale/Kconfig > @@ -45,6 +45,16 @@ config PHY_FSL_IMX8MQ_DP > Enable this to support the Cadence HDPTX DP PHY driver > on i.MX8MQ SOC. > > +config PHY_FSL_IMX8MQ_HDMI > + tristate "Freescale i.MX8MQ HDMI PHY support" > + depends on OF && HAS_IOMEM > + depends on COMMON_CLK > + select GENERIC_PHY > + select CDNS_MHDP_HELPER > + help > + Enable this to support the Cadence HDPTX HDMI PHY driver > + on i.MX8MQ SOC. > + > endif > > config PHY_FSL_LYNX_28G > diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile > index 47e5285209fa8..1380ac31c2ead 100644 > --- a/drivers/phy/freescale/Makefile > +++ b/drivers/phy/freescale/Makefile > @@ -1,5 +1,6 @@ > # SPDX-License-Identifier: GPL-2.0-only > obj-$(CONFIG_PHY_FSL_IMX8MQ_DP) += phy-fsl-imx8mq-dp.o > +obj-$(CONFIG_PHY_FSL_IMX8MQ_HDMI) += phy-fsl-imx8mq-hdmi.o > obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o > obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o > obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c > b/drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c new file mode 100644 > index 0000000000000..9e03c726f290c > --- /dev/null > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c > @@ -0,0 +1,959 @@ > [snip] > +int cdns_hdptx_hdmi_phy_valid(struct phy *phy, enum phy_mode mode, int > submode, + union phy_configure_opts *opts) This function can be made static. Thanks and best regards, Alexander > +{ > + u32 rate = opts->hdmi.pixel_clk_rate; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(pixel_clk_output_ctrl_table); i++) > + if (rate == pixel_clk_output_ctrl_table[i].pixel_clk_freq_min) > + return 0; > + > + return -EINVAL; > +} > + > +static int cdns_hdptx_hdmi_phy_init(struct phy *phy) > +{ > + return 0; > +} > + > +static int cdns_hdptx_hdmi_configure(struct phy *phy, > + union phy_configure_opts *opts) > +{ > + struct cdns_hdptx_hdmi_phy *cdns_phy = phy_get_drvdata(phy); > + int ret; > + > + cdns_phy->pixel_clk_rate = opts->hdmi.pixel_clk_rate; > + cdns_phy->color_space = opts->hdmi.color_space; > + cdns_phy->bpc = opts->hdmi.bpc; > + > + /* Check HDMI FW alive before HDMI PHY init */ > + ret = hdptx_phy_check_alive(cdns_phy); > + if (!ret) { > + dev_err(cdns_phy->dev, "NO HDMI FW running\n"); > + return -ENXIO; > + } > + > + /* Configure PHY */ > + if (hdptx_hdmi_phy_cfg(cdns_phy, cdns_phy->pixel_clk_rate) < 0) { > + dev_err(cdns_phy->dev, "failed to set phy pclock\n"); > + return -EINVAL; > + } > + > + ret = hdptx_hdmi_phy_power_up(cdns_phy); > + if (ret < 0) > + return ret; > + > + hdptx_hdmi_phy_set_vswing(cdns_phy); > + > + return 0; > +} > + > +static const struct phy_ops cdns_hdptx_hdmi_phy_ops = { > + .init = cdns_hdptx_hdmi_phy_init, > + .configure = cdns_hdptx_hdmi_configure, > + .power_on = cdns_hdptx_hdmi_phy_on, > + .power_off = cdns_hdptx_hdmi_phy_off, > + .validate = cdns_hdptx_hdmi_phy_valid, > + .owner = THIS_MODULE, > +}; > + > +static int cdns_hdptx_hdmi_phy_probe(struct platform_device *pdev) > +{ > + struct cdns_hdptx_hdmi_phy *cdns_phy; > + struct device *dev = &pdev->dev; > + struct device_node *node = dev->of_node; > + struct phy_provider *phy_provider; > + struct resource *res; > + struct phy *phy; > + int ret; > + > + cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL); > + if (!cdns_phy) > + return -ENOMEM; > + > + dev_set_drvdata(dev, cdns_phy); > + cdns_phy->dev = dev; > + mutex_init(&cdns_phy->mbox_mutex); > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) > + return -ENODEV; > + cdns_phy->regs = devm_ioremap(dev, res->start, resource_size(res)); > + if (IS_ERR(cdns_phy->regs)) > + return PTR_ERR(cdns_phy->regs); > + > + phy = devm_phy_create(dev, node, &cdns_hdptx_hdmi_phy_ops); > + if (IS_ERR(phy)) > + return PTR_ERR(phy); > + > + phy->attrs.mode = PHY_MODE_HDMI; > + > + cdns_phy->phy = phy; > + phy_set_drvdata(phy, cdns_phy); > + > + /* init base struct for access mhdp mailbox */ > + cdns_phy->base.dev = cdns_phy->dev; > + cdns_phy->base.regs = cdns_phy->regs; > + cdns_phy->base.mbox_mutex = &cdns_phy->mbox_mutex; > + > + ret = hdptx_hdmi_clk_enable(cdns_phy); > + if (ret) { > + dev_err(dev, "Init clk fail\n"); > + return -EINVAL; > + } > + > + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > + if (IS_ERR(phy_provider)) { > + ret = PTR_ERR(phy_provider); > + goto clk_disable; > + } > + > + dev_dbg(dev, "probe success!\n"); > + > + return 0; > + > +clk_disable: > + hdptx_hdmi_clk_disable(cdns_phy); > + > + return -EINVAL; > +} > + > +static int cdns_hdptx_hdmi_phy_remove(struct platform_device *pdev) > +{ > + struct cdns_hdptx_hdmi_phy *cdns_phy = platform_get_drvdata(pdev); > + > + hdptx_hdmi_clk_disable(cdns_phy); > + > + return 0; > +} > + > +static const struct of_device_id cdns_hdptx_hdmi_phy_of_match[] = { > + {.compatible = "fsl,imx8mq-hdmi-phy" }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, cdns_hdptx_hdmi_phy_of_match); > + > +static struct platform_driver cdns_hdptx_hdmi_phy_driver = { > + .probe = cdns_hdptx_hdmi_phy_probe, > + .remove = cdns_hdptx_hdmi_phy_remove, > + .driver = { > + .name = "cdns-hdptx-hdmi-phy", > + .of_match_table = cdns_hdptx_hdmi_phy_of_match, > + } > +}; > +module_platform_driver(cdns_hdptx_hdmi_phy_driver); > + > +MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>"); > +MODULE_DESCRIPTION("Cadence HDP-TX HDMI PHY driver"); > +MODULE_LICENSE("GPL");
Hi Alexander, Thanks your comments, > -----Original Message----- > From: Alexander Stein <alexander.stein@ew.tq-group.com> > Sent: 2024年1月17日 17:47 > To: dmitry.baryshkov@linaro.org; andrzej.hajda@intel.com; > neil.armstrong@linaro.org; Laurent Pinchart > <laurent.pinchart@ideasonboard.com>; jonas@kwiboo.se; > jernej.skrabec@gmail.com; airlied@gmail.com; daniel@ffwll.ch; > robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org; > shawnguo@kernel.org; s.hauer@pengutronix.de; festevam@gmail.com; > vkoul@kernel.org; dri-devel@lists.freedesktop.org; > devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org; > linux-kernel@vger.kernel.org; linux-phy@lists.infradead.org; Sandor Yu > <sandor.yu@nxp.com> > Cc: kernel@pengutronix.de; dl-linux-imx <linux-imx@nxp.com>; Sandor Yu > <sandor.yu@nxp.com>; Oliver Brown <oliver.brown@nxp.com>; > sam@ravnborg.org > Subject: [EXT] Re: [PATCH v12 7/7] phy: freescale: Add HDMI PHY driver for > i.MX8MQ > > Caution: This is an external email. Please take care when clicking links or > opening attachments. When in doubt, report the message using the 'Report > this email' button > > > Hi Sandor, > > thanks for the update. > > Am Mittwoch, 10. Januar 2024, 02:08:48 CET schrieb Sandor Yu: > > Add Cadence HDP-TX HDMI PHY driver for i.MX8MQ. > > > > Cadence HDP-TX PHY could be put in either DP mode or HDMI mode base > on > > the configuration chosen. > > HDMI PHY mode is configurated in the driver. > > > > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com> > > Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com> > > --- > > v11->v12: > > - Adjust clk disable order. > > - Return error code to replace -1 for function wait_for_ack(). > > - Use bool for variable pclk_in. > > - Add year 2024 to copyright. > > > > drivers/phy/freescale/Kconfig | 10 + > > drivers/phy/freescale/Makefile | 1 + > > drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c | 959 > > ++++++++++++++++++++ > > 3 files changed, 970 insertions(+) > > create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c > > > > diff --git a/drivers/phy/freescale/Kconfig > > b/drivers/phy/freescale/Kconfig index c39709fd700ac..14f47b7cc77ab > > 100644 > > --- a/drivers/phy/freescale/Kconfig > > +++ b/drivers/phy/freescale/Kconfig > > @@ -45,6 +45,16 @@ config PHY_FSL_IMX8MQ_DP > > Enable this to support the Cadence HDPTX DP PHY driver > > on i.MX8MQ SOC. > > > > +config PHY_FSL_IMX8MQ_HDMI > > + tristate "Freescale i.MX8MQ HDMI PHY support" > > + depends on OF && HAS_IOMEM > > + depends on COMMON_CLK > > + select GENERIC_PHY > > + select CDNS_MHDP_HELPER > > + help > > + Enable this to support the Cadence HDPTX HDMI PHY driver > > + on i.MX8MQ SOC. > > + > > endif > > > > config PHY_FSL_LYNX_28G > > diff --git a/drivers/phy/freescale/Makefile > > b/drivers/phy/freescale/Makefile index 47e5285209fa8..1380ac31c2ead > > 100644 > > --- a/drivers/phy/freescale/Makefile > > +++ b/drivers/phy/freescale/Makefile > > @@ -1,5 +1,6 @@ > > # SPDX-License-Identifier: GPL-2.0-only > > obj-$(CONFIG_PHY_FSL_IMX8MQ_DP) += > phy-fsl-imx8mq-dp.o > > +obj-$(CONFIG_PHY_FSL_IMX8MQ_HDMI) += phy-fsl-imx8mq-hdmi.o > > obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o > > obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o > > obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o > > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c > > b/drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c new file mode 100644 > > index 0000000000000..9e03c726f290c > > --- /dev/null > > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-hdmi.c > > @@ -0,0 +1,959 @@ > > [snip] > > +int cdns_hdptx_hdmi_phy_valid(struct phy *phy, enum phy_mode mode, > > +int > > submode, + union phy_configure_opts > *opts) > > This function can be made static. > OK, thanks! B.R Sandor > Thanks and best regards, > Alexander > > > +{ > > + u32 rate = opts->hdmi.pixel_clk_rate; > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(pixel_clk_output_ctrl_table); i++) > > + if (rate == > pixel_clk_output_ctrl_table[i].pixel_clk_freq_min) > > + return 0; > > + > > + return -EINVAL; > > +} > > + > > +static int cdns_hdptx_hdmi_phy_init(struct phy *phy) { > > + return 0; > > +} > > + > > +static int cdns_hdptx_hdmi_configure(struct phy *phy, > > + union phy_configure_opts *opts) > { > > + struct cdns_hdptx_hdmi_phy *cdns_phy = phy_get_drvdata(phy); > > + int ret; > > + > > + cdns_phy->pixel_clk_rate = opts->hdmi.pixel_clk_rate; > > + cdns_phy->color_space = opts->hdmi.color_space; > > + cdns_phy->bpc = opts->hdmi.bpc; > > + > > + /* Check HDMI FW alive before HDMI PHY init */ > > + ret = hdptx_phy_check_alive(cdns_phy); > > + if (!ret) { > > + dev_err(cdns_phy->dev, "NO HDMI FW running\n"); > > + return -ENXIO; > > + } > > + > > + /* Configure PHY */ > > + if (hdptx_hdmi_phy_cfg(cdns_phy, cdns_phy->pixel_clk_rate) < 0) { > > + dev_err(cdns_phy->dev, "failed to set phy pclock\n"); > > + return -EINVAL; > > + } > > + > > + ret = hdptx_hdmi_phy_power_up(cdns_phy); > > + if (ret < 0) > > + return ret; > > + > > + hdptx_hdmi_phy_set_vswing(cdns_phy); > > + > > + return 0; > > +} > > + > > +static const struct phy_ops cdns_hdptx_hdmi_phy_ops = { > > + .init = cdns_hdptx_hdmi_phy_init, > > + .configure = cdns_hdptx_hdmi_configure, > > + .power_on = cdns_hdptx_hdmi_phy_on, > > + .power_off = cdns_hdptx_hdmi_phy_off, > > + .validate = cdns_hdptx_hdmi_phy_valid, > > + .owner = THIS_MODULE, > > +}; > > + > > +static int cdns_hdptx_hdmi_phy_probe(struct platform_device *pdev) { > > + struct cdns_hdptx_hdmi_phy *cdns_phy; > > + struct device *dev = &pdev->dev; > > + struct device_node *node = dev->of_node; > > + struct phy_provider *phy_provider; > > + struct resource *res; > > + struct phy *phy; > > + int ret; > > + > > + cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL); > > + if (!cdns_phy) > > + return -ENOMEM; > > + > > + dev_set_drvdata(dev, cdns_phy); > > + cdns_phy->dev = dev; > > + mutex_init(&cdns_phy->mbox_mutex); > > + > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + if (!res) > > + return -ENODEV; > > + cdns_phy->regs = devm_ioremap(dev, res->start, resource_size(res)); > > + if (IS_ERR(cdns_phy->regs)) > > + return PTR_ERR(cdns_phy->regs); > > + > > + phy = devm_phy_create(dev, node, &cdns_hdptx_hdmi_phy_ops); > > + if (IS_ERR(phy)) > > + return PTR_ERR(phy); > > + > > + phy->attrs.mode = PHY_MODE_HDMI; > > + > > + cdns_phy->phy = phy; > > + phy_set_drvdata(phy, cdns_phy); > > + > > + /* init base struct for access mhdp mailbox */ > > + cdns_phy->base.dev = cdns_phy->dev; > > + cdns_phy->base.regs = cdns_phy->regs; > > + cdns_phy->base.mbox_mutex = &cdns_phy->mbox_mutex; > > + > > + ret = hdptx_hdmi_clk_enable(cdns_phy); > > + if (ret) { > > + dev_err(dev, "Init clk fail\n"); > > + return -EINVAL; > > + } > > + > > + phy_provider = devm_of_phy_provider_register(dev, > of_phy_simple_xlate); > > + if (IS_ERR(phy_provider)) { > > + ret = PTR_ERR(phy_provider); > > + goto clk_disable; > > + } > > + > > + dev_dbg(dev, "probe success!\n"); > > + > > + return 0; > > + > > +clk_disable: > > + hdptx_hdmi_clk_disable(cdns_phy); > > + > > + return -EINVAL; > > +} > > + > > +static int cdns_hdptx_hdmi_phy_remove(struct platform_device *pdev) { > > + struct cdns_hdptx_hdmi_phy *cdns_phy = > > +platform_get_drvdata(pdev); > > + > > + hdptx_hdmi_clk_disable(cdns_phy); > > + > > + return 0; > > +} > > + > > +static const struct of_device_id cdns_hdptx_hdmi_phy_of_match[] = { > > + {.compatible = "fsl,imx8mq-hdmi-phy" }, > > + { /* sentinel */ } > > +}; > > +MODULE_DEVICE_TABLE(of, cdns_hdptx_hdmi_phy_of_match); > > + > > +static struct platform_driver cdns_hdptx_hdmi_phy_driver = { > > + .probe = cdns_hdptx_hdmi_phy_probe, > > + .remove = cdns_hdptx_hdmi_phy_remove, > > + .driver = { > > + .name = "cdns-hdptx-hdmi-phy", > > + .of_match_table = cdns_hdptx_hdmi_phy_of_match, > > + } > > +}; > > +module_platform_driver(cdns_hdptx_hdmi_phy_driver); > > + > > +MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>"); > > +MODULE_DESCRIPTION("Cadence HDP-TX HDMI PHY driver"); > > +MODULE_LICENSE("GPL"); > > > -- > 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%7Cb17a4addce1e4 > 8b54f8a08dc17414379%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0 > %7C638410816282055456%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjA > wMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7 > C%7C&sdata=YFO2ShpepVs%2B%2FTSDfzLdZjkPc7s0VHrqjX9jxsqSXok%3D&res > erved=0 >
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@nxp.com> > > Tested-by: Alexander Stein <alexander.stein@ew.tq-group.com> > > --- > > 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 >