浏览代码

Merge "disp: msm: sde: add support to handle mdp limits property"

qctecmdr 5 年之前
父节点
当前提交
1643b63bd7
共有 3 个文件被更改,包括 243 次插入0 次删除
  1. 33 0
      msm/sde/sde_crtc.c
  2. 170 0
      msm/sde/sde_hw_catalog.c
  3. 40 0
      msm/sde/sde_hw_catalog.h

+ 33 - 0
msm/sde/sde_crtc.c

@@ -4708,6 +4708,8 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
 	struct drm_device *dev;
 	struct sde_kms_info *info;
 	struct sde_kms *sde_kms;
+	int i, j;
+
 	static const struct drm_prop_enum_list e_secure_level[] = {
 		{SDE_DRM_SEC_NON_SEC, "sec_and_non_sec"},
 		{SDE_DRM_SEC_ONLY, "sec_only"},
@@ -4925,6 +4927,37 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
 	if (sde_kms->perf.max_core_clk_rate)
 		sde_kms_info_add_keyint(info, "max_mdp_clk",
 				sde_kms->perf.max_core_clk_rate);
+
+	for (i = 0; i < catalog->limit_count; i++) {
+		sde_kms_info_add_keyint(info,
+			catalog->limit_cfg[i].name,
+			catalog->limit_cfg[i].lmt_case_cnt);
+
+		for (j = 0; j < catalog->limit_cfg[i].lmt_case_cnt; j++) {
+			sde_kms_info_add_keyint(info,
+				catalog->limit_cfg[i].vector_cfg[j].usecase,
+				catalog->limit_cfg[i].vector_cfg[j].value);
+		}
+
+		if (!strcmp(catalog->limit_cfg[i].name,
+			"sspp_linewidth_usecases"))
+			sde_kms_info_add_keyint(info,
+				"sspp_linewidth_values",
+				catalog->limit_cfg[i].lmt_vec_cnt);
+		else if (!strcmp(catalog->limit_cfg[i].name,
+			"sde_bwlimit_usecases"))
+			sde_kms_info_add_keyint(info,
+				"sde_bwlimit_values",
+				catalog->limit_cfg[i].lmt_vec_cnt);
+
+		for (j = 0; j < catalog->limit_cfg[i].lmt_vec_cnt; j++) {
+			sde_kms_info_add_keyint(info, "limit_usecase",
+				catalog->limit_cfg[i].value_cfg[j].use_concur);
+			sde_kms_info_add_keyint(info, "limit_value",
+				catalog->limit_cfg[i].value_cfg[j].value);
+		}
+	}
+
 	sde_kms_info_add_keystr(info, "core_ib_ff",
 			catalog->perf.core_ib_ff);
 	sde_kms_info_add_keystr(info, "core_clk_ff",

+ 170 - 0
msm/sde/sde_hw_catalog.c

@@ -185,6 +185,7 @@ enum sde_prop {
 	UBWC_BW_CALC_VERSION,
 	PIPE_ORDER_VERSION,
 	SEC_SID_MASK,
+	SDE_LIMITS,
 	SDE_PROP_MAX,
 };
 
@@ -279,6 +280,14 @@ enum {
 	INTF_PROP_MAX,
 };
 
+enum {
+	LIMIT_NAME,
+	LIMIT_USECASE,
+	LIMIT_ID,
+	LIMIT_VALUE,
+	LIMIT_PROP_MAX,
+};
+
 enum {
 	PP_OFF,
 	PP_LEN,
@@ -479,6 +488,7 @@ static struct sde_prop_type sde_prop[] = {
 	{PIPE_ORDER_VERSION, "qcom,sde-pipe-order-version", false,
 			PROP_TYPE_U32},
 	{SEC_SID_MASK, "qcom,sde-secure-sid-mask", false, PROP_TYPE_U32_ARRAY},
+	{SDE_LIMITS, "qcom,sde-limits", false, PROP_TYPE_NODE},
 };
 
 static struct sde_prop_type sde_perf_prop[] = {
@@ -765,6 +775,14 @@ static struct sde_prop_type qdss_prop[] = {
 	{HW_LEN, "qcom,sde-qdss-size", false, PROP_TYPE_U32},
 };
 
+static struct sde_prop_type limit_usecase_prop[] = {
+	{LIMIT_NAME, "qcom,sde-limit-name", false, PROP_TYPE_STRING},
+	{LIMIT_USECASE, "qcom,sde-limit-cases", false, PROP_TYPE_STRING_ARRAY},
+	{LIMIT_ID, "qcom,sde-limit-ids", false, PROP_TYPE_U32_ARRAY},
+	{LIMIT_VALUE, "qcom,sde-limit-values", false,
+			PROP_TYPE_BIT_OFFSET_ARRAY},
+};
+
 /*************************************************************
  * static API list
  *************************************************************/
@@ -3146,6 +3164,149 @@ static int _sde_parse_prop_check(struct sde_mdss_cfg *cfg,
 	return 0;
 }
 
+static int sde_read_limit_node(struct device_node *snp,
+	struct sde_prop_value *lmt_val, struct sde_mdss_cfg *cfg)
+{
+	int j, i = 0, rc = 0;
+	const char *type = NULL;
+	struct device_node *node = NULL;
+
+	for_each_child_of_node(snp, node) {
+		cfg->limit_cfg[i].vector_cfg =
+			kcalloc(cfg->limit_cfg[i].lmt_case_cnt,
+				sizeof(struct limit_vector_cfg), GFP_KERNEL);
+		if (!cfg->limit_cfg[i].vector_cfg) {
+			rc = -ENOMEM;
+			goto error;
+		}
+
+		for (j = 0; j < cfg->limit_cfg[i].lmt_case_cnt; j++) {
+			of_property_read_string_index(node,
+				limit_usecase_prop[LIMIT_USECASE].prop_name,
+				j, &type);
+			cfg->limit_cfg[i].vector_cfg[j].usecase = type;
+			cfg->limit_cfg[i].vector_cfg[j].value =
+				PROP_VALUE_ACCESS(&lmt_val[i * LIMIT_PROP_MAX],
+				LIMIT_ID, j);
+		}
+
+		cfg->limit_cfg[i].value_cfg =
+				kcalloc(cfg->limit_cfg[i].lmt_vec_cnt,
+				sizeof(struct limit_value_cfg), GFP_KERNEL);
+
+		if (!cfg->limit_cfg[i].value_cfg) {
+			rc = -ENOMEM;
+			goto error;
+		}
+
+		for (j = 0; j < cfg->limit_cfg[i].lmt_vec_cnt; j++) {
+			cfg->limit_cfg[i].value_cfg[j].use_concur =
+				PROP_BITVALUE_ACCESS(
+					&lmt_val[i * LIMIT_PROP_MAX],
+					LIMIT_VALUE, j, 0);
+			cfg->limit_cfg[i].value_cfg[j].value =
+				PROP_BITVALUE_ACCESS(
+					&lmt_val[i * LIMIT_PROP_MAX],
+					LIMIT_VALUE, j, 1);
+
+		}
+		i++;
+	}
+
+	return 0;
+error:
+	for (j = 0; j < cfg->limit_count; j++) {
+		kfree(cfg->limit_cfg[j].vector_cfg);
+		kfree(cfg->limit_cfg[j].value_cfg);
+	}
+
+	cfg->limit_count = 0;
+	return rc;
+}
+
+static int sde_validate_limit_node(struct device_node *snp,
+	struct sde_prop_value *sde_limit_value, struct sde_mdss_cfg *cfg)
+{
+	int i = 0, rc = 0;
+	struct device_node *node = NULL;
+	int limit_value_count[LIMIT_PROP_MAX];
+	bool limit_value_exists[LIMIT_SUBBLK_COUNT_MAX][LIMIT_PROP_MAX];
+	const char *type = NULL;
+
+	for_each_child_of_node(snp, node) {
+		rc = _validate_dt_entry(node, limit_usecase_prop,
+			ARRAY_SIZE(limit_usecase_prop),
+			limit_value_count, NULL);
+		if (rc)
+			goto end;
+
+		rc = _read_dt_entry(node, limit_usecase_prop,
+			ARRAY_SIZE(limit_usecase_prop), limit_value_count,
+			&limit_value_exists[i][0],
+			&sde_limit_value[i * LIMIT_PROP_MAX]);
+		if (rc)
+			goto end;
+
+		cfg->limit_cfg[i].lmt_case_cnt =
+				limit_value_count[LIMIT_ID];
+
+		cfg->limit_cfg[i].lmt_vec_cnt =
+				limit_value_count[LIMIT_VALUE];
+		of_property_read_string(node,
+			limit_usecase_prop[LIMIT_NAME].prop_name, &type);
+		cfg->limit_cfg[i].name = type;
+
+		if (!limit_value_count[LIMIT_ID] ||
+				!limit_value_count[LIMIT_VALUE]) {
+			rc = -EINVAL;
+			goto end;
+		}
+		i++;
+	}
+	return 0;
+end:
+	cfg->limit_count = 0;
+	return rc;
+}
+
+static int sde_limit_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
+{
+	struct device_node *snp = NULL;
+	struct sde_prop_value  *sde_limit_value = NULL;
+	int rc = 0;
+
+	snp = of_get_child_by_name(np, sde_prop[SDE_LIMITS].prop_name);
+	if (!snp)
+		goto end;
+
+	cfg->limit_count = of_get_child_count(snp);
+	if (cfg->limit_count < 0) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	sde_limit_value = kzalloc(cfg->limit_count * LIMIT_PROP_MAX *
+			sizeof(struct sde_prop_value), GFP_KERNEL);
+	if (!sde_limit_value) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	rc = sde_validate_limit_node(snp, sde_limit_value, cfg);
+	if (rc) {
+		SDE_ERROR("validating limit node failed\n");
+		goto end;
+	}
+
+	rc = sde_read_limit_node(snp, sde_limit_value, cfg);
+	if (rc)
+		SDE_ERROR("reading limit node failed\n");
+
+end:
+	kfree(sde_limit_value);
+	return rc;
+}
+
 static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
 {
 	int rc, i, dma_rc, len, prop_count[SDE_PROP_MAX];
@@ -3256,6 +3417,10 @@ static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
 	cfg->has_idle_pc = PROP_VALUE_ACCESS(prop_value, IDLE_PC, 0);
 	cfg->pipe_order_type = PROP_VALUE_ACCESS(prop_value,
 		PIPE_ORDER_VERSION, 0);
+
+	rc = sde_limit_parse_dt(np, cfg);
+	if (rc)
+		SDE_DEBUG("parsing of sde limit failed\n");
 end:
 	kfree(prop_value);
 	return rc;
@@ -4176,6 +4341,11 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
 			kfree(sde_cfg->vbif[i].qos_tbl[j].priority_lvl);
 	}
 
+	for (i = 0; i < sde_cfg->limit_count; i++) {
+		kfree(sde_cfg->limit_cfg[i].vector_cfg);
+		kfree(sde_cfg->limit_cfg[i].value_cfg);
+	}
+
 	for (i = 0; i < SDE_QOS_LUT_USAGE_MAX; i++) {
 		kfree(sde_cfg->perf.sfe_lut_tbl[i].entries);
 		kfree(sde_cfg->perf.qos_lut_tbl[i].entries);

+ 40 - 0
msm/sde/sde_hw_catalog.h

@@ -80,6 +80,7 @@
 
 #define MAX_XIN_COUNT 16
 #define SSPP_SUBBLK_COUNT_MAX 2
+#define LIMIT_SUBBLK_COUNT_MAX 10
 
 #define SDE_CTL_CFG_VERSION_1_0_0       0x100
 #define MAX_INTF_PER_CTL_V1                 2
@@ -1181,6 +1182,42 @@ struct sde_perf_cfg {
 	u32 num_mnoc_ports;
 };
 
+/**
+ * struct limit_vector_cfg - information on the usecase for each limit
+ * @usecase: usecase for each limit
+ * @value: id corresponding to each usecase
+ */
+struct limit_vector_cfg {
+	const char *usecase;
+	u32 value;
+};
+
+/**
+ * struct limit_value_cfg - information on the value of usecase
+ * @use_concur: usecase for each limit
+ * @value: value corresponding to usecase for each limit
+ */
+struct limit_value_cfg {
+	u32 use_concur;
+	u32 value;
+};
+
+/**
+ * struct sde_limit_cfg - information om different mdp limits
+ * @name: name of the limit property
+ * @lmt_vec_cnt: number of vector values for each limit
+ * @lmt_case_cnt: number of usecases for each limit
+ * @vector_cfg: pointer to the vector entries containing info on usecase
+ * @value_cfg: pointer to the value of each vector entry
+ */
+struct sde_limit_cfg {
+	const char *name;
+	u32 lmt_vec_cnt;
+	u32 lmt_case_cnt;
+	struct limit_vector_cfg *vector_cfg;
+	struct limit_value_cfg *value_cfg;
+};
+
 /**
  * struct sde_mdss_cfg - information of MDSS HW
  * This is the main catalog data structure representing
@@ -1366,6 +1403,9 @@ struct sde_mdss_cfg {
 	u32 qdss_count;
 	struct sde_qdss_cfg qdss[MAX_BLOCKS];
 
+	u32 limit_count;
+	struct sde_limit_cfg limit_cfg[LIMIT_SUBBLK_COUNT_MAX];
+
 	/* Add additional block data structures here */
 
 	struct sde_perf_cfg perf;