This patch add the initial and necessary logic for CORE to support scaler:
- Complete the struct komeda_scaler and komeda_scaler_state for adding
  the scaler specific features and capablities.
- Implement komeda_scaler_validate to check the scaler with the data flow
  configurations.
- Enable scaling support for plane input path (layer input data flow).

v2: Fix a typo, and rename "needs_scaling" to "en_scaling"

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.w...@arm.com>
---
 .../drm/arm/display/komeda/komeda_pipeline.c  |  14 +++
 .../drm/arm/display/komeda/komeda_pipeline.h  |  20 ++-
 .../display/komeda/komeda_pipeline_state.c    | 116 ++++++++++++++++++
 .../gpu/drm/arm/display/komeda/komeda_plane.c |   8 ++
 4 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c 
b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index a130b62fa6d1..96248586b4e8 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -126,6 +126,20 @@ komeda_pipeline_get_component(struct komeda_pipeline 
*pipe, int id)
        return c;
 }
 
+struct komeda_component *
+komeda_pipeline_get_first_component(struct komeda_pipeline *pipe,
+                                   u32 comp_mask)
+{
+       struct komeda_component *c = NULL;
+       int id;
+
+       id = find_first_bit((unsigned long *)&comp_mask, 32);
+       if (id < 32)
+               c = komeda_pipeline_get_component(pipe, id);
+
+       return c;
+}
+
 /** komeda_component_add - Add a component to &komeda_pipeline */
 struct komeda_component *
 komeda_component_add(struct komeda_pipeline *pipe,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h 
b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index fdde93bad8de..400af217ed86 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -244,11 +244,17 @@ struct komeda_layer_state {
 
 struct komeda_scaler {
        struct komeda_component base;
-       /* scaler features and caps */
+       struct malidp_range hsize, vsize;
+       u32 max_upscaling;
+       u32 max_downscaling;
 };
 
 struct komeda_scaler_state {
        struct komeda_component_state base;
+       u16 hsize_in, vsize_in;
+       u16 hsize_out, vsize_out;
+       u8 en_scaling : 1,
+          en_alpha : 1; /* enable alpha processing */
 };
 
 struct komeda_compiz {
@@ -307,6 +313,7 @@ struct komeda_data_flow_cfg {
        u32 rot;
        int blending_zorder;
        u8 pixel_blend_mode, layer_alpha;
+       u8 en_scaling : 1;
 };
 
 /** struct komeda_pipeline_funcs */
@@ -407,6 +414,9 @@ void komeda_pipeline_destroy(struct komeda_dev *mdev,
 int komeda_assemble_pipelines(struct komeda_dev *mdev);
 struct komeda_component *
 komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
+struct komeda_component *
+komeda_pipeline_get_first_component(struct komeda_pipeline *pipe,
+                                   u32 comp_mask);
 
 void komeda_pipeline_dump_register(struct komeda_pipeline *pipe,
                                   struct seq_file *sf);
@@ -423,6 +433,14 @@ komeda_component_add(struct komeda_pipeline *pipe,
 void komeda_component_destroy(struct komeda_dev *mdev,
                              struct komeda_component *c);
 
+static inline struct komeda_component *
+komeda_component_pickup_output(struct komeda_component *c, u32 avail_comps)
+{
+       u32 avail_inputs = c->supported_outputs & (avail_comps);
+
+       return komeda_pipeline_get_first_component(c->pipeline, avail_inputs);
+}
+
 struct komeda_plane_state;
 struct komeda_crtc_state;
 struct komeda_crtc;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c 
b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
index db2c3d6d2a8a..a5300ef92eb7 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -249,6 +249,26 @@ komeda_component_validate_private(struct komeda_component 
*c,
        return err;
 }
 
+/* Get current available scaler from the component->supported_outputs */
+static struct komeda_scaler *
+komeda_component_get_avail_scaler(struct komeda_component *c,
+                                 struct drm_atomic_state *state)
+{
+       struct komeda_pipeline_state *pipe_st;
+       u32 avail_scalers;
+
+       pipe_st = komeda_pipeline_get_state(c->pipeline, state);
+       if (!pipe_st)
+               return NULL;
+
+       avail_scalers = (pipe_st->active_comps & KOMEDA_PIPELINE_SCALERS) ^
+                       KOMEDA_PIPELINE_SCALERS;
+
+       c = komeda_component_pickup_output(c, avail_scalers);
+
+       return to_scaler(c);
+}
+
 static int
 komeda_layer_check_cfg(struct komeda_layer *layer,
                       struct komeda_plane_state *kplane_st,
@@ -355,6 +375,98 @@ komeda_wb_layer_validate(struct komeda_layer *wb_layer,
        return 0;
 }
 
+static bool scaling_ratio_valid(u32 size_in, u32 size_out,
+                               u32 max_upscaling, u32 max_downscaling)
+{
+       if (size_out > size_in * max_upscaling)
+               return false;
+       else if (size_in > size_out * max_downscaling)
+               return false;
+       return true;
+}
+
+static int
+komeda_scaler_check_cfg(struct komeda_scaler *scaler,
+                       struct komeda_data_flow_cfg *dflow)
+{
+       u32 hsize_in, vsize_in, hsize_out, vsize_out;
+
+       hsize_in = dflow->in_w;
+       vsize_in = dflow->in_h;
+       hsize_out = dflow->out_w;
+       vsize_out = dflow->out_h;
+
+       if (!in_range(&scaler->hsize, hsize_in) ||
+           !in_range(&scaler->hsize, hsize_out)) {
+               DRM_DEBUG_ATOMIC("Invalid horizontal sizes");
+               return -EINVAL;
+       }
+
+       if (!in_range(&scaler->vsize, vsize_in) ||
+           !in_range(&scaler->vsize, vsize_out)) {
+               DRM_DEBUG_ATOMIC("Invalid vertical sizes");
+               return -EINVAL;
+       }
+
+       if (!scaling_ratio_valid(hsize_in, hsize_out, scaler->max_upscaling,
+                                scaler->max_downscaling)) {
+               DRM_DEBUG_ATOMIC("Invalid horizontal scaling ratio");
+               return -EINVAL;
+       }
+
+       if (!scaling_ratio_valid(vsize_in, vsize_out, scaler->max_upscaling,
+                                scaler->max_downscaling)) {
+               DRM_DEBUG_ATOMIC("Invalid vertical scaling ratio");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int
+komeda_scaler_validate(void *user,
+                      struct komeda_crtc_state *kcrtc_st,
+                      struct komeda_data_flow_cfg *dflow)
+{
+       struct drm_atomic_state *drm_st = kcrtc_st->base.state;
+       struct komeda_component_state *c_st;
+       struct komeda_scaler_state *st;
+       struct komeda_scaler *scaler;
+       int err = 0;
+
+       if (!dflow->en_scaling)
+               return 0;
+
+       scaler = komeda_component_get_avail_scaler(dflow->input.component,
+                                                  drm_st);
+       if (!scaler) {
+               DRM_DEBUG_ATOMIC("No scaler available");
+               return -EINVAL;
+       }
+
+       err = komeda_scaler_check_cfg(scaler, dflow);
+       if (err)
+               return err;
+
+       c_st = komeda_component_get_state_and_set_user(&scaler->base,
+                       drm_st, user, kcrtc_st->base.crtc);
+       if (IS_ERR(c_st))
+               return PTR_ERR(c_st);
+
+       st = to_scaler_st(c_st);
+
+       st->hsize_in = dflow->in_w;
+       st->vsize_in = dflow->in_h;
+       st->hsize_out = dflow->out_w;
+       st->vsize_out = dflow->out_h;
+       st->en_scaling = dflow->en_scaling;
+       /* Enable alpha processing if the next stage needs the pixel alpha */
+       st->en_alpha = dflow->pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE;
+
+       komeda_component_add_input(&st->base, &dflow->input, 0);
+       komeda_component_set_output(&dflow->input, &scaler->base, 0);
+       return err;
+}
+
 void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
                               u16 *hsize, u16 *vsize)
 {
@@ -520,6 +632,10 @@ int komeda_build_layer_data_flow(struct komeda_layer 
*layer,
        if (err)
                return err;
 
+       err = komeda_scaler_validate(plane, kcrtc_st, dflow);
+       if (err)
+               return err;
+
        err = komeda_compiz_set_input(pipe->compiz, kcrtc_st, dflow);
 
        return err;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c 
b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
index 6462c0206942..cd3a7172a756 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -16,6 +16,7 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
                            struct komeda_data_flow_cfg *dflow)
 {
        struct drm_framebuffer *fb = st->fb;
+       u32 w, h;
 
        memset(dflow, 0, sizeof(*dflow));
 
@@ -36,6 +37,13 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
        dflow->in_w = st->src_w >> 16;
        dflow->in_h = st->src_h >> 16;
 
+       w = dflow->in_w;
+       h = dflow->in_h;
+       if (drm_rotation_90_or_270(dflow->rot))
+               swap(w, h);
+
+       dflow->en_scaling = (w != dflow->out_w) || (h != dflow->out_h);
+
        return 0;
 }
 
-- 
2.17.1

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

Reply via email to