disp: msm: sde: add support for CWB ROI cropping feature
This change exposes capabilities for CWB ROI to userspace as well as implements the cropping feature which is now supported. Change-Id: Idf76727175bf7c183367be715eaa45f3a432640c Signed-off-by: Samantha Tran <samtran@codeaurora.org>
This commit is contained in:

committed by
Samantha Tran

parent
052949d046
commit
1e4664fcec
@@ -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);
|
||||
|
||||
|
@@ -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,7 +377,6 @@ 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);
|
||||
@@ -382,13 +385,25 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc,
|
||||
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 {
|
||||
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;
|
||||
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);
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user