diff --git a/include/uapi/display/drm/msm_drm_pp.h b/include/uapi/display/drm/msm_drm_pp.h index 646a68d1c0..3fc2e40b3c 100644 --- a/include/uapi/display/drm/msm_drm_pp.h +++ b/include/uapi/display/drm/msm_drm_pp.h @@ -8,6 +8,12 @@ #define _MSM_DRM_PP_H_ #include +#include + +#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_ */ diff --git a/include/uapi/display/drm/sde_drm.h b/include/uapi/display/drm/sde_drm.h index 88bf86f0b7..8cb12843ff 100644 --- a/include/uapi/display/drm/sde_drm.h +++ b/include/uapi/display/drm/sde_drm.h @@ -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 diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index 5a52c75283..b30cb04da2 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -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) { diff --git a/msm/sde/sde_color_processing.h b/msm/sde/sde_color_processing.h index 32f40905c4..86955f58f5 100644 --- a/msm/sde/sde_color_processing.h +++ b/msm/sde/sde_color_processing.h @@ -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 */ diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 53bcc53fbe..406554be90 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -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; } @@ -1933,7 +1938,7 @@ static void sde_connector_update_colorspace(struct drm_connector *connector) } static int -sde_connector_detect_ctx(struct drm_connector *connector, +sde_connector_detect_ctx(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx, bool force) { @@ -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: diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 7628fa3f72..501ff6c453 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -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; }; /** diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 8a0a48c255..4e316f8e14 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -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, + ¤t_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); } @@ -7850,6 +7907,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) { diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index e32219d274..7a0ffde011 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -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 @@ -316,6 +326,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; @@ -421,6 +433,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 { diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c976766ee3..23e0bb5c15 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -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, ¤t_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); + } +} diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index d56a21e96c..c0660ff070 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -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__ */ diff --git a/msm/sde/sde_hw_color_proc_v4.c b/msm/sde/sde_hw_color_proc_v4.c index aafa41d21b..a1f429e2d5 100644 --- a/msm/sde/sde_hw_color_proc_v4.c +++ b/msm/sde/sde_hw_color_proc_v4.c @@ -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; +} diff --git a/msm/sde/sde_hw_color_proc_v4.h b/msm/sde/sde_hw_color_proc_v4.h index fa24e4567a..0a1c1839b3 100644 --- a/msm/sde/sde_hw_color_proc_v4.h +++ b/msm/sde/sde_hw_color_proc_v4.h @@ -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_ */ diff --git a/msm/sde/sde_hw_dspp.c b/msm/sde/sde_hw_dspp.c index f14340daf5..022984d4d7 100644 --- a/msm/sde/sde_hw_dspp.c +++ b/msm/sde/sde_hw_dspp.c @@ -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; } } diff --git a/msm/sde/sde_hw_dspp.h b/msm/sde/sde_hw_dspp.h index 3d6c0ae625..b7ab5a3c12 100644 --- a/msm/sde/sde_hw_dspp.h +++ b/msm/sde/sde_hw_dspp.h @@ -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