diff options
Diffstat (limited to 'drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c')
-rw-r--r-- | drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c index 73a7d0a04f21..067290b3b3ad 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c @@ -226,6 +226,7 @@ void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp) static enum drm_connector_status cdns_hdmi_connector_detect(struct drm_connector *connector, bool force) { + struct edid *edid; struct cdns_mhdp_device *mhdp = container_of(connector, struct cdns_mhdp_device, connector.base); @@ -233,15 +234,21 @@ cdns_hdmi_connector_detect(struct drm_connector *connector, bool force) hpd = cdns_mhdp_read_hpd(mhdp); - if (hpd == 1) + if (hpd == 1) { /* Cable Connected */ return connector_status_connected; - else if (hpd == 0) + } else if (hpd == 0) { /* Cable Disconnedted */ return connector_status_disconnected; - else { + } else if (mhdp->ddc) { + edid = drm_get_edid(connector, mhdp->ddc); + if (drm_edid_is_valid(edid)) + return connector_status_connected; + else + return connector_status_disconnected; + } else { /* Cable status unknown */ - DRM_INFO("Unknow cable status, hdp=%u\n", hpd); + DRM_INFO("Unknow cable status, hpd=%u\n", hpd); return connector_status_unknown; } } @@ -253,8 +260,15 @@ static int cdns_hdmi_connector_get_modes(struct drm_connector *connector) int num_modes = 0; struct edid *edid; - edid = drm_do_get_edid(&mhdp->connector.base, - cdns_hdmi_get_edid_block, mhdp); + /* + * Check if optional regular DDC I2C bus should be used. + * Fall-back to using IP/firmware integrated one. + */ + if (mhdp->ddc) + edid = drm_get_edid(&mhdp->connector.base, mhdp->ddc); + else + edid = drm_do_get_edid(&mhdp->connector.base, + 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], @@ -374,9 +388,12 @@ cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, if (mode->hdisplay > 3840 || mode->vdisplay > 2160) return MODE_BAD_HVALUE; - vic = drm_match_cea_mode(mode); - if (vic == 0) - return MODE_BAD; + /* imx8mq-hdmi does not support non CEA modes */ + if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) { + vic = drm_match_cea_mode(mode); + if (vic == 0) + return MODE_BAD; + } mhdp->valid_mode = mode; ret = cdns_mhdp_plat_call(mhdp, phy_video_valid); @@ -503,6 +520,7 @@ static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data) static void cdns_hdmi_parse_dt(struct cdns_mhdp_device *mhdp) { struct device_node *of_node = mhdp->dev->of_node; + struct device_node *ddc_phandle; int ret; ret = of_property_read_u32(of_node, "lane-mapping", &mhdp->lane_mapping); @@ -511,6 +529,17 @@ static void cdns_hdmi_parse_dt(struct cdns_mhdp_device *mhdp) dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n"); } dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping); + + /* get optional regular DDC I2C bus */ + ddc_phandle = of_parse_phandle(of_node, "ddc-i2c-bus", 0); + if (ddc_phandle) { + mhdp->ddc = of_get_i2c_adapter_by_node(ddc_phandle); + if (mhdp->ddc) + dev_info(mhdp->dev, "Connector's ddc i2c bus found\n"); + else + ret = -EPROBE_DEFER; + of_node_put(ddc_phandle); + } } static int __cdns_hdmi_probe(struct platform_device *pdev, |