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 36 #include "common.h" 37 38 extern void tegra_secondary_startup(void); 39 40 static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); 41 42 #define EVP_CPU_RESET_VECTOR \ 43 (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) 44 45 static void __cpuinit tegra_secondary_init(unsigned int cpu) 46 { 47 /* 48 * if any interrupts are already enabled for the primary 49 * core (e.g. timer irq), then they will not have been enabled 50 * for us: do so 51 */ 52 gic_secondary_init(0); 53 54 } 55 56 static int tegra20_power_up_cpu(unsigned int cpu) 57 { 58 /* Enable the CPU clock. */ 59 tegra_enable_cpu_clock(cpu); 60 61 /* Clear flow controller CSR. */ 62 flowctrl_write_cpu_csr(cpu, 0); 63 64 return 0; 65 } 66 67 static int tegra30_power_up_cpu(unsigned int cpu) 68 { 69 int ret, pwrgateid; 70 unsigned long timeout; 71 72 pwrgateid = tegra_cpu_powergate_id(cpu); 73 if (pwrgateid < 0) 74 return pwrgateid; 75 76 /* If this is the first boot, toggle powergates directly. */ 77 if (!tegra_powergate_is_powered(pwrgateid)) { 78 ret = tegra_powergate_power_on(pwrgateid); 79 if (ret) 80 return ret; 81 82 /* Wait for the power to come up. */ 83 timeout = jiffies + 10*HZ; 84 while (tegra_powergate_is_powered(pwrgateid)) { 85 if (time_after(jiffies, timeout)) 86 return -ETIMEDOUT; 87 udelay(10); 88 } 89 } 90 91 /* CPU partition is powered. Enable the CPU clock. */ 92 tegra_enable_cpu_clock(cpu); 93 udelay(10); 94 95 /* Remove I/O clamps. */ 96 ret = tegra_powergate_remove_clamping(pwrgateid); 97 udelay(10); 98 99 /* Clear flow controller CSR. */ 100 flowctrl_write_cpu_csr(cpu, 0); 101 102 return 0; 103 } 104 105 static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle) 106 { 107 int status; 108 109 /* 110 * Force the CPU into reset. The CPU must remain in reset when the 111 * flow controller state is cleared (which will cause the flow 112 * controller to stop driving reset if the CPU has been power-gated 113 * via the flow controller). This will have no effect on first boot 114 * of the CPU since it should already be in reset. 115 */ 116 tegra_put_cpu_in_reset(cpu); 117 118 /* 119 * Unhalt the CPU. If the flow controller was used to power-gate the 120 * CPU this will cause the flow controller to stop driving reset. 121 * The CPU will remain in reset because the clock and reset block 122 * is now driving reset. 123 */ 124 flowctrl_write_cpu_halt(cpu, 0); 125 126 switch (tegra_chip_id) { 127 case TEGRA20: 128 status = tegra20_power_up_cpu(cpu); 129 break; 130 case TEGRA30: 131 status = tegra30_power_up_cpu(cpu); 132 break; 133 default: 134 status = -EINVAL; 135 break; 136 } 137 138 if (status) 139 goto done; 140 141 /* Take the CPU out of reset. */ 142 tegra_cpu_out_of_reset(cpu); 143 done: 144 return status; 145 } 146 147 /* 148 * Initialise the CPU possible map early - this describes the CPUs 149 * which may be present or become present in the system. 150 */ 151 static void __init tegra_smp_init_cpus(void) 152 { 153 unsigned int i, ncores = scu_get_core_count(scu_base); 154 155 if (ncores > nr_cpu_ids) { 156 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 157 ncores, nr_cpu_ids); 158 ncores = nr_cpu_ids; 159 } 160 161 for (i = 0; i < ncores; i++) 162 set_cpu_possible(i, true); 163 164 set_smp_cross_call(gic_raise_softirq); 165 } 166 167 static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) 168 { 169 tegra_cpu_reset_handler_init(); 170 scu_enable(scu_base); 171 } 172 173 struct smp_operations tegra_smp_ops __initdata = { 174 .smp_init_cpus = tegra_smp_init_cpus, 175 .smp_prepare_cpus = tegra_smp_prepare_cpus, 176 .smp_secondary_init = tegra_secondary_init, 177 .smp_boot_secondary = tegra_boot_secondary, 178 #ifdef CONFIG_HOTPLUG_CPU 179 .cpu_die = tegra_cpu_die, 180 .cpu_disable = tegra_cpu_disable, 181 #endif 182 }; 183