Merge "disp: msm: sde: enable WB rotation feature for pineapple target"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
03f6a06942
@@ -244,6 +244,8 @@ enum msm_mdp_conn_property {
|
||||
CONNECTOR_PROP_CACHE_STATE,
|
||||
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
|
||||
|
@@ -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};
|
||||
@@ -94,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;
|
||||
@@ -146,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;
|
||||
@@ -199,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;
|
||||
@@ -336,9 +348,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;
|
||||
@@ -358,6 +372,9 @@ static void _sde_enc_phys_wb_get_out_resolution(struct drm_crtc_state *crtc_stat
|
||||
*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 +486,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 +532,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 */
|
||||
@@ -803,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",
|
||||
@@ -849,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);
|
||||
@@ -966,6 +1006,138 @@ 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;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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",
|
||||
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 +1159,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 +1201,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 +1244,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 +1261,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);
|
||||
|
@@ -2550,6 +2550,11 @@ 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->rot_format_list = sde_cfg->wb_rot_formats;
|
||||
}
|
||||
|
||||
wb->format_list = sde_cfg->wb_formats;
|
||||
}
|
||||
|
||||
@@ -4665,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;
|
||||
@@ -4746,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;
|
||||
@@ -4766,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,
|
||||
@@ -4790,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:
|
||||
@@ -5234,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;
|
||||
@@ -5418,6 +5438,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);
|
||||
|
||||
|
@@ -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,
|
||||
@@ -1484,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
|
||||
@@ -1493,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;
|
||||
@@ -1864,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
|
||||
@@ -1982,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;
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -503,11 +503,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
|
||||
|
@@ -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
|
||||
@@ -200,6 +201,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) |
|
||||
@@ -300,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);
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ struct sde_hw_wb_cfg {
|
||||
struct sde_rect roi;
|
||||
struct sde_rect crop;
|
||||
bool is_secure;
|
||||
bool rotate_90;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -48,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;
|
||||
};
|
||||
|
||||
|
@@ -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",
|
||||
@@ -609,6 +621,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 +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)) {
|
||||
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);
|
||||
|
Reference in New Issue
Block a user