summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos/exynos_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_hdmi.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c114
1 files changed, 64 insertions, 50 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 95dd399aa9cc..01813e11e6c6 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -21,8 +21,8 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -522,6 +522,15 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
},
},
+ {
+ .pixel_clock = 154000000,
+ .conf = {
+ 0x01, 0xD1, 0x20, 0x01, 0x40, 0x30, 0x08, 0xCC,
+ 0x8C, 0xE8, 0xC1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+ 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
+ 0x54, 0x3F, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
+ },
+ },
};
static const struct hdmiphy_config hdmiphy_5433_configs[] = {
@@ -874,29 +883,37 @@ static const struct drm_connector_funcs hdmi_connector_funcs = {
static int hdmi_get_modes(struct drm_connector *connector)
{
struct hdmi_context *hdata = connector_to_hdmi(connector);
- struct edid *edid;
+ const struct drm_display_info *info = &connector->display_info;
+ const struct drm_edid *drm_edid;
int ret;
if (!hdata->ddc_adpt)
- return -ENODEV;
+ goto no_edid;
- edid = drm_get_edid(connector, hdata->ddc_adpt);
- if (!edid)
- return -ENODEV;
+ drm_edid = drm_edid_read_ddc(connector, hdata->ddc_adpt);
+
+ ret = drm_edid_connector_update(connector, drm_edid);
+ if (ret)
+ return 0;
- hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
+ cec_notifier_set_phys_addr(hdata->notifier, info->source_physical_address);
+
+ if (!drm_edid)
+ goto no_edid;
+
+ hdata->dvi_mode = !info->is_hdmi;
DRM_DEV_DEBUG_KMS(hdata->dev, "%s : width[%d] x height[%d]\n",
(hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
- edid->width_cm, edid->height_cm);
+ info->width_mm / 10, info->height_mm / 10);
- drm_connector_update_edid_property(connector, edid);
- cec_notifier_set_phys_addr_from_edid(hdata->notifier, edid);
+ ret = drm_edid_connector_add_modes(connector);
- ret = drm_add_edid_modes(connector, edid);
-
- kfree(edid);
+ drm_edid_free(drm_edid);
return ret;
+
+no_edid:
+ return drm_add_modes_noedid(connector, 640, 480);
}
static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
@@ -913,15 +930,16 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
return -EINVAL;
}
-static int hdmi_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
+static enum drm_mode_status hdmi_mode_valid(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
{
struct hdmi_context *hdata = connector_to_hdmi(connector);
int ret;
DRM_DEV_DEBUG_KMS(hdata->dev,
"xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
- mode->hdisplay, mode->vdisplay, mode->vrefresh,
+ mode->hdisplay, mode->vdisplay,
+ drm_mode_vrefresh(mode),
(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
false, mode->clock * 1000);
@@ -960,11 +978,8 @@ static int hdmi_create_connector(struct drm_encoder *encoder)
drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
drm_connector_attach_encoder(connector, encoder);
- if (hdata->bridge) {
+ if (hdata->bridge)
ret = drm_bridge_attach(encoder, hdata->bridge, NULL, 0);
- if (ret)
- DRM_DEV_ERROR(hdata->dev, "Failed to attach bridge\n");
- }
cec_fill_conn_info_from_drm(&conn_info, connector);
@@ -1020,7 +1035,7 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
DRM_DEV_DEBUG_KMS(dev->dev,
"Adjusted Mode: [%d]x[%d] [%d]Hz\n",
m->hdisplay, m->vdisplay,
- m->vrefresh);
+ drm_mode_vrefresh(m));
drm_mode_copy(adjusted_mode, m);
break;
@@ -1473,10 +1488,16 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on)
/* Should be called with hdata->mutex mutex held. */
static void hdmiphy_enable(struct hdmi_context *hdata)
{
+ int ret;
+
if (hdata->powered)
return;
- pm_runtime_get_sync(hdata->dev);
+ ret = pm_runtime_resume_and_get(hdata->dev);
+ if (ret < 0) {
+ dev_err(hdata->dev, "failed to enable HDMIPHY device.\n");
+ return;
+ }
if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
DRM_DEV_DEBUG_KMS(hdata->dev,
@@ -1581,12 +1602,12 @@ static int hdmi_audio_hw_params(struct device *dev, void *data,
struct hdmi_context *hdata = dev_get_drvdata(dev);
if (daifmt->fmt != HDMI_I2S || daifmt->bit_clk_inv ||
- daifmt->frame_clk_inv || daifmt->bit_clk_master ||
- daifmt->frame_clk_master) {
+ daifmt->frame_clk_inv || daifmt->bit_clk_provider ||
+ daifmt->frame_clk_provider) {
dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
daifmt->bit_clk_inv, daifmt->frame_clk_inv,
- daifmt->bit_clk_master,
- daifmt->frame_clk_master);
+ daifmt->bit_clk_provider,
+ daifmt->frame_clk_provider);
return -EINVAL;
}
@@ -1604,7 +1625,8 @@ static int hdmi_audio_hw_params(struct device *dev, void *data,
return 0;
}
-static int hdmi_audio_digital_mute(struct device *dev, void *data, bool mute)
+static int hdmi_audio_mute(struct device *dev, void *data,
+ bool mute, int direction)
{
struct hdmi_context *hdata = dev_get_drvdata(dev);
@@ -1626,7 +1648,9 @@ static int hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
struct hdmi_context *hdata = dev_get_drvdata(dev);
struct drm_connector *connector = &hdata->connector;
+ mutex_lock(&connector->eld_mutex);
memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
+ mutex_unlock(&connector->eld_mutex);
return 0;
}
@@ -1634,7 +1658,7 @@ static int hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
static const struct hdmi_codec_ops audio_codec_ops = {
.hw_params = hdmi_audio_hw_params,
.audio_shutdown = hdmi_audio_shutdown,
- .digital_mute = hdmi_audio_digital_mute,
+ .mute_stream = hdmi_audio_mute,
.get_eld = hdmi_audio_get_eld,
};
@@ -1644,6 +1668,7 @@ static int hdmi_register_audio_device(struct hdmi_context *hdata)
.ops = &audio_codec_ops,
.max_i2s_channels = 6,
.i2s = 1,
+ .no_capture_mute = 1,
};
hdata->audio.pdev = platform_device_register_data(
@@ -1794,11 +1819,8 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
hdata->regul_bulk[i].supply = supply[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to get regulators\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get regulators\n");
hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
@@ -1849,6 +1871,8 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
crtc = exynos_drm_crtc_get_by_type(drm_dev, EXYNOS_DISPLAY_TYPE_HDMI);
+ if (IS_ERR(crtc))
+ return PTR_ERR(crtc);
crtc->pipe_clk = &hdata->phy_clk;
ret = hdmi_create_connector(encoder);
@@ -1905,10 +1929,9 @@ static int hdmi_get_ddc_adapter(struct hdmi_context *hdata)
static int hdmi_get_phy_io(struct hdmi_context *hdata)
{
const char *compatible_str = "samsung,exynos4212-hdmiphy";
- struct device_node *np;
- int ret = 0;
+ struct device_node *np __free(device_node) =
+ of_find_compatible_node(NULL, NULL, compatible_str);
- np = of_find_compatible_node(NULL, NULL, compatible_str);
if (!np) {
np = of_parse_phandle(hdata->dev->of_node, "phy", 0);
if (!np) {
@@ -1923,21 +1946,17 @@ static int hdmi_get_phy_io(struct hdmi_context *hdata)
if (!hdata->regs_hdmiphy) {
DRM_DEV_ERROR(hdata->dev,
"failed to ioremap hdmi phy\n");
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
} else {
hdata->hdmiphy_port = of_find_i2c_device_by_node(np);
if (!hdata->hdmiphy_port) {
DRM_INFO("Failed to get hdmi phy i2c client\n");
- ret = -EPROBE_DEFER;
- goto out;
+ return -EPROBE_DEFER;
}
}
-out:
- of_node_put(np);
- return ret;
+ return 0;
}
static int hdmi_probe(struct platform_device *pdev)
@@ -1945,7 +1964,6 @@ static int hdmi_probe(struct platform_device *pdev)
struct hdmi_audio_infoframe *audio_infoframe;
struct device *dev = &pdev->dev;
struct hdmi_context *hdata;
- struct resource *res;
int ret;
hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
@@ -1967,8 +1985,7 @@ static int hdmi_probe(struct platform_device *pdev)
return ret;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdata->regs = devm_ioremap_resource(dev, res);
+ hdata->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hdata->regs)) {
ret = PTR_ERR(hdata->regs);
return ret;
@@ -2057,7 +2074,7 @@ err_ddc:
return ret;
}
-static int hdmi_remove(struct platform_device *pdev)
+static void hdmi_remove(struct platform_device *pdev)
{
struct hdmi_context *hdata = platform_get_drvdata(pdev);
@@ -2080,8 +2097,6 @@ static int hdmi_remove(struct platform_device *pdev)
put_device(&hdata->ddc_adpt->dev);
mutex_destroy(&hdata->mutex);
-
- return 0;
}
static int __maybe_unused exynos_hdmi_suspend(struct device *dev)
@@ -2116,7 +2131,6 @@ struct platform_driver hdmi_driver = {
.remove = hdmi_remove,
.driver = {
.name = "exynos-hdmi",
- .owner = THIS_MODULE,
.pm = &exynos_hdmi_pm_ops,
.of_match_table = hdmi_match_types,
},