summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-03-23 19:15:12 -0700
committerGary King <gking@nvidia.com>2010-03-26 12:47:27 -0800
commite942ce81fb8d18ecbbba3ebf8b6a98048e7cfe0b (patch)
treee8f917f0ea5303c346c99dffc89950c9be64dbfc
parent94e55929b1f29c3f7b0f362f9264790471f705ef (diff)
arm tegra: update platsmp to follow kernel code style
squash hotplug code into platsmp file, to limit overall spaghettiness Change-Id: I6704323837ad545564a0dcfd47894835f2adeb1a Reviewed-on: http://git-master/r/948 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/Makefile5
-rw-r--r--arch/arm/mach-tegra/hotplug.c49
-rw-r--r--arch/arm/mach-tegra/platsmp.c355
3 files changed, 131 insertions, 278 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 5b4c352e0d4e..7116e76c5263 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -27,6 +27,7 @@ obj-y += tegra_exports.o
# Linux CPU frequency scaling interface
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
# Dynamic voltage and frequency scaling support
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += idle-t2.o
@@ -38,13 +39,9 @@ obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-# CPU hotplug support
-ifeq ($(CONFIG_HOTPLUG_CPU),y)
-obj-y += hotplug.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += power-t2.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += power-context-t2.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += power-lp.o
-endif
# System DMA
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
deleted file mode 100644
index efda7b72d762..000000000000
--- a/arch/arm/mach-tegra/hotplug.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/arm/mach-tegra/hotplug.c
- *
- * CPU hotplug support for Tegra SoCs
- *
- * Copyright (c) 2009, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/completion.h>
-#include <asm/cacheflush.h>
-
-
-static DECLARE_COMPLETION(cpu_killed);
-
-extern void cpu_ap20_do_lp2(void);
-
-int platform_cpu_kill(unsigned int cpu)
-{
- return wait_for_completion_timeout(&cpu_killed, 5000);
-}
-
-void platform_cpu_die(unsigned int cpu)
-{
- flush_cache_all();
- preempt_enable_no_resched();
- complete(&cpu_killed);
- cpu_ap20_do_lp2();
-}
-
-int mach_cpu_disable(unsigned int cpu)
-{
- return (cpu==0) ? -EPERM : 0;
-}
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index bea6c3e176cc..3bd0300dc9b3 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -3,7 +3,7 @@
*
* SMP management routines for SMP Tegra SoCs
*
- * Copyright (c) 2009, NVIDIA Corporation.
+ * Copyright (c) 2010, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,259 +24,164 @@
#include <linux/smp.h>
#include <asm/cacheflush.h>
#include <asm/localtimer.h>
-
-#include "mach/nvrm_linux.h"
-#include "nvrm_module.h"
-#include "nvrm_init.h"
-#include "nvrm_drf.h"
-#include "nvrm_hardware_access.h"
-#include "nvcommon.h"
-#include "ap20/arscu.h"
-#include "ap20/arevp.h"
-#include "ap20/arclk_rst.h"
-#include "ap20/arfic_proc_if.h"
-#include "ap20/arflow_ctlr.h"
+#include <linux/io.h>
+#include <mach/iomap.h>
static DEFINE_SPINLOCK(boot_lock);
-
extern void exit_lp2(void);
+extern void tegra_secondary_startup(void);
+
+#define SCU_CONTROL_0 0x0
+#define SCU_CONFIG_0 0x4
+
+#define EVP_CPU_RESET_VECTOR_0 0x100
+
+/* takes cpu out of reset */
+#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR_0 0x344
+#define CPU_RESET(cpu) (0x1011ul<<(cpu))
+
+/* used as mask to enable clock to cpu */
+#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 0x4c
+#define CPU_CLK_STOP(cpu) (0x1<<(8+cpu))
-static inline volatile NvU8 *TegraScuAddress(void)
+/* write 0 to take cpu out of flow controlled state */
+#define FLOW_CTRL_HALT_CPUx_EVENTS(cpu) ((cpu)?((cpu-1)*0x8 + 0x14) : 0x0)
+
+static DECLARE_BITMAP(cpu_init_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_init_mask = to_cpumask(cpu_init_bits);
+#define cpu_init_map (*(cpumask_t *)cpu_init_mask)
+
+static u32 orig_reset;
+
+void platform_secondary_init(unsigned int cpu)
{
- NvRmPhysAddr Pa;
- NvU32 Len;
- volatile NvU8 *pScu = NULL;
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmPrivModuleID_ArmPerif, 0), &Pa, &Len);
-
- if (Pa==0xffffffffUL || !Len) {
- printk("TegraSMP: No SCU present\n");
- return NULL;
- }
-
- NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void**)&pScu);
- return pScu;
+ if (cpumask_test_cpu(cpu, cpu_init_mask))
+ return;
+
+ trace_hardirqs_off();
+ spin_lock(&boot_lock);
+ cpu_set(cpu, cpu_init_map);
+ spin_unlock(&boot_lock);
+
+ gic_cpu_init(0, IO_ADDRESS(TEGRA_GIC_PROC_IF_BASE));
}
-#if 0
-#define TegraCoreCount() 1
-#else
-static unsigned int __init TegraCoreCount(void)
+void __init smp_init_cpus()
{
- volatile NvU8 *pScu = TegraScuAddress();
- unsigned int Cores = 1;
- if (pScu) {
- Cores = NV_READ32(pScu + SCU_CONFIG_0);
- Cores = NV_DRF_VAL(SCU, CONFIG, CPU_NUM, Cores) + 1;
- }
-
- if (Cores>NR_CPUS) {
- printk("TegraSMP: Kernel configured for fewer NR_CPUS than hardware\n");
- Cores = NR_CPUS;
- }
- return Cores;
+ unsigned int cfg;
+ unsigned int cpus;
+ void __iomem *evp = IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE);
+
+ cfg = __raw_readl(IO_ADDRESS(TEGRA_SCU_BASE) + SCU_CONFIG_0);
+
+ cpus = min_t(unsigned int, NR_CPUS, (cfg & 3) + 1);
+
+ while (cpus--)
+ cpu_set(cpus, cpu_possible_map);
+
+ orig_reset = __raw_readl(evp + EVP_CPU_RESET_VECTOR_0);
}
-#endif
-void platform_secondary_init(unsigned int cpu)
+void __init smp_prepare_cpus(unsigned int max)
{
- NvRmPhysAddr Pa;
- NvU32 Len;
- volatile NvU8* pArm = NULL;
- static unsigned int first_init = 1;
-
- if (first_init == 0)
- return;
-
- trace_hardirqs_off();
-
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
-
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmPrivModuleID_ArmPerif,0), &Pa, &Len);
- BUG_ON(Pa==-1UL || !Len);
- NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void**)&pArm);
- BUG_ON(!pArm);
-
- gic_cpu_init(0, (void __iomem*)pArm + FIC_PROC_IF_CONTROL_0);
-
- first_init = 0;
+ unsigned int cpu;
+
+ smp_store_cpu_info(smp_processor_id());
+ for_each_possible_cpu(cpu)
+ cpu_set(cpu, cpu_present_map);
+
+ if (num_present_cpus()>1) {
+ u32 ctrl;
+
+ percpu_timer_setup();
+ ctrl = __raw_readl(IO_ADDRESS(TEGRA_SCU_BASE) + SCU_CONTROL_0);
+ ctrl |= 1;
+ __raw_writel(ctrl, IO_ADDRESS(TEGRA_SCU_BASE) + SCU_CONTROL_0);
+ }
}
-void __init smp_init_cpus(void)
+static inline void bwritel(unsigned long v, void __iomem *a)
{
- unsigned int i;
- unsigned int Cores = TegraCoreCount();
-
- for (i=0; i<Cores; i++)
- cpu_set(i, cpu_possible_map);
+ __raw_writel(v, a);
+ dsb();
+ isb();
}
-void __init smp_prepare_cpus(unsigned int Max)
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- unsigned int Cores = TegraCoreCount();
- unsigned int Cpu = smp_processor_id();
- volatile NvU8 *pScu = NULL;
- unsigned int i;
+ void __iomem *clk = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+ void __iomem *flow = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE);
+ void __iomem *evp = IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE);
+ unsigned long boot;
+ unsigned long timeout;
+ u32 r;
+
+ spin_lock(&boot_lock);
+
+ if (likely(cpumask_test_cpu(cpu, cpu_init_mask)))
+ boot = virt_to_phys((void *)exit_lp2);
+ else
+ boot = virt_to_phys((void *)tegra_secondary_startup);
+
+ flush_cache_all();
+ smp_wmb();
+
+ bwritel(boot, evp + EVP_CPU_RESET_VECTOR_0);
+
+ bwritel(0, flow + FLOW_CTRL_HALT_CPUx_EVENTS(cpu));
- smp_store_cpu_info(Cpu);
+ r = __raw_readl(clk + CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0);
+ r &= ~CPU_CLK_STOP(cpu);
+ bwritel(r, clk + CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0);
+ bwritel(CPU_RESET(cpu), clk + CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR_0);
- pScu = TegraScuAddress();
- if (!pScu)
- Cores = 1;
+ timeout = jiffies + 10*HZ;
- Max = NV_MIN(Max, Cores);
+ do {
+ r = __raw_readl(evp + EVP_CPU_RESET_VECTOR_0);
+ if (r!=boot)
+ break;
+ cpu_relax();
+ } while (time_before(jiffies, timeout));
- for (i=0; i<Max; i++)
- cpu_set(i, cpu_present_map);
+ __raw_writel(orig_reset, evp + EVP_CPU_RESET_VECTOR_0);
+ spin_unlock(&boot_lock);
- if (Max > 1)
- {
- /*
- * Enable the local timer or broadcast device for the
- * boot CPU, but only if we have more than one CPU.
- */
- percpu_timer_setup();
+ if (r==boot) {
+ pr_err("failed to initialize CPU %u\n", cpu);
+ return -EIO;
+ }
- NvU32 v = NV_READ32(pScu + SCU_CONTROL_0);
- v = NV_FLD_SET_DRF_NUM(SCU, CONTROL, SCU_ENABLE, 1, v);
- NV_WRITE32(pScu + SCU_CONTROL_0, v);
- }
+ return 0;
}
-#define CHECK_ADDR(P,L,N) \
- do { \
- if ((P)==-1UL || !(L)) \
- { \
- printk("TegraSMP: No %s module present\n", #N); \
- return -ENOSYS; \
- } \
- } while (0);
+#ifdef CONFIG_HOTPLUG_CPU
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+static DECLARE_COMPLETION(cpu_killed);
+extern void cpu_ap20_do_lp2(void);
+
+int platform_cpu_kill(unsigned int cpu)
{
- volatile NvU8 *pEvp = NULL;
- volatile NvU8 *pFlowCtrl = NULL;
- volatile NvU8 *pClkRst = NULL;
- NvUPtr BootFunc;
- NvRmPhysAddr Pa;
- NvU32 Len;
- NvU32 HaltAddr;
- NvU32 ResetVal;
- NvU32 ClkEnable;
- NvU32 OldReset;
- NvU32 v, Msg;
- extern void tegra_secondary_startup(void);
-#ifdef CONFIG_HOTPLUG_CPU
- extern void TegraHotplugStartup(void);
- static NvU32 EnabledCores = 0;
-#endif
- unsigned long timeout;
-
- spin_lock(&boot_lock);
-
- /* Map exception vector, flow controller and clock & reset module */
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_ExceptionVector, 0), &Pa, &Len);
- CHECK_ADDR(Pa, Len, EVP);
- NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void**)&pEvp);
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_FlowCtrl, 0), &Pa, &Len);
- CHECK_ADDR(Pa, Len, FlowCtrl);
- NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void**)&pFlowCtrl);
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmPrivModuleID_ClockAndReset,0), &Pa, &Len);
- CHECK_ADDR(Pa, Len, ClockReset);
- NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void**)&pClkRst);
-
- if (!pClkRst || !pFlowCtrl || !pEvp)
- {
- printk("TegraSMP: Unable to map necessary modules for SMP start-up\n");
- return -ENOSYS;
- }
-
- ResetVal =
- NV_DRF_NUM(CLK_RST_CONTROLLER, RST_CPU_CMPLX_CLR, CLR_CPURESET0, 1)|
- NV_DRF_NUM(CLK_RST_CONTROLLER, RST_CPU_CMPLX_CLR, CLR_DBGRESET0, 1)|
- NV_DRF_NUM(CLK_RST_CONTROLLER, RST_CPU_CMPLX_CLR, CLR_DERESET0, 1);
- ResetVal <<= cpu;
-
- switch (cpu) {
- case 0:
- // Kernel should never call this, since master CPU will always be up
- HaltAddr = FLOW_CTLR_HALT_CPU_EVENTS_0;
- ClkEnable =
- ~NV_DRF_NUM(CLK_RST_CONTROLLER, CLK_CPU_CMPLX, CPU0_CLK_STP, 1);
- break;
- case 1:
- HaltAddr = FLOW_CTLR_HALT_CPU1_EVENTS_0;
- ClkEnable =
- ~NV_DRF_NUM(CLK_RST_CONTROLLER, CLK_CPU_CMPLX, CPU1_CLK_STP, 1);
- break;
- default:
- panic("Unsupported cpu ID: %u\n", cpu);
- }
+ return wait_for_completion_timeout(&cpu_killed, 5000);
+}
-#ifdef CONFIG_HOTPLUG_CPU
- if (EnabledCores & (1<<cpu)) {
- BootFunc = virt_to_phys((void*)exit_lp2);
- }
- else
-#endif
- {
- BootFunc = virt_to_phys((void*)tegra_secondary_startup);
- }
- OldReset = NV_READ32(pEvp + EVP_CPU_RESET_VECTOR_0);
- smp_wmb();
- flush_cache_all();
-
- NV_WRITE32(pEvp + EVP_CPU_RESET_VECTOR_0, BootFunc);
- dsb();
- isb();
- NV_WRITE32(pFlowCtrl + HaltAddr,
- NV_DRF_DEF(FLOW_CTLR, HALT_CPU_EVENTS, MODE, FLOW_MODE_NONE));
- v = NV_READ32(pClkRst + CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0);
- dsb();
- isb();
- v &= ClkEnable;
- NV_WRITE32(pClkRst + CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0, v);
- dsb();
- isb();
- NV_WRITE32(pClkRst + CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR_0, ResetVal);
- dsb();
- isb();
-
- timeout = jiffies + (10 * HZ);
- do {
- /* The slave CPU will put its ID into the reset vector register after
- * it initializes its cache */
- Msg = NV_READ32(pEvp + EVP_CPU_RESET_VECTOR_0);
- if (Msg != BootFunc)
- break;
- } while (time_before(jiffies, timeout));
-
- /* Restore the original reset vector, after either the slave processor
- * wakes up, or we timeout waiting for it */
- NV_WRITE32(pEvp + EVP_CPU_RESET_VECTOR_0, OldReset);
-
- spin_unlock(&boot_lock);
- if (Msg == BootFunc) {
- printk(KERN_INFO "TegraSMP: Failed to init CPU %u\n", cpu);
- return -ENOSYS;
- }
-
- printk(KERN_INFO "TegraSMP: CPU %u responded with \"0x%08x\"\n", cpu, Msg);
+void platform_cpu_die(unsigned int cpu)
+{
+ flush_cache_all();
+ preempt_enable_no_resched();
+ complete(&cpu_killed);
+ cpu_ap20_do_lp2();
+}
-#ifdef CONFIG_HOTPLUG_CPU
- EnabledCores |= (1<<cpu);
-#endif
+int mach_cpu_disable(unsigned int cpu)
+{
+ WARN_ON(!cpu);
+ if (!cpu)
+ return -EPERM;
- return 0;
+ return 0;
}
+
+
+#endif