1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/*
* R-Car Generation 2 Power management support
*
* Copyright (C) 2013 - 2015 Renesas Electronics Corporation
* Copyright (C) 2011 Renesas Solutions Corp.
* Copyright (C) 2011 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/smp.h>
#include <asm/io.h>
#include <asm/cputype.h>
#include "common.h"
#include "rcar-gen2.h"
/* RST */
#define RST 0xe6160000
#define CA15BAR 0x0020 /* CA15 Boot Address Register */
#define CA7BAR 0x0030 /* CA7 Boot Address Register */
#define CA15RESCNT 0x0040 /* CA15 Reset Control Register */
#define CA7RESCNT 0x0044 /* CA7 Reset Control Register */
/* SYS Boot Address Register */
#define SBAR_BAREN BIT(4) /* SBAR is valid */
/* Reset Control Registers */
#define CA15RESCNT_CODE 0xa5a50000
#define CA15RESCNT_CPUS 0xf /* CPU0-3 */
#define CA7RESCNT_CODE 0x5a5a0000
#define CA7RESCNT_CPUS 0xf /* CPU0-3 */
/* On-chip RAM */
#define ICRAM1 0xe63c0000 /* Inter Connect RAM1 (4 KiB) */
static inline u32 phys_to_sbar(phys_addr_t addr)
{
return (addr >> 8) & 0xfffffc00;
}
void __init rcar_gen2_pm_init(void)
{
void __iomem *p;
u32 bar;
static int once;
struct device_node *np;
bool has_a7 = false;
bool has_a15 = false;
struct resource res;
int error;
if (once++)
return;
for_each_of_cpu_node(np) {
if (of_device_is_compatible(np, "arm,cortex-a15"))
has_a15 = true;
else if (of_device_is_compatible(np, "arm,cortex-a7"))
has_a7 = true;
}
np = of_find_compatible_node(NULL, NULL, "renesas,smp-sram");
if (!np) {
/* No smp-sram in DT, fall back to hardcoded address */
res = (struct resource)DEFINE_RES_MEM(ICRAM1,
shmobile_boot_size);
goto map;
}
error = of_address_to_resource(np, 0, &res);
if (error) {
pr_err("Failed to get smp-sram address: %d\n", error);
return;
}
map:
/* RAM for jump stub, because BAR requires 256KB aligned address */
if (res.start & (256 * 1024 - 1) ||
resource_size(&res) < shmobile_boot_size) {
pr_err("Invalid smp-sram region\n");
return;
}
p = ioremap(res.start, resource_size(&res));
if (!p)
return;
/*
* install the reset vector, use the largest version if we have enough
* memory available
*/
if (resource_size(&res) >= shmobile_boot_size_gen2) {
shmobile_boot_cpu_gen2 = read_cpuid_mpidr();
memcpy_toio(p, shmobile_boot_vector_gen2,
shmobile_boot_size_gen2);
} else {
memcpy_toio(p, shmobile_boot_vector, shmobile_boot_size);
}
iounmap(p);
/* setup reset vectors */
p = ioremap_nocache(RST, 0x63);
bar = phys_to_sbar(res.start);
if (has_a15) {
writel_relaxed(bar, p + CA15BAR);
writel_relaxed(bar | SBAR_BAREN, p + CA15BAR);
/* de-assert reset for CA15 CPUs */
writel_relaxed((readl_relaxed(p + CA15RESCNT) &
~CA15RESCNT_CPUS) | CA15RESCNT_CODE,
p + CA15RESCNT);
}
if (has_a7) {
writel_relaxed(bar, p + CA7BAR);
writel_relaxed(bar | SBAR_BAREN, p + CA7BAR);
/* de-assert reset for CA7 CPUs */
writel_relaxed((readl_relaxed(p + CA7RESCNT) &
~CA7RESCNT_CPUS) | CA7RESCNT_CODE,
p + CA7RESCNT);
}
iounmap(p);
shmobile_smp_apmu_suspend_init();
}
|