blob: 27fbe80ed41a8a963685cd9504b2d98bc0ca06c2 [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>
Tingting Menga1a24f12025-02-21 21:49:41 +08004 * Copyright (C) 2025 Altera Corporation <www.altera.com>
Ley Foon Tan25572cf2019-11-27 15:55:26 +08005 *
6 */
7
Ley Foon Tan25572cf2019-11-27 15:55:26 +08008#include <cpu_func.h>
9#include <dm.h>
10#include <errno.h>
11#include <div64.h>
12#include <fdtdec.h>
Simon Glassf11478f2019-12-28 10:45:07 -070013#include <hang.h>
Simon Glass97589732020-05-10 11:40:02 -060014#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060015#include <log.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080016#include <ram.h>
17#include <reset.h>
18#include "sdram_soc64.h"
19#include <wait_bit.h>
20#include <asm/arch/firewall.h>
21#include <asm/arch/system_manager.h>
22#include <asm/arch/reset_manager.h>
Simon Glass274e0b02020-05-10 11:39:56 -060023#include <asm/cache.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060024#include <asm/global_data.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080025#include <asm/io.h>
Simon Glass9bc15642020-02-03 07:36:16 -070026#include <dm/device_compat.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080027#include <linux/sizes.h>
Rasmus Villemoesf2811fa2024-10-03 23:28:00 +020028#include <u-boot/schedule.h>
Ley Foon Tan25572cf2019-11-27 15:55:26 +080029
30#define PGTABLE_OFF 0x4000
31
Tingting Menga1a24f12025-02-21 21:49:41 +080032#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
Simon Glassb75b15b2020-12-03 16:55:23 -070033u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080034{
35 return readl(plat->iomhc + reg);
36}
37
Simon Glassb75b15b2020-12-03 16:55:23 -070038u32 hmc_ecc_readl(struct altera_sdram_plat *plat, u32 reg)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080039{
40 return readl(plat->hmc + reg);
41}
42
Simon Glassb75b15b2020-12-03 16:55:23 -070043u32 hmc_ecc_writel(struct altera_sdram_plat *plat,
Ley Foon Tan25572cf2019-11-27 15:55:26 +080044 u32 data, u32 reg)
45{
46 return writel(data, plat->hmc + reg);
47}
48
Simon Glassb75b15b2020-12-03 16:55:23 -070049u32 ddr_sch_writel(struct altera_sdram_plat *plat, u32 data,
Ley Foon Tan25572cf2019-11-27 15:55:26 +080050 u32 reg)
51{
52 return writel(data, plat->ddr_sch + reg);
53}
54
Simon Glassb75b15b2020-12-03 16:55:23 -070055int emif_clear(struct altera_sdram_plat *plat)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080056{
57 hmc_ecc_writel(plat, 0, RSTHANDSHAKECTRL);
58
59 return wait_for_bit_le32((const void *)(plat->hmc +
60 RSTHANDSHAKESTAT),
61 DDR_HMC_RSTHANDSHAKE_MASK,
62 false, 1000, false);
63}
64
Simon Glassb75b15b2020-12-03 16:55:23 -070065int emif_reset(struct altera_sdram_plat *plat)
Ley Foon Tan25572cf2019-11-27 15:55:26 +080066{
67 u32 c2s, s2c, ret;
68
69 c2s = hmc_ecc_readl(plat, RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK;
70 s2c = hmc_ecc_readl(plat, RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK;
71
72 debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n",
73 c2s, s2c, hmc_readl(plat, NIOSRESERVED0),
74 hmc_readl(plat, NIOSRESERVED1), hmc_readl(plat, NIOSRESERVED2),
75 hmc_readl(plat, DRAMSTS));
76
77 if (s2c && emif_clear(plat)) {
78 printf("DDR: emif_clear() failed\n");
79 return -1;
80 }
81
82 debug("DDR: Triggerring emif reset\n");
83 hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL);
84
85 /* if seq2core[3] = 0, we are good */
86 ret = wait_for_bit_le32((const void *)(plat->hmc +
87 RSTHANDSHAKESTAT),
88 DDR_HMC_SEQ2CORE_INT_RESP_MASK,
89 false, 1000, false);
90 if (ret) {
91 printf("DDR: failed to get ack from EMIF\n");
92 return ret;
93 }
94
95 ret = emif_clear(plat);
96 if (ret) {
97 printf("DDR: emif_clear() failed\n");
98 return ret;
99 }
100
101 debug("DDR: %s triggered successly\n", __func__);
102 return 0;
103}
Tingting Menga1a24f12025-02-21 21:49:41 +0800104#endif
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800105
Tingting Menga1a24f12025-02-21 21:49:41 +0800106#if !(IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) || IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5))
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800107int poll_hmc_clock_status(void)
108{
109 return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() +
110 SYSMGR_SOC64_HMC_CLK),
111 SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false);
112}
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800113#endif
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800114
115void sdram_clear_mem(phys_addr_t addr, phys_size_t size)
116{
117 phys_size_t i;
118
119 if (addr % CONFIG_SYS_CACHELINE_SIZE) {
120 printf("DDR: address 0x%llx is not cacheline size aligned.\n",
121 addr);
122 hang();
123 }
124
125 if (size % CONFIG_SYS_CACHELINE_SIZE) {
126 printf("DDR: size 0x%llx is not multiple of cacheline size\n",
127 size);
128 hang();
129 }
130
131 /* Use DC ZVA instruction to clear memory to zeros by a cache line */
132 for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) {
133 asm volatile("dc zva, %0"
134 :
135 : "r"(addr)
136 : "memory");
137 addr += CONFIG_SYS_CACHELINE_SIZE;
138 }
139}
140
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900141void sdram_init_ecc_bits(struct bd_info *bd)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800142{
143 phys_size_t size, size_init;
144 phys_addr_t start_addr;
145 int bank = 0;
146 unsigned int start = get_timer(0);
147
148 icache_enable();
149
150 start_addr = bd->bi_dram[0].start;
151 size = bd->bi_dram[0].size;
152
153 /* Initialize small block for page table */
154 memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF);
155 gd->arch.tlb_addr = start_addr + PGTABLE_OFF;
156 gd->arch.tlb_size = PGTABLE_SIZE;
157 start_addr += PGTABLE_SIZE + PGTABLE_OFF;
158 size -= (PGTABLE_OFF + PGTABLE_SIZE);
159 dcache_enable();
160
161 while (1) {
162 while (size) {
163 size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size);
164 sdram_clear_mem(start_addr, size_init);
165 size -= size_init;
166 start_addr += size_init;
Stefan Roese80877fa2022-09-02 14:10:46 +0200167 schedule();
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800168 }
169
170 bank++;
171 if (bank >= CONFIG_NR_DRAM_BANKS)
172 break;
173
174 start_addr = bd->bi_dram[bank].start;
175 size = bd->bi_dram[bank].size;
176 }
177
178 dcache_disable();
179 icache_disable();
180
181 printf("SDRAM-ECC: Initialized success with %d ms\n",
182 (unsigned int)get_timer(start));
183}
184
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900185void sdram_size_check(struct bd_info *bd)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800186{
187 phys_size_t total_ram_check = 0;
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800188 int bank;
189
190 /* Sanity check ensure correct SDRAM size specified */
191 debug("DDR: Running SDRAM size sanity check\n");
192
193 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
Tingting Mengdc6c9272025-04-15 14:50:51 +0800194 phys_size_t ram_check = 0;
195 phys_addr_t start = 0;
196 phys_size_t remaining_size;
197
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800198 start = bd->bi_dram[bank].start;
Tien Fong Cheea5132382021-08-10 11:26:36 +0800199 remaining_size = bd->bi_dram[bank].size;
Tingting Mengdc6c9272025-04-15 14:50:51 +0800200 debug("Checking bank %d: start=0x%llx, size=0x%llx\n",
201 bank, start, remaining_size);
202
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800203 while (ram_check < bd->bi_dram[bank].size) {
Tingting Mengdc6c9272025-04-15 14:50:51 +0800204 phys_size_t size, test_size, detected_size;
205
206 size = min((phys_addr_t)SZ_1G, (phys_addr_t)remaining_size);
207
208 if (size < SZ_8) {
209 puts("Invalid size: Memory size required to be multiple\n");
210 puts("of 64-Bit word!\n");
211 hang();
212 }
213
214 /* Adjust size to the nearest power of two to support get_ram_size() */
215 test_size = SZ_8;
216
217 while (test_size * 2 <= size)
218 test_size *= 2;
Tien Fong Cheea5132382021-08-10 11:26:36 +0800219
Tingting Mengdc6c9272025-04-15 14:50:51 +0800220 debug("Testing memory at 0x%llx with size 0x%llx\n",
221 start + ram_check, test_size);
222 detected_size = get_ram_size((void *)(start + ram_check), test_size);
223
224 if (detected_size != test_size) {
225 debug("Detected size 0x%llx doesn’t match the test size 0x%llx!\n",
226 detected_size, test_size);
227 puts("Memory testing failed!\n");
Tien Fong Cheea5132382021-08-10 11:26:36 +0800228 hang();
229 }
Tingting Mengdc6c9272025-04-15 14:50:51 +0800230
231 ram_check += detected_size;
232 remaining_size = bd->bi_dram[bank].size - ram_check;
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800233 }
Tien Fong Cheea5132382021-08-10 11:26:36 +0800234
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800235 total_ram_check += ram_check;
236 ram_check = 0;
237 }
238
239 /* If the ram_size is 2GB smaller, we can assume the IO space is
240 * not mapped in. gd->ram_size is the actual size of the dram
241 * not the accessible size.
242 */
243 if (total_ram_check != gd->ram_size) {
244 puts("DDR: SDRAM size check failed!\n");
245 hang();
246 }
247
248 debug("DDR: SDRAM size check passed!\n");
249}
250
251/**
252 * sdram_calculate_size() - Calculate SDRAM size
253 *
254 * Calculate SDRAM device size based on SDRAM controller parameters.
255 * Size is specified in bytes.
256 */
Simon Glassb75b15b2020-12-03 16:55:23 -0700257phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800258{
259 u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
260
Dinesh Maniyameeea5ec2022-06-01 18:49:02 +0800261 phys_size_t size = (phys_size_t)1 <<
262 (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800263 DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
264 DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
265 DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
266 DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw));
267
Naresh Kumar Ravulapalli6e745662025-03-07 02:28:51 -0800268 size *= ((phys_size_t)2 << (hmc_ecc_readl(plat, DDRIOCTRL) &
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800269 DDR_HMC_DDRIOCTRL_IOSIZE_MSK));
270
271 return size;
272}
273
Tingting Menga1a24f12025-02-21 21:49:41 +0800274static void sdram_set_firewall_non_f2sdram(struct bd_info *bd)
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800275{
276 u32 i;
277 phys_size_t value;
278 u32 lower, upper;
279
280 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
281 if (!bd->bi_dram[i].size)
282 continue;
283
284 value = bd->bi_dram[i].start;
285
286 /* Keep first 1MB of SDRAM memory region as secure region when
287 * using ATF flow, where the ATF code is located.
288 */
289 if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0)
290 value += SZ_1M;
291
292 /* Setting non-secure MPU region base and base extended */
293 lower = lower_32_bits(value);
294 upper = upper_32_bits(value);
295 FW_MPU_DDR_SCR_WRITEL(lower,
296 FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE +
297 (i * 4 * sizeof(u32)));
298 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
299 FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT +
300 (i * 4 * sizeof(u32)));
301
302 /* Setting non-secure Non-MPU region base and base extended */
303 FW_MPU_DDR_SCR_WRITEL(lower,
304 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE +
305 (i * 4 * sizeof(u32)));
306 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
307 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT +
308 (i * 4 * sizeof(u32)));
309
Tingting Menga1a24f12025-02-21 21:49:41 +0800310 /* Setting non-secure MPU limit and limit extended */
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800311 value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
312
313 lower = lower_32_bits(value);
314 upper = upper_32_bits(value);
315
316 FW_MPU_DDR_SCR_WRITEL(lower,
317 FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT +
318 (i * 4 * sizeof(u32)));
319 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
320 FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT +
321 (i * 4 * sizeof(u32)));
322
Tingting Menga1a24f12025-02-21 21:49:41 +0800323 /* Setting non-secure Non-MPU limit and limit extended */
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800324 FW_MPU_DDR_SCR_WRITEL(lower,
325 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT +
326 (i * 4 * sizeof(u32)));
327 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
328 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT +
329 (i * 4 * sizeof(u32)));
330
331 FW_MPU_DDR_SCR_WRITEL(BIT(i) | BIT(i + 8),
332 FW_MPU_DDR_SCR_EN_SET);
333 }
334}
335
Tingting Menga1a24f12025-02-21 21:49:41 +0800336#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
337static void sdram_set_firewall_f2sdram(struct bd_info *bd)
338{
339 u32 i, lower, upper;
340 phys_size_t value;
341
342 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
343 if (!bd->bi_dram[i].size)
344 continue;
345
346 value = bd->bi_dram[i].start;
347
348 /* Keep first 1MB of SDRAM memory region as secure region when
349 * using ATF flow, where the ATF code is located.
350 */
351 if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0)
352 value += SZ_1M;
353
354 /* Setting base and base extended */
355 lower = lower_32_bits(value);
356 upper = upper_32_bits(value);
357 FW_F2SDRAM_DDR_SCR_WRITEL(lower,
358 FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE +
359 (i * 4 * sizeof(u32)));
360 FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff,
361 FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT +
362 (i * 4 * sizeof(u32)));
363
364 /* Setting limit and limit extended */
365 value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
366
367 lower = lower_32_bits(value);
368 upper = upper_32_bits(value);
369
370 FW_F2SDRAM_DDR_SCR_WRITEL(lower,
371 FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT +
372 (i * 4 * sizeof(u32)));
373 FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff,
374 FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT +
375 (i * 4 * sizeof(u32)));
376
377 FW_F2SDRAM_DDR_SCR_WRITEL(BIT(i), FW_F2SDRAM_DDR_SCR_EN_SET);
378 }
379}
380#endif
381
382void sdram_set_firewall(struct bd_info *bd)
383{
384 sdram_set_firewall_non_f2sdram(bd);
385
386#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
387 sdram_set_firewall_f2sdram(bd);
388#endif
389}
390
Simon Glassaad29ae2020-12-03 16:55:21 -0700391static int altera_sdram_of_to_plat(struct udevice *dev)
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800392{
Tingting Menga1a24f12025-02-21 21:49:41 +0800393#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
Simon Glass95588622020-12-22 19:30:28 -0700394 struct altera_sdram_plat *plat = dev_get_plat(dev);
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800395 fdt_addr_t addr;
Tingting Menga1a24f12025-02-21 21:49:41 +0800396#endif
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800397
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800398 /* These regs info are part of DDR handoff in bitstream */
399#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
400 return 0;
Tingting Menga1a24f12025-02-21 21:49:41 +0800401#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
402 addr = dev_read_addr_index(dev, 0);
403 if (addr == FDT_ADDR_T_NONE)
404 return -EINVAL;
405 plat->mpfe_base_addr = addr;
406#else
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800407
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800408 addr = dev_read_addr_index(dev, 0);
409 if (addr == FDT_ADDR_T_NONE)
410 return -EINVAL;
411 plat->ddr_sch = (void __iomem *)addr;
412
413 addr = dev_read_addr_index(dev, 1);
414 if (addr == FDT_ADDR_T_NONE)
415 return -EINVAL;
416 plat->iomhc = (void __iomem *)addr;
417
418 addr = dev_read_addr_index(dev, 2);
419 if (addr == FDT_ADDR_T_NONE)
420 return -EINVAL;
421 plat->hmc = (void __iomem *)addr;
Tingting Menga1a24f12025-02-21 21:49:41 +0800422#endif
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800423 return 0;
424}
425
426static int altera_sdram_probe(struct udevice *dev)
427{
428 int ret;
429 struct altera_sdram_priv *priv = dev_get_priv(dev);
430
431 ret = reset_get_bulk(dev, &priv->resets);
432 if (ret) {
433 dev_err(dev, "Can't get reset: %d\n", ret);
434 return -ENODEV;
435 }
436 reset_deassert_bulk(&priv->resets);
437
438 if (sdram_mmr_init_full(dev) != 0) {
439 puts("SDRAM init failed.\n");
440 goto failed;
441 }
442
443 return 0;
444
445failed:
446 reset_release_bulk(&priv->resets);
447 return -ENODEV;
448}
449
450static int altera_sdram_get_info(struct udevice *dev,
451 struct ram_info *info)
452{
453 struct altera_sdram_priv *priv = dev_get_priv(dev);
454
455 info->base = priv->info.base;
456 info->size = priv->info.size;
457
458 return 0;
459}
460
461static struct ram_ops altera_sdram_ops = {
462 .get_info = altera_sdram_get_info,
463};
464
465static const struct udevice_id altera_sdram_ids[] = {
466 { .compatible = "altr,sdr-ctl-s10" },
Ley Foon Tan4ddb9092019-11-27 15:55:27 +0800467 { .compatible = "intel,sdr-ctl-agilex" },
Tien Fong Cheef8e2eab2021-08-10 11:26:37 +0800468 { .compatible = "intel,sdr-ctl-n5x" },
Tingting Menga1a24f12025-02-21 21:49:41 +0800469 { .compatible = "intel,sdr-ctl-agilex5" },
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800470 { /* sentinel */ }
471};
472
473U_BOOT_DRIVER(altera_sdram) = {
474 .name = "altr_sdr_ctl",
475 .id = UCLASS_RAM,
476 .of_match = altera_sdram_ids,
477 .ops = &altera_sdram_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700478 .of_to_plat = altera_sdram_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700479 .plat_auto = sizeof(struct altera_sdram_plat),
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800480 .probe = altera_sdram_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700481 .priv_auto = sizeof(struct altera_sdram_priv),
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800482};