blob: 491f689c44df52d0ffdc4d13648f5415d4b0ac7d [file] [log] [blame]
Ley Foon Tan25572cf2019-11-27 15:55:26 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2016-2019 Intel Corporation <www.intel.com>
4 *
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 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>
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
30u32 hmc_readl(struct altera_sdram_platdata *plat, u32 reg)
31{
32 return readl(plat->iomhc + reg);
33}
34
35u32 hmc_ecc_readl(struct altera_sdram_platdata *plat, u32 reg)
36{
37 return readl(plat->hmc + reg);
38}
39
40u32 hmc_ecc_writel(struct altera_sdram_platdata *plat,
41 u32 data, u32 reg)
42{
43 return writel(data, plat->hmc + reg);
44}
45
46u32 ddr_sch_writel(struct altera_sdram_platdata *plat, u32 data,
47 u32 reg)
48{
49 return writel(data, plat->ddr_sch + reg);
50}
51
52int emif_clear(struct altera_sdram_platdata *plat)
53{
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
62int emif_reset(struct altera_sdram_platdata *plat)
63{
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
102int poll_hmc_clock_status(void)
103{
104 return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() +
105 SYSMGR_SOC64_HMC_CLK),
106 SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false);
107}
108
109void sdram_clear_mem(phys_addr_t addr, phys_size_t size)
110{
111 phys_size_t i;
112
113 if (addr % CONFIG_SYS_CACHELINE_SIZE) {
114 printf("DDR: address 0x%llx is not cacheline size aligned.\n",
115 addr);
116 hang();
117 }
118
119 if (size % CONFIG_SYS_CACHELINE_SIZE) {
120 printf("DDR: size 0x%llx is not multiple of cacheline size\n",
121 size);
122 hang();
123 }
124
125 /* Use DC ZVA instruction to clear memory to zeros by a cache line */
126 for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) {
127 asm volatile("dc zva, %0"
128 :
129 : "r"(addr)
130 : "memory");
131 addr += CONFIG_SYS_CACHELINE_SIZE;
132 }
133}
134
135void sdram_init_ecc_bits(bd_t *bd)
136{
137 phys_size_t size, size_init;
138 phys_addr_t start_addr;
139 int bank = 0;
140 unsigned int start = get_timer(0);
141
142 icache_enable();
143
144 start_addr = bd->bi_dram[0].start;
145 size = bd->bi_dram[0].size;
146
147 /* Initialize small block for page table */
148 memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF);
149 gd->arch.tlb_addr = start_addr + PGTABLE_OFF;
150 gd->arch.tlb_size = PGTABLE_SIZE;
151 start_addr += PGTABLE_SIZE + PGTABLE_OFF;
152 size -= (PGTABLE_OFF + PGTABLE_SIZE);
153 dcache_enable();
154
155 while (1) {
156 while (size) {
157 size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size);
158 sdram_clear_mem(start_addr, size_init);
159 size -= size_init;
160 start_addr += size_init;
161 WATCHDOG_RESET();
162 }
163
164 bank++;
165 if (bank >= CONFIG_NR_DRAM_BANKS)
166 break;
167
168 start_addr = bd->bi_dram[bank].start;
169 size = bd->bi_dram[bank].size;
170 }
171
172 dcache_disable();
173 icache_disable();
174
175 printf("SDRAM-ECC: Initialized success with %d ms\n",
176 (unsigned int)get_timer(start));
177}
178
179void sdram_size_check(bd_t *bd)
180{
181 phys_size_t total_ram_check = 0;
182 phys_size_t ram_check = 0;
183 phys_addr_t start = 0;
184 int bank;
185
186 /* Sanity check ensure correct SDRAM size specified */
187 debug("DDR: Running SDRAM size sanity check\n");
188
189 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
190 start = bd->bi_dram[bank].start;
191 while (ram_check < bd->bi_dram[bank].size) {
192 ram_check += get_ram_size((void *)(start + ram_check),
193 (phys_size_t)SZ_1G);
194 }
195 total_ram_check += ram_check;
196 ram_check = 0;
197 }
198
199 /* If the ram_size is 2GB smaller, we can assume the IO space is
200 * not mapped in. gd->ram_size is the actual size of the dram
201 * not the accessible size.
202 */
203 if (total_ram_check != gd->ram_size) {
204 puts("DDR: SDRAM size check failed!\n");
205 hang();
206 }
207
208 debug("DDR: SDRAM size check passed!\n");
209}
210
211/**
212 * sdram_calculate_size() - Calculate SDRAM size
213 *
214 * Calculate SDRAM device size based on SDRAM controller parameters.
215 * Size is specified in bytes.
216 */
217phys_size_t sdram_calculate_size(struct altera_sdram_platdata *plat)
218{
219 u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
220
221 phys_size_t size = 1 << (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
222 DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
223 DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
224 DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
225 DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw));
226
227 size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) &
228 DDR_HMC_DDRIOCTRL_IOSIZE_MSK));
229
230 return size;
231}
232
233static int altera_sdram_ofdata_to_platdata(struct udevice *dev)
234{
235 struct altera_sdram_platdata *plat = dev->platdata;
236 fdt_addr_t addr;
237
238 addr = dev_read_addr_index(dev, 0);
239 if (addr == FDT_ADDR_T_NONE)
240 return -EINVAL;
241 plat->ddr_sch = (void __iomem *)addr;
242
243 addr = dev_read_addr_index(dev, 1);
244 if (addr == FDT_ADDR_T_NONE)
245 return -EINVAL;
246 plat->iomhc = (void __iomem *)addr;
247
248 addr = dev_read_addr_index(dev, 2);
249 if (addr == FDT_ADDR_T_NONE)
250 return -EINVAL;
251 plat->hmc = (void __iomem *)addr;
252
253 return 0;
254}
255
256static int altera_sdram_probe(struct udevice *dev)
257{
258 int ret;
259 struct altera_sdram_priv *priv = dev_get_priv(dev);
260
261 ret = reset_get_bulk(dev, &priv->resets);
262 if (ret) {
263 dev_err(dev, "Can't get reset: %d\n", ret);
264 return -ENODEV;
265 }
266 reset_deassert_bulk(&priv->resets);
267
268 if (sdram_mmr_init_full(dev) != 0) {
269 puts("SDRAM init failed.\n");
270 goto failed;
271 }
272
273 return 0;
274
275failed:
276 reset_release_bulk(&priv->resets);
277 return -ENODEV;
278}
279
280static int altera_sdram_get_info(struct udevice *dev,
281 struct ram_info *info)
282{
283 struct altera_sdram_priv *priv = dev_get_priv(dev);
284
285 info->base = priv->info.base;
286 info->size = priv->info.size;
287
288 return 0;
289}
290
291static struct ram_ops altera_sdram_ops = {
292 .get_info = altera_sdram_get_info,
293};
294
295static const struct udevice_id altera_sdram_ids[] = {
296 { .compatible = "altr,sdr-ctl-s10" },
Ley Foon Tan4ddb9092019-11-27 15:55:27 +0800297 { .compatible = "intel,sdr-ctl-agilex" },
Ley Foon Tan25572cf2019-11-27 15:55:26 +0800298 { /* sentinel */ }
299};
300
301U_BOOT_DRIVER(altera_sdram) = {
302 .name = "altr_sdr_ctl",
303 .id = UCLASS_RAM,
304 .of_match = altera_sdram_ids,
305 .ops = &altera_sdram_ops,
306 .ofdata_to_platdata = altera_sdram_ofdata_to_platdata,
307 .platdata_auto_alloc_size = sizeof(struct altera_sdram_platdata),
308 .probe = altera_sdram_probe,
309 .priv_auto_alloc_size = sizeof(struct altera_sdram_priv),
310};