mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
![Jean Delvare](/assets/img/avatar_default.png)
The code in fb_ddc_read() is said to be based on the implementation of the radeon driver: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=fc5891c8a3ba284f13994d7bc1f1bfa8283982de However, comparing the old radeon driver code with the new fb_ddc code reveals some differences. Most notably, the I2C bus lines are held at the end of the function, while the original code was releasing them (as the comment above correctly says.) There are a few other differences, which appear to be responsible for read failures on my system. While tracing low-level I2C code in i2c-algo-bit, I noticed that the initial attempt to read the EDID always failed. It takes one retry for the read to succeed. As we are about to remove this automatic retry property from i2c-algo-bit, reading the EDID would really fail. As a summary, the I2C lines quirk which is supposedly needed to read EDID on some older monitors is currently breaking the (first) read on all other monitors (and might not even work with older ones - did anyone try since October 2006?) After applying the patch below, which makes the code in fb_ddc_read() really similar to what the radeon driver used to have, the first EDID read succeeds again. On top of that, as it appears that this code has been broken for one year now and nobody seems to have complained, I'm curious if it makes sense to keep this quirk in place. It makes the code more complex and slower just for the sake of monitors which I guess nobody uses anymore. Can't we just get rid of it? Signed-off-by: Jean Delvare <khali@linux-fr.org> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Tested-by: Roger Leigh <rleigh@whinlatter.ukfsn.org> Tested-by: Michael Buesch <mb@bu3sch.de> Cc: "Antonino A. Daplas" <adaplas@pol.net> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
116 lines
2.5 KiB
C
116 lines
2.5 KiB
C
/*
|
|
* driver/vide/fb_ddc.c - DDC/EDID read support.
|
|
*
|
|
* Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file COPYING in the main directory of this archive
|
|
* for more details.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fb.h>
|
|
#include <linux/i2c-algo-bit.h>
|
|
|
|
#include "edid.h"
|
|
|
|
#define DDC_ADDR 0x50
|
|
|
|
static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
|
|
{
|
|
unsigned char start = 0x0;
|
|
unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
|
struct i2c_msg msgs[] = {
|
|
{
|
|
.addr = DDC_ADDR,
|
|
.flags = 0,
|
|
.len = 1,
|
|
.buf = &start,
|
|
}, {
|
|
.addr = DDC_ADDR,
|
|
.flags = I2C_M_RD,
|
|
.len = EDID_LENGTH,
|
|
.buf = buf,
|
|
}
|
|
};
|
|
|
|
if (!buf) {
|
|
dev_warn(&adapter->dev, "unable to allocate memory for EDID "
|
|
"block.\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (i2c_transfer(adapter, msgs, 2) == 2)
|
|
return buf;
|
|
|
|
dev_warn(&adapter->dev, "unable to read EDID block.\n");
|
|
kfree(buf);
|
|
return NULL;
|
|
}
|
|
|
|
unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
|
|
{
|
|
struct i2c_algo_bit_data *algo_data = adapter->algo_data;
|
|
unsigned char *edid = NULL;
|
|
int i, j;
|
|
|
|
algo_data->setscl(algo_data->data, 1);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
/* For some old monitors we need the
|
|
* following process to initialize/stop DDC
|
|
*/
|
|
algo_data->setsda(algo_data->data, 1);
|
|
msleep(13);
|
|
|
|
algo_data->setscl(algo_data->data, 1);
|
|
for (j = 0; j < 5; j++) {
|
|
msleep(10);
|
|
if (algo_data->getscl(algo_data->data))
|
|
break;
|
|
}
|
|
if (j == 5)
|
|
continue;
|
|
|
|
algo_data->setsda(algo_data->data, 0);
|
|
msleep(15);
|
|
algo_data->setscl(algo_data->data, 0);
|
|
msleep(15);
|
|
algo_data->setsda(algo_data->data, 1);
|
|
msleep(15);
|
|
|
|
/* Do the real work */
|
|
edid = fb_do_probe_ddc_edid(adapter);
|
|
algo_data->setsda(algo_data->data, 0);
|
|
algo_data->setscl(algo_data->data, 0);
|
|
msleep(15);
|
|
|
|
algo_data->setscl(algo_data->data, 1);
|
|
for (j = 0; j < 10; j++) {
|
|
msleep(10);
|
|
if (algo_data->getscl(algo_data->data))
|
|
break;
|
|
}
|
|
|
|
algo_data->setsda(algo_data->data, 1);
|
|
msleep(15);
|
|
algo_data->setscl(algo_data->data, 0);
|
|
algo_data->setsda(algo_data->data, 0);
|
|
if (edid)
|
|
break;
|
|
}
|
|
/* Release the DDC lines when done or the Apple Cinema HD display
|
|
* will switch off
|
|
*/
|
|
algo_data->setsda(algo_data->data, 1);
|
|
algo_data->setscl(algo_data->data, 1);
|
|
|
|
return edid;
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(fb_ddc_read);
|
|
|
|
MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");
|
|
MODULE_DESCRIPTION("DDC/EDID reading support");
|
|
MODULE_LICENSE("GPL");
|