disp: msm: sde: add support for hardware based rounded corner
Add support for hardware based rounded corner part of color processing framework. Change-Id: I3e5f4dac6ffc759bb940215b7621ac716f255169 Signed-off-by: Amine Najahi <anajahi@codeaurora.org> Signed-off-by: Steve Cohen <cohens@codeaurora.org>
This commit is contained in:

committed by
Steve Cohen

parent
818651c2f1
commit
af07b8a5d4
@@ -76,6 +76,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
|
|||||||
sde/sde_hw_qdss.o \
|
sde/sde_hw_qdss.o \
|
||||||
sde_dsc_helper.o \
|
sde_dsc_helper.o \
|
||||||
sde_vdc_helper.o \
|
sde_vdc_helper.o \
|
||||||
|
sde/sde_hw_rc.o \
|
||||||
|
|
||||||
msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \
|
msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \
|
||||||
sde/sde_encoder_phys_wb.o \
|
sde/sde_encoder_phys_wb.o \
|
||||||
|
@@ -56,6 +56,8 @@ static void dspp_ad_install_property(struct drm_crtc *crtc);
|
|||||||
|
|
||||||
static void dspp_ltm_install_property(struct drm_crtc *crtc);
|
static void dspp_ltm_install_property(struct drm_crtc *crtc);
|
||||||
|
|
||||||
|
static void dspp_rc_install_property(struct drm_crtc *crtc);
|
||||||
|
|
||||||
static void dspp_vlut_install_property(struct drm_crtc *crtc);
|
static void dspp_vlut_install_property(struct drm_crtc *crtc);
|
||||||
|
|
||||||
static void dspp_gamut_install_property(struct drm_crtc *crtc);
|
static void dspp_gamut_install_property(struct drm_crtc *crtc);
|
||||||
@@ -112,6 +114,7 @@ do { \
|
|||||||
func[SDE_DSPP_IGC] = dspp_igc_install_property; \
|
func[SDE_DSPP_IGC] = dspp_igc_install_property; \
|
||||||
func[SDE_DSPP_HIST] = dspp_hist_install_property; \
|
func[SDE_DSPP_HIST] = dspp_hist_install_property; \
|
||||||
func[SDE_DSPP_DITHER] = dspp_dither_install_property; \
|
func[SDE_DSPP_DITHER] = dspp_dither_install_property; \
|
||||||
|
func[SDE_DSPP_RC] = dspp_rc_install_property; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
|
typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
|
||||||
@@ -160,6 +163,7 @@ enum sde_cp_crtc_features {
|
|||||||
SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3,
|
SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3,
|
||||||
SDE_CP_CRTC_DSPP_LTM_VLUT,
|
SDE_CP_CRTC_DSPP_LTM_VLUT,
|
||||||
SDE_CP_CRTC_DSPP_SB,
|
SDE_CP_CRTC_DSPP_SB,
|
||||||
|
SDE_CP_CRTC_DSPP_RC_MASK,
|
||||||
SDE_CP_CRTC_DSPP_MAX,
|
SDE_CP_CRTC_DSPP_MAX,
|
||||||
/* DSPP features end */
|
/* DSPP features end */
|
||||||
|
|
||||||
@@ -172,11 +176,15 @@ enum sde_cp_crtc_features {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum sde_cp_crtc_pu_features {
|
enum sde_cp_crtc_pu_features {
|
||||||
|
SDE_CP_CRTC_DSPP_RC_PU,
|
||||||
SDE_CP_CRTC_MAX_PU_FEATURES,
|
SDE_CP_CRTC_MAX_PU_FEATURES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum sde_cp_crtc_pu_features
|
static enum sde_cp_crtc_pu_features
|
||||||
sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES];
|
sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES] = {
|
||||||
|
[SDE_CP_CRTC_DSPP_RC_PU] =
|
||||||
|
(enum sde_cp_crtc_pu_features) SDE_CP_CRTC_DSPP_RC_MASK,
|
||||||
|
};
|
||||||
|
|
||||||
static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc);
|
static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc);
|
||||||
|
|
||||||
@@ -672,10 +680,122 @@ static int set_ltm_hist_crtl_feature(struct sde_hw_dspp *hw_dspp,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_rc_mask_feature(struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
struct sde_crtc *sde_crtc)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg || !sde_crtc) {
|
||||||
|
DRM_ERROR("invalid arguments");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hw_dspp->ops.validate_rc_mask) {
|
||||||
|
DRM_ERROR("invalid rc ops");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hw_dspp->ops.validate_rc_mask(hw_dspp, hw_cfg);
|
||||||
|
if (ret)
|
||||||
|
DRM_ERROR("failed to validate rc mask %d", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_rc_mask_feature(struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
struct sde_crtc *sde_crtc)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg || !sde_crtc) {
|
||||||
|
DRM_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hw_dspp->ops.setup_rc_mask || !hw_dspp->ops.setup_rc_data) {
|
||||||
|
DRM_ERROR("invalid rc ops\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("dspp %d setup mask for rc instance %u\n",
|
||||||
|
hw_dspp->idx, hw_dspp->cap->sblk->rc.idx);
|
||||||
|
|
||||||
|
ret = hw_dspp->ops.setup_rc_mask(hw_dspp, hw_cfg);
|
||||||
|
if (ret) {
|
||||||
|
DRM_ERROR("failed to setup rc mask, ret %d\n", ret);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rc data should be programmed once if dspp are in multi-pipe mode */
|
||||||
|
if (hw_dspp->cap->sblk->rc.idx % hw_cfg->num_of_mixers == 0) {
|
||||||
|
ret = hw_dspp->ops.setup_rc_data(hw_dspp, hw_cfg);
|
||||||
|
if (ret) {
|
||||||
|
DRM_ERROR("failed to setup rc data, ret %d\n", ret);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_rc_pu_feature(struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
struct sde_crtc *sde_crtc)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg || !sde_crtc) {
|
||||||
|
DRM_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hw_dspp->ops.setup_rc_pu_roi) {
|
||||||
|
DRM_ERROR("invalid rc ops\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("dspp %d setup pu roi for rc instance %u\n",
|
||||||
|
hw_dspp->idx, hw_dspp->cap->sblk->rc.idx);
|
||||||
|
|
||||||
|
ret = hw_dspp->ops.setup_rc_pu_roi(hw_dspp, hw_cfg);
|
||||||
|
if (ret < 0)
|
||||||
|
DRM_ERROR("failed to setup rc pu roi, ret %d\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_rc_pu_feature(struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
struct sde_crtc *sde_crtc)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg || !sde_crtc) {
|
||||||
|
DRM_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hw_dspp->ops.validate_rc_pu_roi) {
|
||||||
|
SDE_ERROR("invalid rc ops");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hw_dspp->ops.validate_rc_pu_roi(hw_dspp, hw_cfg);
|
||||||
|
if (ret)
|
||||||
|
SDE_ERROR("failed to validate rc pu roi, ret %d", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
|
feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
|
||||||
#define setup_check_crtc_feature_wrappers(wrappers) \
|
#define setup_check_crtc_feature_wrappers(wrappers) \
|
||||||
memset(wrappers, 0, sizeof(wrappers))
|
do { \
|
||||||
|
memset(wrappers, 0, sizeof(wrappers)); \
|
||||||
|
wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = check_rc_mask_feature; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
|
feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
|
||||||
#define setup_set_crtc_feature_wrappers(wrappers) \
|
#define setup_set_crtc_feature_wrappers(wrappers) \
|
||||||
@@ -718,15 +838,22 @@ do { \
|
|||||||
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = set_ltm_queue_buf_feature; \
|
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = set_ltm_queue_buf_feature; \
|
||||||
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = set_ltm_queue_buf_feature; \
|
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = set_ltm_queue_buf_feature; \
|
||||||
wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \
|
wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \
|
||||||
|
wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = set_rc_mask_feature; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES];
|
feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES];
|
||||||
#define setup_set_crtc_pu_feature_wrappers(wrappers) \
|
#define setup_set_crtc_pu_feature_wrappers(wrappers) \
|
||||||
memset(wrappers, 0, sizeof(wrappers))
|
do { \
|
||||||
|
memset(wrappers, 0, sizeof(wrappers)); \
|
||||||
|
wrappers[SDE_CP_CRTC_DSPP_RC_PU] = set_rc_pu_feature; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
feature_wrapper check_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES];
|
feature_wrapper check_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES];
|
||||||
#define setup_check_crtc_pu_feature_wrappers(wrappers) \
|
#define setup_check_crtc_pu_feature_wrappers(wrappers) \
|
||||||
memset(wrappers, 0, sizeof(wrappers))
|
do { \
|
||||||
|
memset(wrappers, 0, sizeof(wrappers)); \
|
||||||
|
wrappers[SDE_CP_CRTC_DSPP_RC_PU] = check_rc_pu_feature; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
|
#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
|
||||||
do { \
|
do { \
|
||||||
@@ -1372,6 +1499,7 @@ static const int dspp_feature_to_sub_blk_tbl[SDE_CP_CRTC_MAX_FEATURES] = {
|
|||||||
[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = SDE_DSPP_LTM,
|
[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = SDE_DSPP_LTM,
|
||||||
[SDE_CP_CRTC_DSPP_LTM_VLUT] = SDE_DSPP_LTM,
|
[SDE_CP_CRTC_DSPP_LTM_VLUT] = SDE_DSPP_LTM,
|
||||||
[SDE_CP_CRTC_DSPP_SB] = SDE_DSPP_SB,
|
[SDE_CP_CRTC_DSPP_SB] = SDE_DSPP_SB,
|
||||||
|
[SDE_CP_CRTC_DSPP_RC_MASK] = SDE_DSPP_RC,
|
||||||
[SDE_CP_CRTC_DSPP_MAX] = SDE_DSPP_MAX,
|
[SDE_CP_CRTC_DSPP_MAX] = SDE_DSPP_MAX,
|
||||||
[SDE_CP_CRTC_LM_GC] = SDE_DSPP_MAX,
|
[SDE_CP_CRTC_LM_GC] = SDE_DSPP_MAX,
|
||||||
};
|
};
|
||||||
@@ -2391,6 +2519,36 @@ static void dspp_ltm_install_property(struct drm_crtc *crtc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dspp_rc_install_property(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
char feature_name[256];
|
||||||
|
struct sde_kms *kms = NULL;
|
||||||
|
struct sde_mdss_cfg *catalog = NULL;
|
||||||
|
u32 version;
|
||||||
|
|
||||||
|
if (!crtc) {
|
||||||
|
DRM_ERROR("invalid arguments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kms = get_kms(crtc);
|
||||||
|
catalog = kms->catalog;
|
||||||
|
version = catalog->dspp[0].sblk->rc.version >> 16;
|
||||||
|
switch (version) {
|
||||||
|
case 1:
|
||||||
|
snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
|
||||||
|
"SDE_DSPP_RC_MASK_V", version);
|
||||||
|
sde_cp_crtc_install_blob_property(crtc, feature_name,
|
||||||
|
SDE_CP_CRTC_DSPP_RC_MASK,
|
||||||
|
sizeof(struct drm_msm_rc_mask_cfg));
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("version %d not supported\n", version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void lm_gc_install_property(struct drm_crtc *crtc)
|
static void lm_gc_install_property(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
char feature_name[256];
|
char feature_name[256];
|
||||||
|
@@ -755,6 +755,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sde_kms_rect_merge_rectangles(&sde_conn_state->rois, &conn_roi);
|
sde_kms_rect_merge_rectangles(&sde_conn_state->rois, &conn_roi);
|
||||||
|
SDE_DEBUG("conn_roi x:%u, y:%u, w:%u, h:%u\n",
|
||||||
|
conn_roi.x, conn_roi.y,
|
||||||
|
conn_roi.w, conn_roi.h);
|
||||||
SDE_EVT32_VERBOSE(DRMID(crtc), DRMID(conn),
|
SDE_EVT32_VERBOSE(DRMID(crtc), DRMID(conn),
|
||||||
conn_roi.x, conn_roi.y,
|
conn_roi.x, conn_roi.y,
|
||||||
conn_roi.w, conn_roi.h);
|
conn_roi.w, conn_roi.h);
|
||||||
@@ -5003,8 +5006,13 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
|
|||||||
sde_crtc_install_dest_scale_properties(sde_crtc, catalog,
|
sde_crtc_install_dest_scale_properties(sde_crtc, catalog,
|
||||||
info);
|
info);
|
||||||
|
|
||||||
|
if (catalog->dspp_count && catalog->rc_count)
|
||||||
|
sde_kms_info_add_keyint(info, "rc_mem_size",
|
||||||
|
catalog->dspp[0].sblk->rc.mem_total_size);
|
||||||
|
|
||||||
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
|
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
|
||||||
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
|
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
|
||||||
|
|
||||||
msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info,
|
msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info,
|
||||||
info->data, SDE_KMS_INFO_DATALEN(info),
|
info->data, SDE_KMS_INFO_DATALEN(info),
|
||||||
CRTC_PROP_INFO);
|
CRTC_PROP_INFO);
|
||||||
|
@@ -383,6 +383,14 @@ enum {
|
|||||||
LTM_PROP_MAX,
|
LTM_PROP_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RC_OFF,
|
||||||
|
RC_LEN,
|
||||||
|
RC_VERSION,
|
||||||
|
RC_MEM_TOTAL_SIZE,
|
||||||
|
RC_PROP_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MIXER_OFF,
|
MIXER_OFF,
|
||||||
MIXER_LEN,
|
MIXER_LEN,
|
||||||
@@ -699,6 +707,13 @@ static struct sde_prop_type ltm_prop[] = {
|
|||||||
{LTM_VERSION, "qcom,sde-dspp-ltm-version", false, PROP_TYPE_U32},
|
{LTM_VERSION, "qcom,sde-dspp-ltm-version", false, PROP_TYPE_U32},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct sde_prop_type rc_prop[] = {
|
||||||
|
{RC_OFF, "qcom,sde-dspp-rc-off", false, PROP_TYPE_U32_ARRAY},
|
||||||
|
{RC_LEN, "qcom,sde-dspp-rc-size", false, PROP_TYPE_U32},
|
||||||
|
{RC_VERSION, "qcom,sde-dspp-rc-version", false, PROP_TYPE_U32},
|
||||||
|
{RC_MEM_TOTAL_SIZE, "qcom,sde-dspp-rc-mem-size", false, PROP_TYPE_U32},
|
||||||
|
};
|
||||||
|
|
||||||
static struct sde_prop_type ds_top_prop[] = {
|
static struct sde_prop_type ds_top_prop[] = {
|
||||||
{DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32},
|
{DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32},
|
||||||
{DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32},
|
{DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32},
|
||||||
@@ -2471,8 +2486,8 @@ static int sde_dspp_parse_dt(struct device_node *np,
|
|||||||
struct sde_mdss_cfg *sde_cfg)
|
struct sde_mdss_cfg *sde_cfg)
|
||||||
{
|
{
|
||||||
int rc = 0, i;
|
int rc = 0, i;
|
||||||
u32 off_count, ad_off_count, ltm_off_count;
|
u32 off_count, ad_off_count, ltm_off_count, rc_off_count;
|
||||||
struct sde_dt_props *props, *ad_props, *ltm_props;
|
struct sde_dt_props *props, *ad_props, *ltm_props, *rc_props;
|
||||||
struct sde_dt_props *blocks_props = NULL;
|
struct sde_dt_props *blocks_props = NULL;
|
||||||
struct sde_dspp_cfg *dspp;
|
struct sde_dspp_cfg *dspp;
|
||||||
struct sde_dspp_sub_blks *sblk;
|
struct sde_dspp_sub_blks *sblk;
|
||||||
@@ -2506,6 +2521,14 @@ static int sde_dspp_parse_dt(struct device_node *np,
|
|||||||
goto put_ad_props;
|
goto put_ad_props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse RC dtsi entries */
|
||||||
|
rc_props = sde_get_dt_props(np, RC_PROP_MAX, rc_prop,
|
||||||
|
ARRAY_SIZE(rc_prop), &rc_off_count);
|
||||||
|
if (IS_ERR_OR_NULL(rc_props)) {
|
||||||
|
rc = PTR_ERR(rc_props);
|
||||||
|
goto put_ltm_props;
|
||||||
|
}
|
||||||
|
|
||||||
/* get DSPP feature dt properties if they exist */
|
/* get DSPP feature dt properties if they exist */
|
||||||
snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name);
|
snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name);
|
||||||
if (snp) {
|
if (snp) {
|
||||||
@@ -2514,7 +2537,7 @@ static int sde_dspp_parse_dt(struct device_node *np,
|
|||||||
NULL);
|
NULL);
|
||||||
if (IS_ERR_OR_NULL(blocks_props)) {
|
if (IS_ERR_OR_NULL(blocks_props)) {
|
||||||
rc = PTR_ERR(blocks_props);
|
rc = PTR_ERR(blocks_props);
|
||||||
goto put_ltm_props;
|
goto put_rc_props;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2571,10 +2594,28 @@ static int sde_dspp_parse_dt(struct device_node *np,
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sblk->rc.id = SDE_DSPP_RC;
|
||||||
|
sde_cfg->rc_count = rc_off_count;
|
||||||
|
if (rc_props && (i < rc_off_count) &&
|
||||||
|
rc_props->exists[RC_OFF]) {
|
||||||
|
sblk->rc.base = PROP_VALUE_ACCESS(rc_props->values,
|
||||||
|
RC_OFF, i);
|
||||||
|
sblk->rc.len = PROP_VALUE_ACCESS(rc_props->values,
|
||||||
|
RC_LEN, 0);
|
||||||
|
sblk->rc.version = PROP_VALUE_ACCESS(rc_props->values,
|
||||||
|
RC_VERSION, 0);
|
||||||
|
sblk->rc.mem_total_size = PROP_VALUE_ACCESS(
|
||||||
|
rc_props->values, RC_MEM_TOTAL_SIZE,
|
||||||
|
0);
|
||||||
|
sblk->rc.idx = i;
|
||||||
|
set_bit(SDE_DSPP_RC, &dspp->features);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
sde_put_dt_props(blocks_props);
|
sde_put_dt_props(blocks_props);
|
||||||
|
put_rc_props:
|
||||||
|
sde_put_dt_props(rc_props);
|
||||||
put_ltm_props:
|
put_ltm_props:
|
||||||
sde_put_dt_props(ltm_props);
|
sde_put_dt_props(ltm_props);
|
||||||
put_ad_props:
|
put_ad_props:
|
||||||
|
@@ -755,6 +755,20 @@ struct sde_lm_sub_blks {
|
|||||||
struct sde_pp_blk gc;
|
struct sde_pp_blk gc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sde_dspp_rc: Pixel processing rounded corner sub-blk information
|
||||||
|
* @info: HW register and features supported by this sub-blk.
|
||||||
|
* @version: HW Algorithm version.
|
||||||
|
* @idx: HW block instance id.
|
||||||
|
* @mem_total_size: data memory size.
|
||||||
|
*/
|
||||||
|
struct sde_dspp_rc {
|
||||||
|
SDE_HW_SUBBLK_INFO;
|
||||||
|
u32 version;
|
||||||
|
u32 idx;
|
||||||
|
u32 mem_total_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct sde_dspp_sub_blks {
|
struct sde_dspp_sub_blks {
|
||||||
struct sde_pp_blk igc;
|
struct sde_pp_blk igc;
|
||||||
struct sde_pp_blk pcc;
|
struct sde_pp_blk pcc;
|
||||||
@@ -768,6 +782,7 @@ struct sde_dspp_sub_blks {
|
|||||||
struct sde_pp_blk ad;
|
struct sde_pp_blk ad;
|
||||||
struct sde_pp_blk ltm;
|
struct sde_pp_blk ltm;
|
||||||
struct sde_pp_blk vlut;
|
struct sde_pp_blk vlut;
|
||||||
|
struct sde_dspp_rc rc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sde_pingpong_sub_blks {
|
struct sde_pingpong_sub_blks {
|
||||||
@@ -1426,6 +1441,7 @@ struct sde_limit_cfg {
|
|||||||
* @has_vig_p010 indicates if vig pipe supports p010 format
|
* @has_vig_p010 indicates if vig pipe supports p010 format
|
||||||
* @inline_rot_formats formats supported by the inline rotator feature
|
* @inline_rot_formats formats supported by the inline rotator feature
|
||||||
* @irq_offset_list list of sde_intr_irq_offsets to initialize irq table
|
* @irq_offset_list list of sde_intr_irq_offsets to initialize irq table
|
||||||
|
* @rc_count number of rounded corner hardware instances
|
||||||
*/
|
*/
|
||||||
struct sde_mdss_cfg {
|
struct sde_mdss_cfg {
|
||||||
u32 hwversion;
|
u32 hwversion;
|
||||||
@@ -1536,6 +1552,7 @@ struct sde_mdss_cfg {
|
|||||||
|
|
||||||
u32 ad_count;
|
u32 ad_count;
|
||||||
u32 ltm_count;
|
u32 ltm_count;
|
||||||
|
u32 rc_count;
|
||||||
|
|
||||||
u32 merge_3d_count;
|
u32 merge_3d_count;
|
||||||
struct sde_merge_3d_cfg merge_3d[MAX_BLOCKS];
|
struct sde_merge_3d_cfg merge_3d[MAX_BLOCKS];
|
||||||
@@ -1583,6 +1600,7 @@ struct sde_mdss_hw_cfg_handler {
|
|||||||
#define BLK_WB(s) ((s)->wb)
|
#define BLK_WB(s) ((s)->wb)
|
||||||
#define BLK_AD(s) ((s)->ad)
|
#define BLK_AD(s) ((s)->ad)
|
||||||
#define BLK_LTM(s) ((s)->ltm)
|
#define BLK_LTM(s) ((s)->ltm)
|
||||||
|
#define BLK_RC(s) ((s)->rc)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_hw_set_preference: populate the individual hw lm preferences,
|
* sde_hw_set_preference: populate the individual hw lm preferences,
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <drm/msm_drm_pp.h>
|
#include <drm/msm_drm_pp.h>
|
||||||
#include "sde_hw_mdss.h"
|
#include "sde_hw_mdss.h"
|
||||||
#include "sde_hwio.h"
|
#include "sde_hwio.h"
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
#include "sde_hw_color_processing.h"
|
#include "sde_hw_color_processing.h"
|
||||||
#include "sde_dbg.h"
|
#include "sde_dbg.h"
|
||||||
#include "sde_ad4.h"
|
#include "sde_ad4.h"
|
||||||
|
#include "sde_hw_rc.h"
|
||||||
#include "sde_kms.h"
|
#include "sde_kms.h"
|
||||||
|
|
||||||
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
|
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
|
||||||
@@ -241,6 +243,37 @@ static void dspp_ltm(struct sde_hw_dspp *c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dspp_rc(struct sde_hw_dspp *c)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!c) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->cap->sblk->rc.version == SDE_COLOR_PROCESS_VER(0x1, 0x0)) {
|
||||||
|
ret = sde_hw_rc_init(c);
|
||||||
|
if (ret) {
|
||||||
|
SDE_ERROR("rc init failed, ret %d\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_RC, c->idx);
|
||||||
|
if (!ret)
|
||||||
|
c->ops.setup_rc_data =
|
||||||
|
sde_hw_rc_setup_data_dma;
|
||||||
|
else
|
||||||
|
c->ops.setup_rc_data =
|
||||||
|
sde_hw_rc_setup_data_ahb;
|
||||||
|
|
||||||
|
c->ops.validate_rc_mask = sde_hw_rc_check_mask;
|
||||||
|
c->ops.setup_rc_mask = sde_hw_rc_setup_mask;
|
||||||
|
c->ops.validate_rc_pu_roi = sde_hw_rc_check_pu_roi;
|
||||||
|
c->ops.setup_rc_pu_roi = sde_hw_rc_setup_pu_roi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void (*dspp_blocks[SDE_DSPP_MAX])(struct sde_hw_dspp *c);
|
static void (*dspp_blocks[SDE_DSPP_MAX])(struct sde_hw_dspp *c);
|
||||||
|
|
||||||
static void _init_dspp_ops(void)
|
static void _init_dspp_ops(void)
|
||||||
@@ -257,6 +290,7 @@ static void _init_dspp_ops(void)
|
|||||||
dspp_blocks[SDE_DSPP_VLUT] = dspp_vlut;
|
dspp_blocks[SDE_DSPP_VLUT] = dspp_vlut;
|
||||||
dspp_blocks[SDE_DSPP_AD] = dspp_ad;
|
dspp_blocks[SDE_DSPP_AD] = dspp_ad;
|
||||||
dspp_blocks[SDE_DSPP_LTM] = dspp_ltm;
|
dspp_blocks[SDE_DSPP_LTM] = dspp_ltm;
|
||||||
|
dspp_blocks[SDE_DSPP_RC] = dspp_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
|
static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
|
||||||
@@ -286,6 +320,7 @@ struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
|
|||||||
struct sde_hw_dspp *c;
|
struct sde_hw_dspp *c;
|
||||||
struct sde_dspp_cfg *cfg;
|
struct sde_dspp_cfg *cfg;
|
||||||
int rc;
|
int rc;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
if (!addr || !m)
|
if (!addr || !m)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
@@ -329,6 +364,13 @@ struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
|
|||||||
c->hw.xin_id);
|
c->hw.xin_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((cfg->sblk->rc.id == SDE_DSPP_RC) && cfg->sblk->rc.base) {
|
||||||
|
snprintf(buf, ARRAY_SIZE(buf), "%s_%d", "rc", c->idx - DSPP_0);
|
||||||
|
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, buf,
|
||||||
|
c->hw.blk_off + cfg->sblk->rc.base,
|
||||||
|
c->hw.blk_off + cfg->sblk->rc.base +
|
||||||
|
cfg->sblk->rc.len, c->hw.xin_id);
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
|
|
||||||
blk_init_error:
|
blk_init_error:
|
||||||
|
@@ -209,6 +209,46 @@ struct sde_hw_dspp_ops {
|
|||||||
* @status: Pointer to u32 where ltm status value is dumped.
|
* @status: Pointer to u32 where ltm status value is dumped.
|
||||||
*/
|
*/
|
||||||
void (*ltm_read_intr_status)(struct sde_hw_dspp *ctx, u32 *status);
|
void (*ltm_read_intr_status)(struct sde_hw_dspp *ctx, u32 *status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate_rc_mask - Validate RC mask configuration
|
||||||
|
* @ctx: Pointer to dspp context.
|
||||||
|
* @cfg: Pointer to configuration.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int (*validate_rc_mask)(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setup_rc_mask - Setup RC mask configuration
|
||||||
|
* @ctx: Pointer to dspp context.
|
||||||
|
* @cfg: Pointer to configuration.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int (*setup_rc_mask)(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate_rc_pu_roi - Validate RC regions in during partial update.
|
||||||
|
* @ctx: Pointer to dspp context.
|
||||||
|
* @cfg: Pointer to configuration.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int (*validate_rc_pu_roi)(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setup_rc_pu_roi - Setup RC regions in during partial update.
|
||||||
|
* @ctx: Pointer to dspp context.
|
||||||
|
* @cfg: Pointer to configuration.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int (*setup_rc_pu_roi)(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setup_rc_data - Program RC mask data
|
||||||
|
* @ctx: Pointer to dspp context.
|
||||||
|
* @cfg: Pointer to configuration.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int (*setup_rc_data)(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -172,6 +172,7 @@ enum sde_stage {
|
|||||||
SDE_STAGE_10,
|
SDE_STAGE_10,
|
||||||
SDE_STAGE_MAX
|
SDE_STAGE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sde_dspp {
|
enum sde_dspp {
|
||||||
DSPP_0 = 1,
|
DSPP_0 = 1,
|
||||||
DSPP_1,
|
DSPP_1,
|
||||||
@@ -186,6 +187,12 @@ enum sde_ltm {
|
|||||||
LTM_MAX
|
LTM_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum sde_rc {
|
||||||
|
RC_0 = DSPP_0,
|
||||||
|
RC_1,
|
||||||
|
RC_MAX
|
||||||
|
};
|
||||||
|
|
||||||
enum sde_ds {
|
enum sde_ds {
|
||||||
DS_TOP,
|
DS_TOP,
|
||||||
DS_0,
|
DS_0,
|
||||||
|
974
msm/sde/sde_hw_rc.c
Normal file
974
msm/sde/sde_hw_rc.c
Normal file
@@ -0,0 +1,974 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <drm/msm_drm_pp.h>
|
||||||
|
#include "sde_kms.h"
|
||||||
|
#include "sde_reg_dma.h"
|
||||||
|
#include "sde_hw_rc.h"
|
||||||
|
#include "sde_hw_catalog.h"
|
||||||
|
#include "sde_hw_util.h"
|
||||||
|
#include "sde_hw_dspp.h"
|
||||||
|
#include "sde_hw_reg_dma_v1_color_proc.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardware register set
|
||||||
|
*/
|
||||||
|
#define SDE_HW_RC_REG0 0x00
|
||||||
|
#define SDE_HW_RC_REG1 0x04
|
||||||
|
#define SDE_HW_RC_REG2 0x08
|
||||||
|
#define SDE_HW_RC_REG3 0x0C
|
||||||
|
#define SDE_HW_RC_REG4 0x10
|
||||||
|
#define SDE_HW_RC_REG5 0x14
|
||||||
|
#define SDE_HW_RC_REG6 0x18
|
||||||
|
#define SDE_HW_RC_REG7 0x1C
|
||||||
|
#define SDE_HW_RC_REG8 0x20
|
||||||
|
#define SDE_HW_RC_REG9 0x24
|
||||||
|
#define SDE_HW_RC_REG10 0x28
|
||||||
|
#define SDE_HW_RC_REG11 0x2C
|
||||||
|
#define SDE_HW_RC_REG12 0x30
|
||||||
|
#define SDE_HW_RC_REG13 0x34
|
||||||
|
|
||||||
|
#define SDE_HW_RC_DATA_REG_SIZE 18
|
||||||
|
#define SDE_HW_RC_SKIP_DATA_PROG 0x1
|
||||||
|
|
||||||
|
#define SDE_HW_RC_DISABLE_R1 0x01E
|
||||||
|
#define SDE_HW_RC_DISABLE_R2 0x1E0
|
||||||
|
|
||||||
|
#define SDE_HW_RC_PU_SKIP_OP 0x1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sde_hw_rc_state - rounded corner cached state per RC instance
|
||||||
|
*
|
||||||
|
* @last_rc_mask_cfg: cached value of most recent programmed mask.
|
||||||
|
* @mask_programmed: true if mask was programmed at least once to RC hardware.
|
||||||
|
* @last_roi_list: cached value of most recent processed list of ROIs.
|
||||||
|
* @roi_programmed: true if list of ROIs were processed at least once.
|
||||||
|
*/
|
||||||
|
struct sde_hw_rc_state {
|
||||||
|
struct drm_msm_rc_mask_cfg *last_rc_mask_cfg;
|
||||||
|
bool mask_programmed;
|
||||||
|
struct msm_roi_list *last_roi_list;
|
||||||
|
bool roi_programmed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sde_hw_rc_state rc_state[RC_MAX - RC_0] = {
|
||||||
|
{
|
||||||
|
.last_rc_mask_cfg = NULL,
|
||||||
|
.last_roi_list = NULL,
|
||||||
|
.mask_programmed = false,
|
||||||
|
.roi_programmed = false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.last_rc_mask_cfg = NULL,
|
||||||
|
.last_roi_list = NULL,
|
||||||
|
.mask_programmed = false,
|
||||||
|
.roi_programmed = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#define RC_STATE(hw_dspp) rc_state[hw_dspp->cap->sblk->rc.idx]
|
||||||
|
|
||||||
|
enum rc_param_r {
|
||||||
|
RC_PARAM_R0 = 0x0,
|
||||||
|
RC_PARAM_R1 = 0x1,
|
||||||
|
RC_PARAM_R2 = 0x2,
|
||||||
|
RC_PARAM_R1R2 = (RC_PARAM_R1 | RC_PARAM_R2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rc_param_a {
|
||||||
|
RC_PARAM_A0 = 0x2,
|
||||||
|
RC_PARAM_A1 = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rc_param_b {
|
||||||
|
RC_PARAM_B0 = 0x0,
|
||||||
|
RC_PARAM_B1 = 0x1,
|
||||||
|
RC_PARAM_B2 = 0x2,
|
||||||
|
RC_PARAM_B1B2 = (RC_PARAM_B1 | RC_PARAM_B2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rc_param_c {
|
||||||
|
RC_PARAM_C0 = (BIT(8)),
|
||||||
|
RC_PARAM_C1 = (BIT(10)),
|
||||||
|
RC_PARAM_C2 = (BIT(10) | BIT(11)),
|
||||||
|
RC_PARAM_C3 = (BIT(8) | BIT(10)),
|
||||||
|
RC_PARAM_C4 = (BIT(8) | BIT(9)),
|
||||||
|
RC_PARAM_C5 = (BIT(8) | BIT(9) | BIT(10) | BIT(11)),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rc_merge_mode {
|
||||||
|
RC_MERGE_SINGLE_PIPE = 0x0,
|
||||||
|
RC_MERGE_DUAL_PIPE = 0x1
|
||||||
|
};
|
||||||
|
struct rc_config_table {
|
||||||
|
enum rc_param_a param_a;
|
||||||
|
enum rc_param_b param_b;
|
||||||
|
enum rc_param_c param_c;
|
||||||
|
enum rc_merge_mode merge_mode;
|
||||||
|
enum rc_merge_mode merge_mode_en;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rc_config_table config_table[] = {
|
||||||
|
/* RC_PARAM_A0 configurations */
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A0,
|
||||||
|
.param_b = RC_PARAM_B1B2,
|
||||||
|
.param_c = RC_PARAM_C3,
|
||||||
|
.merge_mode = RC_MERGE_SINGLE_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A0,
|
||||||
|
.param_b = RC_PARAM_B1,
|
||||||
|
.param_c = RC_PARAM_C0,
|
||||||
|
.merge_mode = RC_MERGE_SINGLE_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A0,
|
||||||
|
.param_b = RC_PARAM_B2,
|
||||||
|
.param_c = RC_PARAM_C1,
|
||||||
|
.merge_mode = RC_MERGE_SINGLE_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A0,
|
||||||
|
.param_b = RC_PARAM_B1B2,
|
||||||
|
.param_c = RC_PARAM_C3,
|
||||||
|
.merge_mode = RC_MERGE_DUAL_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_DUAL_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A0,
|
||||||
|
.param_b = RC_PARAM_B1,
|
||||||
|
.param_c = RC_PARAM_C0,
|
||||||
|
.merge_mode = RC_MERGE_DUAL_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A0,
|
||||||
|
.param_b = RC_PARAM_B2,
|
||||||
|
.param_c = RC_PARAM_C1,
|
||||||
|
.merge_mode = RC_MERGE_DUAL_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* RC_PARAM_A1 configurations */
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A1,
|
||||||
|
.param_b = RC_PARAM_B1B2,
|
||||||
|
.param_c = RC_PARAM_C5,
|
||||||
|
.merge_mode = RC_MERGE_SINGLE_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A1,
|
||||||
|
.param_b = RC_PARAM_B1,
|
||||||
|
.param_c = RC_PARAM_C4,
|
||||||
|
.merge_mode = RC_MERGE_SINGLE_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A1,
|
||||||
|
.param_b = RC_PARAM_B2,
|
||||||
|
.param_c = RC_PARAM_C2,
|
||||||
|
.merge_mode = RC_MERGE_SINGLE_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A1,
|
||||||
|
.param_b = RC_PARAM_B1B2,
|
||||||
|
.param_c = RC_PARAM_C5,
|
||||||
|
.merge_mode = RC_MERGE_DUAL_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_DUAL_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A1,
|
||||||
|
.param_b = RC_PARAM_B1,
|
||||||
|
.param_c = RC_PARAM_C4,
|
||||||
|
.merge_mode = RC_MERGE_DUAL_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.param_a = RC_PARAM_A1,
|
||||||
|
.param_b = RC_PARAM_B2,
|
||||||
|
.param_c = RC_PARAM_C2,
|
||||||
|
.merge_mode = RC_MERGE_DUAL_PIPE,
|
||||||
|
.merge_mode_en = RC_MERGE_SINGLE_PIPE,
|
||||||
|
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void _sde_hw_rc_reg_write(
|
||||||
|
struct sde_hw_dspp *hw_dspp,
|
||||||
|
int offset,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
u32 address = hw_dspp->cap->sblk->rc.base + offset;
|
||||||
|
|
||||||
|
SDE_DEBUG("rc:%u, address:0x%08X, value:0x%08X\n",
|
||||||
|
hw_dspp->cap->sblk->rc.idx,
|
||||||
|
hw_dspp->hw.blk_off + address, value);
|
||||||
|
SDE_REG_WRITE(&hw_dspp->hw, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_get_enable_bits(
|
||||||
|
enum rc_param_a param_a,
|
||||||
|
enum rc_param_b param_b,
|
||||||
|
enum rc_param_c *param_c,
|
||||||
|
u32 merge_mode,
|
||||||
|
u32 *merge_mode_en)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (!param_c || !merge_mode_en) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(config_table); i++) {
|
||||||
|
if (merge_mode == config_table[i].merge_mode &&
|
||||||
|
param_a == config_table[i].param_a &&
|
||||||
|
param_b == config_table[i].param_b) {
|
||||||
|
*param_c = config_table[i].param_c;
|
||||||
|
*merge_mode_en = config_table[i].merge_mode_en;
|
||||||
|
SDE_DEBUG("found param_c:0x%08X, merge_mode_en:%d\n",
|
||||||
|
*param_c, *merge_mode_en);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDE_ERROR("configuration not supported");
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_get_merge_mode(
|
||||||
|
const struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
u32 *merge_mode)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!hw_cfg || !merge_mode) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->num_of_mixers == 1)
|
||||||
|
*merge_mode = RC_MERGE_SINGLE_PIPE;
|
||||||
|
else if (hw_cfg->num_of_mixers == 2)
|
||||||
|
*merge_mode = RC_MERGE_DUAL_PIPE;
|
||||||
|
else {
|
||||||
|
SDE_ERROR("invalid number of mixers:%d\n",
|
||||||
|
hw_cfg->num_of_mixers);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDE_DEBUG("number mixers:%u, merge mode:%u\n",
|
||||||
|
hw_cfg->num_of_mixers, *merge_mode);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_get_ajusted_roi(
|
||||||
|
const struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
const struct sde_rect *pu_roi,
|
||||||
|
struct sde_rect *rc_roi)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!hw_cfg || !pu_roi || !rc_roi) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*when partial update is disabled, use full screen ROI*/
|
||||||
|
if (pu_roi->w == 0 && pu_roi->h == 0) {
|
||||||
|
rc_roi->x = pu_roi->x;
|
||||||
|
rc_roi->y = pu_roi->y;
|
||||||
|
rc_roi->w = hw_cfg->displayh;
|
||||||
|
rc_roi->h = hw_cfg->displayv;
|
||||||
|
} else {
|
||||||
|
memcpy(rc_roi, pu_roi, sizeof(struct sde_rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDE_DEBUG("displayh:%u, displayv:%u\n", hw_cfg->displayh,
|
||||||
|
hw_cfg->displayv);
|
||||||
|
SDE_DEBUG("pu_roi x:%u, y:%u, w:%u, h:%u\n", pu_roi->x, pu_roi->y,
|
||||||
|
pu_roi->w, pu_roi->h);
|
||||||
|
SDE_DEBUG("rc_roi x:%u, y:%u, w:%u, h:%u\n", rc_roi->x, rc_roi->y,
|
||||||
|
rc_roi->w, rc_roi->h);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_get_param_rb(
|
||||||
|
const struct drm_msm_rc_mask_cfg *rc_mask_cfg,
|
||||||
|
const struct sde_rect *rc_roi,
|
||||||
|
enum rc_param_r *param_r,
|
||||||
|
enum rc_param_b *param_b)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
int half_panel_x = 0, half_panel_w = 0;
|
||||||
|
int cfg_param_01 = 0, cfg_param_02 = 0;
|
||||||
|
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
|
||||||
|
|
||||||
|
if (!rc_mask_cfg || !rc_roi || !param_r || !param_b) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc_mask_cfg->cfg_param_03 == RC_PARAM_A1)
|
||||||
|
half_panel_w = rc_mask_cfg->cfg_param_04[0] +
|
||||||
|
rc_mask_cfg->cfg_param_04[1];
|
||||||
|
else if (rc_mask_cfg->cfg_param_03 == RC_PARAM_A0)
|
||||||
|
half_panel_w = rc_mask_cfg->cfg_param_04[0];
|
||||||
|
else {
|
||||||
|
SDE_ERROR("invalid cfg_param_03:%u\n",
|
||||||
|
rc_mask_cfg->cfg_param_03);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_param_01 = rc_mask_cfg->cfg_param_01;
|
||||||
|
cfg_param_02 = rc_mask_cfg->cfg_param_02;
|
||||||
|
x1 = rc_roi->x;
|
||||||
|
x2 = rc_roi->x + rc_roi->w - 1;
|
||||||
|
y1 = rc_roi->y;
|
||||||
|
y2 = rc_roi->y + rc_roi->h - 1;
|
||||||
|
half_panel_x = half_panel_w - 1;
|
||||||
|
|
||||||
|
SDE_DEBUG("x1:%u y1:%u x2:%u y2:%u\n", x1, y1, x2, y2);
|
||||||
|
SDE_DEBUG("cfg_param_01:%u cfg_param_02:%u half_panel_x:%u",
|
||||||
|
cfg_param_01, cfg_param_02, half_panel_x);
|
||||||
|
SDE_DEBUG("param_r:0x%08X param_b:0x%08X\n",
|
||||||
|
*param_r, *param_b);
|
||||||
|
|
||||||
|
if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 || half_panel_x < 0 ||
|
||||||
|
x1 >= x2 || y1 >= y2) {
|
||||||
|
SDE_ERROR("invalid coordinates\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y1 <= cfg_param_01) {
|
||||||
|
*param_r |= RC_PARAM_R1;
|
||||||
|
if (x1 <= half_panel_x && x2 <= half_panel_x)
|
||||||
|
*param_b |= RC_PARAM_B1;
|
||||||
|
else if (x1 > half_panel_x && x2 > half_panel_x)
|
||||||
|
*param_b |= RC_PARAM_B2;
|
||||||
|
else
|
||||||
|
*param_b |= RC_PARAM_B1B2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y2 >= cfg_param_02) {
|
||||||
|
*param_r |= RC_PARAM_R2;
|
||||||
|
if (x1 <= half_panel_x && x2 <= half_panel_x)
|
||||||
|
*param_b |= RC_PARAM_B1;
|
||||||
|
else if (x1 > half_panel_x && x2 > half_panel_x)
|
||||||
|
*param_b |= RC_PARAM_B2;
|
||||||
|
else
|
||||||
|
*param_b |= RC_PARAM_B1B2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_program_enable_bits(
|
||||||
|
struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg,
|
||||||
|
enum rc_param_r param_r,
|
||||||
|
enum rc_param_a param_a,
|
||||||
|
enum rc_param_b param_b,
|
||||||
|
int merge_mode,
|
||||||
|
struct sde_rect *rc_roi)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
u32 val = 0, param_c = 0, rc_merge_mode = 0, ystart = 0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !rc_mask_cfg || !rc_roi) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_enable_bits(param_a, param_b, ¶m_c,
|
||||||
|
merge_mode, &rc_merge_mode);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid enable bits, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param_r & RC_PARAM_R1) {
|
||||||
|
val |= BIT(0);
|
||||||
|
SDE_DEBUG("enable R1\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param_r & RC_PARAM_R2) {
|
||||||
|
val |= BIT(4);
|
||||||
|
SDE_DEBUG("enable R2\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*corner case for partial update*/
|
||||||
|
if (param_r == RC_PARAM_R0) {
|
||||||
|
ystart = rc_roi->y;
|
||||||
|
SDE_DEBUG("set partial update ystart:%u\n", ystart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc_mask_cfg->flags & SDE_HW_RC_DISABLE_R1)
|
||||||
|
== SDE_HW_RC_DISABLE_R1) {
|
||||||
|
val &= ~BIT(0);
|
||||||
|
SDE_DEBUG("override disable R1\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc_mask_cfg->flags & SDE_HW_RC_DISABLE_R2)
|
||||||
|
== SDE_HW_RC_DISABLE_R2) {
|
||||||
|
val &= ~BIT(4);
|
||||||
|
SDE_DEBUG("override disable R2\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
val |= param_c;
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG1, val);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG13, ystart);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG9, rc_merge_mode);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_program_roi(
|
||||||
|
struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg,
|
||||||
|
int merge_mode,
|
||||||
|
struct sde_rect *rc_roi)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
u32 val2 = 0, val3 = 0, val4 = 0;
|
||||||
|
enum rc_param_r param_r = RC_PARAM_R0;
|
||||||
|
enum rc_param_a param_a = RC_PARAM_A0;
|
||||||
|
enum rc_param_b param_b = RC_PARAM_B0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !rc_mask_cfg || !rc_roi) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_param_rb(rc_mask_cfg, rc_roi, ¶m_r,
|
||||||
|
¶m_b);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid rc roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
param_a = rc_mask_cfg->cfg_param_03;
|
||||||
|
rc = _sde_hw_rc_program_enable_bits(hw_dspp, rc_mask_cfg,
|
||||||
|
param_r, param_a, param_b, merge_mode, rc_roi);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("failed to program enable bits, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
val2 = ((rc_mask_cfg->cfg_param_01 & 0x0000FFFF) |
|
||||||
|
((rc_mask_cfg->cfg_param_02 << 16) & 0xFFFF0000));
|
||||||
|
if (param_a == RC_PARAM_A1) {
|
||||||
|
val3 = (rc_mask_cfg->cfg_param_04[0] |
|
||||||
|
(rc_mask_cfg->cfg_param_04[1] << 16));
|
||||||
|
val4 = (rc_mask_cfg->cfg_param_04[2] |
|
||||||
|
(rc_mask_cfg->cfg_param_04[3] << 16));
|
||||||
|
} else if (param_a == RC_PARAM_A0) {
|
||||||
|
val3 = (rc_mask_cfg->cfg_param_04[0]);
|
||||||
|
val4 = (rc_mask_cfg->cfg_param_04[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG2, val2);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG3, val3);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG4, val4);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sde_hw_rc_program_data_offset(
|
||||||
|
struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
u32 val5 = 0, val6 = 0, val7 = 0, val8 = 0;
|
||||||
|
u32 cfg_param_07;
|
||||||
|
|
||||||
|
if (!hw_dspp || !rc_mask_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_param_07 = rc_mask_cfg->cfg_param_07;
|
||||||
|
if (rc_mask_cfg->cfg_param_03 == RC_PARAM_A1) {
|
||||||
|
val5 = ((rc_mask_cfg->cfg_param_05[0] + cfg_param_07) |
|
||||||
|
((rc_mask_cfg->cfg_param_05[1] + cfg_param_07)
|
||||||
|
<< 16));
|
||||||
|
val6 = ((rc_mask_cfg->cfg_param_05[2] + cfg_param_07)|
|
||||||
|
((rc_mask_cfg->cfg_param_05[3] + cfg_param_07)
|
||||||
|
<< 16));
|
||||||
|
val7 = ((rc_mask_cfg->cfg_param_06[0] + cfg_param_07) |
|
||||||
|
((rc_mask_cfg->cfg_param_06[1] + cfg_param_07)
|
||||||
|
<< 16));
|
||||||
|
val8 = ((rc_mask_cfg->cfg_param_06[2] + cfg_param_07) |
|
||||||
|
((rc_mask_cfg->cfg_param_06[3] + cfg_param_07)
|
||||||
|
<< 16));
|
||||||
|
} else if (rc_mask_cfg->cfg_param_03 == RC_PARAM_A0) {
|
||||||
|
val5 = (rc_mask_cfg->cfg_param_05[0] + cfg_param_07);
|
||||||
|
val6 = (rc_mask_cfg->cfg_param_05[1] + cfg_param_07);
|
||||||
|
val7 = (rc_mask_cfg->cfg_param_06[0] + cfg_param_07);
|
||||||
|
val8 = (rc_mask_cfg->cfg_param_06[1] + cfg_param_07);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG5, val5);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG6, val6);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG7, val7);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG8, val8);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sde_hw_rc_check_mask_cfg(
|
||||||
|
struct sde_hw_dspp *hw_dspp,
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg,
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
u32 i = 0;
|
||||||
|
u32 half_panel_width;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg || !rc_mask_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc_mask_cfg->cfg_param_08 ||
|
||||||
|
rc_mask_cfg->cfg_param_08 > RC_DATA_SIZE_MAX) {
|
||||||
|
SDE_ERROR("invalid cfg_param_08:%d\n",
|
||||||
|
rc_mask_cfg->cfg_param_08);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc_mask_cfg->cfg_param_07 + rc_mask_cfg->cfg_param_08 >
|
||||||
|
hw_dspp->cap->sblk->rc.mem_total_size) {
|
||||||
|
SDE_ERROR("invalid cfg_param_08:%d, cfg_param_07:%d, max:%u\n",
|
||||||
|
rc_mask_cfg->cfg_param_08,
|
||||||
|
rc_mask_cfg->cfg_param_07,
|
||||||
|
hw_dspp->cap->sblk->rc.mem_total_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc_mask_cfg->cfg_param_03 ||
|
||||||
|
(rc_mask_cfg->cfg_param_03 != RC_PARAM_A1 &&
|
||||||
|
rc_mask_cfg->cfg_param_03 != RC_PARAM_A0)) {
|
||||||
|
SDE_ERROR("invalid cfg_param_03:%d\n",
|
||||||
|
rc_mask_cfg->cfg_param_03);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc_mask_cfg->cfg_param_01 < 1) ||
|
||||||
|
((hw_cfg->displayv - rc_mask_cfg->cfg_param_02) < 1)) {
|
||||||
|
SDE_ERROR("invalid min cfg_param_01:%d or cfg_param_02:%d\n",
|
||||||
|
rc_mask_cfg->cfg_param_01,
|
||||||
|
rc_mask_cfg->cfg_param_02);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc_mask_cfg->cfg_param_01 > rc_mask_cfg->cfg_param_02) {
|
||||||
|
SDE_ERROR("invalid cfg_param_01:%d or cfg_param_02:%d\n",
|
||||||
|
rc_mask_cfg->cfg_param_01,
|
||||||
|
rc_mask_cfg->cfg_param_02);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rc_mask_cfg->cfg_param_03; i++) {
|
||||||
|
if (rc_mask_cfg->cfg_param_04[i] < 4) {
|
||||||
|
SDE_ERROR("invalid cfg_param_04[%d]:%d\n", i,
|
||||||
|
rc_mask_cfg->cfg_param_04[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
half_panel_width = hw_cfg->displayh / rc_mask_cfg->cfg_param_03 * 2;
|
||||||
|
for (i = 0; i < rc_mask_cfg->cfg_param_03; i += 2) {
|
||||||
|
if (rc_mask_cfg->cfg_param_04[i] +
|
||||||
|
rc_mask_cfg->cfg_param_04[i+1] !=
|
||||||
|
half_panel_width) {
|
||||||
|
SDE_ERROR("invalid ratio [%d]:%d, [%d]:%d, %d\n",
|
||||||
|
i,
|
||||||
|
rc_mask_cfg->cfg_param_04[i],
|
||||||
|
i+1,
|
||||||
|
rc_mask_cfg->cfg_param_04[i+1],
|
||||||
|
half_panel_width);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rc_mask_cfg->cfg_param_03 - 1; i++) {
|
||||||
|
if (rc_mask_cfg->cfg_param_05[i] >=
|
||||||
|
rc_mask_cfg->cfg_param_05[i+1]) {
|
||||||
|
SDE_ERROR("invalid cfg_param_05 overlap %d, %d\n",
|
||||||
|
rc_mask_cfg->cfg_param_05[i],
|
||||||
|
rc_mask_cfg->cfg_param_05[i+1]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rc_mask_cfg->cfg_param_03; i++) {
|
||||||
|
if (rc_mask_cfg->cfg_param_05[i] >
|
||||||
|
RC_DATA_SIZE_MAX) {
|
||||||
|
SDE_ERROR("invalid cfg_param_05[%d]:%d\n", i,
|
||||||
|
rc_mask_cfg->cfg_param_05[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_check_mask(struct sde_hw_dspp *hw_dspp, void *cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hw_cfg->len == 0 && hw_cfg->payload == NULL)) {
|
||||||
|
SDE_DEBUG("rc feature disabled, skip mask checks\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) ||
|
||||||
|
!hw_cfg->payload) {
|
||||||
|
SDE_ERROR("invalid payload\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = hw_cfg->payload;
|
||||||
|
if (hw_cfg->num_of_mixers != 1 && hw_cfg->num_of_mixers != 2) {
|
||||||
|
SDE_ERROR("invalid number of mixers:%d\n",
|
||||||
|
hw_cfg->num_of_mixers);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sde_hw_rc_check_mask_cfg(hw_dspp, hw_cfg, rc_mask_cfg);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid rc mask configuration, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_check_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct msm_roi_list *roi_list;
|
||||||
|
struct sde_rect rc_roi, merged_roi;
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
bool mask_programmed = false;
|
||||||
|
enum rc_param_r param_r = RC_PARAM_R0;
|
||||||
|
enum rc_param_b param_b = RC_PARAM_B0;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct sde_drm_roi_v1)) {
|
||||||
|
SDE_ERROR("invalid payload size\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = RC_STATE(hw_dspp).last_rc_mask_cfg;
|
||||||
|
mask_programmed = RC_STATE(hw_dspp).mask_programmed;
|
||||||
|
|
||||||
|
/* early return when there is no mask in memory */
|
||||||
|
if (!mask_programmed || !rc_mask_cfg) {
|
||||||
|
SDE_DEBUG("no previous rc mask programmed\n");
|
||||||
|
return SDE_HW_RC_PU_SKIP_OP;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sde_hw_rc_check_mask_cfg(hw_dspp, hw_cfg, rc_mask_cfg);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid rc mask configuration, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
roi_list = hw_cfg->payload;
|
||||||
|
sde_kms_rect_merge_rectangles(roi_list, &merged_roi);
|
||||||
|
rc = _sde_hw_rc_get_ajusted_roi(hw_cfg, &merged_roi, &rc_roi);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("failed to get adjusted roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_param_rb(rc_mask_cfg, &rc_roi,
|
||||||
|
¶m_r, ¶m_b);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid rc roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_setup_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct msm_roi_list *roi_list;
|
||||||
|
struct sde_rect rc_roi, merged_roi;
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
enum rc_param_r param_r = RC_PARAM_R0;
|
||||||
|
enum rc_param_a param_a = RC_PARAM_A0;
|
||||||
|
enum rc_param_b param_b = RC_PARAM_B0;
|
||||||
|
u32 merge_mode = 0;
|
||||||
|
bool mask_programmed = false;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct sde_drm_roi_v1)) {
|
||||||
|
SDE_ERROR("invalid payload size\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = RC_STATE(hw_dspp).last_rc_mask_cfg;
|
||||||
|
mask_programmed = RC_STATE(hw_dspp).mask_programmed;
|
||||||
|
|
||||||
|
/* early return when there is no mask in memory */
|
||||||
|
if (!mask_programmed || !rc_mask_cfg) {
|
||||||
|
SDE_DEBUG("no previous rc mask programmed\n");
|
||||||
|
return SDE_HW_RC_PU_SKIP_OP;
|
||||||
|
}
|
||||||
|
|
||||||
|
roi_list = hw_cfg->payload;
|
||||||
|
sde_kms_rect_merge_rectangles(roi_list, &merged_roi);
|
||||||
|
rc = _sde_hw_rc_get_ajusted_roi(hw_cfg, &merged_roi, &rc_roi);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("failed to get adjusted roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_merge_mode(hw_cfg, &merge_mode);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid merge_mode, rc:%d\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_param_rb(rc_mask_cfg, &rc_roi, ¶m_r,
|
||||||
|
¶m_b);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
param_a = rc_mask_cfg->cfg_param_03;
|
||||||
|
rc = _sde_hw_rc_program_enable_bits(hw_dspp, rc_mask_cfg,
|
||||||
|
param_r, param_a, param_b, merge_mode, &rc_roi);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("failed to program enable bits, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(RC_STATE(hw_dspp).last_roi_list,
|
||||||
|
roi_list, sizeof(struct msm_roi_list));
|
||||||
|
RC_STATE(hw_dspp).roi_programmed = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_setup_mask(struct sde_hw_dspp *hw_dspp, void *cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
struct sde_rect rc_roi, merged_roi;
|
||||||
|
struct msm_roi_list *last_roi_list;
|
||||||
|
u32 merge_mode = 0;
|
||||||
|
bool roi_programmed = false;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hw_cfg->len == 0 && hw_cfg->payload == NULL)) {
|
||||||
|
SDE_DEBUG("rc feature disabled\n");
|
||||||
|
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG1, 0);
|
||||||
|
|
||||||
|
memset(RC_STATE(hw_dspp).last_rc_mask_cfg, 0,
|
||||||
|
sizeof(struct drm_msm_rc_mask_cfg));
|
||||||
|
RC_STATE(hw_dspp).mask_programmed = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) ||
|
||||||
|
!hw_cfg->payload) {
|
||||||
|
SDE_ERROR("invalid payload\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = hw_cfg->payload;
|
||||||
|
last_roi_list = RC_STATE(hw_dspp).last_roi_list;
|
||||||
|
roi_programmed = RC_STATE(hw_dspp).roi_programmed;
|
||||||
|
|
||||||
|
if (!roi_programmed) {
|
||||||
|
SDE_DEBUG("no previously programmed partial update rois\n");
|
||||||
|
memset(&merged_roi, 0, sizeof(struct sde_rect));
|
||||||
|
} else {
|
||||||
|
sde_kms_rect_merge_rectangles(last_roi_list, &merged_roi);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_ajusted_roi(hw_cfg, &merged_roi, &rc_roi);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("failed to get adjusted roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_get_merge_mode(hw_cfg, &merge_mode);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("invalid merge_mode, rc:%d\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_program_roi(hw_dspp, rc_mask_cfg,
|
||||||
|
merge_mode, &rc_roi);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("unable to program rc roi, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _sde_hw_rc_program_data_offset(hw_dspp, rc_mask_cfg);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("unable to program data offsets, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(RC_STATE(hw_dspp).last_rc_mask_cfg, rc_mask_cfg,
|
||||||
|
sizeof(struct drm_msm_rc_mask_cfg));
|
||||||
|
RC_STATE(hw_dspp).mask_programmed = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_setup_data_dma(struct sde_hw_dspp *hw_dspp, void *cfg)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hw_cfg->len == 0 && hw_cfg->payload == NULL)) {
|
||||||
|
SDE_DEBUG("rc feature disabled, skip data programming\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) ||
|
||||||
|
!hw_cfg->payload) {
|
||||||
|
SDE_ERROR("invalid payload\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = hw_cfg->payload;
|
||||||
|
|
||||||
|
if (rc_mask_cfg->flags & SDE_HW_RC_SKIP_DATA_PROG) {
|
||||||
|
SDE_DEBUG("skip data programming\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = reg_dmav1_setup_rc_datav1(hw_dspp, cfg);
|
||||||
|
if (rc) {
|
||||||
|
SDE_ERROR("unable to setup rc with dma, rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_setup_data_ahb(struct sde_hw_dspp *hw_dspp, void *cfg)
|
||||||
|
{
|
||||||
|
int rc = 0, i = 0;
|
||||||
|
u32 data = 0, cfg_param_07 = 0;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
|
||||||
|
if (!hw_dspp || !hw_cfg) {
|
||||||
|
SDE_ERROR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hw_cfg->len == 0 && hw_cfg->payload == NULL)) {
|
||||||
|
SDE_DEBUG("rc feature disabled, skip data programming\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) ||
|
||||||
|
!hw_cfg->payload) {
|
||||||
|
SDE_ERROR("invalid payload\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = hw_cfg->payload;
|
||||||
|
|
||||||
|
if (rc_mask_cfg->flags & SDE_HW_RC_SKIP_DATA_PROG) {
|
||||||
|
SDE_DEBUG("skip data programming\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_param_07 = rc_mask_cfg->cfg_param_07;
|
||||||
|
SDE_DEBUG("cfg_param_07:%u\n", cfg_param_07);
|
||||||
|
|
||||||
|
for (i = 0; i < rc_mask_cfg->cfg_param_08; i++) {
|
||||||
|
SDE_DEBUG("cfg_param_09[%d] = 0x%016lX at %u\n", i,
|
||||||
|
rc_mask_cfg->cfg_param_09[i], i + cfg_param_07);
|
||||||
|
|
||||||
|
data = (i == 0) ? (BIT(30) | (cfg_param_07 << 18)) : 0;
|
||||||
|
data |= (rc_mask_cfg->cfg_param_09[i] & 0x3FFFF);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG10, data);
|
||||||
|
data = ((rc_mask_cfg->cfg_param_09[i] >>
|
||||||
|
SDE_HW_RC_DATA_REG_SIZE) & 0x3FFFF);
|
||||||
|
_sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG10, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_hw_rc_init(struct sde_hw_dspp *hw_dspp)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
RC_STATE(hw_dspp).last_roi_list = kzalloc(
|
||||||
|
sizeof(struct msm_roi_list), GFP_KERNEL);
|
||||||
|
if (!RC_STATE(hw_dspp).last_roi_list)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
RC_STATE(hw_dspp).last_rc_mask_cfg = kzalloc(
|
||||||
|
sizeof(struct drm_msm_rc_mask_cfg), GFP_KERNEL);
|
||||||
|
if (!RC_STATE(hw_dspp).last_rc_mask_cfg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
71
msm/sde/sde_hw_rc.h
Normal file
71
msm/sde/sde_hw_rc.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SDE_HW_RC_H
|
||||||
|
#define _SDE_HW_RC_H
|
||||||
|
|
||||||
|
#include "sde_hw_mdss.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_init - Initialize RC internal state object and ops
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_init(struct sde_hw_dspp *hw_dspp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_check_mask - Validate RC mask configuration
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* @cfg: Pointer to configuration blob.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_check_mask(struct sde_hw_dspp *hw_dspp, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_setup_mask - Setup RC mask configuration
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* @cfg: Pointer to configuration blob.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_setup_mask(struct sde_hw_dspp *hw_dspp, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_check_pu_roi - Validate RC partial update region of interest
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* @cfg: Pointer to configuration blob.
|
||||||
|
* Return: 0 on success.
|
||||||
|
* > 0 on early return.
|
||||||
|
* < 0 on error.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_check_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_setup_pu_roi - Setup RC partial update region of interest
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* @cfg: Pointer to configuration blob.
|
||||||
|
* Return: 0 on success.
|
||||||
|
* > 0 on early return.
|
||||||
|
* < 0 on error.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_setup_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_setup_data_ahb - Program mask data with AHB
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* @cfg: Pointer to configuration blob.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_setup_data_ahb(struct sde_hw_dspp *hw_dspp, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_hw_rc_setup_data_dma - Program mask data with DMA
|
||||||
|
* @hw_dspp: DSPP instance.
|
||||||
|
* @cfg: Pointer to configuration blob.
|
||||||
|
* Return: 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int sde_hw_rc_setup_data_dma(struct sde_hw_dspp *hw_dspp, void *cfg);
|
||||||
|
|
||||||
|
#endif
|
@@ -806,6 +806,8 @@ int init_v12(struct sde_hw_reg_dma *cfg)
|
|||||||
v1_supported[LTM_INIT] = GRP_LTM_HW_BLK_SELECT;
|
v1_supported[LTM_INIT] = GRP_LTM_HW_BLK_SELECT;
|
||||||
v1_supported[LTM_ROI] = GRP_LTM_HW_BLK_SELECT;
|
v1_supported[LTM_ROI] = GRP_LTM_HW_BLK_SELECT;
|
||||||
v1_supported[LTM_VLUT] = GRP_LTM_HW_BLK_SELECT;
|
v1_supported[LTM_VLUT] = GRP_LTM_HW_BLK_SELECT;
|
||||||
|
v1_supported[RC_DATA] = (GRP_DSPP_HW_BLK_SELECT |
|
||||||
|
GRP_MDSS_HW_BLK_SELECT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <drm/msm_drm_pp.h>
|
#include <drm/msm_drm_pp.h>
|
||||||
#include "sde_reg_dma.h"
|
#include "sde_reg_dma.h"
|
||||||
#include "sde_hw_reg_dma_v1_color_proc.h"
|
#include "sde_hw_reg_dma_v1_color_proc.h"
|
||||||
@@ -65,6 +66,9 @@
|
|||||||
#define MEMCOLOR_MEM_SIZE ((sizeof(struct drm_msm_memcol)) + \
|
#define MEMCOLOR_MEM_SIZE ((sizeof(struct drm_msm_memcol)) + \
|
||||||
REG_DMA_HEADERS_BUFFER_SZ)
|
REG_DMA_HEADERS_BUFFER_SZ)
|
||||||
|
|
||||||
|
#define RC_MEM_SIZE ((RC_DATA_SIZE_MAX * 2 * sizeof(u32)) + \
|
||||||
|
REG_DMA_HEADERS_BUFFER_SZ)
|
||||||
|
|
||||||
#define QSEED3_MEM_SIZE (sizeof(struct sde_hw_scaler3_cfg) + \
|
#define QSEED3_MEM_SIZE (sizeof(struct sde_hw_scaler3_cfg) + \
|
||||||
(450 * sizeof(u32)) + \
|
(450 * sizeof(u32)) + \
|
||||||
REG_DMA_HEADERS_BUFFER_SZ)
|
REG_DMA_HEADERS_BUFFER_SZ)
|
||||||
@@ -133,6 +137,7 @@ static u32 feature_map[SDE_DSPP_MAX] = {
|
|||||||
[SDE_DSPP_DITHER] = REG_DMA_FEATURES_MAX,
|
[SDE_DSPP_DITHER] = REG_DMA_FEATURES_MAX,
|
||||||
[SDE_DSPP_HIST] = REG_DMA_FEATURES_MAX,
|
[SDE_DSPP_HIST] = REG_DMA_FEATURES_MAX,
|
||||||
[SDE_DSPP_AD] = REG_DMA_FEATURES_MAX,
|
[SDE_DSPP_AD] = REG_DMA_FEATURES_MAX,
|
||||||
|
[SDE_DSPP_RC] = RC_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 sspp_feature_map[SDE_SSPP_MAX] = {
|
static u32 sspp_feature_map[SDE_SSPP_MAX] = {
|
||||||
@@ -159,6 +164,7 @@ static u32 feature_reg_dma_sz[SDE_DSPP_MAX] = {
|
|||||||
[SDE_DSPP_HSIC] = HSIC_MEM_SIZE,
|
[SDE_DSPP_HSIC] = HSIC_MEM_SIZE,
|
||||||
[SDE_DSPP_SIXZONE] = SIXZONE_MEM_SIZE,
|
[SDE_DSPP_SIXZONE] = SIXZONE_MEM_SIZE,
|
||||||
[SDE_DSPP_MEMCOLOR] = MEMCOLOR_MEM_SIZE,
|
[SDE_DSPP_MEMCOLOR] = MEMCOLOR_MEM_SIZE,
|
||||||
|
[SDE_DSPP_RC] = RC_MEM_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 sspp_feature_reg_dma_sz[SDE_SSPP_MAX] = {
|
static u32 sspp_feature_reg_dma_sz[SDE_SSPP_MAX] = {
|
||||||
@@ -1117,6 +1123,89 @@ void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg)
|
|||||||
DRM_ERROR("failed to kick off ret %d\n", rc);
|
DRM_ERROR("failed to kick off ret %d\n", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int reg_dmav1_setup_rc_datav1(struct sde_hw_dspp *ctx, void *cfg)
|
||||||
|
{
|
||||||
|
struct drm_msm_rc_mask_cfg *rc_mask_cfg;
|
||||||
|
struct sde_hw_reg_dma_ops *dma_ops;
|
||||||
|
struct sde_reg_dma_kickoff_cfg kick_off;
|
||||||
|
struct sde_hw_cp_cfg *hw_cfg = cfg;
|
||||||
|
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
|
||||||
|
int rc = 0;
|
||||||
|
u32 i = 0;
|
||||||
|
u32 *data = NULL;
|
||||||
|
u32 buf_sz = 0, abs_offset = 0;
|
||||||
|
u32 cfg_param_07;
|
||||||
|
u64 cfg_param_09;
|
||||||
|
|
||||||
|
rc = reg_dma_dspp_check(ctx, cfg, RC_DATA);
|
||||||
|
if (rc) {
|
||||||
|
DRM_ERROR("invalid dma dspp check rc = %d\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg)) {
|
||||||
|
DRM_ERROR("invalid size of payload len %d exp %zd\n",
|
||||||
|
hw_cfg->len, sizeof(struct drm_msm_rc_mask_cfg));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_mask_cfg = hw_cfg->payload;
|
||||||
|
buf_sz = rc_mask_cfg->cfg_param_08 * 2 * sizeof(u32);
|
||||||
|
abs_offset = ctx->hw.blk_off + ctx->cap->sblk->rc.base + 0x28;
|
||||||
|
|
||||||
|
dma_ops = sde_reg_dma_get_ops();
|
||||||
|
dma_ops->reset_reg_dma_buf(dspp_buf[RC_DATA][ctx->idx]);
|
||||||
|
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, RC_DATA,
|
||||||
|
dspp_buf[RC_DATA][ctx->idx]);
|
||||||
|
|
||||||
|
REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
|
||||||
|
rc = dma_ops->setup_payload(&dma_write_cfg);
|
||||||
|
if (rc) {
|
||||||
|
DRM_ERROR("write decode select failed ret %d\n", rc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("allocating %u bytes of memory for dma\n", buf_sz);
|
||||||
|
data = kzalloc(buf_sz, GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
DRM_ERROR("memory allocation failed ret %d\n", rc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_param_07 = rc_mask_cfg->cfg_param_07;
|
||||||
|
for (i = 0; i < rc_mask_cfg->cfg_param_08; i++) {
|
||||||
|
cfg_param_09 = rc_mask_cfg->cfg_param_09[i];
|
||||||
|
DRM_DEBUG_DRIVER("cfg_param_09[%d] = 0x%016lX at %u\n", i,
|
||||||
|
cfg_param_09,
|
||||||
|
i + cfg_param_07);
|
||||||
|
data[i * 2] = (i == 0) ? (BIT(30) | (cfg_param_07 << 18)) : 0;
|
||||||
|
data[i * 2] |= (cfg_param_09 & 0x3FFFF);
|
||||||
|
data[i * 2 + 1] = ((cfg_param_09 >> 18) & 0x3FFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_DMA_SETUP_OPS(dma_write_cfg, abs_offset, data, buf_sz,
|
||||||
|
REG_BLK_WRITE_INC, 0, 0, 0);
|
||||||
|
rc = dma_ops->setup_payload(&dma_write_cfg);
|
||||||
|
if (rc) {
|
||||||
|
DRM_ERROR("rc dma write failed ret %d\n", rc);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defer trigger to kickoff phase */
|
||||||
|
REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
|
||||||
|
dspp_buf[RC_DATA][ctx->idx], REG_DMA_WRITE,
|
||||||
|
DMA_CTL_QUEUE0, WRITE_TRIGGER);
|
||||||
|
rc = dma_ops->kick_off(&kick_off);
|
||||||
|
if (rc) {
|
||||||
|
DRM_ERROR("failed to kick off ret %d\n", rc);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
kfree(data);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static void _dspp_pccv4_off(struct sde_hw_dspp *ctx, void *cfg)
|
static void _dspp_pccv4_off(struct sde_hw_dspp *ctx, void *cfg)
|
||||||
{
|
{
|
||||||
struct sde_reg_dma_kickoff_cfg kick_off;
|
struct sde_reg_dma_kickoff_cfg kick_off;
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SDE_HW_REG_DMA_V1_COLOR_PROC_H
|
#ifndef _SDE_HW_REG_DMA_V1_COLOR_PROC_H
|
||||||
#define _SDE_HW_REG_DMA_V1_COLOR_PROC_H
|
#define _SDE_HW_REG_DMA_V1_COLOR_PROC_H
|
||||||
|
|
||||||
@@ -242,6 +243,14 @@ void reg_dmav1_setup_ltm_roiv1(struct sde_hw_dspp *ctx, void *cfg);
|
|||||||
*/
|
*/
|
||||||
void reg_dmav1_setup_ltm_vlutv1(struct sde_hw_dspp *ctx, void *cfg);
|
void reg_dmav1_setup_ltm_vlutv1(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reg_dmav1_setup_rc_datav1() - RC DATA v1 implementation using reg dma v1.
|
||||||
|
* @ctx: dspp ctx info
|
||||||
|
* @cfg: pointer to struct sde_hw_cp_cfg
|
||||||
|
* @returns: 0 if success, non-zero otherwise
|
||||||
|
*/
|
||||||
|
int reg_dmav1_setup_rc_datav1(struct sde_hw_dspp *ctx, void *cfg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reg_dmav1_deinit_ltm_ops() - deinitialize the ltm feature op for sde v4
|
* reg_dmav1_deinit_ltm_ops() - deinitialize the ltm feature op for sde v4
|
||||||
* which were initialized.
|
* which were initialized.
|
||||||
|
@@ -57,6 +57,7 @@ enum sde_reg_dma_read_sel {
|
|||||||
* @LTM_INIT: LTM INIT
|
* @LTM_INIT: LTM INIT
|
||||||
* @LTM_ROI: LTM ROI
|
* @LTM_ROI: LTM ROI
|
||||||
* @LTM_VLUT: LTM VLUT
|
* @LTM_VLUT: LTM VLUT
|
||||||
|
* @RC_DATA: Rounded corner data
|
||||||
* @REG_DMA_FEATURES_MAX: invalid selection
|
* @REG_DMA_FEATURES_MAX: invalid selection
|
||||||
*/
|
*/
|
||||||
enum sde_reg_dma_features {
|
enum sde_reg_dma_features {
|
||||||
@@ -75,6 +76,7 @@ enum sde_reg_dma_features {
|
|||||||
LTM_INIT,
|
LTM_INIT,
|
||||||
LTM_ROI,
|
LTM_ROI,
|
||||||
LTM_VLUT,
|
LTM_VLUT,
|
||||||
|
RC_DATA,
|
||||||
REG_DMA_FEATURES_MAX,
|
REG_DMA_FEATURES_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -152,6 +154,7 @@ enum sde_reg_dma_setup_ops {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define REG_DMA_BLK_MAX 32
|
#define REG_DMA_BLK_MAX 32
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum sde_reg_dma_blk - defines blocks for which reg dma op should be
|
* enum sde_reg_dma_blk - defines blocks for which reg dma op should be
|
||||||
* performed
|
* performed
|
||||||
|
Reference in New Issue
Block a user