omap-smp.c 10.8 KB
Newer Older
1
/*
2
 * OMAP4 SMP source file. It contains platform specific functions
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * needed for the linux smp kernel.
 *
 * Copyright (C) 2009 Texas Instruments, Inc.
 *
 * Author:
 *      Santosh Shilimkar <santosh.shilimkar@ti.com>
 *
 * Platform file needed for the OMAP4 SMP. This file is based on arm
 * realview smp platform.
 * * Copyright (c) 2002 ARM Limited.
 *
 * 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/init.h>
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
22
#include <linux/irqchip/arm-gic.h>
23

24
#include <asm/sections.h>
25
#include <asm/smp_scu.h>
26
#include <asm/virt.h>
27

28
#include "omap-secure.h"
29
#include "omap-wakeupgen.h"
30
#include <asm/cputype.h>
31

32
#include "soc.h"
33
#include "iomap.h"
34
#include "common.h"
35
#include "clockdomain.h"
36
#include "pm.h"
37

S
Santosh Shilimkar 已提交
38 39 40 41 42 43
#define CPU_MASK		0xff0ffff0
#define CPU_CORTEX_A9		0x410FC090
#define CPU_CORTEX_A15		0x410FC0F0

#define OMAP5_CORE_COUNT	0x2

44 45 46
#define AUX_CORE_BOOT0_GP_RELEASE	0x020
#define AUX_CORE_BOOT0_HS_RELEASE	0x200

47 48 49 50
struct omap_smp_config {
	unsigned long cpu1_rstctrl_pa;
	void __iomem *cpu1_rstctrl_va;
	void __iomem *scu_base;
51
	void __iomem *wakeupgen_base;
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	void *startup_addr;
};

static struct omap_smp_config cfg;

static const struct omap_smp_config omap443x_cfg __initconst = {
	.cpu1_rstctrl_pa = 0x4824380c,
	.startup_addr = omap4_secondary_startup,
};

static const struct omap_smp_config omap446x_cfg __initconst = {
	.cpu1_rstctrl_pa = 0x4824380c,
	.startup_addr = omap4460_secondary_startup,
};

static const struct omap_smp_config omap5_cfg __initconst = {
	.cpu1_rstctrl_pa = 0x48243810,
	.startup_addr = omap5_secondary_startup,
};
71 72 73

static DEFINE_SPINLOCK(boot_lock);

74 75
void __iomem *omap4_get_scu_base(void)
{
76
	return cfg.scu_base;
77 78
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
#ifdef CONFIG_OMAP5_ERRATA_801819
void omap5_erratum_workaround_801819(void)
{
	u32 acr, revidr;
	u32 acr_mask;

	/* REVIDR[3] indicates erratum fix available on silicon */
	asm volatile ("mrc p15, 0, %0, c0, c0, 6" : "=r" (revidr));
	if (revidr & (0x1 << 3))
		return;

	asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr));
	/*
	 * BIT(27) - Disables streaming. All write-allocate lines allocate in
	 * the L1 or L2 cache.
	 * BIT(25) - Disables streaming. All write-allocate lines allocate in
	 * the L1 cache.
	 */
	acr_mask = (0x3 << 25) | (0x3 << 27);
	/* do we already have it done.. if yes, skip expensive smc */
	if ((acr & acr_mask) == acr_mask)
		return;

	acr |= acr_mask;
	omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr);

	pr_debug("%s: ARM erratum workaround 801819 applied on CPU%d\n",
		 __func__, smp_processor_id());
}
#else
static inline void omap5_erratum_workaround_801819(void) { }
#endif

112
static void omap4_secondary_init(unsigned int cpu)
113
{
114 115 116 117 118 119 120 121
	/*
	 * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device.
	 * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA
	 * init and for CPU1, a secure PPA API provided. CPU0 must be ON
	 * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+.
	 * OMAP443X GP devices- SMP bit isn't accessible.
	 * OMAP446X GP devices - SMP bit access is enabled on both CPUs.
	 */
122
	if (soc_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP))
123 124 125
		omap_secure_dispatcher(OMAP4_PPA_CPU_ACTRL_SMP_INDEX,
							4, 0, 0, 0, 0, 0);

126 127 128 129 130
	if (soc_is_omap54xx() || soc_is_dra7xx()) {
		/*
		 * Configure the CNTFRQ register for the secondary cpu's which
		 * indicates the frequency of the cpu local timers.
		 */
131
		set_cntfreq();
132 133 134
		/* Configure ACR to disable streaming WA for 801819 */
		omap5_erratum_workaround_801819();
	}
135

136 137 138 139 140 141 142
	/*
	 * Synchronise with the boot thread.
	 */
	spin_lock(&boot_lock);
	spin_unlock(&boot_lock);
}

143
static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
144
{
145 146
	static struct clockdomain *cpu1_clkdm;
	static bool booted;
147
	static struct powerdomain *cpu1_pwrdm;
148

149 150 151 152 153 154 155
	/*
	 * Set synchronisation state between this boot processor
	 * and the secondary one
	 */
	spin_lock(&boot_lock);

	/*
156
	 * Update the AuxCoreBoot0 with boot state for secondary core.
157
	 * omap4_secondary_startup() routine will hold the secondary core till
158 159 160
	 * the AuxCoreBoot1 register is updated with cpu state
	 * A barrier is added to ensure that write buffer is drained
	 */
161
	if (omap_secure_apis_support())
162 163
		omap_modify_auxcoreboot0(AUX_CORE_BOOT0_HS_RELEASE,
					 0xfffffdff);
164
	else
165 166
		writel_relaxed(AUX_CORE_BOOT0_GP_RELEASE,
			       cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
167

168
	if (!cpu1_clkdm && !cpu1_pwrdm) {
169
		cpu1_clkdm = clkdm_lookup("mpu1_clkdm");
170 171
		cpu1_pwrdm = pwrdm_lookup("cpu1_pwrdm");
	}
172 173 174 175 176 177 178 179 180 181 182 183

	/*
	 * The SGI(Software Generated Interrupts) are not wakeup capable
	 * from low power states. This is known limitation on OMAP4 and
	 * needs to be worked around by using software forced clockdomain
	 * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to
	 * software force wakeup. The clockdomain is then put back to
	 * hardware supervised mode.
	 * More details can be found in OMAP4430 TRM - Version J
	 * Section :
	 *	4.3.4.2 Power States of CPU0 and CPU1
	 */
184
	if (booted && cpu1_pwrdm && cpu1_clkdm) {
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
		/*
		 * GIC distributor control register has changed between
		 * CortexA9 r1pX and r2pX. The Control Register secure
		 * banked version is now composed of 2 bits:
		 * bit 0 == Secure Enable
		 * bit 1 == Non-Secure Enable
		 * The Non-Secure banked register has not changed
		 * Because the ROM Code is based on the r1pX GIC, the CPU1
		 * GIC restoration will cause a problem to CPU0 Non-Secure SW.
		 * The workaround must be:
		 * 1) Before doing the CPU1 wakeup, CPU0 must disable
		 * the GIC distributor
		 * 2) CPU1 must re-enable the GIC distributor on
		 * it's wakeup path.
		 */
200 201
		if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
			local_irq_disable();
202
			gic_dist_disable();
203
		}
204

205 206 207 208
		/*
		 * Ensure that CPU power state is set to ON to avoid CPU
		 * powerdomain transition on wfi
		 */
209
		clkdm_deny_idle_nolock(cpu1_clkdm);
210 211
		pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON);
		clkdm_allow_idle_nolock(cpu1_clkdm);
212 213 214 215 216 217 218 219 220

		if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
			while (gic_dist_disabled()) {
				udelay(1);
				cpu_relax();
			}
			gic_timer_retrigger();
			local_irq_enable();
		}
221 222 223 224 225
	} else {
		dsb_sev();
		booted = true;
	}

226
	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
227 228 229 230 231 232 233 234 235 236 237 238 239 240

	/*
	 * Now the secondary core is starting up let it run its
	 * calibrations, then wait for it to finish
	 */
	spin_unlock(&boot_lock);

	return 0;
}

/*
 * Initialise the CPU possible map early - this describes the CPUs
 * which may be present or become present in the system.
 */
241
static void __init omap4_smp_init_cpus(void)
242
{
S
Santosh Shilimkar 已提交
243 244 245
	unsigned int i = 0, ncores = 1, cpu_id;

	/* Use ARM cpuid check here, as SoC detection will not work so early */
246
	cpu_id = read_cpuid_id() & CPU_MASK;
S
Santosh Shilimkar 已提交
247 248 249 250 251
	if (cpu_id == CPU_CORTEX_A9) {
		/*
		 * Currently we can't call ioremap here because
		 * SoC detection won't work until after init_early.
		 */
252 253 254
		cfg.scu_base =  OMAP2_L4_IO_ADDRESS(scu_a9_get_base());
		BUG_ON(!cfg.scu_base);
		ncores = scu_get_core_count(cfg.scu_base);
S
Santosh Shilimkar 已提交
255 256 257
	} else if (cpu_id == CPU_CORTEX_A15) {
		ncores = OMAP5_CORE_COUNT;
	}
258 259

	/* sanity check */
260 261 262 263
	if (ncores > nr_cpu_ids) {
		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
			ncores, nr_cpu_ids);
		ncores = nr_cpu_ids;
264 265
	}

266 267 268 269
	for (i = 0; i < ncores; i++)
		set_cpu_possible(i, true);
}

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
/*
 * For now, just make sure the start-up address is not within the booting
 * kernel space as that means we just overwrote whatever secondary_startup()
 * code there was.
 */
static bool __init omap4_smp_cpu1_startup_valid(unsigned long addr)
{
	if ((addr >= __pa(PAGE_OFFSET)) && (addr <= __pa(__bss_start)))
		return false;

	return true;
}

/*
 * We may need to reset CPU1 before configuring, otherwise kexec boot can end
 * up trying to use old kernel startup address or suspend-resume will
 * occasionally fail to bring up CPU1 on 4430 if CPU1 fails to enter deeper
 * idle states.
 */
static void __init omap4_smp_maybe_reset_cpu1(struct omap_smp_config *c)
{
	unsigned long cpu1_startup_pa, cpu1_ns_pa_addr;
	bool needs_reset = false;
	u32 released;

	if (omap_secure_apis_support())
		released = omap_read_auxcoreboot0() & AUX_CORE_BOOT0_HS_RELEASE;
	else
		released = readl_relaxed(cfg.wakeupgen_base +
					 OMAP_AUX_CORE_BOOT_0) &
						AUX_CORE_BOOT0_GP_RELEASE;
	if (released) {
		pr_warn("smp: CPU1 not parked?\n");

		return;
	}

	cpu1_startup_pa = readl_relaxed(cfg.wakeupgen_base +
					OMAP_AUX_CORE_BOOT_1);
	cpu1_ns_pa_addr = omap4_get_cpu1_ns_pa_addr();

	/* Did the configured secondary_startup() get overwritten? */
	if (!omap4_smp_cpu1_startup_valid(cpu1_startup_pa))
		needs_reset = true;

	/*
	 * If omap4 or 5 has NS_PA_ADDR configured, CPU1 may be in a
	 * deeper idle state in WFI and will wake to an invalid address.
	 */
	if ((soc_is_omap44xx() || soc_is_omap54xx()) &&
	    !omap4_smp_cpu1_startup_valid(cpu1_ns_pa_addr))
		needs_reset = true;

	if (!needs_reset || !c->cpu1_rstctrl_va)
		return;

	pr_info("smp: CPU1 parked within kernel, needs reset (0x%lx 0x%lx)\n",
		cpu1_startup_pa, cpu1_ns_pa_addr);

	writel_relaxed(1, c->cpu1_rstctrl_va);
	readl_relaxed(c->cpu1_rstctrl_va);
	writel_relaxed(0, c->cpu1_rstctrl_va);
}

334
static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
335
{
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
	const struct omap_smp_config *c = NULL;

	if (soc_is_omap443x())
		c = &omap443x_cfg;
	else if (soc_is_omap446x())
		c = &omap446x_cfg;
	else if (soc_is_dra74x() || soc_is_omap54xx())
		c = &omap5_cfg;

	if (!c) {
		pr_err("%s Unknown SMP SoC?\n", __func__);
		return;
	}

	/* Must preserve cfg.scu_base set earlier */
	cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa;
	cfg.startup_addr = c->startup_addr;
353
	cfg.wakeupgen_base = omap_get_wakeupgen_base();
354 355 356 357 358 359 360 361 362 363

	if (soc_is_dra74x() || soc_is_omap54xx()) {
		if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
			cfg.startup_addr = omap5_secondary_hyp_startup;
		omap5_erratum_workaround_801819();
	}

	cfg.cpu1_rstctrl_va = ioremap(cfg.cpu1_rstctrl_pa, 4);
	if (!cfg.cpu1_rstctrl_va)
		return;
364

365 366 367 368
	/*
	 * Initialise the SCU and wake up the secondary core using
	 * wakeup_secondary().
	 */
369 370
	if (cfg.scu_base)
		scu_enable(cfg.scu_base);
371

372
	omap4_smp_maybe_reset_cpu1(&cfg);
373 374 375 376 377 378 379 380

	/*
	 * Write the address of secondary startup routine into the
	 * AuxCoreBoot1 where ROM code will jump and start executing
	 * on secondary core once out of WFE
	 * A barrier is added to ensure that write buffer is drained
	 */
	if (omap_secure_apis_support())
381
		omap_auxcoreboot_addr(__pa_symbol(cfg.startup_addr));
382
	else
383
		writel_relaxed(__pa_symbol(cfg.startup_addr),
384
			       cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_1);
385
}
386

387
const struct smp_operations omap4_smp_ops __initconst = {
388 389 390 391 392 393
	.smp_init_cpus		= omap4_smp_init_cpus,
	.smp_prepare_cpus	= omap4_smp_prepare_cpus,
	.smp_secondary_init	= omap4_secondary_init,
	.smp_boot_secondary	= omap4_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= omap4_cpu_die,
394
	.cpu_kill		= omap4_cpu_kill,
395 396
#endif
};