@@ -985,6 +985,10 @@ static void d71_improc_update(struct komeda_component *c,
else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444)
ctrl |= IPS_CTRL_YUV;
+ /* slave input has been enabled, means side by side */
+ if (has_bit(1, state->active_inputs))
+ ctrl |= IPS_CTRL_SBS;
+
malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
}
@@ -361,19 +361,26 @@ komeda_crtc_atomic_flush(struct drm_crtc *crtc,
komeda_crtc_do_flush(crtc, old);
}
-/* Returns the minimum frequency of the aclk rate (main engine clock) in Hz */
+/*
+ * Returns the minimum frequency of the aclk rate (main engine clock) in Hz.
+ *
+ * The DPU output can be split into two halves, to stay within the bandwidth
+ * capabilities of the external link (dual-link mode).
+ * In these cases, each output link runs at half the pixel clock rate of the
+ * combined display, and has half the number of pixels.
+ * Beside split the output, the DPU internal pixel processing also can be split
+ * into two halves (LEFT/RIGHT) and handles by two pipelines simultaneously.
+ * So if side by side, the pipeline (main engine clock) also can run at half
+ * the clock rate of the combined display.
+ */
static unsigned long
komeda_calc_min_aclk_rate(struct komeda_crtc *kcrtc,
unsigned long pxlclk)
{
- /* Once dual-link one display pipeline drives two display outputs,
- * the aclk needs run on the double rate of pxlclk
- */
- if (kcrtc->master->dual_link)
+ if (kcrtc->master->dual_link && !kcrtc->side_by_side)
return pxlclk * 2;
else
return pxlclk;
-
}
/* Get current aclk rate that specified by state */
@@ -530,6 +530,7 @@ struct komeda_crtc_state;
struct komeda_crtc;
void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
+ bool side_by_side,
u16 *hsize, u16 *vsize);
int komeda_build_layer_data_flow(struct komeda_layer *layer,
@@ -637,12 +637,13 @@ komeda_merger_validate(struct komeda_merger *merger,
}
void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
+ bool side_by_side,
u16 *hsize, u16 *vsize)
{
struct drm_display_mode *m = &kcrtc_st->base.adjusted_mode;
if (hsize)
- *hsize = m->hdisplay;
+ *hsize = side_by_side ? m->hdisplay / 2 : m->hdisplay;
if (vsize)
*vsize = m->vdisplay;
}
@@ -653,12 +654,14 @@ komeda_compiz_set_input(struct komeda_compiz *compiz,
struct komeda_data_flow_cfg *dflow)
{
struct drm_atomic_state *drm_st = kcrtc_st->base.state;
+ struct drm_crtc *crtc = kcrtc_st->base.crtc;
struct komeda_component_state *c_st, *old_st;
struct komeda_compiz_input_cfg *cin;
u16 compiz_w, compiz_h;
int idx = dflow->blending_zorder;
- pipeline_composition_size(kcrtc_st, &compiz_w, &compiz_h);
+ pipeline_composition_size(kcrtc_st, to_kcrtc(crtc)->side_by_side,
+ &compiz_w, &compiz_h);
/* check display rect */
if ((dflow->out_x + dflow->out_w > compiz_w) ||
(dflow->out_y + dflow->out_h > compiz_h) ||
@@ -670,7 +673,7 @@ komeda_compiz_set_input(struct komeda_compiz *compiz,
}
c_st = komeda_component_get_state_and_set_user(&compiz->base, drm_st,
- kcrtc_st->base.crtc, kcrtc_st->base.crtc);
+ crtc, crtc);
if (IS_ERR(c_st))
return PTR_ERR(c_st);
@@ -704,17 +707,19 @@ komeda_compiz_validate(struct komeda_compiz *compiz,
struct komeda_crtc_state *state,
struct komeda_data_flow_cfg *dflow)
{
+ struct drm_crtc *crtc = state->base.crtc;
struct komeda_component_state *c_st;
struct komeda_compiz_state *st;
c_st = komeda_component_get_state_and_set_user(&compiz->base,
- state->base.state, state->base.crtc, state->base.crtc);
+ state->base.state, crtc, crtc);
if (IS_ERR(c_st))
return PTR_ERR(c_st);
st = to_compiz_st(c_st);
- pipeline_composition_size(state, &st->hsize, &st->vsize);
+ pipeline_composition_size(state, to_kcrtc(crtc)->side_by_side,
+ &st->hsize, &st->vsize);
komeda_component_set_output(&dflow->input, &compiz->base, 0);
@@ -740,7 +745,8 @@ komeda_compiz_validate(struct komeda_compiz *compiz,
static int
komeda_improc_validate(struct komeda_improc *improc,
struct komeda_crtc_state *kcrtc_st,
- struct komeda_data_flow_cfg *dflow)
+ struct komeda_data_flow_cfg *m_dflow,
+ struct komeda_data_flow_cfg *s_dflow)
{
struct drm_crtc *crtc = kcrtc_st->base.crtc;
struct drm_crtc_state *crtc_st = &kcrtc_st->base;
@@ -754,8 +760,8 @@ komeda_improc_validate(struct komeda_improc *improc,
st = to_improc_st(c_st);
- st->hsize = dflow->in_w;
- st->vsize = dflow->in_h;
+ st->hsize = m_dflow->in_w;
+ st->vsize = m_dflow->in_h;
if (drm_atomic_crtc_needs_modeset(crtc_st)) {
u32 output_depths, output_formats;
@@ -793,8 +799,10 @@ komeda_improc_validate(struct komeda_improc *improc,
drm_ctm_to_coeffs(kcrtc_st->base.ctm, st->ctm_coeffs);
}
- komeda_component_add_input(&st->base, &dflow->input, 0);
- komeda_component_set_output(&dflow->input, &improc->base, 0);
+ komeda_component_add_input(&st->base, &m_dflow->input, 0);
+ if (s_dflow)
+ komeda_component_add_input(&st->base, &s_dflow->input, 1);
+ komeda_component_set_output(&m_dflow->input, &improc->base, 0);
return 0;
}
@@ -1118,7 +1126,7 @@ komeda_split_sbs_master_data_flow(struct komeda_crtc_state *kcrtc_st,
u32 disp_end = master->out_x + master->out_w;
u16 boundary;
- pipeline_composition_size(kcrtc_st, &boundary, NULL);
+ pipeline_composition_size(kcrtc_st, true, &boundary, NULL);
if (disp_end <= boundary) {
/* the master viewport only located in master side, no need
@@ -1181,7 +1189,7 @@ komeda_split_sbs_slave_data_flow(struct komeda_crtc_state *kcrtc_st,
{
u16 boundary;
- pipeline_composition_size(kcrtc_st, &boundary, NULL);
+ pipeline_composition_size(kcrtc_st, true, &boundary, NULL);
if (slave->out_x < boundary) {
DRM_DEBUG_ATOMIC("SBS Slave plane is only allowed to configure the right part frame.\n");
@@ -1356,7 +1364,20 @@ int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
memset(&m_dflow, 0, sizeof(m_dflow));
memset(&s_dflow, 0, sizeof(s_dflow));
- if (slave && has_bit(slave->id, kcrtc_st->active_pipes)) {
+ /* build slave output data flow */
+ if (kcrtc->side_by_side) {
+ /* on side by side, the slave data flows into the improc of
+ * itself first, and then merge it into master's image processor
+ */
+ err = komeda_compiz_validate(slave->compiz, kcrtc_st, &s_dflow);
+ if (err)
+ return err;
+
+ err = komeda_improc_validate(slave->improc, kcrtc_st,
+ &s_dflow, NULL);
+ if (err)
+ return err;
+ } else if (slave && has_bit(slave->id, kcrtc_st->active_pipes)) {
err = komeda_compiz_validate(slave->compiz, kcrtc_st, &s_dflow);
if (err)
return err;
@@ -1372,7 +1393,9 @@ int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
if (err)
return err;
- err = komeda_improc_validate(master->improc, kcrtc_st, &m_dflow);
+ /* on side by side, merge the slave dflow into master */
+ err = komeda_improc_validate(master->improc, kcrtc_st, &m_dflow,
+ kcrtc->side_by_side ? &s_dflow : NULL);
if (err)
return err;
@@ -22,7 +22,7 @@ komeda_wb_init_data_flow(struct komeda_layer *wb_layer,
dflow->out_h = fb->height;
/* the write back data comes from the compiz */
- pipeline_composition_size(kcrtc_st, &dflow->in_w, &dflow->in_h);
+ pipeline_composition_size(kcrtc_st, false, &dflow->in_w, &dflow->in_h);
dflow->input.component = &wb_layer->base.pipeline->compiz->base;
/* compiz doesn't output alpha */
dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
For side by side, the slave pipeline merges to master via image processor slave-layers -> slave-compiz-> slave-improc- \ master-layers -> master-compiz -------------> master-improc -> Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com> --- .../arm/display/komeda/d71/d71_component.c | 4 ++ .../gpu/drm/arm/display/komeda/komeda_crtc.c | 19 ++++--- .../drm/arm/display/komeda/komeda_pipeline.h | 1 + .../display/komeda/komeda_pipeline_state.c | 51 ++++++++++++++----- .../arm/display/komeda/komeda_wb_connector.c | 2 +- 5 files changed, 56 insertions(+), 21 deletions(-) -- 2.20.1