linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] drm/komeda: Add layer split support
@ 2019-06-10 10:15 james qian wang (Arm Technology China)
  2019-06-10 10:15 ` [PATCH v2 1/3] drm/komeda: Add component komeda_merger james qian wang (Arm Technology China)
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-06-10 10:15 UTC (permalink / raw)
  To: Liviu Dudau, airlied, Brian Starkey, maarten.lankhorst, sean
  Cc: Jonathan Chai (Arm Technology China),
	Julien Yin (Arm Technology China),
	thomas Sun (Arm Technology China),
	Lowry Li (Arm Technology China),
	Ayan Halder, Tiannan Zhu (Arm Technology China),
	Yiqi Kang (Arm Technology China),
	nd, linux-kernel, dri-devel, Ben Davis,
	Oscar Zhang (Arm Technology China),
	Channing Chen (Arm Technology China),
	james qian wang (Arm Technology China)

This patch series add laye split support for komeda.

For layer split, a plane state will be split to two data flows and handled
by two separated komeda layer input pipelines. komeda supports two types of
layer split:

- none-scaling split:
             / layer-left -> \
  plane_state                  compiz-> ...
             \ layer-right-> /

- scaling split:
             / layer-left -> scaler->\
 plane_state                          merger -> compiz-> ...
             \ layer-right-> scaler->/

Since merger only supports scaler as input, so for none-scaling split, two
layer data flows will be output to compiz directly. for scaling_split, two
data flows will be merged by merger firstly, then merger outputs one merged
data flow to compiz.

This patch series depends on:
- https://patchwork.freedesktop.org/series/60767/
- https://patchwork.freedesktop.org/series/60838/

v2: Rebase and addressed Liviu's comments

james qian wang (Arm Technology China) (3):
  drm/komeda: Add component komeda_merger
  drm/komeda: Add split support for scaler
  drm/komeda: Add layer split support

 .../arm/display/komeda/d71/d71_component.c    | 121 ++++++-
 .../gpu/drm/arm/display/komeda/komeda_kms.c   |   8 +
 .../gpu/drm/arm/display/komeda/komeda_kms.h   |  22 +-
 .../drm/arm/display/komeda/komeda_pipeline.c  |  26 +-
 .../drm/arm/display/komeda/komeda_pipeline.h  |  49 ++-
 .../display/komeda/komeda_pipeline_state.c    | 318 +++++++++++++++++-
 .../gpu/drm/arm/display/komeda/komeda_plane.c |  33 +-
 .../arm/display/komeda/komeda_private_obj.c   |  49 +++
 .../arm/display/komeda/komeda_wb_connector.c  |   2 +-
 9 files changed, 600 insertions(+), 28 deletions(-)

--
2.17.1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/3] drm/komeda: Add component komeda_merger
  2019-06-10 10:15 [PATCH v2 0/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)
@ 2019-06-10 10:15 ` james qian wang (Arm Technology China)
  2019-06-10 10:16 ` [PATCH v2 2/3] drm/komeda: Add split support for scaler james qian wang (Arm Technology China)
  2019-06-10 10:16 ` [PATCH v2 3/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)
  2 siblings, 0 replies; 4+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-06-10 10:15 UTC (permalink / raw)
  To: Liviu Dudau, airlied, Brian Starkey, maarten.lankhorst, sean
  Cc: Jonathan Chai (Arm Technology China),
	Julien Yin (Arm Technology China),
	thomas Sun (Arm Technology China),
	Lowry Li (Arm Technology China),
	Ayan Halder, Tiannan Zhu (Arm Technology China),
	Yiqi Kang (Arm Technology China),
	nd, linux-kernel, dri-devel, Ben Davis,
	Oscar Zhang (Arm Technology China),
	Channing Chen (Arm Technology China),
	james qian wang (Arm Technology China)

Introduce a new component komeda_merger, because D71 HW supports to split
a whole image to two half parts and does the scaling independently. Merger
merges two separate results to one, and output it to compositor or wb_layer
For this patch:
- Add the definition of komeda_merger/merger_state
- Report and initialize komeda_merger according to the D71 HW.

v2: Rebase

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
---
 .../arm/display/komeda/d71/d71_component.c    | 74 +++++++++++++++++++
 .../drm/arm/display/komeda/komeda_pipeline.c  |  3 +
 .../drm/arm/display/komeda/komeda_pipeline.h  | 18 ++++-
 .../arm/display/komeda/komeda_private_obj.c   | 49 ++++++++++++
 4 files changed, 143 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
index c5185ce062a4..71f58bf1e880 100644
--- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
@@ -767,6 +767,77 @@ static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
 	       0 : -EINVAL;
 }

+static void d71_merger_update(struct komeda_component *c,
+			      struct komeda_component_state *state)
+{
+	struct komeda_merger_state *st = to_merger_st(state);
+	u32 __iomem *reg = c->reg;
+	u32 index;
+
+	for_each_changed_input(state, index)
+		malidp_write32(reg, MG_INPUT_ID0 + index * 4,
+			       to_d71_input_id(&state->inputs[index]));
+
+	malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
+					     st->vsize_merged));
+	malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
+}
+
+static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
+{
+	u32 v;
+
+	dump_block_header(sf, c->reg);
+
+	get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
+	seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
+
+	get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
+	seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
+
+	get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);
+	seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);
+
+	get_values_from_reg(c->reg, MG_SIZE, 1, &v);
+	seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);
+}
+
+static const struct komeda_component_funcs d71_merger_funcs = {
+	.update		= d71_merger_update,
+	.disable	= d71_component_disable,
+	.dump_register	= d71_merger_dump,
+};
+
+static int d71_merger_init(struct d71_dev *d71,
+			   struct block_header *blk, u32 __iomem *reg)
+{
+	struct komeda_component *c;
+	struct komeda_merger *merger;
+	u32 pipe_id, comp_id;
+
+	get_resources_id(blk->block_info, &pipe_id, &comp_id);
+
+	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),
+				 comp_id,
+				 BLOCK_INFO_INPUT_ID(blk->block_info),
+				 &d71_merger_funcs,
+				 MG_NUM_INPUTS_IDS, get_valid_inputs(blk),
+				 MG_NUM_OUTPUTS_IDS, reg,
+				 "CU%d_MERGER", pipe_id);
+
+	if (IS_ERR(c)) {
+		DRM_ERROR("Failed to initialize merger.\n");
+		return PTR_ERR(c);
+	}
+
+	merger = to_merger(c);
+
+	set_range(&merger->hsize_merged, 4, 4032);
+	set_range(&merger->vsize_merged, 4, 4096);
+
+	return 0;
+}
+
 static void d71_improc_update(struct komeda_component *c,
 			      struct komeda_component_state *state)
 {
@@ -992,7 +1063,10 @@ int d71_probe_block(struct d71_dev *d71,
 		break;

 	case D71_BLK_TYPE_CU_SPLITTER:
+		break;
+
 	case D71_BLK_TYPE_CU_MERGER:
+		err = d71_merger_init(d71, blk, reg);
 		break;

 	case D71_BLK_TYPE_DOU:
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index f4882c1b70d7..543ecc80703f 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -91,6 +91,9 @@ komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
 	case KOMEDA_COMPONENT_SCALER1:
 		pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
 		break;
+	case KOMEDA_COMPONENT_MERGER:
+		pos = to_cpos(pipe->merger);
+		break;
 	case KOMEDA_COMPONENT_IPS0:
 	case KOMEDA_COMPONENT_IPS1:
 		temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 1a9b2cf8061a..20e6f7a78d12 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -276,6 +276,18 @@ struct komeda_compiz_state {
 	struct komeda_compiz_input_cfg cins[KOMEDA_COMPONENT_N_INPUTS];
 };

+struct komeda_merger {
+	struct komeda_component base;
+	struct malidp_range hsize_merged;
+	struct malidp_range vsize_merged;
+};
+
+struct komeda_merger_state {
+	struct komeda_component_state base;
+	u16 hsize_merged;
+	u16 vsize_merged;
+};
+
 struct komeda_improc {
 	struct komeda_component base;
 	u32 supported_color_formats;  /* DRM_RGB/YUV444/YUV420*/
@@ -357,6 +369,8 @@ struct komeda_pipeline {
 	struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
 	/** @compiz: compositor */
 	struct komeda_compiz *compiz;
+	/** @merger: merger */
+	struct komeda_merger *merger;
 	/** @wb_layer: writeback layer */
 	struct komeda_layer  *wb_layer;
 	/** @improc: post image processor */
@@ -399,17 +413,19 @@ struct komeda_pipeline_state {
 #define to_layer(c)	container_of(c, struct komeda_layer, base)
 #define to_compiz(c)	container_of(c, struct komeda_compiz, base)
 #define to_scaler(c)	container_of(c, struct komeda_scaler, base)
+#define to_merger(c)	container_of(c, struct komeda_merger, base)
 #define to_improc(c)	container_of(c, struct komeda_improc, base)
 #define to_ctrlr(c)	container_of(c, struct komeda_timing_ctrlr, base)

 #define to_layer_st(c)	container_of(c, struct komeda_layer_state, base)
 #define to_compiz_st(c)	container_of(c, struct komeda_compiz_state, base)
 #define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
+#define to_merger_st(c) container_of(c, struct komeda_merger_state, base)
 #define to_improc_st(c)	container_of(c, struct komeda_improc_state, base)
 #define to_ctrlr_st(c)	container_of(c, struct komeda_timing_ctrlr_state, base)

 #define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
-#define priv_to_pipe_st(o)  container_of(o, struct komeda_pipeline_state, obj)
+#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)

 /* pipeline APIs */
 struct komeda_pipeline *
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
index bac90ab8fdc9..0f4e1f601ce0 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -146,6 +146,49 @@ static int komeda_compiz_obj_add(struct komeda_kms_dev *kms,
 	return 0;
 }

+static struct drm_private_state *
+komeda_merger_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+	struct komeda_merger_state *st;
+
+	st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return NULL;
+
+	komeda_component_state_reset(&st->base);
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &st->base.obj);
+
+	return &st->base.obj;
+}
+
+static void komeda_merger_atomic_destroy_state(struct drm_private_obj *obj,
+					       struct drm_private_state *state)
+{
+	kfree(to_merger_st(priv_to_comp_st(state)));
+}
+
+static const struct drm_private_state_funcs komeda_merger_obj_funcs = {
+	.atomic_duplicate_state	= komeda_merger_atomic_duplicate_state,
+	.atomic_destroy_state	= komeda_merger_atomic_destroy_state,
+};
+
+static int komeda_merger_obj_add(struct komeda_kms_dev *kms,
+				 struct komeda_merger *merger)
+{
+	struct komeda_merger_state *st;
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	st->base.component = &merger->base;
+	drm_atomic_private_obj_init(&kms->base,
+				    &merger->base.obj, &st->base.obj,
+				    &komeda_merger_obj_funcs);
+
+	return 0;
+}
+
 static struct drm_private_state *
 komeda_improc_atomic_duplicate_state(struct drm_private_obj *obj)
 {
@@ -311,6 +354,12 @@ int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
 		if (err)
 			return err;

+		if (pipe->merger) {
+			err = komeda_merger_obj_add(kms, pipe->merger);
+			if (err)
+				return err;
+		}
+
 		err = komeda_improc_obj_add(kms, pipe->improc);
 		if (err)
 			return err;
--
2.17.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/3] drm/komeda: Add split support for scaler
  2019-06-10 10:15 [PATCH v2 0/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)
  2019-06-10 10:15 ` [PATCH v2 1/3] drm/komeda: Add component komeda_merger james qian wang (Arm Technology China)
@ 2019-06-10 10:16 ` james qian wang (Arm Technology China)
  2019-06-10 10:16 ` [PATCH v2 3/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)
  2 siblings, 0 replies; 4+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-06-10 10:16 UTC (permalink / raw)
  To: Liviu Dudau, airlied, Brian Starkey, maarten.lankhorst, sean
  Cc: Jonathan Chai (Arm Technology China),
	Julien Yin (Arm Technology China),
	thomas Sun (Arm Technology China),
	Lowry Li (Arm Technology China),
	Ayan Halder, Tiannan Zhu (Arm Technology China),
	Yiqi Kang (Arm Technology China),
	nd, linux-kernel, dri-devel, Ben Davis,
	Oscar Zhang (Arm Technology China),
	Channing Chen (Arm Technology China),
	james qian wang (Arm Technology China)

To achieve same caling effect compare with none split, the texel
calculation need to use the same scaling ratio before split, so add
"total_xxx" to pipeline to describe the hsize/vsize before split.
Update pipeline and d71_scaler_update accordingly.

v2: Rebase and addressed Liviu's comments

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
---
 .../arm/display/komeda/d71/d71_component.c    | 47 +++++++++++++++++--
 .../drm/arm/display/komeda/komeda_pipeline.h  | 19 ++++++--
 .../display/komeda/komeda_pipeline_state.c    | 18 ++++++-
 .../gpu/drm/arm/display/komeda/komeda_plane.c | 11 ++---
 .../arm/display/komeda/komeda_wb_connector.c  |  2 +-
 5 files changed, 80 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
index 71f58bf1e880..c83b95b33139 100644
--- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
@@ -642,23 +642,58 @@ static void d71_scaler_update(struct komeda_component *c,

 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
 	malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
+	malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
+
+	/* for right part, HW only sample the valid pixel which means the pixels
+	 * in left_crop will be jumpped, and the first sample pixel is:
+	 *
+	 * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
+	 *
+	 * Then the corresponding texel in src is:
+	 *
+	 * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
+	 * src_a = dst_A * h_delta_phase;
+	 *
+	 * and h_init_phase is src_a deduct the real source start src_S;
+	 *
+	 * src_S = st->total_hsize_in - st->hsize_in;
+	 * h_init_phase = src_a - src_S;
+	 *
+	 * And HW precision for the initial/delta_phase is 16:16 fixed point,
+	 * the following is the simplified formula
+	 */
+	if (st->right_part) {
+		u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
+
+		if (st->en_img_enhancement)
+			dst_a -= 1;
+
+		init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
+			    2 * st->total_hsize_out * (st->total_hsize_in -
+			    st->hsize_in)) << 15) / st->total_hsize_out;
+	} else {
+		init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
+	}

-	init_ph = (st->hsize_in << 15) / st->hsize_out;
 	malidp_write32(reg, SC_H_INIT_PH, init_ph);

-	delta_ph = (st->hsize_in << 16) / st->hsize_out;
+	delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
 	malidp_write32(reg, SC_H_DELTA_PH, delta_ph);

-	init_ph = (st->vsize_in << 15) / st->vsize_out;
+	init_ph = (st->total_vsize_in << 15) / st->vsize_out;
 	malidp_write32(reg, SC_V_INIT_PH, init_ph);

-	delta_ph = (st->vsize_in << 16) / st->vsize_out;
+	delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
 	malidp_write32(reg, SC_V_DELTA_PH, delta_ph);

 	ctrl = 0;
 	ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
 	ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
 	ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
+	/* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
+	if (st->en_split &&
+	    state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
+		ctrl |= SC_CTRL_LS;

 	malidp_write32(reg, BLK_CONTROL, ctrl);
 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
@@ -716,10 +751,12 @@ static int d71_scaler_init(struct d71_dev *d71,
 	}

 	scaler = to_scaler(c);
-	set_range(&scaler->hsize, 4, d71->max_line_size);
+	set_range(&scaler->hsize, 4, 2048);
 	set_range(&scaler->vsize, 4, 4096);
 	scaler->max_downscaling = 6;
 	scaler->max_upscaling = 64;
+	scaler->scaling_split_overlap = 8;
+	scaler->enh_split_overlap = 1;

 	malidp_write32(c->reg, BLK_CONTROL, 0);

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 20e6f7a78d12..857be3f64b32 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -247,15 +247,22 @@ struct komeda_scaler {
 	struct malidp_range hsize, vsize;
 	u32 max_upscaling;
 	u32 max_downscaling;
+	u8 scaling_split_overlap; /* split overlap for scaling */
+	u8 enh_split_overlap; /* split overlap for image enhancement */
 };

 struct komeda_scaler_state {
 	struct komeda_component_state base;
 	u16 hsize_in, vsize_in;
 	u16 hsize_out, vsize_out;
+	u16 total_hsize_in, total_vsize_in;
+	u16 total_hsize_out; /* total_xxxx are size before split */
+	u16 left_crop, right_crop;
 	u8 en_scaling : 1,
 	   en_alpha : 1, /* enable alpha processing */
-	   en_img_enhancement : 1;
+	   en_img_enhancement : 1,
+	   en_split : 1,
+	   right_part : 1; /* right part of split image */
 };

 struct komeda_compiz {
@@ -323,11 +330,16 @@ struct komeda_data_flow_cfg {
 	struct komeda_component_output input;
 	u16 in_x, in_y, in_w, in_h;
 	u32 out_x, out_y, out_w, out_h;
+	u16 total_in_h, total_in_w;
+	u16 total_out_w;
+	u16 left_crop, right_crop, overlap;
 	u32 rot;
 	int blending_zorder;
 	u8 pixel_blend_mode, layer_alpha;
 	u8 en_scaling : 1,
-	   en_img_enhancement : 1;
+	   en_img_enhancement : 1,
+	   en_split : 1,
+	   right_part : 1; /* right part of display image if split enabled */
 };

 struct komeda_pipeline_funcs {
@@ -492,6 +504,7 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe,
 void komeda_pipeline_update(struct komeda_pipeline *pipe,
 			    struct drm_atomic_state *old_state);

-void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow);
+void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
+				   struct drm_framebuffer *fb);

 #endif /* _KOMEDA_PIPELINE_H_*/
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 7fb7f725a6de..714961a0f91e 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -507,11 +507,18 @@ komeda_scaler_validate(void *user,
 	st->vsize_in = dflow->in_h;
 	st->hsize_out = dflow->out_w;
 	st->vsize_out = dflow->out_h;
+	st->right_crop = dflow->right_crop;
+	st->left_crop = dflow->left_crop;
+	st->total_vsize_in = dflow->total_in_h;
+	st->total_hsize_in = dflow->total_in_w;
+	st->total_hsize_out = dflow->total_out_w;

 	/* Enable alpha processing if the next stage needs the pixel alpha */
 	st->en_alpha = dflow->pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE;
 	st->en_scaling = dflow->en_scaling;
 	st->en_img_enhancement = dflow->en_img_enhancement;
+	st->en_split = dflow->en_split;
+	st->right_part = dflow->right_part;

 	komeda_component_add_input(&st->base, &dflow->input, 0);
 	komeda_component_set_output(&dflow->input, &scaler->base, 0);
@@ -665,11 +672,20 @@ komeda_timing_ctrlr_validate(struct komeda_timing_ctrlr *ctrlr,
 	return 0;
 }

-void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow)
+void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
+				   struct drm_framebuffer *fb)
 {
 	u32 w = dflow->in_w;
 	u32 h = dflow->in_h;

+	dflow->total_in_w = dflow->in_w;
+	dflow->total_in_h = dflow->in_h;
+	dflow->total_out_w = dflow->out_w;
+
+	/* if format doesn't have alpha, fix blend mode to PIXEL_NONE */
+	if (!fb->format->has_alpha)
+		dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
+
 	if (drm_rotation_90_or_270(dflow->rot))
 		swap(w, h);

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
index c0e381cee524..9d29820345b9 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -23,10 +23,7 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
 	memset(dflow, 0, sizeof(*dflow));

 	dflow->blending_zorder = st->normalized_zpos;
-
-	/* if format doesn't have alpha, fix blend mode to PIXEL_NONE */
-	dflow->pixel_blend_mode = fb->format->has_alpha ?
-			st->pixel_blend_mode : DRM_MODE_BLEND_PIXEL_NONE;
+	dflow->pixel_blend_mode = st->pixel_blend_mode;
 	dflow->layer_alpha = st->alpha >> 8;

 	dflow->out_x = st->crtc_x;
@@ -39,8 +36,6 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
 	dflow->in_w = st->src_w >> 16;
 	dflow->in_h = st->src_h >> 16;

-	dflow->en_img_enhancement = kplane_st->img_enhancement;
-
 	dflow->rot = drm_rotation_simplify(st->rotation, caps->supported_rots);
 	if (!has_bits(dflow->rot, caps->supported_rots)) {
 		DRM_DEBUG_ATOMIC("rotation(0x%x) isn't supported by %s.\n",
@@ -50,7 +45,9 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
 		return -EINVAL;
 	}

-	komeda_complete_data_flow_cfg(dflow);
+	dflow->en_img_enhancement = kplane_st->img_enhancement;
+
+	komeda_complete_data_flow_cfg(dflow, fb);

 	return 0;
 }
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 eed521218ef3..20295291572f 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
@@ -31,7 +31,7 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer,
 	dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
 	dflow->rot = DRM_MODE_ROTATE_0;

-	komeda_complete_data_flow_cfg(dflow);
+	komeda_complete_data_flow_cfg(dflow, fb);

 	return 0;
 }
--
2.17.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 3/3] drm/komeda: Add layer split support
  2019-06-10 10:15 [PATCH v2 0/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)
  2019-06-10 10:15 ` [PATCH v2 1/3] drm/komeda: Add component komeda_merger james qian wang (Arm Technology China)
  2019-06-10 10:16 ` [PATCH v2 2/3] drm/komeda: Add split support for scaler james qian wang (Arm Technology China)
@ 2019-06-10 10:16 ` james qian wang (Arm Technology China)
  2 siblings, 0 replies; 4+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-06-10 10:16 UTC (permalink / raw)
  To: Liviu Dudau, airlied, Brian Starkey, maarten.lankhorst, sean
  Cc: Jonathan Chai (Arm Technology China),
	Julien Yin (Arm Technology China),
	thomas Sun (Arm Technology China),
	Lowry Li (Arm Technology China),
	Ayan Halder, Tiannan Zhu (Arm Technology China),
	Yiqi Kang (Arm Technology China),
	nd, linux-kernel, dri-devel, Ben Davis,
	Oscar Zhang (Arm Technology China),
	Channing Chen (Arm Technology China),
	james qian wang (Arm Technology China)

Komeda supports two types of layer split:
- none-scaling split
- scaling split
Since D71 merger only support scaler as input, so for none-scaling split,
the two layer dflow will be output to compiz directly. for scaling_split,
the data flow will be merged by merger firstly, then output the merged
data flow to compiz.

Komeda handles the split in kernel completely to hide the detailed and
complicated split calcualtion to user mode, for user only need to set the
layer_split property to enable/disable it.

v2: Rebase

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
---
 .../gpu/drm/arm/display/komeda/komeda_kms.c   |   8 +
 .../gpu/drm/arm/display/komeda/komeda_kms.h   |  22 +-
 .../drm/arm/display/komeda/komeda_pipeline.c  |  23 +-
 .../drm/arm/display/komeda/komeda_pipeline.h  |  12 +
 .../display/komeda/komeda_pipeline_state.c    | 300 +++++++++++++++++-
 .../gpu/drm/arm/display/komeda/komeda_plane.c |  24 +-
 6 files changed, 378 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
index 0ec76656cd1f..5d10c55c9c40 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -173,6 +173,14 @@ static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc,
 		plane = plane_st->plane;

 		plane_st->normalized_zpos = order++;
+		/* When layer_split has been enabled, one plane will be handled
+		 * by two separated komeda layers (left/right), which may needs
+		 * two zorders.
+		 * - zorder: for left_layer for left display part.
+		 * - zorder + 1: will be reserved for right layer.
+		 */
+		if (to_kplane_st(plane_st)->layer_split)
+			order++;

 		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] zpos:%d, normalized zpos: %d\n",
 				 plane->base.id, plane->name,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
index 5f71e669d92b..9dcfe5a01e23 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -36,6 +36,8 @@ struct komeda_plane {

 	/** @prop_img_enhancement: for on/off image enhancement */
 	struct drm_property *prop_img_enhancement;
+	/** @prop_layer_split: for on/off layer_split */
+	struct drm_property *prop_layer_split;
 };

 /**
@@ -50,8 +52,11 @@ struct komeda_plane_state {
 	/** @zlist_node: zorder list node */
 	struct list_head zlist_node;

-	/* @img_enhancement: on/off image enhancement */
-	u8 img_enhancement : 1;
+	/* @img_enhancement: on/off image enhancement
+	 * @layer_split: on/off layer_split
+	 */
+	u8 img_enhancement : 1,
+	   layer_split : 1;
 };

 /**
@@ -155,6 +160,19 @@ is_only_changed_connector(struct drm_crtc_state *st, struct drm_connector *conn)
 	return BIT(drm_connector_index(conn)) == changed_connectors;
 }

+static inline bool has_flip_h(u32 rot)
+{
+	u32 rotation = drm_rotation_simplify(rot,
+					     DRM_MODE_ROTATE_0 |
+					     DRM_MODE_ROTATE_90 |
+					     DRM_MODE_REFLECT_MASK);
+
+	if (rotation & DRM_MODE_ROTATE_90)
+		return !!(rotation & DRM_MODE_REFLECT_Y);
+	else
+		return !!(rotation & DRM_MODE_REFLECT_X);
+}
+
 unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st);

 int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index 543ecc80703f..eb9e0c0af8f3 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -265,16 +265,35 @@ static void komeda_component_verify_inputs(struct komeda_component *c)
 	}
 }

+static struct komeda_layer *
+komeda_get_layer_split_right_layer(struct komeda_pipeline *pipe,
+				   struct komeda_layer *left)
+{
+	int index = left->base.id - KOMEDA_COMPONENT_LAYER0;
+	int i;
+
+	for (i = index + 1; i < pipe->n_layers; i++)
+		if (left->layer_type == pipe->layers[i]->layer_type)
+			return pipe->layers[i];
+	return NULL;
+}
+
 static void komeda_pipeline_assemble(struct komeda_pipeline *pipe)
 {
 	struct komeda_component *c;
-	int id;
+	struct komeda_layer *layer;
+	int i, id;

 	dp_for_each_set_bit(id, pipe->avail_comps) {
 		c = komeda_pipeline_get_component(pipe, id);
-
 		komeda_component_verify_inputs(c);
 	}
+	/* calculate right layer for the layer split */
+	for (i = 0; i < pipe->n_layers; i++) {
+		layer = pipe->layers[i];
+
+		layer->right = komeda_get_layer_split_right_layer(pipe, layer);
+	}
 }

 int komeda_assemble_pipelines(struct komeda_dev *mdev)
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 857be3f64b32..f6a4a51cb5f7 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -228,6 +228,12 @@ struct komeda_layer {
 	struct malidp_range hsize_in, vsize_in;
 	u32 layer_type; /* RICH, SIMPLE or WB */
 	u32 supported_rots;
+	/* komeda supports layer split which splits a whole image to two parts
+	 * left and right and handle them by two individual layer processors
+	 * Note: left/right are always according to the final display rect,
+	 * not the source buffer.
+	 */
+	struct komeda_layer *right;
 };

 struct komeda_layer_state {
@@ -339,6 +345,7 @@ struct komeda_data_flow_cfg {
 	u8 en_scaling : 1,
 	   en_img_enhancement : 1,
 	   en_split : 1,
+	   is_yuv : 1,
 	   right_part : 1; /* right part of display image if split enabled */
 };

@@ -493,6 +500,11 @@ int komeda_build_wb_data_flow(struct komeda_layer *wb_layer,
 int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
 				   struct komeda_crtc_state *kcrtc_st);

+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_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 714961a0f91e..c0102faea00e 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -211,13 +211,14 @@ komeda_component_check_input(struct komeda_component_state *state,
 	struct komeda_component *c = state->component;

 	if ((idx < 0) || (idx >= c->max_active_inputs)) {
-		DRM_DEBUG_ATOMIC("%s invalid input id: %d.\n", c->name, idx);
+		DRM_DEBUG_ATOMIC("%s required an invalid %s-input[%d].\n",
+				 input->component->name, c->name, idx);
 		return -EINVAL;
 	}

 	if (has_bit(idx, state->active_inputs)) {
-		DRM_DEBUG_ATOMIC("%s required input_id: %d has been occupied already.\n",
-				 c->name, idx);
+		DRM_DEBUG_ATOMIC("%s required %s-input[%d] has been occupied already.\n",
+				 input->component->name, c->name, idx);
 		return -EINVAL;
 	}

@@ -269,6 +270,15 @@ komeda_component_get_avail_scaler(struct komeda_component *c,
 	return to_scaler(c);
 }

+static void
+komeda_rotate_data_flow(struct komeda_data_flow_cfg *dflow, u32 rot)
+{
+	if (drm_rotation_90_or_270(rot)) {
+		swap(dflow->in_h, dflow->in_w);
+		swap(dflow->total_in_h, dflow->total_in_w);
+	}
+}
+
 static int
 komeda_layer_check_cfg(struct komeda_layer *layer,
 		       struct komeda_fb *kfb,
@@ -360,8 +370,7 @@ komeda_layer_validate(struct komeda_layer *layer,
 	 * The rotation has been handled by layer, so adjusted the data flow for
 	 * the next stage.
 	 */
-	if (drm_rotation_90_or_270(st->rot))
-		swap(dflow->in_h, dflow->in_w);
+	komeda_rotate_data_flow(dflow, st->rot);

 	return 0;
 }
@@ -525,6 +534,52 @@ komeda_scaler_validate(void *user,
 	return err;
 }

+static int
+komeda_merger_validate(struct komeda_merger *merger,
+		       void *user,
+		       struct komeda_crtc_state *kcrtc_st,
+		       struct komeda_data_flow_cfg *left_input,
+		       struct komeda_data_flow_cfg *right_input,
+		       struct komeda_data_flow_cfg *output)
+{
+	struct komeda_component_state *c_st;
+	struct komeda_merger_state *st;
+	int err = 0;
+
+	if (!merger) {
+		DRM_DEBUG_ATOMIC("No merger is available");
+		return -EINVAL;
+	}
+
+	if (!in_range(&merger->hsize_merged, output->out_w)) {
+		DRM_DEBUG_ATOMIC("merged_w: %d is out of the accepted range.\n",
+				 output->out_w);
+		return -EINVAL;
+	}
+
+	if (!in_range(&merger->vsize_merged, output->out_h)) {
+		DRM_DEBUG_ATOMIC("merged_h: %d is out of the accepted range.\n",
+				 output->out_h);
+		return -EINVAL;
+	}
+
+	c_st = komeda_component_get_state_and_set_user(&merger->base,
+			kcrtc_st->base.state, kcrtc_st->base.crtc, kcrtc_st->base.crtc);
+
+	if (IS_ERR(c_st))
+		return PTR_ERR(c_st);
+
+	st = to_merger_st(c_st);
+	st->hsize_merged = output->out_w;
+	st->vsize_merged = output->out_h;
+
+	komeda_component_add_input(c_st, &left_input->input, 0);
+	komeda_component_add_input(c_st, &right_input->input, 1);
+	komeda_component_set_output(&output->input, &merger->base, 0);
+
+	return err;
+}
+
 void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
 			       u16 *hsize, u16 *vsize)
 {
@@ -583,6 +638,7 @@ komeda_compiz_set_input(struct komeda_compiz *compiz,
 		c_st->changed_active_inputs |= BIT(idx);

 	komeda_component_add_input(c_st, &dflow->input, idx);
+	komeda_component_set_output(&dflow->input, &compiz->base, 0);

 	return 0;
 }
@@ -690,6 +746,16 @@ void komeda_complete_data_flow_cfg(struct komeda_data_flow_cfg *dflow,
 		swap(w, h);

 	dflow->en_scaling = (w != dflow->out_w) || (h != dflow->out_h);
+	dflow->is_yuv = fb->format->is_yuv;
+}
+
+static bool merger_is_available(struct komeda_pipeline *pipe,
+				struct komeda_data_flow_cfg *dflow)
+{
+	u32 avail_inputs = pipe->merger ?
+			   pipe->merger->base.supported_inputs : 0;
+
+	return has_bit(dflow->input.component->id, avail_inputs);
 }

 int komeda_build_layer_data_flow(struct komeda_layer *layer,
@@ -714,6 +780,230 @@ int komeda_build_layer_data_flow(struct komeda_layer *layer,
 	if (err)
 		return err;

+	/* if split, check if can put the data flow into merger */
+	if (dflow->en_split && merger_is_available(pipe, dflow))
+		return 0;
+
+	err = komeda_compiz_set_input(pipe->compiz, kcrtc_st, dflow);
+
+	return err;
+}
+
+/*
+ * Split is introduced for workaround scaler's input/output size limitation.
+ * The idea is simple, if one scaler can not fit the requirement, use two.
+ * So split splits the big source image to two half parts (left/right) and do
+ * the scaling by two scaler separately and independently.
+ * But split also imports an edge problem in the middle of the image when
+ * scaling, to avoid it, split isn't a simple half-and-half, but add an extra
+ * pixels (overlap) to both side, after split the left/right will be:
+ * - left: [0, src_length/2 + overlap]
+ * - right: [src_length/2 - overlap, src_length]
+ * The extra overlap do eliminate the edge problem, but which may also generates
+ * unnecessary pixels when scaling, we need to crop them before scaler output
+ * the result to the next stage. and for the how to crop, it depends on the
+ * unneeded pixels, another words the position where overlay has been added.
+ * - left: crop the right
+ * - right: crop the left
+ *
+ * The diagram for how to do the split
+ *
+ *  <---------------------left->out_w ---------------->
+ * |--------------------------------|---right_crop-----| <- left after split
+ *  \                                \                /
+ *   \                                \<--overlap--->/
+ *   |-----------------|-------------|(Middle)------|-----------------| <- src
+ *                     /<---overlap--->\                               \
+ *                    /                 \                               \
+ * right after split->|-----left_crop---|--------------------------------|
+ *                    ^<------------------- right->out_w --------------->^
+ *
+ * NOTE: To consistent with HW the output_w always contains the crop size.
+ */
+
+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)
+{
+	bool r90 = drm_rotation_90_or_270(dflow->rot);
+	bool flip_h = has_flip_h(dflow->rot);
+	u32 l_out, r_out, overlap;
+
+	memcpy(l_dflow, dflow, sizeof(*dflow));
+	memcpy(r_dflow, dflow, sizeof(*dflow));
+
+	l_dflow->right_part = false;
+	r_dflow->right_part = true;
+	r_dflow->blending_zorder = dflow->blending_zorder + 1;
+
+	overlap = 0;
+	if (dflow->en_scaling && scaler)
+		overlap += scaler->scaling_split_overlap;
+
+	/* original dflow may fed into splitter, and which doesn't need
+	 * enhancement overlap
+	 */
+	dflow->overlap = overlap;
+
+	if (dflow->en_img_enhancement && scaler)
+		overlap += scaler->enh_split_overlap;
+
+	l_dflow->overlap = overlap;
+	r_dflow->overlap = overlap;
+
+	/* split the origin content */
+	/* left/right here always means the left/right part of display image,
+	 * not the source Image
+	 */
+	/* DRM rotation is anti-clockwise */
+	if (r90) {
+		if (dflow->en_scaling) {
+			l_dflow->in_h = ALIGN(dflow->in_h, 2) / 2 + l_dflow->overlap;
+			r_dflow->in_h = l_dflow->in_h;
+		} else if (dflow->en_img_enhancement) {
+			/* enhancer only */
+			l_dflow->in_h = ALIGN(dflow->in_h, 2) / 2 + l_dflow->overlap;
+			r_dflow->in_h = dflow->in_h / 2 + r_dflow->overlap;
+		} else {
+			/* split without scaler, no overlap */
+			l_dflow->in_h = ALIGN(((dflow->in_h + 1) >> 1), 2);
+			r_dflow->in_h = dflow->in_h - l_dflow->in_h;
+		}
+
+		/* Consider YUV format, after split, the split source w/h
+		 * may not aligned to 2. we have two choices for such case.
+		 * 1. scaler is enabled (overlap != 0), we can do a alignment
+		 *    both left/right and crop the extra data by scaler.
+		 * 2. scaler is not enabled, only align the split left
+		 *    src/disp, and the rest part assign to right
+		 */
+		if ((overlap != 0) && dflow->is_yuv) {
+			l_dflow->in_h = ALIGN(l_dflow->in_h, 2);
+			r_dflow->in_h = ALIGN(r_dflow->in_h, 2);
+		}
+
+		if (flip_h)
+			l_dflow->in_y = dflow->in_y + dflow->in_h - l_dflow->in_h;
+		else
+			r_dflow->in_y = dflow->in_y + dflow->in_h - r_dflow->in_h;
+	} else {
+		if (dflow->en_scaling) {
+			l_dflow->in_w = ALIGN(dflow->in_w, 2) / 2 + l_dflow->overlap;
+			r_dflow->in_w = l_dflow->in_w;
+		} else if (dflow->en_img_enhancement) {
+			l_dflow->in_w = ALIGN(dflow->in_w, 2) / 2 + l_dflow->overlap;
+			r_dflow->in_w = dflow->in_w / 2 + r_dflow->overlap;
+		} else {
+			l_dflow->in_w = ALIGN(((dflow->in_w + 1) >> 1), 2);
+			r_dflow->in_w = dflow->in_w - l_dflow->in_w;
+		}
+
+		/* do YUV alignment when scaler enabled */
+		if ((overlap != 0) && dflow->is_yuv) {
+			l_dflow->in_w = ALIGN(l_dflow->in_w, 2);
+			r_dflow->in_w = ALIGN(r_dflow->in_w, 2);
+		}
+
+		/* on flip_h, the left display content from the right-source */
+		if (flip_h)
+			l_dflow->in_x = dflow->in_w + dflow->in_x - l_dflow->in_w;
+		else
+			r_dflow->in_x = dflow->in_w + dflow->in_x - r_dflow->in_w;
+	}
+
+	/* split the disp_rect */
+	if (dflow->en_scaling || dflow->en_img_enhancement)
+		l_dflow->out_w = ((dflow->out_w + 1) >> 1);
+	else
+		l_dflow->out_w = ALIGN(((dflow->out_w + 1) >> 1), 2);
+
+	r_dflow->out_w = dflow->out_w - l_dflow->out_w;
+
+	l_dflow->out_x = dflow->out_x;
+	r_dflow->out_x = l_dflow->out_w + l_dflow->out_x;
+
+	/* calculate the scaling crop */
+	/* left scaler output more data and do crop */
+	if (r90) {
+		l_out = (dflow->out_w * l_dflow->in_h) / dflow->in_h;
+		r_out = (dflow->out_w * r_dflow->in_h) / dflow->in_h;
+	} else {
+		l_out = (dflow->out_w * l_dflow->in_w) / dflow->in_w;
+		r_out = (dflow->out_w * r_dflow->in_w) / dflow->in_w;
+	}
+
+	l_dflow->left_crop  = 0;
+	l_dflow->right_crop = l_out - l_dflow->out_w;
+	r_dflow->left_crop  = r_out - r_dflow->out_w;
+	r_dflow->right_crop = 0;
+
+	/* out_w includes the crop length */
+	l_dflow->out_w += l_dflow->right_crop + l_dflow->left_crop;
+	r_dflow->out_w += r_dflow->right_crop + r_dflow->left_crop;
+}
+
+/* For layer split, a plane state will be split to two data flows and handled
+ * by two separated komeda layer input pipelines. komeda supports two types of
+ * layer split:
+ * - none-scaling split:
+ *             / layer-left -> \
+ * plane_state                  compiz-> ...
+ *             \ layer-right-> /
+ *
+ * - scaling split:
+ *             / layer-left -> scaler->\
+ * plane_state                          merger -> compiz-> ...
+ *             \ layer-right-> scaler->/
+ *
+ * Since merger only supports scaler as input, so for none-scaling split, two
+ * layer data flows will be output to compiz directly. for scaling_split, two
+ * data flow will be merged by merger firstly, then merger outputs one merged
+ * data flow to compiz.
+ */
+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)
+{
+	struct drm_plane *plane = kplane_st->base.plane;
+	struct komeda_pipeline *pipe = left->base.pipeline;
+	struct komeda_layer *right = left->right;
+	struct komeda_data_flow_cfg l_dflow, r_dflow;
+	int err;
+
+	komeda_split_data_flow(pipe->scalers[0], dflow, &l_dflow, &r_dflow);
+
+	DRM_DEBUG_ATOMIC("Assign %s + %s to [PLANE:%d:%s]: "
+			 "src[x/y:%d/%d, w/h:%d/%d] disp[x/y:%d/%d, w/h:%d/%d]",
+			 left->base.name, right->base.name,
+			 plane->base.id, plane->name,
+			 dflow->in_x, dflow->in_y, dflow->in_w, dflow->in_h,
+			 dflow->out_x, dflow->out_y, dflow->out_w, dflow->out_h);
+
+	err = komeda_build_layer_data_flow(left, kplane_st, kcrtc_st, &l_dflow);
+	if (err)
+		return err;
+
+	err = komeda_build_layer_data_flow(right, kplane_st, kcrtc_st, &r_dflow);
+	if (err)
+		return err;
+
+	/* The rotation has been handled by layer, so adjusted the data flow */
+	komeda_rotate_data_flow(dflow, dflow->rot);
+
+	/* left and right dflow has been merged to compiz already,
+	 * no need merger to merge them anymore.
+	 */
+	if (r_dflow.input.component == l_dflow.input.component)
+		return 0;
+
+	/* line merger path */
+	err = komeda_merger_validate(pipe->merger, plane, kcrtc_st,
+				     &l_dflow, &r_dflow, 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 9d29820345b9..d1c58a88d9e2 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -45,7 +45,8 @@ komeda_plane_init_data_flow(struct drm_plane_state *st,
 		return -EINVAL;
 	}

-	dflow->en_img_enhancement = kplane_st->img_enhancement;
+	dflow->en_img_enhancement = !!kplane_st->img_enhancement;
+	dflow->en_split = !!kplane_st->layer_split;

 	komeda_complete_data_flow_cfg(dflow, fb);

@@ -91,7 +92,12 @@ komeda_plane_atomic_check(struct drm_plane *plane,
 	if (err)
 		return err;

-	err = komeda_build_layer_data_flow(layer, kplane_st, kcrtc_st, &dflow);
+	if (dflow.en_split)
+		err = komeda_build_layer_split_data_flow(layer,
+				kplane_st, kcrtc_st, &dflow);
+	else
+		err = komeda_build_layer_data_flow(layer,
+				kplane_st, kcrtc_st, &dflow);

 	return err;
 }
@@ -181,6 +187,8 @@ komeda_plane_atomic_get_property(struct drm_plane *plane,

 	if (property == kplane->prop_img_enhancement)
 		*val = st->img_enhancement;
+	else if (property == kplane->prop_layer_split)
+		*val = st->layer_split;
 	else
 		return -EINVAL;

@@ -198,6 +206,8 @@ komeda_plane_atomic_set_property(struct drm_plane *plane,

 	if (property == kplane->prop_img_enhancement)
 		st->img_enhancement = !!val;
+	else if (property == kplane->prop_layer_split)
+		st->layer_split = !!val;
 	else
 		return -EINVAL;

@@ -247,6 +257,16 @@ komeda_plane_create_layer_properties(struct komeda_plane *kplane,
 		kplane->prop_img_enhancement = prop;
 	}

+	/* property: layer split */
+	if (layer->right) {
+		prop = drm_property_create_bool(drm, DRM_MODE_PROP_ATOMIC,
+						"layer_split");
+		if (!prop)
+			return -ENOMEM;
+		kplane->prop_layer_split = prop;
+		drm_object_attach_property(&plane->base, prop, 0);
+	}
+
 	return 0;
 }

--
2.17.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-06-10 10:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-10 10:15 [PATCH v2 0/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)
2019-06-10 10:15 ` [PATCH v2 1/3] drm/komeda: Add component komeda_merger james qian wang (Arm Technology China)
2019-06-10 10:16 ` [PATCH v2 2/3] drm/komeda: Add split support for scaler james qian wang (Arm Technology China)
2019-06-10 10:16 ` [PATCH v2 3/3] drm/komeda: Add layer split support james qian wang (Arm Technology China)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).