1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
4 * Copyright (C) 2020 Marek Behun <marek.behun@nic.cz>
11 #include <fdt_support.h>
13 #include <asm/global_data.h>
14 #include <linux/bitops.h>
15 #include <linux/libfdt.h>
16 #include <linux/sizes.h>
18 #include <asm/system.h>
19 #include <asm/arch/cpu.h>
20 #include <asm/arch/soc.h>
21 #include <asm/armv8/mmu.h>
25 #define MVEBU_GPIO_NB_REG_BASE (MVEBU_REGISTER(0x13800))
27 #define MVEBU_TEST_PIN_LATCH_N (MVEBU_GPIO_NB_REG_BASE + 0x8)
28 #define MVEBU_XTAL_MODE_MASK BIT(9)
29 #define MVEBU_XTAL_MODE_OFFS 9
30 #define MVEBU_XTAL_CLOCK_25MHZ 0x0
31 #define MVEBU_XTAL_CLOCK_40MHZ 0x1
33 #define MVEBU_NB_WARM_RST_REG (MVEBU_GPIO_NB_REG_BASE + 0x40)
34 #define MVEBU_NB_WARM_RST_MAGIC_NUM 0x1d1e
36 /* Armada 3700 CPU Address Decoder registers */
37 #define MVEBU_CPU_DEC_WIN_REG_BASE (size_t)(MVEBU_REGISTER(0xcf00))
38 #define MVEBU_CPU_DEC_WIN_CTRL(w) \
39 (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
40 #define MVEBU_CPU_DEC_WIN_CTRL_EN BIT(0)
41 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
42 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
43 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
44 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
45 #define MVEBU_CPU_DEC_WIN_SIZE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
46 #define MVEBU_CPU_DEC_WIN_BASE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
47 #define MVEBU_CPU_DEC_WIN_REMAP(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
48 #define MVEBU_CPU_DEC_WIN_GRANULARITY 16
49 #define MVEBU_CPU_DEC_WINS 5
50 #define MVEBU_CPU_DEC_CCI_BASE (MVEBU_CPU_DEC_WIN_REG_BASE + 0xe0)
51 #define MVEBU_CPU_DEC_ROM_BASE (MVEBU_CPU_DEC_WIN_REG_BASE + 0xf4)
53 #define MAX_MEM_MAP_REGIONS (MVEBU_CPU_DEC_WINS + 4)
55 #define A3700_PTE_BLOCK_NORMAL \
56 (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
57 #define A3700_PTE_BLOCK_DEVICE \
58 (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
60 DECLARE_GLOBAL_DATA_PTR;
62 static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
66 * Don't remove this, build_mem_map needs it.
68 .phys = SOC_REGS_PHY_BASE,
69 .virt = SOC_REGS_PHY_BASE,
70 .size = 0x02000000UL, /* 32MiB internal registers */
71 .attrs = A3700_PTE_BLOCK_DEVICE
75 struct mm_region *mem_map = mvebu_mem_map;
77 static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
81 reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
82 if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
86 reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
87 reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
92 reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
93 *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
98 * Window size is encoded as the number of 1s from LSB to MSB,
99 * followed by 0s. The number of 1s specifies the size in 64 KiB
102 reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
103 *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
110 * Builds mem_map according to CPU Address Decoder settings, which were set by
111 * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
113 static void build_mem_map(void)
121 reg = readl(MVEBU_CPU_DEC_CCI_BASE);
122 mvebu_mem_map[region].phys = reg << 20;
123 mvebu_mem_map[region].virt = reg << 20;
124 mvebu_mem_map[region].size = SZ_64K;
125 mvebu_mem_map[region].attrs = A3700_PTE_BLOCK_DEVICE;
129 reg = readl(MVEBU_CPU_DEC_ROM_BASE);
130 mvebu_mem_map[region].phys = reg << 20;
131 mvebu_mem_map[region].virt = reg << 20;
132 mvebu_mem_map[region].size = SZ_1M;
133 mvebu_mem_map[region].attrs = A3700_PTE_BLOCK_NORMAL;
136 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
140 /* skip disabled windows */
141 if (get_cpu_dec_win(win, &tgt, &base, &size))
144 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
145 attrs = A3700_PTE_BLOCK_NORMAL;
146 else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
147 attrs = A3700_PTE_BLOCK_DEVICE;
149 /* skip windows with other targets */
152 mvebu_mem_map[region].phys = base;
153 mvebu_mem_map[region].virt = base;
154 mvebu_mem_map[region].size = size;
155 mvebu_mem_map[region].attrs = attrs;
159 /* add list terminator */
160 mvebu_mem_map[region].size = 0;
161 mvebu_mem_map[region].attrs = 0;
164 void enable_caches(void)
170 int a3700_dram_init(void)
177 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
180 /* skip disabled windows */
181 if (get_cpu_dec_win(win, &tgt, &base, &size))
184 /* skip non-DRAM windows */
185 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
189 * It is possible that one image was built for boards with
190 * different RAM sizes, for example 512 MiB and 1 GiB.
191 * We therefore try to determine the actual RAM size in the
192 * window with get_ram_size.
194 gd->ram_size += get_ram_size((void *)(size_t)base, size);
200 struct a3700_dram_window {
204 static int dram_win_cmp(const void *a, const void *b)
208 ab = ((const struct a3700_dram_window *)a)->base;
209 bb = ((const struct a3700_dram_window *)b)->base;
219 int a3700_dram_init_banksize(void)
221 struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
222 int bank, win, ndram_wins;
227 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
230 /* skip disabled windows */
231 if (get_cpu_dec_win(win, &tgt, &base, &size))
234 /* skip non-DRAM windows */
235 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
238 dram_wins[win].base = base;
239 dram_wins[win].size = size;
243 qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
248 for (win = 0; win < ndram_wins; ++win) {
249 /* again determining actual RAM size as in a3700_dram_init */
250 size = get_ram_size((void *)dram_wins[win].base,
251 dram_wins[win].size);
254 * Check if previous window ends as the current starts. If yes,
255 * merge these windows into one "bank". This is possible by this
256 * simple check thanks to mem_map regions being qsorted in
259 if (last_end == dram_wins[win].base) {
260 gd->bd->bi_dram[bank - 1].size += size;
263 if (bank == CONFIG_NR_DRAM_BANKS) {
264 printf("Need more CONFIG_NR_DRAM_BANKS\n");
268 gd->bd->bi_dram[bank].start = dram_wins[win].base;
269 gd->bd->bi_dram[bank].size = size;
270 last_end = dram_wins[win].base + size;
276 * If there is more place for DRAM BANKS definitions than needed, fill
277 * the rest with zeros.
279 for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
280 gd->bd->bi_dram[bank].start = 0;
281 gd->bd->bi_dram[bank].size = 0;
287 static u32 find_pcie_window_base(void)
291 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
294 /* skip disabled windows */
295 if (get_cpu_dec_win(win, &tgt, &base, NULL))
298 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
305 static int fdt_setprop_inplace_u32_partial(void *blob, int node,
309 val = cpu_to_fdt32(val);
311 return fdt_setprop_inplace_namelen_partial(blob, node, name,
317 int a3700_fdt_fix_pcie_regions(void *blob)
319 int acells, pacells, scells;
320 u32 base, fix_offset;
325 base = find_pcie_window_base();
329 node = fdt_node_offset_by_compatible(blob, -1, "marvell,armada-3700-pcie");
333 ranges = fdt_getprop(blob, node, "ranges", &len);
334 if (!ranges || len % sizeof(u32))
338 * The "ranges" property is an array of
339 * { <child address> <parent address> <size in child address space> }
341 * All 3 elements can span a diffent number of cells. Fetch their sizes.
343 pnode = fdt_parent_offset(blob, node);
344 acells = fdt_address_cells(blob, node);
345 pacells = fdt_address_cells(blob, pnode);
346 scells = fdt_size_cells(blob, node);
348 /* Child PCI addresses always use 3 cells */
352 /* Calculate fixup offset from first child address (in last cell) */
353 fix_offset = base - fdt32_to_cpu(ranges[2]);
355 /* If fixup offset is zero then there is nothing to fix */
360 * Fix address (last cell) of each child address and each parent
363 for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
366 /* fix child address */
367 idx = i + acells - 1;
368 ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
369 fdt32_to_cpu(ranges[idx]) +
374 /* fix parent address */
375 idx = i + acells + pacells - 1;
376 ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
377 fdt32_to_cpu(ranges[idx]) +
389 * Write magic number of 0x1d1e to North Bridge Warm Reset register
390 * to trigger warm reset
392 writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
398 * return: reference clock in MHz (25 or 40)
400 u32 get_ref_clk(void)
404 regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
405 MVEBU_XTAL_MODE_OFFS;
407 if (regval == MVEBU_XTAL_CLOCK_25MHZ)