linux/arch/arm/kernel/smp_scu.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/smp_scu.c
   3 *
   4 *  Copyright (C) 2002 ARM Ltd.
   5 *  All Rights Reserved
   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 version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#include <linux/init.h>
  12#include <linux/io.h>
  13
  14#include <asm/smp_plat.h>
  15#include <asm/smp_scu.h>
  16#include <asm/cacheflush.h>
  17#include <asm/cputype.h>
  18
  19#define SCU_CTRL                0x00
  20#define SCU_ENABLE              (1 << 0)
  21#define SCU_STANDBY_ENABLE      (1 << 5)
  22#define SCU_CONFIG              0x04
  23#define SCU_CPU_STATUS          0x08
  24#define SCU_INVALIDATE          0x0c
  25#define SCU_FPGA_REVISION       0x10
  26
  27#ifdef CONFIG_SMP
  28/*
  29 * Get the number of CPU cores from the SCU configuration
  30 */
  31unsigned int __init scu_get_core_count(void __iomem *scu_base)
  32{
  33        unsigned int ncores = readl_relaxed(scu_base + SCU_CONFIG);
  34        return (ncores & 0x03) + 1;
  35}
  36
  37/*
  38 * Enable the SCU
  39 */
  40void scu_enable(void __iomem *scu_base)
  41{
  42        u32 scu_ctrl;
  43
  44#ifdef CONFIG_ARM_ERRATA_764369
  45        /* Cortex-A9 only */
  46        if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090) {
  47                scu_ctrl = readl_relaxed(scu_base + 0x30);
  48                if (!(scu_ctrl & 1))
  49                        writel_relaxed(scu_ctrl | 0x1, scu_base + 0x30);
  50        }
  51#endif
  52
  53        scu_ctrl = readl_relaxed(scu_base + SCU_CTRL);
  54        /* already enabled? */
  55        if (scu_ctrl & SCU_ENABLE)
  56                return;
  57
  58        scu_ctrl |= SCU_ENABLE;
  59
  60        /* Cortex-A9 earlier than r2p0 has no standby bit in SCU */
  61        if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090 &&
  62            (read_cpuid_id() & 0x00f0000f) >= 0x00200000)
  63                scu_ctrl |= SCU_STANDBY_ENABLE;
  64
  65        writel_relaxed(scu_ctrl, scu_base + SCU_CTRL);
  66
  67        /*
  68         * Ensure that the data accessed by CPU0 before the SCU was
  69         * initialised is visible to the other CPUs.
  70         */
  71        flush_cache_all();
  72}
  73#endif
  74
  75/*
  76 * Set the executing CPUs power mode as defined.  This will be in
  77 * preparation for it executing a WFI instruction.
  78 *
  79 * This function must be called with preemption disabled, and as it
  80 * has the side effect of disabling coherency, caches must have been
  81 * flushed.  Interrupts must also have been disabled.
  82 */
  83int scu_power_mode(void __iomem *scu_base, unsigned int mode)
  84{
  85        unsigned int val;
  86        int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
  87
  88        if (mode > 3 || mode == 1 || cpu > 3)
  89                return -EINVAL;
  90
  91        val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;
  92        val |= mode;
  93        writeb_relaxed(val, scu_base + SCU_CPU_STATUS + cpu);
  94
  95        return 0;
  96}
  97