The crtcs are now nodes in the device tree, and the encoder endpoints
fall under the crtc port.

ipu_client_platformdata is no longer needed and is gone. The crtc
retrieves the following required parameters from its node:

- ipu phandle.
- di number.
- the port endpoints.

Optionally, "dual-plane" can be specified to configure the crtc device
with a foreground plane. If not given, the crtc will have only a
single plane.

The DC and IDMAC channels can be inferred from the dual-plane parameter.
In table form, the channel usage is:

                 Background Plane   Foreground Plane     Single Plane
                 ----------------   ----------------     ------------
    Flow Type    IDMAC   DC   DP     IDMAC   DP           IDMAC   DC
    ---------    -----  ---  ---     -----  ---           -----  ---
    Sync          23     5    0       27     1             28     1
    Async         24     6    2       29     3             41     2

Async flows are included in the above table but async displays are
not yet supported by the crtc and plane drivers.

Signed-off-by: Steve Longerbeam <steve_longerbeam at mentor.com>
---
 drivers/staging/imx-drm/imx-drm-core.c |   28 +++--
 drivers/staging/imx-drm/ipuv3-crtc.c   |  204 +++++++++++++++++++++++---------
 2 files changed, 162 insertions(+), 70 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c 
b/drivers/staging/imx-drm/imx-drm-core.c
index 9cb222e..e5ec010 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -591,37 +591,43 @@ static const struct component_master_ops imx_drm_ops = {

 static int imx_drm_platform_probe(struct platform_device *pdev)
 {
-       struct device_node *ep, *port, *remote;
+       struct device_node *ep, *crtc, *port, *remote;
        struct component_match *match = NULL;
        int ret;
        int i;

        /*
-        * Bind the IPU display interface ports first, so that
-        * imx_drm_encoder_parse_of called from encoder .bind callbacks
-        * works as expected.
+        * Bind the crtcs first, so that imx_drm_encoder_parse_of called
+        * from encoder .bind callbacks works as expected.
         */
        for (i = 0; ; i++) {
-               port = of_parse_phandle(pdev->dev.of_node, "ports", i);
-               if (!port)
+               crtc = of_parse_phandle(pdev->dev.of_node, "crtcs", i);
+               if (!crtc)
                        break;

-               component_match_add(&pdev->dev, &match, compare_of, port);
+               component_match_add(&pdev->dev, &match, compare_of, crtc);
        }

        if (i == 0) {
-               dev_err(&pdev->dev, "missing 'ports' property\n");
+               dev_err(&pdev->dev, "missing 'crtcs' property\n");
                return -ENODEV;
        }

        /* Then bind all encoders */
        for (i = 0; ; i++) {
-               port = of_parse_phandle(pdev->dev.of_node, "ports", i);
-               if (!port)
+               crtc = of_parse_phandle(pdev->dev.of_node, "crtcs", i);
+               if (!crtc)
                        break;

+               port = of_get_child_by_name(crtc, "port");
+               if (!port) {
+                       dev_warn(&pdev->dev, "%s has no port\n", crtc->name);
+                       continue;
+               }
+
                for_each_child_of_node(port, ep) {
                        remote = of_graph_get_remote_port_parent(ep);
+
                        if (!remote || !of_device_is_available(remote)) {
                                of_node_put(remote);
                                continue;
@@ -635,7 +641,7 @@ static int imx_drm_platform_probe(struct platform_device 
*pdev)
                        component_match_add(&pdev->dev, &match, compare_of, 
remote);
                        of_node_put(remote);
                }
-               of_node_put(port);
+               of_node_put(crtc);
        }

        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c 
b/drivers/staging/imx-drm/ipuv3-crtc.c
index 8b4440a..5a60017 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -36,10 +36,52 @@

 #define DRIVER_DESC            "i.MX IPUv3 Graphics"

+struct ipu_channels {
+       int dma[2]; /* BG, FG */
+       int dp[2];  /* BG, FG */
+       int dc;
+};
+
+#define NO_DP -1
+
+static const struct ipu_channels sync_dual_plane = {
+       .dma = { IPUV3_CHANNEL_MEM_BG_SYNC, IPUV3_CHANNEL_MEM_FG_SYNC },
+       .dp  = { IPU_DP_FLOW_SYNC_BG, IPU_DP_FLOW_SYNC_FG },
+       .dc  = IPU_DC_CHANNEL_DP_SYNC,
+};
+static const struct ipu_channels sync_single_plane = {
+       .dma = { IPUV3_CHANNEL_MEM_DC_SYNC, },
+       .dp  = { NO_DP, NO_DP },
+       .dc  = IPU_DC_CHANNEL_SYNC,
+};
+
+/*
+ * This driver does not yet support async flows for "smart" displays,
+ * but keep this around for future reference. The crtc nodes could in
+ * future add an "async" property.
+ */
+#if 0
+static const struct ipu_channels async_dual_plane = {
+       .dma = { IPUV3_CHANNEL_MEM_BG_ASYNC, IPUV3_CHANNEL_MEM_FG_ASYNC },
+       .dp  = { IPU_DP_FLOW_ASYNC0_BG, IPU_DP_FLOW_ASYNC0_FG },
+       .dc  = IPU_DC_CHANNEL_DP_ASYNC,
+};
+static const struct ipu_channels async_single_plane = {
+       .dma = { IPUV3_CHANNEL_MEM_DC_ASYNC, },
+       .dp  = { NO_DP, NO_DP },
+       .dc    = IPU_DC_CHANNEL_ASYNC,
+};
+#endif
+
 struct ipu_crtc {
        struct device           *dev;
        struct drm_crtc         base;
        struct imx_drm_crtc     *imx_crtc;
+       struct device           *ipu_dev; /* our ipu */
+       struct ipu_soc          *ipu;
+       struct device_node      *port;    /* our port */
+
+       const struct ipu_channels *ch;

        /* plane[0] is the full plane, plane[1] is the partial plane */
        struct ipu_plane        *plane[2];
@@ -311,32 +353,106 @@ static const struct imx_drm_crtc_helper_funcs 
ipu_crtc_helper_funcs = {
        .crtc_helper_funcs = &ipu_helper_funcs,
 };

+static int of_dev_node_match(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+static int get_ipu(struct ipu_crtc *ipu_crtc, struct device_node *node)
+{
+       struct device_node *ipu_node;
+       struct device *ipu_dev;
+       int ret;
+
+       ipu_node = of_parse_phandle(node, "ipu", 0);
+       if (!ipu_node) {
+               dev_err(ipu_crtc->dev, "missing ipu phandle!\n");
+               return -ENODEV;
+       }
+
+       ipu_dev = bus_find_device(&platform_bus_type, NULL,
+                                 ipu_node, of_dev_node_match);
+       of_node_put(ipu_node);
+
+       if (!ipu_dev) {
+               dev_err(ipu_crtc->dev, "failed to find ipu device!\n");
+               return -ENODEV;
+       }
+
+       device_lock(ipu_dev);
+
+       if (!ipu_dev->driver || !try_module_get(ipu_dev->driver->owner)) {
+               ret = -EPROBE_DEFER;
+               dev_warn(ipu_crtc->dev, "IPU driver not loaded\n");
+               device_unlock(ipu_dev);
+               goto dev_put;
+       }
+
+       ipu_crtc->ipu_dev = ipu_dev;
+       ipu_crtc->ipu = dev_get_drvdata(ipu_dev);
+
+       device_unlock(ipu_dev);
+       return 0;
+dev_put:
+       put_device(ipu_dev);
+       return ret;
+}
+
 static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
 {
        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);
+       if (!IS_ERR_OR_NULL(ipu_crtc->ipu_dev)) {
+               module_put(ipu_crtc->ipu_dev->driver->owner);
+               put_device(ipu_crtc->ipu_dev);
+       }
 }

 static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
-               struct ipu_client_platformdata *pdata)
+                            struct device_node *np)
 {
-       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+       u32 di;
        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;
+       ret = get_ipu(ipu_crtc, np);
+       if (ret) {
+               dev_warn(ipu_crtc->dev, "could not get ipu\n");
+               return ret;
+       }
+
+       /* get our port */
+       ipu_crtc->port = of_get_child_by_name(np, "port");
+       if (!ipu_crtc->port) {
+               dev_err(ipu_crtc->dev, "could not get port\n");
+               return -ENODEV;
        }

-       ipu_crtc->di = ipu_di_get(ipu, pdata->di);
+       ret = of_property_read_u32(np, "di", &di);
+       if (ret < 0)
+               goto err_out;
+
+       ipu_crtc->di = ipu_di_get(ipu_crtc->ipu, di);
        if (IS_ERR(ipu_crtc->di)) {
                ret = PTR_ERR(ipu_crtc->di);
                goto err_out;
        }

+       if (!of_find_property(np, "dual-plane", NULL)) {
+               dev_info(ipu_crtc->dev, "single plane mode\n");
+               ipu_crtc->ch = &sync_single_plane;
+       } else {
+               dev_info(ipu_crtc->dev, "dual plane mode\n");
+               ipu_crtc->ch = &sync_dual_plane;
+       }
+
+       ipu_crtc->dc = ipu_dc_get(ipu_crtc->ipu, ipu_crtc->ch->dc);
+       if (IS_ERR(ipu_crtc->dc)) {
+               ret = PTR_ERR(ipu_crtc->dc);
+               goto err_out;
+       }
+
        return 0;
 err_out:
        ipu_put_resources(ipu_crtc);
@@ -345,14 +461,13 @@ err_out:
 }

 static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
-       struct ipu_client_platformdata *pdata, struct drm_device *drm)
+                        struct drm_device *drm)
 {
-       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
-       int dp = -EINVAL;
+       struct device_node *np = ipu_crtc->dev->of_node;
        int ret;
        int id;

-       ret = ipu_get_resources(ipu_crtc, pdata);
+       ret = ipu_get_resources(ipu_crtc, np);
        if (ret) {
                dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
                                ret);
@@ -360,17 +475,18 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
        }

        ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
-                       &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
+                              &ipu_crtc_helper_funcs, ipu_crtc->port);
        if (ret) {
                dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
                goto err_put_resources;
        }

-       if (pdata->dp >= 0)
-               dp = IPU_DP_FLOW_SYNC_BG;
        id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
-       ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
-                                           pdata->dma[0], dp, BIT(id), true);
+       ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev,
+                                           ipu_crtc->ipu,
+                                           ipu_crtc->ch->dma[0],
+                                           ipu_crtc->ch->dp[0],
+                                           BIT(id), true);
        ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
        if (ret) {
                dev_err(ipu_crtc->dev, "getting plane 0 resources failed with 
%d.\n",
@@ -379,10 +495,11 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
        }

        /* If this crtc is using the DP, add an overlay plane */
-       if (pdata->dp >= 0 && pdata->dma[1] > 0) {
-               ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
-                                                   pdata->dma[1],
-                                                   IPU_DP_FLOW_SYNC_FG,
+       if (ipu_crtc->ch->dp[1] >= 0) {
+               ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev,
+                                                   ipu_crtc->ipu,
+                                                   ipu_crtc->ch->dma[1],
+                                                   ipu_crtc->ch->dp[1],
                                                    BIT(id), false);
                if (IS_ERR(ipu_crtc->plane[1]))
                        ipu_crtc->plane[1] = NULL;
@@ -408,31 +525,8 @@ err_put_resources:
        return ret;
 }

-static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
-                                                 int port_id)
-{
-       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"));
-       }
-
-       return NULL;
-}
-
 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;
@@ -443,7 +537,7 @@ static int ipu_drm_bind(struct device *dev, struct device 
*master, void *data)

        ipu_crtc->dev = dev;

-       ret = ipu_crtc_init(ipu_crtc, pdata, drm);
+       ret = ipu_crtc_init(ipu_crtc, drm);
        if (ret)
                return ret;

@@ -471,23 +565,8 @@ static const struct component_ops ipu_crtc_ops = {
 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;
@@ -501,9 +580,16 @@ static int ipu_drm_remove(struct platform_device *pdev)
        return 0;
 }

+static struct of_device_id ipu_drm_dt_ids[] = {
+       { .compatible = "fsl,imx-ipuv3-crtc" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ipu_drm_dt_ids);
+
 static struct platform_driver ipu_drm_driver = {
        .driver = {
                .name = "imx-ipuv3-crtc",
+               .of_match_table = ipu_drm_dt_ids,
        },
        .probe = ipu_drm_probe,
        .remove = ipu_drm_remove,
-- 
1.7.9.5

Reply via email to