On Wed, 2012-03-21 at 15:21 +0530, Chandrabhanu Mahapatra wrote: > In OMAP3 DISPC video overlays suffer from some undocumented horizontal position > and timing related limitations leading to SYNCLOST errors. Whenever the image > window is moved towards the right of the screen SYNCLOST errors become > frequent. Checks have been implemented to see that DISPC driver rejects > configuration exceeding above limitations. > > This code was successfully tested on OMAP3. This code is written based on code > written by Ville Syrjälä <ville.syrjala@xxxxxxxxx> in Linux OMAP kernel. Ville > Syrjälä <ville.syrjala@xxxxxxxxx> had added checks for video overlay horizontal > timing and DISPC horizontal blanking length limitations. > > Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@xxxxxx> > --- > drivers/video/omap2/dss/dispc.c | 97 +++++++++++++++++++++++++++++---------- > 1 files changed, 72 insertions(+), 25 deletions(-) > > diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c > index 5a1963e..d8a1672 100644 > --- a/drivers/video/omap2/dss/dispc.c > +++ b/drivers/video/omap2/dss/dispc.c > @@ -1622,6 +1622,57 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, > } > } > > +static int check_horiz_timing(enum omap_channel channel, u16 pos_x, > + u16 width, u16 height, u16 out_width, u16 out_height) I think the function could be named check_horiz_timing_omap3 or something. It's kinda hard to realize that this is an omap3 work-around. Perhaps a short comment above the function would be in order. > +{ > + int DS = DIV_ROUND_UP(height, out_height); > + struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); > + struct omap_video_timings t = dssdev->panel.timings; > + unsigned long nonactive, lclk, pclk; > + static const u8 limits[3] = { 8, 10, 20 }; > + u64 val, blank; > + int i; > + > + nonactive = t.x_res + t.hfp + t.hsw + t.hbp - out_width; > + pclk = dispc_mgr_pclk_rate(channel); > + lclk = dispc_mgr_lclk_rate(channel); > + > + i = 0; > + if (out_height < height) > + i++; > + if (out_width < width) > + i++; > + blank = div_u64((u64)(t.hbp + t.hsw + t.hfp) * lclk, pclk); > + DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]); > + if (blank <= limits[i]) > + return -EINVAL; > + > + /* > + * Pixel data should be prepared before visible display point starts. > + * So, atleast DS-2 lines must have already been fetched by DISPC > + * during nonactive - pos_x period. > + */ > + val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); > + DSSDBG("(nonactive - pos_x) * pcd = %llu," > + " max(0, DS - 2) * width = %d\n", > + val, max(0, DS - 2) * width); > + if (val < max(0, DS - 2) * width) > + return -EINVAL; > + > + /* > + * All lines need to be refilled during the nonactive period of which > + * only one line can be loaded during the active period. So, atleast > + * DS - 1 lines should be loaded during nonactive period. > + */ > + val = div_u64((u64)nonactive * lclk, pclk); > + DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", > + val, max(0, DS - 1) * width); > + if (val < max(0, DS - 1) * width) > + return -EINVAL; > + > + return 0; > +} > + > static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, > u16 height, u16 out_width, u16 out_height, > enum omap_color_mode color_mode) > @@ -1702,7 +1753,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, > enum omap_channel channel, u16 width, u16 height, > u16 out_width, u16 out_height, > enum omap_color_mode color_mode, bool *five_taps, > - int *x_predecim, int *y_predecim) > + int *x_predecim, int *y_predecim, u16 pos_x) > { > struct omap_overlay *ovl = omap_dss_get_overlay(plane); > const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); > @@ -1778,6 +1829,9 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, > fclk = calc_fclk_five_taps(channel, in_width, in_height, > out_width, out_height, color_mode); > > + error = check_horiz_timing(channel, pos_x, in_width, > + in_height, out_width, out_height); > + > if (in_width > maxsinglelinewidth) > if (in_height > out_height && > in_height < out_height * 2) > @@ -1785,7 +1839,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, > if (!*five_taps) > fclk = calc_fclk(channel, in_width, in_height, > out_width, out_height); > - error = (in_width > maxsinglelinewidth * 2 || > + error = (error || in_width > maxsinglelinewidth * 2 || > (in_width > maxsinglelinewidth && *five_taps) || > !fclk || fclk > dispc_fclk_rate()); > if (error) { > @@ -1801,6 +1855,12 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, > } while (decim_x <= *x_predecim && decim_y <= *y_predecim > && error); > > + if (check_horiz_timing(channel, pos_x, width, height, > + out_width, out_height)){ > + DSSERR("horizontal timing too tight\n"); > + return -EINVAL; > + } > + > if (in_width > (maxsinglelinewidth * 2)) { > DSSERR("Cannot setup scaling"); > DSSERR("width exceeds maximum width possible"); > @@ -1901,7 +1961,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, > > r = dispc_ovl_calc_scaling(plane, channel, in_width, in_height, > out_width, out_height, oi->color_mode, &five_taps, > - &x_predecim, &y_predecim); > + &x_predecim, &y_predecim, oi->pos_x); > if (r) > return r; > > @@ -2472,32 +2532,19 @@ unsigned long dispc_fclk_rate(void) > > unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) > { > - struct platform_device *dsidev; > - int lcd; > - unsigned long r; > - u32 l; > + unsigned long r = dispc_fclk_rate(); > > - l = dispc_read_reg(DISPC_DIVISORo(channel)); > + if (dispc_mgr_is_lcd(channel)) { > + u32 l; > + int lcd; > > - lcd = FLD_GET(l, 23, 16); > + l = dispc_read_reg(DISPC_DIVISORo(channel)); > + lcd = FLD_GET(l, 23, 16); > > - switch (dss_get_lcd_clk_source(channel)) { > - case OMAP_DSS_CLK_SRC_FCK: > - r = clk_get_rate(dispc.dss_clk); > - break; > - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: > - dsidev = dsi_get_dsidev_from_id(0); > - r = dsi_get_pll_hsdiv_dispc_rate(dsidev); > - break; > - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: > - dsidev = dsi_get_dsidev_from_id(1); > - r = dsi_get_pll_hsdiv_dispc_rate(dsidev); > - break; > - default: > - BUG(); > + return r / lcd; > + } else { > + return r; > } > - > - return r / lcd; > } I don't the change to dispc_mgr_lclk_rate has anything to do with this patch (fixing omap3 sync lost error). Shouldn't it be a separate fix? Tomi
Attachment:
signature.asc
Description: This is a digitally signed message part