linux/arch/arm/mach-shmobile/smp-sh73a0.c
<<
>>
Prefs
   1/*
   2 * SMP support for R-Mobile / SH-Mobile - sh73a0 portion
   3 *
   4 * Copyright (C) 2010  Magnus Damm
   5 * Copyright (C) 2010  Takashi Yoshii
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; version 2 of the License.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  19 */
  20#include <linux/kernel.h>
  21#include <linux/init.h>
  22#include <linux/smp.h>
  23#include <linux/spinlock.h>
  24#include <linux/io.h>
  25#include <linux/delay.h>
  26#include <mach/common.h>
  27#include <asm/cacheflush.h>
  28#include <asm/smp_plat.h>
  29#include <mach/sh73a0.h>
  30#include <asm/smp_scu.h>
  31#include <asm/smp_twd.h>
  32
  33#define WUPCR           IOMEM(0xe6151010)
  34#define SRESCR          IOMEM(0xe6151018)
  35#define PSTR            IOMEM(0xe6151040)
  36#define SBAR            IOMEM(0xe6180020)
  37#define APARMBAREA      IOMEM(0xe6f10020)
  38
  39#define PSTR_SHUTDOWN_MODE      3
  40
  41#define SH73A0_SCU_BASE 0xf0000000
  42
  43#ifdef CONFIG_HAVE_ARM_TWD
  44static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, SH73A0_SCU_BASE + 0x600, 29);
  45void __init sh73a0_register_twd(void)
  46{
  47        twd_local_timer_register(&twd_local_timer);
  48}
  49#endif
  50
  51static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle)
  52{
  53        cpu = cpu_logical_map(cpu);
  54
  55        if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3)
  56                __raw_writel(1 << cpu, WUPCR);  /* wake up */
  57        else
  58                __raw_writel(1 << cpu, SRESCR); /* reset */
  59
  60        return 0;
  61}
  62
  63static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus)
  64{
  65        scu_enable(shmobile_scu_base);
  66
  67        /* Map the reset vector (in headsmp-scu.S) */
  68        __raw_writel(0, APARMBAREA);      /* 4k */
  69        __raw_writel(__pa(shmobile_secondary_vector_scu), SBAR);
  70
  71        /* enable cache coherency on booting CPU */
  72        scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);
  73}
  74
  75static void __init sh73a0_smp_init_cpus(void)
  76{
  77        /* setup sh73a0 specific SCU base */
  78        shmobile_scu_base = IOMEM(SH73A0_SCU_BASE);
  79
  80        shmobile_smp_init_cpus(scu_get_core_count(shmobile_scu_base));
  81}
  82
  83#ifdef CONFIG_HOTPLUG_CPU
  84static int sh73a0_cpu_kill(unsigned int cpu)
  85{
  86
  87        int k;
  88        u32 pstr;
  89
  90        /*
  91         * wait until the power status register confirms the shutdown of the
  92         * offline target
  93         */
  94        for (k = 0; k < 1000; k++) {
  95                pstr = (__raw_readl(PSTR) >> (4 * cpu)) & 3;
  96                if (pstr == PSTR_SHUTDOWN_MODE)
  97                        return 1;
  98
  99                mdelay(1);
 100        }
 101
 102        return 0;
 103}
 104
 105static void sh73a0_cpu_die(unsigned int cpu)
 106{
 107        /* Set power off mode. This takes the CPU out of the MP cluster */
 108        scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF);
 109
 110        /* Enter shutdown mode */
 111        cpu_do_idle();
 112}
 113
 114static int sh73a0_cpu_disable(unsigned int cpu)
 115{
 116        return 0; /* CPU0 and CPU1 supported */
 117}
 118#endif /* CONFIG_HOTPLUG_CPU */
 119
 120struct smp_operations sh73a0_smp_ops __initdata = {
 121        .smp_init_cpus          = sh73a0_smp_init_cpus,
 122        .smp_prepare_cpus       = sh73a0_smp_prepare_cpus,
 123        .smp_boot_secondary     = sh73a0_boot_secondary,
 124#ifdef CONFIG_HOTPLUG_CPU
 125        .cpu_kill               = sh73a0_cpu_kill,
 126        .cpu_die                = sh73a0_cpu_die,
 127        .cpu_disable            = sh73a0_cpu_disable,
 128#endif
 129};
 130