You are on page 1of 6

By Andries Koopmans, 2-6-2016

Even though exact replacement screen for Lenovo laptops can be bought through for example Ebay,
these will not be recognized due to Lenovo’s EDID white-listing, presumably in the BIOS. Screens that
are not recognized will have their brightness control to be stuck at maximum under Windows (Linux
and MacOS ignore this white-listing)

A solution to this problem is to change the EDID of the replacement screen to match an officially
recognized, white-listed EDID.

The EDID is stored in an EEPROM on the LCD panel, which is read out by the graphics driver through
I2C. In almost all cases the chip is write protected to prevent tampering. Most often this write
protection is implemented through hardware: when one of the pins of the EEPROM is pulled high, it
cannot be written to.

Unless you are a lucky one who has a non-write protected screen, you have to break-out the chip.
The easiest is to connect an Arduino to the EEPROM chip directly and by-pass the write protect.

Check the EEPROM chip on your screen


I peeled away the plastic covering the screen electronics and found something that looked like a
EEPROM chip. I googled the text “464F 8442” that I found on the chip and discovered it was a Hitachi
HN58X2464FP serial EEPROM. The datasheet told me the exact pin out.

Note: To find out what is ground on a PCB, go around with your multimeter connectivity check.
Ground is usually one big connected plane on the PCB, and many capacitors (the big square grey
blocks) are connected to it (usually to regulate voltage ripples). The I2C pins, SCL and SDA, are
(almost) always connected through ‘pull-up’ resistors to Vcc. Often these are 4.7kOhm resistors. Look
for those to find out what is Vcc, using your resistance measurement function on the multimeter.

Pin 7 is the Write Protect pin. Having the screen disconnected from the laptop, with a multimeter I
verified the pin out. The SCL and SDA pins, used for the I2C connection, were connected to Vcc
through two 4.7kOhm pull-up resistors. The WP was connected to Vcc through 2.7kOhm, therefore
enabling the write-protect. Vss was connected to ground, as well as A0 and A1. A2 was connected
also connected to Vss, meaning that according to the datasheet the I2C address should be 0x54.
Connecting Arduino to screen
I was very happy to find break-out pins for the EEPROM on the other side of the PCB. With a
multimeter I verified that all were directly connected to the chip, except for the Vcc, which showed
some weird resistance to ground, so I ignored it, instead soldering a wire to a big capacitor which was
connected directly to the Vcc on the chip.

Below you can see the break-out pins on the other side of the screen PCB. At first I tried to just short
the write-protect pin (left) to ground, and try to program the chip directly from linux, but this didn’t
work. I suspect there is a chip in between that regulates communication to the EEPROM, as Linux
listed the screen on a different I2C address (0x50). Note that I didn’t use such clips when connecting
to the Arduino. They are way too big and came loose easily. I had some smaller hook-clips lying
around, but you might have to solder to the pads to ensure a good and secure connection.
A note on voltages & arduino!
With the screen connected I read out from the Vcc that the EEPROM chip operates on 2.5V.
Furthermore, I found some 3.3V on some other locations. Arduinos typically operate at 5V, so you
should not connect an Arduino directly to the LCD screen.

However, the EEPROM chips themselves are usually 5V tolerant (see the datasheet). So what I did was
power the chip with an external power source at 2.5V, but I connected the I2C pins from the Arduino
directly (= 5V). I didn’t notice anything weird, and everything was fine afterwards, so I guess it was
fine.You can add a current limiting resistor in series on the I2C line to have a little bit more safety, but
I do recommend a level shifter (make 5V -> 3.3V or 2.5V and vice versa) to be on the safe side.

In summary:

- Connect Vcc to a 2.5V power supply (if you don’t have that, you can try the 3.3V out of the
Arduino at your own risk)
- Connect all the grounds (power supply, EEPROM and Arduino) to one another. This is
important to make sure they are all referencing voltages to the same ground, and nothing is
‘floating’.
- Connect SDA to the SDA pin of your Arduino through a level shifter, or directly if you dare.
- Connect SCL to the SCL pin of your Arduino through a level shifter, or directly if you dare.
- Connect the WP (write-protect) pin to any other digital pin on the Arduino.

To find out what are the I2C pins of your arduino, see https://www.arduino.cc/en/Reference/Wire

Checking the address of the EEPROM.


I first used a I2C address scanner to find out the correct I2C address of the EEPROM. I used a
standard piece of code of the official Arduino website to do this.

http://playground.arduino.cc/Main/I2cScanner

Upload that to the Arduino, run it, and see what pops up. In my case I saw only one device on port
0x54, which was as expected.

If you find multiple devices, you can query each of them in the next step.

Reading out EEPROM


Next I used some code to read out the first 256 bytes of the EEPROM. I based my code on the
following website:

http://www.hobbytronics.co.uk/arduino-external-eeprom

I changed it a bit to suit my needs. The following code checks the first 256 bytes of the EEPROM.
Make sure the address (here named disk1) and where you connected the Write Protect to, is correct.
(Note I haven’t actually tested this code! It is only slightly modified and it should be correct, but I
just typed it up. Anyway, not much can go wrong with reading if the code turns out to be incorrect,
so trying it is quite safe).

The result should look like 128 hexdecimals representing the EDID, and then 128 times 0xFF or 0x00.
You should copy the result in some text document to have a backup in case you need to put it back.
#include <Wire.h>

#define disk1 0x54 //Address of 24LC256 eeprom chip


#define WP_PIN 4 //Write protect pin

void setup(void)
{
digitalWrite(WP_PIN, HIGH); //enable write protect to be safe

Serial.begin(9600);
Wire.begin();

for (unsigned int address = 0; address < 256; address++) //first 256
bytes
{
Serial.print(readEEPROM(disk1, address), HEX);
Serial.print(' '); //a space to separate the numbers
if (address % 16 == 0) Serial.println(); //new line every 16 numbers
for readability
}
}

void loop(){}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )


{
Wire.beginTransmission(deviceaddress);
Wire.write(eeaddress);
Wire.write(data);
Wire.endTransmission();

delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )


{
byte rdata = 0xFF;

Wire.beginTransmission(deviceaddress);
Wire.write(eeaddress);
Wire.endTransmission();

Wire.requestFrom(deviceaddress,1);

if (Wire.available()) rdata = Wire.read();

return rdata;
}

Writing the Lenovo EDID


Using almost the exact same code above we can now write the Lenovo EDID. Make sure you are
using a EDID of a Lenovo ‘approved’ screen that has properties exactly similar to your screen, or else
your screen might not work properly, or even be damaged.

Change the hexadecimals in the array in the code below to the EDID you want to flash. Again, this
code is NOT tested, so use at your own risk.
#include <Wire.h>

#define disk1 0x54 //Address of 24LC256 eeprom chip


#define WP_PIN 4 //Write protect pin

char lenovo_EDID[128] =
{0x83,0x84,0xdc,0x85,0x27,0x1f,0x38,0x11,0x61,0x02,0xa9,0x4f,0x31,0x95,0x0d
,0x8e,0x7b,0xbd,0x10,0xd1,0x8e,0xfb,0xdc,0xe3,0x5a,0x16,0x38,0x3a,0xa3,0x20
,0xbe,0x5d,0x08,0x68,0xa5,0x0c,0xf2,0xfb,0xa3,0x92,0xc9,0x75,0x5b,0x4b,0x85
,0x67,0x5a,0xb0,0x32,0x5e,0x5e,0x59,0x55,0x43,0x10,0xd4,0x96,0x83,0x5b,0x23
,0x75,0xbf,0x28,0xc6,0xb9,0xd9,0x07,0xcc,0x89,0x4b,0x09,0xd7,0xab,0xcc,0x96
,0xcb,0xda,0x99,0x27,0x2d,0x7e,0x13,0x0a,0xd4,0xd5,0x98,0xbd,0xe7,0x26,0xc1
,0xb5,0x62,0x77,0x56,0x64,0x67,0x41,0xec,0x45,0xa3,0x50,0xc5,0x94,0x45,0x94
,0xfb,0xb6,0x4b,0xbb,0x3e,0x9c,0x95,0xcb,0xa1,0xa4,0x28,0xe4,0x52,0xa0,0xcf
,0x29,0x5e,0x7b,0xa9,0xfc,0xea,0x27,0xee};

void setup(void)
{
digitalWrite(WP_PIN, LOW); //disable write protect to be safe

Serial.begin(9600);
Wire.begin();

for (unsigned int address = 0; address <= 127; address++)


{
writeEEPROM(disk1, address, lenovo_EDID[address]);

}
}

void loop(){}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )


{
Wire.beginTransmission(deviceaddress);
Wire.write(eeaddress);
Wire.write(data);
Wire.endTransmission();

delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )


{
byte rdata = 0xFF;

Wire.beginTransmission(deviceaddress);
Wire.write(eeaddress);
Wire.endTransmission();

Wire.requestFrom(deviceaddress,1);

if (Wire.available()) rdata = Wire.read();

return rdata;
}
Voilá! You should now have flashed the new Lenovo EDID. Change the code back to reading, and
verify if indeed the right EDID is now on the EEPROM. Install your screen back into your laptop, and
see if the brightness control now works!

You might also like