diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 95efe54edb..33d73d445c 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -233,6 +234,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_AVR_STEP, CONNECTOR_PROP_CACHE_STATE, CONNECTOR_PROP_DSC_MODE, + CONNECTOR_PROP_WB_USAGE_TYPE, /* total # of properties */ CONNECTOR_PROP_COUNT diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index b7e0b74134..2355a4e8a2 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -682,6 +683,7 @@ struct sde_connector { * @dnsc_blur_count: Number of downscale blur blocks used * @dnsc_blur_cfg: Configs for the downscale blur block * @dnsc_blur_lut: LUT idx used for the Gaussian filter LUTs in downscale blur block + * @usage_type: WB connector usage type */ struct sde_connector_state { struct drm_connector_state base; @@ -702,6 +704,7 @@ struct sde_connector_state { u32 dnsc_blur_count; struct sde_drm_dnsc_blur_cfg dnsc_blur_cfg[DNSC_BLUR_MAX_COUNT]; u32 dnsc_blur_lut; + enum sde_wb_usage_type usage_type; }; /** diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 24b5505b76..ba46c6e4bd 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -140,6 +140,26 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) return to_sde_kms(priv->kms); } +enum sde_wb_usage_type sde_crtc_get_wb_usage_type(struct drm_crtc *crtc) +{ + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + enum sde_wb_usage_type usage_type = 0; + + drm_connector_list_iter_begin(crtc->dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + if (conn->state && (conn->state->crtc == crtc) + && (conn->connector_type == DRM_MODE_CONNECTOR_VIRTUAL)) { + usage_type = sde_connector_get_property(conn->state, + CONNECTOR_PROP_WB_USAGE_TYPE); + break; + } + } + drm_connector_list_iter_end(&conn_iter); + + return usage_type; +} + static inline struct drm_connector_state *_sde_crtc_get_virt_conn_state( struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 0eb7864dbb..e847768e38 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -720,6 +720,12 @@ u32 sde_crtc_get_fps_mode(struct drm_crtc *crtc); */ u32 sde_crtc_get_dfps_maxfps(struct drm_crtc *crtc); +/** + * sde_crtc_get_wb_usage_type - get writeback usage type + * @crtc: Pointert to crtc + */ +enum sde_wb_usage_type sde_crtc_get_wb_usage_type(struct drm_crtc *crtc); + /** * sde_crtc_get_client_type - check the crtc type- rt, rsc_rt, etc. * @crtc: Pointer to crtc diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index ea7b9b8dec..de03bee4c9 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -78,19 +78,24 @@ static enum sde_intr_type sde_encoder_phys_wb_get_intr_type( * sde_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface * @phys_enc: Pointer to physical encoder */ -static void sde_encoder_phys_wb_set_ot_limit( - struct sde_encoder_phys *phys_enc) +static void sde_encoder_phys_wb_set_ot_limit(struct sde_encoder_phys *phys_enc) { struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct drm_connector_state *conn_state; struct sde_vbif_set_ot_params ot_params; + enum sde_wb_usage_type usage_type; + + conn_state = phys_enc->connector->state; + usage_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_USAGE_TYPE); memset(&ot_params, 0, sizeof(ot_params)); ot_params.xin_id = hw_wb->caps->xin_id; ot_params.num = hw_wb->idx - WB_0; ot_params.width = wb_enc->wb_roi.w; ot_params.height = wb_enc->wb_roi.h; - ot_params.is_wfd = !(phys_enc->in_clone_mode); + ot_params.is_wfd = ((phys_enc->in_clone_mode) || (usage_type == WB_USAGE_OFFLINE_WB)) ? + false : true; ot_params.frame_rate = drm_mode_vrefresh(&phys_enc->cached_mode); ot_params.vbif_idx = hw_wb->caps->vbif_idx; ot_params.clk_ctrl = hw_wb->caps->clk_ctrl; @@ -108,7 +113,9 @@ static void sde_encoder_phys_wb_set_qos_remap(struct sde_encoder_phys *phys_enc) struct sde_encoder_phys_wb *wb_enc; struct sde_hw_wb *hw_wb; struct drm_crtc *crtc; + struct drm_connector_state *conn_state; struct sde_vbif_set_qos_params qos_params; + enum sde_wb_usage_type usage_type; if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) { SDE_ERROR("invalid arguments\n"); @@ -122,6 +129,8 @@ static void sde_encoder_phys_wb_set_qos_remap(struct sde_encoder_phys *phys_enc) } crtc = wb_enc->crtc; + conn_state = phys_enc->connector->state; + usage_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_USAGE_TYPE); if (!wb_enc->hw_wb || !wb_enc->hw_wb->caps) { SDE_ERROR("[enc:%d wb:%d] invalid WB HW\n", DRMID(phys_enc->parent), WBID(wb_enc)); @@ -135,8 +144,12 @@ static void sde_encoder_phys_wb_set_qos_remap(struct sde_encoder_phys *phys_enc) qos_params.xin_id = hw_wb->caps->xin_id; qos_params.clk_ctrl = hw_wb->caps->clk_ctrl; qos_params.num = hw_wb->idx - WB_0; - qos_params.client_type = phys_enc->in_clone_mode ? - VBIF_CWB_CLIENT : VBIF_NRT_CLIENT; + if (phys_enc->in_clone_mode) + qos_params.client_type = VBIF_CWB_CLIENT; + else if (usage_type == WB_USAGE_OFFLINE_WB) + qos_params.client_type = VBIF_OFFLINE_WB_CLIENT; + else + qos_params.client_type = VBIF_NRT_CLIENT; SDE_DEBUG("[enc:%d wb:%d] qos_remap - wb:%d vbif:%d xin:%d clone:%d\n", DRMID(phys_enc->parent), WBID(wb_enc), qos_params.num, @@ -153,9 +166,11 @@ static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) { struct sde_encoder_phys_wb *wb_enc; struct sde_hw_wb *hw_wb; + struct drm_connector_state *conn_state; struct sde_hw_wb_qos_cfg qos_cfg = {0}; struct sde_perf_cfg *perf; u32 fps_index = 0, lut_index, creq_index, ds_index, frame_rate, qos_count; + enum sde_wb_usage_type usage_type; if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog) { SDE_ERROR("invalid parameter(s)\n"); @@ -168,6 +183,9 @@ static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) return; } + conn_state = phys_enc->connector->state; + usage_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_USAGE_TYPE); + perf = &phys_enc->sde_kms->catalog->perf; frame_rate = drm_mode_vrefresh(&phys_enc->cached_mode); @@ -182,13 +200,13 @@ static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) qos_cfg.danger_safe_en = true; - if (phys_enc->in_clone_mode && (SDE_FORMAT_IS_TILE(wb_enc->wb_fmt) || - SDE_FORMAT_IS_UBWC(wb_enc->wb_fmt))) - lut_index = SDE_QOS_LUT_USAGE_CWB_TILE; - else if (phys_enc->in_clone_mode) - lut_index = SDE_QOS_LUT_USAGE_CWB; + if (phys_enc->in_clone_mode) + lut_index = (SDE_FORMAT_IS_TILE(wb_enc->wb_fmt) + || SDE_FORMAT_IS_UBWC(wb_enc->wb_fmt)) ? + SDE_QOS_LUT_USAGE_CWB_TILE : SDE_QOS_LUT_USAGE_CWB; else - lut_index = SDE_QOS_LUT_USAGE_NRT; + lut_index = (usage_type == WB_USAGE_OFFLINE_WB) ? + SDE_QOS_LUT_USAGE_OFFLINE_WB : SDE_QOS_LUT_USAGE_NRT; creq_index = lut_index * SDE_CREQ_LUT_TYPE_MAX; creq_index += (fps_index * SDE_QOS_LUT_USAGE_MAX * SDE_CREQ_LUT_TYPE_MAX); @@ -199,9 +217,9 @@ static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) qos_cfg.danger_lut = perf->danger_lut[ds_index]; qos_cfg.safe_lut = (u32) perf->safe_lut[ds_index]; - SDE_DEBUG("[enc:%d wb:%d] fps:%d mode:%d luts[0x%x,0x%x 0x%llx]\n", + SDE_DEBUG("[enc:%d wb:%d] fps:%d mode:%d type:%d luts[0x%x,0x%x 0x%llx]\n", DRMID(phys_enc->parent), WBID(wb_enc), frame_rate, phys_enc->in_clone_mode, - qos_cfg.danger_lut, qos_cfg.safe_lut, qos_cfg.creq_lut); + usage_type, qos_cfg.danger_lut, qos_cfg.safe_lut, qos_cfg.creq_lut); if (hw_wb->ops.setup_qos_lut) hw_wb->ops.setup_qos_lut(hw_wb, &qos_cfg); diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index f7bad0ae0b..26adf628e5 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -494,6 +494,7 @@ enum { VBIF_QOS_CWB_REMAP, VBIF_QOS_LUTDMA_REMAP, VBIF_QOS_CNOC_REMAP, + VBIF_QOS_OFFLINE_WB_REMAP, VBIF_PROP_MAX, }; @@ -928,6 +929,8 @@ static struct sde_prop_type vbif_prop[] = { {VBIF_QOS_CWB_REMAP, "qcom,sde-vbif-qos-cwb-remap", false, PROP_TYPE_U32_ARRAY}, {VBIF_QOS_LUTDMA_REMAP, "qcom,sde-vbif-qos-lutdma-remap", false, PROP_TYPE_U32_ARRAY}, {VBIF_QOS_CNOC_REMAP, "qcom,sde-vbif-qos-cnoc-remap", false, PROP_TYPE_U32_ARRAY}, + {VBIF_QOS_OFFLINE_WB_REMAP, "qcom,sde-vbif-qos-offline-wb-remap", false, + PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type uidle_prop[] = { @@ -3735,6 +3738,11 @@ static int sde_vbif_parse_dt(struct device_node *np, if (rc) goto end; + rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_OFFLINE_WB_REMAP], 1, + &prop_count[VBIF_QOS_OFFLINE_WB_REMAP], NULL); + if (rc) + goto end; + sde_cfg->vbif_count = off_count; rc = _read_dt_entry(np, vbif_prop, ARRAY_SIZE(vbif_prop), prop_count, diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 1641833eb2..c4daa4d49a 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -844,6 +844,7 @@ enum sde_qos_lut_usage { SDE_QOS_LUT_USAGE_CWB_TILE, SDE_QOS_LUT_USAGE_INLINE, SDE_QOS_LUT_USAGE_INLINE_RESTRICTED_FMTS, + SDE_QOS_LUT_USAGE_OFFLINE_WB, SDE_QOS_LUT_USAGE_MAX, }; @@ -1491,6 +1492,7 @@ struct sde_vbif_qos_tbl { * @VBIF_CWB_CLIENT: concurrent writeback client * @VBIF_LUTDMA_CLIENT: LUTDMA client * @VBIF_CNOC_CLIENT: HW fence client + * @VBIF_OFFLINE_WB_CLIENT: Offline WB client used in 2-pass composition * @VBIF_MAX_CLIENT: max number of clients */ enum sde_vbif_client_type { @@ -1499,6 +1501,7 @@ enum sde_vbif_client_type { VBIF_CWB_CLIENT, VBIF_LUTDMA_CLIENT, VBIF_CNOC_CLIENT, + VBIF_OFFLINE_WB_CLIENT, VBIF_MAX_CLIENT }; diff --git a/msm/sde/sde_hw_mdss.h b/msm/sde/sde_hw_mdss.h index 23ef3b9d40..fcd9a6a3fa 100644 --- a/msm/sde/sde_hw_mdss.h +++ b/msm/sde/sde_hw_mdss.h @@ -488,6 +488,18 @@ enum sde_sys_cache_state { CACHE_STATE_FRAME_READ }; +/** + * enum sde_wb_usage_type: Type of usage of the WB connector + * WB_USAGE_WFD: WB connector used for WFD + * WB_USAGE_CWB: WB connector used for concurrent writeback + * WB_USAGE_OFFLINE_WB: WB connector used for 2-pass composition + */ +enum sde_wb_usage_type { + WB_USAGE_WFD, + WB_USAGE_CWB, + WB_USAGE_OFFLINE_WB, +}; + /** struct sde_format - defines the format configuration which * allows SDE HW to correctly fetch and decode the format * @base: base msm_format struture containing fourcc code diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index fcc4f96977..7b30c3dc20 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -78,18 +78,6 @@ enum sde_plane_qos { SDE_PLANE_QOS_PANIC_CTRL = BIT(2), }; -/* - * struct sde_plane - local sde plane structure - * @aspace: address space pointer - * @csc_cfg: Decoded user configuration for csc - * @csc_usr_ptr: Points to csc_cfg if valid user config available - * @csc_ptr: Points to sde_csc_cfg structure to use for current - * @mplane_list: List of multirect planes of the same pipe - * @catalog: Points to sde catalog structure - * @revalidate: force revalidation of all the plane properties - * @xin_halt_forced_clk: whether or not clocks were forced on for xin halt - * @blob_rot_caps: Pointer to rotator capability blob - */ struct sde_plane { struct drm_plane base; @@ -108,6 +96,7 @@ struct sde_plane { uint32_t color_fill; bool is_error; bool is_rt_pipe; + enum sde_wb_usage_type wb_usage_type; bool is_virtual; struct list_head mplane_list; struct sde_mdss_cfg *catalog; @@ -305,7 +294,8 @@ static void _sde_plane_set_qos_lut(struct drm_plane *plane, else lut_index = SDE_QOS_LUT_USAGE_MACROTILE; } else { - lut_index = SDE_QOS_LUT_USAGE_NRT; + lut_index = (psde->wb_usage_type == WB_USAGE_OFFLINE_WB) ? + SDE_QOS_LUT_USAGE_OFFLINE_WB : SDE_QOS_LUT_USAGE_NRT; } creq_lut_index = lut_index * SDE_CREQ_LUT_TYPE_MAX; @@ -325,11 +315,12 @@ static void _sde_plane_set_qos_lut(struct drm_plane *plane, (fmt) ? fmt->fetch_mode : 0, psde->pipe_qos_cfg.danger_lut, psde->pipe_qos_cfg.safe_lut, psde->pipe_qos_cfg.creq_lut); - SDE_DEBUG("plane%u: pnum:%d fmt:%4.4s fps:%d mode:%d luts[0x%x,0x%x 0x%llx]\n", + SDE_DEBUG("plane%u: pnum:%d fmt:%4.4s fps:%d mode:%d lut[0x%x,0x%x 0x%llx] rt:%d type:%d\n", plane->base.id, psde->pipe - SSPP_VIG0, fmt ? (char *)&fmt->base.pixel_format : NULL, frame_rate, fmt ? fmt->fetch_mode : -1, psde->pipe_qos_cfg.danger_lut, - psde->pipe_qos_cfg.safe_lut, psde->pipe_qos_cfg.creq_lut); + psde->pipe_qos_cfg.safe_lut, psde->pipe_qos_cfg.creq_lut, + psde->is_rt_pipe, psde->wb_usage_type); psde->pipe_hw->ops.setup_qos_lut(psde->pipe_hw, &psde->pipe_qos_cfg); } @@ -472,7 +463,8 @@ static void _sde_plane_set_ot_limit(struct drm_plane *plane, ot_params.num = psde->pipe_hw->idx - SSPP_NONE; ot_params.width = psde->pipe_cfg.src_rect.w; ot_params.height = psde->pipe_cfg.src_rect.h; - ot_params.is_wfd = !psde->is_rt_pipe; + ot_params.is_wfd = ((psde->is_rt_pipe) + || (psde->wb_usage_type == WB_USAGE_OFFLINE_WB)) ? false : true; ot_params.frame_rate = drm_mode_vrefresh(&crtc->mode); ot_params.vbif_idx = VBIF_RT; ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl; @@ -515,8 +507,11 @@ static void _sde_plane_set_qos_remap(struct drm_plane *plane) qos_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl; qos_params.xin_id = psde->pipe_hw->cap->xin_id; qos_params.num = psde->pipe_hw->idx - SSPP_VIG0; - qos_params.client_type = psde->is_rt_pipe ? - VBIF_RT_CLIENT : VBIF_NRT_CLIENT; + if (psde->is_rt_pipe) + qos_params.client_type = VBIF_RT_CLIENT; + else + qos_params.client_type = (psde->wb_usage_type == WB_USAGE_OFFLINE_WB) ? + VBIF_OFFLINE_WB_CLIENT : VBIF_NRT_CLIENT; SDE_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n", plane->base.id, qos_params.num, @@ -3329,6 +3324,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, is_rt = sde_crtc_is_rt_client(crtc, crtc->state); if (is_rt != psde->is_rt_pipe || crtc->state->mode_changed) { psde->is_rt_pipe = is_rt; + psde->wb_usage_type = psde->is_rt_pipe ? 0 : sde_crtc_get_wb_usage_type(crtc); pstate->dirty |= SDE_PLANE_DIRTY_QOS; } diff --git a/msm/sde/sde_wb.c b/msm/sde/sde_wb.c index bd296b95b7..e9e6f07bba 100644 --- a/msm/sde/sde_wb.c +++ b/msm/sde/sde_wb.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -602,6 +603,12 @@ int sde_wb_connector_post_init(struct drm_connector *connector, void *display) {CACHE_STATE_ENABLED, "cache_state_enabled"}, }; + static const struct drm_prop_enum_list e_wb_usage_type[] = { + {WB_USAGE_WFD, "wb_usage_wfd"}, + {WB_USAGE_CWB, "wb_usage_cwb"}, + {WB_USAGE_OFFLINE_WB, "wb_usage_offline_wb"}, + }; + if (!connector || !display || !wb_dev->wb_cfg || !wb_dev->drm_dev->dev_private) { SDE_ERROR("invalid params\n"); return -EINVAL; @@ -654,8 +661,11 @@ int sde_wb_connector_post_init(struct drm_connector *connector, void *display) msm_property_install_range(&c_conn->property_info, "dnsc_blur", 0x0, 0, ~0, 0, CONNECTOR_PROP_DNSC_BLUR); - _sde_wb_connector_install_dither_property(wb_dev); + msm_property_install_enum(&c_conn->property_info, "wb_usage_type", + 0x0, 0, e_wb_usage_type, ARRAY_SIZE(e_wb_usage_type), + 0, CONNECTOR_PROP_WB_USAGE_TYPE); + _sde_wb_connector_install_dither_property(wb_dev); return 0; }