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