Calculate scaling parameters and call appropriate scaler set up
function.

Signed-off-by: Jernej Skrabec <jernej.skra...@siol.net>
---
 drivers/gpu/drm/sun4i/sun8i_layer.c |  12 +++-
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 115 +++++++++++++++++++++++++-----------
 drivers/gpu/drm/sun4i/sun8i_mixer.h |   4 --
 3 files changed, 90 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_layer.c
index e1b6ad82145e..6860271e5415 100644
--- a/drivers/gpu/drm/sun4i/sun8i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
@@ -25,8 +25,11 @@
 static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
                                          struct drm_plane_state *state)
 {
+       struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
        struct drm_crtc *crtc = state->crtc;
        struct drm_crtc_state *crtc_state;
+       int min_scale, max_scale;
+       bool scaler_supported;
        struct drm_rect clip;
 
        if (!crtc)
@@ -41,9 +44,14 @@ static int sun8i_mixer_layer_atomic_check(struct drm_plane 
*plane,
        clip.x2 = crtc_state->adjusted_mode.hdisplay;
        clip.y2 = crtc_state->adjusted_mode.vdisplay;
 
+       scaler_supported = !!(layer->mixer->cfg->scaler_mask & BIT(layer->id));
+
+       min_scale = scaler_supported ? 1 : DRM_PLANE_HELPER_NO_SCALING;
+       max_scale = scaler_supported ? (1UL << 20) - 1 :
+                                      DRM_PLANE_HELPER_NO_SCALING;
+
        return drm_plane_helper_check_state(state, &clip,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           DRM_PLANE_HELPER_NO_SCALING,
+                                           min_scale, max_scale,
                                            true, true);
 }
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 291dd8806444..7c9c87a0535b 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -28,6 +28,7 @@
 #include "sun8i_mixer.h"
 #include "sun8i_layer.h"
 #include "sunxi_engine.h"
+#include "sun8i_scaler.h"
 
 struct de2_fmt_info {
        u32 drm_fmt;
@@ -194,29 +195,34 @@ int sun8i_mixer_update_ui_layer_coord(struct sun8i_mixer 
*mixer,
                                      int layer, struct drm_plane *plane)
 {
        struct drm_plane_state *state = plane->state;
-       u32 width, height, size;
+       u32 src_w, src_h, dst_w, dst_h;
+       u32 outsize, insize;
+       u32 hphase, vphase;
 
-       DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
+       DRM_DEBUG_DRIVER("Updating UI layer %d\n", layer);
 
-       /*
-        * Same source and destination width and height are guaranteed
-        * by atomic check function.
-        */
-       width = drm_rect_width(&state->dst);
-       height = drm_rect_height(&state->dst);
-       size = SUN8I_MIXER_SIZE(width, height);
+       src_w = drm_rect_width(&state->src) >> 16;
+       src_h = drm_rect_height(&state->src) >> 16;
+       dst_w = drm_rect_width(&state->dst);
+       dst_h = drm_rect_height(&state->dst);
+
+       hphase = state->src.x1 & 0xffff;
+       vphase = state->src.y1 & 0xffff;
+
+       insize = SUN8I_MIXER_SIZE(src_w, src_h);
+       outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
 
        if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
                bool interlaced = false;
                u32 val;
 
                DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: 
%u\n",
-                                width, height);
+                                dst_w, dst_h);
                regmap_write(mixer->engine.regs,
                             SUN8I_MIXER_GLOBAL_SIZE,
-                            size);
+                            outsize);
                regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
-                            size);
+                            outsize);
 
                if (state->crtc)
                        interlaced = state->crtc->state->adjusted_mode.flags
@@ -237,23 +243,40 @@ int sun8i_mixer_update_ui_layer_coord(struct sun8i_mixer 
*mixer,
        }
 
        /* Set height and width */
-       DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", width, height);
+       DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
+                        state->src.x1 >> 16, state->src.y1 >> 16);
+       DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_UI_LAYER_SIZE(layer, 0),
-                    size);
+                    SUN8I_MIXER_CHAN_UI_LAYER_SIZE(layer, 0), insize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_UI_OVL_SIZE(layer),
-                    size);
+                    SUN8I_MIXER_CHAN_UI_OVL_SIZE(layer), insize);
+
+       if (insize != outsize || hphase || vphase) {
+               u32 hscale, vscale;
+
+               DRM_DEBUG_DRIVER("HW scaling is enabled\n");
+
+               hscale = state->src_w / state->crtc_w;
+               vscale = state->src_h / state->crtc_h;
+
+               sun8i_scaler_gsu_setup(mixer, layer, src_w, src_h, dst_w, dst_h,
+                                      hscale, vscale, hphase, vphase);
+               sun8i_scaler_gsu_enable(mixer, layer, true);
+       } else {
+               DRM_DEBUG_DRIVER("HW scaling is not needed\n");
+               sun8i_scaler_gsu_enable(mixer, layer, false);
+       }
 
        /* Set base coordinates */
-       DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
+       DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
                         state->dst.x1, state->dst.y1);
+       DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
        regmap_write(mixer->engine.regs,
                     SUN8I_MIXER_BLEND_ATTR_COORD(layer),
                     SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
        regmap_write(mixer->engine.regs,
                     SUN8I_MIXER_BLEND_ATTR_INSIZE(layer),
-                    size);
+                    outsize);
 
        return 0;
 }
@@ -262,36 +285,58 @@ int sun8i_mixer_update_vi_layer_coord(struct sun8i_mixer 
*mixer,
                                      int layer, struct drm_plane *plane)
 {
        struct drm_plane_state *state = plane->state;
-       u32 width, height, size;
+       u32 src_w, src_h, dst_w, dst_h;
+       u32 outsize, insize;
+       u32 hphase, vphase;
 
-       DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
+       DRM_DEBUG_DRIVER("Updating VI layer %d\n", layer);
 
-       /*
-        * Same source and destination width and height are guaranteed
-        * by atomic check function.
-        */
-       width = drm_rect_width(&state->dst);
-       height = drm_rect_height(&state->dst);
-       size = SUN8I_MIXER_SIZE(width, height);
+       src_w = drm_rect_width(&state->src) >> 16;
+       src_h = drm_rect_height(&state->src) >> 16;
+       dst_w = drm_rect_width(&state->dst);
+       dst_h = drm_rect_height(&state->dst);
+
+       hphase = state->src.x1 & 0xffff;
+       vphase = state->src.y1 & 0xffff;
+
+       insize = SUN8I_MIXER_SIZE(src_w, src_h);
+       outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
 
        /* Set height and width */
-       DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", width, height);
+       DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
+                        state->src.x1 >> 16, state->src.y1 >> 16);
+       DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_VI_LAYER_SIZE(layer, 0),
-                    size);
+                    SUN8I_MIXER_CHAN_VI_LAYER_SIZE(layer, 0), insize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_VI_OVL_SIZE(layer),
-                    size);
+                    SUN8I_MIXER_CHAN_VI_OVL_SIZE(layer), insize);
+
+       if (insize != outsize || hphase || vphase) {
+               u32 hscale, vscale;
+
+               DRM_DEBUG_DRIVER("HW scaling is enabled\n");
+
+               hscale = state->src_w / state->crtc_w;
+               vscale = state->src_h / state->crtc_h;
+
+               sun8i_scaler_vsu_setup(mixer, layer, src_w, src_h, dst_w, dst_h,
+                                      hscale, vscale, hphase, vphase);
+               sun8i_scaler_vsu_enable(mixer, layer, true);
+       } else {
+               DRM_DEBUG_DRIVER("HW scaling is not needed\n");
+               sun8i_scaler_vsu_enable(mixer, layer, false);
+       }
 
        /* Set base coordinates */
-       DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
+       DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
                         state->dst.x1, state->dst.y1);
+       DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
        regmap_write(mixer->engine.regs,
                     SUN8I_MIXER_BLEND_ATTR_COORD(layer),
                     SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
        regmap_write(mixer->engine.regs,
                     SUN8I_MIXER_BLEND_ATTR_INSIZE(layer),
-                    size);
+                    outsize);
 
        return 0;
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index ad5aef5846ae..355a45e6cfb4 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -124,10 +124,6 @@
  * These sub-engines are still unknown now, the EN registers are here only to
  * be used to disable these sub-engines.
  */
-#define SUN8I_MIXER_VSU_EN                     0x20000
-#define SUN8I_MIXER_GSU1_EN                    0x30000
-#define SUN8I_MIXER_GSU2_EN                    0x40000
-#define SUN8I_MIXER_GSU3_EN                    0x50000
 #define SUN8I_MIXER_FCE_EN                     0xa0000
 #define SUN8I_MIXER_BWS_EN                     0xa2000
 #define SUN8I_MIXER_LTI_EN                     0xa4000
-- 
2.15.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to