From 4cca89d6155f5494463227a655e6427d6867c911 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 1 Jun 2022 01:10:29 -0700 Subject: [PATCH 1/6] disp: msm: sde: add drm properties required for wb rotation This change installs required drm properties for writeback connector to implement rotation with writeback hw in mdss. Change-Id: I85ed359d06ff4bafee85a4bfa5b8a99774311e60 Signed-off-by: Prabhanjan Kandula --- msm/msm_drv.h | 1 + msm/sde/sde_hw_catalog.c | 3 +++ msm/sde/sde_hw_catalog.h | 5 ++++- msm/sde/sde_hw_mdss.h | 16 ++++++++++++++++ msm/sde/sde_wb.c | 13 +++++++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 313e183f84..761020687b 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -243,6 +243,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_CACHE_STATE, CONNECTOR_PROP_DSC_MODE, CONNECTOR_PROP_WB_USAGE_TYPE, + CONNECTOR_PROP_WB_ROT_TYPE, /* total # of properties */ CONNECTOR_PROP_COUNT diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 9821a04831..ebc5f5be28 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2550,6 +2550,9 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) sde_cfg->mdp[0].clk_ctrls[wb->clk_ctrl].bit_off); } + if (test_bit(SDE_FEATURE_WB_ROTATION, sde_cfg->features)) + set_bit(SDE_WB_LINEAR_ROTATION, &wb->features); + wb->format_list = sde_cfg->wb_formats; } diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 90541b7fcc..0d7d5fe444 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -637,6 +637,7 @@ enum { * @SDE_WB_DCWB_CTRL Separate DCWB control is available for configuring * @SDE_WB_CWB_DITHER_CTRL CWB dither is available for configuring * @SDE_WB_PROG_LINE Writeback block supports programmable line ptr + * @SDE_WB_LINEAR_ROTATION Writeback block supports line mode image rotation * @SDE_WB_MAX maximum value */ enum { @@ -661,6 +662,7 @@ enum { SDE_WB_DCWB_CTRL, SDE_WB_CWB_DITHER_CTRL, SDE_WB_PROG_LINE, + SDE_WB_LINEAR_ROTATION, SDE_WB_MAX }; @@ -708,7 +710,7 @@ enum { * @SDE_FEATURE_CWB_DITHER CWB dither is supported * @SDE_FEATURE_DEDICATED_CWB Dedicated-CWB supported * @SDE_FEATURE_DUAL_DEDICATED_CWB Dual Dedicated-CWB supported - * @SDE_FEATURE_IDLE_PC Idle Power Collapse supported + * @SDE_FEATURE_WB_ROTATION Support for image rotation through WB block * @SDE_FEATURE_3D_MERGE_RESET 3D merge reset supported * @SDE_FEATURE_DECIMATION Decimation supported * @SDE_FEATURE_COMBINED_ALPHA Combined Alpha supported @@ -751,6 +753,7 @@ enum sde_mdss_features { SDE_FEATURE_CWB_DITHER, SDE_FEATURE_DEDICATED_CWB, SDE_FEATURE_DUAL_DEDICATED_CWB, + SDE_FEATURE_WB_ROTATION, SDE_FEATURE_IDLE_PC, SDE_FEATURE_3D_MERGE_RESET, SDE_FEATURE_DECIMATION, diff --git a/msm/sde/sde_hw_mdss.h b/msm/sde/sde_hw_mdss.h index 58e49ffcb7..25c7fe4a53 100644 --- a/msm/sde/sde_hw_mdss.h +++ b/msm/sde/sde_hw_mdss.h @@ -502,11 +502,27 @@ enum sde_sys_cache_state { * 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 + * WB_USAGE_ROT: WB connector used for image rotation for 2 pass composition */ enum sde_wb_usage_type { WB_USAGE_WFD, WB_USAGE_CWB, WB_USAGE_OFFLINE_WB, + WB_USAGE_ROT, +}; + +/** + * enum sde_wb_rot_type: Type of rotation use case of the WB connector + * WB_ROT_NONE : WB Rotation not in use + * WB_ROT_SINGLE: WB Rotation used in single job mode for full image rotation + * WB_ROT_JOB1: WB Rotation used for rotating half image as first-job + * WB_ROT_JOB2: WB Rotation used for rotating half image as second-job + */ +enum sde_wb_rot_type { + WB_ROT_NONE, + WB_ROT_SINGLE, + WB_ROT_JOB1, + WB_ROT_JOB2, }; /** struct sde_format - defines the format configuration which diff --git a/msm/sde/sde_wb.c b/msm/sde/sde_wb.c index 27a1537b57..0c27f1998a 100644 --- a/msm/sde/sde_wb.c +++ b/msm/sde/sde_wb.c @@ -609,6 +609,14 @@ int sde_wb_connector_post_init(struct drm_connector *connector, void *display) {WB_USAGE_WFD, "wb_usage_wfd"}, {WB_USAGE_CWB, "wb_usage_cwb"}, {WB_USAGE_OFFLINE_WB, "wb_usage_offline_wb"}, + {WB_USAGE_ROT, "wb_usage_rot"}, + }; + + static const struct drm_prop_enum_list e_wb_rotate_type[] = { + {WB_ROT_NONE, "wb_rot_none"}, + {WB_ROT_SINGLE, "wb_rot_single"}, + {WB_ROT_JOB1, "wb_rot_job1"}, + {WB_ROT_JOB2, "wb_rot_job2"}, }; if (!connector || !display || !wb_dev->wb_cfg || !wb_dev->drm_dev->dev_private) { @@ -662,6 +670,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); + 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_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); From f3c2c5e37dd86838594535d9d3e944aa2f135bab Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Tue, 26 Apr 2022 18:21:12 -0700 Subject: [PATCH 2/6] disp: msm: sde: add WB rotation output color formats MDSS 10.0.0 HW supports rotation of input image with writeback HW but output color formats are restricted to 32 bit uncompressed A5X tile formats. This change exposes the supported WB output color formats to client for WB rotation usecase. Change-Id: Ic52e6ee4ab882b7dad6edd0daa91b593afbcae01 Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_hw_catalog.c | 23 ++++++++++++++++++++--- msm/sde/sde_hw_catalog.h | 6 +++++- msm/sde/sde_hw_catalog_format.h | 12 ++++++++++++ msm/sde/sde_wb.c | 12 ++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index ebc5f5be28..0efa22e83c 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2550,8 +2550,10 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) sde_cfg->mdp[0].clk_ctrls[wb->clk_ctrl].bit_off); } - if (test_bit(SDE_FEATURE_WB_ROTATION, sde_cfg->features)) + if (test_bit(SDE_FEATURE_WB_ROTATION, sde_cfg->features)) { set_bit(SDE_WB_LINEAR_ROTATION, &wb->features); + wb->rot_format_list = sde_cfg->wb_rot_formats; + } wb->format_list = sde_cfg->wb_formats; } @@ -4668,7 +4670,7 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) { int rc = 0; - uint32_t dma_list_size, vig_list_size, wb2_list_size; + uint32_t dma_list_size, vig_list_size, wb2_list_size, wb_rot_fmt_list_size; uint32_t virt_vig_list_size, in_rot_list_size = 0; uint32_t index = 0; uint32_t in_rot_restricted_list_size = 0; @@ -4749,6 +4751,18 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, index = sde_copy_formats(sde_cfg->wb_formats, wb2_list_size, 0, wb2_formats, ARRAY_SIZE(wb2_formats)); + /* WB rotation output formats */ + wb_rot_fmt_list_size = ARRAY_SIZE(wb_rot_formats); + sde_cfg->wb_rot_formats = kcalloc(wb_rot_fmt_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->wb_rot_formats) { + rc = -ENOMEM; + goto free_wb; + } + + index = sde_copy_formats(sde_cfg->wb_rot_formats, wb_rot_fmt_list_size, + 0, wb_rot_formats, ARRAY_SIZE(wb_rot_formats)); + /* Rotation enabled input formats */ if (IS_SDE_INLINE_ROT_REV_100(sde_cfg->true_inline_rot_rev)) { inline_fmt_tbl = true_inline_rot_v1_fmts; @@ -4769,7 +4783,7 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, if (!sde_cfg->inline_rot_formats) { SDE_ERROR("failed to alloc inline rot format list\n"); rc = -ENOMEM; - goto free_wb; + goto free_wb_rot; } index = sde_copy_formats(sde_cfg->inline_rot_formats, @@ -4793,6 +4807,8 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, return 0; free_in_rot: kfree(sde_cfg->inline_rot_formats); +free_wb_rot: + kfree(sde_cfg->wb_rot_formats); free_wb: kfree(sde_cfg->wb_formats); free_virt: @@ -5421,6 +5437,7 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg) kfree(sde_cfg->dma_formats); kfree(sde_cfg->vig_formats); kfree(sde_cfg->wb_formats); + kfree(sde_cfg->wb_rot_formats); kfree(sde_cfg->virt_vig_formats); kfree(sde_cfg->inline_rot_formats); diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 0d7d5fe444..84cb0efd0a 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1487,7 +1487,8 @@ struct sde_intf_cfg { * @base register offset of this block * @features bit mask identifying sub-blocks/features * @sblk sub-block information - * @format_list: Pointer to list of supported formats + * @format_list: Pointer to list of supported output formats + * @rot_format_list: Pointer to list of supported output formats in WB rotation * @vbif_idx vbif identifier * @xin_id client interface identifier * @clk_ctrl clock control identifier @@ -1496,6 +1497,7 @@ struct sde_wb_cfg { SDE_HW_BLK_INFO; const struct sde_wb_sub_blocks *sblk; const struct sde_format_extended *format_list; + const struct sde_format_extended *rot_format_list; u32 vbif_idx; u32 xin_id; enum sde_clk_ctrl_type clk_ctrl; @@ -1867,6 +1869,7 @@ struct sde_perf_cfg { * @dma_formats supported formats for dma pipe * @vig_formats supported formats for vig pipe * @wb_formats supported formats for wb + * @wb_rot_formats supported output formats for wb rotation operation * @virt_vig_formats supported formats for virtual vig pipe * @inline_rot_formats supported formats for inline rotation * @inline_rot_restricted_formats restricted formats for inline rotation @@ -1985,6 +1988,7 @@ struct sde_mdss_cfg { struct sde_format_extended *dma_formats; struct sde_format_extended *vig_formats; struct sde_format_extended *wb_formats; + struct sde_format_extended *wb_rot_formats; struct sde_format_extended *virt_vig_formats; struct sde_format_extended *inline_rot_formats; struct sde_format_extended *inline_rot_restricted_formats; diff --git a/msm/sde/sde_hw_catalog_format.h b/msm/sde/sde_hw_catalog_format.h index caeb7fd6b3..063054ea68 100644 --- a/msm/sde/sde_hw_catalog_format.h +++ b/msm/sde/sde_hw_catalog_format.h @@ -94,6 +94,10 @@ static const struct sde_format_extended wb2_formats[] = { {DRM_FORMAT_ARGB8888, 0}, {DRM_FORMAT_RGBA8888, 0}, {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_TILE}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_TILE}, + {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_TILE}, + {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_TILE}, {DRM_FORMAT_XRGB8888, 0}, {DRM_FORMAT_RGBX8888, 0}, {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, @@ -131,6 +135,14 @@ static const struct sde_format_extended wb2_formats[] = { {0, 0}, }; +static const struct sde_format_extended wb_rot_formats[] = { + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_TILE}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_TILE}, + {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_TILE}, + {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_TILE}, + {0, 0}, +}; + static const struct sde_format_extended p010_ubwc_formats[] = { P010_UBWC_FMTS, }; diff --git a/msm/sde/sde_wb.c b/msm/sde/sde_wb.c index 0c27f1998a..741fd36b40 100644 --- a/msm/sde/sde_wb.c +++ b/msm/sde/sde_wb.c @@ -532,6 +532,18 @@ int sde_wb_connector_set_info_blob(struct drm_connector *connector, sde_kms_info_stop(info); } + /* Populate info buffer with WB rotation output formats */ + format_list = wb_dev->wb_cfg->rot_format_list; + if (format_list) { + sde_kms_info_start(info, "rot_output_formats"); + while (format_list->fourcc_format) { + sde_kms_info_append_format(info, format_list->fourcc_format, + format_list->modifier); + ++format_list; + } + sde_kms_info_stop(info); + } + sde_kms_info_add_keyint(info, "wb_intf_index", wb_dev->wb_idx - WB_0); sde_kms_info_add_keyint(info, "maxlinewidth", wb_dev->wb_cfg->sblk->maxlinewidth); sde_kms_info_add_keyint(info, "maxlinewidth_linear", From 3128214eac65018c958a7d8af82d726ac8a810e9 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Tue, 10 May 2022 11:47:22 -0700 Subject: [PATCH 3/6] disp: msm: sde: add rotation support with writeback block MDSS 10.0.0 HW is capable to rotate input image in WB hardware block. WB hardware can only perform rotation of clockwise 90 degrees and this can be used to achieve the required 2D rotation by adding appropriate FLIP transformation to the SSPP. This change adds required software support in display driver to excericse input image rotation through WB block. Change-Id: Ia5c2fc84eabb68f29d130333316527b60d02cbc7 Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_encoder_phys_wb.c | 197 ++++++++++++++++++++++++++++++---- msm/sde/sde_hw_wb.c | 7 ++ msm/sde/sde_hw_wb.h | 1 + 3 files changed, 185 insertions(+), 20 deletions(-) diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 81c00e4f75..6ebb5087a4 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -31,6 +31,13 @@ ((SDE_FORMAT_IS_UBWC(fmt) || SDE_FORMAT_IS_YUV(fmt)) ? wb_cfg->sblk->maxlinewidth : \ wb_cfg->sblk->maxlinewidth_linear) +/* a5x mini-tile width and height */ +#define MINI_TILE_W 4 +#define MINI_TILE_H 4 + +#define SDE_WB_ROT_MAX_SRCW 4096 +#define SDE_WB_ROT_MAX_SRCH 4096 + static const u32 cwb_irq_tbl[PINGPONG_MAX] = {SDE_NONE, INTR_IDX_PP1_OVFL, INTR_IDX_PP2_OVFL, INTR_IDX_PP3_OVFL, INTR_IDX_PP4_OVFL, INTR_IDX_PP5_OVFL, SDE_NONE, SDE_NONE}; @@ -336,9 +343,11 @@ static void _sde_enc_phys_wb_get_out_resolution(struct drm_crtc_state *crtc_stat const struct drm_display_mode *mode = &crtc_state->mode; struct sde_io_res ds_res = {0, }, dnsc_blur_res = {0, }; u32 ds_tap_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT); + enum sde_wb_rot_type rotation_type; sde_crtc_get_ds_io_res(crtc_state, &ds_res); sde_connector_get_dnsc_blur_io_res(conn_state, &dnsc_blur_res); + rotation_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_ROT_TYPE); if (dnsc_blur_res.enabled) { *out_width = dnsc_blur_res.dst_w; @@ -354,10 +363,13 @@ static void _sde_enc_phys_wb_get_out_resolution(struct drm_crtc_state *crtc_stat *out_width = mode->hdisplay; *out_height = mode->vdisplay; } - } else { + } else { *out_width = mode->hdisplay; *out_height = mode->vdisplay; } + + if (rotation_type != WB_ROT_NONE) + swap(*out_width, *out_height); } static void _sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc, @@ -469,9 +481,10 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, struct sde_hw_wb *hw_wb; struct sde_hw_wb_cfg *wb_cfg; const struct msm_format *format; - int ret; + enum sde_wb_rot_type rotation_type; struct msm_gem_address_space *aspace; u32 fb_mode; + int ret; if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog || !phys_enc->connector) { @@ -514,6 +527,17 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, return; } + rotation_type = sde_connector_get_property(phys_enc->connector->state, + CONNECTOR_PROP_WB_ROT_TYPE); + wb_cfg->rotate_90 = (rotation_type != WB_ROT_NONE); + + SDE_DEBUG("[enc:%d wb:%d] conn:%d rotation_type:%d format %4.4s and modifier 0x%llX\n", + DRMID(phys_enc->parent), WBID(wb_enc), DRMID(phys_enc->connector), + rotation_type, (char *)&format->pixel_format, fb->modifier); + + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), rotation_type, out_width, out_height, + fb->width, fb->height); + wb_cfg->dest.format = sde_get_sde_format_ext(format->pixel_format, fb->modifier); if (!wb_cfg->dest.format) { /* this error should be detected during atomic_check */ @@ -966,6 +990,130 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, return ret; } +static int _sde_encoder_phys_wb_validate_rotation(struct sde_encoder_phys *phys_enc, + struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) +{ + enum sde_wb_rot_type rotation_type; + int ret = 0; + u32 src_w, src_h; + 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; + 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; + + usage_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_USAGE_TYPE); + if (usage_type != WB_USAGE_ROT) { + SDE_ERROR("[enc:%d wb:%d] invalid WB usage_ype:%d for rotation_type:%d\n", + DRMID(phys_enc->parent), WBID(wb_enc), usage_type, rotation_type); + 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", + DRMID(phys_enc->parent), WBID(wb_enc), ret); + return ret; + } + + sde_crtc_get_crtc_roi(crtc_state, &crtc_roi); + if (!crtc_roi) { + SDE_ERROR("[enc:%d wb:%d] could not get crtc roi\n", + DRMID(phys_enc->parent), WBID(wb_enc)); + return -EINVAL; + } else if (!sde_kms_rect_is_null(crtc_roi)) { + SDE_ERROR("[enc:%d wb:%d] not supporting pu scenario on wb\n", + DRMID(phys_enc->parent), WBID(wb_enc)); + return -EINVAL; + } + + mode = &crtc_state->mode; + sde_crtc_get_resolution(crtc_state->crtc, crtc_state, mode, &src_w, &src_h); + if (!src_w || !src_h) { + SDE_ERROR("[enc:%d wb:%d] invalid wb input dimensions src_w:%d src_h:%d\n", + DRMID(phys_enc->parent), WBID(wb_enc), src_w, src_h); + return -EINVAL; + } + + sde_connector_get_dnsc_blur_io_res(conn_state, &dnsc_res); + wb_src.w = dnsc_res.enabled ? dnsc_res.dst_w : src_w; + wb_src.h = dnsc_res.enabled ? dnsc_res.dst_h : src_h; + + SDE_DEBUG("[enc:%d wb:%d] wb_src=[%dx%d] dnsc_dst=[%dx%d] wb_roi=[%dx%d]\n", + DRMID(phys_enc->parent), WBID(wb_enc), wb_src.w, wb_src.h, + dnsc_res.dst_w, dnsc_res.dst_h, wb_roi.w, wb_roi.h); + + if (((wb_src.w != wb_roi.h) || (wb_src.h != wb_roi.w))) { + SDE_ERROR("[enc:%d wb:%d] invalid dimension for rotation src:%dx%d vs out:%dx%d\n", + DRMID(phys_enc->parent), WBID(wb_enc), wb_src.w, wb_src.h, + wb_roi.w, wb_roi.h); + return -EINVAL; + } else if ((wb_roi.x % MINI_TILE_W) || (wb_roi.y % MINI_TILE_H)) { + SDE_ERROR("[enc:%d wb:%d] unaligned x,y offsets for rotation:%d x:%d y:%d\n", + DRMID(phys_enc->parent), WBID(wb_enc), rotation_type, + wb_roi.x, wb_roi.y); + return -EINVAL; + } else if ((rotation_type == WB_ROT_JOB1) && (wb_roi.h % MINI_TILE_H)) { + SDE_ERROR("[enc:%d wb:%d] job1 rotation height:%d is not tile aligned\n", + DRMID(phys_enc->parent), WBID(wb_enc), wb_roi.h); + return -EINVAL; + } else if (wb_src.w > SDE_WB_ROT_MAX_SRCW || wb_src.h > SDE_WB_ROT_MAX_SRCH) { + SDE_ERROR("[enc:%d wb:%d] rotate limit exceeded srcw:[%d vs %d], srch:[%d vs %d]\n", + DRMID(phys_enc->parent), WBID(wb_enc), wb_src.w, SDE_WB_ROT_MAX_SRCW, + wb_src.h, SDE_WB_ROT_MAX_SRCH); + return -EINVAL; + } + + return ret; +} + +static int _sde_encoder_phys_wb_validate_output_fmt(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb, enum sde_wb_rot_type rotation_type) +{ + int ret = 0; + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + const struct sde_format *fmt; + const struct sde_format_extended *format_list; + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + const struct sde_wb_cfg *wb_cfg = hw_wb->caps; + struct sde_kms *sde_kms = phys_enc->sde_kms; + + fmt = sde_get_sde_format_ext(fb->format->format, fb->modifier); + if (!fmt) { + SDE_ERROR("[enc:%d wb:%d] invalid output pixel format:0x%x mod:0x%x\n", + DRMID(phys_enc->parent), WBID(wb_enc), + fb->format->format, fb->modifier); + return -EINVAL; + } + + /* find if sde format is listed as supported format on WB */ + format_list = (rotation_type != WB_ROT_NONE) ? + wb_cfg->rot_format_list : wb_cfg->format_list; + + ret = sde_format_validate_fmt(&sde_kms->base, fmt, format_list); + if (ret) { + SDE_ERROR("[enc:%d wb:%d] unsupported format for wb rotate:%d fmt:0x%x mod:0x%x\n", + DRMID(phys_enc->parent), WBID(wb_enc), rotation_type, + fb->format->format, fb->modifier); + return ret; + } else if (fmt->chroma_sample == SDE_CHROMA_H2V1 || fmt->chroma_sample == SDE_CHROMA_H1V2) { + SDE_ERROR("[enc:%d wb:%d] invalid chroma sample type in output format:%x\n", + DRMID(phys_enc->parent), WBID(wb_enc), fmt->base.pixel_format); + return -EINVAL; + } else if (SDE_FORMAT_IS_UBWC(fmt) && !(wb_cfg->features & BIT(SDE_WB_UBWC))) { + SDE_ERROR("[enc:%d wb:%d] invalid output format:%x\n", + DRMID(phys_enc->parent), WBID(wb_enc), fmt->base.pixel_format); + return -EINVAL; + } + + return ret; +} + /** * sde_encoder_phys_wb_atomic_check - verify and fixup given atomic states * @phys_enc: Pointer to physical encoder @@ -987,6 +1135,7 @@ static int sde_encoder_phys_wb_atomic_check(struct sde_encoder_phys *phys_enc, const struct drm_display_mode *mode = &crtc_state->mode; int rc; bool clone_mode_curr = false; + enum sde_wb_rot_type rotation_type; SDE_DEBUG("[enc:%d wb:%d] atomic_check:\"%s\",%d,%d]\n", DRMID(phys_enc->parent), WBID(wb_enc), mode->name, mode->hdisplay, mode->vdisplay); @@ -1028,28 +1177,27 @@ static int sde_encoder_phys_wb_atomic_check(struct sde_encoder_phys *phys_enc, return -EINVAL; } + rotation_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_ROT_TYPE); + fmt = sde_get_sde_format_ext(fb->format->format, fb->modifier); if (!fmt) { - SDE_ERROR("[enc:%d wb:%d] unsupported output pixel format:%x\n", - DRMID(phys_enc->parent), WBID(wb_enc), fb->format->format); + SDE_ERROR("[enc:%d wb:%d] invalid output pixel format:0x%x mod:0x%x\n", + DRMID(phys_enc->parent), WBID(wb_enc), + fb->format->format, fb->modifier); return -EINVAL; } - SDE_DEBUG("[enc:%d enc:%d] fb_id:%u, wxh:%ux%u, fb_fmt:%x,%llx, roi:{%d,%d,%d,%d}\n", + SDE_DEBUG("[enc:%d wb:%d] fb_id:%u, wxh:%ux%u, fb_fmt:%x,%llx, roi:{%d,%d,%d,%d}, rot:%d\n", DRMID(phys_enc->parent), WBID(wb_enc), fb->base.id, fb->width, fb->height, - fb->format->format, fb->modifier, wb_roi.x, wb_roi.y, wb_roi.w, wb_roi.h); + fb->format->format, fb->modifier, wb_roi.x, wb_roi.y, wb_roi.w, wb_roi.h, + rotation_type); - if (fmt->chroma_sample == SDE_CHROMA_H2V1 || - fmt->chroma_sample == SDE_CHROMA_H1V2) { - SDE_ERROR("[enc:%d wb:%d] invalid chroma sample type in output format:%x\n", - DRMID(phys_enc->parent), WBID(wb_enc), fmt->base.pixel_format); - return -EINVAL; - } - - if (SDE_FORMAT_IS_UBWC(fmt) && !(wb_cfg->features & BIT(SDE_WB_UBWC))) { - SDE_ERROR("[enc:%d wb:%d] invalid output format:%x\n", - DRMID(phys_enc->parent), WBID(wb_enc), fmt->base.pixel_format); - return -EINVAL; + rc = _sde_encoder_phys_wb_validate_output_fmt(phys_enc, fb, rotation_type); + if (rc) { + SDE_ERROR("[enc:%d wb:%d] output fmt validation failed fb:%u fmt:0x%x mod:0x%x\n", + DRMID(phys_enc->parent), WBID(wb_enc), fb->base.id, + fb->format->format, fb->modifier, rotation_type); + return rc; } if (SDE_FORMAT_IS_YUV(fmt) != !!phys_enc->hw_cdm) @@ -1072,6 +1220,15 @@ static int sde_encoder_phys_wb_atomic_check(struct sde_encoder_phys *phys_enc, return rc; } + if (rotation_type != WB_ROT_NONE) { + rc = _sde_encoder_phys_wb_validate_rotation(phys_enc, crtc_state, conn_state); + if (rc) { + SDE_ERROR("[enc:%d wb:%d] failed in WB rotation validation %d\n", + DRMID(phys_enc->parent), WBID(wb_enc), rc); + return rc; + } + } + _sde_enc_phys_wb_get_out_resolution(crtc_state, conn_state, &out_width, &out_height); if (!wb_roi.w || !wb_roi.h) { wb_roi.x = 0; @@ -1080,17 +1237,17 @@ static int sde_encoder_phys_wb_atomic_check(struct sde_encoder_phys *phys_enc, wb_roi.h = out_height; } - if ((wb_roi.x + wb_roi.w > fb->width) || (wb_roi.x + wb_roi.w > out_width)) { + if ((wb_roi.x + wb_roi.w > fb->width) || (wb_roi.w > out_width)) { SDE_ERROR("[enc:%d wb:%d] invalid roi x:%d, w:%d, fb_w:%d, mode_w:%d, out_w:%d\n", DRMID(phys_enc->parent), WBID(wb_enc), wb_roi.x, wb_roi.w, fb->width, mode->hdisplay, out_width); return -EINVAL; - } else if ((wb_roi.y + wb_roi.h > fb->height) || (wb_roi.y + wb_roi.h > out_height)) { + } else if ((wb_roi.y + wb_roi.h > fb->height) || (wb_roi.h > out_height)) { SDE_ERROR("[enc:%d wb:%d] invalid roi y:%d, h:%d, fb_h:%d, mode_h%d, out_h:%d\n", DRMID(phys_enc->parent), WBID(wb_enc), wb_roi.y, wb_roi.h, fb->height, mode->vdisplay, out_height); return -EINVAL; - } else if ((out_width > mode->hdisplay) || (out_height > mode->vdisplay)) { + } else if ((rotation_type == WB_ROT_NONE) && ((out_width > mode->hdisplay) || (out_height > mode->vdisplay))) { SDE_ERROR("[enc:%d wb:%d] invalid o w/h o_w:%d, mode_w:%d, o_h:%d, mode_h:%d\n", DRMID(phys_enc->parent), WBID(wb_enc), out_width, mode->hdisplay, out_height, mode->vdisplay); diff --git a/msm/sde/sde_hw_wb.c b/msm/sde/sde_hw_wb.c index 42383b0c43..68199ca6ea 100644 --- a/msm/sde/sde_hw_wb.c +++ b/msm/sde/sde_hw_wb.c @@ -200,6 +200,13 @@ static void sde_hw_wb_setup_format(struct sde_hw_wb *ctx, if (SDE_FORMAT_IS_DX(fmt)) dst_format |= BIT(21); + /* Set A5x tile bit for uncompressed tile formats also */ + if (SDE_FORMAT_IS_TILE(fmt)) + dst_format |= BIT(31); + + if (data->rotate_90) + dst_format |= BIT(11); + pattern = (fmt->element[3] << 24) | (fmt->element[2] << 16) | (fmt->element[1] << 8) | diff --git a/msm/sde/sde_hw_wb.h b/msm/sde/sde_hw_wb.h index 0ace743978..a2a6bbea4d 100644 --- a/msm/sde/sde_hw_wb.h +++ b/msm/sde/sde_hw_wb.h @@ -22,6 +22,7 @@ struct sde_hw_wb_cfg { struct sde_rect roi; struct sde_rect crop; bool is_secure; + bool rotate_90; }; /** From c3991049c199efe8544f5df363327079cdcfd04c Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Thu, 23 Jun 2022 00:31:38 -0700 Subject: [PATCH 4/6] disp: msm: sde: add support for new QoS mode of WB rotation This change adds support for new dynamic QoS mode for WB rotation which is required to achieve rotation output available at required rate to meet real time use case. Though traffic shaper can be disabled in dynamic QoS mode, part of traffic shaper algo to track WB operating speed is enabled and WB generates creq priority based on current ouput rate compared to targetted ouput to help meeting real time use case requirement. Change-Id: I98c2dcae53f1b175dc49b40238b9da33e95717a6 Signed-off-by: Prabhanjan Kandula --- msm/msm_drv.h | 1 + msm/sde/sde_encoder_phys_wb.c | 23 ++++++++++++++++++----- msm/sde/sde_hw_wb.c | 6 ++++++ msm/sde/sde_hw_wb.h | 14 ++++++++++++++ msm/sde/sde_wb.c | 6 +++++- 5 files changed, 44 insertions(+), 6 deletions(-) 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); From bdfc560f6efc6b4bec3cb8d45ebe387abcbacafc Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Mon, 26 Sep 2022 12:15:09 -0700 Subject: [PATCH 5/6] disp: msm: sde: extend DNSC validation for wb rotate Atomic validation checks added for DNSC feature need to be extended considering WB rotate feature enable. Change-Id: Iff908da062280418536d00a5fcdeb99939267659 Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_encoder_phys_wb.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 7f5ab28002..6f28523541 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -832,13 +832,16 @@ static int _sde_enc_phys_wb_validate_dnsc_blur_ds(struct drm_crtc_state *crtc_st struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); const struct drm_display_mode *mode = &crtc_state->mode; struct sde_io_res ds_res = {0, }, dnsc_blur_res = {0, }; + enum sde_wb_rot_type rotation_type; u32 ds_tap_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT); sde_crtc_get_ds_io_res(crtc_state, &ds_res); sde_connector_get_dnsc_blur_io_res(conn_state, &dnsc_blur_res); + rotation_type = sde_connector_get_property(conn_state, CONNECTOR_PROP_WB_ROT_TYPE); /* wb_roi should match with mode w/h if none of these features are enabled */ - if ((!ds_res.enabled && !dnsc_blur_res.enabled && !cstate->cwb_enc_mask) + if ((rotation_type == WB_ROT_NONE) && + (!ds_res.enabled && !dnsc_blur_res.enabled && !cstate->cwb_enc_mask) && ((wb_roi->w && (wb_roi->w != mode->hdisplay)) || (wb_roi->h && (wb_roi->h != mode->vdisplay)))) { SDE_ERROR("invalid wb-roi {%u,%u,%u,%u} mode:%ux%u\n", @@ -878,8 +881,16 @@ static int _sde_enc_phys_wb_validate_dnsc_blur_ds(struct drm_crtc_state *crtc_st } else if (SDE_FORMAT_IS_YUV(fmt)) { SDE_ERROR("YUV output not supported with dnsc_blur\n"); return -EINVAL; - } else if ((wb_roi->w && (wb_roi->w != dnsc_blur_res.dst_w)) || - (wb_roi->h && (wb_roi->h != dnsc_blur_res.dst_h))) { + } else if ((rotation_type != WB_ROT_NONE) && + ((wb_roi->w && (wb_roi->w != dnsc_blur_res.dst_h)) || + (wb_roi->h && (wb_roi->h != dnsc_blur_res.dst_w)))) { + SDE_ERROR("invalid WB ROI for dnsc and rotate, roi:{%d,%d,%d,%d}, dnsc dst:%ux%u\n", + wb_roi->x, wb_roi->y, wb_roi->w, wb_roi->h, + dnsc_blur_res.dst_w, dnsc_blur_res.dst_h); + return -EINVAL; + } else if ((rotation_type == WB_ROT_NONE) && + ((wb_roi->w && (wb_roi->w != dnsc_blur_res.dst_w)) || + (wb_roi->h && (wb_roi->h != dnsc_blur_res.dst_h)))) { SDE_ERROR("invalid WB ROI with dnsc_blur, roi:{%d,%d,%d,%d}, dnsc_blur dst:%ux%u\n", wb_roi->x, wb_roi->y, wb_roi->w, wb_roi->h, dnsc_blur_res.dst_w, dnsc_blur_res.dst_h); From 973fb33096b66d8a94662684c21825d303c61b74 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Fri, 14 Oct 2022 15:04:32 -0700 Subject: [PATCH 6/6] disp: msm: sde: enable WB rotation feature for pineapple target This change enables the WB rotation feature support for pineapple target. Change-Id: Ib222c2b2996a40c72414c6c3a581916b95ebffd6 Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_hw_catalog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 0efa22e83c..592bf0eb06 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -5253,6 +5253,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) set_bit(SDE_FEATURE_TRUSTED_VM, sde_cfg->features); set_bit(SDE_SYS_CACHE_DISP, sde_cfg->sde_sys_cache_type_map); set_bit(SDE_SYS_CACHE_DISP_WB, sde_cfg->sde_sys_cache_type_map); + set_bit(SDE_FEATURE_WB_ROTATION, sde_cfg->features); sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH; sde_cfg->autorefresh_disable_seq = AUTOREFRESH_DISABLE_SEQ2; sde_cfg->perf.min_prefill_lines = 40;