summaryrefslogtreecommitdiffstats
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/Kconfig3
-rw-r--r--drivers/gpu/drm/imx/dw_hdmi-imx.c95
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c109
-rw-r--r--drivers/gpu/drm/imx/imx-tve.c109
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c131
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c69
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.h3
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c93
8 files changed, 280 insertions, 332 deletions
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 6231048aa5aa..b5fa0e45a839 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -28,6 +28,7 @@ config DRM_IMX_TVE
config DRM_IMX_LDB
tristate "Support for LVDS displays"
depends on DRM_IMX && MFD_SYSCON
+ depends on COMMON_CLK
select DRM_PANEL
help
Choose this to enable the internal LVDS Display Bridge (LDB)
@@ -36,7 +37,7 @@ config DRM_IMX_LDB
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
select DRM_DW_HDMI
- depends on DRM_IMX
+ depends on DRM_IMX && OF
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index d07b39b8afd2..87428fb23d9f 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -15,23 +15,32 @@
#include <drm/bridge/dw_hdmi.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h>
#include "imx-drm.h"
+struct imx_hdmi;
+
+struct imx_hdmi_encoder {
+ struct drm_encoder encoder;
+ struct imx_hdmi *hdmi;
+};
+
struct imx_hdmi {
struct device *dev;
- struct drm_encoder encoder;
+ struct drm_bridge *bridge;
struct dw_hdmi *hdmi;
struct regmap *regmap;
};
static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
{
- return container_of(e, struct imx_hdmi, encoder);
+ return container_of(e, struct imx_hdmi_encoder, encoder)->hdmi;
}
static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
@@ -98,19 +107,6 @@ static const struct dw_hdmi_phy_config imx_phy_config[] = {
{ ~0UL, 0x0000, 0x0000, 0x0000}
};
-static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
-{
- struct device_node *np = hdmi->dev->of_node;
-
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap)) {
- dev_err(hdmi->dev, "Unable to get gpr\n");
- return PTR_ERR(hdmi->regmap);
- }
-
- return 0;
-}
-
static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
{
struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder);
@@ -195,65 +191,36 @@ MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
void *data)
{
- struct platform_device *pdev = to_platform_device(dev);
- const struct dw_hdmi_plat_data *plat_data;
- const struct of_device_id *match;
struct drm_device *drm = data;
+ struct imx_hdmi_encoder *hdmi_encoder;
struct drm_encoder *encoder;
- struct imx_hdmi *hdmi;
int ret;
- if (!pdev->dev.of_node)
- return -ENODEV;
+ hdmi_encoder = drmm_simple_encoder_alloc(drm, struct imx_hdmi_encoder,
+ encoder, DRM_MODE_ENCODER_TMDS);
+ if (IS_ERR(hdmi_encoder))
+ return PTR_ERR(hdmi_encoder);
- hdmi = dev_get_drvdata(dev);
- memset(hdmi, 0, sizeof(*hdmi));
-
- match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
- plat_data = match->data;
- hdmi->dev = &pdev->dev;
- encoder = &hdmi->encoder;
+ hdmi_encoder->hdmi = dev_get_drvdata(dev);
+ encoder = &hdmi_encoder->encoder;
ret = imx_drm_encoder_parse_of(drm, encoder, dev->of_node);
if (ret)
return ret;
- ret = dw_hdmi_imx_parse_dt(hdmi);
- if (ret < 0)
- return ret;
-
drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
-
- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
- /*
- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
- * which would have called the encoder cleanup. Do it manually.
- */
- if (IS_ERR(hdmi->hdmi)) {
- ret = PTR_ERR(hdmi->hdmi);
- drm_encoder_cleanup(encoder);
- }
-
- return ret;
-}
-
-static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-
- dw_hdmi_unbind(hdmi->hdmi);
+ return drm_bridge_attach(encoder, hdmi_encoder->hdmi->bridge, NULL, 0);
}
static const struct component_ops dw_hdmi_imx_ops = {
.bind = dw_hdmi_imx_bind,
- .unbind = dw_hdmi_imx_unbind,
};
static int dw_hdmi_imx_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match = of_match_node(dw_hdmi_imx_dt_ids, np);
struct imx_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -261,13 +228,33 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, hdmi);
+ hdmi->dev = &pdev->dev;
+
+ hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(hdmi->regmap)) {
+ dev_err(hdmi->dev, "Unable to get gpr\n");
+ return PTR_ERR(hdmi->regmap);
+ }
+
+ hdmi->hdmi = dw_hdmi_probe(pdev, match->data);
+ if (IS_ERR(hdmi->hdmi))
+ return PTR_ERR(hdmi->hdmi);
+
+ hdmi->bridge = of_drm_find_bridge(np);
+ if (!hdmi->bridge) {
+ dev_err(hdmi->dev, "Unable to find bridge\n");
+ return -ENODEV;
+ }
return component_add(&pdev->dev, &dw_hdmi_imx_ops);
}
static int dw_hdmi_imx_remove(struct platform_device *pdev)
{
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+
component_del(&pdev->dev, &dw_hdmi_imx_ops);
+ dw_hdmi_remove(hdmi->hdmi);
return 0;
}
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 41e2978cb1eb..dbfe39e2f7f6 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -22,6 +22,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
@@ -47,12 +48,18 @@
#define LDB_DI1_VS_POL_ACT_LOW (1 << 10)
#define LDB_BGREF_RMODE_INT (1 << 15)
+struct imx_ldb_channel;
+
+struct imx_ldb_encoder {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+ struct imx_ldb_channel *channel;
+};
+
struct imx_ldb;
struct imx_ldb_channel {
struct imx_ldb *ldb;
- struct drm_connector connector;
- struct drm_encoder encoder;
/* Defines what is connected to the ldb, only one at a time */
struct drm_panel *panel;
@@ -70,12 +77,12 @@ struct imx_ldb_channel {
static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c)
{
- return container_of(c, struct imx_ldb_channel, connector);
+ 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_channel, encoder);
+ return container_of(e, struct imx_ldb_encoder, encoder)->channel;
}
struct bus_mux {
@@ -411,9 +418,20 @@ static int imx_ldb_register(struct drm_device *drm,
struct imx_ldb_channel *imx_ldb_ch)
{
struct imx_ldb *ldb = imx_ldb_ch->ldb;
- struct drm_encoder *encoder = &imx_ldb_ch->encoder;
+ struct imx_ldb_encoder *ldb_encoder;
+ struct drm_connector *connector;
+ struct drm_encoder *encoder;
int ret;
+ ldb_encoder = drmm_simple_encoder_alloc(drm, struct imx_ldb_encoder,
+ encoder, DRM_MODE_ENCODER_LVDS);
+ if (IS_ERR(ldb_encoder))
+ 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);
if (ret)
return ret;
@@ -429,11 +447,9 @@ static int imx_ldb_register(struct drm_device *drm,
}
drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs);
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_LVDS);
if (imx_ldb_ch->bridge) {
- ret = drm_bridge_attach(&imx_ldb_ch->encoder,
- imx_ldb_ch->bridge, NULL, 0);
+ ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL, 0);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return ret;
@@ -445,13 +461,13 @@ static int imx_ldb_register(struct drm_device *drm,
* historical reasons, the ldb driver can also work without
* a panel.
*/
- drm_connector_helper_add(&imx_ldb_ch->connector,
- &imx_ldb_connector_helper_funcs);
- drm_connector_init_with_ddc(drm, &imx_ldb_ch->connector,
+ 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(&imx_ldb_ch->connector, encoder);
+ drm_connector_attach_encoder(connector, encoder);
}
return 0;
@@ -559,17 +575,42 @@ static int imx_ldb_panel_ddc(struct device *dev,
static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
+ struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+ int ret;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct imx_ldb_channel *channel = &imx_ldb->channel[i];
+
+ if (!channel->ldb)
+ break;
+
+ ret = imx_ldb_register(drm, channel);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct component_ops imx_ldb_ops = {
+ .bind = imx_ldb_bind,
+};
+
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- const struct of_device_id *of_id =
- of_match_device(imx_ldb_dt_ids, dev);
+ const struct of_device_id *of_id = of_match_device(imx_ldb_dt_ids, dev);
struct device_node *child;
struct imx_ldb *imx_ldb;
int dual;
int ret;
int i;
- imx_ldb = dev_get_drvdata(dev);
- memset(imx_ldb, 0, sizeof(*imx_ldb));
+ imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
+ if (!imx_ldb)
+ return -ENOMEM;
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(imx_ldb->regmap)) {
@@ -669,25 +710,20 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
}
channel->bus_format = bus_format;
channel->child = child;
-
- ret = imx_ldb_register(drm, channel);
- if (ret) {
- channel->child = NULL;
- goto free_child;
- }
}
- return 0;
+ platform_set_drvdata(pdev, imx_ldb);
+
+ return component_add(&pdev->dev, &imx_ldb_ops);
free_child:
of_node_put(child);
return ret;
}
-static void imx_ldb_unbind(struct device *dev, struct device *master,
- void *data)
+static int imx_ldb_remove(struct platform_device *pdev)
{
- struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+ struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
int i;
for (i = 0; i < 2; i++) {
@@ -696,28 +732,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
kfree(channel->edid);
i2c_put_adapter(channel->ddc);
}
-}
-
-static const struct component_ops imx_ldb_ops = {
- .bind = imx_ldb_bind,
- .unbind = imx_ldb_unbind,
-};
-
-static int imx_ldb_probe(struct platform_device *pdev)
-{
- struct imx_ldb *imx_ldb;
-
- imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
- if (!imx_ldb)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, imx_ldb);
-
- return component_add(&pdev->dev, &imx_ldb_ops);
-}
-static int imx_ldb_remove(struct platform_device *pdev)
-{
component_del(&pdev->dev, &imx_ldb_ops);
return 0;
}
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index 2a8d2e32e7b4..bc8c3f802a15 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -19,6 +19,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -99,9 +100,13 @@ enum {
TVE_MODE_VGA,
};
-struct imx_tve {
+struct imx_tve_encoder {
struct drm_connector connector;
struct drm_encoder encoder;
+ struct imx_tve *tve;
+};
+
+struct imx_tve {
struct device *dev;
int mode;
int di_hsync_pin;
@@ -118,12 +123,12 @@ struct imx_tve {
static inline struct imx_tve *con_to_tve(struct drm_connector *c)
{
- return container_of(c, struct imx_tve, connector);
+ return container_of(c, struct imx_tve_encoder, connector)->tve;
}
static inline struct imx_tve *enc_to_tve(struct drm_encoder *e)
{
- return container_of(e, struct imx_tve, encoder);
+ return container_of(e, struct imx_tve_encoder, encoder)->tve;
}
static void tve_enable(struct imx_tve *tve)
@@ -418,7 +423,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
init.parent_names = (const char **)&tve_di_parent;
tve->clk_hw_di.init = &init;
- tve->di_clk = clk_register(tve->dev, &tve->clk_hw_di);
+ tve->di_clk = devm_clk_register(tve->dev, &tve->clk_hw_di);
if (IS_ERR(tve->di_clk)) {
dev_err(tve->dev, "failed to register TVE output clock: %ld\n",
PTR_ERR(tve->di_clk));
@@ -428,33 +433,6 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
return 0;
}
-static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
-{
- int encoder_type;
- int ret;
-
- encoder_type = tve->mode == TVE_MODE_VGA ?
- DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
-
- ret = imx_drm_encoder_parse_of(drm, &tve->encoder, tve->dev->of_node);
- if (ret)
- return ret;
-
- drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
- drm_simple_encoder_init(drm, &tve->encoder, encoder_type);
-
- drm_connector_helper_add(&tve->connector,
- &imx_tve_connector_helper_funcs);
- drm_connector_init_with_ddc(drm, &tve->connector,
- &imx_tve_connector_funcs,
- DRM_MODE_CONNECTOR_VGA,
- tve->ddc);
-
- drm_connector_attach_encoder(&tve->connector, &tve->encoder);
-
- return 0;
-}
-
static void imx_tve_disable_regulator(void *data)
{
struct imx_tve *tve = data;
@@ -502,8 +480,49 @@ static int of_get_tve_mode(struct device_node *np)
static int imx_tve_bind(struct device *dev, struct device *master, void *data)
{
- struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data;
+ struct imx_tve *tve = dev_get_drvdata(dev);
+ struct imx_tve_encoder *tvee;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ int encoder_type;
+ int ret;
+
+ encoder_type = tve->mode == TVE_MODE_VGA ?
+ DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
+
+ tvee = drmm_simple_encoder_alloc(drm, struct imx_tve_encoder, encoder,
+ encoder_type);
+ if (IS_ERR(tvee))
+ return PTR_ERR(tvee);
+
+ tvee->tve = tve;
+ encoder = &tvee->encoder;
+ connector = &tvee->connector;
+
+ ret = imx_drm_encoder_parse_of(drm, encoder, tve->dev->of_node);
+ if (ret)
+ return ret;
+
+ drm_encoder_helper_add(encoder, &imx_tve_encoder_helper_funcs);
+
+ drm_connector_helper_add(connector, &imx_tve_connector_helper_funcs);
+ ret = drm_connector_init_with_ddc(drm, connector,
+ &imx_tve_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA, tve->ddc);
+ if (ret)
+ return ret;
+
+ return drm_connector_attach_encoder(connector, encoder);
+}
+
+static const struct component_ops imx_tve_ops = {
+ .bind = imx_tve_bind,
+};
+
+static int imx_tve_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_tve *tve;
@@ -513,8 +532,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
int irq;
int ret;
- tve = dev_get_drvdata(dev);
- memset(tve, 0, sizeof(*tve));
+ tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
+ if (!tve)
+ return -ENOMEM;
tve->dev = dev;
@@ -621,28 +641,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
- ret = imx_tve_register(drm, tve);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static const struct component_ops imx_tve_ops = {
- .bind = imx_tve_bind,
-};
-
-static int imx_tve_probe(struct platform_device *pdev)
-{
- struct imx_tve *tve;
-
- tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
- if (!tve)
- return -ENOMEM;
-
platform_set_drvdata(pdev, tve);
- return component_add(&pdev->dev, &imx_tve_ops);
+ return component_add(dev, &imx_tve_ops);
}
static int imx_tve_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 7ebd99ee3240..e6431a227feb 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -20,6 +20,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@@ -163,7 +164,6 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
static const struct drm_crtc_funcs ipu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
- .destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip,
.reset = imx_drm_crtc_reset,
.atomic_duplicate_state = imx_drm_crtc_duplicate_state,
@@ -322,73 +322,73 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
.atomic_enable = ipu_crtc_atomic_enable,
};
-static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
+static void ipu_put_resources(struct drm_device *dev, void *ptr)
{
+ struct ipu_crtc *ipu_crtc = ptr;
+
if (!IS_ERR_OR_NULL(ipu_crtc->dc))
ipu_dc_put(ipu_crtc->dc);
if (!IS_ERR_OR_NULL(ipu_crtc->di))
ipu_di_put(ipu_crtc->di);
}
-static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
- struct ipu_client_platformdata *pdata)
+static int ipu_get_resources(struct drm_device *dev, struct ipu_crtc *ipu_crtc,
+ struct ipu_client_platformdata *pdata)
{
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int ret;
ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
- if (IS_ERR(ipu_crtc->dc)) {
- ret = PTR_ERR(ipu_crtc->dc);
- goto err_out;
- }
+ if (IS_ERR(ipu_crtc->dc))
+ return PTR_ERR(ipu_crtc->dc);
+
+ ret = drmm_add_action_or_reset(dev, ipu_put_resources, ipu_crtc);
+ if (ret)
+ return ret;
ipu_crtc->di = ipu_di_get(ipu, pdata->di);
- if (IS_ERR(ipu_crtc->di)) {
- ret = PTR_ERR(ipu_crtc->di);
- goto err_out;
- }
+ if (IS_ERR(ipu_crtc->di))
+ return PTR_ERR(ipu_crtc->di);
return 0;
-err_out:
- ipu_put_resources(ipu_crtc);
-
- return ret;
}
-static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
- struct ipu_client_platformdata *pdata, struct drm_device *drm)
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
{
- struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
- struct drm_crtc *crtc = &ipu_crtc->base;
+ struct ipu_client_platformdata *pdata = dev->platform_data;
+ struct ipu_soc *ipu = dev_get_drvdata(dev->parent);
+ struct drm_device *drm = data;
+ struct ipu_plane *primary_plane;
+ struct ipu_crtc *ipu_crtc;
+ struct drm_crtc *crtc;
int dp = -EINVAL;
int ret;
- ret = ipu_get_resources(ipu_crtc, pdata);
- if (ret) {
- dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
- ret);
- return ret;
- }
-
if (pdata->dp >= 0)
dp = IPU_DP_FLOW_SYNC_BG;
- ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
- DRM_PLANE_TYPE_PRIMARY);
- if (IS_ERR(ipu_crtc->plane[0])) {
- ret = PTR_ERR(ipu_crtc->plane[0]);
- goto err_put_resources;
- }
+ primary_plane = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
+ DRM_PLANE_TYPE_PRIMARY);
+ if (IS_ERR(primary_plane))
+ return PTR_ERR(primary_plane);
+
+ ipu_crtc = drmm_crtc_alloc_with_planes(drm, struct ipu_crtc, base,
+ &primary_plane->base, NULL,
+ &ipu_crtc_funcs, NULL);
+ if (IS_ERR(ipu_crtc))
+ return PTR_ERR(ipu_crtc);
+ ipu_crtc->dev = dev;
+ ipu_crtc->plane[0] = primary_plane;
+
+ crtc = &ipu_crtc->base;
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]);
+ ret = ipu_get_resources(drm, ipu_crtc, pdata);
if (ret) {
- dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
+ dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
ret);
- goto err_put_resources;
+ return ret;
}
/* If this crtc is using the DP, add an overlay plane */
@@ -397,16 +397,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
IPU_DP_FLOW_SYNC_FG,
drm_crtc_mask(&ipu_crtc->base),
DRM_PLANE_TYPE_OVERLAY);
- if (IS_ERR(ipu_crtc->plane[1])) {
+ if (IS_ERR(ipu_crtc->plane[1]))
ipu_crtc->plane[1] = NULL;
- } else {
- ret = ipu_plane_get_resources(ipu_crtc->plane[1]);
- if (ret) {
- dev_err(ipu_crtc->dev, "getting plane 1 "
- "resources failed with %d.\n", ret);
- goto err_put_plane0_res;
- }
- }
}
ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
@@ -414,58 +406,21 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
"imx_drm", ipu_crtc);
if (ret < 0) {
dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
- goto err_put_plane1_res;
+ return ret;
}
/* Only enable IRQ when we actually need it to trigger work. */
disable_irq(ipu_crtc->irq);
return 0;
-
-err_put_plane1_res:
- if (ipu_crtc->plane[1])
- ipu_plane_put_resources(ipu_crtc->plane[1]);
-err_put_plane0_res:
- ipu_plane_put_resources(ipu_crtc->plane[0]);
-err_put_resources:
- ipu_put_resources(ipu_crtc);
-
- return ret;
-}
-
-static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
-{
- struct ipu_client_platformdata *pdata = dev->platform_data;
- struct drm_device *drm = data;
- struct ipu_crtc *ipu_crtc;
-
- ipu_crtc = dev_get_drvdata(dev);
- memset(ipu_crtc, 0, sizeof(*ipu_crtc));
-
- ipu_crtc->dev = dev;
-
- return ipu_crtc_init(ipu_crtc, pdata, drm);
-}
-
-static void ipu_drm_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
-
- ipu_put_resources(ipu_crtc);
- if (ipu_crtc->plane[1])
- ipu_plane_put_resources(ipu_crtc->plane[1]);
- ipu_plane_put_resources(ipu_crtc->plane[0]);
}
static const struct component_ops ipu_crtc_ops = {
.bind = ipu_drm_bind,
- .unbind = ipu_drm_unbind,
};
static int ipu_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct ipu_crtc *ipu_crtc;
int ret;
if (!dev->platform_data)
@@ -475,12 +430,6 @@ static int ipu_drm_probe(struct platform_device *pdev)
if (ret)
return ret;
- ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
- if (!ipu_crtc)
- return -ENOMEM;
-
- dev_set_drvdata(dev, ipu_crtc);
-
return component_add(dev, &ipu_crtc_ops);
}
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 8a4235d9d9f1..075508051b5f 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -11,6 +11,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_plane_helper.h>
#include <video/imx-ipu-v3.h>
@@ -142,8 +143,10 @@ drm_plane_state_to_vbo(struct drm_plane_state *state)
fb->format->cpp[2] * x - eba;
}
-void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
+static void ipu_plane_put_resources(struct drm_device *dev, void *ptr)
{
+ struct ipu_plane *ipu_plane = ptr;
+
if (!IS_ERR_OR_NULL(ipu_plane->dp))
ipu_dp_put(ipu_plane->dp);
if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
@@ -154,7 +157,8 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
ipu_idmac_put(ipu_plane->alpha_ch);
}
-int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
+static int ipu_plane_get_resources(struct drm_device *dev,
+ struct ipu_plane *ipu_plane)
{
int ret;
int alpha_ch;
@@ -166,6 +170,10 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
return ret;
}
+ ret = drmm_add_action_or_reset(dev, ipu_plane_put_resources, ipu_plane);
+ if (ret)
+ 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);
@@ -181,7 +189,7 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
if (IS_ERR(ipu_plane->dmfc)) {
ret = PTR_ERR(ipu_plane->dmfc);
DRM_ERROR("failed to get dmfc: ret %d\n", ret);
- goto err_out;
+ return ret;
}
if (ipu_plane->dp_flow >= 0) {
@@ -189,15 +197,11 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
if (IS_ERR(ipu_plane->dp)) {
ret = PTR_ERR(ipu_plane->dp);
DRM_ERROR("failed to get dp flow: %d\n", ret);
- goto err_out;
+ return ret;
}
}
return 0;
-err_out:
- ipu_plane_put_resources(ipu_plane);
-
- return ret;
}
static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
@@ -262,16 +266,6 @@ void ipu_plane_disable_deferred(struct drm_plane *plane)
}
EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
-static void ipu_plane_destroy(struct drm_plane *plane)
-{
- struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- drm_plane_cleanup(plane);
- kfree(ipu_plane);
-}
-
static void ipu_plane_state_reset(struct drm_plane *plane)
{
unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
@@ -336,7 +330,6 @@ static bool ipu_plane_format_mod_supported(struct drm_plane *plane,
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 = ipu_plane_state_reset,
.atomic_duplicate_state = ipu_plane_duplicate_state,
.atomic_destroy_state = ipu_plane_destroy_state,
@@ -834,10 +827,15 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
dma, dp, possible_crtcs);
- ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
- if (!ipu_plane) {
- DRM_ERROR("failed to allocate plane\n");
- return ERR_PTR(-ENOMEM);
+ ipu_plane = drmm_universal_plane_alloc(dev, struct ipu_plane, base,
+ possible_crtcs, &ipu_plane_funcs,
+ ipu_plane_formats,
+ ARRAY_SIZE(ipu_plane_formats),
+ modifiers, type, NULL);
+ if (IS_ERR(ipu_plane)) {
+ DRM_ERROR("failed to allocate and initialize %s plane\n",
+ zpos ? "overlay" : "primary");
+ return ipu_plane;
}
ipu_plane->ipu = ipu;
@@ -847,22 +845,23 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
if (ipu_prg_present(ipu))
modifiers = pre_format_modifiers;
- ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
- &ipu_plane_funcs, ipu_plane_formats,
- ARRAY_SIZE(ipu_plane_formats),
- modifiers, type, NULL);
- if (ret) {
- DRM_ERROR("failed to initialize plane\n");
- kfree(ipu_plane);
- return ERR_PTR(ret);
- }
-
drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG)
- drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, 1);
+ ret = drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0,
+ 1);
else
- drm_plane_create_zpos_immutable_property(&ipu_plane->base, 0);
+ ret = drm_plane_create_zpos_immutable_property(&ipu_plane->base,
+ 0);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = ipu_plane_get_resources(dev, ipu_plane);
+ if (ret) {
+ DRM_ERROR("failed to get %s plane resources: %pe\n",
+ zpos ? "overlay" : "primary", &ret);
+ return ERR_PTR(ret);
+ }
return ipu_plane;
}
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h
index ffacbcdd2f98..6d544e6ce63f 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.h
+++ b/drivers/gpu/drm/imx/ipuv3-plane.h
@@ -41,9 +41,6 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
uint32_t src_x, uint32_t src_y, uint32_t src_w,
uint32_t src_h, bool interlaced);
-int ipu_plane_get_resources(struct ipu_plane *plane);
-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);
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 2eb8df4697df..e0412e694fd9 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -15,6 +15,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -22,10 +23,14 @@
#include "imx-drm.h"
-struct imx_parallel_display {
+struct imx_parallel_display_encoder {
struct drm_connector connector;
struct drm_encoder encoder;
struct drm_bridge bridge;
+ struct imx_parallel_display *pd;
+};
+
+struct imx_parallel_display {
struct device *dev;
void *edid;
u32 bus_format;
@@ -37,12 +42,12 @@ struct imx_parallel_display {
static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
{
- return container_of(c, struct imx_parallel_display, connector);
+ return container_of(c, struct imx_parallel_display_encoder, connector)->pd;
}
static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
{
- return container_of(b, struct imx_parallel_display, bridge);
+ return container_of(b, struct imx_parallel_display_encoder, bridge)->pd;
}
static int imx_pd_connector_get_modes(struct drm_connector *connector)
@@ -74,7 +79,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return ret;
drm_mode_copy(mode, &imxpd->mode);
- mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
num_modes++;
}
@@ -253,12 +258,26 @@ static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
.atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
};
-static int imx_pd_register(struct drm_device *drm,
- struct imx_parallel_display *imxpd)
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{
- struct drm_encoder *encoder = &imxpd->encoder;
+ struct drm_device *drm = data;
+ struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
+ struct imx_parallel_display_encoder *imxpd_encoder;
+ struct drm_connector *connector;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
int ret;
+ imxpd_encoder = drmm_simple_encoder_alloc(drm, struct imx_parallel_display_encoder,
+ encoder, DRM_MODE_ENCODER_NONE);
+ if (IS_ERR(imxpd_encoder))
+ return PTR_ERR(imxpd_encoder);
+
+ imxpd_encoder->pd = imxpd;
+ connector = &imxpd_encoder->connector;
+ encoder = &imxpd_encoder->encoder;
+ bridge = &imxpd_encoder->bridge;
+
ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
if (ret)
return ret;
@@ -268,39 +287,37 @@ static int imx_pd_register(struct drm_device *drm,
* immediately since the current state is ON
* at this point.
*/
- imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
-
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
-
- imxpd->bridge.funcs = &imx_pd_bridge_funcs;
- drm_bridge_attach(encoder, &imxpd->bridge, NULL, 0);
+ connector->dpms = DRM_MODE_DPMS_OFF;
- if (!imxpd->next_bridge) {
- drm_connector_helper_add(&imxpd->connector,
- &imx_pd_connector_helper_funcs);
- drm_connector_init(drm, &imxpd->connector,
- &imx_pd_connector_funcs,
- DRM_MODE_CONNECTOR_DPI);
- }
+ bridge->funcs = &imx_pd_bridge_funcs;
+ drm_bridge_attach(encoder, bridge, NULL, 0);
if (imxpd->next_bridge) {
- ret = drm_bridge_attach(encoder, imxpd->next_bridge,
- &imxpd->bridge, 0);
+ ret = drm_bridge_attach(encoder, imxpd->next_bridge, bridge, 0);
if (ret < 0) {
dev_err(imxpd->dev, "failed to attach bridge: %d\n",
ret);
return ret;
}
} else {
- drm_connector_attach_encoder(&imxpd->connector, encoder);
+ drm_connector_helper_add(connector,
+ &imx_pd_connector_helper_funcs);
+ drm_connector_init(drm, connector, &imx_pd_connector_funcs,
+ DRM_MODE_CONNECTOR_DPI);
+
+ drm_connector_attach_encoder(connector, encoder);
}
return 0;
}
-static int imx_pd_bind(struct device *dev, struct device *master, void *data)
+static const struct component_ops imx_pd_ops = {
+ .bind = imx_pd_bind,
+};
+
+static int imx_pd_probe(struct platform_device *pdev)
{
- struct drm_device *drm = data;
+ struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const u8 *edidp;
struct imx_parallel_display *imxpd;
@@ -309,8 +326,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
u32 bus_format = 0;
const char *fmt;
- imxpd = dev_get_drvdata(dev);
- memset(imxpd, 0, sizeof(*imxpd));
+ imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
+ if (!imxpd)
+ return -ENOMEM;
/* port@1 is the output port */
ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
@@ -337,28 +355,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
imxpd->dev = dev;
- ret = imx_pd_register(drm, imxpd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static const struct component_ops imx_pd_ops = {
- .bind = imx_pd_bind,
-};
-
-static int imx_pd_probe(struct platform_device *pdev)
-{
- struct imx_parallel_display *imxpd;
-
- imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
- if (!imxpd)
- return -ENOMEM;
-
platform_set_drvdata(pdev, imxpd);
- return component_add(&pdev->dev, &imx_pd_ops);
+ return component_add(dev, &imx_pd_ops);
}
static int imx_pd_remove(struct platform_device *pdev)