kernel-fxtec-pro1x/arch/arm/mach-prima2/platsmp.c
Linus Torvalds 99c6bcf46d ARM: arm-soc multiplatform updates for 3.10
More multiplatform enablement for ARM platforms. The ones converted in
 this branch are:
 - bcm2835
 - cns3xxx
 - sirf
 - nomadik
 - msx
 - spear
 - tegra
 - ux500
 
 We're getting close to having most of them converted!
 
 One of the larger platforms remaining is Samsung Exynos, and there are
 a bunch of supporting patches in this merge window for it. There was a
 patch in this branch to a early version of multiplatform conversion,
 but it ended up being reverted due to need of more bake time. The
 revert commit is part of the branch since it would have required
 rebasing multiple dependent branches and they were stable by then.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJRgg99AAoJEIwa5zzehBx3n78P/j0w/8v+F4dM29ba5M/tqbFI
 e3wpeFykZ/HJH+FFIEYfIablpfHsLB0LEMh0dZmwHESFC6eR0RfGL2jOkpfcH9Ne
 7B/JIFN4l1iwqqKCXf+QbYL6e8YFxlJkg6BIB4KhNgliQoO/ASP/8EbcgROYuxmN
 KPVdw9laUCCvb5Ogh2NWVAkBHhVGAEiqK20r4TQz8alI8RUmMleWM3o+wLBWVhOO
 d3gtYSfuFSbrJfbpKSdycLizoV/NekdOC1A9Ov9YuOdw8DzNbrThCRQtu0tIUgxN
 JjfnGlEJLsJS9SESfr8SYWxTuhe/lB2dGqjQPvRtl2HGBhbtTlnWfQ0k2ZHdeJuD
 J50SLrGA2gN9E5PlHJXjYk8uhhGIq8bNTJ//CtDkfKTq1D7PuHVEpEctsaz3BBbM
 U+x9zP2v4FB+yrZu8w+gkQY/wDgHsxj08mT6BK0+l8ePdyQV22CvwmM5XlJFI03x
 5J0nLYiYfef+ZN9rGgVrQbn+yv+IEkE4DmeiscjeVJE5LVdVrDpYGfx7UA7V0UA7
 i3KRVpNKuy1v7GJDnKlEBPkmB+vgXTRXUPDVCuC4n0Hi5PYj4es1gY6AoXGF90wm
 vtKxGr/2XDLP7Ro+m0OXMttSgQShnmbrbOngfkWcFwUmG7cB3SSUUOGKM+2LNnXM
 MJTqVhPjkZ2GYBi/J6S/
 =4hSo
 -----END PGP SIGNATURE-----

Merge tag 'multiplatform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC multiplatform updates from Olof Johansson:
 "More multiplatform enablement for ARM platforms.  The ones converted
  in this branch are:

   - bcm2835
   - cns3xxx
   - sirf
   - nomadik
   - msx
   - spear
   - tegra
   - ux500

  We're getting close to having most of them converted!

  One of the larger platforms remaining is Samsung Exynos, and there are
  a bunch of supporting patches in this merge window for it.  There was
  a patch in this branch to a early version of multiplatform conversion,
  but it ended up being reverted due to need of more bake time.  The
  revert commit is part of the branch since it would have required
  rebasing multiple dependent branches and they were stable by then"

* tag 'multiplatform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (70 commits)
  mmc: sdhci-s3c: Fix operation on non-single image Samsung platforms
  clocksource: nomadik-mtu: fix up clocksource/timer
  Revert "ARM: exynos: enable multiplatform support"
  ARM: SPEAr13xx: Fix typo "ARCH_HAVE_CPUFREQ"
  ARM: exynos: enable multiplatform support
  rtc: s3c: make header file local
  mtd: onenand/samsung: make regs-onenand.h file local
  thermal/exynos: remove unnecessary header inclusions
  mmc: sdhci-s3c: remove platform dependencies
  ARM: samsung: move mfc device definition to s5p-dev-mfc.c
  ARM: exynos: move debug-macro.S to include/debug/
  ARM: exynos: prepare for sparse IRQ
  ARM: exynos: introduce EXYNOS_ATAGS symbol
  ARM: tegra: build assembly files with -march=armv7-a
  ARM: Push selects for TWD/SCU into machine entries
  ARM: ux500: build hotplug.o for ARMv7-a
  ARM: ux500: move to multiplatform
  ARM: ux500: make remaining headers local
  ARM: ux500: make irqs.h local to platform
  ARM: ux500: get rid of <mach/[hardware|db8500-regs].h>
  ...
2013-05-02 09:38:16 -07:00

148 lines
3.5 KiB
C

/*
* plat smp support for CSR Marco dual-core SMP SoCs
*
* Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include "common.h"
static void __iomem *scu_base;
static void __iomem *rsc_base;
static DEFINE_SPINLOCK(boot_lock);
static struct map_desc scu_io_desc __initdata = {
.length = SZ_4K,
.type = MT_DEVICE,
};
void __init sirfsoc_map_scu(void)
{
unsigned long base;
/* Get SCU base */
asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
scu_io_desc.virtual = SIRFSOC_VA(base);
scu_io_desc.pfn = __phys_to_pfn(base);
iotable_init(&scu_io_desc, 1);
scu_base = (void __iomem *)SIRFSOC_VA(base);
}
static void __cpuinit sirfsoc_secondary_init(unsigned int cpu)
{
/*
* let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
pen_release = -1;
smp_wmb();
/*
* Synchronise with the boot thread.
*/
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
}
static struct of_device_id rsc_ids[] = {
{ .compatible = "sirf,marco-rsc" },
{},
};
static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
struct device_node *np;
np = of_find_matching_node(NULL, rsc_ids);
if (!np)
return -ENODEV;
rsc_base = of_iomap(np, 0);
if (!rsc_base)
return -ENOMEM;
/*
* write the address of secondary startup into the sram register
* at offset 0x2C, then write the magic number 0x3CAF5D62 to the
* RSC register at offset 0x28, which is what boot rom code is
* waiting for. This would wake up the secondary core from WFE
*/
#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C
__raw_writel(virt_to_phys(sirfsoc_secondary_startup),
rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28
__raw_writel(0x3CAF5D62,
rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
/* make sure write buffer is drained */
mb();
spin_lock(&boot_lock);
/*
* The secondary processor is waiting to be released from
* the holding pen - release it, then wait for it to flag
* that it has been released by resetting pen_release.
*
* Note that "pen_release" is the hardware CPU ID, whereas
* "cpu" is Linux's internal ID.
*/
pen_release = cpu_logical_map(cpu);
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
/*
* Send the secondary CPU SEV, thereby causing the boot monitor to read
* the JUMPADDR and WAKEMAGIC, and branch to the address found there.
*/
dsb_sev();
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
smp_rmb();
if (pen_release == -1)
break;
udelay(10);
}
/*
* now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
*/
spin_unlock(&boot_lock);
return pen_release != -1 ? -ENOSYS : 0;
}
static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus)
{
scu_enable(scu_base);
}
struct smp_operations sirfsoc_smp_ops __initdata = {
.smp_prepare_cpus = sirfsoc_smp_prepare_cpus,
.smp_secondary_init = sirfsoc_secondary_init,
.smp_boot_secondary = sirfsoc_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = sirfsoc_cpu_die,
#endif
};