]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - drivers/video/omap2/dss/dsi.c
Merge tag 'fbdev-updates-for-3.7' of git://github.com/schandinat/linux-2.6
[can-eth-gw-linux.git] / drivers / video / omap2 / dss / dsi.c
index 05ee04667af1bdca019c8d4be15b78ce3d421b0f..d64ac3842884f4e9eac994dd03fdc311646d27b9 100644 (file)
@@ -41,7 +41,6 @@
 
 #include <video/omapdss.h>
 #include <video/mipi_display.h>
-#include <plat/clock.h>
 
 #include "dss.h"
 #include "dss_features.h"
@@ -333,6 +332,12 @@ struct dsi_data {
        unsigned scp_clk_refcount;
 
        struct dss_lcd_mgr_config mgr_config;
+       struct omap_video_timings timings;
+       enum omap_dss_dsi_pixel_format pix_fmt;
+       enum omap_dss_dsi_mode mode;
+       struct omap_dss_dsi_videomode_timings vm_timings;
+
+       struct omap_dss_output output;
 };
 
 struct dsi_packet_sent_handler_data {
@@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data {
        struct completion *completion;
 };
 
-static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
-
 #ifdef DEBUG
 static bool dsi_perf;
 module_param(dsi_perf, bool, 0644);
@@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside
 
 static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
 {
-       return dsi_pdev_map[dssdev->phy.dsi.module];
+       return dssdev->output->pdev;
 }
 
 struct platform_device *dsi_get_dsidev_from_id(int module)
 {
-       return dsi_pdev_map[module];
+       struct omap_dss_output *out;
+       enum omap_dss_output_id id;
+
+       id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+       out = omap_dss_get_output(id);
+
+       return out->pdev;
 }
 
 static inline void dsi_write_reg(struct platform_device *dsidev,
@@ -1450,6 +1460,148 @@ found:
        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)
+{
+       unsigned long max_dsi_fck;
+
+       max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
+
+       cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
+       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)
 {
@@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
 
        BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
 
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
+
        if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
                f = cinfo->fint < 1000000 ? 0x3 :
                        cinfo->fint < 1250000 ? 0x4 :
                        cinfo->fint < 1500000 ? 0x5 :
                        cinfo->fint < 1750000 ? 0x6 :
                        0x7;
-       }
 
-       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
-
-       if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
                l = FLD_MOD(l, f, 4, 1);        /* DSI_PLL_FREQSEL */
+       } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
+               f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
+
+               l = FLD_MOD(l, f, 4, 1);        /* PLL_SELFREQDCO */
+       }
+
        l = FLD_MOD(l, 1, 13, 13);              /* DSI_PLL_REFEN */
        l = FLD_MOD(l, 0, 14, 14);              /* DSIPHY_CLKINEN */
        l = FLD_MOD(l, 1, 20, 20);              /* DSI_HSDIVBYPASS */
+       if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
+               l = FLD_MOD(l, 3, 22, 21);      /* REF_SYSCLK = sysclk */
        dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
 
        REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0);       /* DSI_PLL_GO */
@@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
                return 1194 * 3;        /* 1194x24 bits */
        case 6:
                return 1365 * 3;        /* 1365x24 bits */
+       case 7:
+               return 1920 * 3;        /* 1920x24 bits */
        default:
                BUG();
                return 0;
        }
 }
 
-static int dsi_set_lane_config(struct omap_dss_device *dssdev)
+static int dsi_set_lane_config(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        static const u8 offsets[] = { 0, 4, 8, 12, 16 };
        static const enum dsi_lane_function functions[] = {
@@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev)
        dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
 
        r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
-       r = FLD_MOD(r, tlpx_half, 22, 16);
+       r = FLD_MOD(r, tlpx_half, 20, 16);
        r = FLD_MOD(r, tclk_trail, 15, 8);
        r = FLD_MOD(r, tclk_zero, 7, 0);
+
+       if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
+               r = FLD_MOD(r, 0, 21, 21);      /* DCCEN = disable */
+               r = FLD_MOD(r, 1, 22, 22);      /* CLKINP_DIVBY2EN = enable */
+               r = FLD_MOD(r, 1, 23, 23);      /* CLKINP_SEL = enable */
+       }
+
        dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
 
        r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
@@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev)
 }
 
 /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
-static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
+static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
                unsigned mask_p, unsigned mask_n)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
        u32 l;
@@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
        REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
 }
 
-static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
+static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int t, i;
        bool in_use[DSI_MAX_NR_LANES];
@@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
 }
 
 /* return bitmask of enabled lanes, lane0 being the lsb */
-static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
+static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned mask = 0;
        int i;
@@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
        return mask;
 }
 
-static int dsi_cio_init(struct omap_dss_device *dssdev)
+static int dsi_cio_init(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r;
        u32 l;
 
        DSSDBGF();
 
-       r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+       r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
        if (r)
                return r;
 
@@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
                goto err_scp_clk_dom;
        }
 
-       r = dsi_set_lane_config(dssdev);
+       r = dsi_set_lane_config(dsidev);
        if (r)
                goto err_scp_clk_dom;
 
@@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
                        mask_p |= 1 << i;
                }
 
-               dsi_cio_enable_lane_override(dssdev, mask_p, 0);
+               dsi_cio_enable_lane_override(dsidev, mask_p, 0);
        }
 
        r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
@@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
        dsi_if_enable(dsidev, false);
        REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
 
-       r = dsi_cio_wait_tx_clk_esc_reset(dssdev);
+       r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
        if (r)
                goto err_tx_clk_esc_rst;
 
@@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
 
        dsi_cio_timings(dsidev);
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+       if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                /* DDR_CLK_ALWAYS_ON */
                REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
-                       dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13);
+                       dsi->vm_timings.ddr_clk_always_on, 13, 13);
        }
 
        dsi->ulps_enabled = false;
@@ -2381,13 +2543,12 @@ err_cio_pwr:
                dsi_cio_disable_lane_override(dsidev);
 err_scp_clk_dom:
        dsi_disable_scp_clk(dsidev);
-       dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+       dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
        return r;
 }
 
-static void dsi_cio_uninit(struct omap_dss_device *dssdev)
+static void dsi_cio_uninit(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        /* DDR_CLK_ALWAYS_ON */
@@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev)
 
        dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
        dsi_disable_scp_clk(dsidev);
-       dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+       dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
 }
 
 static void dsi_config_tx_fifo(struct platform_device *dsidev,
@@ -2685,6 +2846,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
                bool enable)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
 
@@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
        dsi_force_tx_stop_mode_io(dsidev);
 
        /* start the DDR clock by sending a NULL packet */
-       if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable)
+       if (dsi->vm_timings.ddr_clk_always_on && enable)
                dsi_vc_send_null(dssdev, channel);
 }
 EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
@@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
 }
 EXPORT_SYMBOL(dsi_vc_send_null);
 
-static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
+static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
                int channel, u8 *data, int len, enum dss_dsi_content_type type)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
        if (len == 0) {
@@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
 int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
                u8 *data, int len)
 {
-       return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+       return dsi_vc_write_nosync_common(dsidev, channel, data, len,
                        DSS_DSI_CONTENT_DCS);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
@@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
 int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
                u8 *data, int len)
 {
-       return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+       return dsi_vc_write_nosync_common(dsidev, channel, data, len,
                        DSS_DSI_CONTENT_GENERIC);
 }
 EXPORT_SYMBOL(dsi_vc_generic_write_nosync);
@@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type);
+       r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
        if (r)
                goto err;
 
@@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel,
 }
 EXPORT_SYMBOL(dsi_vc_generic_write_2);
 
-static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
+static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
                int channel, u8 dcs_cmd)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r;
 
@@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
        return 0;
 }
 
-static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev,
+static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
                int channel, u8 *reqdata, int reqlen)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u16 data;
        u8 data_type;
@@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd);
+       r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
        if (r)
                goto err;
 
@@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen);
+       r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
        if (r)
                return r;
 
@@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
+static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int num_line_buffers;
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
-               int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+       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 = &dssdev->panel.timings;
+               struct omap_video_timings *timings = &dsi->timings;
                /*
                 * Don't use line buffers if width is greater than the video
                 * port's line buffer size
@@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
        REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
 }
 
-static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
+static void dsi_config_vp_sync_events(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end;
-       bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
+       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;
        u32 r;
 
        r = dsi_read_reg(dsidev, DSI_CTRL);
@@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
        dsi_write_reg(dsidev, DSI_CTRL, r);
 }
 
-static void dsi_config_blanking_modes(struct omap_dss_device *dssdev)
+static void dsi_config_blanking_modes(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode;
-       int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode;
-       int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode;
-       int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int blanking_mode = dsi->vm_timings.blanking_mode;
+       int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
+       int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
+       int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
        u32 r;
 
        /*
@@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
        int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
        int tclk_trail, ths_exit, exiths_clk;
        bool ddr_alwon;
-       struct omap_video_timings *timings = &dssdev->panel.timings;
-       int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+       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 hsa_interleave_hs = 0, hsa_interleave_lp = 0;
@@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r;
        int buswidth = 0;
 
@@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
        dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
 
-       switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) {
+       switch (dsi_get_pixel_size(dsi->pix_fmt)) {
        case 16:
                buswidth = 0;
                break;
@@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
 
        dsi_write_reg(dsidev, DSI_CTRL, r);
 
-       dsi_config_vp_num_line_buffers(dssdev);
+       dsi_config_vp_num_line_buffers(dsidev);
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
-               dsi_config_vp_sync_events(dssdev);
-               dsi_config_blanking_modes(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);
        }
 
@@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void dsi_proto_timings(struct omap_dss_device *dssdev)
+static void dsi_proto_timings(struct platform_device *dsidev)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
        unsigned tclk_pre, tclk_post;
@@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        ths_exit = FLD_GET(r, 7, 0);
 
        r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
-       tlpx = FLD_GET(r, 22, 16) * 2;
+       tlpx = FLD_GET(r, 20, 16) * 2;
        tclk_trail = FLD_GET(r, 15, 8);
        tclk_zero = FLD_GET(r, 7, 0);
 
@@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
                        enter_hs_mode_lat, exit_hs_mode_lat);
 
-        if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+        if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                /* TODO: Implement a video mode check_timings function */
-               int hsa = dssdev->panel.dsi_vm_data.hsa;
-               int hfp = dssdev->panel.dsi_vm_data.hfp;
-               int hbp = dssdev->panel.dsi_vm_data.hbp;
-               int vsa = dssdev->panel.dsi_vm_data.vsa;
-               int vfp = dssdev->panel.dsi_vm_data.vfp;
-               int vbp = dssdev->panel.dsi_vm_data.vbp;
-               int window_sync = dssdev->panel.dsi_vm_data.window_sync;
-               bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
-               struct omap_video_timings *timings = &dssdev->panel.timings;
-               int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+               int hsa = dsi->vm_timings.hsa;
+               int hfp = dsi->vm_timings.hfp;
+               int hbp = dsi->vm_timings.hbp;
+               int vsa = dsi->vm_timings.vsa;
+               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;
+               struct omap_video_timings *timings = &dsi->timings;
+               int bpp = dsi_get_pixel_size(dsi->pix_fmt);
                int tl, t_he, width_bytes;
 
                t_he = hsync_end ?
@@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_dsi_configure_pins);
 
-int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
+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;
+
+       DSSDBGF("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;
+       int bpp = dsi_get_pixel_size(dsi->pix_fmt);
        u8 data_type;
        u16 word_count;
        int r;
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
-               switch (dssdev->panel.dsi_pix_fmt) {
+       if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               switch (dsi->pix_fmt) {
                case OMAP_DSS_DSI_FMT_RGB888:
                        data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
                        break;
@@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
                /* MODE, 1 = video mode */
                REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
 
-               word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
+               word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
 
                dsi_vc_write_long_header(dsidev, channel, data_type,
                                word_count, 0);
@@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
                dsi_if_enable(dsidev, true);
        }
 
-       r = dss_mgr_enable(dssdev->manager);
+       r = dss_mgr_enable(mgr);
        if (r) {
-               if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                        dsi_if_enable(dsidev, false);
                        dsi_vc_enable(dsidev, channel, false);
                }
@@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output);
 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;
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+       if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
                dsi_if_enable(dsidev, false);
                dsi_vc_enable(dsidev, channel, false);
 
@@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
                dsi_if_enable(dsidev, true);
        }
 
-       dss_mgr_disable(dssdev->manager);
+       dss_mgr_disable(mgr);
 }
 EXPORT_SYMBOL(dsi_disable_video_output);
 
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
-               u16 w, u16 h)
+static void dsi_update_screen_dispc(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_overlay_manager *mgr = dssdev->output->manager;
        unsigned bytespp;
        unsigned bytespl;
        unsigned bytespf;
@@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        int r;
        const unsigned channel = dsi->update_channel;
        const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+       u16 w = dsi->timings.x_res;
+       u16 h = dsi->timings.y_res;
 
        DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
 
        dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
 
-       bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+       bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
        bytespl = w * bytespp;
        bytespf = bytespl * h;
 
@@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                msecs_to_jiffies(250));
        BUG_ON(r == 0);
 
-       dss_mgr_start_update(dssdev->manager);
+       dss_mgr_set_timings(mgr, &dsi->timings);
+
+       dss_mgr_start_update(mgr);
 
        if (dsi->te_enabled) {
                /* disable LP_RX_TO, so that we can receive TE.  Time to wait
@@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 
 static void dsi_framedone_irq_callback(void *data, u32 mask)
 {
-       struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct platform_device *dsidev = (struct platform_device *) data;
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
@@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
        dsi->framedone_callback = callback;
        dsi->framedone_data = data;
 
-       dssdev->driver->get_resolution(dssdev, &dw, &dh);
+       dw = dsi->timings.x_res;
+       dh = dsi->timings.y_res;
 
 #ifdef DEBUG
        dsi->update_bytes = dw * dh *
-               dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+               dsi_get_pixel_size(dsi->pix_fmt) / 8;
 #endif
-       dsi_update_screen_dispc(dssdev, dw, dh);
+       dsi_update_screen_dispc(dssdev);
 
        return 0;
 }
@@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(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_video_timings timings;
+       struct omap_overlay_manager *mgr = dssdev->output->manager;
        int r;
        u32 irq = 0;
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
-               u16 dw, dh;
-
-               dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
-               timings.x_res = dw;
-               timings.y_res = dh;
-               timings.hsw = 1;
-               timings.hfp = 1;
-               timings.hbp = 1;
-               timings.vsw = 1;
-               timings.vfp = 0;
-               timings.vbp = 0;
+       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;
 
-               irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+               irq = dispc_mgr_get_framedone_irq(mgr->id);
 
                r = omap_dispc_register_isr(dsi_framedone_irq_callback,
-                       (void *) dssdev, irq);
+                       (void *) dsidev, irq);
                if (r) {
                        DSSERR("can't get FRAMEDONE irq\n");
                        goto err;
@@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
                dsi->mgr_config.stallmode = true;
                dsi->mgr_config.fifohandcheck = true;
        } else {
-               timings = dssdev->panel.timings;
-
                dsi->mgr_config.stallmode = false;
                dsi->mgr_config.fifohandcheck = false;
        }
@@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
         * override interlace, logic level and edge related parameters in
         * omap_video_timings with default values
         */
-       timings.interlace = false;
-       timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
-       timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
-       timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
-       timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
-       timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+       dsi->timings.interlace = false;
+       dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+       dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+       dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+       dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+       dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
 
-       dss_mgr_set_timings(dssdev->manager, &timings);
+       dss_mgr_set_timings(mgr, &dsi->timings);
 
        r = dsi_configure_dispc_clocks(dssdev);
        if (r)
@@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 
        dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
        dsi->mgr_config.video_port_width =
-                       dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+                       dsi_get_pixel_size(dsi->pix_fmt);
        dsi->mgr_config.lcden_sig_polarity = 0;
 
-       dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config);
+       dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
 
        return 0;
 err1:
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE)
+       if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
                omap_dispc_unregister_isr(dsi_framedone_irq_callback,
-                       (void *) dssdev, irq);
+                       (void *) dsidev, irq);
 err:
        return r;
 }
 
 static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
 {
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+       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) {
                u32 irq;
 
-               irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+               irq = dispc_mgr_get_framedone_irq(mgr->id);
 
                omap_dispc_unregister_isr(dsi_framedone_irq_callback,
-                       (void *) dssdev, irq);
+                       (void *) dsidev, irq);
        }
 }
 
@@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(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_overlay_manager *mgr = dssdev->output->manager;
        int r;
 
        r = dsi_pll_init(dsidev, true, true);
@@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 
        dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
        dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
-       dss_select_lcd_clk_source(dssdev->manager->id,
+       dss_select_lcd_clk_source(mgr->id,
                        dssdev->clocks.dispc.channel.lcd_clk_src);
 
        DSSDBG("PLL OK\n");
 
-       r = dsi_cio_init(dssdev);
+       r = dsi_cio_init(dsidev);
        if (r)
                goto err2;
 
        _dsi_print_reset_status(dsidev);
 
-       dsi_proto_timings(dssdev);
+       dsi_proto_timings(dsidev);
        dsi_set_lp_clk_divisor(dssdev);
 
        if (1)
@@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 
        return 0;
 err3:
-       dsi_cio_uninit(dssdev);
+       dsi_cio_uninit(dsidev);
 err2:
        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
        dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
-       dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+       dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
 
 err1:
        dsi_pll_uninit(dsidev, true);
@@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(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_overlay_manager *mgr = dssdev->output->manager;
 
        if (enter_ulps && !dsi->ulps_enabled)
                dsi_enter_ulps(dsidev);
@@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
 
        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
        dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
-       dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
-       dsi_cio_uninit(dssdev);
+       dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
+       dsi_cio_uninit(dsidev);
        dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
@@ -4559,6 +4794,7 @@ 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");
@@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 
        mutex_lock(&dsi->lock);
 
-       if (dssdev->manager == NULL) {
-               DSSERR("failed to enable display: no manager\n");
+       if (out == NULL || out->manager == NULL) {
+               DSSERR("failed to enable display: no output/manager\n");
                r = -ENODEV;
                goto err_start_dev;
        }
@@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
-static int __init dsi_init_display(struct omap_dss_device *dssdev)
+void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-       DSSDBG("DSI init\n");
+       mutex_lock(&dsi->lock);
 
-       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
-               dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
-                       OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
-       }
+       dsi->timings = *timings;
+
+       mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_timings);
+
+void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       mutex_lock(&dsi->lock);
+
+       dsi->timings.x_res = w;
+       dsi->timings.y_res = h;
+
+       mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_size);
+
+void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
+               enum omap_dss_dsi_pixel_format fmt)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       mutex_lock(&dsi->lock);
+
+       dsi->pix_fmt = fmt;
+
+       mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
+
+void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
+               enum omap_dss_dsi_mode mode)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       mutex_lock(&dsi->lock);
+
+       dsi->mode = mode;
+
+       mutex_unlock(&dsi->lock);
+}
+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)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       mutex_lock(&dsi->lock);
+
+       dsi->vm_timings = *timings;
+
+       mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
+
+static int __init dsi_init_display(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev =
+                       dsi_get_dsidev_from_id(dssdev->phy.dsi.module);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       DSSDBG("DSI init\n");
 
        if (dsi->vdds_dsi_reg == NULL) {
                struct regulator *vdds_dsi;
@@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev)
                clk_put(dsi->sys_clk);
 }
 
-static void __init dsi_probe_pdata(struct platform_device *dsidev)
+static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
 {
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_dss_board_info *pdata = dsidev->dev.platform_data;
-       int i, r;
+       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+       const char *def_disp_name = dss_get_default_display_name();
+       struct omap_dss_device *def_dssdev;
+       int i;
+
+       def_dssdev = NULL;
 
        for (i = 0; i < pdata->num_devices; ++i) {
                struct omap_dss_device *dssdev = pdata->devices[i];
@@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
                if (dssdev->phy.dsi.module != dsi->module_id)
                        continue;
 
-               r = dsi_init_display(dssdev);
-               if (r) {
-                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
-                       continue;
+               if (def_dssdev == NULL)
+                       def_dssdev = dssdev;
+
+               if (def_disp_name != NULL &&
+                               strcmp(dssdev->name, def_disp_name) == 0) {
+                       def_dssdev = dssdev;
+                       break;
                }
+       }
 
-               r = omap_dss_register_device(dssdev, &dsidev->dev, i);
-               if (r)
-                       DSSERR("device %s register failed: %d\n",
-                                       dssdev->name, r);
+       return def_dssdev;
+}
+
+static void __init dsi_probe_pdata(struct platform_device *dsidev)
+{
+       struct omap_dss_device *plat_dssdev;
+       struct omap_dss_device *dssdev;
+       int r;
+
+       plat_dssdev = dsi_find_dssdev(dsidev);
+
+       if (!plat_dssdev)
+               return;
+
+       dssdev = dss_alloc_and_init_device(&dsidev->dev);
+       if (!dssdev)
+               return;
+
+       dss_copy_device_pdata(dssdev, plat_dssdev);
+
+       r = dsi_init_display(dssdev);
+       if (r) {
+               DSSERR("device %s init failed: %d\n", dssdev->name, r);
+               dss_put_device(dssdev);
+               return;
+       }
+
+       r = dss_add_device(dssdev);
+       if (r) {
+               DSSERR("device %s register failed: %d\n", dssdev->name, r);
+               dss_put_device(dssdev);
+               return;
        }
 }
 
+static void __init dsi_init_output(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct omap_dss_output *out = &dsi->output;
+
+       out->pdev = dsidev;
+       out->id = dsi->module_id == 0 ?
+                       OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+       out->type = OMAP_DISPLAY_TYPE_DSI;
+
+       dss_register_output(out);
+}
+
+static void __exit dsi_uninit_output(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct omap_dss_output *out = &dsi->output;
+
+       dss_unregister_output(out);
+}
+
 /* DSI1 HW IP initialisation */
 static int __init omap_dsihw_probe(struct platform_device *dsidev)
 {
@@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
 
        dsi->module_id = dsidev->id;
        dsi->pdev = dsidev;
-       dsi_pdev_map[dsi->module_id] = dsidev;
        dev_set_drvdata(&dsidev->dev, dsi);
 
        spin_lock_init(&dsi->irq_lock);
@@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
        else
                dsi->num_lanes_supported = 3;
 
+       dsi_init_output(dsidev);
+
        dsi_probe_pdata(dsidev);
 
        dsi_runtime_put(dsidev);
@@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
 
        WARN_ON(dsi->scp_clk_refcount > 0);
 
-       omap_dss_unregister_child_devices(&dsidev->dev);
+       dss_unregister_child_devices(&dsidev->dev);
+
+       dsi_uninit_output(dsidev);
 
        pm_runtime_disable(&dsidev->dev);