root/lm-sensors/trunk/prog/eeprom/decode-dimms.pl @ 5537

Revision 5537, 45.5 KB (checked in by khali, 5 years ago)

Spelling fixes.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/perl -w
2#
3# Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
4# modified by Christian Zuckschwerdt <zany@triq.net>
5# modified by Burkart Lingner <burkart@bollchen.de>
6#
7#    This program is free software; you can redistribute it and/or modify
8#    it under the terms of the GNU General Public License as published by
9#    the Free Software Foundation; either version 2 of the License, or
10#    (at your option) any later version.
11#
12#    This program is distributed in the hope that it will be useful,
13#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#    GNU General Public License for more details.
16#
17#    You should have received a copy of the GNU General Public License
18#    along with this program; if not, write to the Free Software
19#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20#
21# Version 0.4  1999  Philip Edelbrock <phil@netroedge.com>
22# Version 0.5  2000-03-30  Christian Zuckschwerdt <zany@triq.net>
23#  html output (selectable by commandline switches)
24# Version 0.6  2000-09-16  Christian Zuckschwerdt <zany@triq.net>
25#  updated according to SPD Spec Rev 1.2B
26#  see http://developer.intel.com/technology/memory/pc133sdram/spec/Spdsd12b.htm
27# Version 0.7  2002-11-08  Jean Delvare <khali@linux-fr.org>
28#  pass -w and use strict
29#  valid HTML 3.2 output (--format mode)
30#  miscellaneous formatting enhancements and bug fixes
31#  clearer HTML output (original patch by Nick Kurshev <nickols_k@mail.ru>)
32#  stop decoding on checksum error by default (--checksum option forces)
33# Version 0.8  2005-06-20  Burkart Lingner <burkart@bollchen.de>
34#  adapted to Kernel 2.6's /sys filesystem
35# Version 0.9  2005-07-15  Jean Delvare <khali@linux-fr.org>
36#  fix perl warning
37#  fix typo
38#  refactor some code
39# Version 1.0  2005-09-18  Jean Delvare <khali@linux-fr.org>
40#  add large lookup tables for manufacturer names, based on data
41#  provided by Rudolf Marek, taken from:
42#  http://www.jedec.org/download/search/JEP106r.pdf
43# Version 1.1  2006-01-22  Jean Delvare <khali@linux-fr.org>
44#  improve the text output, making it hopefully clearer
45#  read eeprom by 64-byte blocks, this allows some code cleanups
46#  use sysopen/sysread instead of open/read for better performance
47#  verify checksum before decoding anything
48# Version 1.2  2006-05-15  Jean Delvare <khali@linux-fr.org>
49#  implement per-memory-type decoding
50#  don't decode revision code, manufacturing date and assembly serial
51#  number where not set
52#  decode the manufacturing date to an ISO8601 date
53# Version 1.3  2006-05-21  Jean Delvare <khali@linux-fr.org>
54#  detect undefined manufacturer code and handle it properly
55#  round up timing data
56#  minor display adjustments
57#  group cycle and access times, display the CAS value for each (SDRAM)
58#  refactor some bitfield tests into loops (SDRAM)
59#  display latencies and burst length on a single line (SDRAM)
60#  don't display manufacturing location when undefined
61#  check that the manufacturing date is proper BCD, else fall back to
62#  hexadecimal display
63# Version 1.4  2006-05-26  Jean Delvare <khali@linux-fr.org>
64#  fix latencies decoding (SDRAM)
65#  fix CAS latency decoding (DDR SDRAM)
66#  decode latencies, timings and module height (DDR SDRAM)
67#  decode size (Direct Rambus, Rambus)
68#  decode latencies and timings (DDR2 SDRAM)
69#  SPD revision decoding depends on memory type
70#  use more user-friendly labels
71#  fix HTML formatted output on checksum error
72# Version 1.5  2007-11-08  Jean Delvare <khali@linux-fr.org>
73#  fix module speed (DDR2 SDRAM)
74#
75#
76# EEPROM data decoding for SDRAM DIMM modules.
77#
78# The eeprom driver must be loaded. For kernels older than 2.6.0, the
79# eeprom driver can be found in the lm-sensors package.
80#
81# use the following command line switches
82#  -f, --format            print nice html output
83#  -b, --bodyonly          don't print html header
84#                          (useful for postprocessing the output)
85#  -c, --checksum          decode completely even if checksum fails
86#  -h, --help              display this usage summary
87#
88# References:
89# PC SDRAM Serial Presence
90# Detect (SPD) Specification, Intel,
91# 1997,1999, Rev 1.2B
92#
93# Jedec Standards 4.1.x & 4.5.x
94# http://www.jedec.org
95#
96
97require 5.004;
98
99use strict;
100use POSIX qw(ceil);
101use Fcntl qw(:DEFAULT :seek);
102use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
103            @vendors %decode_callback);
104
105@vendors = (
106["AMD", "AMI", "Fairchild", "Fujitsu",
107 "GTE", "Harris", "Hitachi", "Inmos",
108 "Intel", "I.T.T.", "Intersil", "Monolithic Memories",
109 "Mostek", "Freescale (former Motorola)", "National", "NEC",
110 "RCA", "Raytheon", "Conexant (Rockwell)", "Seeq",
111 "NXP (former Signetics, Philips Semi.)", "Synertek", "Texas Instruments", "Toshiba",
112 "Xicor", "Zilog", "Eurotechnique", "Mitsubishi",
113 "Lucent (AT&T)", "Exel", "Atmel", "SGS/Thomson",
114 "Lattice Semi.", "NCR", "Wafer Scale Integration", "IBM",
115 "Tristar", "Visic", "Intl. CMOS Technology", "SSSI",
116 "MicrochipTechnology", "Ricoh Ltd.", "VLSI", "Micron Technology",
117 "Hyundai Electronics", "OKI Semiconductor", "ACTEL", "Sharp",
118 "Catalyst", "Panasonic", "IDT", "Cypress",
119 "DEC", "LSI Logic", "Zarlink (former Plessey)", "UTMC",
120 "Thinking Machine", "Thomson CSF", "Integrated CMOS (Vertex)", "Honeywell",
121 "Tektronix", "Sun Microsystems", "SST", "ProMos/Mosel Vitelic",
122 "Infineon (former Siemens)", "Macronix", "Xerox", "Plus Logic",
123 "SunDisk", "Elan Circuit Tech.", "European Silicon Str.", "Apple Computer",
124 "Xilinx", "Compaq", "Protocol Engines", "SCI",
125 "Seiko Instruments", "Samsung", "I3 Design System", "Klic",
126 "Crosspoint Solutions", "Alliance Semiconductor", "Tandem", "Hewlett-Packard",
127 "Intg. Silicon Solutions", "Brooktree", "New Media", "MHS Electronic",
128 "Performance Semi.", "Winbond Electronic", "Kawasaki Steel", "Bright Micro",
129 "TECMAR", "Exar", "PCMCIA", "LG Semi (former Goldstar)",
130 "Northern Telecom", "Sanyo", "Array Microsystems", "Crystal Semiconductor",
131 "Analog Devices", "PMC-Sierra", "Asparix", "Convex Computer",
132 "Quality Semiconductor", "Nimbus Technology", "Transwitch", "Micronas (ITT Intermetall)",
133 "Cannon", "Altera", "NEXCOM", "QUALCOMM",
134 "Sony", "Cray Research", "AMS(Austria Micro)", "Vitesse",
135 "Aster Electronics", "Bay Networks (Synoptic)", "Zentrum or ZMD", "TRW",
136 "Thesys", "Solbourne Computer", "Allied-Signal", "Dialog",
137 "Media Vision", "Level One Communication"],
138["Cirrus Logic", "National Instruments", "ILC Data Device", "Alcatel Mietec",
139 "Micro Linear", "Univ. of NC", "JTAG Technologies", "BAE Systems",
140 "Nchip", "Galileo Tech", "Bestlink Systems", "Graychip",
141 "GENNUM", "VideoLogic", "Robert Bosch", "Chip Express",
142 "DATARAM", "United Microelec Corp.", "TCSI", "Smart Modular",
143 "Hughes Aircraft", "Lanstar Semiconductor", "Qlogic", "Kingston",
144 "Music Semi", "Ericsson Components", "SpaSE", "Eon Silicon Devices",
145 "Programmable Micro Corp", "DoD", "Integ. Memories Tech.", "Corollary Inc.",
146 "Dallas Semiconductor", "Omnivision", "EIV(Switzerland)", "Novatel Wireless",
147 "Zarlink (former Mitel)", "Clearpoint", "Cabletron", "STEC (former Silicon Technology)",
148 "Vanguard", "Hagiwara Sys-Com", "Vantis", "Celestica",
149 "Century", "Hal Computers", "Rohm Company Ltd.", "Juniper Networks",
150 "Libit Signal Processing", "Mushkin Enhanced Memory", "Tundra Semiconductor", "Adaptec Inc.",
151 "LightSpeed Semi.", "ZSP Corp.", "AMIC Technology", "Adobe Systems",
152 "Dynachip", "PNY Electronics", "Newport Digital", "MMC Networks",
153 "T Square", "Seiko Epson", "Broadcom", "Viking Components",
154 "V3 Semiconductor", "Flextronics (former Orbit)", "Suwa Electronics", "Transmeta",
155 "Micron CMS", "American Computer & Digital Components Inc", "Enhance 3000 Inc", "Tower Semiconductor",
156 "CPU Design", "Price Point", "Maxim Integrated Product", "Tellabs",
157 "Centaur Technology", "Unigen Corporation", "Transcend Information", "Memory Card Technology",
158 "CKD Corporation Ltd.", "Capital Instruments, Inc.", "Aica Kogyo, Ltd.", "Linvex Technology",
159 "MSC Vertriebs GmbH", "AKM Company, Ltd.", "Dynamem, Inc.", "NERA ASA",
160 "GSI Technology", "Dane-Elec (C Memory)", "Acorn Computers", "Lara Technology",
161 "Oak Technology, Inc.", "Itec Memory", "Tanisys Technology", "Truevision",
162 "Wintec Industries", "Super PC Memory", "MGV Memory", "Galvantech",
163 "Gadzoox Nteworks", "Multi Dimensional Cons.", "GateField", "Integrated Memory System",
164 "Triscend", "XaQti", "Goldenram", "Clear Logic",
165 "Cimaron Communications", "Nippon Steel Semi. Corp.", "Advantage Memory", "AMCC",
166 "LeCroy", "Yamaha Corporation", "Digital Microwave", "NetLogic Microsystems",
167 "MIMOS Semiconductor", "Advanced Fibre", "BF Goodrich Data.", "Epigram",
168 "Acbel Polytech Inc.", "Apacer Technology", "Admor Memory", "FOXCONN",
169 "Quadratics Superconductor", "3COM"],
170["Camintonn Corporation", "ISOA Incorporated", "Agate Semiconductor", "ADMtek Incorporated",
171 "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", "Ardent Technologies",
172 "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", "WorkX AG",
173 "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions", "Power General",
174 "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity", "Delkin Devices",
175 "Symagery Microsystems", "C-Port Corporation", "SiberCore Technologies", "Southland Microsystems",
176 "Malleable Technologies", "Kendin Communications", "Great Technology Microcomputer", "Sanmina Corporation",
177 "HADCO Corporation", "Corsair", "Actrans System Inc.", "ALPHA Technologies",
178 "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies", "Align Manufacturing", "Peregrine Semiconductor",
179 "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies", "Chrysalis ITS",
180 "ADTEC Corporation", "Kentron Technologies", "Win Technologies", "Tachyon Semiconductor (former ASIC Designs Inc.)",
181 "Extreme Packet Devices", "RF Micro Devices", "Siemens AG", "Sarnoff Corporation",
182 "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)", "Legend",
183 "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated", "SwitchOn Networks",
184 "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology", "Virata Corporation",
185 "Excess Bandwidth", "West Bay Semiconductor", "DSP Group", "Newport Communications",
186 "Chip2Chip Incorporated", "Phobos Corporation", "Intellitech Corporation", "Nordic VLSI ASA",
187 "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor", "Agilent Technologies",
188 "Centillium Communications", "W.L. Gore", "HanBit Electronics", "GlobeSpan",
189 "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated",
190 "MetaLink Technologies", "Feiya Technology", "I & C Technology", "Shikatronics",
191 "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions",
192 "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)", "3ParData",
193 "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys",
194 "Skyup Technology", "HiNT Corporation", "Chiaro", "MDT Technologies GmbH (former MCI Computer GMBH)",
195 "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory", "Legerity",
196 "Jasmine Networks", "Caspian Networks", "nCUBE", "Silicon Access Networks",
197 "FDK Corporation", "High Bandwidth Access", "MultiLink Technology", "BRECIS",
198 "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic",
199 "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power",
200 "eSilicon", "Morphics Technology", "Accelerant Networks", "Silicon Wave",
201 "SandCraft", "Elpida"],
202["Solectron", "Optosys Technologies", "Buffalo (former Melco)", "TriMedia Technologies",
203 "Cyan Technologies", "Global Locate", "Optillion", "Terago Communications",
204 "Ikanos Communications", "Princeton Technology", "Nanya Technology", "Elite Flash Storage",
205 "Mysticom", "LightSand Communications", "ATI Technologies", "Agere Systems",
206 "NeoMagic", "AuroraNetics", "Golden Empire", "Mushkin",
207 "Tioga Technologies", "Netlist", "TeraLogic", "Cicada Semiconductor",
208 "Centon Electronics", "Tyco Electronics", "Magis Works", "Zettacom",
209 "Cogency Semiconductor", "Chipcon AS", "Aspex Technology", "F5 Networks",
210 "Programmable Silicon Solutions", "ChipWrights", "Acorn Networks", "Quicklogic",
211 "Kingmax Semiconductor", "BOPS", "Flasys", "BitBlitz Communications",
212 "eMemory Technology", "Procket Networks", "Purple Ray", "Trebia Networks",
213 "Delta Electronics", "Onex Communications", "Ample Communications", "Memory Experts Intl",
214 "Astute Networks", "Azanda Network Devices", "Dibcom", "Tekmos",
215 "API NetWorks", "Bay Microsystems", "Firecron Ltd", "Resonext Communications",
216 "Tachys Technologies", "Equator Technology", "Concept Computer", "SILCOM",
217 "3Dlabs", "c't Magazine", "Sanera Systems", "Silicon Packets",
218 "Viasystems Group", "Simtek", "Semicon Devices Singapore", "Satron Handelsges",
219 "Improv Systems", "INDUSYS GmbH", "Corrent", "Infrant Technologies",
220 "Ritek Corp", "empowerTel Networks", "Hypertec", "Cavium Networks",
221 "PLX Technology", "Massana Design", "Intrinsity", "Valence Semiconductor",
222 "Terawave Communications", "IceFyre Semiconductor", "Primarion", "Picochip Designs Ltd",
223 "Silverback Systems", "Jade Star Technologies", "Pijnenburg Securealink",
224 "TakeMS International AG", "Cambridge Silicon Radio",
225 "Swissbit", "Nazomi Communications", "eWave System",
226 "Rockwell Collins", "Picocel Co., Ltd.", "Alphamosaic Ltd", "Sandburst",
227 "SiCon Video", "NanoAmp Solutions", "Ericsson Technology", "PrairieComm",
228 "Mitac International", "Layer N Networks", "MtekVision", "Allegro Networks",
229 "Marvell Semiconductors", "Netergy Microelectronic", "NVIDIA", "Internet Machines",
230 "Peak Electronics", "Litchfield Communication", "Accton Technology", "Teradiant Networks",
231 "Europe Technologies", "Cortina Systems", "RAM Components", "Raqia Networks",
232 "ClearSpeed", "Matsushita Battery", "Xelerated", "SimpleTech",
233 "Utron Technology", "Astec International", "AVM gmbH", "Redux Communications",
234 "Dot Hill Systems", "TeraChip"],
235["T-RAM Incorporated", "Innovics Wireless", "Teknovus", "KeyEye Communications",
236 "Runcom Technologies", "RedSwitch", "Dotcast", "Silicon Mountain Memory",
237 "Signia Technologies", "Pixim", "Galazar Networks", "White Electronic Designs",
238 "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology", "Europe Technologies",
239 "Potentia Power Systems", "C-guys Incorporated", "Digital Communications Technology Incorporated", "Silicon-Based Technology",
240 "Fulcrum Microsystems", "Positivo Informatica Ltd", "XIOtech Corporation", "PortalPlayer",
241 "Zhiying Software", "Direct2Data", "Phonex Broadband", "Skyworks Solutions",
242 "Entropic Communications", "Pacific Force Technology", "Zensys A/S", "Legend Silicon Corp.",
243 "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)", "Renesas Technology", "Raza Microelectronics",
244 "Phyworks", "MediaTek", "Non-cents Productions", "US Modular",
245 "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies",
246 "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ",
247 "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies",
248 "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology",
249 "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision",
250 "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom", "Bandspeed",
251 "LeWiz Communications", "CPU Technology", "Ramaxel Technology", "DSP Group",
252 "Axis Communications", "Legacy Electronics", "Chrontel", "Powerchip Semiconductor",
253 "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology", "VirtualDigm",
254 "G Skill Intl", "Quanta Computer", "Yield Microelectronics", "Afa Technologies",
255 "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks", "Advance Modules",
256 "Microsoft", "Open-Silicon", "Goal Semiconductor", "ARC International",
257 "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics",
258 "Adimos", "SiGe Semiconductor", "Fodus Communications", "Credence Systems Corp.",
259 "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies", "GateChange Technologies",
260 "High Density Devices AS", "Synopsys", "Gigaram", "Enigma Semiconductor Inc.",
261 "Century Micro Inc.", "Icera Semiconductor", "Mediaworks Integrated Systems", "O'Neil Product Development",
262 "Supreme Top Technology Ltd.", "MicroDisplay Corporation", "Team Group Inc.", "Sinett Corporation",
263 "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.",
264 "SMaL Camera Technologies", "Thomson SC", "Airgo Networks", "Wisair Ltd.",
265 "SigmaTel", "Arkados", "Compete IT gmbH Co. KG", "Eudar Technology Inc.",
266 "Focus Enhancements", "Xyratex"],
267["Specular Networks", "Patriot Memory", "U-Chip Technology Corp.", "Silicon Optix",
268 "Greenfield Networks", "CompuRAM GmbH", "Stargen, Inc.", "NetCell Corporation",
269 "Excalibrus Technologies Ltd", "SCM Microsystems", "Xsigo Systems, Inc.", "CHIPS & Systems Inc",
270 "Tier 1 Multichip Solutions", "CWRL Labs", "Teradici", "Gigaram, Inc.",
271 "g2 Microsystems", "PowerFlash Semiconductor", "P.A. Semi, Inc.", "NovaTech Solutions, S.A.",
272 "c2 Microsystems, Inc.", "Level5 Networks", "COS Memory AG", "Innovasic Semiconductor",
273 "02IC Co. Ltd", "Tabula, Inc.", "Crucial Technology", "Chelsio Communications",
274 "Solarflare Communications", "Xambala Inc.", "EADS Astrium", "ATO Semicon Co. Ltd.",
275 "Imaging Works, Inc.", "Astute Networks, Inc.", "Tzero", "Emulex",
276 "Power-One", "Pulse~LINK Inc.", "Hon Hai Precision Industry", "White Rock Networks Inc.",
277 "Telegent Systems USA, Inc.", "Atrua Technologies, Inc.", "Acbel Polytech Inc.",
278 "eRide Inc.","ULi Electronics Inc.", "Magnum Semiconductor Inc.", "neoOne Technology, Inc.",
279 "Connex Technology, Inc.", "Stream Processors, Inc.", "Focus Enhancements", "Telecis Wireless, Inc.",
280 "uNav Microelectronics", "Tarari, Inc.", "Ambric, Inc.", "Newport Media, Inc.", "VMTS",
281 "Enuclia Semiconductor, Inc.", "Virtium Technology Inc.", "Solid State System Co., Ltd.", "Kian Tech LLC",
282 "Artimi", "Power Quotient International", "Avago Technologies", "ADTechnology", "Sigma Designs",
283 "SiCortex, Inc.", "Ventura Technology Group", "eASIC", "M.H.S. SAS", "Micro Star International", 
284 "Rapport Inc.", "Makway International", "Broad Reach Engineering Co.", 
285 "Semiconductor Mfg Intl Corp", "SiConnect", "FCI USA Inc.", "Validity Sensors", 
286 "Coney Technology Co. Ltd.", "Spans Logic", "Neterion Inc.", "Qimonda",
287 "New Japan Radio Co. Ltd.", "Velogix", "Montalvo Systems", "iVivity Inc.", "Walton Chaintech",
288 "AENEON", "Lorom Industrial Co. Ltd.", "Radiospire Networks", "Sensio Technologies, Inc.",
289 "Nethra Imaging", "Hexon Technology Pte Ltd", "CompuStocx (CSX)", "Methode Electronics, Inc.",
290 "Connect One Ltd.", "Opulan Technologies", "Septentrio NV", "Goldenmars Technology Inc.",
291 "Kreton Corporation", "Cochlear Ltd.", "Altair Semiconductor", "NetEffect, Inc.",
292 "Spansion, Inc.", "Taiwan Semiconductor Mfg", "Emphany Systems Inc.",
293 "ApaceWave Technologies", "Mobilygen Corporation", "Tego", "Cswitch Corporation",
294 "Haier (Beijing) IC Design Co.", "MetaRAM", "Axel Electronics Co. Ltd.", "Tilera Corporation",
295 "Aquantia", "Vivace Semiconductor", "Redpine Signals", "Octalica", "InterDigital Communications",
296 "Avant Technology", "Asrock, Inc.", "Availink", "Quartics, Inc.", "Element CXI",
297 "Innovaciones Microelectronicas", "VeriSilicon Microelectronics", "W5 Networks"],
298["MOVEKING", "Mavrix Technology, Inc.", "CellGuide Ltd.", "Faraday Technology",
299 "Diablo Technologies, Inc.", "Jennic", "Octasic", "Molex Incorporated", "3Leaf Networks",
300 "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.", "DisplayLink", "ZMOS Technology",
301 "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.", "BRN Phoenix",
302 "InSilica", "Ember Corporation", "Avexir Technologies Corporation", "Echelon Corporation",
303 "Edgewater Computer Systems", "XMOS Semiconductor Ltd.", "GENUSION, Inc.", "Memory Corp NV",
304 "SiliconBlue Technologies", "Rambus Inc."]);
305
306$use_sysfs = -d '/sys/bus';
307
308# We consider that no data was written to this area of the SPD EEPROM if
309# all bytes read 0x00 or all bytes read 0xff
310sub spd_written(@)
311{
312        my $all_00 = 1;
313        my $all_ff = 1;
314       
315        foreach my $b (@_) {
316                $all_00 = 0 unless $b == 0x00;
317                $all_ff = 0 unless $b == 0xff;
318                return 1 unless $all_00 or $all_ff;
319        }
320
321        return 0;
322}
323
324sub parity($)
325{
326        my $n = shift;
327        my $parity = 0;
328
329        while ($n) {
330                $parity++ if ($n & 1);
331                $n >>= 1;
332        }
333
334        return ($parity & 1);
335}
336
337sub manufacturer(@)
338{
339        my @bytes = @_;
340        my $ai = 0;
341        my $first;
342
343        return ("Undefined", []) unless spd_written(@bytes);
344       
345        while (defined($first = shift(@bytes)) && $first == 0x7F) {
346                $ai++;
347        }
348
349        return ("Invalid", []) unless defined $first;
350        return ("Invalid", [$first, @bytes]) if parity($first) != 1;
351        return ("Unknown", \@bytes) unless (($first & 0x7F) - 1 <= $vendors[$ai]);
352
353        return ($vendors[$ai][($first & 0x7F) - 1], \@bytes);
354}
355
356sub manufacturer_data(@)
357{
358        my $hex = "";
359        my $asc = "";
360
361        return unless spd_written(@_);
362
363        foreach my $byte (@_) {
364                $hex .= sprintf("\%02X ", $byte);
365                $asc .= ($byte >= 32 && $byte < 127) ? chr($byte) : '?';
366        }
367
368        return "$hex(\"$asc\")";
369}
370
371sub part_number(@)
372{
373        my $asc = "";
374        my $byte;
375
376        while (defined ($byte = shift) && $byte >= 32 && $byte < 127) {
377                $asc .= chr($byte);
378        }
379
380        return ($asc eq "") ? "Undefined" : $asc;
381}
382
383sub printl ($$) # print a line w/ label and value
384{
385        my ($label, $value) = @_;
386        if ($opt_html) {
387                $label =~ s/</\&lt;/sg;
388                $label =~ s/>/\&gt;/sg;
389                $label =~ s/\n/<br>\n/sg;
390                $value =~ s/</\&lt;/sg;
391                $value =~ s/>/\&gt;/sg;
392                $value =~ s/\n/<br>\n/sg;
393                print "<tr><td valign=top>$label</td><td>$value</td></tr>\n";
394        } else {
395                my @values = split /\n/, $value;
396                printf "%-47s %s\n", $label, shift @values;
397                printf "%-47s %s\n", "", $_ foreach (@values);
398        }
399}
400
401sub printl2 ($$) # print a line w/ label and value (outside a table)
402{
403        my ($label, $value) = @_;
404        if ($opt_html) {
405                $label =~ s/</\&lt;/sg;
406                $label =~ s/>/\&gt;/sg;
407                $label =~ s/\n/<br>\n/sg;
408                $value =~ s/</\&lt;/sg;
409                $value =~ s/>/\&gt;/sg;
410                $value =~ s/\n/<br>\n/sg;
411        }
412        print "$label: $value\n";
413}
414
415sub prints ($) # print separator w/ given text
416{
417        my ($label) = @_;
418        if ($opt_html) {
419                $label =~ s/</\&lt;/sg;
420                $label =~ s/>/\&gt;/sg;
421                $label =~ s/\n/<br>\n/sg;
422                print "<tr><td align=center colspan=2><b>$label</b></td></tr>\n";
423        } else {
424                print "\n---=== $label ===---\n";
425        }
426}
427
428sub printh ($$) # print header w/ given text
429{
430        my ($header, $sub) = @_;
431        if ($opt_html) {
432                $header =~ s/</\&lt;/sg;
433                $header =~ s/>/\&gt;/sg;
434                $header =~ s/\n/<br>\n/sg;
435                $sub =~ s/</\&lt;/sg;
436                $sub =~ s/>/\&gt;/sg;
437                $sub =~ s/\n/<br>\n/sg;
438                print "<h1>$header</h1>\n";
439                print "<p>$sub</p>\n";
440        } else {
441                print "\n$header\n$sub\n";
442        }
443}
444
445# Parameter: bytes 0-63
446sub decode_sdr_sdram($)
447{
448        my $bytes = shift;
449        my ($l, $temp);
450
451# SPD revision
452        printl "SPD Revision", $bytes->[62];
453
454#size computation
455
456        prints "Memory Characteristics";
457
458        my $k=0;
459        my $ii=0;
460       
461        $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
462        if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) {
463                 $k = $bytes->[5] * $bytes->[17];
464        }
465       
466        if($ii > 0 && $ii <= 12 && $k > 0) {
467                printl "Size", ((1 << $ii) * $k) . " MB"; }
468        else { 
469                printl "INVALID SIZE", $bytes->[3] . "," . $bytes->[4] . "," .
470                                       $bytes->[5] . "," . $bytes->[17];
471        }
472
473        my @cas;
474        for ($ii = 0; $ii < 7; $ii++) {
475                push(@cas, $ii + 1) if ($bytes->[18] & (1 << $ii));
476        }
477
478        my $trcd;
479        my $trp;
480        my $tras;
481        my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
482
483        $trcd =$bytes->[29];
484        $trp =$bytes->[27];;
485        $tras =$bytes->[30];
486
487        printl "tCL-tRCD-tRP-tRAS",
488                $cas[$#cas] . "-" .
489                ceil($trcd/$ctime) . "-" .
490                ceil($trp/$ctime) . "-" .
491                ceil($tras/$ctime);
492
493        $l = "Number of Row Address Bits";
494        if ($bytes->[3] == 0) { printl $l, "Undefined!"; }
495        elsif ($bytes->[3] == 1) { printl $l, "1/16"; }
496        elsif ($bytes->[3] == 2) { printl $l, "2/17"; }
497        elsif ($bytes->[3] == 3) { printl $l, "3/18"; }
498        else { printl $l, $bytes->[3]; }
499
500        $l = "Number of Col Address Bits";
501        if ($bytes->[4] == 0) { printl $l, "Undefined!"; }
502        elsif ($bytes->[4] == 1) { printl $l, "1/16"; }
503        elsif ($bytes->[4] == 2) { printl $l, "2/17"; }
504        elsif ($bytes->[4] == 3) { printl $l, "3/18"; }
505        else { printl $l, $bytes->[4]; }
506
507        $l = "Number of Module Rows";
508        if ($bytes->[5] == 0 ) { printl $l, "Undefined!"; }
509        else { printl $l, $bytes->[5]; }
510
511        $l = "Data Width";
512        if ($bytes->[7] > 1) {
513                printl $l, "Undefined!"
514        } else {
515                $temp = ($bytes->[7] * 256) + $bytes->[6];
516                printl $l, $temp;
517        }
518
519        $l = "Module Interface Signal Levels";
520        if ($bytes->[8] == 0) { printl $l, "5.0 Volt/TTL"; }
521        elsif ($bytes->[8] == 1) { printl $l, "LVTTL"; }
522        elsif ($bytes->[8] == 2) { printl $l, "HSTL 1.5"; }
523        elsif ($bytes->[8] == 3) { printl $l, "SSTL 3.3"; }
524        elsif ($bytes->[8] == 4) { printl $l, "SSTL 2.5"; }
525        elsif ($bytes->[8] == 255) { printl $l, "New Table"; }
526        else { printl $l, "Undefined!"; }
527
528        $l = "Module Configuration Type";
529        if ($bytes->[11] == 0) { printl $l, "No Parity"; }
530        elsif ($bytes->[11] == 1) { printl $l, "Parity"; }
531        elsif ($bytes->[11] == 2) { printl $l, "ECC"; }
532        else { printl $l, "Undefined!"; }
533
534        $l = "Refresh Type";
535        if ($bytes->[12] > 126) { printl $l, "Self Refreshing"; }
536        else { printl $l, "Not Self Refreshing"; }
537
538        $l = "Refresh Rate";
539        $temp = $bytes->[12] & 0x7f;
540        if ($temp == 0) { printl $l, "Normal (15.625 us)"; }
541        elsif ($temp == 1) { printl $l, "Reduced (3.9 us)"; }
542        elsif ($temp == 2) { printl $l, "Reduced (7.8 us)"; }
543        elsif ($temp == 3) { printl $l, "Extended (31.3 us)"; }
544        elsif ($temp == 4) { printl $l, "Extended (62.5 us)"; }
545        elsif ($temp == 5) { printl $l, "Extended (125 us)"; }
546        else { printl $l, "Undefined!"; }
547
548        $l = "Primary SDRAM Component Bank Config";
549        if ($bytes->[13] > 126) { printl $l, "Bank2 = 2 x Bank1"; }
550        else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; }
551
552        $l = "Primary SDRAM Component Widths";
553        $temp = $bytes->[13] & 0x7f;
554        if ($temp == 0) { printl $l, "Undefined!\n"; }
555        else { printl $l, $temp; }
556
557        $l = "Error Checking SDRAM Component Bank Config";
558        if ($bytes->[14] > 126) { printl $l, "Bank2 = 2 x Bank1"; }
559        else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; }
560
561        $l = "Error Checking SDRAM Component Widths";
562        $temp = $bytes->[14] & 0x7f;
563        if ($temp == 0) { printl $l, "Undefined!"; }
564        else { printl $l, $temp; }
565
566        $l = "Min Clock Delay for Back to Back Random Access";
567        if ($bytes->[15] == 0) { printl $l, "Undefined!"; }
568        else { printl $l, $bytes->[15]; }
569
570        $l = "Burst lengths supported";
571        my @array;
572        for ($ii = 0; $ii < 4; $ii++) {
573                push(@array, 1 << $ii) if ($bytes->[16] & (1 << $ii));
574        }
575        push(@array, "Page") if ($bytes->[16] & 128);
576        if (@array) { $temp = join ', ', @array; }
577        else { $temp = "None"; }
578        printl $l, $temp;
579
580        $l = "Number of Device Banks";
581        if ($bytes->[17] == 0) { printl $l, "Undefined/Reserved!"; }
582        else { printl $l, $bytes->[17]; }
583
584        $l = "Supported CAS Latencies";
585        if (@cas) { $temp = join ', ', @cas; }
586        else { $temp = "None"; }
587        printl $l, $temp;
588
589        $l = "Supported CS Latencies";
590        @array = ();
591        for ($ii = 0; $ii < 7; $ii++) {
592                push(@array, $ii) if ($bytes->[19] & (1 << $ii));
593        }
594        if (@array) { $temp = join ', ', @array; }
595        else { $temp = "None"; }
596        printl $l, $temp;
597
598        $l = "Supported WE Latencies";
599        @array = ();
600        for ($ii = 0; $ii < 7; $ii++) {
601                push(@array, $ii) if ($bytes->[20] & (1 << $ii));
602        }
603        if (@array) { $temp = join ', ', @array; }
604        else { $temp = "None"; }
605        printl $l, $temp;
606
607        if (@cas >= 1) {
608                $l = "Cycle Time (CAS ".$cas[$#cas].")";
609                printl $l, "$ctime ns";
610
611                $l = "Access Time (CAS ".$cas[$#cas].")";
612                $temp = ($bytes->[10] >> 4) + ($bytes->[10] & 0xf) * 0.1;
613                printl $l, "$temp ns";
614        }
615
616        if (@cas >= 2 && spd_written(@$bytes[23..24])) {
617                $l = "Cycle Time (CAS ".$cas[$#cas-1].")";
618                $temp = $bytes->[23] >> 4;
619                if ($temp == 0) { printl $l, "Undefined!"; }
620                else {
621                        if ($temp < 4 ) { $temp=$temp + 15; }
622                        printl $l, $temp + (($bytes->[23] & 0xf) * 0.1) . " ns";
623                }
624
625                $l = "Access Time (CAS ".$cas[$#cas-1].")";
626                $temp = $bytes->[24] >> 4;
627                if ($temp == 0) { printl $l, "Undefined!"; }
628                else {
629                        if ($temp < 4 ) { $temp=$temp + 15; }
630                        printl $l, $temp + (($bytes->[24] & 0xf) * 0.1) . " ns";
631                }
632        }
633
634        if (@cas >= 3 && spd_written(@$bytes[25..26])) {
635                $l = "Cycle Time (CAS ".$cas[$#cas-2].")";
636                $temp = $bytes->[25] >> 2;
637                if ($temp == 0) { printl $l, "Undefined!"; }
638                else { printl $l, $temp + ($bytes->[25] & 0x3) * 0.25 . " ns"; }
639
640                $l = "Access Time (CAS ".$cas[$#cas-2].")";
641                $temp = $bytes->[26] >> 2;
642                if ($temp == 0) { printl $l, "Undefined!"; }
643                else { printl $l, $temp + ($bytes->[26] & 0x3) * 0.25 . " ns"; }
644        }
645
646        $l = "SDRAM Module Attributes";
647        $temp = "";
648        if ($bytes->[21] & 1) { $temp .= "Buffered Address/Control Inputs\n"; }
649        if ($bytes->[21] & 2) { $temp .= "Registered Address/Control Inputs\n"; }
650        if ($bytes->[21] & 4) { $temp .= "On card PLL (clock)\n"; }
651        if ($bytes->[21] & 8) { $temp .= "Buffered DQMB Inputs\n"; }
652        if ($bytes->[21] & 16) { $temp .= "Registered DQMB Inputs\n"; }
653        if ($bytes->[21] & 32) { $temp .= "Differential Clock Input\n"; }
654        if ($bytes->[21] & 64) { $temp .= "Redundant Row Address\n"; }
655        if ($bytes->[21] & 128) { $temp .= "Undefined (bit 7)\n"; }
656        if ($bytes->[21] == 0) { $temp .= "(None Reported)\n"; }
657        printl $l, $temp;
658
659        $l = "SDRAM Device Attributes (General)";
660        $temp = "";
661        if ($bytes->[22] & 1) { $temp .= "Supports Early RAS# Recharge\n"; }
662        if ($bytes->[22] & 2) { $temp .= "Supports Auto-Precharge\n"; }
663        if ($bytes->[22] & 4) { $temp .= "Supports Precharge All\n"; }
664        if ($bytes->[22] & 8) { $temp .= "Supports Write1/Read Burst\n"; }
665        if ($bytes->[22] & 16) { $temp .= "Lower VCC Tolerance: 5%\n"; }
666        else { $temp .= "Lower VCC Tolerance: 10%\n"; }
667        if ($bytes->[22] & 32) { $temp .= "Upper VCC Tolerance: 5%\n"; }
668        else { $temp .= "Upper VCC Tolerance: 10%\n"; }
669        if ($bytes->[22] & 64) { $temp .= "Undefined (bit 6)\n"; }
670        if ($bytes->[22] & 128) { $temp .= "Undefined (bit 7)\n"; }
671        printl $l, $temp;
672
673        $l = "Minimum Row Precharge Time";
674        if ($bytes->[27] == 0) { printl $l, "Undefined!"; }
675        else { printl $l, "$bytes->[27] ns"; }
676
677        $l = "Row Active to Row Active Min";
678        if ($bytes->[28] == 0) { printl $l, "Undefined!"; }
679        else { printl $l, "$bytes->[28] ns"; }
680
681        $l = "RAS to CAS Delay";
682        if ($bytes->[29] == 0) { printl $l, "Undefined!"; }
683        else { printl $l, "$bytes->[29] ns"; }
684
685        $l = "Min RAS Pulse Width";
686        if ($bytes->[30] == 0) { printl $l, "Undefined!"; }
687        else { printl $l, "$bytes->[30] ns"; }
688
689        $l = "Row Densities";
690        $temp = "";
691        if ($bytes->[31] & 1) { $temp .= "4 MByte\n"; }
692        if ($bytes->[31] & 2) { $temp .= "8 MByte\n"; }
693        if ($bytes->[31] & 4) { $temp .= "16 MByte\n"; }
694        if ($bytes->[31] & 8) { $temp .= "32 MByte\n"; }
695        if ($bytes->[31] & 16) { $temp .= "64 MByte\n"; }
696        if ($bytes->[31] & 32) { $temp .= "128 MByte\n"; }
697        if ($bytes->[31] & 64) { $temp .= "256 MByte\n"; }
698        if ($bytes->[31] & 128) { $temp .= "512 MByte\n"; }
699        if ($bytes->[31] == 0) { $temp .= "(Undefined! -- None Reported!)\n"; }
700        printl $l, $temp;
701
702        if (($bytes->[32] & 0xf) <= 9) {
703                $l = "Command and Address Signal Setup Time";
704                $temp = (($bytes->[32] & 0x7f) >> 4) + ($bytes->[32] & 0xf) * 0.1;
705                printl $l, (($bytes->[32] >> 7) ? -$temp : $temp) . " ns";
706        }
707
708        if (($bytes->[33] & 0xf) <= 9) {
709                $l = "Command and Address Signal Hold Time";
710                $temp = (($bytes->[33] & 0x7f) >> 4) + ($bytes->[33] & 0xf) * 0.1;
711                printl $l, (($bytes->[33] >> 7) ? -$temp : $temp) . " ns";
712        }
713
714        if (($bytes->[34] & 0xf) <= 9) {
715                $l = "Data Signal Setup Time";
716                $temp = (($bytes->[34] & 0x7f) >> 4) + ($bytes->[34] & 0xf) * 0.1;
717                printl $l, (($bytes->[34] >> 7) ? -$temp : $temp) . " ns";
718        }
719
720        if (($bytes->[35] & 0xf) <= 9) {
721                $l = "Data Signal Hold Time";
722                $temp = (($bytes->[35] & 0x7f) >> 4) + ($bytes->[35] & 0xf) * 0.1;
723                printl $l, (($bytes->[35] >> 7) ? -$temp : $temp) . " ns";
724        }
725}
726
727# Parameter: bytes 0-63
728sub decode_ddr_sdram($)
729{
730        my $bytes = shift;
731        my ($l, $temp);
732
733# SPD revision
734        if ($bytes->[62] != 0xff) {
735                printl "SPD Revision", ($bytes->[62] >> 4) . "." .
736                                       ($bytes->[62] & 0xf);
737        }
738
739# speed
740        prints "Memory Characteristics";
741
742        $l = "Maximum module speed";
743        $temp = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
744        my $ddrclk = 2 * (1000 / $temp);
745        my $tbits = ($bytes->[7] * 256) + $bytes->[6];
746        if (($bytes->[11] == 2) || ($bytes->[11] == 1)) { $tbits = $tbits - 8; }
747        my $pcclk = int ($ddrclk * $tbits / 8);
748        $pcclk += 100 if ($pcclk % 100) >= 50; # Round properly
749        $pcclk = $pcclk - ($pcclk % 100);
750        $ddrclk = int ($ddrclk);
751        printl $l, "${ddrclk}MHz (PC${pcclk})";
752
753#size computation
754        my $k=0;
755        my $ii=0;
756       
757        $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
758        if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) {
759                 $k = $bytes->[5] * $bytes->[17];
760        }
761       
762        if($ii > 0 && $ii <= 12 && $k > 0) {
763                printl "Size", ((1 << $ii) * $k) . " MB"; }
764        else { 
765                printl "INVALID SIZE", $bytes->[3] . ", " . $bytes->[4] . ", " .
766                                       $bytes->[5] . ", " . $bytes->[17];
767        }
768
769        my $highestCAS = 0;
770        my %cas;
771        for ($ii = 0; $ii < 7; $ii++) {
772                if ($bytes->[18] & (1 << $ii)) {
773                        $highestCAS = 1+$ii*0.5;
774                        $cas{$highestCAS}++;
775                }
776        }
777
778        my $trcd;
779        my $trp;
780        my $tras;
781        my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
782
783        $trcd =($bytes->[29] >> 2)+(($bytes->[29] & 3)*0.25);
784        $trp =($bytes->[27] >> 2)+(($bytes->[27] & 3)*0.25);
785        $tras = $bytes->[30];
786
787        printl "tCL-tRCD-tRP-tRAS",
788                $highestCAS . "-" .
789                ceil($trcd/$ctime) . "-" .
790                ceil($trp/$ctime) . "-" .
791                ceil($tras/$ctime);
792
793# latencies
794        if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; }
795        else { $temp = "None"; }
796        printl "Supported CAS Latencies", $temp;
797
798        my @array;
799        for ($ii = 0; $ii < 7; $ii++) {
800                push(@array, $ii) if ($bytes->[19] & (1 << $ii));
801        }
802        if (@array) { $temp = join ', ', @array; }
803        else { $temp = "None"; }
804        printl "Supported CS Latencies", $temp;
805
806        @array = ();
807        for ($ii = 0; $ii < 7; $ii++) {
808                push(@array, $ii) if ($bytes->[20] & (1 << $ii));
809        }
810        if (@array) { $temp = join ', ', @array; }
811        else { $temp = "None"; }
812        printl "Supported WE Latencies", $temp;
813
814# timings
815        if (exists $cas{$highestCAS}) {
816                printl "Minimum Cycle Time (CAS $highestCAS)",
817                       "$ctime ns";
818
819                printl "Maximum Access Time (CAS $highestCAS)",
820                       (($bytes->[10] >> 4) * 0.1 + ($bytes->[10] & 0xf) * 0.01) . " ns";
821        }
822
823        if (exists $cas{$highestCAS-0.5} && spd_written(@$bytes[23..24])) {
824                printl "Minimum Cycle Time (CAS ".($highestCAS-0.5).")",
825                       (($bytes->[23] >> 4) + ($bytes->[23] & 0xf) * 0.1) . " ns";
826
827                printl "Maximum Access Time (CAS ".($highestCAS-0.5).")",
828                       (($bytes->[24] >> 4) * 0.1 + ($bytes->[24] & 0xf) * 0.01) . " ns";
829        }
830
831        if (exists $cas{$highestCAS-1} && spd_written(@$bytes[25..26])) {
832                printl "Minimum Cycle Time (CAS ".($highestCAS-1).")",
833                       (($bytes->[25] >> 4) + ($bytes->[25] & 0xf) * 0.1) . " ns";
834
835                printl "Maximum Access Time (CAS ".($highestCAS-1).")",
836                       (($bytes->[26] >> 4) * 0.1 + ($bytes->[26] & 0xf) * 0.01) . " ns";
837        }
838
839# module attributes
840        if ($bytes->[47] & 0x03) {
841                if (($bytes->[47] & 0x03) == 0x01) { $temp = "1.125\" to 1.25\""; }
842                elsif (($bytes->[47] & 0x03) == 0x02) { $temp = "1.7\""; }
843                elsif (($bytes->[47] & 0x03) == 0x03) { $temp = "Other"; }
844                printl "Module Height", $temp;
845        }
846}
847
848sub ddr2_sdram_ctime($)
849{
850        my $byte = shift;
851        my $ctime;
852       
853        $ctime = $byte >> 4;
854        if (($byte & 0xf) <= 9) { $ctime += ($byte & 0xf) * 0.1; }
855        elsif (($byte & 0xf) == 10) { $ctime += 0.25; }
856        elsif (($byte & 0xf) == 11) { $ctime += 0.33; }
857        elsif (($byte & 0xf) == 12) { $ctime += 0.66; }
858        elsif (($byte & 0xf) == 13) { $ctime += 0.75; }
859
860        return $ctime;
861}
862
863sub ddr2_sdram_atime($)
864{
865        my $byte = shift;
866        my $atime;
867       
868        $atime = ($byte >> 4) * 0.1 + ($byte & 0xf) * 0.01;
869
870        return $atime;
871}
872
873# Parameter: bytes 0-63
874sub decode_ddr2_sdram($)
875{
876        my $bytes = shift;
877        my ($l, $temp);
878        my $ctime;
879
880# SPD revision
881        if ($bytes->[62] != 0xff) {
882                printl "SPD Revision", ($bytes->[62] >> 4) . "." .
883                                       ($bytes->[62] & 0xf);
884        }
885
886# speed
887        prints "Memory Characteristics";
888
889        $l = "Maximum module speed";
890        $ctime = ddr2_sdram_ctime($bytes->[9]);
891        my $ddrclk = 2 * (1000 / $ctime);
892        my $tbits = ($bytes->[7] * 256) + $bytes->[6];
893        if ($bytes->[11] & 0x03) { $tbits = $tbits - 8; }
894        my $pcclk = int ($ddrclk * $tbits / 8);
895        # Round down to comply with Jedec
896        $pcclk = $pcclk - ($pcclk % 100);
897        $ddrclk = int ($ddrclk);
898        printl $l, "${ddrclk}MHz (PC2-${pcclk})";
899
900#size computation
901        my $k=0;
902        my $ii=0;
903
904        $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
905        $k = (($bytes->[5] & 0x7) + 1) * $bytes->[17];
906       
907        if($ii > 0 && $ii <= 12 && $k > 0) {
908                printl "Size", ((1 << $ii) * $k) . " MB"; 
909        } else {
910                printl "INVALID SIZE", $bytes->[3] . "," . $bytes->[4] . "," .
911                                       $bytes->[5] . "," . $bytes->[17];
912        }
913
914        my $highestCAS = 0;
915        my %cas;
916        for ($ii = 2; $ii < 7; $ii++) {
917                if ($bytes->[18] & (1 << $ii)) {
918                        $highestCAS = $ii;
919                        $cas{$highestCAS}++;
920                }
921        }
922
923        my $trcd;
924        my $trp;
925        my $tras;
926       
927        $trcd =($bytes->[29] >> 2)+(($bytes->[29] & 3)*0.25);
928        $trp =($bytes->[27] >> 2)+(($bytes->[27] & 3)*0.25);
929        $tras =$bytes->[30];
930
931        printl "tCL-tRCD-tRP-tRAS",
932                $highestCAS . "-" .
933                ceil($trcd/$ctime) . "-" .
934                ceil($trp/$ctime) . "-" .
935                ceil($tras/$ctime);
936
937# latencies
938        if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; }
939        else { $temp = "None"; }
940        printl "Supported CAS Latencies", $temp;
941
942# timings
943        if (exists $cas{$highestCAS}) {
944                printl "Minimum Cycle Time (CAS $highestCAS)",
945                       "$ctime ns";
946                printl "Maximum Access Time (CAS $highestCAS)",
947                       ddr2_sdram_atime($bytes->[10]) . " ns";
948        }
949
950        if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) {
951                printl "Minimum Cycle Time (CAS ".($highestCAS-1).")",
952                       ddr2_sdram_ctime($bytes->[23]) . " ns";
953                printl "Maximum Access Time (CAS ".($highestCAS-1).")",
954                       ddr2_sdram_atime($bytes->[24]) . " ns";
955        }
956
957        if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) {
958                printl "Minimum Cycle Time (CAS ".($highestCAS-2).")",
959                       ddr2_sdram_ctime($bytes->[25]) . " ns";
960                printl "Maximum Access Time (CAS ".($highestCAS-2).")",
961                       ddr2_sdram_atime($bytes->[26]) . " ns";
962        }
963}
964
965# Parameter: bytes 0-63
966sub decode_direct_rambus($)
967{
968        my $bytes = shift;
969
970#size computation
971        prints "Memory Characteristics";
972
973        my $ii;
974
975        $ii = ($bytes->[4] & 0x0f) + ($bytes->[4] >> 4) + ($bytes->[5] & 0x07) - 13;
976       
977        if ($ii > 0 && $ii < 16) {
978                printl "Size", (1 << $ii) . " MB";
979        } else {
980                printl "INVALID SIZE", sprintf("0x%02x, 0x%02x",
981                                               $bytes->[4], $bytes->[5]);
982        }
983}
984
985# Parameter: bytes 0-63
986sub decode_rambus($)
987{
988        my $bytes = shift;
989
990#size computation
991        prints "Memory Characteristics";
992
993        my $ii;
994       
995        $ii = ($bytes->[3] & 0x0f) + ($bytes->[3] >> 4) + ($bytes->[5] & 0x07) - 13;
996       
997        if ($ii > 0 && $ii < 16) {
998                printl "Size", (1 << $ii) . " MB";
999        } else {
1000                printl "INVALID SIZE", sprintf("0x%02x, 0x%02x",
1001                                               $bytes->[3], $bytes->[5]);
1002        }
1003}
1004
1005%decode_callback = (
1006        "SDR SDRAM"     => \&decode_sdr_sdram,
1007        "DDR SDRAM"     => \&decode_ddr_sdram,
1008        "DDR2 SDRAM"    => \&decode_ddr2_sdram,
1009        "Direct Rambus" => \&decode_direct_rambus,
1010        "Rambus"        => \&decode_rambus,
1011);
1012
1013# Parameter: bytes 64-127
1014sub decode_intel_spec_freq($)
1015{
1016        my $bytes = shift;
1017        my ($l, $temp);
1018
1019        prints "Intel Specification";
1020
1021        $l = "Frequency";
1022        if ($bytes->[62] == 0x66) { $temp = "66MHz\n"; }
1023        elsif ($bytes->[62] == 100) { $temp = "100MHz or 133MHz\n"; }
1024        elsif ($bytes->[62] == 133) { $temp = "133MHz\n"; }
1025        else { $temp = "Undefined!\n"; }
1026        printl $l, $temp;
1027
1028        $l = "Details for 100MHz Support";
1029        $temp="";
1030        if ($bytes->[63] & 1) { $temp .= "Intel Concurrent Auto-precharge\n"; }
1031        if ($bytes->[63] & 2) { $temp .= "CAS Latency = 2\n"; }
1032        if ($bytes->[63] & 4) { $temp .= "CAS Latency = 3\n"; }
1033        if ($bytes->[63] & 8) { $temp .= "Junction Temp A (100 degrees C)\n"; }
1034        else { $temp .= "Junction Temp B (90 degrees C)\n"; }
1035        if ($bytes->[63] & 16) { $temp .= "CLK 3 Connected\n"; }
1036        if ($bytes->[63] & 32) { $temp .= "CLK 2 Connected\n"; }
1037        if ($bytes->[63] & 64) { $temp .= "CLK 1 Connected\n"; }
1038        if ($bytes->[63] & 128) { $temp .= "CLK 0 Connected\n"; }
1039        if (($bytes->[63] & 192) == 192) { $temp .= "Double-sided DIMM\n"; }
1040        elsif (($bytes->[63] & 192) != 0) { $temp .= "Single-sided DIMM\n"; }
1041        printl $l, $temp;
1042}
1043
1044sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
1045        my ($offset, $dimm_i) = @_;
1046        my @bytes;
1047        if ($use_sysfs) {
1048                # Kernel 2.6 with sysfs
1049                sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
1050                        or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
1051                binmode HANDLE;
1052                sysseek(HANDLE, $offset, SEEK_SET);
1053                sysread(HANDLE, my $eeprom, 64);
1054                close HANDLE;
1055                @bytes = unpack("C64", $eeprom);
1056        } else {
1057                # Kernel 2.4 with procfs
1058                for my $i (0 .. 3) {
1059                        my $hexoff = sprintf('%02x', $offset + $i * 16);
1060                        push @bytes, split(" ", `cat /proc/sys/dev/sensors/$dimm_i/$hexoff`);
1061                }
1062        }
1063        return @bytes;
1064}
1065
1066for (@ARGV) {
1067    if (/-h/) {
1068                print "Usage: $0 [-c] [-f [-b]]\n",
1069                        "       $0 -h\n\n",
1070                        "  -f, --format            print nice html output\n",
1071                        "  -b, --bodyonly          don't print html header\n",
1072                        "                          (useful for postprocessing the output)\n",
1073                        "  -c, --checksum          decode completely even if checksum fails\n",
1074                        "  -h, --help              display this usage summary\n";
1075                exit;
1076    }
1077    $opt_html = 1 if (/-f/);
1078    $opt_bodyonly = 1 if (/-b/);
1079    $opt_igncheck = 1 if (/-c/);
1080}
1081$opt_body = $opt_html && ! $opt_bodyonly;
1082
1083if ($opt_body)
1084{
1085        print "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
1086              "<html><head>\n",
1087                  "\t<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n",
1088                  "\t<title>PC DIMM Serial Presence Detect Tester/Decoder Output</title>\n",
1089                  "</head><body>\n";
1090}
1091
1092printh 'Memory Serial Presence Detect Decoder',
1093'By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner,
1094Jean Delvare and others
1095Version 2.10.6';
1096
1097
1098my $dimm_count=0;
1099my @dimm_list;
1100my $dir;
1101if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
1102else { $dir = '/proc/sys/dev/sensors'; }
1103if (-d $dir) {
1104        @dimm_list = split(/\s+/, `ls $dir`);
1105} elsif (! -d '/sys/module/eeprom') {
1106        print "No EEPROM found, are you sure the eeprom module is loaded?\n";
1107        exit;
1108}
1109
1110for my $i ( 0 .. $#dimm_list ) {
1111        $_=$dimm_list[$i];
1112        if (($use_sysfs && /^\d+-\d+$/)
1113         || (!$use_sysfs && /^eeprom-/)) {
1114                print "<b><u>" if $opt_html;
1115                printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
1116                        "/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
1117                        "/proc/sys/dev/sensors/$dimm_list[$i]");
1118                print "</u></b>" if $opt_html;
1119                print "<table border=1>\n" if $opt_html;
1120                if (($use_sysfs && /^[^-]+-([^-]+)$/)
1121                 || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
1122                        my $dimm_num=$1 - 49;
1123                        printl "Guessing DIMM is in", "bank $dimm_num";
1124                }
1125
1126# Decode first 3 bytes (0-2)
1127                prints "SPD EEPROM Information";
1128
1129                my @bytes = readspd64(0, $dimm_list[$i]);
1130                my $dimm_checksum = 0;
1131                $dimm_checksum += $bytes[$_] foreach (0 .. 62);
1132                $dimm_checksum &= 0xff;
1133
1134                my $l = "EEPROM Checksum of bytes 0-62";
1135                printl $l, ($bytes[63] == $dimm_checksum ?
1136                        sprintf("OK (0x%.2X)", $bytes[63]):
1137                        sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n",
1138                                $bytes[63], $dimm_checksum));
1139
1140                unless ($bytes[63] == $dimm_checksum or $opt_igncheck) {
1141                        print "</table>\n" if $opt_html;
1142                        next;
1143                }
1144               
1145                $dimm_count++;
1146                # Simple heuristic to detect Rambus
1147                my $is_rambus = $bytes[0] < 4;
1148                my $temp;
1149                if ($is_rambus) {
1150                        if ($bytes[0] == 1) { $temp = "0.7"; }
1151                        elsif ($bytes[0] == 2) { $temp = "1.0"; }
1152                        elsif ($bytes[0] == 0 || $bytes[0] == 255) { $temp = "Invalid"; }
1153                        else { $temp = "Reserved"; }
1154                        printl "SPD Revision", $temp;
1155                } else {
1156                        printl "# of bytes written to SDRAM EEPROM",
1157                               $bytes[0];
1158                }
1159
1160                $l = "Total number of bytes in EEPROM";
1161                if ($bytes[1] <= 14) {
1162                        printl $l, 2**$bytes[1];
1163                } elsif ($bytes[1] == 0) {
1164                        printl $l, "RFU"; 
1165                } else { printl $l, "ERROR!"; }
1166
1167                $l = "Fundamental Memory type";
1168                my $type = "Unknown";
1169                if ($is_rambus) {
1170                        if ($bytes[2] == 1) { $type = "Direct Rambus"; }
1171                        elsif ($bytes[2] == 17) { $type = "Rambus"; }
1172                } else {
1173                        if ($bytes[2] == 1) { $type = "FPM DRAM"; }
1174                        elsif ($bytes[2] == 2) { $type = "EDO"; }
1175                        elsif ($bytes[2] == 3) { $type = "Pipelined Nibble"; }
1176                        elsif ($bytes[2] == 4) { $type = "SDR SDRAM"; }
1177                        elsif ($bytes[2] == 5) { $type = "Multiplexed ROM"; }
1178                        elsif ($bytes[2] == 6) { $type = "DDR SGRAM"; }
1179                        elsif ($bytes[2] == 7) { $type = "DDR SDRAM"; }
1180                        elsif ($bytes[2] == 8) { $type = "DDR2 SDRAM"; }
1181                }
1182                printl $l, $type;
1183
1184# Decode next 61 bytes (3-63, depend on memory type)
1185                $decode_callback{$type}->(\@bytes)
1186                        if exists $decode_callback{$type};
1187
1188# Decode next 35 bytes (64-98, common to all memory types)
1189                prints "Manufacturing Information";
1190
1191                @bytes = readspd64(64, $dimm_list[$i]);
1192               
1193                $l = "Manufacturer";
1194                # $extra is a reference to an array containing up to
1195                # 7 extra bytes from the Manufacturer field. Sometimes
1196                # these bytes are filled with interesting data.
1197                ($temp, my $extra) = manufacturer(@bytes[0..7]);
1198                printl $l, $temp;
1199                $l = "Custom Manufacturer Data";
1200                $temp = manufacturer_data(@{$extra});
1201                printl $l, $temp if defined $temp;
1202               
1203                if (spd_written($bytes[8])) {
1204                        # Try the location code as ASCII first, as earlier specifications
1205                        # suggested this. As newer specifications don't mention it anymore,
1206                        # we still fall back to binary.
1207                        $l = "Manufacturing Location Code";
1208                        $temp = (chr($bytes[8]) =~ m/^[\w\d]$/) ? chr($bytes[8])
1209                              : sprintf("0x%.2X", $bytes[8]);
1210                        printl $l, $temp;
1211                }
1212               
1213                $l = "Part Number";
1214                $temp = part_number(@bytes[9..26]);
1215                printl $l, $temp;
1216               
1217                if (spd_written(@bytes[27..28])) {
1218                        $l = "Revision Code";
1219                        $temp = sprintf("0x%02X%02X\n", @bytes[27..28]);
1220                        printl $l, $temp;
1221                }
1222               
1223                if (spd_written(@bytes[29..30])) {
1224                        $l = "Manufacturing Date";
1225                        # In theory the year and week are in BCD format, but
1226                        # this is not always true in practice :(
1227                        if (($bytes[29] & 0xf0) <= 0x90
1228                         && ($bytes[29] & 0x0f) <= 0x09
1229                         && ($bytes[30] & 0xf0) <= 0x90
1230                         && ($bytes[30] & 0x0f) <= 0x09) {
1231                                # Note that this heuristic will break in year 2080
1232                                $temp = sprintf("%d%02X-W%02X\n",
1233                                                $bytes[29] >= 0x80 ? 19 : 20,
1234                                                @bytes[29..30]);
1235                        } else {
1236                                $temp = sprintf("0x%02X%02X\n",
1237                                                @bytes[29..30]);
1238                        }
1239                        printl $l, $temp;
1240                }
1241               
1242                if (spd_written(@bytes[31..34])) {
1243                        $l = "Assembly Serial Number";
1244                        $temp = sprintf("0x%02X%02X%02X%02X\n",
1245                                        @bytes[31..34]);
1246                        printl $l, $temp;
1247                }
1248
1249# Next 27 bytes (99-125) are manufacturer specific, can't decode
1250
1251# Last 2 bytes (126-127) are reserved, Intel used them as an extension
1252                if ($type eq "SDR SDRAM") {
1253                        decode_intel_spec_freq(\@bytes);
1254                }
1255               
1256                print "</table>\n" if $opt_html;
1257        }
1258}
1259printl2 "\n\nNumber of SDRAM DIMMs detected and decoded", $dimm_count;
1260
1261print "</body></html>\n" if $opt_body;
Note: See TracBrowser for help on using the browser.