blob: cb7dd40e0d3b29ed580c827b9f4c85b40ed64101 [file] [log] [blame]
Russell Kinga8cbcd92009-05-16 11:51:14 +01001/*
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_scu.h>
Catalin Marinasaf731102009-05-18 16:26:27 +010015#include <asm/cacheflush.h>
Will Deacon85fd3232011-09-15 11:45:15 +010016#include <asm/cputype.h>
Russell Kinga8cbcd92009-05-16 11:51:14 +010017
18#define SCU_CTRL 0x00
19#define SCU_CONFIG 0x04
20#define SCU_CPU_STATUS 0x08
21#define SCU_INVALIDATE 0x0c
22#define SCU_FPGA_REVISION 0x10
23
24/*
25 * Get the number of CPU cores from the SCU configuration
26 */
27unsigned int __init scu_get_core_count(void __iomem *scu_base)
28{
29 unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);
30 return (ncores & 0x03) + 1;
31}
32
33/*
34 * Enable the SCU
35 */
36void __init scu_enable(void __iomem *scu_base)
37{
38 u32 scu_ctrl;
39
Will Deacon85fd3232011-09-15 11:45:15 +010040#ifdef CONFIG_ARM_ERRATA_764369
41 /* Cortex-A9 only */
42 if ((read_cpuid(CPUID_ID) & 0xff0ffff0) == 0x410fc090) {
43 scu_ctrl = __raw_readl(scu_base + 0x30);
44 if (!(scu_ctrl & 1))
45 __raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
46 }
47#endif
48
Russell Kinga8cbcd92009-05-16 11:51:14 +010049 scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
Catalin Marinas9b229fa2009-11-04 12:16:38 +000050 /* already enabled? */
51 if (scu_ctrl & 1)
52 return;
53
Russell Kinga8cbcd92009-05-16 11:51:14 +010054 scu_ctrl |= 1;
55 __raw_writel(scu_ctrl, scu_base + SCU_CTRL);
Catalin Marinasaf731102009-05-18 16:26:27 +010056
57 /*
58 * Ensure that the data accessed by CPU0 before the SCU was
59 * initialised is visible to the other CPUs.
60 */
61 flush_cache_all();
Russell Kinga8cbcd92009-05-16 11:51:14 +010062}
Russell King292ec422011-02-04 10:36:39 +000063
64/*
65 * Set the executing CPUs power mode as defined. This will be in
66 * preparation for it executing a WFI instruction.
67 *
68 * This function must be called with preemption disabled, and as it
69 * has the side effect of disabling coherency, caches must have been
70 * flushed. Interrupts must also have been disabled.
71 */
72int scu_power_mode(void __iomem *scu_base, unsigned int mode)
73{
74 unsigned int val;
75 int cpu = smp_processor_id();
76
77 if (mode > 3 || mode == 1 || cpu > 3)
78 return -EINVAL;
79
80 val = __raw_readb(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;
81 val |= mode;
82 __raw_writeb(val, scu_base + SCU_CPU_STATUS + cpu);
83
84 return 0;
85}