diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2015-06-22 07:56:01 -0400 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2015-06-22 07:56:01 -0400 |
commit | f778dad38a54ca5207d024b5ebe0e6d71b8bad83 (patch) | |
tree | b9dc1c84c0052a51ca8ccfba8ab91c26eec6607c | |
parent | a9bd32a8b4c4c2670f9ed8cae63f9378b6df3ded (diff) | |
parent | a9fad6886f5229fc9989ac6cdd7ddecbf570a58f (diff) |
Merge omapdss scaling fixes
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dispc.c | 114 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi4.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi_wp.c | 16 |
3 files changed, 116 insertions, 16 deletions
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index c8e34163211a..be716c9ffb88 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c | |||
@@ -96,6 +96,9 @@ struct dispc_features { | |||
96 | bool mstandby_workaround:1; | 96 | bool mstandby_workaround:1; |
97 | 97 | ||
98 | bool set_max_preload:1; | 98 | bool set_max_preload:1; |
99 | |||
100 | /* PIXEL_INC is not added to the last pixel of a line */ | ||
101 | bool last_pixel_inc_missing:1; | ||
99 | }; | 102 | }; |
100 | 103 | ||
101 | #define DISPC_MAX_NR_FIFOS 5 | 104 | #define DISPC_MAX_NR_FIFOS 5 |
@@ -1742,6 +1745,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, | |||
1742 | row_repeat = false; | 1745 | row_repeat = false; |
1743 | } | 1746 | } |
1744 | 1747 | ||
1748 | /* | ||
1749 | * OMAP4/5 Errata i631: | ||
1750 | * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra | ||
1751 | * rows beyond the framebuffer, which may cause OCP error. | ||
1752 | */ | ||
1753 | if (color_mode == OMAP_DSS_COLOR_NV12 && | ||
1754 | rotation_type != OMAP_DSS_ROT_TILER) | ||
1755 | vidrot = 1; | ||
1756 | |||
1745 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); | 1757 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); |
1746 | if (dss_has_feature(FEAT_ROWREPEATENABLE)) | 1758 | if (dss_has_feature(FEAT_ROWREPEATENABLE)) |
1747 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), | 1759 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), |
@@ -2155,7 +2167,7 @@ static unsigned long calc_core_clk_five_taps(unsigned long pclk, | |||
2155 | if (height > out_height) { | 2167 | if (height > out_height) { |
2156 | unsigned int ppl = mgr_timings->x_res; | 2168 | unsigned int ppl = mgr_timings->x_res; |
2157 | 2169 | ||
2158 | tmp = pclk * height * out_width; | 2170 | tmp = (u64)pclk * height * out_width; |
2159 | do_div(tmp, 2 * out_height * ppl); | 2171 | do_div(tmp, 2 * out_height * ppl); |
2160 | core_clk = tmp; | 2172 | core_clk = tmp; |
2161 | 2173 | ||
@@ -2163,14 +2175,14 @@ static unsigned long calc_core_clk_five_taps(unsigned long pclk, | |||
2163 | if (ppl == out_width) | 2175 | if (ppl == out_width) |
2164 | return 0; | 2176 | return 0; |
2165 | 2177 | ||
2166 | tmp = pclk * (height - 2 * out_height) * out_width; | 2178 | tmp = (u64)pclk * (height - 2 * out_height) * out_width; |
2167 | do_div(tmp, 2 * out_height * (ppl - out_width)); | 2179 | do_div(tmp, 2 * out_height * (ppl - out_width)); |
2168 | core_clk = max_t(u32, core_clk, tmp); | 2180 | core_clk = max_t(u32, core_clk, tmp); |
2169 | } | 2181 | } |
2170 | } | 2182 | } |
2171 | 2183 | ||
2172 | if (width > out_width) { | 2184 | if (width > out_width) { |
2173 | tmp = pclk * width; | 2185 | tmp = (u64)pclk * width; |
2174 | do_div(tmp, out_width); | 2186 | do_div(tmp, out_width); |
2175 | core_clk = max_t(u32, core_clk, tmp); | 2187 | core_clk = max_t(u32, core_clk, tmp); |
2176 | 2188 | ||
@@ -2268,6 +2280,11 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, | |||
2268 | } | 2280 | } |
2269 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | 2281 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); |
2270 | 2282 | ||
2283 | if (error) { | ||
2284 | DSSERR("failed to find scaling settings\n"); | ||
2285 | return -EINVAL; | ||
2286 | } | ||
2287 | |||
2271 | if (in_width > maxsinglelinewidth) { | 2288 | if (in_width > maxsinglelinewidth) { |
2272 | DSSERR("Cannot scale max input width exceeded"); | 2289 | DSSERR("Cannot scale max input width exceeded"); |
2273 | return -EINVAL; | 2290 | return -EINVAL; |
@@ -2284,7 +2301,6 @@ static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, | |||
2284 | { | 2301 | { |
2285 | int error; | 2302 | int error; |
2286 | u16 in_width, in_height; | 2303 | u16 in_width, in_height; |
2287 | int min_factor = min(*decim_x, *decim_y); | ||
2288 | const int maxsinglelinewidth = | 2304 | const int maxsinglelinewidth = |
2289 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | 2305 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); |
2290 | 2306 | ||
@@ -2318,20 +2334,32 @@ again: | |||
2318 | error = (error || in_width > maxsinglelinewidth * 2 || | 2334 | error = (error || in_width > maxsinglelinewidth * 2 || |
2319 | (in_width > maxsinglelinewidth && *five_taps) || | 2335 | (in_width > maxsinglelinewidth && *five_taps) || |
2320 | !*core_clk || *core_clk > dispc_core_clk_rate()); | 2336 | !*core_clk || *core_clk > dispc_core_clk_rate()); |
2321 | if (error) { | 2337 | |
2322 | if (*decim_x == *decim_y) { | 2338 | if (!error) { |
2323 | *decim_x = min_factor; | 2339 | /* verify that we're inside the limits of scaler */ |
2324 | ++*decim_y; | 2340 | if (in_width / 4 > out_width) |
2341 | error = 1; | ||
2342 | |||
2343 | if (*five_taps) { | ||
2344 | if (in_height / 4 > out_height) | ||
2345 | error = 1; | ||
2325 | } else { | 2346 | } else { |
2326 | swap(*decim_x, *decim_y); | 2347 | if (in_height / 2 > out_height) |
2327 | if (*decim_x < *decim_y) | 2348 | error = 1; |
2328 | ++*decim_x; | ||
2329 | } | 2349 | } |
2330 | } | 2350 | } |
2351 | |||
2352 | if (error) | ||
2353 | ++*decim_y; | ||
2331 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | 2354 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); |
2332 | 2355 | ||
2333 | if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width, | 2356 | if (error) { |
2334 | height, out_width, out_height, *five_taps)) { | 2357 | DSSERR("failed to find scaling settings\n"); |
2358 | return -EINVAL; | ||
2359 | } | ||
2360 | |||
2361 | if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width, | ||
2362 | in_height, out_width, out_height, *five_taps)) { | ||
2335 | DSSERR("horizontal timing too tight\n"); | 2363 | DSSERR("horizontal timing too tight\n"); |
2336 | return -EINVAL; | 2364 | return -EINVAL; |
2337 | } | 2365 | } |
@@ -2391,6 +2419,9 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, | |||
2391 | return 0; | 2419 | return 0; |
2392 | } | 2420 | } |
2393 | 2421 | ||
2422 | #define DIV_FRAC(dividend, divisor) \ | ||
2423 | ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) | ||
2424 | |||
2394 | static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, | 2425 | static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, |
2395 | enum omap_overlay_caps caps, | 2426 | enum omap_overlay_caps caps, |
2396 | const struct omap_video_timings *mgr_timings, | 2427 | const struct omap_video_timings *mgr_timings, |
@@ -2450,8 +2481,19 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, | |||
2450 | if (ret) | 2481 | if (ret) |
2451 | return ret; | 2482 | return ret; |
2452 | 2483 | ||
2453 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); | 2484 | DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n", |
2454 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); | 2485 | width, height, |
2486 | out_width, out_height, | ||
2487 | out_width / width, DIV_FRAC(out_width, width), | ||
2488 | out_height / height, DIV_FRAC(out_height, height), | ||
2489 | |||
2490 | decim_x, decim_y, | ||
2491 | width / decim_x, height / decim_y, | ||
2492 | out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x), | ||
2493 | out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y), | ||
2494 | |||
2495 | *five_taps ? 5 : 3, | ||
2496 | core_clk, dispc_core_clk_rate()); | ||
2455 | 2497 | ||
2456 | if (!core_clk || core_clk > dispc_core_clk_rate()) { | 2498 | if (!core_clk || core_clk > dispc_core_clk_rate()) { |
2457 | DSSERR("failed to set up scaling, " | 2499 | DSSERR("failed to set up scaling, " |
@@ -2534,6 +2576,21 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
2534 | if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) | 2576 | if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) |
2535 | return -EINVAL; | 2577 | return -EINVAL; |
2536 | 2578 | ||
2579 | switch (color_mode) { | ||
2580 | case OMAP_DSS_COLOR_YUV2: | ||
2581 | case OMAP_DSS_COLOR_UYVY: | ||
2582 | case OMAP_DSS_COLOR_NV12: | ||
2583 | if (in_width & 1) { | ||
2584 | DSSERR("input width %d is not even for YUV format\n", | ||
2585 | in_width); | ||
2586 | return -EINVAL; | ||
2587 | } | ||
2588 | break; | ||
2589 | |||
2590 | default: | ||
2591 | break; | ||
2592 | } | ||
2593 | |||
2537 | out_width = out_width == 0 ? width : out_width; | 2594 | out_width = out_width == 0 ? width : out_width; |
2538 | out_height = out_height == 0 ? height : out_height; | 2595 | out_height = out_height == 0 ? height : out_height; |
2539 | 2596 | ||
@@ -2564,6 +2621,27 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
2564 | in_width = in_width / x_predecim; | 2621 | in_width = in_width / x_predecim; |
2565 | in_height = in_height / y_predecim; | 2622 | in_height = in_height / y_predecim; |
2566 | 2623 | ||
2624 | if (x_predecim > 1 || y_predecim > 1) | ||
2625 | DSSDBG("predecimation %d x %x, new input size %d x %d\n", | ||
2626 | x_predecim, y_predecim, in_width, in_height); | ||
2627 | |||
2628 | switch (color_mode) { | ||
2629 | case OMAP_DSS_COLOR_YUV2: | ||
2630 | case OMAP_DSS_COLOR_UYVY: | ||
2631 | case OMAP_DSS_COLOR_NV12: | ||
2632 | if (in_width & 1) { | ||
2633 | DSSDBG("predecimated input width is not even for YUV format\n"); | ||
2634 | DSSDBG("adjusting input width %d -> %d\n", | ||
2635 | in_width, in_width & ~1); | ||
2636 | |||
2637 | in_width &= ~1; | ||
2638 | } | ||
2639 | break; | ||
2640 | |||
2641 | default: | ||
2642 | break; | ||
2643 | } | ||
2644 | |||
2567 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 2645 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
2568 | color_mode == OMAP_DSS_COLOR_UYVY || | 2646 | color_mode == OMAP_DSS_COLOR_UYVY || |
2569 | color_mode == OMAP_DSS_COLOR_NV12) | 2647 | color_mode == OMAP_DSS_COLOR_NV12) |
@@ -2633,6 +2711,9 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
2633 | dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); | 2711 | dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); |
2634 | } | 2712 | } |
2635 | 2713 | ||
2714 | if (dispc.feat->last_pixel_inc_missing) | ||
2715 | row_inc += pix_inc - 1; | ||
2716 | |||
2636 | dispc_ovl_set_row_inc(plane, row_inc); | 2717 | dispc_ovl_set_row_inc(plane, row_inc); |
2637 | dispc_ovl_set_pix_inc(plane, pix_inc); | 2718 | dispc_ovl_set_pix_inc(plane, pix_inc); |
2638 | 2719 | ||
@@ -3710,6 +3791,7 @@ static const struct dispc_features omap24xx_dispc_feats = { | |||
3710 | .num_fifos = 3, | 3791 | .num_fifos = 3, |
3711 | .no_framedone_tv = true, | 3792 | .no_framedone_tv = true, |
3712 | .set_max_preload = false, | 3793 | .set_max_preload = false, |
3794 | .last_pixel_inc_missing = true, | ||
3713 | }; | 3795 | }; |
3714 | 3796 | ||
3715 | static const struct dispc_features omap34xx_rev1_0_dispc_feats = { | 3797 | static const struct dispc_features omap34xx_rev1_0_dispc_feats = { |
@@ -3730,6 +3812,7 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats = { | |||
3730 | .num_fifos = 3, | 3812 | .num_fifos = 3, |
3731 | .no_framedone_tv = true, | 3813 | .no_framedone_tv = true, |
3732 | .set_max_preload = false, | 3814 | .set_max_preload = false, |
3815 | .last_pixel_inc_missing = true, | ||
3733 | }; | 3816 | }; |
3734 | 3817 | ||
3735 | static const struct dispc_features omap34xx_rev3_0_dispc_feats = { | 3818 | static const struct dispc_features omap34xx_rev3_0_dispc_feats = { |
@@ -3750,6 +3833,7 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats = { | |||
3750 | .num_fifos = 3, | 3833 | .num_fifos = 3, |
3751 | .no_framedone_tv = true, | 3834 | .no_framedone_tv = true, |
3752 | .set_max_preload = false, | 3835 | .set_max_preload = false, |
3836 | .last_pixel_inc_missing = true, | ||
3753 | }; | 3837 | }; |
3754 | 3838 | ||
3755 | static const struct dispc_features omap44xx_dispc_feats = { | 3839 | static const struct dispc_features omap44xx_dispc_feats = { |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index d35312d69025..6d3aa3f51c20 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c | |||
@@ -230,9 +230,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
230 | err_mgr_enable: | 230 | err_mgr_enable: |
231 | hdmi_wp_video_stop(&hdmi.wp); | 231 | hdmi_wp_video_stop(&hdmi.wp); |
232 | err_vid_enable: | 232 | err_vid_enable: |
233 | err_phy_cfg: | ||
234 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | 233 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); |
235 | err_phy_pwr: | 234 | err_phy_pwr: |
235 | err_phy_cfg: | ||
236 | err_pll_cfg: | 236 | err_pll_cfg: |
237 | dss_pll_disable(&hdmi.pll.pll); | 237 | dss_pll_disable(&hdmi.pll.pll); |
238 | err_pll_enable: | 238 | err_pll_enable: |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c index c15377e242cc..7c544bc56fb5 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c | |||
@@ -110,7 +110,23 @@ int hdmi_wp_video_start(struct hdmi_wp_data *wp) | |||
110 | 110 | ||
111 | void hdmi_wp_video_stop(struct hdmi_wp_data *wp) | 111 | void hdmi_wp_video_stop(struct hdmi_wp_data *wp) |
112 | { | 112 | { |
113 | int i; | ||
114 | |||
115 | hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE); | ||
116 | |||
113 | REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31); | 117 | REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31); |
118 | |||
119 | for (i = 0; i < 50; ++i) { | ||
120 | u32 v; | ||
121 | |||
122 | msleep(20); | ||
123 | |||
124 | v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW); | ||
125 | if (v & HDMI_IRQ_VIDEO_FRAME_DONE) | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | DSSERR("no HDMI FRAMEDONE when disabling output\n"); | ||
114 | } | 130 | } |
115 | 131 | ||
116 | void hdmi_wp_video_config_format(struct hdmi_wp_data *wp, | 132 | void hdmi_wp_video_config_format(struct hdmi_wp_data *wp, |