disp: msm: sde: add offline WB QoS support

Add support to parse and configure QoS values for offline writeback.
Expose a writeback connector property to allow user-mode to set
the usage type of the writeback block - WFD, CWB, offline-WB.

Change-Id: I864f79c4896ec757ac2d8b0f57a6a5775d164f21
Signed-off-by: Veera Sundaram Sankaran <quic_veeras@quicinc.com>
This commit is contained in:
Veera Sundaram Sankaran
2021-12-17 16:24:49 -08:00
parent 3c8871f45b
commit b7f241585a
10 changed files with 113 additions and 35 deletions

View File

@@ -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 <robdclark@gmail.com>
@@ -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

View File

@@ -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;
};
/**

View File

@@ -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) 2014-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
@@ -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)
{

View File

@@ -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 <robdclark@gmail.com>
@@ -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

View File

@@ -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);

View File

@@ -502,6 +502,7 @@ enum {
VBIF_QOS_CWB_REMAP,
VBIF_QOS_LUTDMA_REMAP,
VBIF_QOS_CNOC_REMAP,
VBIF_QOS_OFFLINE_WB_REMAP,
VBIF_PROP_MAX,
};
@@ -943,6 +944,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[] = {
@@ -3863,6 +3866,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,

View File

@@ -850,6 +850,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,
};
@@ -1509,6 +1510,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 {
@@ -1517,6 +1519,7 @@ enum sde_vbif_client_type {
VBIF_CWB_CLIENT,
VBIF_LUTDMA_CLIENT,
VBIF_CNOC_CLIENT,
VBIF_OFFLINE_WB_CLIENT,
VBIF_MAX_CLIENT
};

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 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.
*/
@@ -500,6 +500,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

View File

@@ -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,
@@ -3331,6 +3326,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;
}

View File

@@ -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;
}