blob: 4716abfc9a8b051aa562e8bc9a1f54f089d32e6d [file] [log] [blame]
Ley Foon Tan733cc6c2019-11-27 15:55:26 +08001// SPDX-License-Identifier: GPL-2.0
2/*
Dinesh Maniyam32e03792022-06-01 18:49:02 +08003 * Copyright (C) 2016-2022 Intel Corporation <www.intel.com>
Ley Foon Tan733cc6c2019-11-27 15:55:26 +08004 *
5 */
6
7#include <common.h>
8#include <cpu_func.h>
9#include <dm.h>
10#include <errno.h>
11#include <div64.h>
12#include <fdtdec.h>
Simon Glassdb41d652019-12-28 10:45:07 -070013#include <hang.h>
Simon Glass691d7192020-05-10 11:40:02 -060014#include <init.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060015#include <log.h>
Ley Foon Tan733cc6c2019-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 Glass90526e92020-05-10 11:39:56 -060023#include <asm/cache.h>
Simon Glass401d1c42020-10-30 21:38:53 -060024#include <asm/global_data.h>
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080025#include <asm/io.h>
Simon Glass336d4612020-02-03 07:36:16 -070026#include <dm/device_compat.h>
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080027#include <linux/sizes.h>
28
29#define PGTABLE_OFF 0x4000
30
Simon Glass8a8d24b2020-12-03 16:55:23 -070031u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080032{
33 return readl(plat->iomhc + reg);
34}
35
Simon Glass8a8d24b2020-12-03 16:55:23 -070036u32 hmc_ecc_readl(struct altera_sdram_plat *plat, u32 reg)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080037{
38 return readl(plat->hmc + reg);
39}
40
Simon Glass8a8d24b2020-12-03 16:55:23 -070041u32 hmc_ecc_writel(struct altera_sdram_plat *plat,
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080042 u32 data, u32 reg)
43{
44 return writel(data, plat->hmc + reg);
45}
46
Simon Glass8a8d24b2020-12-03 16:55:23 -070047u32 ddr_sch_writel(struct altera_sdram_plat *plat, u32 data,
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080048 u32 reg)
49{
50 return writel(data, plat->ddr_sch + reg);
51}
52
Simon Glass8a8d24b2020-12-03 16:55:23 -070053int emif_clear(struct altera_sdram_plat *plat)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080054{
55 hmc_ecc_writel(plat, 0, RSTHANDSHAKECTRL);
56
57 return wait_for_bit_le32((const void *)(plat->hmc +
58 RSTHANDSHAKESTAT),
59 DDR_HMC_RSTHANDSHAKE_MASK,
60 false, 1000, false);
61}
62
Simon Glass8a8d24b2020-12-03 16:55:23 -070063int emif_reset(struct altera_sdram_plat *plat)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +080064{
65 u32 c2s, s2c, ret;
66
67 c2s = hmc_ecc_readl(plat, RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK;
68 s2c = hmc_ecc_readl(plat, RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK;
69
70 debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n",
71 c2s, s2c, hmc_readl(plat, NIOSRESERVED0),
72 hmc_readl(plat, NIOSRESERVED1), hmc_readl(plat, NIOSRESERVED2),
73 hmc_readl(plat, DRAMSTS));
74
75 if (s2c && emif_clear(plat)) {
76 printf("DDR: emif_clear() failed\n");
77 return -1;
78 }
79
80 debug("DDR: Triggerring emif reset\n");
81 hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL);
82
83 /* if seq2core[3] = 0, we are good */
84 ret = wait_for_bit_le32((const void *)(plat->hmc +
85 RSTHANDSHAKESTAT),
86 DDR_HMC_SEQ2CORE_INT_RESP_MASK,
87 false, 1000, false);
88 if (ret) {
89 printf("DDR: failed to get ack from EMIF\n");
90 return ret;
91 }
92
93 ret = emif_clear(plat);
94 if (ret) {
95 printf("DDR: emif_clear() failed\n");
96 return ret;
97 }
98
99 debug("DDR: %s triggered successly\n", __func__);
100 return 0;
101}
102
Tien Fong Chee59d42302021-08-10 11:26:37 +0800103#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800104int poll_hmc_clock_status(void)
105{
106 return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() +
107 SYSMGR_SOC64_HMC_CLK),
108 SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false);
109}
Tien Fong Chee59d42302021-08-10 11:26:37 +0800110#endif
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800111
112void sdram_clear_mem(phys_addr_t addr, phys_size_t size)
113{
114 phys_size_t i;
115
116 if (addr % CONFIG_SYS_CACHELINE_SIZE) {
117 printf("DDR: address 0x%llx is not cacheline size aligned.\n",
118 addr);
119 hang();
120 }
121
122 if (size % CONFIG_SYS_CACHELINE_SIZE) {
123 printf("DDR: size 0x%llx is not multiple of cacheline size\n",
124 size);
125 hang();
126 }
127
128 /* Use DC ZVA instruction to clear memory to zeros by a cache line */
129 for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) {
130 asm volatile("dc zva, %0"
131 :
132 : "r"(addr)
133 : "memory");
134 addr += CONFIG_SYS_CACHELINE_SIZE;
135 }
136}
137
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900138void sdram_init_ecc_bits(struct bd_info *bd)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800139{
140 phys_size_t size, size_init;
141 phys_addr_t start_addr;
142 int bank = 0;
143 unsigned int start = get_timer(0);
144
145 icache_enable();
146
147 start_addr = bd->bi_dram[0].start;
148 size = bd->bi_dram[0].size;
149
150 /* Initialize small block for page table */
151 memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF);
152 gd->arch.tlb_addr = start_addr + PGTABLE_OFF;
153 gd->arch.tlb_size = PGTABLE_SIZE;
154 start_addr += PGTABLE_SIZE + PGTABLE_OFF;
155 size -= (PGTABLE_OFF + PGTABLE_SIZE);
156 dcache_enable();
157
158 while (1) {
159 while (size) {
160 size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size);
161 sdram_clear_mem(start_addr, size_init);
162 size -= size_init;
163 start_addr += size_init;
Stefan Roese29caf932022-09-02 14:10:46 +0200164 schedule();
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800165 }
166
167 bank++;
168 if (bank >= CONFIG_NR_DRAM_BANKS)
169 break;
170
171 start_addr = bd->bi_dram[bank].start;
172 size = bd->bi_dram[bank].size;
173 }
174
175 dcache_disable();
176 icache_disable();
177
178 printf("SDRAM-ECC: Initialized success with %d ms\n",
179 (unsigned int)get_timer(start));
180}
181
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900182void sdram_size_check(struct bd_info *bd)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800183{
184 phys_size_t total_ram_check = 0;
185 phys_size_t ram_check = 0;
186 phys_addr_t start = 0;
Tien Fong Chee1b378cc2021-08-10 11:26:36 +0800187 phys_size_t size, remaining_size;
Ley Foon Tan733cc6c2019-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++) {
194 start = bd->bi_dram[bank].start;
Tien Fong Chee1b378cc2021-08-10 11:26:36 +0800195 remaining_size = bd->bi_dram[bank].size;
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800196 while (ram_check < bd->bi_dram[bank].size) {
Tien Fong Chee1b378cc2021-08-10 11:26:36 +0800197 size = min((phys_addr_t)SZ_1G,
198 (phys_addr_t)remaining_size);
199
200 /*
201 * Ensure the size is power of two, this is requirement
202 * to run get_ram_size() / memory test
203 */
204 if (size != 0 && ((size & (size - 1)) == 0)) {
205 ram_check += get_ram_size((void *)
206 (start + ram_check), size);
207 remaining_size = bd->bi_dram[bank].size -
208 ram_check;
209 } else {
210 puts("DDR: Memory test requires SDRAM size ");
211 puts("in power of two!\n");
212 hang();
213 }
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800214 }
Tien Fong Chee1b378cc2021-08-10 11:26:36 +0800215
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800216 total_ram_check += ram_check;
217 ram_check = 0;
218 }
219
220 /* If the ram_size is 2GB smaller, we can assume the IO space is
221 * not mapped in. gd->ram_size is the actual size of the dram
222 * not the accessible size.
223 */
224 if (total_ram_check != gd->ram_size) {
225 puts("DDR: SDRAM size check failed!\n");
226 hang();
227 }
228
229 debug("DDR: SDRAM size check passed!\n");
230}
231
232/**
233 * sdram_calculate_size() - Calculate SDRAM size
234 *
235 * Calculate SDRAM device size based on SDRAM controller parameters.
236 * Size is specified in bytes.
237 */
Simon Glass8a8d24b2020-12-03 16:55:23 -0700238phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800239{
240 u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
241
Dinesh Maniyam32e03792022-06-01 18:49:02 +0800242 phys_size_t size = (phys_size_t)1 <<
243 (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800244 DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
245 DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
246 DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
247 DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw));
248
249 size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) &
250 DDR_HMC_DDRIOCTRL_IOSIZE_MSK));
251
252 return size;
253}
254
Tien Fong Chee59d42302021-08-10 11:26:37 +0800255void sdram_set_firewall(struct bd_info *bd)
256{
257 u32 i;
258 phys_size_t value;
259 u32 lower, upper;
260
261 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
262 if (!bd->bi_dram[i].size)
263 continue;
264
265 value = bd->bi_dram[i].start;
266
267 /* Keep first 1MB of SDRAM memory region as secure region when
268 * using ATF flow, where the ATF code is located.
269 */
270 if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0)
271 value += SZ_1M;
272
273 /* Setting non-secure MPU region base and base extended */
274 lower = lower_32_bits(value);
275 upper = upper_32_bits(value);
276 FW_MPU_DDR_SCR_WRITEL(lower,
277 FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE +
278 (i * 4 * sizeof(u32)));
279 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
280 FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT +
281 (i * 4 * sizeof(u32)));
282
283 /* Setting non-secure Non-MPU region base and base extended */
284 FW_MPU_DDR_SCR_WRITEL(lower,
285 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE +
286 (i * 4 * sizeof(u32)));
287 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
288 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT +
289 (i * 4 * sizeof(u32)));
290
291 /* Setting non-secure MPU limit and limit extexded */
292 value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
293
294 lower = lower_32_bits(value);
295 upper = upper_32_bits(value);
296
297 FW_MPU_DDR_SCR_WRITEL(lower,
298 FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT +
299 (i * 4 * sizeof(u32)));
300 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
301 FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT +
302 (i * 4 * sizeof(u32)));
303
304 /* Setting non-secure Non-MPU limit and limit extexded */
305 FW_MPU_DDR_SCR_WRITEL(lower,
306 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT +
307 (i * 4 * sizeof(u32)));
308 FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
309 FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT +
310 (i * 4 * sizeof(u32)));
311
312 FW_MPU_DDR_SCR_WRITEL(BIT(i) | BIT(i + 8),
313 FW_MPU_DDR_SCR_EN_SET);
314 }
315}
316
Simon Glassd1998a92020-12-03 16:55:21 -0700317static int altera_sdram_of_to_plat(struct udevice *dev)
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800318{
Simon Glass0fd3d912020-12-22 19:30:28 -0700319 struct altera_sdram_plat *plat = dev_get_plat(dev);
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800320 fdt_addr_t addr;
321
Tien Fong Chee59d42302021-08-10 11:26:37 +0800322 /* These regs info are part of DDR handoff in bitstream */
323#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
324 return 0;
325#endif
326
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800327 addr = dev_read_addr_index(dev, 0);
328 if (addr == FDT_ADDR_T_NONE)
329 return -EINVAL;
330 plat->ddr_sch = (void __iomem *)addr;
331
332 addr = dev_read_addr_index(dev, 1);
333 if (addr == FDT_ADDR_T_NONE)
334 return -EINVAL;
335 plat->iomhc = (void __iomem *)addr;
336
337 addr = dev_read_addr_index(dev, 2);
338 if (addr == FDT_ADDR_T_NONE)
339 return -EINVAL;
340 plat->hmc = (void __iomem *)addr;
341
342 return 0;
343}
344
345static int altera_sdram_probe(struct udevice *dev)
346{
347 int ret;
348 struct altera_sdram_priv *priv = dev_get_priv(dev);
349
350 ret = reset_get_bulk(dev, &priv->resets);
351 if (ret) {
352 dev_err(dev, "Can't get reset: %d\n", ret);
353 return -ENODEV;
354 }
355 reset_deassert_bulk(&priv->resets);
356
357 if (sdram_mmr_init_full(dev) != 0) {
358 puts("SDRAM init failed.\n");
359 goto failed;
360 }
361
362 return 0;
363
364failed:
365 reset_release_bulk(&priv->resets);
366 return -ENODEV;
367}
368
369static int altera_sdram_get_info(struct udevice *dev,
370 struct ram_info *info)
371{
372 struct altera_sdram_priv *priv = dev_get_priv(dev);
373
374 info->base = priv->info.base;
375 info->size = priv->info.size;
376
377 return 0;
378}
379
380static struct ram_ops altera_sdram_ops = {
381 .get_info = altera_sdram_get_info,
382};
383
384static const struct udevice_id altera_sdram_ids[] = {
385 { .compatible = "altr,sdr-ctl-s10" },
Ley Foon Tan6a48c342019-11-27 15:55:27 +0800386 { .compatible = "intel,sdr-ctl-agilex" },
Tien Fong Chee59d42302021-08-10 11:26:37 +0800387 { .compatible = "intel,sdr-ctl-n5x" },
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800388 { /* sentinel */ }
389};
390
391U_BOOT_DRIVER(altera_sdram) = {
392 .name = "altr_sdr_ctl",
393 .id = UCLASS_RAM,
394 .of_match = altera_sdram_ids,
395 .ops = &altera_sdram_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700396 .of_to_plat = altera_sdram_of_to_plat,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700397 .plat_auto = sizeof(struct altera_sdram_plat),
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800398 .probe = altera_sdram_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700399 .priv_auto = sizeof(struct altera_sdram_priv),
Ley Foon Tan733cc6c2019-11-27 15:55:26 +0800400};