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

Commit c15f3490 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm: msm: handle resolution switch for LTM"

parents f1f9f4cd 1690129d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
	sde/sde_hw_qdss.o \
	sde_dsc_helper.o \
	sde_vdc_helper.o \
	sde/sde_hw_rc.o \

msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \
	sde/sde_encoder_phys_wb.o \
+185 −4
Original line number Diff line number Diff line
@@ -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_rc_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);
@@ -112,6 +114,7 @@ do { \
	func[SDE_DSPP_IGC] = dspp_igc_install_property; \
	func[SDE_DSPP_HIST] = dspp_hist_install_property; \
	func[SDE_DSPP_DITHER] = dspp_dither_install_property; \
	func[SDE_DSPP_RC] = dspp_rc_install_property; \
} while (0)

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_VLUT,
	SDE_CP_CRTC_DSPP_SB,
	SDE_CP_CRTC_DSPP_RC_MASK,
	SDE_CP_CRTC_DSPP_MAX,
	/* DSPP features end */

@@ -172,11 +176,15 @@ enum sde_cp_crtc_features {
};

enum sde_cp_crtc_pu_features {
	SDE_CP_CRTC_DSPP_RC_PU,
	SDE_CP_CRTC_MAX_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);

@@ -672,10 +680,122 @@ static int set_ltm_hist_crtl_feature(struct sde_hw_dspp *hw_dspp,
	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];
#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];
#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_BUF3] = set_ltm_queue_buf_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)

feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES];
#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];
#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) \
	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_VLUT] = SDE_DSPP_LTM,
	[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_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)
{
	char feature_name[256];
@@ -3775,3 +3933,26 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en,
{
	return 0;
}

void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm)
{
	struct sde_cp_node *prop_node = NULL, *n = NULL;
	struct sde_crtc *crtc;

	if (!crtc_drm) {
		DRM_ERROR("invalid crtc handle");
		return;
	}
	crtc = to_sde_crtc(crtc_drm);
	mutex_lock(&crtc->crtc_cp_lock);
	list_for_each_entry_safe(prop_node, n, &crtc->active_list,
				 active_list) {
		if (prop_node->feature == SDE_CP_CRTC_DSPP_LTM_INIT ||
			prop_node->feature == SDE_CP_CRTC_DSPP_LTM_VLUT) {
			list_del_init(&prop_node->active_list);
			list_add_tail(&prop_node->dirty_list,
				&crtc->dirty_list);
		}
	}
	mutex_unlock(&crtc->crtc_cp_lock);
}
+6 −0
Original line number Diff line number Diff line
@@ -199,4 +199,10 @@ int sde_cp_ltm_wb_pb_interrupt(struct drm_crtc *crtc_drm, bool en,
 */
int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en,
	struct sde_irq_callback *hist_irq);

/**
 * sde_cp_mode_switch_prop_dirty: API marks mode dependent features as dirty
 * @crtc_drm: Pointer to crtc.
 */
void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm);
#endif /*_SDE_COLOR_PROCESSING_H */
+9 −0
Original line number Diff line number Diff line
@@ -429,6 +429,7 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc,
{
	SDE_DEBUG("\n");

	sde_cp_mode_switch_prop_dirty(crtc);
	if ((msm_is_mode_seamless(adjusted_mode) ||
	     (msm_is_mode_seamless_vrr(adjusted_mode) ||
	      msm_is_mode_seamless_dyn_clk(adjusted_mode))) &&
@@ -755,6 +756,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
		}

		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),
				conn_roi.x, conn_roi.y,
				conn_roi.w, conn_roi.h);
@@ -5003,8 +5007,13 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
		sde_crtc_install_dest_scale_properties(sde_crtc, catalog,
				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",
		DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);

	msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info,
			info->data, SDE_KMS_INFO_DATALEN(info),
			CRTC_PROP_INFO);
+202 −179
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@
/* each entry will have register address and bit offset in that register */
#define MAX_BIT_OFFSET 2

/* max table size for dts property lists, increase if tables grow larger */
#define MAX_SDE_DT_TABLE_SIZE 64

/* default line width for sspp, mixer, ds (input), wb */
#define DEFAULT_SDE_LINE_WIDTH 2048

@@ -380,6 +383,14 @@ enum {
	LTM_PROP_MAX,
};

enum {
	RC_OFF,
	RC_LEN,
	RC_VERSION,
	RC_MEM_TOTAL_SIZE,
	RC_PROP_MAX,
};

enum {
	MIXER_OFF,
	MIXER_LEN,
@@ -475,6 +486,20 @@ struct sde_prop_value {
	u32 bit_value[MAX_SDE_HW_BLK][MAX_BIT_OFFSET];
};

/**
 * struct sde_dt_props - stores dts properties read from a sde_prop_type table
 * @exists:	Array of bools indicating if the given prop name was present
 * @counts:	Count of the number of valid values for the property
 * @values:	Array storing the count[i] property values
 *
 * Must use the sde_[get|put]_dt_props APIs to allocate/free this object.
 */
struct sde_dt_props {
	bool exists[MAX_SDE_DT_TABLE_SIZE];
	int counts[MAX_SDE_DT_TABLE_SIZE];
	struct sde_prop_value *values;
};

/*************************************************************
 * dts property list
 *************************************************************/
@@ -682,6 +707,13 @@ static struct sde_prop_type ltm_prop[] = {
	{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[] = {
	{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},
@@ -912,6 +944,8 @@ static int _validate_dt_entry(struct device_node *np,
		case PROP_TYPE_U32:
			rc = of_property_read_u32(np, sde_prop[i].prop_name,
				&val);
			if (!rc)
				prop_count[i] = 1;
			break;
		case PROP_TYPE_U32_ARRAY:
			prop_count[i] = of_property_count_u32_elems(np,
@@ -935,6 +969,14 @@ static int _validate_dt_entry(struct device_node *np,
			if (!snp)
				rc = -EINVAL;
			break;
		case PROP_TYPE_BOOL:
			/**
			 * No special handling for bool properties here.
			 * They will always exist, with value indicating
			 * if the given key is present or not.
			 */
			prop_count[i] = 1;
			break;
		default:
			SDE_DEBUG("invalid property type:%d\n",
							sde_prop[i].type);
@@ -1091,6 +1133,50 @@ static int _read_dt_entry(struct device_node *np,
	return rc;
}

static struct sde_dt_props *sde_get_dt_props(struct device_node *np,
		size_t prop_max, struct sde_prop_type *sde_prop,
		u32 prop_size, u32 *off_count)
{
	struct sde_dt_props *props;
	int rc = -ENOMEM;

	props = kzalloc(sizeof(*props), GFP_KERNEL);
	if (!props)
		return ERR_PTR(rc);

	props->values = kcalloc(prop_max, sizeof(*props->values),
			GFP_KERNEL);
	if (!props->values)
		goto free_props;

	rc = _validate_dt_entry(np, sde_prop, prop_size, props->counts,
			off_count);
	if (rc)
		goto free_vals;

	rc = _read_dt_entry(np, sde_prop, prop_size, props->counts,
		props->exists, props->values);
	if (rc)
		goto free_vals;

	return props;

free_vals:
	kfree(props->values);
free_props:
	kfree(props);
	return ERR_PTR(rc);
}

static void sde_put_dt_props(struct sde_dt_props *props)
{
	if (!props)
		return;

	kfree(props->values);
	kfree(props);
}

static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg,
		enum sde_intr_hwblk_type blk_type, u32 instance, u32 offset)
{
@@ -1709,43 +1795,29 @@ static int sde_sspp_parse_dt(struct device_node *np,
static int sde_ctl_parse_dt(struct device_node *np,
		struct sde_mdss_cfg *sde_cfg)
{
	int rc, prop_count[HW_PROP_MAX], i;
	bool prop_exists[HW_PROP_MAX];
	struct sde_prop_value *prop_value = NULL;
	int i;
	struct sde_dt_props *props;
	struct sde_ctl_cfg *ctl;
	u32 off_count;

	if (!sde_cfg) {
		SDE_ERROR("invalid argument input param\n");
		rc = -EINVAL;
		goto end;
	}

	prop_value = kzalloc(HW_PROP_MAX *
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!prop_value) {
		rc = -ENOMEM;
		goto end;
		return -EINVAL;
	}

	rc = _validate_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count,
		&off_count);
	if (rc)
		goto end;
	props = sde_get_dt_props(np, HW_PROP_MAX, ctl_prop,
			ARRAY_SIZE(ctl_prop), &off_count);
	if (IS_ERR_OR_NULL(props))
		return PTR_ERR(props);

	sde_cfg->ctl_count = off_count;

	rc = _read_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count,
		prop_exists, prop_value);
	if (rc)
		goto end;

	for (i = 0; i < off_count; i++) {
		const char *disp_pref = NULL;

		ctl = sde_cfg->ctl + i;
		ctl->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i);
		ctl->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0);
		ctl->base = PROP_VALUE_ACCESS(props->values, HW_OFF, i);
		ctl->len = PROP_VALUE_ACCESS(props->values, HW_LEN, 0);
		ctl->id = CTL_0 + i;
		snprintf(ctl->name, SDE_HW_BLK_NAME_LEN, "ctl_%u",
				ctl->id - CTL_0);
@@ -1766,9 +1838,9 @@ static int sde_ctl_parse_dt(struct device_node *np,
				SDE_HW_MAJOR(SDE_HW_VER_700))
			set_bit(SDE_CTL_UNIFIED_DSPP_FLUSH, &ctl->features);
	}
end:
	kfree(prop_value);
	return rc;

	sde_put_dt_props(props);
	return 0;
}

void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm,
@@ -1840,14 +1912,7 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm,
static int sde_mixer_parse_dt(struct device_node *np,
						struct sde_mdss_cfg *sde_cfg)
{
	int rc, prop_count[MIXER_PROP_MAX], i, j;
	int blocks_prop_count[MIXER_BLOCKS_PROP_MAX];
	int blend_prop_count[MIXER_BLEND_PROP_MAX];
	bool prop_exists[MIXER_PROP_MAX];
	bool blocks_prop_exists[MIXER_BLOCKS_PROP_MAX];
	bool blend_prop_exists[MIXER_BLEND_PROP_MAX];
	struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL;
	struct sde_prop_value *blend_prop_value = NULL;
	int rc = 0, i, j;
	u32 off_count, blend_off_count, max_blendstages, lm_pair_mask;
	struct sde_lm_cfg *mixer;
	struct sde_lm_sub_blks *sblk;
@@ -1855,30 +1920,18 @@ static int sde_mixer_parse_dt(struct device_node *np,
	u32 pp_idx, dspp_idx, ds_idx;
	u32 mixer_base;
	struct device_node *snp = NULL;
	struct sde_dt_props *props, *blend_props, *blocks_props = NULL;

	if (!sde_cfg) {
		SDE_ERROR("invalid argument input param\n");
		rc = -EINVAL;
		goto end;
		return -EINVAL;
	}
	max_blendstages = sde_cfg->max_mixer_blendstages;

	prop_value = kcalloc(MIXER_PROP_MAX,
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!prop_value) {
		rc = -ENOMEM;
		goto end;
	}

	rc = _validate_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop),
		prop_count, &off_count);
	if (rc)
		goto end;

	rc = _read_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), prop_count,
		prop_exists, prop_value);
	if (rc)
		goto end;
	props = sde_get_dt_props(np, MIXER_PROP_MAX, mixer_prop,
			ARRAY_SIZE(mixer_prop), &off_count);
	if (IS_ERR_OR_NULL(props))
		return PTR_ERR(props);

	pp_count = sde_cfg->pingpong_count;
	dspp_count = sde_cfg->dspp_count;
@@ -1887,47 +1940,30 @@ static int sde_mixer_parse_dt(struct device_node *np,
	/* get mixer feature dt properties if they exist */
	snp = of_get_child_by_name(np, mixer_prop[MIXER_BLOCKS].prop_name);
	if (snp) {
		blocks_prop_value = kzalloc(MIXER_BLOCKS_PROP_MAX *
				MAX_SDE_HW_BLK * sizeof(struct sde_prop_value),
				GFP_KERNEL);
		if (!blocks_prop_value) {
			rc = -ENOMEM;
			goto end;
		blocks_props = sde_get_dt_props(snp, MIXER_PROP_MAX,
				mixer_blocks_prop,
				ARRAY_SIZE(mixer_blocks_prop), NULL);
		if (IS_ERR_OR_NULL(blocks_props)) {
			rc = PTR_ERR(blocks_props);
			goto put_props;
		}
		rc = _validate_dt_entry(snp, mixer_blocks_prop,
			ARRAY_SIZE(mixer_blocks_prop), blocks_prop_count, NULL);
		if (rc)
			goto end;
		rc = _read_dt_entry(snp, mixer_blocks_prop,
				ARRAY_SIZE(mixer_blocks_prop),
				blocks_prop_count, blocks_prop_exists,
				blocks_prop_value);
	}

	/* get the blend_op register offsets */
	blend_prop_value = kzalloc(MIXER_BLEND_PROP_MAX *
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!blend_prop_value) {
		rc = -ENOMEM;
		goto end;
	}
	rc = _validate_dt_entry(np, mixer_blend_prop,
		ARRAY_SIZE(mixer_blend_prop), blend_prop_count,
	blend_props = sde_get_dt_props(np, MIXER_BLEND_PROP_MAX,
			mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop),
			&blend_off_count);
	if (rc)
		goto end;

	rc = _read_dt_entry(np, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop),
		blend_prop_count, blend_prop_exists, blend_prop_value);
	if (rc)
		goto end;
	if (IS_ERR_OR_NULL(blend_props)) {
		rc = PTR_ERR(blend_props);
		goto put_blocks;
	}

	for (i = 0, mixer_count = 0, pp_idx = 0, dspp_idx = 0,
			ds_idx = 0; i < off_count; i++) {
		const char *disp_pref = NULL;
		const char *cwb_pref = NULL;

		mixer_base = PROP_VALUE_ACCESS(prop_value, MIXER_OFF, i);
		mixer_base = PROP_VALUE_ACCESS(props->values, MIXER_OFF, i);
		if (!mixer_base)
			continue;

@@ -1942,15 +1978,15 @@ static int sde_mixer_parse_dt(struct device_node *np,
		mixer->sblk = sblk;

		mixer->base = mixer_base;
		mixer->len = PROP_VALUE_ACCESS(prop_value, MIXER_LEN, 0);
		mixer->len = PROP_VALUE_ACCESS(props->values, MIXER_LEN, 0);
		mixer->id = LM_0 + i;
		snprintf(mixer->name, SDE_HW_BLK_NAME_LEN, "lm_%u",
				mixer->id - LM_0);

		if (!prop_exists[MIXER_LEN])
		if (!props->exists[MIXER_LEN])
			mixer->len = DEFAULT_SDE_HW_BLOCK_LEN;

		lm_pair_mask = PROP_VALUE_ACCESS(prop_value,
		lm_pair_mask = PROP_VALUE_ACCESS(props->values,
				MIXER_PAIR_MASK, i);
		if (lm_pair_mask)
			mixer->lm_pair_mask = 1 << lm_pair_mask;
@@ -1960,7 +1996,7 @@ static int sde_mixer_parse_dt(struct device_node *np,

		for (j = 0; j < blend_off_count; j++)
			sblk->blendstage_base[j] =
				PROP_VALUE_ACCESS(blend_prop_value,
				PROP_VALUE_ACCESS(blend_props->values,
						MIXER_BLEND_OP_OFF, j);

		if (sde_cfg->has_src_split)
@@ -1995,11 +2031,11 @@ static int sde_mixer_parse_dt(struct device_node *np,
		mixer_count++;

		sblk->gc.id = SDE_MIXER_GC;
		if (blocks_prop_value && blocks_prop_exists[MIXER_GC_PROP]) {
			sblk->gc.base = PROP_VALUE_ACCESS(blocks_prop_value,
		if (blocks_props && blocks_props->exists[MIXER_GC_PROP]) {
			sblk->gc.base = PROP_VALUE_ACCESS(blocks_props->values,
					MIXER_GC_PROP, 0);
			sblk->gc.version = PROP_VALUE_ACCESS(blocks_prop_value,
					MIXER_GC_PROP, 1);
			sblk->gc.version = PROP_VALUE_ACCESS(
					blocks_props->values, MIXER_GC_PROP, 1);
			sblk->gc.len = 0;
			set_bit(SDE_MIXER_GC, &mixer->features);
		}
@@ -2007,9 +2043,11 @@ static int sde_mixer_parse_dt(struct device_node *np,
	sde_cfg->mixer_count = mixer_count;

end:
	kfree(prop_value);
	kfree(blocks_prop_value);
	kfree(blend_prop_value);
	sde_put_dt_props(blend_props);
put_blocks:
	sde_put_dt_props(blocks_props);
put_props:
	sde_put_dt_props(props);
	return rc;
}

@@ -2455,102 +2493,66 @@ static int sde_dspp_top_parse_dt(struct device_node *np,
static int sde_dspp_parse_dt(struct device_node *np,
						struct sde_mdss_cfg *sde_cfg)
{
	int rc, prop_count[DSPP_PROP_MAX], i;
	int ad_prop_count[AD_PROP_MAX];
	int ltm_prop_count[LTM_PROP_MAX];
	bool prop_exists[DSPP_PROP_MAX], ad_prop_exists[AD_PROP_MAX];
	bool ltm_prop_exists[LTM_PROP_MAX];
	bool blocks_prop_exists[DSPP_BLOCKS_PROP_MAX];
	struct sde_prop_value *ad_prop_value = NULL, *ltm_prop_value = NULL;
	int blocks_prop_count[DSPP_BLOCKS_PROP_MAX];
	struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL;
	u32 off_count, ad_off_count, ltm_off_count;
	int rc = 0, i;
	u32 off_count, ad_off_count, ltm_off_count, rc_off_count;
	struct sde_dt_props *props, *ad_props, *ltm_props, *rc_props;
	struct sde_dt_props *blocks_props = NULL;
	struct sde_dspp_cfg *dspp;
	struct sde_dspp_sub_blks *sblk;
	struct device_node *snp = NULL;

	if (!sde_cfg) {
		SDE_ERROR("invalid argument\n");
		rc = -EINVAL;
		goto end;
		return -EINVAL;
	}

	prop_value = kzalloc(DSPP_PROP_MAX *
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!prop_value) {
		rc = -ENOMEM;
		goto end;
	}

	rc = _validate_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop),
		prop_count, &off_count);
	if (rc)
		goto end;
	props = sde_get_dt_props(np, DSPP_PROP_MAX, dspp_prop,
			ARRAY_SIZE(dspp_prop), &off_count);
	if (IS_ERR_OR_NULL(props))
		return PTR_ERR(props);

	sde_cfg->dspp_count = off_count;

	rc = _read_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), prop_count,
		prop_exists, prop_value);
	if (rc)
		goto end;

	/* Parse AD dtsi entries */
	ad_prop_value = kcalloc(AD_PROP_MAX,
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!ad_prop_value) {
		rc = -ENOMEM;
		goto end;
	ad_props = sde_get_dt_props(np, AD_PROP_MAX, ad_prop,
			ARRAY_SIZE(ad_prop), &ad_off_count);
	if (IS_ERR_OR_NULL(ad_props)) {
		rc = PTR_ERR(ad_props);
		goto put_props;
	}
	rc = _validate_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop),
		ad_prop_count, &ad_off_count);
	if (rc)
		goto end;
	rc = _read_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), ad_prop_count,
		ad_prop_exists, ad_prop_value);
	if (rc)
		goto end;

	/* Parse LTM dtsi entries */
	ltm_prop_value = kcalloc(LTM_PROP_MAX,
			sizeof(struct sde_prop_value), GFP_KERNEL);
	if (!ltm_prop_value) {
		rc = -ENOMEM;
		goto end;
	ltm_props = sde_get_dt_props(np, LTM_PROP_MAX, ltm_prop,
			ARRAY_SIZE(ltm_prop), &ltm_off_count);
	if (IS_ERR_OR_NULL(ltm_props)) {
		rc = PTR_ERR(ltm_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;
	}
	rc = _validate_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop),
		ltm_prop_count, &ltm_off_count);
	if (rc)
		goto end;
	rc = _read_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), ltm_prop_count,
		ltm_prop_exists, ltm_prop_value);
	if (rc)
		goto end;

	/* get DSPP feature dt properties if they exist */
	snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name);
	if (snp) {
		blocks_prop_value = kzalloc(DSPP_BLOCKS_PROP_MAX *
				MAX_SDE_HW_BLK * sizeof(struct sde_prop_value),
				GFP_KERNEL);
		if (!blocks_prop_value) {
			rc = -ENOMEM;
			goto end;
		blocks_props = sde_get_dt_props(snp, DSPP_BLOCKS_PROP_MAX,
				dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop),
				NULL);
		if (IS_ERR_OR_NULL(blocks_props)) {
			rc = PTR_ERR(blocks_props);
			goto put_rc_props;
		}
		rc = _validate_dt_entry(snp, dspp_blocks_prop,
			ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, NULL);
		if (rc)
			goto end;
		rc = _read_dt_entry(snp, dspp_blocks_prop,
			ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count,
			blocks_prop_exists, blocks_prop_value);
		if (rc)
			goto end;
	}

	for (i = 0; i < off_count; i++) {
		dspp = sde_cfg->dspp + i;
		dspp->base = PROP_VALUE_ACCESS(prop_value, DSPP_OFF, i);
		dspp->len = PROP_VALUE_ACCESS(prop_value, DSPP_SIZE, 0);
		dspp->base = PROP_VALUE_ACCESS(props->values, DSPP_OFF, i);
		dspp->len = PROP_VALUE_ACCESS(props->values, DSPP_SIZE, 0);
		dspp->id = DSPP_0 + i;
		snprintf(dspp->name, SDE_HW_BLK_NAME_LEN, "dspp_%u",
				dspp->id - DSPP_0);
@@ -2563,17 +2565,18 @@ static int sde_dspp_parse_dt(struct device_node *np,
		}
		dspp->sblk = sblk;

		if (blocks_prop_value)
		if (blocks_props)
			_sde_dspp_setup_blocks(sde_cfg, dspp, sblk,
					blocks_prop_exists, blocks_prop_value);
					blocks_props->exists,
					blocks_props->values);

		sblk->ad.id = SDE_DSPP_AD;
		sde_cfg->ad_count = ad_off_count;
		if (ad_prop_value && (i < ad_off_count) &&
		    ad_prop_exists[AD_OFF]) {
			sblk->ad.base = PROP_VALUE_ACCESS(ad_prop_value,
		if (ad_props && (i < ad_off_count) &&
		    ad_props->exists[AD_OFF]) {
			sblk->ad.base = PROP_VALUE_ACCESS(ad_props->values,
				AD_OFF, i);
			sblk->ad.version = PROP_VALUE_ACCESS(ad_prop_value,
			sblk->ad.version = PROP_VALUE_ACCESS(ad_props->values,
				AD_VERSION, 0);
			set_bit(SDE_DSPP_AD, &dspp->features);
			rc = _add_to_irq_offset_list(sde_cfg,
@@ -2585,11 +2588,11 @@ static int sde_dspp_parse_dt(struct device_node *np,

		sblk->ltm.id = SDE_DSPP_LTM;
		sde_cfg->ltm_count = ltm_off_count;
		if (ltm_prop_value && (i < ltm_off_count) &&
		    ltm_prop_exists[LTM_OFF]) {
			sblk->ltm.base = PROP_VALUE_ACCESS(ltm_prop_value,
		if (ltm_props && (i < ltm_off_count) &&
		    ltm_props->exists[LTM_OFF]) {
			sblk->ltm.base = PROP_VALUE_ACCESS(ltm_props->values,
				LTM_OFF, i);
			sblk->ltm.version = PROP_VALUE_ACCESS(ltm_prop_value,
			sblk->ltm.version = PROP_VALUE_ACCESS(ltm_props->values,
				LTM_VERSION, 0);
			set_bit(SDE_DSPP_LTM, &dspp->features);
			rc = _add_to_irq_offset_list(sde_cfg,
@@ -2599,13 +2602,34 @@ static int sde_dspp_parse_dt(struct device_node *np,
				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:
	kfree(prop_value);
	kfree(ad_prop_value);
	kfree(ltm_prop_value);
	kfree(blocks_prop_value);
	sde_put_dt_props(blocks_props);
put_rc_props:
	sde_put_dt_props(rc_props);
put_ltm_props:
	sde_put_dt_props(ltm_props);
put_ad_props:
	sde_put_dt_props(ad_props);
put_props:
	sde_put_dt_props(props);
	return rc;
}

@@ -2713,7 +2737,6 @@ static int sde_ds_parse_dt(struct device_node *np,
			set_bit(SDE_SSPP_SCALER_QSEED3, &ds->features);
		else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3LITE)
			set_bit(SDE_SSPP_SCALER_QSEED3LITE, &ds->features);

	}

end:
Loading