|
@@ -123,6 +123,9 @@ static struct {
|
|
|
|
|
|
struct regmap *syscon_pol;
|
|
|
u32 syscon_pol_offset;
|
|
|
+
|
|
|
+ /* DISPC_CONTROL & DISPC_CONFIG lock*/
|
|
|
+ spinlock_t control_lock;
|
|
|
} dispc;
|
|
|
|
|
|
enum omap_color_component {
|
|
@@ -261,7 +264,16 @@ static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
|
|
|
static void mgr_fld_write(enum omap_channel channel,
|
|
|
enum mgr_reg_fields regfld, int val) {
|
|
|
const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
|
|
|
+ const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (need_lock)
|
|
|
+ spin_lock_irqsave(&dispc.control_lock, flags);
|
|
|
+
|
|
|
REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
|
|
|
+
|
|
|
+ if (need_lock)
|
|
|
+ spin_unlock_irqrestore(&dispc.control_lock, flags);
|
|
|
}
|
|
|
|
|
|
#define SR(reg) \
|
|
@@ -1126,6 +1138,7 @@ static void dispc_init_fifos(void)
|
|
|
int fifo;
|
|
|
u8 start, end;
|
|
|
u32 unit;
|
|
|
+ int i;
|
|
|
|
|
|
unit = dss_feat_get_buffer_size_unit();
|
|
|
|
|
@@ -1165,6 +1178,20 @@ static void dispc_init_fifos(void)
|
|
|
dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
|
|
|
dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Setup default fifo thresholds.
|
|
|
+ */
|
|
|
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
|
|
|
+ u32 low, high;
|
|
|
+ const bool use_fifomerge = false;
|
|
|
+ const bool manual_update = false;
|
|
|
+
|
|
|
+ dispc_ovl_compute_fifo_thresholds(i, &low, &high,
|
|
|
+ use_fifomerge, manual_update);
|
|
|
+
|
|
|
+ dispc_ovl_set_fifo_threshold(i, low, high);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
|
|
@@ -1278,6 +1305,63 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
|
|
|
}
|
|
|
EXPORT_SYMBOL(dispc_ovl_compute_fifo_thresholds);
|
|
|
|
|
|
+static void dispc_ovl_set_mflag(enum omap_plane plane, bool enable)
|
|
|
+{
|
|
|
+ int bit;
|
|
|
+
|
|
|
+ if (plane == OMAP_DSS_GFX)
|
|
|
+ bit = 14;
|
|
|
+ else
|
|
|
+ bit = 23;
|
|
|
+
|
|
|
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
|
|
|
+}
|
|
|
+
|
|
|
+static void dispc_ovl_set_mflag_threshold(enum omap_plane plane,
|
|
|
+ int low, int high)
|
|
|
+{
|
|
|
+ dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane),
|
|
|
+ FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
|
|
|
+}
|
|
|
+
|
|
|
+static void dispc_init_mflag(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * HACK: NV12 color format and MFLAG seem to have problems working
|
|
|
+ * together: using two displays, and having an NV12 overlay on one of
|
|
|
+ * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
|
|
|
+ * Changing MFLAG thresholds and PRELOAD to certain values seem to
|
|
|
+ * remove the errors, but there doesn't seem to be a clear logic on
|
|
|
+ * which values work and which not.
|
|
|
+ *
|
|
|
+ * As a work-around, set force MFLAG to always on.
|
|
|
+ */
|
|
|
+ dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE,
|
|
|
+ (1 << 0) | /* MFLAG_CTRL = force always on */
|
|
|
+ (0 << 2)); /* MFLAG_START = disable */
|
|
|
+
|
|
|
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
|
|
|
+ u32 size = dispc_ovl_get_fifo_size(i);
|
|
|
+ u32 unit = dss_feat_get_buffer_size_unit();
|
|
|
+ u32 low, high;
|
|
|
+
|
|
|
+ dispc_ovl_set_mflag(i, true);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Simulation team suggests below thesholds:
|
|
|
+ * HT = fifosize * 5 / 8;
|
|
|
+ * LT = fifosize * 4 / 8;
|
|
|
+ */
|
|
|
+
|
|
|
+ low = size * 4 / 8 / unit;
|
|
|
+ high = size * 5 / 8 / unit;
|
|
|
+
|
|
|
+ dispc_ovl_set_mflag_threshold(i, low, high);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void dispc_ovl_set_fir(enum omap_plane plane,
|
|
|
int hinc, int vinc,
|
|
|
enum omap_color_component color_comp)
|
|
@@ -2322,6 +2406,11 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
|
|
|
if (width == out_width && height == out_height)
|
|
|
return 0;
|
|
|
|
|
|
+ if (pclk == 0 || mgr_timings->pixelclock == 0) {
|
|
|
+ DSSERR("cannot calculate scaling settings: pclk is zero\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -2441,7 +2530,7 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
|
|
|
unsigned long pclk = dispc_plane_pclk_rate(plane);
|
|
|
unsigned long lclk = dispc_plane_lclk_rate(plane);
|
|
|
|
|
|
- if (paddr == 0)
|
|
|
+ if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
|
|
|
return -EINVAL;
|
|
|
|
|
|
out_width = out_width == 0 ? width : out_width;
|
|
@@ -2915,7 +3004,7 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
|
|
|
|
|
|
{
|
|
|
u32 timing_h, timing_v, l;
|
|
|
- bool onoff, rf, ipc;
|
|
|
+ bool onoff, rf, ipc, vs, hs, de;
|
|
|
|
|
|
timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
|
|
|
FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
|
|
@@ -2927,6 +3016,39 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
|
|
|
dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
|
|
|
dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
|
|
|
|
|
|
+ switch (vsync_level) {
|
|
|
+ case OMAPDSS_SIG_ACTIVE_LOW:
|
|
|
+ vs = true;
|
|
|
+ break;
|
|
|
+ case OMAPDSS_SIG_ACTIVE_HIGH:
|
|
|
+ vs = false;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (hsync_level) {
|
|
|
+ case OMAPDSS_SIG_ACTIVE_LOW:
|
|
|
+ hs = true;
|
|
|
+ break;
|
|
|
+ case OMAPDSS_SIG_ACTIVE_HIGH:
|
|
|
+ hs = false;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (de_level) {
|
|
|
+ case OMAPDSS_SIG_ACTIVE_LOW:
|
|
|
+ de = true;
|
|
|
+ break;
|
|
|
+ case OMAPDSS_SIG_ACTIVE_HIGH:
|
|
|
+ de = false;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ }
|
|
|
+
|
|
|
switch (data_pclk_edge) {
|
|
|
case OMAPDSS_DRIVE_SIG_RISING_EDGE:
|
|
|
ipc = false;
|
|
@@ -2934,22 +3056,18 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
|
|
|
case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
|
|
|
ipc = true;
|
|
|
break;
|
|
|
- case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES:
|
|
|
default:
|
|
|
BUG();
|
|
|
}
|
|
|
|
|
|
+ /* always use the 'rf' setting */
|
|
|
+ onoff = true;
|
|
|
+
|
|
|
switch (sync_pclk_edge) {
|
|
|
- case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES:
|
|
|
- onoff = false;
|
|
|
- rf = false;
|
|
|
- break;
|
|
|
case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
|
|
|
- onoff = true;
|
|
|
rf = false;
|
|
|
break;
|
|
|
case OMAPDSS_DRIVE_SIG_RISING_EDGE:
|
|
|
- onoff = true;
|
|
|
rf = true;
|
|
|
break;
|
|
|
default:
|
|
@@ -2958,10 +3076,10 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
|
|
|
|
|
|
l = FLD_VAL(onoff, 17, 17) |
|
|
|
FLD_VAL(rf, 16, 16) |
|
|
|
- FLD_VAL(de_level, 15, 15) |
|
|
|
+ FLD_VAL(de, 15, 15) |
|
|
|
FLD_VAL(ipc, 14, 14) |
|
|
|
- FLD_VAL(hsync_level, 13, 13) |
|
|
|
- FLD_VAL(vsync_level, 12, 12);
|
|
|
+ FLD_VAL(hs, 13, 13) |
|
|
|
+ FLD_VAL(vs, 12, 12);
|
|
|
|
|
|
dispc_write_reg(DISPC_POL_FREQ(channel), l);
|
|
|
|
|
@@ -3569,6 +3687,9 @@ static void _omap_dispc_initial_config(void)
|
|
|
|
|
|
if (dispc.feat->mstandby_workaround)
|
|
|
REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
|
|
|
+
|
|
|
+ if (dss_has_feature(FEAT_MFLAG))
|
|
|
+ dispc_init_mflag();
|
|
|
}
|
|
|
|
|
|
static const struct dispc_features omap24xx_dispc_feats __initconst = {
|
|
@@ -3770,6 +3891,8 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|
|
|
|
|
dispc.pdev = pdev;
|
|
|
|
|
|
+ spin_lock_init(&dispc.control_lock);
|
|
|
+
|
|
|
r = dispc_init_features(dispc.pdev);
|
|
|
if (r)
|
|
|
return r;
|