clk: msm: clock-local2: Set RCG root_enable bit prior to changing rate
Firmware running on HW blocks could be powering down the branch clock or the RCG whilst software is doing frequency changes. If this happens, the RCG behavior is undefined and may cause issues with its functioning. To work around this, use the RCG root_en bit and force turn it on while scaling the rate. In addition, make the polling timeouts configurable. CRs-Fixed: 971305 Change-Id: If2db14c70614c47d673fc735f5f4bac276d4a3d9 Signed-off-by: Deepak Katragadda <dkatraga@codeaurora.org>
This commit is contained in:
parent
ffed8c4da3
commit
7947c04641
2 changed files with 27 additions and 17 deletions
|
@ -36,6 +36,8 @@
|
|||
/* For clock without halt checking, wait this long after enables/disables. */
|
||||
#define HALT_CHECK_DELAY_US 500
|
||||
|
||||
#define RCG_FORCE_DISABLE_DELAY_US 100
|
||||
|
||||
/*
|
||||
* When updating an RCG configuration, check the update bit up to this number
|
||||
* number of times (with a 1 us delay in between) before continuing.
|
||||
|
@ -105,14 +107,18 @@ struct div_map {
|
|||
*/
|
||||
static void rcg_update_config(struct rcg_clk *rcg)
|
||||
{
|
||||
u32 cmd_rcgr_regval, count;
|
||||
u32 cmd_rcgr_regval;
|
||||
int count = UPDATE_CHECK_MAX_LOOPS;
|
||||
|
||||
if (rcg->non_local_control_timeout)
|
||||
count = rcg->non_local_control_timeout;
|
||||
|
||||
cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
|
||||
cmd_rcgr_regval |= CMD_RCGR_CONFIG_UPDATE_BIT;
|
||||
writel_relaxed(cmd_rcgr_regval, CMD_RCGR_REG(rcg));
|
||||
|
||||
/* Wait for update to take effect */
|
||||
for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) {
|
||||
for (; count > 0; count--) {
|
||||
if (!(readl_relaxed(CMD_RCGR_REG(rcg)) &
|
||||
CMD_RCGR_CONFIG_UPDATE_BIT))
|
||||
return;
|
||||
|
@ -124,10 +130,13 @@ static void rcg_update_config(struct rcg_clk *rcg)
|
|||
|
||||
static void rcg_on_check(struct rcg_clk *rcg)
|
||||
{
|
||||
int count;
|
||||
int count = UPDATE_CHECK_MAX_LOOPS;
|
||||
|
||||
if (rcg->non_local_control_timeout)
|
||||
count = rcg->non_local_control_timeout;
|
||||
|
||||
/* Wait for RCG to turn on */
|
||||
for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) {
|
||||
for (; count > 0; count--) {
|
||||
if (!(readl_relaxed(CMD_RCGR_REG(rcg)) &
|
||||
CMD_RCGR_ROOT_STATUS_BIT))
|
||||
return;
|
||||
|
@ -211,6 +220,8 @@ static void rcg_clear_force_enable(struct rcg_clk *rcg)
|
|||
cmd_rcgr_regval &= ~CMD_RCGR_ROOT_ENABLE_BIT;
|
||||
writel_relaxed(cmd_rcgr_regval, CMD_RCGR_REG(rcg));
|
||||
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
|
||||
/* Add a delay of 100usecs to let the RCG disable */
|
||||
udelay(RCG_FORCE_DISABLE_DELAY_US);
|
||||
}
|
||||
|
||||
static int rcg_clk_enable(struct clk *c)
|
||||
|
@ -291,25 +302,20 @@ static int rcg_clk_set_rate(struct clk *c, unsigned long rate)
|
|||
|
||||
BUG_ON(!rcg->set_rate);
|
||||
|
||||
/*
|
||||
* Perform clock-specific frequency switch operations.
|
||||
*
|
||||
* For RCGs with non_local_children set to true:
|
||||
* If this RCG has at least one branch that is controlled by another
|
||||
* execution entity, ensure that the enable/disable and mux switch
|
||||
* are staggered.
|
||||
*/
|
||||
if (!rcg->non_local_children) {
|
||||
rcg->set_rate(rcg, nf);
|
||||
} else if (c->count) {
|
||||
/* Perform clock-specific frequency switch operations. */
|
||||
if ((rcg->non_local_children && c->count) ||
|
||||
rcg->non_local_control_timeout) {
|
||||
/*
|
||||
* Force enable the RCG here since there could be a disable
|
||||
* call happening between pre_reparent and set_rate.
|
||||
* Force enable the RCG here since the clock could be disabled
|
||||
* between pre_reparent and set_rate.
|
||||
*/
|
||||
rcg_set_force_enable(rcg);
|
||||
rcg->set_rate(rcg, nf);
|
||||
rcg_clear_force_enable(rcg);
|
||||
} else if (!rcg->non_local_children) {
|
||||
rcg->set_rate(rcg, nf);
|
||||
}
|
||||
|
||||
/*
|
||||
* If non_local_children is set and the RCG is not enabled,
|
||||
* the following operations switch parent in software and cache
|
||||
|
|
|
@ -57,6 +57,9 @@ struct clk_freq_tbl {
|
|||
* @current_freq: current RCG frequency
|
||||
* @c: generic clock data
|
||||
* @non_local_children: set if RCG has at least one branch owned by a diff EE
|
||||
* @non_local_control_timeout: configurable RCG timeout needed when all RCG
|
||||
* children can be controlled by an entity outside of
|
||||
HLOS.
|
||||
* @force_enable_rcgr: set if RCG needs to be force enabled/disabled during
|
||||
* power sequence
|
||||
* @base: pointer to base address of ioremapped registers.
|
||||
|
@ -71,6 +74,7 @@ struct rcg_clk {
|
|||
struct clk c;
|
||||
|
||||
bool non_local_children;
|
||||
int non_local_control_timeout;
|
||||
bool force_enable_rcgr;
|
||||
void *const __iomem *base;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue