From 264b9436d23b065cb74d76dff49b4ffac2cee11e Mon Sep 17 00:00:00 2001 From: "james qian wang (Arm Technology China)" Date: Wed, 12 Jun 2019 11:20:18 +0100 Subject: [PATCH] drm/komeda: Enable writeback split support Writeback split is also for workaround the size limitation of d71 scaler. Like layer_split, writeback downscaling also can use two scalers to handle the scaling half-by-half. The only differnence is writback needs a standalone component (splitter)'s help to split the composition result. The data pipeline of writeback split as below: /-> scaler-0 ->\ compiz -> splitter merger -> wb_layer -> memory \-> scaler-1 ->/ v2: Rebase Signed-off-by: James Qian Wang (Arm Technology China) Signed-off-by: Liviu Dudau --- .../gpu/drm/arm/display/komeda/komeda_pipeline.h | 4 + .../drm/arm/display/komeda/komeda_pipeline_state.c | 117 ++++++++++++++++++--- .../drm/arm/display/komeda/komeda_wb_connector.c | 17 ++- 3 files changed, 124 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index 54353a970d51..fc1b8613385e 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -521,6 +521,10 @@ int komeda_build_layer_split_data_flow(struct komeda_layer *left, struct komeda_plane_state *kplane_st, struct komeda_crtc_state *kcrtc_st, struct komeda_data_flow_cfg *dflow); +int komeda_build_wb_split_data_flow(struct komeda_layer *wb_layer, + struct drm_connector_state *conn_st, + struct komeda_crtc_state *kcrtc_st, + struct komeda_data_flow_cfg *dflow); int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, struct komeda_crtc_state *kcrtc_st); 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 6c35afd69a5b..2b415ef2b7d3 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -284,30 +284,33 @@ komeda_layer_check_cfg(struct komeda_layer *layer, struct komeda_fb *kfb, struct komeda_data_flow_cfg *dflow) { - u32 hsize_in, vsize_in; + u32 src_x, src_y, src_w, src_h; if (!komeda_fb_is_layer_supported(kfb, layer->layer_type, dflow->rot)) return -EINVAL; - if (komeda_fb_check_src_coords(kfb, dflow->in_x, dflow->in_y, - dflow->in_w, dflow->in_h)) - return -EINVAL; - if (layer->base.id == KOMEDA_COMPONENT_WB_LAYER) { - hsize_in = dflow->out_w; - vsize_in = dflow->out_h; + src_x = dflow->out_x; + src_y = dflow->out_y; + src_w = dflow->out_w; + src_h = dflow->out_h; } else { - hsize_in = dflow->in_w; - vsize_in = dflow->in_h; + src_x = dflow->in_x; + src_y = dflow->in_y; + src_w = dflow->in_w; + src_h = dflow->in_h; } - if (!in_range(&layer->hsize_in, hsize_in)) { - DRM_DEBUG_ATOMIC("invalidate src_w %d.\n", hsize_in); + if (komeda_fb_check_src_coords(kfb, src_x, src_y, src_w, src_h)) + return -EINVAL; + + if (!in_range(&layer->hsize_in, src_w)) { + DRM_DEBUG_ATOMIC("invalidate src_w %d.\n", src_w); return -EINVAL; } - if (!in_range(&layer->vsize_in, vsize_in)) { - DRM_DEBUG_ATOMIC("invalidate src_h %d.\n", vsize_in); + if (!in_range(&layer->vsize_in, src_h)) { + DRM_DEBUG_ATOMIC("invalidate src_h %d.\n", src_h); return -EINVAL; } @@ -534,6 +537,59 @@ komeda_scaler_validate(void *user, return err; } +static void komeda_split_data_flow(struct komeda_scaler *scaler, + struct komeda_data_flow_cfg *dflow, + struct komeda_data_flow_cfg *l_dflow, + struct komeda_data_flow_cfg *r_dflow); + +static int +komeda_splitter_validate(struct komeda_splitter *splitter, + struct drm_connector_state *conn_st, + struct komeda_data_flow_cfg *dflow, + struct komeda_data_flow_cfg *l_output, + struct komeda_data_flow_cfg *r_output) +{ + struct komeda_component_state *c_st; + struct komeda_splitter_state *st; + + if (!splitter) { + DRM_DEBUG_ATOMIC("Current HW doesn't support splitter.\n"); + return -EINVAL; + } + + if (!in_range(&splitter->hsize, dflow->in_w)) { + DRM_DEBUG_ATOMIC("split in_w:%d is out of the acceptable range.\n", + dflow->in_w); + return -EINVAL; + } + + if (!in_range(&splitter->vsize, dflow->in_h)) { + DRM_DEBUG_ATOMIC("split in_in: %d exceed the acceptable range.\n", + dflow->in_w); + return -EINVAL; + } + + c_st = komeda_component_get_state_and_set_user(&splitter->base, + conn_st->state, conn_st->connector, conn_st->crtc); + + if (IS_ERR(c_st)) + return PTR_ERR(c_st); + + komeda_split_data_flow(splitter->base.pipeline->scalers[0], + dflow, l_output, r_output); + + st = to_splitter_st(c_st); + st->hsize = dflow->in_w; + st->vsize = dflow->in_h; + st->overlap = dflow->overlap; + + komeda_component_add_input(&st->base, &dflow->input, 0); + komeda_component_set_output(&l_output->input, &splitter->base, 0); + komeda_component_set_output(&r_output->input, &splitter->base, 1); + + return 0; +} + static int komeda_merger_validate(struct komeda_merger *merger, void *user, @@ -1025,6 +1081,41 @@ int komeda_build_wb_data_flow(struct komeda_layer *wb_layer, return komeda_wb_layer_validate(wb_layer, conn_st, dflow); } +/* writeback scaling split data path: + * /-> scaler ->\ + * compiz -> splitter merger -> wb_layer -> memory + * \-> scaler ->/ + */ +int komeda_build_wb_split_data_flow(struct komeda_layer *wb_layer, + struct drm_connector_state *conn_st, + struct komeda_crtc_state *kcrtc_st, + struct komeda_data_flow_cfg *dflow) +{ + struct komeda_pipeline *pipe = wb_layer->base.pipeline; + struct drm_connector *conn = conn_st->connector; + struct komeda_data_flow_cfg l_dflow, r_dflow; + int err; + + err = komeda_splitter_validate(pipe->splitter, conn_st, + dflow, &l_dflow, &r_dflow); + if (err) + return err; + err = komeda_scaler_validate(conn, kcrtc_st, &l_dflow); + if (err) + return err; + + err = komeda_scaler_validate(conn, kcrtc_st, &r_dflow); + if (err) + return err; + + err = komeda_merger_validate(pipe->merger, conn_st, kcrtc_st, + &l_dflow, &r_dflow, dflow); + if (err) + return err; + + return komeda_wb_layer_validate(wb_layer, conn_st, dflow); +} + /* build display output data flow, the data path is: * compiz -> improc -> timing_ctrlr */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c index 0d734244f662..bb8a61f6e9a4 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c @@ -13,6 +13,7 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer, struct komeda_crtc_state *kcrtc_st, struct komeda_data_flow_cfg *dflow) { + struct komeda_scaler *scaler = wb_layer->base.pipeline->scalers[0]; struct drm_framebuffer *fb = conn_st->writeback_job->fb; memset(dflow, 0, sizeof(*dflow)); @@ -29,6 +30,13 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer, komeda_complete_data_flow_cfg(dflow, fb); + /* if scaling exceed the acceptable scaler input/output range, try to + * enable split. + */ + if (dflow->en_scaling && scaler) + dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) || + !in_range(&scaler->hsize, dflow->out_w); + return 0; } @@ -66,7 +74,14 @@ komeda_wb_encoder_atomic_check(struct drm_encoder *encoder, if (err) return err; - return komeda_build_wb_data_flow(wb_layer, conn_st, kcrtc_st, &dflow); + if (dflow.en_split) + err = komeda_build_wb_split_data_flow(wb_layer, + conn_st, kcrtc_st, &dflow); + else + err = komeda_build_wb_data_flow(wb_layer, + conn_st, kcrtc_st, &dflow); + + return err; } static const struct drm_encoder_helper_funcs komeda_wb_encoder_helper_funcs = { -- 2.11.0