Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge omapdss scaling fixes

+116 -16
+99 -15
drivers/video/fbdev/omap2/dss/dispc.c
··· 96 96 bool mstandby_workaround:1; 97 97 98 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 104 #define DISPC_MAX_NR_FIFOS 5 ··· 1745 1742 row_repeat = false; 1746 1743 } 1747 1744 1745 + /* 1746 + * OMAP4/5 Errata i631: 1747 + * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra 1748 + * rows beyond the framebuffer, which may cause OCP error. 1749 + */ 1750 + if (color_mode == OMAP_DSS_COLOR_NV12 && 1751 + rotation_type != OMAP_DSS_ROT_TILER) 1752 + vidrot = 1; 1753 + 1748 1754 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); 1749 1755 if (dss_has_feature(FEAT_ROWREPEATENABLE)) 1750 1756 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ··· 2167 2155 if (height > out_height) { 2168 2156 unsigned int ppl = mgr_timings->x_res; 2169 2157 2170 - tmp = pclk * height * out_width; 2158 + tmp = (u64)pclk * height * out_width; 2171 2159 do_div(tmp, 2 * out_height * ppl); 2172 2160 core_clk = tmp; 2173 2161 ··· 2175 2163 if (ppl == out_width) 2176 2164 return 0; 2177 2165 2178 - tmp = pclk * (height - 2 * out_height) * out_width; 2166 + tmp = (u64)pclk * (height - 2 * out_height) * out_width; 2179 2167 do_div(tmp, 2 * out_height * (ppl - out_width)); 2180 2168 core_clk = max_t(u32, core_clk, tmp); 2181 2169 } 2182 2170 } 2183 2171 2184 2172 if (width > out_width) { 2185 - tmp = pclk * width; 2173 + tmp = (u64)pclk * width; 2186 2174 do_div(tmp, out_width); 2187 2175 core_clk = max_t(u32, core_clk, tmp); 2188 2176 ··· 2280 2268 } 2281 2269 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); 2282 2270 2271 + if (error) { 2272 + DSSERR("failed to find scaling settings\n"); 2273 + return -EINVAL; 2274 + } 2275 + 2283 2276 if (in_width > maxsinglelinewidth) { 2284 2277 DSSERR("Cannot scale max input width exceeded"); 2285 2278 return -EINVAL; ··· 2301 2284 { 2302 2285 int error; 2303 2286 u16 in_width, in_height; 2304 - int min_factor = min(*decim_x, *decim_y); 2305 2287 const int maxsinglelinewidth = 2306 2288 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); 2307 2289 ··· 2334 2318 error = (error || in_width > maxsinglelinewidth * 2 || 2335 2319 (in_width > maxsinglelinewidth && *five_taps) || 2336 2320 !*core_clk || *core_clk > dispc_core_clk_rate()); 2337 - if (error) { 2338 - if (*decim_x == *decim_y) { 2339 - *decim_x = min_factor; 2340 - ++*decim_y; 2321 + 2322 + if (!error) { 2323 + /* verify that we're inside the limits of scaler */ 2324 + if (in_width / 4 > out_width) 2325 + error = 1; 2326 + 2327 + if (*five_taps) { 2328 + if (in_height / 4 > out_height) 2329 + error = 1; 2341 2330 } else { 2342 - swap(*decim_x, *decim_y); 2343 - if (*decim_x < *decim_y) 2344 - ++*decim_x; 2331 + if (in_height / 2 > out_height) 2332 + error = 1; 2345 2333 } 2346 2334 } 2335 + 2336 + if (error) 2337 + ++*decim_y; 2347 2338 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); 2348 2339 2349 - if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width, 2350 - height, out_width, out_height, *five_taps)) { 2340 + if (error) { 2341 + DSSERR("failed to find scaling settings\n"); 2342 + return -EINVAL; 2343 + } 2344 + 2345 + if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width, 2346 + in_height, out_width, out_height, *five_taps)) { 2351 2347 DSSERR("horizontal timing too tight\n"); 2352 2348 return -EINVAL; 2353 2349 } ··· 2418 2390 out_width, out_height, mem_to_mem); 2419 2391 return 0; 2420 2392 } 2393 + 2394 + #define DIV_FRAC(dividend, divisor) \ 2395 + ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) 2421 2396 2422 2397 static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, 2423 2398 enum omap_overlay_caps caps, ··· 2481 2450 if (ret) 2482 2451 return ret; 2483 2452 2484 - DSSDBG("required core clk rate = %lu Hz\n", core_clk); 2485 - DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); 2453 + 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 + width, height, 2455 + out_width, out_height, 2456 + out_width / width, DIV_FRAC(out_width, width), 2457 + out_height / height, DIV_FRAC(out_height, height), 2458 + 2459 + decim_x, decim_y, 2460 + width / decim_x, height / decim_y, 2461 + out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x), 2462 + out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y), 2463 + 2464 + *five_taps ? 5 : 3, 2465 + core_clk, dispc_core_clk_rate()); 2486 2466 2487 2467 if (!core_clk || core_clk > dispc_core_clk_rate()) { 2488 2468 DSSERR("failed to set up scaling, " ··· 2576 2534 if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) 2577 2535 return -EINVAL; 2578 2536 2537 + switch (color_mode) { 2538 + case OMAP_DSS_COLOR_YUV2: 2539 + case OMAP_DSS_COLOR_UYVY: 2540 + case OMAP_DSS_COLOR_NV12: 2541 + if (in_width & 1) { 2542 + DSSERR("input width %d is not even for YUV format\n", 2543 + in_width); 2544 + return -EINVAL; 2545 + } 2546 + break; 2547 + 2548 + default: 2549 + break; 2550 + } 2551 + 2579 2552 out_width = out_width == 0 ? width : out_width; 2580 2553 out_height = out_height == 0 ? height : out_height; 2581 2554 ··· 2620 2563 2621 2564 in_width = in_width / x_predecim; 2622 2565 in_height = in_height / y_predecim; 2566 + 2567 + if (x_predecim > 1 || y_predecim > 1) 2568 + DSSDBG("predecimation %d x %x, new input size %d x %d\n", 2569 + x_predecim, y_predecim, in_width, in_height); 2570 + 2571 + switch (color_mode) { 2572 + case OMAP_DSS_COLOR_YUV2: 2573 + case OMAP_DSS_COLOR_UYVY: 2574 + case OMAP_DSS_COLOR_NV12: 2575 + if (in_width & 1) { 2576 + DSSDBG("predecimated input width is not even for YUV format\n"); 2577 + DSSDBG("adjusting input width %d -> %d\n", 2578 + in_width, in_width & ~1); 2579 + 2580 + in_width &= ~1; 2581 + } 2582 + break; 2583 + 2584 + default: 2585 + break; 2586 + } 2623 2587 2624 2588 if (color_mode == OMAP_DSS_COLOR_YUV2 || 2625 2589 color_mode == OMAP_DSS_COLOR_UYVY || ··· 2710 2632 dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); 2711 2633 dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); 2712 2634 } 2635 + 2636 + if (dispc.feat->last_pixel_inc_missing) 2637 + row_inc += pix_inc - 1; 2713 2638 2714 2639 dispc_ovl_set_row_inc(plane, row_inc); 2715 2640 dispc_ovl_set_pix_inc(plane, pix_inc); ··· 3791 3710 .num_fifos = 3, 3792 3711 .no_framedone_tv = true, 3793 3712 .set_max_preload = false, 3713 + .last_pixel_inc_missing = true, 3794 3714 }; 3795 3715 3796 3716 static const struct dispc_features omap34xx_rev1_0_dispc_feats = { ··· 3812 3730 .num_fifos = 3, 3813 3731 .no_framedone_tv = true, 3814 3732 .set_max_preload = false, 3733 + .last_pixel_inc_missing = true, 3815 3734 }; 3816 3735 3817 3736 static const struct dispc_features omap34xx_rev3_0_dispc_feats = { ··· 3833 3750 .num_fifos = 3, 3834 3751 .no_framedone_tv = true, 3835 3752 .set_max_preload = false, 3753 + .last_pixel_inc_missing = true, 3836 3754 }; 3837 3755 3838 3756 static const struct dispc_features omap44xx_dispc_feats = {
+1 -1
drivers/video/fbdev/omap2/dss/hdmi4.c
··· 230 230 err_mgr_enable: 231 231 hdmi_wp_video_stop(&hdmi.wp); 232 232 err_vid_enable: 233 - err_phy_cfg: 234 233 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); 235 234 err_phy_pwr: 235 + err_phy_cfg: 236 236 err_pll_cfg: 237 237 dss_pll_disable(&hdmi.pll.pll); 238 238 err_pll_enable:
+16
drivers/video/fbdev/omap2/dss/hdmi_wp.c
··· 110 110 111 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 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 132 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,