mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	clk: core: support clocks which requires parents enable (part 2)
On Freescale i.MX7D platform, all clocks operations, including enable/disable, rate change and re-parent, requires its parent clock on. Current clock core can not support it well. This patch adding flag CLK_OPS_PARENT_ENABLE to handle this special case in clock core that enable its parent clock firstly for each operation and disable it later after operation complete. The patch part 2 fixes set clock rate and set parent while its parent is off. The most special case is for set_parent() operation which requires all parents including both old and new one to be enabled at the same time during the operation. Cc: Michael Turquette <mturquette@baylibre.com> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Shawn Guo <shawnguo@kernel.org> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com> [sboyd@codeaurora.org: Move set_rate tracepoint after prepare_enable] Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
		
							parent
							
								
									a4b3518d14
								
							
						
					
					
						commit
						fc8726a2c0
					
				
					 1 changed files with 33 additions and 15 deletions
				
			
		| 
						 | 
				
			
			@ -1172,7 +1172,9 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core,
 | 
			
		|||
	struct clk_core *old_parent = core->parent;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Migrate prepare state between parents and prevent race with
 | 
			
		||||
	 * 1. enable parents for CLK_OPS_PARENT_ENABLE clock
 | 
			
		||||
	 *
 | 
			
		||||
	 * 2. Migrate prepare state between parents and prevent race with
 | 
			
		||||
	 * clk_enable().
 | 
			
		||||
	 *
 | 
			
		||||
	 * If the clock is not prepared, then a race with
 | 
			
		||||
| 
						 | 
				
			
			@ -1188,12 +1190,17 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core,
 | 
			
		|||
	 *
 | 
			
		||||
	 * See also: Comment for clk_set_parent() below.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* enable old_parent & parent if CLK_OPS_PARENT_ENABLE is set */
 | 
			
		||||
	if (core->flags & CLK_OPS_PARENT_ENABLE) {
 | 
			
		||||
		clk_core_prepare_enable(old_parent);
 | 
			
		||||
		clk_core_prepare_enable(parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* migrate prepare count if > 0 */
 | 
			
		||||
	if (core->prepare_count) {
 | 
			
		||||
		clk_core_prepare(parent);
 | 
			
		||||
		flags = clk_enable_lock();
 | 
			
		||||
		clk_core_enable(parent);
 | 
			
		||||
		clk_core_enable(core);
 | 
			
		||||
		clk_enable_unlock(flags);
 | 
			
		||||
		clk_core_prepare_enable(parent);
 | 
			
		||||
		clk_core_enable_lock(core);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* update the clk tree topology */
 | 
			
		||||
| 
						 | 
				
			
			@ -1208,18 +1215,19 @@ static void __clk_set_parent_after(struct clk_core *core,
 | 
			
		|||
				   struct clk_core *parent,
 | 
			
		||||
				   struct clk_core *old_parent)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Finish the migration of prepare state and undo the changes done
 | 
			
		||||
	 * for preventing a race with clk_enable().
 | 
			
		||||
	 */
 | 
			
		||||
	if (core->prepare_count) {
 | 
			
		||||
		flags = clk_enable_lock();
 | 
			
		||||
		clk_core_disable(core);
 | 
			
		||||
		clk_core_disable(old_parent);
 | 
			
		||||
		clk_enable_unlock(flags);
 | 
			
		||||
		clk_core_unprepare(old_parent);
 | 
			
		||||
		clk_core_disable_lock(core);
 | 
			
		||||
		clk_core_disable_unprepare(old_parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* re-balance ref counting if CLK_OPS_PARENT_ENABLE is set */
 | 
			
		||||
	if (core->flags & CLK_OPS_PARENT_ENABLE) {
 | 
			
		||||
		clk_core_disable_unprepare(parent);
 | 
			
		||||
		clk_core_disable_unprepare(old_parent);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1466,13 +1474,17 @@ static void clk_change_rate(struct clk_core *core)
 | 
			
		|||
	unsigned long best_parent_rate = 0;
 | 
			
		||||
	bool skip_set_rate = false;
 | 
			
		||||
	struct clk_core *old_parent;
 | 
			
		||||
	struct clk_core *parent = NULL;
 | 
			
		||||
 | 
			
		||||
	old_rate = core->rate;
 | 
			
		||||
 | 
			
		||||
	if (core->new_parent)
 | 
			
		||||
	if (core->new_parent) {
 | 
			
		||||
		parent = core->new_parent;
 | 
			
		||||
		best_parent_rate = core->new_parent->rate;
 | 
			
		||||
	else if (core->parent)
 | 
			
		||||
	} else if (core->parent) {
 | 
			
		||||
		parent = core->parent;
 | 
			
		||||
		best_parent_rate = core->parent->rate;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (core->flags & CLK_SET_RATE_UNGATE) {
 | 
			
		||||
		unsigned long flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -1500,6 +1512,9 @@ static void clk_change_rate(struct clk_core *core)
 | 
			
		|||
		__clk_set_parent_after(core, core->new_parent, old_parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (core->flags & CLK_OPS_PARENT_ENABLE)
 | 
			
		||||
		clk_core_prepare_enable(parent);
 | 
			
		||||
 | 
			
		||||
	trace_clk_set_rate(core, core->new_rate);
 | 
			
		||||
 | 
			
		||||
	if (!skip_set_rate && core->ops->set_rate)
 | 
			
		||||
| 
						 | 
				
			
			@ -1518,6 +1533,9 @@ static void clk_change_rate(struct clk_core *core)
 | 
			
		|||
		clk_core_unprepare(core);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (core->flags & CLK_OPS_PARENT_ENABLE)
 | 
			
		||||
		clk_core_disable_unprepare(parent);
 | 
			
		||||
 | 
			
		||||
	if (core->notifier_count && old_rate != core->rate)
 | 
			
		||||
		__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue