platsmp.c revision bb6032776d81d01cf6fecac7ccc27dd5abbffd7a
1/* 2 * linux/arch/arm/mach-tegra/platsmp.c 3 * 4 * Copyright (C) 2002 ARM Ltd. 5 * All Rights Reserved 6 * 7 * Copyright (C) 2009 Palm 8 * All Rights Reserved 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14#include <linux/init.h> 15#include <linux/errno.h> 16#include <linux/delay.h> 17#include <linux/device.h> 18#include <linux/jiffies.h> 19#include <linux/smp.h> 20#include <linux/io.h> 21 22#include <asm/cacheflush.h> 23#include <asm/hardware/gic.h> 24#include <asm/mach-types.h> 25#include <asm/smp_scu.h> 26 27#include <mach/clk.h> 28#include <mach/iomap.h> 29#include <mach/powergate.h> 30 31#include "fuse.h" 32#include "flowctrl.h" 33#include "reset.h" 34#include "tegra_cpu_car.h" 35 36extern void tegra_secondary_startup(void); 37 38static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); 39 40#define EVP_CPU_RESET_VECTOR \ 41 (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) 42 43void __cpuinit platform_secondary_init(unsigned int cpu) 44{ 45 /* 46 * if any interrupts are already enabled for the primary 47 * core (e.g. timer irq), then they will not have been enabled 48 * for us: do so 49 */ 50 gic_secondary_init(0); 51 52} 53 54static int tegra20_power_up_cpu(unsigned int cpu) 55{ 56 /* Enable the CPU clock. */ 57 tegra_enable_cpu_clock(cpu); 58 59 /* Clear flow controller CSR. */ 60 flowctrl_write_cpu_csr(cpu, 0); 61 62 return 0; 63} 64 65static int tegra30_power_up_cpu(unsigned int cpu) 66{ 67 int ret, pwrgateid; 68 unsigned long timeout; 69 70 pwrgateid = tegra_cpu_powergate_id(cpu); 71 if (pwrgateid < 0) 72 return pwrgateid; 73 74 /* If this is the first boot, toggle powergates directly. */ 75 if (!tegra_powergate_is_powered(pwrgateid)) { 76 ret = tegra_powergate_power_on(pwrgateid); 77 if (ret) 78 return ret; 79 80 /* Wait for the power to come up. */ 81 timeout = jiffies + 10*HZ; 82 while (tegra_powergate_is_powered(pwrgateid)) { 83 if (time_after(jiffies, timeout)) 84 return -ETIMEDOUT; 85 udelay(10); 86 } 87 } 88 89 /* CPU partition is powered. Enable the CPU clock. */ 90 tegra_enable_cpu_clock(cpu); 91 udelay(10); 92 93 /* Remove I/O clamps. */ 94 ret = tegra_powergate_remove_clamping(pwrgateid); 95 udelay(10); 96 97 /* Clear flow controller CSR. */ 98 flowctrl_write_cpu_csr(cpu, 0); 99 100 return 0; 101} 102 103int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 104{ 105 int status; 106 107 /* 108 * Force the CPU into reset. The CPU must remain in reset when the 109 * flow controller state is cleared (which will cause the flow 110 * controller to stop driving reset if the CPU has been power-gated 111 * via the flow controller). This will have no effect on first boot 112 * of the CPU since it should already be in reset. 113 */ 114 tegra_put_cpu_in_reset(cpu); 115 116 /* 117 * Unhalt the CPU. If the flow controller was used to power-gate the 118 * CPU this will cause the flow controller to stop driving reset. 119 * The CPU will remain in reset because the clock and reset block 120 * is now driving reset. 121 */ 122 flowctrl_write_cpu_halt(cpu, 0); 123 124 switch (tegra_chip_id) { 125 case TEGRA20: 126 status = tegra20_power_up_cpu(cpu); 127 break; 128 case TEGRA30: 129 status = tegra30_power_up_cpu(cpu); 130 break; 131 default: 132 status = -EINVAL; 133 break; 134 } 135 136 if (status) 137 goto done; 138 139 /* Take the CPU out of reset. */ 140 tegra_cpu_out_of_reset(cpu); 141done: 142 return status; 143} 144 145/* 146 * Initialise the CPU possible map early - this describes the CPUs 147 * which may be present or become present in the system. 148 */ 149void __init smp_init_cpus(void) 150{ 151 unsigned int i, ncores = scu_get_core_count(scu_base); 152 153 if (ncores > nr_cpu_ids) { 154 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 155 ncores, nr_cpu_ids); 156 ncores = nr_cpu_ids; 157 } 158 159 for (i = 0; i < ncores; i++) 160 set_cpu_possible(i, true); 161 162 set_smp_cross_call(gic_raise_softirq); 163} 164 165void __init platform_smp_prepare_cpus(unsigned int max_cpus) 166{ 167 tegra_cpu_reset_handler_init(); 168 scu_enable(scu_base); 169} 170