aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imx')
-rw-r--r--drivers/gpu/drm/imx/Kconfig7
-rw-r--r--drivers/gpu/drm/imx/Makefile3
-rw-r--r--drivers/gpu/drm/imx/dw_hdmi-imx.c2
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c163
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h18
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c27
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c90
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c344
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.h6
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c36
10 files changed, 391 insertions, 305 deletions
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index f2c9ae822149..c9e439c82241 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -31,13 +31,6 @@ config DRM_IMX_LDB
Choose this to enable the internal LVDS Display Bridge (LDB)
found on i.MX53 and i.MX6 processors.
-config DRM_IMX_IPUV3
- tristate
- depends on DRM_IMX
- depends on IMX_IPUV3_CORE
- default y if DRM_IMX=y
- default m if DRM_IMX=m
-
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
select DRM_DW_HDMI
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index f3ecd8903d97..16ecef33e008 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -1,5 +1,5 @@
-imxdrm-objs := imx-drm-core.o
+imxdrm-objs := imx-drm-core.o ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX) += imxdrm.o
@@ -7,6 +7,5 @@ obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index f645275e6e63..f039641070ac 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -175,7 +175,6 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.phy_config = imx_phy_config,
- .dev_type = IMX6Q_HDMI,
.mode_valid = imx6q_hdmi_mode_valid,
};
@@ -183,7 +182,6 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.phy_config = imx_phy_config,
- .dev_type = IMX6DL_HDMI,
.mode_valid = imx6dl_hdmi_mode_valid,
};
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index f562cb7964b0..50add2f9e250 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -30,27 +30,17 @@
#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
+#include "ipuv3-plane.h"
#define MAX_CRTC 4
-struct imx_drm_component {
- struct device_node *of_node;
- struct list_head list;
-};
-
struct imx_drm_device {
struct drm_device *drm;
- struct imx_drm_crtc *crtc[MAX_CRTC];
unsigned int pipes;
struct drm_fbdev_cma *fbhelper;
struct drm_atomic_state *state;
};
-struct imx_drm_crtc {
- struct drm_crtc *crtc;
- struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
-};
-
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
@@ -63,48 +53,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
}
-static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
-{
- struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
- int ret;
-
- if (!imx_drm_crtc)
- return -EINVAL;
-
- if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
- return -ENOSYS;
-
- ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
- imx_drm_crtc->crtc);
-
- return ret;
-}
-
-static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
-{
- struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
-
- if (!imx_drm_crtc)
- return;
-
- if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
- return;
-
- imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
-}
-
-static const struct file_operations imx_drm_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_gem_cma_mmap,
- .poll = drm_poll,
- .read = drm_read,
- .llseek = noop_llseek,
-};
+DEFINE_DRM_GEM_CMA_FOPS(imx_drm_driver_fops);
void imx_drm_connector_destroy(struct drm_connector *connector)
{
@@ -147,6 +96,11 @@ static int imx_drm_atomic_check(struct drm_device *dev,
if (ret)
return ret;
+ /* Assign PRG/PRE channels and check if all constrains are satisfied. */
+ ret = ipu_planes_assign_pre(dev, state);
+ if (ret)
+ return ret;
+
return ret;
}
@@ -160,6 +114,10 @@ static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
+ struct drm_plane *plane;
+ struct drm_plane_state *old_plane_state;
+ bool plane_disabling = false;
+ int i;
drm_atomic_helper_commit_modeset_disables(dev, state);
@@ -169,78 +127,26 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_commit_modeset_enables(dev, state);
- drm_atomic_helper_commit_hw_done(state);
-
- drm_atomic_helper_wait_for_vblanks(dev, state);
-
- drm_atomic_helper_cleanup_planes(dev, state);
-}
-
-static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
- .atomic_commit_tail = imx_drm_atomic_commit_tail,
-};
-
-/*
- * imx_drm_add_crtc - add a new crtc
- */
-int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
- struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
- const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
- struct device_node *port)
-{
- struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
-
- /*
- * The vblank arrays are dimensioned by MAX_CRTC - we can't
- * pass IDs greater than this to those functions.
- */
- if (imxdrm->pipes >= MAX_CRTC)
- return -EINVAL;
-
- if (imxdrm->drm->open_count)
- return -EBUSY;
-
- imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
- if (!imx_drm_crtc)
- return -ENOMEM;
-
- imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
- imx_drm_crtc->crtc = crtc;
-
- crtc->port = port;
-
- imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc;
+ for_each_plane_in_state(state, plane, old_plane_state, i) {
+ if (drm_atomic_plane_disabling(old_plane_state, plane->state))
+ plane_disabling = true;
+ }
- *new_crtc = imx_drm_crtc;
+ if (plane_disabling) {
+ drm_atomic_helper_wait_for_vblanks(dev, state);
- drm_crtc_helper_add(crtc,
- imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+ for_each_plane_in_state(state, plane, old_plane_state, i)
+ ipu_plane_disable_deferred(plane);
- drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
- imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL);
+ }
- return 0;
+ drm_atomic_helper_commit_hw_done(state);
}
-EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
-/*
- * imx_drm_remove_crtc - remove a crtc
- */
-int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
-{
- struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
- unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc);
-
- drm_crtc_cleanup(imx_drm_crtc->crtc);
-
- imxdrm->crtc[pipe] = NULL;
-
- kfree(imx_drm_crtc);
+static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
+ .atomic_commit_tail = imx_drm_atomic_commit_tail,
+};
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
int imx_drm_encoder_parse_of(struct drm_device *drm,
struct drm_encoder *encoder, struct device_node *np)
@@ -288,9 +194,6 @@ static struct drm_driver imx_drm_driver = {
.gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,
- .get_vblank_counter = drm_vblank_no_hw_counter,
- .enable_vblank = imx_drm_enable_vblank,
- .disable_vblank = imx_drm_disable_vblank,
.ioctls = imx_drm_ioctls,
.num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
.fops = &imx_drm_driver_fops,
@@ -519,7 +422,23 @@ static struct platform_driver imx_drm_pdrv = {
.of_match_table = imx_drm_dt_ids,
},
};
-module_platform_driver(imx_drm_pdrv);
+
+static struct platform_driver * const drivers[] = {
+ &imx_drm_pdrv,
+ &ipu_drm_driver,
+};
+
+static int __init imx_drm_init(void)
+{
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_init(imx_drm_init);
+
+static void __exit imx_drm_exit(void)
+{
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_exit(imx_drm_exit);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX drm driver core");
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index 5a91cb16c8fa..f6dd64be9cd5 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -25,23 +25,12 @@ static inline struct imx_crtc_state *to_imx_crtc_state(struct drm_crtc_state *s)
{
return container_of(s, struct imx_crtc_state, base);
}
-
-struct imx_drm_crtc_helper_funcs {
- int (*enable_vblank)(struct drm_crtc *crtc);
- void (*disable_vblank)(struct drm_crtc *crtc);
- const struct drm_crtc_helper_funcs *crtc_helper_funcs;
- const struct drm_crtc_funcs *crtc_funcs;
-};
-
-int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
- struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
- const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
- struct device_node *port);
-int imx_drm_remove_crtc(struct imx_drm_crtc *);
int imx_drm_init_drm(struct platform_device *pdev,
int preferred_bpp);
int imx_drm_exit_drm(void);
+extern struct platform_driver ipu_drm_driver;
+
void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
@@ -52,4 +41,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
void imx_drm_connector_destroy(struct drm_connector *connector);
void imx_drm_encoder_destroy(struct drm_encoder *encoder);
+int ipu_planes_assign_pre(struct drm_device *dev,
+ struct drm_atomic_state *state);
+
#endif /* _IMX_DRM_H_ */
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 88cd11d30134..8fb801fab039 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -647,7 +647,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
for_each_child_of_node(np, child) {
struct imx_ldb_channel *channel;
- struct device_node *ep;
int bus_format;
ret = of_property_read_u32(child, "reg", &i);
@@ -671,27 +670,11 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
* The output port is port@4 with an external 4-port mux or
* port@2 with the internal 2-port mux.
*/
- ep = of_graph_get_endpoint_by_regs(child,
- imx_ldb->lvds_mux ? 4 : 2,
- -1);
- if (ep) {
- struct device_node *remote;
-
- remote = of_graph_get_remote_port_parent(ep);
- of_node_put(ep);
- if (remote) {
- channel->panel = of_drm_find_panel(remote);
- channel->bridge = of_drm_find_bridge(remote);
- } else
- return -EPROBE_DEFER;
- of_node_put(remote);
-
- if (!channel->panel && !channel->bridge) {
- dev_err(dev, "panel/bridge not found: %s\n",
- remote->full_name);
- return -EPROBE_DEFER;
- }
- }
+ ret = drm_of_find_panel_or_bridge(child,
+ imx_ldb->lvds_mux ? 4 : 2, 0,
+ &channel->panel, &channel->bridge);
+ if (ret)
+ return ret;
/* panel ddc only if there is no bridge */
if (!channel->bridge) {
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 6be515a9fb69..5456c15d962c 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -55,11 +55,32 @@ static void ipu_crtc_enable(struct drm_crtc *crtc)
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+ ipu_prg_enable(ipu);
ipu_dc_enable(ipu);
ipu_dc_enable_channel(ipu_crtc->dc);
ipu_di_enable(ipu_crtc->di);
}
+static void ipu_crtc_disable_planes(struct ipu_crtc *ipu_crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ bool disable_partial = false;
+ bool disable_full = false;
+ struct drm_plane *plane;
+
+ drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
+ if (plane == &ipu_crtc->plane[0]->base)
+ disable_full = true;
+ if (&ipu_crtc->plane[1] && plane == &ipu_crtc->plane[1]->base)
+ disable_partial = true;
+ }
+
+ if (disable_partial)
+ ipu_plane_disable(ipu_crtc->plane[1], true);
+ if (disable_full)
+ ipu_plane_disable(ipu_crtc->plane[0], false);
+}
+
static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
@@ -73,8 +94,9 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
* attached IDMACs will be left in undefined state, possibly hanging
* the IPU or even system.
*/
- drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
+ ipu_crtc_disable_planes(ipu_crtc, old_crtc_state);
ipu_dc_disable(ipu);
+ ipu_prg_disable(ipu);
spin_lock_irq(&crtc->dev->event_lock);
if (crtc->state->event) {
@@ -129,18 +151,31 @@ static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc,
kfree(to_imx_crtc_state(state));
}
-static void imx_drm_crtc_destroy(struct drm_crtc *crtc)
+static int ipu_enable_vblank(struct drm_crtc *crtc)
{
- imx_drm_remove_crtc(to_ipu_crtc(crtc)->imx_crtc);
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ enable_irq(ipu_crtc->irq);
+
+ return 0;
+}
+
+static void ipu_disable_vblank(struct drm_crtc *crtc)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ disable_irq_nosync(ipu_crtc->irq);
}
static const struct drm_crtc_funcs ipu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
- .destroy = imx_drm_crtc_destroy,
+ .destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip,
.reset = imx_drm_crtc_reset,
.atomic_duplicate_state = imx_drm_crtc_duplicate_state,
.atomic_destroy_state = imx_drm_crtc_destroy_state,
+ .enable_vblank = ipu_enable_vblank,
+ .disable_vblank = ipu_disable_vblank,
};
static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
@@ -261,29 +296,6 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
.enable = ipu_crtc_enable,
};
-static int ipu_enable_vblank(struct drm_crtc *crtc)
-{
- struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
- enable_irq(ipu_crtc->irq);
-
- return 0;
-}
-
-static void ipu_disable_vblank(struct drm_crtc *crtc)
-{
- struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
- disable_irq_nosync(ipu_crtc->irq);
-}
-
-static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
- .enable_vblank = ipu_enable_vblank,
- .disable_vblank = ipu_disable_vblank,
- .crtc_funcs = &ipu_crtc_funcs,
- .crtc_helper_funcs = &ipu_helper_funcs,
-};
-
static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
{
if (!IS_ERR_OR_NULL(ipu_crtc->dc))
@@ -321,6 +333,7 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
struct ipu_client_platformdata *pdata, struct drm_device *drm)
{
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+ struct drm_crtc *crtc = &ipu_crtc->base;
int dp = -EINVAL;
int ret;
@@ -340,19 +353,16 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
goto err_put_resources;
}
- ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
- &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
- pdata->of_node);
- if (ret) {
- dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
- goto err_put_resources;
- }
+ crtc->port = pdata->of_node;
+ drm_crtc_helper_add(crtc, &ipu_helper_funcs);
+ drm_crtc_init_with_planes(drm, crtc, &ipu_crtc->plane[0]->base, NULL,
+ &ipu_crtc_funcs, NULL);
ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
if (ret) {
dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
ret);
- goto err_remove_crtc;
+ goto err_put_resources;
}
/* If this crtc is using the DP, add an overlay plane */
@@ -390,8 +400,6 @@ err_put_plane1_res:
ipu_plane_put_resources(ipu_crtc->plane[1]);
err_put_plane0_res:
ipu_plane_put_resources(ipu_crtc->plane[0]);
-err_remove_crtc:
- imx_drm_remove_crtc(ipu_crtc->imx_crtc);
err_put_resources:
ipu_put_resources(ipu_crtc);
@@ -457,16 +465,10 @@ static int ipu_drm_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver ipu_drm_driver = {
+struct platform_driver ipu_drm_driver = {
.driver = {
.name = "imx-ipuv3-crtc",
},
.probe = ipu_drm_probe,
.remove = ipu_drm_remove,
};
-module_platform_driver(ipu_drm_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 8b5294d47cee..d63e853a0300 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -23,6 +23,17 @@
#include "video/imx-ipu-v3.h"
#include "ipuv3-plane.h"
+struct ipu_plane_state {
+ struct drm_plane_state base;
+ bool use_pre;
+};
+
+static inline struct ipu_plane_state *
+to_ipu_plane_state(struct drm_plane_state *p)
+{
+ return container_of(p, struct ipu_plane_state, base);
+}
+
static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
{
return container_of(p, struct ipu_plane, base);
@@ -57,6 +68,12 @@ static const uint32_t ipu_plane_formats[] = {
DRM_FORMAT_NV12,
DRM_FORMAT_NV16,
DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB565_A8,
+ DRM_FORMAT_BGR565_A8,
+ DRM_FORMAT_RGB888_A8,
+ DRM_FORMAT_BGR888_A8,
+ DRM_FORMAT_RGBX8888_A8,
+ DRM_FORMAT_BGRX8888_A8,
};
int ipu_plane_irq(struct ipu_plane *ipu_plane)
@@ -66,18 +83,18 @@ int ipu_plane_irq(struct ipu_plane *ipu_plane)
}
static inline unsigned long
-drm_plane_state_to_eba(struct drm_plane_state *state)
+drm_plane_state_to_eba(struct drm_plane_state *state, int plane)
{
struct drm_framebuffer *fb = state->fb;
struct drm_gem_cma_object *cma_obj;
- int x = state->src_x >> 16;
- int y = state->src_y >> 16;
+ int x = state->src.x1 >> 16;
+ int y = state->src.y1 >> 16;
- cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ cma_obj = drm_fb_cma_get_gem_obj(fb, plane);
BUG_ON(!cma_obj);
- return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
- fb->format->cpp[0] * x;
+ return cma_obj->paddr + fb->offsets[plane] + fb->pitches[plane] * y +
+ fb->format->cpp[plane] * x;
}
static inline unsigned long
@@ -85,9 +102,9 @@ drm_plane_state_to_ubo(struct drm_plane_state *state)
{
struct drm_framebuffer *fb = state->fb;
struct drm_gem_cma_object *cma_obj;
- unsigned long eba = drm_plane_state_to_eba(state);
- int x = state->src_x >> 16;
- int y = state->src_y >> 16;
+ unsigned long eba = drm_plane_state_to_eba(state, 0);
+ int x = state->src.x1 >> 16;
+ int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
BUG_ON(!cma_obj);
@@ -104,9 +121,9 @@ drm_plane_state_to_vbo(struct drm_plane_state *state)
{
struct drm_framebuffer *fb = state->fb;
struct drm_gem_cma_object *cma_obj;
- unsigned long eba = drm_plane_state_to_eba(state);
- int x = state->src_x >> 16;
- int y = state->src_y >> 16;
+ unsigned long eba = drm_plane_state_to_eba(state, 0);
+ int x = state->src.x1 >> 16;
+ int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
BUG_ON(!cma_obj);
@@ -126,11 +143,14 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
ipu_dmfc_put(ipu_plane->dmfc);
if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
ipu_idmac_put(ipu_plane->ipu_ch);
+ if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
+ ipu_idmac_put(ipu_plane->alpha_ch);
}
int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
{
int ret;
+ int alpha_ch;
ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
if (IS_ERR(ipu_plane->ipu_ch)) {
@@ -139,6 +159,17 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
return ret;
}
+ alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
+ if (alpha_ch >= 0) {
+ ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
+ if (IS_ERR(ipu_plane->alpha_ch)) {
+ ret = PTR_ERR(ipu_plane->alpha_ch);
+ DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
+ alpha_ch, ret);
+ return ret;
+ }
+ }
+
ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
if (IS_ERR(ipu_plane->dmfc)) {
ret = PTR_ERR(ipu_plane->dmfc);
@@ -162,33 +193,61 @@ err_out:
return ret;
}
+static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
+{
+ switch (ipu_plane->base.state->fb->format->format) {
+ case DRM_FORMAT_RGB565_A8:
+ case DRM_FORMAT_BGR565_A8:
+ case DRM_FORMAT_RGB888_A8:
+ case DRM_FORMAT_BGR888_A8:
+ case DRM_FORMAT_RGBX8888_A8:
+ case DRM_FORMAT_BGRX8888_A8:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void ipu_plane_enable(struct ipu_plane *ipu_plane)
{
if (ipu_plane->dp)
ipu_dp_enable(ipu_plane->ipu);
ipu_dmfc_enable_channel(ipu_plane->dmfc);
ipu_idmac_enable_channel(ipu_plane->ipu_ch);
+ if (ipu_plane_separate_alpha(ipu_plane))
+ ipu_idmac_enable_channel(ipu_plane->alpha_ch);
if (ipu_plane->dp)
ipu_dp_enable_channel(ipu_plane->dp);
}
-static int ipu_disable_plane(struct drm_plane *plane)
+void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
{
- struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
- if (ipu_plane->dp)
- ipu_dp_disable_channel(ipu_plane->dp);
+ if (ipu_plane->dp && disable_dp_channel)
+ ipu_dp_disable_channel(ipu_plane->dp, false);
ipu_idmac_disable_channel(ipu_plane->ipu_ch);
+ if (ipu_plane->alpha_ch)
+ ipu_idmac_disable_channel(ipu_plane->alpha_ch);
ipu_dmfc_disable_channel(ipu_plane->dmfc);
if (ipu_plane->dp)
ipu_dp_disable(ipu_plane->ipu);
+ if (ipu_prg_present(ipu_plane->ipu))
+ ipu_prg_channel_disable(ipu_plane->ipu_ch);
+}
- return 0;
+void ipu_plane_disable_deferred(struct drm_plane *plane)
+{
+ struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+ if (ipu_plane->disabling) {
+ ipu_plane->disabling = false;
+ ipu_plane_disable(ipu_plane, false);
+ }
}
+EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
static void ipu_plane_destroy(struct drm_plane *plane)
{
@@ -200,13 +259,56 @@ static void ipu_plane_destroy(struct drm_plane *plane)
kfree(ipu_plane);
}
+void ipu_plane_state_reset(struct drm_plane *plane)
+{
+ struct ipu_plane_state *ipu_state;
+
+ if (plane->state) {
+ ipu_state = to_ipu_plane_state(plane->state);
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+ kfree(ipu_state);
+ }
+
+ ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
+
+ if (ipu_state) {
+ ipu_state->base.plane = plane;
+ ipu_state->base.rotation = DRM_ROTATE_0;
+ }
+
+ plane->state = &ipu_state->base;
+}
+
+struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct ipu_plane_state *state;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+
+ return &state->base;
+}
+
+void ipu_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
+
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(ipu_state);
+}
+
static const struct drm_plane_funcs ipu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = ipu_plane_destroy,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .reset = ipu_plane_state_reset,
+ .atomic_duplicate_state = ipu_plane_duplicate_state,
+ .atomic_destroy_state = ipu_plane_destroy_state,
};
static int ipu_plane_atomic_check(struct drm_plane *plane,
@@ -217,8 +319,11 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
struct device *dev = plane->dev->dev;
struct drm_framebuffer *fb = state->fb;
struct drm_framebuffer *old_fb = old_state->fb;
- unsigned long eba, ubo, vbo, old_ubo, old_vbo;
+ unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
+ bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
+ struct drm_rect clip;
int hsub, vsub;
+ int ret;
/* Ok to disable */
if (!fb)
@@ -232,44 +337,35 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
if (WARN_ON(!crtc_state))
return -EINVAL;
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc_state->adjusted_mode.hdisplay;
+ clip.y2 = crtc_state->adjusted_mode.vdisplay;
+ ret = drm_plane_helper_check_state(state, &clip,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ can_position, true);
+ if (ret)
+ return ret;
+
/* CRTC should be enabled */
if (!crtc_state->enable)
return -EINVAL;
- /* no scaling */
- if (state->src_w >> 16 != state->crtc_w ||
- state->src_h >> 16 != state->crtc_h)
- return -EINVAL;
-
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
- /* full plane doesn't support partial off screen */
- if (state->crtc_x || state->crtc_y ||
- state->crtc_w != crtc_state->adjusted_mode.hdisplay ||
- state->crtc_h != crtc_state->adjusted_mode.vdisplay)
- return -EINVAL;
-
/* full plane minimum width is 13 pixels */
- if (state->crtc_w < 13)
+ if (drm_rect_width(&state->dst) < 13)
return -EINVAL;
break;
case DRM_PLANE_TYPE_OVERLAY:
- if (state->crtc_x < 0 || state->crtc_y < 0)
- return -EINVAL;
-
- if (state->crtc_x + state->crtc_w >
- crtc_state->adjusted_mode.hdisplay)
- return -EINVAL;
- if (state->crtc_y + state->crtc_h >
- crtc_state->adjusted_mode.vdisplay)
- return -EINVAL;
break;
default:
- dev_warn(dev, "Unsupported plane type\n");
+ dev_warn(dev, "Unsupported plane type %d\n", plane->type);
return -EINVAL;
}
- if (state->crtc_h < 2)
+ if (drm_rect_height(&state->dst) < 2)
return -EINVAL;
/*
@@ -279,12 +375,13 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
* callback. The planes will be reenabled in plane's ->atomic_update
* callback.
*/
- if (old_fb && (state->src_w != old_state->src_w ||
- state->src_h != old_state->src_h ||
- fb->format != old_fb->format))
+ if (old_fb &&
+ (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
+ drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
+ fb->format != old_fb->format))
crtc_state->mode_changed = true;
- eba = drm_plane_state_to_eba(state);
+ eba = drm_plane_state_to_eba(state, 0);
if (eba & 0x7)
return -EINVAL;
@@ -350,9 +447,26 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
*/
hsub = drm_format_horz_chroma_subsampling(fb->format->format);
vsub = drm_format_vert_chroma_subsampling(fb->format->format);
- if (((state->src_x >> 16) & (hsub - 1)) ||
- ((state->src_y >> 16) & (vsub - 1)))
+ if (((state->src.x1 >> 16) & (hsub - 1)) ||
+ ((state->src.y1 >> 16) & (vsub - 1)))
return -EINVAL;
+ break;
+ case DRM_FORMAT_RGB565_A8:
+ case DRM_FORMAT_BGR565_A8:
+ case DRM_FORMAT_RGB888_A8:
+ case DRM_FORMAT_BGR888_A8:
+ case DRM_FORMAT_RGBX8888_A8:
+ case DRM_FORMAT_BGRX8888_A8:
+ alpha_eba = drm_plane_state_to_eba(state, 1);
+ if (alpha_eba & 0x7)
+ return -EINVAL;
+
+ if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
+ return -EINVAL;
+
+ if (old_fb && old_fb->pitches[1] != fb->pitches[1])
+ crtc_state->mode_changed = true;
+ break;
}
return 0;
@@ -361,7 +475,25 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
static void ipu_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- ipu_disable_plane(plane);
+ struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+ if (ipu_plane->dp)
+ ipu_dp_disable_channel(ipu_plane->dp, true);
+ ipu_plane->disabling = true;
+}
+
+static int ipu_chan_assign_axi_id(int ipu_chan)
+{
+ switch (ipu_chan) {
+ case IPUV3_CHANNEL_MEM_BG_SYNC:
+ return 1;
+ case IPUV3_CHANNEL_MEM_FG_SYNC:
+ return 2;
+ case IPUV3_CHANNEL_MEM_DC_SYNC:
+ return 3;
+ default:
+ return 0;
+ }
}
static void ipu_plane_atomic_update(struct drm_plane *plane,
@@ -369,18 +501,47 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
{
struct ipu_plane *ipu_plane = to_ipu_plane(plane);
struct drm_plane_state *state = plane->state;
+ struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
struct drm_crtc_state *crtc_state = state->crtc->state;
struct drm_framebuffer *fb = state->fb;
+ struct drm_rect *dst = &state->dst;
unsigned long eba, ubo, vbo;
+ unsigned long alpha_eba = 0;
enum ipu_color_space ics;
+ unsigned int axi_id = 0;
int active;
- eba = drm_plane_state_to_eba(state);
+ if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
+ ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
+
+ eba = drm_plane_state_to_eba(state, 0);
+
+ /*
+ * Configure PRG channel and attached PRE, this changes the EBA to an
+ * internal SRAM location.
+ */
+ if (ipu_state->use_pre) {
+ axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
+ ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
+ drm_rect_width(&state->src) >> 16,
+ drm_rect_height(&state->src) >> 16,
+ state->fb->pitches[0],
+ state->fb->format->format, &eba);
+ }
if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
+ /* nothing to do if PRE is used */
+ if (ipu_state->use_pre)
+ return;
active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
+ if (ipu_plane_separate_alpha(ipu_plane)) {
+ active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
+ ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
+ alpha_eba);
+ ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
+ }
return;
}
@@ -395,8 +556,6 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
ics = ipu_drm_fourcc_to_colorspace(state->fb->format->format);
ipu_dp_setup_channel(ipu_plane->dp, ics,
IPUV3_COLORSPACE_UNKNOWN);
- ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x,
- state->crtc_y);
/* Enable local alpha on partial plane */
switch (state->fb->format->format) {
case DRM_FORMAT_ARGB1555:
@@ -408,6 +567,12 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_RGB565_A8:
+ case DRM_FORMAT_BGR565_A8:
+ case DRM_FORMAT_RGB888_A8:
+ case DRM_FORMAT_BGR888_A8:
+ case DRM_FORMAT_RGBX8888_A8:
+ case DRM_FORMAT_BGRX8888_A8:
ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
break;
default:
@@ -416,15 +581,17 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
}
}
- ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w);
+ ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
ipu_cpmem_zero(ipu_plane->ipu_ch);
- ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16,
- state->src_h >> 16);
+ ipu_cpmem_set_resolution(ipu_plane->ipu_ch,
+ drm_rect_width(&state->src) >> 16,
+ drm_rect_height(&state->src) >> 16);
ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->format->format);
ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
+ ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
switch (fb->format->format) {
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
@@ -444,7 +611,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
dev_dbg(ipu_plane->base.dev->dev,
"phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
- state->src_x >> 16, state->src_y >> 16);
+ state->src.x1 >> 16, state->src.y1 >> 16);
break;
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV16:
@@ -455,11 +622,37 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
dev_dbg(ipu_plane->base.dev->dev,
"phy = %lu %lu, x = %d, y = %d", eba, ubo,
- state->src_x >> 16, state->src_y >> 16);
+ state->src.x1 >> 16, state->src.y1 >> 16);
+ break;
+ case DRM_FORMAT_RGB565_A8:
+ case DRM_FORMAT_BGR565_A8:
+ case DRM_FORMAT_RGB888_A8:
+ case DRM_FORMAT_BGR888_A8:
+ case DRM_FORMAT_RGBX8888_A8:
+ case DRM_FORMAT_BGRX8888_A8:
+ alpha_eba = drm_plane_state_to_eba(state, 1);
+
+ dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
+ eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
+
+ ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
+
+ ipu_cpmem_zero(ipu_plane->alpha_ch);
+ ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
+ drm_rect_width(&state->src) >> 16,
+ drm_rect_height(&state->src) >> 16);
+ ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
+ ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
+ ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
+ ipu_cpmem_set_stride(ipu_plane->alpha_ch,
+ state->fb->pitches[1]);
+ ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
+ ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
+ ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
break;
default:
dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
- eba, state->src_x >> 16, state->src_y >> 16);
+ eba, state->src.x1 >> 16, state->src.y1 >> 16);
break;
}
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
@@ -474,6 +667,35 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
.atomic_update = ipu_plane_atomic_update,
};
+int ipu_planes_assign_pre(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *plane_state;
+ struct drm_plane *plane;
+ int available_pres = ipu_prg_max_active_channels();
+ int i;
+
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ struct ipu_plane_state *ipu_state =
+ to_ipu_plane_state(plane_state);
+ struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+ if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
+ plane_state->fb &&
+ ipu_prg_format_supported(ipu_plane->ipu,
+ plane_state->fb->format->format,
+ plane_state->fb->modifier)) {
+ ipu_state->use_pre = true;
+ available_pres--;
+ } else {
+ ipu_state->use_pre = false;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
+
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
int dma, int dp, unsigned int possible_crtcs,
enum drm_plane_type type)
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h
index 338b88a74eb6..596b24ddbf65 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.h
+++ b/drivers/gpu/drm/imx/ipuv3-plane.h
@@ -18,11 +18,14 @@ struct ipu_plane {
struct ipu_soc *ipu;
struct ipuv3_channel *ipu_ch;
+ struct ipuv3_channel *alpha_ch;
struct dmfc_channel *dmfc;
struct ipu_dp *dp;
int dma;
int dp_flow;
+
+ bool disabling;
};
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
@@ -42,4 +45,7 @@ void ipu_plane_put_resources(struct ipu_plane *plane);
int ipu_plane_irq(struct ipu_plane *plane);
+void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
+void ipu_plane_disable_deferred(struct drm_plane *plane);
+
#endif
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index d5c06fd89f90..636031a30e17 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -19,10 +19,10 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <linux/videodev2.h>
#include <video/of_display_timing.h>
-#include <linux/of_graph.h>
#include "imx-drm.h"
@@ -208,7 +208,6 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
- struct device_node *ep;
const u8 *edidp;
struct imx_parallel_display *imxpd;
int ret;
@@ -237,36 +236,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
imxpd->bus_format = bus_format;
/* port@1 is the output port */
- ep = of_graph_get_endpoint_by_regs(np, 1, -1);
- if (ep) {
- struct device_node *remote;
-
- remote = of_graph_get_remote_port_parent(ep);
- if (!remote) {
- dev_warn(dev, "endpoint %s not connected\n",
- ep->full_name);
- of_node_put(ep);
- return -ENODEV;
- }
- of_node_put(ep);
-
- imxpd->panel = of_drm_find_panel(remote);
- if (imxpd->panel) {
- dev_dbg(dev, "found panel %s\n", remote->full_name);
- } else {
- imxpd->bridge = of_drm_find_bridge(remote);
- if (imxpd->bridge)
- dev_dbg(dev, "found bridge %s\n",
- remote->full_name);
- }
- if (!imxpd->panel && !imxpd->bridge) {
- dev_dbg(dev, "waiting for panel or bridge %s\n",
- remote->full_name);
- of_node_put(remote);
- return -EPROBE_DEFER;
- }
- of_node_put(remote);
- }
+ ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge);
+ if (ret)
+ return ret;
imxpd->dev = dev;