From 9423445a34f289ed4f0be9509304829beb8109d2 Mon Sep 17 00:00:00 2001 From: Akshay Ashtunkar Date: Mon, 28 Feb 2022 16:18:41 +0530 Subject: [PATCH] disp: msm: sde: add custom event to notify OPR, MISR value change This change collects the OPR, MISR values. If the values are different than the previous then notify to client with custom event. Change-Id: I2546439be1f665d90e6505d65283d28096bf7cdd Signed-off-by: Akshay Ashtunkar --- include/uapi/display/drm/msm_drm_pp.h | 23 ++++++ include/uapi/display/drm/sde_drm.h | 2 + msm/sde/sde_color_processing.c | 14 ++++ msm/sde/sde_color_processing.h | 8 +++ msm/sde/sde_connector.c | 17 ++++- msm/sde/sde_connector.h | 16 +++++ msm/sde/sde_crtc.c | 72 ++++++++++++++++++- msm/sde/sde_crtc.h | 15 ++++ msm/sde/sde_encoder.c | 100 ++++++++++++++++++++++++-- msm/sde/sde_encoder.h | 36 +++++++++- msm/sde/sde_hw_color_proc_v4.c | 14 ++++ msm/sde/sde_hw_color_proc_v4.h | 8 +++ msm/sde/sde_hw_dspp.c | 1 + msm/sde/sde_hw_dspp.h | 9 +++ 14 files changed, 328 insertions(+), 7 deletions(-) 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