diff options
Diffstat (limited to 'drivers/interconnect/qcom/icc-rpm.c')
-rw-r--r-- | drivers/interconnect/qcom/icc-rpm.c | 112 |
1 files changed, 59 insertions, 53 deletions
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 5341fa169dbf..6acc7686ed38 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -50,7 +50,7 @@ #define NOC_QOS_MODE_FIXED_VAL 0x0 #define NOC_QOS_MODE_BYPASS_VAL 0x2 -static int qcom_icc_set_qnoc_qos(struct icc_node *src, u64 max_bw) +static int qcom_icc_set_qnoc_qos(struct icc_node *src) { struct icc_provider *provider = src->provider; struct qcom_icc_provider *qp = to_qcom_provider(provider); @@ -95,7 +95,7 @@ static int qcom_icc_bimc_set_qos_health(struct qcom_icc_provider *qp, mask, val); } -static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw) +static int qcom_icc_set_bimc_qos(struct icc_node *src) { struct qcom_icc_provider *qp; struct qcom_icc_node *qn; @@ -150,7 +150,7 @@ static int qcom_icc_noc_set_qos_priority(struct qcom_icc_provider *qp, NOC_QOS_PRIORITY_P0_MASK, qos->prio_level); } -static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw) +static int qcom_icc_set_noc_qos(struct icc_node *src) { struct qcom_icc_provider *qp; struct qcom_icc_node *qn; @@ -187,7 +187,7 @@ static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw) NOC_QOS_MODEn_MASK, mode); } -static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw) +static int qcom_icc_qos_set(struct icc_node *node) { struct qcom_icc_provider *qp = to_qcom_provider(node->provider); struct qcom_icc_node *qn = node->data; @@ -196,38 +196,41 @@ static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw) switch (qp->type) { case QCOM_ICC_BIMC: - return qcom_icc_set_bimc_qos(node, sum_bw); + return qcom_icc_set_bimc_qos(node); case QCOM_ICC_QNOC: - return qcom_icc_set_qnoc_qos(node, sum_bw); + return qcom_icc_set_qnoc_qos(node); default: - return qcom_icc_set_noc_qos(node, sum_bw); + return qcom_icc_set_noc_qos(node); } } -static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw) +static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 sum_bw) { int ret = 0; - if (mas_rpm_id != -1) { + if (qn->qos.ap_owned) + return 0; + + if (qn->mas_rpm_id != -1) { ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, RPM_BUS_MASTER_REQ, - mas_rpm_id, + qn->mas_rpm_id, sum_bw); if (ret) { pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", - mas_rpm_id, ret); + qn->mas_rpm_id, ret); return ret; } } - if (slv_rpm_id != -1) { + if (qn->slv_rpm_id != -1) { ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, RPM_BUS_SLAVE_REQ, - slv_rpm_id, + qn->slv_rpm_id, sum_bw); if (ret) { pr_err("qcom_icc_rpm_smd_send slv %d error %d\n", - slv_rpm_id, ret); + qn->slv_rpm_id, ret); return ret; } } @@ -235,26 +238,6 @@ static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw) return ret; } -static int __qcom_icc_set(struct icc_node *n, struct qcom_icc_node *qn, - u64 sum_bw) -{ - int ret; - - if (!qn->qos.ap_owned) { - /* send bandwidth request message to the RPM processor */ - ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw); - if (ret) - return ret; - } else if (qn->qos.qos_mode != NOC_QOS_MODE_INVALID) { - /* set bandwidth directly from the AP */ - ret = qcom_icc_qos_set(n, sum_bw); - if (ret) - return ret; - } - - return 0; -} - /** * qcom_icc_pre_bw_aggregate - cleans up values before re-aggregate requests * @node: icc node to operate on @@ -370,16 +353,17 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) sum_bw = icc_units_to_bps(max_agg_avg); - ret = __qcom_icc_set(src, src_qn, sum_bw); + ret = qcom_icc_rpm_set(src_qn, sum_bw); if (ret) return ret; + if (dst_qn) { - ret = __qcom_icc_set(dst, dst_qn, sum_bw); + ret = qcom_icc_rpm_set(dst_qn, sum_bw); if (ret) return ret; } - for (i = 0; i < qp->num_clks; i++) { + for (i = 0; i < qp->num_bus_clks; i++) { /* * Use WAKE bucket for active clock, otherwise, use SLEEP bucket * for other clocks. If a platform doesn't set interconnect @@ -425,7 +409,7 @@ int qnoc_probe(struct platform_device *pdev) struct qcom_icc_provider *qp; struct icc_node *node; size_t num_nodes, i; - const char * const *cds; + const char * const *cds = NULL; int cd_num; int ret; @@ -440,21 +424,20 @@ int qnoc_probe(struct platform_device *pdev) qnodes = desc->nodes; num_nodes = desc->num_nodes; - if (desc->num_clocks) { - cds = desc->clocks; - cd_num = desc->num_clocks; + if (desc->num_intf_clocks) { + cds = desc->intf_clocks; + cd_num = desc->num_intf_clocks; } else { - cds = bus_clocks; - cd_num = ARRAY_SIZE(bus_clocks); + /* 0 intf clocks is perfectly fine */ + cd_num = 0; } - qp = devm_kzalloc(dev, struct_size(qp, bus_clks, cd_num), GFP_KERNEL); + qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); if (!qp) return -ENOMEM; - qp->bus_clk_rate = devm_kcalloc(dev, cd_num, sizeof(*qp->bus_clk_rate), - GFP_KERNEL); - if (!qp->bus_clk_rate) + qp->intf_clks = devm_kcalloc(dev, cd_num, sizeof(*qp->intf_clks), GFP_KERNEL); + if (!qp->intf_clks) return -ENOMEM; data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), @@ -462,9 +445,13 @@ int qnoc_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + qp->num_intf_clks = cd_num; for (i = 0; i < cd_num; i++) - qp->bus_clks[i].id = cds[i]; - qp->num_clks = cd_num; + qp->intf_clks[i].id = cds[i]; + + qp->num_bus_clks = desc->no_clk_scaling ? 0 : NUM_BUS_CLKS; + for (i = 0; i < qp->num_bus_clks; i++) + qp->bus_clks[i].id = bus_clocks[i]; qp->type = desc->type; qp->qos_offset = desc->qos_offset; @@ -494,11 +481,15 @@ int qnoc_probe(struct platform_device *pdev) } regmap_done: - ret = devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks); + ret = devm_clk_bulk_get(dev, qp->num_bus_clks, qp->bus_clks); + if (ret) + return ret; + + ret = clk_bulk_prepare_enable(qp->num_bus_clks, qp->bus_clks); if (ret) return ret; - ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks); + ret = devm_clk_bulk_get(dev, qp->num_intf_clks, qp->intf_clks); if (ret) return ret; @@ -512,6 +503,11 @@ regmap_done: icc_provider_init(provider); + /* If this fails, bus accesses will crash the platform! */ + ret = clk_bulk_prepare_enable(qp->num_intf_clks, qp->intf_clks); + if (ret) + return ret; + for (i = 0; i < num_nodes; i++) { size_t j; @@ -528,10 +524,20 @@ regmap_done: for (j = 0; j < qnodes[i]->num_links; j++) icc_link_create(node, qnodes[i]->links[j]); + /* Set QoS registers (we only need to do it once, generally) */ + if (qnodes[i]->qos.ap_owned && + qnodes[i]->qos.qos_mode != NOC_QOS_MODE_INVALID) { + ret = qcom_icc_qos_set(node); + if (ret) + return ret; + } + data->nodes[i] = node; } data->num_nodes = num_nodes; + clk_bulk_disable_unprepare(qp->num_intf_clks, qp->intf_clks); + ret = icc_provider_register(provider); if (ret) goto err_remove_nodes; @@ -551,7 +557,7 @@ err_deregister_provider: icc_provider_deregister(provider); err_remove_nodes: icc_nodes_remove(provider); - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks); return ret; } @@ -563,7 +569,7 @@ int qnoc_remove(struct platform_device *pdev) icc_provider_deregister(&qp->provider); icc_nodes_remove(&qp->provider); - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks); return 0; } |