Hackay DDR3 SPD

Original author: Hannu Hartikainen
  • Transfer
I upgraded the old laptop with two 4GB DDR3-1333 memory modules, but it turned out that the laptop is compatible with DDR3-1066 maximum. What will a real man do? Of course, flashing the EEPROM for DDR3 re-upgrading to a slower model!


Workplace. On the right is a Thinkpad for flashing, and on the left is a problematic MacBook Pro.

Be very careful. Obviously, you can damage or permanently lock the entry on your DIMM. Possible more subtle problems, including a battery logic failure, or the motherboard will turn into a brick .

How it all began


I have a 13-inch MacBook Pro mid-2010. Its file system was damaged during a normal reboot, and the disk utility (from the recovery partition) couldn't do anything about it. Well, I've been waiting for this for a long time: it's time to put the SSD and add a little RAM.

I bought an SSD and I was lucky to find a pair of broken laptops with suitable RAM modules in the e-garbage mount. We insert the SSD and two 4 GB modules, we launch Internet Recovery - and in an hour we should have a working system. But no. The download just hangs. Because of which? These RAM modules are the most suspicious, after all, they are from garbage. Therefore, we do what anyone would do: create a USB flash drive with memtest86 and run it for the night. Great, the memory is fine. After many hours with tests of different installation methods for different versions of macOS, the discovery finally comes that everything works fine if you simply insert the old memory back. one

True reason


Understanding the problem, I quickly learned that the 2009–2010 MacBook Pro does not actually work with memory faster than PC3-8500 , and that the problem can be circumvented by changing the RAM metadata using a Windows program called Thaiphoon Burner .

The real reason for the failure is the integrated GeForce 320M graphics processor, which uses shared memory, that is, regular RAM. It can work maximum with PC3-8500 (aka DDR3-1066, that is, with a DRAM clock frequency of 533 MHz), but the system memory controller is not aware of this and increases the maximum available speed to 667 MHz (i.e. PC3-10600 aka DDR3 -1333). The rest of the components have no problems with this, like the GPU in VESA mode (I think).

I have not heard of any other equipment that fails in the operation of RAM capable of higher speeds than the equipment can use. Of course, when buying memory modules on the market, sellers would warn about this nuance. It is still much better than the soldered RAM, as in Apple laptops since 2012.

Firmware setting


Having dealt with the cause, I installed one original PC3-8500 module for 2 GB and one new module for 4 GB, and it all worked. But DDR3 rebuinting seemed like a good project, so I decided to give it a try.

Of course, I am not going to install Windows only for EEPROM firmware and I am not going to buy fancy software if everything can be done manually. I thought the task should obviously run on Linux, perhaps with some additional tools. I also did not want to install Linux on MacBook just for this. Therefore, my old reliable Thinkpad X220 with NixOS has become an ideal platform for work. It took a little time to update it, because I didn't load the car for a year or so.

Then it was time to choose which module to try first. The Thinkpad already had two 4 GB each, and I found four 4 GB modules, so I had a lot to choose from. I decided to start with the strangest Micron production. All the rest were Samsung. One had a Lenovo sticker.

SPD reading


Memory modules are shipped with an EEPROM chip that contains metadata about the Serial Presence Detect (SPD) module . The format itself is simple, and access to the EEPROM can be organized via the SMBus bus , which is essentially no different from I²C . 2

Fortunately, there are kernel drivers and off-the-shelf software for interacting with SMBus and even reading the DDR3 EEPROM.

First, to view the devices on the bus, you need i2c-toolssome kernel modules. Of interest here is an SMBus adapter, in my case . The package even comes with a tool for reading RAM information in a readable format. This requires a kernel module . Here is part of the issue for one memory module:

$ nix-shell -p i2c-tools
$ modprobe i2c-dev
$ modprobe i2c-i801
$ i2cdetect -l
i2c-0 unknown i915 gmbus ssc N/A
i2c-1 unknown i915 gmbus vga N/A
i2c-2 unknown i915 gmbus panel N/A
i2c-3 unknown i915 gmbus dpc N/A
i2c-4 unknown i915 gmbus dpb N/A
i2c-5 unknown i915 gmbus dpd N/A
i2c-6 unknown DPDDC-B N/A
i2c-7 unknown DPDDC-C N/A
i2c-8 unknown DPDDC-D N/A
i2c-9 unknown SMBus I801 adapter at efa0 N/A


i2c-9

i2c-toolsdecode-dimmseeprom

$ modprobe eeprom
$ decode-dimms
$ modprobe -r eeprom




Memory Serial Presence Detect Decoder
By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner,
Jean Delvare, Trent Piepho and others
Decoding EEPROM: / sys / bus / i2c / drivers / eeprom / 9-0050
Guessing DIMM is in bank 1
--- === SPD EEPROM Information === ---
EEPROM CRC of bytes 0-116 OK (0xAEA4)
# of bytes written to SDRAM EEPROM 176
Total number of bytes in EEPROM 256
Fundamental Memory type DDR3 SDRAM
Module Type SO-DIMM
--- === Memory Characteristics === ---
Maximum module speed 1333 MHz (PC3-10600)
Size 4096 MB
Banks x Rows x Columns x Bits 8 x 15 x 10 x 64
Ranks 2
SDRAM Device Width 8 bits
Bus Width Extension 0 bits
tCL-tRCD-tRP-tRAS 9-9-9-24
Supported CAS Latencies (tCL) 10T, 9T, 8T, 7T, 6T, 5T
--- === Timings at Standard Speeds === ---
tCL-tRCD-tRP-tRAS as DDR3-1333 9-9-9-24
tCL-tRCD-tRP-tRAS as DDR3-1066 7-7-7-20
tCL-tRCD-tRP-tRAS as DDR3-800 6-6-6-15
--- === Timing Parameters === ---
Minimum Cycle Time (tCK) 1.500 ns
Minimum CAS Latency Time (tAA) 13.125 ns
Minimum Write Recovery time (tWR) 15.000 ns
Minimum RAS # to CAS # Delay (tRCD) 13.125 ns
Minimum Row Active to Row Active Delay (tRRD) 6.000 ns
Minimum Row Precharge Delay (tRP) 13.125 ns
Minimum Active to Precharge Delay (tRAS) 36.000 ns
Minimum Active to Auto-Refresh Delay (tRC) 49.125 ns
Minimum Recovery Delay (tRFC) 160.000 ns
Minimum Write to Read CMD Delay (tWTR) 7.500 ns
Minimum Read to Pre-charge CMD Delay (tRTP) 7.500 ns
Minimum Four Activate Window Delay (tFAW) 30.000 ns
--- === Optional Features === ---
Operable voltages 1.5V
RZQ / 6 supported? No
RZQ / 7 supported? Yes
DLL Off Mode supported? Yes
Operating temperature range 0-95 degrees C
Refresh Rate 2X
Auto Self-Refresh? Yes
On-Die Thermal Sensor readout? No
Partial Array Self-Refresh? No
Module Thermal Sensor Yes
SDRAM Device Type Standard Monolithic
--- === Physical Characteristics === ---
Module Height 30 mm
Module Thickness 2 mm front, 2 mm back
Module Width 67.6 mm
Module Reference Card F revision 0
Rank 1 Mapping Standard
--- === Manufacturer Data === ---
Module Manufacturer Micron Technology
DRAM Manufacturer Micron Technology
Manufacturing Location Code 0x0F
Manufacturing Date 2011-W23
Assembly Serial Number 0xFB5C7F1A
Part Number 16JSF51264HZ-1G4D1
Revision Code 0x4431

Quite a lot of data. Some of the information shown is calculated from the data. For example, timings at standard speeds (i.e., cycle counts) are calculated based on timing parameters in nanosecond resolution. Even they are stored as multiples of a time base unit installed elsewhere on the EEPROM, but this is not the case for the article. This RAM module produces 7-7-7-20 on DDR3-1066, which complies with the DDR3-1066F JEDEC standard. Do not ask me what JEDEC is, but it is faster than the cheapest DDR3-1066G.

I spent a lot of time confirming my conclusion: when I try to rebuild the memory, the only important number is the minimum cycle time (tCK). Here it is 1.5 ns, i.e. 667 MHz.

Let's look at the source data.

$ i2cdump 9 0x50
No size specified (using byte-data access)
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe the file / dev / i2c-9, address 0x50, mode byte
Continue? [Y / n]
     0 1 2 3 4 5 6 7 8 9 abcdef 0123456789abcdef
00: 92 10 0b 03 03 19 00 09 03 52 01 08 0c 00 7e 00 ??????. ?? R ???. ~.
10: 69 78 69 30 69 11 20 89 00 05 3c 3c 00 f0 82 05 ixi0i? ?.? <<. ???
20: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00? ...............
30: 00 00 00 00 00 00 00 00 00 00 00 00 0f 11 05 00 ............ ???.
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
70: 00 00 00 00 80 80 2c 0f 11 23 fb 5c 7f 1a a4 ae .....?, ?? #? \ ????
80: 31 36 4a 53 46 35 31 32 36 34 48 5a 2d 31 47 34 16JSF51264HZ-1G4
90: 44 31 44 31 80 2c 00 00 00 00 00 00 00 00 00 00 D1D1 ?, ..........
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................

Specifications say the minimum time is specified at 0x0c. Let's see, it is in the first line ( 00:), in the column c. By the way, its value is also 0x0c or 12. This is a multiple of the average time base (MTB), which is the quotient of dividing the value in 0x0a by the value in 0x0b (in nanoseconds). Here 1⁄8 ns. So 12 MTB corresponds to 1.5 ns.

Change planning


To go down to DDR3-1066, we need 533 MHz, which is 1.875 ns or 15 MTB, or 0x0f. That is, we want to write 0x0f at 0x0c.

But wait, obviously, there is a correction of errors. The CRC of the first 116 bytes is stored in 0x7e-7f. I looked there and saw a4 ae, then went to look for a calculator to calculate. It took me a surprisingly long time to find a workable CRC calculator. I tried several command line tools, but still stopped at the online calculator http://crccalc.com/ . Then I learned that the CRC-16 / XMODEM variant is used here, and the checksum is actually 0xAEA4. Byte order and all that. Should have noticed her in the issuance decode-dimms.

Therefore, you need to write a new minimum cycle time (0x0f) at 0x0c and a new checksum of 0x7e as a word.

SPD Record


Now I knew what to write, and finally dared to try. With shaking hands, I typed y, pressed Enter for final confirmation and ...

$ i2cset 9 0x50 0x0c 0x0f
WARNING! This program can confuse your I2C bus, cause data loss and worse!
DANGEROUS! Writing to a serial EEPROM on a memory DIMM
may render your memory and make your system UNBOOTABLE!
I will write to the device file / dev / i2c-9, chip address 0x50, data address
0x0c, data 0x0f, mode byte.
Continue? [y / n] y
Error: Write failed

Mistake. Wait what?

Being a pedantic guy, I began to study the sources of i2cset, as well as the corresponding kernel modules. At some point, I realized that this might be caused by write protection.

I took out a memory module, looked at it and recognized the EEPROM chip. It is written on it 97B, 321and some other things. Googling, I found out that this is an SE97B chip . I looked through the data table and several times carefully read the write protection section. Using programs, I made several attempts to remove temporary write protection, but failed. The write protection was probably permanent, so I just decided to look for a module that does not have write protection.

A funny fact, by the way, is that real-time write protection is enabled by writing something to a specific address. I don’t think i2cdetectit does it normally, but the launch i2cget 9 0x30 <any-address>will probably set a real write protection, which is really permanent. I did not try to do this.

I took the next module, and there was no error message. EEPROM just hasn't changed.

Finally, success!


With the third module, the operation finally turned out. I calculated the CRC and recorded it along with the cycle time. After loading the kernel module eepromand running the decode-dimmsmodule, it looked like a regular 4GB PC3-8500. When I installed it in the MacBook Pro, I finally booted the system with 8 GB of memory.


DDR3 SODIMM after rebooking ready for use in MacBook Pro

To: original DDR3-1333


     0 1 2 3 4 5 6 7 8 9 abcdef 0123456789abcdef
00: 92 10 0b 03 03 19 00 09 03 52 01 08 0c 00 3e 00 ??????. ?? R ???.>.
10: 69 78 69 30 69 11 20 89 00 05 3c 3c 00 f0 83 01 ixi0i? ?.? <<. ???
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 0f 11 45 00 ............ ?? E.
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
70: 00 00 00 00 80 ce 02 11 30 b1 5b 13 a1 0e 59 ..... ???? 0? [??? Y
80: 4d 34 37 31 42 35 32 37 33 43 48 30 2d 43 48 39 M471B5273CH0-CH9
90: 20 20 00 00 80 ce 00 00 00 53 31 42 4e 30 30 30 .. ?? ... S1BN000
a0: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 03??? ............?
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 32 59 00 ............. 2Y.
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

After: looks like DDR3-1066


     0 1 2 3 4 5 6 7 8 9 abcdef 0123456789abcdef
00: 92 10 0b 03 03 19 00 09 03 52 01 08 0f 00 3e 00 ??????. ?? R ???.>.
10: 69 78 69 30 69 11 20 89 00 05 3c 3c 00 f0 83 01 ixi0i? ?.? <<. ???
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 0f 11 45 00 ............ ?? E.
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
70: 00 00 00 00 80 ce 02 11 30 b1 5b 13 a1 06 54 ..... ???? 0? [??? T
80: 4d 34 37 31 42 35 32 37 33 43 48 30 2d 43 48 39 M471B5273CH0-CH9
90: 20 20 00 00 80 ce 00 00 00 53 31 42 4e 30 30 30 .. ?? ... S1BN000
a0: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 03??? ............?
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 32 59 00 ............. 2Y.
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

If you don’t see the difference right away, then you didn’t dig in these dumps for as long as I did.

Your thoughts


Is it worth doing? Financially, of course, no!

But it was fun and I learned a lot. I have no idea exactly where this knowledge can be applied, but I feel that at some point they will be needed. And just the feeling that you can solve the problem correctly is really nice and gives you confidence.



1. My assumption that RAM will work on this equipment, if it passes memtest86, was obviously wrong. However, even looking back, the assumption does not seem silly. By experience, a strange combination of hardware is not so rarely encountered, because of which the standard test falls.

2. I recently learned about using I²C in another project. I think I can read and write the EEPROM on the Cortex-M microcontroller using my own program, but in practice the soldering of the connector will be very difficult, and writing the code is too much work for me to get interested in. Nevertheless, I am really happy that I am theoretically capable of that!

Also popular now: