From: Jean Delvare <jdelvare@suse.de>
To: Linux I2C <linux-i2c@vger.kernel.org>
Subject: [PATCH 2/6] decode-dimms: Decode size and timings of DDR4
Date: Sun, 19 Nov 2017 13:34:18 +0100 [thread overview]
Message-ID: <20171119133418.63d7e0a6@endymion> (raw)
In-Reply-To: <20171119133309.67d4c596@endymion>
Decode the memory module size and timings of DDR4 memory.
---
eeprom/decode-dimms | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 176 insertions(+), 1 deletion(-)
--- i2c-tools.orig/eeprom/decode-dimms 2017-11-17 11:21:44.196398606 +0100
+++ i2c-tools/eeprom/decode-dimms 2017-11-17 11:24:29.028405403 +0100
@@ -1702,15 +1702,190 @@ sub decode_ddr3_sdram($)
}
-# Parameter: EEPROM bytes 0-127 (using 1-1)
+# Return combined time in ns
+sub ddr4_mtb_ftb($$$$)
+{
+ my ($byte1, $byte2, $mtb, $ftb) = @_;
+
+ # byte1 is unsigned in ps, but byte2 is signed in ps
+ $byte2 -= 0x100 if $byte2 & 0x80;
+
+ return ($byte1 * $mtb + $byte2 * $ftb) / 1000;
+}
+
+# Rounded per DDR4 specifications
+sub ddr4_core_timings($$$$$)
+{
+ my ($cas, $ctime, $trcd, $trp, $tras) = @_;
+
+ return $cas . "-" . ceil($trcd/$ctime - 0.025) .
+ "-" . ceil($trp/$ctime - 0.025) .
+ "-" . ceil($tras/$ctime - 0.025);
+}
+
+use constant DDR4_UNBUFFERED => 1;
+use constant DDR4_REGISTERED => 2;
+use constant DDR4_LOAD_REDUCED => 4;
+
+# Parameter: EEPROM bytes 0-383 (using 1-125)
sub decode_ddr4_sdram($)
{
my $bytes = shift;
+ my ($ctime, $ctime_max);
+ my ($ftb, $mtb);
+ my $ii;
+
+ my @module_types = (
+ { type => "Extended type", },
+ { type => "RDIMM", family => DDR4_REGISTERED },
+ { type => "UDIMM", family => DDR4_UNBUFFERED },
+ { type => "SO-DIMM", family => DDR4_UNBUFFERED },
+ { type => "LRDIMM", family => DDR4_LOAD_REDUCED },
+ { type => "Mini-RDIMM", family => DDR4_REGISTERED },
+ { type => "Mini-UDIMM", family => DDR4_UNBUFFERED },
+ { type => "Reserved (0x07)", },
+ { type => "72b-SO-RDIMM", family => DDR4_REGISTERED },
+ { type => "72b-SO-UDIMM", family => DDR4_UNBUFFERED },
+ { type => "Reserved (0x0A)", },
+ { type => "Reserved (0x0B)", },
+ { type => "16b-SO-DIMM", family => DDR4_UNBUFFERED },
+ { type => "32b-SO-DIMM", family => DDR4_UNBUFFERED },
+ { type => "Reserved (0x0E)", },
+ { type => "No base memory", },
+ );
# SPD revision
printl_cond($bytes->[1] != 0xff, "SPD Revision",
($bytes->[1] >> 4) . "." . ($bytes->[1] & 0xf));
+ printl("Module Type", $module_types[$bytes->[3] & 0x0f]->{type});
+
+# time bases
+ if (($bytes->[17] & 0x03) != 0x00 || ($bytes->[17] & 0xc0) != 0x00) {
+ print STDERR "Unknown time base values, can't decode\n";
+ return;
+ }
+ $ftb = 1; # ps
+ $mtb = 125; # ps
+
+# speed
+ prints("Memory Characteristics");
+
+ $ctime = ddr4_mtb_ftb($bytes->[18], $bytes->[125], $mtb, $ftb);
+ $ctime_max = ddr4_mtb_ftb($bytes->[19], $bytes->[124], $mtb, $ftb);
+
+ my $ddrclk = 2 * (1000 / $ctime);
+ my $tbits = 8 << ($bytes->[13] & 7);
+ my $pcclk = int ($ddrclk * $tbits / 8);
+ # Round down to comply with Jedec
+ $pcclk = $pcclk - ($pcclk % 100);
+ $ddrclk = int ($ddrclk);
+ printl("Maximum module speed", "$ddrclk MHz (PC4-${pcclk})");
+
+# Size computation
+ my $sdram_width = 4 << ($bytes->[12] & 0x07);
+ my $ranks = (($bytes->[12] >> 3) & 0x07) + 1;
+ my $signal_loading = $bytes->[6] & 0x03;
+ my $die_count = (($bytes->[6] >> 4) & 0x07) + 1;
+ my $cap = (256 << ($bytes->[4] & 0x0f)) / 8;
+ $cap *= (8 << ($bytes->[13] & 0x07)) / $sdram_width;
+ $cap *= $ranks;
+ $cap *= $die_count if $signal_loading == 0x02; # 3DS
+ printl("Size", $cap . " MB");
+
+ printl("Banks x Rows x Columns x Bits",
+ join(' x ', (1 << ($bytes->[4] >> 6)) * (4 << (($bytes->[4] >> 4) & 0x03)),
+ ((($bytes->[5] >> 3) & 7) + 12),
+ ( ($bytes->[5] & 7) + 9),
+ (8 << ($bytes->[13] & 0x07))));
+
+ printl("SDRAM Device Width", "$sdram_width bits");
+ printl("Ranks", $ranks);
+ printl_cond($ranks > 1, "Rank Mix",
+ $bytes->[12] & 0x40 ? "Asymmetrical" : "Symmetrical");
+ printl_cond($bytes->[13] & 0x18, "Bus Width Extension", ($bytes->[13] & 0x18)." bits");
+
+ my $taa;
+ my $trcd;
+ my $trp;
+ my $tras;
+
+ $taa = ddr4_mtb_ftb($bytes->[24], $bytes->[123], $mtb, $ftb);
+ $trcd = ddr4_mtb_ftb($bytes->[25], $bytes->[122], $mtb, $ftb);
+ $trp = ddr4_mtb_ftb($bytes->[26], $bytes->[121], $mtb, $ftb);
+ $tras = ((($bytes->[27] & 0x0f) << 8) + $bytes->[28]) * $mtb / 1000;
+
+ printl("AA-RCD-RP-RAS (cycles)",
+ ddr4_core_timings(ceil($taa/$ctime - 0.025), $ctime,
+ $trcd, $trp, $tras));
+
+# latencies
+ my %cas;
+ my $cas_sup = ($bytes->[23] << 24) + ($bytes->[22] << 16) +
+ ($bytes->[21] << 8) + $bytes->[20];
+ my $base_cas = $bytes->[23] & 0x80 ? 23 : 7;
+
+ for ($ii = 0; $ii < 30; $ii++) {
+ if ($cas_sup & (1 << $ii)) {
+ $cas{$base_cas + $ii}++;
+ }
+ }
+ printl("Supported CAS Latencies", cas_latencies(keys %cas));
+
+# standard DDR4 speeds
+ prints("Timings at Standard Speeds");
+ foreach my $ctime_at_speed (15/24, 15/22, 15/20, 15/18, 15/16, 15/14, 15/12) {
+ my $best_cas = 0;
+
+ # Find min CAS latency at this speed
+ for ($ii = 29; $ii >= 0; $ii--) {
+ next unless ($cas_sup & (1 << $ii));
+ if (ceil($taa/$ctime_at_speed - 0.025) <= $base_cas + $ii) {
+ $best_cas = $base_cas + $ii;
+ }
+ }
+
+ printl_cond($best_cas && $ctime_at_speed >= $ctime
+ && $ctime_at_speed <= $ctime_max,
+ "AA-RCD-RP-RAS (cycles)" . as_ddr(4, $ctime_at_speed),
+ ddr4_core_timings($best_cas, $ctime_at_speed,
+ $trcd, $trp, $tras));
+ }
+
+# more timing information
+ prints("Timing Parameters");
+
+ printl("Minimum Cycle Time (tCKmin)", tns3($ctime));
+ printl("Maximum Cycle Time (tCKmax)", tns3($ctime_max));
+ printl("Minimum CAS Latency Time (tAA)", tns3($taa));
+ printl("Minimum RAS to CAS Delay (tRCD)", tns3($trcd));
+ printl("Minimum Row Precharge Delay (tRP)", tns3($trp));
+ printl("Minimum Active to Precharge Delay (tRAS)", tns3($tras));
+ printl("Minimum Active to Auto-Refresh Delay (tRC)",
+ tns3(ddr4_mtb_ftb((($bytes->[27] & 0xf0) << 4) + $bytes->[29],
+ $bytes->[120], $mtb, $ftb)));
+ printl("Minimum Recovery Delay (tRFC1)",
+ tns3((($bytes->[31] << 8) + $bytes->[30]) * $mtb / 1000));
+ printl("Minimum Recovery Delay (tRFC2)",
+ tns3((($bytes->[33] << 8) + $bytes->[32]) * $mtb / 1000));
+ printl("Minimum Recovery Delay (tRFC4)",
+ tns3((($bytes->[35] << 8) + $bytes->[34]) * $mtb / 1000));
+ printl("Minimum Four Activate Window Delay (tFAW)",
+ tns3(((($bytes->[36] & 0x0f) << 8) + $bytes->[37]) * $mtb / 1000));
+ printl("Minimum Row Active to Row Active Delay (tRRD_S)",
+ tns3(ddr4_mtb_ftb($bytes->[38], $bytes->[119], $mtb, $ftb)));
+ printl("Minimum Row Active to Row Active Delay (tRRD_L)",
+ tns3(ddr4_mtb_ftb($bytes->[39], $bytes->[118], $mtb, $ftb)));
+ printl("Minimum CAS to CAS Delay (tCCD_L)",
+ tns3(ddr4_mtb_ftb($bytes->[40], $bytes->[117], $mtb, $ftb)));
+
+ # Optional?
+ my $twr = ((($bytes->[41] & 0x0f) << 8) + $bytes->[42]) * $mtb / 1000;
+ printl_cond($twr, "Minimum Write Recovery Time (tWR)", tns3($twr));
+ my $twtr = ((($bytes->[43] & 0x0f) << 8) + $bytes->[44]) * $mtb / 1000;
+ printl_cond($twtr, "Minimum Write to Read Time (tWTR_S)", tns3($twtr));
+ $twtr = ((($bytes->[43] & 0xf0) << 4) + $bytes->[45]) * $mtb / 1000;
+ printl_cond($twtr, "Minimum Write to Read Time (tWTR_L)", tns3($twtr));
}
# Parameter: EEPROM bytes 0-127 (using 4-5)
--
Jean Delvare
SUSE L3 Support
next prev parent reply other threads:[~2017-11-19 12:34 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-19 12:33 [PATCH 0/6] decode-dimms: Add support for DDR4 SDRAM memory Jean Delvare
2017-11-19 12:33 ` [PATCH 1/6] decode-dimms: Add preliminary DDR4 support Jean Delvare
2017-11-19 12:34 ` Jean Delvare [this message]
2017-11-19 12:34 ` [PATCH 3/6] decode-dimms: Decode misc parameters of DDR4 Jean Delvare
2017-11-19 12:35 ` [PATCH 4/6] decode-dimms: Decode physical characteristics " Jean Delvare
2017-11-19 12:36 ` [PATCH 5/6] decode-dimms: Documentation update for DDR4 Jean Delvare
2017-11-19 12:37 ` [PATCH 6/6] decode-dimms: Verify the CRC of DDR4 data block 1 Jean Delvare
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171119133418.63d7e0a6@endymion \
--to=jdelvare@suse.de \
--cc=linux-i2c@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).