Browse Source

Patch from Trent Piepho:

This lets decode-dimms.pl decode almost all of the SPD data for DDR2 dimms.
Included are all the detailed timing parameters with their standard tXXX
names, useful if one is trying to program a DDR memory controller for
example.  Or just to compare against any other SPD dump or memory spec
sheet.


git-svn-id: http://lm-sensors.org/svn/i2c-tools/trunk@5152 7894878c-1315-0410-8ee3-d5d059ff63e0
tags/v3.0.1
Jean Delvare 18 years ago
parent
commit
09e1d02772
  1. 3
      CHANGES
  2. 125
      eeprom/decode-dimms.pl

3
CHANGES

@ -3,8 +3,9 @@ i2c-tools CHANGES
SVN
decode-dimms: Fix DDR2 SDRAM module speed decoding
Update manufacturer IDs.
Update manufacturer IDs
Don't print anything by default if checksum fails
Decode all DDR2 SDRAM timing information
decode-vaio: Private data might not be readable by non-root users
Print the asset tag
Fix the timestamp decoding

125
eeprom/decode-dimms.pl

@ -406,6 +406,11 @@ sub printc ($) # print comment
}
}
sub tns($) # print a time in ns
{
return sprintf("%3.2f ns", $_[0]);
}
# Parameter: bytes 0-63
sub decode_sdr_sdram($)
{
@ -834,6 +839,41 @@ sub ddr2_sdram_atime($)
return $atime;
}
# Base, high-bit, 3-bit fraction code
sub ddr2_sdram_rtime($$$)
{
my ($rtime, $msb, $ext) = @_;
my @table = (0, .25, .33, .50, .66, .75);
return $rtime + $msb * 256 + $table[$ext];
}
sub ddr2_module_types($)
{
my $byte = shift;
my @types = qw(RDIMM UDIMM SO-DIMM Micro-DIMM Mini-RDIMM Mini-UDIMM);
my @widths = (133.35, 133.25, 67.6, 45.5, 82.0, 82.0);
my @suptypes;
local $_;
foreach (0..5) {
push @suptypes, "$types[$_] ($widths[$_] mm)"
if ($byte & (1 << $_));
}
return @suptypes;
}
sub ddr2_refresh_rate($)
{
my $byte = shift;
my @refresh = qw(Normal Reduced Reduced Extended Extended Extended);
my @refresht = (15.625, 3.9, 7.8, 31.3, 62.5, 125);
return "$refresh[$byte & 0x7f] ($refresht[$byte & 0x7f] us)".
($byte & 0x80 ? " - Self Refresh" : "");
}
# Parameter: bytes 0-63
sub decode_ddr2_sdram($)
{
@ -875,6 +915,32 @@ sub decode_ddr2_sdram($)
$bytes->[5] . "," . $bytes->[17];
}
printl "Banks x Rows x Columns x Bits",
join(' x ', $bytes->[17], $bytes->[3], $bytes->[4], $bytes->[6]);
printl "Ranks", ($bytes->[5] & 7) + 1;
printl "SDRAM Device Width", $bytes->[13]." bits";
my @heights = ('< 25.4', '25.4', '25.4 - 30.0', '30.0', '30.5', '> 30.5');
printl "Module Height", $heights[$bytes->[5] >> 5]." mm";
my @suptypes = ddr2_module_types($bytes->[20]);
printl "Module Type".(@suptypes > 1 ? 's' : ''), join(', ', @suptypes);
printl "DRAM Package", $bytes->[5] & 0x10 ? "Stack" : "Planar";
my @volts = ("TTL (5V Tolerant)", "LVTTL", "HSTL 1.5V",
"SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD");
printl "Voltage Interface Level", $volts[$bytes->[8]];
printl "Refresh Rate", ddr2_refresh_rate($bytes->[12]);
my @burst;
push @burst, 4 if ($bytes->[16] & 4);
push @burst, 8 if ($bytes->[16] & 8);
$burst[0] = 'None' if !@burst;
printl "Supported Burst Lengths", join(', ', @burst);
my $highestCAS = 0;
my %cas;
for ($ii = 2; $ii < 7; $ii++) {
@ -899,31 +965,60 @@ sub decode_ddr2_sdram($)
ceil($tras/$ctime);
# latencies
if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; }
if (keys %cas) { $temp = join ', ', map("${_}T", sort { $b <=> $a } keys %cas); }
else { $temp = "None"; }
printl "Supported CAS Latencies", $temp;
printl "Supported CAS Latencies (tCL)", $temp;
# timings
if (exists $cas{$highestCAS}) {
printl "Minimum Cycle Time (CAS $highestCAS)",
"$ctime ns";
printl "Maximum Access Time (CAS $highestCAS)",
ddr2_sdram_atime($bytes->[10]) . " ns";
printl "Minimum Cycle Time at CAS $highestCAS (tCK min)",
tns($ctime);
printl "Maximum Access Time at CAS $highestCAS (tAC)",
tns(ddr2_sdram_atime($bytes->[10]));
}
if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) {
printl "Minimum Cycle Time (CAS ".($highestCAS-1).")",
ddr2_sdram_ctime($bytes->[23]) . " ns";
printl "Maximum Access Time (CAS ".($highestCAS-1).")",
ddr2_sdram_atime($bytes->[24]) . " ns";
printl "Minimum Cycle Time at CAS ".($highestCAS-1),
tns(ddr2_sdram_ctime($bytes->[23]));
printl "Maximum Access Time at CAS ".($highestCAS-1),
tns(ddr2_sdram_atime($bytes->[24]));
}
if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) {
printl "Minimum Cycle Time (CAS ".($highestCAS-2).")",
ddr2_sdram_ctime($bytes->[25]) . " ns";
printl "Maximum Access Time (CAS ".($highestCAS-2).")",
ddr2_sdram_atime($bytes->[26]) . " ns";
}
printl "Minimum Cycle Time at CAS ".($highestCAS-2),
tns(ddr2_sdram_ctime($bytes->[25]));
printl "Maximum Access Time at CAS ".($highestCAS-2),
tns(ddr2_sdram_atime($bytes->[26]));
}
printl "Maximum Cycle Time (tCK max)",
tns(ddr2_sdram_ctime($bytes->[43]));
# more timing information
prints("Timing Parameters");
printl "Address/Command Setup Time Before Clock (tIS)",
tns(ddr2_sdram_atime($bytes->[32]));
printl "Address/Command Hold Time After Clock (tIH)",
tns(ddr2_sdram_atime($bytes->[33]));
printl "Data Input Setup Time Before Strobe (tDS)",
tns(ddr2_sdram_atime($bytes->[34]));
printl "Data Input Hold Time After Strobe (tDH)",
tns(ddr2_sdram_atime($bytes->[35]));
printl "Minimum Row Precharge Delay (tRP)", tns($trp);
printl "Minimum Row Active to Row Active Delay (tRRD)",
tns($bytes->[28]/4);
printl "Minimum RAS# to CAS# Delay (tRCD)", tns($trcd);
printl "Minimum RAS# Pulse Width (tRAS)", tns($tras);
printl "Write Recovery Time (tWR)", tns($bytes->[36]/4);
printl "Minimum Write to Read CMD Delay (tWTR)", tns($bytes->[37]/4);
printl "Minimum Read to Pre-charge CMD Delay (tRTP)", tns($bytes->[38]/4);
printl "Minimum Active to Auto-refresh Delay (tRC)",
tns(ddr2_sdram_rtime($bytes->[41], 0, ($bytes->[40] >> 4) & 7));
printl "Minimum Recovery Delay (tRFC)",
tns(ddr2_sdram_rtime($bytes->[42], $bytes->[40] & 1,
($bytes->[40] >> 1) & 7));
printl "Maximum DQS to DQ Skew (tDQSQ)", tns($bytes->[44]/100);
printl "Maximum Read Data Hold Skew (tQHS)", tns($bytes->[45]/100);
printl "PLL Relock Time", $bytes->[46] . " us" if ($bytes->[46]);
}
# Parameter: bytes 0-63

Loading…
Cancel
Save