In order to integrate with a chain of drm_bridge, the internal SDI
output has to expose its operations through the drm_bridge API.
Register a bridge at initialisation time to do so and remove the
omap_dss_device operations that are now unused.

Signed-off-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
---
 drivers/gpu/drm/omapdrm/dss/sdi.c | 178 +++++++++++++++++++-----------
 1 file changed, 113 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c 
b/drivers/gpu/drm/omapdrm/dss/sdi.c
index 7dedfcc86922..6927b67a9a4b 100644
--- a/drivers/gpu/drm/omapdrm/dss/sdi.c
+++ b/drivers/gpu/drm/omapdrm/dss/sdi.c
@@ -15,6 +15,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/string.h>
 
+#include <drm/drm_bridge.h>
+
 #include "dss.h"
 #include "omapdss.h"
 
@@ -30,9 +32,11 @@ struct sdi_device {
        int datapairs;
 
        struct omap_dss_device output;
+       struct drm_bridge bridge;
 };
 
-#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output)
+#define drm_bridge_to_sdi(bridge) \
+       container_of(bridge, struct sdi_device, bridge)
 
 struct sdi_clk_calc_ctx {
        struct sdi_device *sdi;
@@ -118,9 +122,82 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)
        dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);
 }
 
-static void sdi_display_enable(struct omap_dss_device *dssdev)
+/* 
-----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int sdi_bridge_attach(struct drm_bridge *bridge,
+                            enum drm_bridge_attach_flags flags)
 {
-       struct sdi_device *sdi = dssdev_to_sdi(dssdev);
+       struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+
+       if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+               return -EINVAL;
+
+       return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge,
+                                bridge, flags);
+}
+
+static enum drm_mode_status
+sdi_bridge_mode_valid(struct drm_bridge *bridge,
+                     const struct drm_display_mode *mode)
+{
+       struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+       unsigned long pixelclock = mode->clock * 1000;
+       struct dispc_clock_info dispc_cinfo;
+       unsigned long fck;
+       int ret;
+
+       if (pixelclock == 0)
+               return MODE_NOCLOCK;
+
+       ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
+       if (ret < 0)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static bool sdi_bridge_mode_fixup(struct drm_bridge *bridge,
+                                 const struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+       unsigned long pixelclock = mode->clock * 1000;
+       struct dispc_clock_info dispc_cinfo;
+       unsigned long fck;
+       unsigned long pck;
+       int ret;
+
+       ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
+       if (ret < 0)
+               return false;
+
+       pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
+
+       if (pck != pixelclock)
+               dev_dbg(&sdi->pdev->dev,
+                       "pixel clock adjusted from %lu Hz to %lu Hz\n",
+                       pixelclock, pck);
+
+       adjusted_mode->clock = pck / 1000;
+
+       return true;
+}
+
+static void sdi_bridge_mode_set(struct drm_bridge *bridge,
+                               const struct drm_display_mode *mode,
+                               const struct drm_display_mode *adjusted_mode)
+{
+       struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
+
+       sdi->pixelclock = adjusted_mode->clock * 1000;
+}
+
+static void sdi_bridge_enable(struct drm_bridge *bridge,
+                             struct drm_atomic_state *state)
+{
+       struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
        struct dispc_clock_info dispc_cinfo;
        unsigned long fck;
        int r;
@@ -181,9 +258,10 @@ static void sdi_display_enable(struct omap_dss_device 
*dssdev)
        regulator_disable(sdi->vdds_sdi_reg);
 }
 
-static void sdi_display_disable(struct omap_dss_device *dssdev)
+static void sdi_bridge_disable(struct drm_bridge *bridge,
+                              struct drm_atomic_state *state)
 {
-       struct sdi_device *sdi = dssdev_to_sdi(dssdev);
+       struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
 
        dss_mgr_disable(&sdi->output);
 
@@ -194,71 +272,40 @@ static void sdi_display_disable(struct omap_dss_device 
*dssdev)
        regulator_disable(sdi->vdds_sdi_reg);
 }
 
-static void sdi_set_timings(struct omap_dss_device *dssdev,
-                           const struct drm_display_mode *mode)
-{
-       struct sdi_device *sdi = dssdev_to_sdi(dssdev);
-
-       sdi->pixelclock = mode->clock * 1000;
-}
-
-static int sdi_check_timings(struct omap_dss_device *dssdev,
-                            struct drm_display_mode *mode)
-{
-       struct sdi_device *sdi = dssdev_to_sdi(dssdev);
-       struct dispc_clock_info dispc_cinfo;
-       unsigned long pixelclock = mode->clock * 1000;
-       unsigned long fck;
-       unsigned long pck;
-       int r;
-
-       if (pixelclock == 0)
-               return -EINVAL;
-
-       r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
-       if (r)
-               return r;
-
-       pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
-
-       if (pck != pixelclock) {
-               DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
-                       pixelclock, pck);
-
-               mode->clock = pck / 1000;
-       }
-
-       return 0;
-}
-
-static int sdi_connect(struct omap_dss_device *src,
-                      struct omap_dss_device *dst)
-{
-       return omapdss_device_connect(dst->dss, dst, dst->next);
-}
-
-static void sdi_disconnect(struct omap_dss_device *src,
-                          struct omap_dss_device *dst)
-{
-       omapdss_device_disconnect(dst, dst->next);
-}
-
-static const struct omap_dss_device_ops sdi_ops = {
-       .connect = sdi_connect,
-       .disconnect = sdi_disconnect,
-
-       .enable = sdi_display_enable,
-       .disable = sdi_display_disable,
-
-       .check_timings = sdi_check_timings,
-       .set_timings = sdi_set_timings,
+static const struct drm_bridge_funcs sdi_bridge_funcs = {
+       .attach = sdi_bridge_attach,
+       .mode_valid = sdi_bridge_mode_valid,
+       .mode_fixup = sdi_bridge_mode_fixup,
+       .mode_set = sdi_bridge_mode_set,
+       .atomic_enable = sdi_bridge_enable,
+       .atomic_disable = sdi_bridge_disable,
 };
 
+static void sdi_bridge_init(struct sdi_device *sdi)
+{
+       sdi->bridge.funcs = &sdi_bridge_funcs;
+       sdi->bridge.of_node = sdi->pdev->dev.of_node;
+       sdi->bridge.type = DRM_MODE_CONNECTOR_LVDS;
+
+       drm_bridge_add(&sdi->bridge);
+}
+
+static void sdi_bridge_cleanup(struct sdi_device *sdi)
+{
+       drm_bridge_remove(&sdi->bridge);
+}
+
+/* 
-----------------------------------------------------------------------------
+ * Initialisation and Cleanup
+ */
+
 static int sdi_init_output(struct sdi_device *sdi)
 {
        struct omap_dss_device *out = &sdi->output;
        int r;
 
+       sdi_bridge_init(sdi);
+
        out->dev = &sdi->pdev->dev;
        out->id = OMAP_DSS_OUTPUT_SDI;
        out->type = OMAP_DISPLAY_TYPE_SDI;
@@ -266,12 +313,11 @@ static int sdi_init_output(struct sdi_device *sdi)
        out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
        /* We have SDI only on OMAP3, where it's on port 1 */
        out->of_port = 1;
-       out->ops = &sdi_ops;
        out->owner = THIS_MODULE;
        out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE     /* 15.5.9.1.2 */
                       | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
 
-       r = omapdss_device_init_output(out, NULL);
+       r = omapdss_device_init_output(out, &sdi->bridge);
        if (r < 0)
                return r;
 
@@ -284,6 +330,8 @@ static void sdi_uninit_output(struct sdi_device *sdi)
 {
        omapdss_device_unregister(&sdi->output);
        omapdss_device_cleanup_output(&sdi->output);
+
+       sdi_bridge_cleanup(sdi);
 }
 
 int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to