1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Stefan Roese <sr@denx.de>
4  * Copyright (C) 2020 Marek Behun <marek.behun@nic.cz>
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 /* Armada 3700 */
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 /* Armada 3700 CPU Address Decoder registers */
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 
58 DECLARE_GLOBAL_DATA_PTR;
59 
60 static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
61 	{
62 		/*
63 		 * SRAM, MMIO regions
64 		 * Don't remove this, a3700_build_mem_map needs it.
65 		 */
66 		.phys = SOC_REGS_PHY_BASE,
67 		.virt = SOC_REGS_PHY_BASE,
68 		.size = 0x02000000UL,	/* 32MiB internal registers */
69 		.attrs = A3700_PTE_BLOCK_DEVICE
70 	},
71 };
72 
73 struct mm_region *mem_map = mvebu_mem_map;
74 
get_cpu_dec_win(int win,u32 * tgt,u32 * base,u32 * size)75 static 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 		 * Window size is encoded as the number of 1s from LSB to MSB,
97 		 * followed by 0s. The number of 1s specifies the size in 64 KiB
98 		 * granularity.
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  * Builds mem_map according to CPU Address Decoder settings, which were set by
109  * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
110  */
build_mem_map(void)111 static 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 		/* skip disabled windows */
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 			/* skip windows with other targets */
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 	/* add list terminator */
140 	mvebu_mem_map[region].size = 0;
141 	mvebu_mem_map[region].attrs = 0;
142 }
143 
enable_caches(void)144 void enable_caches(void)
145 {
146 	build_mem_map();
147 
148 	icache_enable();
149 	dcache_enable();
150 }
151 
a3700_dram_init(void)152 int 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 		/* skip disabled windows */
161 		if (get_cpu_dec_win(win, &tgt, &base, &size))
162 			continue;
163 
164 		/* skip non-DRAM windows */
165 		if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
166 			continue;
167 
168 		/*
169 		 * It is possible that one image was built for boards with
170 		 * different RAM sizes, for example 512 MiB and 1 GiB.
171 		 * We therefore try to determine the actual RAM size in the
172 		 * window with get_ram_size.
173 		 */
174 		gd->ram_size += get_ram_size((void *)(size_t)base, size);
175 	}
176 
177 	return 0;
178 }
179 
180 struct a3700_dram_window {
181 	size_t base, size;
182 };
183 
dram_win_cmp(const void * a,const void * b)184 static 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 
a3700_dram_init_banksize(void)199 int 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 		/* skip disabled windows */
211 		if (get_cpu_dec_win(win, &tgt, &base, &size))
212 			continue;
213 
214 		/* skip non-DRAM windows */
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 		/* again determining actual RAM size as in a3700_dram_init */
230 		size = get_ram_size((void *)dram_wins[win].base,
231 				    dram_wins[win].size);
232 
233 		/*
234 		 * Check if previous window ends as the current starts. If yes,
235 		 * merge these windows into one "bank". This is possible by this
236 		 * simple check thanks to mem_map regions being qsorted in
237 		 * build_mem_map.
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 	 * If there is more place for DRAM BANKS definitions than needed, fill
257 	 * the rest with zeros.
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 
find_pcie_window_base(void)267 static 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 		/* skip disabled windows */
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 
a3700_fdt_fix_pcie_regions(void * blob)285 int 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 
reset_cpu(ulong ignored)317 void reset_cpu(ulong ignored)
318 {
319 	/*
320 	 * Write magic number of 0x1d1e to North Bridge Warm Reset register
321 	 * to trigger warm reset
322 	 */
323 	writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
324 }
325 
326 /*
327  * get_ref_clk
328  *
329  * return: reference clock in MHz (25 or 40)
330  */
get_ref_clk(void)331 u32 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