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ä <[email protected]> in Linux OMAP kernel. Ville
> Syrjälä <[email protected]> had added checks for video overlay 
> horizontal
> timing and DISPC horizontal blanking length limitations.
> 
> Signed-off-by: Chandrabhanu Mahapatra <[email protected]>
> ---
>  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

Reply via email to