]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
9bbd2132 DN |
2 | /* |
3 | * Copyright Altera Corporation (C) 2014-2015 | |
9bbd2132 DN |
4 | */ |
5 | #include <common.h> | |
29873c74 | 6 | #include <dm.h> |
99f453e9 | 7 | #include <errno.h> |
9bbd2132 | 8 | #include <div64.h> |
9b4a205f | 9 | #include <init.h> |
f7ae49fc | 10 | #include <log.h> |
29873c74 SG |
11 | #include <ram.h> |
12 | #include <reset.h> | |
9bbd2132 DN |
13 | #include <watchdog.h> |
14 | #include <asm/arch/fpga_manager.h> | |
29873c74 | 15 | #include <asm/arch/reset_manager.h> |
9bbd2132 | 16 | #include <asm/arch/sdram.h> |
9bbd2132 DN |
17 | #include <asm/arch/system_manager.h> |
18 | #include <asm/io.h> | |
336d4615 | 19 | #include <dm/device_compat.h> |
9bbd2132 | 20 | |
29873c74 SG |
21 | #include "sequencer.h" |
22 | ||
23 | #ifdef CONFIG_SPL_BUILD | |
24 | ||
25 | struct altera_gen5_sdram_priv { | |
26 | struct ram_info info; | |
27 | }; | |
28 | ||
29 | struct altera_gen5_sdram_platdata { | |
30 | struct socfpga_sdr *sdr; | |
31 | }; | |
32 | ||
42f7ebb8 | 33 | struct sdram_prot_rule { |
08eb9470 MV |
34 | u32 sdram_start; /* SDRAM start address */ |
35 | u32 sdram_end; /* SDRAM end address */ | |
42f7ebb8 MV |
36 | u32 rule; /* SDRAM protection rule number: 0-19 */ |
37 | int valid; /* Rule valid or not? 1 - valid, 0 not*/ | |
38 | ||
39 | u32 security; | |
40 | u32 portmask; | |
41 | u32 result; | |
42 | u32 lo_prot_id; | |
43 | u32 hi_prot_id; | |
44 | }; | |
45 | ||
29873c74 | 46 | static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl); |
9bbd2132 | 47 | |
f3671697 MV |
48 | /** |
49 | * get_errata_rows() - Up the number of DRAM rows to cover entire address space | |
764aa9a9 | 50 | * @cfg: SDRAM controller configuration data |
f3671697 MV |
51 | * |
52 | * SDRAM Failure happens when accessing non-existent memory. Artificially | |
53 | * increase the number of rows so that the memory controller thinks it has | |
54 | * 4GB of RAM. This function returns such amount of rows. | |
55 | */ | |
5af91418 | 56 | static int get_errata_rows(const struct socfpga_sdram_config *cfg) |
9bbd2132 | 57 | { |
f3671697 MV |
58 | /* Define constant for 4G memory - used for SDRAM errata workaround */ |
59 | #define MEMSIZE_4G (4ULL * 1024ULL * 1024ULL * 1024ULL) | |
60 | const unsigned long long memsize = MEMSIZE_4G; | |
764aa9a9 MV |
61 | const unsigned int cs = |
62 | ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >> | |
63 | SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1; | |
64 | const unsigned int rows = | |
65 | (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >> | |
66 | SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; | |
67 | const unsigned int banks = | |
68 | (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK) >> | |
69 | SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB; | |
70 | const unsigned int cols = | |
71 | (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK) >> | |
72 | SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB; | |
f3671697 MV |
73 | const unsigned int width = 8; |
74 | ||
9bbd2132 | 75 | unsigned long long newrows; |
f3671697 | 76 | int bits, inewrowslog2; |
9bbd2132 DN |
77 | |
78 | debug("workaround rows - memsize %lld\n", memsize); | |
79 | debug("workaround rows - cs %d\n", cs); | |
80 | debug("workaround rows - width %d\n", width); | |
81 | debug("workaround rows - rows %d\n", rows); | |
82 | debug("workaround rows - banks %d\n", banks); | |
83 | debug("workaround rows - cols %d\n", cols); | |
84 | ||
791d20e1 | 85 | newrows = lldiv(memsize, cs * (width / 8)); |
9bbd2132 DN |
86 | debug("rows workaround - term1 %lld\n", newrows); |
87 | ||
791d20e1 | 88 | newrows = lldiv(newrows, (1 << banks) * (1 << cols)); |
9bbd2132 DN |
89 | debug("rows workaround - term2 %lld\n", newrows); |
90 | ||
791d20e1 MV |
91 | /* |
92 | * Compute the hamming weight - same as number of bits set. | |
9bbd2132 DN |
93 | * Need to see if result is ordinal power of 2 before |
94 | * attempting log2 of result. | |
95 | */ | |
58d86144 | 96 | bits = generic_hweight32(newrows); |
9bbd2132 DN |
97 | |
98 | debug("rows workaround - bits %d\n", bits); | |
99 | ||
100 | if (bits != 1) { | |
101 | printf("SDRAM workaround failed, bits set %d\n", bits); | |
102 | return rows; | |
103 | } | |
104 | ||
105 | if (newrows > UINT_MAX) { | |
106 | printf("SDRAM workaround rangecheck failed, %lld\n", newrows); | |
107 | return rows; | |
108 | } | |
109 | ||
791d20e1 | 110 | inewrowslog2 = __ilog2(newrows); |
9bbd2132 | 111 | |
791d20e1 | 112 | debug("rows workaround - ilog2 %d, %lld\n", inewrowslog2, newrows); |
9bbd2132 DN |
113 | |
114 | if (inewrowslog2 == -1) { | |
791d20e1 | 115 | printf("SDRAM workaround failed, newrows %lld\n", newrows); |
9bbd2132 DN |
116 | return rows; |
117 | } | |
118 | ||
119 | return inewrowslog2; | |
120 | } | |
121 | ||
122 | /* SDRAM protection rules vary from 0-19, a total of 20 rules. */ | |
29873c74 SG |
123 | static void sdram_set_rule(struct socfpga_sdr_ctrl *sdr_ctrl, |
124 | struct sdram_prot_rule *prule) | |
9bbd2132 | 125 | { |
08eb9470 MV |
126 | u32 lo_addr_bits; |
127 | u32 hi_addr_bits; | |
9bbd2132 DN |
128 | int ruleno = prule->rule; |
129 | ||
130 | /* Select the rule */ | |
131 | writel(ruleno, &sdr_ctrl->prot_rule_rdwr); | |
132 | ||
133 | /* Obtain the address bits */ | |
a003740a | 134 | lo_addr_bits = prule->sdram_start >> 20ULL; |
164eb23f | 135 | hi_addr_bits = (prule->sdram_end - 1) >> 20ULL; |
9bbd2132 | 136 | |
08eb9470 | 137 | debug("sdram set rule start %x, %d\n", lo_addr_bits, |
9bbd2132 | 138 | prule->sdram_start); |
08eb9470 | 139 | debug("sdram set rule end %x, %d\n", hi_addr_bits, |
9bbd2132 DN |
140 | prule->sdram_end); |
141 | ||
142 | /* Set rule addresses */ | |
143 | writel(lo_addr_bits | (hi_addr_bits << 12), &sdr_ctrl->prot_rule_addr); | |
144 | ||
145 | /* Set rule protection ids */ | |
146 | writel(prule->lo_prot_id | (prule->hi_prot_id << 12), | |
147 | &sdr_ctrl->prot_rule_id); | |
148 | ||
149 | /* Set the rule data */ | |
150 | writel(prule->security | (prule->valid << 2) | | |
151 | (prule->portmask << 3) | (prule->result << 13), | |
152 | &sdr_ctrl->prot_rule_data); | |
153 | ||
154 | /* write the rule */ | |
a003740a | 155 | writel(ruleno | (1 << 5), &sdr_ctrl->prot_rule_rdwr); |
9bbd2132 DN |
156 | |
157 | /* Set rule number to 0 by default */ | |
158 | writel(0, &sdr_ctrl->prot_rule_rdwr); | |
159 | } | |
160 | ||
29873c74 SG |
161 | static void sdram_get_rule(struct socfpga_sdr_ctrl *sdr_ctrl, |
162 | struct sdram_prot_rule *prule) | |
9bbd2132 | 163 | { |
6d01595f MV |
164 | u32 addr; |
165 | u32 id; | |
166 | u32 data; | |
9bbd2132 DN |
167 | int ruleno = prule->rule; |
168 | ||
169 | /* Read the rule */ | |
170 | writel(ruleno, &sdr_ctrl->prot_rule_rdwr); | |
6d01595f | 171 | writel(ruleno | (1 << 6), &sdr_ctrl->prot_rule_rdwr); |
9bbd2132 DN |
172 | |
173 | /* Get the addresses */ | |
174 | addr = readl(&sdr_ctrl->prot_rule_addr); | |
175 | prule->sdram_start = (addr & 0xFFF) << 20; | |
176 | prule->sdram_end = ((addr >> 12) & 0xFFF) << 20; | |
177 | ||
178 | /* Get the configured protection IDs */ | |
179 | id = readl(&sdr_ctrl->prot_rule_id); | |
180 | prule->lo_prot_id = id & 0xFFF; | |
181 | prule->hi_prot_id = (id >> 12) & 0xFFF; | |
182 | ||
183 | /* Get protection data */ | |
184 | data = readl(&sdr_ctrl->prot_rule_data); | |
185 | ||
186 | prule->security = data & 0x3; | |
187 | prule->valid = (data >> 2) & 0x1; | |
188 | prule->portmask = (data >> 3) & 0x3FF; | |
189 | prule->result = (data >> 13) & 0x1; | |
190 | } | |
191 | ||
08eb9470 | 192 | static void |
29873c74 SG |
193 | sdram_set_protection_config(struct socfpga_sdr_ctrl *sdr_ctrl, |
194 | const u32 sdram_start, const u32 sdram_end) | |
9bbd2132 DN |
195 | { |
196 | struct sdram_prot_rule rule; | |
197 | int rules; | |
198 | ||
199 | /* Start with accepting all SDRAM transaction */ | |
200 | writel(0x0, &sdr_ctrl->protport_default); | |
201 | ||
202 | /* Clear all protection rules for warm boot case */ | |
a003740a | 203 | memset(&rule, 0, sizeof(rule)); |
9bbd2132 DN |
204 | |
205 | for (rules = 0; rules < 20; rules++) { | |
206 | rule.rule = rules; | |
29873c74 | 207 | sdram_set_rule(sdr_ctrl, &rule); |
9bbd2132 DN |
208 | } |
209 | ||
210 | /* new rule: accept SDRAM */ | |
211 | rule.sdram_start = sdram_start; | |
212 | rule.sdram_end = sdram_end; | |
213 | rule.lo_prot_id = 0x0; | |
214 | rule.hi_prot_id = 0xFFF; | |
215 | rule.portmask = 0x3FF; | |
216 | rule.security = 0x3; | |
217 | rule.result = 0; | |
218 | rule.valid = 1; | |
219 | rule.rule = 0; | |
220 | ||
221 | /* set new rule */ | |
29873c74 | 222 | sdram_set_rule(sdr_ctrl, &rule); |
9bbd2132 DN |
223 | |
224 | /* default rule: reject everything */ | |
225 | writel(0x3ff, &sdr_ctrl->protport_default); | |
226 | } | |
227 | ||
29873c74 | 228 | static void sdram_dump_protection_config(struct socfpga_sdr_ctrl *sdr_ctrl) |
9bbd2132 DN |
229 | { |
230 | struct sdram_prot_rule rule; | |
231 | int rules; | |
232 | ||
233 | debug("SDRAM Prot rule, default %x\n", | |
234 | readl(&sdr_ctrl->protport_default)); | |
235 | ||
236 | for (rules = 0; rules < 20; rules++) { | |
1720fad0 | 237 | rule.rule = rules; |
29873c74 | 238 | sdram_get_rule(sdr_ctrl, &rule); |
9bbd2132 | 239 | debug("Rule %d, rules ...\n", rules); |
08eb9470 MV |
240 | debug(" sdram start %x\n", rule.sdram_start); |
241 | debug(" sdram end %x\n", rule.sdram_end); | |
9bbd2132 DN |
242 | debug(" low prot id %d, hi prot id %d\n", |
243 | rule.lo_prot_id, | |
244 | rule.hi_prot_id); | |
245 | debug(" portmask %x\n", rule.portmask); | |
246 | debug(" security %d\n", rule.security); | |
247 | debug(" result %d\n", rule.result); | |
248 | debug(" valid %d\n", rule.valid); | |
249 | } | |
250 | } | |
251 | ||
269de4f0 MV |
252 | /** |
253 | * sdram_write_verify() - write to register and verify the write. | |
254 | * @addr: Register address | |
255 | * @val: Value to be written and verified | |
256 | * | |
257 | * This function writes to a register, reads back the value and compares | |
258 | * the result with the written value to check if the data match. | |
259 | */ | |
260 | static unsigned sdram_write_verify(const u32 *addr, const u32 val) | |
9bbd2132 | 261 | { |
269de4f0 MV |
262 | u32 rval; |
263 | ||
264 | debug(" Write - Address 0x%p Data 0x%08x\n", addr, val); | |
265 | writel(val, addr); | |
266 | ||
9bbd2132 | 267 | debug(" Read and verify..."); |
269de4f0 MV |
268 | rval = readl(addr); |
269 | if (rval != val) { | |
270 | debug("FAIL - Address 0x%p Expected 0x%08x Data 0x%08x\n", | |
271 | addr, val, rval); | |
272 | return -EINVAL; | |
9bbd2132 | 273 | } |
269de4f0 | 274 | |
9bbd2132 | 275 | debug("correct!\n"); |
9bbd2132 DN |
276 | return 0; |
277 | } | |
278 | ||
96b869b6 MV |
279 | /** |
280 | * sdr_get_ctrlcfg() - Get the value of DRAM CTRLCFG register | |
281 | * @cfg: SDRAM controller configuration data | |
282 | * | |
283 | * Return the value of DRAM CTRLCFG register. | |
284 | */ | |
5af91418 | 285 | static u32 sdr_get_ctrlcfg(const struct socfpga_sdram_config *cfg) |
9bbd2132 | 286 | { |
764aa9a9 MV |
287 | const u32 csbits = |
288 | ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >> | |
289 | SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1; | |
290 | u32 addrorder = | |
291 | (cfg->ctrl_cfg & SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK) >> | |
292 | SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB; | |
293 | ||
04ae4489 | 294 | u32 ctrl_cfg = cfg->ctrl_cfg; |
9bbd2132 | 295 | |
067c853f MV |
296 | /* |
297 | * SDRAM Failure When Accessing Non-Existent Memory | |
9bbd2132 DN |
298 | * Set the addrorder field of the SDRAM control register |
299 | * based on the CSBITs setting. | |
300 | */ | |
764aa9a9 MV |
301 | if (csbits == 1) { |
302 | if (addrorder != 0) | |
067c853f | 303 | debug("INFO: Changing address order to 0 (chip, row, bank, column)\n"); |
764aa9a9 MV |
304 | addrorder = 0; |
305 | } else if (csbits == 2) { | |
306 | if (addrorder != 2) | |
067c853f | 307 | debug("INFO: Changing address order to 2 (row, chip, bank, column)\n"); |
764aa9a9 | 308 | addrorder = 2; |
9bbd2132 DN |
309 | } |
310 | ||
764aa9a9 | 311 | ctrl_cfg &= ~SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK; |
067c853f | 312 | ctrl_cfg |= addrorder << SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB; |
9bbd2132 | 313 | |
9d6b012c | 314 | return ctrl_cfg; |
9bbd2132 DN |
315 | } |
316 | ||
96b869b6 MV |
317 | /** |
318 | * sdr_get_addr_rw() - Get the value of DRAM ADDRW register | |
319 | * @cfg: SDRAM controller configuration data | |
320 | * | |
321 | * Return the value of DRAM ADDRW register. | |
322 | */ | |
5af91418 | 323 | static u32 sdr_get_addr_rw(const struct socfpga_sdram_config *cfg) |
9bbd2132 | 324 | { |
9bbd2132 DN |
325 | /* |
326 | * SDRAM Failure When Accessing Non-Existent Memory | |
9bbd2132 DN |
327 | * Set SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB to |
328 | * log2(number of chip select bits). Since there's only | |
329 | * 1 or 2 chip selects, log2(1) => 0, and log2(2) => 1, | |
330 | * which is the same as "chip selects" - 1. | |
331 | */ | |
764aa9a9 MV |
332 | const int rows = get_errata_rows(cfg); |
333 | u32 dram_addrw = cfg->dram_addrw & ~SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK; | |
04ae4489 | 334 | |
9d6b012c | 335 | return dram_addrw | (rows << SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB); |
9bbd2132 DN |
336 | } |
337 | ||
1a302a45 MV |
338 | /** |
339 | * sdr_load_regs() - Load SDRAM controller registers | |
340 | * @cfg: SDRAM controller configuration data | |
341 | * | |
342 | * This function loads the register values into the SDRAM controller block. | |
343 | */ | |
29873c74 SG |
344 | static void sdr_load_regs(struct socfpga_sdr_ctrl *sdr_ctrl, |
345 | const struct socfpga_sdram_config *cfg) | |
9bbd2132 | 346 | { |
9d6b012c MV |
347 | const u32 ctrl_cfg = sdr_get_ctrlcfg(cfg); |
348 | const u32 dram_addrw = sdr_get_addr_rw(cfg); | |
349 | ||
9d6b012c MV |
350 | debug("\nConfiguring CTRLCFG\n"); |
351 | writel(ctrl_cfg, &sdr_ctrl->ctrl_cfg); | |
076470ee MV |
352 | |
353 | debug("Configuring DRAMTIMING1\n"); | |
354 | writel(cfg->dram_timing1, &sdr_ctrl->dram_timing1); | |
355 | ||
356 | debug("Configuring DRAMTIMING2\n"); | |
357 | writel(cfg->dram_timing2, &sdr_ctrl->dram_timing2); | |
358 | ||
359 | debug("Configuring DRAMTIMING3\n"); | |
360 | writel(cfg->dram_timing3, &sdr_ctrl->dram_timing3); | |
361 | ||
362 | debug("Configuring DRAMTIMING4\n"); | |
363 | writel(cfg->dram_timing4, &sdr_ctrl->dram_timing4); | |
364 | ||
365 | debug("Configuring LOWPWRTIMING\n"); | |
366 | writel(cfg->lowpwr_timing, &sdr_ctrl->lowpwr_timing); | |
367 | ||
9d6b012c MV |
368 | debug("Configuring DRAMADDRW\n"); |
369 | writel(dram_addrw, &sdr_ctrl->dram_addrw); | |
9bbd2132 DN |
370 | |
371 | debug("Configuring DRAMIFWIDTH\n"); | |
dc3b91d9 | 372 | writel(cfg->dram_if_width, &sdr_ctrl->dram_if_width); |
9bbd2132 DN |
373 | |
374 | debug("Configuring DRAMDEVWIDTH\n"); | |
dc3b91d9 | 375 | writel(cfg->dram_dev_width, &sdr_ctrl->dram_dev_width); |
9bbd2132 DN |
376 | |
377 | debug("Configuring LOWPWREQ\n"); | |
dc3b91d9 | 378 | writel(cfg->lowpwr_eq, &sdr_ctrl->lowpwr_eq); |
9bbd2132 DN |
379 | |
380 | debug("Configuring DRAMINTR\n"); | |
dc3b91d9 | 381 | writel(cfg->dram_intr, &sdr_ctrl->dram_intr); |
9bbd2132 | 382 | |
076470ee MV |
383 | debug("Configuring STATICCFG\n"); |
384 | writel(cfg->static_cfg, &sdr_ctrl->static_cfg); | |
9bbd2132 DN |
385 | |
386 | debug("Configuring CTRLWIDTH\n"); | |
dc3b91d9 | 387 | writel(cfg->ctrl_width, &sdr_ctrl->ctrl_width); |
9bbd2132 DN |
388 | |
389 | debug("Configuring PORTCFG\n"); | |
dc3b91d9 | 390 | writel(cfg->port_cfg, &sdr_ctrl->port_cfg); |
9bbd2132 | 391 | |
076470ee MV |
392 | debug("Configuring FIFOCFG\n"); |
393 | writel(cfg->fifo_cfg, &sdr_ctrl->fifo_cfg); | |
9bbd2132 DN |
394 | |
395 | debug("Configuring MPPRIORITY\n"); | |
dc3b91d9 | 396 | writel(cfg->mp_priority, &sdr_ctrl->mp_priority); |
9bbd2132 | 397 | |
076470ee MV |
398 | debug("Configuring MPWEIGHT_MPWEIGHT_0\n"); |
399 | writel(cfg->mp_weight0, &sdr_ctrl->mp_weight0); | |
400 | writel(cfg->mp_weight1, &sdr_ctrl->mp_weight1); | |
401 | writel(cfg->mp_weight2, &sdr_ctrl->mp_weight2); | |
402 | writel(cfg->mp_weight3, &sdr_ctrl->mp_weight3); | |
403 | ||
404 | debug("Configuring MPPACING_MPPACING_0\n"); | |
405 | writel(cfg->mp_pacing0, &sdr_ctrl->mp_pacing0); | |
406 | writel(cfg->mp_pacing1, &sdr_ctrl->mp_pacing1); | |
407 | writel(cfg->mp_pacing2, &sdr_ctrl->mp_pacing2); | |
408 | writel(cfg->mp_pacing3, &sdr_ctrl->mp_pacing3); | |
409 | ||
410 | debug("Configuring MPTHRESHOLDRST_MPTHRESHOLDRST_0\n"); | |
411 | writel(cfg->mp_threshold0, &sdr_ctrl->mp_threshold0); | |
412 | writel(cfg->mp_threshold1, &sdr_ctrl->mp_threshold1); | |
413 | writel(cfg->mp_threshold2, &sdr_ctrl->mp_threshold2); | |
9bbd2132 DN |
414 | |
415 | debug("Configuring PHYCTRL_PHYCTRL_0\n"); | |
dc3b91d9 | 416 | writel(cfg->phy_ctrl0, &sdr_ctrl->phy_ctrl0); |
9bbd2132 DN |
417 | |
418 | debug("Configuring CPORTWIDTH\n"); | |
dc3b91d9 | 419 | writel(cfg->cport_width, &sdr_ctrl->cport_width); |
9bbd2132 DN |
420 | |
421 | debug("Configuring CPORTWMAP\n"); | |
dc3b91d9 | 422 | writel(cfg->cport_wmap, &sdr_ctrl->cport_wmap); |
9bbd2132 DN |
423 | |
424 | debug("Configuring CPORTRMAP\n"); | |
dc3b91d9 | 425 | writel(cfg->cport_rmap, &sdr_ctrl->cport_rmap); |
9bbd2132 DN |
426 | |
427 | debug("Configuring RFIFOCMAP\n"); | |
dc3b91d9 | 428 | writel(cfg->rfifo_cmap, &sdr_ctrl->rfifo_cmap); |
9bbd2132 DN |
429 | |
430 | debug("Configuring WFIFOCMAP\n"); | |
dc3b91d9 | 431 | writel(cfg->wfifo_cmap, &sdr_ctrl->wfifo_cmap); |
9bbd2132 DN |
432 | |
433 | debug("Configuring CPORTRDWR\n"); | |
dc3b91d9 | 434 | writel(cfg->cport_rdwr, &sdr_ctrl->cport_rdwr); |
9bbd2132 DN |
435 | |
436 | debug("Configuring DRAMODT\n"); | |
dc3b91d9 | 437 | writel(cfg->dram_odt, &sdr_ctrl->dram_odt); |
89a54abf | 438 | |
9a5a90ad MV |
439 | if (dram_is_ddr(3)) { |
440 | debug("Configuring EXTRATIME1\n"); | |
441 | writel(cfg->extratime1, &sdr_ctrl->extratime1); | |
442 | } | |
1a302a45 MV |
443 | } |
444 | ||
1e8a85f8 MV |
445 | /** |
446 | * sdram_mmr_init_full() - Function to initialize SDRAM MMR | |
447 | * @sdr_phy_reg: Value of the PHY control register 0 | |
448 | * | |
449 | * Initialize the SDRAM MMR. | |
450 | */ | |
29873c74 SG |
451 | int sdram_mmr_init_full(struct socfpga_sdr_ctrl *sdr_ctrl, |
452 | unsigned int sdr_phy_reg) | |
1a302a45 | 453 | { |
5af91418 | 454 | const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config(); |
1a302a45 MV |
455 | const unsigned int rows = |
456 | (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >> | |
457 | SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; | |
269de4f0 | 458 | int ret; |
1a302a45 | 459 | |
db5741f7 LFT |
460 | writel(rows, |
461 | socfpga_get_sysmgr_addr() + SYSMGR_ISWGRP_HANDOFF_OFFSET(4)); | |
1a302a45 | 462 | |
29873c74 | 463 | sdr_load_regs(sdr_ctrl, cfg); |
9bbd2132 DN |
464 | |
465 | /* saving this value to SYSMGR.ISWGRP.HANDOFF.FPGA2SDR */ | |
db5741f7 LFT |
466 | writel(cfg->fpgaport_rst, |
467 | socfpga_get_sysmgr_addr() + SYSMGR_ISWGRP_HANDOFF_OFFSET(3)); | |
9bbd2132 DN |
468 | |
469 | /* only enable if the FPGA is programmed */ | |
470 | if (fpgamgr_test_fpga_ready()) { | |
269de4f0 MV |
471 | ret = sdram_write_verify(&sdr_ctrl->fpgaport_rst, |
472 | cfg->fpgaport_rst); | |
473 | if (ret) | |
474 | return ret; | |
9bbd2132 DN |
475 | } |
476 | ||
477 | /* Restore the SDR PHY Register if valid */ | |
478 | if (sdr_phy_reg != 0xffffffff) | |
479 | writel(sdr_phy_reg, &sdr_ctrl->phy_ctrl0); | |
480 | ||
dc3b91d9 MV |
481 | /* Final step - apply configuration changes */ |
482 | debug("Configuring STATICCFG\n"); | |
483 | clrsetbits_le32(&sdr_ctrl->static_cfg, | |
484 | SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK, | |
9bbd2132 | 485 | 1 << SDR_CTRLGRP_STATICCFG_APPLYCFG_LSB); |
9bbd2132 | 486 | |
29873c74 SG |
487 | sdram_set_protection_config(sdr_ctrl, 0, |
488 | sdram_calculate_size(sdr_ctrl) - 1); | |
9bbd2132 | 489 | |
29873c74 | 490 | sdram_dump_protection_config(sdr_ctrl); |
9bbd2132 | 491 | |
269de4f0 | 492 | return 0; |
9bbd2132 DN |
493 | } |
494 | ||
f97606f2 MV |
495 | /** |
496 | * sdram_calculate_size() - Calculate SDRAM size | |
9bbd2132 | 497 | * |
f97606f2 MV |
498 | * Calculate SDRAM device size based on SDRAM controller parameters. |
499 | * Size is specified in bytes. | |
9bbd2132 | 500 | */ |
29873c74 | 501 | static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl) |
9bbd2132 DN |
502 | { |
503 | unsigned long temp; | |
504 | unsigned long row, bank, col, cs, width; | |
bb056d9c MV |
505 | const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config(); |
506 | const unsigned int csbits = | |
507 | ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >> | |
508 | SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1; | |
509 | const unsigned int rowbits = | |
510 | (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >> | |
511 | SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; | |
9bbd2132 DN |
512 | |
513 | temp = readl(&sdr_ctrl->dram_addrw); | |
514 | col = (temp & SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK) >> | |
515 | SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB; | |
516 | ||
f97606f2 MV |
517 | /* |
518 | * SDRAM Failure When Accessing Non-Existent Memory | |
9bbd2132 DN |
519 | * Use ROWBITS from Quartus/QSys to calculate SDRAM size |
520 | * since the FB specifies we modify ROWBITs to work around SDRAM | |
521 | * controller issue. | |
9bbd2132 | 522 | */ |
db5741f7 LFT |
523 | row = readl(socfpga_get_sysmgr_addr() + |
524 | SYSMGR_ISWGRP_HANDOFF_OFFSET(4)); | |
9bbd2132 | 525 | if (row == 0) |
bb056d9c | 526 | row = rowbits; |
f97606f2 MV |
527 | /* |
528 | * If the stored handoff value for rows is greater than | |
9bbd2132 DN |
529 | * the field width in the sdr.dramaddrw register then |
530 | * something is very wrong. Revert to using the the #define | |
531 | * value handed off by the SOCEDS tool chain instead of | |
532 | * using a broken value. | |
533 | */ | |
534 | if (row > 31) | |
bb056d9c | 535 | row = rowbits; |
9bbd2132 DN |
536 | |
537 | bank = (temp & SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK) >> | |
538 | SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB; | |
539 | ||
f97606f2 MV |
540 | /* |
541 | * SDRAM Failure When Accessing Non-Existent Memory | |
9bbd2132 DN |
542 | * Use CSBITs from Quartus/QSys to calculate SDRAM size |
543 | * since the FB specifies we modify CSBITs to work around SDRAM | |
544 | * controller issue. | |
545 | */ | |
bb056d9c | 546 | cs = csbits; |
9bbd2132 DN |
547 | |
548 | width = readl(&sdr_ctrl->dram_if_width); | |
f97606f2 | 549 | |
9bbd2132 DN |
550 | /* ECC would not be calculated as its not addressible */ |
551 | if (width == SDRAM_WIDTH_32BIT_WITH_ECC) | |
552 | width = 32; | |
553 | if (width == SDRAM_WIDTH_16BIT_WITH_ECC) | |
554 | width = 16; | |
555 | ||
556 | /* calculate the SDRAM size base on this info */ | |
557 | temp = 1 << (row + bank + col); | |
558 | temp = temp * cs * (width / 8); | |
559 | ||
f97606f2 | 560 | debug("%s returns %ld\n", __func__, temp); |
9bbd2132 DN |
561 | |
562 | return temp; | |
563 | } | |
29873c74 SG |
564 | |
565 | static int altera_gen5_sdram_ofdata_to_platdata(struct udevice *dev) | |
566 | { | |
567 | struct altera_gen5_sdram_platdata *plat = dev->platdata; | |
568 | ||
569 | plat->sdr = (struct socfpga_sdr *)devfdt_get_addr_index(dev, 0); | |
570 | if (!plat->sdr) | |
571 | return -ENODEV; | |
572 | ||
573 | return 0; | |
574 | } | |
575 | ||
576 | static int altera_gen5_sdram_probe(struct udevice *dev) | |
577 | { | |
578 | int ret; | |
579 | unsigned long sdram_size; | |
580 | struct altera_gen5_sdram_platdata *plat = dev->platdata; | |
581 | struct altera_gen5_sdram_priv *priv = dev_get_priv(dev); | |
582 | struct socfpga_sdr_ctrl *sdr_ctrl = &plat->sdr->sdr_ctrl; | |
583 | struct reset_ctl_bulk resets; | |
584 | ||
585 | ret = reset_get_bulk(dev, &resets); | |
586 | if (ret) { | |
587 | dev_err(dev, "Can't get reset: %d\n", ret); | |
588 | return -ENODEV; | |
589 | } | |
590 | reset_deassert_bulk(&resets); | |
591 | ||
592 | if (sdram_mmr_init_full(sdr_ctrl, 0xffffffff) != 0) { | |
593 | puts("SDRAM init failed.\n"); | |
594 | goto failed; | |
595 | } | |
596 | ||
597 | debug("SDRAM: Calibrating PHY\n"); | |
598 | /* SDRAM calibration */ | |
599 | if (sdram_calibration_full(plat->sdr) == 0) { | |
600 | puts("SDRAM calibration failed.\n"); | |
601 | goto failed; | |
602 | } | |
603 | ||
604 | sdram_size = sdram_calculate_size(sdr_ctrl); | |
605 | debug("SDRAM: %ld MiB\n", sdram_size >> 20); | |
606 | ||
607 | /* Sanity check ensure correct SDRAM size specified */ | |
608 | if (get_ram_size(0, sdram_size) != sdram_size) { | |
609 | puts("SDRAM size check failed!\n"); | |
610 | goto failed; | |
611 | } | |
612 | ||
613 | priv->info.base = 0; | |
614 | priv->info.size = sdram_size; | |
615 | ||
616 | return 0; | |
617 | ||
618 | failed: | |
619 | reset_release_bulk(&resets); | |
620 | return -ENODEV; | |
621 | } | |
622 | ||
623 | static int altera_gen5_sdram_get_info(struct udevice *dev, | |
624 | struct ram_info *info) | |
625 | { | |
626 | struct altera_gen5_sdram_priv *priv = dev_get_priv(dev); | |
627 | ||
628 | info->base = priv->info.base; | |
629 | info->size = priv->info.size; | |
630 | ||
631 | return 0; | |
632 | } | |
633 | ||
aacd7b92 | 634 | static const struct ram_ops altera_gen5_sdram_ops = { |
29873c74 SG |
635 | .get_info = altera_gen5_sdram_get_info, |
636 | }; | |
637 | ||
638 | static const struct udevice_id altera_gen5_sdram_ids[] = { | |
639 | { .compatible = "altr,sdr-ctl" }, | |
640 | { /* sentinel */ } | |
641 | }; | |
642 | ||
643 | U_BOOT_DRIVER(altera_gen5_sdram) = { | |
644 | .name = "altr_sdr_ctl", | |
645 | .id = UCLASS_RAM, | |
646 | .of_match = altera_gen5_sdram_ids, | |
647 | .ops = &altera_gen5_sdram_ops, | |
648 | .ofdata_to_platdata = altera_gen5_sdram_ofdata_to_platdata, | |
649 | .platdata_auto_alloc_size = sizeof(struct altera_gen5_sdram_platdata), | |
650 | .probe = altera_gen5_sdram_probe, | |
651 | .priv_auto_alloc_size = sizeof(struct altera_gen5_sdram_priv), | |
652 | }; | |
653 | ||
654 | #endif /* CONFIG_SPL_BUILD */ |