On Tue, Mar 27, 2012 at 4:27 PM, Tomi Valkeinen <[email protected]> wrote:
> 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.
>
Yes, you are right! Do you mean to include some comments within the
code definition itself? The patch description includes all that this
function does.
>> +{
>> + 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
>
I am thinking to to move this fix to the third patch in the series
"OMAPDSS: DISPC: Correct DISPC functional clock usage" and make it
separate patch from the series and if possible move it ahead of the
predecimation patch series. What do you say?
--
Chandrabhanu Mahapatra
Texas Instruments India Pvt. Ltd.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html