1
2
3
4
5
6
7#include <common.h>
8#include <cpu_func.h>
9#include <dm.h>
10#include <fdtdec.h>
11#include <init.h>
12#include <asm/global_data.h>
13#include <linux/bitops.h>
14#include <linux/libfdt.h>
15#include <asm/io.h>
16#include <asm/system.h>
17#include <asm/arch/cpu.h>
18#include <asm/arch/soc.h>
19#include <asm/armv8/mmu.h>
20#include <sort.h>
21
22
23#define MVEBU_GPIO_NB_REG_BASE (MVEBU_REGISTER(0x13800))
24
25#define MVEBU_TEST_PIN_LATCH_N (MVEBU_GPIO_NB_REG_BASE + 0x8)
26#define MVEBU_XTAL_MODE_MASK BIT(9)
27#define MVEBU_XTAL_MODE_OFFS 9
28#define MVEBU_XTAL_CLOCK_25MHZ 0x0
29#define MVEBU_XTAL_CLOCK_40MHZ 0x1
30
31#define MVEBU_NB_WARM_RST_REG (MVEBU_GPIO_NB_REG_BASE + 0x40)
32#define MVEBU_NB_WARM_RST_MAGIC_NUM 0x1d1e
33
34
35#define MVEBU_CPU_DEC_WIN_REG_BASE (size_t)(MVEBU_REGISTER(0xcf00))
36#define MVEBU_CPU_DEC_WIN_CTRL(w) \
37 (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
38#define MVEBU_CPU_DEC_WIN_CTRL_EN BIT(0)
39#define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
40#define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
41#define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
42#define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
43#define MVEBU_CPU_DEC_WIN_SIZE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
44#define MVEBU_CPU_DEC_WIN_BASE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
45#define MVEBU_CPU_DEC_WIN_REMAP(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
46#define MVEBU_CPU_DEC_WIN_GRANULARITY 16
47#define MVEBU_CPU_DEC_WINS 5
48
49#define MAX_MEM_MAP_REGIONS (MVEBU_CPU_DEC_WINS + 2)
50
51#define A3700_PTE_BLOCK_NORMAL \
52 (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
53#define A3700_PTE_BLOCK_DEVICE \
54 (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
55
56#define PCIE_PATH "/soc/pcie@d0070000"
57
58DECLARE_GLOBAL_DATA_PTR;
59
60static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
61 {
62
63
64
65
66 .phys = SOC_REGS_PHY_BASE,
67 .virt = SOC_REGS_PHY_BASE,
68 .size = 0x02000000UL,
69 .attrs = A3700_PTE_BLOCK_DEVICE
70 },
71};
72
73struct mm_region *mem_map = mvebu_mem_map;
74
75static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
76{
77 u32 reg;
78
79 reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
80 if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
81 return -1;
82
83 if (tgt) {
84 reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
85 reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
86 *tgt = reg;
87 }
88
89 if (base) {
90 reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
91 *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
92 }
93
94 if (size) {
95
96
97
98
99
100 reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
101 *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
102 }
103
104 return 0;
105}
106
107
108
109
110
111static void build_mem_map(void)
112{
113 int win, region;
114
115 region = 1;
116 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
117 u32 base, tgt, size;
118 u64 attrs;
119
120
121 if (get_cpu_dec_win(win, &tgt, &base, &size))
122 continue;
123
124 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
125 attrs = A3700_PTE_BLOCK_NORMAL;
126 else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
127 attrs = A3700_PTE_BLOCK_DEVICE;
128 else
129
130 continue;
131
132 mvebu_mem_map[region].phys = base;
133 mvebu_mem_map[region].virt = base;
134 mvebu_mem_map[region].size = size;
135 mvebu_mem_map[region].attrs = attrs;
136 ++region;
137 }
138
139
140 mvebu_mem_map[region].size = 0;
141 mvebu_mem_map[region].attrs = 0;
142}
143
144void enable_caches(void)
145{
146 build_mem_map();
147
148 icache_enable();
149 dcache_enable();
150}
151
152int a3700_dram_init(void)
153{
154 int win;
155
156 gd->ram_size = 0;
157 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
158 u32 base, tgt, size;
159
160
161 if (get_cpu_dec_win(win, &tgt, &base, &size))
162 continue;
163
164
165 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
166 continue;
167
168
169
170
171
172
173
174 gd->ram_size += get_ram_size((void *)(size_t)base, size);
175 }
176
177 return 0;
178}
179
180struct a3700_dram_window {
181 size_t base, size;
182};
183
184static int dram_win_cmp(const void *a, const void *b)
185{
186 size_t ab, bb;
187
188 ab = ((const struct a3700_dram_window *)a)->base;
189 bb = ((const struct a3700_dram_window *)b)->base;
190
191 if (ab < bb)
192 return -1;
193 else if (ab > bb)
194 return 1;
195 else
196 return 0;
197}
198
199int a3700_dram_init_banksize(void)
200{
201 struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
202 int bank, win, ndram_wins;
203 u32 last_end;
204 size_t size;
205
206 ndram_wins = 0;
207 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
208 u32 base, tgt, size;
209
210
211 if (get_cpu_dec_win(win, &tgt, &base, &size))
212 continue;
213
214
215 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
216 continue;
217
218 dram_wins[win].base = base;
219 dram_wins[win].size = size;
220 ++ndram_wins;
221 }
222
223 qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
224
225 bank = 0;
226 last_end = -1;
227
228 for (win = 0; win < ndram_wins; ++win) {
229
230 size = get_ram_size((void *)dram_wins[win].base,
231 dram_wins[win].size);
232
233
234
235
236
237
238
239 if (last_end == dram_wins[win].base) {
240 gd->bd->bi_dram[bank - 1].size += size;
241 last_end += size;
242 } else {
243 if (bank == CONFIG_NR_DRAM_BANKS) {
244 printf("Need more CONFIG_NR_DRAM_BANKS\n");
245 return -ENOBUFS;
246 }
247
248 gd->bd->bi_dram[bank].start = dram_wins[win].base;
249 gd->bd->bi_dram[bank].size = size;
250 last_end = dram_wins[win].base + size;
251 ++bank;
252 }
253 }
254
255
256
257
258
259 for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
260 gd->bd->bi_dram[bank].start = 0;
261 gd->bd->bi_dram[bank].size = 0;
262 }
263
264 return 0;
265}
266
267static u32 find_pcie_window_base(void)
268{
269 int win;
270
271 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
272 u32 base, tgt;
273
274
275 if (get_cpu_dec_win(win, &tgt, &base, NULL))
276 continue;
277
278 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
279 return base;
280 }
281
282 return -1;
283}
284
285int a3700_fdt_fix_pcie_regions(void *blob)
286{
287 u32 new_ranges[14], base;
288 const u32 *ranges;
289 int node, len;
290
291 node = fdt_path_offset(blob, PCIE_PATH);
292 if (node < 0)
293 return node;
294
295 ranges = fdt_getprop(blob, node, "ranges", &len);
296 if (!ranges)
297 return -ENOENT;
298
299 if (len != sizeof(new_ranges))
300 return -EINVAL;
301
302 memcpy(new_ranges, ranges, len);
303
304 base = find_pcie_window_base();
305 if (base == -1)
306 return -ENOENT;
307
308 new_ranges[2] = cpu_to_fdt32(base);
309 new_ranges[4] = new_ranges[2];
310
311 new_ranges[9] = cpu_to_fdt32(base + 0x1000000);
312 new_ranges[11] = new_ranges[9];
313
314 return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
315}
316
317void reset_cpu(ulong ignored)
318{
319
320
321
322
323 writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
324}
325
326
327
328
329
330
331u32 get_ref_clk(void)
332{
333 u32 regval;
334
335 regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
336 MVEBU_XTAL_MODE_OFFS;
337
338 if (regval == MVEBU_XTAL_CLOCK_25MHZ)
339 return 25;
340 else
341 return 40;
342}
343