arm64: mvebu: a37xx: add device-tree fixer for PCIe regions
[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 <linux/libfdt.h>
12 #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>
17 #include <sort.h>
18
19 /* 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
31 /* 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
53 #define PCIE_PATH                       "/soc/pcie@d0070000"
54
55 DECLARE_GLOBAL_DATA_PTR;
56
57 static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
58         {
59                 /*
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,
65                 .size = 0x02000000UL,   /* 32MiB internal registers */
66                 .attrs = A3700_PTE_BLOCK_DEVICE
67         },
68 };
69
70 struct mm_region *mem_map = mvebu_mem_map;
71
72 static 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  */
108 static 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
141 void enable_caches(void)
142 {
143         build_mem_map();
144
145         icache_enable();
146         dcache_enable();
147 }
148
149 int 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
177 struct a3700_dram_window {
178         size_t base, size;
179 };
180
181 static 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
196 int 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
264 static 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
282 int 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
314 void 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  */
328 u32 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 }