Merge "disp: msm: sde: add custom event to notify OPR, MISR value change"

This commit is contained in:
qctecmdr
2022-05-10 21:25:05 -07:00
committed by Gerrit - the friendly Code Review server
14 changed files with 328 additions and 7 deletions

View File

@@ -8,6 +8,12 @@
#define _MSM_DRM_PP_H_
#include <linux/types.h>
#include <drm/drm.h>
#define ENABLE_EVENT_SPR_OPR_VALUE
#define ENABLE_EVENT_INTF_MISR_SIGNATURE
#define MAX_DSI_DISPLAY 4
/**
* struct drm_msm_pcc_coeff - PCC coefficient structure for each color
* component.
@@ -752,4 +758,21 @@ struct drm_msm_dimming_bl_lut {
__u32 mapped_bl[DIMMING_BL_LUT_LEN];
};
struct drm_msm_opr_value {
__u32 num_valid_opr;
__u32 opr_value[MAX_DSI_DISPLAY];
};
#define SDE_MAX_ROI 4
struct drm_msm_roi {
__u32 num_rects;
struct drm_clip_rect roi[SDE_MAX_ROI];
};
struct drm_msm_misr_sign {
__u64 num_valid_misr;
struct drm_msm_roi roi_list;
__u64 misr_sign_value[MAX_DSI_DISPLAY];
};
#endif /* _MSM_DRM_PP_H_ */

View File

@@ -917,6 +917,8 @@ struct sde_drm_dnsc_blur_cfg {
#define DRM_EVENT_FRAME_DATA 0x8000000C
#define DRM_EVENT_DIMMING_BL 0X8000000D
#define DRM_EVENT_VM_RELEASE 0X8000000E
#define DRM_EVENT_OPR_VALUE 0X8000000F
#define DRM_EVENT_MISR_SIGN 0X80000010
#ifndef DRM_MODE_FLAG_VID_MODE_PANEL
#define DRM_MODE_FLAG_VID_MODE_PANEL 0x01

View File

@@ -837,6 +837,20 @@ static int _set_spr_pu_feature(struct sde_hw_dspp *hw_dspp,
return 0;
}
int sde_dspp_spr_read_opr_value(struct sde_hw_dspp *hw_dspp, u32 *opr_value)
{
int rc;
if (!opr_value || !hw_dspp || !hw_dspp->ops.read_spr_opr_value)
return -EINVAL;
rc = hw_dspp->ops.read_spr_opr_value(hw_dspp, opr_value);
if (rc)
SDE_ERROR("invalid opr read %d", rc);
return rc;
}
static int _set_demura_pu_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc)
{

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
*/
@@ -366,4 +367,11 @@ void sde_cp_disable_features(struct drm_crtc *crtc);
void sde_cp_set_skip_blend_plane_info(struct drm_crtc *crtc,
struct sde_cp_crtc_skip_blend_plane *skip_blend);
/**
* sde_dspp_spr_read_opr_value(): read opr value
* @hw_dspp: Pointer to DSPP hardware description.
* @opr_value: Pointer to opr value.
*/
int sde_dspp_spr_read_opr_value(struct sde_hw_dspp *hw_dspp, u32 *opr_value);
#endif /*_SDE_COLOR_PROCESSING_H */

View File

@@ -1794,6 +1794,11 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
case CONNECTOR_PROP_DYN_TRANSFER_TIME:
_sde_connector_set_prop_dyn_transfer_time(c_conn, val);
break;
case CONNECTOR_PROP_LP:
/* suspend case: clear stale MISR */
if (val == SDE_MODE_DPMS_OFF)
memset(&c_conn->previous_misr_sign, 0, sizeof(struct sde_misr_sign));
break;
default:
break;
}
@@ -3415,6 +3420,15 @@ int sde_connector_register_custom_event(struct sde_kms *kms,
c_conn->dimming_bl_notify_enabled = val;
ret = 0;
break;
case DRM_EVENT_MISR_SIGN:
if (!conn_drm) {
SDE_ERROR("invalid connector\n");
return -EINVAL;
}
c_conn = to_sde_connector(conn_drm);
c_conn->misr_event_notify_enabled = val;
ret = sde_encoder_register_misr_event(c_conn->encoder, val);
break;
case DRM_EVENT_PANEL_DEAD:
ret = 0;
break;
@@ -3444,6 +3458,7 @@ int sde_connector_event_notify(struct drm_connector *connector, uint32_t type,
case DRM_EVENT_DIMMING_BL:
case DRM_EVENT_PANEL_DEAD:
case DRM_EVENT_SDE_HW_RECOVERY:
case DRM_EVENT_MISR_SIGN:
ret = 0;
break;
default:

View File

@@ -482,6 +482,18 @@ struct sde_connector_dyn_hdr_metadata {
bool dynamic_hdr_update;
};
/**
* struct sde_misr_sign - defines sde misr signature structure
* @num_valid_misr : count of valid misr signature
* @roi_list : list of roi
* @misr_sign_value : list of misr signature
*/
struct sde_misr_sign {
atomic64_t num_valid_misr;
struct msm_roi_list roi_list;
u64 misr_sign_value[MAX_DSI_DISPLAYS];
};
/**
* struct sde_connector - local sde connector structure
* @base: Base drm connector structure
@@ -541,6 +553,8 @@ struct sde_connector_dyn_hdr_metadata {
* @cmd_rx_buf: the return buffer of response of command transfer
* @rx_len: the length of dcs command received buffer
* @cached_edid: cached edid data for the connector
* @misr_event_notify_enabled: Flag to indicate if misr event notify is enabled or not
* @previous_misr_sign: store previous misr signature
*/
struct sde_connector {
struct drm_connector base;
@@ -616,6 +630,8 @@ struct sde_connector {
int rx_len;
struct edid *cached_edid;
bool misr_event_notify_enabled;
struct sde_misr_sign previous_misr_sign;
};
/**

View File

@@ -78,7 +78,8 @@ static int _sde_crtc_set_noise_layer(struct sde_crtc *sde_crtc,
void __user *usr_ptr);
static int sde_crtc_vm_release_handler(struct drm_crtc *crtc_drm,
bool en, struct sde_irq_callback *irq);
static int sde_crtc_opr_event_handler(struct drm_crtc *crtc_drm,
bool en, struct sde_irq_callback *irq);
static struct sde_crtc_custom_events custom_events[] = {
{DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt},
@@ -92,6 +93,7 @@ static struct sde_crtc_custom_events custom_events[] = {
{DRM_EVENT_MMRM_CB, sde_crtc_mmrm_interrupt_handler},
{DRM_EVENT_VM_RELEASE, sde_crtc_vm_release_handler},
{DRM_EVENT_FRAME_DATA, sde_crtc_frame_data_interrupt_handler},
{DRM_EVENT_OPR_VALUE, sde_crtc_opr_event_handler},
};
/* default input fence timeout, in ms */
@@ -2989,6 +2991,56 @@ static void _sde_crtc_retire_event(struct drm_connector *connector,
SDE_ATRACE_END("signal_retire_fence");
}
void sde_crtc_opr_event_notify(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc;
uint32_t current_opr_value[MAX_DSI_DISPLAYS] = {0};
int i, rc;
bool updated = false;
struct drm_event event;
sde_crtc = to_sde_crtc(crtc);
atomic_set(&sde_crtc->previous_opr_value.num_valid_opr, 0);
for (i = 0; i < sde_crtc->num_mixers; i++) {
rc = sde_dspp_spr_read_opr_value(sde_crtc->mixers[i].hw_dspp,
&current_opr_value[i]);
if (rc) {
SDE_ERROR("failed to collect OPR %d", i, rc);
continue;
}
atomic_inc(&sde_crtc->previous_opr_value.num_valid_opr);
if (current_opr_value[i] == sde_crtc->previous_opr_value.opr_value[i])
continue;
sde_crtc->previous_opr_value.opr_value[i] = current_opr_value[i];
updated = true;
}
if (updated) {
event.type = DRM_EVENT_OPR_VALUE;
event.length = sizeof(sde_crtc->previous_opr_value);
msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
(u8 *)&sde_crtc->previous_opr_value);
}
}
static void _sde_crtc_frame_done_notify(struct drm_crtc *crtc,
struct sde_crtc_frame_event *fevent)
{
struct sde_crtc *sde_crtc;
struct sde_connector *sde_conn;
sde_crtc = to_sde_crtc(crtc);
if (sde_crtc->opr_event_notify_enabled)
sde_crtc_opr_event_notify(crtc);
sde_conn = to_sde_connector(fevent->connector);
if (sde_conn && sde_conn->misr_event_notify_enabled)
sde_encoder_misr_sign_event_notify(fevent->connector->encoder);
}
static void sde_crtc_frame_event_work(struct kthread_work *work)
{
struct msm_drm_private *priv;
@@ -3059,6 +3111,7 @@ static void sde_crtc_frame_event_work(struct kthread_work *work)
sde_fence_signal(sde_crtc->output_fence, fevent->ts,
(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);
_sde_crtc_frame_done_notify(crtc, fevent);
SDE_ATRACE_END("signal_release_fence");
}
@@ -4913,6 +4966,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
power_on = 0;
sde_crtc_event_notify(crtc, DRM_EVENT_CRTC_POWER, &power_on, sizeof(u32));
/* suspend case: clear stale OPR value */
if (sde_crtc->opr_event_notify_enabled)
memset(&sde_crtc->previous_opr_value, 0, sizeof(struct sde_opr_value));
mutex_unlock(&sde_crtc->crtc_lock);
}
@@ -7859,6 +7916,19 @@ static int sde_crtc_mmrm_interrupt_handler(struct drm_crtc *crtc_drm,
return 0;
}
static int sde_crtc_opr_event_handler(struct drm_crtc *crtc_drm,
bool en, struct sde_irq_callback *irq)
{
struct sde_crtc *sde_crtc;
sde_crtc = to_sde_crtc(crtc_drm);
if (!sde_crtc)
return -EINVAL;
sde_crtc->opr_event_notify_enabled = en;
return 0;
}
static int sde_crtc_vm_release_handler(struct drm_crtc *crtc_drm,
bool en, struct sde_irq_callback *irq)
{

View File

@@ -232,6 +232,16 @@ struct sde_frame_data {
struct sde_frame_data_buffer *buf[SDE_FRAME_DATA_BUFFER_MAX];
};
/**
* struct sde_opr_value - defines sde opr value structure
* @num_valid_opr : count of valid opr values
* @opr_value : list of opr value
*/
struct sde_opr_value {
atomic_t num_valid_opr;
u32 opr_value[MAX_DSI_DISPLAYS];
};
/**
* struct sde_crtc - virtualized CRTC data structure
* @base : Base drm crtc structure
@@ -317,6 +327,8 @@ struct sde_frame_data {
* @skip_blend_plane_h: skip blend plane height
* @line_time_in_ns : current mode line time in nano sec is needed for QOS update
* @frame_data : Framedata data structure
* @previous_opr_value : store previous opr values
* @opr_event_notify_enabled : Flag to indicate if opr event notify is enabled or not
*/
struct sde_crtc {
struct drm_crtc base;
@@ -423,6 +435,9 @@ struct sde_crtc {
u32 line_time_in_ns;
struct sde_frame_data frame_data;
struct sde_opr_value previous_opr_value;
bool opr_event_notify_enabled;
};
enum sde_crtc_dirty_flags {

View File

@@ -77,6 +77,9 @@
/* Maximum number of VSYNC wait attempts for RSC state transition */
#define MAX_RSC_WAIT 5
#define IS_ROI_UPDATED(a, b) (a.x1 != b.x1 || a.x2 != b.x2 || \
a.y1 != b.y1 || a.y2 != b.y2)
/**
* enum sde_enc_rc_events - events for resource control state machine
* @SDE_ENC_RC_EVENT_KICKOFF:
@@ -2193,6 +2196,7 @@ static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc,
struct drm_crtc *crtc = drm_enc->crtc;
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
struct sde_connector *sde_conn;
int crtc_id = 0;
priv = drm_enc->dev->dev_private;
sde_kms = to_sde_kms(priv->kms);
@@ -2218,10 +2222,14 @@ static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc,
goto end;
}
crtc_id = drm_crtc_index(crtc);
if (is_vid_mode) {
sde_encoder_irq_control(drm_enc, false);
_sde_encoder_pm_qos_remove_request(drm_enc);
} else {
if (priv->event_thread[crtc_id].thread)
kthread_flush_worker(&priv->event_thread[crtc_id].worker);
/* disable all the clks and resources */
_sde_encoder_update_rsc_client(drm_enc, false);
_sde_encoder_resource_control_helper(drm_enc, false);
@@ -2985,6 +2993,13 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
_sde_encoder_virt_enable_helper(drm_enc);
sde_encoder_control_te(drm_enc, true);
/*
* During IPC misr ctl register is reset.
* Need to reconfigure misr after every IPC.
*/
if (atomic_read(&sde_enc->misr_enable))
sde_enc->misr_reconfigure = true;
}
static void sde_encoder_populate_encoder_phys(struct drm_encoder *drm_enc,
@@ -3032,7 +3047,7 @@ static void sde_encoder_populate_encoder_phys(struct drm_encoder *drm_enc,
phys->ops.enable(phys);
}
if (sde_enc->misr_enable && phys->ops.setup_misr &&
if (atomic_read(&sde_enc->misr_enable) && phys->ops.setup_misr &&
(sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_VIDEO_MODE)))
phys->ops.setup_misr(phys, true,
sde_enc->misr_frame_count);
@@ -3977,7 +3992,7 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc,
}
}
if (sde_enc->misr_enable)
if (atomic_read(&sde_enc->misr_enable))
sde_encoder_misr_configure(&sde_enc->base, true,
sde_enc->misr_frame_count);
@@ -4888,7 +4903,7 @@ static ssize_t _sde_encoder_misr_setup(struct file *file,
if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
return -EINVAL;
sde_enc->misr_enable = enable;
atomic_set(&sde_enc->misr_enable, enable);
sde_enc->misr_reconfigure = true;
sde_enc->misr_frame_count = frame_count;
return count;
@@ -4935,7 +4950,7 @@ static ssize_t _sde_encoder_misr_read(struct file *file,
goto end;
}
if (!sde_enc->misr_enable) {
if (!atomic_read(&sde_enc->misr_enable)) {
len += scnprintf(buf + len, MISR_BUFF_SIZE - len,
"disabled\n");
goto buff_check;
@@ -5914,3 +5929,80 @@ void sde_encoder_add_data_to_minidump_va(struct drm_encoder *drm_enc)
phys_enc->ops.add_to_minidump(phys_enc);
}
}
void sde_encoder_misr_sign_event_notify(struct drm_encoder *drm_enc)
{
struct drm_event event;
struct drm_connector *connector;
struct sde_connector *c_conn = NULL;
struct sde_connector_state *c_state = NULL;
struct sde_encoder_virt *sde_enc = NULL;
struct sde_encoder_phys *phys = NULL;
u32 current_misr_value[MAX_DSI_DISPLAYS] = {0};
int rc = 0, i = 0;
bool misr_updated = false, roi_updated = false;
struct msm_roi_list *prev_roi, *c_state_roi;
if (!drm_enc)
return;
sde_enc = to_sde_encoder_virt(drm_enc);
if (!atomic_read(&sde_enc->misr_enable)) {
SDE_DEBUG("MISR is disabled\n");
return;
}
connector = sde_enc->cur_master->connector;
if (!connector)
return;
c_conn = to_sde_connector(connector);
c_state = to_sde_connector_state(connector->state);
atomic64_set(&c_conn->previous_misr_sign.num_valid_misr, 0);
for (i = 0; i < sde_enc->num_phys_encs; i++) {
phys = sde_enc->phys_encs[i];
if (!phys || !phys->ops.collect_misr) {
SDE_DEBUG("invalid misr ops\n", i);
continue;
}
rc = phys->ops.collect_misr(phys, true, &current_misr_value[i]);
if (rc) {
SDE_ERROR("failed to collect misr %d\n", rc);
return;
}
atomic64_inc(&c_conn->previous_misr_sign.num_valid_misr);
}
for (i = 0; i < sde_enc->num_phys_encs; i++) {
if (current_misr_value[i] != c_conn->previous_misr_sign.misr_sign_value[i]) {
c_conn->previous_misr_sign.misr_sign_value[i] = current_misr_value[i];
misr_updated = true;
}
}
prev_roi = &c_conn->previous_misr_sign.roi_list;
c_state_roi = &c_state->rois;
if (prev_roi->num_rects != c_state_roi->num_rects) {
roi_updated = true;
} else {
for (i = 0; i < prev_roi->num_rects; i++) {
if (IS_ROI_UPDATED(prev_roi->roi[i], c_state_roi->roi[i]))
roi_updated = true;
}
}
if (roi_updated)
memcpy(&c_conn->previous_misr_sign.roi_list, &c_state->rois, sizeof(c_state->rois));
if (misr_updated || roi_updated) {
event.type = DRM_EVENT_MISR_SIGN;
event.length = sizeof(c_conn->previous_misr_sign);
msm_mode_object_event_notify(&connector->base, connector->dev, &event,
(u8 *)&c_conn->previous_misr_sign);
}
}

View File

@@ -222,7 +222,7 @@ struct sde_encoder_virt {
struct sde_rsc_client *rsc_client;
bool rsc_state_init;
struct msm_display_info disp_info;
bool misr_enable;
atomic_t misr_enable;
bool misr_reconfigure;
u32 misr_frame_count;
@@ -692,4 +692,38 @@ static inline bool sde_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
bool sde_encoder_is_line_insertion_supported(struct drm_encoder *drm_enc);
void sde_encoder_add_data_to_minidump_va(struct drm_encoder *drm_enc);
/**
* sde_encoder_misr_sign_event_notify - collect MISR, check with previous value
* if change then notify to client with custom event
* @drm_enc: pointer to drm encoder
*/
void sde_encoder_misr_sign_event_notify(struct drm_encoder *drm_enc);
/**
* sde_encoder_register_misr_event - register or deregister MISR event
* @drm_enc: pointer to drm encoder
* @val: indicates register or deregister
*/
static inline int sde_encoder_register_misr_event(struct drm_encoder *drm_enc, bool val)
{
struct sde_encoder_virt *sde_enc = NULL;
if (!drm_enc)
return -EINVAL;
sde_enc = to_sde_encoder_virt(drm_enc);
atomic_set(&sde_enc->misr_enable, val);
/*
* To setup MISR ctl reg, set misr_reconfigure as true.
* MISR is calculated for the specific number of frames.
*/
if (atomic_read(&sde_enc->misr_enable)) {
sde_enc->misr_reconfigure = true;
sde_enc->misr_frame_count = 1;
}
return 0;
}
#endif /* __SDE_ENCODER_H__ */

View File

@@ -745,3 +745,17 @@ void sde_demura_pu_cfg(struct sde_hw_dspp *dspp, void *cfg)
((roi_list) ? roi_list->roi[0].y2 : -1),
((hw_cfg) ? hw_cfg->panel_height : -1));
}
int sde_spr_read_opr_value(struct sde_hw_dspp *ctx, uint32_t *opr_value)
{
uint32_t reg_off;
if (!ctx || !opr_value)
return -EINVAL;
reg_off = ctx->cap->sblk->spr.base + 0x78;
*opr_value = SDE_REG_READ(&ctx->hw, reg_off);
return 0;
}

View File

@@ -153,4 +153,12 @@ void sde_setup_fp16_unmultv1(struct sde_hw_pipe *ctx,
* @cfg: partial update configuraton for the frame.
*/
void sde_demura_pu_cfg(struct sde_hw_dspp *ctx, void *cfg);
/**
* sde_spr_read_opr_value - api to read spr opr value
* @ctx: pointer to dspp object.
* @opr_value: Pointer to opr value.
*/
int sde_spr_read_opr_value(struct sde_hw_dspp *ctx, uint32_t *opr_value);
#endif /* _SDE_HW_COLOR_PROC_V4_H_ */

View File

@@ -343,6 +343,7 @@ static void dspp_spr(struct sde_hw_dspp *c)
c->ops.setup_spr_init_config = reg_dmav1_setup_spr_init_cfgv1;
c->ops.setup_spr_pu_config = reg_dmav1_setup_spr_pu_cfgv1;
c->ops.read_spr_opr_value = sde_spr_read_opr_value;
}
}

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -268,6 +269,14 @@ struct sde_hw_dspp_ops {
* @cfg: Pointer to configuration
*/
void (*setup_spr_pu_config)(struct sde_hw_dspp *ctx, void *cfg);
/**
* read_spr_opr_value - function to read spr opr value
* @ctx: Pointer to dspp context
* @opr_value: Pointer to opr value
*/
int (*read_spr_opr_value)(struct sde_hw_dspp *ctx, u32 *opr_value);
/**
* setup_demura_cfg - function to program demura cfg
* @ctx: Pointer to dspp context