summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imx/hdp/imx-hdp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imx/hdp/imx-hdp.c')
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-hdp.c76
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 = {