Skip to content

Commit

Permalink
Merge branch 'msm-smp' of git://codeaurora.org/quic/kernel/davidb/lin…
Browse files Browse the repository at this point in the history
…ux-msm

* 'msm-smp' of git://codeaurora.org/quic/kernel/davidb/linux-msm:
  msm: add SMP support for msm
  msm: hotplug: support cpu hotplug on msm
  msm: timer: SMP timer support for msm
  msm: scm-boot: Support for setting cold/warm boot addresses
  msm: Secure Channel Manager (SCM) support
  • Loading branch information
Linus Torvalds committed Jan 10, 2011
2 parents e0e736f + e14411d commit abf8792
Show file tree
Hide file tree
Showing 12 changed files with 819 additions and 24 deletions.
5 changes: 5 additions & 0 deletions arch/arm/mach-msm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ config ARCH_MSM8X60
bool "MSM8X60"
select MACH_MSM8X60_SURF if (!MACH_MSM8X60_RUMI3 && !MACH_MSM8X60_SIM \
&& !MACH_MSM8X60_FFA)
select ARCH_MSM_SCORPIONMP
select ARM_GIC
select CPU_V7
select MSM_V2_TLMM
select MSM_GPIOMUX
select IOMMU_API
select MSM_SCM if SMP

endchoice

Expand Down Expand Up @@ -172,4 +174,7 @@ config MSM_V2_TLMM

config IOMMU_API
bool

config MSM_SCM
bool
endif
4 changes: 4 additions & 0 deletions arch/arm/mach-msm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ obj-$(CONFIG_MSM_PROC_COMM) += clock.o
obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
obj-$(CONFIG_MSM_SMD) += last_radio_log.o
obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o

obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_SMP) += headsmp.o platsmp.o

obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o
obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o
Expand Down
40 changes: 40 additions & 0 deletions arch/arm/mach-msm/headsmp.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* linux/arch/arm/mach-realview/headsmp.S
*
* Copyright (c) 2003 ARM Limited
* All Rights Reserved
*
* 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/linkage.h>
#include <linux/init.h>

__INIT

/*
* MSM specific entry point for secondary CPUs. This provides
* a "holding pen" into which all secondary cores are held until we're
* ready for them to initialise.
*/
ENTRY(msm_secondary_startup)
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #15
adr r4, 1f
ldmia r4, {r5, r6}
sub r4, r4, r5
add r6, r6, r4
pen: ldr r7, [r6]
cmp r7, r0
bne pen

/*
* we've been released from the holding pen: secondary_stack
* should now contain the SVC stack for this core
*/
b secondary_startup

.align
1: .long .
.long pen_release
91 changes: 91 additions & 0 deletions arch/arm/mach-msm/hotplug.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
*
* 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/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>

#include <asm/cacheflush.h>

extern volatile int pen_release;

static inline void cpu_enter_lowpower(void)
{
/* Just flush the cache. Changing the coherency is not yet
* available on msm. */
flush_cache_all();
}

static inline void cpu_leave_lowpower(void)
{
}

static inline void platform_do_lowpower(unsigned int cpu)
{
/* Just enter wfi for now. TODO: Properly shut off the cpu. */
for (;;) {
/*
* here's the WFI
*/
asm("wfi"
:
:
: "memory", "cc");

if (pen_release == cpu) {
/*
* OK, proper wakeup, we're done
*/
break;
}

/*
* getting here, means that we have come out of WFI without
* having been woken up - this shouldn't happen
*
* The trouble is, letting people know about this is not really
* possible, since we are currently running incoherently, and
* therefore cannot safely call printk() or anything else
*/
pr_debug("CPU%u: spurious wakeup call\n", cpu);
}
}

int platform_cpu_kill(unsigned int cpu)
{
return 1;
}

/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
*/
void platform_cpu_die(unsigned int cpu)
{
/*
* we're ready for shutdown now, so do it
*/
cpu_enter_lowpower();
platform_do_lowpower(cpu);

/*
* bring this CPU back into the world of cache
* coherency, and then restore interrupts
*/
cpu_leave_lowpower();
}

int platform_cpu_disable(unsigned int cpu)
{
/*
* we don't allow CPU 0 to be shutdown (it is still too special
* e.g. clock tick interrupts)
*/
return cpu == 0 ? -EPERM : 0;
}
6 changes: 5 additions & 1 deletion arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@

#define MSM_TMR_BASE IOMEM(0xF0200000)
#define MSM_TMR_PHYS 0x02000000
#define MSM_TMR_SIZE (SZ_1M)
#define MSM_TMR_SIZE SZ_4K

#define MSM_TMR0_BASE IOMEM(0xF0201000)
#define MSM_TMR0_PHYS 0x02040000
#define MSM_TMR0_SIZE SZ_4K

#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-msm/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static struct map_desc msm8x60_io_desc[] __initdata = {
MSM_DEVICE(QGIC_DIST),
MSM_DEVICE(QGIC_CPU),
MSM_DEVICE(TMR),
MSM_DEVICE(TMR0),
MSM_DEVICE(ACC),
MSM_DEVICE(GCC),
};
Expand Down
166 changes: 166 additions & 0 deletions arch/arm/mach-msm/platsmp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* 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/errno.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>

#include <asm/hardware/gic.h>
#include <asm/cacheflush.h>
#include <asm/mach-types.h>

#include <mach/msm_iomap.h>

#include "scm-boot.h"

#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0
#define SCSS_CPU1CORE_RESET 0xD80
#define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64

/* Mask for edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
#define GIC_PPI_EDGE_MASK 0xFFFFD7FF

extern void msm_secondary_startup(void);
/*
* control for which core is the next to come out of the secondary
* boot "holding pen".
*/
volatile int pen_release = -1;

static DEFINE_SPINLOCK(boot_lock);

void __cpuinit platform_secondary_init(unsigned int cpu)
{
/* Configure edge-triggered PPIs */
writel(GIC_PPI_EDGE_MASK, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);

/*
* if any interrupts are already enabled for the primary
* core (e.g. timer irq), then they will not have been enabled
* for us: do so
*/
gic_secondary_init(0);

/*
* 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 __cpuinit void prepare_cold_cpu(unsigned int cpu)
{
int ret;
ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup),
SCM_FLAG_COLDBOOT_CPU1);
if (ret == 0) {
void *sc1_base_ptr;
sc1_base_ptr = ioremap_nocache(0x00902000, SZ_4K*2);
if (sc1_base_ptr) {
writel(0, sc1_base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
writel(0, sc1_base_ptr + SCSS_CPU1CORE_RESET);
writel(3, sc1_base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP);
iounmap(sc1_base_ptr);
}
} else
printk(KERN_DEBUG "Failed to set secondary core boot "
"address\n");
}

int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
static int cold_boot_done;

/* Only need to bring cpu out of reset this way once */
if (cold_boot_done == false) {
prepare_cold_cpu(cpu);
cold_boot_done = true;
}

/*
* set synchronisation state between this boot processor
* and the secondary one
*/
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;
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));

/*
* Send the secondary CPU a soft interrupt, thereby causing
* the boot monitor to read the system wide flags register,
* and branch to the address found there.
*/
smp_cross_call(cpumask_of(cpu), 1);

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;
}

/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system. The msm8x60
* does not support the ARM SCU, so just set the possible cpu mask to
* NR_CPUS.
*/
void __init smp_init_cpus(void)
{
unsigned int i;

for (i = 0; i < NR_CPUS; i++)
set_cpu_possible(i, true);
}

void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
int i;

/*
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time.
*/
for (i = 0; i < max_cpus; i++)
set_cpu_present(i, true);
}
39 changes: 39 additions & 0 deletions arch/arm/mach-msm/scm-boot.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

#include <linux/module.h>
#include <linux/slab.h>

#include "scm.h"
#include "scm-boot.h"

/*
* Set the cold/warm boot address for one of the CPU cores.
*/
int scm_set_boot_addr(phys_addr_t addr, int flags)
{
struct {
unsigned int flags;
phys_addr_t addr;
} cmd;

cmd.addr = addr;
cmd.flags = flags;
return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR,
&cmd, sizeof(cmd), NULL, 0);
}
EXPORT_SYMBOL(scm_set_boot_addr);
Loading

0 comments on commit abf8792

Please sign in to comment.