mirror of
https://github.com/torvalds/linux.git
synced 2026-08-01 03:59:40 +02:00
clk: qcom: Calculate branch/RCG timeouts based on frequency
Clocks with extremely low rates (i.e. 10s of Hz) take much longer to enable, disable, or change rates than our current timeouts allow. Instead of increasing the timeouts to huge values for all clocks, dynamically compute the required timeouts based on the configured clock rates. Change-Id: I122ace891c2246763f9fe6da8df2c4a4307ba42d Signed-off-by: Mike Tipton <quic_mdtipton@quicinc.com>
This commit is contained in:
parent
6f6c0c5b1b
commit
aa899c2d1f
|
|
@ -73,9 +73,25 @@ static bool clk_branch2_check_halt(const struct clk_branch *br, bool enabling)
|
|||
}
|
||||
}
|
||||
|
||||
static int get_branch_timeout(const struct clk_branch *br)
|
||||
{
|
||||
int rate, period_us, timeout;
|
||||
|
||||
/*
|
||||
* The time it takes a clock branch to toggle is roughly 3 clock cycles.
|
||||
*/
|
||||
rate = clk_hw_get_rate(&br->clkr.hw);
|
||||
period_us = 1000000 / rate;
|
||||
timeout = 3 * period_us;
|
||||
|
||||
return max(timeout, 200);
|
||||
}
|
||||
|
||||
static int clk_branch_wait(const struct clk_branch *br, bool enabling,
|
||||
bool (check_halt)(const struct clk_branch *, bool))
|
||||
{
|
||||
int timeout, count;
|
||||
|
||||
bool voted = br->halt_check & BRANCH_VOTED;
|
||||
/*
|
||||
* Skip checking halt bit if we're explicitly ignoring the bit or the
|
||||
|
|
@ -89,15 +105,15 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
|
|||
} else if (br->halt_check == BRANCH_HALT_ENABLE ||
|
||||
br->halt_check == BRANCH_HALT ||
|
||||
(enabling && voted)) {
|
||||
int count = 200;
|
||||
timeout = get_branch_timeout(br);
|
||||
|
||||
while (count-- > 0) {
|
||||
for (count = timeout; count > 0; count--) {
|
||||
if (check_halt(br, enabling))
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
WARN_CLK((struct clk_hw *)&br->clkr.hw, 1, "status stuck at 'o%s'",
|
||||
enabling ? "ff" : "n");
|
||||
WARN_CLK((struct clk_hw *)&br->clkr.hw, 1, "status stuck at 'o%s' after %d us",
|
||||
enabling ? "ff" : "n", timeout);
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ struct clk_rcg2 {
|
|||
u8 safe_src_index;
|
||||
const struct parent_map *parent_map;
|
||||
const struct freq_tbl *freq_tbl;
|
||||
unsigned long configured_freq;
|
||||
unsigned long current_freq;
|
||||
bool enable_safe_config;
|
||||
struct clk_regmap clkr;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013, 2016-2018, 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -118,9 +119,25 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw)
|
|||
return __clk_rcg2_get_parent(hw, cfg);
|
||||
}
|
||||
|
||||
static int get_update_timeout(const struct clk_rcg2 *rcg)
|
||||
{
|
||||
int timeout = 0;
|
||||
|
||||
/*
|
||||
* The time it takes an RCG to update is roughly 3 clock cycles of the
|
||||
* old and new clock rates.
|
||||
*/
|
||||
if (rcg->current_freq)
|
||||
timeout += 3 * (1000000 / rcg->current_freq);
|
||||
if (rcg->configured_freq)
|
||||
timeout += 3 * (1000000 / rcg->configured_freq);
|
||||
|
||||
return max(timeout, 500);
|
||||
}
|
||||
|
||||
static int update_config(struct clk_rcg2 *rcg)
|
||||
{
|
||||
int count, ret;
|
||||
int timeout, count, ret;
|
||||
u32 cmd;
|
||||
struct clk_hw *hw = &rcg->clkr.hw;
|
||||
|
||||
|
|
@ -129,8 +146,10 @@ static int update_config(struct clk_rcg2 *rcg)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
timeout = get_update_timeout(rcg);
|
||||
|
||||
/* Wait for update to take effect */
|
||||
for (count = 500; count > 0; count--) {
|
||||
for (count = timeout; count > 0; count--) {
|
||||
ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -139,7 +158,7 @@ static int update_config(struct clk_rcg2 *rcg)
|
|||
udelay(1);
|
||||
}
|
||||
|
||||
WARN_CLK(hw, 1, "rcg didn't update its configuration.");
|
||||
WARN_CLK(hw, 1, "rcg didn't update its configuration after %d us.", timeout);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
|
@ -487,6 +506,8 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
rcg->configured_freq = f->freq;
|
||||
|
||||
return update_config(rcg);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user