common: Drop init.h from common header
[oweals/u-boot.git] / arch / arm / mach-mvebu / armada3700 / cpu.c
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 <linux/libfdt.h>
13 #include <asm/io.h>
14 #include <asm/system.h>
15 #include <asm/arch/cpu.h>
16 #include <asm/arch/soc.h>
17 #include <asm/armv8/mmu.h>
18 #include <sort.h>
19
20 /* Armada 3700 */
21 #define MVEBU_GPIO_NB_REG_BASE          (MVEBU_REGISTER(0x13800))
22
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
28
29 #define MVEBU_NB_WARM_RST_REG           (MVEBU_GPIO_NB_REG_BASE + 0x40)
30 #define MVEBU_NB_WARM_RST_MAGIC_NUM     0x1d1e
31
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
46
47 #define MAX_MEM_MAP_REGIONS             (MVEBU_CPU_DEC_WINS + 2)
48
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)
53
54 #define PCIE_PATH                       "/soc/pcie@d0070000"
55
56 DECLARE_GLOBAL_DATA_PTR;
57
58 static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
59         {
60                 /*
61                  * SRAM, MMIO regions
62                  * Don't remove this, a3700_build_mem_map needs it.
63                  */
64                 .phys = SOC_REGS_PHY_BASE,
65                 .virt = SOC_REGS_PHY_BASE,
66                 .size = 0x02000000UL,   /* 32MiB internal registers */
67                 .attrs = A3700_PTE_BLOCK_DEVICE
68         },
69 };
70
71 struct mm_region *mem_map = mvebu_mem_map;
72
73 static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
74 {
75         u32 reg;
76
77         reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
78         if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
79                 return -1;
80
81         if (tgt) {
82                 reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
83                 reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
84                 *tgt = reg;
85         }
86
87         if (base) {
88                 reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
89                 *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
90         }
91
92         if (size) {
93                 /*
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
96                  * granularity.
97                  */
98                 reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
99                 *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
100         }
101
102         return 0;
103 }
104
105 /*
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
108  */
109 static void build_mem_map(void)
110 {
111         int win, region;
112
113         region = 1;
114         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
115                 u32 base, tgt, size;
116                 u64 attrs;
117
118                 /* skip disabled windows */
119                 if (get_cpu_dec_win(win, &tgt, &base, &size))
120                         continue;
121
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;
126                 else
127                         /* skip windows with other targets */
128                         continue;
129
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;
134                 ++region;
135         }
136
137         /* add list terminator */
138         mvebu_mem_map[region].size = 0;
139         mvebu_mem_map[region].attrs = 0;
140 }
141
142 void enable_caches(void)
143 {
144         build_mem_map();
145
146         icache_enable();
147         dcache_enable();
148 }
149
150 int a3700_dram_init(void)
151 {
152         int win;
153
154         gd->ram_size = 0;
155         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
156                 u32 base, tgt, size;
157
158                 /* skip disabled windows */
159                 if (get_cpu_dec_win(win, &tgt, &base, &size))
160                         continue;
161
162                 /* skip non-DRAM windows */
163                 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
164                         continue;
165
166                 /*
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.
171                  */
172                 gd->ram_size += get_ram_size((void *)(size_t)base, size);
173         }
174
175         return 0;
176 }
177
178 struct a3700_dram_window {
179         size_t base, size;
180 };
181
182 static int dram_win_cmp(const void *a, const void *b)
183 {
184         size_t ab, bb;
185
186         ab = ((const struct a3700_dram_window *)a)->base;
187         bb = ((const struct a3700_dram_window *)b)->base;
188
189         if (ab < bb)
190                 return -1;
191         else if (ab > bb)
192                 return 1;
193         else
194                 return 0;
195 }
196
197 int a3700_dram_init_banksize(void)
198 {
199         struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
200         int bank, win, ndram_wins;
201         u32 last_end;
202         size_t size;
203
204         ndram_wins = 0;
205         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
206                 u32 base, tgt, size;
207
208                 /* skip disabled windows */
209                 if (get_cpu_dec_win(win, &tgt, &base, &size))
210                         continue;
211
212                 /* skip non-DRAM windows */
213                 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
214                         continue;
215
216                 dram_wins[win].base = base;
217                 dram_wins[win].size = size;
218                 ++ndram_wins;
219         }
220
221         qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
222
223         bank = 0;
224         last_end = -1;
225
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);
230
231                 /*
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
235                  * build_mem_map.
236                  */
237                 if (last_end == dram_wins[win].base) {
238                         gd->bd->bi_dram[bank - 1].size += size;
239                         last_end += size;
240                 } else {
241                         if (bank == CONFIG_NR_DRAM_BANKS) {
242                                 printf("Need more CONFIG_NR_DRAM_BANKS\n");
243                                 return -ENOBUFS;
244                         }
245
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;
249                         ++bank;
250                 }
251         }
252
253         /*
254          * If there is more place for DRAM BANKS definitions than needed, fill
255          * the rest with zeros.
256          */
257         for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
258                 gd->bd->bi_dram[bank].start = 0;
259                 gd->bd->bi_dram[bank].size = 0;
260         }
261
262         return 0;
263 }
264
265 static u32 find_pcie_window_base(void)
266 {
267         int win;
268
269         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
270                 u32 base, tgt;
271
272                 /* skip disabled windows */
273                 if (get_cpu_dec_win(win, &tgt, &base, NULL))
274                         continue;
275
276                 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
277                         return base;
278         }
279
280         return -1;
281 }
282
283 int a3700_fdt_fix_pcie_regions(void *blob)
284 {
285         u32 new_ranges[14], base;
286         const u32 *ranges;
287         int node, len;
288
289         node = fdt_path_offset(blob, PCIE_PATH);
290         if (node < 0)
291                 return node;
292
293         ranges = fdt_getprop(blob, node, "ranges", &len);
294         if (!ranges)
295                 return -ENOENT;
296
297         if (len != sizeof(new_ranges))
298                 return -EINVAL;
299
300         memcpy(new_ranges, ranges, len);
301
302         base = find_pcie_window_base();
303         if (base == -1)
304                 return -ENOENT;
305
306         new_ranges[2] = cpu_to_fdt32(base);
307         new_ranges[4] = new_ranges[2];
308
309         new_ranges[9] = cpu_to_fdt32(base + 0x1000000);
310         new_ranges[11] = new_ranges[9];
311
312         return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
313 }
314
315 void reset_cpu(ulong ignored)
316 {
317         /*
318          * Write magic number of 0x1d1e to North Bridge Warm Reset register
319          * to trigger warm reset
320          */
321         writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
322 }
323
324 /*
325  * get_ref_clk
326  *
327  * return: reference clock in MHz (25 or 40)
328  */
329 u32 get_ref_clk(void)
330 {
331         u32 regval;
332
333         regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
334                 MVEBU_XTAL_MODE_OFFS;
335
336         if (regval == MVEBU_XTAL_CLOCK_25MHZ)
337                 return 25;
338         else
339                 return 40;
340 }