@@ -50,6 +50,8 @@
#define NOC_QOS_MODE_FIXED_VAL 0x0
#define NOC_QOS_MODE_BYPASS_VAL 0x2
+#define ICC_BUS_CLK_MIN_RATE 19200000ULL
+
static int qcom_icc_set_qnoc_qos(struct icc_node *src)
{
struct icc_provider *provider = src->provider;
@@ -380,6 +382,13 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
do_div(rate, src_qn->buswidth);
rate = min_t(u64, rate, LONG_MAX);
+ /*
+ * Downstream checks whether the requested rate is zero, but it makes little sense
+ * to vote for a value that's below the lower threshold, so let's not do so.
+ */
+ if (bucket == QCOM_ICC_BUCKET_WAKE && qp->keep_alive)
+ rate = max(ICC_BUS_CLK_MIN_RATE, rate);
+
if (qp->bus_clk_rate[i] == rate)
continue;
@@ -453,6 +462,7 @@ int qnoc_probe(struct platform_device *pdev)
for (i = 0; i < qp->num_bus_clks; i++)
qp->bus_clks[i].id = bus_clocks[i];
+ qp->keep_alive = desc->keep_alive;
qp->type = desc->type;
qp->qos_offset = desc->qos_offset;
@@ -33,6 +33,7 @@ enum qcom_icc_type {
* @bus_clk_rate: bus clock rate in Hz
* @bus_clks: the clk_bulk_data table of bus clocks
* @intf_clks: a clk_bulk_data array of interface clocks
+ * @keep_alive: whether to always keep a minimum vote on the bus clocks
* @is_on: whether the bus is powered on
*/
struct qcom_icc_provider {
@@ -45,6 +46,7 @@ struct qcom_icc_provider {
u64 bus_clk_rate[NUM_BUS_CLKS];
struct clk_bulk_data bus_clks[NUM_BUS_CLKS];
struct clk_bulk_data *intf_clks;
+ bool keep_alive;
bool is_on;
};
@@ -102,6 +104,7 @@ struct qcom_icc_desc {
const char * const *bus_clocks;
const char * const *intf_clocks;
size_t num_intf_clocks;
+ bool keep_alive;
bool no_clk_scaling;
enum qcom_icc_type type;
const struct regmap_config *regmap_cfg;