summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r--drivers/video/omap2/dss/Makefile2
-rw-r--r--drivers/video/omap2/dss/core.c3
-rw-r--r--drivers/video/omap2/dss/dispc.c286
-rw-r--r--drivers/video/omap2/dss/display.c4
-rw-r--r--drivers/video/omap2/dss/dsi.c464
-rw-r--r--drivers/video/omap2/dss/dss.c6
-rw-r--r--drivers/video/omap2/dss/dss.h11
-rw-r--r--drivers/video/omap2/dss/dss_features.c191
-rw-r--r--drivers/video/omap2/dss/dss_features.h50
-rw-r--r--drivers/video/omap2/dss/manager.c237
-rw-r--r--drivers/video/omap2/dss/overlay.c26
-rw-r--r--drivers/video/omap2/dss/rfbi.c2
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);
}