drm: msm: sde: Add support for SPR V2

Introduce support for SPR V2 features. Full validation
has been performed.

Change-Id: Ia83c06b30729fef12cae014ee5ce4792236a0a8a
Signed-off-by: Christopher Braga <quic_cbraga@quicinc.com>
This commit is contained in:
Christopher Braga
2022-10-20 11:57:01 -04:00
parent be07875590
commit d617e25729
12 changed files with 910 additions and 162 deletions

View File

@@ -587,11 +587,11 @@ struct drm_msm_ltm_buffer {
#define SPR_INIT_PARAM_SIZE_3 16 #define SPR_INIT_PARAM_SIZE_3 16
#define SPR_INIT_PARAM_SIZE_4 24 #define SPR_INIT_PARAM_SIZE_4 24
#define SPR_INIT_PARAM_SIZE_5 32 #define SPR_INIT_PARAM_SIZE_5 32
#define SPR_INIT_PARAM_SIZE_6 7
#define SPR_FLAG_BYPASS (1 << 0) #define SPR_FLAG_BYPASS (1 << 0)
/** /**
* struct drm_msm_spr_init_cfg - SPR initial configuration structure * struct drm_msm_spr_init_cfg - SPR initial configuration structure
*
*/ */
struct drm_msm_spr_init_cfg { struct drm_msm_spr_init_cfg {
__u64 flags; __u64 flags;
@@ -613,8 +613,25 @@ struct drm_msm_spr_init_cfg {
__u16 cfg15[SPR_INIT_PARAM_SIZE_5]; __u16 cfg15[SPR_INIT_PARAM_SIZE_5];
int cfg16[SPR_INIT_PARAM_SIZE_3]; int cfg16[SPR_INIT_PARAM_SIZE_3];
int cfg17[SPR_INIT_PARAM_SIZE_4]; int cfg17[SPR_INIT_PARAM_SIZE_4];
__u16 cfg18_en;
__u8 cfg18[SPR_INIT_PARAM_SIZE_6];
}; };
/**
* struct drm_msm_spr_udc_cfg - SPR UDC configuration structure
*/
#define SPR_UDC_PARAM_SIZE_1 27
#define SPR_UDC_PARAM_SIZE_2 1536
struct drm_msm_spr_udc_cfg {
__u64 flags;
__u16 init_cfg4;
__u16 init_cfg11[SPR_INIT_PARAM_SIZE_1];
__u16 cfg1[SPR_UDC_PARAM_SIZE_1];
__u16 cfg2[SPR_UDC_PARAM_SIZE_2];
};
#define FEATURE_DEM #define FEATURE_DEM
#define CFG0_PARAM_LEN 8 #define CFG0_PARAM_LEN 8
#define CFG1_PARAM_LEN 8 #define CFG1_PARAM_LEN 8

View File

@@ -736,6 +736,52 @@ static int _check_rc_mask_feature(struct sde_hw_dspp *hw_dspp,
return ret; return ret;
} }
static int _check_spr_init_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_spr_init_config) {
DRM_ERROR("invalid spr validate op");
return -EINVAL;
}
ret = hw_dspp->ops.validate_spr_init_config(hw_dspp, hw_cfg);
if (ret)
DRM_ERROR("failed to validate spr config %d", ret);
return ret;
}
static int _check_spr_udc_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_spr_udc_config) {
DRM_ERROR("invalid spr udc validate op");
return -EINVAL;
}
ret = hw_dspp->ops.validate_spr_udc_config(hw_dspp, hw_cfg);
if (ret)
DRM_ERROR("failed to validate spr udc config %d", ret);
return ret;
}
static int _set_rc_mask_feature(struct sde_hw_dspp *hw_dspp, static int _set_rc_mask_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg, struct sde_hw_cp_cfg *hw_cfg,
struct sde_crtc *sde_crtc) struct sde_crtc *sde_crtc)
@@ -912,6 +958,23 @@ static int _set_spr_init_feature(struct sde_hw_dspp *hw_dspp,
return ret; return ret;
} }
static int _set_spr_udc_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg,
struct sde_crtc *sde_crtc)
{
int ret = 0;
if (!sde_crtc || !hw_dspp) {
DRM_ERROR("invalid arguments\n");
ret = -EINVAL;
} else {
if (hw_dspp->ops.setup_spr_udc_config)
hw_dspp->ops.setup_spr_udc_config(hw_dspp, hw_cfg);
}
return ret;
}
static int _set_demura_feature(struct sde_hw_dspp *hw_dspp, static int _set_demura_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg, struct sde_hw_cp_cfg *hw_cfg,
struct sde_crtc *sde_crtc) struct sde_crtc *sde_crtc)
@@ -948,6 +1011,8 @@ feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
do { \ do { \
memset(wrappers, 0, sizeof(wrappers)); \ memset(wrappers, 0, sizeof(wrappers)); \
wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = _check_rc_mask_feature; \ wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = _check_rc_mask_feature; \
wrappers[SDE_CP_CRTC_DSPP_SPR_INIT] = _check_spr_init_feature; \
wrappers[SDE_CP_CRTC_DSPP_SPR_UDC] = _check_spr_udc_feature; \
} while (0) } while (0)
feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
@@ -993,6 +1058,7 @@ do { \
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; \ wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = _set_rc_mask_feature; \
wrappers[SDE_CP_CRTC_DSPP_SPR_INIT] = _set_spr_init_feature; \ wrappers[SDE_CP_CRTC_DSPP_SPR_INIT] = _set_spr_init_feature; \
wrappers[SDE_CP_CRTC_DSPP_SPR_UDC] = _set_spr_udc_feature; \
wrappers[SDE_CP_CRTC_DSPP_DEMURA_INIT] = _set_demura_feature; \ wrappers[SDE_CP_CRTC_DSPP_DEMURA_INIT] = _set_demura_feature; \
} while (0) } while (0)
@@ -1784,6 +1850,7 @@ static const int dspp_feature_to_sub_blk_tbl[SDE_CP_CRTC_MAX_FEATURES] = {
[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_SPR_INIT] = SDE_DSPP_SPR, [SDE_CP_CRTC_DSPP_SPR_INIT] = SDE_DSPP_SPR,
[SDE_CP_CRTC_DSPP_SPR_UDC] = SDE_DSPP_SPR,
[SDE_CP_CRTC_DSPP_RC_MASK] = SDE_DSPP_RC, [SDE_CP_CRTC_DSPP_RC_MASK] = SDE_DSPP_RC,
[SDE_CP_CRTC_DSPP_DEMURA_INIT] = SDE_DSPP_DEMURA, [SDE_CP_CRTC_DSPP_DEMURA_INIT] = SDE_DSPP_DEMURA,
[SDE_CP_CRTC_DSPP_DEMURA_BACKLIGHT] = SDE_DSPP_DEMURA, [SDE_CP_CRTC_DSPP_DEMURA_BACKLIGHT] = SDE_DSPP_DEMURA,
@@ -2190,15 +2257,6 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
goto exit; goto exit;
} }
rc = _sde_cp_crtc_update_pu_features(crtc, &need_flush);
if (rc) {
DRM_ERROR("failed to set pu features, skip cp updates\n");
goto exit;
} else if (need_flush) {
set_dspp_flush = true;
set_lm_flush = true;
}
list_for_each_entry_safe(prop_node, n, &sde_crtc->cp_dirty_list, list_for_each_entry_safe(prop_node, n, &sde_crtc->cp_dirty_list,
cp_dirty_list) { cp_dirty_list) {
_sde_cp_crtc_commit_feature(prop_node, sde_crtc); _sde_cp_crtc_commit_feature(prop_node, sde_crtc);
@@ -2210,6 +2268,15 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
set_lm_flush = true; set_lm_flush = true;
} }
rc = _sde_cp_crtc_update_pu_features(crtc, &need_flush);
if (rc) {
DRM_ERROR("failed to set pu features, skip cp updates\n");
goto exit;
} else if (need_flush) {
set_dspp_flush = true;
set_lm_flush = true;
}
_sde_cp_dspp_flush_helper(sde_crtc, SDE_CP_CRTC_DSPP_SB); _sde_cp_dspp_flush_helper(sde_crtc, SDE_CP_CRTC_DSPP_SB);
if (!list_empty(&sde_crtc->ad_active)) { if (!list_empty(&sde_crtc->ad_active)) {
@@ -3194,6 +3261,7 @@ static void _dspp_rc_install_property(struct drm_crtc *crtc)
static void _dspp_spr_install_property(struct drm_crtc *crtc) static void _dspp_spr_install_property(struct drm_crtc *crtc)
{ {
char feature_name[256];
struct sde_kms *kms = NULL; struct sde_kms *kms = NULL;
u32 version = 0; u32 version = 0;
@@ -3205,10 +3273,24 @@ static void _dspp_spr_install_property(struct drm_crtc *crtc)
version = kms->catalog->dspp[0].sblk->spr.version >> 16; version = kms->catalog->dspp[0].sblk->spr.version >> 16;
switch (version) { switch (version) {
case 2:
snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
"SDE_SPR_UDC_CFG_V", version);
_sde_cp_crtc_install_blob_property(crtc, feature_name,
SDE_CP_CRTC_DSPP_SPR_UDC,
sizeof(struct drm_msm_spr_udc_cfg));
snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
"SDE_SPR_INIT_CFG_V", version);
_sde_cp_crtc_install_blob_property(crtc, feature_name,
SDE_CP_CRTC_DSPP_SPR_INIT,
sizeof(struct drm_msm_spr_init_cfg));
break;
case 1: case 1:
_sde_cp_crtc_install_blob_property(crtc, "SDE_SPR_INIT_CFG_V1", snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
SDE_CP_CRTC_DSPP_SPR_INIT, "SDE_SPR_INIT_CFG_V", version);
sizeof(struct drm_msm_spr_init_cfg)); _sde_cp_crtc_install_blob_property(crtc, feature_name,
SDE_CP_CRTC_DSPP_SPR_INIT,
sizeof(struct drm_msm_spr_init_cfg));
break; break;
default: default:
DRM_ERROR("version %d not supported\n", version); DRM_ERROR("version %d not supported\n", version);

View File

@@ -104,6 +104,7 @@ enum sde_cp_crtc_features {
SDE_CP_CRTC_DSPP_SB, SDE_CP_CRTC_DSPP_SB,
SDE_CP_CRTC_DSPP_RC_MASK, SDE_CP_CRTC_DSPP_RC_MASK,
SDE_CP_CRTC_DSPP_SPR_INIT, SDE_CP_CRTC_DSPP_SPR_INIT,
SDE_CP_CRTC_DSPP_SPR_UDC,
SDE_CP_CRTC_DSPP_DEMURA_INIT, SDE_CP_CRTC_DSPP_DEMURA_INIT,
SDE_CP_CRTC_DSPP_DEMURA_BACKLIGHT, SDE_CP_CRTC_DSPP_DEMURA_BACKLIGHT,
SDE_CP_CRTC_DSPP_DEMURA_BOOT_PLANE, SDE_CP_CRTC_DSPP_DEMURA_BOOT_PLANE,

View File

@@ -473,6 +473,18 @@ enum {
SDE_LTM_MAX SDE_LTM_MAX
}; };
/**
* SPR sub-features
* @SDE_SPR_INIT SPR INIT feature
* @SDE_SPR_UDC SPR UDC feature
* @SDE_SPR_MAX maximum value
*/
enum {
SDE_SPR_INIT = 0x1,
SDE_SPR_UDC,
SDE_SPR_MAX
};
/** /**
* PINGPONG sub-blocks * PINGPONG sub-blocks
* @SDE_PINGPONG_TE Tear check block * @SDE_PINGPONG_TE Tear check block

View File

@@ -746,6 +746,123 @@ void sde_demura_pu_cfg(struct sde_hw_dspp *dspp, void *cfg)
((hw_cfg) ? hw_cfg->panel_height : -1)); ((hw_cfg) ? hw_cfg->panel_height : -1));
} }
int sde_spr_check_init_cfg(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_spr_init_cfg *spr_payload;
struct sde_hw_cp_cfg *hw_cfg = cfg;
int rc = 0;
if (!ctx || !cfg)
return -EINVAL;
if (!hw_cfg->payload)
return 0;
spr_payload = hw_cfg->payload;
if (spr_payload->cfg18_en) {
bool invalid = spr_payload->cfg11[0] != 1 || spr_payload->cfg11[1] != 0 ||
spr_payload->cfg11[2] != 1;
if (spr_payload->cfg4 || invalid) {
DRM_ERROR("CFG18 can't be enabled with this config. CFG4: %u CFG11: %u\n",
spr_payload->cfg4, invalid);
return -EINVAL;
}
}
return rc;
}
int sde_spr_check_udc_cfg(struct sde_hw_dspp *ctx, void *cfg)
{
uint32_t j = 0, i = 0;
struct drm_msm_spr_udc_cfg *spr_payload;
struct sde_hw_cp_cfg *hw_cfg = cfg;
bool invalid = false;
if (!ctx || !cfg)
return -EINVAL;
if (!hw_cfg->payload)
return 0;
spr_payload = hw_cfg->payload;
invalid = !(spr_payload->init_cfg11[0] || spr_payload->init_cfg11[1] ||
spr_payload->init_cfg11[2]);
if (spr_payload->init_cfg4 || invalid) {
DRM_ERROR("SPR UDC can not be used with this config. CFG4: %u CFG11: %u",
spr_payload->init_cfg4, invalid);
return -EINVAL;
}
for (i = 0; i < 3; i++) {
uint32_t max_h, max_v, limit;
uint32_t cfg_1_start = (SPR_UDC_PARAM_SIZE_2 / 3) * i;
uint32_t x1 =
spr_payload->cfg1[(SPR_UDC_PARAM_SIZE_1 / 3) * i] & 0xffff;
uint32_t y1 =
spr_payload->cfg1[(SPR_UDC_PARAM_SIZE_1 / 3) * i + 1] & 0xffff;
uint32_t w = spr_payload->cfg1[(SPR_UDC_PARAM_SIZE_1 / 3) * i + 2];
uint32_t lines = spr_payload->cfg1[(SPR_UDC_PARAM_SIZE_1 / 3) * i + 3];
uint32_t x2 = x1 + w;
uint32_t y2 = y1 + lines;
switch (spr_payload->init_cfg11[i]) {
case 0:
max_h = hw_cfg->panel_width;
max_v = hw_cfg->panel_height;
break;
case 1:
max_h = (hw_cfg->panel_width + 1) >> 1;
max_v = hw_cfg->panel_height;
break;
case 2:
max_h = (hw_cfg->panel_width * 2 + 2) / 3;
max_v = hw_cfg->panel_height;
break;
default:
DRM_ERROR("Can't calculate decimation");
return -EINVAL;
}
if (x2 >= max_h) {
DRM_ERROR("Invalid CFG1 - C%u x2 %u", i, x2);
return -EINVAL;
} else if (y2 >= max_v) {
DRM_ERROR("Invalid CFG1 - C%u y2 %u", i, y2);
return -EINVAL;
} else if (lines < 2 || lines > 256) {
DRM_ERROR("Invalid CFG1 - C%u Lines %u", i, lines);
return -EINVAL;
} else if (w < 2 || w > 512) {
DRM_ERROR("Invalid CFG1 - C%u W %u", i, w);
return -EINVAL;
}
j = 0;
limit = (w >> 1) + 1;
for (j = 0; j < lines; j++) {
uint32_t o1 = spr_payload->cfg2[cfg_1_start + (j*2)];
uint32_t o2 = spr_payload->cfg2[cfg_1_start + (j*2) + 1];
if (o1 > limit) {
DRM_ERROR("Invalid CFG2 - C%u L%u, o1 exceeds limits",
i, j);
return -EINVAL;
} else if (o2 > limit) {
DRM_ERROR("Invalid CFG2 - C%u L%u, o2 exceeds limits",
i, j);
return -EINVAL;
}
}
}
return 0;
}
int sde_spr_read_opr_value(struct sde_hw_dspp *ctx, uint32_t *opr_value) int sde_spr_read_opr_value(struct sde_hw_dspp *ctx, uint32_t *opr_value)
{ {
uint32_t reg_off; uint32_t reg_off;

View File

@@ -154,6 +154,20 @@ void sde_setup_fp16_unmultv1(struct sde_hw_pipe *ctx,
*/ */
void sde_demura_pu_cfg(struct sde_hw_dspp *ctx, void *cfg); void sde_demura_pu_cfg(struct sde_hw_dspp *ctx, void *cfg);
/**
* sde_spr_check_init_cfg - api to validate the SPR configuration for the frame
* @ctx: pointer to dspp object.
* @cfg: spr configuration for the frame.
*/
int sde_spr_check_init_cfg(struct sde_hw_dspp *ctx, void *cfg);
/**
* sde_spr_check_udc_cfg - api to validate the SPR UDC configuration for the frame
* @ctx: pointer to dspp object.
* @cfg: spr UDC configuration for the frame.
*/
int sde_spr_check_udc_cfg(struct sde_hw_dspp *ctx, void *cfg);
/** /**
* sde_spr_read_opr_value - api to read spr opr value * sde_spr_read_opr_value - api to read spr opr value
* @ctx: pointer to dspp object. * @ctx: pointer to dspp object.

View File

@@ -331,11 +331,15 @@ static void dspp_spr(struct sde_hw_dspp *c)
return; return;
} }
c->ops.validate_spr_init_config = NULL;
c->ops.validate_spr_udc_config = NULL;
c->ops.setup_spr_init_config = NULL; c->ops.setup_spr_init_config = NULL;
c->ops.setup_spr_udc_config = NULL;
c->ops.setup_spr_pu_config = NULL; c->ops.setup_spr_pu_config = NULL;
c->ops.read_spr_opr_value = NULL;
if (c->cap->sblk->spr.version == SDE_COLOR_PROCESS_VER(0x1, 0x0)) { if (c->cap->sblk->spr.version == SDE_COLOR_PROCESS_VER(0x1, 0x0)) {
ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_SPR, c->idx); ret = reg_dmav2_init_spr_op_v1(SDE_SPR_INIT, c->idx);
if (ret) { if (ret) {
SDE_ERROR("regdma init failed for spr, ret %d\n", ret); SDE_ERROR("regdma init failed for spr, ret %d\n", ret);
return; return;
@@ -344,6 +348,25 @@ static void dspp_spr(struct sde_hw_dspp *c)
c->ops.setup_spr_init_config = reg_dmav1_setup_spr_init_cfgv1; c->ops.setup_spr_init_config = reg_dmav1_setup_spr_init_cfgv1;
c->ops.setup_spr_pu_config = reg_dmav1_setup_spr_pu_cfgv1; c->ops.setup_spr_pu_config = reg_dmav1_setup_spr_pu_cfgv1;
c->ops.read_spr_opr_value = sde_spr_read_opr_value; c->ops.read_spr_opr_value = sde_spr_read_opr_value;
} else if (c->cap->sblk->spr.version == SDE_COLOR_PROCESS_VER(0x2, 0x0)) {
ret = reg_dmav2_init_spr_op_v1(SDE_SPR_INIT, c->idx);
if (ret) {
SDE_ERROR("regdma init failed for spr, ret %d\n", ret);
return;
}
ret = reg_dmav2_init_spr_op_v1(SDE_SPR_UDC, c->idx);
if (ret) {
SDE_ERROR("regdma init failed for spr udc, ret %d\n", ret);
return;
}
c->ops.validate_spr_init_config = sde_spr_check_init_cfg;
c->ops.validate_spr_udc_config = sde_spr_check_udc_cfg;
c->ops.setup_spr_init_config = reg_dmav1_setup_spr_init_cfgv2;
c->ops.setup_spr_udc_config = reg_dmav1_setup_spr_udc_cfgv2;
c->ops.setup_spr_pu_config = reg_dmav1_setup_spr_pu_cfgv2;
c->ops.read_spr_opr_value = sde_spr_read_opr_value;
} }
} }

View File

@@ -256,6 +256,22 @@ struct sde_hw_dspp_ops {
*/ */
int (*setup_rc_data)(struct sde_hw_dspp *ctx, void *cfg); int (*setup_rc_data)(struct sde_hw_dspp *ctx, void *cfg);
/**
* validate_spr_init_config - Validate SPR configuration
* @ctx: Pointer to dspp context.
* @cfg: Pointer to configuration.
* Return: 0 on success, non-zero otherwise.
*/
int (*validate_spr_init_config)(struct sde_hw_dspp *ctx, void *cfg);
/**
* validate_spr_udc_config - Validate SPR configuration
* @ctx: Pointer to dspp context.
* @cfg: Pointer to configuration.
* Return: 0 on success, non-zero otherwise.
*/
int (*validate_spr_udc_config)(struct sde_hw_dspp *ctx, void *cfg);
/** /**
* setup_spr_init_config - function to configure spr hw block * setup_spr_init_config - function to configure spr hw block
* @ctx: Pointer to dspp context * @ctx: Pointer to dspp context
@@ -263,6 +279,13 @@ struct sde_hw_dspp_ops {
*/ */
void (*setup_spr_init_config)(struct sde_hw_dspp *ctx, void *cfg); void (*setup_spr_init_config)(struct sde_hw_dspp *ctx, void *cfg);
/**
* setup_spr_udc_config - function to configure spr hw block
* @ctx: Pointer to dspp context
* @cfg: Pointer to configuration
*/
void (*setup_spr_udc_config)(struct sde_hw_dspp *ctx, void *cfg);
/** /**
* setup_spr_pu_config - function to configure spr hw block pu offsets * setup_spr_pu_config - function to configure spr hw block pu offsets
* @ctx: Pointer to dspp context * @ctx: Pointer to dspp context
@@ -315,6 +338,7 @@ struct sde_hw_dspp_ops {
* @sb_dma_in_use: hint indicating if sb dma is being used for this dspp * @sb_dma_in_use: hint indicating if sb dma is being used for this dspp
* @ops: Pointer to operations possible for this DSPP * @ops: Pointer to operations possible for this DSPP
* @ltm_checksum_support: flag to check if checksum present * @ltm_checksum_support: flag to check if checksum present
* @spr_cfg_18_default: Default SPR cfg 18 HW details. Needed for PU handling
*/ */
struct sde_hw_dspp { struct sde_hw_dspp {
struct sde_hw_blk_reg_map hw; struct sde_hw_blk_reg_map hw;
@@ -327,6 +351,7 @@ struct sde_hw_dspp {
const struct sde_dspp_cfg *cap; const struct sde_dspp_cfg *cap;
bool sb_dma_in_use; bool sb_dma_in_use;
bool ltm_checksum_support; bool ltm_checksum_support;
u32 spr_cfg_18_default;
/* Ops */ /* Ops */
struct sde_hw_dspp_ops ops; struct sde_hw_dspp_ops ops;

View File

@@ -908,6 +908,8 @@ int init_v12(struct sde_hw_reg_dma *cfg)
GRP_MDSS_HW_BLK_SELECT); GRP_MDSS_HW_BLK_SELECT);
v1_supported[SPR_INIT] = (GRP_DSPP_HW_BLK_SELECT | v1_supported[SPR_INIT] = (GRP_DSPP_HW_BLK_SELECT |
GRP_MDSS_HW_BLK_SELECT); GRP_MDSS_HW_BLK_SELECT);
v1_supported[SPR_UDC] = (GRP_DSPP_HW_BLK_SELECT |
GRP_MDSS_HW_BLK_SELECT);
v1_supported[SPR_PU_CFG] = (GRP_DSPP_HW_BLK_SELECT | v1_supported[SPR_PU_CFG] = (GRP_DSPP_HW_BLK_SELECT |
GRP_MDSS_HW_BLK_SELECT); GRP_MDSS_HW_BLK_SELECT);
v1_supported[DEMURA_CFG] = MDSS | DSPP0 | DSPP1; v1_supported[DEMURA_CFG] = MDSS | DSPP0 | DSPP1;

View File

@@ -44,6 +44,8 @@
#define REG_DMA_LTM_VLUT_DISABLE_OP_MASK 0xFEFF8CAD #define REG_DMA_LTM_VLUT_DISABLE_OP_MASK 0xFEFF8CAD
#define REG_DMA_LTM_UPDATE_REQ_MASK 0xFFFFFFFE #define REG_DMA_LTM_UPDATE_REQ_MASK 0xFFFFFFFE
#define REG_DMA_SPR_CONFIG_MASK ~0xFDFFFFFF
#define GAMUT_LUT_MEM_SIZE ((sizeof(struct drm_msm_3d_gamut)) + \ #define GAMUT_LUT_MEM_SIZE ((sizeof(struct drm_msm_3d_gamut)) + \
REG_DMA_HEADERS_BUFFER_SZ) REG_DMA_HEADERS_BUFFER_SZ)
#define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * sizeof(u32)) #define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * sizeof(u32))
@@ -81,6 +83,8 @@
REG_DMA_HEADERS_BUFFER_SZ) REG_DMA_HEADERS_BUFFER_SZ)
#define SPR_INIT_MEM_SIZE ((sizeof(struct drm_msm_spr_init_cfg)) + \ #define SPR_INIT_MEM_SIZE ((sizeof(struct drm_msm_spr_init_cfg)) + \
REG_DMA_HEADERS_BUFFER_SZ) REG_DMA_HEADERS_BUFFER_SZ)
#define SPR_UDC_MEM_SIZE ((sizeof(struct drm_msm_spr_udc_cfg)) + \
REG_DMA_HEADERS_BUFFER_SZ)
#define DEMURA_MEM_SIZE ((sizeof(struct drm_msm_dem_cfg)) + \ #define DEMURA_MEM_SIZE ((sizeof(struct drm_msm_dem_cfg)) + \
REG_DMA_HEADERS_BUFFER_SZ) REG_DMA_HEADERS_BUFFER_SZ)
@@ -350,16 +354,6 @@ static int _reg_dma_init_dspp_feature_buf(int feature, enum sde_dspp idx)
rc = reg_dma_buf_init( rc = reg_dma_buf_init(
&dspp_buf[MEMC_PROT][idx], &dspp_buf[MEMC_PROT][idx],
feature_reg_dma_sz[feature]); feature_reg_dma_sz[feature]);
} else if (feature == SDE_DSPP_SPR) {
rc = reg_dma_buf_init(
&dspp_buf[SPR_INIT][idx],
feature_reg_dma_sz[feature]);
if (rc)
return rc;
rc = reg_dma_buf_init(
&dspp_buf[SPR_PU_CFG][idx],
feature_reg_dma_sz[feature]);
} else { } else {
rc = reg_dma_buf_init( rc = reg_dma_buf_init(
&dspp_buf[feature_map[feature]][idx], &dspp_buf[feature_map[feature]][idx],
@@ -4853,6 +4847,51 @@ exit:
kvfree(data); kvfree(data);
} }
int reg_dmav2_init_spr_op_v1(int feature, enum sde_dspp dspp_idx)
{
int rc = -EOPNOTSUPP;
struct sde_hw_reg_dma_ops *dma_ops;
bool is_supported = false;
enum sde_reg_dma_features dma_features[2];
u32 i, blk, buffer_size, dma_feature_cnt = 0;
/* SPR blocks are hardwired to DSPP blocks */
if (feature >= SDE_SPR_MAX || dspp_idx >= DSPP_MAX) {
DRM_ERROR("invalid feature %x max %x dspp idx %x max %xd\n",
feature, SDE_SPR_MAX, dspp_idx, DSPP_MAX);
return rc;
}
dma_ops = sde_reg_dma_get_ops();
if (IS_ERR_OR_NULL(dma_ops))
return -EOPNOTSUPP;
if (feature == SDE_SPR_INIT) {
dma_features[dma_feature_cnt++] = SPR_INIT;
dma_features[dma_feature_cnt++] = SPR_PU_CFG;
buffer_size = SPR_INIT_MEM_SIZE;
} else if (feature == SDE_SPR_UDC) {
dma_features[dma_feature_cnt++] = SPR_UDC;
buffer_size = SPR_UDC_MEM_SIZE;
}
rc = 0;
blk = dspp_mapping[dspp_idx];
for (i = 0; (i < dma_feature_cnt) && !rc; i++) {
rc = dma_ops->check_support(dma_features[i], blk, &is_supported);
if (!rc) {
if (is_supported)
rc = reg_dma_buf_init(&dspp_buf[dma_features[i]][dspp_idx],
buffer_size);
else
rc = -EOPNOTSUPP;
}
}
return rc;
}
int reg_dmav1_setup_spr_cfg3_params(struct sde_hw_dspp *ctx, int reg_dmav1_setup_spr_cfg3_params(struct sde_hw_dspp *ctx,
struct drm_msm_spr_init_cfg *payload, struct drm_msm_spr_init_cfg *payload,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg, struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
@@ -4932,13 +4971,65 @@ int reg_dmav1_setup_spr_cfg4_params(struct sde_hw_dspp *ctx,
return rc; return rc;
} }
int reg_dmav1_setup_spr_cfg5_params(struct sde_hw_dspp *ctx,
struct drm_msm_spr_init_cfg *payload,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
struct sde_hw_reg_dma_ops *dma_ops)
{
uint32_t reg_off, base_off, i;
uint32_t reg[1];
int rc = 0;
if (!payload->cfg18_en) {
ctx->spr_cfg_18_default = 0;
return rc;
}
reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg18[0], 3, 16) |
APPLY_MASK_AND_SHIFT(payload->cfg18[1], 3, 20) |
APPLY_MASK_AND_SHIFT(payload->cfg18[2], 3, 24);
for (i = 0; i < 4; i++) {
uint32_t val = 0;
switch (payload->cfg18[3 + i]) {
case 0:
val = 0;
break;
case 2:
val = 1;
break;
case 4:
val = 2;
break;
default:
DRM_ERROR("Invalid payload for cfg18. Val %u\n", payload->cfg18[3 + i]);
break;
}
reg[0] |= APPLY_MASK_AND_SHIFT(val, 2, 4 * i);
}
base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
reg_off = base_off + 0x7C;
REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, reg, sizeof(u32), REG_SINGLE_WRITE, 0, 0, 0);
rc = dma_ops->setup_payload(dma_write_cfg);
if (rc)
DRM_ERROR("write spr cfg18 failed ret %d\n", rc);
else
ctx->spr_cfg_18_default = reg[0];
return rc;
}
void reg_dmav1_disable_spr(struct sde_hw_dspp *ctx, void *cfg) void reg_dmav1_disable_spr(struct sde_hw_dspp *ctx, void *cfg)
{ {
struct sde_reg_dma_setup_ops_cfg dma_write_cfg; struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg; struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_reg_dma_kickoff_cfg kick_off; struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_reg_dma_ops *dma_ops; struct sde_hw_reg_dma_ops *dma_ops;
uint32_t reg_off, reg = 0; uint32_t reg_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base + 0x4;
uint32_t reg = 0;
int rc = 0; int rc = 0;
dma_ops = sde_reg_dma_get_ops(); dma_ops = sde_reg_dma_get_ops();
@@ -4952,10 +5043,9 @@ void reg_dmav1_disable_spr(struct sde_hw_dspp *ctx, void *cfg)
DRM_ERROR("spr write decode select failed ret %d\n", rc); DRM_ERROR("spr write decode select failed ret %d\n", rc);
return; return;
} }
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
reg_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base + 0x04; REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, &reg, sizeof(u32),
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, &reg, REG_SINGLE_MODIFY, 0, 0, REG_DMA_SPR_CONFIG_MASK);
sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg); rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) { if (rc) {
DRM_ERROR("write spr disable failed ret %d\n", rc); DRM_ERROR("write spr disable failed ret %d\n", rc);
@@ -4971,122 +5061,39 @@ void reg_dmav1_disable_spr(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);
return; return;
} }
ctx->spr_cfg_18_default = 0;
} }
void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg) int reg_dmav1_setup_spr_init_common(struct sde_hw_dspp *ctx,
struct drm_msm_spr_init_cfg *payload,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
struct sde_hw_reg_dma_ops *dma_ops)
{ {
struct drm_msm_spr_init_cfg *payload = NULL; uint32_t reg_off, reg_cnt;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_reg_dma_ops *dma_ops;
uint32_t reg_off, reg_cnt, base_off;
uint32_t reg[16]; uint32_t reg[16];
uint32_t base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
int i, index, rc = 0; int i, index, rc = 0;
bool spr_bypass = false;
rc = reg_dma_dspp_check(ctx, cfg, SPR_INIT);
if (rc)
return;
if (!hw_cfg->payload) {
LOG_FEATURE_OFF;
return reg_dmav1_disable_spr(ctx, cfg);
}
if (hw_cfg->len != sizeof(struct drm_msm_spr_init_cfg)) {
DRM_ERROR("invalid payload size len %d exp %zd\n", hw_cfg->len,
sizeof(struct drm_msm_spr_init_cfg));
return;
}
payload = hw_cfg->payload;
base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
dma_ops = sde_reg_dma_get_ops();
dma_ops->reset_reg_dma_buf(dspp_buf[SPR_INIT][ctx->idx]);
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_INIT,
dspp_buf[SPR_INIT][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("spr write decode select failed ret %d\n", rc);
return;
}
spr_bypass = (payload->flags & SPR_FLAG_BYPASS) ? true : false;
reg_cnt = 2;
reg_off = base_off + 0x04;
reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg0, 1, 0) |
APPLY_MASK_AND_SHIFT(payload->cfg1, 1, 1) |
APPLY_MASK_AND_SHIFT(payload->cfg2, 1, 2) |
APPLY_MASK_AND_SHIFT(payload->cfg4, 1, 3) |
APPLY_MASK_AND_SHIFT(payload->cfg3, 1, 24);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg5, 4, 16);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg6, 3, 20);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg7, 2, 4);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg8, 2, 6);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[0], 2, 8);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[1], 2, 10);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[2], 2, 12);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[3], 1, 14);
if (spr_bypass)
reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg1, 1, 1) |
APPLY_MASK_AND_SHIFT(payload->cfg2, 1, 2) |
APPLY_MASK_AND_SHIFT(payload->cfg3, 1, 24);
reg[1] = 0;
if (hw_cfg->num_of_mixers == 2)
reg[1] = 1;
else if (hw_cfg->num_of_mixers == 4)
reg[1] = 3;
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg,
reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("write spr config failed ret %d\n", rc);
return;
}
if (spr_bypass)
goto bypass;
reg_cnt = 1;
reg_off = base_off + 0x54;
reg[0] = 0;
for (i = 0; i < ARRAY_SIZE(payload->cfg14); i++)
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg14[i], 5, 5 * i);
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg,
reg_cnt * sizeof(u32), REG_SINGLE_WRITE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("write spr cfg14 failed ret %d\n", rc);
return;
}
reg_cnt = ARRAY_SIZE(payload->cfg17) / 6; reg_cnt = ARRAY_SIZE(payload->cfg17) / 6;
reg_off = base_off + 0x24; reg_off = base_off + 0x24;
for (i = 0; i < reg_cnt; i++) { for (i = 0; i < reg_cnt; i++) {
index = 6 * i; index = 6 * i;
reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg17[index], 5, 0) | reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg17[index], 5, 0) |
APPLY_MASK_AND_SHIFT(payload->cfg17[index + 1], 5, 5) | APPLY_MASK_AND_SHIFT(payload->cfg17[index + 1], 5, 5) |
APPLY_MASK_AND_SHIFT(payload->cfg17[index + 2], 5, 10) | APPLY_MASK_AND_SHIFT(payload->cfg17[index + 2], 5, 10) |
APPLY_MASK_AND_SHIFT(payload->cfg17[index + 3], 5, 15) | APPLY_MASK_AND_SHIFT(payload->cfg17[index + 3], 5, 15) |
APPLY_MASK_AND_SHIFT(payload->cfg17[index + 4], 5, 20) | APPLY_MASK_AND_SHIFT(payload->cfg17[index + 4], 5, 20) |
APPLY_MASK_AND_SHIFT(payload->cfg17[index + 5], 5, 25); APPLY_MASK_AND_SHIFT(payload->cfg17[index + 5], 5, 25);
} }
reg[reg_cnt - 1] &= 0x3FF; reg[reg_cnt - 1] &= 0x3FF;
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg, REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, reg,
reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0); reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg); rc = dma_ops->setup_payload(dma_write_cfg);
if (rc) { if (rc) {
DRM_ERROR("write spr cfg17 failed ret %d\n", rc); DRM_ERROR("write spr cfg17 failed ret %d\n", rc);
return; return rc;
} }
reg_cnt = ARRAY_SIZE(payload->cfg16) / 2; reg_cnt = ARRAY_SIZE(payload->cfg16) / 2;
@@ -5094,84 +5101,410 @@ void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg)
for (i = 0; i < reg_cnt; i++) { for (i = 0; i < reg_cnt; i++) {
index = 2 * i; index = 2 * i;
reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg16[index], 11, 0) | reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg16[index], 11, 0) |
APPLY_MASK_AND_SHIFT(payload->cfg16[index + 1], 11, 16); APPLY_MASK_AND_SHIFT(payload->cfg16[index + 1], 11, 16);
} }
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg, reg_cnt * sizeof(u32), REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, reg, reg_cnt * sizeof(u32),
REG_BLK_WRITE_SINGLE, 0, 0, 0); REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg); rc = dma_ops->setup_payload(dma_write_cfg);
if (rc) { if (rc) {
DRM_ERROR("write spr cfg16 failed ret %d\n", rc); DRM_ERROR("write spr cfg16 failed ret %d\n", rc);
return; return rc;
} }
rc = reg_dmav1_setup_spr_cfg3_params(ctx, payload, rc = reg_dmav1_setup_spr_cfg3_params(ctx, payload,
&dma_write_cfg, dma_ops); dma_write_cfg, dma_ops);
if (rc) if (rc)
return; return rc;
rc = reg_dmav1_setup_spr_cfg4_params(ctx, payload, rc = reg_dmav1_setup_spr_cfg4_params(ctx, payload,
&dma_write_cfg, dma_ops); dma_write_cfg, dma_ops);
if (rc)
return; return rc;
}
int reg_dmav1_get_spr_target(struct sde_hw_dspp *ctx, void *cfg,
struct sde_hw_reg_dma_ops **dma_ops, uint32_t *base_off,
struct sde_reg_dma_buffer **buffer, bool *disable)
{
struct sde_hw_cp_cfg *hw_cfg = cfg;
int rc = reg_dma_dspp_check(ctx, cfg, SPR_INIT);
if (rc) {
return rc;
}
*base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
*buffer = dspp_buf[SPR_INIT][ctx->idx];
*dma_ops = sde_reg_dma_get_ops();
(*dma_ops)->reset_reg_dma_buf(*buffer);
if (!hw_cfg->payload) {
*disable = true;
} else {
*disable = false;
if (hw_cfg->len != sizeof(struct drm_msm_spr_init_cfg)) {
DRM_ERROR("invalid payload size len %d exp %zd\n", hw_cfg->len,
sizeof(struct drm_msm_spr_init_cfg));
rc = -EINVAL;
}
}
return rc;
}
int reg_dmav1_setup_spr_init_kickoff(uint32_t version, uint32_t base_off,
struct sde_hw_reg_dma_ops *dma_ops,
struct sde_hw_cp_cfg *hw_cfg,
struct drm_msm_spr_init_cfg *payload,
struct sde_reg_dma_setup_ops_cfg *dma_write_cfg)
{
struct sde_reg_dma_kickoff_cfg kick_off;
uint32_t reg[2];
uint32_t reg_off;
int rc = 0;
if ((payload->flags & SPR_FLAG_BYPASS)) {
reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg1, 1, 1) |
APPLY_MASK_AND_SHIFT(payload->cfg2, 1, 2) |
APPLY_MASK_AND_SHIFT(payload->cfg3, 1, 24);
} else {
reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg0, 1, 0) |
APPLY_MASK_AND_SHIFT(payload->cfg1, 1, 1) |
APPLY_MASK_AND_SHIFT(payload->cfg2, 1, 2) |
APPLY_MASK_AND_SHIFT(payload->cfg4, 1, 3) |
APPLY_MASK_AND_SHIFT(payload->cfg3, 1, 24);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg5, 4, 16);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg6, 3, 20);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg7, 2, 4);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg8, 2, 6);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[0], 2, 8);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[1], 2, 10);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[2], 2, 12);
reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[3], 1, 14);
if (version == 2) {
reg[0] |= payload->cfg18_en ? (1 << 26) : 0;
reg[0] |= payload->cfg7 & 0x4 ? (1 << 15) : 0;
}
}
reg[1] = 0;
if (hw_cfg->num_of_mixers == 2)
reg[1] = 1;
else if (hw_cfg->num_of_mixers == 4)
reg[1] = 3;
reg_off = base_off + 0x04;
REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, &reg[0], sizeof(u32),
REG_SINGLE_MODIFY, 0, 0, REG_DMA_SPR_CONFIG_MASK);
rc = dma_ops->setup_payload(dma_write_cfg);
if (rc) {
DRM_ERROR("write spr config pt1 failed ret %d\n", rc);
return rc;
}
reg_off = base_off + 0x08;
REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, &reg[1], sizeof(u32),
REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(dma_write_cfg);
if (rc) {
DRM_ERROR("write spr config failed ret %d\n", rc);
return rc;
}
bypass:
REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
dspp_buf[SPR_INIT][ctx->idx], dma_write_cfg->dma_buf,
REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE, REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE,
SPR_INIT); SPR_INIT);
LOG_FEATURE_ON;
rc = dma_ops->kick_off(&kick_off); rc = dma_ops->kick_off(&kick_off);
if (rc) { if (rc) {
DRM_ERROR("failed to kick off ret %d\n", rc); DRM_ERROR("failed to kick off ret %d\n", rc);
return; return rc;
} }
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
return rc;
} }
void reg_dmav1_setup_spr_pu_cfgv1(struct sde_hw_dspp *ctx, void *cfg) void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg)
{ {
struct drm_msm_spr_init_cfg *payload = NULL;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg; struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg; struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_reg_dma_ops *dma_ops; struct sde_hw_reg_dma_ops *dma_ops;
uint32_t reg, reg_off, base_off; struct sde_reg_dma_buffer *buffer;
struct msm_roi_list *roi_list; uint32_t base_off;
int rc = 0; int rc = 0;
bool disable = false;
rc = reg_dma_dspp_check(ctx, cfg, SPR_PU_CFG); if (reg_dmav1_get_spr_target(ctx, cfg, &dma_ops, &base_off,
if (rc) &buffer, &disable))
return; return;
if (!hw_cfg->payload || hw_cfg->len != sizeof(struct sde_drm_roi_v1)) { if (disable) {
LOG_FEATURE_OFF;
return reg_dmav1_disable_spr(ctx, cfg);
}
payload = hw_cfg->payload;
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_INIT, buffer);
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("spr write decode select failed ret %d\n", rc);
return;
}
if (!(payload->flags & SPR_FLAG_BYPASS)) {
rc = reg_dmav1_setup_spr_init_common(ctx, payload, &dma_write_cfg, dma_ops);
if (rc)
return;
}
if (!reg_dmav1_setup_spr_init_kickoff(1, base_off, dma_ops, hw_cfg,
payload, &dma_write_cfg))
LOG_FEATURE_ON;
}
void reg_dmav1_setup_spr_init_cfgv2(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_spr_init_cfg *payload = NULL;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_hw_reg_dma_ops *dma_ops;
struct sde_reg_dma_buffer *buffer;
uint32_t base_off;
int rc = 0;
bool disable = false;
if (reg_dmav1_get_spr_target(ctx, cfg, &dma_ops, &base_off, &buffer, &disable))
return;
if (disable) {
LOG_FEATURE_OFF;
return reg_dmav1_disable_spr(ctx, cfg);
}
payload = hw_cfg->payload;
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_INIT, buffer);
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("spr write decode select failed ret %d\n", rc);
return;
}
if (!(payload->flags & SPR_FLAG_BYPASS)) {
rc = reg_dmav1_setup_spr_init_common(ctx, payload, &dma_write_cfg, dma_ops);
if (rc)
return;
rc = reg_dmav1_setup_spr_cfg5_params(ctx, payload, &dma_write_cfg, dma_ops);
if (rc)
return;
} else {
ctx->spr_cfg_18_default = 0;
}
if (!reg_dmav1_setup_spr_init_kickoff(2, base_off, dma_ops, hw_cfg,
payload, &dma_write_cfg))
LOG_FEATURE_ON;
}
#define SPR_UDC_MAX_REG_CNT 128
#define SPR_UDC_TARGET (1 << 25)
void reg_dmav1_setup_spr_udc_cfgv2(struct sde_hw_dspp *ctx, void *cfg)
{
size_t UDC_LENGTH = sizeof(uint32_t) * SPR_UDC_PARAM_SIZE_2 / 4;
struct drm_msm_spr_udc_cfg *payload = NULL;
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_hw_reg_dma_ops *dma_ops;
struct sde_reg_dma_buffer *buffer;
uint32_t base_off, reg_off, reg_cnt;
uint32_t *reg = kvzalloc(UDC_LENGTH, GFP_KERNEL);
int rc = 0;
bool disable = false;
if (reg == NULL) {
DRM_ERROR("Unable to allocate memory for UDC mask programming\n");
return;
}
if (!hw_cfg->payload) {
disable = true;
} else {
disable = false;
if (hw_cfg->len != sizeof(struct drm_msm_spr_udc_cfg)) {
DRM_ERROR("invalid payload size len %d exp %zd\n", hw_cfg->len,
sizeof(struct drm_msm_spr_udc_cfg));
goto cleanup;
}
}
if (reg_dma_dspp_check(ctx, cfg, SPR_UDC))
goto cleanup;
dma_ops = sde_reg_dma_get_ops();
buffer = dspp_buf[SPR_UDC][ctx->idx];
payload = hw_cfg->payload;
base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
dma_ops->reset_reg_dma_buf(buffer);
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_UDC, buffer);
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("spr write decode select failed ret %d\n", rc);
goto cleanup;
}
if (disable) {
reg[0] = 0;
} else {
uint32_t lines[3];
uint32_t index = 0;
uint32_t i = 0, j = 0;
for (i = 0; i < 3; i++) {
index = i * 4;
reg[index++] = APPLY_MASK_AND_SHIFT(payload->cfg1[j], 16, 0) |
APPLY_MASK_AND_SHIFT(payload->cfg1[j + 1], 16, 16);
j += 2;
lines[i] = APPLY_MASK_AND_SHIFT(payload->cfg1[j + 1], 9, 0);
reg[index++] =
APPLY_MASK_AND_SHIFT(payload->cfg1[j], 10, 0) | lines[i] << 16;
j += 2;
reg[index++] = APPLY_MASK_AND_SHIFT(payload->cfg1[j], 4, 0) |
APPLY_MASK_AND_SHIFT(payload->cfg1[j + 1], 4, 8) |
APPLY_MASK_AND_SHIFT(payload->cfg1[j + 2], 4, 16) |
APPLY_MASK_AND_SHIFT(payload->cfg1[j + 3], 4, 24);
j += 4;
reg[index++] = APPLY_MASK_AND_SHIFT(payload->cfg1[j++], 11, 0);
}
reg_off = base_off + 0x120;
reg_cnt = index;
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg,
reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("write spr udc cfg p1 failed ret %d\n", rc);
goto cleanup;
}
reg_off = base_off + 0x150;
reg[0] = 0;
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg, sizeof(u32),
REG_SINGLE_WRITE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("write spr udc cfg p2 failed - ret %d\n", rc);
goto cleanup;
}
memset(reg, 0, UDC_LENGTH);
for (i = 0; i < 3; i++) {
uint32_t line = 0;
uint32_t index = i * (SPR_UDC_PARAM_SIZE_2 / 3);
uint32_t line_cnt = (lines[i] + 1) >> 1;
if (i == 0)
j = (SPR_UDC_PARAM_SIZE_2 / 12) * 2;
else if (i == 1)
j = 0;
else
j = (SPR_UDC_PARAM_SIZE_2 / 12);
for (line = 0; line < line_cnt; line++) {
reg[j++] = (payload->cfg2[index] & 0xff) |
((payload->cfg2[index + 1] & 0xff) << 8) |
((payload->cfg2[index + 2] & 0xff) << 16) |
((payload->cfg2[index + 3] & 0xff) << 24);
index += 4;
}
}
reg_off = base_off + 0x154;
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg, UDC_LENGTH,
REG_BLK_WRITE_INC, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("write spr udc cfg p3 failed - L%d\t ret %d\n", i, rc);
goto cleanup;
}
reg[0] = SPR_UDC_TARGET;
}
reg_off = base_off + 0x4;
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg, sizeof(u32),
REG_SINGLE_MODIFY, 0, 0, ~SPR_UDC_TARGET);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("write spr udc config failed ret %d\n", rc);
goto cleanup;
}
REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
dma_write_cfg.dma_buf,
REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE, SPR_UDC);
rc = dma_ops->kick_off(&kick_off);
if (rc) {
DRM_ERROR("failed to kick off ret %d\n", rc);
goto cleanup;
}
if (disable)
LOG_FEATURE_OFF;
else
LOG_FEATURE_ON;
cleanup:
kvfree(reg);
}
int reg_dmav1_setup_spr_pu_common(struct sde_hw_dspp *ctx, struct sde_hw_cp_cfg *hw_cfg,
struct msm_roi_list *roi_list,
struct sde_hw_reg_dma_ops *dma_ops, struct sde_reg_dma_buffer *buffer)
{
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
uint32_t reg, reg_off, base_off;
int rc = 0;
if (!roi_list) {
DRM_DEBUG("invalid payload of pu rects\n"); DRM_DEBUG("invalid payload of pu rects\n");
reg = 0; reg = 0;
} else { } else {
roi_list = hw_cfg->payload; roi_list = hw_cfg->payload;
if (roi_list->num_rects > 1) { if (roi_list->num_rects > 1) {
DRM_ERROR("multiple pu regions not supported with spr\n"); DRM_ERROR("multiple pu regions not supported with spr\n");
return; return -EINVAL;
} }
if ((roi_list->roi[0].x2 - roi_list->roi[0].x1) != hw_cfg->displayh) { if ((roi_list->roi[0].x2 - roi_list->roi[0].x1) != hw_cfg->displayh) {
DRM_ERROR("pu region not full width %d\n", DRM_ERROR("pu region not full width %d\n",
(roi_list->roi[0].x2 - roi_list->roi[0].x1)); (roi_list->roi[0].x2 - roi_list->roi[0].x1));
return; return -EINVAL;
} }
reg = APPLY_MASK_AND_SHIFT(roi_list->roi[0].x1, 16, 0) | reg = APPLY_MASK_AND_SHIFT(roi_list->roi[0].x1, 16, 0) |
APPLY_MASK_AND_SHIFT(roi_list->roi[0].y1, 16, 16); APPLY_MASK_AND_SHIFT(roi_list->roi[0].y1, 16, 16);
} }
dma_ops = sde_reg_dma_get_ops(); REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_PU_CFG, buffer);
dma_ops->reset_reg_dma_buf(dspp_buf[SPR_PU_CFG][ctx->idx]);
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_PU_CFG,
dspp_buf[SPR_PU_CFG][ctx->idx]);
REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg); rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) { if (rc) {
DRM_ERROR("spr write decode select failed ret %d\n", rc); DRM_ERROR("spr write decode select failed ret %d\n", rc);
return; return rc;
} }
base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base; base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
@@ -5182,14 +5515,42 @@ void reg_dmav1_setup_spr_pu_cfgv1(struct sde_hw_dspp *ctx, void *cfg)
rc = dma_ops->setup_payload(&dma_write_cfg); rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) { if (rc) {
DRM_ERROR("write pu config failed ret %d\n", rc); DRM_ERROR("write pu config failed ret %d\n", rc);
return;
} }
return rc;
}
void reg_dmav1_setup_spr_pu_cfgv1(struct sde_hw_dspp *ctx, void *cfg)
{
struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_reg_dma_ops *dma_ops;
struct sde_reg_dma_buffer *buffer;
struct msm_roi_list *roi_list = NULL;
int rc = 0;
rc = reg_dma_dspp_check(ctx, cfg, SPR_PU_CFG);
if (rc)
return;
buffer = dspp_buf[SPR_PU_CFG][ctx->idx];
dma_ops = sde_reg_dma_get_ops();
if (dma_ops == NULL)
return;
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
dma_ops->reset_reg_dma_buf(buffer);
if (hw_cfg->payload && hw_cfg->len == sizeof(struct sde_drm_roi_v1))
roi_list = hw_cfg->payload;
rc = reg_dmav1_setup_spr_pu_common(ctx, cfg, roi_list, dma_ops, buffer);
if (rc)
return;
REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
dspp_buf[SPR_PU_CFG][ctx->idx], buffer, REG_DMA_WRITE, DMA_CTL_QUEUE0,
REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE, WRITE_IMMEDIATE, SPR_PU_CFG);
SPR_PU_CFG);
LOG_FEATURE_ON;
rc = dma_ops->kick_off(&kick_off); rc = dma_ops->kick_off(&kick_off);
if (rc) { if (rc) {
DRM_ERROR("failed to kick off ret %d\n", rc); DRM_ERROR("failed to kick off ret %d\n", rc);
@@ -5198,6 +5559,71 @@ void reg_dmav1_setup_spr_pu_cfgv1(struct sde_hw_dspp *ctx, void *cfg)
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
} }
void reg_dmav1_setup_spr_pu_cfgv2(struct sde_hw_dspp *ctx, void *cfg)
{
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg;
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_reg_dma_ops *dma_ops;
struct sde_reg_dma_buffer *buffer;
uint32_t reg_off, base_off;
struct msm_roi_list *roi_list = NULL;
int rc;
rc = reg_dma_dspp_check(ctx, cfg, SPR_PU_CFG);
if (rc)
return;
buffer = dspp_buf[SPR_PU_CFG][ctx->idx];
dma_ops = sde_reg_dma_get_ops();
if (dma_ops == NULL)
return;
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
dma_ops->reset_reg_dma_buf(buffer);
if (hw_cfg->payload && hw_cfg->len == sizeof(struct sde_drm_roi_v1))
roi_list = hw_cfg->payload;
rc = reg_dmav1_setup_spr_pu_common(ctx, cfg, roi_list, dma_ops, buffer);
if (rc)
return;
if (ctx->spr_cfg_18_default != 0) {
uint32_t reg = ctx->spr_cfg_18_default;
//No ROI list means full screen update so apply without modification
if (roi_list && roi_list->roi[0].y1 != 0)
reg &= 0xFFFFFFFC;
if (roi_list && roi_list->roi[0].y2 != hw_cfg->displayv)
reg &= 0xFFFFFFCF;
base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
reg_off = base_off + 0x7C;
REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_PU_CFG, buffer);
REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, &reg, sizeof(u32),
REG_SINGLE_WRITE, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
if (rc) {
DRM_ERROR("SPR V2 PU failed ret %d\n", rc);
return;
}
}
REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
buffer, REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE, SPR_PU_CFG);
rc = dma_ops->kick_off(&kick_off);
if (rc) {
DRM_ERROR("failed to kick off ret %d\n", rc);
return;
}
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
}
static void reg_dma_demura_off(struct sde_hw_dspp *ctx, static void reg_dma_demura_off(struct sde_hw_dspp *ctx,
struct sde_hw_cp_cfg *hw_cfg) struct sde_hw_cp_cfg *hw_cfg)
{ {

View File

@@ -311,6 +311,13 @@ void reg_dmav2_setup_dspp_3d_gamutv43(struct sde_hw_dspp *ctx, void *cfg);
*/ */
void reg_dmav2_setup_vig_gamutv61(struct sde_hw_pipe *ctx, void *cfg); void reg_dmav2_setup_vig_gamutv61(struct sde_hw_pipe *ctx, void *cfg);
/**
* reg_dmav2_init_spr_op_v1() - initialize spr sub-feature buffer for reg dma v2.
* @feature: SPR sub-feature
* @dspp_idx: dspp idx to allocate for
*/
int reg_dmav2_init_spr_op_v1(int feature, enum sde_dspp dspp_idx);
/** /**
* reg_dmav1_setup_spr_init_cfgv1 - function to configure spr through LUTDMA * reg_dmav1_setup_spr_init_cfgv1 - function to configure spr through LUTDMA
* @ctx: Pointer to dspp context * @ctx: Pointer to dspp context
@@ -318,6 +325,20 @@ void reg_dmav2_setup_vig_gamutv61(struct sde_hw_pipe *ctx, void *cfg);
*/ */
void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg); void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg);
/**
* reg_dmav1_setup_spr_init_cfgv2 - function to configure spr v2 through LUTDMA
* @ctx: Pointer to dspp context
* @cfg: Pointer to configuration
*/
void reg_dmav1_setup_spr_init_cfgv2(struct sde_hw_dspp *ctx, void *cfg);
/**
* reg_dmav1_setup_spr_udc_cfgv2 - function to configure spr v2 UDC through LUTDMA
* @ctx: Pointer to dspp context
* @cfg: Pointer to configuration
*/
void reg_dmav1_setup_spr_udc_cfgv2(struct sde_hw_dspp *ctx, void *cfg);
/** /**
* reg_dmav1_setup_spr_pu_cfgv1 - function to configure spr pu through LUTDMA * reg_dmav1_setup_spr_pu_cfgv1 - function to configure spr pu through LUTDMA
* @ctx: Pointer to dspp context * @ctx: Pointer to dspp context
@@ -325,6 +346,13 @@ void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg);
*/ */
void reg_dmav1_setup_spr_pu_cfgv1(struct sde_hw_dspp *ctx, void *cfg); void reg_dmav1_setup_spr_pu_cfgv1(struct sde_hw_dspp *ctx, void *cfg);
/**
* reg_dmav1_setup_spr_pu_cfgv2 - function to configure spr v2 pu through LUTDMA
* @ctx: Pointer to dspp context
* @cfg: Pointer to configuration
*/
void reg_dmav1_setup_spr_pu_cfgv2(struct sde_hw_dspp *ctx, void *cfg);
/** /**
* reg_dmav1_setup_demurav1() - function to set up the demurav1 configuration. * reg_dmav1_setup_demurav1() - function to set up the demurav1 configuration.
* @ctx: dspp ctx info * @ctx: dspp ctx info

View File

@@ -78,6 +78,7 @@ enum sde_reg_dma_features {
HSIC, HSIC,
GC, GC,
SPR_INIT, SPR_INIT,
SPR_UDC,
SPR_PU_CFG, SPR_PU_CFG,
LTM_INIT, LTM_INIT,
LTM_ROI, LTM_ROI,