Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f402d8e5 authored by Narendra Muppalla's avatar Narendra Muppalla
Browse files

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



This change programs dither based on user mode input data and
reprograms the dither when device comes out of power collapse.

Change-Id: I83be20c8eb2dc2221cc57cd2395f6512338ff6ef
Signed-off-by: default avatarNarendra Muppalla <NarendraM@codeaurora.org>
parent 52161a09
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -412,10 +412,12 @@ struct drm_msm_ad4_cfg {
};

#define DITHER_MATRIX_SZ 16
#define DITHER_LUMA_MODE (1 << 0)

/**
 * 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
 * @c0_bitdepth: c0 component bit depth
 * @c1_bitdepth: c1 component bit depth
+27 −80
Original line number Diff line number Diff line
@@ -29,9 +29,6 @@

#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
		(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[] = {
	{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);
}

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,
		struct sde_kms *sde_kms, struct sde_connector *c_conn)
{
	char prop_name[DRM_PROP_NAME_LEN];
	struct sde_mdss_cfg *catalog = NULL;
	struct drm_property_blob *blob_ptr;
	void *cfg;
	int ret = 0;
	u32 version = 0, len = 0;
	bool defalut_dither_needed = false;
	u32 version = 0;

	if (!dev || !sde_kms || !c_conn) {
		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);
	switch (version) {
	case 1:
	case 2:
		msm_property_install_blob(&c_conn->property_info, prop_name,
			DRM_MODE_PROP_BLOB,
			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;
	default:
		SDE_ERROR("unsupported dither version %d\n", version);
		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,
			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_state *c_state = NULL;
	size_t dither_sz = 0;
	bool is_dirty;
	u32 *p = (u32 *)cfg;

	if (!conn || !state || !p)
	if (!conn || !state || !p) {
		SDE_ERROR("invalid arguments\n");
		return -EINVAL;
	}

	c_conn = to_sde_connector(conn);
	c_state = to_sde_connector_state(state);

	/* try to get user config data first */
	is_dirty = msm_property_is_dirty(&c_conn->property_info,
			&c_state->property_state,
			CONNECTOR_PROP_PP_DITHER);

	if (!is_dirty && !idle_pc) {
		return -ENODATA;
	} else if (is_dirty || idle_pc) {
		*cfg = msm_property_get_blob(&c_conn->property_info,
				&c_state->property_state,
				&dither_sz,
				CONNECTOR_PROP_PP_DITHER);
	/* if user config data doesn't exist, use default dither blob */
	if (*cfg == NULL && c_conn->blob_dither) {
		*cfg = &c_conn->blob_dither->data;
		dither_sz = c_conn->blob_dither->length;
		/*
		 * 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;
	return 0;
+3 −1
Original line number Diff line number Diff line
@@ -854,10 +854,12 @@ static inline bool sde_connector_needs_offset(struct drm_connector *connector)
 * @state: Pointer to drm_connector_state struct
 * @cfg: Pointer to pointer to dither cfg
 * @len: length of the dither data
 * @idle_pc: flag to indicate idle_pc_restore happened
 * Returns: Zero on success
 */
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
+57 −49
Original line number Diff line number Diff line
@@ -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));
}

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)
{
	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)
			phys->ops.restore(phys);

		_sde_encoder_setup_dither(phys);
	}

	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;
}

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,
		struct drm_display_mode *mode)
{
+4 −0
Original line number Diff line number Diff line
@@ -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,
								0);

		if (sde_cfg->dither_luma_mode_support)
			set_bit(SDE_PINGPONG_DITHER_LUMA, &pp->features);

		if (prop_exists[PP_MERGE_3D_ID]) {
			set_bit(SDE_PINGPONG_MERGE_3D, &pp->features);
			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->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_1;
		sde_cfg->vbif_disable_inner_outer_shareable = true;
		sde_cfg->dither_luma_mode_support = true;
	} else {
		SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
		sde_cfg->perf.min_prefill_lines = 0xffff;
Loading