Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 138990
b: refs/heads/master
c: 167f3a0
h: refs/heads/master
v: v3
  • Loading branch information
Ma Ling authored and Dave Airlie committed Mar 29, 2009
1 parent 9a7aefc commit 0382623
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 955a23eb3cfc773e71b05bb7a0a0938a9e1b2568
refs/heads/master: 167f3a04d7366d65c7fa9a92f0d604cdcf4a11ae
121 changes: 93 additions & 28 deletions trunk/drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,20 @@ static int add_detailed_info(struct drm_connector *connector,
}

#define DDC_ADDR 0x50

unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
/**
* Get EDID information via I2C.
*
* \param adapter : i2c device adaptor
* \param buf : EDID data buffer to be filled
* \param len : EDID data buffer length
* \return 0 on success or -1 on failure.
*
* Try to fetch EDID information by calling i2c driver function.
*/
int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
unsigned char *buf, int len)
{
unsigned char start = 0x0;
unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
struct i2c_msg msgs[] = {
{
.addr = DDC_ADDR,
Expand All @@ -564,31 +573,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
}, {
.addr = DDC_ADDR,
.flags = I2C_M_RD,
.len = EDID_LENGTH,
.len = len,
.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;
return 0;

dev_info(&adapter->dev, "unable to read EDID block.\n");
kfree(buf);
return NULL;
return -1;
}
EXPORT_SYMBOL(drm_do_probe_ddc_edid);

static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
/**
* Get EDID information.
*
* \param adapter : i2c device adaptor.
* \param buf : EDID data buffer to be filled
* \param len : EDID data buffer length
* \return 0 on success or -1 on failure.
*
* Initialize DDC, then fetch EDID information
* by calling drm_do_probe_ddc_edid function.
*/
static int drm_ddc_read(struct i2c_adapter *adapter,
unsigned char *buf, int len)
{
struct i2c_algo_bit_data *algo_data = adapter->algo_data;
unsigned char *edid = NULL;
int i, j;
int ret = -1;

algo_data->setscl(algo_data->data, 1);

Expand Down Expand Up @@ -616,7 +630,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
msleep(15);

/* Do the real work */
edid = drm_do_probe_ddc_edid(adapter);
ret = drm_do_probe_ddc_edid(adapter, buf, len);
algo_data->setsda(algo_data->data, 0);
algo_data->setscl(algo_data->data, 0);
msleep(15);
Expand All @@ -632,7 +646,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
msleep(15);
algo_data->setscl(algo_data->data, 0);
algo_data->setsda(algo_data->data, 0);
if (edid)
if (ret == 0)
break;
}
/* Release the DDC lines when done or the Apple Cinema HD display
Expand All @@ -641,9 +655,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
algo_data->setsda(algo_data->data, 1);
algo_data->setscl(algo_data->data, 1);

return edid;
return ret;
}

static int drm_ddc_read_edid(struct drm_connector *connector,
struct i2c_adapter *adapter,
char *buf, int len)
{
int ret;

ret = drm_ddc_read(adapter, buf, len);
if (ret != 0) {
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
drm_get_connector_name(connector));
goto end;
}
if (!edid_is_valid((struct edid *)buf)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
ret = -1;
}
end:
return ret;
}

#define MAX_EDID_EXT_NUM 4
/**
* drm_get_edid - get EDID data, if available
* @connector: connector we're probing
Expand All @@ -656,24 +692,53 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter)
{
int ret;
struct edid *edid;

edid = (struct edid *)drm_ddc_read(adapter);
if (!edid) {
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
drm_get_connector_name(connector));
return NULL;
edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
GFP_KERNEL);
if (edid == NULL) {
dev_warn(&connector->dev->pdev->dev,
"Failed to allocate EDID\n");
goto end;
}
if (!edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
kfree(edid);
return NULL;

/* Read first EDID block */
ret = drm_ddc_read_edid(connector, adapter,
(unsigned char *)edid, EDID_LENGTH);
if (ret != 0)
goto clean_up;

/* There are EDID extensions to be read */
if (edid->extensions != 0) {
int edid_ext_num = edid->extensions;

if (edid_ext_num > MAX_EDID_EXT_NUM) {
dev_warn(&connector->dev->pdev->dev,
"The number of extension(%d) is "
"over max (%d), actually read number (%d)\n",
edid_ext_num, MAX_EDID_EXT_NUM,
MAX_EDID_EXT_NUM);
/* Reset EDID extension number to be read */
edid_ext_num = MAX_EDID_EXT_NUM;
}
/* Read EDID including extensions too */
ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
EDID_LENGTH * (edid_ext_num + 1));
if (ret != 0)
goto clean_up;

}

connector->display_info.raw_edid = (char *)edid;
goto end;

clean_up:
kfree(edid);
edid = NULL;
end:
return edid;

}
EXPORT_SYMBOL(drm_get_edid);

Expand Down
3 changes: 2 additions & 1 deletion trunk/include/drm/drm_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,8 @@ extern void drm_fb_release(struct drm_file *file_priv);
extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
extern struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter);
extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter);
extern int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
unsigned char *buf, int len);
extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
Expand Down

0 comments on commit 0382623

Please sign in to comment.