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:
Deepak Katragadda 2016-02-23 15:21:59 -08:00 committed by David Keitel
parent ffed8c4da3
commit 7947c04641
2 changed files with 27 additions and 17 deletions

View file

@ -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

View file

@ -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;
};