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>
12 #include <linux/libfdt.h>
14 #include <asm/system.h>
15 #include <asm/arch/cpu.h>
16 #include <asm/arch/soc.h>
17 #include <asm/armv8/mmu.h>
21 #define MVEBU_GPIO_NB_REG_BASE (MVEBU_REGISTER(0x13800))
23 #define MVEBU_TEST_PIN_LATCH_N (MVEBU_GPIO_NB_REG_BASE + 0x8)
24 #define MVEBU_XTAL_MODE_MASK BIT(9)
25 #define MVEBU_XTAL_MODE_OFFS 9
26 #define MVEBU_XTAL_CLOCK_25MHZ 0x0
27 #define MVEBU_XTAL_CLOCK_40MHZ 0x1
29 #define MVEBU_NB_WARM_RST_REG (MVEBU_GPIO_NB_REG_BASE + 0x40)
30 #define MVEBU_NB_WARM_RST_MAGIC_NUM 0x1d1e
32 /* Armada 3700 CPU Address Decoder registers */
33 #define MVEBU_CPU_DEC_WIN_REG_BASE (size_t)(MVEBU_REGISTER(0xcf00))
34 #define MVEBU_CPU_DEC_WIN_CTRL(w) \
35 (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
36 #define MVEBU_CPU_DEC_WIN_CTRL_EN BIT(0)
37 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
38 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
39 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
40 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
41 #define MVEBU_CPU_DEC_WIN_SIZE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
42 #define MVEBU_CPU_DEC_WIN_BASE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
43 #define MVEBU_CPU_DEC_WIN_REMAP(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
44 #define MVEBU_CPU_DEC_WIN_GRANULARITY 16
45 #define MVEBU_CPU_DEC_WINS 5
47 #define MAX_MEM_MAP_REGIONS (MVEBU_CPU_DEC_WINS + 2)
49 #define A3700_PTE_BLOCK_NORMAL \
50 (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
51 #define A3700_PTE_BLOCK_DEVICE \
52 (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
54 #define PCIE_PATH "/soc/pcie@d0070000"
56 DECLARE_GLOBAL_DATA_PTR;
58 static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
62 * Don't remove this, a3700_build_mem_map needs it.
64 .phys = SOC_REGS_PHY_BASE,
65 .virt = SOC_REGS_PHY_BASE,
66 .size = 0x02000000UL, /* 32MiB internal registers */
67 .attrs = A3700_PTE_BLOCK_DEVICE
71 struct mm_region *mem_map = mvebu_mem_map;
73 static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
77 reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
78 if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
82 reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
83 reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
88 reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
89 *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
94 * Window size is encoded as the number of 1s from LSB to MSB,
95 * followed by 0s. The number of 1s specifies the size in 64 KiB
98 reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
99 *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
106 * Builds mem_map according to CPU Address Decoder settings, which were set by
107 * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
109 static void build_mem_map(void)
114 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
118 /* skip disabled windows */
119 if (get_cpu_dec_win(win, &tgt, &base, &size))
122 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
123 attrs = A3700_PTE_BLOCK_NORMAL;
124 else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
125 attrs = A3700_PTE_BLOCK_DEVICE;
127 /* skip windows with other targets */
130 mvebu_mem_map[region].phys = base;
131 mvebu_mem_map[region].virt = base;
132 mvebu_mem_map[region].size = size;
133 mvebu_mem_map[region].attrs = attrs;
137 /* add list terminator */
138 mvebu_mem_map[region].size = 0;
139 mvebu_mem_map[region].attrs = 0;
142 void enable_caches(void)
150 int a3700_dram_init(void)
155 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
158 /* skip disabled windows */
159 if (get_cpu_dec_win(win, &tgt, &base, &size))
162 /* skip non-DRAM windows */
163 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
167 * It is possible that one image was built for boards with
168 * different RAM sizes, for example 512 MiB and 1 GiB.
169 * We therefore try to determine the actual RAM size in the
170 * window with get_ram_size.
172 gd->ram_size += get_ram_size((void *)(size_t)base, size);
178 struct a3700_dram_window {
182 static int dram_win_cmp(const void *a, const void *b)
186 ab = ((const struct a3700_dram_window *)a)->base;
187 bb = ((const struct a3700_dram_window *)b)->base;
197 int a3700_dram_init_banksize(void)
199 struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
200 int bank, win, ndram_wins;
205 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
208 /* skip disabled windows */
209 if (get_cpu_dec_win(win, &tgt, &base, &size))
212 /* skip non-DRAM windows */
213 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
216 dram_wins[win].base = base;
217 dram_wins[win].size = size;
221 qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
226 for (win = 0; win < ndram_wins; ++win) {
227 /* again determining actual RAM size as in a3700_dram_init */
228 size = get_ram_size((void *)dram_wins[win].base,
229 dram_wins[win].size);
232 * Check if previous window ends as the current starts. If yes,
233 * merge these windows into one "bank". This is possible by this
234 * simple check thanks to mem_map regions being qsorted in
237 if (last_end == dram_wins[win].base) {
238 gd->bd->bi_dram[bank - 1].size += size;
241 if (bank == CONFIG_NR_DRAM_BANKS) {
242 printf("Need more CONFIG_NR_DRAM_BANKS\n");
246 gd->bd->bi_dram[bank].start = dram_wins[win].base;
247 gd->bd->bi_dram[bank].size = size;
248 last_end = dram_wins[win].base + size;
254 * If there is more place for DRAM BANKS definitions than needed, fill
255 * the rest with zeros.
257 for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
258 gd->bd->bi_dram[bank].start = 0;
259 gd->bd->bi_dram[bank].size = 0;
265 static u32 find_pcie_window_base(void)
269 for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
272 /* skip disabled windows */
273 if (get_cpu_dec_win(win, &tgt, &base, NULL))
276 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
283 int a3700_fdt_fix_pcie_regions(void *blob)
285 u32 new_ranges[14], base;
289 node = fdt_path_offset(blob, PCIE_PATH);
293 ranges = fdt_getprop(blob, node, "ranges", &len);
297 if (len != sizeof(new_ranges))
300 memcpy(new_ranges, ranges, len);
302 base = find_pcie_window_base();
306 new_ranges[2] = cpu_to_fdt32(base);
307 new_ranges[4] = new_ranges[2];
309 new_ranges[9] = cpu_to_fdt32(base + 0x1000000);
310 new_ranges[11] = new_ranges[9];
312 return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
315 void reset_cpu(ulong ignored)
318 * Write magic number of 0x1d1e to North Bridge Warm Reset register
319 * to trigger warm reset
321 writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
327 * return: reference clock in MHz (25 or 40)
329 u32 get_ref_clk(void)
333 regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
334 MVEBU_XTAL_MODE_OFFS;
336 if (regval == MVEBU_XTAL_CLOCK_25MHZ)