blob: 17d2d43babb60f615b6f865c295c69ae46876c82 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese05b17652016-05-17 15:00:30 +02002/*
3 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
Marek Behúnf9d5e732020-04-08 19:25:19 +02004 * Copyright (C) 2020 Marek Behun <marek.behun@nic.cz>
Stefan Roese05b17652016-05-17 15:00:30 +02005 */
6
7#include <common.h>
Simon Glassafb02152019-12-28 10:45:01 -07008#include <cpu_func.h>
Stefan Roese05b17652016-05-17 15:00:30 +02009#include <dm.h>
10#include <fdtdec.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090011#include <linux/libfdt.h>
Stefan Roese05b17652016-05-17 15:00:30 +020012#include <asm/io.h>
13#include <asm/system.h>
14#include <asm/arch/cpu.h>
15#include <asm/arch/soc.h>
16#include <asm/armv8/mmu.h>
Marek Behúnf9d5e732020-04-08 19:25:19 +020017#include <sort.h>
Stefan Roese05b17652016-05-17 15:00:30 +020018
Stefan Roese05b17652016-05-17 15:00:30 +020019/* Armada 3700 */
20#define MVEBU_GPIO_NB_REG_BASE (MVEBU_REGISTER(0x13800))
21
22#define MVEBU_TEST_PIN_LATCH_N (MVEBU_GPIO_NB_REG_BASE + 0x8)
23#define MVEBU_XTAL_MODE_MASK BIT(9)
24#define MVEBU_XTAL_MODE_OFFS 9
25#define MVEBU_XTAL_CLOCK_25MHZ 0x0
26#define MVEBU_XTAL_CLOCK_40MHZ 0x1
27
28#define MVEBU_NB_WARM_RST_REG (MVEBU_GPIO_NB_REG_BASE + 0x40)
29#define MVEBU_NB_WARM_RST_MAGIC_NUM 0x1d1e
30
Marek Behúnf9d5e732020-04-08 19:25:19 +020031/* Armada 3700 CPU Address Decoder registers */
32#define MVEBU_CPU_DEC_WIN_REG_BASE (size_t)(MVEBU_REGISTER(0xcf00))
33#define MVEBU_CPU_DEC_WIN_CTRL(w) \
34 (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
35#define MVEBU_CPU_DEC_WIN_CTRL_EN BIT(0)
36#define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
37#define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
38#define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
39#define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
40#define MVEBU_CPU_DEC_WIN_SIZE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
41#define MVEBU_CPU_DEC_WIN_BASE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
42#define MVEBU_CPU_DEC_WIN_REMAP(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
43#define MVEBU_CPU_DEC_WIN_GRANULARITY 16
44#define MVEBU_CPU_DEC_WINS 5
45
46#define MAX_MEM_MAP_REGIONS (MVEBU_CPU_DEC_WINS + 2)
47
48#define A3700_PTE_BLOCK_NORMAL \
49 (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
50#define A3700_PTE_BLOCK_DEVICE \
51 (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
52
Marek Behún41d2c402020-04-08 19:25:21 +020053#define PCIE_PATH "/soc/pcie@d0070000"
54
Marek Behúnf9d5e732020-04-08 19:25:19 +020055DECLARE_GLOBAL_DATA_PTR;
56
57static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
Stefan Roese05b17652016-05-17 15:00:30 +020058 {
Marek Behúnf9d5e732020-04-08 19:25:19 +020059 /*
60 * SRAM, MMIO regions
61 * Don't remove this, a3700_build_mem_map needs it.
62 */
63 .phys = SOC_REGS_PHY_BASE,
64 .virt = SOC_REGS_PHY_BASE,
Stefan Roese05b17652016-05-17 15:00:30 +020065 .size = 0x02000000UL, /* 32MiB internal registers */
Marek Behúnf9d5e732020-04-08 19:25:19 +020066 .attrs = A3700_PTE_BLOCK_DEVICE
Wilson Ding80af2f92018-03-26 15:57:28 +080067 },
Stefan Roese05b17652016-05-17 15:00:30 +020068};
69
70struct mm_region *mem_map = mvebu_mem_map;
71
Marek Behúnf9d5e732020-04-08 19:25:19 +020072static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
73{
74 u32 reg;
75
76 reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
77 if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
78 return -1;
79
80 if (tgt) {
81 reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
82 reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
83 *tgt = reg;
84 }
85
86 if (base) {
87 reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
88 *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
89 }
90
91 if (size) {
92 /*
93 * Window size is encoded as the number of 1s from LSB to MSB,
94 * followed by 0s. The number of 1s specifies the size in 64 KiB
95 * granularity.
96 */
97 reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
98 *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
99 }
100
101 return 0;
102}
103
104/*
105 * Builds mem_map according to CPU Address Decoder settings, which were set by
106 * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
107 */
108static void build_mem_map(void)
109{
110 int win, region;
111
112 region = 1;
113 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
114 u32 base, tgt, size;
115 u64 attrs;
116
117 /* skip disabled windows */
118 if (get_cpu_dec_win(win, &tgt, &base, &size))
119 continue;
120
121 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
122 attrs = A3700_PTE_BLOCK_NORMAL;
123 else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
124 attrs = A3700_PTE_BLOCK_DEVICE;
125 else
126 /* skip windows with other targets */
127 continue;
128
129 mvebu_mem_map[region].phys = base;
130 mvebu_mem_map[region].virt = base;
131 mvebu_mem_map[region].size = size;
132 mvebu_mem_map[region].attrs = attrs;
133 ++region;
134 }
135
136 /* add list terminator */
137 mvebu_mem_map[region].size = 0;
138 mvebu_mem_map[region].attrs = 0;
139}
140
141void enable_caches(void)
142{
143 build_mem_map();
144
145 icache_enable();
146 dcache_enable();
147}
148
149int a3700_dram_init(void)
150{
151 int win;
152
153 gd->ram_size = 0;
154 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
155 u32 base, tgt, size;
156
157 /* skip disabled windows */
158 if (get_cpu_dec_win(win, &tgt, &base, &size))
159 continue;
160
161 /* skip non-DRAM windows */
162 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
163 continue;
164
165 /*
166 * It is possible that one image was built for boards with
167 * different RAM sizes, for example 512 MiB and 1 GiB.
168 * We therefore try to determine the actual RAM size in the
169 * window with get_ram_size.
170 */
171 gd->ram_size += get_ram_size((void *)(size_t)base, size);
172 }
173
174 return 0;
175}
176
177struct a3700_dram_window {
178 size_t base, size;
179};
180
181static int dram_win_cmp(const void *a, const void *b)
182{
183 size_t ab, bb;
184
185 ab = ((const struct a3700_dram_window *)a)->base;
186 bb = ((const struct a3700_dram_window *)b)->base;
187
188 if (ab < bb)
189 return -1;
190 else if (ab > bb)
191 return 1;
192 else
193 return 0;
194}
195
196int a3700_dram_init_banksize(void)
197{
198 struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
199 int bank, win, ndram_wins;
200 u32 last_end;
201 size_t size;
202
203 ndram_wins = 0;
204 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
205 u32 base, tgt, size;
206
207 /* skip disabled windows */
208 if (get_cpu_dec_win(win, &tgt, &base, &size))
209 continue;
210
211 /* skip non-DRAM windows */
212 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
213 continue;
214
215 dram_wins[win].base = base;
216 dram_wins[win].size = size;
217 ++ndram_wins;
218 }
219
220 qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
221
222 bank = 0;
223 last_end = -1;
224
225 for (win = 0; win < ndram_wins; ++win) {
226 /* again determining actual RAM size as in a3700_dram_init */
227 size = get_ram_size((void *)dram_wins[win].base,
228 dram_wins[win].size);
229
230 /*
231 * Check if previous window ends as the current starts. If yes,
232 * merge these windows into one "bank". This is possible by this
233 * simple check thanks to mem_map regions being qsorted in
234 * build_mem_map.
235 */
236 if (last_end == dram_wins[win].base) {
237 gd->bd->bi_dram[bank - 1].size += size;
238 last_end += size;
239 } else {
240 if (bank == CONFIG_NR_DRAM_BANKS) {
241 printf("Need more CONFIG_NR_DRAM_BANKS\n");
242 return -ENOBUFS;
243 }
244
245 gd->bd->bi_dram[bank].start = dram_wins[win].base;
246 gd->bd->bi_dram[bank].size = size;
247 last_end = dram_wins[win].base + size;
248 ++bank;
249 }
250 }
251
252 /*
253 * If there is more place for DRAM BANKS definitions than needed, fill
254 * the rest with zeros.
255 */
256 for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
257 gd->bd->bi_dram[bank].start = 0;
258 gd->bd->bi_dram[bank].size = 0;
259 }
260
261 return 0;
262}
263
Marek Behún41d2c402020-04-08 19:25:21 +0200264static u32 find_pcie_window_base(void)
265{
266 int win;
267
268 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
269 u32 base, tgt;
270
271 /* skip disabled windows */
272 if (get_cpu_dec_win(win, &tgt, &base, NULL))
273 continue;
274
275 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
276 return base;
277 }
278
279 return -1;
280}
281
282int a3700_fdt_fix_pcie_regions(void *blob)
283{
284 u32 new_ranges[14], base;
285 const u32 *ranges;
286 int node, len;
287
288 node = fdt_path_offset(blob, PCIE_PATH);
289 if (node < 0)
290 return node;
291
292 ranges = fdt_getprop(blob, node, "ranges", &len);
293 if (!ranges)
294 return -ENOENT;
295
296 if (len != sizeof(new_ranges))
297 return -EINVAL;
298
299 memcpy(new_ranges, ranges, len);
300
301 base = find_pcie_window_base();
302 if (base == -1)
303 return -ENOENT;
304
305 new_ranges[2] = cpu_to_fdt32(base);
306 new_ranges[4] = new_ranges[2];
307
308 new_ranges[9] = cpu_to_fdt32(base + 0x1000000);
309 new_ranges[11] = new_ranges[9];
310
311 return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
312}
313
Stefan Roese05b17652016-05-17 15:00:30 +0200314void reset_cpu(ulong ignored)
315{
316 /*
317 * Write magic number of 0x1d1e to North Bridge Warm Reset register
318 * to trigger warm reset
319 */
320 writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
321}
322
323/*
324 * get_ref_clk
325 *
326 * return: reference clock in MHz (25 or 40)
327 */
328u32 get_ref_clk(void)
329{
330 u32 regval;
331
332 regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
333 MVEBU_XTAL_MODE_OFFS;
334
335 if (regval == MVEBU_XTAL_CLOCK_25MHZ)
336 return 25;
337 else
338 return 40;
339}