Loading Documentation/devicetree/bindings/display/msm/sde.txt +37 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,15 @@ Optional properties: - qcom,sde-axi-bus-width: A u32 property to indicate the axi bus width value in bytes - qcom,sde-mixer-stage-base-layer: A boolean property to indicate if a layer can be staged on base stage instead of border fill - qcom,sde-limits: A node that lists the limits for different properties. This node can have multiple child nodes. Each child node represents a specific usecase limit. The usecase can be defined for properties like sspp linewidth, bw limit etc. e.g. qcom,sde-limits -- qcom,sde-limit-name: name of the usecase -- qcom,sde-limit-cases: different usecases to be considered -- qcom,sde-limit-ids: respective ids for the above usecases -- qcom,sde-limit-values: usecase and value for different combinations Bus Scaling Subnodes: - qcom,sde-reg-bus: Property to provide Bus scaling for register access for Loading Loading @@ -771,6 +780,34 @@ Example: qcom,sde-dspp-vlut = <0x0 0x00010000>; }; qcom,sde-limits { qcom,sde-linewidth-limits{ qcom,sde-limit-cases = "vig", "dma", "scaling", "inline_rot"; qcom,sde-limit-ids= <0x1 0x2 0x4 0x8>; /* the qcom,sde-limit-values property consist of two values: one for the usecase and the other for the value. The usecase can be any combination of the values mentioned in qcom,sde-limit-ids. For eg: <0x5 2560> means usecase is 0x5 and value is 2560. 0x5 = (0x1 | 0x4) = vig + scaling. Thus the linewidth for usecase vig + scaling = 2560 */ qcom,sde-limit-values = <0x1 4096>, <0x5 2560>, <0xd 1088>, <0x2 4096>; }; qcom,sde-bw-limits{ qcom,sde-limit-cases = "per_pipe", "total_bw", "vfe_on", "cwb_on"; qcom,sde-limit-ids = <0x1 0x2 0x4 0x8>; qcom,sde-limit-values = <0x1 2600000>, <0x9 2600000>, <0x5 2600000>, <0xd 2600000>, <0x2 5800000>, <0xa 5500000>, <0x6 4400000>, <0xe 3900000>; }; }; qcom,sde-mixer-blocks { qcom,sde-mixer-gc = <0x3c0 0x00010000>; }; Loading arch/arm64/boot/dts/qcom/atoll-sde.dtsi +32 −0 Original line number Diff line number Diff line Loading @@ -274,6 +274,38 @@ <1 590 0 150000>, <1 590 0 300000>; }; qcom,sde-limits { qcom,sde-linewidth-limits{ qcom,sde-limit-name = "sspp_linewidth_usecases"; qcom,sde-limit-cases = "vig", "dma", "scale"; qcom,sde-limit-ids= <0x1 0x2 0x4>; qcom,sde-limit-values = <0x1 4096>, <0x5 2560>, <0x2 2160>; }; qcom,sde-bw-limits{ qcom,sde-limit-name = "sde_bwlimit_usecases"; qcom,sde-limit-cases = "per_vig_pipe", "per_dma_pipe", "total_max_bw", "camera_concurrency", "cwb_concurrency"; qcom,sde-limit-ids = <0x1 0x2 0x4 0x8 0x10>; qcom,sde-limit-values = <0x1 2600000>, <0x11 2600000>, <0x9 2600000>, <0x19 2600000>, <0x2 2600000>, <0x12 2600000>, <0xa 2600000>, <0x1a 2600000>, <0x4 5800000>, <0x14 5500000>, <0xc 4400000>, <0x1c 3900000>; }; }; }; sde_rscc: qcom,sde_rscc@af20000 { Loading drivers/gpu/drm/msm/sde/sde_crtc.c +33 −0 Original line number Diff line number Diff line Loading @@ -5589,6 +5589,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"}, Loading Loading @@ -5800,6 +5802,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", Loading drivers/gpu/drm/msm/sde/sde_hw_catalog.c +169 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ enum sde_prop { SEC_SID_MASK, LINE_INSERTION, BASE_LAYER, SDE_LIMITS, SDE_PROP_MAX, }; Loading Loading @@ -267,6 +268,14 @@ enum { INTF_PROP_MAX, }; enum { LIMIT_NAME, LIMIT_USECASE, LIMIT_ID, LIMIT_VALUE, LIMIT_PROP_MAX, }; enum { PP_OFF, PP_LEN, Loading Loading @@ -463,6 +472,7 @@ static struct sde_prop_type sde_prop[] = { {SEC_SID_MASK, "qcom,sde-secure-sid-mask", false, PROP_TYPE_U32_ARRAY}, {LINE_INSERTION, "qcom,sde-has-line-insertion", false, PROP_TYPE_BOOL}, {BASE_LAYER, "qcom,sde-mixer-stage-base-layer", false, PROP_TYPE_BOOL}, {SDE_LIMITS, "qcom,sde-limits", false, PROP_TYPE_NODE}, }; static struct sde_prop_type sde_perf_prop[] = { Loading Loading @@ -745,6 +755,14 @@ static struct sde_prop_type inline_rot_prop[INLINE_ROT_PROP_MAX] = { PROP_TYPE_BIT_OFFSET_ARRAY}, }; 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 *************************************************************/ Loading Loading @@ -2935,6 +2953,148 @@ static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) return rc; } 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_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) { int rc, i, dma_rc, len, prop_count[SDE_PROP_MAX]; Loading Loading @@ -3103,6 +3263,10 @@ static int sde_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) cfg->has_line_insertion = PROP_VALUE_ACCESS(prop_value, LINE_INSERTION, 0); cfg->has_base_layer = PROP_VALUE_ACCESS(prop_value, BASE_LAYER, 0); rc = sde_limit_parse_dt(np, cfg); if (rc) SDE_DEBUG("parsing of sde limit failed\n"); end: kfree(prop_value); return rc; Loading Loading @@ -3919,6 +4083,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); Loading drivers/gpu/drm/msm/sde/sde_hw_catalog.h +39 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,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 Loading Loading @@ -1088,6 +1089,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 Loading Loading @@ -1253,6 +1290,8 @@ 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; Loading Loading
Documentation/devicetree/bindings/display/msm/sde.txt +37 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,15 @@ Optional properties: - qcom,sde-axi-bus-width: A u32 property to indicate the axi bus width value in bytes - qcom,sde-mixer-stage-base-layer: A boolean property to indicate if a layer can be staged on base stage instead of border fill - qcom,sde-limits: A node that lists the limits for different properties. This node can have multiple child nodes. Each child node represents a specific usecase limit. The usecase can be defined for properties like sspp linewidth, bw limit etc. e.g. qcom,sde-limits -- qcom,sde-limit-name: name of the usecase -- qcom,sde-limit-cases: different usecases to be considered -- qcom,sde-limit-ids: respective ids for the above usecases -- qcom,sde-limit-values: usecase and value for different combinations Bus Scaling Subnodes: - qcom,sde-reg-bus: Property to provide Bus scaling for register access for Loading Loading @@ -771,6 +780,34 @@ Example: qcom,sde-dspp-vlut = <0x0 0x00010000>; }; qcom,sde-limits { qcom,sde-linewidth-limits{ qcom,sde-limit-cases = "vig", "dma", "scaling", "inline_rot"; qcom,sde-limit-ids= <0x1 0x2 0x4 0x8>; /* the qcom,sde-limit-values property consist of two values: one for the usecase and the other for the value. The usecase can be any combination of the values mentioned in qcom,sde-limit-ids. For eg: <0x5 2560> means usecase is 0x5 and value is 2560. 0x5 = (0x1 | 0x4) = vig + scaling. Thus the linewidth for usecase vig + scaling = 2560 */ qcom,sde-limit-values = <0x1 4096>, <0x5 2560>, <0xd 1088>, <0x2 4096>; }; qcom,sde-bw-limits{ qcom,sde-limit-cases = "per_pipe", "total_bw", "vfe_on", "cwb_on"; qcom,sde-limit-ids = <0x1 0x2 0x4 0x8>; qcom,sde-limit-values = <0x1 2600000>, <0x9 2600000>, <0x5 2600000>, <0xd 2600000>, <0x2 5800000>, <0xa 5500000>, <0x6 4400000>, <0xe 3900000>; }; }; qcom,sde-mixer-blocks { qcom,sde-mixer-gc = <0x3c0 0x00010000>; }; Loading
arch/arm64/boot/dts/qcom/atoll-sde.dtsi +32 −0 Original line number Diff line number Diff line Loading @@ -274,6 +274,38 @@ <1 590 0 150000>, <1 590 0 300000>; }; qcom,sde-limits { qcom,sde-linewidth-limits{ qcom,sde-limit-name = "sspp_linewidth_usecases"; qcom,sde-limit-cases = "vig", "dma", "scale"; qcom,sde-limit-ids= <0x1 0x2 0x4>; qcom,sde-limit-values = <0x1 4096>, <0x5 2560>, <0x2 2160>; }; qcom,sde-bw-limits{ qcom,sde-limit-name = "sde_bwlimit_usecases"; qcom,sde-limit-cases = "per_vig_pipe", "per_dma_pipe", "total_max_bw", "camera_concurrency", "cwb_concurrency"; qcom,sde-limit-ids = <0x1 0x2 0x4 0x8 0x10>; qcom,sde-limit-values = <0x1 2600000>, <0x11 2600000>, <0x9 2600000>, <0x19 2600000>, <0x2 2600000>, <0x12 2600000>, <0xa 2600000>, <0x1a 2600000>, <0x4 5800000>, <0x14 5500000>, <0xc 4400000>, <0x1c 3900000>; }; }; }; sde_rscc: qcom,sde_rscc@af20000 { Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +33 −0 Original line number Diff line number Diff line Loading @@ -5589,6 +5589,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"}, Loading Loading @@ -5800,6 +5802,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", Loading
drivers/gpu/drm/msm/sde/sde_hw_catalog.c +169 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ enum sde_prop { SEC_SID_MASK, LINE_INSERTION, BASE_LAYER, SDE_LIMITS, SDE_PROP_MAX, }; Loading Loading @@ -267,6 +268,14 @@ enum { INTF_PROP_MAX, }; enum { LIMIT_NAME, LIMIT_USECASE, LIMIT_ID, LIMIT_VALUE, LIMIT_PROP_MAX, }; enum { PP_OFF, PP_LEN, Loading Loading @@ -463,6 +472,7 @@ static struct sde_prop_type sde_prop[] = { {SEC_SID_MASK, "qcom,sde-secure-sid-mask", false, PROP_TYPE_U32_ARRAY}, {LINE_INSERTION, "qcom,sde-has-line-insertion", false, PROP_TYPE_BOOL}, {BASE_LAYER, "qcom,sde-mixer-stage-base-layer", false, PROP_TYPE_BOOL}, {SDE_LIMITS, "qcom,sde-limits", false, PROP_TYPE_NODE}, }; static struct sde_prop_type sde_perf_prop[] = { Loading Loading @@ -745,6 +755,14 @@ static struct sde_prop_type inline_rot_prop[INLINE_ROT_PROP_MAX] = { PROP_TYPE_BIT_OFFSET_ARRAY}, }; 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 *************************************************************/ Loading Loading @@ -2935,6 +2953,148 @@ static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) return rc; } 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_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) { int rc, i, dma_rc, len, prop_count[SDE_PROP_MAX]; Loading Loading @@ -3103,6 +3263,10 @@ static int sde_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) cfg->has_line_insertion = PROP_VALUE_ACCESS(prop_value, LINE_INSERTION, 0); cfg->has_base_layer = PROP_VALUE_ACCESS(prop_value, BASE_LAYER, 0); rc = sde_limit_parse_dt(np, cfg); if (rc) SDE_DEBUG("parsing of sde limit failed\n"); end: kfree(prop_value); return rc; Loading Loading @@ -3919,6 +4083,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); Loading
drivers/gpu/drm/msm/sde/sde_hw_catalog.h +39 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,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 Loading Loading @@ -1088,6 +1089,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 Loading Loading @@ -1253,6 +1290,8 @@ 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; Loading