Loading drivers/interconnect/qcom/icc-rpm.c +20 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #include <linux/soc/qcom/smd-rpm.h> #include "icc-rpm.h" #include "qnoc-qos.h" static int qcom_icc_rpm_smd_send_msg(int ctx, int rsc_type, int rpm_id, u64 val) { Loading Loading @@ -77,6 +78,9 @@ int qcom_icc_rpm_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, } } *agg_avg += avg_bw; *agg_peak = max_t(u32, *agg_peak, peak_bw); qn->dirty = true; return 0; Loading Loading @@ -209,6 +213,22 @@ int qcom_icc_rpm_set(struct icc_node *src, struct icc_node *dst) } } qn = node->data; /* Defer setting QoS until the first non-zero bandwidth request. */ if (qn && qn->qosbox && !qn->qosbox->initialized && (node->avg_bw || node->peak_bw)) { ret = clk_bulk_prepare_enable(qp->num_qos_clks, qp->qos_clks); if (ret) { pr_err("%s: Clock enable failed for node %s\n", __func__, node->name); return ret; } qn->noc_ops->set_qos(qn); clk_bulk_disable_unprepare(qp->num_qos_clks, qp->qos_clks); qn->qosbox->initialized = true; } return 0; } EXPORT_SYMBOL_GPL(qcom_icc_rpm_set); Loading drivers/interconnect/qcom/icc-rpm.h +4 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ enum qcom_icc_rpm_context { * struct qcom_icc_provider - QTI specific interconnect provider * @provider: generic interconnect provider * @dev: reference to the NoC device * @qos_clks: the clk_bulk_data table of QoS clocks * @num_qos_clks: the total number of clk_bulk_data entries * @bus_clks: the clk_bulk_data table of bus clocks * @num_clks: the total number of clk_bulk_data entries * @bus_clk_cur_rate: current frequency of bus clock Loading @@ -57,6 +59,8 @@ struct qcom_icc_provider { struct device *dev; struct regmap *regmap; struct list_head probe_list; struct clk_bulk_data *qos_clks; int num_qos_clks; struct clk_bulk_data *bus_clks; int num_clks; u32 util_factor; Loading drivers/interconnect/qcom/qnoc-qos.c +76 −3 Original line number Diff line number Diff line Loading @@ -8,7 +8,11 @@ #include <linux/interconnect-provider.h> #include <linux/module.h> #ifdef CONFIG_INTERCONNECT_QCOM_RPMH #include "icc-rpmh.h" #else #include "icc-rpm.h" #endif #include "qnoc-qos.h" #define QOSGEN_MAINCTL_LO(p, qp) ((p)->offsets[qp] + \ Loading @@ -17,6 +21,23 @@ # define QOS_DFLT_PRIO_MASK 0x7 # define QOS_DFLT_PRIO_SHFT 4 #ifndef CONFIG_INTERCONNECT_QCOM_RPMH #define QOSGEN_M_BKE_HEALTH(p, qp, n) ((p)->offsets[qp] + ((n) * 4) + \ (p)->regs[QOSGEN_OFF_MPORT_BKE_HEALTH]) #define QOS_PRIOLVL_MASK 0x7 #define QOS_PRIOLVL_SHFT 0x0 #define QOS_AREQPRIO_MASK 0x70 #define QOS_AREQPRIO_SHFT 0x8 #define QOSGEN_M_BKE_EN(p, qp) ((p)->offsets[qp] + \ (p)->regs[QOSGEN_OFF_MPORT_BKE_EN]) #define QOS_BKE_EN_MASK 0x1 #define QOS_BKE_EN_SHFT 0x0 #define NUM_BKE_HEALTH_LEVELS 4 #endif const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = { [ICC_QNOC_QOSGEN_TYPE_RPMH] = { [QOSGEN_OFF_MAINCTL_LO] = 0x8, Loading @@ -29,6 +50,15 @@ const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = { }; EXPORT_SYMBOL(icc_qnoc_qos_regs); #ifndef CONFIG_INTERCONNECT_QCOM_RPMH const u8 icc_bimc_qos_regs[][QOSGEN_OFF_MAX_REGS] = { [ICC_QNOC_QOSGEN_TYPE_RPMH] = { [QOSGEN_OFF_MPORT_BKE_EN] = 0x0, [QOSGEN_OFF_MPORT_BKE_HEALTH] = 0x40, }, }; EXPORT_SYMBOL(icc_bimc_qos_regs); #endif /** * qcom_icc_set_qos - initialize static QoS configurations * @node: qcom icc node to operate on Loading @@ -49,11 +79,16 @@ static void qcom_icc_set_qos(struct qcom_icc_node *node) QOS_DFLT_PRIO_MASK << QOS_DFLT_PRIO_SHFT, qos->config->prio << QOS_DFLT_PRIO_SHFT); if (qos->config->urg_fwd) regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port), QOS_SLV_URG_MSG_EN, QOS_SLV_URG_MSG_EN); else regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port), QOS_SLV_URG_MSG_EN, 0x0); } } Loading @@ -62,4 +97,42 @@ const struct qcom_icc_noc_ops qcom_qnoc4_ops = { }; EXPORT_SYMBOL(qcom_qnoc4_ops); #ifndef CONFIG_INTERCONNECT_QCOM_RPMH /** * qcom_icc_set_bimc_qos - initialize static QoS configurations * @node: qcom icc node to operate on */ static void qcom_icc_set_bimc_qos(struct qcom_icc_node *node) { struct qcom_icc_qosbox *qos = node->qosbox; int port, i; if (!node->regmap) return; if (!qos) return; for (port = 0; port < qos->num_ports; port++) { for (i = 0; i < NUM_BKE_HEALTH_LEVELS; i++) { regmap_update_bits(node->regmap, QOSGEN_M_BKE_HEALTH(qos, port, i), ((qos->config->prio << QOS_PRIOLVL_SHFT) | (qos->config->prio << QOS_AREQPRIO_SHFT)), (QOS_PRIOLVL_MASK | QOS_AREQPRIO_MASK)); }; regmap_update_bits(node->regmap, QOSGEN_M_BKE_EN(qos, port), qos->config->bke_enable << QOS_BKE_EN_SHFT, QOS_BKE_EN_MASK); }; } const struct qcom_icc_noc_ops qcom_bimc_ops = { .set_qos = qcom_icc_set_bimc_qos, }; EXPORT_SYMBOL(qcom_bimc_ops); #endif MODULE_LICENSE("GPL v2"); drivers/interconnect/qcom/qnoc-qos.h +14 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,14 @@ enum { QOSGEN_OFF_REGUL0BW_LO, }; #ifndef CONFIG_INTERCONNECT_QCOM_RPMH enum { QOSGEN_OFF_MPORT_BKE_HEALTH, QOSGEN_OFF_MPORT_BKE_EN, }; extern const u8 icc_bimc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS]; #endif extern const u8 icc_qnoc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS]; struct qcom_icc_noc_ops { Loading @@ -32,6 +40,9 @@ struct qcom_icc_noc_ops { struct qos_config { u32 prio; u32 urg_fwd; #ifndef CONFIG_INTERCONNECT_QCOM_RPMH u32 bke_enable; #endif }; struct qcom_icc_qosbox { Loading @@ -55,5 +66,8 @@ struct qcom_icc_qosbox { } \ extern const struct qcom_icc_noc_ops qcom_qnoc4_ops; #ifndef CONFIG_INTERCONNECT_QCOM_RPMH extern const struct qcom_icc_noc_ops qcom_bimc_ops; #endif #endif Loading
drivers/interconnect/qcom/icc-rpm.c +20 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #include <linux/soc/qcom/smd-rpm.h> #include "icc-rpm.h" #include "qnoc-qos.h" static int qcom_icc_rpm_smd_send_msg(int ctx, int rsc_type, int rpm_id, u64 val) { Loading Loading @@ -77,6 +78,9 @@ int qcom_icc_rpm_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, } } *agg_avg += avg_bw; *agg_peak = max_t(u32, *agg_peak, peak_bw); qn->dirty = true; return 0; Loading Loading @@ -209,6 +213,22 @@ int qcom_icc_rpm_set(struct icc_node *src, struct icc_node *dst) } } qn = node->data; /* Defer setting QoS until the first non-zero bandwidth request. */ if (qn && qn->qosbox && !qn->qosbox->initialized && (node->avg_bw || node->peak_bw)) { ret = clk_bulk_prepare_enable(qp->num_qos_clks, qp->qos_clks); if (ret) { pr_err("%s: Clock enable failed for node %s\n", __func__, node->name); return ret; } qn->noc_ops->set_qos(qn); clk_bulk_disable_unprepare(qp->num_qos_clks, qp->qos_clks); qn->qosbox->initialized = true; } return 0; } EXPORT_SYMBOL_GPL(qcom_icc_rpm_set); Loading
drivers/interconnect/qcom/icc-rpm.h +4 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ enum qcom_icc_rpm_context { * struct qcom_icc_provider - QTI specific interconnect provider * @provider: generic interconnect provider * @dev: reference to the NoC device * @qos_clks: the clk_bulk_data table of QoS clocks * @num_qos_clks: the total number of clk_bulk_data entries * @bus_clks: the clk_bulk_data table of bus clocks * @num_clks: the total number of clk_bulk_data entries * @bus_clk_cur_rate: current frequency of bus clock Loading @@ -57,6 +59,8 @@ struct qcom_icc_provider { struct device *dev; struct regmap *regmap; struct list_head probe_list; struct clk_bulk_data *qos_clks; int num_qos_clks; struct clk_bulk_data *bus_clks; int num_clks; u32 util_factor; Loading
drivers/interconnect/qcom/qnoc-qos.c +76 −3 Original line number Diff line number Diff line Loading @@ -8,7 +8,11 @@ #include <linux/interconnect-provider.h> #include <linux/module.h> #ifdef CONFIG_INTERCONNECT_QCOM_RPMH #include "icc-rpmh.h" #else #include "icc-rpm.h" #endif #include "qnoc-qos.h" #define QOSGEN_MAINCTL_LO(p, qp) ((p)->offsets[qp] + \ Loading @@ -17,6 +21,23 @@ # define QOS_DFLT_PRIO_MASK 0x7 # define QOS_DFLT_PRIO_SHFT 4 #ifndef CONFIG_INTERCONNECT_QCOM_RPMH #define QOSGEN_M_BKE_HEALTH(p, qp, n) ((p)->offsets[qp] + ((n) * 4) + \ (p)->regs[QOSGEN_OFF_MPORT_BKE_HEALTH]) #define QOS_PRIOLVL_MASK 0x7 #define QOS_PRIOLVL_SHFT 0x0 #define QOS_AREQPRIO_MASK 0x70 #define QOS_AREQPRIO_SHFT 0x8 #define QOSGEN_M_BKE_EN(p, qp) ((p)->offsets[qp] + \ (p)->regs[QOSGEN_OFF_MPORT_BKE_EN]) #define QOS_BKE_EN_MASK 0x1 #define QOS_BKE_EN_SHFT 0x0 #define NUM_BKE_HEALTH_LEVELS 4 #endif const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = { [ICC_QNOC_QOSGEN_TYPE_RPMH] = { [QOSGEN_OFF_MAINCTL_LO] = 0x8, Loading @@ -29,6 +50,15 @@ const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = { }; EXPORT_SYMBOL(icc_qnoc_qos_regs); #ifndef CONFIG_INTERCONNECT_QCOM_RPMH const u8 icc_bimc_qos_regs[][QOSGEN_OFF_MAX_REGS] = { [ICC_QNOC_QOSGEN_TYPE_RPMH] = { [QOSGEN_OFF_MPORT_BKE_EN] = 0x0, [QOSGEN_OFF_MPORT_BKE_HEALTH] = 0x40, }, }; EXPORT_SYMBOL(icc_bimc_qos_regs); #endif /** * qcom_icc_set_qos - initialize static QoS configurations * @node: qcom icc node to operate on Loading @@ -49,11 +79,16 @@ static void qcom_icc_set_qos(struct qcom_icc_node *node) QOS_DFLT_PRIO_MASK << QOS_DFLT_PRIO_SHFT, qos->config->prio << QOS_DFLT_PRIO_SHFT); if (qos->config->urg_fwd) regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port), QOS_SLV_URG_MSG_EN, QOS_SLV_URG_MSG_EN); else regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port), QOS_SLV_URG_MSG_EN, 0x0); } } Loading @@ -62,4 +97,42 @@ const struct qcom_icc_noc_ops qcom_qnoc4_ops = { }; EXPORT_SYMBOL(qcom_qnoc4_ops); #ifndef CONFIG_INTERCONNECT_QCOM_RPMH /** * qcom_icc_set_bimc_qos - initialize static QoS configurations * @node: qcom icc node to operate on */ static void qcom_icc_set_bimc_qos(struct qcom_icc_node *node) { struct qcom_icc_qosbox *qos = node->qosbox; int port, i; if (!node->regmap) return; if (!qos) return; for (port = 0; port < qos->num_ports; port++) { for (i = 0; i < NUM_BKE_HEALTH_LEVELS; i++) { regmap_update_bits(node->regmap, QOSGEN_M_BKE_HEALTH(qos, port, i), ((qos->config->prio << QOS_PRIOLVL_SHFT) | (qos->config->prio << QOS_AREQPRIO_SHFT)), (QOS_PRIOLVL_MASK | QOS_AREQPRIO_MASK)); }; regmap_update_bits(node->regmap, QOSGEN_M_BKE_EN(qos, port), qos->config->bke_enable << QOS_BKE_EN_SHFT, QOS_BKE_EN_MASK); }; } const struct qcom_icc_noc_ops qcom_bimc_ops = { .set_qos = qcom_icc_set_bimc_qos, }; EXPORT_SYMBOL(qcom_bimc_ops); #endif MODULE_LICENSE("GPL v2");
drivers/interconnect/qcom/qnoc-qos.h +14 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,14 @@ enum { QOSGEN_OFF_REGUL0BW_LO, }; #ifndef CONFIG_INTERCONNECT_QCOM_RPMH enum { QOSGEN_OFF_MPORT_BKE_HEALTH, QOSGEN_OFF_MPORT_BKE_EN, }; extern const u8 icc_bimc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS]; #endif extern const u8 icc_qnoc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS]; struct qcom_icc_noc_ops { Loading @@ -32,6 +40,9 @@ struct qcom_icc_noc_ops { struct qos_config { u32 prio; u32 urg_fwd; #ifndef CONFIG_INTERCONNECT_QCOM_RPMH u32 bke_enable; #endif }; struct qcom_icc_qosbox { Loading @@ -55,5 +66,8 @@ struct qcom_icc_qosbox { } \ extern const struct qcom_icc_noc_ops qcom_qnoc4_ops; #ifndef CONFIG_INTERCONNECT_QCOM_RPMH extern const struct qcom_icc_noc_ops qcom_bimc_ops; #endif #endif