disp: msm: sde: expose early-wb-fence option for 2-pass composition

Add a writeback connector property EARLY-FENCE-LINE to give usermode
the control on when to trigger the retire fence. This option is useful
in 2-pass composition, where the writeback triggers the retire-fence
early based on the prog-line which allows primary to start the fetch
before wb transaction is fully completed. This helps to keep the clks
and bw low. WB hardware generates the line-ptr-irq when wb output reaches
the configured prog-line. Retire fence is triggered based on the irq by
default and wb-done handles for cases where line-ptr-irq is missed.

Change-Id: I20867979693dc3447f77da24cd7e88305947fb6d
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
This commit is contained in:
Veera Sundaram Sankaran
2021-07-18 15:38:27 -07:00
parent 95300ca3df
commit 762252400d
4 changed files with 79 additions and 8 deletions

View File

@@ -218,6 +218,7 @@ enum msm_mdp_conn_property {
CONNECTOR_PROP_DYN_BIT_CLK, CONNECTOR_PROP_DYN_BIT_CLK,
CONNECTOR_PROP_DIMMING_CTRL, CONNECTOR_PROP_DIMMING_CTRL,
CONNECTOR_PROP_DIMMING_MIN_BL, CONNECTOR_PROP_DIMMING_MIN_BL,
CONNECTOR_PROP_EARLY_FENCE_LINE,
/* enum/bitmask properties */ /* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME, CONNECTOR_PROP_TOPOLOGY_NAME,

View File

@@ -437,6 +437,7 @@ struct sde_encoder_phys_cmd {
* @bo_disable: Buffer object(s) to use during the disabling state * @bo_disable: Buffer object(s) to use during the disabling state
* @fb_disable: Frame buffer to use during the disabling state * @fb_disable: Frame buffer to use during the disabling state
* @crtc Pointer to drm_crtc * @crtc Pointer to drm_crtc
* @prog_line: Cached programmable line value used to trigger early wb-fence
*/ */
struct sde_encoder_phys_wb { struct sde_encoder_phys_wb {
struct sde_encoder_phys base; struct sde_encoder_phys base;
@@ -455,6 +456,7 @@ struct sde_encoder_phys_wb {
struct drm_gem_object *bo_disable[SDE_MAX_PLANES]; struct drm_gem_object *bo_disable[SDE_MAX_PLANES];
struct drm_framebuffer *fb_disable; struct drm_framebuffer *fb_disable;
struct drm_crtc *crtc; struct drm_crtc *crtc;
u32 prog_line;
}; };
/** /**

View File

@@ -682,7 +682,7 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
int out_width = 0, out_height = 0; int out_width = 0, out_height = 0;
int ds_srcw = 0, ds_srch = 0, ds_outw = 0, ds_outh = 0; int ds_srcw = 0, ds_srch = 0, ds_outw = 0, ds_outh = 0;
const struct sde_format *fmt; const struct sde_format *fmt;
int data_pt; int data_pt, prog_line;
int ds_in_use = false; int ds_in_use = false;
int i = 0; int i = 0;
int ret = 0; int ret = 0;
@@ -710,6 +710,12 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
return -EINVAL; return -EINVAL;
} }
prog_line = sde_connector_get_property(conn_state, CONNECTOR_PROP_EARLY_FENCE_LINE);
if (prog_line) {
SDE_ERROR("early fence not supported with CWB, prog_line:%d\n", prog_line);
return -EINVAL;
}
data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT); data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT);
/* compute cumulative ds output dimensions if in use */ /* compute cumulative ds output dimensions if in use */
@@ -1139,6 +1145,24 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
hw_wb->idx - WB_0); hw_wb->idx - WB_0);
} }
static void _sde_encoder_phys_wb_setup_prog_line(struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
struct sde_wb_device *wb_dev = wb_enc->wb_dev;
struct drm_connector_state *state = wb_dev->connector->state;
struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
u32 prog_line;
if (phys_enc->in_clone_mode || !hw_wb->ops.set_prog_line_count)
return;
prog_line = sde_connector_get_property(state, CONNECTOR_PROP_EARLY_FENCE_LINE);
if (wb_enc->prog_line != prog_line) {
wb_enc->prog_line = prog_line;
hw_wb->ops.set_prog_line_count(hw_wb, prog_line);
}
}
/** /**
* sde_encoder_phys_wb_setup - setup writeback encoder * sde_encoder_phys_wb_setup - setup writeback encoder
* @phys_enc: Pointer to physical encoder * @phys_enc: Pointer to physical encoder
@@ -1213,12 +1237,16 @@ static void sde_encoder_phys_wb_setup(
sde_encoder_phys_wb_setup_cdp(phys_enc, wb_enc->wb_fmt); sde_encoder_phys_wb_setup_cdp(phys_enc, wb_enc->wb_fmt);
_sde_encoder_phys_wb_setup_cwb(phys_enc, true); _sde_encoder_phys_wb_setup_cwb(phys_enc, true);
_sde_encoder_phys_wb_setup_prog_line(phys_enc);
} }
static void sde_encoder_phys_wb_ctl_start_irq(void *arg, int irq_idx) static void sde_encoder_phys_wb_ctl_start_irq(void *arg, int irq_idx)
{ {
struct sde_encoder_phys_wb *wb_enc = arg; struct sde_encoder_phys_wb *wb_enc = arg;
struct sde_encoder_phys *phys_enc; struct sde_encoder_phys *phys_enc;
struct sde_hw_wb *hw_wb;
u32 line_cnt = 0;
if (!wb_enc) if (!wb_enc)
return; return;
@@ -1227,7 +1255,11 @@ static void sde_encoder_phys_wb_ctl_start_irq(void *arg, int irq_idx)
if (atomic_add_unless(&phys_enc->pending_ctl_start_cnt, -1, 0)) if (atomic_add_unless(&phys_enc->pending_ctl_start_cnt, -1, 0))
wake_up_all(&phys_enc->pending_kickoff_wq); wake_up_all(&phys_enc->pending_kickoff_wq);
SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc)); hw_wb = wb_enc->hw_wb;
if (hw_wb->ops.get_line_count)
line_cnt = hw_wb->ops.get_line_count(hw_wb);
SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), line_cnt);
} }
static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error) static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
@@ -1242,11 +1274,23 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
if (phys_enc->parent_ops.handle_frame_done && if (phys_enc->parent_ops.handle_frame_done &&
atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) { atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) {
event |= SDE_ENCODER_FRAME_EVENT_DONE event |= SDE_ENCODER_FRAME_EVENT_DONE;
| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
/*
* signal retire-fence during wb-done
* - when prog_line is not configured
* - when prog_line is configured and line-ptr-irq is missed
*/
if (!wb_enc->prog_line || (wb_enc->prog_line &&
(atomic_read(&phys_enc->pending_kickoff_cnt) <
atomic_read(&phys_enc->pending_retire_fence_cnt)))) {
atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
}
if (phys_enc->in_clone_mode) if (phys_enc->in_clone_mode)
event |= SDE_ENCODER_FRAME_EVENT_CWB_DONE; event |= SDE_ENCODER_FRAME_EVENT_CWB_DONE
| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
else else
event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
@@ -1258,7 +1302,9 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
end: end:
SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), phys_enc->in_clone_mode, SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), phys_enc->in_clone_mode,
phys_enc->enable_state, event, frame_error); phys_enc->enable_state, event, atomic_read(&phys_enc->pending_kickoff_cnt),
atomic_read(&phys_enc->pending_retire_fence_cnt),
frame_error);
wake_up_all(&phys_enc->pending_kickoff_wq); wake_up_all(&phys_enc->pending_kickoff_wq);
} }
@@ -1287,13 +1333,24 @@ static void sde_encoder_phys_wb_lineptr_irq(void *arg, int irq_idx)
{ {
struct sde_encoder_phys_wb *wb_enc = arg; struct sde_encoder_phys_wb *wb_enc = arg;
struct sde_encoder_phys *phys_enc; struct sde_encoder_phys *phys_enc;
struct sde_hw_wb *hw_wb;
u32 event = 0, line_cnt = 0;
if (!wb_enc) if (!wb_enc || !wb_enc->prog_line)
return; return;
phys_enc = &wb_enc->base; phys_enc = &wb_enc->base;
if (phys_enc->parent_ops.handle_frame_done &&
atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) {
event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event);
}
SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc)); hw_wb = wb_enc->hw_wb;
if (hw_wb->ops.get_line_count)
line_cnt = hw_wb->ops.get_line_count(hw_wb);
SDE_EVT32_IRQ(DRMID(phys_enc->parent), WBID(wb_enc), event, wb_enc->prog_line, line_cnt);
} }
/** /**
@@ -1338,6 +1395,9 @@ static void sde_encoder_phys_wb_irq_ctrl(
sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE); sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
sde_encoder_helper_register_irq(phys, INTR_IDX_CTL_START); sde_encoder_helper_register_irq(phys, INTR_IDX_CTL_START);
if (test_bit(SDE_WB_PROG_LINE, &wb_cfg->features))
sde_encoder_helper_register_irq(phys, INTR_IDX_WB_LINEPTR);
for (index = 0; index < max_num_of_irqs; index++) for (index = 0; index < max_num_of_irqs; index++)
if (irq_table[index + pp] != SDE_NONE) if (irq_table[index + pp] != SDE_NONE)
sde_encoder_helper_register_irq(phys, irq_table[index + pp]); sde_encoder_helper_register_irq(phys, irq_table[index + pp]);
@@ -1345,6 +1405,9 @@ static void sde_encoder_phys_wb_irq_ctrl(
sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE); sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
sde_encoder_helper_unregister_irq(phys, INTR_IDX_CTL_START); sde_encoder_helper_unregister_irq(phys, INTR_IDX_CTL_START);
if (test_bit(SDE_WB_PROG_LINE, &wb_cfg->features))
sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_LINEPTR);
for (index = 0; index < max_num_of_irqs; index++) for (index = 0; index < max_num_of_irqs; index++)
if (irq_table[index + pp] != SDE_NONE) if (irq_table[index + pp] != SDE_NONE)
sde_encoder_helper_unregister_irq(phys, irq_table[index + pp]); sde_encoder_helper_unregister_irq(phys, irq_table[index + pp]);
@@ -1522,6 +1585,7 @@ static int _sde_encoder_phys_wb_wait_for_ctl_start(struct sde_encoder_phys *phys
SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), phys_enc->in_clone_mode, SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), phys_enc->in_clone_mode,
atomic_read(&phys_enc->pending_kickoff_cnt), atomic_read(&phys_enc->pending_kickoff_cnt),
atomic_read(&phys_enc->pending_retire_fence_cnt),
atomic_read(&phys_enc->pending_ctl_start_cnt)); atomic_read(&phys_enc->pending_ctl_start_cnt));
wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.wq = &phys_enc->pending_kickoff_wq;

View File

@@ -564,6 +564,10 @@ int sde_wb_connector_post_init(struct drm_connector *connector, void *display)
ARRAY_SIZE(e_fb_translation_mode), 0, ARRAY_SIZE(e_fb_translation_mode), 0,
CONNECTOR_PROP_FB_TRANSLATION_MODE); CONNECTOR_PROP_FB_TRANSLATION_MODE);
if (wb_dev->wb_cfg->features & BIT(SDE_WB_PROG_LINE))
msm_property_install_range(&c_conn->property_info, "early_fence_line",
0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_EARLY_FENCE_LINE);
sde_wb_connector_install_dither_property(wb_dev, c_conn); sde_wb_connector_install_dither_property(wb_dev, c_conn);
return 0; return 0;