summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imx/ipuv3/imx-ldb.c')
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-ldb.c203
1 files changed, 41 insertions, 162 deletions
diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
index 793dfb1a3ed0..ff74018ac5cd 100644
--- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
@@ -19,19 +19,16 @@
#include <linux/regmap.h>
#include <linux/videodev2.h>
-#include <video/of_display_timing.h>
-#include <video/of_videomode.h>
-
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_edid.h>
+#include <drm/drm_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
+#include <drm/bridge/imx.h>
#include "imx-drm.h"
@@ -55,7 +52,6 @@
struct imx_ldb_channel;
struct imx_ldb_encoder {
- struct drm_connector connector;
struct drm_encoder encoder;
struct imx_ldb_channel *channel;
};
@@ -65,25 +61,13 @@ struct imx_ldb;
struct imx_ldb_channel {
struct imx_ldb *ldb;
- /* Defines what is connected to the ldb, only one at a time */
- struct drm_panel *panel;
struct drm_bridge *bridge;
struct device_node *child;
- struct i2c_adapter *ddc;
int chno;
- const struct drm_edid *drm_edid;
- struct drm_display_mode mode;
- int mode_valid;
u32 bus_format;
- u32 bus_flags;
};
-static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c)
-{
- return container_of(c, struct imx_ldb_encoder, connector)->channel;
-}
-
static inline struct imx_ldb_channel *enc_to_imx_ldb_ch(struct drm_encoder *e)
{
return container_of(e, struct imx_ldb_encoder, encoder)->channel;
@@ -133,38 +117,6 @@ static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch,
}
}
-static int imx_ldb_connector_get_modes(struct drm_connector *connector)
-{
- struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
- int num_modes;
-
- num_modes = drm_panel_get_modes(imx_ldb_ch->panel, connector);
- if (num_modes > 0)
- return num_modes;
-
- if (!imx_ldb_ch->drm_edid && imx_ldb_ch->ddc) {
- imx_ldb_ch->drm_edid = drm_edid_read_ddc(connector,
- imx_ldb_ch->ddc);
- drm_edid_connector_update(connector, imx_ldb_ch->drm_edid);
- }
-
- if (imx_ldb_ch->drm_edid)
- num_modes = drm_edid_connector_add_modes(connector);
-
- if (imx_ldb_ch->mode_valid) {
- struct drm_display_mode *mode;
-
- mode = drm_mode_duplicate(connector->dev, &imx_ldb_ch->mode);
- if (!mode)
- return -EINVAL;
- mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
- drm_mode_probed_add(connector, mode);
- num_modes++;
- }
-
- return num_modes;
-}
-
static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
unsigned long serial_clk, unsigned long di_clk)
{
@@ -205,8 +157,6 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
return;
}
- drm_panel_prepare(imx_ldb_ch->panel);
-
if (dual) {
clk_set_parent(ldb->clk_sel[mux], ldb->clk[0]);
clk_set_parent(ldb->clk_sel[mux], ldb->clk[1]);
@@ -245,8 +195,6 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
}
regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
-
- drm_panel_enable(imx_ldb_ch->panel);
}
static void
@@ -323,8 +271,6 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
int mux, ret;
- drm_panel_disable(imx_ldb_ch->panel);
-
if (imx_ldb_ch == &ldb->channel[0] || dual)
ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
if (imx_ldb_ch == &ldb->channel[1] || dual)
@@ -358,8 +304,6 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
dev_err(ldb->dev,
"unable to set di%d parent clock to original parent\n",
mux);
-
- drm_panel_unprepare(imx_ldb_ch->panel);
}
static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
@@ -374,11 +318,12 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
/* Bus format description in DT overrides connector display info. */
if (!bus_format && di->num_bus_formats) {
bus_format = di->bus_formats[0];
- imx_crtc_state->bus_flags = di->bus_flags;
} else {
bus_format = imx_ldb_ch->bus_format;
- imx_crtc_state->bus_flags = imx_ldb_ch->bus_flags;
}
+
+ imx_crtc_state->bus_flags = di->bus_flags;
+
switch (bus_format) {
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
@@ -398,18 +343,6 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
}
-static const struct drm_connector_funcs imx_ldb_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = imx_drm_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
- .get_modes = imx_ldb_connector_get_modes,
-};
-
static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
.atomic_mode_set = imx_ldb_encoder_atomic_mode_set,
.enable = imx_ldb_encoder_enable,
@@ -447,7 +380,6 @@ static int imx_ldb_register(struct drm_device *drm,
return PTR_ERR(ldb_encoder);
ldb_encoder->channel = imx_ldb_ch;
- connector = &ldb_encoder->connector;
encoder = &ldb_encoder->encoder;
ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child);
@@ -466,25 +398,16 @@ static int imx_ldb_register(struct drm_device *drm,
drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs);
- if (imx_ldb_ch->bridge) {
- ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL, 0);
- if (ret)
- return ret;
- } else {
- /*
- * We want to add the connector whenever there is no bridge
- * that brings its own, not only when there is a panel. For
- * historical reasons, the ldb driver can also work without
- * a panel.
- */
- drm_connector_helper_add(connector,
- &imx_ldb_connector_helper_funcs);
- drm_connector_init_with_ddc(drm, connector,
- &imx_ldb_connector_funcs,
- DRM_MODE_CONNECTOR_LVDS,
- imx_ldb_ch->ddc);
- drm_connector_attach_encoder(connector, encoder);
- }
+ ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL,
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ if (ret)
+ return ret;
+
+ connector = drm_bridge_connector_init(drm, encoder);
+ if (IS_ERR(connector))
+ return PTR_ERR(connector);
+
+ drm_connector_attach_encoder(connector, encoder);
return 0;
}
@@ -549,47 +472,6 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
-static int imx_ldb_panel_ddc(struct device *dev,
- struct imx_ldb_channel *channel, struct device_node *child)
-{
- struct device_node *ddc_node;
- int ret;
-
- ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
- if (ddc_node) {
- channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
- of_node_put(ddc_node);
- if (!channel->ddc) {
- dev_warn(dev, "failed to get ddc i2c adapter\n");
- return -EPROBE_DEFER;
- }
- }
-
- if (!channel->ddc) {
- const void *edidp;
- int edid_len;
-
- /* if no DDC available, fallback to hardcoded EDID */
- dev_dbg(dev, "no ddc available\n");
-
- edidp = of_get_property(child, "edid", &edid_len);
- if (edidp) {
- channel->drm_edid = drm_edid_alloc(edidp, edid_len);
- if (!channel->drm_edid)
- return -ENOMEM;
- } else if (!channel->panel) {
- /* fallback to display-timings node */
- ret = of_get_drm_display_mode(child,
- &channel->mode,
- &channel->bus_flags,
- OF_USE_NATIVE_MODE);
- if (!ret)
- channel->mode_valid = 1;
- }
- }
- return 0;
-}
-
static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
@@ -694,29 +576,22 @@ static int imx_ldb_probe(struct platform_device *pdev)
* The output port is port@4 with an external 4-port mux or
* port@2 with the internal 2-port mux.
*/
- ret = drm_of_find_panel_or_bridge(child,
- imx_ldb->lvds_mux ? 4 : 2, 0,
- &channel->panel, &channel->bridge);
- if (ret && ret != -ENODEV)
- goto free_child;
-
- /* panel ddc only if there is no bridge */
- if (!channel->bridge) {
- ret = imx_ldb_panel_ddc(dev, channel, child);
- if (ret)
+ channel->bridge = devm_drm_of_get_bridge(dev, child,
+ imx_ldb->lvds_mux ? 4 : 2, 0);
+ if (IS_ERR(channel->bridge)) {
+ ret = PTR_ERR(channel->bridge);
+ if (ret != -ENODEV)
goto free_child;
+ channel->bridge = NULL;
}
bus_format = of_get_bus_format(dev, child);
- if (bus_format == -EINVAL) {
- /*
- * If no bus format was specified in the device tree,
- * we can still get it from the connected panel later.
- */
- if (channel->panel && channel->panel->funcs &&
- channel->panel->funcs->get_modes)
- bus_format = 0;
- }
+ /*
+ * If no bus format was specified in the device tree,
+ * we can still get it from the connected panel later.
+ */
+ if (bus_format == -EINVAL && channel->bridge)
+ bus_format = 0;
if (bus_format < 0) {
dev_err(dev, "could not determine data mapping: %d\n",
bus_format);
@@ -724,6 +599,20 @@ static int imx_ldb_probe(struct platform_device *pdev)
goto free_child;
}
channel->bus_format = bus_format;
+
+ /*
+ * legacy bridge doesn't handle bus_format, so create it after
+ * checking the bus_format property.
+ */
+ if (!channel->bridge) {
+ channel->bridge = devm_imx_drm_legacy_bridge(dev, child,
+ DRM_MODE_CONNECTOR_LVDS);
+ if (IS_ERR(channel->bridge)) {
+ ret = PTR_ERR(channel->bridge);
+ goto free_child;
+ }
+ }
+
channel->child = child;
}
@@ -738,16 +627,6 @@ free_child:
static void imx_ldb_remove(struct platform_device *pdev)
{
- struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < 2; i++) {
- struct imx_ldb_channel *channel = &imx_ldb->channel[i];
-
- drm_edid_free(channel->drm_edid);
- i2c_put_adapter(channel->ddc);
- }
-
component_del(&pdev->dev, &imx_ldb_ops);
}