diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 1e5acfdf7d..4568e81922 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -19,6 +19,7 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ #include #include +#include #include #include diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 22d634250e..b47f77e568 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include "sde_hw_mdss.h" diff --git a/msm/sde_power_handle.c b/msm/sde_power_handle.c index 1ed7c4885d..b8db0e2a9a 100644 --- a/msm/sde_power_handle.c +++ b/msm/sde_power_handle.c @@ -14,8 +14,6 @@ #include #include -#include -#include #include #include @@ -23,6 +21,13 @@ #include "sde_trace.h" #include "sde_dbg.h" +static const struct sde_power_bus_scaling_data sde_reg_bus_table[] = { + {0, 0}, + {0, 76800}, + {0, 150000}, + {0, 300000}, +}; + static const char *data_bus_name[SDE_POWER_HANDLE_DBUS_ID_MAX] = { [SDE_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,sde-data-bus", [SDE_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,sde-llcc-bus", @@ -277,68 +282,50 @@ clk_err: return rc; } -#ifdef CONFIG_QCOM_BUS_SCALING - #define MAX_AXI_PORT_COUNT 3 static int _sde_power_data_bus_set_quota( struct sde_power_data_bus_handle *pdbus, u64 in_ab_quota, u64 in_ib_quota) { - int new_uc_idx; - u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0}; - u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0}; - int rc; + int rc = 0, i = 0, j = 0; - if (pdbus->data_bus_hdl < 1) { - pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl); + if (!pdbus->data_paths_cnt) { + pr_err("invalid data bus handle\n"); return -EINVAL; } - if (!in_ab_quota && !in_ib_quota) { - new_uc_idx = 0; - } else { - int i; - struct msm_bus_vectors *vect = NULL; - struct msm_bus_scale_pdata *bw_table = - pdbus->data_bus_scale_table; - u32 total_data_paths_cnt = pdbus->data_paths_cnt; + pr_debug("ab=%llu ib=%llu\n", in_ab_quota, in_ib_quota); - if (!bw_table || !total_data_paths_cnt || - total_data_paths_cnt > MAX_AXI_PORT_COUNT) { - pr_err("invalid input\n"); - return -EINVAL; - } - - ab_quota[0] = div_u64(in_ab_quota, total_data_paths_cnt); - ib_quota[0] = div_u64(in_ib_quota, total_data_paths_cnt); - - for (i = 1; i < total_data_paths_cnt; i++) { - ab_quota[i] = ab_quota[0]; - ib_quota[i] = ib_quota[0]; - } - - new_uc_idx = (pdbus->curr_bw_uc_idx % - (bw_table->num_usecases - 1)) + 1; - - for (i = 0; i < total_data_paths_cnt; i++) { - vect = &bw_table->usecase[new_uc_idx].vectors[i]; - vect->ab = ab_quota[i]; - vect->ib = ib_quota[i]; - - pr_debug( - "%s uc_idx=%d idx=%d ab=%llu ib=%llu\n", - bw_table->name, new_uc_idx, i, vect->ab, - vect->ib); - } - } - pdbus->curr_bw_uc_idx = new_uc_idx; + in_ab_quota = div_u64(in_ab_quota, pdbus->data_paths_cnt); SDE_ATRACE_BEGIN("msm_bus_scale_req"); - rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl, - new_uc_idx); + for (i = 0; i < pdbus->data_paths_cnt; i++) { + if (pdbus->data_bus_hdl[i]) { + rc = icc_set_bw(pdbus->data_bus_hdl[i], + in_ab_quota, in_ib_quota); + if (rc) + goto err; + } + } + + pdbus->curr_val.ab = in_ab_quota; + pdbus->curr_val.ib = in_ib_quota; + SDE_ATRACE_END("msm_bus_scale_req"); + return rc; +err: + for (j = 0; j < i; j++) + if (pdbus->data_bus_hdl[j]) + icc_set_bw(pdbus->data_bus_hdl[j], + pdbus->curr_val.ab, + pdbus->curr_val.ib); + + SDE_ATRACE_END("msm_bus_scale_req"); + pr_err("failed to set data bus vote ab=%llu ib=%llu rc=%d\n", + rc, in_ab_quota, in_ib_quota); + return rc; } @@ -356,7 +343,7 @@ int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, trace_sde_perf_update_bus(bus_id, ab_quota, ib_quota); - if (phandle->data_bus_handle[bus_id].data_bus_hdl) + if (phandle->data_bus_handle[bus_id].data_paths_cnt > 0) rc = _sde_power_data_bus_set_quota( &phandle->data_bus_handle[bus_id], ab_quota, ib_quota); @@ -368,96 +355,96 @@ int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, static void sde_power_data_bus_unregister( struct sde_power_data_bus_handle *pdbus) { - if (pdbus->data_bus_hdl) { - msm_bus_scale_unregister_client(pdbus->data_bus_hdl); - pdbus->data_bus_hdl = 0; + int i = 0; + + for (i = 0; i < pdbus->data_paths_cnt; i++) { + if (pdbus->data_bus_hdl[i]) { + icc_put(pdbus->data_bus_hdl[i]); + pdbus->data_bus_hdl[i] = NULL; + } } } static int sde_power_data_bus_parse(struct platform_device *pdev, struct sde_power_data_bus_handle *pdbus, const char *name) { - struct device_node *node; - int rc = 0; - int paths; + char bus_name[32]; + int i = 0, ret = 0; - node = of_get_child_by_name(pdev->dev.of_node, name); - if (!node) - goto end; + for (i = 0; i < DATA_BUS_PATH_MAX; i++) { + snprintf(bus_name, sizeof(bus_name), "%s%d", name, i); + ret = of_property_match_string(pdev->dev.of_node, + "interconnect-names", bus_name); + if (ret < 0) { + if (!pdbus->data_paths_cnt) { + pr_debug("sde: bus %s dt node missing\n", bus_name); + return 0; + } else + goto end; + } else + pdbus->data_bus_hdl[i] = of_icc_get(&pdev->dev, bus_name); - rc = of_property_read_u32(node, "qcom,msm-bus,num-paths", &paths); - if (rc) { - pr_err("Error. qcom,msm-bus,num-paths not found\n"); - return rc; + if (IS_ERR_OR_NULL(pdbus->data_bus_hdl[i])) { + pr_debug("icc get path failed for %s\n", bus_name); + break; + } + pdbus->data_paths_cnt++; } - pdbus->data_paths_cnt = paths; - pdbus->data_bus_scale_table = msm_bus_pdata_from_node(pdev, node); - if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) { - pr_err("reg bus handle parsing failed\n"); - rc = PTR_ERR(pdbus->data_bus_scale_table); - if (!pdbus->data_bus_scale_table) - rc = -EINVAL; - goto end; + if (!pdbus->data_paths_cnt) { + pr_err("get none data bus path for %s\n", name); + return -EINVAL; } - pdbus->data_bus_hdl = msm_bus_scale_register_client( - pdbus->data_bus_scale_table); - if (!pdbus->data_bus_hdl) { - pr_err("data_bus_client register failed\n"); - rc = -EINVAL; - goto end; - } - pr_debug("register %s data_bus_hdl=%x\n", name, pdbus->data_bus_hdl); end: - return rc; + if (of_find_property(pdev->dev.of_node, + "qcom,msm-bus,active-only", NULL)) { + pdbus->bus_active_only = true; + for (i = 0; i < pdbus->data_paths_cnt; i++) { + icc_set_tag(pdbus->data_bus_hdl[i], + QCOM_ICC_TAG_ACTIVE_ONLY); + } + } + + pr_debug("register %s data_bus success, path number=%d\n", + name, pdbus->data_paths_cnt); + + return 0; } static int sde_power_reg_bus_parse(struct platform_device *pdev, struct sde_power_handle *phandle) { - struct device_node *node; - struct msm_bus_scale_pdata *bus_scale_table; int rc = 0; - node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-reg-bus"); - if (node) { - bus_scale_table = msm_bus_pdata_from_node(pdev, node); - if (IS_ERR_OR_NULL(bus_scale_table)) { - pr_err("reg bus handle parsing failed\n"); - rc = PTR_ERR(bus_scale_table); - if (!bus_scale_table) - rc = -EINVAL; - goto end; - } - phandle->reg_bus_hdl = msm_bus_scale_register_client( - bus_scale_table); - if (!phandle->reg_bus_hdl) { - pr_err("reg_bus_client register failed\n"); - rc = -EINVAL; - goto end; - } - pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl); + phandle->reg_bus_hdl = of_icc_get(&pdev->dev, "qcom,sde-reg-bus"); + if (IS_ERR_OR_NULL(phandle->reg_bus_hdl)) { + pr_err("reg bus handle parsing failed\n"); + phandle->reg_bus_hdl = NULL; + rc = -EINVAL; + } else { + pr_debug("reg_bus_hdl parsing success\n"); } -end: return rc; } -static void sde_power_reg_bus_unregister(u32 reg_bus_hdl) +static void sde_power_reg_bus_unregister(struct icc_path *reg_bus_hdl) { if (reg_bus_hdl) - msm_bus_scale_unregister_client(reg_bus_hdl); + icc_put(reg_bus_hdl); } -static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) +static int sde_power_reg_bus_update(struct icc_path *reg_bus_hdl, + u32 usecase_ndx) { int rc = 0; if (reg_bus_hdl) { SDE_ATRACE_BEGIN("msm_bus_scale_req"); - rc = msm_bus_scale_client_update_request(reg_bus_hdl, - usecase_ndx); + rc = icc_set_bw(reg_bus_hdl, + sde_reg_bus_table[usecase_ndx].ab, + sde_reg_bus_table[usecase_ndx].ib); SDE_ATRACE_END("msm_bus_scale_req"); } @@ -466,52 +453,6 @@ static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) return rc; } -#else -static int _sde_power_data_bus_set_quota( - struct sde_power_data_bus_handle *pdbus, - u64 in_ab_quota, u64 in_ib_quota) -{ - return 0; -} - -static int sde_power_data_bus_parse(struct platform_device *pdev, - struct sde_power_data_bus_handle *pdbus, const char *name) -{ - return 0; -} - -static void sde_power_data_bus_unregister( - struct sde_power_data_bus_handle *pdbus) -{ -} - -int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, - u32 bus_id, u64 ab_quota, u64 ib_quota) -{ - return 0; -} - -static int sde_power_reg_bus_parse(struct platform_device *pdev, - struct sde_power_handle *phandle) -{ - return 0; -} - -static void sde_power_reg_bus_unregister(u32 reg_bus_hdl) -{ -} - -static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) -{ - return 0; -} - -int sde_power_data_bus_state_update(struct sde_power_handle *phandle, - bool enable) -{ - return 0; -} -#endif int sde_power_resource_init(struct platform_device *pdev, struct sde_power_handle *phandle) @@ -675,6 +616,13 @@ int sde_power_scale_reg_bus(struct sde_power_handle *phandle, usecase_ndx); if (rc) pr_err("failed to set reg bus vote rc=%d\n", rc); + else { + phandle->reg_bus_curr_val.ab = + sde_reg_bus_table[usecase_ndx].ab; + phandle->reg_bus_curr_val.ib = + sde_reg_bus_table[usecase_ndx].ib; + phandle->current_usecase_ndx = usecase_ndx; + } if (!skip_lock) mutex_unlock(&phandle->phandle_lock); @@ -723,7 +671,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable) SDE_POWER_EVENT_PRE_ENABLE); for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX && - phandle->data_bus_handle[i].data_bus_hdl; i++) { + phandle->data_bus_handle[i].data_paths_cnt > 0; i++) { rc = _sde_power_data_bus_set_quota( &phandle->data_bus_handle[i], SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, @@ -777,7 +725,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable) msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); for (i = SDE_POWER_HANDLE_DBUS_ID_MAX - 1; i >= 0; i--) - if (phandle->data_bus_handle[i].data_bus_hdl) + if (phandle->data_bus_handle[i].data_paths_cnt > 0) _sde_power_data_bus_set_quota( &phandle->data_bus_handle[i], SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA, @@ -799,7 +747,7 @@ rsc_err: reg_bus_hdl_err: msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0); vreg_err: - for (i-- ; i >= 0 && phandle->data_bus_handle[i].data_bus_hdl; i--) + for (i-- ; i >= 0 && phandle->data_bus_handle[i].data_paths_cnt > 0; i--) _sde_power_data_bus_set_quota( &phandle->data_bus_handle[i], SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA, diff --git a/msm/sde_power_handle.h b/msm/sde_power_handle.h index 2587c3734f..d45189d5dd 100644 --- a/msm/sde_power_handle.h +++ b/msm/sde_power_handle.h @@ -18,6 +18,7 @@ #define SDE_POWER_HANDLE_CONT_SPLASH_BUS_AB_QUOTA 3000000000ULL #include +#include #include /* event will be triggered before power handler disable */ @@ -31,6 +32,23 @@ /* event will be triggered after power handler enable */ #define SDE_POWER_EVENT_POST_ENABLE 0x8 +#define DATA_BUS_PATH_MAX 0x2 + +/* + * The AMC bucket denotes constraints that are applied to hardware when + * icc_set_bw() completes, whereas the WAKE and SLEEP constraints are applied + * when the execution environment transitions between active and low power mode. + */ +#define QCOM_ICC_BUCKET_AMC 0 +#define QCOM_ICC_BUCKET_WAKE 1 +#define QCOM_ICC_BUCKET_SLEEP 2 +#define QCOM_ICC_NUM_BUCKETS 3 +#define QCOM_ICC_TAG_AMC BIT(QCOM_ICC_BUCKET_AMC) +#define QCOM_ICC_TAG_WAKE BIT(QCOM_ICC_BUCKET_WAKE) +#define QCOM_ICC_TAG_SLEEP BIT(QCOM_ICC_BUCKET_SLEEP) +#define QCOM_ICC_TAG_ACTIVE_ONLY (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE) +#define QCOM_ICC_TAG_ALWAYS (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE |\ + QCOM_ICC_TAG_SLEEP) /** * mdss_bus_vote_type: register bus vote type @@ -73,30 +91,27 @@ enum SDE_POWER_HANDLE_DBUS_ID { SDE_POWER_HANDLE_DBUS_ID_MAX, }; +/** + * struct sde_power_bus_scaling_data: struct for bus setting + * @ab: average bandwidth in kilobytes per second + * @ib: peak bandwidth in kilobytes per second + */ +struct sde_power_bus_scaling_data { + uint64_t ab; /* Arbitrated bandwidth */ + uint64_t ib; /* Instantaneous bandwidth */ +}; + /** * struct sde_power_data_handle: power handle struct for data bus - * @data_bus_scale_table: pointer to bus scaling table * @data_bus_hdl: current data bus handle + * @curr_val : save the current bus value * @data_paths_cnt: number of rt data path ports - * @curr_bw_uc_idx: current use case index of data bus - * @ao_bw_uc_idx: active only use case index of data bus - * @ab_rt: realtime ab quota - * @ib_rt: realtime ib quota - * @ab_nrt: non-realtime ab quota - * @ib_nrt: non-realtime ib quota - * @enable: true if bus is enabled */ struct sde_power_data_bus_handle { - struct msm_bus_scale_pdata *data_bus_scale_table; - u32 data_bus_hdl; + struct icc_path *data_bus_hdl[DATA_BUS_PATH_MAX]; + struct sde_power_bus_scaling_data curr_val; u32 data_paths_cnt; - u32 curr_bw_uc_idx; - u32 ao_bw_uc_idx; - u64 ab_rt; - u64 ib_rt; - u64 ab_nrt; - u64 ib_nrt; - bool enable; + bool bus_active_only; }; /* @@ -124,6 +139,7 @@ struct sde_power_event { * @dev: pointer to device structure * @usecase_ndx: current usecase index * @reg_bus_hdl: current register bus handle + * @reg_bus_curr_val: save currecnt reg bus value * @data_bus_handle: context structure for data bus control * @event_list: current power handle event list * @rsc_client: sde rsc client pointer @@ -135,7 +151,8 @@ struct sde_power_handle { struct mutex phandle_lock; struct device *dev; u32 current_usecase_ndx; - u32 reg_bus_hdl; + struct icc_path *reg_bus_hdl; + struct sde_power_bus_scaling_data reg_bus_curr_val; struct sde_power_data_bus_handle data_bus_handle [SDE_POWER_HANDLE_DBUS_ID_MAX]; struct list_head event_list; diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index d361bcade0..7cc120a17e 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -64,6 +63,21 @@ static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT]; static struct device *rpmh_dev[MAX_RSC_COUNT]; +static void sde_rsc_set_data_bus_mode(struct sde_power_handle *phandle, u32 tag) +{ + int i = 0, j = 0; + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + if (!phandle->data_bus_handle[i].bus_active_only) + continue; + + for (j = 0; j < phandle->data_bus_handle[i].data_paths_cnt; j++) + icc_set_tag(phandle->data_bus_handle[i].data_bus_hdl[j], + tag); + + } +} + /** * sde_rsc_client_create() - create the client for sde rsc. * Different displays like DSI, HDMI, DP, WB, etc should call this @@ -523,8 +537,11 @@ static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc, if (rsc->hw_ops.state_update) { rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE); - if (!rc) + if (!rc) { rpmh_mode_solver_set(rsc->rpmh_dev, true); + sde_rsc_set_data_bus_mode(&rsc->phandle, + QCOM_ICC_TAG_WAKE); + } } vsync_wait: @@ -574,8 +591,11 @@ static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc, if (rsc->hw_ops.state_update) { rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE); - if (!rc) + if (!rc) { rpmh_mode_solver_set(rsc->rpmh_dev, false); + sde_rsc_set_data_bus_mode(&rsc->phandle, + QCOM_ICC_TAG_AMC); + } } /* indicate wait for vsync for cmd/vid to clk state switch */ @@ -661,9 +681,13 @@ static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc, if (rsc->hw_ops.state_update) { rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE); - if (!rc) + if (!rc) { rpmh_mode_solver_set(rsc->rpmh_dev, rsc->version == SDE_RSC_REV_3 ? true : false); + sde_rsc_set_data_bus_mode(&rsc->phandle, + rsc->version == SDE_RSC_REV_3 ? + QCOM_ICC_TAG_WAKE : QCOM_ICC_TAG_AMC); + } } vsync_wait: @@ -737,8 +761,11 @@ static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc, rc = CLK_MODE_SWITCH_SUCCESS; } else if (rsc->hw_ops.state_update) { rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE); - if (!rc) + if (!rc) { rpmh_mode_solver_set(rsc->rpmh_dev, true); + sde_rsc_set_data_bus_mode(&rsc->phandle, + QCOM_ICC_TAG_WAKE); + } } return rc;