Merge omapdss scaling fixes
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Mon, 22 Jun 2015 11:56:01 +0000 (14:56 +0300)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Mon, 22 Jun 2015 11:56:01 +0000 (14:56 +0300)
1  2 
drivers/video/fbdev/omap2/dss/dispc.c
drivers/video/fbdev/omap2/dss/hdmi4.c

index c8e34163211ae3b81af11dfdf19c58e3e324da0c,f8c9115cdb4b9381b36fcb75084050f1c2b24e6e..be716c9ffb88a8bc998cc07ba42de950d55a2ac0
@@@ -39,7 -39,6 +39,7 @@@
  #include <linux/mfd/syscon.h>
  #include <linux/regmap.h>
  #include <linux/of.h>
 +#include <linux/component.h>
  
  #include <video/omapdss.h>
  
@@@ -96,6 -95,9 +96,9 @@@ struct dispc_features 
        bool mstandby_workaround:1;
  
        bool set_max_preload:1;
+       /* PIXEL_INC is not added to the last pixel of a line */
+       bool last_pixel_inc_missing:1;
  };
  
  #define DISPC_MAX_NR_FIFOS 5
@@@ -1742,6 -1744,15 +1745,15 @@@ static void dispc_ovl_set_rotation_attr
                        row_repeat = false;
        }
  
+       /*
+        * OMAP4/5 Errata i631:
+        * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
+        * rows beyond the framebuffer, which may cause OCP error.
+        */
+       if (color_mode == OMAP_DSS_COLOR_NV12 &&
+                       rotation_type != OMAP_DSS_ROT_TILER)
+               vidrot = 1;
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
        if (dss_has_feature(FEAT_ROWREPEATENABLE))
                REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
@@@ -2155,7 -2166,7 +2167,7 @@@ static unsigned long calc_core_clk_five
        if (height > out_height) {
                unsigned int ppl = mgr_timings->x_res;
  
-               tmp = pclk * height * out_width;
+               tmp = (u64)pclk * height * out_width;
                do_div(tmp, 2 * out_height * ppl);
                core_clk = tmp;
  
                        if (ppl == out_width)
                                return 0;
  
-                       tmp = pclk * (height - 2 * out_height) * out_width;
+                       tmp = (u64)pclk * (height - 2 * out_height) * out_width;
                        do_div(tmp, 2 * out_height * (ppl - out_width));
                        core_clk = max_t(u32, core_clk, tmp);
                }
        }
  
        if (width > out_width) {
-               tmp = pclk * width;
+               tmp = (u64)pclk * width;
                do_div(tmp, out_width);
                core_clk = max_t(u32, core_clk, tmp);
  
@@@ -2268,6 -2279,11 +2280,11 @@@ static int dispc_ovl_calc_scaling_24xx(
                }
        } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
  
+       if (error) {
+               DSSERR("failed to find scaling settings\n");
+               return -EINVAL;
+       }
        if (in_width > maxsinglelinewidth) {
                DSSERR("Cannot scale max input width exceeded");
                return -EINVAL;
@@@ -2284,7 -2300,6 +2301,6 @@@ static int dispc_ovl_calc_scaling_34xx(
  {
        int error;
        u16 in_width, in_height;
-       int min_factor = min(*decim_x, *decim_y);
        const int maxsinglelinewidth =
                        dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
  
@@@ -2318,20 -2333,32 +2334,32 @@@ again
                error = (error || in_width > maxsinglelinewidth * 2 ||
                        (in_width > maxsinglelinewidth && *five_taps) ||
                        !*core_clk || *core_clk > dispc_core_clk_rate());
-               if (error) {
-                       if (*decim_x == *decim_y) {
-                               *decim_x = min_factor;
-                               ++*decim_y;
+               if (!error) {
+                       /* verify that we're inside the limits of scaler */
+                       if (in_width / 4 > out_width)
+                                       error = 1;
+                       if (*five_taps) {
+                               if (in_height / 4 > out_height)
+                                       error = 1;
                        } else {
-                               swap(*decim_x, *decim_y);
-                               if (*decim_x < *decim_y)
-                                       ++*decim_x;
+                               if (in_height / 2 > out_height)
+                                       error = 1;
                        }
                }
+               if (error)
+                       ++*decim_y;
        } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
  
-       if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width,
-                               height, out_width, out_height, *five_taps)) {
+       if (error) {
+               DSSERR("failed to find scaling settings\n");
+               return -EINVAL;
+       }
+       if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width,
+                               in_height, out_width, out_height, *five_taps)) {
                        DSSERR("horizontal timing too tight\n");
                        return -EINVAL;
        }
@@@ -2391,6 -2418,9 +2419,9 @@@ static int dispc_ovl_calc_scaling_44xx(
        return 0;
  }
  
+ #define DIV_FRAC(dividend, divisor) \
+       ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
  static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
                enum omap_overlay_caps caps,
                const struct omap_video_timings *mgr_timings,
        if (ret)
                return ret;
  
-       DSSDBG("required core clk rate = %lu Hz\n", core_clk);
-       DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
+       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",
+               width, height,
+               out_width, out_height,
+               out_width / width, DIV_FRAC(out_width, width),
+               out_height / height, DIV_FRAC(out_height, height),
+               decim_x, decim_y,
+               width / decim_x, height / decim_y,
+               out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
+               out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
+               *five_taps ? 5 : 3,
+               core_clk, dispc_core_clk_rate());
  
        if (!core_clk || core_clk > dispc_core_clk_rate()) {
                DSSERR("failed to set up scaling, "
@@@ -2534,6 -2575,21 +2576,21 @@@ static int dispc_ovl_setup_common(enum 
        if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
                return -EINVAL;
  
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_YUV2:
+       case OMAP_DSS_COLOR_UYVY:
+       case OMAP_DSS_COLOR_NV12:
+               if (in_width & 1) {
+                       DSSERR("input width %d is not even for YUV format\n",
+                               in_width);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               break;
+       }
        out_width = out_width == 0 ? width : out_width;
        out_height = out_height == 0 ? height : out_height;
  
        in_width = in_width / x_predecim;
        in_height = in_height / y_predecim;
  
+       if (x_predecim > 1 || y_predecim > 1)
+               DSSDBG("predecimation %d x %x, new input size %d x %d\n",
+                       x_predecim, y_predecim, in_width, in_height);
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_YUV2:
+       case OMAP_DSS_COLOR_UYVY:
+       case OMAP_DSS_COLOR_NV12:
+               if (in_width & 1) {
+                       DSSDBG("predecimated input width is not even for YUV format\n");
+                       DSSDBG("adjusting input width %d -> %d\n",
+                               in_width, in_width & ~1);
+                       in_width &= ~1;
+               }
+               break;
+       default:
+               break;
+       }
        if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY ||
                        color_mode == OMAP_DSS_COLOR_NV12)
                dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
        }
  
+       if (dispc.feat->last_pixel_inc_missing)
+               row_inc += pix_inc - 1;
        dispc_ovl_set_row_inc(plane, row_inc);
        dispc_ovl_set_pix_inc(plane, pix_inc);
  
@@@ -3693,7 -3773,7 +3774,7 @@@ static void _omap_dispc_initial_config(
                dispc_init_mflag();
  }
  
 -static const struct dispc_features omap24xx_dispc_feats __initconst = {
 +static const struct dispc_features omap24xx_dispc_feats = {
        .sw_start               =       5,
        .fp_start               =       15,
        .bp_start               =       27,
        .num_fifos              =       3,
        .no_framedone_tv        =       true,
        .set_max_preload        =       false,
+       .last_pixel_inc_missing =       true,
  };
  
 -static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
 +static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
        .sw_start               =       5,
        .fp_start               =       15,
        .bp_start               =       27,
        .num_fifos              =       3,
        .no_framedone_tv        =       true,
        .set_max_preload        =       false,
+       .last_pixel_inc_missing =       true,
  };
  
 -static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
 +static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
        .sw_start               =       7,
        .fp_start               =       19,
        .bp_start               =       31,
        .num_fifos              =       3,
        .no_framedone_tv        =       true,
        .set_max_preload        =       false,
+       .last_pixel_inc_missing =       true,
  };
  
 -static const struct dispc_features omap44xx_dispc_feats __initconst = {
 +static const struct dispc_features omap44xx_dispc_feats = {
        .sw_start               =       7,
        .fp_start               =       19,
        .bp_start               =       31,
        .set_max_preload        =       true,
  };
  
 -static const struct dispc_features omap54xx_dispc_feats __initconst = {
 +static const struct dispc_features omap54xx_dispc_feats = {
        .sw_start               =       7,
        .fp_start               =       19,
        .bp_start               =       31,
        .set_max_preload        =       true,
  };
  
 -static int __init dispc_init_features(struct platform_device *pdev)
 +static int dispc_init_features(struct platform_device *pdev)
  {
        const struct dispc_features *src;
        struct dispc_features *dst;
@@@ -3883,9 -3966,8 +3967,9 @@@ void dispc_free_irq(void *dev_id
  EXPORT_SYMBOL(dispc_free_irq);
  
  /* DISPC HW IP initialisation */
 -static int __init omap_dispchw_probe(struct platform_device *pdev)
 +static int dispc_bind(struct device *dev, struct device *master, void *data)
  {
 +      struct platform_device *pdev = to_platform_device(dev);
        u32 rev;
        int r = 0;
        struct resource *dispc_mem;
@@@ -3957,27 -4039,12 +4041,27 @@@ err_runtime_get
        return r;
  }
  
 -static int __exit omap_dispchw_remove(struct platform_device *pdev)
 +static void dispc_unbind(struct device *dev, struct device *master,
 +                             void *data)
  {
 -      pm_runtime_disable(&pdev->dev);
 +      pm_runtime_disable(dev);
  
        dss_uninit_overlay_managers();
 +}
 +
 +static const struct component_ops dispc_component_ops = {
 +      .bind   = dispc_bind,
 +      .unbind = dispc_unbind,
 +};
  
 +static int dispc_probe(struct platform_device *pdev)
 +{
 +      return component_add(&pdev->dev, &dispc_component_ops);
 +}
 +
 +static int dispc_remove(struct platform_device *pdev)
 +{
 +      component_del(&pdev->dev, &dispc_component_ops);
        return 0;
  }
  
@@@ -4030,8 -4097,7 +4114,8 @@@ static const struct of_device_id dispc_
  };
  
  static struct platform_driver omap_dispchw_driver = {
 -      .remove         = __exit_p(omap_dispchw_remove),
 +      .probe          = dispc_probe,
 +      .remove         = dispc_remove,
        .driver         = {
                .name   = "omapdss_dispc",
                .pm     = &dispc_pm_ops,
  
  int __init dispc_init_platform_driver(void)
  {
 -      return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe);
 +      return platform_driver_register(&omap_dispchw_driver);
  }
  
 -void __exit dispc_uninit_platform_driver(void)
 +void dispc_uninit_platform_driver(void)
  {
        platform_driver_unregister(&omap_dispchw_driver);
  }
index d35312d6902534eb9caee2e8f111f54367fb853e,e1345abd41bb1a97cfff335e6749d21a68159175..6d3aa3f51c205704a41e0506149ec9f81154b074
@@@ -32,7 -32,6 +32,7 @@@
  #include <linux/clk.h>
  #include <linux/gpio.h>
  #include <linux/regulator/consumer.h>
 +#include <linux/component.h>
  #include <video/omapdss.h>
  #include <sound/omap-hdmi-audio.h>
  
@@@ -230,9 -229,9 +230,9 @@@ static int hdmi_power_on_full(struct om
  err_mgr_enable:
        hdmi_wp_video_stop(&hdmi.wp);
  err_vid_enable:
- err_phy_cfg:
        hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
  err_phy_pwr:
+ err_phy_cfg:
  err_pll_cfg:
        dss_pll_disable(&hdmi.pll.pll);
  err_pll_enable:
@@@ -647,9 -646,8 +647,9 @@@ static int hdmi_audio_register(struct d
  }
  
  /* HDMI HW IP initialisation */
 -static int omapdss_hdmihw_probe(struct platform_device *pdev)
 +static int hdmi4_bind(struct device *dev, struct device *master, void *data)
  {
 +      struct platform_device *pdev = to_platform_device(dev);
        int r;
        int irq;
  
@@@ -715,10 -713,8 +715,10 @@@ err
        return r;
  }
  
 -static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 +static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
  {
 +      struct platform_device *pdev = to_platform_device(dev);
 +
        if (hdmi.audio_pdev)
                platform_device_unregister(hdmi.audio_pdev);
  
        hdmi_pll_uninit(&hdmi.pll);
  
        pm_runtime_disable(&pdev->dev);
 +}
 +
 +static const struct component_ops hdmi4_component_ops = {
 +      .bind   = hdmi4_bind,
 +      .unbind = hdmi4_unbind,
 +};
  
 +static int hdmi4_probe(struct platform_device *pdev)
 +{
 +      return component_add(&pdev->dev, &hdmi4_component_ops);
 +}
 +
 +static int hdmi4_remove(struct platform_device *pdev)
 +{
 +      component_del(&pdev->dev, &hdmi4_component_ops);
        return 0;
  }
  
@@@ -774,8 -756,8 +774,8 @@@ static const struct of_device_id hdmi_o
  };
  
  static struct platform_driver omapdss_hdmihw_driver = {
 -      .probe          = omapdss_hdmihw_probe,
 -      .remove         = __exit_p(omapdss_hdmihw_remove),
 +      .probe          = hdmi4_probe,
 +      .remove         = hdmi4_remove,
        .driver         = {
                .name   = "omapdss_hdmi",
                .pm     = &hdmi_pm_ops,
@@@ -789,7 -771,7 +789,7 @@@ int __init hdmi4_init_platform_driver(v
        return platform_driver_register(&omapdss_hdmihw_driver);
  }
  
 -void __exit hdmi4_uninit_platform_driver(void)
 +void hdmi4_uninit_platform_driver(void)
  {
        platform_driver_unregister(&omapdss_hdmihw_driver);
  }
This page took 0.0333 seconds and 5 git commands to generate.