blob: 9e57c2ecfa4f63c26584320c83842e5c213deede [file] [log] [blame]
Ley Foon Tan25572cf2019-11-27 15:55:26 +08001// SPDX-License-Identifier: GPL-2.0
2/*
Dinesh Maniyameeea5ec2022-06-01 18:49:02 +08003 * Copyright (C) 2016-2022 Intel Corporation <www.intel.com>
Ley Foon Tan25572cf2019-11-27 15:55:26 +08004 *
5 */
6
Ley Foon Tan25572cf2019-11-27 15:55:26 +08007#include <cpu_func.h>
8#include <dm.h>
9#include <errno.h>
10#include <div64.h>
11#include <fdtdec.h>
Simon Glassf11478f2019-12-28 10:45:07 -070012#include <hang.h>
Simon Glass97589732020-05-10 11:40:02 -060013#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080015#include <ram.h>
16#include <reset.h>
17#include "sdram_soc64.h"
18#include <wait_bit.h>
19#include <asm/arch/firewall.h>
20#include <asm/arch/system_manager.h>
21#include <asm/arch/reset_manager.h>
Simon Glass274e0b02020-05-10 11:39:56 -060022#include <asm/cache.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060023#include <asm/global_data.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080024#include <asm/io.h>
Simon Glass9bc15642020-02-03 07:36:16 -070025#include <dm/device_compat.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080026#include <linux/sizes.h>
27
28#define PGTABLE_OFF 0x4000
29
Simon Glassb75b15b2020-12-03 16:55:23 -070030u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080031{
32 return readl(plat->iomhc + reg);
33}
34
Simon Glassb75b15b2020-12-03 16:55:23 -070035u32 hmc_ecc_readl(struct altera_sdram_plat *plat, u32 reg)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080036{
37 return readl(plat->hmc + reg);
38}
39
Simon Glassb75b15b2020-12-03 16:55:23 -070040u32 hmc_ecc_writel(struct altera_sdram_plat *plat,
Ley Foon Tan25572cf2019-11-27 15:55:26 +080041 u32 data, u32 reg)
42{
43 return writel(data, plat->hmc + reg);
44}
45
Simon Glassb75b15b2020-12-03 16:55:23 -070046u32 ddr_sch_writel(struct altera_sdram_plat *plat, u32 data,
Ley Foon Tan25572cf2019-11-27 15:55:26 +080047 u32 reg)
48{
49 return writel(data, plat->ddr_sch + reg);
50}
51
Simon Glassb75b15b2020-12-03 16:55:23 -070052int emif_clear(struct altera_sdram_plat *plat)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080053{
54 hmc_ecc_writel(plat, 0, RSTHANDSHAKECTRL);
55
56 return wait_for_bit_le32((const void *)(plat->hmc +
57 RSTHANDSHAKESTAT),
58 DDR_HMC_RSTHANDSHAKE_MASK,
59 false, 1000, false);
60}
61
Simon Glassb75b15b2020-12-03 16:55:23 -070062int emif_reset(struct altera_sdram_plat *plat)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080063{
64 u32 c2s, s2c, ret;
65
66 c2s = hmc_ecc_readl(plat, RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK;
67 s2c = hmc_ecc_readl(plat, RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK;
68
69 debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n",
70 c2s, s2c, hmc_readl(plat, NIOSRESERVED0),
71 hmc_readl(plat, NIOSRESERVED1), hmc_readl(plat, NIOSRESERVED2),
72 hmc_readl(plat, DRAMSTS));
73
74 if (s2c && emif_clear(plat)) {
75 printf("DDR: emif_clear() failed\n");
76 return -1;
77 }
78
79 debug("DDR: Triggerring emif reset\n");
80 hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL);
81
82 /* if seq2core[3] = 0, we are good */
83 ret = wait_for_bit_le32((const void *)(plat->hmc +
84 RSTHANDSHAKESTAT),
85 DDR_HMC_SEQ2CORE_INT_RESP_MASK,
86 false, 1000, false);
87 if (ret) {
88 printf("DDR: failed to get ack from EMIF\n");
89 return ret;
90 }
91
92 ret = emif_clear(plat);
93 if (ret) {
94 printf("DDR: emif_clear() failed\n");
95 return ret;
96 }
97
98 debug("DDR: %s triggered successly\n", __func__);
99 return 0;
100}
101
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800102#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800103int poll_hmc_clock_status(void)
104{
105 return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() +
106 SYSMGR_SOC64_HMC_CLK),
107 SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false);
108}
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800109#endif
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800110
111void sdram_clear_mem(phys_addr_t addr, phys_size_t size)
112{
113 phys_size_t i;
114
115 if (addr % CONFIG_SYS_CACHELINE_SIZE) {
116 printf("DDR: address 0x%llx is not cacheline size aligned.\n",
117 addr);
118 hang();
119 }
120
121 if (size % CONFIG_SYS_CACHELINE_SIZE) {
122 printf("DDR: size 0x%llx is not multiple of cacheline size\n",
123 size);
124 hang();
125 }
126
127 /* Use DC ZVA instruction to clear memory to zeros by a cache line */
128 for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) {
129 asm volatile("dc zva, %0"
130 :
131 : "r"(addr)
132 : "memory");
133 addr += CONFIG_SYS_CACHELINE_SIZE;
134 }
135}
136
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900137void sdram_init_ecc_bits(struct bd_info *bd)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800138{
139 phys_size_t size, size_init;
140 phys_addr_t start_addr;
141 int bank = 0;
142 unsigned int start = get_timer(0);
143
144 icache_enable();
145
146 start_addr = bd->bi_dram[0].start;
147 size = bd->bi_dram[0].size;
148
149 /* Initialize small block for page table */
150 memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF);
151 gd->arch.tlb_addr = start_addr + PGTABLE_OFF;
152 gd->arch.tlb_size = PGTABLE_SIZE;
153 start_addr += PGTABLE_SIZE + PGTABLE_OFF;
154 size -= (PGTABLE_OFF + PGTABLE_SIZE);
155 dcache_enable();
156
157 while (1) {
158 while (size) {
159 size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size);
160 sdram_clear_mem(start_addr, size_init);
161 size -= size_init;
162 start_addr += size_init;
Stefan Roese80877fa2022-09-02 14:10:46 +0200163 schedule();
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800164 }
165
166 bank++;
167 if (bank >= CONFIG_NR_DRAM_BANKS)
168 break;
169
170 start_addr = bd->bi_dram[bank].start;
171 size = bd->bi_dram[bank].size;
172 }
173
174 dcache_disable();
175 icache_disable();
176
177 printf("SDRAM-ECC: Initialized success with %d ms\n",
178 (unsigned int)get_timer(start));
179}
180
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900181void sdram_size_check(struct bd_info *bd)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800182{
183 phys_size_t total_ram_check = 0;
184 phys_size_t ram_check = 0;
185 phys_addr_t start = 0;
Tien Fong Cheea5132382021-08-10 11:26:36 +0800186 phys_size_t size, remaining_size;
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800187 int bank;
188
189 /* Sanity check ensure correct SDRAM size specified */
190 debug("DDR: Running SDRAM size sanity check\n");
191
192 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
193 start = bd->bi_dram[bank].start;
Tien Fong Cheea5132382021-08-10 11:26:36 +0800194 remaining_size = bd->bi_dram[bank].size;
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800195 while (ram_check < bd->bi_dram[bank].size) {
Tien Fong Cheea5132382021-08-10 11:26:36 +0800196 size = min((phys_addr_t)SZ_1G,
197 (phys_addr_t)remaining_size);
198
199 /*
200 * Ensure the size is power of two, this is requirement
201 * to run get_ram_size() / memory test
202 */
203 if (size != 0 && ((size & (size - 1)) == 0)) {
204 ram_check += get_ram_size((void *)
205 (start + ram_check), size);
206 remaining_size = bd->bi_dram[bank].size -
207 ram_check;
208 } else {
209 puts("DDR: Memory test requires SDRAM size ");
210 puts("in power of two!\n");
211 hang();
212 }
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800213 }
Tien Fong Cheea5132382021-08-10 11:26:36 +0800214
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800215 total_ram_check += ram_check;
216 ram_check = 0;
217 }
218
219 /* If the ram_size is 2GB smaller, we can assume the IO space is
220 * not mapped in. gd->ram_size is the actual size of the dram
221 * not the accessible size.
222 */
223 if (total_ram_check != gd->ram_size) {
224 puts("DDR: SDRAM size check failed!\n");
225 hang();
226 }
227
228 debug("DDR: SDRAM size check passed!\n");
229}
230
231/**
232 * sdram_calculate_size() - Calculate SDRAM size
233 *
234 * Calculate SDRAM device size based on SDRAM controller parameters.
235 * Size is specified in bytes.
236 */
Simon Glassb75b15b2020-12-03 16:55:23 -0700237phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800238{
239 u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
240
Dinesh Maniyameeea5ec2022-06-01 18:49:02 +0800241 phys_size_t size = (phys_size_t)1 <<
242 (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800243 DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
244 DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
245 DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
246 DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw));
247
248 size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) &
249 DDR_HMC_DDRIOCTRL_IOSIZE_MSK));
250
251 return size;
252}
253
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800254void sdram_set_firewall(struct bd_info *bd)
255{
256 u32 i;
257 phys_size_t value;
258 u32 lower, upper;
259
260 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
261 if (!bd->bi_dram[i].size)
262 continue;
263
264 value = bd->bi_dram[i].start;
265
266 /* Keep first 1MB of SDRAM memory region as secure region when
267 * using ATF flow, where the ATF code is located.
268 */
269 if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0)
270 value += SZ_1M;
271
272 /* Setting non-secure MPU region base and base extended */
273 lower = lower_32_bits(value);
274 upper = upper_32_bits(value);
275 FW_MPU_DDR_SCR_WRITEL(lower,
276 FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE +
277 (i * 4 * sizeof(u32)));
278 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
279 FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT +
280 (i * 4 * sizeof(u32)));
281
282 /* Setting non-secure Non-MPU region base and base extended */
283 FW_MPU_DDR_SCR_WRITEL(lower,
284 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE +
285 (i * 4 * sizeof(u32)));
286 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
287 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT +
288 (i * 4 * sizeof(u32)));
289
290 /* Setting non-secure MPU limit and limit extexded */
291 value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
292
293 lower = lower_32_bits(value);
294 upper = upper_32_bits(value);
295
296 FW_MPU_DDR_SCR_WRITEL(lower,
297 FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT +
298 (i * 4 * sizeof(u32)));
299 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
300 FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT +
301 (i * 4 * sizeof(u32)));
302
303 /* Setting non-secure Non-MPU limit and limit extexded */
304 FW_MPU_DDR_SCR_WRITEL(lower,
305 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT +
306 (i * 4 * sizeof(u32)));
307 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
308 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT +
309 (i * 4 * sizeof(u32)));
310
311 FW_MPU_DDR_SCR_WRITEL(BIT(i) | BIT(i + 8),
312 FW_MPU_DDR_SCR_EN_SET);
313 }
314}
315
Simon Glassaad29ae2020-12-03 16:55:21 -0700316static int altera_sdram_of_to_plat(struct udevice *dev)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800317{
Simon Glass95588622020-12-22 19:30:28 -0700318 struct altera_sdram_plat *plat = dev_get_plat(dev);
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800319 fdt_addr_t addr;
320
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800321 /* These regs info are part of DDR handoff in bitstream */
322#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
323 return 0;
324#endif
325
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800326 addr = dev_read_addr_index(dev, 0);
327 if (addr == FDT_ADDR_T_NONE)
328 return -EINVAL;
329 plat->ddr_sch = (void __iomem *)addr;
330
331 addr = dev_read_addr_index(dev, 1);
332 if (addr == FDT_ADDR_T_NONE)
333 return -EINVAL;
334 plat->iomhc = (void __iomem *)addr;
335
336 addr = dev_read_addr_index(dev, 2);
337 if (addr == FDT_ADDR_T_NONE)
338 return -EINVAL;
339 plat->hmc = (void __iomem *)addr;
340
341 return 0;
342}
343
344static int altera_sdram_probe(struct udevice *dev)
345{
346 int ret;
347 struct altera_sdram_priv *priv = dev_get_priv(dev);
348
349 ret = reset_get_bulk(dev, &priv->resets);
350 if (ret) {
351 dev_err(dev, "Can't get reset: %d\n", ret);
352 return -ENODEV;
353 }
354 reset_deassert_bulk(&priv->resets);
355
356 if (sdram_mmr_init_full(dev) != 0) {
357 puts("SDRAM init failed.\n");
358 goto failed;
359 }
360
361 return 0;
362
363failed:
364 reset_release_bulk(&priv->resets);
365 return -ENODEV;
366}
367
368static int altera_sdram_get_info(struct udevice *dev,
369 struct ram_info *info)
370{
371 struct altera_sdram_priv *priv = dev_get_priv(dev);
372
373 info->base = priv->info.base;
374 info->size = priv->info.size;
375
376 return 0;
377}
378
379static struct ram_ops altera_sdram_ops = {
380 .get_info = altera_sdram_get_info,
381};
382
383static const struct udevice_id altera_sdram_ids[] = {
384 { .compatible = "altr,sdr-ctl-s10" },
Ley Foon Tan4ddb9092019-11-27 15:55:27 +0800385 { .compatible = "intel,sdr-ctl-agilex" },
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800386 { .compatible = "intel,sdr-ctl-n5x" },
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800387 { /* sentinel */ }
388};
389
390U_BOOT_DRIVER(altera_sdram) = {
391 .name = "altr_sdr_ctl",
392 .id = UCLASS_RAM,
393 .of_match = altera_sdram_ids,
394 .ops = &altera_sdram_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700395 .of_to_plat = altera_sdram_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700396 .plat_auto = sizeof(struct altera_sdram_plat),
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800397 .probe = altera_sdram_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700398 .priv_auto = sizeof(struct altera_sdram_priv),
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800399};