diff options
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 621 |
1 files changed, 457 insertions, 164 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 345757c..93b52f6 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -36,6 +36,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/debugfs.h> +#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/clock.h> @@ -205,6 +206,7 @@ struct dsi_reg { u16 idx; }; #define DSI_DT_DCS_LONG_WRITE 0x39 #define DSI_DT_RX_ACK_WITH_ERR 0x02 +#define DSI_DT_RX_LONG_READ 0x1a #define DSI_DT_RX_DCS_LONG_READ 0x1c #define DSI_DT_RX_SHORT_READ_1 0x21 #define DSI_DT_RX_SHORT_READ_2 0x22 @@ -267,8 +269,15 @@ struct dsi_isr_tables { struct dsi_data { struct platform_device *pdev; void __iomem *base; + + struct mutex runtime_lock; + int runtime_count; + int irq; + struct clk *dss_clk; + struct clk *sys_clk; + void (*dsi_mux_pads)(bool enable); struct dsi_clock_info current_cinfo; @@ -389,15 +398,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev, return __raw_readl(dsi->base + idx.idx); } - -void dsi_save_context(void) -{ -} - -void dsi_restore_context(void) -{ -} - void dsi_bus_lock(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -493,9 +493,18 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_bytes * 1000 / total_us); } #else -#define dsi_perf_mark_setup(x) -#define dsi_perf_mark_start(x) -#define dsi_perf_show(x, y) +static inline void dsi_perf_mark_setup(struct platform_device *dsidev) +{ +} + +static inline void dsi_perf_mark_start(struct platform_device *dsidev) +{ +} + +static inline void dsi_perf_show(struct platform_device *dsidev, + const char *name) +{ +} #endif static void print_irq_status(u32 status) @@ -1039,13 +1048,69 @@ static u32 dsi_get_errors(struct platform_device *dsidev) return e; } -/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ -static inline void enable_clocks(bool enable) +int dsi_runtime_get(struct platform_device *dsidev) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int r; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->runtime_lock); + + if (dsi->runtime_count++ == 0) { + DSSDBG("dsi_runtime_get\n"); + + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; + + /* XXX dsi fclk can also come from DSI PLL */ + clk_enable(dsi->dss_clk); + + r = pm_runtime_get_sync(&dsi->pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + } + + mutex_unlock(&dsi->runtime_lock); + + return 0; + +err_runtime_get: + clk_disable(dsi->dss_clk); + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: + mutex_unlock(&dsi->runtime_lock); + + return r; +} + +void dsi_runtime_put(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->runtime_lock); + + if (--dsi->runtime_count == 0) { + int r; + + DSSDBG("dsi_runtime_put\n"); + + r = pm_runtime_put_sync(&dsi->pdev->dev); + WARN_ON(r); + + clk_disable(dsi->dss_clk); + + dispc_runtime_put(); + dss_runtime_put(); + } + + mutex_unlock(&dsi->runtime_lock); } /* source clock for DSI PLL. this could also be PCLKFREE */ @@ -1055,9 +1120,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (enable) - dss_clk_enable(DSS_CLK_SYSCK); + clk_enable(dsi->sys_clk); else - dss_clk_disable(DSS_CLK_SYSCK); + clk_disable(dsi->sys_clk); if (enable && dsi->pll_locked) { if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) @@ -1150,10 +1215,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) { unsigned long r; int dsi_module = dsi_get_dsidev_id(dsidev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dsi->dss_clk); } else { /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ r = dsi_get_pll_hsdiv_dsi_rate(dsidev); @@ -1262,7 +1328,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, return -EINVAL; if (cinfo->use_sys_clk) { - cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK); + cinfo->clkin = clk_get_rate(dsi->sys_clk); /* XXX it is unclear if highfreq should be used * with DSS_SYS_CLK source also */ cinfo->highfreq = 0; @@ -1311,7 +1377,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, int match = 0; unsigned long dss_sys_clk, max_dss_fck; - dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); + dss_sys_clk = clk_get_rate(dsi->sys_clk); max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); @@ -1539,6 +1605,9 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, 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 (cpu_is_omap44xx()) + l = FLD_MOD(l, 3, 22, 21); /* DSI_REF_SEL */ dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ @@ -1601,7 +1670,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, dsi->vdds_dsi_reg = vdds_dsi; } - enable_clocks(1); dsi_enable_pll_clock(dsidev, 1); /* * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. @@ -1653,7 +1721,6 @@ err1: } err0: dsi_disable_scp_clk(dsidev); - enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); return r; } @@ -1671,7 +1738,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) } dsi_disable_scp_clk(dsidev); - enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); DSSDBG("PLL uninit done\n"); @@ -1688,7 +1754,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, dispc_clk_src = dss_get_dispc_clk_source(); dsi_clk_src = dss_get_dsi_clk_source(dsi_module); - enable_clocks(1); + if (dsi_runtime_get(dsidev)) + return; seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); @@ -1731,7 +1798,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk); - enable_clocks(0); + dsi_runtime_put(dsidev); } void dsi_dump_clocks(struct seq_file *s) @@ -1873,7 +1940,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dsi_runtime_get(dsidev)) + return; dsi_enable_scp_clk(dsidev); DUMPREG(DSI_REVISION); @@ -1947,7 +2015,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, DUMPREG(DSI_PLL_CONFIGURATION2); dsi_disable_scp_clk(dsidev); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dsi_runtime_put(dsidev); #undef DUMPREG } @@ -1994,6 +2062,10 @@ static int dsi_cio_power(struct platform_device *dsidev, /* PWR_CMD */ REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27); + if (cpu_is_omap44xx()) + /*bit 30 has to be set to 1 to GO in omap4*/ + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, 1, 30, 30); + /* PWR_STATUS */ while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1), 26, 25) != state) { @@ -2354,6 +2426,13 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) if (dsi->dsi_mux_pads) dsi->dsi_mux_pads(true); + if (cpu_is_omap44xx()) { + /* DDR_CLK_ALWAYS_ON */ + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); + /* HS_AUTO_STOP_ENABLE */ + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 18, 18); + } + dsi_enable_scp_clk(dsidev); /* A dummy read using the SCP interface to any DSIPHY register is @@ -2463,28 +2542,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev) dsi->dsi_mux_pads(false); } -static int _dsi_wait_reset(struct platform_device *dsidev) -{ - int t = 0; - - while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) { - if (++t > 5) { - DSSERR("soft reset failed\n"); - return -ENODEV; - } - udelay(1); - } - - return 0; -} - -static int _dsi_reset(struct platform_device *dsidev) -{ - /* Soft reset */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1); - return _dsi_wait_reset(dsidev); -} - static void dsi_config_tx_fifo(struct platform_device *dsidev, enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) @@ -2722,6 +2779,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */ if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH)) r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */ + if (channel == 0) + r = FLD_MOD(r, 1, 11, 10); /* OCP_WIDTH = 32 bit */ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ @@ -2885,6 +2944,10 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, } else if (dt == DSI_DT_RX_SHORT_READ_2) { DSSERR("\tDCS short response, 2 byte: %#x\n", FLD_GET(val, 23, 8)); + } else if (dt == DSI_DT_RX_LONG_READ) { + DSSERR("\tlong response, len %d\n", + FLD_GET(val, 23, 8)); + dsi_vc_flush_long_data(dsidev, channel); } else if (dt == DSI_DT_RX_DCS_LONG_READ) { DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); @@ -3229,7 +3292,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, buf[1] = (data >> 8) & 0xff; return 2; - } else if (dt == DSI_DT_RX_DCS_LONG_READ) { + } else if (dt == DSI_DT_RX_DCS_LONG_READ || dt == DSI_DT_RX_LONG_READ) { int w; int len = FLD_GET(val, 23, 8); if (dsi->debug_read) @@ -3386,6 +3449,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); + /* Reset LANEx_ULPS_SIG2 */ + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), + 7, 5); + dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); dsi_if_enable(dsidev, false); @@ -3401,7 +3468,7 @@ err: } static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned ticks, bool x4, bool x16, bool to) { unsigned long fck; unsigned long total_ticks; @@ -3413,7 +3480,7 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, fck = dsi_fclk_rate(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING2); - r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ + r = FLD_MOD(r, to ? 1 : 0, 15, 15); /* LP_RX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ @@ -3428,7 +3495,7 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, } static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, - bool x8, bool x16) + bool x8, bool x16, bool to) { unsigned long fck; unsigned long total_ticks; @@ -3440,7 +3507,7 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, fck = dsi_fclk_rate(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING1); - r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ + r = FLD_MOD(r, to ? 1 : 0, 31, 31); /* TA_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ @@ -3455,7 +3522,8 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, } static void dsi_set_stop_state_counter(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned ticks, bool x4, bool x16, + bool stop_mode) { unsigned long fck; unsigned long total_ticks; @@ -3467,7 +3535,7 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, fck = dsi_fclk_rate(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING1); - r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ + r = FLD_MOD(r, stop_mode ? 1 : 0, 15, 15); /* FORCE_TX_STOP_MODE_IO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ @@ -3482,7 +3550,7 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, } static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned ticks, bool x4, bool x16, bool to) { unsigned long fck; unsigned long total_ticks; @@ -3494,7 +3562,7 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, fck = dsi_get_txbyteclkhs(dsidev); r = dsi_read_reg(dsidev, DSI_TIMING2); - r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ + r = FLD_MOD(r, to ? 1 : 0, 31, 31); /* HS_TX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ @@ -3507,7 +3575,8 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, ticks, x4 ? " x4" : "", x16 ? " x16" : "", (total_ticks * 1000) / (fck / 1000 / 1000)); } -static int dsi_proto_config(struct omap_dss_device *dssdev) + +static int dsi_cmd_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); u32 r; @@ -3524,10 +3593,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ - dsi_set_stop_state_counter(dsidev, 0x1000, false, false); - dsi_set_ta_timeout(dsidev, 0x1fff, true, true); - dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); - dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); + dsi_set_stop_state_counter(dsidev, 0x1000, false, false, true); + dsi_set_ta_timeout(dsidev, 0x1fff, true, true, true); + dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true, true); + dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true, true); switch (dssdev->ctrl.pixel_size) { case 16: @@ -3569,6 +3638,165 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) return 0; } +static int dispc_to_dsi_clock(int val, int bytes_per_pixel, int lanes) +{ + return (val * bytes_per_pixel + lanes / 2) / lanes; +} +static int dsi_video_proto_config(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct omap_video_timings *timings = &dssdev->panel.timings; + int buswidth = 0; + u32 r; + int bytes_per_pixel; + int hbp, hfp, hsa, tl; + + dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); + + dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32, + DSI_FIFO_SIZE_32); + + dsi_set_stop_state_counter(dsidev, 0x1fff, true, true, false); + dsi_set_ta_timeout(dsidev, 0x1fff, true, true, true); + dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true, false); + dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true, true); + + switch (dssdev->ctrl.pixel_size) { + case 16: + buswidth = 0; + bytes_per_pixel = 2; + break; + case 18: + buswidth = 1; + bytes_per_pixel = 3; + break; + case 24: + buswidth = 2; + bytes_per_pixel = 3; + break; + default: + BUG(); + } + + r = dsi_read_reg(dsidev, DSI_CTRL); + r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */ + r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/ + r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */ + r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ + r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ + r = FLD_MOD(r, 0, 10, 10); /* VP_HSYNC_POL */ + r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ + r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER */ + r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ + r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ + r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ + r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ + r = FLD_MOD(r, 1, 20, 20); /* BLANKING_MODE */ + r = FLD_MOD(r, 1, 21, 21); /* HFP_BLANKING */ + r = FLD_MOD(r, 1, 22, 22); /* HBP_BLANKING */ + r = FLD_MOD(r, 1, 23, 23); /* HSA_BLANKING */ + dsi_write_reg(dsidev, DSI_CTRL, r); + + if(!dssdev->skip_init){ + dsi_vc_initial_config(dsidev, 0); + dsi_vc_initial_config(dsidev, 1); + dsi_vc_initial_config(dsidev, 2); + dsi_vc_initial_config(dsidev, 3); + } + + hbp = dispc_to_dsi_clock(timings->hbp, bytes_per_pixel, 4); + hfp = dispc_to_dsi_clock(timings->hfp, bytes_per_pixel, 4); + hsa = dispc_to_dsi_clock(timings->hsw, bytes_per_pixel, 4); + tl = hbp + hfp + hsa + + dispc_to_dsi_clock(timings->x_res, bytes_per_pixel, 4); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = FLD_MOD(r, hbp - 1, 11, 0); /* HBP */ + r = FLD_MOD(r, hfp - 1, 23, 12); /* HFP */ + r = FLD_MOD(r, hsa - 1, 31, 24); /* HSA */ + dsi_write_reg(dsidev, DSI_VM_TIMING1, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING2); + r = FLD_MOD(r, timings->vbp, 7, 0); /* VBP */ + r = FLD_MOD(r, timings->vfp, 15, 8); /* VFP */ + r = FLD_MOD(r, timings->vsw, 23, 16); /* VSA */ + r = FLD_MOD(r, 4, 27, 24); /* WINDOW_SYNC */ + dsi_write_reg(dsidev, DSI_VM_TIMING2, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING3); + r = FLD_MOD(r, timings->y_res, 14, 0); + r = FLD_MOD(r, tl - 1, 31, 16); + dsi_write_reg(dsidev, DSI_VM_TIMING3, r); + + /* TODO: either calculate these values or make them configurable */ + r = FLD_VAL(72, 23, 16) | /* HSA_HS_INTERLEAVING */ + FLD_VAL(114, 15, 8) | /* HFB_HS_INTERLEAVING */ + FLD_VAL(150, 7, 0); /* HbB_HS_INTERLEAVING */ + dsi_write_reg(dsidev, DSI_VM_TIMING4, r); + + r = FLD_VAL(130, 23, 16) | /* HSA_LP_INTERLEAVING */ + FLD_VAL(223, 15, 8) | /* HFB_LP_INTERLEAVING */ + FLD_VAL(59, 7, 0); /* HBB_LP_INTERLEAVING */ + dsi_write_reg(dsidev, DSI_VM_TIMING5, r); + + r = FLD_VAL(0x7A67, 31, 16) | /* BL_HS_INTERLEAVING */ + FLD_VAL(0x31D1, 15, 0); /* BL_LP_INTERLEAVING */ + dsi_write_reg(dsidev, DSI_VM_TIMING6, r); + + r = FLD_VAL(18, 31, 16) | /* ENTER_HS_MODE_LATENCY */ + FLD_VAL(15, 15, 0); /* EXIT_HS_MODE_LATENCY */ + dsi_write_reg(dsidev, DSI_VM_TIMING7, r); + + return 0; +} + +int dsi_video_mode_enable(struct omap_dss_device *dssdev, u8 data_type) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + u16 word_count; + u32 r; + u32 header; + + dsi_if_enable(dsidev, 0); + dsi_vc_enable(dsidev, 1, 0); + dsi_vc_enable(dsidev, 0, 0); + + r = dsi_read_reg(dsidev, DSI_TIMING1); + r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ + dsi_write_reg(dsidev, DSI_TIMING1, r); + + if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 15, 0) != 0) + BUG(); + + r = dsi_read_reg(dsidev, DSI_VC_CTRL(0)); + r = FLD_MOD(r, 1, 4, 4); + r = FLD_MOD(r, 1, 9, 9); + dsi_write_reg(dsidev, DSI_VC_CTRL(0), r); + + r = dsi_read_reg(dsidev, DSI_VC_CTRL(1)); + r = FLD_MOD(r, 0, 4, 4); + r = FLD_MOD(r, 1, 9, 9); + dsi_write_reg(dsidev, DSI_VC_CTRL(1), r); + + word_count = dssdev->panel.timings.x_res * 3; + header = FLD_VAL(0, 31, 24) | /* ECC */ + FLD_VAL(word_count, 23, 8) | /* WORD_COUNT */ + FLD_VAL(0, 7, 6) | /* VC_ID */ + FLD_VAL(data_type, 5, 0); + dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(0), header); + + dsi_vc_enable(dsidev, 1, 1); + dsi_vc_enable(dsidev, 0, 1); + dsi_if_enable(dsidev, 1); + + return 0; +} + static void dsi_proto_timings(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -3579,6 +3807,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) unsigned ddr_clk_pre, ddr_clk_post; unsigned enter_hs_mode_lat, exit_hs_mode_lat; unsigned ths_eot; + unsigned offset_ddr_clk; u32 r; r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); @@ -3603,9 +3832,13 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev)); + /* DDR PRE & DDR POST increased to keep LP-11 under 10 usec */ + offset_ddr_clk = dssdev->clocks.dsi.offset_ddr_clk; + ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare, - 4); - ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot; + 4) + offset_ddr_clk; + ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot + + offset_ddr_clk; BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255); BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255); @@ -3807,6 +4040,11 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", x, y, w, h); + if (dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_VIDEO_MODE) { + dss_start_update(dssdev); + return; + } + dsi_vc_config_vp(dsidev, channel); bytespp = dssdev->ctrl.pixel_size / 8; @@ -4017,23 +4255,30 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; - r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev, - irq); - if (r) { - DSSERR("can't get FRAMEDONE irq\n"); - return r; + if (dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) { + r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev, + irq); + if (r) { + DSSERR("can't get FRAMEDONE irq\n"); + return r; + } + + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_DSI); + dispc_enable_fifohandcheck(dssdev->manager->id, 1); + } else { + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + dispc_enable_fifohandcheck(dssdev->manager->id, 0); } dispc_set_lcd_display_type(dssdev->manager->id, OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(dssdev->manager->id, - OMAP_DSS_PARALLELMODE_DSI); - dispc_enable_fifohandcheck(dssdev->manager->id, 1); dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); - { + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) { struct omap_video_timings timings = { .hsw = 1, .hfp = 1, @@ -4044,6 +4289,9 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) }; dispc_set_lcd_timings(dssdev->manager->id, &timings); + } else { + dispc_set_lcd_timings(dssdev->manager->id, + &dssdev->panel.timings); } return 0; @@ -4056,8 +4304,9 @@ static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; - omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev, - irq); + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) + omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev, + irq); } static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) @@ -4120,13 +4369,20 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) int dsi_module = dsi_get_dsidev_id(dsidev); int r; + /* The SCPClk is required for PLL and complexio registers on OMAP4 */ + if (cpu_is_omap44xx()) + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); + r = dsi_pll_init(dsidev, true, true); + if (r) goto err0; - r = dsi_configure_dsi_clocks(dssdev); - if (r) - goto err1; + if(!dssdev->skip_init){ + r = dsi_configure_dsi_clocks(dssdev); + if (r) + goto err1; + } dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src); @@ -4135,13 +4391,19 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) DSSDBG("PLL OK\n"); - r = dsi_configure_dispc_clocks(dssdev); - if (r) - goto err2; + if(!dssdev->skip_init){ + r = dsi_configure_dispc_clocks(dssdev); + if (r) + goto err2; + } - r = dsi_cio_init(dssdev); - if (r) - goto err2; + if(!dssdev->skip_init){ + r = dsi_cio_init(dssdev); + if (r) + goto err2; + } + else + dsi_enable_scp_clk(dsidev); _dsi_print_reset_status(dsidev); @@ -4151,17 +4413,23 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (1) _dsi_print_reset_status(dsidev); - r = dsi_proto_config(dssdev); + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) + r = dsi_cmd_proto_config(dssdev); + else + r = dsi_video_proto_config(dssdev); + if (r) goto err3; /* enable interface */ - dsi_vc_enable(dsidev, 0, 1); - dsi_vc_enable(dsidev, 1, 1); - dsi_vc_enable(dsidev, 2, 1); - dsi_vc_enable(dsidev, 3, 1); - dsi_if_enable(dsidev, 1); - dsi_force_tx_stop_mode_io(dsidev); + if(!dssdev->skip_init){ + dsi_vc_enable(dsidev, 0, 1); + dsi_vc_enable(dsidev, 1, 1); + dsi_vc_enable(dsidev, 2, 1); + dsi_vc_enable(dsidev, 3, 1); + dsi_if_enable(dsidev, 1); + dsi_force_tx_stop_mode_io(dsidev); + } return 0; err3: @@ -4198,22 +4466,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_pll_uninit(dsidev, disconnect_lanes); } -static int dsi_core_init(struct platform_device *dsidev) -{ - /* Autoidle */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0); - - /* ENWAKEUP */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2); - - /* SIDLEMODE smart-idle */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3); - - _dsi_initialize_irq(dsidev); - - return 0; -} - int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -4229,37 +4481,40 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err0; + goto err_start_dev; } - enable_clocks(1); - dsi_enable_pll_clock(dsidev, 1); - - r = _dsi_reset(dsidev); + r = dsi_runtime_get(dsidev); if (r) - goto err1; + goto err_get_dsi; - dsi_core_init(dsidev); + if(!dssdev->skip_init) + dsi_enable_pll_clock(dsidev, 1); - r = dsi_display_init_dispc(dssdev); - if (r) - goto err1; + _dsi_initialize_irq(dsidev); + + if(!dssdev->skip_init){ + r = dsi_display_init_dispc(dssdev); + if (r) + goto err_init_dispc; + } r = dsi_display_init_dsi(dssdev); if (r) - goto err2; + goto err_init_dsi; mutex_unlock(&dsi->lock); return 0; -err2: +err_init_dsi: dsi_display_uninit_dispc(dssdev); -err1: - enable_clocks(0); +err_init_dispc: dsi_enable_pll_clock(dsidev, 0); + dsi_runtime_put(dsidev); +err_get_dsi: omap_dss_stop_device(dssdev); -err0: +err_start_dev: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); return r; @@ -4282,7 +4537,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); - enable_clocks(0); + dsi_runtime_put(dsidev); dsi_enable_pll_clock(dsidev, 0); omap_dss_stop_device(dssdev); @@ -4322,9 +4577,12 @@ int dsi_init_display(struct omap_dss_device *dssdev) DSSDBG("DSI init\n"); - /* XXX these should be figured out dynamically */ - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | + if(dssdev->phy.dsi.type == OMAP_DSS_DSI_TYPE_CMD_MODE) { + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; + } else { + dssdev->caps = 0; + } if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4437,7 +4695,44 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev) dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); } -static int dsi_init(struct platform_device *dsidev) +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, "dss_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get dss_clk\n"); + return PTR_ERR(clk); + } + + dsi->dss_clk = clk; + + clk = 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); + } + + dsi->sys_clk = clk; + + 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); +} + +/* DSI1 HW IP initialisation */ +static int omap_dsi1hw_probe(struct platform_device *dsidev) { struct omap_display_platform_data *dss_plat_data; struct omap_dss_board_info *board_info; @@ -4449,7 +4744,7 @@ static int dsi_init(struct platform_device *dsidev) dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) { r = -ENOMEM; - goto err0; + goto err_alloc; } dsi->pdev = dsidev; @@ -4472,6 +4767,14 @@ static int dsi_init(struct platform_device *dsidev) mutex_init(&dsi->lock); sema_init(&dsi->bus_lock, 1); + r = dsi_get_clocks(dsidev); + if (r) + goto err_get_clk; + + mutex_init(&dsi->runtime_lock); + + pm_runtime_enable(&dsidev->dev); + INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -4484,26 +4787,26 @@ static int dsi_init(struct platform_device *dsidev) if (!dsi_mem) { DSSERR("can't get IORESOURCE_MEM DSI\n"); r = -EINVAL; - goto err1; + goto err_ioremap; } dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); if (!dsi->base) { DSSERR("can't ioremap DSI\n"); r = -ENOMEM; - goto err1; + goto err_ioremap; } dsi->irq = platform_get_irq(dsi->pdev, 0); if (dsi->irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err2; + goto err_get_irq; } r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto err2; + goto err_get_irq; } /* DSI VCs initialization */ @@ -4515,7 +4818,9 @@ static int dsi_init(struct platform_device *dsidev) dsi_calc_clock_param_ranges(dsidev); - enable_clocks(1); + r = dsi_runtime_get(dsidev); + if (r) + goto err_get_dsi; rev = dsi_read_reg(dsidev, DSI_REVISION); dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", @@ -4523,21 +4828,32 @@ static int dsi_init(struct platform_device *dsidev) dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); - enable_clocks(0); + dsi_runtime_put(dsidev); return 0; -err2: + +err_get_dsi: + free_irq(dsi->irq, dsi->pdev); +err_get_irq: iounmap(dsi->base); -err1: +err_ioremap: + pm_runtime_disable(&dsidev->dev); +err_get_clk: kfree(dsi); -err0: +err_alloc: return r; } -static void dsi_exit(struct platform_device *dsidev) +static int omap_dsi1hw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + WARN_ON(dsi->scp_clk_refcount > 0); + + 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); @@ -4553,29 +4869,6 @@ static void dsi_exit(struct platform_device *dsidev) kfree(dsi); - DSSDBG("omap_dsi_exit\n"); -} - -/* DSI1 HW IP initialisation */ -static int omap_dsi1hw_probe(struct platform_device *dsidev) -{ - int r; - - r = dsi_init(dsidev); - if (r) { - DSSERR("Failed to initialize DSI\n"); - goto err_dsi; - } -err_dsi: - return r; -} - -static int omap_dsi1hw_remove(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - dsi_exit(dsidev); - WARN_ON(dsi->scp_clk_refcount > 0); return 0; } |