]> git.sur5r.net Git - u-boot/blob - arch/arm/mach-uniphier/dram_init.c
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
[u-boot] / arch / arm / mach-uniphier / dram_init.c
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 DECLARE_GLOBAL_DATA_PTR;
19
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_LD4_ID,
29                 .sparse_ch1_base = 0xc0000000,
30         },
31         {
32                 .soc_id = UNIPHIER_PRO4_ID,
33                 .sparse_ch1_base = 0xa0000000,
34         },
35         {
36                 .soc_id = UNIPHIER_SLD8_ID,
37                 .sparse_ch1_base = 0xc0000000,
38         },
39         {
40                 .soc_id = UNIPHIER_PRO5_ID,
41                 .sparse_ch1_base = 0xc0000000,
42         },
43         {
44                 .soc_id = UNIPHIER_PXS2_ID,
45                 .sparse_ch1_base = 0xc0000000,
46                 .have_ch2 = 1,
47         },
48         {
49                 .soc_id = UNIPHIER_LD6B_ID,
50                 .sparse_ch1_base = 0xc0000000,
51                 .have_ch2 = 1,
52         },
53         {
54                 .soc_id = UNIPHIER_LD11_ID,
55                 .sparse_ch1_base = 0xc0000000,
56         },
57         {
58                 .soc_id = UNIPHIER_LD20_ID,
59                 .sparse_ch1_base = 0xc0000000,
60                 .have_ch2 = 1,
61         },
62         {
63                 .soc_id = UNIPHIER_PXS3_ID,
64                 .sparse_ch1_base = 0xc0000000,
65                 .have_ch2 = 1,
66         },
67 };
68 UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data)
69
70 struct uniphier_dram_map {
71         unsigned long base;
72         unsigned long size;
73 };
74
75 static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map)
76 {
77         const struct uniphier_memif_data *data;
78         unsigned long size;
79         u32 val;
80
81         data = uniphier_get_memif_data();
82         if (!data) {
83                 pr_err("unsupported SoC\n");
84                 return -EINVAL;
85         }
86
87         val = readl(SG_MEMCONF);
88
89         /* set up ch0 */
90         dram_map[0].base = CONFIG_SYS_SDRAM_BASE;
91
92         switch (val & SG_MEMCONF_CH0_SZ_MASK) {
93         case SG_MEMCONF_CH0_SZ_64M:
94                 size = SZ_64M;
95                 break;
96         case SG_MEMCONF_CH0_SZ_128M:
97                 size = SZ_128M;
98                 break;
99         case SG_MEMCONF_CH0_SZ_256M:
100                 size = SZ_256M;
101                 break;
102         case SG_MEMCONF_CH0_SZ_512M:
103                 size = SZ_512M;
104                 break;
105         case SG_MEMCONF_CH0_SZ_1G:
106                 size = SZ_1G;
107                 break;
108         default:
109                 pr_err("error: invalid value is set to MEMCONF ch0 size\n");
110                 return -EINVAL;
111         }
112
113         if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
114                 size *= 2;
115
116         dram_map[0].size = size;
117
118         /* set up ch1 */
119         dram_map[1].base = dram_map[0].base + size;
120
121         if (val & SG_MEMCONF_SPARSEMEM) {
122                 if (dram_map[1].base > data->sparse_ch1_base) {
123                         pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
124                         pr_warn("Only ch0 is available\n");
125                         dram_map[1].base = 0;
126                         return 0;
127                 }
128
129                 dram_map[1].base = data->sparse_ch1_base;
130         }
131
132         switch (val & SG_MEMCONF_CH1_SZ_MASK) {
133         case SG_MEMCONF_CH1_SZ_64M:
134                 size = SZ_64M;
135                 break;
136         case SG_MEMCONF_CH1_SZ_128M:
137                 size = SZ_128M;
138                 break;
139         case SG_MEMCONF_CH1_SZ_256M:
140                 size = SZ_256M;
141                 break;
142         case SG_MEMCONF_CH1_SZ_512M:
143                 size = SZ_512M;
144                 break;
145         case SG_MEMCONF_CH1_SZ_1G:
146                 size = SZ_1G;
147                 break;
148         default:
149                 pr_err("error: invalid value is set to MEMCONF ch1 size\n");
150                 return -EINVAL;
151         }
152
153         if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
154                 size *= 2;
155
156         dram_map[1].size = size;
157
158         if (!data->have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
159                 return 0;
160
161         /* set up ch2 */
162         dram_map[2].base = dram_map[1].base + size;
163
164         switch (val & SG_MEMCONF_CH2_SZ_MASK) {
165         case SG_MEMCONF_CH2_SZ_64M:
166                 size = SZ_64M;
167                 break;
168         case SG_MEMCONF_CH2_SZ_128M:
169                 size = SZ_128M;
170                 break;
171         case SG_MEMCONF_CH2_SZ_256M:
172                 size = SZ_256M;
173                 break;
174         case SG_MEMCONF_CH2_SZ_512M:
175                 size = SZ_512M;
176                 break;
177         case SG_MEMCONF_CH2_SZ_1G:
178                 size = SZ_1G;
179                 break;
180         default:
181                 pr_err("error: invalid value is set to MEMCONF ch2 size\n");
182                 return -EINVAL;
183         }
184
185         if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
186                 size *= 2;
187
188         dram_map[2].size = size;
189
190         return 0;
191 }
192
193 int dram_init(void)
194 {
195         struct uniphier_dram_map dram_map[3] = {};
196         int ret, i;
197
198         gd->ram_size = 0;
199
200         ret = uniphier_memconf_decode(dram_map);
201         if (ret)
202                 return ret;
203
204         for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
205
206                 if (!dram_map[i].size)
207                         break;
208
209                 /*
210                  * U-Boot relocates itself to the tail of the memory region,
211                  * but it does not expect sparse memory.  We use the first
212                  * contiguous chunk here.
213                  */
214                 if (i > 0 && dram_map[i - 1].base + dram_map[i - 1].size <
215                                                         dram_map[i].base)
216                         break;
217
218                 gd->ram_size += dram_map[i].size;
219         }
220
221         return 0;
222 }
223
224 int dram_init_banksize(void)
225 {
226         struct uniphier_dram_map dram_map[3] = {};
227         int i;
228
229         uniphier_memconf_decode(dram_map);
230
231         for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
232                 if (i >= ARRAY_SIZE(gd->bd->bi_dram))
233                         break;
234
235                 gd->bd->bi_dram[i].start = dram_map[i].base;
236                 gd->bd->bi_dram[i].size = dram_map[i].size;
237         }
238
239         return 0;
240 }
241
242 #ifdef CONFIG_OF_BOARD_SETUP
243 /*
244  * The DRAM PHY requires 64 byte scratch area in each DRAM channel
245  * for its dynamic PHY training feature.
246  */
247 int ft_board_setup(void *fdt, bd_t *bd)
248 {
249         unsigned long rsv_addr;
250         const unsigned long rsv_size = 64;
251         int i, ret;
252
253         if (uniphier_get_soc_id() != UNIPHIER_LD20_ID)
254                 return 0;
255
256         for (i = 0; i < ARRAY_SIZE(gd->bd->bi_dram); i++) {
257                 if (!gd->bd->bi_dram[i].size)
258                         continue;
259
260                 rsv_addr = gd->bd->bi_dram[i].start + gd->bd->bi_dram[i].size;
261                 rsv_addr -= rsv_size;
262
263                 ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size);
264                 if (ret)
265                         return -ENOSPC;
266
267                 printf("   Reserved memory region for DRAM PHY training: addr=%lx size=%lx\n",
268                        rsv_addr, rsv_size);
269         }
270
271         return 0;
272 }
273 #endif