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

Commit cccc277b authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'tegra-for-3.7-cpu-hotplug' of...

Merge tag 'tegra-for-3.7-cpu-hotplug' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra into next/soc

From Stephen Warren:

ARM: tegra: implement CPU hotplug

This branch implements CPU hot-plugging support for both Tegra20 and
Tegra30. Portions of the implementation are contained in the clock
driver, hence this branch is based on the common clock conversion in
order to avoid duplicating work.

By Joseph Lo
via Stephen Warren
* tag 'tegra-for-3.7-cpu-hotplug' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra:
  ARM: tegra20: add CPU hotplug support
  ARM: tegra30: add CPU hotplug support
  ARM: tegra: clean up the common assembly macros into sleep.h
  ARM: tegra: replace the CPU CAR access code by tegra_cpu_car_ops
  ARM: tegra: introduce tegra_cpu_car_ops structures
parents ea2abb67 453689e4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -15,8 +15,10 @@ obj-$(CONFIG_CPU_IDLE) += sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-t20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-t30.o
obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
obj-$(CONFIG_SMP)                       += reset.o
obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
+4 −0
Original line number Diff line number Diff line
@@ -31,6 +31,10 @@

#include "board.h"
#include "clock.h"
#include "tegra_cpu_car.h"

/* Global data of Tegra CPU CAR ops */
struct tegra_cpu_car_ops *tegra_cpu_car_ops;

/*
 * Locking:
+3 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include "fuse.h"
#include "pmc.h"
#include "apbio.h"
#include "sleep.h"

/*
 * Storage for debug-macro.S's state.
@@ -135,6 +136,7 @@ void __init tegra20_init_early(void)
	tegra_init_cache(0x331, 0x441);
	tegra_pmc_init();
	tegra_powergate_init();
	tegra20_hotplug_init();
}
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -147,6 +149,7 @@ void __init tegra30_init_early(void)
	tegra_init_cache(0x441, 0x551);
	tegra_pmc_init();
	tegra_powergate_init();
	tegra30_hotplug_init();
}
#endif

+1 −5
Original line number Diff line number Diff line
@@ -7,17 +7,13 @@

#include "flowctrl.h"
#include "reset.h"
#include "sleep.h"

#define APB_MISC_GP_HIDREV	0x804
#define PMC_SCRATCH41	0x140

#define RESET_DATA(x)	((TEGRA_RESET_##x)*4)

	.macro mov32, reg, val
	movw	\reg, #:lower16:\val
	movt	\reg, #:upper16:\val
	.endm

        .section ".text.head", "ax"
	__CPUINIT

+32 −86
Original line number Diff line number Diff line
/*
 *  linux/arch/arm/mach-realview/hotplug.c
 *
 *  Copyright (C) 2002 ARM Ltd.
 *  All Rights Reserved
 *  Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>

#include <asm/cacheflush.h>
#include <asm/cp15.h>
#include <asm/smp_plat.h>

static inline void cpu_enter_lowpower(void)
{
	unsigned int v;

	flush_cache_all();
	asm volatile(
	"	mcr	p15, 0, %1, c7, c5, 0\n"
	"	mcr	p15, 0, %1, c7, c10, 4\n"
	/*
	 * Turn off coherency
	 */
	"	mrc	p15, 0, %0, c1, c0, 1\n"
	"	bic	%0, %0, #0x20\n"
	"	mcr	p15, 0, %0, c1, c0, 1\n"
	"	mrc	p15, 0, %0, c1, c0, 0\n"
	"	bic	%0, %0, %2\n"
	"	mcr	p15, 0, %0, c1, c0, 0\n"
	  : "=&r" (v)
	  : "r" (0), "Ir" (CR_C)
	  : "cc");
}

static inline void cpu_leave_lowpower(void)
{
	unsigned int v;

	asm volatile(
	"mrc	p15, 0, %0, c1, c0, 0\n"
	"	orr	%0, %0, %1\n"
	"	mcr	p15, 0, %0, c1, c0, 0\n"
	"	mrc	p15, 0, %0, c1, c0, 1\n"
	"	orr	%0, %0, #0x20\n"
	"	mcr	p15, 0, %0, c1, c0, 1\n"
	  : "=&r" (v)
	  : "Ir" (CR_C)
	  : "cc");
}

static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
{
	/*
	 * there is no power-control hardware on this platform, so all
	 * we can do is put the core into WFI; this is safe as the calling
	 * code will have already disabled interrupts
	 */
	for (;;) {
		/*
		 * here's the WFI
		 */
		asm(".word	0xe320f003\n"
		    :
		    :
		    : "memory", "cc");

		/*if (pen_release == cpu) {*/
			/*
			 * OK, proper wakeup, we're done
			 */
			break;
		/*}*/
#include "sleep.h"
#include "tegra_cpu_car.h"

		/*
		 * Getting here, means that we have come out of WFI without
		 * having been woken up - this shouldn't happen
		 *
		 * Just note it happening - when we're woken, we can report
		 * its occurrence.
		 */
		(*spurious)++;
	}
}
static void (*tegra_hotplug_shutdown)(void);

int platform_cpu_kill(unsigned int cpu)
{
@@ -99,22 +31,20 @@ int platform_cpu_kill(unsigned int cpu)
 */
void platform_cpu_die(unsigned int cpu)
{
	int spurious = 0;
	cpu = cpu_logical_map(cpu);

	/*
	 * we're ready for shutdown now, so do it
	 */
	cpu_enter_lowpower();
	platform_do_lowpower(cpu, &spurious);
	/* Flush the L1 data cache. */
	flush_cache_all();

	/*
	 * bring this CPU back into the world of cache
	 * coherency, and then restore interrupts
	 */
	cpu_leave_lowpower();
	/* Shut down the current CPU. */
	tegra_hotplug_shutdown();

	/* Clock gate the CPU */
	tegra_wait_cpu_in_reset(cpu);
	tegra_disable_cpu_clock(cpu);

	if (spurious)
		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
	/* Should never return here. */
	BUG();
}

int platform_cpu_disable(unsigned int cpu)
@@ -125,3 +55,19 @@ int platform_cpu_disable(unsigned int cpu)
	 */
	return cpu == 0 ? -EPERM : 0;
}

#ifdef CONFIG_ARCH_TEGRA_2x_SOC
extern void tegra20_hotplug_shutdown(void);
void __init tegra20_hotplug_init(void)
{
	tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
}
#endif

#ifdef CONFIG_ARCH_TEGRA_3x_SOC
extern void tegra30_hotplug_shutdown(void);
void __init tegra30_hotplug_init(void)
{
	tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
}
#endif
Loading