diff mbox series

[2/2] drm/komeda: Enable writeback split support

Message ID 20190530104335.2395-3-james.qian.wang@arm.com (mailing list archive)
State New, archived
Headers show
Series drm/komeda: Add writeback downscaling split support | expand

Commit Message

James Qian Wang May 30, 2019, 10:44 a.m. UTC
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 ->/

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
---
 .../drm/arm/display/komeda/komeda_pipeline.h  |   4 +
 .../display/komeda/komeda_pipeline_state.c    | 117 ++++++++++++++++--
 .../arm/display/komeda/komeda_wb_connector.c  |  17 ++-
 3 files changed, 124 insertions(+), 14 deletions(-)

--
2.17.1
diff mbox series

Patch

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 4632fc5ec71f..9057dc512cf2 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -524,6 +524,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 82ea6cf9a989..afd857ef2239 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,
@@ -1031,6 +1087,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 2613bb0d79ce..4e26b2786ce0 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->needs_scaling && scaler)
+		dflow->needs_split = !in_range(&scaler->hsize, dflow->in_w) ||
+				     !in_range(&scaler->hsize, dflow->out_w);
+
 	return 0;
 }

@@ -65,7 +73,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.needs_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 = {