aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/dss
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss')
-rw-r--r--drivers/gpu/drm/omapdrm/dss/Makefile2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/base.c55
-rw-r--r--drivers/gpu/drm/omapdrm/dss/display.c9
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dpi.c349
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c4
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss-of.c28
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.c46
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi.h4
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c313
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.c59
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.h4
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c295
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.c48
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.h5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss.h46
-rw-r--r--drivers/gpu/drm/omapdrm/dss/output.c53
-rw-r--r--drivers/gpu/drm/omapdrm/dss/sdi.c178
-rw-r--r--drivers/gpu/drm/omapdrm/dss/venc.c269
19 files changed, 906 insertions, 866 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile
index 5950c3f52c2e..f967e6948f2e 100644
--- a/drivers/gpu/drm/omapdrm/dss/Makefile
+++ b/drivers/gpu/drm/omapdrm/dss/Makefile
@@ -2,7 +2,7 @@
obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
obj-$(CONFIG_OMAP_DSS_BASE) += omapdss-base.o
-omapdss-base-y := base.o display.o dss-of.o output.o
+omapdss-base-y := base.o display.o output.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files
diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c
index a1970b9db6ab..c7650a7c155d 100644
--- a/drivers/gpu/drm/omapdrm/dss/base.c
+++ b/drivers/gpu/drm/omapdrm/dss/base.c
@@ -149,8 +149,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
goto done;
}
- if (dssdev->id &&
- (dssdev->next || dssdev->bridge || dssdev->panel))
+ if (dssdev->id && (dssdev->next || dssdev->bridge))
goto done;
}
@@ -185,11 +184,10 @@ int omapdss_device_connect(struct dss_device *dss,
if (!dst) {
/*
* The destination is NULL when the source is connected to a
- * bridge or panel instead of a DSS device. Stop here, we will
- * attach the bridge or panel later when we will have a DRM
- * encoder.
+ * bridge instead of a DSS device. Stop here, we will attach
+ * the bridge later when we will have a DRM encoder.
*/
- return src && (src->bridge || src->panel) ? 0 : -EINVAL;
+ return src && src->bridge ? 0 : -EINVAL;
}
if (omapdss_device_is_connected(dst))
@@ -197,10 +195,12 @@ int omapdss_device_connect(struct dss_device *dss,
dst->dss = dss;
- ret = dst->ops->connect(src, dst);
- if (ret < 0) {
- dst->dss = NULL;
- return ret;
+ if (dst->ops && dst->ops->connect) {
+ ret = dst->ops->connect(src, dst);
+ if (ret < 0) {
+ dst->dss = NULL;
+ return ret;
+ }
}
return 0;
@@ -217,7 +217,7 @@ void omapdss_device_disconnect(struct omap_dss_device *src,
dst ? dev_name(dst->dev) : "NULL");
if (!dst) {
- WARN_ON(!src->bridge && !src->panel);
+ WARN_ON(!src->bridge);
return;
}
@@ -228,29 +228,18 @@ void omapdss_device_disconnect(struct omap_dss_device *src,
WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
- dst->ops->disconnect(src, dst);
+ if (dst->ops && dst->ops->disconnect)
+ dst->ops->disconnect(src, dst);
dst->dss = NULL;
}
EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
-void omapdss_device_pre_enable(struct omap_dss_device *dssdev)
-{
- if (!dssdev)
- return;
-
- omapdss_device_pre_enable(dssdev->next);
-
- if (dssdev->ops->pre_enable)
- dssdev->ops->pre_enable(dssdev);
-}
-EXPORT_SYMBOL_GPL(omapdss_device_pre_enable);
-
void omapdss_device_enable(struct omap_dss_device *dssdev)
{
if (!dssdev)
return;
- if (dssdev->ops->enable)
+ if (dssdev->ops && dssdev->ops->enable)
dssdev->ops->enable(dssdev);
omapdss_device_enable(dssdev->next);
@@ -266,25 +255,11 @@ void omapdss_device_disable(struct omap_dss_device *dssdev)
omapdss_device_disable(dssdev->next);
- if (dssdev->ops->disable)
+ if (dssdev->ops && dssdev->ops->disable)
dssdev->ops->disable(dssdev);
}
EXPORT_SYMBOL_GPL(omapdss_device_disable);
-void omapdss_device_post_disable(struct omap_dss_device *dssdev)
-{
- if (!dssdev)
- return;
-
- if (dssdev->ops->post_disable)
- dssdev->ops->post_disable(dssdev);
-
- omapdss_device_post_disable(dssdev->next);
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-}
-EXPORT_SYMBOL_GPL(omapdss_device_post_disable);
-
/* -----------------------------------------------------------------------------
* Components Handling
*/
diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c
index 8a3f61f5825f..3b82158b1bfd 100644
--- a/drivers/gpu/drm/omapdrm/dss/display.c
+++ b/drivers/gpu/drm/omapdrm/dss/display.c
@@ -40,15 +40,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL_GPL(omapdss_display_init);
-struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output)
-{
- while (output->next)
- output = output->next;
-
- return omapdss_device_get(output);
-}
-EXPORT_SYMBOL_GPL(omapdss_display_get);
-
int omapdss_display_get_modes(struct drm_connector *connector,
const struct videomode *vm)
{
diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
index 95147437b990..5110acb0c6c1 100644
--- a/drivers/gpu/drm/omapdrm/dss/dpi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -9,20 +9,22 @@
#define DSS_SUBSYS_NAME "DPI"
-#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/export.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
-#include <linux/of.h>
-#include <linux/clk.h>
#include <linux/sys_soc.h>
-#include "omapdss.h"
+#include <drm/drm_bridge.h>
+
#include "dss.h"
+#include "omapdss.h"
struct dpi_data {
struct platform_device *pdev;
@@ -34,19 +36,19 @@ struct dpi_data {
enum dss_clk_source clk_src;
struct dss_pll *pll;
- struct mutex lock;
-
struct dss_lcd_mgr_config mgr_config;
unsigned long pixelclock;
int data_lines;
struct omap_dss_device output;
+ struct drm_bridge bridge;
};
-static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
-{
- return container_of(dssdev, struct dpi_data, output);
-}
+#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
+
+/* -----------------------------------------------------------------------------
+ * Clock Handling and PLL
+ */
static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,
enum omap_channel channel)
@@ -283,9 +285,7 @@ static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,
-static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel,
- unsigned long pck_req, unsigned long *fck, int *lck_div,
- int *pck_div)
+static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)
{
struct dpi_clk_calc_ctx ctx;
int r;
@@ -299,19 +299,15 @@ static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel,
if (r)
return r;
- dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src);
+ dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
+ dpi->clk_src);
dpi->mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
- *lck_div = ctx.dispc_cinfo.lck_div;
- *pck_div = ctx.dispc_cinfo.pck_div;
-
return 0;
}
-static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
- unsigned long *fck, int *lck_div, int *pck_div)
+static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)
{
struct dpi_clk_calc_ctx ctx;
int r;
@@ -327,29 +323,19 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
dpi->mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = ctx.fck;
- *lck_div = ctx.dispc_cinfo.lck_div;
- *pck_div = ctx.dispc_cinfo.pck_div;
-
return 0;
}
static int dpi_set_mode(struct dpi_data *dpi)
{
- int lck_div = 0, pck_div = 0;
- unsigned long fck = 0;
- int r = 0;
+ int r;
if (dpi->pll)
- r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel,
- dpi->pixelclock, &fck, &lck_div, &pck_div);
+ r = dpi_set_pll_clk(dpi, dpi->pixelclock);
else
- r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck,
- &lck_div, &pck_div);
- if (r)
- return r;
+ r = dpi_set_dispc_clk(dpi, dpi->pixelclock);
- return 0;
+ return r;
}
static void dpi_config_lcd_manager(struct dpi_data *dpi)
@@ -366,25 +352,149 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
}
-static void dpi_display_enable(struct omap_dss_device *dssdev)
+static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
+{
+ int lck_div, pck_div;
+ unsigned long fck;
+ struct dpi_clk_calc_ctx ctx;
+
+ if (dpi->pll) {
+ if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
+ return -EINVAL;
+
+ fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
+ } else {
+ if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
+ return -EINVAL;
+
+ fck = ctx.fck;
+ }
+
+ lck_div = ctx.dispc_cinfo.lck_div;
+ pck_div = ctx.dispc_cinfo.pck_div;
+
+ *clock = fck / lck_div / pck_div;
+
+ return 0;
+}
+
+static int dpi_verify_pll(struct dss_pll *pll)
{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
- struct omap_dss_device *out = &dpi->output;
int r;
- mutex_lock(&dpi->lock);
+ /* do initial setup with the PLL to see if it is operational */
+
+ r = dss_pll_enable(pll);
+ if (r)
+ return r;
+
+ dss_pll_disable(pll);
+
+ return 0;
+}
+
+static void dpi_init_pll(struct dpi_data *dpi)
+{
+ struct dss_pll *pll;
+
+ if (dpi->pll)
+ return;
+
+ dpi->clk_src = dpi_get_clk_src(dpi);
+
+ pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);
+ if (!pll)
+ return;
+
+ if (dpi_verify_pll(pll)) {
+ DSSWARN("PLL not operational\n");
+ return;
+ }
+
+ dpi->pll = pll;
+}
+
+/* -----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int dpi_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+ return -EINVAL;
+
+ dpi_init_pll(dpi);
+
+ return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
+ bridge, flags);
+}
+
+static enum drm_mode_status
+dpi_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode)
+{
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+ unsigned long clock = mode->clock * 1000;
+ int ret;
+
+ if (mode->hdisplay % 8 != 0)
+ return MODE_BAD_WIDTH;
+
+ if (mode->clock == 0)
+ return MODE_NOCLOCK;
+
+ ret = dpi_clock_update(dpi, &clock);
+ if (ret < 0)
+ return MODE_CLOCK_RANGE;
+
+ return MODE_OK;
+}
+
+static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+ unsigned long clock = mode->clock * 1000;
+ int ret;
+
+ ret = dpi_clock_update(dpi, &clock);
+ if (ret < 0)
+ return false;
+
+ adjusted_mode->clock = clock / 1000;
+
+ return true;
+}
+
+static void dpi_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
+{
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+
+ dpi->pixelclock = adjusted_mode->clock * 1000;
+}
+
+static void dpi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+ int r;
if (dpi->vdds_dsi_reg) {
r = regulator_enable(dpi->vdds_dsi_reg);
if (r)
- goto err_reg_enable;
+ return;
}
r = dispc_runtime_get(dpi->dss->dispc);
if (r)
goto err_get_dispc;
- r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
+ r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
if (r)
goto err_src_sel;
@@ -406,8 +516,6 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_mgr_enable;
- mutex_unlock(&dpi->lock);
-
return;
err_mgr_enable:
@@ -420,15 +528,11 @@ err_src_sel:
err_get_dispc:
if (dpi->vdds_dsi_reg)
regulator_disable(dpi->vdds_dsi_reg);
-err_reg_enable:
- mutex_unlock(&dpi->lock);
}
-static void dpi_display_disable(struct omap_dss_device *dssdev)
+static void dpi_bridge_disable(struct drm_bridge *bridge)
{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-
- mutex_lock(&dpi->lock);
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
dss_mgr_disable(&dpi->output);
@@ -442,99 +546,34 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
if (dpi->vdds_dsi_reg)
regulator_disable(dpi->vdds_dsi_reg);
-
- mutex_unlock(&dpi->lock);
}
-static void dpi_set_timings(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode)
-{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-
- DSSDBG("dpi_set_timings\n");
-
- mutex_lock(&dpi->lock);
-
- dpi->pixelclock = mode->clock * 1000;
-
- mutex_unlock(&dpi->lock);
-}
+static const struct drm_bridge_funcs dpi_bridge_funcs = {
+ .attach = dpi_bridge_attach,
+ .mode_valid = dpi_bridge_mode_valid,
+ .mode_fixup = dpi_bridge_mode_fixup,
+ .mode_set = dpi_bridge_mode_set,
+ .enable = dpi_bridge_enable,
+ .disable = dpi_bridge_disable,
+};
-static int dpi_check_timings(struct omap_dss_device *dssdev,
- struct drm_display_mode *mode)
+static void dpi_bridge_init(struct dpi_data *dpi)
{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
- int lck_div, pck_div;
- unsigned long fck;
- unsigned long pck;
- struct dpi_clk_calc_ctx ctx;
- bool ok;
+ dpi->bridge.funcs = &dpi_bridge_funcs;
+ dpi->bridge.of_node = dpi->pdev->dev.of_node;
+ dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
- if (mode->hdisplay % 8 != 0)
- return -EINVAL;
-
- if (mode->clock == 0)
- return -EINVAL;
-
- if (dpi->pll) {
- ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
- if (!ok)
- return -EINVAL;
-
- fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
- } else {
- ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
- if (!ok)
- return -EINVAL;
-
- fck = ctx.fck;
- }
-
- lck_div = ctx.dispc_cinfo.lck_div;
- pck_div = ctx.dispc_cinfo.pck_div;
-
- pck = fck / lck_div / pck_div;
-
- mode->clock = pck / 1000;
-
- return 0;
+ drm_bridge_add(&dpi->bridge);
}
-static int dpi_verify_pll(struct dss_pll *pll)
+static void dpi_bridge_cleanup(struct dpi_data *dpi)
{
- int r;
-
- /* do initial setup with the PLL to see if it is operational */
-
- r = dss_pll_enable(pll);
- if (r)
- return r;
-
- dss_pll_disable(pll);
-
- return 0;
+ drm_bridge_remove(&dpi->bridge);
}
-static void dpi_init_pll(struct dpi_data *dpi)
-{
- struct dss_pll *pll;
-
- if (dpi->pll)
- return;
-
- dpi->clk_src = dpi_get_clk_src(dpi);
-
- pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);
- if (!pll)
- return;
-
- if (dpi_verify_pll(pll)) {
- DSSWARN("PLL not operational\n");
- return;
- }
-
- dpi->pll = pll;
-}
+/* -----------------------------------------------------------------------------
+ * Initialisation and Cleanup
+ */
/*
* Return a hardcoded channel for the DPI output. This should work for
@@ -572,39 +611,14 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
}
}
-static int dpi_connect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
-
- dpi_init_pll(dpi);
-
- return omapdss_device_connect(dst->dss, dst, dst->next);
-}
-
-static void dpi_disconnect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- omapdss_device_disconnect(dst, dst->next);
-}
-
-static const struct omap_dss_device_ops dpi_ops = {
- .connect = dpi_connect,
- .disconnect = dpi_disconnect,
-
- .enable = dpi_display_enable,
- .disable = dpi_display_disable,
-
- .check_timings = dpi_check_timings,
- .set_timings = dpi_set_timings,
-};
-
static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
{
struct omap_dss_device *out = &dpi->output;
u32 port_num = 0;
int r;
+ dpi_bridge_init(dpi);
+
of_property_read_u32(port, "reg", &port_num);
dpi->id = port_num <= 2 ? port_num : 0;
@@ -625,13 +639,14 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
out->id = OMAP_DSS_OUTPUT_DPI;
out->type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(dpi);
- out->of_ports = BIT(port_num);
- out->ops = &dpi_ops;
+ out->of_port = port_num;
out->owner = THIS_MODULE;
- r = omapdss_device_init_output(out);
- if (r < 0)
+ r = omapdss_device_init_output(out, &dpi->bridge);
+ if (r < 0) {
+ dpi_bridge_cleanup(dpi);
return r;
+ }
omapdss_device_register(out);
@@ -645,8 +660,14 @@ static void dpi_uninit_output_port(struct device_node *port)
omapdss_device_unregister(out);
omapdss_device_cleanup_output(out);
+
+ dpi_bridge_cleanup(dpi);
}
+/* -----------------------------------------------------------------------------
+ * Initialisation and Cleanup
+ */
+
static const struct soc_device_attribute dpi_soc_devices[] = {
{ .machine = "OMAP3[456]*" },
{ .machine = "[AD]M37*" },
@@ -706,8 +727,6 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
dpi->dss = dss;
port->data = dpi;
- mutex_init(&dpi->lock);
-
r = dpi_init_regulator(dpi);
if (r)
return r;
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index da16ea095f13..79ddfbfd1b58 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -5116,12 +5116,12 @@ static int dsi_init_output(struct dsi_data *dsi)
out->dispc_channel = dsi_get_channel(dsi);
out->ops = &dsi_ops;
out->owner = THIS_MODULE;
- out->of_ports = BIT(0);
+ out->of_port = 0;
out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE
| DRM_BUS_FLAG_DE_HIGH
| DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
- r = omapdss_device_init_output(out);
+ r = omapdss_device_init_output(out, NULL);
if (r < 0)
return r;
diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c
deleted file mode 100644
index b7981f3b80ad..000000000000
--- a/drivers/gpu/drm/omapdrm/dss/dss-of.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- */
-
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
-
-#include "omapdss.h"
-
-struct omap_dss_device *
-omapdss_of_find_connected_device(struct device_node *node, unsigned int port)
-{
- struct device_node *remote_node;
- struct omap_dss_device *dssdev;
-
- remote_node = of_graph_get_remote_node(node, port, 0);
- if (!remote_node)
- return NULL;
-
- dssdev = omapdss_find_device_by_node(remote_node);
- of_node_put(remote_node);
-
- return dssdev ? dssdev : ERR_PTR(-EPROBE_DEFER);
-}
-EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device);
diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c
index 225ec808b01a..b76fc2b56227 100644
--- a/drivers/gpu/drm/omapdrm/dss/dss.c
+++ b/drivers/gpu/drm/omapdrm/dss/dss.c
@@ -1151,46 +1151,38 @@ static const struct dss_features dra7xx_dss_feats = {
.has_lcd_clk_src = true,
};
-static int dss_init_ports(struct dss_device *dss)
+static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports)
{
struct platform_device *pdev = dss->pdev;
struct device_node *parent = pdev->dev.of_node;
struct device_node *port;
unsigned int i;
- int r;
- for (i = 0; i < dss->feat->num_ports; i++) {
+ for (i = 0; i < num_ports; i++) {
port = of_graph_get_port_by_id(parent, i);
if (!port)
continue;
switch (dss->feat->ports[i]) {
case OMAP_DISPLAY_TYPE_DPI:
- r = dpi_init_port(dss, pdev, port, dss->feat->model);
- if (r)
- return r;
+ dpi_uninit_port(port);
break;
-
case OMAP_DISPLAY_TYPE_SDI:
- r = sdi_init_port(dss, pdev, port);
- if (r)
- return r;
+ sdi_uninit_port(port);
break;
-
default:
break;
}
}
-
- return 0;
}
-static void dss_uninit_ports(struct dss_device *dss)
+static int dss_init_ports(struct dss_device *dss)
{
struct platform_device *pdev = dss->pdev;
struct device_node *parent = pdev->dev.of_node;
struct device_node *port;
- int i;
+ unsigned int i;
+ int r;
for (i = 0; i < dss->feat->num_ports; i++) {
port = of_graph_get_port_by_id(parent, i);
@@ -1199,15 +1191,32 @@ static void dss_uninit_ports(struct dss_device *dss)
switch (dss->feat->ports[i]) {
case OMAP_DISPLAY_TYPE_DPI:
- dpi_uninit_port(port);
+ r = dpi_init_port(dss, pdev, port, dss->feat->model);
+ if (r)
+ goto error;
break;
+
case OMAP_DISPLAY_TYPE_SDI:
- sdi_uninit_port(port);
+ r = sdi_init_port(dss, pdev, port);
+ if (r)
+ goto error;
break;
+
default:
break;
}
}
+
+ return 0;
+
+error:
+ __dss_uninit_ports(dss, i);
+ return r;
+}
+
+static void dss_uninit_ports(struct dss_device *dss)
+{
+ __dss_uninit_ports(dss, dss->feat->num_ports);
}
static int dss_video_pll_probe(struct dss_device *dss)
@@ -1543,7 +1552,8 @@ static void dss_shutdown(struct platform_device *pdev)
DSSDBG("shutdown\n");
for_each_dss_output(dssdev) {
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
+ dssdev->ops && dssdev->ops->disable)
dssdev->ops->disable(dssdev);
}
}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h
index c867552c925c..3a40833d3368 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h
@@ -14,6 +14,7 @@
#include <linux/hdmi.h>
#include <sound/omap-hdmi-audio.h>
#include <media/cec.h>
+#include <drm/drm_bridge.h>
#include "omapdss.h"
#include "dss.h"
@@ -364,6 +365,7 @@ struct omap_hdmi {
bool core_enabled;
struct omap_dss_device output;
+ struct drm_bridge bridge;
struct platform_device *audio_pdev;
void (*audio_abort_cb)(struct device *dev);
@@ -378,6 +380,6 @@ struct omap_hdmi {
bool display_enabled;
};
-#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output)
+#define drm_bridge_to_hdmi(b) container_of(b, struct omap_hdmi, bridge)
#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 0f557fad4513..2578c95570f6 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -28,6 +28,9 @@
#include <sound/omap-hdmi-audio.h>
#include <media/cec.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+
#include "omapdss.h"
#include "hdmi4_core.h"
#include "hdmi4_cec.h"
@@ -237,20 +240,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
hdmi_power_off_core(hdmi);
}
-static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode)
-{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
- mutex_lock(&hdmi->lock);
-
- drm_display_mode_to_videomode(mode, &hdmi->cfg.vm);
-
- dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000);
-
- mutex_unlock(&hdmi->lock);
-}
-
static int hdmi_dump_regs(struct seq_file *s, void *p)
{
struct omap_hdmi *hdmi = s->private;
@@ -272,57 +261,139 @@ static int hdmi_dump_regs(struct seq_file *s, void *p)
return 0;
}
-static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
+static void hdmi_start_audio_stream(struct omap_hdmi *hd)
{
- int r;
+ hdmi_wp_audio_enable(&hd->wp, true);
+ hdmi4_audio_start(&hd->core, &hd->wp);
+}
- mutex_lock(&hdmi->lock);
+static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
+{
+ hdmi4_audio_stop(&hd->core, &hd->wp);
+ hdmi_wp_audio_enable(&hd->wp, false);
+}
- r = hdmi_runtime_get(hdmi);
- BUG_ON(r);
+int hdmi4_core_enable(struct hdmi_core_data *core)
+{
+ struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
+ int r = 0;
- r = hdmi4_read_edid(&hdmi->core, buf, len);
+ DSSDBG("ENTER omapdss_hdmi4_core_enable\n");
+
+ mutex_lock(&hdmi->lock);
+
+ r = hdmi_power_on_core(hdmi);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
- hdmi_runtime_put(hdmi);
mutex_unlock(&hdmi->lock);
+ return 0;
+err0:
+ mutex_unlock(&hdmi->lock);
return r;
}
-static void hdmi_start_audio_stream(struct omap_hdmi *hd)
+void hdmi4_core_disable(struct hdmi_core_data *core)
{
- hdmi_wp_audio_enable(&hd->wp, true);
- hdmi4_audio_start(&hd->core, &hd->wp);
+ struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
+
+ DSSDBG("Enter omapdss_hdmi4_core_disable\n");
+
+ mutex_lock(&hdmi->lock);
+
+ hdmi_power_off_core(hdmi);
+
+ mutex_unlock(&hdmi->lock);
}
-static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
+/* -----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int hdmi4_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
{
- hdmi4_audio_stop(&hd->core, &hd->wp);
- hdmi_wp_audio_enable(&hd->wp, false);
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+ return -EINVAL;
+
+ return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
+ bridge, flags);
}
-static void hdmi_display_enable(struct omap_dss_device *dssdev)
+static void hdmi4_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ mutex_lock(&hdmi->lock);
+
+ drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm);
+
+ dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000);
+
+ mutex_unlock(&hdmi->lock);
+}
+
+static void hdmi4_bridge_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+ struct drm_atomic_state *state = bridge_state->base.state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *connector;
+ struct drm_crtc_state *crtc_state;
unsigned long flags;
- int r;
+ int ret;
+
+ /*
+ * None of these should fail, as the bridge can't be enabled without a
+ * valid CRTC to connector path with fully populated new states.
+ */
+ connector = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ if (WARN_ON(!connector))
+ return;
+ 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;
+
+ hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi
+ ? HDMI_HDMI : HDMI_DVI;
- DSSDBG("ENTER hdmi_display_enable\n");
+ if (connector->display_info.is_hdmi) {
+ const struct drm_display_mode *mode;
+ struct hdmi_avi_infoframe avi;
+
+ mode = &crtc_state->adjusted_mode;
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
+ mode);
+ if (ret == 0)
+ hdmi->cfg.infoframe = avi;
+ }
mutex_lock(&hdmi->lock);
- r = hdmi_power_on_full(hdmi);
- if (r) {
+ ret = hdmi_power_on_full(hdmi);
+ if (ret) {
DSSERR("failed to power on device\n");
goto done;
}
if (hdmi->audio_configured) {
- r = hdmi4_audio_config(&hdmi->core, &hdmi->wp,
- &hdmi->audio_config,
- hdmi->cfg.vm.pixelclock);
- if (r) {
- DSSERR("Error restoring audio configuration: %d", r);
+ ret = hdmi4_audio_config(&hdmi->core, &hdmi->wp,
+ &hdmi->audio_config,
+ hdmi->cfg.vm.pixelclock);
+ if (ret) {
+ DSSERR("Error restoring audio configuration: %d", ret);
hdmi->audio_abort_cb(&hdmi->pdev->dev);
hdmi->audio_configured = false;
}
@@ -338,13 +409,12 @@ done:
mutex_unlock(&hdmi->lock);
}
-static void hdmi_display_disable(struct omap_dss_device *dssdev)
+static void hdmi4_bridge_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
unsigned long flags;
- DSSDBG("Enter hdmi_display_disable\n");
-
mutex_lock(&hdmi->lock);
spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
@@ -357,58 +427,21 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi->lock);
}
-int hdmi4_core_enable(struct hdmi_core_data *core)
+static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge,
+ enum drm_connector_status status)
{
- struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
- int r = 0;
-
- DSSDBG("ENTER omapdss_hdmi4_core_enable\n");
-
- mutex_lock(&hdmi->lock);
-
- r = hdmi_power_on_core(hdmi);
- if (r) {
- DSSERR("failed to power on device\n");
- goto err0;
- }
-
- mutex_unlock(&hdmi->lock);
- return 0;
-
-err0:
- mutex_unlock(&hdmi->lock);
- return r;
-}
-
-void hdmi4_core_disable(struct hdmi_core_data *core)
-{
- struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
-
- DSSDBG("Enter omapdss_hdmi4_core_disable\n");
-
- mutex_lock(&hdmi->lock);
-
- hdmi_power_off_core(hdmi);
-
- mutex_unlock(&hdmi->lock);
-}
-
-static int hdmi_connect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- return omapdss_device_connect(dst->dss, dst, dst->next);
-}
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
-static void hdmi_disconnect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- omapdss_device_disconnect(dst, dst->next);
+ if (status == connector_status_disconnected)
+ hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
}
-static int hdmi_read_edid(struct omap_dss_device *dssdev,
- u8 *edid, int len)
+static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+ struct edid *edid = NULL;
+ unsigned int cec_addr;
bool need_enable;
int r;
@@ -417,63 +450,65 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
if (need_enable) {
r = hdmi4_core_enable(&hdmi->core);
if (r)
- return r;
+ return NULL;
}
- r = read_edid(hdmi, edid, len);
- if (r >= 256)
- hdmi4_cec_set_phys_addr(&hdmi->core,
- cec_get_edid_phys_addr(edid, r, NULL));
- else
- hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
- if (need_enable)
- hdmi4_core_disable(&hdmi->core);
+ mutex_lock(&hdmi->lock);
+ r = hdmi_runtime_get(hdmi);
+ BUG_ON(r);
- return r;
-}
+ r = hdmi4_core_ddc_init(&hdmi->core);
+ if (r)
+ goto done;
-static void hdmi_lost_hotplug(struct omap_dss_device *dssdev)
-{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core);
- hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
-}
+done:
+ hdmi_runtime_put(hdmi);
+ mutex_unlock(&hdmi->lock);
-static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
- const struct hdmi_avi_infoframe *avi)
-{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ if (edid && edid->extensions) {
+ unsigned int len = (edid->extensions + 1) * EDID_LENGTH;
- hdmi->cfg.infoframe = *avi;
- return 0;
-}
+ cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL);
+ } else {
+ cec_addr = CEC_PHYS_ADDR_INVALID;
+ }
-static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
- bool hdmi_mode)
-{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
- hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
- return 0;
-}
+ if (need_enable)
+ hdmi4_core_disable(&hdmi->core);
-static const struct omap_dss_device_ops hdmi_ops = {
- .connect = hdmi_connect,
- .disconnect = hdmi_disconnect,
+ return edid;
+}
- .enable = hdmi_display_enable,
- .disable = hdmi_display_disable,
+static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
+ .attach = hdmi4_bridge_attach,
+ .mode_set = hdmi4_bridge_mode_set,
+ .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,
+ .atomic_enable = hdmi4_bridge_enable,
+ .atomic_disable = hdmi4_bridge_disable,
+ .hpd_notify = hdmi4_bridge_hpd_notify,
+ .get_edid = hdmi4_bridge_get_edid,
+};
- .set_timings = hdmi_display_set_timings,
+static void hdmi4_bridge_init(struct omap_hdmi *hdmi)
+{
+ hdmi->bridge.funcs = &hdmi4_bridge_funcs;
+ hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
+ hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
+ hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
- .read_edid = hdmi_read_edid,
+ drm_bridge_add(&hdmi->bridge);
+}
- .hdmi = {
- .lost_hotplug = hdmi_lost_hotplug,
- .set_infoframe = hdmi_set_infoframe,
- .set_hdmi_mode = hdmi_set_hdmi_mode,
- },
-};
+static void hdmi4_bridge_cleanup(struct omap_hdmi *hdmi)
+{
+ drm_bridge_remove(&hdmi->bridge);
+}
/* -----------------------------------------------------------------------------
* Audio Callbacks
@@ -666,19 +701,21 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)
struct omap_dss_device *out = &hdmi->output;
int r;
+ hdmi4_bridge_init(hdmi);
+
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
- out->ops = &hdmi_ops;
out->owner = THIS_MODULE;
- out->of_ports = BIT(0);
- out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
+ out->of_port = 0;
- r = omapdss_device_init_output(out);
- if (r < 0)
+ r = omapdss_device_init_output(out, &hdmi->bridge);
+ if (r < 0) {
+ hdmi4_bridge_cleanup(hdmi);
return r;
+ }
omapdss_device_register(out);
@@ -691,6 +728,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
omapdss_device_unregister(out);
omapdss_device_cleanup_output(out);
+
+ hdmi4_bridge_cleanup(hdmi);
}
static int hdmi4_probe_of(struct omap_hdmi *hdmi)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
index ea5d5c228534..751985a2679a 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
@@ -32,7 +32,7 @@ static inline void __iomem *hdmi_av_base(struct hdmi_core_data *core)
return core->base + HDMI_CORE_AV;
}
-static int hdmi_core_ddc_init(struct hdmi_core_data *core)
+int hdmi4_core_ddc_init(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
@@ -74,13 +74,11 @@ static int hdmi_core_ddc_init(struct hdmi_core_data *core)
return 0;
}
-static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
- u8 *pedid, int ext)
+int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len)
{
+ struct hdmi_core_data *core = data;
void __iomem *base = core->base;
u32 i;
- char checksum;
- u32 offset = 0;
/* HDMI_CORE_DDC_STATUS_IN_PROG */
if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
@@ -89,24 +87,21 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
return -ETIMEDOUT;
}
- if (ext % 2 != 0)
- offset = 0x80;
-
/* Load Segment Address Register */
- REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, block / 2, 7, 0);
/* Load Slave Address Register */
REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
/* Load Offset Address Register */
- REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, block % 2 ? 0x80 : 0, 7, 0);
/* Load Byte Count */
- REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, len, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
/* Set DDC_CMD */
- if (ext)
+ if (block)
REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);
else
REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0);
@@ -122,7 +117,7 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
return -EIO;
}
- for (i = 0; i < 0x80; ++i) {
+ for (i = 0; i < len; ++i) {
int t;
/* IN_PROG */
@@ -141,48 +136,12 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
udelay(1);
}
- pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
- }
-
- checksum = 0;
- for (i = 0; i < 0x80; ++i)
- checksum += pedid[i];
-
- if (checksum != 0) {
- DSSERR("E-EDID checksum failed!!\n");
- return -EIO;
+ buf[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
}
return 0;
}
-int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
-{
- int r, l;
-
- if (len < 128)
- return -EINVAL;
-
- r = hdmi_core_ddc_init(core);
- if (r)
- return r;
-
- r = hdmi_core_ddc_edid(core, edid, 0);
- if (r)
- return r;
-
- l = 128;
-
- if (len >= 128 * 2 && edid[0x7e] > 0) {
- r = hdmi_core_ddc_edid(core, edid + 0x80, 1);
- if (r)
- return r;
- l += 128;
- }
-
- return l;
-}
-
static void hdmi_core_init(struct hdmi_core_video_config *video_cfg)
{
DSSDBG("Enter hdmi_core_init\n");
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
index 11c4b7ba1eee..dc64ae2aa300 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
@@ -249,7 +249,9 @@ struct hdmi_core_packet_enable_repeat {
u32 generic_pkt_repeat;
};
-int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
+int hdmi4_core_ddc_init(struct hdmi_core_data *core);
+int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len);
+
void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct hdmi_config *cfg);
void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index d9463b332554..4d4c1fabd0a1 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -31,6 +31,9 @@
#include <linux/of_graph.h>
#include <sound/omap-hdmi-audio.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+
#include "omapdss.h"
#include "hdmi5_core.h"
#include "dss.h"
@@ -236,20 +239,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
hdmi_power_off_core(hdmi);
}
-static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode)
-{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
- mutex_lock(&hdmi->lock);
-
- drm_display_mode_to_videomode(mode, &hdmi->cfg.vm);
-
- dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000);
-
- mutex_unlock(&hdmi->lock);
-}
-
static int hdmi_dump_regs(struct seq_file *s, void *p)
{
struct omap_hdmi *hdmi = s->private;
@@ -271,66 +260,138 @@ static int hdmi_dump_regs(struct seq_file *s, void *p)
return 0;
}
-static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
+static void hdmi_start_audio_stream(struct omap_hdmi *hd)
{
- int r;
- int idlemode;
+ REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+ hdmi_wp_audio_enable(&hd->wp, true);
+ hdmi_wp_audio_core_req_enable(&hd->wp, true);
+}
- mutex_lock(&hdmi->lock);
+static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
+{
+ hdmi_wp_audio_core_req_enable(&hd->wp, false);
+ hdmi_wp_audio_enable(&hd->wp, false);
+ REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
+}
- r = hdmi_runtime_get(hdmi);
- BUG_ON(r);
+static int hdmi_core_enable(struct omap_hdmi *hdmi)
+{
+ int r = 0;
- idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
- /* No-idle mode */
- REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+ DSSDBG("ENTER omapdss_hdmi_core_enable\n");
- r = hdmi5_read_edid(&hdmi->core, buf, len);
+ mutex_lock(&hdmi->lock);
- REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
+ r = hdmi_power_on_core(hdmi);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
- hdmi_runtime_put(hdmi);
mutex_unlock(&hdmi->lock);
+ return 0;
+err0:
+ mutex_unlock(&hdmi->lock);
return r;
}
-static void hdmi_start_audio_stream(struct omap_hdmi *hd)
+static void hdmi_core_disable(struct omap_hdmi *hdmi)
{
- REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
- hdmi_wp_audio_enable(&hd->wp, true);
- hdmi_wp_audio_core_req_enable(&hd->wp, true);
+ DSSDBG("Enter omapdss_hdmi_core_disable\n");
+
+ mutex_lock(&hdmi->lock);
+
+ hdmi_power_off_core(hdmi);
+
+ mutex_unlock(&hdmi->lock);
}
-static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
+/* -----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int hdmi5_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
{
- hdmi_wp_audio_core_req_enable(&hd->wp, false);
- hdmi_wp_audio_enable(&hd->wp, false);
- REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+ return -EINVAL;
+
+ return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
+ bridge, flags);
}
-static void hdmi_display_enable(struct omap_dss_device *dssdev)
+static void hdmi5_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
- unsigned long flags;
- int r;
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ mutex_lock(&hdmi->lock);
- DSSDBG("ENTER hdmi_display_enable\n");
+ drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm);
+
+ dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000);
+
+ mutex_unlock(&hdmi->lock);
+}
+
+static void hdmi5_bridge_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+ struct drm_atomic_state *state = bridge_state->base.state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *connector;
+ struct drm_crtc_state *crtc_state;
+ unsigned long flags;
+ int ret;
+
+ /*
+ * None of these should fail, as the bridge can't be enabled without a
+ * valid CRTC to connector path with fully populated new states.
+ */
+ connector = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ if (WARN_ON(!connector))
+ return;
+ 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;
+
+ hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi
+ ? HDMI_HDMI : HDMI_DVI;
+
+ if (connector->display_info.is_hdmi) {
+ const struct drm_display_mode *mode;
+ struct hdmi_avi_infoframe avi;
+
+ mode = &crtc_state->adjusted_mode;
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
+ mode);
+ if (ret == 0)
+ hdmi->cfg.infoframe = avi;
+ }
mutex_lock(&hdmi->lock);
- r = hdmi_power_on_full(hdmi);
- if (r) {
+ ret = hdmi_power_on_full(hdmi);
+ if (ret) {
DSSERR("failed to power on device\n");
goto done;
}
if (hdmi->audio_configured) {
- r = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
- &hdmi->audio_config,
- hdmi->cfg.vm.pixelclock);
- if (r) {
- DSSERR("Error restoring audio configuration: %d", r);
+ ret = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
+ &hdmi->audio_config,
+ hdmi->cfg.vm.pixelclock);
+ if (ret) {
+ DSSERR("Error restoring audio configuration: %d", ret);
hdmi->audio_abort_cb(&hdmi->pdev->dev);
hdmi->audio_configured = false;
}
@@ -346,13 +407,12 @@ done:
mutex_unlock(&hdmi->lock);
}
-static void hdmi_display_disable(struct omap_dss_device *dssdev)
+static void hdmi5_bridge_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
unsigned long flags;
- DSSDBG("Enter hdmi_display_disable\n");
-
mutex_lock(&hdmi->lock);
spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
@@ -365,109 +425,74 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi->lock);
}
-static int hdmi_core_enable(struct omap_hdmi *hdmi)
+static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
{
- int r = 0;
-
- DSSDBG("ENTER omapdss_hdmi_core_enable\n");
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+ struct edid *edid;
+ bool need_enable;
+ int idlemode;
+ int r;
- mutex_lock(&hdmi->lock);
+ need_enable = hdmi->core_enabled == false;
- r = hdmi_power_on_core(hdmi);
- if (r) {
- DSSERR("failed to power on device\n");
- goto err0;
+ if (need_enable) {
+ r = hdmi_core_enable(hdmi);
+ if (r)
+ return NULL;
}
- mutex_unlock(&hdmi->lock);
- return 0;
-
-err0:
- mutex_unlock(&hdmi->lock);
- return r;
-}
-
-static void hdmi_core_disable(struct omap_hdmi *hdmi)
-{
- DSSDBG("Enter omapdss_hdmi_core_disable\n");
-
mutex_lock(&hdmi->lock);
+ r = hdmi_runtime_get(hdmi);
+ BUG_ON(r);
- hdmi_power_off_core(hdmi);
-
- mutex_unlock(&hdmi->lock);
-}
-
-static int hdmi_connect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- return omapdss_device_connect(dst->dss, dst, dst->next);
-}
+ idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2);
+ /* No-idle mode */
+ REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
-static void hdmi_disconnect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- omapdss_device_disconnect(dst, dst->next);
-}
+ hdmi5_core_ddc_init(&hdmi->core);
-static int hdmi_read_edid(struct omap_dss_device *dssdev,
- u8 *edid, int len)
-{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
- bool need_enable;
- int r;
+ edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, &hdmi->core);
- need_enable = hdmi->core_enabled == false;
+ hdmi5_core_ddc_uninit(&hdmi->core);
- if (need_enable) {
- r = hdmi_core_enable(hdmi);
- if (r)
- return r;
- }
+ REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
- r = read_edid(hdmi, edid, len);
+ hdmi_runtime_put(hdmi);
+ mutex_unlock(&hdmi->lock);
if (need_enable)
hdmi_core_disable(hdmi);
- return r;
+ return (struct edid *)edid;
}
-static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
- const struct hdmi_avi_infoframe *avi)
+static const struct drm_bridge_funcs hdmi5_bridge_funcs = {
+ .attach = hdmi5_bridge_attach,
+ .mode_set = hdmi5_bridge_mode_set,
+ .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,
+ .atomic_enable = hdmi5_bridge_enable,
+ .atomic_disable = hdmi5_bridge_disable,
+ .get_edid = hdmi5_bridge_get_edid,
+};
+
+static void hdmi5_bridge_init(struct omap_hdmi *hdmi)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ hdmi->bridge.funcs = &hdmi5_bridge_funcs;
+ hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
+ hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
+ hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
- hdmi->cfg.infoframe = *avi;
- return 0;
+ drm_bridge_add(&hdmi->bridge);
}
-static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
- bool hdmi_mode)
+static void hdmi5_bridge_cleanup(struct omap_hdmi *hdmi)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
-
- hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
- return 0;
+ drm_bridge_remove(&hdmi->bridge);
}
-static const struct omap_dss_device_ops hdmi_ops = {
- .connect = hdmi_connect,
- .disconnect = hdmi_disconnect,
-
- .enable = hdmi_display_enable,
- .disable = hdmi_display_disable,
-
- .set_timings = hdmi_display_set_timings,
-
- .read_edid = hdmi_read_edid,
-
- .hdmi = {
- .set_infoframe = hdmi_set_infoframe,
- .set_hdmi_mode = hdmi_set_hdmi_mode,
- },
-};
-
/* -----------------------------------------------------------------------------
* Audio Callbacks
*/
@@ -650,19 +675,21 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi)
struct omap_dss_device *out = &hdmi->output;
int r;
+ hdmi5_bridge_init(hdmi);
+
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
- out->ops = &hdmi_ops;
out->owner = THIS_MODULE;
- out->of_ports = BIT(0);
- out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
+ out->of_port = 0;
- r = omapdss_device_init_output(out);
- if (r < 0)
+ r = omapdss_device_init_output(out, &hdmi->bridge);
+ if (r < 0) {
+ hdmi5_bridge_cleanup(hdmi);
return r;
+ }
omapdss_device_register(out);
@@ -675,6 +702,8 @@ static void hdmi5_uninit_output(struct omap_hdmi *hdmi)
omapdss_device_unregister(out);
omapdss_device_cleanup_output(out);
+
+ hdmi5_bridge_cleanup(hdmi);
}
static int hdmi5_probe_of(struct omap_hdmi *hdmi)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
index ff4d35c8771f..7dd587035160 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
@@ -23,7 +23,7 @@
#include "hdmi5_core.h"
-static void hdmi_core_ddc_init(struct hdmi_core_data *core)
+void hdmi5_core_ddc_init(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
const unsigned long long iclk = 266000000; /* DSS L3 ICLK */
@@ -102,7 +102,7 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core)
REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2);
}
-static void hdmi_core_ddc_uninit(struct hdmi_core_data *core)
+void hdmi5_core_ddc_uninit(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
@@ -112,14 +112,14 @@ static void hdmi_core_ddc_uninit(struct hdmi_core_data *core)
REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
}
-static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)
+int hdmi5_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len)
{
+ struct hdmi_core_data *core = data;
void __iomem *base = core->base;
u8 cur_addr;
- char checksum = 0;
const int retries = 1000;
- u8 seg_ptr = ext / 2;
- u8 edidbase = ((ext % 2) * 0x80);
+ u8 seg_ptr = block / 2;
+ u8 edidbase = ((block % 2) * EDID_LENGTH);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0);
@@ -127,7 +127,7 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)
* TODO: We use polling here, although we probably should use proper
* interrupts.
*/
- for (cur_addr = 0; cur_addr < 128; ++cur_addr) {
+ for (cur_addr = 0; cur_addr < len; ++cur_addr) {
int i;
/* clear ERROR and DONE */
@@ -164,45 +164,13 @@ static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)
return -EIO;
}
- pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0);
- checksum += pedid[cur_addr];
+ buf[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0);
}
return 0;
}
-int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
-{
- int r, n, i;
- int max_ext_blocks = (len / 128) - 1;
-
- if (len < 128)
- return -EINVAL;
-
- hdmi_core_ddc_init(core);
-
- r = hdmi_core_ddc_edid(core, edid, 0);
- if (r)
- goto out;
-
- n = edid[0x7e];
-
- if (n > max_ext_blocks)
- n = max_ext_blocks;
-
- for (i = 1; i <= n; i++) {
- r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i);
- if (r)
- goto out;
- }
-
-out:
- hdmi_core_ddc_uninit(core);
-
- return r ? r : len;
-}
-
void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)
{
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
index f10b8a283011..65eadefdb3f9 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
@@ -281,7 +281,10 @@ struct csc_table {
u16 c1, c2, c3, c4;
};
-int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
+void hdmi5_core_ddc_init(struct hdmi_core_data *core);
+int hdmi5_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len);
+void hdmi5_core_ddc_uninit(struct hdmi_core_data *core);
+
void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s);
int hdmi5_core_handle_irqs(struct hdmi_core_data *core);
void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
index ce67891eedd4..00372f4ce711 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -174,12 +174,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
};
static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = {
- { .compatible = "composite-video-connector" },
- { .compatible = "hdmi-connector" },
{ .compatible = "panel-dsi-cm" },
- { .compatible = "svideo-connector" },
- { .compatible = "ti,opa362" },
- { .compatible = "ti,tpd12s015" },
{},
};
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 79f6b195c7cf..ab19d4af8de7 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -285,13 +285,6 @@ struct omap_dss_writeback_info {
u8 pre_mult_alpha;
};
-struct omapdss_hdmi_ops {
- void (*lost_hotplug)(struct omap_dss_device *dssdev);
- int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
- int (*set_infoframe)(struct omap_dss_device *dssdev,
- const struct hdmi_avi_infoframe *avi);
-};
-
struct omapdss_dsi_ops {
void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes,
bool enter_ulps);
@@ -349,46 +342,23 @@ struct omap_dss_device_ops {
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
- void (*pre_enable)(struct omap_dss_device *dssdev);
void (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
- void (*post_disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct drm_display_mode *mode);
- void (*set_timings)(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode);
-
- bool (*detect)(struct omap_dss_device *dssdev);
-
- void (*register_hpd_cb)(struct omap_dss_device *dssdev,
- void (*cb)(void *cb_data,
- enum drm_connector_status status),
- void *cb_data);
- void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
-
- int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
int (*get_modes)(struct omap_dss_device *dssdev,
struct drm_connector *connector);
- union {
- const struct omapdss_hdmi_ops hdmi;
- const struct omapdss_dsi_ops dsi;
- };
+ const struct omapdss_dsi_ops dsi;
};
/**
* enum omap_dss_device_ops_flag - Indicates which device ops are supported
- * @OMAP_DSS_DEVICE_OP_DETECT: The device supports output connection detection
- * @OMAP_DSS_DEVICE_OP_HPD: The device supports all hot-plug-related operations
- * @OMAP_DSS_DEVICE_OP_EDID: The device supports reading EDID
* @OMAP_DSS_DEVICE_OP_MODES: The device supports reading modes
*/
enum omap_dss_device_ops_flag {
- OMAP_DSS_DEVICE_OP_DETECT = BIT(0),
- OMAP_DSS_DEVICE_OP_HPD = BIT(1),
- OMAP_DSS_DEVICE_OP_EDID = BIT(2),
OMAP_DSS_DEVICE_OP_MODES = BIT(3),
};
@@ -400,6 +370,7 @@ struct omap_dss_device {
struct dss_device *dss;
struct omap_dss_device *next;
struct drm_bridge *bridge;
+ struct drm_bridge *next_bridge;
struct drm_panel *panel;
struct list_head list;
@@ -436,8 +407,8 @@ struct omap_dss_device {
/* output instance */
enum omap_dss_output_id id;
- /* bitmask of port numbers in DT */
- unsigned int of_ports;
+ /* port number in DT */
+ unsigned int of_port;
};
struct omap_dss_driver {
@@ -461,7 +432,6 @@ static inline bool omapdss_is_initialized(void)
}
void omapdss_display_init(struct omap_dss_device *dssdev);
-struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);
int omapdss_display_get_modes(struct drm_connector *connector,
const struct videomode *vm);
@@ -475,10 +445,8 @@ int omapdss_device_connect(struct dss_device *dss,
struct omap_dss_device *dst);
void omapdss_device_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst);
-void omapdss_device_pre_enable(struct omap_dss_device *dssdev);
void omapdss_device_enable(struct omap_dss_device *dssdev);
void omapdss_device_disable(struct omap_dss_device *dssdev);
-void omapdss_device_post_disable(struct omap_dss_device *dssdev);
int omap_dss_get_num_overlay_managers(void);
@@ -487,7 +455,8 @@ int omap_dss_get_num_overlays(void);
#define for_each_dss_output(d) \
while ((d = omapdss_device_next_output(d)) != NULL)
struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from);
-int omapdss_device_init_output(struct omap_dss_device *out);
+int omapdss_device_init_output(struct omap_dss_device *out,
+ struct drm_bridge *local_bridge);
void omapdss_device_cleanup_output(struct omap_dss_device *out);
typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
@@ -502,9 +471,6 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
}
-struct omap_dss_device *
-omapdss_of_find_connected_device(struct device_node *node, unsigned int port);
-
enum dss_writeback_channel {
DSS_WB_LCD1_MGR = 0,
DSS_WB_LCD2_MGR = 1,
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
index 0693d34fca1b..ce21c798cca6 100644
--- a/drivers/gpu/drm/omapdrm/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -4,7 +4,6 @@
* Author: Archit Taneja <archit@ti.com>
*/
-#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -18,12 +17,14 @@
#include "dss.h"
#include "omapdss.h"
-int omapdss_device_init_output(struct omap_dss_device *out)
+int omapdss_device_init_output(struct omap_dss_device *out,
+ struct drm_bridge *local_bridge)
{
struct device_node *remote_node;
+ int ret;
remote_node = of_graph_get_remote_node(out->dev->of_node,
- ffs(out->of_ports) - 1, 0);
+ out->of_port, 0);
if (!remote_node) {
dev_dbg(out->dev, "failed to find video sink\n");
return 0;
@@ -39,17 +40,55 @@ int omapdss_device_init_output(struct omap_dss_device *out)
if (out->next && out->type != out->next->type) {
dev_err(out->dev, "output type and display type don't match\n");
- omapdss_device_put(out->next);
- out->next = NULL;
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
- return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER;
+ if (out->panel) {
+ struct drm_bridge *bridge;
+
+ bridge = drm_panel_bridge_add(out->panel);
+ if (IS_ERR(bridge)) {
+ dev_err(out->dev,
+ "unable to create panel bridge (%ld)\n",
+ PTR_ERR(bridge));
+ ret = PTR_ERR(bridge);
+ goto error;
+ }
+
+ out->bridge = bridge;
+ }
+
+ if (local_bridge) {
+ if (!out->bridge) {
+ ret = -EPROBE_DEFER;
+ goto error;
+ }
+
+ out->next_bridge = out->bridge;
+ out->bridge = local_bridge;
+ }
+
+ if (!out->next && !out->bridge) {
+ ret = -EPROBE_DEFER;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ omapdss_device_cleanup_output(out);
+ out->next = NULL;
+ return ret;
}
EXPORT_SYMBOL(omapdss_device_init_output);
void omapdss_device_cleanup_output(struct omap_dss_device *out)
{
+ if (out->bridge && out->panel)
+ drm_panel_bridge_remove(out->next_bridge ?
+ out->next_bridge : out->bridge);
+
if (out->next)
omapdss_device_put(out->next);
}
diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c
index 3b447c01fa2a..417a8740ad0a 100644
--- a/drivers/gpu/drm/omapdrm/dss/sdi.c
+++ b/drivers/gpu/drm/omapdrm/dss/sdi.c
@@ -6,17 +6,19 @@
#define DSS_SUBSYS_NAME "SDI"
-#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/regulator/consumer.h>
#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/string.h>
-#include <linux/of.h>
-#include "omapdss.h"
+#include <drm/drm_bridge.h>
+
#include "dss.h"
+#include "omapdss.h"
struct sdi_device {
struct platform_device *pdev;
@@ -30,9 +32,11 @@ struct sdi_device {
int datapairs;
struct omap_dss_device output;
+ struct drm_bridge bridge;
};
-#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output)
+#define drm_bridge_to_sdi(bridge) \
+ container_of(bridge, struct sdi_device, bridge)
struct sdi_clk_calc_ctx {
struct sdi_device *sdi;
@@ -118,9 +122,82 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)
dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);
}
-static void sdi_display_enable(struct omap_dss_device *dssdev)
+/* -----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int sdi_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+ return -EINVAL;
+
+ return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge,
+ bridge, flags);
+}
+
+static enum drm_mode_status
+sdi_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode)
+{
+ struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+ unsigned long pixelclock = mode->clock * 1000;
+ struct dispc_clock_info dispc_cinfo;
+ unsigned long fck;
+ int ret;
+
+ if (pixelclock == 0)
+ return MODE_NOCLOCK;
+
+ ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
+ if (ret < 0)
+ return MODE_CLOCK_RANGE;
+
+ return MODE_OK;
+}
+
+static bool sdi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+ unsigned long pixelclock = mode->clock * 1000;
+ struct dispc_clock_info dispc_cinfo;
+ unsigned long fck;
+ unsigned long pck;
+ int ret;
+
+ ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
+ if (ret < 0)
+ return false;
+
+ pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
+
+ if (pck != pixelclock)
+ dev_dbg(&sdi->pdev->dev,
+ "pixel clock adjusted from %lu Hz to %lu Hz\n",
+ pixelclock, pck);
+
+ adjusted_mode->clock = pck / 1000;
+
+ return true;
+}
+
+static void sdi_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
+{
+ struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+
+ sdi->pixelclock = adjusted_mode->clock * 1000;
+}
+
+static void sdi_bridge_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
{
- struct sdi_device *sdi = dssdev_to_sdi(dssdev);
+ struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
struct dispc_clock_info dispc_cinfo;
unsigned long fck;
int r;
@@ -181,9 +258,10 @@ err_get_dispc:
regulator_disable(sdi->vdds_sdi_reg);
}
-static void sdi_display_disable(struct omap_dss_device *dssdev)
+static void sdi_bridge_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state)
{
- struct sdi_device *sdi = dssdev_to_sdi(dssdev);
+ struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
dss_mgr_disable(&sdi->output);
@@ -194,86 +272,56 @@ static void sdi_display_disable(struct omap_dss_device *dssdev)
regulator_disable(sdi->vdds_sdi_reg);
}
-static void sdi_set_timings(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode)
-{
- struct sdi_device *sdi = dssdev_to_sdi(dssdev);
-
- sdi->pixelclock = mode->clock * 1000;
-}
+static const struct drm_bridge_funcs sdi_bridge_funcs = {
+ .attach = sdi_bridge_attach,
+ .mode_valid = sdi_bridge_mode_valid,
+ .mode_fixup = sdi_bridge_mode_fixup,
+ .mode_set = sdi_bridge_mode_set,
+ .atomic_enable = sdi_bridge_enable,
+ .atomic_disable = sdi_bridge_disable,
+};
-static int sdi_check_timings(struct omap_dss_device *dssdev,
- struct drm_display_mode *mode)
+static void sdi_bridge_init(struct sdi_device *sdi)
{
- struct sdi_device *sdi = dssdev_to_sdi(dssdev);
- struct dispc_clock_info dispc_cinfo;
- unsigned long pixelclock = mode->clock * 1000;
- unsigned long fck;
- unsigned long pck;
- int r;
+ sdi->bridge.funcs = &sdi_bridge_funcs;
+ sdi->bridge.of_node = sdi->pdev->dev.of_node;
+ sdi->bridge.type = DRM_MODE_CONNECTOR_LVDS;
- if (pixelclock == 0)
- return -EINVAL;
-
- r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
- if (r)
- return r;
-
- pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
-
- if (pck != pixelclock) {
- DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
- pixelclock, pck);
-
- mode->clock = pck / 1000;
- }
-
- return 0;
+ drm_bridge_add(&sdi->bridge);
}
-static int sdi_connect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
+static void sdi_bridge_cleanup(struct sdi_device *sdi)
{
- return omapdss_device_connect(dst->dss, dst, dst->next);
+ drm_bridge_remove(&sdi->bridge);
}
-static void sdi_disconnect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
-{
- omapdss_device_disconnect(dst, dst->next);
-}
-
-static const struct omap_dss_device_ops sdi_ops = {
- .connect = sdi_connect,
- .disconnect = sdi_disconnect,
-
- .enable = sdi_display_enable,
- .disable = sdi_display_disable,
-
- .check_timings = sdi_check_timings,
- .set_timings = sdi_set_timings,
-};
+/* -----------------------------------------------------------------------------
+ * Initialisation and Cleanup
+ */
static int sdi_init_output(struct sdi_device *sdi)
{
struct omap_dss_device *out = &sdi->output;
int r;
+ sdi_bridge_init(sdi);
+
out->dev = &sdi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_SDI;
out->type = OMAP_DISPLAY_TYPE_SDI;
out->name = "sdi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
/* We have SDI only on OMAP3, where it's on port 1 */
- out->of_ports = BIT(1);
- out->ops = &sdi_ops;
+ out->of_port = 1;
out->owner = THIS_MODULE;
out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */
| DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
- r = omapdss_device_init_output(out);
- if (r < 0)
+ r = omapdss_device_init_output(out, &sdi->bridge);
+ if (r < 0) {
+ sdi_bridge_cleanup(sdi);
return r;
+ }
omapdss_device_register(out);
@@ -284,6 +332,8 @@ static void sdi_uninit_output(struct sdi_device *sdi)
{
omapdss_device_unregister(&sdi->output);
omapdss_device_cleanup_output(&sdi->output);
+
+ sdi_bridge_cleanup(sdi);
}
int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index 596a297d5813..766553bb2f87 100644
--- a/drivers/gpu/drm/omapdrm/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -13,7 +13,6 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/string.h>
@@ -26,6 +25,8 @@
#include <linux/component.h>
#include <linux/sys_soc.h>
+#include <drm/drm_bridge.h>
+
#include "omapdss.h"
#include "dss.h"
@@ -289,7 +290,6 @@ static const struct drm_display_mode omap_dss_ntsc_mode = {
struct venc_device {
struct platform_device *pdev;
void __iomem *base;
- struct mutex venc_lock;
struct regulator *vdda_dac_reg;
struct dss_device *dss;
@@ -303,9 +303,10 @@ struct venc_device {
bool requires_tv_dac_clk;
struct omap_dss_device output;
+ struct drm_bridge bridge;
};
-#define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output)
+#define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge)
static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val)
{
@@ -477,56 +478,6 @@ static void venc_power_off(struct venc_device *venc)
venc_runtime_put(venc);
}
-static void venc_display_enable(struct omap_dss_device *dssdev)
-{
- struct venc_device *venc = dssdev_to_venc(dssdev);
-
- DSSDBG("venc_display_enable\n");
-
- mutex_lock(&venc->venc_lock);
-
- venc_power_on(venc);
-
- mutex_unlock(&venc->venc_lock);
-}
-
-static void venc_display_disable(struct omap_dss_device *dssdev)
-{
- struct venc_device *venc = dssdev_to_venc(dssdev);
-
- DSSDBG("venc_display_disable\n");
-
- mutex_lock(&venc->venc_lock);
-
- venc_power_off(venc);
-
- mutex_unlock(&venc->venc_lock);
-}
-
-static int venc_get_modes(struct omap_dss_device *dssdev,
- struct drm_connector *connector)
-{
- static const struct drm_display_mode *modes[] = {
- &omap_dss_pal_mode,
- &omap_dss_ntsc_mode,
- };
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(modes); ++i) {
- struct drm_display_mode *mode;
-
- mode = drm_mode_duplicate(connector->dev, modes[i]);
- if (!mode)
- return i;
-
- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
- drm_mode_set_name(mode);
- drm_mode_probed_add(connector, mode);
- }
-
- return ARRAY_SIZE(modes);
-}
-
static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)
{
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
@@ -545,57 +496,6 @@ static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mod
return VENC_MODE_UNKNOWN;
}
-static void venc_set_timings(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode)
-{
- struct venc_device *venc = dssdev_to_venc(dssdev);
- enum venc_videomode venc_mode = venc_get_videomode(mode);
-
- DSSDBG("venc_set_timings\n");
-
- mutex_lock(&venc->venc_lock);
-
- switch (venc_mode) {
- default:
- WARN_ON_ONCE(1);
- /* Fall-through */
- case VENC_MODE_PAL:
- venc->config = &venc_config_pal_trm;
- break;
-
- case VENC_MODE_NTSC:
- venc->config = &venc_config_ntsc_trm;
- break;
- }
-
- dispc_set_tv_pclk(venc->dss->dispc, 13500000);
-
- mutex_unlock(&venc->venc_lock);
-}
-
-static int venc_check_timings(struct omap_dss_device *dssdev,
- struct drm_display_mode *mode)
-{
- DSSDBG("venc_check_timings\n");
-
- switch (venc_get_videomode(mode)) {
- case VENC_MODE_PAL:
- drm_mode_copy(mode, &omap_dss_pal_mode);
- break;
-
- case VENC_MODE_NTSC:
- drm_mode_copy(mode, &omap_dss_ntsc_mode);
- break;
-
- default:
- return -EINVAL;
- }
-
- drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
- drm_mode_set_name(mode);
- return 0;
-}
-
static int venc_dump_regs(struct seq_file *s, void *p)
{
struct venc_device *venc = s->private;
@@ -673,31 +573,149 @@ static int venc_get_clocks(struct venc_device *venc)
return 0;
}
-static int venc_connect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
+/* -----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int venc_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct venc_device *venc = drm_bridge_to_venc(bridge);
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+ return -EINVAL;
+
+ return drm_bridge_attach(bridge->encoder, venc->output.next_bridge,
+ bridge, flags);
+}
+
+static enum drm_mode_status
+venc_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode)
+{
+ switch (venc_get_videomode(mode)) {
+ case VENC_MODE_PAL:
+ case VENC_MODE_NTSC:
+ return MODE_OK;
+
+ default:
+ return MODE_BAD;
+ }
+}
+
+static bool venc_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ const struct drm_display_mode *venc_mode;
+
+ switch (venc_get_videomode(adjusted_mode)) {
+ case VENC_MODE_PAL:
+ venc_mode = &omap_dss_pal_mode;
+ break;
+
+ case VENC_MODE_NTSC:
+ venc_mode = &omap_dss_ntsc_mode;
+ break;
+
+ default:
+ return false;
+ }
+
+ drm_mode_copy(adjusted_mode, venc_mode);
+ drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_set_name(adjusted_mode);
+
+ return true;
+}
+
+static void venc_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
+{
+ struct venc_device *venc = drm_bridge_to_venc(bridge);
+ enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode);
+
+ switch (venc_mode) {
+ default:
+ WARN_ON_ONCE(1);
+ /* Fall-through */
+ case VENC_MODE_PAL:
+ venc->config = &venc_config_pal_trm;
+ break;
+
+ case VENC_MODE_NTSC:
+ venc->config = &venc_config_ntsc_trm;
+ break;
+ }
+
+ dispc_set_tv_pclk(venc->dss->dispc, 13500000);
+}
+
+static void venc_bridge_enable(struct drm_bridge *bridge)
{
- return omapdss_device_connect(dst->dss, dst, dst->next);
+ struct venc_device *venc = drm_bridge_to_venc(bridge);
+
+ venc_power_on(venc);
}
-static void venc_disconnect(struct omap_dss_device *src,
- struct omap_dss_device *dst)
+static void venc_bridge_disable(struct drm_bridge *bridge)
{
- omapdss_device_disconnect(dst, dst->next);
+ struct venc_device *venc = drm_bridge_to_venc(bridge);
+
+ venc_power_off(venc);
}
-static const struct omap_dss_device_ops venc_ops = {
- .connect = venc_connect,
- .disconnect = venc_disconnect,
+static int venc_bridge_get_modes(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ static const struct drm_display_mode *modes[] = {
+ &omap_dss_pal_mode,
+ &omap_dss_ntsc_mode,
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(modes); ++i) {
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, modes[i]);
+ if (!mode)
+ return i;
- .enable = venc_display_enable,
- .disable = venc_display_disable,
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
- .check_timings = venc_check_timings,
- .set_timings = venc_set_timings,
+ return ARRAY_SIZE(modes);
+}
- .get_modes = venc_get_modes,
+static const struct drm_bridge_funcs venc_bridge_funcs = {
+ .attach = venc_bridge_attach,
+ .mode_valid = venc_bridge_mode_valid,
+ .mode_fixup = venc_bridge_mode_fixup,
+ .mode_set = venc_bridge_mode_set,
+ .enable = venc_bridge_enable,
+ .disable = venc_bridge_disable,
+ .get_modes = venc_bridge_get_modes,
};
+static void venc_bridge_init(struct venc_device *venc)
+{
+ venc->bridge.funcs = &venc_bridge_funcs;
+ venc->bridge.of_node = venc->pdev->dev.of_node;
+ venc->bridge.ops = DRM_BRIDGE_OP_MODES;
+ venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO;
+ venc->bridge.interlace_allowed = true;
+
+ drm_bridge_add(&venc->bridge);
+}
+
+static void venc_bridge_cleanup(struct venc_device *venc)
+{
+ drm_bridge_remove(&venc->bridge);
+}
+
/* -----------------------------------------------------------------------------
* Component Bind & Unbind
*/
@@ -747,19 +765,22 @@ static int venc_init_output(struct venc_device *venc)
struct omap_dss_device *out = &venc->output;
int r;
+ venc_bridge_init(venc);
+
out->dev = &venc->pdev->dev;
out->id = OMAP_DSS_OUTPUT_VENC;
out->type = OMAP_DISPLAY_TYPE_VENC;
out->name = "venc.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
- out->ops = &venc_ops;
out->owner = THIS_MODULE;
- out->of_ports = BIT(0);
+ out->of_port = 0;
out->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
- r = omapdss_device_init_output(out);
- if (r < 0)
+ r = omapdss_device_init_output(out, &venc->bridge);
+ if (r < 0) {
+ venc_bridge_cleanup(venc);
return r;
+ }
omapdss_device_register(out);
@@ -770,6 +791,8 @@ static void venc_uninit_output(struct venc_device *venc)
{
omapdss_device_unregister(&venc->output);
omapdss_device_cleanup_output(&venc->output);
+
+ venc_bridge_cleanup(venc);
}
static int venc_probe_of(struct venc_device *venc)
@@ -839,8 +862,6 @@ static int venc_probe(struct platform_device *pdev)
if (soc_device_match(venc_soc_devices))
venc->requires_tv_dac_clk = true;
- mutex_init(&venc->venc_lock);
-
venc->config = &venc_config_pal_trm;
venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0);