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:
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
@@ -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))
|
||||||
|
@@ -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.
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user