arm: a37xx: pci: Optimize a3700_fdt_fix_pcie_regions() when fixup offset is zero
[platform/kernel/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 <fdt_support.h>
12 #include <init.h>
13 #include <asm/global_data.h>
14 #include <linux/bitops.h>
15 #include <linux/libfdt.h>
16 #include <asm/io.h>
17 #include <asm/system.h>
18 #include <asm/arch/cpu.h>
19 #include <asm/arch/soc.h>
20 #include <asm/armv8/mmu.h>
21 #include <sort.h>
22
23 /* Armada 3700 */
24 #define MVEBU_GPIO_NB_REG_BASE          (MVEBU_REGISTER(0x13800))
25
26 #define MVEBU_TEST_PIN_LATCH_N          (MVEBU_GPIO_NB_REG_BASE + 0x8)
27 #define MVEBU_XTAL_MODE_MASK            BIT(9)
28 #define MVEBU_XTAL_MODE_OFFS            9
29 #define MVEBU_XTAL_CLOCK_25MHZ          0x0
30 #define MVEBU_XTAL_CLOCK_40MHZ          0x1
31
32 #define MVEBU_NB_WARM_RST_REG           (MVEBU_GPIO_NB_REG_BASE + 0x40)
33 #define MVEBU_NB_WARM_RST_MAGIC_NUM     0x1d1e
34
35 /* Armada 3700 CPU Address Decoder registers */
36 #define MVEBU_CPU_DEC_WIN_REG_BASE      (size_t)(MVEBU_REGISTER(0xcf00))
37 #define MVEBU_CPU_DEC_WIN_CTRL(w) \
38         (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
39 #define MVEBU_CPU_DEC_WIN_CTRL_EN       BIT(0)
40 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
41 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
42 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
43 #define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
44 #define MVEBU_CPU_DEC_WIN_SIZE(w)       (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
45 #define MVEBU_CPU_DEC_WIN_BASE(w)       (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
46 #define MVEBU_CPU_DEC_WIN_REMAP(w)      (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
47 #define MVEBU_CPU_DEC_WIN_GRANULARITY   16
48 #define MVEBU_CPU_DEC_WINS              5
49
50 #define MAX_MEM_MAP_REGIONS             (MVEBU_CPU_DEC_WINS + 2)
51
52 #define A3700_PTE_BLOCK_NORMAL \
53         (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
54 #define A3700_PTE_BLOCK_DEVICE \
55         (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
56
57 DECLARE_GLOBAL_DATA_PTR;
58
59 static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
60         {
61                 /*
62                  * SRAM, MMIO regions
63                  * Don't remove this, a3700_build_mem_map needs it.
64                  */
65                 .phys = SOC_REGS_PHY_BASE,
66                 .virt = SOC_REGS_PHY_BASE,
67                 .size = 0x02000000UL,   /* 32MiB internal registers */
68                 .attrs = A3700_PTE_BLOCK_DEVICE
69         },
70 };
71
72 struct mm_region *mem_map = mvebu_mem_map;
73
74 static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
75 {
76         u32 reg;
77
78         reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
79         if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
80                 return -1;
81
82         if (tgt) {
83                 reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
84                 reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
85                 *tgt = reg;
86         }
87
88         if (base) {
89                 reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
90                 *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
91         }
92
93         if (size) {
94                 /*
95                  * Window size is encoded as the number of 1s from LSB to MSB,
96                  * followed by 0s. The number of 1s specifies the size in 64 KiB
97                  * granularity.
98                  */
99                 reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
100                 *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
101         }
102
103         return 0;
104 }
105
106 /*
107  * Builds mem_map according to CPU Address Decoder settings, which were set by
108  * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
109  */
110 static void build_mem_map(void)
111 {
112         int win, region;
113
114         region = 1;
115         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
116                 u32 base, tgt, size;
117                 u64 attrs;
118
119                 /* skip disabled windows */
120                 if (get_cpu_dec_win(win, &tgt, &base, &size))
121                         continue;
122
123                 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
124                         attrs = A3700_PTE_BLOCK_NORMAL;
125                 else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
126                         attrs = A3700_PTE_BLOCK_DEVICE;
127                 else
128                         /* skip windows with other targets */
129                         continue;
130
131                 mvebu_mem_map[region].phys = base;
132                 mvebu_mem_map[region].virt = base;
133                 mvebu_mem_map[region].size = size;
134                 mvebu_mem_map[region].attrs = attrs;
135                 ++region;
136         }
137
138         /* add list terminator */
139         mvebu_mem_map[region].size = 0;
140         mvebu_mem_map[region].attrs = 0;
141 }
142
143 void enable_caches(void)
144 {
145         build_mem_map();
146
147         icache_enable();
148         dcache_enable();
149 }
150
151 int a3700_dram_init(void)
152 {
153         int win;
154
155         gd->ram_size = 0;
156         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
157                 u32 base, tgt, size;
158
159                 /* skip disabled windows */
160                 if (get_cpu_dec_win(win, &tgt, &base, &size))
161                         continue;
162
163                 /* skip non-DRAM windows */
164                 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
165                         continue;
166
167                 /*
168                  * It is possible that one image was built for boards with
169                  * different RAM sizes, for example 512 MiB and 1 GiB.
170                  * We therefore try to determine the actual RAM size in the
171                  * window with get_ram_size.
172                  */
173                 gd->ram_size += get_ram_size((void *)(size_t)base, size);
174         }
175
176         return 0;
177 }
178
179 struct a3700_dram_window {
180         size_t base, size;
181 };
182
183 static int dram_win_cmp(const void *a, const void *b)
184 {
185         size_t ab, bb;
186
187         ab = ((const struct a3700_dram_window *)a)->base;
188         bb = ((const struct a3700_dram_window *)b)->base;
189
190         if (ab < bb)
191                 return -1;
192         else if (ab > bb)
193                 return 1;
194         else
195                 return 0;
196 }
197
198 int a3700_dram_init_banksize(void)
199 {
200         struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
201         int bank, win, ndram_wins;
202         u32 last_end;
203         size_t size;
204
205         ndram_wins = 0;
206         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
207                 u32 base, tgt, size;
208
209                 /* skip disabled windows */
210                 if (get_cpu_dec_win(win, &tgt, &base, &size))
211                         continue;
212
213                 /* skip non-DRAM windows */
214                 if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
215                         continue;
216
217                 dram_wins[win].base = base;
218                 dram_wins[win].size = size;
219                 ++ndram_wins;
220         }
221
222         qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
223
224         bank = 0;
225         last_end = -1;
226
227         for (win = 0; win < ndram_wins; ++win) {
228                 /* again determining actual RAM size as in a3700_dram_init */
229                 size = get_ram_size((void *)dram_wins[win].base,
230                                     dram_wins[win].size);
231
232                 /*
233                  * Check if previous window ends as the current starts. If yes,
234                  * merge these windows into one "bank". This is possible by this
235                  * simple check thanks to mem_map regions being qsorted in
236                  * build_mem_map.
237                  */
238                 if (last_end == dram_wins[win].base) {
239                         gd->bd->bi_dram[bank - 1].size += size;
240                         last_end += size;
241                 } else {
242                         if (bank == CONFIG_NR_DRAM_BANKS) {
243                                 printf("Need more CONFIG_NR_DRAM_BANKS\n");
244                                 return -ENOBUFS;
245                         }
246
247                         gd->bd->bi_dram[bank].start = dram_wins[win].base;
248                         gd->bd->bi_dram[bank].size = size;
249                         last_end = dram_wins[win].base + size;
250                         ++bank;
251                 }
252         }
253
254         /*
255          * If there is more place for DRAM BANKS definitions than needed, fill
256          * the rest with zeros.
257          */
258         for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
259                 gd->bd->bi_dram[bank].start = 0;
260                 gd->bd->bi_dram[bank].size = 0;
261         }
262
263         return 0;
264 }
265
266 static u32 find_pcie_window_base(void)
267 {
268         int win;
269
270         for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
271                 u32 base, tgt;
272
273                 /* skip disabled windows */
274                 if (get_cpu_dec_win(win, &tgt, &base, NULL))
275                         continue;
276
277                 if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
278                         return base;
279         }
280
281         return -1;
282 }
283
284 static int fdt_setprop_inplace_u32_partial(void *blob, int node,
285                                            const char *name,
286                                            u32 idx, u32 val)
287 {
288         val = cpu_to_fdt32(val);
289
290         return fdt_setprop_inplace_namelen_partial(blob, node, name,
291                                                    strlen(name),
292                                                    idx * sizeof(u32),
293                                                    &val, sizeof(u32));
294 }
295
296 int a3700_fdt_fix_pcie_regions(void *blob)
297 {
298         int acells, pacells, scells;
299         u32 base, fix_offset;
300         const u32 *ranges;
301         int node, pnode;
302         int ret, i, len;
303
304         base = find_pcie_window_base();
305         if (base == -1)
306                 return -ENOENT;
307
308         node = fdt_node_offset_by_compatible(blob, -1, "marvell,armada-3700-pcie");
309         if (node < 0)
310                 return node;
311
312         ranges = fdt_getprop(blob, node, "ranges", &len);
313         if (!ranges || len % sizeof(u32))
314                 return -ENOENT;
315
316         /*
317          * The "ranges" property is an array of
318          * { <child address> <parent address> <size in child address space> }
319          *
320          * All 3 elements can span a diffent number of cells. Fetch their sizes.
321          */
322         pnode = fdt_parent_offset(blob, node);
323         acells = fdt_address_cells(blob, node);
324         pacells = fdt_address_cells(blob, pnode);
325         scells = fdt_size_cells(blob, node);
326
327         /* Child PCI addresses always use 3 cells */
328         if (acells != 3)
329                 return -ENOENT;
330
331         /* Calculate fixup offset from first child address (in last cell) */
332         fix_offset = base - fdt32_to_cpu(ranges[2]);
333
334         /* If fixup offset is zero then there is nothing to fix */
335         if (!fix_offset)
336                 return 0;
337
338         /*
339          * Fix address (last cell) of each child address and each parent
340          * address
341          */
342         for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
343                 int idx;
344
345                 /* fix child address */
346                 idx = i + acells - 1;
347                 ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
348                                                       fdt32_to_cpu(ranges[idx]) +
349                                                       fix_offset);
350                 if (ret)
351                         return ret;
352
353                 /* fix parent address */
354                 idx = i + acells + pacells - 1;
355                 ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
356                                                       fdt32_to_cpu(ranges[idx]) +
357                                                       fix_offset);
358                 if (ret)
359                         return ret;
360         }
361
362         return 0;
363 }
364
365 void reset_cpu(void)
366 {
367         /*
368          * Write magic number of 0x1d1e to North Bridge Warm Reset register
369          * to trigger warm reset
370          */
371         writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
372 }
373
374 /*
375  * get_ref_clk
376  *
377  * return: reference clock in MHz (25 or 40)
378  */
379 u32 get_ref_clk(void)
380 {
381         u32 regval;
382
383         regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
384                 MVEBU_XTAL_MODE_OFFS;
385
386         if (regval == MVEBU_XTAL_CLOCK_25MHZ)
387                 return 25;
388         else
389                 return 40;
390 }