]>
Commit | Line | Data |
---|---|---|
5894ca00 | 1 | /* |
3e9952be MY |
2 | * Copyright (C) 2012-2015 Panasonic Corporation |
3 | * Copyright (C) 2015-2017 Socionext Inc. | |
4 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | |
5894ca00 MY |
5 | * |
6 | * SPDX-License-Identifier: GPL-2.0+ | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
7b3a032d | 10 | #include <fdtdec.h> |
0f4ec05b | 11 | #include <linux/errno.h> |
3e9952be | 12 | #include <linux/sizes.h> |
cf88affa | 13 | |
51ea5a06 | 14 | #include "init.h" |
3e9952be | 15 | #include "sg-regs.h" |
51ea5a06 MY |
16 | #include "soc-info.h" |
17 | ||
cf88affa MY |
18 | DECLARE_GLOBAL_DATA_PTR; |
19 | ||
3e9952be MY |
20 | struct uniphier_memif_data { |
21 | unsigned int soc_id; | |
22 | unsigned long sparse_ch1_base; | |
23 | int have_ch2; | |
24 | }; | |
25 | ||
26 | static const struct uniphier_memif_data uniphier_memif_data[] = { | |
27 | { | |
28 | .soc_id = UNIPHIER_SLD3_ID, | |
29 | .sparse_ch1_base = 0xc0000000, | |
30 | /* | |
31 | * In fact, SLD3 has DRAM ch2, but the memory regions for ch1 | |
32 | * and ch2 overlap, and host cannot get access to them at the | |
33 | * same time. Hide the ch2 from U-Boot. | |
34 | */ | |
35 | }, | |
36 | { | |
37 | .soc_id = UNIPHIER_LD4_ID, | |
38 | .sparse_ch1_base = 0xc0000000, | |
39 | }, | |
40 | { | |
41 | .soc_id = UNIPHIER_PRO4_ID, | |
42 | .sparse_ch1_base = 0xa0000000, | |
43 | }, | |
44 | { | |
45 | .soc_id = UNIPHIER_SLD8_ID, | |
46 | .sparse_ch1_base = 0xc0000000, | |
47 | }, | |
48 | { | |
49 | .soc_id = UNIPHIER_PRO5_ID, | |
50 | .sparse_ch1_base = 0xc0000000, | |
51 | }, | |
52 | { | |
53 | .soc_id = UNIPHIER_PXS2_ID, | |
54 | .sparse_ch1_base = 0xc0000000, | |
55 | .have_ch2 = 1, | |
56 | }, | |
57 | { | |
58 | .soc_id = UNIPHIER_LD6B_ID, | |
59 | .sparse_ch1_base = 0xc0000000, | |
60 | .have_ch2 = 1, | |
61 | }, | |
62 | { | |
63 | .soc_id = UNIPHIER_LD11_ID, | |
64 | .sparse_ch1_base = 0xc0000000, | |
65 | }, | |
66 | { | |
67 | .soc_id = UNIPHIER_LD20_ID, | |
68 | .sparse_ch1_base = 0xc0000000, | |
69 | .have_ch2 = 1, | |
70 | }, | |
71 | { | |
72 | .soc_id = UNIPHIER_PXS3_ID, | |
73 | .sparse_ch1_base = 0xc0000000, | |
74 | .have_ch2 = 1, | |
75 | }, | |
76 | }; | |
77 | UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data) | |
78 | ||
79 | static int uniphier_memconf_decode(struct uniphier_dram_ch *dram_ch) | |
cf88affa | 80 | { |
3e9952be MY |
81 | const struct uniphier_memif_data *data; |
82 | unsigned long size; | |
83 | u32 val; | |
cf88affa | 84 | |
3e9952be MY |
85 | data = uniphier_get_memif_data(); |
86 | if (!data) { | |
87 | pr_err("unsupported SoC\n"); | |
88 | return -EINVAL; | |
89 | } | |
cf88affa | 90 | |
3e9952be | 91 | val = readl(SG_MEMCONF); |
5894ca00 | 92 | |
3e9952be MY |
93 | /* set up ch0 */ |
94 | dram_ch[0].base = CONFIG_SYS_SDRAM_BASE; | |
95 | ||
96 | switch (val & SG_MEMCONF_CH0_SZ_MASK) { | |
97 | case SG_MEMCONF_CH0_SZ_64M: | |
98 | size = SZ_64M; | |
99 | break; | |
100 | case SG_MEMCONF_CH0_SZ_128M: | |
101 | size = SZ_128M; | |
102 | break; | |
103 | case SG_MEMCONF_CH0_SZ_256M: | |
104 | size = SZ_256M; | |
105 | break; | |
106 | case SG_MEMCONF_CH0_SZ_512M: | |
107 | size = SZ_512M; | |
108 | break; | |
109 | case SG_MEMCONF_CH0_SZ_1G: | |
110 | size = SZ_1G; | |
111 | break; | |
112 | default: | |
0f5bf09c | 113 | pr_err("error: invalid value is set to MEMCONF ch0 size\n"); |
cf88affa | 114 | return -EINVAL; |
ac2a1030 MY |
115 | } |
116 | ||
3e9952be MY |
117 | if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2) |
118 | size *= 2; | |
119 | ||
120 | dram_ch[0].size = size; | |
121 | ||
122 | /* set up ch1 */ | |
123 | dram_ch[1].base = dram_ch[0].base + size; | |
124 | ||
125 | if (val & SG_MEMCONF_SPARSEMEM) { | |
126 | if (dram_ch[1].base > data->sparse_ch1_base) { | |
127 | pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n"); | |
128 | pr_warn("Only ch0 is available\n"); | |
129 | dram_ch[1].base = 0; | |
130 | return 0; | |
131 | } | |
132 | ||
133 | dram_ch[1].base = data->sparse_ch1_base; | |
134 | } | |
135 | ||
136 | switch (val & SG_MEMCONF_CH1_SZ_MASK) { | |
137 | case SG_MEMCONF_CH1_SZ_64M: | |
138 | size = SZ_64M; | |
139 | break; | |
140 | case SG_MEMCONF_CH1_SZ_128M: | |
141 | size = SZ_128M; | |
142 | break; | |
143 | case SG_MEMCONF_CH1_SZ_256M: | |
144 | size = SZ_256M; | |
145 | break; | |
146 | case SG_MEMCONF_CH1_SZ_512M: | |
147 | size = SZ_512M; | |
148 | break; | |
149 | case SG_MEMCONF_CH1_SZ_1G: | |
150 | size = SZ_1G; | |
151 | break; | |
152 | default: | |
0f5bf09c | 153 | pr_err("error: invalid value is set to MEMCONF ch1 size\n"); |
ac2a1030 | 154 | return -EINVAL; |
3e9952be MY |
155 | } |
156 | ||
157 | if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2) | |
158 | size *= 2; | |
ac2a1030 | 159 | |
3e9952be | 160 | dram_ch[1].size = size; |
cf88affa | 161 | |
bed1624d | 162 | if (!data->have_ch2 || val & SG_MEMCONF_CH2_DISABLE) |
3e9952be | 163 | return 0; |
cf88affa | 164 | |
3e9952be MY |
165 | /* set up ch2 */ |
166 | dram_ch[2].base = dram_ch[1].base + size; | |
167 | ||
168 | switch (val & SG_MEMCONF_CH2_SZ_MASK) { | |
169 | case SG_MEMCONF_CH2_SZ_64M: | |
170 | size = SZ_64M; | |
171 | break; | |
172 | case SG_MEMCONF_CH2_SZ_128M: | |
173 | size = SZ_128M; | |
174 | break; | |
175 | case SG_MEMCONF_CH2_SZ_256M: | |
176 | size = SZ_256M; | |
177 | break; | |
178 | case SG_MEMCONF_CH2_SZ_512M: | |
179 | size = SZ_512M; | |
180 | break; | |
181 | case SG_MEMCONF_CH2_SZ_1G: | |
182 | size = SZ_1G; | |
183 | break; | |
184 | default: | |
0f5bf09c | 185 | pr_err("error: invalid value is set to MEMCONF ch2 size\n"); |
3e9952be MY |
186 | return -EINVAL; |
187 | } | |
188 | ||
189 | if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2) | |
190 | size *= 2; | |
191 | ||
192 | dram_ch[2].size = size; | |
5894ca00 | 193 | |
5894ca00 MY |
194 | return 0; |
195 | } | |
cf88affa | 196 | |
3e9952be | 197 | int dram_init(void) |
cf88affa | 198 | { |
3e9952be MY |
199 | struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {}; |
200 | int ret, i; | |
201 | ||
202 | gd->ram_size = 0; | |
203 | ||
204 | ret = uniphier_memconf_decode(dram_ch); | |
205 | if (ret) | |
206 | return ret; | |
207 | ||
208 | for (i = 0; i < ARRAY_SIZE(dram_ch); i++) { | |
209 | ||
210 | if (!dram_ch[i].size) | |
211 | break; | |
212 | ||
213 | /* | |
214 | * U-Boot relocates itself to the tail of the memory region, | |
215 | * but it does not expect sparse memory. We use the first | |
216 | * contiguous chunk here. | |
217 | */ | |
218 | if (i > 0 && | |
219 | dram_ch[i - 1].base + dram_ch[i - 1].size < dram_ch[i].base) | |
220 | break; | |
221 | ||
222 | gd->ram_size += dram_ch[i].size; | |
ac2a1030 MY |
223 | } |
224 | ||
3e9952be MY |
225 | return 0; |
226 | } | |
227 | ||
228 | void dram_init_banksize(void) | |
229 | { | |
230 | struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {}; | |
231 | int i; | |
ac2a1030 | 232 | |
3e9952be | 233 | uniphier_memconf_decode(dram_ch); |
cf88affa | 234 | |
3e9952be MY |
235 | for (i = 0; i < ARRAY_SIZE(dram_ch); i++) { |
236 | if (i >= ARRAY_SIZE(gd->bd->bi_dram)) | |
237 | break; | |
cf88affa | 238 | |
3e9952be MY |
239 | gd->bd->bi_dram[i].start = dram_ch[i].base; |
240 | gd->bd->bi_dram[i].size = dram_ch[i].size; | |
cf88affa MY |
241 | } |
242 | } | |
51ea5a06 MY |
243 | |
244 | #ifdef CONFIG_OF_BOARD_SETUP | |
245 | /* | |
246 | * The DRAM PHY requires 64 byte scratch area in each DRAM channel | |
247 | * for its dynamic PHY training feature. | |
248 | */ | |
249 | int ft_board_setup(void *fdt, bd_t *bd) | |
250 | { | |
51ea5a06 MY |
251 | unsigned long rsv_addr; |
252 | const unsigned long rsv_size = 64; | |
c995f3a3 | 253 | int i, ret; |
51ea5a06 | 254 | |
e27d6c7d | 255 | if (uniphier_get_soc_id() != UNIPHIER_LD20_ID) |
51ea5a06 MY |
256 | return 0; |
257 | ||
c995f3a3 | 258 | for (i = 0; i < ARRAY_SIZE(gd->bd->bi_dram); i++) { |
87c3308c MY |
259 | if (!gd->bd->bi_dram[i].size) |
260 | continue; | |
261 | ||
c995f3a3 | 262 | rsv_addr = gd->bd->bi_dram[i].start + gd->bd->bi_dram[i].size; |
51ea5a06 MY |
263 | rsv_addr -= rsv_size; |
264 | ||
265 | ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size); | |
266 | if (ret) | |
267 | return -ENOSPC; | |
268 | ||
269 | printf(" Reserved memory region for DRAM PHY training: addr=%lx size=%lx\n", | |
270 | rsv_addr, rsv_size); | |
271 | } | |
272 | ||
273 | return 0; | |
274 | } | |
275 | #endif |