10462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King/*
20462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King *  linux/arch/arm/plat-versatile/platsmp.c
30462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King *
40462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King *  Copyright (C) 2002 ARM Ltd.
50462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King *  All Rights Reserved
60462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King *
70462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * This program is free software; you can redistribute it and/or modify
80462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * it under the terms of the GNU General Public License version 2 as
90462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * published by the Free Software Foundation.
100462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */
110462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/init.h>
120462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/errno.h>
130462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/delay.h>
140462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/device.h>
150462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/jiffies.h>
160462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <linux/smp.h>
170462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
180462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King#include <asm/cacheflush.h>
19eb50439b92b6298bf209a982f295ba9c0f7cb30bWill Deacon#include <asm/smp_plat.h>
200462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
210462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King/*
220462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * Write pen_release in a way that is guaranteed to be visible to all
230462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * observers, irrespective of whether they're taking part in coherency
240462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King * or not.  This is necessary for the hotplug code to work reliably.
250462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King */
268bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakerstatic void write_pen_release(int val)
270462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King{
280462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	pen_release = val;
290462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	smp_wmb();
30f45913fde00f13f502730809d128e607da2a57c8Nicolas Pitre	sync_cache_w(&pen_release);
310462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King}
320462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
330462b4477ea3260304bbcd97c64c0b704b4f0f85Russell Kingstatic DEFINE_SPINLOCK(boot_lock);
340462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
358bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakervoid versatile_secondary_init(unsigned int cpu)
360462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King{
370462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	/*
380462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * let the primary processor know we're out of the
390462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * pen, then head off into the C entry point
400462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 */
410462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	write_pen_release(-1);
420462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
430462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	/*
440462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * Synchronise with the boot thread.
450462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 */
460462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	spin_lock(&boot_lock);
470462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	spin_unlock(&boot_lock);
480462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King}
490462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
508bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakerint versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
510462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King{
520462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	unsigned long timeout;
530462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
540462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	/*
550462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * Set synchronisation state between this boot processor
560462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * and the secondary one
570462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 */
580462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	spin_lock(&boot_lock);
590462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
600462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	/*
610462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * This is really belt and braces; we hold unintended secondary
620462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * CPUs in the holding pen until we're ready for them.  However,
630462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * since we haven't sent them a soft interrupt, they shouldn't
640462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * be there.
650462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 */
664a139b64703115e41e1a4e16ebf7eb93d0a0e349Will Deacon	write_pen_release(cpu_logical_map(cpu));
670462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
680462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	/*
690462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * Send the secondary CPU a soft interrupt, thereby causing
700462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * the boot monitor to read the system wide flags register,
710462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * and branch to the address found there.
720462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 */
73b1cffebf1029c87e1f1984d48463ee21093a6bc7Rob Herring	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
740462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
750462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	timeout = jiffies + (1 * HZ);
760462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	while (time_before(jiffies, timeout)) {
770462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King		smp_rmb();
780462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King		if (pen_release == -1)
790462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King			break;
800462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
810462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King		udelay(10);
820462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	}
830462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
840462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	/*
850462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * now the secondary core is starting up let it run its
860462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 * calibrations, then wait for it to finish
870462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	 */
880462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	spin_unlock(&boot_lock);
890462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King
900462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King	return pen_release != -1 ? -ENOSYS : 0;
910462b4477ea3260304bbcd97c64c0b704b4f0f85Russell King}
92