1
2
3
4
5
6
7
8#include <common.h>
9#include <linux/errno.h>
10#include <linux/io.h>
11#include <linux/kernel.h>
12#include <linux/printk.h>
13#include <linux/sizes.h>
14#include <asm/global_data.h>
15
16#include "init.h"
17#include "sg-regs.h"
18#include "soc-info.h"
19
20DECLARE_GLOBAL_DATA_PTR;
21
22struct uniphier_dram_map {
23 unsigned long base;
24 unsigned long size;
25};
26
27static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map,
28 unsigned long sparse_ch1_base, bool have_ch2)
29{
30 unsigned long size;
31 u32 val;
32
33 val = readl(sg_base + SG_MEMCONF);
34
35
36 dram_map[0].base = 0x80000000;
37
38 switch (val & SG_MEMCONF_CH0_SZ_MASK) {
39 case SG_MEMCONF_CH0_SZ_64M:
40 size = SZ_64M;
41 break;
42 case SG_MEMCONF_CH0_SZ_128M:
43 size = SZ_128M;
44 break;
45 case SG_MEMCONF_CH0_SZ_256M:
46 size = SZ_256M;
47 break;
48 case SG_MEMCONF_CH0_SZ_512M:
49 size = SZ_512M;
50 break;
51 case SG_MEMCONF_CH0_SZ_1G:
52 size = SZ_1G;
53 break;
54 default:
55 pr_err("error: invalid value is set to MEMCONF ch0 size\n");
56 return -EINVAL;
57 }
58
59 if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
60 size *= 2;
61
62 dram_map[0].size = size;
63
64
65 dram_map[1].base = dram_map[0].base + size;
66
67 if (val & SG_MEMCONF_SPARSEMEM) {
68 if (dram_map[1].base > sparse_ch1_base) {
69 pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
70 pr_warn("Only ch0 is available\n");
71 dram_map[1].base = 0;
72 return 0;
73 }
74
75 dram_map[1].base = sparse_ch1_base;
76 }
77
78 switch (val & SG_MEMCONF_CH1_SZ_MASK) {
79 case SG_MEMCONF_CH1_SZ_64M:
80 size = SZ_64M;
81 break;
82 case SG_MEMCONF_CH1_SZ_128M:
83 size = SZ_128M;
84 break;
85 case SG_MEMCONF_CH1_SZ_256M:
86 size = SZ_256M;
87 break;
88 case SG_MEMCONF_CH1_SZ_512M:
89 size = SZ_512M;
90 break;
91 case SG_MEMCONF_CH1_SZ_1G:
92 size = SZ_1G;
93 break;
94 default:
95 pr_err("error: invalid value is set to MEMCONF ch1 size\n");
96 return -EINVAL;
97 }
98
99 if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
100 size *= 2;
101
102 dram_map[1].size = size;
103
104 if (!have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
105 return 0;
106
107
108 dram_map[2].base = dram_map[1].base + size;
109
110 switch (val & SG_MEMCONF_CH2_SZ_MASK) {
111 case SG_MEMCONF_CH2_SZ_64M:
112 size = SZ_64M;
113 break;
114 case SG_MEMCONF_CH2_SZ_128M:
115 size = SZ_128M;
116 break;
117 case SG_MEMCONF_CH2_SZ_256M:
118 size = SZ_256M;
119 break;
120 case SG_MEMCONF_CH2_SZ_512M:
121 size = SZ_512M;
122 break;
123 case SG_MEMCONF_CH2_SZ_1G:
124 size = SZ_1G;
125 break;
126 default:
127 pr_err("error: invalid value is set to MEMCONF ch2 size\n");
128 return -EINVAL;
129 }
130
131 if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
132 size *= 2;
133
134 dram_map[2].size = size;
135
136 return 0;
137}
138
139static int uniphier_ld4_dram_map_get(struct uniphier_dram_map dram_map[])
140{
141 return uniphier_memconf_decode(dram_map, 0xc0000000, false);
142}
143
144static int uniphier_pro4_dram_map_get(struct uniphier_dram_map dram_map[])
145{
146 return uniphier_memconf_decode(dram_map, 0xa0000000, false);
147}
148
149static int uniphier_pxs2_dram_map_get(struct uniphier_dram_map dram_map[])
150{
151 return uniphier_memconf_decode(dram_map, 0xc0000000, true);
152}
153
154struct uniphier_dram_init_data {
155 unsigned int soc_id;
156 int (*dram_map_get)(struct uniphier_dram_map dram_map[]);
157};
158
159static const struct uniphier_dram_init_data uniphier_dram_init_data[] = {
160 {
161 .soc_id = UNIPHIER_LD4_ID,
162 .dram_map_get = uniphier_ld4_dram_map_get,
163 },
164 {
165 .soc_id = UNIPHIER_PRO4_ID,
166 .dram_map_get = uniphier_pro4_dram_map_get,
167 },
168 {
169 .soc_id = UNIPHIER_SLD8_ID,
170 .dram_map_get = uniphier_ld4_dram_map_get,
171 },
172 {
173 .soc_id = UNIPHIER_PRO5_ID,
174 .dram_map_get = uniphier_ld4_dram_map_get,
175 },
176 {
177 .soc_id = UNIPHIER_PXS2_ID,
178 .dram_map_get = uniphier_pxs2_dram_map_get,
179 },
180 {
181 .soc_id = UNIPHIER_LD6B_ID,
182 .dram_map_get = uniphier_pxs2_dram_map_get,
183 },
184 {
185 .soc_id = UNIPHIER_LD11_ID,
186 .dram_map_get = uniphier_ld4_dram_map_get,
187 },
188 {
189 .soc_id = UNIPHIER_LD20_ID,
190 .dram_map_get = uniphier_pxs2_dram_map_get,
191 },
192 {
193 .soc_id = UNIPHIER_PXS3_ID,
194 .dram_map_get = uniphier_pxs2_dram_map_get,
195 },
196};
197UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_dram_init_data,
198 uniphier_dram_init_data)
199
200static int uniphier_dram_map_get(struct uniphier_dram_map *dram_map)
201{
202 const struct uniphier_dram_init_data *data;
203
204 data = uniphier_get_dram_init_data();
205 if (!data) {
206 pr_err("unsupported SoC\n");
207 return -ENOTSUPP;
208 }
209
210 return data->dram_map_get(dram_map);
211}
212
213int dram_init(void)
214{
215 struct uniphier_dram_map dram_map[3] = {};
216 bool valid_bank_found = false;
217 unsigned long prev_top;
218 int ret, i;
219
220 gd->ram_size = 0;
221
222 ret = uniphier_dram_map_get(dram_map);
223 if (ret)
224 return ret;
225
226 for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
227 unsigned long max_size;
228
229 if (!dram_map[i].size)
230 continue;
231
232
233
234
235
236
237 if (valid_bank_found && prev_top < dram_map[i].base)
238 break;
239
240
241
242
243
244
245
246 if (dram_map[i].base >= 1ULL << 32)
247 break;
248
249 max_size = (1ULL << 32) - dram_map[i].base;
250
251 gd->ram_size = min(dram_map[i].size, max_size);
252
253 if (!valid_bank_found)
254 gd->ram_base = dram_map[i].base;
255
256 prev_top = dram_map[i].base + dram_map[i].size;
257 valid_bank_found = true;
258 }
259
260
261
262
263
264 if (uniphier_get_soc_id() == UNIPHIER_LD20_ID)
265 gd->ram_size -= 64;
266
267 return 0;
268}
269
270int dram_init_banksize(void)
271{
272 struct uniphier_dram_map dram_map[3] = {};
273 unsigned long base, top;
274 bool valid_bank_found = false;
275 int ret, i;
276
277 ret = uniphier_dram_map_get(dram_map);
278 if (ret)
279 return ret;
280
281 for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
282 if (i < ARRAY_SIZE(gd->bd->bi_dram)) {
283 gd->bd->bi_dram[i].start = dram_map[i].base;
284 gd->bd->bi_dram[i].size = dram_map[i].size;
285 }
286
287 if (!dram_map[i].size)
288 continue;
289
290 if (!valid_bank_found)
291 base = dram_map[i].base;
292 top = dram_map[i].base + dram_map[i].size;
293 valid_bank_found = true;
294 }
295
296 if (!valid_bank_found)
297 return -EINVAL;
298
299
300 uniphier_mem_map_init(base, top - base);
301
302 return 0;
303}
304