aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2015-06-22 07:56:01 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-06-22 07:56:01 -0400
commitf778dad38a54ca5207d024b5ebe0e6d71b8bad83 (patch)
treeb9dc1c84c0052a51ca8ccfba8ab91c26eec6607c
parenta9bd32a8b4c4c2670f9ed8cae63f9378b6df3ded (diff)
parenta9fad6886f5229fc9989ac6cdd7ddecbf570a58f (diff)
Merge omapdss scaling fixes
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c114
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c2
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_wp.c16
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
2394static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, 2425static 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
3715static const struct dispc_features omap34xx_rev1_0_dispc_feats = { 3797static 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
3735static const struct dispc_features omap34xx_rev3_0_dispc_feats = { 3818static 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
3755static const struct dispc_features omap44xx_dispc_feats = { 3839static 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)
230err_mgr_enable: 230err_mgr_enable:
231 hdmi_wp_video_stop(&hdmi.wp); 231 hdmi_wp_video_stop(&hdmi.wp);
232err_vid_enable: 232err_vid_enable:
233err_phy_cfg:
234 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); 233 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
235err_phy_pwr: 234err_phy_pwr:
235err_phy_cfg:
236err_pll_cfg: 236err_pll_cfg:
237 dss_pll_disable(&hdmi.pll.pll); 237 dss_pll_disable(&hdmi.pll.pll);
238err_pll_enable: 238err_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
111void hdmi_wp_video_stop(struct hdmi_wp_data *wp) 111void 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
116void hdmi_wp_video_config_format(struct hdmi_wp_data *wp, 132void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,