提交 167f3a04 编写于 作者: M Ma Ling 提交者: Dave Airlie

drm: read EDID extensions from monitor

Usually drm read basic EDID, that is enough for us, but since igital display
were introduced i.e. HDMI monitor, sometime we need to interact with monitor by
EDID extension information,

EDID extensions include audio/video data block, speaker allocation and vendor specific data blocks.

This patch intends to read EDID extensions from digital monitor for users.
Signed-off-by: NMa Ling <ling.ma@intel.com>
Signed-off-by: NDave Airlie <airlied@redhat.com>
上级 955a23eb
...@@ -550,11 +550,20 @@ static int add_detailed_info(struct drm_connector *connector, ...@@ -550,11 +550,20 @@ static int add_detailed_info(struct drm_connector *connector,
} }
#define DDC_ADDR 0x50 #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 start = 0x0;
unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
struct i2c_msg msgs[] = { struct i2c_msg msgs[] = {
{ {
.addr = DDC_ADDR, .addr = DDC_ADDR,
...@@ -564,31 +573,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) ...@@ -564,31 +573,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
}, { }, {
.addr = DDC_ADDR, .addr = DDC_ADDR,
.flags = I2C_M_RD, .flags = I2C_M_RD,
.len = EDID_LENGTH, .len = len,
.buf = buf, .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) if (i2c_transfer(adapter, msgs, 2) == 2)
return buf; return 0;
dev_info(&adapter->dev, "unable to read EDID block.\n"); dev_info(&adapter->dev, "unable to read EDID block.\n");
kfree(buf); return -1;
return NULL;
} }
EXPORT_SYMBOL(drm_do_probe_ddc_edid); 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; struct i2c_algo_bit_data *algo_data = adapter->algo_data;
unsigned char *edid = NULL;
int i, j; int i, j;
int ret = -1;
algo_data->setscl(algo_data->data, 1); algo_data->setscl(algo_data->data, 1);
...@@ -616,7 +630,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) ...@@ -616,7 +630,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
msleep(15); msleep(15);
/* Do the real work */ /* 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->setsda(algo_data->data, 0);
algo_data->setscl(algo_data->data, 0); algo_data->setscl(algo_data->data, 0);
msleep(15); msleep(15);
...@@ -632,7 +646,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) ...@@ -632,7 +646,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
msleep(15); msleep(15);
algo_data->setscl(algo_data->data, 0); algo_data->setscl(algo_data->data, 0);
algo_data->setsda(algo_data->data, 0); algo_data->setsda(algo_data->data, 0);
if (edid) if (ret == 0)
break; break;
} }
/* Release the DDC lines when done or the Apple Cinema HD display /* Release the DDC lines when done or the Apple Cinema HD display
...@@ -641,9 +655,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) ...@@ -641,9 +655,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
algo_data->setsda(algo_data->data, 1); algo_data->setsda(algo_data->data, 1);
algo_data->setscl(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 * drm_get_edid - get EDID data, if available
* @connector: connector we're probing * @connector: connector we're probing
...@@ -656,24 +692,53 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) ...@@ -656,24 +692,53 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
struct edid *drm_get_edid(struct drm_connector *connector, struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter) struct i2c_adapter *adapter)
{ {
int ret;
struct edid *edid; struct edid *edid;
edid = (struct edid *)drm_ddc_read(adapter); edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
if (!edid) { GFP_KERNEL);
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n", if (edid == NULL) {
drm_get_connector_name(connector)); dev_warn(&connector->dev->pdev->dev,
return NULL; "Failed to allocate EDID\n");
goto end;
} }
if (!edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", /* Read first EDID block */
drm_get_connector_name(connector)); ret = drm_ddc_read_edid(connector, adapter,
kfree(edid); (unsigned char *)edid, EDID_LENGTH);
return NULL; 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; connector->display_info.raw_edid = (char *)edid;
goto end;
clean_up:
kfree(edid);
edid = NULL;
end:
return edid; return edid;
} }
EXPORT_SYMBOL(drm_get_edid); EXPORT_SYMBOL(drm_get_edid);
......
...@@ -613,7 +613,8 @@ extern void drm_fb_release(struct drm_file *file_priv); ...@@ -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 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, extern struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter); 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 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_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); extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册