2019-05-30 10:45:28

by James Qian Wang

[permalink] [raw]
Subject: [PATCH 0/2] drm/komeda: Add writeback downscaling 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 ->/

Depends on:
- https://patchwork.freedesktop.org/series/58710/
- https://patchwork.freedesktop.org/series/59000/
- https://patchwork.freedesktop.org/series/59002/
- https://patchwork.freedesktop.org/series/59747/
- https://patchwork.freedesktop.org/series/59915/
- https://patchwork.freedesktop.org/series/60083/
- https://patchwork.freedesktop.org/series/60698/
- https://patchwork.freedesktop.org/series/60856/
- https://patchwork.freedesktop.org/series/60893/
- https://patchwork.freedesktop.org/series/61370/

James Qian Wang (Arm Technology China) (2):
drm/komeda: Add new component komeda_splitter
drm/komeda: Enable writeback split support

.../arm/display/komeda/d71/d71_component.c | 63 ++++++++++
.../drm/arm/display/komeda/komeda_pipeline.c | 3 +
.../drm/arm/display/komeda/komeda_pipeline.h | 23 +++-
.../display/komeda/komeda_pipeline_state.c | 117 ++++++++++++++++--
.../arm/display/komeda/komeda_private_obj.c | 50 ++++++++
.../arm/display/komeda/komeda_wb_connector.c | 17 ++-
6 files changed, 257 insertions(+), 16 deletions(-)

--
2.17.1


2019-05-30 10:46:36

by James Qian Wang

[permalink] [raw]
Subject: [PATCH 2/2] 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 ->/

Signed-off-by: James Qian Wang (Arm Technology China) <[email protected]>
---
.../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(-)

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 = {
--
2.17.1

2019-05-30 10:46:52

by James Qian Wang

[permalink] [raw]
Subject: [PATCH 1/2] drm/komeda: Add new component komeda_splitter

Similar to Layer Split, but Splitter is used for writeback, which splits
the compiz result to two half parts and then feed them to two scalers.

Signed-off-by: James Qian Wang (Arm Technology China) <[email protected]>
---
.../arm/display/komeda/d71/d71_component.c | 63 +++++++++++++++++++
.../drm/arm/display/komeda/komeda_pipeline.c | 3 +
.../drm/arm/display/komeda/komeda_pipeline.h | 19 +++++-
.../arm/display/komeda/komeda_private_obj.c | 50 +++++++++++++++
4 files changed, 133 insertions(+), 2 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 240f82cb9fa0..769f5a2da030 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,68 @@ static int d71_scaler_init(struct d71_dev *d71,
return 0;
}

+static void d71_splitter_update(struct komeda_component *c,
+ struct komeda_component_state *state)
+{
+ struct komeda_splitter_state *st = to_splitter_st(state);
+ u32 __iomem *reg = c->reg;
+
+ malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
+ malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
+ malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);
+ malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
+}
+
+static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)
+{
+ u32 v[3];
+
+ dump_block_header(sf, c->reg);
+
+ get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);
+ seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);
+
+ get_values_from_reg(c->reg, BLK_CONTROL, 3, v);
+ seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);
+ seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);
+ seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);
+}
+
+static const struct komeda_component_funcs d71_splitter_funcs = {
+ .update = d71_splitter_update,
+ .disable = d71_component_disable,
+ .dump_register = d71_splitter_dump,
+};
+
+static int d71_splitter_init(struct d71_dev *d71,
+ struct block_header *blk, u32 __iomem *reg)
+{
+ struct komeda_component *c;
+ struct komeda_splitter *splitter;
+ 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(*splitter),
+ comp_id,
+ BLOCK_INFO_INPUT_ID(blk->block_info),
+ &d71_splitter_funcs,
+ 1, get_valid_inputs(blk), 2, reg,
+ "CU%d_SPLITTER", pipe_id);
+
+ if (IS_ERR(c)) {
+ DRM_ERROR("Failed to initialize splitter");
+ return -1;
+ }
+
+ splitter = to_splitter(c);
+
+ set_range(&splitter->hsize, 4, d71->max_line_size);
+ set_range(&splitter->vsize, 4, d71->max_vsize);
+
+ return 0;
+}
+
static void d71_merger_update(struct komeda_component *c,
struct komeda_component_state *state)
{
@@ -1126,6 +1188,7 @@ int d71_probe_block(struct d71_dev *d71,
break;

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

case D71_BLK_TYPE_CU_MERGER:
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index c7c3caad13bd..0b76e2acd38c 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -92,6 +92,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_SPLITTER:
+ pos = to_cpos(pipe->splitter);
+ break;
case KOMEDA_COMPONENT_MERGER:
pos = to_cpos(pipe->merger);
break;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 989408b53091..4632fc5ec71f 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -302,6 +302,17 @@ struct komeda_merger_state {
u16 vsize_merged;
};

+struct komeda_splitter {
+ struct komeda_component base;
+ struct malidp_range hsize, vsize;
+};
+
+struct komeda_splitter_state {
+ struct komeda_component_state base;
+ u16 hsize, vsize;
+ u16 overlap;
+};
+
struct komeda_improc {
struct komeda_component base;
u32 supported_color_formats; /* DRM_RGB/YUV444/YUV420*/
@@ -393,6 +404,8 @@ struct komeda_pipeline {
struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
/** @compiz: compositor */
struct komeda_compiz *compiz;
+ /** @splitter: for split the compiz output to two half data flows */
+ struct komeda_splitter *splitter;
/** @merger: merger */
struct komeda_merger *merger;
/** @wb_layer: writeback layer */
@@ -437,14 +450,16 @@ 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_splitter(c) container_of(c, struct komeda_splitter, 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_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
+#define to_splitter_st(c) container_of(c, struct komeda_splitter_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)

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 0f4e1f601ce0..914400c4af73 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,50 @@ static int komeda_compiz_obj_add(struct komeda_kms_dev *kms,
return 0;
}

+static struct drm_private_state *
+komeda_splitter_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_splitter_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_splitter_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ kfree(to_splitter_st(priv_to_comp_st(state)));
+}
+
+static const struct drm_private_state_funcs komeda_splitter_obj_funcs = {
+ .atomic_duplicate_state = komeda_splitter_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_splitter_atomic_destroy_state,
+};
+
+static int komeda_splitter_obj_add(struct komeda_kms_dev *kms,
+ struct komeda_splitter *splitter)
+{
+ struct komeda_splitter_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->base.component = &splitter->base;
+ drm_atomic_private_obj_init(&kms->base,
+ &splitter->base.obj, &st->base.obj,
+ &komeda_splitter_obj_funcs);
+
+ return 0;
+}
+
static struct drm_private_state *
komeda_merger_atomic_duplicate_state(struct drm_private_obj *obj)
{
@@ -354,6 +398,12 @@ int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
if (err)
return err;

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