[PATCH] ARM: imx: avoid calling clk APIs in idle thread which may cause schedule

Anson Huang b20788 at freescale.com
Tue Feb 11 03:11:47 EST 2014


On Tue, Feb 11, 2014 at 02:18:35PM +0800, Shawn Guo wrote:
> On Mon, Feb 10, 2014 at 02:34:50PM +0800, Anson Huang wrote:
> > @@ -81,19 +99,67 @@ static const u32 clks_init_on[] __initconst = {
> >   * entering WAIT mode.
> >   *
> >   * This function will set the ARM clk to max value within the 12:5 limit.
> > + * As IPG clock is fixed at 66MHz(so ARM freq must not exceed 158.4MHz),
> > + * ARM freq are one of below setpoints: 396MHz, 792MHz and 996MHz, since
> > + * the clk APIs can NOT be called in idle thread(may cause kernel schedule
> > + * as there is sleep function in PLL wait function), so here we just slow
> > + * down ARM to below freq according to previous freq:
> > + *
> > + * run mode      wait mode
> > + * 396MHz   ->   132MHz;
> > + * 792MHz   ->   158.4MHz;
> > + * 996MHz   ->   142.3MHz;
> >   */
> > +static int imx6sl_get_arm_divider_for_wait(void)
> > +{
> > +	if (readl_relaxed(ccm_base + CCSR) & BM_CCSR_PLL1_SW_CLK_SEL) {
> > +		return ARM_WAIT_DIV_396M;
> > +	} else {
> > +		if ((readl_relaxed(anatop_base + PLL_ARM) &
> > +			BM_PLL_ARM_DIV_SELECT) == PLL_ARM_DIV_792M)
> > +			return ARM_WAIT_DIV_792M;
> > +		else
> > +			return ARM_WAIT_DIV_996M;
> > +	}
> > +}
> > +
> > +static void imx6sl_enable_pll_arm(bool enable)
> > +{
> > +	static u32 saved_pll_arm;
> > +	u32 val;
> > +
> > +	if (enable) {
> > +		saved_pll_arm = val = readl_relaxed(anatop_base + PLL_ARM);
> > +		val |= BM_PLL_ARM_ENABLE;
> > +		val &= ~BM_PLL_ARM_POWERDOWN;
> > +		writel_relaxed(val, anatop_base + PLL_ARM);
> > +		while (!(__raw_readl(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK))
> > +			;
> > +	} else {
> > +		 writel_relaxed(saved_pll_arm, anatop_base + PLL_ARM);
> > +	}
> > +}
> > +
> >  void imx6sl_set_wait_clk(bool enter)
> >  {
> > -	static unsigned long saved_arm_rate;
> > +	static unsigned long saved_arm_div;
> >  
> > +	/*
> > +	 * According to hardware design, arm podf change need
> > +	 * PLL1 clock enabled.
> > +	 */
> > +	imx6sl_enable_pll_arm(true);
> 
> This only applies to the ARM_WAIT_DIV_396M case, since for the other two
> PLL1 must already be enabled, right?

Yes, I will add condition check to make sure it is only called when ARM is
@396MHz.

> 
> >  	if (enter) {
> > -		unsigned long ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]);
> > -		unsigned long max_arm_wait_rate = (12 * ipg_rate) / 5;
> > -		saved_arm_rate = clk_get_rate(clks[IMX6SL_CLK_ARM]);
> > -		clk_set_rate(clks[IMX6SL_CLK_ARM], max_arm_wait_rate);
> > +		saved_arm_div = readl_relaxed(ccm_base + CACRR);
> > +		writel_relaxed(imx6sl_get_arm_divider_for_wait(),
> > +			ccm_base + CACRR);
> >  	} else {
> > -		clk_set_rate(clks[IMX6SL_CLK_ARM], saved_arm_rate);
> > +		writel_relaxed(saved_arm_div, ccm_base + CACRR);
> >  	}
> > +
> > +	while (__raw_readl(ccm_base + CDHIPR) & BM_CDHIPR_ARM_PODF_BUSY)
> > +		;
> > +	imx6sl_enable_pll_arm(false);
> >  }
> >  
> >  static void __init imx6sl_clocks_init(struct device_node *ccm_node)
> > @@ -110,6 +176,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
> >  
> >  	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
> >  	base = of_iomap(np, 0);
> > +	anatop_base = base;
> 
> More logical to put it after the WARN_ON() below?
> 
> >  	WARN_ON(!base);
> >  
> >  	/*                                             type               name            parent  base         div_mask */
> > @@ -157,6 +224,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
> >  
> >  	np = ccm_node;
> >  	base = of_iomap(np, 0);
> > +	ccm_base = base;
> 
> Ditto.

Will improve it in V2, thanks.

Anson.

> 
> Shawn
> 
> >  	WARN_ON(!base);
> >  
> >  	/* Reuse imx6q pm code */
> > -- 
> > 1.7.9.5
> > 
> > 
> 




More information about the linux-arm-kernel mailing list