linux/arch/arm/mach-omap2/omap-smp.c
<<
>>
Prefs
   1/*
   2 * OMAP4 SMP source file. It contains platform specific functions
   3 * needed for the linux smp kernel.
   4 *
   5 * Copyright (C) 2009 Texas Instruments, Inc.
   6 *
   7 * Author:
   8 *      Santosh Shilimkar <santosh.shilimkar@ti.com>
   9 *
  10 * Platform file needed for the OMAP4 SMP. This file is based on arm
  11 * realview smp platform.
  12 * * Copyright (c) 2002 ARM Limited.
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License version 2 as
  16 * published by the Free Software Foundation.
  17 */
  18#include <linux/init.h>
  19#include <linux/device.h>
  20#include <linux/smp.h>
  21#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
  38#define CPU_MASK                0xff0ffff0
  39#define CPU_CORTEX_A9           0x410FC090
  40#define CPU_CORTEX_A15          0x410FC0F0
  41
  42#define OMAP5_CORE_COUNT        0x2
  43
  44#define AUX_CORE_BOOT0_GP_RELEASE       0x020
  45#define AUX_CORE_BOOT0_HS_RELEASE       0x200
  46
  47struct omap_smp_config {
  48        unsigned long cpu1_rstctrl_pa;
  49        void __iomem *cpu1_rstctrl_va;
  50        void __iomem *scu_base;
  51        void __iomem *wakeupgen_base;
  52        void *startup_addr;
  53};
  54
  55static struct omap_smp_config cfg;
  56
  57static const struct omap_smp_config omap443x_cfg __initconst = {
  58        .cpu1_rstctrl_pa = 0x4824380c,
  59        .startup_addr = omap4_secondary_startup,
  60};
  61
  62static const struct omap_smp_config omap446x_cfg __initconst = {
  63        .cpu1_rstctrl_pa = 0x4824380c,
  64        .startup_addr = omap4460_secondary_startup,
  65};
  66
  67static const struct omap_smp_config omap5_cfg __initconst = {
  68        .cpu1_rstctrl_pa = 0x48243810,
  69        .startup_addr = omap5_secondary_startup,
  70};
  71
  72static DEFINE_SPINLOCK(boot_lock);
  73
  74void __iomem *omap4_get_scu_base(void)
  75{
  76        return cfg.scu_base;
  77}
  78
  79#ifdef CONFIG_OMAP5_ERRATA_801819
  80void omap5_erratum_workaround_801819(void)
  81{
  82        u32 acr, revidr;
  83        u32 acr_mask;
  84
  85        /* REVIDR[3] indicates erratum fix available on silicon */
  86        asm volatile ("mrc p15, 0, %0, c0, c0, 6" : "=r" (revidr));
  87        if (revidr & (0x1 << 3))
  88                return;
  89
  90        asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr));
  91        /*
  92         * BIT(27) - Disables streaming. All write-allocate lines allocate in
  93         * the L1 or L2 cache.
  94         * BIT(25) - Disables streaming. All write-allocate lines allocate in
  95         * the L1 cache.
  96         */
  97        acr_mask = (0x3 << 25) | (0x3 << 27);
  98        /* do we already have it done.. if yes, skip expensive smc */
  99        if ((acr & acr_mask) == acr_mask)
 100                return;
 101
 102        acr |= acr_mask;
 103        omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr);
 104
 105        pr_debug("%s: ARM erratum workaround 801819 applied on CPU%d\n",
 106                 __func__, smp_processor_id());
 107}
 108#else
 109static inline void omap5_erratum_workaround_801819(void) { }
 110#endif
 111
 112static void omap4_secondary_init(unsigned int cpu)
 113{
 114        /*
 115         * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device.
 116         * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA
 117         * init and for CPU1, a secure PPA API provided. CPU0 must be ON
 118         * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+.
 119         * OMAP443X GP devices- SMP bit isn't accessible.
 120         * OMAP446X GP devices - SMP bit access is enabled on both CPUs.
 121         */
 122        if (soc_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP))
 123                omap_secure_dispatcher(OMAP4_PPA_CPU_ACTRL_SMP_INDEX,
 124                                                        4, 0, 0, 0, 0, 0);
 125
 126        if (soc_is_omap54xx() || soc_is_dra7xx()) {
 127                /*
 128                 * Configure the CNTFRQ register for the secondary cpu's which
 129                 * indicates the frequency of the cpu local timers.
 130                 */
 131                set_cntfreq();
 132                /* Configure ACR to disable streaming WA for 801819 */
 133                omap5_erratum_workaround_801819();
 134        }
 135
 136        /*
 137         * Synchronise with the boot thread.
 138         */
 139        spin_lock(&boot_lock);
 140        spin_unlock(&boot_lock);
 141}
 142
 143static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
 144{
 145        static struct clockdomain *cpu1_clkdm;
 146        static bool booted;
 147        static struct powerdomain *cpu1_pwrdm;
 148
 149        /*
 150         * Set synchronisation state between this boot processor
 151         * and the secondary one
 152         */
 153        spin_lock(&boot_lock);
 154
 155        /*
 156         * Update the AuxCoreBoot0 with boot state for secondary core.
 157         * omap4_secondary_startup() routine will hold the secondary core till
 158         * the AuxCoreBoot1 register is updated with cpu state
 159         * A barrier is added to ensure that write buffer is drained
 160         */
 161        if (omap_secure_apis_support())
 162                omap_modify_auxcoreboot0(AUX_CORE_BOOT0_HS_RELEASE,
 163                                         0xfffffdff);
 164        else
 165                writel_relaxed(AUX_CORE_BOOT0_GP_RELEASE,
 166                               cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
 167
 168        if (!cpu1_clkdm && !cpu1_pwrdm) {
 169                cpu1_clkdm = clkdm_lookup("mpu1_clkdm");
 170                cpu1_pwrdm = pwrdm_lookup("cpu1_pwrdm");
 171        }
 172
 173        /*
 174         * The SGI(Software Generated Interrupts) are not wakeup capable
 175         * from low power states. This is known limitation on OMAP4 and
 176         * needs to be worked around by using software forced clockdomain
 177         * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to
 178         * software force wakeup. The clockdomain is then put back to
 179         * hardware supervised mode.
 180         * More details can be found in OMAP4430 TRM - Version J
 181         * Section :
 182         *      4.3.4.2 Power States of CPU0 and CPU1
 183         */
 184        if (booted && cpu1_pwrdm && cpu1_clkdm) {
 185                /*
 186                 * GIC distributor control register has changed between
 187                 * CortexA9 r1pX and r2pX. The Control Register secure
 188                 * banked version is now composed of 2 bits:
 189                 * bit 0 == Secure Enable
 190                 * bit 1 == Non-Secure Enable
 191                 * The Non-Secure banked register has not changed
 192                 * Because the ROM Code is based on the r1pX GIC, the CPU1
 193                 * GIC restoration will cause a problem to CPU0 Non-Secure SW.
 194                 * The workaround must be:
 195                 * 1) Before doing the CPU1 wakeup, CPU0 must disable
 196                 * the GIC distributor
 197                 * 2) CPU1 must re-enable the GIC distributor on
 198                 * it's wakeup path.
 199                 */
 200                if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
 201                        local_irq_disable();
 202                        gic_dist_disable();
 203                }
 204
 205                /*
 206                 * Ensure that CPU power state is set to ON to avoid CPU
 207                 * powerdomain transition on wfi
 208                 */
 209                clkdm_deny_idle_nolock(cpu1_clkdm);
 210                pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON);
 211                clkdm_allow_idle_nolock(cpu1_clkdm);
 212
 213                if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
 214                        while (gic_dist_disabled()) {
 215                                udelay(1);
 216                                cpu_relax();
 217                        }
 218                        gic_timer_retrigger();
 219                        local_irq_enable();
 220                }
 221        } else {
 222                dsb_sev();
 223                booted = true;
 224        }
 225
 226        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 227
 228        /*
 229         * Now the secondary core is starting up let it run its
 230         * calibrations, then wait for it to finish
 231         */
 232        spin_unlock(&boot_lock);
 233
 234        return 0;
 235}
 236
 237/*
 238 * Initialise the CPU possible map early - this describes the CPUs
 239 * which may be present or become present in the system.
 240 */
 241static void __init omap4_smp_init_cpus(void)
 242{
 243        unsigned int i = 0, ncores = 1, cpu_id;
 244
 245        /* Use ARM cpuid check here, as SoC detection will not work so early */
 246        cpu_id = read_cpuid_id() & CPU_MASK;
 247        if (cpu_id == CPU_CORTEX_A9) {
 248                /*
 249                 * Currently we can't call ioremap here because
 250                 * SoC detection won't work until after init_early.
 251                 */
 252                cfg.scu_base =  OMAP2_L4_IO_ADDRESS(scu_a9_get_base());
 253                BUG_ON(!cfg.scu_base);
 254                ncores = scu_get_core_count(cfg.scu_base);
 255        } else if (cpu_id == CPU_CORTEX_A15) {
 256                ncores = OMAP5_CORE_COUNT;
 257        }
 258
 259        /* sanity check */
 260        if (ncores > nr_cpu_ids) {
 261                pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
 262                        ncores, nr_cpu_ids);
 263                ncores = nr_cpu_ids;
 264        }
 265
 266        for (i = 0; i < ncores; i++)
 267                set_cpu_possible(i, true);
 268}
 269
 270/*
 271 * For now, just make sure the start-up address is not within the booting
 272 * kernel space as that means we just overwrote whatever secondary_startup()
 273 * code there was.
 274 */
 275static bool __init omap4_smp_cpu1_startup_valid(unsigned long addr)
 276{
 277        if ((addr >= __pa(PAGE_OFFSET)) && (addr <= __pa(__bss_start)))
 278                return false;
 279
 280        return true;
 281}
 282
 283/*
 284 * We may need to reset CPU1 before configuring, otherwise kexec boot can end
 285 * up trying to use old kernel startup address or suspend-resume will
 286 * occasionally fail to bring up CPU1 on 4430 if CPU1 fails to enter deeper
 287 * idle states.
 288 */
 289static void __init omap4_smp_maybe_reset_cpu1(struct omap_smp_config *c)
 290{
 291        unsigned long cpu1_startup_pa, cpu1_ns_pa_addr;
 292        bool needs_reset = false;
 293        u32 released;
 294
 295        if (omap_secure_apis_support())
 296                released = omap_read_auxcoreboot0() & AUX_CORE_BOOT0_HS_RELEASE;
 297        else
 298                released = readl_relaxed(cfg.wakeupgen_base +
 299                                         OMAP_AUX_CORE_BOOT_0) &
 300                                                AUX_CORE_BOOT0_GP_RELEASE;
 301        if (released) {
 302                pr_warn("smp: CPU1 not parked?\n");
 303
 304                return;
 305        }
 306
 307        cpu1_startup_pa = readl_relaxed(cfg.wakeupgen_base +
 308                                        OMAP_AUX_CORE_BOOT_1);
 309
 310        /* Did the configured secondary_startup() get overwritten? */
 311        if (!omap4_smp_cpu1_startup_valid(cpu1_startup_pa))
 312                needs_reset = true;
 313
 314        /*
 315         * If omap4 or 5 has NS_PA_ADDR configured, CPU1 may be in a
 316         * deeper idle state in WFI and will wake to an invalid address.
 317         */
 318        if ((soc_is_omap44xx() || soc_is_omap54xx())) {
 319                cpu1_ns_pa_addr = omap4_get_cpu1_ns_pa_addr();
 320                if (!omap4_smp_cpu1_startup_valid(cpu1_ns_pa_addr))
 321                        needs_reset = true;
 322        } else {
 323                cpu1_ns_pa_addr = 0;
 324        }
 325
 326        if (!needs_reset || !c->cpu1_rstctrl_va)
 327                return;
 328
 329        pr_info("smp: CPU1 parked within kernel, needs reset (0x%lx 0x%lx)\n",
 330                cpu1_startup_pa, cpu1_ns_pa_addr);
 331
 332        writel_relaxed(1, c->cpu1_rstctrl_va);
 333        readl_relaxed(c->cpu1_rstctrl_va);
 334        writel_relaxed(0, c->cpu1_rstctrl_va);
 335}
 336
 337static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
 338{
 339        const struct omap_smp_config *c = NULL;
 340
 341        if (soc_is_omap443x())
 342                c = &omap443x_cfg;
 343        else if (soc_is_omap446x())
 344                c = &omap446x_cfg;
 345        else if (soc_is_dra74x() || soc_is_omap54xx() || soc_is_dra76x())
 346                c = &omap5_cfg;
 347
 348        if (!c) {
 349                pr_err("%s Unknown SMP SoC?\n", __func__);
 350                return;
 351        }
 352
 353        /* Must preserve cfg.scu_base set earlier */
 354        cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa;
 355        cfg.startup_addr = c->startup_addr;
 356        cfg.wakeupgen_base = omap_get_wakeupgen_base();
 357
 358        if (soc_is_dra74x() || soc_is_omap54xx() || soc_is_dra76x()) {
 359                if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
 360                        cfg.startup_addr = omap5_secondary_hyp_startup;
 361                omap5_erratum_workaround_801819();
 362        }
 363
 364        cfg.cpu1_rstctrl_va = ioremap(cfg.cpu1_rstctrl_pa, 4);
 365        if (!cfg.cpu1_rstctrl_va)
 366                return;
 367
 368        /*
 369         * Initialise the SCU and wake up the secondary core using
 370         * wakeup_secondary().
 371         */
 372        if (cfg.scu_base)
 373                scu_enable(cfg.scu_base);
 374
 375        omap4_smp_maybe_reset_cpu1(&cfg);
 376
 377        /*
 378         * Write the address of secondary startup routine into the
 379         * AuxCoreBoot1 where ROM code will jump and start executing
 380         * on secondary core once out of WFE
 381         * A barrier is added to ensure that write buffer is drained
 382         */
 383        if (omap_secure_apis_support())
 384                omap_auxcoreboot_addr(__pa_symbol(cfg.startup_addr));
 385        else
 386                writel_relaxed(__pa_symbol(cfg.startup_addr),
 387                               cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_1);
 388}
 389
 390const struct smp_operations omap4_smp_ops __initconst = {
 391        .smp_init_cpus          = omap4_smp_init_cpus,
 392        .smp_prepare_cpus       = omap4_smp_prepare_cpus,
 393        .smp_secondary_init     = omap4_secondary_init,
 394        .smp_boot_secondary     = omap4_boot_secondary,
 395#ifdef CONFIG_HOTPLUG_CPU
 396        .cpu_die                = omap4_cpu_die,
 397        .cpu_kill               = omap4_cpu_kill,
 398#endif
 399};
 400