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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Andes Technology Corporation
* Rick Chen, Andes Technology Corporation <rick@andestech.com>
*/
#include <command.h>
#include <cache.h>
#include <dm.h>
#include <hang.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <dm/ofnode.h>
#include <linux/bitops.h>
struct l2cache {
volatile u64 configure;
volatile u64 control;
volatile u64 hpm0;
volatile u64 hpm1;
volatile u64 hpm2;
volatile u64 hpm3;
volatile u64 error_status;
volatile u64 ecc_error;
volatile u64 cctl_command0;
volatile u64 cctl_access_line0;
volatile u64 cctl_command1;
volatile u64 cctl_access_line1;
volatile u64 cctl_command2;
volatile u64 cctl_access_line2;
volatile u64 cctl_command3;
volatile u64 cctl_access_line3;
volatile u64 cctl_status;
};
/* Configuration register */
#define MEM_MAP_OFF 20
#define MEM_MAP_MSK BIT(MEM_MAP_OFF)
/* offset of v0 memory map (Gen1) */
static u32 cmd_stride = 0x10;
static u32 status_stride = 0x0;
static u32 status_bit_offset = 0x4;
/* Control Register */
#define L2_ENABLE 0x1
/* prefetch */
#define IPREPETCH_OFF 3
#define DPREPETCH_OFF 5
#define IPREPETCH_MSK (3 << IPREPETCH_OFF)
#define DPREPETCH_MSK (3 << DPREPETCH_OFF)
/* tag ram */
#define TRAMOCTL_OFF 8
#define TRAMICTL_OFF 10
#define TRAMOCTL_MSK (3 << TRAMOCTL_OFF)
#define TRAMICTL_MSK BIT(TRAMICTL_OFF)
/* data ram */
#define DRAMOCTL_OFF 11
#define DRAMICTL_OFF 13
#define DRAMOCTL_MSK (3 << DRAMOCTL_OFF)
#define DRAMICTL_MSK BIT(DRAMICTL_OFF)
/* CCTL Command Register */
#define CCTL_CMD_REG(base, hart) ((ulong)(base) + 0x40 + (hart) * (cmd_stride))
#define L2_WBINVAL_ALL 0x12
/* CCTL Status Register */
#define CCTL_STATUS_REG(base, hart) ((ulong)(base) + 0x80 + (hart) * (status_stride))
#define CCTL_STATUS_MSK(hart) (0xf << ((hart) * (status_bit_offset)))
#define CCTL_STATUS_IDLE(hart) (0 << ((hart) * (status_bit_offset)))
#define CCTL_STATUS_PROCESS(hart) (1 << ((hart) * (status_bit_offset)))
#define CCTL_STATUS_ILLEGAL(hart) (2 << ((hart) * (status_bit_offset)))
DECLARE_GLOBAL_DATA_PTR;
struct andes_l2_plat {
struct l2cache *regs;
u32 iprefetch;
u32 dprefetch;
u32 tram_ctl[2];
u32 dram_ctl[2];
};
static int andes_l2_enable(struct udevice *dev)
{
struct andes_l2_plat *plat = dev_get_plat(dev);
volatile struct l2cache *regs = plat->regs;
if (regs)
setbits_le32(®s->control, L2_ENABLE);
return 0;
}
static int andes_l2_disable(struct udevice *dev)
{
struct andes_l2_plat *plat = dev_get_plat(dev);
volatile struct l2cache *regs = plat->regs;
u8 hart = gd->arch.boot_hart;
void __iomem *cctlcmd = (void __iomem *)CCTL_CMD_REG(regs, hart);
void __iomem *cctlstatus = (void __iomem *)CCTL_STATUS_REG(regs, hart);
if ((regs) && (readl(®s->control) & L2_ENABLE)) {
writel(L2_WBINVAL_ALL, cctlcmd);
while ((readl(cctlstatus) & CCTL_STATUS_MSK(hart))) {
if ((readl(cctlstatus) & CCTL_STATUS_ILLEGAL(hart))) {
printf("L2 flush illegal! hanging...");
hang();
}
}
clrbits_le32(®s->control, L2_ENABLE);
}
return 0;
}
static int andes_l2_of_to_plat(struct udevice *dev)
{
struct andes_l2_plat *plat = dev_get_plat(dev);
struct l2cache *regs;
regs = dev_read_addr_ptr(dev);
plat->regs = regs;
plat->iprefetch = -EINVAL;
plat->dprefetch = -EINVAL;
plat->tram_ctl[0] = -EINVAL;
plat->dram_ctl[0] = -EINVAL;
/* Instruction and data fetch prefetch depth */
dev_read_u32(dev, "andes,inst-prefetch", &plat->iprefetch);
dev_read_u32(dev, "andes,data-prefetch", &plat->dprefetch);
/* Set tag RAM and data RAM setup and output cycle */
dev_read_u32_array(dev, "andes,tag-ram-ctl", plat->tram_ctl, 2);
dev_read_u32_array(dev, "andes,data-ram-ctl", plat->dram_ctl, 2);
return 0;
}
static int andes_l2_probe(struct udevice *dev)
{
struct andes_l2_plat *plat = dev_get_plat(dev);
struct l2cache *regs = plat->regs;
u32 cfg_val, ctl_val;
cfg_val = readl(®s->configure);
ctl_val = readl(®s->control);
/* If true, v1 memory map (Gen2) */
if (cfg_val & MEM_MAP_MSK) {
cmd_stride = 0x1000;
status_stride = 0x1000;
status_bit_offset = 0x0;
}
ctl_val |= L2_ENABLE;
if (plat->iprefetch != -EINVAL) {
ctl_val &= ~(IPREPETCH_MSK);
ctl_val |= (plat->iprefetch << IPREPETCH_OFF);
}
if (plat->dprefetch != -EINVAL) {
ctl_val &= ~(DPREPETCH_MSK);
ctl_val |= (plat->dprefetch << DPREPETCH_OFF);
}
if (plat->tram_ctl[0] != -EINVAL) {
ctl_val &= ~(TRAMOCTL_MSK | TRAMICTL_MSK);
ctl_val |= plat->tram_ctl[0] << TRAMOCTL_OFF;
ctl_val |= plat->tram_ctl[1] << TRAMICTL_OFF;
}
if (plat->dram_ctl[0] != -EINVAL) {
ctl_val &= ~(DRAMOCTL_MSK | DRAMICTL_MSK);
ctl_val |= plat->dram_ctl[0] << DRAMOCTL_OFF;
ctl_val |= plat->dram_ctl[1] << DRAMICTL_OFF;
}
writel(ctl_val, ®s->control);
return 0;
}
static const struct udevice_id andes_l2_cache_ids[] = {
{ .compatible = "cache" },
{}
};
static const struct cache_ops andes_l2_cache_ops = {
.enable = andes_l2_enable,
.disable = andes_l2_disable,
};
U_BOOT_DRIVER(andes_l2_cache) = {
.name = "andes_l2_cache",
.id = UCLASS_CACHE,
.of_match = andes_l2_cache_ids,
.of_to_plat = andes_l2_of_to_plat,
.probe = andes_l2_probe,
.plat_auto = sizeof(struct andes_l2_plat),
.ops = &andes_l2_cache_ops,
.flags = DM_FLAG_PRE_RELOC,
};
|