disp: msm: sde: handle LTM switch in and out of dual pipe merge mode

When LTM is switching on/off, merge_mode bit value gets toggled between
0x1 (dual pipe merge configuration) and 0x0 (single pipe configuration).
It is illegal to reconfigure LTM to/from dual-pipe merge mode before
both LTM instances have completed their current workloads. This change
adds support to disable merge_mode one frame after histogram is disabled
to make sure both hardware instances are completely idle and avoid
corrupted histogram data collection.

Change-Id: I9a6b5cbfb69e8af7936749e57fe7c8f7c2703b95
Signed-off-by: Ping Li <pingli@codeaurora.org>
This commit is contained in:
Ping Li
2021-02-16 22:53:24 -08:00
parent e12be40f65
commit 9dc60208de
8 changed files with 76 additions and 3 deletions

View File

@@ -2041,6 +2041,41 @@ static int _sde_cp_crtc_update_pu_features(struct drm_crtc *crtc, bool *need_flu
return 0; return 0;
} }
static void _sde_clear_ltm_merge_mode(struct sde_crtc *sde_crtc)
{
u32 num_mixers = 0, i = 0;
struct sde_hw_ctl *ctl = NULL;
struct sde_hw_dspp *hw_dspp = NULL;
unsigned long irq_flags;
num_mixers = sde_crtc->num_mixers;
if (!num_mixers) {
DRM_ERROR("no mixers for this crtc\n");
return;
}
spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags);
if (!sde_crtc->ltm_merge_clear_pending) {
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
return;
}
_sde_cp_dspp_flush_helper(sde_crtc, SDE_CP_CRTC_DSPP_LTM_HIST_CTL);
for (i = 0; i < num_mixers; i++) {
hw_dspp = sde_crtc->mixers[i].hw_dspp;
ctl = sde_crtc->mixers[i].hw_ctl;
if (!hw_dspp || !ctl || i >= DSPP_MAX)
continue;
if (hw_dspp->ops.clear_ltm_merge_mode)
hw_dspp->ops.clear_ltm_merge_mode(hw_dspp);
if (ctl->ops.update_bitmask_dspp)
ctl->ops.update_bitmask_dspp(ctl, hw_dspp->idx, 1);
}
sde_crtc->ltm_merge_clear_pending = false;
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
}
void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
{ {
struct sde_crtc *sde_crtc = NULL; struct sde_crtc *sde_crtc = NULL;
@@ -2078,6 +2113,7 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
_sde_cp_flush_properties(crtc); _sde_cp_flush_properties(crtc);
mutex_lock(&sde_crtc->crtc_cp_lock); mutex_lock(&sde_crtc->crtc_cp_lock);
_sde_clear_ltm_merge_mode(sde_crtc);
if (list_empty(&sde_crtc->cp_dirty_list) && if (list_empty(&sde_crtc->cp_dirty_list) &&
list_empty(&sde_crtc->ad_dirty) && list_empty(&sde_crtc->ad_dirty) &&
@@ -2546,6 +2582,7 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
} }
sde_crtc->ltm_buffer_cnt = 0; sde_crtc->ltm_buffer_cnt = 0;
sde_crtc->ltm_hist_en = false; sde_crtc->ltm_hist_en = false;
sde_crtc->ltm_merge_clear_pending = false;
sde_crtc->hist_irq_idx = -1; sde_crtc->hist_irq_idx = -1;
mutex_destroy(&sde_crtc->crtc_cp_lock); mutex_destroy(&sde_crtc->crtc_cp_lock);
@@ -2689,6 +2726,7 @@ void sde_cp_crtc_clear(struct drm_crtc *crtc)
} }
sde_crtc->ltm_buffer_cnt = 0; sde_crtc->ltm_buffer_cnt = 0;
sde_crtc->ltm_hist_en = false; sde_crtc->ltm_hist_en = false;
sde_crtc->ltm_merge_clear_pending = false;
sde_crtc->hist_irq_idx = -1; sde_crtc->hist_irq_idx = -1;
INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); INIT_LIST_HEAD(&sde_crtc->ltm_buf_free);
INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy);
@@ -4082,6 +4120,7 @@ static void _sde_cp_crtc_disable_ltm_hist(struct sde_crtc *sde_crtc,
spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags);
sde_crtc->ltm_hist_en = false; sde_crtc->ltm_hist_en = false;
sde_crtc->ltm_merge_clear_pending = true;
INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); INIT_LIST_HEAD(&sde_crtc->ltm_buf_free);
INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy);
for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++) for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++)
@@ -4153,7 +4192,7 @@ static void _sde_cp_ltm_hist_interrupt_cb(void *arg, int irq_idx)
hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, NULL, false, hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, NULL, false,
0); 0);
} }
sde_crtc->ltm_merge_clear_pending = true;
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
DRM_DEBUG_DRIVER("LTM histogram is disabled\n"); DRM_DEBUG_DRIVER("LTM histogram is disabled\n");
return; return;

View File

@@ -312,6 +312,7 @@ struct sde_frame_data {
* @ltm_buf_free : list of LTM buffers that are available * @ltm_buf_free : list of LTM buffers that are available
* @ltm_buf_busy : list of LTM buffers that are been used by HW * @ltm_buf_busy : list of LTM buffers that are been used by HW
* @ltm_hist_en : flag to indicate whether LTM hist is enabled or not * @ltm_hist_en : flag to indicate whether LTM hist is enabled or not
* @ltm_merge_clear_pending : flag indicates merge mode bit needs to be cleared
* @ltm_buffer_lock : muttx to protect ltm_buffers allcation and free * @ltm_buffer_lock : muttx to protect ltm_buffers allcation and free
* @ltm_lock : Spinlock to protect ltm buffer_cnt, hist_en and ltm lists * @ltm_lock : Spinlock to protect ltm buffer_cnt, hist_en and ltm lists
* @needs_hw_reset : Initiate a hw ctl reset * @needs_hw_reset : Initiate a hw ctl reset
@@ -407,6 +408,7 @@ struct sde_crtc {
struct list_head ltm_buf_free; struct list_head ltm_buf_free;
struct list_head ltm_buf_busy; struct list_head ltm_buf_busy;
bool ltm_hist_en; bool ltm_hist_en;
bool ltm_merge_clear_pending;
struct drm_msm_ltm_cfg_param ltm_cfg; struct drm_msm_ltm_cfg_param ltm_cfg;
struct mutex ltm_buffer_lock; struct mutex ltm_buffer_lock;
spinlock_t ltm_lock; spinlock_t ltm_lock;

View File

@@ -148,6 +148,8 @@ enum {
#define SSPP 0 #define SSPP 0
#define DSPP 1 #define DSPP 1
#define LTM_CONFIG_MERGE_MODE_ONLY (BIT(16) | BIT(17))
struct sde_ltm_phase_info { struct sde_ltm_phase_info {
u32 init_h[LTM_MAX]; u32 init_h[LTM_MAX];
u32 init_v; u32 init_v;

View File

@@ -340,7 +340,7 @@ void sde_setup_dspp_ltm_hist_ctrlv1(struct sde_hw_dspp *ctx, void *cfg,
if (op_mode & BIT(1)) if (op_mode & BIT(1))
op_mode &= ~BIT(0); op_mode &= ~BIT(0);
else else
op_mode = 0; op_mode &= LTM_CONFIG_MERGE_MODE_ONLY;
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x4, SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x4,
(op_mode & 0x1FFFFFF)); (op_mode & 0x1FFFFFF));
@@ -399,6 +399,21 @@ void sde_ltm_read_intr_status(struct sde_hw_dspp *ctx, u32 *status)
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x58, clear); SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x58, clear);
} }
void sde_ltm_clear_merge_mode(struct sde_hw_dspp *ctx)
{
u32 clear;
if (!ctx) {
DRM_ERROR("invalid parameters ctx %pK\n", ctx);
return;
}
/* clear the merge_mode bit */
clear = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->ltm.base + 0x04);
clear &= ~LTM_CONFIG_MERGE_MODE_ONLY;
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x04, clear);
}
void sde_demura_backlight_cfg(struct sde_hw_dspp *ctx, u64 val) void sde_demura_backlight_cfg(struct sde_hw_dspp *ctx, u64 val)
{ {
u32 demura_base; u32 demura_base;

View File

@@ -72,6 +72,13 @@ void sde_setup_dspp_ltm_hist_bufferv1(struct sde_hw_dspp *ctx, u64 addr);
*/ */
void sde_ltm_read_intr_status(struct sde_hw_dspp *dspp, u32 *status); void sde_ltm_read_intr_status(struct sde_hw_dspp *dspp, u32 *status);
/**
* sde_ltm_clear_merge_mode - api to clear ltm merge_mode
* @dspp: pointer to dspp object
*/
void sde_ltm_clear_merge_mode(struct sde_hw_dspp *dspp);
/** /**
* sde_demura_backlight_cfg - api to set backlight for demura * sde_demura_backlight_cfg - api to set backlight for demura
* @ctx: pointer to dspp object * @ctx: pointer to dspp object

View File

@@ -247,6 +247,7 @@ static void dspp_ltm(struct sde_hw_dspp *c)
c->ops.setup_ltm_hist_buffer = c->ops.setup_ltm_hist_buffer =
sde_setup_dspp_ltm_hist_bufferv1; sde_setup_dspp_ltm_hist_bufferv1;
c->ops.ltm_read_intr_status = sde_ltm_read_intr_status; c->ops.ltm_read_intr_status = sde_ltm_read_intr_status;
c->ops.clear_ltm_merge_mode = sde_ltm_clear_merge_mode;
} else { } else {
c->ops.setup_ltm_init = NULL; c->ops.setup_ltm_init = NULL;
c->ops.setup_ltm_roi = NULL; c->ops.setup_ltm_roi = NULL;
@@ -255,6 +256,7 @@ static void dspp_ltm(struct sde_hw_dspp *c)
c->ops.setup_ltm_hist_ctrl = NULL; c->ops.setup_ltm_hist_ctrl = NULL;
c->ops.setup_ltm_hist_buffer = NULL; c->ops.setup_ltm_hist_buffer = NULL;
c->ops.ltm_read_intr_status = NULL; c->ops.ltm_read_intr_status = NULL;
c->ops.clear_ltm_merge_mode = NULL;
} }
if (!ret && c->cap->sblk->ltm.version == if (!ret && c->cap->sblk->ltm.version ==
SDE_COLOR_PROCESS_VER(0x1, 0x1)) SDE_COLOR_PROCESS_VER(0x1, 0x1))

View File

@@ -210,6 +210,12 @@ struct sde_hw_dspp_ops {
*/ */
void (*ltm_read_intr_status)(struct sde_hw_dspp *ctx, u32 *status); void (*ltm_read_intr_status)(struct sde_hw_dspp *ctx, u32 *status);
/**
* clear_ltm_merge_mode - clear LTM merge_mode bit
* @ctx: Pointer to dspp context
*/
void (*clear_ltm_merge_mode)(struct sde_hw_dspp *ctx);
/** /**
* validate_rc_mask - Validate RC mask configuration * validate_rc_mask - Validate RC mask configuration
* @ctx: Pointer to dspp context. * @ctx: Pointer to dspp context.

View File

@@ -3795,7 +3795,7 @@ static void ltm_vlutv1_disable(struct sde_hw_dspp *ctx)
/* disable VLUT/INIT/ROI */ /* disable VLUT/INIT/ROI */
opmode &= REG_DMA_LTM_VLUT_DISABLE_OP_MASK; opmode &= REG_DMA_LTM_VLUT_DISABLE_OP_MASK;
else else
opmode = 0; opmode &= LTM_CONFIG_MERGE_MODE_ONLY;
SDE_REG_WRITE(&ctx->hw, offset, opmode); SDE_REG_WRITE(&ctx->hw, offset, opmode);
} }