diff options
author | Kevin Huang <kevinh@nvidia.com> | 2011-10-06 15:48:52 -0700 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2011-10-11 05:08:08 -0700 |
commit | 8a2ec9a20d88db2f96e17cb7136d81560b989542 (patch) | |
tree | 3d2a572776b899ea9b70386cbbf0c8dc634e7325 | |
parent | 0adbe7449cf2a8a4752077824649a113e967bf90 (diff) |
video: tegra: hdmi: Add support to HDMI test in driver.
Test function is invoked by hdmi test module to test DC1, HDMI and
EDID modules.
Bug 834332
Change-Id: Ib67069ce2b8969ea13ebb1f4ac15a28d62da8adb
Reviewed-on: http://git-master/r/56482
Reviewed-by: Kevin Huang (Eng-SW) <kevinh@nvidia.com>
Tested-by: Kevin Huang (Eng-SW) <kevinh@nvidia.com>
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
-rw-r--r-- | drivers/video/tegra/dc/edid.c | 74 | ||||
-rw-r--r-- | drivers/video/tegra/dc/edid.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/hdmi.c | 78 |
3 files changed, 138 insertions, 16 deletions
diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c index 5c0e26e2677d..21445f95263a 100644 --- a/drivers/video/tegra/dc/edid.c +++ b/drivers/video/tegra/dc/edid.c @@ -329,6 +329,80 @@ static void data_release(struct kref *ref) vfree(data); } +int tegra_edid_get_monspecs_test(struct tegra_edid *edid, + struct fb_monspecs *specs, unsigned char *edid_ptr) +{ + int i, j, ret; + int extension_blocks; + struct tegra_edid_pvt *new_data, *old_data; + u8 *data; + + new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt)); + if (!new_data) + return -ENOMEM; + + kref_init(&new_data->refcnt); + + new_data->support_stereo = 0; + + data = new_data->dc_edid.buf; + memcpy(data, edid_ptr, 128); + + memset(specs, 0x0, sizeof(struct fb_monspecs)); + memset(&new_data->eld, 0x0, sizeof(new_data->eld)); + fb_edid_to_monspecs(data, specs); + if (specs->modedb == NULL) { + ret = -EINVAL; + goto fail; + } + + memcpy(new_data->eld.monitor_name, specs->monitor, + sizeof(specs->monitor)); + + new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1; + new_data->eld.product_id[0] = data[0x8]; + new_data->eld.product_id[1] = data[0x9]; + new_data->eld.manufacture_id[0] = data[0xA]; + new_data->eld.manufacture_id[1] = data[0xB]; + + extension_blocks = data[0x7e]; + for (i = 1; i <= extension_blocks; i++) { + memcpy(data+128, edid_ptr+128, 128); + + if (data[i * 128] == 0x2) { + fb_edid_add_monspecs(data + i * 128, specs); + + tegra_edid_parse_ext_block(data + i * 128, + data[i * 128 + 2], new_data); + + if (new_data->support_stereo) { + for (j = 0; j < specs->modedb_len; j++) { + if (tegra_edid_mode_support_stereo( + &specs->modedb[j])) + specs->modedb[j].vmode |= + FB_VMODE_STEREO_FRAME_PACK; + } + } + } + } + + new_data->dc_edid.len = i * 128; + + mutex_lock(&edid->lock); + old_data = edid->data; + edid->data = new_data; + mutex_unlock(&edid->lock); + + if (old_data) + kref_put(&old_data->refcnt, data_release); + + tegra_edid_dump(edid); + return 0; +fail: + vfree(new_data); + return ret; +} + int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs) { int i; diff --git a/drivers/video/tegra/dc/edid.h b/drivers/video/tegra/dc/edid.h index 773fa0afd18c..88438e4f1f55 100644 --- a/drivers/video/tegra/dc/edid.h +++ b/drivers/video/tegra/dc/edid.h @@ -50,6 +50,8 @@ struct tegra_edid_hdmi_eld { struct tegra_edid *tegra_edid_create(int bus); void tegra_edid_destroy(struct tegra_edid *edid); +int tegra_edid_get_monspecs_test(struct tegra_edid *edid, + struct fb_monspecs *specs, u8 *edid_ptr); int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs); int tegra_edid_get_eld(struct tegra_edid *edid, struct tegra_edid_hdmi_eld *elddata); diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index c9cd767725df..db56e817a5e0 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -355,7 +355,7 @@ const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = { {25200000, 11760, 26250, 25000}, {27000000, 11760, 28125, 25000}, {74250000, 9408, 61875, 20000}, - {148500000, 9408, 123750,20000}, + {148500000, 9408, 123750, 20000}, {0, 0, 0}, }; @@ -740,6 +740,66 @@ static bool tegra_dc_hdmi_hpd(struct tegra_dc *dc) (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level); } + +bool tegra_dc_hdmi_detect_config(struct tegra_dc *dc, + struct fb_monspecs *specs) +{ + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + + /* monitors like to lie about these but they are still useful for + * detecting aspect ratios + */ + dc->out->h_size = specs->max_x * 1000; + dc->out->v_size = specs->max_y * 1000; + + hdmi->dvi = !(specs->misc & FB_MISC_HDMI); + + tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter); + hdmi->hpd_switch.state = 0; + switch_set_state(&hdmi->hpd_switch, 1); + dev_info(&dc->ndev->dev, "display detected\n"); + + dc->connected = true; + tegra_dc_ext_process_hotplug(dc->ndev->id); +} + +/* This function is used to enable DC1 and HDMI for the purpose of testing. */ +bool tegra_dc_hdmi_detect_test(struct tegra_dc *dc, unsigned char *edid_ptr) +{ + int err; + struct fb_monspecs specs; + struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); + + if (!dc || !hdmi || !edid_ptr) { + dev_err(&dc->ndev->dev, "HDMI test failed to get arguments.\n"); + return false; + } + + err = tegra_edid_get_monspecs_test(hdmi->edid, &specs, edid_ptr); + if (err < 0) { + dev_err(&dc->ndev->dev, "error reading edid\n"); + goto fail; + } + + err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld); + if (err < 0) { + dev_err(&dc->ndev->dev, "error populating eld\n"); + goto fail; + } + hdmi->eld_retrieved = true; + + tegra_dc_hdmi_detect_config(dc, &specs); + + return true; + +fail: + hdmi->eld_retrieved = false; + switch_set_state(&hdmi->hpd_switch, 0); + tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0); + return false; +} +EXPORT_SYMBOL(tegra_dc_hdmi_detect_test); + static bool tegra_dc_hdmi_detect(struct tegra_dc *dc) { struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); @@ -761,22 +821,8 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc) goto fail; } hdmi->eld_retrieved = true; - /* monitors like to lie about these but they are still useful for - * detecting aspect ratios - */ - dc->out->h_size = specs.max_x * 1000; - dc->out->v_size = specs.max_y * 1000; - - hdmi->dvi = !(specs.misc & FB_MISC_HDMI); - - tegra_fb_update_monspecs(dc->fb, &specs, tegra_dc_hdmi_mode_filter); - hdmi->hpd_switch.state = 0; - switch_set_state(&hdmi->hpd_switch, 1); - dev_info(&dc->ndev->dev, "display detected\n"); - - dc->connected = true; - tegra_dc_ext_process_hotplug(dc->ndev->id); + tegra_dc_hdmi_detect_config(dc, &specs); return true; |