ARM: uniphier: de-couple SG macros into base address and offset
[oweals/u-boot.git] / arch / arm / mach-uniphier / dram_init.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2012-2015 Panasonic Corporation
4  * Copyright (C) 2015-2017 Socionext Inc.
5  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
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 "sg-regs.h"
17 #include "soc-info.h"
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 struct uniphier_memif_data {
22         unsigned int soc_id;
23         unsigned long sparse_ch1_base;
24         int have_ch2;
25 };
26
27 static const struct uniphier_memif_data uniphier_memif_data[] = {
28         {
29                 .soc_id = UNIPHIER_LD4_ID,
30                 .sparse_ch1_base = 0xc0000000,
31         },
32         {
33                 .soc_id = UNIPHIER_PRO4_ID,
34                 .sparse_ch1_base = 0xa0000000,
35         },
36         {
37                 .soc_id = UNIPHIER_SLD8_ID,
38                 .sparse_ch1_base = 0xc0000000,
39         },
40         {
41                 .soc_id = UNIPHIER_PRO5_ID,
42                 .sparse_ch1_base = 0xc0000000,
43         },
44         {
45                 .soc_id = UNIPHIER_PXS2_ID,
46                 .sparse_ch1_base = 0xc0000000,
47                 .have_ch2 = 1,
48         },
49         {
50                 .soc_id = UNIPHIER_LD6B_ID,
51                 .sparse_ch1_base = 0xc0000000,
52                 .have_ch2 = 1,
53         },
54         {
55                 .soc_id = UNIPHIER_LD11_ID,
56                 .sparse_ch1_base = 0xc0000000,
57         },
58         {
59                 .soc_id = UNIPHIER_LD20_ID,
60                 .sparse_ch1_base = 0xc0000000,
61                 .have_ch2 = 1,
62         },
63         {
64                 .soc_id = UNIPHIER_PXS3_ID,
65                 .sparse_ch1_base = 0xc0000000,
66                 .have_ch2 = 1,
67         },
68 };
69 UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data)
70
71 struct uniphier_dram_map {
72         unsigned long base;
73         unsigned long size;
74 };
75
76 static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map)
77 {
78         const struct uniphier_memif_data *data;
79         unsigned long size;
80         u32 val;
81
82         data = uniphier_get_memif_data();
83         if (!data) {
84                 pr_err("unsupported SoC\n");
85                 return -EINVAL;
86         }
87
88         val = readl(sg_base + SG_MEMCONF);
89
90         /* set up ch0 */
91         dram_map[0].base = CONFIG_SYS_SDRAM_BASE;
92
93         switch (val & SG_MEMCONF_CH0_SZ_MASK) {
94         case SG_MEMCONF_CH0_SZ_64M:
95                 size = SZ_64M;
96                 break;
97         case SG_MEMCONF_CH0_SZ_128M:
98                 size = SZ_128M;
99                 break;
100         case SG_MEMCONF_CH0_SZ_256M:
101                 size = SZ_256M;
102                 break;
103         case SG_MEMCONF_CH0_SZ_512M:
104                 size = SZ_512M;
105                 break;
106         case SG_MEMCONF_CH0_SZ_1G:
107                 size = SZ_1G;
108                 break;
109         default:
110                 pr_err("error: invalid value is set to MEMCONF ch0 size\n");
111                 return -EINVAL;
112         }
113
114         if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
115                 size *= 2;
116
117         dram_map[0].size = size;
118
119         /* set up ch1 */
120         dram_map[1].base = dram_map[0].base + size;
121
122         if (val & SG_MEMCONF_SPARSEMEM) {
123                 if (dram_map[1].base > data->sparse_ch1_base) {
124                         pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
125                         pr_warn("Only ch0 is available\n");
126                         dram_map[1].base = 0;
127                         return 0;
128                 }
129
130                 dram_map[1].base = data->sparse_ch1_base;
131         }
132
133         switch (val & SG_MEMCONF_CH1_SZ_MASK) {
134         case SG_MEMCONF_CH1_SZ_64M:
135                 size = SZ_64M;
136                 break;
137         case SG_MEMCONF_CH1_SZ_128M:
138                 size = SZ_128M;
139                 break;
140         case SG_MEMCONF_CH1_SZ_256M:
141                 size = SZ_256M;
142                 break;
143         case SG_MEMCONF_CH1_SZ_512M:
144                 size = SZ_512M;
145                 break;
146         case SG_MEMCONF_CH1_SZ_1G:
147                 size = SZ_1G;
148                 break;
149         default:
150                 pr_err("error: invalid value is set to MEMCONF ch1 size\n");
151                 return -EINVAL;
152         }
153
154         if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
155                 size *= 2;
156
157         dram_map[1].size = size;
158
159         if (!data->have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
160                 return 0;
161
162         /* set up ch2 */
163         dram_map[2].base = dram_map[1].base + size;
164
165         switch (val & SG_MEMCONF_CH2_SZ_MASK) {
166         case SG_MEMCONF_CH2_SZ_64M:
167                 size = SZ_64M;
168                 break;
169         case SG_MEMCONF_CH2_SZ_128M:
170                 size = SZ_128M;
171                 break;
172         case SG_MEMCONF_CH2_SZ_256M:
173                 size = SZ_256M;
174                 break;
175         case SG_MEMCONF_CH2_SZ_512M:
176                 size = SZ_512M;
177                 break;
178         case SG_MEMCONF_CH2_SZ_1G:
179                 size = SZ_1G;
180                 break;
181         default:
182                 pr_err("error: invalid value is set to MEMCONF ch2 size\n");
183                 return -EINVAL;
184         }
185
186         if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
187                 size *= 2;
188
189         dram_map[2].size = size;
190
191         return 0;
192 }
193
194 int dram_init(void)
195 {
196         struct uniphier_dram_map dram_map[3] = {};
197         int ret, i;
198
199         gd->ram_size = 0;
200
201         ret = uniphier_memconf_decode(dram_map);
202         if (ret)
203                 return ret;
204
205         for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
206                 unsigned long max_size;
207
208                 if (!dram_map[i].size)
209                         break;
210
211                 /*
212                  * U-Boot relocates itself to the tail of the memory region,
213                  * but it does not expect sparse memory.  We use the first
214                  * contiguous chunk here.
215                  */
216                 if (i > 0 && dram_map[i - 1].base + dram_map[i - 1].size <
217                                                         dram_map[i].base)
218                         break;
219
220                 /*
221                  * Do not use memory that exceeds 32bit address range.  U-Boot
222                  * relocates itself to the end of the effectively available RAM.
223                  * This could be a problem for DMA engines that do not support
224                  * 64bit address (SDMA of SDHCI, UniPhier AV-ether, etc.)
225                  */
226                 if (dram_map[i].base >= 1ULL << 32)
227                         break;
228
229                 max_size = (1ULL << 32) - dram_map[i].base;
230
231                 if (dram_map[i].size > max_size) {
232                         gd->ram_size += max_size;
233                         break;
234                 }
235
236                 gd->ram_size += dram_map[i].size;
237         }
238
239         /*
240          * LD20 uses the last 64 byte for each channel for dynamic
241          * DDR PHY training
242          */
243         if (uniphier_get_soc_id() == UNIPHIER_LD20_ID)
244                 gd->ram_size -= 64;
245
246         return 0;
247 }
248
249 int dram_init_banksize(void)
250 {
251         struct uniphier_dram_map dram_map[3] = {};
252         int i;
253
254         uniphier_memconf_decode(dram_map);
255
256         for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
257                 if (i >= ARRAY_SIZE(gd->bd->bi_dram))
258                         break;
259
260                 gd->bd->bi_dram[i].start = dram_map[i].base;
261                 gd->bd->bi_dram[i].size = dram_map[i].size;
262         }
263
264         return 0;
265 }