Merge "disp: msm: sde: program dither based on input data"

This commit is contained in:
qctecmdr
2020-02-10 17:19:07 -08:00
committed by Gerrit - the friendly Code Review server
7 changed files with 118 additions and 141 deletions

View File

@@ -412,10 +412,12 @@ struct drm_msm_ad4_cfg {
}; };
#define DITHER_MATRIX_SZ 16 #define DITHER_MATRIX_SZ 16
#define DITHER_LUMA_MODE (1 << 0)
/** /**
* struct drm_msm_dither - dither feature structure * struct drm_msm_dither - dither feature structure
* @flags: for customizing operations * @flags: flags for the feature customization, values can be:
-DITHER_LUMA_MODE: Enable LUMA dither mode
* @temporal_en: temperal dither enable * @temporal_en: temperal dither enable
* @c0_bitdepth: c0 component bit depth * @c0_bitdepth: c0 component bit depth
* @c1_bitdepth: c1 component bit depth * @c1_bitdepth: c1 component bit depth

View File

@@ -29,9 +29,6 @@
#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\ #define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
(c) ? (c)->base.base.id : -1, ##__VA_ARGS__) (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
};
static const struct drm_prop_enum_list e_topology_name[] = { static const struct drm_prop_enum_list e_topology_name[] = {
{SDE_RM_TOPOLOGY_NONE, "sde_none"}, {SDE_RM_TOPOLOGY_NONE, "sde_none"},
@@ -245,60 +242,12 @@ void sde_connector_unregister_event(struct drm_connector *connector,
(void)sde_connector_register_event(connector, event_idx, 0, 0); (void)sde_connector_register_event(connector, event_idx, 0, 0);
} }
static int _sde_connector_get_default_dither_cfg_v1(
struct sde_connector *c_conn, void *cfg)
{
struct drm_msm_dither *dither_cfg = (struct drm_msm_dither *)cfg;
enum dsi_pixel_format dst_format = DSI_PIXEL_FORMAT_MAX;
if (!c_conn || !cfg) {
SDE_ERROR("invalid argument(s), c_conn %pK, cfg %pK\n",
c_conn, cfg);
return -EINVAL;
}
if (!c_conn->ops.get_dst_format) {
SDE_DEBUG("get_dst_format is unavailable\n");
return 0;
}
dst_format = c_conn->ops.get_dst_format(&c_conn->base, c_conn->display);
switch (dst_format) {
case DSI_PIXEL_FORMAT_RGB888:
dither_cfg->c0_bitdepth = 8;
dither_cfg->c1_bitdepth = 8;
dither_cfg->c2_bitdepth = 8;
dither_cfg->c3_bitdepth = 8;
break;
case DSI_PIXEL_FORMAT_RGB666:
case DSI_PIXEL_FORMAT_RGB666_LOOSE:
dither_cfg->c0_bitdepth = 6;
dither_cfg->c1_bitdepth = 6;
dither_cfg->c2_bitdepth = 6;
dither_cfg->c3_bitdepth = 6;
break;
default:
SDE_DEBUG("no default dither config for dst_format %d\n",
dst_format);
return -ENODATA;
}
memcpy(&dither_cfg->matrix, dither_matrix,
sizeof(u32) * DITHER_MATRIX_SZ);
dither_cfg->temporal_en = 0;
return 0;
}
static void _sde_connector_install_dither_property(struct drm_device *dev, static void _sde_connector_install_dither_property(struct drm_device *dev,
struct sde_kms *sde_kms, struct sde_connector *c_conn) struct sde_kms *sde_kms, struct sde_connector *c_conn)
{ {
char prop_name[DRM_PROP_NAME_LEN]; char prop_name[DRM_PROP_NAME_LEN];
struct sde_mdss_cfg *catalog = NULL; struct sde_mdss_cfg *catalog = NULL;
struct drm_property_blob *blob_ptr; u32 version = 0;
void *cfg;
int ret = 0;
u32 version = 0, len = 0;
bool defalut_dither_needed = false;
if (!dev || !sde_kms || !c_conn) { if (!dev || !sde_kms || !c_conn) {
SDE_ERROR("invld args (s), dev %pK, sde_kms %pK, c_conn %pK\n", SDE_ERROR("invld args (s), dev %pK, sde_kms %pK, c_conn %pK\n",
@@ -313,57 +262,55 @@ static void _sde_connector_install_dither_property(struct drm_device *dev,
"SDE_PP_DITHER_V", version); "SDE_PP_DITHER_V", version);
switch (version) { switch (version) {
case 1: case 1:
case 2:
msm_property_install_blob(&c_conn->property_info, prop_name, msm_property_install_blob(&c_conn->property_info, prop_name,
DRM_MODE_PROP_BLOB, DRM_MODE_PROP_BLOB,
CONNECTOR_PROP_PP_DITHER); CONNECTOR_PROP_PP_DITHER);
len = sizeof(struct drm_msm_dither);
cfg = kzalloc(len, GFP_KERNEL);
if (!cfg)
return;
ret = _sde_connector_get_default_dither_cfg_v1(c_conn, cfg);
if (!ret)
defalut_dither_needed = true;
break; break;
default: default:
SDE_ERROR("unsupported dither version %d\n", version); SDE_ERROR("unsupported dither version %d\n", version);
return; return;
} }
if (defalut_dither_needed) {
blob_ptr = drm_property_create_blob(dev, len, cfg);
if (IS_ERR_OR_NULL(blob_ptr))
goto exit;
c_conn->blob_dither = blob_ptr;
}
exit:
kfree(cfg);
} }
int sde_connector_get_dither_cfg(struct drm_connector *conn, int sde_connector_get_dither_cfg(struct drm_connector *conn,
struct drm_connector_state *state, void **cfg, struct drm_connector_state *state, void **cfg,
size_t *len) size_t *len, bool idle_pc)
{ {
struct sde_connector *c_conn = NULL; struct sde_connector *c_conn = NULL;
struct sde_connector_state *c_state = NULL; struct sde_connector_state *c_state = NULL;
size_t dither_sz = 0; size_t dither_sz = 0;
bool is_dirty;
u32 *p = (u32 *)cfg; u32 *p = (u32 *)cfg;
if (!conn || !state || !p) if (!conn || !state || !p) {
SDE_ERROR("invalid arguments\n");
return -EINVAL; return -EINVAL;
}
c_conn = to_sde_connector(conn); c_conn = to_sde_connector(conn);
c_state = to_sde_connector_state(state); c_state = to_sde_connector_state(state);
/* try to get user config data first */ is_dirty = msm_property_is_dirty(&c_conn->property_info,
*cfg = msm_property_get_blob(&c_conn->property_info, &c_state->property_state,
&c_state->property_state, CONNECTOR_PROP_PP_DITHER);
&dither_sz,
CONNECTOR_PROP_PP_DITHER); if (!is_dirty && !idle_pc) {
/* if user config data doesn't exist, use default dither blob */ return -ENODATA;
if (*cfg == NULL && c_conn->blob_dither) { } else if (is_dirty || idle_pc) {
*cfg = &c_conn->blob_dither->data; *cfg = msm_property_get_blob(&c_conn->property_info,
dither_sz = c_conn->blob_dither->length; &c_state->property_state,
&dither_sz,
CONNECTOR_PROP_PP_DITHER);
/*
* in idle_pc use case return early,
* when dither is already disabled.
*/
if (idle_pc && *cfg == NULL)
return -ENODATA;
/* disable dither based on user config data */
else if (*cfg == NULL)
return 0;
} }
*len = dither_sz; *len = dither_sz;
return 0; return 0;

View File

@@ -854,10 +854,12 @@ static inline bool sde_connector_needs_offset(struct drm_connector *connector)
* @state: Pointer to drm_connector_state struct * @state: Pointer to drm_connector_state struct
* @cfg: Pointer to pointer to dither cfg * @cfg: Pointer to pointer to dither cfg
* @len: length of the dither data * @len: length of the dither data
* @idle_pc: flag to indicate idle_pc_restore happened
* Returns: Zero on success * Returns: Zero on success
*/ */
int sde_connector_get_dither_cfg(struct drm_connector *conn, int sde_connector_get_dither_cfg(struct drm_connector *conn,
struct drm_connector_state *state, void **cfg, size_t *len); struct drm_connector_state *state, void **cfg,
size_t *len, bool idle_pc);
/** /**
* sde_connector_set_blob_data - set connector blob property data * sde_connector_set_blob_data - set connector blob property data

View File

@@ -2354,6 +2354,61 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi)); memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi));
} }
static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
{
void *dither_cfg = NULL;
int ret = 0, i = 0;
size_t len = 0;
enum sde_rm_topology_name topology;
struct drm_encoder *drm_enc;
struct msm_display_dsc_info *dsc = NULL;
struct sde_encoder_virt *sde_enc;
struct sde_hw_pingpong *hw_pp;
u32 bpp, bpc;
if (!phys || !phys->connector || !phys->hw_pp ||
!phys->hw_pp->ops.setup_dither || !phys->parent)
return;
topology = sde_connector_get_topology_name(phys->connector);
if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) &&
(phys->split_role == ENC_ROLE_SLAVE))
return;
drm_enc = phys->parent;
sde_enc = to_sde_encoder_virt(drm_enc);
dsc = &sde_enc->mode_info.comp_info.dsc_info;
bpc = dsc->config.bits_per_component;
bpp = dsc->config.bits_per_pixel;
/* disable dither for 10 bpp or 10bpc dsc config */
if (bpp == 10 || bpc == 10) {
phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0);
return;
}
ret = sde_connector_get_dither_cfg(phys->connector,
phys->connector->state, &dither_cfg,
&len, sde_enc->idle_pc_restore);
/* skip reg writes when return values are invalid or no data */
if (ret && ret == -ENODATA)
return;
if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) {
for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
hw_pp = sde_enc->hw_pp[i];
phys->hw_pp->ops.setup_dither(hw_pp,
dither_cfg, len);
}
} else {
phys->hw_pp->ops.setup_dither(phys->hw_pp,
dither_cfg, len);
}
}
void sde_encoder_virt_restore(struct drm_encoder *drm_enc) void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
{ {
struct sde_encoder_virt *sde_enc = NULL; struct sde_encoder_virt *sde_enc = NULL;
@@ -2386,6 +2441,8 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
if ((phys != sde_enc->cur_master) && phys->ops.restore) if ((phys != sde_enc->cur_master) && phys->ops.restore)
phys->ops.restore(phys); phys->ops.restore(phys);
_sde_encoder_setup_dither(phys);
} }
if (sde_enc->cur_master->ops.restore) if (sde_enc->cur_master->ops.restore)
@@ -3452,55 +3509,6 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
sde_enc->idle_pc_restore = false; sde_enc->idle_pc_restore = false;
} }
static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
{
void *dither_cfg;
int ret = 0, i = 0;
size_t len = 0;
enum sde_rm_topology_name topology;
struct drm_encoder *drm_enc;
struct msm_display_dsc_info *dsc = NULL;
struct sde_encoder_virt *sde_enc;
struct sde_hw_pingpong *hw_pp;
u16 bpp;
if (!phys || !phys->connector || !phys->hw_pp ||
!phys->hw_pp->ops.setup_dither || !phys->parent)
return;
topology = sde_connector_get_topology_name(phys->connector);
if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) &&
(phys->split_role == ENC_ROLE_SLAVE))
return;
drm_enc = phys->parent;
sde_enc = to_sde_encoder_virt(drm_enc);
dsc = &sde_enc->mode_info.comp_info.dsc_info;
/* disable dither for 10 bpp or 10bpc dsc config */
bpp = DSC_BPP(dsc->config);
if (bpp == 10 || dsc->config.bits_per_component == 10) {
phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0);
return;
}
ret = sde_connector_get_dither_cfg(phys->connector,
phys->connector->state, &dither_cfg, &len);
if (ret)
return;
if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) {
for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
hw_pp = sde_enc->hw_pp[i];
if (hw_pp) {
phys->hw_pp->ops.setup_dither(hw_pp, dither_cfg,
len);
}
}
} else {
phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len);
}
}
static u32 _sde_encoder_calculate_linetime(struct sde_encoder_virt *sde_enc, static u32 _sde_encoder_calculate_linetime(struct sde_encoder_virt *sde_enc,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {

View File

@@ -3344,6 +3344,9 @@ static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
sblk->dither.version = PROP_VALUE_ACCESS(prop_value, DITHER_VER, sblk->dither.version = PROP_VALUE_ACCESS(prop_value, DITHER_VER,
0); 0);
if (sde_cfg->dither_luma_mode_support)
set_bit(SDE_PINGPONG_DITHER_LUMA, &pp->features);
if (prop_exists[PP_MERGE_3D_ID]) { if (prop_exists[PP_MERGE_3D_ID]) {
set_bit(SDE_PINGPONG_MERGE_3D, &pp->features); set_bit(SDE_PINGPONG_MERGE_3D, &pp->features);
pp->merge_3d_id = PROP_VALUE_ACCESS(prop_value, pp->merge_3d_id = PROP_VALUE_ACCESS(prop_value,
@@ -4561,6 +4564,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_0; sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_0;
sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_1; sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_1;
sde_cfg->vbif_disable_inner_outer_shareable = true; sde_cfg->vbif_disable_inner_outer_shareable = true;
sde_cfg->dither_luma_mode_support = true;
} else { } else {
SDE_ERROR("unsupported chipset id:%X\n", hw_rev); SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
sde_cfg->perf.min_prefill_lines = 0xffff; sde_cfg->perf.min_prefill_lines = 0xffff;

View File

@@ -367,12 +367,13 @@ enum {
/** /**
* PINGPONG sub-blocks * PINGPONG sub-blocks
* @SDE_PINGPONG_TE Tear check block * @SDE_PINGPONG_TE Tear check block
* @SDE_PINGPONG_TE2 Additional tear check block for split pipes * @SDE_PINGPONG_TE2 Additional tear check block for split pipes
* @SDE_PINGPONG_SPLIT PP block supports split fifo * @SDE_PINGPONG_SPLIT PP block supports split fifo
* @SDE_PINGPONG_SLAVE PP block is a suitable slave for split fifo * @SDE_PINGPONG_SLAVE PP block is a suitable slave for split fifo
* @SDE_PINGPONG_DSC, Display stream compression blocks * @SDE_PINGPONG_DSC, Display stream compression blocks
* @SDE_PINGPONG_DITHER, Dither blocks * @SDE_PINGPONG_DITHER, Dither blocks
* @SDE_PINGPONG_DITHER_LUMA, Dither sub-blocks and features
* @SDE_PINGPONG_MERGE_3D, Separate MERGE_3D block exists * @SDE_PINGPONG_MERGE_3D, Separate MERGE_3D block exists
* @SDE_PINGPONG_MAX * @SDE_PINGPONG_MAX
*/ */
@@ -383,6 +384,7 @@ enum {
SDE_PINGPONG_SLAVE, SDE_PINGPONG_SLAVE,
SDE_PINGPONG_DSC, SDE_PINGPONG_DSC,
SDE_PINGPONG_DITHER, SDE_PINGPONG_DITHER,
SDE_PINGPONG_DITHER_LUMA,
SDE_PINGPONG_MERGE_3D, SDE_PINGPONG_MERGE_3D,
SDE_PINGPONG_MAX SDE_PINGPONG_MAX
}; };
@@ -1407,6 +1409,7 @@ struct sde_limit_cfg {
* @has_mixer_combined_alpha Mixer has single register for FG & BG alpha * @has_mixer_combined_alpha Mixer has single register for FG & BG alpha
* @vbif_disable_inner_outer_shareable VBIF requires disabling shareables * @vbif_disable_inner_outer_shareable VBIF requires disabling shareables
* @inline_disable_const_clr Disable constant color during inline rotate * @inline_disable_const_clr Disable constant color during inline rotate
* @dither_luma_mode_support Enables dither luma mode
* @sc_cfg: system cache configuration * @sc_cfg: system cache configuration
* @uidle_cfg Settings for uidle feature * @uidle_cfg Settings for uidle feature
* @sui_misr_supported indicate if secure-ui-misr is supported * @sui_misr_supported indicate if secure-ui-misr is supported
@@ -1464,6 +1467,7 @@ struct sde_mdss_cfg {
bool has_mixer_combined_alpha; bool has_mixer_combined_alpha;
bool vbif_disable_inner_outer_shareable; bool vbif_disable_inner_outer_shareable;
bool inline_disable_const_clr; bool inline_disable_const_clr;
bool dither_luma_mode_support;
struct sde_sc_cfg sc_cfg; struct sde_sc_cfg sc_cfg;

View File

@@ -38,6 +38,10 @@ static u32 dither_depth_map[DITHER_DEPTH_MAP_INDEX] = {
0, 0, 0, 0, 0, 1, 2, 3, 3 0, 0, 0, 0, 0, 1, 2, 3, 3
}; };
#define DITHER_VER_MAJOR_1 1
/* supports LUMA Dither */
#define DITHER_VER_MAJOR_2 2
#define MERGE_3D_MODE 0x004 #define MERGE_3D_MODE 0x004
#define MERGE_3D_MUX 0x000 #define MERGE_3D_MUX 0x000
@@ -311,7 +315,7 @@ static int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp)
return 0; return 0;
} }
static int sde_hw_pp_setup_dither_v1(struct sde_hw_pingpong *pp, static int sde_hw_pp_setup_dither(struct sde_hw_pingpong *pp,
void *cfg, size_t len) void *cfg, size_t len)
{ {
struct sde_hw_blk_reg_map *c; struct sde_hw_blk_reg_map *c;
@@ -357,7 +361,12 @@ static int sde_hw_pp_setup_dither_v1(struct sde_hw_pingpong *pp,
((dither->matrix[i + 3] & REG_MASK(4)) << 12); ((dither->matrix[i + 3] & REG_MASK(4)) << 12);
SDE_REG_WRITE(c, base + offset, data); SDE_REG_WRITE(c, base + offset, data);
} }
SDE_REG_WRITE(c, base, 1);
if (test_bit(SDE_PINGPONG_DITHER_LUMA, &pp->caps->features)
&& (dither->flags & DITHER_LUMA_MODE))
SDE_REG_WRITE(c, base, 0x11);
else
SDE_REG_WRITE(c, base, 1);
return 0; return 0;
} }
@@ -491,8 +500,9 @@ static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops,
version = SDE_COLOR_PROCESS_MAJOR(hw_cap->sblk->dither.version); version = SDE_COLOR_PROCESS_MAJOR(hw_cap->sblk->dither.version);
switch (version) { switch (version) {
case 1: case DITHER_VER_MAJOR_1:
ops->setup_dither = sde_hw_pp_setup_dither_v1; case DITHER_VER_MAJOR_2:
ops->setup_dither = sde_hw_pp_setup_dither;
break; break;
default: default:
ops->setup_dither = NULL; ops->setup_dither = NULL;