diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 761020687b..cd46594e2e 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -244,6 +244,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DSC_MODE, CONNECTOR_PROP_WB_USAGE_TYPE, CONNECTOR_PROP_WB_ROT_TYPE, + CONNECTOR_PROP_WB_ROT_BYTES_PER_CLK, /* total # of properties */ CONNECTOR_PROP_COUNT diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 6ebb5087a4..7f5ab28002 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -101,8 +101,7 @@ static void sde_encoder_phys_wb_set_ot_limit(struct sde_encoder_phys *phys_enc) 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) || (usage_type == WB_USAGE_OFFLINE_WB)) ? - false : true; + ot_params.is_wfd = (usage_type == WB_USAGE_WFD); 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; @@ -153,7 +152,7 @@ static void sde_encoder_phys_wb_set_qos_remap(struct sde_encoder_phys *phys_enc) qos_params.num = hw_wb->idx - WB_0; if (phys_enc->in_clone_mode) qos_params.client_type = VBIF_CWB_CLIENT; - else if (usage_type == WB_USAGE_OFFLINE_WB) + else if (usage_type == WB_USAGE_OFFLINE_WB || usage_type == WB_USAGE_ROT) qos_params.client_type = VBIF_OFFLINE_WB_CLIENT; else qos_params.client_type = VBIF_NRT_CLIENT; @@ -206,13 +205,19 @@ static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) } qos_cfg.danger_safe_en = true; + if (usage_type == WB_USAGE_ROT) { + qos_cfg.danger_safe_en = false; + qos_cfg.qos_mode = SDE_WB_QOS_MODE_DYNAMIC; + qos_cfg.bytes_per_clk = sde_connector_get_property(conn_state, + CONNECTOR_PROP_WB_ROT_BYTES_PER_CLK); + } 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 = (usage_type == WB_USAGE_OFFLINE_WB) ? + lut_index = (usage_type == WB_USAGE_OFFLINE_WB || usage_type == WB_USAGE_ROT) ? SDE_QOS_LUT_USAGE_OFFLINE_WB : SDE_QOS_LUT_USAGE_NRT; creq_index = lut_index * SDE_CREQ_LUT_TYPE_MAX; @@ -996,14 +1001,15 @@ static int _sde_encoder_phys_wb_validate_rotation(struct sde_encoder_phys *phys_ enum sde_wb_rot_type rotation_type; int ret = 0; u32 src_w, src_h; + u32 bytes_per_clk; struct sde_rect wb_src, wb_roi = {0,}; struct sde_io_res dnsc_res = {0,}; const struct sde_rect *crtc_roi = NULL; struct drm_display_mode *mode; + enum sde_wb_usage_type usage_type; struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); rotation_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_ROT_TYPE); - if (rotation_type == WB_ROT_NONE) return ret; @@ -1014,6 +1020,13 @@ static int _sde_encoder_phys_wb_validate_rotation(struct sde_encoder_phys *phys_ return -EINVAL; } + bytes_per_clk = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_ROT_BYTES_PER_CLK); + if (!bytes_per_clk) { + SDE_ERROR("[enc:%d wb:%d] WB output bytes per XO clock is must for rotation\n", + DRMID(phys_enc->parent), WBID(wb_enc)); + return -EINVAL; + } + ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); if (ret) { SDE_ERROR("[enc:%d wb:%d] failed to get WB output roi, ret:%d\n", diff --git a/msm/sde/sde_hw_wb.c b/msm/sde/sde_hw_wb.c index 68199ca6ea..4c010451ee 100644 --- a/msm/sde/sde_hw_wb.c +++ b/msm/sde/sde_hw_wb.c @@ -23,6 +23,7 @@ #define WB_DST3_ADDR 0x018 #define WB_DST_YSTRIDE0 0x01C #define WB_DST_YSTRIDE1 0x020 +#define WB_TS_WR_CLIENT 0x040 #define WB_DST_WRITE_CONFIG 0x048 #define WB_OUT_SIZE 0x074 #define WB_ALPHA_X_VALUE 0x078 @@ -307,6 +308,11 @@ static void sde_hw_wb_setup_qos_lut(struct sde_hw_wb *ctx, if (cfg->danger_safe_en) qos_ctrl |= WB_QOS_CTRL_DANGER_SAFE_EN; + if (test_bit(SDE_WB_LINEAR_ROTATION, &ctx->caps->features)) { + SDE_REG_WRITE(c, WB_TS_WR_CLIENT, cfg->bytes_per_clk & 0xFF); + qos_ctrl |= (cfg->qos_mode << 1); + } + SDE_REG_WRITE(c, WB_QOS_CTRL, qos_ctrl); } diff --git a/msm/sde/sde_hw_wb.h b/msm/sde/sde_hw_wb.h index a2a6bbea4d..87c5400038 100644 --- a/msm/sde/sde_hw_wb.h +++ b/msm/sde/sde_hw_wb.h @@ -49,17 +49,31 @@ struct sde_hw_wb_cdp_cfg { u32 preload_ahead; }; +/** + * enum sde_hw_wb_qos_mode: enumeration of available QOS modes for WB + * @SDE_WB_QOS_MODE_STATIC: static qos mode same as existing NRT qos mode + * @SDE_WB_QOS_MODE_DYNAMIC: new qos mode to support rotation for real time + */ +enum sde_hw_wb_qos_mode { + SDE_WB_QOS_MODE_STATIC, + SDE_WB_QOS_MODE_DYNAMIC, +}; + /** * struct sde_hw_wb_qos_cfg : Writeback pipe QoS configuration * @danger_lut: LUT for generate danger level based on fill level * @safe_lut: LUT for generate safe level based on fill level * @creq_lut: LUT for generate creq level based on fill level + * @bytes_per_clk: WB output bytes per XO clock value used in rotation + * @qos_mode: enum value mapped for selecting WB QOS mode * @danger_safe_en: enable danger safe generation */ struct sde_hw_wb_qos_cfg { u32 danger_lut; u32 safe_lut; u64 creq_lut; + u32 bytes_per_clk; + enum sde_hw_wb_qos_mode qos_mode; bool danger_safe_en; }; diff --git a/msm/sde/sde_wb.c b/msm/sde/sde_wb.c index 741fd36b40..8bd5d3a37c 100644 --- a/msm/sde/sde_wb.c +++ b/msm/sde/sde_wb.c @@ -682,11 +682,15 @@ 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); - if (wb_dev->wb_cfg->features & BIT(SDE_WB_LINEAR_ROTATION)) + if (wb_dev->wb_cfg->features & BIT(SDE_WB_LINEAR_ROTATION)) { msm_property_install_enum(&c_conn->property_info, "wb_rotate_type", 0x0, 0, e_wb_rotate_type, ARRAY_SIZE(e_wb_rotate_type), 0, CONNECTOR_PROP_WB_ROT_TYPE); + msm_property_install_range(&c_conn->property_info, "wb_rot_bytes_per_clk", + 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_WB_ROT_BYTES_PER_CLK); + } + 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);