aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/imx-drm/ipuv3-crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/imx-drm/ipuv3-crtc.c')
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c117
1 files changed, 89 insertions, 28 deletions
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 22be104fbda..720868bff35 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/device.h>
@@ -29,7 +30,7 @@
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
-#include "ipu-v3/imx-ipu-v3.h"
+#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
#include "ipuv3-plane.h"
@@ -59,24 +60,32 @@ struct ipu_crtc {
static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
{
+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
if (ipu_crtc->enabled)
return;
- ipu_di_enable(ipu_crtc->di);
- ipu_dc_enable_channel(ipu_crtc->dc);
+ ipu_dc_enable(ipu);
ipu_plane_enable(ipu_crtc->plane[0]);
+ /* Start DC channel and DI after IDMAC */
+ ipu_dc_enable_channel(ipu_crtc->dc);
+ ipu_di_enable(ipu_crtc->di);
ipu_crtc->enabled = 1;
}
static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
{
+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
if (!ipu_crtc->enabled)
return;
- ipu_plane_disable(ipu_crtc->plane[0]);
+ /* Stop DC channel and DI before IDMAC */
ipu_dc_disable_channel(ipu_crtc->dc);
ipu_di_disable(ipu_crtc->di);
+ ipu_plane_disable(ipu_crtc->plane[0]);
+ ipu_dc_disable(ipu);
ipu_crtc->enabled = 0;
}
@@ -120,7 +129,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
ipu_crtc->newfb = fb;
ipu_crtc->page_flip_event = event;
- crtc->fb = fb;
+ crtc->primary->fb = fb;
return 0;
}
@@ -157,7 +166,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
sig_cfg.Vsync_pol = 1;
sig_cfg.enable_pol = 1;
- sig_cfg.clk_pol = 1;
+ sig_cfg.clk_pol = 0;
sig_cfg.width = mode->hdisplay;
sig_cfg.height = mode->vdisplay;
sig_cfg.pixel_fmt = out_pixel_fmt;
@@ -192,7 +201,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
return ret;
}
- return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
+ return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb,
0, 0, mode->hdisplay, mode->vdisplay,
x, y, mode->hdisplay, mode->vdisplay);
}
@@ -218,7 +227,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
if (ipu_crtc->newfb) {
ipu_crtc->newfb = NULL;
- ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb,
+ ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.primary->fb,
ipu_crtc->plane[0]->x, ipu_crtc->plane[0]->y);
ipu_crtc_handle_pageflip(ipu_crtc);
}
@@ -284,6 +293,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
IPU_DI_CLKMODE_EXT;
break;
+ case DRM_MODE_ENCODER_TMDS:
case DRM_MODE_ENCODER_NONE:
ipu_crtc->di_clkflags = 0;
break;
@@ -334,7 +344,7 @@ err_out:
}
static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
- struct ipu_client_platformdata *pdata)
+ struct ipu_client_platformdata *pdata, struct drm_device *drm)
{
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int dp = -EINVAL;
@@ -348,10 +358,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret;
}
- ret = imx_drm_add_crtc(&ipu_crtc->base,
- &ipu_crtc->imx_crtc,
- &ipu_crtc_helper_funcs, THIS_MODULE,
- ipu_crtc->dev->parent->of_node, pdata->di);
+ ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
+ &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
if (ret) {
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
goto err_put_resources;
@@ -399,43 +407,96 @@ err_put_resources:
return ret;
}
-static int ipu_drm_probe(struct platform_device *pdev)
+static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
+ int port_id)
{
- struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
- struct ipu_crtc *ipu_crtc;
- int ret;
+ struct device_node *port;
+ int id, ret;
+
+ port = of_get_child_by_name(parent, "port");
+ while (port) {
+ ret = of_property_read_u32(port, "reg", &id);
+ if (!ret && id == port_id)
+ return port;
+
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+ }
- if (!pdata)
- return -EINVAL;
+ return NULL;
+}
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- 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;
+ int ret;
- ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+ ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
if (!ipu_crtc)
return -ENOMEM;
- ipu_crtc->dev = &pdev->dev;
+ ipu_crtc->dev = dev;
- ret = ipu_crtc_init(ipu_crtc, pdata);
+ ret = ipu_crtc_init(ipu_crtc, pdata, drm);
if (ret)
return ret;
- platform_set_drvdata(pdev, ipu_crtc);
+ dev_set_drvdata(dev, ipu_crtc);
return 0;
}
-static int ipu_drm_remove(struct platform_device *pdev)
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+ struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
imx_drm_remove_crtc(ipu_crtc->imx_crtc);
ipu_plane_put_resources(ipu_crtc->plane[0]);
ipu_put_resources(ipu_crtc);
+}
+
+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_client_platformdata *pdata = dev->platform_data;
+ int ret;
+
+ if (!dev->platform_data)
+ return -EINVAL;
+
+ if (!dev->of_node) {
+ /* Associate crtc device with the corresponding DI port node */
+ dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
+ pdata->di + 2);
+ if (!dev->of_node) {
+ dev_err(dev, "missing port@%d node in %s\n",
+ pdata->di + 2, dev->parent->of_node->full_name);
+ return -ENODEV;
+ }
+ }
+
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ return component_add(dev, &ipu_crtc_ops);
+}
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ipu_crtc_ops);
return 0;
}