1 /*
2 * Copyright (C) 2018-2021 Marvell International Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
8 #include <string.h>
9
10 #include <lib/mmio.h>
11
12 #include <dram_win.h>
13 #include <marvell_plat_priv.h>
14 #include <mvebu.h>
15 #include <plat_marvell.h>
16
17 /* Armada 3700 has 5 configurable windows */
18 #define MV_CPU_WIN_NUM 5
19
20 #define CPU_WIN_DISABLED 0
21 #define CPU_WIN_ENABLED 1
22
23 /*
24 * There are 2 different cpu decode window configuration cases:
25 * - DRAM size is not over 2GB;
26 * - DRAM size is 4GB.
27 */
28 enum cpu_win_config_num {
29 CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB = 0,
30 CPU_WIN_CONFIG_DRAM_4GB,
31 CPU_WIN_CONFIG_MAX
32 };
33
34 enum cpu_win_target {
35 CPU_WIN_TARGET_DRAM = 0,
36 CPU_WIN_TARGET_INTERNAL_REG,
37 CPU_WIN_TARGET_PCIE,
38 CPU_WIN_TARGET_PCIE_OVER_MCI,
39 CPU_WIN_TARGET_BOOT_ROM,
40 CPU_WIN_TARGET_MCI_EXTERNAL,
41 CPU_WIN_TARGET_RWTM_RAM = 7,
42 CPU_WIN_TARGET_CCI400_REG
43 };
44
45 struct cpu_win_configuration {
46 uint32_t enabled;
47 enum cpu_win_target target;
48 uint64_t base_addr;
49 uint64_t size;
50 uint64_t remap_addr;
51 };
52
53 struct cpu_win_configuration mv_cpu_wins[CPU_WIN_CONFIG_MAX][MV_CPU_WIN_NUM] = {
54 /*
55 * When total dram size is not over 2GB:
56 * DDR window 0 is configured in tim header, its size may be not 512MB,
57 * but the actual dram size, no need to configure it again;
58 * other cpu windows are kept as default.
59 */
60 {
61 /* enabled
62 * target
63 * base
64 * size
65 * remap
66 */
67 {CPU_WIN_ENABLED,
68 CPU_WIN_TARGET_DRAM,
69 0x0,
70 0x08000000,
71 0x0},
72 {CPU_WIN_ENABLED,
73 CPU_WIN_TARGET_MCI_EXTERNAL,
74 0xe0000000,
75 0x08000000,
76 0xe0000000},
77 {CPU_WIN_ENABLED,
78 CPU_WIN_TARGET_PCIE,
79 0xe8000000,
80 0x08000000,
81 0xe8000000},
82 {CPU_WIN_ENABLED,
83 CPU_WIN_TARGET_RWTM_RAM,
84 0xf0000000,
85 0x00020000,
86 0x1fff0000},
87 {CPU_WIN_ENABLED,
88 CPU_WIN_TARGET_PCIE_OVER_MCI,
89 0x80000000,
90 0x10000000,
91 0x80000000},
92 },
93
94 /*
95 * If total DRAM size is more than 2GB, now there is only one case:
96 * 4GB of DRAM; to better utilize address space (for maximization of
97 * DRAM usage), we will use the configuration of CPU windows below:
98 * - Internal Regs and Boot ROM windows are kept as default;
99 * - CCI-400 is moved from its default address to another address
100 * (this is actually done even if DRAM size is not more than 2 GB,
101 * because the firmware is compiled with that address as a
102 * constant);
103 * - PCIe window is moved to another address;
104 * - Use 4 CPU decode windows for DRAM, which cover 3.75GB DRAM;
105 * DDR window 0 is configured in tim header with 2G B size, no need
106 * to configure it again here;
107 *
108 * 0xFFFFFFFF ---> +-----------------------+
109 * | Boot ROM | 1 MB
110 * | AP Boot ROM - 16 KB: |
111 * | 0xFFFF0000-0xFFFF4000 |
112 * 0xFFF00000 ---> +-----------------------+
113 * : :
114 * 0xFE010000 ---> +-----------------------+
115 * | CCI Regs | 64 KB
116 * 0xFE000000 ---> +-----------------------+
117 * : :
118 * 0xFA000000 ---> +-----------------------+
119 * | PCIE | 128 MB
120 * 0xF2000000 ---> +-----------------------+
121 * | DDR window 3 | 512 MB
122 * 0xD2000000 ---> +-----------------------+
123 * | Internal Regs | 32 MB
124 * 0xD0000000 ---> |-----------------------|
125 * | DDR window 2 | 256 MB
126 * 0xC0000000 ---> |-----------------------|
127 * | |
128 * | DDR window 1 | 1 GB
129 * | |
130 * 0x80000000 ---> |-----------------------|
131 * | |
132 * | |
133 * | DDR window 0 | 2 GB
134 * | |
135 * | |
136 * 0x00000000 ---> +-----------------------+
137 */
138 {
139 /* win_id
140 * target
141 * base
142 * size
143 * remap
144 */
145 {CPU_WIN_ENABLED,
146 CPU_WIN_TARGET_DRAM,
147 0x0,
148 0x80000000,
149 0x0},
150 {CPU_WIN_ENABLED,
151 CPU_WIN_TARGET_DRAM,
152 0x80000000,
153 0x40000000,
154 0x80000000},
155 {CPU_WIN_ENABLED,
156 CPU_WIN_TARGET_DRAM,
157 0xc0000000,
158 0x10000000,
159 0xc0000000},
160 {CPU_WIN_ENABLED,
161 CPU_WIN_TARGET_DRAM,
162 0xd2000000,
163 0x20000000,
164 0xd2000000},
165 {CPU_WIN_ENABLED,
166 CPU_WIN_TARGET_PCIE,
167 0xf2000000,
168 0x08000000,
169 0xf2000000},
170 },
171 };
172
173 /*
174 * dram_win_map_build
175 *
176 * This function builds cpu dram windows mapping
177 * which includes base address and window size by
178 * reading cpu dram decode windows registers.
179 *
180 * @input: N/A
181 *
182 * @output:
183 * - win_map: cpu dram windows mapping
184 *
185 * @return: N/A
186 */
dram_win_map_build(struct dram_win_map * win_map)187 void dram_win_map_build(struct dram_win_map *win_map)
188 {
189 int32_t win_id;
190 struct dram_win *win;
191 uint32_t base_reg, ctrl_reg, size_reg, enabled, target;
192
193 memset(win_map, 0, sizeof(struct dram_win_map));
194 for (win_id = 0; win_id < DRAM_WIN_MAP_NUM_MAX; win_id++) {
195 ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id));
196 target = (ctrl_reg & CPU_DEC_CR_WIN_TARGET_MASK) >>
197 CPU_DEC_CR_WIN_TARGET_OFFS;
198 enabled = ctrl_reg & CPU_DEC_CR_WIN_ENABLE;
199 /* Ignore invalid and non-dram windows*/
200 if ((enabled == 0) || (target != DRAM_CPU_DEC_TARGET_NUM))
201 continue;
202
203 win = win_map->dram_windows + win_map->dram_win_num;
204 base_reg = mmio_read_32(CPU_DEC_WIN_BASE_REG(win_id));
205 size_reg = mmio_read_32(CPU_DEC_WIN_SIZE_REG(win_id));
206 /* Base reg [15:0] corresponds to transaction address [39:16] */
207 win->base_addr = (base_reg & CPU_DEC_BR_BASE_MASK) >>
208 CPU_DEC_BR_BASE_OFFS;
209 win->base_addr *= CPU_DEC_CR_WIN_SIZE_ALIGNMENT;
210 /*
211 * Size reg [15:0] is programmed from LSB to MSB as a sequence
212 * of 1s followed by a sequence of 0s and the number of 1s
213 * specifies the size of the window in 64 KB granularity,
214 * for example, a value of 00FFh specifies 256 x 64 KB = 16 MB
215 */
216 win->win_size = (size_reg & CPU_DEC_CR_WIN_SIZE_MASK) >>
217 CPU_DEC_CR_WIN_SIZE_OFFS;
218 win->win_size = (win->win_size + 1) *
219 CPU_DEC_CR_WIN_SIZE_ALIGNMENT;
220
221 win_map->dram_win_num++;
222 }
223 }
224
cpu_win_set(uint32_t win_id,struct cpu_win_configuration * win_cfg)225 static void cpu_win_set(uint32_t win_id, struct cpu_win_configuration *win_cfg)
226 {
227 uint32_t base_reg, ctrl_reg, size_reg, remap_reg;
228
229 /* Disable window */
230 ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id));
231 ctrl_reg &= ~CPU_DEC_CR_WIN_ENABLE;
232 mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg);
233
234 /* For an disabled window, only disable it. */
235 if (!win_cfg->enabled)
236 return;
237
238 /* Set Base Register */
239 base_reg = (uint32_t)(win_cfg->base_addr /
240 CPU_DEC_CR_WIN_SIZE_ALIGNMENT);
241 base_reg <<= CPU_DEC_BR_BASE_OFFS;
242 base_reg &= CPU_DEC_BR_BASE_MASK;
243 mmio_write_32(CPU_DEC_WIN_BASE_REG(win_id), base_reg);
244
245 /* Set Remap Register with the same value
246 * as the <Base> field in Base Register
247 */
248 remap_reg = (uint32_t)(win_cfg->remap_addr /
249 CPU_DEC_CR_WIN_SIZE_ALIGNMENT);
250 remap_reg <<= CPU_DEC_RLR_REMAP_LOW_OFFS;
251 remap_reg &= CPU_DEC_RLR_REMAP_LOW_MASK;
252 mmio_write_32(CPU_DEC_REMAP_LOW_REG(win_id), remap_reg);
253
254 /* Set Size Register */
255 size_reg = (win_cfg->size / CPU_DEC_CR_WIN_SIZE_ALIGNMENT) - 1;
256 size_reg <<= CPU_DEC_CR_WIN_SIZE_OFFS;
257 size_reg &= CPU_DEC_CR_WIN_SIZE_MASK;
258 mmio_write_32(CPU_DEC_WIN_SIZE_REG(win_id), size_reg);
259
260 /* Set Control Register - set target id and enable window */
261 ctrl_reg &= ~CPU_DEC_CR_WIN_TARGET_MASK;
262 ctrl_reg |= (win_cfg->target << CPU_DEC_CR_WIN_TARGET_OFFS);
263 ctrl_reg |= CPU_DEC_CR_WIN_ENABLE;
264 mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg);
265 }
266
cpu_wins_init(void)267 void cpu_wins_init(void)
268 {
269 uint32_t cfg_idx, win_id;
270
271 if (mvebu_get_dram_size(MVEBU_REGS_BASE) <= _2GB_)
272 cfg_idx = CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB;
273 else
274 cfg_idx = CPU_WIN_CONFIG_DRAM_4GB;
275
276 /* Window 0 is configured always for DRAM in tim header
277 * already, no need to configure it again here
278 */
279 for (win_id = 1; win_id < MV_CPU_WIN_NUM; win_id++)
280 cpu_win_set(win_id, &mv_cpu_wins[cfg_idx][win_id]);
281 }
282
283