summaryrefslogtreecommitdiff
path: root/drivers/video/omap2/dss
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2011-09-01 07:56:28 +0100
committerAndy Green <andy.green@linaro.org>2011-09-01 07:56:28 +0100
commit37d2ca480767dc29f49ec5d91423acd49748b6d6 (patch)
treea91b3addb1aab9e8335499113f31b371b5c67ed6 /drivers/video/omap2/dss
parent85bb33e39a5dcd774703db10c06a76d3a2956610 (diff)
OMAP: DSS: HDMI: tame hdmi driver
Main change is to avoid automatically picking timings. Now the driver defaults to a safe 640x480, and leaves it to the upper layer (drm driver) to pick the desired resolution based on what the user selects and the drm infrastucture's parsing of the EDID.
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r--drivers/video/omap2/dss/hdmi.c229
1 files changed, 15 insertions, 214 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 02e84614c4f..5943d3eff8a 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -50,10 +50,12 @@ static struct {
int code;
int mode;
u8 edid[HDMI_EDID_MAX_LENGTH];
- u8 edid_set;
- bool custom_set;
+ bool edid_set;
struct hdmi_config cfg;
-} hdmi;
+} hdmi = {
+ .code = 4, /* setting default value of 640 480 VGA */
+ .mode = 0,
+};
/*
* Logic for the below structure :
@@ -563,222 +565,22 @@ static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
return cm;
}
-/*
- * An amalgamation of work from
- * Mythri P K <mythripk@ti.com>
- * With EDID parsing for DVI Monitor from Rob Clark <rob@ti.com>
- * See d96ea7bff990a2bce52b1087a446f15625993b21
- */
-static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid ,
- struct omap_video_timings *timings)
+static void hdmi_read_edid(void)
{
- union HDMI_EDID_DTD *edid_dtd =
- (union HDMI_EDID_DTD *) &edid[current_descriptor_addrs];
-
- if (edid_dtd->video.pixel_clock) {
- struct HDMI_EDID_DTD_VIDEO *vid = &edid_dtd->video;
-
- timings->pixel_clock = 10 * vid->pixel_clock;
- timings->x_res = vid->horiz_active |
- (((u16)vid->horiz_high & 0xf0) << 4);
- timings->y_res = vid->vert_active |
- (((u16)vid->vert_high & 0xf0) << 4);
-
- /* HORIZONTAL FRONT PORCH */
- timings->hfp = vid->horiz_sync_offset |
- (((u16)vid->sync_pulse_high & 0xc0) << 2);
- /* HORIZONTAL SYNC WIDTH */
- timings->hsw = vid->horiz_sync_pulse |
- (((u16)vid->sync_pulse_high & 0x30) << 4);
- /* HORIZONTAL BACK PORCH */
- timings->hbp = (vid->horiz_blanking |
- (((u16)vid->horiz_high & 0x0f) << 8)) -
- (timings->hfp + timings->hsw);
- /* VERTICAL FRONT PORCH */
- timings->vfp = ((vid->vert_sync_pulse & 0xf0) >> 4) |
- ((vid->sync_pulse_high & 0x0f) << 2);
- /* VERTICAL SYNC WIDTH */
- timings->vsw = (vid->vert_sync_pulse & 0x0f) |
- ((vid->sync_pulse_high & 0x03) << 4);
- /* VERTICAL BACK PORCH */
- timings->vbp = (vid->vert_blanking |
- (((u16)vid->vert_high & 0x0f) << 8)) -
- (timings->vfp + timings->vsw);
- return;
- }
+ int ret = 0;
- switch (edid_dtd->monitor_name.block_type) {
- case HDMI_EDID_DTD_TAG_STANDARD_TIMING_DATA:
- printk(KERN_INFO "standard timing data\n");
- return;
- case HDMI_EDID_DTD_TAG_COLOR_POINT_DATA:
- printk(KERN_INFO "color point data\n");
- return;
- case HDMI_EDID_DTD_TAG_MONITOR_NAME:
- printk(KERN_INFO "monitor name: %s\n",
- edid_dtd->monitor_name.text);
- return;
- case HDMI_EDID_DTD_TAG_MONITOR_LIMITS:
- {
- int i, max_area = 0;
- struct HDMI_EDID_DTD_MONITOR *limits =
- &edid_dtd->monitor_limits;
-
- printk(KERN_INFO "monitor limits\n");
- printk(KERN_INFO " min_vert_freq=%d\n", limits->min_vert_freq);
- printk(KERN_INFO " max_vert_freq=%d\n", limits->max_vert_freq);
- printk(KERN_INFO " min_horiz_freq=%d\n",
- limits->min_horiz_freq);
- printk(KERN_INFO " max_horiz_freq=%d\n",
- limits->max_horiz_freq);
- printk(KERN_INFO " pixel_clock_mhz=%d\n",
- limits->pixel_clock_mhz * 10);
-
- /* find the highest matching resolution (w*h) */
-
- /*
- * XXX since this is mainly for DVI monitors, should we only
- * support VESA timings? My monitor at home would pick
- * 1920x1080 otherwise, but that seems to not work well (monitor
- * blanks out and comes back, and picture doesn't fill full
- * screen, but leaves a black bar on left (native res is
- * 2048x1152). However if I only consider VESA timings, it picks
- * 1680x1050 and the picture is stable and fills whole screen
- */
- for (i = OMAP_HDMI_TIMINGS_VESA_START;
- i < OMAP_HDMI_TIMINGS_NB; i++) {
- const struct omap_video_timings *t =
- &cea_vesa_timings[i].timings;
- int hz, hscan, pixclock;
- int vtotal, htotal;
- htotal = t->hbp + t->hfp + t->hsw + t->x_res;
- vtotal = t->vbp + t->vfp + t->vsw + t->y_res;
-
- /* NOTE: We don't support interlaced mode for VESA */
- pixclock = t->pixel_clock * 1000;
- hscan = (pixclock + htotal / 2) / htotal;
- hscan = (hscan + 500) / 1000 * 1000;
- hz = (hscan + vtotal / 2) / vtotal;
- hscan /= 1000;
- pixclock /= 1000000;
- printk(KERN_DEBUG "debug only pixclock=%d, hscan=%d, hz=%d\n",
- pixclock, hscan, hz);
- if ((pixclock < (limits->pixel_clock_mhz * 10)) &&
- (limits->min_horiz_freq <= hscan) &&
- (hscan <= limits->max_horiz_freq) &&
- (limits->min_vert_freq <= hz) &&
- (hz <= limits->max_vert_freq)) {
- int area = t->x_res * t->y_res;
- printk(KERN_INFO " -> %d: %dx%d\n", i,
- t->x_res, t->y_res);
- if (area > max_area) {
- max_area = area;
- *timings = *t;
- }
- }
- }
- if (max_area)
- printk(KERN_INFO "found best resolution: %dx%d\n",
- timings->x_res, timings->y_res);
- return;
- }
- case HDMI_EDID_DTD_TAG_ASCII_STRING:
- printk(KERN_INFO "ascii string: %s\n", edid_dtd->ascii.text);
- return;
- case HDMI_EDID_DTD_TAG_MONITOR_SERIALNUM:
- printk(KERN_INFO "monitor serialnum: %s\n",
- edid_dtd->monitor_serial_number.text);
- return;
- default:
- printk(KERN_INFO "unsupported EDID descriptor block format\n");
- return;
- }
-}
-
-/* Description : This function gets the resolution information from EDID */
-static void get_edid_timing_data(u8 *edid)
-{
- u8 count;
- u16 current_descriptor_addrs;
- struct hdmi_cm cm;
- struct omap_video_timings edid_timings;
-
- /* search block 0, there are 4 DTDs arranged in priority order */
- for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
- current_descriptor_addrs =
- EDID_DESCRIPTOR_BLOCK0_ADDRESS +
- count * EDID_TIMING_DESCRIPTOR_SIZE;
- get_horz_vert_timing_info(current_descriptor_addrs,
- edid, &edid_timings);
- cm = hdmi_get_code(&edid_timings);
- DSSDBG("Block0[%d] value matches code = %d , mode = %d\n",
- count, cm.code, cm.mode);
- if (cm.code == -1) {
- continue;
- } else {
- hdmi.code = cm.code;
- hdmi.mode = cm.mode;
- DSSDBG("code = %d , mode = %d\n",
- hdmi.code, hdmi.mode);
- return;
- }
- }
- if (edid[0x7e] != 0x00) {
- for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
- count++) {
- current_descriptor_addrs =
- EDID_DESCRIPTOR_BLOCK1_ADDRESS +
- count * EDID_TIMING_DESCRIPTOR_SIZE;
- get_horz_vert_timing_info(current_descriptor_addrs,
- edid, &edid_timings);
- cm = hdmi_get_code(&edid_timings);
- DSSDBG("Block1[%d] value matches code = %d, mode = %d",
- count, cm.code, cm.mode);
- if (cm.code == -1) {
- continue;
- } else {
- hdmi.code = cm.code;
- hdmi.mode = cm.mode;
- DSSDBG("code = %d , mode = %d\n",
- hdmi.code, hdmi.mode);
- return;
- }
- }
- }
-
- DSSINFO("no valid timing found , falling back to VGA\n");
- hdmi.code = 4; /* setting default value of 640 480 VGA */
- hdmi.mode = HDMI_DVI;
-}
-
-static void hdmi_read_edid(struct omap_video_timings *dp)
-{
- int ret = 0, code;
-
- memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
-
- if (!hdmi.edid_set)
+ if (!hdmi.edid_set) {
+ memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH);
+ }
if (!ret) {
if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) {
- /* search for timings of default resolution */
- get_edid_timing_data(hdmi.edid);
hdmi.edid_set = true;
}
} else {
DSSWARN("failed to read E-EDID\n");
}
-
- if (!hdmi.edid_set) {
- DSSINFO("fallback to VGA\n");
- hdmi.code = 4; /* setting default value of 640 480 VGA */
- hdmi.mode = HDMI_DVI;
- }
-
- code = get_timings_index();
-
- *dp = cea_vesa_timings[code].timings;
}
static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
@@ -1236,9 +1038,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
- if (!hdmi.custom_set) {
+ if (!hdmi.edid_set) {
DSSDBG("Read EDID as no EDID is not set on poweron\n");
- hdmi_read_edid(p);
+ hdmi_read_edid();
dirty = get_timings_index() != code;
}
code = get_timings_index();
@@ -1297,6 +1099,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
return 0;
err:
hdmi_enable_clocks(0);
+ hdmi.edid_set = false;
return -EIO;
}
@@ -1309,7 +1112,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
hdmi_enable_clocks(0);
- hdmi.edid_set = 0;
+ hdmi.edid_set = false;
}
bool omapdss_hdmi_is_detected(struct omap_dss_device *dssdev, bool force)
@@ -1338,7 +1141,7 @@ bool omapdss_hdmi_is_detected(struct omap_dss_device *dssdev, bool force)
int omapdss_hdmi_get_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
{
if (!hdmi.edid_set)
- hdmi_read_edid(NULL);
+ hdmi_read_edid();
if (!hdmi.edid_set)
return -EINVAL;
memcpy(buf, hdmi.edid, min(len, HDMI_EDID_MAX_LENGTH));
@@ -1363,12 +1166,10 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
{
struct hdmi_cm cm;
- hdmi.custom_set = 1;
cm = hdmi_get_code(&dssdev->panel.timings);
hdmi.code = cm.code;
hdmi.mode = cm.mode;
omapdss_hdmi_display_enable(dssdev);
- hdmi.custom_set = 0;
}
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)