[EXT] Re: [v2 06/10] drm: bridge: cadence: Add MHDP HDMI driver for i.MX8MQ

Sandor Yu sandor.yu at nxp.com
Wed Nov 9 05:26:14 PST 2022


Thanks for your comments.

> -----Original Message-----
> From: Alexander Stein <alexander.stein at ew.tq-group.com>
> Sent: 2022年11月8日 21:17
> To: jonas at kwiboo.se; Sandor Yu <sandor.yu at nxp.com>
> Cc: dri-devel at lists.freedesktop.org; devicetree at vger.kernel.org;
> linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org;
> linux-phy at lists.infradead.org; andrzej.hajda at intel.com;
> neil.armstrong at linaro.org; robert.foss at linaro.org;
> Laurent.pinchart at ideasonboard.com; jernej.skrabec at gmail.com;
> kishon at ti.com; vkoul at kernel.org; Oliver Brown <oliver.brown at nxp.com>;
> krzysztof.kozlowski+dt at linaro.org; sam at ravnborg.org; jani.nikula at intel.com;
> tzimmermann at suse.de; s.hauer at pengutronix.de; javierm at redhat.com;
> penguin-kernel at i-love.sakura.ne.jp; robh+dt at kernel.org; dl-linux-imx
> <linux-imx at nxp.com>; kernel at pengutronix.de; Sandor Yu
> <sandor.yu at nxp.com>; shawnguo at kernel.org; p.yadav at ti.com;
> maxime at cerno.tech
> Subject: [EXT] Re: [v2 06/10] drm: bridge: cadence: Add MHDP HDMI driver
> for i.MX8MQ
> 
> Caution: EXT Email
> 
> Hello,
> 
> thanks for working on this and the updated version.
> 
> Am Freitag, 4. November 2022, 07:44:56 CET schrieb Sandor Yu:
> > Add a new DRM HDMI bridge driver for Candence MHDP used in i.MX8MQ
> > SOC. MHDP IP could support HDMI or DisplayPort standards according
> > embedded Firmware running in the uCPU.
> >
> > For iMX8MQ SOC, the HDMI FW was loaded and activated by SOC ROM
> code.
> > Bootload binary included HDMI FW was required for the driver.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu at nxp.com>
> > ---
> >  drivers/gpu/drm/bridge/cadence/Kconfig        |   12 +
> >  .../gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 1038
> +++++++++++++++++
> >  2 files changed, 1050 insertions(+)
> >  create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
> >
> > diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig
> > b/drivers/gpu/drm/bridge/cadence/Kconfig index
> > e79ae1af3765..377452d09992
> > 100644
> > --- a/drivers/gpu/drm/bridge/cadence/Kconfig
> > +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
> > @@ -26,6 +26,18 @@ config DRM_CDNS_MHDP8546_J721E
> >         clock and data muxes.
> >  endif
> >
> > +config DRM_CDNS_HDMI
> > +     tristate "Cadence HDMI DRM driver"
> > +     select DRM_KMS_HELPER
> > +     select DRM_PANEL_BRIDGE
> > +     select DRM_DISPLAY_HELPER
> > +     select DRM_CDNS_AUDIO
> > +     depends on OF
> > +     help
> > +       Support Cadence MHDP HDMI driver.
> > +       Cadence MHDP Controller support one or more protocols,
> > +       HDMI firmware is required for this driver.
> > +
> >  config DRM_CDNS_DP
> >       tristate "Cadence DP DRM driver"
> >       select DRM_KMS_HELPER
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c new file mode
> 100644
> > index 000000000000..b392aac015bd
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
> > @@ -0,0 +1,1038 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Cadence High-Definition Multimedia Interface (HDMI) driver
> > + *
> > + * Copyright (C) 2019-2022 NXP Semiconductor, Inc.
> > + *
> > + */
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/hdmi.h>
> > +#include <linux/irq.h>
> > +#include <linux/module.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/mutex.h>
> > +#include <linux/of_device.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/phy/phy-hdmi.h>
> > +
> > +#include <drm/bridge/cdns-mhdp-mailbox.h> #include
> > +<drm/display/drm_hdmi_helper.h> #include
> > +<drm/display/drm_scdc_helper.h> #include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_edid.h> #include <drm/drm_encoder_slave.h>
> #include
> > +<drm/drm_of.h> #include <drm/drm_probe_helper.h> #include
> > +<drm/drm_print.h> #include <drm/drm_vblank.h>
> > +
> > +#include "cdns-mhdp-common.h"
> > +
> > +void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
> > +                                     u8 entry_id, u8 packet_len,
> u8 *packet, u8 packet_type)
> > +{
> > +     u32 *packet32, len32;
> > +     u32 val, i;
> > +
> > +     /* invalidate entry */
> > +     val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
> > +     writel(val, mhdp->regs + SOURCE_PIF_PKT_ALLOC_REG);
> > +     writel(F_PKT_ALLOC_WR_EN(1), mhdp->regs +
> SOURCE_PIF_PKT_ALLOC_WR_EN);
> > +
> > +     /* flush fifo 1 */
> > +     writel(F_FIFO1_FLUSH(1), mhdp->regs +
> SOURCE_PIF_FIFO1_FLUSH);
> > +
> > +     /* write packet into memory */
> > +     packet32 = (u32 *)packet;
> 
> This only works on little-endian machines, no?
Register SOURCE_PIF_DATA_WR require little-endian data,
I will use get_unaligned_le32() to replace it in the next version.
> 
> > +     len32 = packet_len / 4;
> > +     for (i = 0; i < len32; i++)
> > +             writel(F_DATA_WR(packet32[i]), mhdp->regs +
> SOURCE_PIF_DATA_WR);
> > +
> > +     /* write entry id */
> > +     writel(F_WR_ADDR(entry_id), mhdp->regs +
> SOURCE_PIF_WR_ADDR);
> > +
> > +     /* write request */
> > +     writel(F_HOST_WR(1), mhdp->regs + SOURCE_PIF_WR_REQ);
> > +
> > +     /* update entry */
> > +     val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
> > +                     F_PACKET_TYPE(packet_type) |
> F_PKT_ALLOC_ADDRESS(entry_id);
> > +     writel(val, mhdp->regs + SOURCE_PIF_PKT_ALLOC_REG);
> > +
> > +     writel(F_PKT_ALLOC_WR_EN(1), mhdp->regs +
> SOURCE_PIF_PKT_ALLOC_WR_EN);
> > +}
> > +
> > +static int cdns_hdmi_get_edid_block(void *data, u8 *edid,
> > +                       u32 block, size_t length) {
> > +     struct cdns_mhdp_device *mhdp = data;
> > +     u8 msg[2], reg[5], i;
> > +     int ret;
> > +
> > +     mutex_lock(&mhdp->mbox_mutex);
> > +
> > +     for (i = 0; i < 4; i++) {
> 
> What is i? It is not used inside the loop.
EDID data read by HDMI firmware are not guarantee 100% successful.
Base on experiments, try 4 times if EDID read failed.
> 
> > +             msg[0] = block / 2;
> > +             msg[1] = block % 2;
> > +
> > +             ret = cdns_mhdp_mailbox_send(mhdp,
> MB_MODULE_ID_HDMI_TX,
> HDMI_TX_EDID,
> > +                                       sizeof(msg), msg);
> > +             if (ret)
> > +                     continue;
> > +
> > +             ret = cdns_mhdp_mailbox_recv_header(mhdp,
> MB_MODULE_ID_HDMI_TX,
> > +
> HDMI_TX_EDID, sizeof(reg) + length);
> > +             if (ret)
> > +                     continue;
> > +
> > +             ret = cdns_mhdp_mailbox_recv_data(mhdp, reg,
> sizeof(reg));
> > +             if (ret)
> > +                     continue;
> > +
> > +             ret = cdns_mhdp_mailbox_recv_data(mhdp, edid, length);
> > +             if (ret)
> > +                     continue;
> > +
> > +             if ((reg[3] << 8 | reg[4]) == length)
> > +                     break;
> > +     }
> > +
> > +     mutex_unlock(&mhdp->mbox_mutex);
> > +
> > +     if (ret)
> > +             DRM_ERROR("get block[%d] edid failed: %d\n", block,
> ret);
> > +     return ret;
> > +}
> > +
> > +int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8
> > +*data) {
> > +     u8 msg[4], reg[6];
> > +     int ret;
> > +
> > +     msg[0] = 0x54;
> > +     msg[1] = addr;
> > +     msg[2] = 0;
> > +     msg[3] = 1;
> > +
> > +     mutex_lock(&mhdp->mbox_mutex);
> > +
> > +     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX,
> HDMI_TX_READ,
> > +                               sizeof(msg), msg);
> > +     if (ret)
> > +             goto err_scdc_read;
> > +
> > +     ret = cdns_mhdp_mailbox_recv_header(mhdp,
> MB_MODULE_ID_HDMI_TX,
> > +                                           HDMI_TX_READ,
> sizeof(reg));
> > +     if (ret)
> > +             goto err_scdc_read;
> > +
> > +     ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg));
> > +     if (ret)
> > +             goto err_scdc_read;
> > +
> > +     *data = reg[5];
> > +
> > +err_scdc_read:
> > +
> > +     mutex_unlock(&mhdp->mbox_mutex);
> > +
> > +     if (ret)
> > +             DRM_ERROR("scdc read failed: %d\n", ret);
> > +     return ret;
> > +}
> > +
> > +int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8
> > +value) {
> > +     u8 msg[5], reg[5];
> > +     int ret;
> > +
> > +     msg[0] = 0x54;
> > +     msg[1] = addr;
> > +     msg[2] = 0;
> > +     msg[3] = 1;
> > +     msg[4] = value;
> > +
> > +     mutex_lock(&mhdp->mbox_mutex);
> > +
> > +     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX,
> HDMI_TX_WRITE,
> > +                               sizeof(msg), msg);
> > +     if (ret)
> > +             goto err_scdc_write;
> > +
> > +     ret = cdns_mhdp_mailbox_recv_header(mhdp,
> MB_MODULE_ID_HDMI_TX,
> > +                                           HDMI_TX_WRITE,
> sizeof(reg));
> > +     if (ret)
> > +             goto err_scdc_write;
> > +
> > +     ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg));
> > +     if (ret)
> > +             goto err_scdc_write;
> > +
> > +     if (reg[0] != 0)
> > +             ret = -EINVAL;
> > +
> > +err_scdc_write:
> > +
> > +     mutex_unlock(&mhdp->mbox_mutex);
> > +
> > +     if (ret)
> > +             DRM_ERROR("scdc write failed: %d\n", ret);
> > +     return ret;
> > +}
> > +
> > +int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp,
> > +                              int protocol, u32 char_rate) {
> > +     u32 reg0;
> > +     u32 reg1;
> > +     u32 val;
> > +     int ret;
> > +
> > +     /* Set PHY to HDMI data */
> > +     ret = cdns_mhdp_reg_write(mhdp, PHY_DATA_SEL,
> F_SOURCE_PHY_MHDP_SEL(1));
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_HPD,
> > +                                     F_HPD_VALID_WIDTH(4) |
> F_HPD_GLITCH_WIDTH(0));
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* open CARS */
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_PHY_CAR, 0xF);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, 0xFF);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_PKT_CAR, 0xF);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_AIF_CAR, 0xF);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_CIPHER_CAR, 0xF);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_CRYPTO_CAR, 0xF);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, SOURCE_CEC_CAR, 3);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     reg0 = reg1 = 0x7c1f;
> > +     if (protocol == MODE_HDMI_2_0 && char_rate >= 340000) {
> > +             reg0 = 0;
> > +             reg1 = 0xFFFFF;
> > +     }
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_0, reg0);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_1, reg1);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* set hdmi mode and preemble mode data enable */
> > +     val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) |
> > + F_DATA_EN(1)
> |
> > +                     F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) |
> F_PIC_3D(0XF);
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
> > +
> > +     return ret;
> > +}
> > +
> > +int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp,
> > +                                           struct
> drm_display_mode *mode,
> > +                                               struct
> video_info *video_info)
> > +{
> > +     int ret;
> > +     u32 val;
> > +     u32 vsync_lines = mode->vsync_end - mode->vsync_start;
> > +     u32 eof_lines = mode->vsync_start - mode->vdisplay;
> > +     u32 sof_lines = mode->vtotal - mode->vsync_end;
> > +     u32 hblank = mode->htotal - mode->hdisplay;
> > +     u32 hactive = mode->hdisplay;
> > +     u32 vblank = mode->vtotal - mode->vdisplay;
> > +     u32 vactive = mode->vdisplay;
> > +     u32 hfront = mode->hsync_start - mode->hdisplay;
> > +     u32 hback = mode->htotal - mode->hsync_end;
> > +     u32 vfront = eof_lines;
> > +     u32 hsync = hblank - hfront - hback;
> > +     u32 vsync = vsync_lines;
> > +     u32 vback = sof_lines;
> > +     u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ?
> 0 : 1) +
> > +                                             ((mode->flags &
> DRM_MODE_FLAG_NVSYNC) ? 0 : 2);
> 
> Please fix the alignment.
OK.
> 
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_H_SIZE, (hactive <<
> > + 16) +
> > hblank); +    if (ret < 0)
> > +             return ret;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_V_SIZE, (vactive <<
> > + 16) +
> > vblank); +    if (ret < 0)
> > +             return ret;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_FRONT_WIDTH,
> (vfront
> > + <<
> 16) +
> > hfront); +    if (ret < 0)
> > +             return ret;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_SYNC_WIDTH,
> (vsync
> > + <<
> 16) +
> > hsync); +     if (ret < 0)
> > +             return ret;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_BACK_WIDTH,
> (vback
> > + <<
> 16) +
> > hback); +     if (ret < 0)
> > +             return ret;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL,
> v_h_polarity);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* Reset Data Enable */
> > +     cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER, &val);
> > +     val &= ~F_DATA_EN(1);
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* Set bpc */
> > +     val &= ~F_VIF_DATA_WIDTH(3);
> > +     switch (video_info->bpc) {
> > +     case 10:
> > +             val |= F_VIF_DATA_WIDTH(1);
> > +             break;
> > +     case 12:
> > +             val |= F_VIF_DATA_WIDTH(2);
> > +             break;
> > +     case 16:
> > +             val |= F_VIF_DATA_WIDTH(3);
> > +             break;
> > +     case 8:
> > +     default:
> > +             val |= F_VIF_DATA_WIDTH(0);
> > +             break;
> > +     }
> > +
> > +     /* select color encoding */
> > +     val &= ~F_HDMI_ENCODING(3);
> > +     switch (video_info->color_fmt) {
> > +     case DRM_COLOR_FORMAT_YCBCR444:
> > +             val |= F_HDMI_ENCODING(2);
> > +             break;
> > +     case DRM_COLOR_FORMAT_YCBCR422:
> > +             val |= F_HDMI_ENCODING(1);
> > +             break;
> > +     case DRM_COLOR_FORMAT_YCBCR420:
> > +             val |= F_HDMI_ENCODING(3);
> > +             break;
> > +     case DRM_COLOR_FORMAT_RGB444:
> > +     default:
> > +             val |= F_HDMI_ENCODING(0);
> > +             break;
> > +     }
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* set data enable */
> > +     val |= F_DATA_EN(1);
> > +     ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
> > +
> > +     return ret;
> > +}
> > +
> > +int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp) {
> > +     u32 val;
> > +
> > +     cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER, &val);
> > +     val &= ~F_GCP_EN(1);
> > +
> > +     return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); }
> > +
> > +int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp) {
> > +     u32 val;
> > +
> > +     cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER, &val);
> > +     val |= F_GCP_EN(1);
> > +
> > +     return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); }
> > +
> > +static void hdmi_sink_config(struct cdns_mhdp_device *mhdp) {
> > +     struct drm_scdc *scdc =
> &mhdp->curr_conn->display_info.hdmi.scdc;
> > +     u8 buff = 0;
> > +
> > +     /* Default work in HDMI1.4 */
> > +     mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
> > +
> > +     /* check sink support SCDC or not */
> > +     if (scdc->supported != true) {
> > +             DRM_INFO("Sink Not Support SCDC\n");
> > +             return;
> > +     }
> > +
> > +     if (mhdp->hdmi.char_rate > 340000) {
> > +             /*
> > +              * TMDS Character Rate above 340MHz should working in
> HDMI2.0
> > +              * Enable scrambling and TMDS_Bit_Clock_Ratio
> > +              */
> > +             buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 |
> SCDC_SCRAMBLING_ENABLE;
> > +             mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
> > +     } else  if (scdc->scrambling.low_rates) {
> > +             /*
> > +              * Enable scrambling and HDMI2.0 when scrambling
> capability of sink
> > +              * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
> > +              */
> > +             buff = SCDC_SCRAMBLING_ENABLE;
> > +             mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
> > +     }
> > +
> > +     /* TMDS config */
> > +     cdns_hdmi_scdc_write(mhdp, SCDC_TMDS_CONFIG, buff); }
> > +
> > +static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp) {
> > +     u32 lane_mapping = mhdp->plat_data->lane_mapping;
> > +     /* Line swapping */
> > +     cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 |
> > +lane_mapping); }
> > +
> > +int cdns_mhdp_hdmi_read_hpd(struct cdns_mhdp_device *mhdp) {
> > +     u8 status;
> > +     int ret;
> > +
> > +     mutex_lock(&mhdp->mbox_mutex);
> > +
> > +     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX,
> > HDMI_TX_HPD_STATUS, +                           0, NULL);
> > +     if (ret)
> > +             goto err_get_hpd;
> > +
> > +     ret = cdns_mhdp_mailbox_recv_header(mhdp,
> MB_MODULE_ID_HDMI_TX,
> > +
> HDMI_TX_HPD_STATUS, sizeof(status));
> > +     if (ret)
> > +             goto err_get_hpd;
> > +
> > +     ret = cdns_mhdp_mailbox_recv_data(mhdp, &status, sizeof(status));
> > +     if (ret)
> > +             goto err_get_hpd;
> > +
> > +     mutex_unlock(&mhdp->mbox_mutex);
> > +     return status;
> > +
> > +err_get_hpd:
> > +     mutex_unlock(&mhdp->mbox_mutex);
> > +     DRM_ERROR("read hpd  failed: %d\n", ret);
> > +     return ret;
> > +}
> > +
> > +static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
> > +                          struct drm_display_mode *mode) {
> > +     struct hdmi_avi_infoframe frame;
> > +     int format = mhdp->video_info.color_fmt;
> > +     struct drm_connector_state *conn_state = mhdp->curr_conn->state;
> > +     struct drm_display_mode *adj_mode;
> > +     enum hdmi_quantization_range qr;
> > +     u8 buf[32];
> > +     int ret;
> > +
> > +     /* Initialise info frame from DRM mode */
> > +     drm_hdmi_avi_infoframe_from_display_mode(&frame,
> > +                                             mhdp->curr_conn,
> mode);
> > +
> > +     switch (format) {
> > +     case DRM_COLOR_FORMAT_YCBCR444:
> > +             frame.colorspace = HDMI_COLORSPACE_YUV444;
> > +             break;
> > +     case DRM_COLOR_FORMAT_YCBCR422:
> > +             frame.colorspace = HDMI_COLORSPACE_YUV422;
> > +             break;
> > +     case DRM_COLOR_FORMAT_YCBCR420:
> > +             frame.colorspace = HDMI_COLORSPACE_YUV420;
> > +             break;
> > +     default:
> > +             frame.colorspace = HDMI_COLORSPACE_RGB;
> > +             break;
> > +     }
> > +
> > +     drm_hdmi_avi_infoframe_colorimetry(&frame, conn_state);
> > +
> > +     adj_mode = &mhdp->bridge.encoder->crtc->state->adjusted_mode;
> > +
> > +     qr = drm_default_rgb_quant_range(adj_mode);
> > +
> > +     drm_hdmi_avi_infoframe_quant_range(&frame, mhdp->curr_conn,
> > +                                        adj_mode, qr);
> > +
> > +     ret = hdmi_avi_infoframe_check(&frame);
> > +     if (WARN_ON(ret))
> > +             return -EINVAL;
> > +
> > +     ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
> > +     if (ret < 0) {
> > +             DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
> > +             return -1;
> > +     }
> > +
> > +     buf[0] = 0;
> > +     cdns_mhdp_infoframe_set(mhdp, 0, sizeof(buf), buf,
> > HDMI_INFOFRAME_TYPE_AVI); +
> > +     return 0;
> > +}
> > +
> > +static void hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
> > +                             struct drm_display_mode *mode) {
> > +     struct hdmi_vendor_infoframe frame;
> > +     u8 buf[32];
> > +     int ret;
> > +
> > +     /* Initialise vendor frame from DRM mode */
> > +     ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame,
> mhdp-
> >curr_conn,
> > mode); +      if (ret < 0) {
> > +             DRM_INFO("No vendor infoframe\n");
> > +             return;
> > +     }
> > +
> > +     ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
> > +     if (ret < 0) {
> > +             DRM_WARN("Unable to pack vendor infoframe: %d\n",
> ret);
> > +             return;
> > +     }
> > +
> > +     buf[0] = 0;
> > +     cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf,
> > HDMI_INFOFRAME_TYPE_VENDOR); +}
> > +
> > +static void hdmi_drm_info_set(struct cdns_mhdp_device *mhdp) {
> > +     struct drm_connector_state *conn_state;
> > +     struct hdmi_drm_infoframe frame;
> > +     u8 buf[32];
> > +     int ret;
> > +
> > +     conn_state = mhdp->curr_conn->state;
> > +
> > +     if (!conn_state->hdr_output_metadata)
> > +             return;
> > +
> > +     ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state);
> > +     if (ret < 0) {
> > +             DRM_DEBUG_KMS("couldn't set HDR metadata in
> infoframe\n");
> > +             return;
> > +     }
> > +
> > +     ret = hdmi_drm_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
> > +     if (ret < 0) {
> > +             DRM_DEBUG_KMS("couldn't pack HDR infoframe\n");
> > +             return;
> > +     }
> > +
> > +     buf[0] = 0;
> > +     cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf,
> > HDMI_INFOFRAME_TYPE_DRM); +}
> > +
> > +static int hdmi_phy_colorspace(int color_fmt) {
> > +     int color_space;
> > +
> > +     switch (color_fmt) {
> > +     case DRM_COLOR_FORMAT_YCBCR444:
> > +             color_space = HDMI_PHY_COLORSPACE_YUV444;
> > +             break;
> > +     case DRM_COLOR_FORMAT_YCBCR422:
> > +             color_space = HDMI_PHY_COLORSPACE_YUV422;
> > +             break;
> > +     case DRM_COLOR_FORMAT_YCBCR420:
> > +             color_space = HDMI_PHY_COLORSPACE_YUV420;
> > +             break;
> > +     case DRM_COLOR_FORMAT_RGB444:
> > +     default:
> > +             color_space = HDMI_PHY_COLORSPACE_RGB;
> > +             break;
> > +     }
> > +
> > +     return color_space;
> > +}
> > +
> > +void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp) {
> > +     struct drm_display_mode *mode = &mhdp->mode;
> > +     union phy_configure_opts phy_cfg;
> > +     int ret;
> > +
> > +     /* video mode check */
> > +     if (mode->clock == 0 || mode->hdisplay == 0 ||  mode->vdisplay ==
> 0)
> > +             return;
> > +
> > +     hdmi_lanes_config(mhdp);
> > +
> > +     phy_cfg.hdmi.pixel_clk_rate = mode->clock;
> > +     phy_cfg.hdmi.bpc = mhdp->video_info.bpc;
> > +     phy_cfg.hdmi.color_space =
> > hdmi_phy_colorspace(mhdp->video_info.color_fmt); +    ret =
> > phy_configure(mhdp->phy,  &phy_cfg);
> > +     if (ret) {
> > +             dev_err(mhdp->dev, "%s: phy_configure() failed: %d\n",
> > +                     __func__, ret);
> > +             return;
> > +     }
> > +
> > +     hdmi_sink_config(mhdp);
> > +
> > +     ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type,
> > mhdp->hdmi.char_rate); +      if (ret < 0) {
> > +             DRM_ERROR("%s, ret = %d\n", __func__, ret);
> > +             return;
> > +     }
> > +
> > +     /* Config GCP */
> > +     if (mhdp->video_info.bpc == 8)
> > +             cdns_hdmi_disable_gcp(mhdp);
> > +     else
> > +             cdns_hdmi_enable_gcp(mhdp);
> > +
> > +     ret = hdmi_avi_info_set(mhdp, mode);
> > +     if (ret < 0) {
> > +             DRM_ERROR("%s ret = %d\n", __func__, ret);
> > +             return;
> > +     }
> > +
> > +     /* vendor info frame is enabled only for HDMI1.4 4K mode */
> > +     hdmi_vendor_info_set(mhdp, mode);
> > +
> > +     hdmi_drm_info_set(mhdp);
> > +
> > +     ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
> > +     if (ret < 0) {
> > +             DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret
> = %d\n",
> ret);
> > +             return;
> > +     }
> > +}
> > +static enum drm_connector_status
> > +cdns_hdmi_detect(struct cdns_mhdp_device *mhdp) {
> > +     u8 hpd = 0xf;
> > +
> > +     hpd = cdns_mhdp_hdmi_read_hpd(mhdp);
> > +     if (hpd == 1)
> > +             return connector_status_connected;
> > +     else if (hpd == 0)
> > +             return connector_status_disconnected;
> > +
> > +     DRM_INFO("Unknown cable status, hdp=%u\n", hpd);
> > +     return connector_status_unknown; }
> > +
> > +static enum drm_connector_status
> > +cdns_hdmi_bridge_detect(struct drm_bridge *bridge) {
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +
> > +     return cdns_hdmi_detect(mhdp);
> > +}
> > +
> > +static int cdns_hdmi_connector_get_modes(struct drm_connector
> > +*connector) {
> > +     struct cdns_mhdp_device *mhdp =
> > +                             container_of(connector, struct
> cdns_mhdp_device, connector);
> > +     int num_modes = 0;
> > +     struct edid *edid;
> > +
> > +     edid = drm_do_get_edid(connector,
> > +                                cdns_hdmi_get_edid_block,
> mhdp);
> > +     if (edid) {
> > +             dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
> > +                      edid->header[0], edid->header[1],
> > +                      edid->header[2], edid->header[3],
> > +                      edid->header[4], edid->header[5],
> > +                      edid->header[6], edid->header[7]);
> > +             drm_connector_update_edid_property(connector, edid);
> > +             num_modes = drm_add_edid_modes(connector, edid);
> > +             kfree(edid);
> > +     }
> > +
> > +     if (num_modes == 0)
> > +             DRM_ERROR("Invalid edid\n");
> > +     return num_modes;
> > +}
> > +
> > +static bool blob_equal(const struct drm_property_blob *a,
> > +                    const struct drm_property_blob *b) {
> > +     if (a && b)
> > +             return a->length == b->length &&
> > +                     !memcmp(a->data, b->data, a->length);
> > +
> > +     return !a == !b;
> > +}
> > +
> > +static int cdns_hdmi_connector_atomic_check(struct drm_connector
> > *connector, +                                     struct
> drm_atomic_state *state)
> > +{
> > +     struct drm_connector_state *new_con_state =
> > +             drm_atomic_get_new_connector_state(state, connector);
> > +     struct drm_connector_state *old_con_state =
> > +             drm_atomic_get_old_connector_state(state, connector);
> > +     struct drm_crtc *crtc = new_con_state->crtc;
> > +     struct drm_crtc_state *new_crtc_state;
> > +
> > +     if (!blob_equal(new_con_state->hdr_output_metadata,
> > +                     old_con_state->hdr_output_metadata) ||
> > +         new_con_state->colorspace != old_con_state->colorspace) {
> > +             new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
> > +             if (IS_ERR(new_crtc_state))
> > +                     return PTR_ERR(new_crtc_state);
> > +
> > +             new_crtc_state->mode_changed =
> > +                     !new_con_state->hdr_output_metadata ||
> > +                     !old_con_state->hdr_output_metadata ||
> > +                     new_con_state->colorspace != old_con_state-
> >colorspace;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
> > +     .fill_modes = drm_helper_probe_single_connector_modes,
> > +     .destroy = drm_connector_cleanup,
> > +     .reset = drm_atomic_helper_connector_reset,
> > +     .atomic_duplicate_state =
> drm_atomic_helper_connector_duplicate_state,
> > +     .atomic_destroy_state =
> > +drm_atomic_helper_connector_destroy_state,
> > +};
> > +
> > +static const struct drm_connector_helper_funcs
> > cdns_hdmi_connector_helper_funcs = { +        .get_modes =
> > cdns_hdmi_connector_get_modes,
> > +     .atomic_check = cdns_hdmi_connector_atomic_check, };
> > +
> > +static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge,
> > +                              enum drm_bridge_attach_flags flags)
> {
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     struct drm_mode_config *config = &bridge->dev->mode_config;
> > +     struct drm_encoder *encoder = bridge->encoder;
> > +     struct drm_connector *connector = &mhdp->connector;
> > +
> > +     if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > +             connector->interlace_allowed = 0;
> > +             connector->polled = DRM_CONNECTOR_POLL_HPD;
> > +
> > +             drm_connector_helper_add(connector,
> &cdns_hdmi_connector_helper_funcs);
> > +
> > +             drm_connector_init(bridge->dev, connector,
> &cdns_hdmi_connector_funcs,
> > +
> DRM_MODE_CONNECTOR_HDMIA);
> > +
> > +             drm_object_attach_property(&connector->base,
> > +                                        config-
> >hdr_output_metadata_property, 0);
> > +
> > +             if
> (!drm_mode_create_hdmi_colorspace_property(connector))
> > +
> drm_object_attach_property(&connector->base,
> > +                                             connector-
> >colorspace_property, 0);
> > +
> > +             drm_connector_attach_encoder(connector, encoder);
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static enum drm_mode_status
> > +cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
> > +                             const struct drm_display_info *info,
> > +                             const struct drm_display_mode
> *mode) {
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     enum drm_mode_status mode_status = MODE_OK;
> > +     union phy_configure_opts phy_cfg;
> > +     int ret;
> > +
> > +     /* We don't support double-clocked and Interlaced modes */
> > +     if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
> > +                     mode->flags & DRM_MODE_FLAG_INTERLACE)
> > +             return MODE_BAD;
> > +
> > +     /* MAX support pixel clock rate 594MHz */
> > +     if (mode->clock > 594000)
> > +             return MODE_CLOCK_HIGH;
> > +
> > +     /* 4096x2160 is not supported */
> > +     if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
> > +             return MODE_BAD_HVALUE;
> > +
> > +     /* Check modes supported by PHY */
> > +     phy_cfg.hdmi.pixel_clk_rate = mode->clock;
> > +     ret = phy_validate(mhdp->phy, PHY_MODE_HDMI, 0, &phy_cfg);
> > +     if (ret < 0)
> > +             return MODE_CLOCK_RANGE;
> > +
> > +     return mode_status;
> > +}
> > +
> > +bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
> > +                              const struct drm_display_mode
> *mode,
> > +                              struct drm_display_mode
> *adjusted_mode)
> > +{
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     struct video_info *video = &mhdp->video_info;
> > +
> > +     video->bpc = 8;
> > +     video->color_fmt = DRM_COLOR_FORMAT_RGB444;
> > +
> > +     return true;
> > +}
> > +
> > +static struct edid *cdns_hdmi_bridge_get_edid(struct drm_bridge *bridge,
> > +                                           struct
> drm_connector
> *connector)
> > +{
> > +     struct cdns_mhdp_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_mhdp_device *mhdp = bridge->driver_private;
> > +
> > +     mhdp->curr_conn = NULL;
> > +
> > +     mutex_lock(&mhdp->lock);
> > +     phy_power_off(mhdp->phy);
> > +     mutex_unlock(&mhdp->lock);
> > +}
> > +
> > +static void cdns_hdmi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +                                      struct drm_bridge_state
> *old_state)
> > +{
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     struct drm_atomic_state *state = old_state->base.state;
> > +     struct drm_connector *connector;
> > +     struct video_info *video = &mhdp->video_info;
> > +     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;
> > +     DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay,
> mode->vdisplay,
> > + mode-
> >clock);
> > +     memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
> > +
> > +     video->v_sync_polarity = !!(mode->flags &
> DRM_MODE_FLAG_NVSYNC);
> > +     video->h_sync_polarity = !!(mode->flags &
> DRM_MODE_FLAG_NHSYNC);
> > +
> > +     mutex_lock(&mhdp->lock);
> > +     cdns_hdmi_mode_set(mhdp);
> > +     mutex_unlock(&mhdp->lock);
> > +}
> > +
> > +static 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, };
> > +
> > +static void hotplug_work_func(struct work_struct *work) {
> > +     struct cdns_mhdp_device *mhdp = container_of(work,
> > +                                        struct
> cdns_mhdp_device,
> hotplug_work.work);
> > +     enum drm_connector_status status = cdns_hdmi_detect(mhdp);
> > +
> > +     drm_bridge_hpd_notify(&mhdp->bridge, status);
> > +
> > +     if (status == connector_status_connected) {
> > +             DRM_INFO("HDMI Cable Plug In\n");
> > +             enable_irq(mhdp->irq[IRQ_OUT]);
> > +     } else if (status == connector_status_disconnected) {
> > +             /* Cable Disconnedted  */
> > +             DRM_INFO("HDMI Cable Plug Out\n");
> > +             enable_irq(mhdp->irq[IRQ_IN]);
> > +     }
> > +}
> > +
> > +static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data) {
> > +     struct cdns_mhdp_device *mhdp = data;
> > +
> > +     disable_irq_nosync(irq);
> > +
> > +     mod_delayed_work(system_wq, &mhdp->hotplug_work,
> > +                     msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +static int cdns_mhdp_imx_probe(struct platform_device *pdev) {
> > +     struct device *dev = &pdev->dev;
> > +     struct cdns_mhdp_device *mhdp;
> > +     struct platform_device_info pdevinfo;
> > +     struct resource *res;
> > +     u32 reg;
> > +     int ret;
> > +
> > +     mhdp = devm_kzalloc(dev, sizeof(*mhdp), GFP_KERNEL);
> > +     if (!mhdp)
> > +             return -ENOMEM;
> > +
> > +     mutex_init(&mhdp->lock);
> > +     mutex_init(&mhdp->mbox_mutex);
> > +
> > +     INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
> > +
> > +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +     if (!res)
> > +             return -ENODEV;
> > +     mhdp->regs = devm_ioremap(dev, res->start, resource_size(res));
> > +     if (IS_ERR(mhdp->regs))
> > +             return PTR_ERR(mhdp->regs);
> 
> Please use devm_platform_get_and_ioremap_resource.
Both HDMI PHY driver and mhdp HDMI driver should access same APB base register offset for mailbox.
devm_ioremap_resource could not support such feature.
> 
> > +     mhdp->phy = devm_of_phy_get_by_index(dev, pdev->dev.of_node,
> 0);
> > +     if (IS_ERR(mhdp->phy)) {
> > +             dev_err(dev, "no PHY configured\n");
> > +             return PTR_ERR(mhdp->phy);
> > +     }
> 
> Please use dev_err_probe().
OK.
> 
> > +     mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
> > +     if (mhdp->irq[IRQ_IN] < 0) {
> > +             dev_info(dev, "No plug_in irq number\n");
> > +             return -EPROBE_DEFER;
> > +     }
> 
> Please use dev_err_probe().
OK.
> 
> > +     mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev,
> "plug_out");
> > +     if (mhdp->irq[IRQ_OUT] < 0) {
> > +             dev_info(dev, "No plug_out irq number\n");
> > +             return -EPROBE_DEFER;
> > +     }
> 
> Please use dev_err_probe().
OK.
> 
> > +     /*
> > +      * Wait for the KEEP_ALIVE "message" on the first 8 bits.
> > +      * Updated each sched "tick" (~2ms)
> > +      */
> > +     ret = readl_poll_timeout(mhdp->regs + KEEP_ALIVE, reg,
> > +                              reg & CDNS_KEEP_ALIVE_MASK,
> 500,
> > +                              CDNS_KEEP_ALIVE_TIMEOUT);
> 
> This freezes my board TQMa8MQ
> (arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-
> mba8mx.dts) completly if this and the PHY driver are compiled in. I have
> "pd_ignore_unused clk_ignore_unused" passed to kernel command line, so I
> have no idea what's wrong here.
Here is the first time in the driver to access hdmi register when driver probe.
For imx8mq hdmi/dp, mdhp hdmi apb clock and core clock are managed by ROM code, they are always on when device bootup.
Could you dump the clock tree without "pd_ignore_unused clk_ignore_unused" ?
> 
> Best regards,
> Alexander
> 

B.R
Sandor
> > +     if (ret) {
> > +             dev_err(mhdp->dev,
> > +                     "device didn't give any life sign: reg %d\n",
> reg);
> > +             return ret;
> > +     }
> > +
> > +     ret = phy_init(mhdp->phy);
> > +     if (ret) {
> > +             dev_err(mhdp->dev, "Failed to initialize PHY: %d\n", ret);
> > +             return -ENODEV;
> > +     }
> > +
> > +     /* Enable Hotplug Detect thread */
> > +     irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
> > +     ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
> > +                                     NULL,
> cdns_hdmi_irq_thread,
> > +                                     IRQF_ONESHOT,
> dev_name(dev),
> > +                                     mhdp);
> > +     if (ret < 0) {
> > +             dev_err(dev, "can't claim irq %d\n",
> > +                                             mhdp-
> >irq[IRQ_IN]);
> > +             return -EINVAL;
> > +     }
> > +
> > +     irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
> > +     ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
> > +                                     NULL,
> cdns_hdmi_irq_thread,
> > +                                     IRQF_ONESHOT,
> dev_name(dev),
> > +                                     mhdp);
> > +     if (ret < 0) {
> > +             dev_err(dev, "can't claim irq %d\n",
> > +                                             mhdp-
> >irq[IRQ_OUT]);
> > +             return -EINVAL;
> > +     }
> > +
> > +     mhdp->dev = dev;
> > +
> > +     if (cdns_mhdp_hdmi_read_hpd(mhdp))
> > +             enable_irq(mhdp->irq[IRQ_OUT]);
> > +     else
> > +             enable_irq(mhdp->irq[IRQ_IN]);
> > +
> > +     mhdp->bridge.driver_private = mhdp;
> > +     mhdp->bridge.funcs = &cdns_hdmi_bridge_funcs;
> > +     mhdp->bridge.of_node = dev->of_node;
> > +     mhdp->bridge.ops = DRM_BRIDGE_OP_DETECT |
> DRM_BRIDGE_OP_EDID |
> > +                        DRM_BRIDGE_OP_HPD;
> > +     mhdp->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
> > +     drm_bridge_add(&mhdp->bridge);
> > +
> > +     memset(&pdevinfo, 0, sizeof(pdevinfo));
> > +     pdevinfo.parent = dev;
> > +     pdevinfo.id = PLATFORM_DEVID_AUTO;
> > +
> > +     dev_set_drvdata(dev, mhdp);
> > +     mhdp->plat_data = of_device_get_match_data(dev);
> > +
> > +     return 0;
> > +}
> > +
> > +static int cdns_mhdp_imx_remove(struct platform_device *pdev) {
> > +     struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
> > +     int ret = 0;
> > +
> > +     drm_bridge_remove(&mhdp->bridge);
> > +
> > +     return ret;
> > +}
> > +
> > +static struct cdns_plat_data imx8mq_hdmi_drv_data = {
> > +     .lane_mapping = 0xe4,
> > +};
> > +
> > +static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
> > +     { .compatible = "cdns,mhdp-imx8mq-hdmi",
> > +       .data = &imx8mq_hdmi_drv_data
> > +     },
> > +     {},
> > +};
> > +MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids);
> > +
> > +static struct platform_driver cdns_mhdp_imx_platform_driver = {
> > +     .probe  = cdns_mhdp_imx_probe,
> > +     .remove = cdns_mhdp_imx_remove,
> > +     .driver = {
> > +             .name = "cdns-mhdp-imx8mq-hdmi",
> > +             .of_match_table = cdns_mhdp_imx_dt_ids,
> > +     },
> > +};
> > +
> > +module_platform_driver(cdns_mhdp_imx_platform_driver);
> > +
> > +MODULE_AUTHOR("Sandor Yu <sandor.yu at nxp.com>");
> > +MODULE_DESCRIPTION("Cadence HDMI transmitter driver");
> > +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:cdns-hdmi");
> 
> 
> 



More information about the linux-arm-kernel mailing list