Changeset 5551

Show
Ignore:
Timestamp:
12/11/08 11:44:43 (5 years ago)
Author:
khali
Message:

Add support for DDR3 SDRAM. Patch from Paul Goyette.

Location:
i2c-tools/trunk
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • i2c-tools/trunk/CHANGES

    r5543 r5551  
    44SVN 
    55  decode-dimms: Handle CRC of FB-DIMM and DDR3 SDRAM memory modules 
     6                Add support for DDR3 SDRAM 
    67  i2c-stub-from-dump: Use udev settle to speed up initialization 
    78 
  • i2c-tools/trunk/eeprom/decode-dimms

    r5548 r5551  
    428428} 
    429429 
     430sub tns3($) # print a time in ns, with 3 decimal digits 
     431{ 
     432        return sprintf("%.3f ns", $_[0]); 
     433} 
     434 
    430435# Parameter: EEPROM bytes 0-127 (using 3-62) 
    431436sub decode_sdr_sdram($) 
     
    10321037} 
    10331038 
     1039# Parameter: EEPROM bytes 0-127 (using 3-76) 
     1040sub decode_ddr3_sdram($) 
     1041{ 
     1042        my $bytes = shift; 
     1043        my $l; 
     1044        my $temp; 
     1045        my $ctime; 
     1046 
     1047        my @module_types = ("Undefined", "RDIMM", "UDIMM", "SO-DIMM", 
     1048                            "Micro-DIMM", "Mini-RDIMM", "Mini-UDIMM"); 
     1049 
     1050        printl "Module Type", ($bytes->[3] <= $#module_types) ? 
     1051                                        $module_types[$bytes->[3]] : 
     1052                                        sprint("Reserved (0x%.2X)", $bytes->[3]); 
     1053 
     1054# speed 
     1055        prints "Memory Characteristics"; 
     1056 
     1057        $l = "Fine time base"; 
     1058        my $dividend = ($bytes->[9] >> 4) & 15; 
     1059        my $divisor  = $bytes->[9] & 15; 
     1060        printl $l, sprintf("%.3f", $dividend / $divisor) . " ps"; 
     1061 
     1062        $l = "Medium time base"; 
     1063        $dividend = $bytes->[10]; 
     1064        $divisor  = $bytes->[11]; 
     1065        my $mtb = $dividend / $divisor; 
     1066        printl $l, tns3($mtb); 
     1067 
     1068        $l = "Maximum module speed"; 
     1069        $ctime = $bytes->[12] * $mtb; 
     1070        my $ddrclk = 2 * (1000 / $ctime); 
     1071        my $tbits = 1 << (($bytes->[8] & 7) + 3); 
     1072        my $pcclk = int ($ddrclk * $tbits / 8); 
     1073        $ddrclk = int ($ddrclk); 
     1074        printl $l, "${ddrclk}MHz (PC3-${pcclk})"; 
     1075 
     1076# Size computation 
     1077 
     1078        my $cap =  ($bytes->[4]       & 15) + 28; 
     1079        $cap   +=  ($bytes->[8]       & 7)  + 3; 
     1080        $cap   -=  ($bytes->[7]       & 7)  + 2; 
     1081        $cap   -= 20 + 3; 
     1082        my $k   = (($bytes->[7] >> 3) & 31) + 1; 
     1083        printl "Size", ((1 << $cap) * $k) . " MB"; 
     1084 
     1085        printl "Banks x Rows x Columns x Bits", 
     1086               join(' x ', 1 << ((($bytes->[4] >> 4) &  7) +  3), 
     1087                           ((($bytes->[5] >> 3) & 31) + 12), 
     1088                           ( ($bytes->[5]       &  7) +  9), 
     1089                           ( 1 << (($bytes->[8] &  7) + 3)) ); 
     1090        printl "Ranks", $k; 
     1091 
     1092        printl "SDRAM Device Width", (1 << (($bytes->[7] & 7) + 2))." bits"; 
     1093 
     1094        my $taa; 
     1095        my $trcd; 
     1096        my $trp; 
     1097        my $tras; 
     1098 
     1099        $taa  = int($bytes->[16] / $bytes->[12]); 
     1100        $trcd = int($bytes->[18] / $bytes->[12]); 
     1101        $trp  = int($bytes->[20] / $bytes->[12]); 
     1102        $tras = int((($bytes->[21] >> 4) * 256 + $bytes->[22]) / $bytes->[12]); 
     1103 
     1104        printl "tCL-tRCD-tRP-tRAS", join("-", $taa, $trcd, $trp, $tras); 
     1105 
     1106# latencies 
     1107        my $highestCAS = 0; 
     1108        my %cas; 
     1109        my $ii; 
     1110        my $cas_sup = ($bytes->[15] << 8) + $bytes->[14]; 
     1111        for ($ii = 0; $ii < 15; $ii++) { 
     1112                if ($cas_sup & (1 << $ii)) { 
     1113                        $highestCAS = $ii + 4; 
     1114                        $cas{$highestCAS}++; 
     1115                } 
     1116        } 
     1117        printl "Supported CAS Latencies (tCL)", cas_latencies(keys %cas); 
     1118 
     1119# more timing information 
     1120        prints "Timing Parameters" ; 
     1121 
     1122        printl "Minimum Write Recovery time (tWR)", tns3($bytes->[17] * $mtb); 
     1123        printl "Minimum Row Active to Row Active Delay (tRRD)", 
     1124                tns3($bytes->[19] * $mtb); 
     1125        printl "Minimum Active to Auto-Refresh Delay (tRC)", 
     1126                tns3((((($bytes->[21] >> 4) & 15) << 8) + $bytes->[23]) * $mtb); 
     1127        printl "Minimum Recovery Delay (tRFC)",  
     1128                tns3((($bytes->[25] << 8) + $bytes->[24]) * $mtb); 
     1129        printl "Minimum Write to Read CMD Delay (tWTR)", 
     1130                tns3($bytes->[26] * $mtb); 
     1131        printl "Minimum Read to Pre-charge CMD Delay (tRTP)", 
     1132                tns3($bytes->[27] * $mtb); 
     1133        printl "Minimum Four Activate Window Delay (tFAW)", 
     1134                tns3(((($bytes->[28] & 15) << 8) + $bytes->[29]) * $mtb); 
     1135 
     1136# miscellaneous stuff 
     1137        prints "Optional Features"; 
     1138 
     1139        my $volts = "1.5V"; 
     1140        if ($bytes->[6] & 1) { 
     1141                $volts .= " tolerant"; 
     1142        } 
     1143        if ($bytes->[6] & 2) { 
     1144                $volts .= ", 1.35V "; 
     1145        } 
     1146        if ($bytes->[6] & 4) { 
     1147                $volts .= ", 1.2X V"; 
     1148        } 
     1149        printl "Operable voltages", $volts; 
     1150        printl "RZQ/6 supported?", ($bytes->[30] & 1) ? "Yes" : "No"; 
     1151        printl "RZQ/7 supported?", ($bytes->[30] & 2) ? "Yes" : "No"; 
     1152        printl "DLL-Off Mode supported?", ($bytes->[30] & 128) ? "Yes" : "No"; 
     1153        printl "Operating temperature range", sprintf "0-%dC", 
     1154                ($bytes->[31] & 1) ? 95 : 85; 
     1155        printl "Refresh Rate in extended temp range", 
     1156                ($bytes->[31] & 2) ? "2X" : "1X"; 
     1157        printl "Auto Self-Refresh?", ($bytes->[31] & 4) ? "Yes" : "No"; 
     1158        printl "On-Die Thermal Sensor readout?", 
     1159                ($bytes->[31] & 8) ? "Yes" : "No"; 
     1160        printl "Partial Array Self-Refresh?", 
     1161                ($bytes->[31] & 128) ? "Yes" : "No"; 
     1162        printl "Thermal Sensor Accuracy", 
     1163                ($bytes->[32] & 128) ? sprintf($bytes->[32] & 127) : 
     1164                                        "Not implemented"; 
     1165        printl "SDRAM Device Type", 
     1166                ($bytes->[33] & 128) ? sprintf($bytes->[33] & 127) : 
     1167                                        "Standard Monolithic"; 
     1168        if ($bytes->[3] >= 1 && $bytes->[3] <= 6) { 
     1169 
     1170                prints "Physical Characteristics"; 
     1171                printl "Module Height (mm)", ($bytes->[60] & 31) + 15; 
     1172                printl "Module Thickness (mm)", sprintf("%d front, %d back", 
     1173                                                ($bytes->[61] & 15) + 1,  
     1174                                                (($bytes->[61] >> 4) & 15) +1); 
     1175                printl "Module Width (mm)", ($bytes->[3] <= 2) ? 133.5 : 
     1176                                        ($bytes->[3] == 3) ? 67.6 : "TBD"; 
     1177 
     1178                my $alphabet = "ABCDEFGHJKLMNPRTUVWY"; 
     1179                my $ref = $bytes->[62] & 31; 
     1180                my $ref_card; 
     1181                if ($ref == 31) { 
     1182                        $ref_card = "ZZ"; 
     1183                } else { 
     1184                        if ($bytes->[62] & 128) { 
     1185                                $ref += 31; 
     1186                        } 
     1187                        if ($ref < length $alphabet) { 
     1188                                $ref_card = substr $alphabet, $ref, 1; 
     1189                        } else { 
     1190                                my $ref1 = int($ref / (length $alphabet)); 
     1191                                $ref -= (length $alphabet) * $ref1; 
     1192                                $ref_card = (substr $alphabet, $ref1, 1) . 
     1193                                            (substr $alphabet, $ref, 1); 
     1194                        } 
     1195                } 
     1196                printl "Module Reference Card", $ref_card; 
     1197        } 
     1198        if ($bytes->[3] == 1 || $bytes->[3] == 5) { 
     1199                prints "Registered DIMM"; 
     1200 
     1201                my @rows = ("Undefined", 1, 2, 4); 
     1202                printl "# DRAM Rows", $rows[($bytes->[63] >> 2) & 3]; 
     1203                printl "# Registers", $rows[$bytes->[63] & 3]; 
     1204                printl "Register manufacturer", 
     1205                        manufacturer_ddr3($bytes->[65], $bytes->[66]); 
     1206                printl "Register device type", 
     1207                                (($bytes->[68] & 7) == 0) ? "SSTE32882" : 
     1208                                        "Undefined"; 
     1209                printl "Register revision", sprintf("0x%.2X", $bytes->[67]); 
     1210                printl "Heat spreader characteristics", 
     1211                                ($bytes->[64] < 128) ? "Not incorporated" : 
     1212                                        sprintf("%.2X", ($bytes->[64] & 127)); 
     1213                my $regs; 
     1214                for (my $i = 0; $i < 8; $i++) { 
     1215                        $regs = sprintf("SSTE32882 RC%d/RC%d", 
     1216                                        $i * 2, $i * 2 + 1); 
     1217                        printl $regs, sprintf("%.2X", $bytes->[$i + 69]); 
     1218                } 
     1219        } 
     1220} 
     1221 
    10341222# Parameter: EEPROM bytes 0-127 (using 4-5) 
    10351223sub decode_direct_rambus($) 
     
    10761264        "DDR SDRAM"     => \&decode_ddr_sdram, 
    10771265        "DDR2 SDRAM"    => \&decode_ddr2_sdram, 
     1266        "DDR3 SDRAM"    => \&decode_ddr3_sdram, 
    10781267        "Direct Rambus" => \&decode_direct_rambus, 
    10791268        "Rambus"        => \&decode_rambus, 
     
    10951284                return sprintf("0x%02X%02X\n", $year, $week); 
    10961285        } 
     1286} 
     1287 
     1288# Parameter: EEPROM bytes 0-175 (using 117-149) 
     1289sub decode_ddr3_mfg_data($) 
     1290{ 
     1291        my $bytes = shift; 
     1292 
     1293        prints "Manufacturer Data"; 
     1294 
     1295        printl "Module Manufacturer", 
     1296                manufacturer_ddr3($bytes->[117], $bytes->[118]); 
     1297 
     1298        printl "DRAM Manufacturer", 
     1299                manufacturer_ddr3($bytes->[148], $bytes->[149]); 
     1300 
     1301        my $l = "Manufacturing Location"; 
     1302        my $temp = (chr($bytes->[119]) =~ m/^[\w\d]$/) ? chr($bytes->[119]) 
     1303              : sprintf("0x%.2X", $bytes->[119]); 
     1304        printl $l, $temp; 
     1305 
     1306        $l = "Manufacturing Date"; 
     1307        printl $l, manufacture_date($bytes->[120], $bytes->[121]); 
     1308 
     1309        $l = "Assembly Serial Number"; 
     1310        $temp = sprintf("0x%02X%02X%02X%02X\n", $bytes->[122], $bytes->[123], 
     1311                $bytes->[124], $bytes->[125]); 
     1312        printl $l, $temp; 
     1313 
     1314        $l = "Part Number"; 
     1315        $temp = ""; 
     1316        for (my $i = 128; $i <= 145; $i++) { 
     1317                $temp .= chr($bytes->[$i]); 
     1318        }; 
     1319        printl $l, $temp; 
     1320 
     1321        $l = "Revision"; 
     1322        $temp = sprintf("0x%02X%02X\n", $bytes->[146], $bytes->[147]); 
     1323        printl $l, $temp; 
    10971324} 
    10981325 
     
    15091736                        if exists $decode_callback{$type}; 
    15101737 
    1511 # Decode next 35 bytes (64-98, common to all memory types) 
    1512                 decode_manufacturing_information(\@bytes); 
     1738                if ($type eq "DDR3 SDRAM") { 
     1739                        # Decode DDR3-specific manufacturing data in bytes  
     1740                        # 117-149 
     1741                        decode_ddr3_mfg_data(\@bytes) 
     1742                } else { 
     1743                        # Decode next 35 bytes (64-98, common to most 
     1744                        # memory types) 
     1745                        decode_manufacturing_information(\@bytes); 
     1746                } 
    15131747 
    15141748# Next 27 bytes (99-125) are manufacturer specific, can't decode