msm: mdss: hdmi: add support for custom edid
Add sysfs node to provide a custome EDID to HDMI driver to address some special requirements from user applications like switching to a custom EDID in cases where sink doesn't support EDID or DDC line to read EDID. Change-Id: I75726e28722aa128cfc315b3b1b0e97e9a9cde56 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
This commit is contained in:
parent
e75a440cec
commit
9732bbbbd3
2 changed files with 84 additions and 5 deletions
|
@ -675,6 +675,77 @@ static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
|
||||||
return ret;
|
return ret;
|
||||||
} /* hdmi_tx_sysfs_rda_connected */
|
} /* hdmi_tx_sysfs_rda_connected */
|
||||||
|
|
||||||
|
static ssize_t hdmi_tx_sysfs_wta_edid(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
ssize_t ret = strnlen(buf, PAGE_SIZE);
|
||||||
|
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
|
||||||
|
int i = 0;
|
||||||
|
const char *buf_t = buf;
|
||||||
|
const int char_to_nib = 2;
|
||||||
|
int edid_size = count / char_to_nib;
|
||||||
|
|
||||||
|
hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
|
||||||
|
|
||||||
|
if (!hdmi_ctrl || !hdmi_ctrl->edid_buf) {
|
||||||
|
DEV_ERR("%s: invalid data\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(hdmi_ctrl->edid_buf, 0, hdmi_ctrl->edid_buf_size);
|
||||||
|
|
||||||
|
while (edid_size--) {
|
||||||
|
char t[char_to_nib + 1];
|
||||||
|
int d, rc;
|
||||||
|
|
||||||
|
memcpy(t, buf_t, sizeof(char) * char_to_nib);
|
||||||
|
t[char_to_nib] = '\0';
|
||||||
|
|
||||||
|
rc = kstrtoint(t, 16, &d);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("kstrtoint error %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(hdmi_ctrl->edid_buf + i++, &d,
|
||||||
|
sizeof(*hdmi_ctrl->edid_buf));
|
||||||
|
|
||||||
|
buf_t += char_to_nib;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdmi_ctrl->custom_edid = true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t hdmi_tx_sysfs_rda_edid(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
|
||||||
|
u32 size;
|
||||||
|
u32 cea_blks;
|
||||||
|
|
||||||
|
hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
|
||||||
|
|
||||||
|
if (!hdmi_ctrl || !hdmi_ctrl->edid_buf) {
|
||||||
|
DEV_ERR("%s: invalid data\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cea_blks = hdmi_ctrl->edid_buf[EDID_BLOCK_SIZE - 2];
|
||||||
|
size = (cea_blks + 1) * EDID_BLOCK_SIZE;
|
||||||
|
size = min_t(u32, size, PAGE_SIZE);
|
||||||
|
|
||||||
|
DEV_DBG("%s: edid size %d\n", __func__, size);
|
||||||
|
|
||||||
|
memcpy(buf, hdmi_ctrl->edid_buf, size);
|
||||||
|
|
||||||
|
print_hex_dump(KERN_DEBUG, "HDMI EDID: ", DUMP_PREFIX_NONE,
|
||||||
|
16, 1, buf, size, false);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t hdmi_tx_sysfs_wta_audio_cb(struct device *dev,
|
static ssize_t hdmi_tx_sysfs_wta_audio_cb(struct device *dev,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
|
@ -1162,6 +1233,8 @@ error:
|
||||||
|
|
||||||
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
|
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
|
||||||
static DEVICE_ATTR(hdmi_audio_cb, S_IWUSR, NULL, hdmi_tx_sysfs_wta_audio_cb);
|
static DEVICE_ATTR(hdmi_audio_cb, S_IWUSR, NULL, hdmi_tx_sysfs_wta_audio_cb);
|
||||||
|
static DEVICE_ATTR(edid, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_edid,
|
||||||
|
hdmi_tx_sysfs_wta_edid);
|
||||||
static DEVICE_ATTR(video_mode, S_IRUGO, hdmi_tx_sysfs_rda_video_mode, NULL);
|
static DEVICE_ATTR(video_mode, S_IRUGO, hdmi_tx_sysfs_rda_video_mode, NULL);
|
||||||
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
|
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
|
||||||
hdmi_tx_sysfs_wta_hpd);
|
hdmi_tx_sysfs_wta_hpd);
|
||||||
|
@ -1179,6 +1252,7 @@ static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v);
|
||||||
static struct attribute *hdmi_tx_fs_attrs[] = {
|
static struct attribute *hdmi_tx_fs_attrs[] = {
|
||||||
&dev_attr_connected.attr,
|
&dev_attr_connected.attr,
|
||||||
&dev_attr_hdmi_audio_cb.attr,
|
&dev_attr_hdmi_audio_cb.attr,
|
||||||
|
&dev_attr_edid.attr,
|
||||||
&dev_attr_video_mode.attr,
|
&dev_attr_video_mode.attr,
|
||||||
&dev_attr_hpd.attr,
|
&dev_attr_hpd.attr,
|
||||||
&dev_attr_vendor_name.attr,
|
&dev_attr_vendor_name.attr,
|
||||||
|
@ -1774,12 +1848,16 @@ static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl);
|
if (!hdmi_ctrl->custom_edid) {
|
||||||
|
hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl);
|
||||||
|
|
||||||
status = hdmi_tx_read_edid(hdmi_ctrl);
|
status = hdmi_tx_read_edid(hdmi_ctrl);
|
||||||
if (status) {
|
if (status) {
|
||||||
DEV_ERR("%s: error reading edid\n", __func__);
|
DEV_ERR("%s: error reading edid\n", __func__);
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hdmi_ctrl->custom_edid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = hdmi_edid_parser(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
|
status = hdmi_edid_parser(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
|
||||||
|
|
|
@ -173,6 +173,7 @@ struct hdmi_tx_ctrl {
|
||||||
atomic_t audio_ack_pending;
|
atomic_t audio_ack_pending;
|
||||||
bool hdcp14_sw_keys;
|
bool hdcp14_sw_keys;
|
||||||
bool auth_state;
|
bool auth_state;
|
||||||
|
bool custom_edid;
|
||||||
u32 enc_lvl;
|
u32 enc_lvl;
|
||||||
|
|
||||||
u8 spd_vendor_name[9];
|
u8 spd_vendor_name[9];
|
||||||
|
|
Loading…
Add table
Reference in a new issue