diff options
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r-- | drivers/video/omap2/dss/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/omap2/dss/core.c | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 286 | ||||
-rw-r--r-- | drivers/video/omap2/dss/display.c | 4 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 464 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.c | 6 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 11 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 191 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.h | 50 | ||||
-rw-r--r-- | drivers/video/omap2/dss/manager.c | 237 | ||||
-rw-r--r-- | drivers/video/omap2/dss/overlay.c | 26 | ||||
-rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 2 |
12 files changed, 768 insertions, 514 deletions
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index d71b5d9d71b1..7db17b5e570c 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o -omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o +omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index b3a498f22d36..8e89f6049280 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -37,6 +37,7 @@ #include <plat/clock.h> #include "dss.h" +#include "dss_features.h" static struct { struct platform_device *pdev; @@ -502,6 +503,8 @@ static int omap_dss_probe(struct platform_device *pdev) core.pdev = pdev; + dss_features_init(); + dss_init_overlay_managers(pdev); dss_init_overlays(pdev); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index e777e352dbcd..fa40fa59a9ac 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -31,6 +31,7 @@ #include <linux/seq_file.h> #include <linux/delay.h> #include <linux/workqueue.h> +#include <linux/hardirq.h> #include <plat/sram.h> #include <plat/clock.h> @@ -38,6 +39,7 @@ #include <plat/display.h> #include "dss.h" +#include "dss_features.h" /* DISPC */ #define DISPC_BASE 0x48050400 @@ -138,6 +140,22 @@ struct omap_dispc_isr_data { u32 mask; }; +struct dispc_h_coef { + s8 hc4; + s8 hc3; + u8 hc2; + s8 hc1; + s8 hc0; +}; + +struct dispc_v_coef { + s8 vc22; + s8 vc2; + u8 vc1; + s8 vc0; + s8 vc00; +}; + #define REG_GET(idx, start, end) \ FLD_GET(dispc_read_reg(idx), start, end) @@ -335,7 +353,7 @@ void dispc_save_context(void) void dispc_restore_context(void) { RR(SYSCONFIG); - RR(IRQENABLE); + /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); RR(DEFAULT_COLOR0); @@ -472,6 +490,15 @@ void dispc_restore_context(void) /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); + + /* clear spurious SYNC_LOST_DIGIT interrupts */ + dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); + + /* + * enable last so IRQs won't trigger before + * the context is fully restored + */ + RR(IRQENABLE); } #undef SR @@ -554,106 +581,77 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, int vscaleup, int five_taps) { /* Coefficients for horizontal up-sampling */ - static const u32 coef_hup[8] = { - 0x00800000, - 0x0D7CF800, - 0x1E70F5FF, - 0x335FF5FE, - 0xF74949F7, - 0xF55F33FB, - 0xF5701EFE, - 0xF87C0DFF, + static const struct dispc_h_coef coef_hup[8] = { + { 0, 0, 128, 0, 0 }, + { -1, 13, 124, -8, 0 }, + { -2, 30, 112, -11, -1 }, + { -5, 51, 95, -11, -2 }, + { 0, -9, 73, 73, -9 }, + { -2, -11, 95, 51, -5 }, + { -1, -11, 112, 30, -2 }, + { 0, -8, 124, 13, -1 }, }; - /* Coefficients for horizontal down-sampling */ - static const u32 coef_hdown[8] = { - 0x24382400, - 0x28371FFE, - 0x2C361BFB, - 0x303516F9, - 0x11343311, - 0x1635300C, - 0x1B362C08, - 0x1F372804, + /* Coefficients for vertical up-sampling */ + static const struct dispc_v_coef coef_vup_3tap[8] = { + { 0, 0, 128, 0, 0 }, + { 0, 3, 123, 2, 0 }, + { 0, 12, 111, 5, 0 }, + { 0, 32, 89, 7, 0 }, + { 0, 0, 64, 64, 0 }, + { 0, 7, 89, 32, 0 }, + { 0, 5, 111, 12, 0 }, + { 0, 2, 123, 3, 0 }, }; - /* Coefficients for horizontal and vertical up-sampling */ - static const u32 coef_hvup[2][8] = { - { - 0x00800000, - 0x037B02FF, - 0x0C6F05FE, - 0x205907FB, - 0x00404000, - 0x075920FE, - 0x056F0CFF, - 0x027B0300, - }, - { - 0x00800000, - 0x0D7CF8FF, - 0x1E70F5FE, - 0x335FF5FB, - 0xF7404000, - 0xF55F33FE, - 0xF5701EFF, - 0xF87C0D00, - }, + static const struct dispc_v_coef coef_vup_5tap[8] = { + { 0, 0, 128, 0, 0 }, + { -1, 13, 124, -8, 0 }, + { -2, 30, 112, -11, -1 }, + { -5, 51, 95, -11, -2 }, + { 0, -9, 73, 73, -9 }, + { -2, -11, 95, 51, -5 }, + { -1, -11, 112, 30, -2 }, + { 0, -8, 124, 13, -1 }, }; - /* Coefficients for horizontal and vertical down-sampling */ - static const u32 coef_hvdown[2][8] = { - { - 0x24382400, - 0x28391F04, - 0x2D381B08, - 0x3237170C, - 0x123737F7, - 0x173732F9, - 0x1B382DFB, - 0x1F3928FE, - }, - { - 0x24382400, - 0x28371F04, - 0x2C361B08, - 0x3035160C, - 0x113433F7, - 0x163530F9, - 0x1B362CFB, - 0x1F3728FE, - }, + /* Coefficients for horizontal down-sampling */ + static const struct dispc_h_coef coef_hdown[8] = { + { 0, 36, 56, 36, 0 }, + { 4, 40, 55, 31, -2 }, + { 8, 44, 54, 27, -5 }, + { 12, 48, 53, 22, -7 }, + { -9, 17, 52, 51, 17 }, + { -7, 22, 53, 48, 12 }, + { -5, 27, 54, 44, 8 }, + { -2, 31, 55, 40, 4 }, }; - /* Coefficients for vertical up-sampling */ - static const u32 coef_vup[8] = { - 0x00000000, - 0x0000FF00, - 0x0000FEFF, - 0x0000FBFE, - 0x000000F7, - 0x0000FEFB, - 0x0000FFFE, - 0x000000FF, + /* Coefficients for vertical down-sampling */ + static const struct dispc_v_coef coef_vdown_3tap[8] = { + { 0, 36, 56, 36, 0 }, + { 0, 40, 57, 31, 0 }, + { 0, 45, 56, 27, 0 }, + { 0, 50, 55, 23, 0 }, + { 0, 18, 55, 55, 0 }, + { 0, 23, 55, 50, 0 }, + { 0, 27, 56, 45, 0 }, + { 0, 31, 57, 40, 0 }, }; - - /* Coefficients for vertical down-sampling */ - static const u32 coef_vdown[8] = { - 0x00000000, - 0x000004FE, - 0x000008FB, - 0x00000CF9, - 0x0000F711, - 0x0000F90C, - 0x0000FB08, - 0x0000FE04, + static const struct dispc_v_coef coef_vdown_5tap[8] = { + { 0, 36, 56, 36, 0 }, + { 4, 40, 55, 31, -2 }, + { 8, 44, 54, 27, -5 }, + { 12, 48, 53, 22, -7 }, + { -9, 17, 52, 51, 17 }, + { -7, 22, 53, 48, 12 }, + { -5, 27, 54, 44, 8 }, + { -2, 31, 55, 40, 4 }, }; - const u32 *h_coef; - const u32 *hv_coef; - const u32 *hv_coef_mod; - const u32 *v_coef; + const struct dispc_h_coef *h_coef; + const struct dispc_v_coef *v_coef; int i; if (hscaleup) @@ -661,47 +659,34 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, else h_coef = coef_hdown; - if (vscaleup) { - hv_coef = coef_hvup[five_taps]; - v_coef = coef_vup; - - if (hscaleup) - hv_coef_mod = NULL; - else - hv_coef_mod = coef_hvdown[five_taps]; - } else { - hv_coef = coef_hvdown[five_taps]; - v_coef = coef_vdown; - - if (hscaleup) - hv_coef_mod = coef_hvup[five_taps]; - else - hv_coef_mod = NULL; - } + if (vscaleup) + v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; + else + v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; for (i = 0; i < 8; i++) { u32 h, hv; - h = h_coef[i]; - - hv = hv_coef[i]; - - if (hv_coef_mod) { - hv &= 0xffffff00; - hv |= (hv_coef_mod[i] & 0xff); - } + h = FLD_VAL(h_coef[i].hc0, 7, 0) + | FLD_VAL(h_coef[i].hc1, 15, 8) + | FLD_VAL(h_coef[i].hc2, 23, 16) + | FLD_VAL(h_coef[i].hc3, 31, 24); + hv = FLD_VAL(h_coef[i].hc4, 7, 0) + | FLD_VAL(v_coef[i].vc0, 15, 8) + | FLD_VAL(v_coef[i].vc1, 23, 16) + | FLD_VAL(v_coef[i].vc2, 31, 24); _dispc_write_firh_reg(plane, i, h); _dispc_write_firhv_reg(plane, i, hv); } - if (!five_taps) - return; - - for (i = 0; i < 8; i++) { - u32 v; - v = v_coef[i]; - _dispc_write_firv_reg(plane, i, v); + if (five_taps) { + for (i = 0; i < 8; i++) { + u32 v; + v = FLD_VAL(v_coef[i].vc00, 7, 0) + | FLD_VAL(v_coef[i].vc22, 15, 8); + _dispc_write_firv_reg(plane, i, v); + } } } @@ -790,12 +775,12 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) { - - BUG_ON(plane == OMAP_DSS_VIDEO1); - - if (cpu_is_omap24xx()) + if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; + BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1); + if (plane == OMAP_DSS_GFX) REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); else if (plane == OMAP_DSS_VIDEO2) @@ -965,17 +950,14 @@ static void dispc_read_plane_fifo_sizes(void) DISPC_VID_FIFO_SIZE_STATUS(1) }; u32 size; int plane; + u8 start, end; enable_clocks(1); - for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { - if (cpu_is_omap24xx()) - size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0); - else if (cpu_is_omap34xx()) - size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0); - else - BUG(); + dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); + for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { + size = FLD_GET(dispc_read_reg(fsz_reg[plane]), start, end); dispc.fifo_size[plane] = size; } @@ -992,6 +974,8 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD, DISPC_VID_FIFO_THRESHOLD(0), DISPC_VID_FIFO_THRESHOLD(1) }; + u8 hi_start, hi_end, lo_start, lo_end; + enable_clocks(1); DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", @@ -1000,12 +984,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) REG_GET(ftrs_reg[plane], 27, 16), low, high); - if (cpu_is_omap24xx()) - dispc_write_reg(ftrs_reg[plane], - FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0)); - else - dispc_write_reg(ftrs_reg[plane], - FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0)); + dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); + dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); + + dispc_write_reg(ftrs_reg[plane], + FLD_VAL(high, hi_start, hi_end) | + FLD_VAL(low, lo_start, lo_end)); enable_clocks(0); } @@ -1025,13 +1009,16 @@ static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc) u32 val; const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0), DISPC_VID_FIR(1) }; + u8 hinc_start, hinc_end, vinc_start, vinc_end; BUG_ON(plane == OMAP_DSS_GFX); - if (cpu_is_omap24xx()) - val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0); - else - val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0); + dss_feat_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end); + dss_feat_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end); + + val = FLD_VAL(vinc, vinc_start, vinc_end) | + FLD_VAL(hinc, hinc_start, hinc_end); + dispc_write_reg(fir_reg[plane-1], val); } @@ -1557,6 +1544,8 @@ static int _dispc_setup_plane(enum omap_plane plane, case OMAP_DSS_COLOR_ARGB16: case OMAP_DSS_COLOR_ARGB32: case OMAP_DSS_COLOR_RGBA32: + if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) + return -EINVAL; case OMAP_DSS_COLOR_RGBX32: if (cpu_is_omap24xx()) return -EINVAL; @@ -1597,9 +1586,10 @@ static int _dispc_setup_plane(enum omap_plane plane, case OMAP_DSS_COLOR_ARGB16: case OMAP_DSS_COLOR_ARGB32: case OMAP_DSS_COLOR_RGBA32: - if (cpu_is_omap24xx()) + if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return -EINVAL; - if (plane == OMAP_DSS_VIDEO1) + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) return -EINVAL; break; @@ -1992,7 +1982,7 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable) } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) { - if (cpu_is_omap24xx()) + if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; enable_clocks(1); @@ -2006,7 +1996,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) { bool enabled; - if (cpu_is_omap24xx()) + if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return false; enable_clocks(1); @@ -3019,7 +3009,7 @@ void dispc_fake_vsync_irq(void) u32 irqstatus = DISPC_IRQ_VSYNC; int i; - local_irq_disable(); + WARN_ON(!in_interrupt()); for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { struct omap_dispc_isr_data *isr_data; @@ -3031,8 +3021,6 @@ void dispc_fake_vsync_irq(void) if (isr_data->mask & irqstatus) isr_data->isr(isr_data->arg, irqstatus); } - - local_irq_enable(); } #endif diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index ef8c8529dda2..22dd7a474f79 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev, int val, r; enum omap_dss_update_mode mode; + if (!dssdev->driver->set_update_mode) + return -EINVAL; + val = simple_strtoul(buf, NULL, 10); switch (val) { @@ -343,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: return 24; - return 24; default: BUG(); } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 3af207b2bde3..aa4f7a5fae29 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -165,6 +165,14 @@ struct dsi_reg { u16 idx; }; #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25) #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30) #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31) +#define DSI_CIO_IRQ_ERROR_MASK \ + (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \ + DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \ + DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \ + DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3) #define DSI_DT_DCS_SHORT_WRITE_0 0x05 #define DSI_DT_DCS_SHORT_WRITE_1 0x15 @@ -232,13 +240,15 @@ static struct unsigned pll_locked; struct completion bta_completion; + void (*bta_callback)(void); int update_channel; struct dsi_update_region update_region; bool te_enabled; - struct work_struct framedone_work; + struct workqueue_struct *workqueue; + void (*framedone_callback)(int, void *); void *framedone_data; @@ -509,9 +519,13 @@ void dsi_irq_handler(void) dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); #endif - if (vcstatus & DSI_VC_IRQ_BTA) + if (vcstatus & DSI_VC_IRQ_BTA) { complete(&dsi.bta_completion); + if (dsi.bta_callback) + dsi.bta_callback(); + } + if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { DSSERR("DSI VC(%d) error, vc irqstatus %x\n", i, vcstatus); @@ -536,8 +550,12 @@ void dsi_irq_handler(void) /* flush posted write */ dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); - DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); - print_irq_status_cio(ciostatus); + if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) { + DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); + print_irq_status_cio(ciostatus); + } else if (debug_irq) { + print_irq_status_cio(ciostatus); + } } dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); @@ -584,11 +602,8 @@ static void _dsi_initialize_irq(void) for (i = 0; i < 4; ++i) dsi_write_reg(DSI_VC_IRQENABLE(i), l); - /* XXX zonda responds incorrectly, causing control error: - Exit from LP-ESC mode to LP11 uses wrong transition states on the - data lines LP0 and LN0. */ - dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, - -1 & (~DSI_CIO_IRQ_ERRCONTROL2)); + l = DSI_CIO_IRQ_ERROR_MASK; + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); } static u32 dsi_get_errors(void) @@ -1098,6 +1113,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk, if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; + dispc_pck_free_enable(0); goto err1; } @@ -1740,42 +1756,52 @@ static void dsi_vc_initial_config(int channel) dsi.vc[channel].mode = DSI_VC_MODE_L4; } -static void dsi_vc_config_l4(int channel) +static int dsi_vc_config_l4(int channel) { if (dsi.vc[channel].mode == DSI_VC_MODE_L4) - return; + return 0; DSSDBGF("%d", channel); dsi_vc_enable(channel, 0); - if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ + /* VC_BUSY */ + if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { DSSERR("vc(%d) busy when trying to config for L4\n", channel); + return -EIO; + } REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_L4; + + return 0; } -static void dsi_vc_config_vp(int channel) +static int dsi_vc_config_vp(int channel) { if (dsi.vc[channel].mode == DSI_VC_MODE_VP) - return; + return 0; DSSDBGF("%d", channel); dsi_vc_enable(channel, 0); - if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ + /* VC_BUSY */ + if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { DSSERR("vc(%d) busy when trying to config for VP\n", channel); + return -EIO; + } REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */ dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_VP; + + return 0; } @@ -1854,19 +1880,19 @@ static u16 dsi_vc_flush_receive_data(int channel) u32 val; u8 dt; val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); - DSSDBG("\trawval %#08x\n", val); + DSSERR("\trawval %#08x\n", val); dt = FLD_GET(val, 5, 0); if (dt == DSI_DT_RX_ACK_WITH_ERR) { u16 err = FLD_GET(val, 23, 8); dsi_show_rx_ack_with_err(err); } else if (dt == DSI_DT_RX_SHORT_READ_1) { - DSSDBG("\tDCS short response, 1 byte: %#x\n", + DSSERR("\tDCS short response, 1 byte: %#x\n", FLD_GET(val, 23, 8)); } else if (dt == DSI_DT_RX_SHORT_READ_2) { - DSSDBG("\tDCS short response, 2 byte: %#x\n", + DSSERR("\tDCS short response, 2 byte: %#x\n", FLD_GET(val, 23, 8)); } else if (dt == DSI_DT_RX_DCS_LONG_READ) { - DSSDBG("\tDCS long response, len %d\n", + DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); dsi_vc_flush_long_data(channel); } else { @@ -2087,6 +2113,13 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len) if (r) goto err; + if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ + DSSERR("rx fifo not empty after write, dumping data:\n"); + dsi_vc_flush_receive_data(channel); + r = -EIO; + goto err; + } + return 0; err: DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", @@ -2233,11 +2266,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data) } EXPORT_SYMBOL(dsi_vc_dcs_read_1); -int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) +int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2) { + u8 buf[2]; int r; - r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2); + r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2); if (r < 0) return r; @@ -2245,231 +2279,122 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) if (r != 2) return -EIO; + *data1 = buf[0]; + *data2 = buf[1]; + return 0; } EXPORT_SYMBOL(dsi_vc_dcs_read_2); int dsi_vc_set_max_rx_packet_size(int channel, u16 len) { - int r; - r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, + return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, len, 0); - - if (r) - return r; - - r = dsi_vc_send_bta_sync(channel); - - return r; } EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); -static void dsi_set_lp_rx_timeout(unsigned long ns) +static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in DSI_FCK */ + BUG_ON(ticks > 0x1fff); + /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("LP_TX_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING2); r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ - r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */ - r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */ + 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 */ dsi_write_reg(DSI_TIMING2, r); - DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_ta_timeout(unsigned long ns) +static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16) { - u32 r; - unsigned x8, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; + + BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x8 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 8; - x8 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x8 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16); - x8 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("TA_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x8 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING1); r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ - r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */ - r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */ + 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 */ dsi_write_reg(DSI_TIMING1, r); - DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x8 ? " x8" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1); + + DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x8 ? " x8" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_stop_state_counter(unsigned long ns) +static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in DSI_FCK */ + BUG_ON(ticks > 0x1fff); + /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("STOP_STATE_COUNTER_IO over limit, " - "setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ - r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */ - r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_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 */ dsi_write_reg(DSI_TIMING1, r); - DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_hs_tx_timeout(unsigned long ns) +static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in TxByteClkHS */ + BUG_ON(ticks > 0x1fff); + /* ticks in TxByteClkHS */ fck = dsi_get_txbyteclkhs(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("HS_TX_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING2); r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ - r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */ - r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */ + 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 */ dsi_write_reg(DSI_TIMING2, r); - DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } static int dsi_proto_config(struct omap_dss_device *dssdev) { @@ -2487,10 +2412,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(1000); - dsi_set_ta_timeout(6400000); - dsi_set_lp_rx_timeout(48000); - dsi_set_hs_tx_timeout(1000000); + dsi_set_stop_state_counter(0x1000, false, false); + dsi_set_ta_timeout(0x1fff, true, true); + dsi_set_lp_rx_timeout(0x1fff, true, true); + dsi_set_hs_tx_timeout(0x1fff, true, true); switch (dssdev->ctrl.pixel_size) { case 16: @@ -2759,6 +2684,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, unsigned packet_payload; unsigned packet_len; u32 l; + int r; const unsigned channel = dsi.update_channel; /* line buffer is 1024 x 24bits */ /* XXX: for some reason using full buffer size causes considerable TX @@ -2809,8 +2735,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, dsi_perf_mark_start(); - schedule_delayed_work(&dsi.framedone_timeout_work, + r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work, msecs_to_jiffies(250)); + BUG_ON(r == 0); dss_start_update(dssdev); @@ -2834,62 +2761,70 @@ static void dsi_te_timeout(unsigned long arg) } #endif -static void dsi_framedone_timeout_work_callback(struct work_struct *work) +static void dsi_handle_framedone(int error) { - int r; const int channel = dsi.update_channel; - DSSERR("Framedone not received for 250ms!\n"); + cancel_delayed_work(&dsi.framedone_timeout_work); + + dsi_vc_disable_bta_irq(channel); /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); + dsi.bta_callback = NULL; + if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } - /* Send BTA after the frame. We need this for the TE to work, as TE - * trigger is only sent for BTAs without preceding packet. Thus we need - * to BTA after the pixel packets so that next BTA will cause TE - * trigger. - * - * This is not needed when TE is not in use, but we do it anyway to - * make sure that the transfer has been completed. It would be more - * optimal, but more complex, to wait only just before starting next - * transfer. */ - r = dsi_vc_send_bta_sync(channel); - if (r) - DSSERR("BTA after framedone failed\n"); - /* RX_FIFO_NOT_EMPTY */ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { DSSERR("Received error during frame transfer:\n"); dsi_vc_flush_receive_data(channel); + if (!error) + error = -EIO; } - dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); + dsi.framedone_callback(error, dsi.framedone_data); + + if (!error) + dsi_perf_show("DISPC"); } -static void dsi_framedone_irq_callback(void *data, u32 mask) +static void dsi_framedone_timeout_work_callback(struct work_struct *work) { - /* Note: We get FRAMEDONE when DISPC has finished sending pixels and - * turns itself off. However, DSI still has the pixels in its buffers, - * and is sending the data. - */ + /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after + * 250ms which would conflict with this timeout work. What should be + * done is first cancel the transfer on the HW, and then cancel the + * possibly scheduled framedone work. However, cancelling the transfer + * on the HW is buggy, and would probably require resetting the whole + * DSI */ - /* SIDLEMODE back to smart-idle */ - dispc_enable_sidle(); + DSSERR("Framedone not received for 250ms!\n"); - schedule_work(&dsi.framedone_work); + dsi_handle_framedone(-ETIMEDOUT); } -static void dsi_handle_framedone(void) +static void dsi_framedone_bta_callback(void) +{ + dsi_handle_framedone(0); + +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC + dispc_fake_vsync_irq(); +#endif +} + +static void dsi_framedone_irq_callback(void *data, u32 mask) { - int r; const int channel = dsi.update_channel; + int r; - DSSDBG("FRAMEDONE\n"); + /* Note: We get FRAMEDONE when DISPC has finished sending pixels and + * turns itself off. However, DSI still has the pixels in its buffers, + * and is sending the data. + */ if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ @@ -2904,37 +2839,30 @@ static void dsi_handle_framedone(void) * This is not needed when TE is not in use, but we do it anyway to * make sure that the transfer has been completed. It would be more * optimal, but more complex, to wait only just before starting next - * transfer. */ - r = dsi_vc_send_bta_sync(channel); - if (r) - DSSERR("BTA after framedone failed\n"); - - /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { - DSSERR("Received error during frame transfer:\n"); - dsi_vc_flush_receive_data(channel); - } - -#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC - dispc_fake_vsync_irq(); -#endif -} - -static void dsi_framedone_work_callback(struct work_struct *work) -{ - DSSDBGF(); + * transfer. + * + * Also, as there's no interrupt telling when the transfer has been + * done and the channel could be reconfigured, the only way is to + * busyloop until TE_SIZE is zero. With BTA we can do this + * asynchronously. + * */ - cancel_delayed_work_sync(&dsi.framedone_timeout_work); + dsi.bta_callback = dsi_framedone_bta_callback; - dsi_handle_framedone(); + barrier(); - dsi_perf_show("DISPC"); + dsi_vc_enable_bta_irq(channel); - dsi.framedone_callback(0, dsi.framedone_data); + r = dsi_vc_send_bta(channel); + if (r) { + DSSERR("BTA after framedone failed\n"); + dsi_handle_framedone(-EIO); + } } int omap_dsi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h) + u16 *x, u16 *y, u16 *w, u16 *h, + bool enlarge_update_area) { u16 dw, dh; @@ -2958,7 +2886,8 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, dsi_perf_mark_setup(); if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h); + dss_setup_partial_planes(dssdev, x, y, w, h, + enlarge_update_area); dispc_set_lcd_size(*w, *h); } @@ -2973,6 +2902,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, { dsi.update_channel = channel; + /* OMAP DSS cannot send updates of odd widths. + * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON + * here to make sure we catch erroneous updates. Otherwise we'll only + * see rather obscure HW error happening, as DSS halts. */ + BUG_ON(x % 2 == 1); + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dsi.framedone_callback = callback; dsi.framedone_data = data; @@ -2985,7 +2920,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, dsi_update_screen_dispc(dssdev, x, y, w, h); } else { - dsi_update_screen_l4(dssdev, x, y, w, h); + int r; + + r = dsi_update_screen_l4(dssdev, x, y, w, h); + if (r) + return r; + dsi_perf_show("L4"); callback(0, data); } @@ -3048,8 +2988,10 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) cinfo.regm3 = dssdev->phy.dsi.div.regm3; cinfo.regm4 = dssdev->phy.dsi.div.regm4; r = dsi_calc_clock_rates(&cinfo); - if (r) + if (r) { + DSSERR("Failed to calc dsi clocks\n"); return r; + } r = dsi_pll_set_clock_div(&cinfo); if (r) { @@ -3147,6 +3089,13 @@ err0: static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) { + /* disable interface */ + dsi_if_enable(0); + dsi_vc_enable(0, 0); + dsi_vc_enable(1, 0); + dsi_vc_enable(2, 0); + dsi_vc_enable(3, 0); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_complexio_uninit(); @@ -3257,7 +3206,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, burst_size_bytes = 16 * 32 / 8; *fifo_high = fifo_size - burst_size_bytes; - *fifo_low = fifo_size - burst_size_bytes * 8; + *fifo_low = fifo_size - burst_size_bytes * 2; } int dsi_init_display(struct omap_dss_device *dssdev) @@ -3274,6 +3223,18 @@ int dsi_init_display(struct omap_dss_device *dssdev) return 0; } +void dsi_wait_dsi1_pll_active(void) +{ + if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) + DSSERR("DSI1 PLL clock not active\n"); +} + +void dsi_wait_dsi2_pll_active(void) +{ + if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1) + DSSERR("DSI2 PLL clock not active\n"); +} + int dsi_init(struct platform_device *pdev) { u32 rev; @@ -3292,7 +3253,10 @@ int dsi_init(struct platform_device *pdev) mutex_init(&dsi.lock); sema_init(&dsi.bus_lock, 1); - INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); + dsi.workqueue = create_singlethread_workqueue("dsi"); + if (dsi.workqueue == NULL) + return -ENOMEM; + INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -3310,7 +3274,6 @@ int dsi_init(struct platform_device *pdev) dsi.vdds_dsi_reg = dss_get_vdds_dsi(); if (IS_ERR(dsi.vdds_dsi_reg)) { - iounmap(dsi.base); DSSERR("can't get VDDS_DSI regulator\n"); r = PTR_ERR(dsi.vdds_dsi_reg); goto err2; @@ -3328,6 +3291,7 @@ int dsi_init(struct platform_device *pdev) err2: iounmap(dsi.base); err1: + destroy_workqueue(dsi.workqueue); return r; } @@ -3335,6 +3299,8 @@ void dsi_exit(void) { iounmap(dsi.base); + destroy_workqueue(dsi.workqueue); + DSSDBG("omap_dsi_exit\n"); } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 24b18258654f..77c3621c9171 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -265,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + if (clk_src == DSS_SRC_DSI1_PLL_FCLK) + dsi_wait_dsi1_pll_active(); + REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ dss.dispc_clk_source = clk_src; @@ -279,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + if (clk_src == DSS_SRC_DSI2_PLL_FCLK) + dsi_wait_dsi2_pll_active(); + REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ dss.dsi_clk_source = clk_src; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 786f433fd571..5c7940d5f282 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h); + u16 *x, u16 *y, u16 *w, u16 *h, + bool enlarge_update_area); void dss_start_update(struct omap_dss_device *dssdev); /* overlay */ @@ -281,6 +282,8 @@ void dsi_pll_uninit(void); void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, u32 *fifo_low, u32 *fifo_high); +void dsi_wait_dsi1_pll_active(void); +void dsi_wait_dsi2_pll_active(void); #else static inline int dsi_init(struct platform_device *pdev) { @@ -289,6 +292,12 @@ static inline int dsi_init(struct platform_device *pdev) static inline void dsi_exit(void) { } +static inline void dsi_wait_dsi1_pll_active(void) +{ +} +static inline void dsi_wait_dsi2_pll_active(void) +{ +} #endif /* DPI */ diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c new file mode 100644 index 000000000000..867f68de125f --- /dev/null +++ b/drivers/video/omap2/dss/dss_features.c @@ -0,0 +1,191 @@ +/* + * linux/drivers/video/omap2/dss/dss_features.c + * + * Copyright (C) 2010 Texas Instruments + * Author: Archit Taneja <archit@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include <plat/display.h> +#include <plat/cpu.h> + +#include "dss_features.h" + +/* Defines a generic omap register field */ +struct dss_reg_field { + enum dss_feat_reg_field id; + u8 start, end; +}; + +struct omap_dss_features { + const struct dss_reg_field *reg_fields; + const int num_reg_fields; + + const u32 has_feature; + + const int num_mgrs; + const int num_ovls; + const enum omap_display_type *supported_displays; + const enum omap_color_mode *supported_color_modes; +}; + +/* This struct is assigned to one of the below during initialization */ +static struct omap_dss_features *omap_current_dss_features; + +static const struct dss_reg_field omap2_dss_reg_fields[] = { + { FEAT_REG_FIRHINC, 11, 0 }, + { FEAT_REG_FIRVINC, 27, 16 }, + { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 }, + { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 }, + { FEAT_REG_FIFOSIZE, 8, 0 }, +}; + +static const struct dss_reg_field omap3_dss_reg_fields[] = { + { FEAT_REG_FIRHINC, 12, 0 }, + { FEAT_REG_FIRVINC, 28, 16 }, + { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 }, + { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 }, + { FEAT_REG_FIFOSIZE, 10, 0 }, +}; + +static const enum omap_display_type omap2_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_VENC, +}; + +static const enum omap_display_type omap3_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_VENC, +}; + +static const enum omap_color_mode omap2_dss_supported_color_modes[] = { + /* OMAP_DSS_GFX */ + OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | + OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 | + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 | + OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P, + + /* OMAP_DSS_VIDEO1 */ + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 | + OMAP_DSS_COLOR_UYVY, + + /* OMAP_DSS_VIDEO2 */ + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 | + OMAP_DSS_COLOR_UYVY, +}; + +static const enum omap_color_mode omap3_dss_supported_color_modes[] = { + /* OMAP_DSS_GFX */ + OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | + OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 | + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 | + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 | + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32, + + /* OMAP_DSS_VIDEO1 */ + OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P | + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 | + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY, + + /* OMAP_DSS_VIDEO2 */ + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 | + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 | + OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 | + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32, +}; + +/* OMAP2 DSS Features */ +static struct omap_dss_features omap2_dss_features = { + .reg_fields = omap2_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap2_dss_supported_displays, + .supported_color_modes = omap2_dss_supported_color_modes, +}; + +/* OMAP3 DSS Features */ +static struct omap_dss_features omap3_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = FEAT_GLOBAL_ALPHA, + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + +/* Functions returning values related to a DSS feature */ +int dss_feat_get_num_mgrs(void) +{ + return omap_current_dss_features->num_mgrs; +} + +int dss_feat_get_num_ovls(void) +{ + return omap_current_dss_features->num_ovls; +} + +enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel) +{ + return omap_current_dss_features->supported_displays[channel]; +} + +enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) +{ + return omap_current_dss_features->supported_color_modes[plane]; +} + +/* DSS has_feature check */ +bool dss_has_feature(enum dss_feat_id id) +{ + return omap_current_dss_features->has_feature & id; +} + +void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) +{ + if (id >= omap_current_dss_features->num_reg_fields) + BUG(); + + *start = omap_current_dss_features->reg_fields[id].start; + *end = omap_current_dss_features->reg_fields[id].end; +} + +void dss_features_init(void) +{ + if (cpu_is_omap24xx()) + omap_current_dss_features = &omap2_dss_features; + else + omap_current_dss_features = &omap3_dss_features; +} diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h new file mode 100644 index 000000000000..cb231eaa9b31 --- /dev/null +++ b/drivers/video/omap2/dss/dss_features.h @@ -0,0 +1,50 @@ +/* + * linux/drivers/video/omap2/dss/dss_features.h + * + * Copyright (C) 2010 Texas Instruments + * Author: Archit Taneja <archit@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __OMAP2_DSS_FEATURES_H +#define __OMAP2_DSS_FEATURES_H + +#define MAX_DSS_MANAGERS 2 +#define MAX_DSS_OVERLAYS 3 + +/* DSS has feature id */ +enum dss_feat_id { + FEAT_GLOBAL_ALPHA = 1 << 0, + FEAT_GLOBAL_ALPHA_VID1 = 1 << 1, +}; + +/* DSS register field id */ +enum dss_feat_reg_field { + FEAT_REG_FIRHINC, + FEAT_REG_FIRVINC, + FEAT_REG_FIFOHIGHTHRESHOLD, + FEAT_REG_FIFOLOWTHRESHOLD, + FEAT_REG_FIFOSIZE, +}; + +/* DSS Feature Functions */ +int dss_feat_get_num_mgrs(void); +int dss_feat_get_num_ovls(void); +enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); +enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); + +bool dss_has_feature(enum dss_feat_id id); +void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); +void dss_features_init(void); +#endif diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 9e1fbe531bf0..545e9b9a4d92 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -33,6 +33,7 @@ #include <plat/cpu.h> #include "dss.h" +#include "dss_features.h" static int num_managers; static struct list_head manager_list; @@ -440,12 +441,16 @@ struct manager_cache_data { /* manual update region */ u16 x, y, w, h; + + /* enlarge the update area if the update area contains scaled + * overlays */ + bool enlarge_update_area; }; static struct { spinlock_t lock; - struct overlay_cache_data overlay_cache[3]; - struct manager_cache_data manager_cache[2]; + struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; + struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; bool irq_enabled; } dss_cache; @@ -525,7 +530,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) int i; struct omap_dss_device *dssdev = mgr->device; - if (!dssdev) + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { @@ -596,11 +601,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) int r; int i; - if (!ovl->manager || !ovl->manager->device) + if (!ovl->manager) return 0; dssdev = ovl->manager->device; + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; channel = OMAP_DSS_CHANNEL_DIGIT; @@ -718,6 +726,7 @@ static int configure_overlay(enum omap_plane plane) u16 x, y, w, h; u32 paddr; int r; + u16 orig_w, orig_h, orig_outw, orig_outh; DSSDBGF("%d", plane); @@ -738,8 +747,16 @@ static int configure_overlay(enum omap_plane plane) outh = c->out_height == 0 ? c->height : c->out_height; paddr = c->paddr; + orig_w = w; + orig_h = h; + orig_outw = outw; + orig_outh = outh; + if (c->manual_update && mc->do_manual_update) { unsigned bpp; + unsigned scale_x_m = w, scale_x_d = outw; + unsigned scale_y_m = h, scale_y_d = outh; + /* If the overlay is outside the update region, disable it */ if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, x, y, outw, outh)) { @@ -770,38 +787,47 @@ static int configure_overlay(enum omap_plane plane) BUG(); } - if (dispc_is_overlay_scaled(c)) { - /* If the overlay is scaled, the update area has - * already been enlarged to cover the whole overlay. We - * only need to adjust x/y here */ - x = c->pos_x - mc->x; - y = c->pos_y - mc->y; + if (mc->x > c->pos_x) { + x = 0; + outw -= (mc->x - c->pos_x); + paddr += (mc->x - c->pos_x) * + scale_x_m / scale_x_d * bpp / 8; } else { - if (mc->x > c->pos_x) { - x = 0; - w -= (mc->x - c->pos_x); - paddr += (mc->x - c->pos_x) * bpp / 8; - } else { - x = c->pos_x - mc->x; - } - - if (mc->y > c->pos_y) { - y = 0; - h -= (mc->y - c->pos_y); - paddr += (mc->y - c->pos_y) * c->screen_width * - bpp / 8; - } else { - y = c->pos_y - mc->y; - } - - if (mc->w < (x+w)) - w -= (x+w) - (mc->w); + x = c->pos_x - mc->x; + } - if (mc->h < (y+h)) - h -= (y+h) - (mc->h); + if (mc->y > c->pos_y) { + y = 0; + outh -= (mc->y - c->pos_y); + paddr += (mc->y - c->pos_y) * + scale_y_m / scale_y_d * + c->screen_width * bpp / 8; + } else { + y = c->pos_y - mc->y; + } - outw = w; - outh = h; + if (mc->w < (x + outw)) + outw -= (x + outw) - (mc->w); + + if (mc->h < (y + outh)) + outh -= (y + outh) - (mc->h); + + w = w * outw / orig_outw; + h = h * outh / orig_outh; + + /* YUV mode overlay's input width has to be even and the + * algorithm above may adjust the width to be odd. + * + * Here we adjust the width if needed, preferring to increase + * the width if the original width was bigger. + */ + if ((w & 1) && + (c->color_mode == OMAP_DSS_COLOR_YUV2 || + c->color_mode == OMAP_DSS_COLOR_UYVY)) { + if (orig_w > w) + w += 1; + else + w -= 1; } } @@ -857,12 +883,12 @@ static int configure_dispc(void) { struct overlay_cache_data *oc; struct manager_cache_data *mc; - const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache); - const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache); + const int num_ovls = dss_feat_get_num_ovls(); + const int num_mgrs = dss_feat_get_num_mgrs(); int i; int r; - bool mgr_busy[2]; - bool mgr_go[2]; + bool mgr_busy[MAX_DSS_MANAGERS]; + bool mgr_go[MAX_DSS_MANAGERS]; bool busy; r = 0; @@ -960,15 +986,16 @@ static void make_even(u16 *x, u16 *w) /* Configure dispc for partial update. Return possibly modified update * area */ void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *xi, u16 *yi, u16 *wi, u16 *hi) + u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) { struct overlay_cache_data *oc; struct manager_cache_data *mc; - const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache); + const int num_ovls = dss_feat_get_num_ovls(); struct omap_overlay_manager *mgr; int i; u16 x, y, w, h; unsigned long flags; + bool area_changed; x = *xi; y = *yi; @@ -989,73 +1016,91 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, spin_lock_irqsave(&dss_cache.lock, flags); - /* We need to show the whole overlay if it is scaled. So look for - * those, and make the update area larger if found. - * Also mark the overlay cache dirty */ - for (i = 0; i < num_ovls; ++i) { - unsigned x1, y1, x2, y2; - unsigned outw, outh; + /* + * Execute the outer loop until the inner loop has completed + * once without increasing the update area. This will ensure that + * all scaled overlays end up completely within the update area. + */ + do { + area_changed = false; - oc = &dss_cache.overlay_cache[i]; + /* We need to show the whole overlay if it is scaled. So look + * for those, and make the update area larger if found. + * Also mark the overlay cache dirty */ + for (i = 0; i < num_ovls; ++i) { + unsigned x1, y1, x2, y2; + unsigned outw, outh; - if (oc->channel != mgr->id) - continue; + oc = &dss_cache.overlay_cache[i]; - oc->dirty = true; + if (oc->channel != mgr->id) + continue; - if (!oc->enabled) - continue; + oc->dirty = true; - if (!dispc_is_overlay_scaled(oc)) - continue; + if (!enlarge_update_area) + continue; - outw = oc->out_width == 0 ? oc->width : oc->out_width; - outh = oc->out_height == 0 ? oc->height : oc->out_height; + if (!oc->enabled) + continue; - /* is the overlay outside the update region? */ - if (!rectangle_intersects(x, y, w, h, - oc->pos_x, oc->pos_y, - outw, outh)) - continue; + if (!dispc_is_overlay_scaled(oc)) + continue; - /* if the overlay totally inside the update region? */ - if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, - x, y, w, h)) - continue; + outw = oc->out_width == 0 ? + oc->width : oc->out_width; + outh = oc->out_height == 0 ? + oc->height : oc->out_height; + + /* is the overlay outside the update region? */ + if (!rectangle_intersects(x, y, w, h, + oc->pos_x, oc->pos_y, + outw, outh)) + continue; + + /* if the overlay totally inside the update region? */ + if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, + x, y, w, h)) + continue; - if (x > oc->pos_x) - x1 = oc->pos_x; - else - x1 = x; + if (x > oc->pos_x) + x1 = oc->pos_x; + else + x1 = x; - if (y > oc->pos_y) - y1 = oc->pos_y; - else - y1 = y; + if (y > oc->pos_y) + y1 = oc->pos_y; + else + y1 = y; - if ((x + w) < (oc->pos_x + outw)) - x2 = oc->pos_x + outw; - else - x2 = x + w; + if ((x + w) < (oc->pos_x + outw)) + x2 = oc->pos_x + outw; + else + x2 = x + w; - if ((y + h) < (oc->pos_y + outh)) - y2 = oc->pos_y + outh; - else - y2 = y + h; + if ((y + h) < (oc->pos_y + outh)) + y2 = oc->pos_y + outh; + else + y2 = y + h; - x = x1; - y = y1; - w = x2 - x1; - h = y2 - y1; + x = x1; + y = y1; + w = x2 - x1; + h = y2 - y1; - make_even(&x, &w); + make_even(&x, &w); - DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n", + DSSDBG("changing upd area due to ovl(%d) " + "scaling %d,%d %dx%d\n", i, x, y, w, h); - } + + area_changed = true; + } + } while (area_changed); mc = &dss_cache.manager_cache[mgr->id]; mc->do_manual_update = true; + mc->enlarge_update_area = enlarge_update_area; mc->x = x; mc->y = y; mc->w = w; @@ -1077,8 +1122,8 @@ void dss_start_update(struct omap_dss_device *dssdev) { struct manager_cache_data *mc; struct overlay_cache_data *oc; - const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache); - const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache); + const int num_ovls = dss_feat_get_num_ovls(); + const int num_mgrs = dss_feat_get_num_mgrs(); struct omap_overlay_manager *mgr; int i; @@ -1107,10 +1152,10 @@ static void dss_apply_irq_handler(void *data, u32 mask) { struct manager_cache_data *mc; struct overlay_cache_data *oc; - const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache); - const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache); + const int num_ovls = dss_feat_get_num_ovls(); + const int num_mgrs = dss_feat_get_num_mgrs(); int i, r; - bool mgr_busy[2]; + bool mgr_busy[MAX_DSS_MANAGERS]; mgr_busy[0] = dispc_go_busy(0); mgr_busy[1] = dispc_go_busy(1); @@ -1417,7 +1462,7 @@ int dss_init_overlay_managers(struct platform_device *pdev) num_managers = 0; - for (i = 0; i < 2; ++i) { + for (i = 0; i < dss_feat_get_num_mgrs(); ++i) { struct omap_overlay_manager *mgr; mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); @@ -1427,14 +1472,10 @@ int dss_init_overlay_managers(struct platform_device *pdev) case 0: mgr->name = "lcd"; mgr->id = OMAP_DSS_CHANNEL_LCD; - mgr->supported_displays = - OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | - OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI; break; case 1: mgr->name = "tv"; mgr->id = OMAP_DSS_CHANNEL_DIGIT; - mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC; break; } @@ -1450,6 +1491,8 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->disable = &dss_mgr_disable; mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC; + mgr->supported_displays = + dss_feat_get_supported_displays(mgr->id); dss_overlay_setup_dispc_manager(mgr); diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 82336583adef..75642c22cac7 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -35,6 +35,7 @@ #include <plat/cpu.h> #include "dss.h" +#include "dss_features.h" static int num_overlays; static struct list_head overlay_list; @@ -65,7 +66,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { mgr = omap_dss_get_overlay_manager(i); - if (strncmp(buf, mgr->name, len) == 0) + if (sysfs_streq(buf, mgr->name)) break; mgr = NULL; @@ -237,7 +238,8 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, /* Video1 plane does not support global alpha * to always make it 255 completely opaque */ - if (ovl->id == OMAP_DSS_VIDEO1) + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + ovl->id == OMAP_DSS_VIDEO1) info.global_alpha = 255; else info.global_alpha = simple_strtoul(buf, NULL, 10); @@ -510,11 +512,11 @@ static void omap_dss_add_overlay(struct omap_overlay *overlay) list_add_tail(&overlay->list, &overlay_list); } -static struct omap_overlay *dispc_overlays[3]; +static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS]; void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) { - mgr->num_overlays = 3; + mgr->num_overlays = dss_feat_get_num_ovls(); mgr->overlays = dispc_overlays; } @@ -535,7 +537,7 @@ void dss_init_overlays(struct platform_device *pdev) num_overlays = 0; - for (i = 0; i < 3; ++i) { + for (i = 0; i < dss_feat_get_num_ovls(); ++i) { struct omap_overlay *ovl; ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); @@ -545,18 +547,12 @@ void dss_init_overlays(struct platform_device *pdev) case 0: ovl->name = "gfx"; ovl->id = OMAP_DSS_GFX; - ovl->supported_modes = cpu_is_omap34xx() ? - OMAP_DSS_COLOR_GFX_OMAP3 : - OMAP_DSS_COLOR_GFX_OMAP2; ovl->caps = OMAP_DSS_OVL_CAP_DISPC; ovl->info.global_alpha = 255; break; case 1: ovl->name = "vid1"; ovl->id = OMAP_DSS_VIDEO1; - ovl->supported_modes = cpu_is_omap34xx() ? - OMAP_DSS_COLOR_VID1_OMAP3 : - OMAP_DSS_COLOR_VID_OMAP2; ovl->caps = OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_DISPC; ovl->info.global_alpha = 255; @@ -564,9 +560,6 @@ void dss_init_overlays(struct platform_device *pdev) case 2: ovl->name = "vid2"; ovl->id = OMAP_DSS_VIDEO2; - ovl->supported_modes = cpu_is_omap34xx() ? - OMAP_DSS_COLOR_VID2_OMAP3 : - OMAP_DSS_COLOR_VID_OMAP2; ovl->caps = OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_DISPC; ovl->info.global_alpha = 255; @@ -579,6 +572,9 @@ void dss_init_overlays(struct platform_device *pdev) ovl->get_overlay_info = &dss_ovl_get_overlay_info; ovl->wait_for_go = &dss_ovl_wait_for_go; + ovl->supported_modes = + dss_feat_get_supported_color_modes(ovl->id); + omap_dss_add_overlay(ovl); r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, @@ -651,7 +647,7 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) } if (mgr) { - for (i = 0; i < 3; i++) { + for (i = 0; i < dss_feat_get_num_ovls(); i++) { struct omap_overlay *ovl; ovl = omap_dss_get_overlay(i); if (!ovl->manager || force) { diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index cc23f53cc62d..bbe62464e92d 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, return -EINVAL; if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h); + dss_setup_partial_planes(dssdev, x, y, w, h, true); dispc_set_lcd_size(*w, *h); } |