diff options
Diffstat (limited to 'drivers/gpu/drm/imx/hdp/imx-hdp.c')
-rw-r--r-- | drivers/gpu/drm/imx/hdp/imx-hdp.c | 76 |
1 files changed, 65 insertions, 11 deletions
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.c b/drivers/gpu/drm/imx/hdp/imx-hdp.c index bcfad522df43..0fd33ce1f047 100644 --- a/drivers/gpu/drm/imx/hdp/imx-hdp.c +++ b/drivers/gpu/drm/imx/hdp/imx-hdp.c @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/irq.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> #include "imx-hdp.h" #include "imx-hdmi.h" @@ -32,7 +33,9 @@ #define B0_SILICON_ID 0x11 struct drm_display_mode *g_mode; -uint8_t g_default_mode = 3; +uint8_t g_default_mode = 2; +static const uint8_t g_4kp60_mode = 3; + static struct drm_display_mode edid_cea_modes[] = { /* 3 - 720x480@60Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, @@ -833,10 +836,17 @@ imx_hdp_connector_detect(struct drm_connector *connector, bool force) struct imx_hdp, connector); int ret; u8 hpd = 0xf; + struct edid *edid; ret = imx_hdp_call(hdp, get_hpd_state, &hdp->state, &hpd); - if (ret > 0) - return connector_status_unknown; + if (ret > 0) { + /* Check if optional regular DDC I2C bus should be used. */ + if (hdp->ddc) { + edid = drm_get_edid(connector, hdp->ddc); + if (drm_edid_is_valid(edid)) + hpd = 1; + } + } if (hpd == 1) /* Cable Connected */ @@ -846,7 +856,7 @@ imx_hdp_connector_detect(struct drm_connector *connector, bool force) 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; } } @@ -861,7 +871,9 @@ static int imx_hdp_default_video_modes(struct drm_connector *connector) if (!mode) return -EINVAL; drm_mode_copy(mode, &edid_cea_modes[i]); - mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + mode->type |= DRM_MODE_TYPE_DRIVER; + if(i == g_default_mode) + mode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); } return i; @@ -875,8 +887,16 @@ static int imx_hdp_connector_get_modes(struct drm_connector *connector) int num_modes = 0; if (!hdp->no_edid) { - edid = drm_do_get_edid(connector, hdp->ops->get_edid_block, - &hdp->state); + /* + * Check if optional regular DDC I2C bus should be used. + * Fall-back to using IP/firmware integrated one. + */ + if (hdp->ddc) + edid = drm_get_edid(connector, hdp->ddc); + else + edid = drm_do_get_edid(connector, + hdp->ops->get_edid_block, + &hdp->state); if (edid) { dev_info(hdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n", edid->header[0], edid->header[1], @@ -1320,6 +1340,7 @@ static struct hdp_ops imx8qm_hdmi_ops = { }; static struct hdp_devtype imx8qm_dp_devtype = { + .is_hdmi_level = false, .audio_type = CDN_DPTX, .ops = &imx8qm_dp_ops, .rw = &imx8qm_rw, @@ -1327,6 +1348,7 @@ static struct hdp_devtype imx8qm_dp_devtype = { }; static struct hdp_devtype imx8qm_hdmi_devtype = { + .is_hdmi_level = true, .audio_type = CDN_HDMITX_TYPHOON, .ops = &imx8qm_hdmi_ops, .rw = &imx8qm_rw, @@ -1353,6 +1375,7 @@ static struct hdp_ops imx8mq_ops = { }; static struct hdp_devtype imx8mq_hdmi_devtype = { + .is_hdmi_level = true, .audio_type = CDN_HDMITX_KIRAN, .ops = &imx8mq_ops, .rw = &imx8mq_rw, @@ -1399,7 +1422,7 @@ static void hotplug_work_func(struct work_struct *work) /* For HDMI2.0 SCDC should setup again. * So recovery pre video mode if it is 4Kp60 */ if (drm_mode_equal(&hdp->video.pre_mode, - &edid_cea_modes[g_default_mode])) + &edid_cea_modes[g_4kp60_mode])) imx_hdp_mode_setup(hdp, &hdp->video.pre_mode); DRM_INFO("HDMI/DP Cable Plug In\n"); enable_irq(hdp->irq[HPD_IRQ_OUT]); @@ -1428,6 +1451,7 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct imx_hdp *hdp; + struct device_node *ddc_phandle; const struct of_device_id *of_id = of_match_device(imx_hdp_dt_ids, dev); const struct hdp_devtype *devtype = of_id->data; @@ -1495,6 +1519,17 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, if (cpu_is_imx8qm() && (imx8_get_soc_revision() < B0_SILICON_ID)) hdp->no_edid = true; + /* get optional regular DDC I2C bus */ + ddc_phandle = of_parse_phandle(pdev->dev.of_node, "ddc-i2c-bus", 0); + if (ddc_phandle) { + hdp->ddc = of_get_i2c_adapter_by_node(ddc_phandle); + if (hdp->ddc) + dev_info(dev, "Connector's ddc i2c bus found\n"); + else + ret = -EPROBE_DEFER; + of_node_put(ddc_phandle); + } + if (devtype->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { hdp->is_dp = true; hdp->is_edp = of_property_read_bool(pdev->dev.of_node, "fsl,edp"); @@ -1634,6 +1669,18 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, INIT_DELAYED_WORK(&hdp->hotplug_work, hotplug_work_func); + hdp->hdmi_ctrl_gpio = of_get_named_gpio(dev->of_node, "hdmi-ctrl-gpios", 0); + if (gpio_is_valid(hdp->hdmi_ctrl_gpio)) { + ret = gpio_request(hdp->hdmi_ctrl_gpio, "HDMI_CTRL"); + if (ret < 0) { + dev_err(dev, "request HDMI CTRL GPIO failed: %d\n", ret); + goto err_cleanup_encoder; + } + + /* Set signals depending on HDP device type */ + gpio_direction_output(hdp->hdmi_ctrl_gpio, devtype->is_hdmi_level); + } + /* Check cable states before enable irq */ imx_hdp_call(hdp, get_hpd_state, &hdp->state, &hpd); @@ -1647,7 +1694,7 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", hdp->irq[HPD_IRQ_IN]); - goto err_irq; + goto err_free_hdmi_gpio; } /* Cable Disconnedted, enable Plug in IRQ */ if (hpd == 0) @@ -1662,7 +1709,7 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", hdp->irq[HPD_IRQ_OUT]); - goto err_irq; + goto err_free_hdmi_gpio; } /* Cable Connected, enable Plug out IRQ */ if (hpd == 1) @@ -1678,7 +1725,11 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master, imx_hdp_register_audio_driver(dev); return 0; -err_irq: + +err_free_hdmi_gpio: + if (gpio_is_valid(hdp->hdmi_ctrl_gpio)) + gpio_free(hdp->hdmi_ctrl_gpio); +err_cleanup_encoder: drm_encoder_cleanup(encoder); return ret; } @@ -1693,6 +1744,9 @@ static void imx_hdp_imx_unbind(struct device *dev, struct device *master, imx_cec_unregister(&hdp->cec); #endif imx_hdp_call(hdp, pixel_clock_disable, &hdp->clks); + + if (gpio_is_valid(hdp->hdmi_ctrl_gpio)) + gpio_free(hdp->hdmi_ctrl_gpio); } static const struct component_ops imx_hdp_imx_ops = { |