Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bfebc570 authored by Deepak Katragadda's avatar Deepak Katragadda
Browse files

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: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 73135edf
Loading
Loading
Loading
Loading
+23 −17
Original line number Diff line number Diff line
@@ -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. */
	if ((rcg->non_local_children && c->count) ||
			rcg->non_local_control_timeout) {
		/*
	 * 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) {
		/*
		 * 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
+4 −0
Original line number Diff line number Diff line
@@ -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;
};