disp: msm: sde: demura backlight adaptation change

Demura backlight value will be updated based on the backlight event
in the driver. Make HFC gains programmable based on backlight value.

Signed-off-by: Mitika Dodiya <quic_mdodiya@quicinc.com>
Change-Id: I74e9aa2c274eedb473095c5eafef194d6a6f1d94
This commit is contained in:
Mitika Dodiya
2023-03-15 13:06:25 +05:30
committed by Gerrit - the friendly Code Review server
parent 68e4c1a426
commit b573201f7c
9 changed files with 182 additions and 98 deletions

View File

@@ -21,6 +21,9 @@
#include "sde_hw_color_proc_common_v4.h"
#include "sde_vm.h"
#define DEMURA_BACKLIGHT_MAX 1024
#define DEMURA_BACKLIGHT_MIN 64
struct sde_cp_node {
u32 property_id;
u32 prop_flags;
@@ -107,6 +110,8 @@ static void _sde_cp_crtc_update_ltm_roi(struct sde_crtc *sde_crtc,
struct sde_hw_cp_cfg *hw_cfg);
static int _sde_cp_flush_properties(struct drm_crtc *crtc);
static void _sde_cp_mark_bl_properties(struct sde_crtc *crtc);
static int _sde_cp_crtc_cache_property(struct drm_crtc *crtc,
struct sde_crtc_state *cstate,
struct sde_cp_node *prop_node,
@@ -998,6 +1003,37 @@ static int _set_spr_udc_feature(struct sde_hw_dspp *hw_dspp,
return ret;
}
static int _set_demura_backlight(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg,
struct sde_crtc *sde_crtc)
{
int ret = 0;
u64 val = (DEMURA_BACKLIGHT_MAX << 16) | DEMURA_BACKLIGHT_MAX;
u32 brightness, inv;
if (!hw_dspp || !hw_dspp->ops.setup_demura_backlight_cfg) {
ret = -EINVAL;
} else {
if (sde_crtc->back_light && sde_crtc->back_light_max) {
brightness = sde_crtc->back_light * ((1 << 10));
do_div(brightness, sde_crtc->back_light_max);
/* Clip the brightness between 64 (min) and 1024 (max) */
brightness = clamp_val(brightness, DEMURA_BACKLIGHT_MIN,
DEMURA_BACKLIGHT_MAX);
if (brightness) {
inv = (1 << 20);
do_div(inv, brightness);
inv = (inv < ((1 << 14) - 1)) ? inv : ((1 << 14) - 1);
val = (inv << 16) | brightness;
}
sde_crtc->back_light_pending = false;
}
hw_dspp->ops.setup_demura_backlight_cfg(hw_dspp, val, hw_cfg);
}
return ret;
}
static int _set_demura_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg,
struct sde_crtc *sde_crtc)
@@ -1011,6 +1047,7 @@ static int _set_demura_feature(struct sde_hw_dspp *hw_dspp,
hw_dspp->ops.setup_demura_cfg(hw_dspp, hw_cfg);
_update_pu_feature_enable(sde_crtc, SDE_CP_CRTC_DSPP_DEMURA_PU,
hw_cfg->payload != NULL);
_set_demura_backlight(hw_dspp, hw_cfg, sde_crtc);
}
}
@@ -1429,6 +1466,9 @@ void sde_cp_crtc_init(struct drm_crtc *crtc)
INIT_LIST_HEAD(&sde_crtc->ltm_buf_free);
INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy);
sde_crtc->disable_pending_cp = false;
sde_crtc->back_light = 0;
sde_crtc->back_light_max = 0;
sde_crtc->back_light_pending = false;
sde_cp_crtc_disable(crtc);
}
@@ -2320,6 +2360,7 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
}
_sde_cp_flush_properties(crtc);
_sde_cp_mark_bl_properties(sde_crtc);
mutex_lock(&sde_crtc->crtc_cp_lock);
_sde_clear_ltm_merge_mode(sde_crtc);
@@ -5222,3 +5263,41 @@ void _sde_cp_mark_active_dirty_internal(struct sde_crtc *crtc)
}
mutex_unlock(&crtc->crtc_cp_lock);
}
void sde_cp_backlight_notification(struct drm_crtc *drm_crtc, u32 bl_val, u32 bl_max)
{
struct sde_crtc *crtc;
crtc = to_sde_crtc(drm_crtc);
mutex_lock(&crtc->crtc_cp_lock);
if (crtc->back_light != bl_val) {
crtc->back_light = bl_val;
crtc->back_light_max = bl_max;
crtc->back_light_pending = true;
}
mutex_unlock(&crtc->crtc_cp_lock);
}
void _sde_cp_mark_bl_properties(struct sde_crtc *crtc)
{
struct sde_cp_node *prop_node;
mutex_lock(&crtc->crtc_cp_lock);
if (!crtc->back_light_pending)
goto skip_demura_bl;
if (_sde_cp_feature_in_dirtylist(SDE_CP_CRTC_DSPP_DEMURA_INIT,
&crtc->cp_dirty_list))
goto skip_demura_bl;
prop_node = _sde_cp_feature_getnode_activelist(SDE_CP_CRTC_DSPP_DEMURA_INIT,
&crtc->cp_active_list);
if (prop_node) {
_sde_cp_update_list(prop_node, crtc, true);
list_del_init(&prop_node->cp_active_list);
}
skip_demura_bl:
crtc->back_light_pending = false;
mutex_unlock(&crtc->crtc_cp_lock);
}

View File

@@ -376,4 +376,12 @@ void sde_cp_set_skip_blend_plane_info(struct drm_crtc *crtc,
*/
int sde_dspp_spr_read_opr_value(struct sde_hw_dspp *hw_dspp, u32 *opr_value);
/**
* sde_cp_backlight_notification(): disable cp features
* @crtc: Pointer to drm_crtc.
* @bl_val: Backlight value.
* @bl_max: Max backlight value.
*/
void sde_cp_backlight_notification(struct drm_crtc *crtc, u32 bl_val, u32 bl_max);
#endif /*_SDE_COLOR_PROCESSING_H */

View File

@@ -182,8 +182,14 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
}
rc = c_conn->ops.set_backlight(&c_conn->base,
c_conn->display, bl_lvl);
if (!rc)
if (!rc) {
sde_dimming_bl_notify(c_conn, &display->panel->bl_config);
if (c_conn->base.state && c_conn->base.state->crtc) {
sde_crtc_backlight_notify(c_conn->base.state->crtc, brightness,
display->panel->bl_config.brightness_max_level);
}
}
c_conn->unset_bl_level = 0;
}
@@ -835,8 +841,16 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
bl_config->bl_level);
rc = c_conn->ops.set_backlight(&c_conn->base,
dsi_display, bl_config->bl_level);
if (!rc)
if (!rc) {
sde_dimming_bl_notify(c_conn, bl_config);
if (c_conn->base.state && c_conn->base.state->crtc) {
sde_crtc_backlight_notify(c_conn->base.state->crtc,
dsi_display->panel->bl_config.brightness,
dsi_display->panel->bl_config.brightness_max_level);
}
}
c_conn->unset_bl_level = 0;
return rc;

View File

@@ -8744,3 +8744,9 @@ void sde_crtc_calc_vpadding_param(struct drm_crtc_state *state, u32 crtc_y, uint
SDE_DEBUG("crtc:%d padding_y:%d padding_start:%d padding_height:%d\n",
DRMID(cstate->base.crtc), *padding_y, *padding_start, *padding_height);
}
void sde_crtc_backlight_notify(struct drm_crtc *crtc, u32 bl_val, u32 bl_max)
{
SDE_EVT32(bl_val, bl_max);
sde_cp_backlight_notification(crtc, bl_val, bl_max);
}

View File

@@ -377,6 +377,9 @@ enum sde_crtc_hw_fence_flags {
* used to slow-down creation of output hw-fences for debugging purposes.
* @input_fence_status : input fence status, negative if the fence has been completed with error.
* @hanle_fence_error_bw_update: bool to indicate if it is fence error and need to avoid bw vote.
* @back_light: backlight value
* @back_light_max: max backlight value
* @back_light_pending: flag to indicate if backlight update is pending
*/
struct sde_crtc {
struct drm_crtc base;
@@ -493,6 +496,10 @@ struct sde_crtc {
u32 hwfence_out_fences_skip;
int input_fence_status;
bool handle_fence_error_bw_update;
u32 back_light;
u32 back_light_max;
u32 back_light_pending;
};
enum sde_crtc_dirty_flags {
@@ -1201,4 +1208,12 @@ bool sde_crtc_is_line_insertion_supported(struct drm_crtc *crtc);
void sde_crtc_calc_vpadding_param(struct drm_crtc_state *state, u32 crtc_y, u32 crtc_h,
u32 *padding_y, u32 *padding_start, u32 *padding_height);
/**
* sde_crtc_backlight_notify - notify backlight
* @crtc: Pointer to drm_crtc.
* @bl_val: Backlight value.
* @bl_max: Max backlight value.
*/
void sde_crtc_backlight_notify(struct drm_crtc *crtc, u32 bl_val, u32 bl_max);
#endif /* _SDE_CRTC_H_ */

View File

@@ -8,6 +8,9 @@
#include "sde_hw_color_proc_v4.h"
#include "sde_dbg.h"
#define DEMURAV1_CFG0_PARAM4_MASK 5
#define DEMURAV2_CFG0_PARAM4_MASK 7
static int sde_write_3d_gamut(struct sde_hw_blk_reg_map *hw,
struct drm_msm_3d_gamut *payload, u32 base,
u32 *opcode, u32 pipe, u32 scale_tbl_a_len,
@@ -478,20 +481,61 @@ void sde_ltm_clear_merge_mode(struct sde_hw_dspp *ctx)
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, struct sde_hw_cp_cfg *hw_cfg)
{
u32 demura_base;
u32 backlight;
u32 backlight, gain[2];
struct drm_msm_dem_cfg *dcfg = NULL;
uint32_t mask_bits = DEMURAV1_CFG0_PARAM4_MASK;
if (!ctx) {
DRM_ERROR("invalid parameter ctx %pK", ctx);
return;
}
if (!hw_cfg || !hw_cfg->payload) {
DRM_ERROR("invalid parameter hw_cfg");
return;
}
dcfg = (struct drm_msm_dem_cfg *)hw_cfg->payload;
demura_base = ctx->cap->sblk->demura.base;
backlight = (val & REG_MASK_ULL(11));
backlight |= ((val & REG_MASK_SHIFT_ULL(11, 32)) >> 16);
backlight = (val & REG_MASK(32));
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->demura.base + 0x8, backlight);
backlight = backlight & REG_MASK(16);
if (backlight <= 41) {
/* Gain0.....Gain7
* {0, 0, 0, 3, 2, 2, 1, 1}
*/
gain[0] = (0x0 & 0x3f) | ((0x0 & 0x3f) << 8) |
((0x0 & 0x3f) << 16) | ((0x3 & 0x3f) << 24);
gain[1] = (0x2 & 0x3f) | ((0x2 & 0x3f) << 8) |
((0x1 & 0x3f) << 16) | ((0x1 & 0x3f) << 24);
} else if (backlight <= 164) {
/* Gain0.....Gain7
* {0, 0, 0, 2, 1, 1, 2, 3}
*/
gain[0] = (0x0 & 0x3f) | ((0x0 & 0x3f) << 8) |
((0x0 & 0x3f) << 16) | ((0x2 & 0x3f) << 24);
gain[1] = (0x1 & 0x3f) | ((0x1 & 0x3f) << 8) |
((0x2 & 0x3f) << 16) | ((0x3 & 0x3f) << 24);
} else {
/* check for demura v2 and assign mask bit accordingly */
if (ctx->cap->sblk->demura.version == SDE_COLOR_PROCESS_VER(0x2, 0x0))
mask_bits = DEMURAV2_CFG0_PARAM4_MASK;
gain[0] = (dcfg->cfg0_param4[0] & REG_MASK(mask_bits)) |
((dcfg->cfg0_param4[1] & REG_MASK(mask_bits)) << 8) |
((dcfg->cfg0_param4[2] & REG_MASK(mask_bits)) << 16) |
((dcfg->cfg0_param4[3] & REG_MASK(mask_bits)) << 24);
gain[1] = (dcfg->cfg0_param4[4] & REG_MASK(mask_bits)) |
((dcfg->cfg0_param4[5] & REG_MASK(mask_bits)) << 8) |
((dcfg->cfg0_param4[6] & REG_MASK(mask_bits)) << 16) |
((dcfg->cfg0_param4[7] & REG_MASK(mask_bits)) << 24);
}
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->demura.base + 0x4c, gain[0]);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->demura.base + 0x50, gain[1]);
}
void sde_setup_fp16_cscv1(struct sde_hw_pipe *ctx,

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved.
*/
#ifndef _SDE_HW_COLOR_PROC_V4_H_
@@ -101,8 +101,9 @@ void sde_ltm_clear_merge_modev1_2(struct sde_hw_dspp *dspp);
* sde_demura_backlight_cfg - api to set backlight for demura
* @ctx: pointer to dspp object
* @val: value of backlight
* @cfg: pointer to sde_hw_cp_cfg
*/
void sde_demura_backlight_cfg(struct sde_hw_dspp *ctx, u64 val);
void sde_demura_backlight_cfg(struct sde_hw_dspp *ctx, u64 val, struct sde_hw_cp_cfg *cfg);
/**
* sde_demura_read_plane_status - api to read demura plane fetch setup.

View File

@@ -304,9 +304,11 @@ struct sde_hw_dspp_ops {
/**
* setup_demura_backlight_cfg - function to program demura backlight
* @ctx: Pointer to dspp context
* @status: Pointer to configuration.
* @val: value of backlight
* @hw_cfg: Pointer to configuration
*/
void (*setup_demura_backlight_cfg)(struct sde_hw_dspp *ctx, u64 val);
void (*setup_demura_backlight_cfg)(struct sde_hw_dspp *ctx, u64 val,
struct sde_hw_cp_cfg *hw_cfg);
/**
* demura_read_plane_status - Query demura plane status

View File

@@ -126,9 +126,6 @@
#define REG_DMA_DSPP_GAMUT_OP_MASK 0xFFFFFFE0
#define DEMURAV1_CFG0_PARAM4_MASK 5
#define DEMURAV2_CFG0_PARAM4_MASK 7
#define LOG_FEATURE_OFF SDE_EVT32(ctx->idx, 0)
#define LOG_FEATURE_ON SDE_EVT32(ctx->idx, 1)
@@ -6533,26 +6530,14 @@ static bool __reg_dmav1_valid_hfc_en_cfg(struct drm_msm_dem_cfg *dcfg,
return false;
}
static int __reg_dmav1_setup_demura_common_en(struct sde_hw_dspp *ctx,
static void __reg_dmav1_setup_demura_common_en(struct sde_hw_dspp *ctx,
struct drm_msm_dem_cfg *dcfg,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
struct sde_hw_reg_dma_ops *dma_ops,
struct sde_hw_cp_cfg *hw_cfg,
u32 *en)
{
u32 backl;
int rc;
bool valid_hfc_cfg = false;
u32 demura_base = ctx->cap->sblk->demura.base + ctx->hw.blk_off;
backl = (1024 << 16) | 1024;
REG_DMA_SETUP_OPS(*dma_write_cfg, demura_base + 0x8,
&backl, sizeof(backl), REG_SINGLE_WRITE, 0, 0, 0);
rc = dma_ops->setup_payload(dma_write_cfg);
if (rc) {
DRM_ERROR("0x8: REG_SINGLE_WRITE failed ret %d\n", rc);
return rc;
}
*en = (dcfg->src_id == BIT(3)) ? 0 : BIT(31);
*en |= (dcfg->cfg1_high_idx & REG_MASK(3)) << 24;
@@ -6569,8 +6554,6 @@ static int __reg_dmav1_setup_demura_common_en(struct sde_hw_dspp *ctx,
*en |= (dcfg->cfg0_en) ? BIT(2) : 0;
*en |= (dcfg->cfg1_en) ? BIT(1) : 0;
DRM_DEBUG_DRIVER("demura common en %x\n", *en);
return rc;
}
static int __reg_dmav1_setup_demurav1_en(struct sde_hw_dspp *ctx,
@@ -6583,11 +6566,7 @@ static int __reg_dmav1_setup_demurav1_en(struct sde_hw_dspp *ctx,
int rc;
u32 demura_base = ctx->cap->sblk->demura.base + ctx->hw.blk_off;
rc = __reg_dmav1_setup_demura_common_en(ctx, dcfg, dma_write_cfg, dma_ops, hw_cfg, &en);
if (rc) {
DRM_ERROR("failed reg_dmav1_setup_demura_common_en %d", rc);
return rc;
}
__reg_dmav1_setup_demura_common_en(ctx, dcfg, dma_write_cfg, dma_ops, hw_cfg, &en);
DRM_DEBUG_DRIVER("demura v1 en 0x%x\n", en);
SDE_EVT32(en);
@@ -6610,11 +6589,7 @@ static int __reg_dmav1_setup_demurav2_en(struct sde_hw_dspp *ctx,
int rc, val;
u32 demura_base = ctx->cap->sblk->demura.base + ctx->hw.blk_off;
rc = __reg_dmav1_setup_demura_common_en(ctx, dcfg, dma_write_cfg, dma_ops, hw_cfg, &en);
if (rc) {
DRM_ERROR("failed reg_dmav1_setup_demura_common_en %d", rc);
return rc;
}
__reg_dmav1_setup_demura_common_en(ctx, dcfg, dma_write_cfg, dma_ops, hw_cfg, &en);
/* These are Demura V2 config flags */
val = (dcfg->flags & DEMURA_FLAG_2) >> 2;
@@ -6638,52 +6613,6 @@ static int __reg_dmav1_setup_demurav2_en(struct sde_hw_dspp *ctx,
return rc;
}
static int __reg_dmav1_setup_demura_cfg0_param4_common(struct sde_hw_dspp *ctx,
struct drm_msm_dem_cfg *dcfg,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
struct sde_hw_reg_dma_ops *dma_ops,
uint32_t mask_bits)
{
int rc = 0;
u32 *temp = NULL, i;
u32 demura_base = ctx->cap->sblk->demura.base + ctx->hw.blk_off;
if (!dcfg->cfg0_en) {
DRM_DEBUG_DRIVER("dcfg->cfg0_en is disabled\n");
return 0;
}
temp = kvzalloc(sizeof(struct drm_msm_dem_cfg), GFP_KERNEL);
if (!temp)
return -ENOMEM;
memset(temp, 0, sizeof(u32) * 2);
for (i = 0; i < ARRAY_SIZE(dcfg->cfg0_param4); i++)
DRM_DEBUG_DRIVER("hfc gain is %d\n", dcfg->cfg0_param4[i]);
temp[0] = (dcfg->cfg0_param4[0] & REG_MASK(mask_bits)) |
((dcfg->cfg0_param4[1] & REG_MASK(mask_bits)) << 8) |
((dcfg->cfg0_param4[2] & REG_MASK(mask_bits)) << 16) |
((dcfg->cfg0_param4[3] & REG_MASK(mask_bits)) << 24);
temp[1] = (dcfg->cfg0_param4[4] & REG_MASK(mask_bits)) |
((dcfg->cfg0_param4[5] & REG_MASK(mask_bits)) << 8) |
((dcfg->cfg0_param4[6] & REG_MASK(mask_bits)) << 16) |
((dcfg->cfg0_param4[7] & REG_MASK(mask_bits)) << 24);
DRM_DEBUG_DRIVER("0x4c: value is temp[0] %x temp[1] %x\n",
temp[0], temp[1]);
REG_DMA_SETUP_OPS(*dma_write_cfg, demura_base + 0x4c,
temp, sizeof(u32) * 2, REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(dma_write_cfg);
if (rc) {
DRM_ERROR("0x4c: REG_BLK_WRITE_SINGLE %d len %zd buf idx %d\n",
rc, sizeof(u32) * 2, dma_write_cfg->dma_buf->index);
goto quit;
}
quit:
kvfree(temp);
return rc;
}
static int __reg_dmav1_setup_demurav1_dual_pipe(struct sde_hw_dspp *ctx,
struct sde_hw_cp_cfg *hw_cfg,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
@@ -6803,13 +6732,6 @@ void reg_dmav1_setup_demurav1(struct sde_hw_dspp *ctx, void *cfx)
return;
}
rc = __reg_dmav1_setup_demura_cfg0_param4_common(ctx, dcfg, &dma_write_cfg,
dma_ops, DEMURAV1_CFG0_PARAM4_MASK);
if (rc) {
DRM_ERROR("failed setup demura v1 cfg0_param4 rc %d", rc);
return;
}
rc = __reg_dmav1_setup_demurav1_en(ctx, dcfg, &dma_write_cfg, dma_ops, hw_cfg);
if (rc) {
DRM_ERROR("failed setup_demurav1_en rc %d", rc);
@@ -6872,13 +6794,6 @@ void reg_dmav1_setup_demurav2(struct sde_hw_dspp *ctx, void *cfx)
return;
}
rc = __reg_dmav1_setup_demura_cfg0_param4_common(ctx, dcfg, &dma_write_cfg,
dma_ops, DEMURAV2_CFG0_PARAM4_MASK);
if (rc) {
DRM_ERROR("failed setup demura v2 cfg0_param4 rc %d", rc);
return;
}
rc = __reg_dmav1_setup_demurav2_en(ctx, dcfg, &dma_write_cfg, dma_ops, hw_cfg);
if (rc) {
DRM_ERROR("failed setup_demurav2_en rc %d", rc);