[PATCH] ARM: imx: avoid calling clk APIs in idle thread which may cause schedule
Shawn Guo
shawn.guo at linaro.org
Tue Feb 11 01:18:35 EST 2014
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?
> 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.
Shawn
> WARN_ON(!base);
>
> /* Reuse imx6q pm code */
> --
> 1.7.9.5
>
>
More information about the linux-arm-kernel
mailing list