diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index dc519fa9b2..90f551309d 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2592,6 +2592,10 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn, continue; } + sde_kms_info_add_keyint(info, "has_cwb_crop", sde_kms->catalog->has_cwb_crop); + sde_kms_info_add_keyint(info, "has_dedicated_cwb_support", + sde_kms->catalog->has_dedicated_cwb_support); + sde_kms_info_add_keyint(info, "mdp_transfer_time_us", mode_info.mdp_transfer_time_us); diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 6f4b15b105..e49ad684aa 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -314,6 +314,8 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, struct sde_hw_wb_cfg *wb_cfg; struct sde_hw_wb_cdp_cfg *cdp_cfg; const struct msm_format *format; + struct sde_crtc_state *cstate; + struct sde_rect pu_roi = {0,}; int ret; struct msm_gem_address_space *aspace; u32 fb_mode; @@ -324,6 +326,8 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, return; } + cstate = to_sde_crtc_state(wb_enc->crtc->state); + hw_wb = wb_enc->hw_wb; wb_cfg = &wb_enc->wb_cfg; cdp_cfg = &wb_enc->cdp_cfg; @@ -373,22 +377,33 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, } wb_cfg->roi = *wb_roi; - if (hw_wb->caps->features & BIT(SDE_WB_XY_ROI_OFFSET)) { - ret = sde_format_populate_layout(aspace, fb, &wb_cfg->dest); - if (ret) { - SDE_DEBUG("failed to populate layout %d\n", ret); - return; - } - wb_cfg->dest.width = fb->width; - wb_cfg->dest.height = fb->height; - wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes; - } else { - ret = sde_format_populate_layout_with_roi(aspace, fb, wb_roi, - &wb_cfg->dest); - if (ret) { - /* this error should be detected during atomic_check */ - SDE_DEBUG("failed to populate layout %d\n", ret); - return; + ret = sde_format_populate_layout(aspace, fb, &wb_cfg->dest); + if (ret) { + SDE_DEBUG("failed to populate layout %d\n", ret); + return; + } + wb_cfg->dest.width = fb->width; + wb_cfg->dest.height = fb->height; + wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes; + + if (hw_wb->ops.setup_crop) { + wb_cfg->crop.x = wb_cfg->roi.x; + wb_cfg->crop.y = wb_cfg->roi.y; + + if (cstate->user_roi_list.num_rects) { + sde_kms_rect_merge_rectangles(&cstate->user_roi_list, &pu_roi); + + if ((wb_cfg->roi.w != pu_roi.w) || (wb_cfg->roi.h != pu_roi.h)) { + /* offset cropping region to PU region */ + wb_cfg->crop.x = wb_cfg->crop.x - pu_roi.x; + wb_cfg->crop.y = wb_cfg->crop.y - pu_roi.y; + hw_wb->ops.setup_crop(hw_wb, wb_cfg, true); + } + } else if ((wb_cfg->roi.w != wb_cfg->dest.width) || + (wb_cfg->roi.h != wb_cfg->dest.height)) { + hw_wb->ops.setup_crop(hw_wb, wb_cfg, true); + } else { + hw_wb->ops.setup_crop(hw_wb, wb_cfg, false); } } @@ -467,8 +482,8 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc, hw_ctl = crtc->mixers[0].hw_ctl; if (hw_ctl && hw_ctl->ops.setup_intf_cfg_v1 && - test_bit(SDE_WB_CWB_CTRL | SDE_WB_DCWB_CTRL, - &hw_wb->caps->features)) { + (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features) || + test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features))) { struct sde_hw_intf_cfg_v1 intf_cfg = { 0, }; for (i = 0; i < crtc->num_mixers; i++) @@ -621,6 +636,7 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, struct sde_rect pu_roi = {0,}; int out_width = 0, out_height = 0; int ds_srcw = 0, ds_srch = 0, ds_outw = 0, ds_outh = 0; + const struct sde_format *fmt; int data_pt; int ds_in_use = false; int i = 0; @@ -632,6 +648,12 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, return 0; } + fmt = sde_get_sde_format_ext(fb->format->format, fb->modifier); + if (!fmt) { + SDE_ERROR("unsupported output pixel format:%x\n", fb->format->format); + return -EINVAL; + } + ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); if (ret) { SDE_ERROR("failed to get roi %d\n", ret); @@ -672,6 +694,10 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, * 2.2) DSPP Tap point: same as No DS case * a) wb-roi should be inside FB * b) mode resolution & wb-roi should be same + * 3) Partial Update case: additional stride check + * a) cwb roi should be inside PU region or FB + * b) cropping is only allowed for fully sampled data + * c) add check for stride and QOS setting by 256B */ if (ds_in_use && data_pt == CAPTURE_DSPP_OUT) { out_width = ds_outw; @@ -684,9 +710,23 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, out_height = mode->vdisplay; } - if ((wb_roi.w != out_width) || (wb_roi.h != out_height)) { + if (SDE_FORMAT_IS_YUV(fmt) && ((wb_roi.w != out_width) || (wb_roi.h != out_height))) { + SDE_ERROR("invalid wb roi[%dx%d] with ds_use:%d out[%dx%d] fmt:%x\n", + wb_roi.w, wb_roi.h, ds_in_use, out_width, out_height, + fmt->base.pixel_format); + return -EINVAL; + } + + if ((wb_roi.w > out_width) || (wb_roi.h > out_height)) { SDE_ERROR("invalid wb roi[%dx%d] with ds_use:%d out[%dx%d]\n", - wb_roi.w, wb_roi.h, out_width, out_height); + wb_roi.w, wb_roi.h, ds_in_use, out_width, out_height); + return -EINVAL; + } + + if (((wb_roi.w < out_width) || (wb_roi.h < out_height)) && + (wb_roi.w * wb_roi.h * fmt->bpp) % 256) { + SDE_ERROR("invalid stride w = %d h = %d bpp =%d out_width = %d, out_height = %d\n", + wb_roi.w, wb_roi.h, fmt->bpp, out_width, out_height); return -EINVAL; } @@ -701,7 +741,7 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, /* validate wb roi against pu rect */ if (cstate->user_roi_list.num_rects) { sde_kms_rect_merge_rectangles(&cstate->user_roi_list, &pu_roi); - if (wb_roi.w != pu_roi.w || wb_roi.h != pu_roi.h) { + if (wb_roi.w > pu_roi.w || wb_roi.h > pu_roi.h) { SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n", wb_roi.w, wb_roi.h, pu_roi.w, pu_roi.h); return -EINVAL; @@ -927,8 +967,8 @@ static void _sde_encoder_phys_wb_update_cwb_flush( hw_ctl->ops.update_bitmask(hw_ctl, SDE_HW_FLUSH_CDM, hw_cdm->idx, 1); - if (test_bit(SDE_WB_CWB_CTRL | SDE_WB_DCWB_CTRL, - &hw_wb->caps->features)) { + if (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features) || + test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features)) { for (i = 0; i < crtc->num_mixers; i++) { src_pp_idx = (enum sde_cwb) (src_pp_idx + i); diff --git a/msm/sde/sde_formats.c b/msm/sde/sde_formats.c index 56b1e46f43..9f4e82325d 100644 --- a/msm/sde/sde_formats.c +++ b/msm/sde/sde_formats.c @@ -1146,69 +1146,6 @@ int sde_format_populate_layout( return ret; } -static void _sde_format_calc_offset_linear(struct sde_hw_fmt_layout *source, - u32 x, u32 y) -{ - if ((x == 0) && (y == 0)) - return; - - source->plane_addr[0] += y * source->plane_pitch[0]; - - if (source->num_planes == 1) { - source->plane_addr[0] += x * source->format->bpp; - } else { - uint32_t xoff, yoff; - uint32_t v_subsample = 1; - uint32_t h_subsample = 1; - - _sde_get_v_h_subsample_rate(source->format->chroma_sample, - &v_subsample, &h_subsample); - - xoff = x / h_subsample; - yoff = y / v_subsample; - - source->plane_addr[0] += x; - source->plane_addr[1] += xoff + - (yoff * source->plane_pitch[1]); - if (source->num_planes == 2) /* pseudo planar */ - source->plane_addr[1] += xoff; - else /* planar */ - source->plane_addr[2] += xoff + - (yoff * source->plane_pitch[2]); - } -} - -int sde_format_populate_layout_with_roi( - struct msm_gem_address_space *aspace, - struct drm_framebuffer *fb, - struct sde_rect *roi, - struct sde_hw_fmt_layout *layout) -{ - int ret; - - ret = sde_format_populate_layout(aspace, fb, layout); - if (ret || !roi) - return ret; - - if (!roi->w || !roi->h || (roi->x + roi->w > fb->width) || - (roi->y + roi->h > fb->height)) { - DRM_ERROR("invalid roi=[%d,%d,%d,%d], fb=[%u,%u]\n", - roi->x, roi->y, roi->w, roi->h, - fb->width, fb->height); - ret = -EINVAL; - } else if (SDE_FORMAT_IS_LINEAR(layout->format)) { - _sde_format_calc_offset_linear(layout, roi->x, roi->y); - layout->width = roi->w; - layout->height = roi->h; - } else if (roi->x || roi->y || (roi->w != fb->width) || - (roi->h != fb->height)) { - DRM_ERROR("non-linear layout with roi not supported\n"); - ret = -EINVAL; - } - - return ret; -} - int sde_format_check_modified_format( const struct msm_kms *kms, const struct msm_format *msm_fmt, diff --git a/msm/sde/sde_formats.h b/msm/sde/sde_formats.h index 3c47172b87..ddb907dbc9 100644 --- a/msm/sde/sde_formats.h +++ b/msm/sde/sde_formats.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, 2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_FORMATS_H @@ -108,22 +108,6 @@ int sde_format_populate_layout( struct drm_framebuffer *fb, struct sde_hw_fmt_layout *fmtl); -/** - * sde_format_populate_layout_with_roi - populate the given format layout - * based on mmu, fb, roi, and format found in the fb - * @aspace: address space pointer - * @fb: framebuffer pointer - * @roi: region of interest (optional) - * @fmtl: format layout structure to populate - * - * Return: error code on failure, 0 on success - */ -int sde_format_populate_layout_with_roi( - struct msm_gem_address_space *aspace, - struct drm_framebuffer *fb, - struct sde_rect *roi, - struct sde_hw_fmt_layout *fmtl); - /** * sde_format_get_framebuffer_size - get framebuffer memory size * @format: DRM pixel format diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index f4da11486e..fc4d64b2e4 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2530,6 +2530,9 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) if (sde_cfg->has_wb_ubwc) set_bit(SDE_WB_UBWC, &wb->features); + if (sde_cfg->has_cwb_crop) + set_bit(SDE_WB_CROP, &wb->features); + set_bit(SDE_WB_XY_ROI_OFFSET, &wb->features); if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) @@ -5038,6 +5041,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) } else if (IS_WAIPIO_TARGET(hw_rev)) { sde_cfg->has_dedicated_cwb_support = true; sde_cfg->has_wb_ubwc = true; + sde_cfg->has_cwb_crop = true; sde_cfg->has_qsync = true; sde_cfg->perf.min_prefill_lines = 40; sde_cfg->vbif_qos_nlvl = 8; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index d0dd3212fa..0c67b9a37e 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -528,6 +528,7 @@ enum { * data arrives. * @SDE_WB_HAS_CWB Writeback block supports concurrent writeback * @SDE_WB_HAS_DCWB Writeback block supports dedicated CWB + * @SDE_WB_CROP CWB supports cropping * @SDE_WB_CWB_CTRL Separate CWB control is available for configuring * @SDE_WB_DCWB_CTRL Separate DCWB control is available for configuring * @SDE_WB_MAX maximum value @@ -551,6 +552,7 @@ enum { SDE_WB_INPUT_CTRL, SDE_WB_HAS_CWB, SDE_WB_HAS_DCWB, + SDE_WB_CROP, SDE_WB_CWB_CTRL, SDE_WB_DCWB_CTRL, SDE_WB_MAX @@ -1447,6 +1449,7 @@ struct sde_perf_cfg { * @has_src_split source split feature status * @has_cdp Client driven prefetch feature status * @has_wb_ubwc UBWC feature supported on WB + * @has_cwb_crop CWB cropping is supported * @has_cwb_support indicates if device supports primary capture through CWB * @has_dedicated_cwb_support indicates if device supports dedicated path for CWB capture * @cwb_blk_off CWB offset address @@ -1530,6 +1533,7 @@ struct sde_mdss_cfg { bool has_cdp; bool has_dim_layer; bool has_wb_ubwc; + bool has_cwb_crop; bool has_cwb_support; bool has_dedicated_cwb_support; u32 cwb_blk_off; diff --git a/msm/sde/sde_hw_wb.c b/msm/sde/sde_hw_wb.c index 8a8b65a5e2..2715797698 100644 --- a/msm/sde/sde_hw_wb.c +++ b/msm/sde/sde_hw_wb.c @@ -42,6 +42,8 @@ #define WB_CREQ_LUT_1 0x09C #define WB_UBWC_STATIC_CTRL 0x144 #define WB_MUX 0x150 +#define WB_CROP_CTRL 0x154 +#define WB_CROP_OFFSET 0x158 #define WB_CSC_BASE 0x260 #define WB_DST_ADDR_SW_STATUS 0x2B0 #define WB_CDP_CNTL 0x2B4 @@ -233,6 +235,21 @@ static void sde_hw_wb_roi(struct sde_hw_wb *ctx, struct sde_hw_wb_cfg *wb) SDE_REG_WRITE(c, WB_OUT_SIZE, out_size); } +static void sde_hw_wb_crop(struct sde_hw_wb *ctx, struct sde_hw_wb_cfg *wb, bool crop) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 crop_xy; + + crop_xy = (wb->crop.y << 16) | wb->crop.x; + + if (crop) { + SDE_REG_WRITE(c, WB_CROP_CTRL, 0x1); + SDE_REG_WRITE(c, WB_CROP_OFFSET, crop_xy); + } else { + SDE_REG_WRITE(c, WB_CROP_CTRL, 0x0); + } +} + static void sde_hw_wb_setup_qos_lut(struct sde_hw_wb *ctx, struct sde_hw_wb_qos_cfg *cfg) { @@ -366,6 +383,9 @@ static void _setup_wb_ops(struct sde_hw_wb_ops *ops, if (test_bit(SDE_WB_XY_ROI_OFFSET, &features)) ops->setup_roi = sde_hw_wb_roi; + if (test_bit(SDE_WB_CROP, &features)) + ops->setup_crop = sde_hw_wb_crop; + if (test_bit(SDE_WB_QOS, &features)) ops->setup_qos_lut = sde_hw_wb_setup_qos_lut; diff --git a/msm/sde/sde_hw_wb.h b/msm/sde/sde_hw_wb.h index 34485fb3f3..61ced9c939 100644 --- a/msm/sde/sde_hw_wb.h +++ b/msm/sde/sde_hw_wb.h @@ -17,6 +17,7 @@ struct sde_hw_wb_cfg { struct sde_hw_fmt_layout dest; enum sde_intf_mode intf_mode; struct sde_rect roi; + struct sde_rect crop; bool is_secure; }; @@ -88,6 +89,9 @@ struct sde_hw_wb_ops { void (*setup_roi)(struct sde_hw_wb *ctx, struct sde_hw_wb_cfg *wb); + void (*setup_crop)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb, bool crop); + /** * setup_qos_lut - setup danger, safe, creq, etc. LUTs * @ctx: Pointer to pipe context