From 67f3fc050ab4e2006d5b7ec6ec341896627181ab Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 6 Apr 2009 17:32:04 +0200 Subject: [PATCH 19/69] DSS2: Check fclk limits when configuring video planes MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Check that the currect functional clock is fast enough to support the requested scaling ratios. Also check if 5-tap filtering can be used even though the downscaling ratio is less than 1:2 since the functional clock rate required for 5-tap filtering can be less than the requirement for 3-tap filtering, and 5-tap filtering should look better. Signed-off-by: Ville Syrjälä --- drivers/video/omap2/dss/dispc.c | 104 ++++++++++++++++++++++++++++++++++++--- 1 files changed, 97 insertions(+), 7 deletions(-) diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 41734f3..61861d8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1026,11 +1026,11 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) static void _dispc_set_scaling(enum omap_plane plane, u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, - bool ilace) + bool ilace, bool five_taps) { int fir_hinc; int fir_vinc; - int hscaleup, vscaleup, five_taps; + int hscaleup, vscaleup; int fieldmode = 0; int accu0 = 0; int accu1 = 0; @@ -1040,7 +1040,6 @@ static void _dispc_set_scaling(enum omap_plane plane, hscaleup = orig_width <= out_width; vscaleup = orig_height <= out_height; - five_taps = orig_height > out_height * 2; _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps); @@ -1283,6 +1282,73 @@ static void calc_rotation_offset(u8 rotation, bool mirror, } } +static unsigned long calc_fclk_five_taps(u16 width, u16 height, + u16 out_width, u16 out_height, enum omap_color_mode color_mode) +{ + u32 fclk = 0; + /* FIXME venc pclk? */ + u64 tmp, pclk = dispc_pclk_rate(); + + if (height > out_height) { + /* FIXME get real display PPL */ + unsigned int ppl = 800; + + tmp = pclk * height * out_width; + do_div(tmp, 2 * out_height * ppl); + fclk = tmp; + + if (height > 2 * out_height) { + tmp = pclk * (height - 2 * out_height) * out_width; + do_div(tmp, 2 * out_height * (ppl - out_width)); + fclk = max(fclk, (u32) tmp); + } + } + + if (width > out_width) { + tmp = pclk * width; + do_div(tmp, out_width); + fclk = max(fclk, (u32) tmp); + + if (color_mode == OMAP_DSS_COLOR_RGB24U) + fclk <<= 1; + } + + return fclk; +} + +static unsigned long calc_fclk(u16 width, u16 height, + u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool five_taps) +{ + unsigned int hf, vf; + + if (five_taps) + return calc_fclk_five_taps(width, height, + out_width, out_height, color_mode); + + /* + * FIXME how to determine the 'A' factor + * for the no downscaling case ? + */ + + if (width > 3 * out_width) + hf = 4; + else if (width > 2 * out_width) + hf = 3; + else if (width > out_width) + hf = 2; + else + hf = 1; + + if (height > out_height) + vf = 2; + else + vf = 1; + + /* FIXME venc pclk? */ + return dispc_pclk_rate() * vf * hf; +} + static int _dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out, u32 paddr, u16 screen_width, @@ -1294,7 +1360,7 @@ static int _dispc_setup_plane(enum omap_plane plane, u8 rotation, int mirror) { const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; - bool five_taps = height > out_height * 2; + bool five_taps = 0; bool fieldmode = 0; int cconv = 0; unsigned offset0, offset1; @@ -1323,8 +1389,8 @@ static int _dispc_setup_plane(enum omap_plane plane, } } else { /* video plane */ - if (width > (2048 >> five_taps)) - return -EINVAL; + + unsigned long fclk; if (out_width < width / maxdownscale || out_width > width * 8) @@ -1356,6 +1422,30 @@ static int _dispc_setup_plane(enum omap_plane plane, default: return -EINVAL; } + + /* Must use 5-tap filter? */ + five_taps = height > out_height * 2; + + /* Try to use 5-tap filter whenever possible. */ + if (cpu_is_omap34xx() && !five_taps && + height > out_height && width <= 1024) { + fclk = calc_fclk_five_taps(width, height, + out_width, out_height, color_mode); + if (fclk <= dispc_fclk_rate()) + five_taps = true; + } + + if (width > (2048 >> five_taps)) + return -EINVAL; + + fclk = calc_fclk(width, height, out_width, out_height, + color_mode, five_taps); + + DSSDBG("required fclk rate = %lu Hz\n", fclk); + DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); + + if (fclk > dispc_fclk_rate()) + return -EINVAL; } if (ilace && height >= out_height) @@ -1399,7 +1489,7 @@ static int _dispc_setup_plane(enum omap_plane plane, if (plane != OMAP_DSS_GFX) { _dispc_set_scaling(plane, width, height, out_width, out_height, - ilace); + ilace, five_taps); _dispc_set_vid_size(plane, out_width, out_height); _dispc_set_vid_color_conv(plane, cconv); } -- 1.6.2.4