[PATCH v2 8/8] ARM: tegra: support for secondary cores on Tegra30

Colin Cross ccross at android.com
Thu Feb 2 13:17:48 EST 2012


On Tue, Jan 31, 2012 at 8:40 AM, Peter De Schrijver
<pdeschrijver at nvidia.com> wrote:
> Add support for bringing up secondary cores on Tegra30. On Tegra30 secondary
> CPU cores are powergated, so we need to turn on the domains before we can bring
> the CPU cores online. Bringing secondary cores online happens early during the
> sytem boot, so we call powergating initialization from platform early_init
> function.
>
> Based on work by:
>
> Scott Williams <scwilliams at nvidia.com>
> Colin Cross <ccross at android.com>
> Alex Frid <afrid at nvidia.com>
>
> Signed-off-by: Peter De Schrijver <pdeschrijver at nvidia.com>
> ---
>  arch/arm/mach-tegra/headsmp.S |   32 +++++++++++++++++++++++++
>  arch/arm/mach-tegra/platsmp.c |   52 ++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 83 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
> index bb13e22..925c4a0 100644
> --- a/arch/arm/mach-tegra/headsmp.S
> +++ b/arch/arm/mach-tegra/headsmp.S
> @@ -188,6 +188,38 @@ __die:
>        str     r1, [r7, #0x340]                @ CLK_RST_CPU_CMPLX_SET
>  #endif
>  1:
> +#ifdef CONFIG_ARCH_TEGRA_3x_SOC
> +       mov32   r6, TEGRA_FLOW_CTRL_BASE
> +
> +       cmp     r10, #0
> +       moveq   r1, #FLOW_CTRL_HALT_CPU0_EVENTS
> +       moveq   r2, #FLOW_CTRL_CPU0_CSR
> +       movne   r1, r10, lsl #3
> +       addne   r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
> +       addne   r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
> +
> +       /* Clear CPU "event" and "interrupt" flags and power gate
> +          it when halting but not before it is in the "WFI" state. */
> +       ldr     r0, [r6, +r2]
> +       orr     r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
> +       orr     r0, r0, #FLOW_CTRL_CSR_ENABLE
> +       str     r0, [r6, +r2]
> +
> +       /* Unconditionally halt this CPU */
> +       mov     r0, #FLOW_CTRL_WAITEVENT
> +       str     r0, [r6, +r1]
> +       ldr     r0, [r6, +r1]                   @ memory barrier
> +
> +       dsb
> +       isb
> +       wfi                                     @ CPU should be power gated here
> +
> +       /* If the CPU didn't power gate above just kill it's clock. */
> +
> +       mov     r0, r11, lsl #8
> +       str     r0, [r7, #348]                  @ CLK_CPU_CMPLX_SET
> +#endif
> +
>        /* If the CPU still isn't dead, just spin here. */
>        b       .
>  ENDPROC(__tegra_cpu_reset_handler)
> diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
> index 79a241a..1fe3f58 100644
> --- a/arch/arm/mach-tegra/platsmp.c
> +++ b/arch/arm/mach-tegra/platsmp.c
> @@ -24,7 +24,9 @@
>  #include <asm/mach-types.h>
>  #include <asm/smp_scu.h>
>
> +#include <mach/clk.h>
>  #include <mach/iomap.h>
> +#include <mach/powergate.h>
>
>  #include "fuse.h"
>  #include "flowctrl.h"
> @@ -42,6 +44,8 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
>        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
>  #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
>        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
> +#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
> +       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
>
>  #define CPU_CLOCK(cpu) (0x1<<(8+cpu))
>  #define CPU_RESET(cpu) (0x1111ul<<(cpu))
> @@ -73,11 +77,54 @@ static int tegra20_power_up_cpu(unsigned int cpu)
>        return 0;
>  }
>
> +static int tegra30_power_up_cpu(unsigned int cpu)
> +{
> +       u32 reg;
> +       int ret, pwrgateid;
> +       unsigned long timeout;
> +
> +       pwrgateid = tegra_cpu_powergate_id(cpu);
> +       if (pwrgateid < 0)
> +               return pwrgateid;
> +
> +       /* If this is the first boot, toggle powergates directly. */
> +       if (!tegra_powergate_is_powered(pwrgateid)) {
> +               ret = tegra_powergate_power_on(pwrgateid);
> +               if (ret)
> +                       return ret;
> +
> +               /* Wait for the power to come up. */
> +               timeout = jiffies + 10*HZ;
> +               do {
> +                       if (tegra_powergate_is_powered(pwrgateid))
> +                               goto remove_clamps;
> +                       udelay(10);
> +               } while (time_before(jiffies, timeout));
> +               return -ETIMEDOUT;
> +       }

This loop + goto seems convoluted.  Why not untangle it:
                timeout = jiffies + 10*HZ;
                while (tegra_powergate_is_powered(pwrgateid)) {
                        if (time_after(jiffies, timeout))
                                return -ETIMEDOUT;
                        udelay(10);
                }

> +
> +remove_clamps:
> +       /* CPU partition is powered. Enable the CPU clock. */
> +       writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
> +       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
> +       udelay(10);
> +
> +       /* Remove I/O clamps. */
> +       ret = tegra_powergate_remove_clamping(pwrgateid);
> +       udelay(10);
> +
> +       /* Clear flow controller CSR. */
> +       flowctrl_write_cpu_csr(cpu, 0);
> +
> +       return 0;
> +}
> +
>  int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
>  {
>        int status;
>
> -       /* Force the CPU into reset. The CPU must remain in reset when the
> +       /*
> +        * Force the CPU into reset. The CPU must remain in reset when the
>         * flow controller state is cleared (which will cause the flow
>         * controller to stop driving reset if the CPU has been power-gated
>         * via the flow controller). This will have no effect on first boot
> @@ -98,6 +145,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
>        case TEGRA20:
>                status = tegra20_power_up_cpu(cpu);
>                break;
> +       case TEGRA30:
> +               status = tegra30_power_up_cpu(cpu);
> +               break;
>        default:
>                status = -EINVAL;
>                break;
> --
> 1.7.7.rc0.72.g4b5ea.dirty
>

Other than that, Acked-by: Colin Cross <ccross at android.com>



More information about the linux-arm-kernel mailing list