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