1 # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2013-2020 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2017 whitequark <whitequark@whitequark.org>
4 # This file is Copyright (c) 2014 Yann Sionneau <ys@m-labs.hk>
5 # This file is Copyright (c) 2018 bunnie <bunnie@kosagi.com>
6 # This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
9 from nmigen
.utils
import log2_int
12 "PRECHARGE_ALL": "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
13 "MODE_REGISTER": "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
14 "AUTO_REFRESH": "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS",
15 "UNRESET": "DFII_CONTROL_ODT|DFII_CONTROL_RESET_N",
16 "CKE": "DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N"
19 # SDR ----------------------------------------------------------------------------------------------
22 def get_sdr_phy_init_sequence(phy_settings
, timing_settings
):
25 mr
= log2_int(bl
) + (cl
<< 4)
29 ("Bring CKE high", 0x0000, 0, cmds
["CKE"], 20000),
30 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
31 ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(
32 cl
, bl
), mr
+ reset_dll
, 0, cmds
["MODE_REGISTER"], 200),
33 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
34 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
35 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
36 ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl
,
37 bl
), mr
, 0, cmds
["MODE_REGISTER"], 200)
40 return init_sequence
, None
42 # DDR ----------------------------------------------------------------------------------------------
45 def get_ddr_phy_init_sequence(phy_settings
, timing_settings
):
48 mr
= log2_int(bl
) + (cl
<< 4)
53 ("Bring CKE high", 0x0000, 0, cmds
["CKE"], 20000),
54 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
55 ("Load Extended Mode Register", emr
, 1, cmds
["MODE_REGISTER"], 0),
56 ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(
57 cl
, bl
), mr
+ reset_dll
, 0, cmds
["MODE_REGISTER"], 200),
58 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
59 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
60 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
61 ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl
,
62 bl
), mr
, 0, cmds
["MODE_REGISTER"], 200)
65 return init_sequence
, None
67 # LPDDR --------------------------------------------------------------------------------------------
70 def get_lpddr_phy_init_sequence(phy_settings
, timing_settings
):
73 mr
= log2_int(bl
) + (cl
<< 4)
78 ("Bring CKE high", 0x0000, 0, cmds
["CKE"], 20000),
79 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
80 ("Load Extended Mode Register", emr
, 2, cmds
["MODE_REGISTER"], 0),
81 ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(
82 cl
, bl
), mr
+ reset_dll
, 0, cmds
["MODE_REGISTER"], 200),
83 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
84 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
85 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
86 ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl
,
87 bl
), mr
, 0, cmds
["MODE_REGISTER"], 200)
90 return init_sequence
, None
92 # DDR2 ---------------------------------------------------------------------------------------------
95 def get_ddr2_phy_init_sequence(phy_settings
, timing_settings
):
99 mr
= log2_int(bl
) + (cl
<< 4) + (wr
<< 9)
107 ("Bring CKE high", 0x0000, 0, cmds
["CKE"], 20000),
108 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
109 ("Load Extended Mode Register 3", emr3
, 3, cmds
["MODE_REGISTER"], 0),
110 ("Load Extended Mode Register 2", emr2
, 2, cmds
["MODE_REGISTER"], 0),
111 ("Load Extended Mode Register", emr
, 1, cmds
["MODE_REGISTER"], 0),
112 ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(
113 cl
, bl
), mr
+ reset_dll
, 0, cmds
["MODE_REGISTER"], 200),
114 ("Precharge All", 0x0400, 0, cmds
["PRECHARGE_ALL"], 0),
115 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
116 ("Auto Refresh", 0x0, 0, cmds
["AUTO_REFRESH"], 4),
117 ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl
,
118 bl
), mr
, 0, cmds
["MODE_REGISTER"], 200),
119 ("Load Extended Mode Register / OCD Default",
120 emr
+ocd
, 1, cmds
["MODE_REGISTER"], 0),
121 ("Load Extended Mode Register / OCD Exit",
122 emr
, 1, cmds
["MODE_REGISTER"], 0),
125 return init_sequence
, None
127 # DDR3 ---------------------------------------------------------------------------------------------
130 def get_ddr3_phy_init_sequence(phy_settings
, timing_settings
):
133 cwl
= phy_settings
.cwl
135 def format_mr0(bl
, cl
, wr
, dll_reset
):
163 mr0 |
= (cl_to_mr0
[cl
] & 1) << 2
164 mr0 |
= ((cl_to_mr0
[cl
] >> 1) & 0b111) << 4
165 mr0 |
= dll_reset
<< 8
166 mr0 |
= wr_to_mr0
[wr
] << 9
169 def format_mr1(ron
, rtt_nom
):
170 mr1
= ((ron
>> 0) & 1) << 1
171 mr1 |
= ((ron
>> 1) & 1) << 5
172 mr1 |
= ((rtt_nom
>> 0) & 1) << 2
173 mr1 |
= ((rtt_nom
>> 1) & 1) << 6
174 mr1 |
= ((rtt_nom
>> 2) & 1) << 9
177 def format_mr2(cwl
, rtt_wr
):
202 # default electrical settings (point to point)
207 # override electrical settings if specified
208 if hasattr(phy_settings
, "rtt_nom"):
209 rtt_nom
= phy_settings
.rtt_nom
210 if hasattr(phy_settings
, "rtt_wr"):
211 rtt_wr
= phy_settings
.rtt_wr
212 if hasattr(phy_settings
, "ron"):
213 ron
= phy_settings
.ron
215 # >= ceiling(tWR/tCK)
216 wr
= max(timing_settings
.tWTR
*phy_settings
.nphases
, 5)
217 mr0
= format_mr0(bl
, cl
, wr
, 1)
218 mr1
= format_mr1(z_to_ron
[ron
], z_to_rtt_nom
[rtt_nom
])
219 mr2
= format_mr2(cwl
, z_to_rtt_wr
[rtt_wr
])
223 ("Release reset", 0x0000, 0, cmds
["UNRESET"], 50000),
224 ("Bring CKE high", 0x0000, 0, cmds
["CKE"], 10000),
225 ("Load Mode Register 2, CWL={0:d}".format(
226 cwl
), mr2
, 2, cmds
["MODE_REGISTER"], 0),
227 ("Load Mode Register 3", mr3
, 3, cmds
["MODE_REGISTER"], 0),
228 ("Load Mode Register 1", mr1
, 1, cmds
["MODE_REGISTER"], 0),
229 ("Load Mode Register 0, CL={0:d}, BL={1:d}".format(
230 cl
, bl
), mr0
, 0, cmds
["MODE_REGISTER"], 200),
231 ("ZQ Calibration", 0x0400, 0, "DFII_COMMAND_WE|DFII_COMMAND_CS", 200),
234 return init_sequence
, mr1
236 # DDR4 ---------------------------------------------------------------------------------------------
239 def get_ddr4_phy_init_sequence(phy_settings
, timing_settings
):
242 cwl
= phy_settings
.cwl
244 def format_mr0(bl
, cl
, wr
, dll_reset
):
288 mr0 |
= (cl_to_mr0
[cl
] & 0b1) << 2
289 mr0 |
= ((cl_to_mr0
[cl
] >> 1) & 0b111) << 4
290 mr0 |
= ((cl_to_mr0
[cl
] >> 4) & 0b1) << 12
291 mr0 |
= dll_reset
<< 8
292 mr0 |
= (wr_to_mr0
[wr
] & 0b111) << 9
293 mr0 |
= (wr_to_mr0
[wr
] >> 3) << 13
296 def format_mr1(dll_enable
, ron
, rtt_nom
):
298 mr1 |
= ((ron
>> 0) & 0b1) << 1
299 mr1 |
= ((ron
>> 1) & 0b1) << 2
300 mr1 |
= ((rtt_nom
>> 0) & 0b1) << 8
301 mr1 |
= ((rtt_nom
>> 1) & 0b1) << 9
302 mr1 |
= ((rtt_nom
>> 2) & 0b1) << 10
305 def format_mr2(cwl
, rtt_wr
):
316 mr2
= cwl_to_mr2
[cwl
] << 3
320 def format_mr3(fine_refresh_mode
):
321 fine_refresh_mode_to_mr3
= {
326 mr3
= fine_refresh_mode_to_mr3
[fine_refresh_mode
] << 6
329 def format_mr6(tccd
):
337 mr6
= tccd_to_mr6
[tccd
] << 10
364 # default electrical settings (point to point)
369 # override electrical settings if specified
370 if hasattr(phy_settings
, "rtt_nom"):
371 rtt_nom
= phy_settings
.rtt_nom
372 if hasattr(phy_settings
, "rtt_wr"):
373 rtt_wr
= phy_settings
.rtt_wr
374 if hasattr(phy_settings
, "ron"):
375 ron
= phy_settings
.ron
377 # >= ceiling(tWR/tCK)
378 wr
= max(timing_settings
.tWTR
*phy_settings
.nphases
, 10)
379 mr0
= format_mr0(bl
, cl
, wr
, 1)
380 mr1
= format_mr1(1, z_to_ron
[ron
], z_to_rtt_nom
[rtt_nom
])
381 mr2
= format_mr2(cwl
, z_to_rtt_wr
[rtt_wr
])
382 mr3
= format_mr3(timing_settings
.fine_refresh_mode
)
385 mr6
= format_mr6(4) # FIXME: tCCD
388 if phy_settings
.is_rdimm
:
389 def get_coarse_speed(tck
, pll_bypass
):
391 f_to_coarse_speed
= {
403 for f
, speed
in f_to_coarse_speed
.items():
408 def get_fine_speed(tck
):
411 fine_speed
= (freq
- 1240e6
) // 20e6
412 fine_speed
= max(fine_speed
, 0)
413 fine_speed
= min(fine_speed
, 0b1100001)
416 coarse_speed
= get_coarse_speed(
417 phy_settings
.tck
, phy_settings
.rcd_pll_bypass
)
418 fine_speed
= get_fine_speed(phy_settings
.tck
)
420 # F0RC06: command space control; 0: reset RCD
421 rcd_reset
= 0x060 |
0x0
423 f0rc0f
= 0x0F0 |
0x4 # F0RC05: 0 nCK latency adder
425 f0rc03
= 0x030 | phy_settings
.rcd_ca_cs_drive
# F0RC03: CA/CS drive strength
426 f0rc04
= 0x040 | phy_settings
.rcd_odt_cke_drive
# F0RC04: ODT/CKE drive strength
427 f0rc05
= 0x050 | phy_settings
.rcd_clk_drive
# F0RC04: ODT/CKE drive strength
429 # F0RC0A: coarse speed selection and PLL bypass
430 f0rc0a
= 0x0A0 | coarse_speed
431 f0rc3x
= 0x300 | fine_speed
# F0RC3x: fine speed selection
434 ("Reset RCD", rcd_reset
, 7, cmds
["MODE_REGISTER"], 50000),
435 ("Load RCD F0RC0F", f0rc0f
, 7, cmds
["MODE_REGISTER"], 100),
436 ("Load RCD F0RC03", f0rc03
, 7, cmds
["MODE_REGISTER"], 100),
437 ("Load RCD F0RC04", f0rc04
, 7, cmds
["MODE_REGISTER"], 100),
438 ("Load RCD F0RC05", f0rc05
, 7, cmds
["MODE_REGISTER"], 100),
439 ("Load RCD F0RC0A", f0rc0a
, 7, cmds
["MODE_REGISTER"], 100),
440 ("Load RCD F0RC3X", f0rc3x
, 7, cmds
["MODE_REGISTER"], 100),
444 ("Release reset", 0x0000, 0, cmds
["UNRESET"], 50000),
445 ("Bring CKE high", 0x0000, 0, cmds
["CKE"], 10000),
447 ("Load Mode Register 3", mr3
, 3, cmds
["MODE_REGISTER"], 0),
448 ("Load Mode Register 6", mr6
, 6, cmds
["MODE_REGISTER"], 0),
449 ("Load Mode Register 5", mr5
, 5, cmds
["MODE_REGISTER"], 0),
450 ("Load Mode Register 4", mr4
, 4, cmds
["MODE_REGISTER"], 0),
451 ("Load Mode Register 2, CWL={0:d}".format(
452 cwl
), mr2
, 2, cmds
["MODE_REGISTER"], 0),
453 ("Load Mode Register 1", mr1
, 1, cmds
["MODE_REGISTER"], 0),
454 ("Load Mode Register 0, CL={0:d}, BL={1:d}".format(
455 cl
, bl
), mr0
, 0, cmds
["MODE_REGISTER"], 200),
456 ("ZQ Calibration", 0x0400, 0, "DFII_COMMAND_WE|DFII_COMMAND_CS", 200),
459 return init_sequence
, mr1
461 # Init Sequence ------------------------------------------------------------------------------------
464 def get_sdram_phy_init_sequence(phy_settings
, timing_settings
):
466 "SDR": get_sdr_phy_init_sequence
,
467 "DDR": get_ddr_phy_init_sequence
,
468 "LPDDR": get_lpddr_phy_init_sequence
,
469 "DDR2": get_ddr2_phy_init_sequence
,
470 "DDR3": get_ddr3_phy_init_sequence
,
471 "DDR4": get_ddr4_phy_init_sequence
,
472 }[phy_settings
.memtype
](phy_settings
, timing_settings
)
474 # C Header -----------------------------------------------------------------------------------------
477 def get_sdram_phy_c_header(phy_settings
, timing_settings
):
478 r
= "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n"
479 r
+= "#include <hw/common.h>\n"
480 r
+= "#include <generated/csr.h>\n"
483 r
+= "#define DFII_CONTROL_SEL 0x01\n"
484 r
+= "#define DFII_CONTROL_CKE 0x02\n"
485 r
+= "#define DFII_CONTROL_ODT 0x04\n"
486 r
+= "#define DFII_CONTROL_RESET_N 0x08\n"
489 r
+= "#define DFII_COMMAND_CS 0x01\n"
490 r
+= "#define DFII_COMMAND_WE 0x02\n"
491 r
+= "#define DFII_COMMAND_CAS 0x04\n"
492 r
+= "#define DFII_COMMAND_RAS 0x08\n"
493 r
+= "#define DFII_COMMAND_WRDATA 0x10\n"
494 r
+= "#define DFII_COMMAND_RDDATA 0x20\n"
497 phytype
= phy_settings
.phytype
.upper()
498 nphases
= phy_settings
.nphases
500 # Define PHY type and number of phases
501 r
+= "#define SDRAM_PHY_"+phytype
+"\n"
502 r
+= "#define SDRAM_PHY_PHASES "+str(nphases
)+"\n"
504 # Define Read/Write Leveling capability
505 if phytype
in ["USDDRPHY", "USPDDRPHY", "K7DDRPHY", "V7DDRPHY"]:
506 r
+= "#define SDRAM_PHY_WRITE_LEVELING_CAPABLE\n"
507 if phytype
in ["USDDRPHY", "USPDDRPHY"]:
508 r
+= "#define SDRAM_PHY_WRITE_LEVELING_REINIT\n"
509 if phytype
in ["USDDRPHY", "USPDDRPHY", "A7DDRPHY", "K7DDRPHY", "V7DDRPHY", "ECP5DDRPHY"]:
510 r
+= "#define SDRAM_PHY_READ_LEVELING_CAPABLE\n"
512 # Define number of modules/delays/bitslips
513 if phytype
in ["USDDRPHY", "USPDDRPHY"]:
514 r
+= "#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2\n"
515 r
+= "#define SDRAM_PHY_DELAYS 512\n"
516 r
+= "#define SDRAM_PHY_BITSLIPS 16\n"
517 elif phytype
in ["A7DDRPHY", "K7DDRPHY", "V7DDRPHY"]:
518 r
+= "#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2\n"
519 r
+= "#define SDRAM_PHY_DELAYS 32\n"
520 r
+= "#define SDRAM_PHY_BITSLIPS 16\n"
521 elif phytype
in ["ECP5DDRPHY"]:
522 r
+= "#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/4\n"
523 r
+= "#define SDRAM_PHY_DELAYS 8\n"
524 r
+= "#define SDRAM_PHY_BITSLIPS 4\n"
526 if phy_settings
.is_rdimm
:
527 assert phy_settings
.memtype
== "DDR4"
528 r
+= "#define SDRAM_PHY_DDR4_RDIMM\n"
532 r
+= "static void cdelay(int i);\n"
534 # commands_px functions
535 for n
in range(nphases
):
537 __attribute__((unused)) static void command_p{n}(int cmd)
539 sdram_dfii_pi{n}_command_write(cmd);
540 sdram_dfii_pi{n}_command_issue_write(1);
541 }}""".format(n
=str(n
))
544 # rd/wr access macros
546 #define sdram_dfii_pird_address_write(X) sdram_dfii_pi{rdphase}_address_write(X)
547 #define sdram_dfii_piwr_address_write(X) sdram_dfii_pi{wrphase}_address_write(X)
548 #define sdram_dfii_pird_baddress_write(X) sdram_dfii_pi{rdphase}_baddress_write(X)
549 #define sdram_dfii_piwr_baddress_write(X) sdram_dfii_pi{wrphase}_baddress_write(X)
550 #define command_prd(X) command_p{rdphase}(X)
551 #define command_pwr(X) command_p{wrphase}(X)
552 """.format(rdphase
=str(phy_settings
.rdphase
), wrphase
=str(phy_settings
.wrphase
))
556 # sdrrd/sdrwr functions utilities
558 r
+= "#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE\n"
559 sdram_dfii_pix_wrdata_addr
= []
560 for n
in range(nphases
):
561 sdram_dfii_pix_wrdata_addr
.append(
562 "CSR_SDRAM_DFII_PI{n}_WRDATA_ADDR".format(n
=n
))
564 const unsigned long sdram_dfii_pix_wrdata_addr[SDRAM_PHY_PHASES] = {{
565 \t{sdram_dfii_pix_wrdata_addr}
567 """.format(sdram_dfii_pix_wrdata_addr
=",\n\t".join(sdram_dfii_pix_wrdata_addr
))
569 sdram_dfii_pix_rddata_addr
= []
570 for n
in range(nphases
):
571 sdram_dfii_pix_rddata_addr
.append(
572 "CSR_SDRAM_DFII_PI{n}_RDDATA_ADDR".format(n
=n
))
574 const unsigned long sdram_dfii_pix_rddata_addr[SDRAM_PHY_PHASES] = {{
575 \t{sdram_dfii_pix_rddata_addr}
577 """.format(sdram_dfii_pix_rddata_addr
=",\n\t".join(sdram_dfii_pix_rddata_addr
))
580 init_sequence
, mr1
= get_sdram_phy_init_sequence(
581 phy_settings
, timing_settings
)
583 if phy_settings
.memtype
in ["DDR3", "DDR4"]:
584 # the value of MR1 needs to be modified during write leveling
585 r
+= "#define DDRX_MR1 {}\n\n".format(mr1
)
587 r
+= "static void init_sequence(void)\n{\n"
588 for comment
, a
, ba
, cmd
, delay
in init_sequence
:
589 invert_masks
= [(0, 0), ]
590 if phy_settings
.is_rdimm
:
591 assert phy_settings
.memtype
== "DDR4"
594 # B-side chips have certain usually-inconsequential address and BA
595 # bits inverted by the RCD to reduce SSO current. For mode register
596 # writes, however, we must compensate for this. BG[1] also directs
597 # writes either to the A side (BG[1]=0) or B side (BG[1]=1)
599 # The 'ba != 7' is because we don't do this to writes to the RCD
602 invert_masks
.append((0b10101111111000, 0b1111))
604 for a_inv
, ba_inv
in invert_masks
:
605 r
+= "\t/* {0} */\n".format(comment
)
606 r
+= "\tsdram_dfii_pi0_address_write({0:#x});\n".format(a ^ a_inv
)
607 r
+= "\tsdram_dfii_pi0_baddress_write({0:d});\n".format(
609 if cmd
[:12] == "DFII_CONTROL":
610 r
+= "\tsdram_dfii_control_write({0});\n".format(cmd
)
612 r
+= "\tcommand_p0({0});\n".format(cmd
)
614 r
+= "\tcdelay({0:d});\n".format(delay
)
622 # Python Header ------------------------------------------------------------------------------------
625 def get_sdram_phy_py_header(phy_settings
, timing_settings
):
627 r
+= "dfii_control_sel = 0x01\n"
628 r
+= "dfii_control_cke = 0x02\n"
629 r
+= "dfii_control_odt = 0x04\n"
630 r
+= "dfii_control_reset_n = 0x08\n"
632 r
+= "dfii_command_cs = 0x01\n"
633 r
+= "dfii_command_we = 0x02\n"
634 r
+= "dfii_command_cas = 0x04\n"
635 r
+= "dfii_command_ras = 0x08\n"
636 r
+= "dfii_command_wrdata = 0x10\n"
637 r
+= "dfii_command_rddata = 0x20\n"
640 init_sequence
, mr1
= get_sdram_phy_init_sequence(
641 phy_settings
, timing_settings
)
644 r
+= "ddrx_mr1 = 0x{:x}\n".format(mr1
)
647 r
+= "init_sequence = [\n"
648 for comment
, a
, ba
, cmd
, delay
in init_sequence
:
650 r
+= "(\"" + comment
+ "\", "
653 r
+= cmd
.lower() + ", "
654 r
+= str(delay
) + "),"