OMAPDSS: Merge omapdss topic branches
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Mon, 15 Apr 2013 08:57:18 +0000 (11:57 +0300)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Mon, 15 Apr 2013 09:01:02 +0000 (12:01 +0300)
26 files changed:
drivers/gpu/drm/omapdrm/omap_connector.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_encoder.c
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
drivers/gpu/drm/omapdrm/omap_irq.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/dss/apply.c
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.h
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/output.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-main.c
include/video/omapdss.h

index c451c41a7a7d2f5b2333dc2217a2adc2db061ecc..912759daf5625a88bb878f96a15f1ad39bd4c2a2 100644 (file)
@@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect(
                        ret = connector_status_connected;
                else
                        ret = connector_status_disconnected;
+       } else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI ||
+                       dssdev->type == OMAP_DISPLAY_TYPE_DBI ||
+                       dssdev->type == OMAP_DISPLAY_TYPE_SDI ||
+                       dssdev->type == OMAP_DISPLAY_TYPE_DSI) {
+               ret = connector_status_connected;
        } else {
                ret = connector_status_unknown;
        }
@@ -189,12 +194,30 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
        struct omap_video_timings timings = {0};
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *new_mode;
-       int ret = MODE_BAD;
+       int r, ret = MODE_BAD;
 
        copy_timings_drm_to_omap(&timings, mode);
        mode->vrefresh = drm_mode_vrefresh(mode);
 
-       if (!dssdrv->check_timings(dssdev, &timings)) {
+       /*
+        * if the panel driver doesn't have a check_timings, it's most likely
+        * a fixed resolution panel, check if the timings match with the
+        * panel's timings
+        */
+       if (dssdrv->check_timings) {
+               r = dssdrv->check_timings(dssdev, &timings);
+       } else {
+               struct omap_video_timings t = {0};
+
+               dssdrv->get_timings(dssdev, &t);
+
+               if (memcmp(&timings, &t, sizeof(struct omap_video_timings)))
+                       r = -EINVAL;
+               else
+                       r = 0;
+       }
+
+       if (!r) {
                /* check if vrefresh is still valid */
                new_mode = drm_mode_duplicate(dev, mode);
                new_mode->clock = timings.pixel_clock;
index bec66a490b8f7ded93ff3f766c562a8a76967f2e..79b200aee18a50e4b82277a0e2b3e380ab8cf280 100644 (file)
@@ -74,6 +74,13 @@ struct omap_crtc {
        struct work_struct page_flip_work;
 };
 
+uint32_t pipe2vbl(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+
+       return dispc_mgr_get_vsync_irq(omap_crtc->channel);
+}
+
 /*
  * Manager-ops, callbacks from output when they need to configure
  * the upstream part of the video pipe.
@@ -613,7 +620,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        omap_crtc->apply.pre_apply  = omap_crtc_pre_apply;
        omap_crtc->apply.post_apply = omap_crtc_post_apply;
 
-       omap_crtc->apply_irq.irqmask = pipe2vbl(id);
+       omap_crtc->channel = channel;
+       omap_crtc->plane = plane;
+       omap_crtc->plane->crtc = crtc;
+       omap_crtc->name = channel_names[channel];
+       omap_crtc->pipe = id;
+
+       omap_crtc->apply_irq.irqmask = pipe2vbl(crtc);
        omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
 
        omap_crtc->error_irq.irqmask =
@@ -621,12 +634,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        omap_crtc->error_irq.irq = omap_crtc_error_irq;
        omap_irq_register(dev, &omap_crtc->error_irq);
 
-       omap_crtc->channel = channel;
-       omap_crtc->plane = plane;
-       omap_crtc->plane->crtc = crtc;
-       omap_crtc->name = channel_names[channel];
-       omap_crtc->pipe = id;
-
        /* temporary: */
        omap_crtc->mgr.id = channel;
 
index 079c54c6f94c974c966a32524cbd95210ed2572f..9c53c25e5201763a4673734d5ce32d72043f5a35 100644 (file)
@@ -74,54 +74,53 @@ static int get_connector_type(struct omap_dss_device *dssdev)
        }
 }
 
+static bool channel_used(struct drm_device *dev, enum omap_channel channel)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < priv->num_crtcs; i++) {
+               struct drm_crtc *crtc = priv->crtcs[i];
+
+               if (omap_crtc_channel(crtc) == channel)
+                       return true;
+       }
+
+       return false;
+}
+
 static int omap_modeset_init(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
        struct omap_dss_device *dssdev = NULL;
        int num_ovls = dss_feat_get_num_ovls();
-       int id;
+       int num_mgrs = dss_feat_get_num_mgrs();
+       int num_crtcs;
+       int i, id = 0;
 
        drm_mode_config_init(dev);
 
        omap_drm_irq_install(dev);
 
        /*
-        * Create private planes and CRTCs for the last NUM_CRTCs overlay
-        * plus manager:
+        * We usually don't want to create a CRTC for each manager, at least
+        * not until we have a way to expose private planes to userspace.
+        * Otherwise there would not be enough video pipes left for drm planes.
+        * We use the num_crtc argument to limit the number of crtcs we create.
         */
-       for (id = 0; id < min(num_crtc, num_ovls); id++) {
-               struct drm_plane *plane;
-               struct drm_crtc *crtc;
-
-               plane = omap_plane_init(dev, id, true);
-               crtc = omap_crtc_init(dev, plane, pipe2chan(id), id);
+       num_crtcs = min3(num_crtc, num_mgrs, num_ovls);
 
-               BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
-               priv->crtcs[id] = crtc;
-               priv->num_crtcs++;
-
-               priv->planes[id] = plane;
-               priv->num_planes++;
-       }
-
-       /*
-        * Create normal planes for the remaining overlays:
-        */
-       for (; id < num_ovls; id++) {
-               struct drm_plane *plane = omap_plane_init(dev, id, false);
-
-               BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
-               priv->planes[priv->num_planes++] = plane;
-       }
+       dssdev = NULL;
 
        for_each_dss_dev(dssdev) {
                struct drm_connector *connector;
                struct drm_encoder *encoder;
+               enum omap_channel channel;
 
                if (!dssdev->driver) {
                        dev_warn(dev->dev, "%s has no driver.. skipping it\n",
                                        dssdev->name);
-                       return 0;
+                       continue;
                }
 
                if (!(dssdev->driver->get_timings ||
@@ -129,7 +128,7 @@ static int omap_modeset_init(struct drm_device *dev)
                        dev_warn(dev->dev, "%s driver does not support "
                                "get_timings or read_edid.. skipping it!\n",
                                dssdev->name);
-                       return 0;
+                       continue;
                }
 
                encoder = omap_encoder_init(dev, dssdev);
@@ -157,16 +156,118 @@ static int omap_modeset_init(struct drm_device *dev)
 
                drm_mode_connector_attach_encoder(connector, encoder);
 
+               /*
+                * if we have reached the limit of the crtcs we are allowed to
+                * create, let's not try to look for a crtc for this
+                * panel/encoder and onwards, we will, of course, populate the
+                * the possible_crtcs field for all the encoders with the final
+                * set of crtcs we create
+                */
+               if (id == num_crtcs)
+                       continue;
+
+               /*
+                * get the recommended DISPC channel for this encoder. For now,
+                * we only try to get create a crtc out of the recommended, the
+                * other possible channels to which the encoder can connect are
+                * not considered.
+                */
+               channel = dssdev->output->dispc_channel;
+
+               /*
+                * if this channel hasn't already been taken by a previously
+                * allocated crtc, we create a new crtc for it
+                */
+               if (!channel_used(dev, channel)) {
+                       struct drm_plane *plane;
+                       struct drm_crtc *crtc;
+
+                       plane = omap_plane_init(dev, id, true);
+                       crtc = omap_crtc_init(dev, plane, channel, id);
+
+                       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
+                       priv->crtcs[id] = crtc;
+                       priv->num_crtcs++;
+
+                       priv->planes[id] = plane;
+                       priv->num_planes++;
+
+                       id++;
+               }
+       }
+
+       /*
+        * we have allocated crtcs according to the need of the panels/encoders,
+        * adding more crtcs here if needed
+        */
+       for (; id < num_crtcs; id++) {
+
+               /* find a free manager for this crtc */
+               for (i = 0; i < num_mgrs; i++) {
+                       if (!channel_used(dev, i)) {
+                               struct drm_plane *plane;
+                               struct drm_crtc *crtc;
+
+                               plane = omap_plane_init(dev, id, true);
+                               crtc = omap_crtc_init(dev, plane, i, id);
+
+                               BUG_ON(priv->num_crtcs >=
+                                       ARRAY_SIZE(priv->crtcs));
+
+                               priv->crtcs[id] = crtc;
+                               priv->num_crtcs++;
+
+                               priv->planes[id] = plane;
+                               priv->num_planes++;
+
+                               break;
+                       } else {
+                               continue;
+                       }
+               }
+
+               if (i == num_mgrs) {
+                       /* this shouldn't really happen */
+                       dev_err(dev->dev, "no managers left for crtc\n");
+                       return -ENOMEM;
+               }
+       }
+
+       /*
+        * Create normal planes for the remaining overlays:
+        */
+       for (; id < num_ovls; id++) {
+               struct drm_plane *plane = omap_plane_init(dev, id, false);
+
+               BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
+               priv->planes[priv->num_planes++] = plane;
+       }
+
+       for (i = 0; i < priv->num_encoders; i++) {
+               struct drm_encoder *encoder = priv->encoders[i];
+               struct omap_dss_device *dssdev =
+                                       omap_encoder_get_dssdev(encoder);
+
                /* figure out which crtc's we can connect the encoder to: */
                encoder->possible_crtcs = 0;
                for (id = 0; id < priv->num_crtcs; id++) {
-                       enum omap_dss_output_id supported_outputs =
-                                       dss_feat_get_supported_outputs(pipe2chan(id));
+                       struct drm_crtc *crtc = priv->crtcs[id];
+                       enum omap_channel crtc_channel;
+                       enum omap_dss_output_id supported_outputs;
+
+                       crtc_channel = omap_crtc_channel(crtc);
+                       supported_outputs =
+                               dss_feat_get_supported_outputs(crtc_channel);
+
                        if (supported_outputs & dssdev->output->id)
                                encoder->possible_crtcs |= (1 << id);
                }
        }
 
+       DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
+               priv->num_planes, priv->num_crtcs, priv->num_encoders,
+               priv->num_connectors);
+
        dev->mode_config.min_width = 32;
        dev->mode_config.min_height = 32;
 
@@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
        return ret;
 }
 
-struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = {
+static struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = {
        DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH),
        DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH),
@@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = {
 };
 #endif
 
-struct platform_driver pdev = {
+static struct platform_driver pdev = {
                .driver = {
                        .name = DRIVER_NAME,
                        .owner = THIS_MODULE,
index d4f997bb4ac0eaab02f6419d4c832246959bbb45..215a20dd340cc8984ddffad32b0c7c42010d06c1 100644 (file)
@@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
 int omap_gem_resume(struct device *dev);
 #endif
 
-int omap_irq_enable_vblank(struct drm_device *dev, int crtc);
-void omap_irq_disable_vblank(struct drm_device *dev, int crtc);
+int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id);
+void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id);
 irqreturn_t omap_irq_handler(DRM_IRQ_ARGS);
 void omap_irq_preinstall(struct drm_device *dev);
 int omap_irq_postinstall(struct drm_device *dev);
@@ -271,39 +271,9 @@ static inline int align_pitch(int pitch, int width, int bpp)
        return ALIGN(pitch, 8 * bytespp);
 }
 
-static inline enum omap_channel pipe2chan(int pipe)
-{
-       int num_mgrs = dss_feat_get_num_mgrs();
-
-       /*
-        * We usually don't want to create a CRTC for each manager,
-        * at least not until we have a way to expose private planes
-        * to userspace.  Otherwise there would not be enough video
-        * pipes left for drm planes.  The higher #'d managers tend
-        * to have more features so start in reverse order.
-        */
-       return num_mgrs - pipe - 1;
-}
-
 /* map crtc to vblank mask */
-static inline uint32_t pipe2vbl(int crtc)
-{
-       enum omap_channel channel = pipe2chan(crtc);
-       return dispc_mgr_get_vsync_irq(channel);
-}
-
-static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc)
-{
-       struct omap_drm_private *priv = dev->dev_private;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++)
-               if (priv->crtcs[i] == crtc)
-                       return i;
-
-       BUG();  /* bogus CRTC ptr */
-       return -1;
-}
+uint32_t pipe2vbl(struct drm_crtc *crtc);
+struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);
 
 /* should these be made into common util helpers?
  */
index 21d126d0317ebc31ad5b28938ac1ef0452e6bbe1..c29451ba65daeeb06c068c013c926e4652a5432f 100644 (file)
@@ -41,6 +41,13 @@ struct omap_encoder {
        struct omap_dss_device *dssdev;
 };
 
+struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
+{
+       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
+
+       return omap_encoder->dssdev;
+}
+
 static void omap_encoder_destroy(struct drm_encoder *encoder)
 {
        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
@@ -128,13 +135,26 @@ int omap_encoder_update(struct drm_encoder *encoder,
 
        dssdev->output->manager = mgr;
 
-       ret = dssdrv->check_timings(dssdev, timings);
+       if (dssdrv->check_timings) {
+               ret = dssdrv->check_timings(dssdev, timings);
+       } else {
+               struct omap_video_timings t = {0};
+
+               dssdrv->get_timings(dssdev, &t);
+
+               if (memcmp(timings, &t, sizeof(struct omap_video_timings)))
+                       ret = -EINVAL;
+               else
+                       ret = 0;
+       }
+
        if (ret) {
                dev_err(dev->dev, "could not set timings: %d\n", ret);
                return ret;
        }
 
-       dssdrv->set_timings(dssdev, timings);
+       if (dssdrv->set_timings)
+               dssdrv->set_timings(dssdev, timings);
 
        return 0;
 }
index ac74d1bc67bfc885e740e6adc809a0bd5c8d2b1d..0682cb5c01506576b71fe942bbb2127a3427e45c 100644 (file)
@@ -178,7 +178,7 @@ out_unlock:
        return omap_gem_mmap_obj(obj, vma);
 }
 
-struct dma_buf_ops omap_dmabuf_ops = {
+static struct dma_buf_ops omap_dmabuf_ops = {
                .map_dma_buf = omap_gem_map_dma_buf,
                .unmap_dma_buf = omap_gem_unmap_dma_buf,
                .release = omap_gem_dmabuf_release,
index e01303ee00c3b9d64ac48b4e5a956450f4920435..9263db117ff8ae937dbf743ac0e8a267264d95a4 100644 (file)
@@ -130,12 +130,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
  * Zero on success, appropriate errno if the given @crtc's vblank
  * interrupt cannot be enabled.
  */
-int omap_irq_enable_vblank(struct drm_device *dev, int crtc)
+int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id)
 {
        struct omap_drm_private *priv = dev->dev_private;
+       struct drm_crtc *crtc = priv->crtcs[crtc_id];
        unsigned long flags;
 
-       DBG("dev=%p, crtc=%d", dev, crtc);
+       DBG("dev=%p, crtc=%d", dev, crtc_id);
 
        dispc_runtime_get();
        spin_lock_irqsave(&list_lock, flags);
@@ -156,12 +157,13 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc)
  * a hardware vblank counter, this routine should be a no-op, since
  * interrupts will have to stay on to keep the count accurate.
  */
-void omap_irq_disable_vblank(struct drm_device *dev, int crtc)
+void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id)
 {
        struct omap_drm_private *priv = dev->dev_private;
+       struct drm_crtc *crtc = priv->crtcs[crtc_id];
        unsigned long flags;
 
-       DBG("dev=%p, crtc=%d", dev, crtc);
+       DBG("dev=%p, crtc=%d", dev, crtc_id);
 
        dispc_runtime_get();
        spin_lock_irqsave(&list_lock, flags);
@@ -186,9 +188,12 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS)
 
        VERB("irqs: %08x", irqstatus);
 
-       for (id = 0; id < priv->num_crtcs; id++)
-               if (irqstatus & pipe2vbl(id))
+       for (id = 0; id < priv->num_crtcs; id++) {
+               struct drm_crtc *crtc = priv->crtcs[id];
+
+               if (irqstatus & pipe2vbl(crtc))
                        drm_handle_vblank(dev, id);
+       }
 
        spin_lock_irqsave(&list_lock, flags);
        list_for_each_entry_safe(handler, n, &priv->irq_list, node) {
index 2882cda6ea19de38039f498a9a7fa31e488d92c7..8d225d7ff4e300319211fd8ec80eeccfb4e8fdc2 100644 (file)
@@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane,
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        omap_plane->enabled = true;
+
+       if (plane->fb)
+               drm_framebuffer_unreference(plane->fb);
+
+       drm_framebuffer_reference(fb);
+
        return omap_plane_mode_set(plane, crtc, fb,
                        crtc_x, crtc_y, crtc_w, crtc_h,
                        src_x, src_y, src_w, src_h,
index 1e0097de3a23e4eca170e1ae4de592d2b1dd15c1..20c3cd91ff9b2cae8a432b293a614711e310fcf6 100644 (file)
@@ -242,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+
+static int nec_8048_spi_suspend(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
+
        nec_8048_spi_send(spi, 2, 0x01);
        mdelay(40);
 
        return 0;
 }
 
-static int nec_8048_spi_resume(struct spi_device *spi)
+static int nec_8048_spi_resume(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
+
        /* reinitialize the panel */
        spi_setup(spi);
        nec_8048_spi_send(spi, 2, 0x00);
@@ -260,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(nec_8048_spi_pm_ops, nec_8048_spi_suspend,
+               nec_8048_spi_resume);
+#define NEC_8048_SPI_PM_OPS (&nec_8048_spi_pm_ops)
+#else
+#define NEC_8048_SPI_PM_OPS NULL
+#endif
+
 static struct spi_driver nec_8048_spi_driver = {
        .probe          = nec_8048_spi_probe,
        .remove         = nec_8048_spi_remove,
-       .suspend        = nec_8048_spi_suspend,
-       .resume         = nec_8048_spi_resume,
        .driver         = {
                .name   = "nec_8048_spi",
                .owner  = THIS_MODULE,
+               .pm     = NEC_8048_SPI_PM_OPS,
        },
 };
 
index 031d4069f332914274374d939db2443ef749aa51..c4f78bda115a405702bb76e719605be3fc553a1e 100644 (file)
@@ -54,61 +54,6 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 static int taal_panel_reset(struct omap_dss_device *dssdev);
 
-/**
- * struct panel_config - panel configuration
- * @name: panel name
- * @type: panel type
- * @timings: panel resolution
- * @sleep: various panel specific delays, passed to msleep() if non-zero
- * @reset_sequence: reset sequence timings, passed to udelay() if non-zero
- * @regulators: array of panel regulators
- * @num_regulators: number of regulators in the array
- */
-struct panel_config {
-       const char *name;
-       int type;
-
-       struct omap_video_timings timings;
-
-       struct {
-               unsigned int sleep_in;
-               unsigned int sleep_out;
-               unsigned int hw_reset;
-               unsigned int enable_te;
-       } sleep;
-
-       struct {
-               unsigned int high;
-               unsigned int low;
-       } reset_sequence;
-
-};
-
-enum {
-       PANEL_TAAL,
-};
-
-static struct panel_config panel_configs[] = {
-       {
-               .name           = "taal",
-               .type           = PANEL_TAAL,
-               .timings        = {
-                       .x_res          = 864,
-                       .y_res          = 480,
-               },
-               .sleep          = {
-                       .sleep_in       = 5,
-                       .sleep_out      = 5,
-                       .hw_reset       = 5,
-                       .enable_te      = 100, /* possible panel bug */
-               },
-               .reset_sequence = {
-                       .high           = 10,
-                       .low            = 10,
-               },
-       },
-};
-
 struct taal_data {
        struct mutex lock;
 
@@ -121,9 +66,6 @@ struct taal_data {
 
        struct omap_dss_device *dssdev;
 
-       /* panel specific HW info */
-       struct panel_config *panel_config;
-
        /* panel HW configuration from DT or platform data */
        int reset_gpio;
        int ext_te_gpio;
@@ -134,8 +76,6 @@ struct taal_data {
 
        /* runtime variables */
        bool enabled;
-       u8 rotate;
-       bool mirror;
 
        bool te_enabled;
 
@@ -221,8 +161,7 @@ static int taal_sleep_in(struct taal_data *td)
 
        hw_guard_start(td, 120);
 
-       if (td->panel_config->sleep.sleep_in)
-               msleep(td->panel_config->sleep.sleep_in);
+       msleep(5);
 
        return 0;
 }
@@ -239,8 +178,7 @@ static int taal_sleep_out(struct taal_data *td)
 
        hw_guard_start(td, 120);
 
-       if (td->panel_config->sleep.sleep_out)
-               msleep(td->panel_config->sleep.sleep_out);
+       msleep(5);
 
        return 0;
 }
@@ -262,49 +200,6 @@ static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3)
        return 0;
 }
 
-static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror)
-{
-       int r;
-       u8 mode;
-       int b5, b6, b7;
-
-       r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode);
-       if (r)
-               return r;
-
-       switch (rotate) {
-       default:
-       case 0:
-               b7 = 0;
-               b6 = 0;
-               b5 = 0;
-               break;
-       case 1:
-               b7 = 0;
-               b6 = 1;
-               b5 = 1;
-               break;
-       case 2:
-               b7 = 1;
-               b6 = 1;
-               b5 = 0;
-               break;
-       case 3:
-               b7 = 1;
-               b6 = 0;
-               b5 = 1;
-               break;
-       }
-
-       if (mirror)
-               b6 = !b6;
-
-       mode &= ~((1<<7) | (1<<6) | (1<<5));
-       mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
-
-       return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode);
-}
-
 static int taal_set_update_window(struct taal_data *td,
                u16 x, u16 y, u16 w, u16 h)
 {
@@ -515,15 +410,8 @@ static const struct backlight_ops taal_bl_ops = {
 static void taal_get_resolution(struct omap_dss_device *dssdev,
                u16 *xres, u16 *yres)
 {
-       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-
-       if (td->rotate == 0 || td->rotate == 2) {
-               *xres = dssdev->panel.timings.x_res;
-               *yres = dssdev->panel.timings.y_res;
-       } else {
-               *yres = dssdev->panel.timings.x_res;
-               *xres = dssdev->panel.timings.y_res;
-       }
+       *xres = dssdev->panel.timings.x_res;
+       *yres = dssdev->panel.timings.y_res;
 }
 
 static ssize_t taal_num_errors_show(struct device *dev,
@@ -845,17 +733,14 @@ static void taal_hw_reset(struct omap_dss_device *dssdev)
                return;
 
        gpio_set_value(td->reset_gpio, 1);
-       if (td->panel_config->reset_sequence.high)
-               udelay(td->panel_config->reset_sequence.high);
+       udelay(10);
        /* reset the panel */
        gpio_set_value(td->reset_gpio, 0);
        /* assert reset */
-       if (td->panel_config->reset_sequence.low)
-               udelay(td->panel_config->reset_sequence.low);
+       udelay(10);
        gpio_set_value(td->reset_gpio, 1);
        /* wait after releasing reset */
-       if (td->panel_config->sleep.hw_reset)
-               msleep(td->panel_config->sleep.hw_reset);
+       msleep(5);
 }
 
 static void taal_probe_pdata(struct taal_data *td,
@@ -881,8 +766,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
        struct backlight_properties props;
        struct taal_data *td;
        struct backlight_device *bldev = NULL;
-       int r, i;
-       const char *panel_name;
+       int r;
 
        dev_dbg(&dssdev->dev, "probe\n");
 
@@ -897,26 +781,13 @@ static int taal_probe(struct omap_dss_device *dssdev)
                const struct nokia_dsi_panel_data *pdata = dssdev->data;
 
                taal_probe_pdata(td, pdata);
-
-               panel_name = pdata->name;
        } else {
                return -ENODEV;
        }
 
-       if (panel_name == NULL)
-               return -EINVAL;
-
-       for (i = 0; i < ARRAY_SIZE(panel_configs); i++) {
-               if (strcmp(panel_name, panel_configs[i].name) == 0) {
-                       td->panel_config = &panel_configs[i];
-                       break;
-               }
-       }
-
-       if (!td->panel_config)
-               return -EINVAL;
-
-       dssdev->panel.timings = td->panel_config->timings;
+       dssdev->panel.timings.x_res = 864;
+       dssdev->panel.timings.y_res = 480;
+       dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000);
        dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
        dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
                OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
@@ -1049,6 +920,15 @@ static int taal_power_on(struct omap_dss_device *dssdev)
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        u8 id1, id2, id3;
        int r;
+       struct omap_dss_dsi_config dsi_config = {
+               .mode = OMAP_DSS_DSI_CMD_MODE,
+               .pixel_format = OMAP_DSS_DSI_FMT_RGB888,
+               .timings = &dssdev->panel.timings,
+               .hs_clk_min = 150000000,
+               .hs_clk_max = 300000000,
+               .lp_clk_min = 7000000,
+               .lp_clk_max = 10000000,
+       };
 
        r = omapdss_dsi_configure_pins(dssdev, &td->pin_config);
        if (r) {
@@ -1056,14 +936,9 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                goto err0;
        };
 
-       omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res,
-               dssdev->panel.timings.y_res);
-       omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888);
-       omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE);
-
-       r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000);
+       r = omapdss_dsi_set_config(dssdev, &dsi_config);
        if (r) {
-               dev_err(&dssdev->dev, "failed to set HS and LP clocks\n");
+               dev_err(&dssdev->dev, "failed to configure DSI\n");
                goto err0;
        }
 
@@ -1086,8 +961,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                goto err;
 
        /* on early Taal revisions CABC is broken */
-       if (td->panel_config->type == PANEL_TAAL &&
-               (id2 == 0x00 || id2 == 0xff || id2 == 0x81))
+       if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
                td->cabc_broken = true;
 
        r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff);
@@ -1104,10 +978,6 @@ static int taal_power_on(struct omap_dss_device *dssdev)
        if (r)
                goto err;
 
-       r = taal_set_addr_mode(td, td->rotate, td->mirror);
-       if (r)
-               goto err;
-
        if (!td->cabc_broken) {
                r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode);
                if (r)
@@ -1129,8 +999,8 @@ static int taal_power_on(struct omap_dss_device *dssdev)
        td->enabled = 1;
 
        if (!td->intro_printed) {
-               dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n",
-                       td->panel_config->name, id1, id2, id3);
+               dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n",
+                       id1, id2, id3);
                if (td->cabc_broken)
                        dev_info(&dssdev->dev,
                                        "old Taal version, CABC disabled\n");
@@ -1311,8 +1181,8 @@ static int taal_update(struct omap_dss_device *dssdev,
 
        /* XXX no need to send this every frame, but dsi break if not done */
        r = taal_set_update_window(td, 0, 0,
-                       td->panel_config->timings.x_res,
-                       td->panel_config->timings.y_res);
+                       dssdev->panel.timings.x_res,
+                       dssdev->panel.timings.y_res);
        if (r)
                goto err;
 
@@ -1365,8 +1235,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
        if (!gpio_is_valid(td->ext_te_gpio))
                omapdss_dsi_enable_te(dssdev, enable);
 
-       if (td->panel_config->sleep.enable_te)
-               msleep(td->panel_config->sleep.enable_te);
+       /* possible panel bug */
+       msleep(100);
 
        return r;
 }
@@ -1419,112 +1289,6 @@ static int taal_get_te(struct omap_dss_device *dssdev)
        return r;
 }
 
-static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
-{
-       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       u16 dw, dh;
-       int r;
-
-       dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
-
-       mutex_lock(&td->lock);
-
-       if (td->rotate == rotate)
-               goto end;
-
-       dsi_bus_lock(dssdev);
-
-       if (td->enabled) {
-               r = taal_wake_up(dssdev);
-               if (r)
-                       goto err;
-
-               r = taal_set_addr_mode(td, rotate, td->mirror);
-               if (r)
-                       goto err;
-       }
-
-       if (rotate == 0 || rotate == 2) {
-               dw = dssdev->panel.timings.x_res;
-               dh = dssdev->panel.timings.y_res;
-       } else {
-               dw = dssdev->panel.timings.y_res;
-               dh = dssdev->panel.timings.x_res;
-       }
-
-       omapdss_dsi_set_size(dssdev, dw, dh);
-
-       td->rotate = rotate;
-
-       dsi_bus_unlock(dssdev);
-end:
-       mutex_unlock(&td->lock);
-       return 0;
-err:
-       dsi_bus_unlock(dssdev);
-       mutex_unlock(&td->lock);
-       return r;
-}
-
-static u8 taal_get_rotate(struct omap_dss_device *dssdev)
-{
-       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       int r;
-
-       mutex_lock(&td->lock);
-       r = td->rotate;
-       mutex_unlock(&td->lock);
-
-       return r;
-}
-
-static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
-{
-       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       int r;
-
-       dev_dbg(&dssdev->dev, "mirror %d\n", enable);
-
-       mutex_lock(&td->lock);
-
-       if (td->mirror == enable)
-               goto end;
-
-       dsi_bus_lock(dssdev);
-       if (td->enabled) {
-               r = taal_wake_up(dssdev);
-               if (r)
-                       goto err;
-
-               r = taal_set_addr_mode(td, td->rotate, enable);
-               if (r)
-                       goto err;
-       }
-
-       td->mirror = enable;
-
-       dsi_bus_unlock(dssdev);
-end:
-       mutex_unlock(&td->lock);
-       return 0;
-err:
-       dsi_bus_unlock(dssdev);
-       mutex_unlock(&td->lock);
-       return r;
-}
-
-static bool taal_get_mirror(struct omap_dss_device *dssdev)
-{
-       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       int r;
-
-       mutex_lock(&td->lock);
-       r = td->mirror;
-       mutex_unlock(&td->lock);
-
-       return r;
-}
-
 static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
@@ -1758,10 +1522,6 @@ static struct omap_dss_driver taal_driver = {
        .enable_te      = taal_enable_te,
        .get_te         = taal_get_te,
 
-       .set_rotate     = taal_rotate,
-       .get_rotate     = taal_get_rotate,
-       .set_mirror     = taal_mirror,
-       .get_mirror     = taal_get_mirror,
        .run_test       = taal_run_test,
        .memory_read    = taal_memory_read,
 
index d446bdfc4c821fc4a26caf401716cc843cef370a..a4b356a9780d305f37673743f40eb5cbe61942a9 100644 (file)
@@ -435,20 +435,27 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man
 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
 {
        unsigned long timeout = msecs_to_jiffies(500);
-       struct omap_dss_device *dssdev = mgr->get_device(mgr);
        u32 irq;
        int r;
 
+       if (mgr->output == NULL)
+               return -ENODEV;
+
        r = dispc_runtime_get();
        if (r)
                return r;
 
-       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
+       switch (mgr->output->id) {
+       case OMAP_DSS_OUTPUT_VENC:
                irq = DISPC_IRQ_EVSYNC_ODD;
-       else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
+               break;
+       case OMAP_DSS_OUTPUT_HDMI:
                irq = DISPC_IRQ_EVSYNC_EVEN;
-       else
+               break;
+       default:
                irq = dispc_mgr_get_vsync_irq(mgr->id);
+               break;
+       }
 
        r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
 
index f8779d4750ba63f98908492f2b11b9bfe7cf4ea8..60cc6fee654815444c21d46909351f0e15af6b10 100644 (file)
@@ -181,10 +181,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
        d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
                        write, &dss_debug_fops);
 
-       if (IS_ERR(d))
-               return PTR_ERR(d);
-
-       return 0;
+       return PTR_RET(d);
 }
 #else /* CONFIG_OMAP2_DSS_DEBUGFS */
 static inline int dss_initialize_debugfs(void)
index 05ff2b91d9e8a49ee1e11c3c957b634eb4698393..b33b0169bb3b3f85f5722c52d8568cf0ad62ab4e 100644 (file)
@@ -69,6 +69,8 @@ struct dispc_features {
        u8 mgr_height_start;
        u16 mgr_width_max;
        u16 mgr_height_max;
+       unsigned long max_lcd_pclk;
+       unsigned long max_tv_pclk;
        int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
                const struct omap_video_timings *mgr_timings,
                u16 width, u16 height, u16 out_width, u16 out_height,
@@ -85,6 +87,9 @@ struct dispc_features {
 
        /* no DISPC_IRQ_FRAMEDONETV on this SoC */
        bool no_framedone_tv:1;
+
+       /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
+       bool mstandby_workaround:1;
 };
 
 #define DISPC_MAX_NR_FIFOS 5
@@ -97,6 +102,8 @@ static struct {
 
        int irq;
 
+       unsigned long core_clk_rate;
+
        u32 fifo_size[DISPC_MAX_NR_FIFOS];
        /* maps which plane is using a fifo. fifo-id -> plane-id */
        int fifo_assignment[DISPC_MAX_NR_FIFOS];
@@ -1584,6 +1591,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane,
 }
 
 static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
+               enum omap_dss_rotation_type rotation_type,
                bool mirroring, enum omap_color_mode color_mode)
 {
        bool row_repeat = false;
@@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
        if (dss_has_feature(FEAT_ROWREPEATENABLE))
                REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
                        row_repeat ? 1 : 0, 18, 18);
+
+       if (color_mode == OMAP_DSS_COLOR_NV12) {
+               bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
+                                       (rotation == OMAP_DSS_ROT_0 ||
+                                       rotation == OMAP_DSS_ROT_180);
+               /* DOUBLESTRIDE */
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
+       }
+
 }
 
 static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -2512,7 +2529,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
                dispc_ovl_set_vid_color_conv(plane, cconv);
        }
 
-       dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode);
+       dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
+                       color_mode);
 
        dispc_ovl_set_zorder(plane, caps, zorder);
        dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
@@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
        return true;
 }
 
+static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
+               unsigned long pclk)
+{
+       if (dss_mgr_is_lcd(channel))
+               return pclk <= dispc.feat->max_lcd_pclk ? true : false;
+       else
+               return pclk <= dispc.feat->max_tv_pclk ? true : false;
+}
+
 bool dispc_mgr_timings_ok(enum omap_channel channel,
                const struct omap_video_timings *timings)
 {
@@ -2830,11 +2857,13 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
 
        timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
 
-       if (dss_mgr_is_lcd(channel))
-               timings_ok =  timings_ok && _dispc_lcd_timings_ok(timings->hsw,
-                                               timings->hfp, timings->hbp,
-                                               timings->vsw, timings->vfp,
-                                               timings->vbp);
+       timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixel_clock * 1000);
+
+       if (dss_mgr_is_lcd(channel)) {
+               timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
+                               timings->hbp, timings->vsw, timings->vfp,
+                               timings->vbp);
+       }
 
        return timings_ok;
 }
@@ -2951,6 +2980,10 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
 
        dispc_write_reg(DISPC_DIVISORo(channel),
                        FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
+
+       if (dss_has_feature(FEAT_CORE_CLK_DIV) == false &&
+                       channel == OMAP_DSS_CHANNEL_LCD)
+               dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
 }
 
 static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
@@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
 
 unsigned long dispc_core_clk_rate(void)
 {
-       int lcd;
-       unsigned long fclk = dispc_fclk_rate();
-
-       if (dss_has_feature(FEAT_CORE_CLK_DIV))
-               lcd = REG_GET(DISPC_DIVISOR, 23, 16);
-       else
-               lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16);
-
-       return fclk / lcd;
+       return dispc.core_clk_rate;
 }
 
 static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
@@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s)
 #undef DUMPREG
 }
 
-/* with fck as input clock rate, find dispc dividers that produce req_pck */
-void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
+/* calculate clock rates using dividers in cinfo */
+int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
                struct dispc_clock_info *cinfo)
 {
-       u16 pcd_min, pcd_max;
-       unsigned long best_pck;
-       u16 best_ld, cur_ld;
-       u16 best_pd, cur_pd;
+       if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
+               return -EINVAL;
+       if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
+               return -EINVAL;
 
-       pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
-       pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
+       cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
+       cinfo->pck = cinfo->lck / cinfo->pck_div;
 
-       best_pck = 0;
-       best_ld = 0;
-       best_pd = 0;
+       return 0;
+}
 
-       for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
-               unsigned long lck = fck / cur_ld;
+bool dispc_div_calc(unsigned long dispc,
+               unsigned long pck_min, unsigned long pck_max,
+               dispc_div_calc_func func, void *data)
+{
+       int lckd, lckd_start, lckd_stop;
+       int pckd, pckd_start, pckd_stop;
+       unsigned long pck, lck;
+       unsigned long lck_max;
+       unsigned long pckd_hw_min, pckd_hw_max;
+       unsigned min_fck_per_pck;
+       unsigned long fck;
 
-               for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) {
-                       unsigned long pck = lck / cur_pd;
-                       long old_delta = abs(best_pck - req_pck);
-                       long new_delta = abs(pck - req_pck);
+#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
+       min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
+#else
+       min_fck_per_pck = 0;
+#endif
 
-                       if (best_pck == 0 || new_delta < old_delta) {
-                               best_pck = pck;
-                               best_ld = cur_ld;
-                               best_pd = cur_pd;
+       pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
+       pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
 
-                               if (pck == req_pck)
-                                       goto found;
-                       }
+       lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
-                       if (pck < req_pck)
-                               break;
-               }
+       pck_min = pck_min ? pck_min : 1;
+       pck_max = pck_max ? pck_max : ULONG_MAX;
 
-               if (lck / pcd_min < req_pck)
-                       break;
-       }
+       lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
+       lckd_stop = min(dispc / pck_min, 255ul);
 
-found:
-       cinfo->lck_div = best_ld;
-       cinfo->pck_div = best_pd;
-       cinfo->lck = fck / cinfo->lck_div;
-       cinfo->pck = cinfo->lck / cinfo->pck_div;
-}
+       for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
+               lck = dispc / lckd;
 
-/* calculate clock rates using dividers in cinfo */
-int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
-               struct dispc_clock_info *cinfo)
-{
-       if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
-               return -EINVAL;
-       if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
-               return -EINVAL;
+               pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
+               pckd_stop = min(lck / pck_min, pckd_hw_max);
 
-       cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
-       cinfo->pck = cinfo->lck / cinfo->pck_div;
+               for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
+                       pck = lck / pckd;
 
-       return 0;
+                       /*
+                        * For OMAP2/3 the DISPC fclk is the same as LCD's logic
+                        * clock, which means we're configuring DISPC fclk here
+                        * also. Thus we need to use the calculated lck. For
+                        * OMAP4+ the DISPC fclk is a separate clock.
+                        */
+                       if (dss_has_feature(FEAT_CORE_CLK_DIV))
+                               fck = dispc_core_clk_rate();
+                       else
+                               fck = lck;
+
+                       if (fck < pck * min_fck_per_pck)
+                               continue;
+
+                       if (func(lckd, pckd, lck, pck, data))
+                               return true;
+               }
+       }
+
+       return false;
 }
 
 void dispc_mgr_set_clock_div(enum omap_channel channel,
@@ -3451,6 +3488,8 @@ static void _omap_dispc_initial_config(void)
                l = FLD_MOD(l, 1, 0, 0);
                l = FLD_MOD(l, 1, 23, 16);
                dispc_write_reg(DISPC_DIVISOR, l);
+
+               dispc.core_clk_rate = dispc_fclk_rate();
        }
 
        /* FUNCGATED */
@@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void)
        dispc_configure_burst_sizes();
 
        dispc_ovl_enable_zorder_planes();
+
+       if (dispc.feat->mstandby_workaround)
+               REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
 }
 
 static const struct dispc_features omap24xx_dispc_feats __initconst = {
@@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = {
        .mgr_height_start       =       26,
        .mgr_width_max          =       2048,
        .mgr_height_max         =       2048,
+       .max_lcd_pclk           =       66500000,
        .calc_scaling           =       dispc_ovl_calc_scaling_24xx,
        .calc_core_clk          =       calc_core_clk_24xx,
        .num_fifos              =       3,
@@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
        .mgr_height_start       =       26,
        .mgr_width_max          =       2048,
        .mgr_height_max         =       2048,
+       .max_lcd_pclk           =       173000000,
+       .max_tv_pclk            =       59000000,
        .calc_scaling           =       dispc_ovl_calc_scaling_34xx,
        .calc_core_clk          =       calc_core_clk_34xx,
        .num_fifos              =       3,
@@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
        .mgr_height_start       =       26,
        .mgr_width_max          =       2048,
        .mgr_height_max         =       2048,
+       .max_lcd_pclk           =       173000000,
+       .max_tv_pclk            =       59000000,
        .calc_scaling           =       dispc_ovl_calc_scaling_34xx,
        .calc_core_clk          =       calc_core_clk_34xx,
        .num_fifos              =       3,
@@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = {
        .mgr_height_start       =       26,
        .mgr_width_max          =       2048,
        .mgr_height_max         =       2048,
+       .max_lcd_pclk           =       170000000,
+       .max_tv_pclk            =       185625000,
        .calc_scaling           =       dispc_ovl_calc_scaling_44xx,
        .calc_core_clk          =       calc_core_clk_44xx,
        .num_fifos              =       5,
@@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = {
        .mgr_height_start       =       27,
        .mgr_width_max          =       4096,
        .mgr_height_max         =       4096,
+       .max_lcd_pclk           =       170000000,
+       .max_tv_pclk            =       186000000,
        .calc_scaling           =       dispc_ovl_calc_scaling_44xx,
        .calc_core_clk          =       calc_core_clk_44xx,
        .num_fifos              =       5,
        .gfx_fifo_workaround    =       true,
+       .mstandby_workaround    =       true,
 };
 
 static int __init dispc_init_features(struct platform_device *pdev)
index 222363c6e623f794402f68b98d419f5fc0d1f869..de4863d21ab78b7683d490628ef9bc5a7f1f335b 100644 (file)
@@ -39,6 +39,7 @@
 #define DISPC_GLOBAL_BUFFER            0x0800
 #define DISPC_CONTROL3                  0x0848
 #define DISPC_CONFIG3                   0x084C
+#define DISPC_MSTANDBY_CTRL            0x0858
 
 /* DISPC overlay registers */
 #define DISPC_OVL_BA0(n)               (DISPC_OVL_BASE(n) + \
index 4af136a04e53ce4fafc67a3435a0121062e53674..e93c4debea7fc46297a973bac7a3a7149ea5ef76 100644 (file)
@@ -63,15 +63,29 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
        case OMAPDSS_VER_OMAP3630:
        case OMAPDSS_VER_AM35xx:
                return NULL;
-       default:
-               break;
-       }
 
-       switch (channel) {
-       case OMAP_DSS_CHANNEL_LCD:
-               return dsi_get_dsidev_from_id(0);
-       case OMAP_DSS_CHANNEL_LCD2:
-               return dsi_get_dsidev_from_id(1);
+       case OMAPDSS_VER_OMAP4430_ES1:
+       case OMAPDSS_VER_OMAP4430_ES2:
+       case OMAPDSS_VER_OMAP4:
+               switch (channel) {
+               case OMAP_DSS_CHANNEL_LCD:
+                       return dsi_get_dsidev_from_id(0);
+               case OMAP_DSS_CHANNEL_LCD2:
+                       return dsi_get_dsidev_from_id(1);
+               default:
+                       return NULL;
+               }
+
+       case OMAPDSS_VER_OMAP5:
+               switch (channel) {
+               case OMAP_DSS_CHANNEL_LCD:
+                       return dsi_get_dsidev_from_id(0);
+               case OMAP_DSS_CHANNEL_LCD3:
+                       return dsi_get_dsidev_from_id(1);
+               default:
+                       return NULL;
+               }
+
        default:
                return NULL;
        }
@@ -91,75 +105,211 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
        }
 }
 
-static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
+struct dpi_clk_calc_ctx {
+       struct platform_device *dsidev;
+
+       /* inputs */
+
+       unsigned long pck_min, pck_max;
+
+       /* outputs */
+
+       struct dsi_clock_info dsi_cinfo;
+       struct dss_clock_info dss_cinfo;
+       struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+               unsigned long pck, void *data)
+{
+       struct dpi_clk_calc_ctx *ctx = data;
+
+       /*
+        * Odd dividers give us uneven duty cycle, causing problem when level
+        * shifted. So skip all odd dividers when the pixel clock is on the
+        * higher side.
+        */
+       if (ctx->pck_min >= 1000000) {
+               if (lckd > 1 && lckd % 2 != 0)
+                       return false;
+
+               if (pckd > 1 && pckd % 2 != 0)
+                       return false;
+       }
+
+       ctx->dispc_cinfo.lck_div = lckd;
+       ctx->dispc_cinfo.pck_div = pckd;
+       ctx->dispc_cinfo.lck = lck;
+       ctx->dispc_cinfo.pck = pck;
+
+       return true;
+}
+
+
+static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+               void *data)
+{
+       struct dpi_clk_calc_ctx *ctx = data;
+
+       /*
+        * Odd dividers give us uneven duty cycle, causing problem when level
+        * shifted. So skip all odd dividers when the pixel clock is on the
+        * higher side.
+        */
+       if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000)
+               return false;
+
+       ctx->dsi_cinfo.regm_dispc = regm_dispc;
+       ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+       return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
+                       dpi_calc_dispc_cb, ctx);
+}
+
+
+static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
+               unsigned long pll,
+               void *data)
+{
+       struct dpi_clk_calc_ctx *ctx = data;
+
+       ctx->dsi_cinfo.regn = regn;
+       ctx->dsi_cinfo.regm = regm;
+       ctx->dsi_cinfo.fint = fint;
+       ctx->dsi_cinfo.clkin4ddr = pll;
+
+       return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
+                       dpi_calc_hsdiv_cb, ctx);
+}
+
+static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
+{
+       struct dpi_clk_calc_ctx *ctx = data;
+
+       ctx->dss_cinfo.fck = fck;
+       ctx->dss_cinfo.fck_div = fckd;
+
+       return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+                       dpi_calc_dispc_cb, ctx);
+}
+
+static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+       unsigned long clkin;
+       unsigned long pll_min, pll_max;
+
+       clkin = dsi_get_pll_clkin(dpi.dsidev);
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->dsidev = dpi.dsidev;
+       ctx->pck_min = pck - 1000;
+       ctx->pck_max = pck + 1000;
+       ctx->dsi_cinfo.clkin = clkin;
+
+       pll_min = 0;
+       pll_max = 0;
+
+       return dsi_pll_calc(dpi.dsidev, clkin,
+                       pll_min, pll_max,
+                       dpi_calc_pll_cb, ctx);
+}
+
+static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+       int i;
+
+       /*
+        * DSS fck gives us very few possibilities, so finding a good pixel
+        * clock may not be possible. We try multiple times to find the clock,
+        * each time widening the pixel clock range we look for, up to
+        * +/- ~15MHz.
+        */
+
+       for (i = 0; i < 25; ++i) {
+               bool ok;
+
+               memset(ctx, 0, sizeof(*ctx));
+               if (pck > 1000 * i * i * i)
+                       ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
+               else
+                       ctx->pck_min = 0;
+               ctx->pck_max = pck + 1000 * i * i * i;
+
+               ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx);
+               if (ok)
+                       return ok;
+       }
+
+       return false;
+}
+
+
+
+static int dpi_set_dsi_clk(enum omap_channel channel,
                unsigned long pck_req, unsigned long *fck, int *lck_div,
                int *pck_div)
 {
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
-       struct dsi_clock_info dsi_cinfo;
-       struct dispc_clock_info dispc_cinfo;
+       struct dpi_clk_calc_ctx ctx;
        int r;
+       bool ok;
 
-       r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
-                       &dispc_cinfo);
-       if (r)
-               return r;
+       ok = dpi_dsi_clk_calc(pck_req, &ctx);
+       if (!ok)
+               return -EINVAL;
 
-       r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
+       r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
        if (r)
                return r;
 
-       dss_select_lcd_clk_source(mgr->id,
-                       dpi_get_alt_clk_src(mgr->id));
+       dss_select_lcd_clk_source(channel,
+                       dpi_get_alt_clk_src(channel));
 
-       dpi.mgr_config.clock_info = dispc_cinfo;
+       dpi.mgr_config.clock_info = ctx.dispc_cinfo;
 
-       *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
-       *lck_div = dispc_cinfo.lck_div;
-       *pck_div = dispc_cinfo.pck_div;
+       *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+       *lck_div = ctx.dispc_cinfo.lck_div;
+       *pck_div = ctx.dispc_cinfo.pck_div;
 
        return 0;
 }
 
-static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
-               unsigned long pck_req, unsigned long *fck, int *lck_div,
-               int *pck_div)
+static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
+               int *lck_div, int *pck_div)
 {
-       struct dss_clock_info dss_cinfo;
-       struct dispc_clock_info dispc_cinfo;
+       struct dpi_clk_calc_ctx ctx;
        int r;
+       bool ok;
 
-       r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
-       if (r)
-               return r;
+       ok = dpi_dss_clk_calc(pck_req, &ctx);
+       if (!ok)
+               return -EINVAL;
 
-       r = dss_set_clock_div(&dss_cinfo);
+       r = dss_set_clock_div(&ctx.dss_cinfo);
        if (r)
                return r;
 
-       dpi.mgr_config.clock_info = dispc_cinfo;
+       dpi.mgr_config.clock_info = ctx.dispc_cinfo;
 
-       *fck = dss_cinfo.fck;
-       *lck_div = dispc_cinfo.lck_div;
-       *pck_div = dispc_cinfo.pck_div;
+       *fck = ctx.dss_cinfo.fck;
+       *lck_div = ctx.dispc_cinfo.lck_div;
+       *pck_div = ctx.dispc_cinfo.pck_div;
 
        return 0;
 }
 
-static int dpi_set_mode(struct omap_dss_device *dssdev)
+static int dpi_set_mode(struct omap_overlay_manager *mgr)
 {
        struct omap_video_timings *t = &dpi.timings;
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
        int lck_div = 0, pck_div = 0;
        unsigned long fck = 0;
        unsigned long pck;
        int r = 0;
 
        if (dpi.dsidev)
-               r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
+               r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck,
                                &lck_div, &pck_div);
        else
-               r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck,
+               r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck,
                                &lck_div, &pck_div);
        if (r)
                return r;
@@ -179,10 +329,8 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
+static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
 {
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
-
        dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 
        dpi.mgr_config.stallmode = false;
@@ -197,7 +345,7 @@ static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 {
-       struct omap_dss_output *out = dssdev->output;
+       struct omap_dss_output *out = &dpi.output;
        int r;
 
        mutex_lock(&dpi.lock);
@@ -230,7 +378,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err_get_dispc;
 
-       r = dss_dpi_select_source(dssdev->channel);
+       r = dss_dpi_select_source(out->manager->id);
        if (r)
                goto err_src_sel;
 
@@ -244,11 +392,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
                        goto err_dsi_pll_init;
        }
 
-       r = dpi_set_mode(dssdev);
+       r = dpi_set_mode(out->manager);
        if (r)
                goto err_set_mode;
 
-       dpi_config_lcd_manager(dssdev);
+       dpi_config_lcd_manager(out->manager);
 
        mdelay(2);
 
@@ -285,7 +433,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable);
 
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 {
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
+       struct omap_overlay_manager *mgr = dpi.output.manager;
 
        mutex_lock(&dpi.lock);
 
@@ -324,12 +472,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings);
 int dpi_check_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
-       int r;
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
+       struct omap_overlay_manager *mgr = dpi.output.manager;
        int lck_div, pck_div;
        unsigned long fck;
        unsigned long pck;
-       struct dispc_clock_info dispc_cinfo;
+       struct dpi_clk_calc_ctx ctx;
+       bool ok;
 
        if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
                return -EINVAL;
@@ -338,28 +486,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
                return -EINVAL;
 
        if (dpi.dsidev) {
-               struct dsi_clock_info dsi_cinfo;
-               r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
-                               timings->pixel_clock * 1000,
-                               &dsi_cinfo, &dispc_cinfo);
-
-               if (r)
-                       return r;
+               ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx);
+               if (!ok)
+                       return -EINVAL;
 
-               fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+               fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
        } else {
-               struct dss_clock_info dss_cinfo;
-               r = dss_calc_clock_div(timings->pixel_clock * 1000,
-                               &dss_cinfo, &dispc_cinfo);
+               ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx);
+               if (!ok)
+                       return -EINVAL;
 
-               if (r)
-                       return r;
-
-               fck = dss_cinfo.fck;
+               fck = ctx.dss_cinfo.fck;
        }
 
-       lck_div = dispc_cinfo.lck_div;
-       pck_div = dispc_cinfo.pck_div;
+       lck_div = ctx.dispc_cinfo.lck_div;
+       pck_div = ctx.dispc_cinfo.pck_div;
 
        pck = fck / lck_div / pck_div / 1000;
 
@@ -401,6 +542,36 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
        return 0;
 }
 
+/*
+ * Return a hardcoded channel for the DPI output. This should work for
+ * current use cases, but this can be later expanded to either resolve
+ * the channel in some more dynamic manner, or get the channel as a user
+ * parameter.
+ */
+static enum omap_channel dpi_get_channel(void)
+{
+       switch (omapdss_get_version()) {
+       case OMAPDSS_VER_OMAP24xx:
+       case OMAPDSS_VER_OMAP34xx_ES1:
+       case OMAPDSS_VER_OMAP34xx_ES3:
+       case OMAPDSS_VER_OMAP3630:
+       case OMAPDSS_VER_AM35xx:
+               return OMAP_DSS_CHANNEL_LCD;
+
+       case OMAPDSS_VER_OMAP4430_ES1:
+       case OMAPDSS_VER_OMAP4430_ES2:
+       case OMAPDSS_VER_OMAP4:
+               return OMAP_DSS_CHANNEL_LCD2;
+
+       case OMAPDSS_VER_OMAP5:
+               return OMAP_DSS_CHANNEL_LCD3;
+
+       default:
+               DSSWARN("unsupported DSS version\n");
+               return OMAP_DSS_CHANNEL_LCD;
+       }
+}
+
 static int __init dpi_init_display(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev;
@@ -421,12 +592,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
                dpi.vdds_dsi_reg = vdds_dsi;
        }
 
-       /*
-        * XXX We shouldn't need dssdev->channel for this. The dsi pll clock
-        * source for DPI is SoC integration detail, not something that should
-        * be configured in the dssdev
-        */
-       dsidev = dpi_get_dsidev(dssdev->channel);
+       dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
 
        if (dsidev && dpi_verify_dsi_pll(dsidev)) {
                dsidev = NULL;
@@ -517,6 +683,8 @@ static void __init dpi_init_output(struct platform_device *pdev)
        out->pdev = pdev;
        out->id = OMAP_DSS_OUTPUT_DPI;
        out->type = OMAP_DISPLAY_TYPE_DPI;
+       out->name = "dpi.0";
+       out->dispc_channel = dpi_get_channel();
 
        dss_register_output(out);
 }
index 28d41d16b7be45aa10d646ba8983cd57e418e363..9b1c5ecee11517389f17103eb5495321c1b7fc6f 100644 (file)
@@ -200,6 +200,11 @@ struct dsi_reg { u16 idx; };
 
 typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
 
+static int dsi_display_init_dispc(struct platform_device *dsidev,
+       struct omap_overlay_manager *mgr);
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
+       struct omap_overlay_manager *mgr);
+
 #define DSI_MAX_NR_ISRS                2
 #define DSI_MAX_NR_LANES       5
 
@@ -250,6 +255,24 @@ struct dsi_isr_tables {
        struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
 };
 
+struct dsi_clk_calc_ctx {
+       struct platform_device *dsidev;
+
+       /* inputs */
+
+       const struct omap_dss_dsi_config *config;
+
+       unsigned long req_pck_min, req_pck_nom, req_pck_max;
+
+       /* outputs */
+
+       struct dsi_clock_info dsi_cinfo;
+       struct dispc_clock_info dispc_cinfo;
+
+       struct omap_video_timings dispc_vm;
+       struct omap_dss_dsi_videomode_timings dsi_vm;
+};
+
 struct dsi_data {
        struct platform_device *pdev;
        void __iomem    *base;
@@ -261,6 +284,9 @@ struct dsi_data {
        struct clk *dss_clk;
        struct clk *sys_clk;
 
+       struct dispc_clock_info user_dispc_cinfo;
+       struct dsi_clock_info user_dsi_cinfo;
+
        struct dsi_clock_info current_cinfo;
 
        bool vdds_dsi_enabled;
@@ -324,6 +350,7 @@ struct dsi_data {
        unsigned long lpdiv_max;
 
        unsigned num_lanes_supported;
+       unsigned line_buffer_size;
 
        struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
        unsigned num_lanes_used;
@@ -1192,15 +1219,33 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
        return r;
 }
 
-static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
+static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
+               unsigned long lp_clk_min, unsigned long lp_clk_max)
+{
+       unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
+       unsigned lp_clk_div;
+       unsigned long lp_clk;
+
+       lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
+       lp_clk = dsi_fclk / 2 / lp_clk_div;
+
+       if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
+               return -EINVAL;
+
+       cinfo->lp_clk_div = lp_clk_div;
+       cinfo->lp_clk = lp_clk;
+
+       return 0;
+}
+
+static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long dsi_fclk;
        unsigned lp_clk_div;
        unsigned long lp_clk;
 
-       lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
+       lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div;
 
        if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
                return -EINVAL;
@@ -1272,6 +1317,75 @@ static int dsi_pll_power(struct platform_device *dsidev,
        return 0;
 }
 
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       return clk_get_rate(dsi->sys_clk);
+}
+
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+               unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int regm, regm_start, regm_stop;
+       unsigned long out_max;
+       unsigned long out;
+
+       out_min = out_min ? out_min : 1;
+       out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+       regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
+       regm_stop = min(pll / out_min, dsi->regm_dispc_max);
+
+       for (regm = regm_start; regm <= regm_stop; ++regm) {
+               out = pll / regm;
+
+               if (func(regm, out, data))
+                       return true;
+       }
+
+       return false;
+}
+
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+               unsigned long pll_min, unsigned long pll_max,
+               dsi_pll_calc_func func, void *data)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int regn, regn_start, regn_stop;
+       int regm, regm_start, regm_stop;
+       unsigned long fint, pll;
+       const unsigned long pll_hw_max = 1800000000;
+       unsigned long fint_hw_min, fint_hw_max;
+
+       fint_hw_min = dsi->fint_min;
+       fint_hw_max = dsi->fint_max;
+
+       regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+       regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
+
+       pll_max = pll_max ? pll_max : ULONG_MAX;
+
+       for (regn = regn_start; regn <= regn_stop; ++regn) {
+               fint = clkin / regn;
+
+               regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+                               1ul);
+               regm_stop = min3(pll_max / fint / 2,
+                               pll_hw_max / fint / 2,
+                               dsi->regm_max);
+
+               for (regm = regm_start; regm <= regm_stop; ++regm) {
+                       pll = 2 * regm * fint;
+
+                       if (func(regn, regm, fint, pll, data))
+                               return true;
+               }
+       }
+
+       return false;
+}
+
 /* calculate clock rates using dividers in cinfo */
 static int dsi_calc_clock_rates(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo)
@@ -1316,192 +1430,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev,
        return 0;
 }
 
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
-               unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
-               struct dispc_clock_info *dispc_cinfo)
-{
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct dsi_clock_info cur, best;
-       struct dispc_clock_info best_dispc;
-       int min_fck_per_pck;
-       int match = 0;
-       unsigned long dss_sys_clk, max_dss_fck;
-
-       dss_sys_clk = clk_get_rate(dsi->sys_clk);
-
-       max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
-       if (req_pck == dsi->cache_req_pck &&
-                       dsi->cache_cinfo.clkin == dss_sys_clk) {
-               DSSDBG("DSI clock info found from cache\n");
-               *dsi_cinfo = dsi->cache_cinfo;
-               dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk,
-                       dispc_cinfo);
-               return 0;
-       }
-
-       min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
-       if (min_fck_per_pck &&
-               req_pck * min_fck_per_pck > max_dss_fck) {
-               DSSERR("Requested pixel clock not possible with the current "
-                               "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
-                               "the constraint off.\n");
-               min_fck_per_pck = 0;
-       }
-
-       DSSDBG("dsi_pll_calc\n");
-
-retry:
-       memset(&best, 0, sizeof(best));
-       memset(&best_dispc, 0, sizeof(best_dispc));
-
-       memset(&cur, 0, sizeof(cur));
-       cur.clkin = dss_sys_clk;
-
-       /* 0.75MHz < Fint = clkin / regn < 2.1MHz */
-       /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
-       for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
-               cur.fint = cur.clkin / cur.regn;
-
-               if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
-                       continue;
-
-               /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
-               for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
-                       unsigned long a, b;
-
-                       a = 2 * cur.regm * (cur.clkin/1000);
-                       b = cur.regn;
-                       cur.clkin4ddr = a / b * 1000;
-
-                       if (cur.clkin4ddr > 1800 * 1000 * 1000)
-                               break;
-
-                       /* dsi_pll_hsdiv_dispc_clk(MHz) =
-                        * DSIPHY(MHz) / regm_dispc  < 173MHz/186Mhz */
-                       for (cur.regm_dispc = 1; cur.regm_dispc <
-                                       dsi->regm_dispc_max; ++cur.regm_dispc) {
-                               struct dispc_clock_info cur_dispc;
-                               cur.dsi_pll_hsdiv_dispc_clk =
-                                       cur.clkin4ddr / cur.regm_dispc;
-
-                               if (cur.regm_dispc > 1 &&
-                                               cur.regm_dispc % 2 != 0 &&
-                                               req_pck >= 1000000)
-                                       continue;
-
-                               /* this will narrow down the search a bit,
-                                * but still give pixclocks below what was
-                                * requested */
-                               if (cur.dsi_pll_hsdiv_dispc_clk  < req_pck)
-                                       break;
-
-                               if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
-                                       continue;
-
-                               if (min_fck_per_pck &&
-                                       cur.dsi_pll_hsdiv_dispc_clk <
-                                               req_pck * min_fck_per_pck)
-                                       continue;
-
-                               match = 1;
-
-                               dispc_find_clk_divs(req_pck,
-                                               cur.dsi_pll_hsdiv_dispc_clk,
-                                               &cur_dispc);
-
-                               if (abs(cur_dispc.pck - req_pck) <
-                                               abs(best_dispc.pck - req_pck)) {
-                                       best = cur;
-                                       best_dispc = cur_dispc;
-
-                                       if (cur_dispc.pck == req_pck)
-                                               goto found;
-                               }
-                       }
-               }
-       }
-found:
-       if (!match) {
-               if (min_fck_per_pck) {
-                       DSSERR("Could not find suitable clock settings.\n"
-                                       "Turning FCK/PCK constraint off and"
-                                       "trying again.\n");
-                       min_fck_per_pck = 0;
-                       goto retry;
-               }
-
-               DSSERR("Could not find suitable clock settings.\n");
-
-               return -EINVAL;
-       }
-
-       /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
-       best.regm_dsi = 0;
-       best.dsi_pll_hsdiv_dsi_clk = 0;
-
-       if (dsi_cinfo)
-               *dsi_cinfo = best;
-       if (dispc_cinfo)
-               *dispc_cinfo = best_dispc;
-
-       dsi->cache_req_pck = req_pck;
-       dsi->cache_clk_freq = 0;
-       dsi->cache_cinfo = best;
-
-       return 0;
-}
-
-static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
-               unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
-{
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct dsi_clock_info cur, best;
-
-       DSSDBG("dsi_pll_calc_ddrfreq\n");
-
-       memset(&best, 0, sizeof(best));
-       memset(&cur, 0, sizeof(cur));
-
-       cur.clkin = clk_get_rate(dsi->sys_clk);
-
-       for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
-               cur.fint = cur.clkin / cur.regn;
-
-               if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
-                       continue;
-
-               /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
-               for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
-                       unsigned long a, b;
-
-                       a = 2 * cur.regm * (cur.clkin/1000);
-                       b = cur.regn;
-                       cur.clkin4ddr = a / b * 1000;
-
-                       if (cur.clkin4ddr > 1800 * 1000 * 1000)
-                               break;
-
-                       if (abs(cur.clkin4ddr - req_clkin4ddr) <
-                                       abs(best.clkin4ddr - req_clkin4ddr)) {
-                               best = cur;
-                               DSSDBG("best %ld\n", best.clkin4ddr);
-                       }
-
-                       if (cur.clkin4ddr == req_clkin4ddr)
-                               goto found;
-               }
-       }
-found:
-       if (cinfo)
-               *cinfo = best;
-
-       return 0;
-}
-
-static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
-               struct dsi_clock_info *cinfo)
+static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
 {
        unsigned long max_dsi_fck;
 
@@ -1511,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
        cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
 }
 
-static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
-               unsigned long req_pck, struct dsi_clock_info *cinfo,
-               struct dispc_clock_info *dispc_cinfo)
-{
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       unsigned regm_dispc, best_regm_dispc;
-       unsigned long dispc_clk, best_dispc_clk;
-       int min_fck_per_pck;
-       unsigned long max_dss_fck;
-       struct dispc_clock_info best_dispc;
-       bool match;
-
-       max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
-       min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
-       if (min_fck_per_pck &&
-                       req_pck * min_fck_per_pck > max_dss_fck) {
-               DSSERR("Requested pixel clock not possible with the current "
-                               "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
-                               "the constraint off.\n");
-               min_fck_per_pck = 0;
-       }
-
-retry:
-       best_regm_dispc = 0;
-       best_dispc_clk = 0;
-       memset(&best_dispc, 0, sizeof(best_dispc));
-       match = false;
-
-       for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
-               struct dispc_clock_info cur_dispc;
-
-               dispc_clk = cinfo->clkin4ddr / regm_dispc;
-
-               /* this will narrow down the search a bit,
-                * but still give pixclocks below what was
-                * requested */
-               if (dispc_clk  < req_pck)
-                       break;
-
-               if (dispc_clk > max_dss_fck)
-                       continue;
-
-               if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
-                       continue;
-
-               match = true;
-
-               dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
-
-               if (abs(cur_dispc.pck - req_pck) <
-                               abs(best_dispc.pck - req_pck)) {
-                       best_regm_dispc = regm_dispc;
-                       best_dispc_clk = dispc_clk;
-                       best_dispc = cur_dispc;
-
-                       if (cur_dispc.pck == req_pck)
-                               goto found;
-               }
-       }
-
-       if (!match) {
-               if (min_fck_per_pck) {
-                       DSSERR("Could not find suitable clock settings.\n"
-                                       "Turning FCK/PCK constraint off and"
-                                       "trying again.\n");
-                       min_fck_per_pck = 0;
-                       goto retry;
-               }
-
-               DSSERR("Could not find suitable clock settings.\n");
-
-               return -EINVAL;
-       }
-found:
-       cinfo->regm_dispc = best_regm_dispc;
-       cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
-
-       *dispc_cinfo = best_dispc;
-
-       return 0;
-}
-
 int dsi_pll_set_clock_div(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo)
 {
@@ -2783,6 +2628,7 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel,
 
 static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r;
 
        DSSDBG("Initial config of virtual channel %d", channel);
@@ -2807,6 +2653,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
        r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
 
        dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
+
+       dsi->vc[channel].source = DSI_VC_SOURCE_L4;
 }
 
 static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
@@ -3777,13 +3625,12 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
 
        if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                int bpp = dsi_get_pixel_size(dsi->pix_fmt);
-               unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
                struct omap_video_timings *timings = &dsi->timings;
                /*
                 * Don't use line buffers if width is greater than the video
                 * port's line buffer size
                 */
-               if (line_buf_size <= timings->x_res * bpp / 8)
+               if (dsi->line_buffer_size <= timings->x_res * bpp / 8)
                        num_line_buffers = 0;
                else
                        num_line_buffers = 2;
@@ -3799,18 +3646,22 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
 static void dsi_config_vp_sync_events(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       bool vsync_end = dsi->vm_timings.vp_vsync_end;
-       bool hsync_end = dsi->vm_timings.vp_hsync_end;
+       bool sync_end;
        u32 r;
 
+       if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE)
+               sync_end = true;
+       else
+               sync_end = false;
+
        r = dsi_read_reg(dsidev, DSI_CTRL);
        r = FLD_MOD(r, 1, 9, 9);                /* VP_DE_POL */
        r = FLD_MOD(r, 1, 10, 10);              /* VP_HSYNC_POL */
        r = FLD_MOD(r, 1, 11, 11);              /* VP_VSYNC_POL */
        r = FLD_MOD(r, 1, 15, 15);              /* VP_VSYNC_START */
-       r = FLD_MOD(r, vsync_end, 16, 16);      /* VP_VSYNC_END */
+       r = FLD_MOD(r, sync_end, 16, 16);       /* VP_VSYNC_END */
        r = FLD_MOD(r, 1, 17, 17);              /* VP_HSYNC_START */
-       r = FLD_MOD(r, hsync_end, 18, 18);      /* VP_HSYNC_END */
+       r = FLD_MOD(r, sync_end, 18, 18);       /* VP_HSYNC_END */
        dsi_write_reg(dsidev, DSI_CTRL, r);
 }
 
@@ -3897,9 +3748,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
        return max(lp_inter, 0);
 }
 
-static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
+static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int blanking_mode;
        int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
@@ -3910,7 +3760,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
        struct omap_video_timings *timings = &dsi->timings;
        int bpp = dsi_get_pixel_size(dsi->pix_fmt);
        int ndl = dsi->num_lanes_used - 1;
-       int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1;
+       int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1;
        int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
        int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
        int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
@@ -4015,9 +3865,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
        dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
 }
 
-static int dsi_proto_config(struct omap_dss_device *dssdev)
+static int dsi_proto_config(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r;
        int buswidth = 0;
@@ -4075,7 +3924,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                dsi_config_vp_sync_events(dsidev);
                dsi_config_blanking_modes(dsidev);
-               dsi_config_cmd_mode_interleaving(dssdev);
+               dsi_config_cmd_mode_interleaving(dsidev);
        }
 
        dsi_vc_initial_config(dsidev, 0);
@@ -4159,11 +4008,12 @@ static void dsi_proto_timings(struct platform_device *dsidev)
                int vfp = dsi->vm_timings.vfp;
                int vbp = dsi->vm_timings.vbp;
                int window_sync = dsi->vm_timings.window_sync;
-               bool hsync_end = dsi->vm_timings.vp_hsync_end;
+               bool hsync_end;
                struct omap_video_timings *timings = &dsi->timings;
                int bpp = dsi_get_pixel_size(dsi->pix_fmt);
                int tl, t_he, width_bytes;
 
+               hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE;
                t_he = hsync_end ?
                        ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
 
@@ -4266,82 +4116,26 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_dsi_configure_pins);
 
-int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
-               unsigned long ddr_clk, unsigned long lp_clk)
-{
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct dsi_clock_info cinfo;
-       struct dispc_clock_info dispc_cinfo;
-       unsigned lp_clk_div;
-       unsigned long dsi_fclk;
-       int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
-       unsigned long pck;
-       int r;
-
-       DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
-
-       mutex_lock(&dsi->lock);
-
-       /* Calculate PLL output clock */
-       r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
-       if (r)
-               goto err;
-
-       /* Calculate PLL's DSI clock */
-       dsi_pll_calc_dsi_fck(dsidev, &cinfo);
-
-       /* Calculate PLL's DISPC clock and pck & lck divs */
-       pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
-       DSSDBG("finding dispc dividers for pck %lu\n", pck);
-       r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
-       if (r)
-               goto err;
-
-       /* Calculate LP clock */
-       dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
-       lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
-
-       dssdev->clocks.dsi.regn = cinfo.regn;
-       dssdev->clocks.dsi.regm = cinfo.regm;
-       dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
-       dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
-
-       dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
-
-       dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
-       dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
-
-       dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
-
-       dssdev->clocks.dispc.channel.lcd_clk_src =
-               dsi->module_id == 0 ?
-               OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
-               OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
-
-       dssdev->clocks.dsi.dsi_fclk_src =
-               dsi->module_id == 0 ?
-               OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
-               OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI;
-
-       mutex_unlock(&dsi->lock);
-       return 0;
-err:
-       mutex_unlock(&dsi->lock);
-       return r;
-}
-EXPORT_SYMBOL(omapdss_dsi_set_clocks);
-
 int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
+       struct omap_overlay_manager *mgr = dsi->output.manager;
        int bpp = dsi_get_pixel_size(dsi->pix_fmt);
+       struct omap_dss_output *out = &dsi->output;
        u8 data_type;
        u16 word_count;
        int r;
 
+       if (out == NULL || out->manager == NULL) {
+               DSSERR("failed to enable display: no output/manager\n");
+               return -ENODEV;
+       }
+
+       r = dsi_display_init_dispc(dsidev, mgr);
+       if (r)
+               goto err_init_dispc;
+
        if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                switch (dsi->pix_fmt) {
                case OMAP_DSS_DSI_FMT_RGB888:
@@ -4357,8 +4151,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
                        data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
                        break;
                default:
-                       BUG();
-                       return -EINVAL;
+                       r = -EINVAL;
+                       goto err_pix_fmt;
                };
 
                dsi_if_enable(dsidev, false);
@@ -4377,16 +4171,20 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
        }
 
        r = dss_mgr_enable(mgr);
-       if (r) {
-               if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
-                       dsi_if_enable(dsidev, false);
-                       dsi_vc_enable(dsidev, channel, false);
-               }
-
-               return r;
-       }
+       if (r)
+               goto err_mgr_enable;
 
        return 0;
+
+err_mgr_enable:
+       if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               dsi_if_enable(dsidev, false);
+               dsi_vc_enable(dsidev, channel, false);
+       }
+err_pix_fmt:
+       dsi_display_uninit_dispc(dsidev, mgr);
+err_init_dispc:
+       return r;
 }
 EXPORT_SYMBOL(dsi_enable_video_output);
 
@@ -4394,7 +4192,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
+       struct omap_overlay_manager *mgr = dsi->output.manager;
 
        if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                dsi_if_enable(dsidev, false);
@@ -4408,14 +4206,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
        }
 
        dss_mgr_disable(mgr);
+
+       dsi_display_uninit_dispc(dsidev, mgr);
 }
 EXPORT_SYMBOL(dsi_disable_video_output);
 
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
+static void dsi_update_screen_dispc(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
+       struct omap_overlay_manager *mgr = dsi->output.manager;
        unsigned bytespp;
        unsigned bytespl;
        unsigned bytespf;
@@ -4425,7 +4224,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
        u32 l;
        int r;
        const unsigned channel = dsi->update_channel;
-       const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+       const unsigned line_buf_size = dsi->line_buffer_size;
        u16 w = dsi->timings.x_res;
        u16 h = dsi->timings.y_res;
 
@@ -4571,7 +4370,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
        dsi->update_bytes = dw * dh *
                dsi_get_pixel_size(dsi->pix_fmt) / 8;
 #endif
-       dsi_update_screen_dispc(dssdev);
+       dsi_update_screen_dispc(dsidev);
 
        return 0;
 }
@@ -4579,18 +4378,17 @@ EXPORT_SYMBOL(omap_dsi_update);
 
 /* Display funcs */
 
-static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
+static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct dispc_clock_info dispc_cinfo;
        int r;
-       unsigned long long fck;
+       unsigned long fck;
 
        fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
 
-       dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
-       dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
+       dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div;
+       dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div;
 
        r = dispc_calc_clock_rates(fck, &dispc_cinfo);
        if (r) {
@@ -4603,21 +4401,17 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
+static int dsi_display_init_dispc(struct platform_device *dsidev,
+               struct omap_overlay_manager *mgr)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
        int r;
 
-       if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
-               dsi->timings.hsw = 1;
-               dsi->timings.hfp = 1;
-               dsi->timings.hbp = 1;
-               dsi->timings.vsw = 1;
-               dsi->timings.vfp = 0;
-               dsi->timings.vbp = 0;
+       dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
+                       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
+                       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
 
+       if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
                r = dss_mgr_register_framedone_handler(mgr,
                                dsi_framedone_irq_callback, dsidev);
                if (r) {
@@ -4645,7 +4439,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 
        dss_mgr_set_timings(mgr, &dsi->timings);
 
-       r = dsi_configure_dispc_clocks(dssdev);
+       r = dsi_configure_dispc_clocks(dsidev);
        if (r)
                goto err1;
 
@@ -4662,30 +4456,30 @@ err1:
                dss_mgr_unregister_framedone_handler(mgr,
                                dsi_framedone_irq_callback, dsidev);
 err:
+       dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
        return r;
 }
 
-static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
+               struct omap_overlay_manager *mgr)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
 
        if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
                dss_mgr_unregister_framedone_handler(mgr,
                                dsi_framedone_irq_callback, dsidev);
+
+       dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
 }
 
-static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
+static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct dsi_clock_info cinfo;
        int r;
 
-       cinfo.regn  = dssdev->clocks.dsi.regn;
-       cinfo.regm  = dssdev->clocks.dsi.regm;
-       cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
-       cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
+       cinfo = dsi->user_dsi_cinfo;
+
        r = dsi_calc_clock_rates(dsidev, &cinfo);
        if (r) {
                DSSERR("Failed to calc dsi clocks\n");
@@ -4701,24 +4495,22 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
+static int dsi_display_init_dsi(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
        int r;
 
        r = dsi_pll_init(dsidev, true, true);
        if (r)
                goto err0;
 
-       r = dsi_configure_dsi_clocks(dssdev);
+       r = dsi_configure_dsi_clocks(dsidev);
        if (r)
                goto err1;
 
-       dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
-       dss_select_lcd_clk_source(mgr->id,
-                       dssdev->clocks.dispc.channel.lcd_clk_src);
+       dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ?
+                       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
+                       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI);
 
        DSSDBG("PLL OK\n");
 
@@ -4729,12 +4521,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        _dsi_print_reset_status(dsidev);
 
        dsi_proto_timings(dsidev);
-       dsi_set_lp_clk_divisor(dssdev);
+       dsi_set_lp_clk_divisor(dsidev);
 
        if (1)
                _dsi_print_reset_status(dsidev);
 
-       r = dsi_proto_config(dssdev);
+       r = dsi_proto_config(dsidev);
        if (r)
                goto err3;
 
@@ -4751,20 +4543,16 @@ err3:
        dsi_cio_uninit(dsidev);
 err2:
        dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
-       dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
-
 err1:
        dsi_pll_uninit(dsidev, true);
 err0:
        return r;
 }
 
-static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
+static void dsi_display_uninit_dsi(struct platform_device *dsidev,
                bool disconnect_lanes, bool enter_ulps)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_overlay_manager *mgr = dssdev->output->manager;
 
        if (enter_ulps && !dsi->ulps_enabled)
                dsi_enter_ulps(dsidev);
@@ -4777,7 +4565,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
        dsi_vc_enable(dsidev, 3, 0);
 
        dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
-       dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
        dsi_cio_uninit(dsidev);
        dsi_pll_uninit(dsidev, disconnect_lanes);
 }
@@ -4786,7 +4573,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_dss_output *out = dssdev->output;
        int r = 0;
 
        DSSDBG("dsi_display_enable\n");
@@ -4795,12 +4581,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 
        mutex_lock(&dsi->lock);
 
-       if (out == NULL || out->manager == NULL) {
-               DSSERR("failed to enable display: no output/manager\n");
-               r = -ENODEV;
-               goto err_start_dev;
-       }
-
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -4815,11 +4595,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 
        _dsi_initialize_irq(dsidev);
 
-       r = dsi_display_init_dispc(dssdev);
-       if (r)
-               goto err_init_dispc;
-
-       r = dsi_display_init_dsi(dssdev);
+       r = dsi_display_init_dsi(dsidev);
        if (r)
                goto err_init_dsi;
 
@@ -4828,8 +4604,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        return 0;
 
 err_init_dsi:
-       dsi_display_uninit_dispc(dssdev);
-err_init_dispc:
        dsi_enable_pll_clock(dsidev, 0);
        dsi_runtime_put(dsidev);
 err_get_dsi:
@@ -4858,9 +4632,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
        dsi_sync_vc(dsidev, 2);
        dsi_sync_vc(dsidev, 3);
 
-       dsi_display_uninit_dispc(dssdev);
-
-       dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
+       dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
 
        dsi_runtime_put(dsidev);
        dsi_enable_pll_clock(dsidev, 0);
@@ -4881,75 +4653,577 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
-void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+static void print_dsi_vm(const char *str,
+               const struct omap_dss_dsi_videomode_timings *t)
+{
+       unsigned long byteclk = t->hsclk / 4;
+       int bl, wc, pps, tot;
+
+       wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
+       pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
+       bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
+       tot = bl + pps;
+
+#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
+
+       pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
+                       "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
+                       str,
+                       byteclk,
+                       t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
+                       bl, pps, tot,
+                       TO_DSI_T(t->hss),
+                       TO_DSI_T(t->hsa),
+                       TO_DSI_T(t->hse),
+                       TO_DSI_T(t->hbp),
+                       TO_DSI_T(pps),
+                       TO_DSI_T(t->hfp),
+
+                       TO_DSI_T(bl),
+                       TO_DSI_T(pps),
+
+                       TO_DSI_T(tot));
+#undef TO_DSI_T
+}
+
+static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
+{
+       unsigned long pck = t->pixel_clock * 1000;
+       int hact, bl, tot;
+
+       hact = t->x_res;
+       bl = t->hsw + t->hbp + t->hfp;
+       tot = hact + bl;
+
+#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
+
+       pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
+                       "%u/%u/%u/%u = %u + %u = %u\n",
+                       str,
+                       pck,
+                       t->hsw, t->hbp, hact, t->hfp,
+                       bl, hact, tot,
+                       TO_DISPC_T(t->hsw),
+                       TO_DISPC_T(t->hbp),
+                       TO_DISPC_T(hact),
+                       TO_DISPC_T(t->hfp),
+                       TO_DISPC_T(bl),
+                       TO_DISPC_T(hact),
+                       TO_DISPC_T(tot));
+#undef TO_DISPC_T
+}
+
+/* note: this is not quite accurate */
+static void print_dsi_dispc_vm(const char *str,
+               const struct omap_dss_dsi_videomode_timings *t)
+{
+       struct omap_video_timings vm = { 0 };
+       unsigned long byteclk = t->hsclk / 4;
+       unsigned long pck;
+       u64 dsi_tput;
+       int dsi_hact, dsi_htot;
+
+       dsi_tput = (u64)byteclk * t->ndl * 8;
+       pck = (u32)div64_u64(dsi_tput, t->bitspp);
+       dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
+       dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
+
+       vm.pixel_clock = pck / 1000;
+       vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
+       vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
+       vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
+       vm.x_res = t->hact;
+
+       print_dispc_vm(str, &vm);
+}
+#endif /* PRINT_VERBOSE_VM_TIMINGS */
+
+static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+               unsigned long pck, void *data)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_clk_calc_ctx *ctx = data;
+       struct omap_video_timings *t = &ctx->dispc_vm;
 
-       mutex_lock(&dsi->lock);
+       ctx->dispc_cinfo.lck_div = lckd;
+       ctx->dispc_cinfo.pck_div = pckd;
+       ctx->dispc_cinfo.lck = lck;
+       ctx->dispc_cinfo.pck = pck;
 
-       dsi->timings = *timings;
+       *t = *ctx->config->timings;
+       t->pixel_clock = pck / 1000;
+       t->x_res = ctx->config->timings->x_res;
+       t->y_res = ctx->config->timings->y_res;
+       t->hsw = t->hfp = t->hbp = t->vsw = 1;
+       t->vfp = t->vbp = 0;
 
-       mutex_unlock(&dsi->lock);
+       return true;
 }
-EXPORT_SYMBOL(omapdss_dsi_set_timings);
 
-void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+               void *data)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_clk_calc_ctx *ctx = data;
 
-       mutex_lock(&dsi->lock);
+       ctx->dsi_cinfo.regm_dispc = regm_dispc;
+       ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
 
-       dsi->timings.x_res = w;
-       dsi->timings.y_res = h;
+       return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
+                       dsi_cm_calc_dispc_cb, ctx);
+}
 
-       mutex_unlock(&dsi->lock);
+static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
+               unsigned long pll, void *data)
+{
+       struct dsi_clk_calc_ctx *ctx = data;
+
+       ctx->dsi_cinfo.regn = regn;
+       ctx->dsi_cinfo.regm = regm;
+       ctx->dsi_cinfo.fint = fint;
+       ctx->dsi_cinfo.clkin4ddr = pll;
+
+       return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+                       dsi_cm_calc_hsdiv_cb, ctx);
 }
-EXPORT_SYMBOL(omapdss_dsi_set_size);
 
-void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
-               enum omap_dss_dsi_pixel_format fmt)
+static bool dsi_cm_calc(struct dsi_data *dsi,
+               const struct omap_dss_dsi_config *cfg,
+               struct dsi_clk_calc_ctx *ctx)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       unsigned long clkin;
+       int bitspp, ndl;
+       unsigned long pll_min, pll_max;
+       unsigned long pck, txbyteclk;
 
-       mutex_lock(&dsi->lock);
+       clkin = clk_get_rate(dsi->sys_clk);
+       bitspp = dsi_get_pixel_size(cfg->pixel_format);
+       ndl = dsi->num_lanes_used - 1;
+
+       /*
+        * Here we should calculate minimum txbyteclk to be able to send the
+        * frame in time, and also to handle TE. That's not very simple, though,
+        * especially as we go to LP between each pixel packet due to HW
+        * "feature". So let's just estimate very roughly and multiply by 1.5.
+        */
+       pck = cfg->timings->pixel_clock * 1000;
+       pck = pck * 3 / 2;
+       txbyteclk = pck * bitspp / 8 / ndl;
 
-       dsi->pix_fmt = fmt;
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->dsidev = dsi->pdev;
+       ctx->config = cfg;
+       ctx->req_pck_min = pck;
+       ctx->req_pck_nom = pck;
+       ctx->req_pck_max = pck * 3 / 2;
+       ctx->dsi_cinfo.clkin = clkin;
 
-       mutex_unlock(&dsi->lock);
+       pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
+       pll_max = cfg->hs_clk_max * 4;
+
+       return dsi_pll_calc(dsi->pdev, clkin,
+                       pll_min, pll_max,
+                       dsi_cm_calc_pll_cb, ctx);
 }
-EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
 
-void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
-               enum omap_dss_dsi_mode mode)
+static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
+       const struct omap_dss_dsi_config *cfg = ctx->config;
+       int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+       int ndl = dsi->num_lanes_used - 1;
+       unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
+       unsigned long byteclk = hsclk / 4;
 
-       mutex_lock(&dsi->lock);
+       unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
+       int xres;
+       int panel_htot, panel_hbl; /* pixels */
+       int dispc_htot, dispc_hbl; /* pixels */
+       int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
+       int hfp, hsa, hbp;
+       const struct omap_video_timings *req_vm;
+       struct omap_video_timings *dispc_vm;
+       struct omap_dss_dsi_videomode_timings *dsi_vm;
+       u64 dsi_tput, dispc_tput;
 
-       dsi->mode = mode;
+       dsi_tput = (u64)byteclk * ndl * 8;
 
-       mutex_unlock(&dsi->lock);
+       req_vm = cfg->timings;
+       req_pck_min = ctx->req_pck_min;
+       req_pck_max = ctx->req_pck_max;
+       req_pck_nom = ctx->req_pck_nom;
+
+       dispc_pck = ctx->dispc_cinfo.pck;
+       dispc_tput = (u64)dispc_pck * bitspp;
+
+       xres = req_vm->x_res;
+
+       panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
+       panel_htot = xres + panel_hbl;
+
+       dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
+
+       /*
+        * When there are no line buffers, DISPC and DSI must have the
+        * same tput. Otherwise DISPC tput needs to be higher than DSI's.
+        */
+       if (dsi->line_buffer_size < xres * bitspp / 8) {
+               if (dispc_tput != dsi_tput)
+                       return false;
+       } else {
+               if (dispc_tput < dsi_tput)
+                       return false;
+       }
+
+       /* DSI tput must be over the min requirement */
+       if (dsi_tput < (u64)bitspp * req_pck_min)
+               return false;
+
+       /* When non-burst mode, DSI tput must be below max requirement. */
+       if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
+               if (dsi_tput > (u64)bitspp * req_pck_max)
+                       return false;
+       }
+
+       hss = DIV_ROUND_UP(4, ndl);
+
+       if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
+               if (ndl == 3 && req_vm->hsw == 0)
+                       hse = 1;
+               else
+                       hse = DIV_ROUND_UP(4, ndl);
+       } else {
+               hse = 0;
+       }
+
+       /* DSI htot to match the panel's nominal pck */
+       dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
+
+       /* fail if there would be no time for blanking */
+       if (dsi_htot < hss + hse + dsi_hact)
+               return false;
+
+       /* total DSI blanking needed to achieve panel's TL */
+       dsi_hbl = dsi_htot - dsi_hact;
+
+       /* DISPC htot to match the DSI TL */
+       dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
+
+       /* verify that the DSI and DISPC TLs are the same */
+       if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
+               return false;
+
+       dispc_hbl = dispc_htot - xres;
+
+       /* setup DSI videomode */
+
+       dsi_vm = &ctx->dsi_vm;
+       memset(dsi_vm, 0, sizeof(*dsi_vm));
+
+       dsi_vm->hsclk = hsclk;
+
+       dsi_vm->ndl = ndl;
+       dsi_vm->bitspp = bitspp;
+
+       if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) {
+               hsa = 0;
+       } else if (ndl == 3 && req_vm->hsw == 0) {
+               hsa = 0;
+       } else {
+               hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom);
+               hsa = max(hsa - hse, 1);
+       }
+
+       hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
+       hbp = max(hbp, 1);
+
+       hfp = dsi_hbl - (hss + hsa + hse + hbp);
+       if (hfp < 1) {
+               int t;
+               /* we need to take cycles from hbp */
+
+               t = 1 - hfp;
+               hbp = max(hbp - t, 1);
+               hfp = dsi_hbl - (hss + hsa + hse + hbp);
+
+               if (hfp < 1 && hsa > 0) {
+                       /* we need to take cycles from hsa */
+                       t = 1 - hfp;
+                       hsa = max(hsa - t, 1);
+                       hfp = dsi_hbl - (hss + hsa + hse + hbp);
+               }
+       }
+
+       if (hfp < 1)
+               return false;
+
+       dsi_vm->hss = hss;
+       dsi_vm->hsa = hsa;
+       dsi_vm->hse = hse;
+       dsi_vm->hbp = hbp;
+       dsi_vm->hact = xres;
+       dsi_vm->hfp = hfp;
+
+       dsi_vm->vsa = req_vm->vsw;
+       dsi_vm->vbp = req_vm->vbp;
+       dsi_vm->vact = req_vm->y_res;
+       dsi_vm->vfp = req_vm->vfp;
+
+       dsi_vm->trans_mode = cfg->trans_mode;
+
+       dsi_vm->blanking_mode = 0;
+       dsi_vm->hsa_blanking_mode = 1;
+       dsi_vm->hfp_blanking_mode = 1;
+       dsi_vm->hbp_blanking_mode = 1;
+
+       dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
+       dsi_vm->window_sync = 4;
+
+       /* setup DISPC videomode */
+
+       dispc_vm = &ctx->dispc_vm;
+       *dispc_vm = *req_vm;
+       dispc_vm->pixel_clock = dispc_pck / 1000;
+
+       if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
+               hsa = div64_u64((u64)req_vm->hsw * dispc_pck,
+                               req_pck_nom);
+               hsa = max(hsa, 1);
+       } else {
+               hsa = 1;
+       }
+
+       hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
+       hbp = max(hbp, 1);
+
+       hfp = dispc_hbl - hsa - hbp;
+       if (hfp < 1) {
+               int t;
+               /* we need to take cycles from hbp */
+
+               t = 1 - hfp;
+               hbp = max(hbp - t, 1);
+               hfp = dispc_hbl - hsa - hbp;
+
+               if (hfp < 1) {
+                       /* we need to take cycles from hsa */
+                       t = 1 - hfp;
+                       hsa = max(hsa - t, 1);
+                       hfp = dispc_hbl - hsa - hbp;
+               }
+       }
+
+       if (hfp < 1)
+               return false;
+
+       dispc_vm->hfp = hfp;
+       dispc_vm->hsw = hsa;
+       dispc_vm->hbp = hbp;
+
+       return true;
+}
+
+
+static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+               unsigned long pck, void *data)
+{
+       struct dsi_clk_calc_ctx *ctx = data;
+
+       ctx->dispc_cinfo.lck_div = lckd;
+       ctx->dispc_cinfo.pck_div = pckd;
+       ctx->dispc_cinfo.lck = lck;
+       ctx->dispc_cinfo.pck = pck;
+
+       if (dsi_vm_calc_blanking(ctx) == false)
+               return false;
+
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+       print_dispc_vm("dispc", &ctx->dispc_vm);
+       print_dsi_vm("dsi  ", &ctx->dsi_vm);
+       print_dispc_vm("req  ", ctx->config->timings);
+       print_dsi_dispc_vm("act  ", &ctx->dsi_vm);
+#endif
+
+       return true;
+}
+
+static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+               void *data)
+{
+       struct dsi_clk_calc_ctx *ctx = data;
+       unsigned long pck_max;
+
+       ctx->dsi_cinfo.regm_dispc = regm_dispc;
+       ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+       /*
+        * In burst mode we can let the dispc pck be arbitrarily high, but it
+        * limits our scaling abilities. So for now, don't aim too high.
+        */
+
+       if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE)
+               pck_max = ctx->req_pck_max + 10000000;
+       else
+               pck_max = ctx->req_pck_max;
+
+       return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
+                       dsi_vm_calc_dispc_cb, ctx);
+}
+
+static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
+               unsigned long pll, void *data)
+{
+       struct dsi_clk_calc_ctx *ctx = data;
+
+       ctx->dsi_cinfo.regn = regn;
+       ctx->dsi_cinfo.regm = regm;
+       ctx->dsi_cinfo.fint = fint;
+       ctx->dsi_cinfo.clkin4ddr = pll;
+
+       return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+                       dsi_vm_calc_hsdiv_cb, ctx);
+}
+
+static bool dsi_vm_calc(struct dsi_data *dsi,
+               const struct omap_dss_dsi_config *cfg,
+               struct dsi_clk_calc_ctx *ctx)
+{
+       const struct omap_video_timings *t = cfg->timings;
+       unsigned long clkin;
+       unsigned long pll_min;
+       unsigned long pll_max;
+       int ndl = dsi->num_lanes_used - 1;
+       int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+       unsigned long byteclk_min;
+
+       clkin = clk_get_rate(dsi->sys_clk);
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->dsidev = dsi->pdev;
+       ctx->config = cfg;
+
+       ctx->dsi_cinfo.clkin = clkin;
+
+       /* these limits should come from the panel driver */
+       ctx->req_pck_min = t->pixel_clock * 1000 - 1000;
+       ctx->req_pck_nom = t->pixel_clock * 1000;
+       ctx->req_pck_max = t->pixel_clock * 1000 + 1000;
+
+       byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
+       pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
+
+       if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) {
+               pll_max = cfg->hs_clk_max * 4;
+       } else {
+               unsigned long byteclk_max;
+               byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
+                               ndl * 8);
+
+               pll_max = byteclk_max * 4 * 4;
+       }
+
+       return dsi_pll_calc(dsi->pdev, clkin,
+                       pll_min, pll_max,
+                       dsi_vm_calc_pll_cb, ctx);
 }
-EXPORT_SYMBOL(omapdss_dsi_set_operation_mode);
 
-void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
-               struct omap_dss_dsi_videomode_timings *timings)
+int omapdss_dsi_set_config(struct omap_dss_device *dssdev,
+               const struct omap_dss_dsi_config *config)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_clk_calc_ctx ctx;
+       bool ok;
+       int r;
 
        mutex_lock(&dsi->lock);
 
-       dsi->vm_timings = *timings;
+       dsi->pix_fmt = config->pixel_format;
+       dsi->mode = config->mode;
+
+       if (config->mode == OMAP_DSS_DSI_VIDEO_MODE)
+               ok = dsi_vm_calc(dsi, config, &ctx);
+       else
+               ok = dsi_cm_calc(dsi, config, &ctx);
+
+       if (!ok) {
+               DSSERR("failed to find suitable DSI clock settings\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
+
+       r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
+                       config->lp_clk_max);
+       if (r) {
+               DSSERR("failed to find suitable DSI LP clock settings\n");
+               goto err;
+       }
+
+       dsi->user_dsi_cinfo = ctx.dsi_cinfo;
+       dsi->user_dispc_cinfo = ctx.dispc_cinfo;
+
+       dsi->timings = ctx.dispc_vm;
+       dsi->vm_timings = ctx.dsi_vm;
 
        mutex_unlock(&dsi->lock);
+
+       return 0;
+err:
+       mutex_unlock(&dsi->lock);
+
+       return r;
+}
+EXPORT_SYMBOL(omapdss_dsi_set_config);
+
+/*
+ * Return a hardcoded channel for the DSI output. This should work for
+ * current use cases, but this can be later expanded to either resolve
+ * the channel in some more dynamic manner, or get the channel as a user
+ * parameter.
+ */
+static enum omap_channel dsi_get_channel(int module_id)
+{
+       switch (omapdss_get_version()) {
+       case OMAPDSS_VER_OMAP24xx:
+               DSSWARN("DSI not supported\n");
+               return OMAP_DSS_CHANNEL_LCD;
+
+       case OMAPDSS_VER_OMAP34xx_ES1:
+       case OMAPDSS_VER_OMAP34xx_ES3:
+       case OMAPDSS_VER_OMAP3630:
+       case OMAPDSS_VER_AM35xx:
+               return OMAP_DSS_CHANNEL_LCD;
+
+       case OMAPDSS_VER_OMAP4430_ES1:
+       case OMAPDSS_VER_OMAP4430_ES2:
+       case OMAPDSS_VER_OMAP4:
+               switch (module_id) {
+               case 0:
+                       return OMAP_DSS_CHANNEL_LCD;
+               case 1:
+                       return OMAP_DSS_CHANNEL_LCD2;
+               default:
+                       DSSWARN("unsupported module id\n");
+                       return OMAP_DSS_CHANNEL_LCD;
+               }
+
+       case OMAPDSS_VER_OMAP5:
+               switch (module_id) {
+               case 0:
+                       return OMAP_DSS_CHANNEL_LCD;
+               case 1:
+                       return OMAP_DSS_CHANNEL_LCD3;
+               default:
+                       DSSWARN("unsupported module id\n");
+                       return OMAP_DSS_CHANNEL_LCD;
+               }
+
+       default:
+               DSSWARN("unsupported DSS version\n");
+               return OMAP_DSS_CHANNEL_LCD;
+       }
 }
-EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
 
 static int __init dsi_init_display(struct omap_dss_device *dssdev)
 {
@@ -5073,7 +5347,7 @@ static int dsi_get_clocks(struct platform_device *dsidev)
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct clk *clk;
 
-       clk = clk_get(&dsidev->dev, "fck");
+       clk = devm_clk_get(&dsidev->dev, "fck");
        if (IS_ERR(clk)) {
                DSSERR("can't get fck\n");
                return PTR_ERR(clk);
@@ -5081,11 +5355,9 @@ static int dsi_get_clocks(struct platform_device *dsidev)
 
        dsi->dss_clk = clk;
 
-       clk = clk_get(&dsidev->dev, "sys_clk");
+       clk = devm_clk_get(&dsidev->dev, "sys_clk");
        if (IS_ERR(clk)) {
                DSSERR("can't get sys_clk\n");
-               clk_put(dsi->dss_clk);
-               dsi->dss_clk = NULL;
                return PTR_ERR(clk);
        }
 
@@ -5094,16 +5366,6 @@ static int dsi_get_clocks(struct platform_device *dsidev)
        return 0;
 }
 
-static void dsi_put_clocks(struct platform_device *dsidev)
-{
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
-       if (dsi->dss_clk)
-               clk_put(dsi->dss_clk);
-       if (dsi->sys_clk)
-               clk_put(dsi->sys_clk);
-}
-
 static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
 {
        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
@@ -5188,6 +5450,8 @@ static void __init dsi_init_output(struct platform_device *dsidev)
                        OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
 
        out->type = OMAP_DISPLAY_TYPE_DSI;
+       out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
+       out->dispc_channel = dsi_get_channel(dsi->module_id);
 
        dss_register_output(out);
 }
@@ -5293,6 +5557,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
        else
                dsi->num_lanes_supported = 3;
 
+       dsi->line_buffer_size = dsi_get_line_buf_size(dsidev);
+
        dsi_init_output(dsidev);
 
        dsi_probe_pdata(dsidev);
@@ -5314,7 +5580,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
 
 err_runtime_get:
        pm_runtime_disable(&dsidev->dev);
-       dsi_put_clocks(dsidev);
        return r;
 }
 
@@ -5330,8 +5595,6 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
 
        pm_runtime_disable(&dsidev->dev);
 
-       dsi_put_clocks(dsidev);
-
        if (dsi->vdds_dsi_reg != NULL) {
                if (dsi->vdds_dsi_enabled) {
                        regulator_disable(dsi->vdds_dsi_reg);
index 054c2a22b3f1c650aca01037bd6d125d3a55235f..94f66f9f10a3664958623327fb59fe30de101f27 100644 (file)
@@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
        return 0;
 }
 
+bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data)
+{
+       int fckd, fckd_start, fckd_stop;
+       unsigned long fck;
+       unsigned long fck_hw_max;
+       unsigned long fckd_hw_max;
+       unsigned long prate;
+       unsigned m;
+
+       if (dss.dpll4_m4_ck == NULL) {
+               /*
+                * TODO: dss1_fclk can be changed on OMAP2, but the available
+                * dividers are not continuous. We just use the pre-set rate for
+                * now.
+                */
+               fck = clk_get_rate(dss.dss_clk);
+               fckd = 1;
+               return func(fckd, fck, data);
+       }
+
+       fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+       fckd_hw_max = dss.feat->fck_div_max;
+
+       m = dss.feat->dss_fck_multiplier;
+       prate = dss_get_dpll4_rate();
+
+       fck_min = fck_min ? fck_min : 1;
+
+       fckd_start = min(prate * m / fck_min, fckd_hw_max);
+       fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
+
+       for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
+               fck = prate / fckd * m;
+
+               if (func(fckd, fck, data))
+                       return true;
+       }
+
+       return false;
+}
+
 int dss_set_clock_div(struct dss_clock_info *cinfo)
 {
        if (dss.dpll4_m4_ck) {
@@ -482,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
                prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
                DSSDBG("dpll4_m4 = %ld\n", prate);
 
-               r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
+               r = clk_set_rate(dss.dpll4_m4_ck,
+                               DIV_ROUND_UP(prate, cinfo->fck_div));
                if (r)
                        return r;
        } else {
@@ -492,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
 
        dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
 
-       WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch");
+       WARN_ONCE(dss.dss_clk_rate != cinfo->fck,
+                       "clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
+                       cinfo->fck);
 
        DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
 
@@ -542,121 +586,6 @@ static int dss_setup_default_clock(void)
        return 0;
 }
 
-int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
-               struct dispc_clock_info *dispc_cinfo)
-{
-       unsigned long prate;
-       struct dss_clock_info best_dss;
-       struct dispc_clock_info best_dispc;
-
-       unsigned long fck, max_dss_fck;
-
-       u16 fck_div;
-
-       int match = 0;
-       int min_fck_per_pck;
-
-       prate = dss_get_dpll4_rate();
-
-       max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
-       fck = clk_get_rate(dss.dss_clk);
-       if (req_pck == dss.cache_req_pck && prate == dss.cache_prate &&
-               dss.cache_dss_cinfo.fck == fck) {
-               DSSDBG("dispc clock info found from cache.\n");
-               *dss_cinfo = dss.cache_dss_cinfo;
-               *dispc_cinfo = dss.cache_dispc_cinfo;
-               return 0;
-       }
-
-       min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
-       if (min_fck_per_pck &&
-               req_pck * min_fck_per_pck > max_dss_fck) {
-               DSSERR("Requested pixel clock not possible with the current "
-                               "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
-                               "the constraint off.\n");
-               min_fck_per_pck = 0;
-       }
-
-retry:
-       memset(&best_dss, 0, sizeof(best_dss));
-       memset(&best_dispc, 0, sizeof(best_dispc));
-
-       if (dss.dpll4_m4_ck == NULL) {
-               struct dispc_clock_info cur_dispc;
-               /* XXX can we change the clock on omap2? */
-               fck = clk_get_rate(dss.dss_clk);
-               fck_div = 1;
-
-               dispc_find_clk_divs(req_pck, fck, &cur_dispc);
-               match = 1;
-
-               best_dss.fck = fck;
-               best_dss.fck_div = fck_div;
-
-               best_dispc = cur_dispc;
-
-               goto found;
-       } else {
-               for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
-                       struct dispc_clock_info cur_dispc;
-
-                       fck = prate / fck_div * dss.feat->dss_fck_multiplier;
-
-                       if (fck > max_dss_fck)
-                               continue;
-
-                       if (min_fck_per_pck &&
-                                       fck < req_pck * min_fck_per_pck)
-                               continue;
-
-                       match = 1;
-
-                       dispc_find_clk_divs(req_pck, fck, &cur_dispc);
-
-                       if (abs(cur_dispc.pck - req_pck) <
-                                       abs(best_dispc.pck - req_pck)) {
-
-                               best_dss.fck = fck;
-                               best_dss.fck_div = fck_div;
-
-                               best_dispc = cur_dispc;
-
-                               if (cur_dispc.pck == req_pck)
-                                       goto found;
-                       }
-               }
-       }
-
-found:
-       if (!match) {
-               if (min_fck_per_pck) {
-                       DSSERR("Could not find suitable clock settings.\n"
-                                       "Turning FCK/PCK constraint off and"
-                                       "trying again.\n");
-                       min_fck_per_pck = 0;
-                       goto retry;
-               }
-
-               DSSERR("Could not find suitable clock settings.\n");
-
-               return -EINVAL;
-       }
-
-       if (dss_cinfo)
-               *dss_cinfo = best_dss;
-       if (dispc_cinfo)
-               *dispc_cinfo = best_dispc;
-
-       dss.cache_req_pck = req_pck;
-       dss.cache_prate = prate;
-       dss.cache_dss_cinfo = best_dss;
-       dss.cache_dispc_cinfo = best_dispc;
-
-       return 0;
-}
-
 void dss_set_venc_output(enum omap_dss_venc_type type)
 {
        int l = 0;
@@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel)
 static int dss_get_clocks(void)
 {
        struct clk *clk;
-       int r;
 
-       clk = clk_get(&dss.pdev->dev, "fck");
+       clk = devm_clk_get(&dss.pdev->dev, "fck");
        if (IS_ERR(clk)) {
                DSSERR("can't get clock fck\n");
-               r = PTR_ERR(clk);
-               goto err;
+               return PTR_ERR(clk);
        }
 
        dss.dss_clk = clk;
@@ -782,8 +709,7 @@ static int dss_get_clocks(void)
                clk = clk_get(NULL, dss.feat->clk_name);
                if (IS_ERR(clk)) {
                        DSSERR("Failed to get %s\n", dss.feat->clk_name);
-                       r = PTR_ERR(clk);
-                       goto err;
+                       return PTR_ERR(clk);
                }
        } else {
                clk = NULL;
@@ -792,21 +718,12 @@ static int dss_get_clocks(void)
        dss.dpll4_m4_ck = clk;
 
        return 0;
-
-err:
-       if (dss.dss_clk)
-               clk_put(dss.dss_clk);
-       if (dss.dpll4_m4_ck)
-               clk_put(dss.dpll4_m4_ck);
-
-       return r;
 }
 
 static void dss_put_clocks(void)
 {
        if (dss.dpll4_m4_ck)
                clk_put(dss.dpll4_m4_ck);
-       clk_put(dss.dss_clk);
 }
 
 static int dss_runtime_get(void)
index 610c8e563daa2033750c3eec12f3328ad7db38e4..faaf35857b0e5a6abd36f526d84f0660a70420cf 100644 (file)
@@ -268,8 +268,9 @@ void dss_set_dac_pwrdn_bgz(bool enable);
 unsigned long dss_get_dpll4_rate(void);
 int dss_calc_clock_rates(struct dss_clock_info *cinfo);
 int dss_set_clock_div(struct dss_clock_info *cinfo);
-int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
-               struct dispc_clock_info *dispc_cinfo);
+
+typedef bool (*dss_div_calc_func)(int fckd, unsigned long fck, void *data);
+bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data);
 
 /* SDI */
 int sdi_init_platform_driver(void) __init;
@@ -292,12 +293,21 @@ void dsi_dump_clocks(struct seq_file *s);
 void dsi_irq_handler(void);
 u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
 
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
+
+typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
+               unsigned long pll, void *data);
+typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
+               void *data);
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+               unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+               unsigned long pll_min, unsigned long pll_max,
+               dsi_pll_calc_func func, void *data);
+
 unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
 int dsi_pll_set_clock_div(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo);
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
-               unsigned long req_pck, struct dsi_clock_info *cinfo,
-               struct dispc_clock_info *dispc_cinfo);
 int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv);
 void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
@@ -328,14 +338,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
        WARN("%s: DSI not compiled in\n", __func__);
        return -ENODEV;
 }
-static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
-               unsigned long req_pck,
-               struct dsi_clock_info *dsi_cinfo,
-               struct dispc_clock_info *dispc_cinfo)
-{
-       WARN("%s: DSI not compiled in\n", __func__);
-       return -ENODEV;
-}
 static inline int dsi_pll_init(struct platform_device *dsidev,
                bool enable_hsclk, bool enable_hsdiv)
 {
@@ -376,11 +378,15 @@ void dispc_enable_fifomerge(bool enable);
 void dispc_enable_gamma_table(bool enable);
 void dispc_set_loadmode(enum omap_dss_load_mode mode);
 
+typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
+               unsigned long pck, void *data);
+bool dispc_div_calc(unsigned long dispc,
+               unsigned long pck_min, unsigned long pck_max,
+               dispc_div_calc_func func, void *data);
+
 bool dispc_mgr_timings_ok(enum omap_channel channel,
                const struct omap_video_timings *timings);
 unsigned long dispc_fclk_rate(void);
-void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
-               struct dispc_clock_info *cinfo);
 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
                struct dispc_clock_info *cinfo);
 
index 7f791aeda4d24a1025e4d712f11e1b828cdb8b24..77dbe0cfb34ca28c540e5c22c9a593b6ae84018d 100644 (file)
@@ -414,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = {
 };
 
 static const struct dss_param_range omap2_dss_param_range[] = {
-       [FEAT_PARAM_DSS_FCK]                    = { 0, 173000000 },
+       [FEAT_PARAM_DSS_FCK]                    = { 0, 133000000 },
        [FEAT_PARAM_DSS_PCD]                    = { 2, 255 },
        [FEAT_PARAM_DSIPLL_REGN]                = { 0, 0 },
        [FEAT_PARAM_DSIPLL_REGM]                = { 0, 0 },
@@ -459,15 +459,15 @@ static const struct dss_param_range omap4_dss_param_range[] = {
 };
 
 static const struct dss_param_range omap5_dss_param_range[] = {
-       [FEAT_PARAM_DSS_FCK]                    = { 0, 200000000 },
+       [FEAT_PARAM_DSS_FCK]                    = { 0, 209250000 },
        [FEAT_PARAM_DSS_PCD]                    = { 1, 255 },
        [FEAT_PARAM_DSIPLL_REGN]                = { 0, (1 << 8) - 1 },
        [FEAT_PARAM_DSIPLL_REGM]                = { 0, (1 << 12) - 1 },
        [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, (1 << 5) - 1 },
        [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, (1 << 5) - 1 },
-       [FEAT_PARAM_DSIPLL_FINT]                = { 500000, 2500000 },
+       [FEAT_PARAM_DSIPLL_FINT]                = { 150000, 52000000 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, (1 << 13) - 1 },
-       [FEAT_PARAM_DSI_FCK]                    = { 0, 170000000 },
+       [FEAT_PARAM_DSI_FCK]                    = { 0, 209250000 },
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 2048 },
 };
index 72923645dcceddbaf303fdf601f165c6302cf346..79393099d50527a1909c5841735cd63a2eac7158 100644 (file)
@@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
         * Input clock is predivided by N + 1
         * out put of which is reference clk
         */
-       if (dssdev->clocks.hdmi.regn == 0)
-               pi->regn = HDMI_DEFAULT_REGN;
-       else
-               pi->regn = dssdev->clocks.hdmi.regn;
+
+       pi->regn = HDMI_DEFAULT_REGN;
 
        refclk = clkin / pi->regn;
 
-       if (dssdev->clocks.hdmi.regm2 == 0)
-               pi->regm2 = HDMI_DEFAULT_REGM2;
-       else
-               pi->regm2 = dssdev->clocks.hdmi.regm2;
+       pi->regm2 = HDMI_DEFAULT_REGM2;
 
        /*
         * multiplier is pixel_clk/ref_clk
@@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev)
 {
        struct clk *clk;
 
-       clk = clk_get(&pdev->dev, "sys_clk");
+       clk = devm_clk_get(&pdev->dev, "sys_clk");
        if (IS_ERR(clk)) {
                DSSERR("can't get sys_clk\n");
                return PTR_ERR(clk);
@@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev)
        return 0;
 }
 
-static void hdmi_put_clocks(void)
-{
-       if (hdmi.sys_clk)
-               clk_put(hdmi.sys_clk);
-}
-
 #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
 int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
 {
@@ -1017,8 +1006,6 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
        hdmi.ls_oe_gpio = priv->ls_oe_gpio;
        hdmi.hpd_gpio = priv->hpd_gpio;
 
-       dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
-
        r = hdmi_init_display(dssdev);
        if (r) {
                DSSERR("device %s init failed: %d\n", dssdev->name, r);
@@ -1051,6 +1038,8 @@ static void __init hdmi_init_output(struct platform_device *pdev)
        out->pdev = pdev;
        out->id = OMAP_DSS_OUTPUT_HDMI;
        out->type = OMAP_DISPLAY_TYPE_HDMI;
+       out->name = "hdmi.0";
+       out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
 
        dss_register_output(out);
 }
@@ -1097,23 +1086,19 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
        hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
        hdmi.ip_data.phy_offset = HDMI_PHY;
 
+       hdmi_init_output(pdev);
+
        r = hdmi_panel_init();
        if (r) {
                DSSERR("can't init panel\n");
-               goto err_panel_init;
+               return r;
        }
 
        dss_debugfs_create_file("hdmi", hdmi_dump_regs);
 
-       hdmi_init_output(pdev);
-
        hdmi_probe_pdata(pdev);
 
        return 0;
-
-err_panel_init:
-       hdmi_put_clocks();
-       return r;
 }
 
 static int __exit hdmi_remove_child(struct device *dev, void *data)
@@ -1135,8 +1120,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
-       hdmi_put_clocks();
-
        return 0;
 }
 
index 79dea1a1a7320a6f4198891b10172ee10f7afe6b..5214df63e0a9952b0332bfd81dcbbf4f95c77a1b 100644 (file)
@@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
 
        return NULL;
 }
+EXPORT_SYMBOL(omap_dss_get_output);
 
 static const struct dss_mgr_ops *dss_mgr_ops;
 
index e903dd3f54d9466e802126e3801ac0c86dc10d4c..1a691bb27547f3f8c5ebff21cf51063e7053fa0d 100644 (file)
@@ -1025,6 +1025,8 @@ static void __init rfbi_init_output(struct platform_device *pdev)
        out->pdev = pdev;
        out->id = OMAP_DSS_OUTPUT_DBI;
        out->type = OMAP_DISPLAY_TYPE_DBI;
+       out->name = "rfbi.0";
+       out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
 
        dss_register_output(out);
 }
index 62b5374ce438f3ff7e4db23d4ad5c6d5165456cd..e6baee2e84f8cb4b21672bf2e3eb3af01f6b9b20 100644 (file)
@@ -41,6 +41,72 @@ static struct {
        struct omap_dss_output output;
 } sdi;
 
+struct sdi_clk_calc_ctx {
+       unsigned long pck_min, pck_max;
+
+       struct dss_clock_info dss_cinfo;
+       struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+               unsigned long pck, void *data)
+{
+       struct sdi_clk_calc_ctx *ctx = data;
+
+       ctx->dispc_cinfo.lck_div = lckd;
+       ctx->dispc_cinfo.pck_div = pckd;
+       ctx->dispc_cinfo.lck = lck;
+       ctx->dispc_cinfo.pck = pck;
+
+       return true;
+}
+
+static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
+{
+       struct sdi_clk_calc_ctx *ctx = data;
+
+       ctx->dss_cinfo.fck = fck;
+       ctx->dss_cinfo.fck_div = fckd;
+
+       return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+                       dpi_calc_dispc_cb, ctx);
+}
+
+static int sdi_calc_clock_div(unsigned long pclk,
+               struct dss_clock_info *dss_cinfo,
+               struct dispc_clock_info *dispc_cinfo)
+{
+       int i;
+       struct sdi_clk_calc_ctx ctx;
+
+       /*
+        * DSS fclk gives us very few possibilities, so finding a good pixel
+        * clock may not be possible. We try multiple times to find the clock,
+        * each time widening the pixel clock range we look for, up to
+        * +/- 1MHz.
+        */
+
+       for (i = 0; i < 10; ++i) {
+               bool ok;
+
+               memset(&ctx, 0, sizeof(ctx));
+               if (pclk > 1000 * i * i * i)
+                       ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
+               else
+                       ctx.pck_min = 0;
+               ctx.pck_max = pclk + 1000 * i * i * i;
+
+               ok = dss_div_calc(ctx.pck_min, dpi_calc_dss_cb, &ctx);
+               if (ok) {
+                       *dss_cinfo = ctx.dss_cinfo;
+                       *dispc_cinfo = ctx.dispc_cinfo;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
 static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
 {
        struct omap_overlay_manager *mgr = dssdev->output->manager;
@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
        t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
 
-       r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
+       r = sdi_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
        if (r)
                goto err_calc_clock_div;
 
@@ -278,6 +344,8 @@ static void __init sdi_init_output(struct platform_device *pdev)
        out->pdev = pdev;
        out->id = OMAP_DSS_OUTPUT_SDI;
        out->type = OMAP_DISPLAY_TYPE_SDI;
+       out->name = "sdi.0";
+       out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
 
        dss_register_output(out);
 }
index 1598d27c28965c7c7007e277e4cfcca39cdabb83..17764d1363983ca178f85a89fe5e9cf2d044425e 100644 (file)
@@ -712,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev)
        struct clk *clk;
 
        if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
-               clk = clk_get(&pdev->dev, "tv_dac_clk");
+               clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
                if (IS_ERR(clk)) {
                        DSSERR("can't get tv_dac_clk\n");
                        return PTR_ERR(clk);
@@ -726,12 +726,6 @@ static int venc_get_clocks(struct platform_device *pdev)
        return 0;
 }
 
-static void venc_put_clocks(void)
-{
-       if (venc.tv_dac_clk)
-               clk_put(venc.tv_dac_clk);
-}
-
 static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
 {
        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
@@ -777,8 +771,6 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
 
        dss_copy_device_pdata(dssdev, plat_dssdev);
 
-       dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
-
        r = venc_init_display(dssdev);
        if (r) {
                DSSERR("device %s init failed: %d\n", dssdev->name, r);
@@ -810,6 +802,8 @@ static void __init venc_init_output(struct platform_device *pdev)
        out->pdev = pdev;
        out->id = OMAP_DSS_OUTPUT_VENC;
        out->type = OMAP_DISPLAY_TYPE_VENC;
+       out->name = "venc.0";
+       out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
 
        dss_register_output(out);
 }
@@ -877,7 +871,6 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
 err_panel_init:
 err_runtime_get:
        pm_runtime_disable(&pdev->dev);
-       venc_put_clocks();
        return r;
 }
 
@@ -895,7 +888,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)
        venc_uninit_output(pdev);
 
        pm_runtime_disable(&pdev->dev);
-       venc_put_clocks();
 
        return 0;
 }
index ca585ef37f2528d36d0534200a911db95b07baff..f38348ea33757eac5ed3af01e1145e8b246c721a 100644 (file)
@@ -2388,7 +2388,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
                struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
                struct omap_dss_output *out = dssdev->output;
 
-               mgr = omap_dss_get_overlay_manager(dssdev->channel);
+               mgr = omap_dss_get_overlay_manager(out->dispc_channel);
 
                if (!mgr || !out)
                        continue;
index caefa093337d9da1d0ba440cdc98665d91bb1801..62ca9a77c1d65dff76823857e895f61280893a1b 100644 (file)
@@ -257,10 +257,31 @@ void rfbi_bus_unlock(void);
 
 /* DSI */
 
+enum omap_dss_dsi_trans_mode {
+       /* Sync Pulses: both sync start and end packets sent */
+       OMAP_DSS_DSI_PULSE_MODE,
+       /* Sync Events: only sync start packets sent */
+       OMAP_DSS_DSI_EVENT_MODE,
+       /* Burst: only sync start packets sent, pixels are time compressed */
+       OMAP_DSS_DSI_BURST_MODE,
+};
+
 struct omap_dss_dsi_videomode_timings {
+       unsigned long hsclk;
+
+       unsigned ndl;
+       unsigned bitspp;
+
+       /* pixels */
+       u16 hact;
+       /* lines */
+       u16 vact;
+
        /* DSI video mode blanking data */
        /* Unit: byte clock cycles */
+       u16 hss;
        u16 hsa;
+       u16 hse;
        u16 hfp;
        u16 hbp;
        /* Unit: line clocks */
@@ -274,14 +295,24 @@ struct omap_dss_dsi_videomode_timings {
        int hbp_blanking_mode;
        int hfp_blanking_mode;
 
-       /* Video port sync events */
-       bool vp_vsync_end;
-       bool vp_hsync_end;
+       enum omap_dss_dsi_trans_mode trans_mode;
 
        bool ddr_clk_always_on;
        int window_sync;
 };
 
+struct omap_dss_dsi_config {
+       enum omap_dss_dsi_mode mode;
+       enum omap_dss_dsi_pixel_format pixel_format;
+       const struct omap_video_timings *timings;
+
+       unsigned long hs_clk_min, hs_clk_max;
+       unsigned long lp_clk_min, lp_clk_max;
+
+       bool ddr_clk_always_on;
+       enum omap_dss_dsi_trans_mode trans_mode;
+};
+
 void dsi_bus_lock(struct omap_dss_device *dssdev);
 void dsi_bus_unlock(struct omap_dss_device *dssdev);
 int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
@@ -541,9 +572,14 @@ struct omap_dss_writeback_info {
 struct omap_dss_output {
        struct list_head list;
 
+       const char *name;
+
        /* display type supported by the output */
        enum omap_display_type type;
 
+       /* DISPC channel for this output */
+       enum omap_channel dispc_channel;
+
        /* output instance */
        enum omap_dss_output_id id;
 
@@ -561,6 +597,7 @@ struct omap_dss_device {
 
        enum omap_display_type type;
 
+       /* obsolete, to be removed */
        enum omap_channel channel;
 
        union {
@@ -590,41 +627,11 @@ struct omap_dss_device {
                } venc;
        } phy;
 
-       struct {
-               struct {
-                       struct {
-                               u16 lck_div;
-                               u16 pck_div;
-                               enum omap_dss_clk_source lcd_clk_src;
-                       } channel;
-
-                       enum omap_dss_clk_source dispc_fclk_src;
-               } dispc;
-
-               struct {
-                       /* regn is one greater than TRM's REGN value */
-                       u16 regn;
-                       u16 regm;
-                       u16 regm_dispc;
-                       u16 regm_dsi;
-
-                       u16 lp_clk_div;
-                       enum omap_dss_clk_source dsi_fclk_src;
-               } dsi;
-
-               struct {
-                       /* regn is one greater than TRM's REGN value */
-                       u16 regn;
-                       u16 regm2;
-               } hdmi;
-       } clocks;
-
        struct {
                struct omap_video_timings timings;
 
                enum omap_dss_dsi_pixel_format dsi_pix_fmt;
                enum omap_dss_dsi_mode dsi_mode;
-               struct omap_dss_dsi_videomode_timings dsi_vm_timings;
        } panel;
 
        struct {
@@ -829,15 +836,8 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
 void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
                bool enable);
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
-void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings);
-void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h);
-void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
-               enum omap_dss_dsi_pixel_format fmt);
-void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
-               enum omap_dss_dsi_mode mode);
-void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
-               struct omap_dss_dsi_videomode_timings *timings);
+int omapdss_dsi_set_config(struct omap_dss_device *dssdev,
+               const struct omap_dss_dsi_config *config);
 
 int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
                void (*callback)(int, void *), void *data);
@@ -846,8 +846,6 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
 int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
                const struct omap_dsi_pin_config *pin_cfg);
-int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
-               unsigned long ddr_clk, unsigned long lp_clk);
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,