aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLajos Molnar <molnar@ti.com>2011-08-26 15:44:01 -0500
committerErik Gilling <konkers@android.com>2011-09-07 09:21:21 -0700
commitb442e52cba6dcffdf5880ca1c2f2625bfc5ee7f2 (patch)
treeede12cb9fbaa04e5a4486cf1586b575ef816cc57
parentf7dfd268d6c63662c222d226b835b8f273f9daab (diff)
downloadkernel_samsung_espresso10-b442e52cba6dcffdf5880ca1c2f2625bfc5ee7f2.zip
kernel_samsung_espresso10-b442e52cba6dcffdf5880ca1c2f2625bfc5ee7f2.tar.gz
kernel_samsung_espresso10-b442e52cba6dcffdf5880ca1c2f2625bfc5ee7f2.tar.bz2
OMAP:DSS: Switch HDMI timings and EDID handling to use fbmon
- Change hdmi_timings to fb_videomode that contains the same information and more. - Use fbmon's EDID parser; get monspecs from EDID to get screen dimension. - Simplify EDID handling: hdmi_read_edid only reads EDID from HDMI block hdmi_get_monspecs parses out supported video formats. on hdmi_power_on, always set VGA timings that should always be supported. Change-Id: Ie1ab973f4d8cf0f641a7b19c0959ede2fa9bed56 Signed-off-by: Lajos Molnar <molnar@ti.com>
-rw-r--r--drivers/video/hdmi_ti_4xxx_ip.c18
-rw-r--r--drivers/video/omap2/dss/dispc.c3
-rw-r--r--drivers/video/omap2/dss/dss.h3
-rw-r--r--drivers/video/omap2/dss/hdmi.c593
-rw-r--r--drivers/video/omap2/dss/hdmi_panel.c17
-rw-r--r--drivers/video/omap2/omapfb/Kconfig1
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c35
-rw-r--r--include/linux/omapfb.h5
-rw-r--r--include/video/hdmi_ti_4xxx_ip.h3
-rw-r--r--include/video/omapdss.h7
10 files changed, 393 insertions, 292 deletions
diff --git a/drivers/video/hdmi_ti_4xxx_ip.c b/drivers/video/hdmi_ti_4xxx_ip.c
index 5fbcd58..8cd8526 100644
--- a/drivers/video/hdmi_ti_4xxx_ip.c
+++ b/drivers/video/hdmi_ti_4xxx_ip.c
@@ -28,6 +28,7 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/string.h>
+#include <linux/omapfb.h>
#include "hdmi_ti_4xxx_ip.h"
@@ -658,15 +659,10 @@ static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
{
pr_debug("Enter hdmi_wp_video_init_format\n");
- video_fmt->y_res = param->timings.timings.y_res;
- video_fmt->x_res = param->timings.timings.x_res;
+ video_fmt->y_res = param->timings.yres;
+ video_fmt->x_res = param->timings.xres;
- timings->hbp = param->timings.timings.hbp;
- timings->hfp = param->timings.timings.hfp;
- timings->hsw = param->timings.timings.hsw;
- timings->vbp = param->timings.timings.vbp;
- timings->vfp = param->timings.timings.vfp;
- timings->vsw = param->timings.timings.vsw;
+ omapfb_fb2dss_timings(&param->timings, timings);
}
static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data,
@@ -743,9 +739,9 @@ void hdmi_ti_4xxx_basic_configure(struct hdmi_ip_data *ip_data,
hdmi_wp_video_config_format(ip_data, &video_format);
- video_interface.vsp = cfg->timings.vsync_pol;
- video_interface.hsp = cfg->timings.hsync_pol;
- video_interface.interlacing = cfg->interlace;
+ video_interface.vsp = !!(cfg->timings.sync & FB_SYNC_VERT_HIGH_ACT);
+ video_interface.hsp = !!(cfg->timings.sync & FB_SYNC_HOR_HIGH_ACT);
+ video_interface.interlacing = cfg->timings.vmode & FB_VMODE_INTERLACED;
video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
hdmi_wp_video_config_interface(ip_data, &video_interface);
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index b3d7bc8..d8b3635 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -35,6 +35,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/ratelimit.h>
#include <plat/sram.h>
#include <plat/clock.h>
@@ -3516,7 +3517,7 @@ static void dispc_error_worker(struct work_struct *work)
struct omap_overlay_manager *manager = NULL;
bool enable = false;
- DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
+ pr_err_ratelimited("SYNC_LOST_DIGIT, disabling TV\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
struct omap_overlay_manager *mgr;
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 14acc2b..2953339 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -513,10 +513,13 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
+int omapdss_hdmi_display_set_mode(struct omap_dss_device *dssdev,
+ struct fb_videomode *mode);
int hdmi_panel_hpd_handler(int hpd);
int omapdss_hdmi_get_deepcolor(void);
void omapdss_hdmi_set_deepcolor(int val);
int hdmi_get_current_hpd(void);
+void hdmi_get_monspecs(struct fb_monspecs *specs);
u8 *hdmi_read_edid(struct omap_video_timings *);
int hdmi_panel_init(void);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 52e123a..2d69bd5 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -37,6 +37,8 @@
#include <video/omapdss.h>
#include <video/hdmi_ti_4xxx_ip.h>
#include <linux/gpio.h>
+#include <linux/fb.h>
+#include <linux/omapfb.h>
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
#include <sound/soc.h>
@@ -73,6 +75,7 @@ static struct {
int mode;
u8 edid[HDMI_EDID_MAX_LENGTH];
u8 edid_set;
+
bool custom_set;
enum hdmi_deep_color_mode deep_color;
struct hdmi_config cfg;
@@ -98,77 +101,190 @@ static struct {
* map it to corresponding CEA or VESA index.
*/
-static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = {
- { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0},
- { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1},
- { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1},
- { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0},
- { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0},
- { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0},
- { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0},
- { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1},
- { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1},
- { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1},
- { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0},
- { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0},
- { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1},
- { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0},
- { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1},
- /* VESA From Here */
- { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0},
- { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1},
- { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1},
- { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0},
- { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0},
- { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1},
- { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1},
- { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1},
- { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0},
- { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0},
- { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0},
- { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0},
- { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1},
- { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1},
- { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1},
- { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1},
- { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1},
- { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1},
- { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}
-};
-
-/*
- * This is a static mapping array which maps the timing values
- * with corresponding CEA / VESA code
- */
-static const int code_index[OMAP_HDMI_TIMINGS_NB] = {
- 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32,
- /* <--15 CEA 17--> vesa*/
- 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A,
- 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B
+struct fb_videomode cea_timings[] = {
+ /* 640x480 at 60.00 Hz */
+ [1] = { NULL, 60,
+ 640, 480, 39682, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 720x480 at 60.00 Hz */
+ [2] = { NULL, 60,
+ 720, 480, 37000, 60, 16, 30, 9, 62, 6,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 720x480 at 60.00 Hz */
+ [3] = { NULL, 60,
+ 720, 480, 37000, 60, 16, 30, 9, 62, 6,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 1280x720 at 60.00 Hz */
+ [4] = { NULL, 60,
+ 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1920x540 at 60.05 Hz */
+ [5] = { NULL, 60,
+ 1920, 1080, 13468, 148, 88, 15, 2, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED, },
+ /* 1440x240 at 60.11 Hz */
+ [6] = { NULL, 60,
+ 1440, 480, 37000, 114, 38, 15, 4, 124, 3,
+ 0, FB_VMODE_INTERLACED, },
+ /* 1440x240 at 60.11 Hz */
+ [7] = { NULL, 60,
+ 1440, 480, 37000, 114, 38, 15, 4, 124, 3,
+ 0, FB_VMODE_INTERLACED, },
+ /* 1920x1080 at 60.00 Hz */
+ [16] = { NULL, 60,
+ 1920, 1080, 6734, 148, 88, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 720x576 at 50.00 Hz */
+ [17] = { NULL, 50,
+ 720, 576, 37037, 68, 12, 39, 5, 64, 5,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 720x576 at 50.00 Hz */
+ [18] = { NULL, 50,
+ 720, 576, 37037, 68, 12, 39, 5, 64, 5,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 1280x720 at 50.00 Hz */
+ [19] = { NULL, 50,
+ 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1920x540 at 50.04 Hz */
+ [20] = { NULL, 50,
+ 1920, 1080, 13468, 148, 528, 15, 2, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED, },
+ /* 1440x288 at 50.08 Hz */
+ [21] = { NULL, 50,
+ 1440, 576, 37037, 138, 24, 19, 2, 126, 3,
+ 0, FB_VMODE_INTERLACED, },
+ /* 1440x288 at 50.08 Hz */
+ [22] = { NULL, 50,
+ 1440, 576, 37037, 138, 24, 19, 2, 126, 3,
+ 0, FB_VMODE_INTERLACED, },
+ /* 1440x576 at 50.00 Hz */
+ [29] = { NULL, 50,
+ 1440, 576, 18518, 136, 24, 39, 5, 128, 5,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 1440x576 at 50.00 Hz */
+ [30] = { NULL, 50,
+ 1440, 576, 18518, 136, 24, 39, 5, 128, 5,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 1920x1080 at 50.00 Hz */
+ [31] = { NULL, 50,
+ 1920, 1080, 6734, 148, 528, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1920x1080 at 24.00 Hz */
+ [32] = { NULL, 24,
+ 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 2880x480 at 60.00 Hz */
+ [35] = { NULL, 60,
+ 2880, 480, 9250, 240, 64, 30, 9, 248, 6,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 2880x480 at 60.00 Hz */
+ [36] = { NULL, 60,
+ 2880, 480, 9250, 240, 64, 30, 9, 248, 6,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 2880x576 at 50.00 Hz */
+ [37] = { NULL, 50,
+ 2880, 576, 9259, 272, 48, 39, 5, 256, 5,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 2880x576 at 50.00 Hz */
+ [38] = { NULL, 50,
+ 2880, 576, 9259, 272, 48, 39, 5, 256, 5,
+ 0, FB_VMODE_NONINTERLACED, },
};
-
-/*
- * This is reverse static mapping which maps the CEA / VESA code
- * to the corresponding timing values
- */
-static const int code_cea[39] = {
- -1, 0, 3, 3, 2, 8, 5, 5, -1, -1,
- -1, -1, -1, -1, -1, -1, 9, 10, 10, 1,
- 7, 6, 6, -1, -1, -1, -1, -1, -1, 11,
- 11, 12, 14, -1, -1, 13, 13, 4, 4
+struct fb_videomode vesa_timings[] = {
+ /* 640x480 at 60.05 Hz */
+ [4] = { NULL, 60,
+ 640, 480, 39721, 48, 16, 31, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 800x600 at 60.32 Hz */
+ [9] = { NULL, 60,
+ 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 848x480 at 60.00 Hz */
+ [14] = { NULL, 60,
+ 848, 480, 29629, 112, 16, 23, 6, 112, 8,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1024x768 at 60.00 Hz */
+ [16] = { NULL, 60,
+ 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED, },
+ /* 1280x768 at 59.99 Hz */
+ [22] = { NULL, 59,
+ 1280, 768, 14652, 80, 48, 12, 3, 32, 7,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1280x768 at 59.87 Hz */
+ [23] = { NULL, 59,
+ 1280, 768, 12578, 192, 64, 20, 3, 128, 7,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1280x800 at 67.08 Hz */
+ [27] = { NULL, 67,
+ 1280, 800, 12578, 80, 48, 14, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1280x800 at 59.81 Hz */
+ [28] = { NULL, 59,
+ 1280, 800, 11976, 200, 72, 22, 3, 128, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1280x960 at 60.00 Hz */
+ [32] = { NULL, 60,
+ 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1280x1024 at 60.02 Hz */
+ [35] = { NULL, 60,
+ 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1360x768 at 60.02 Hz */
+ [39] = { NULL, 60,
+ 1360, 768, 11695, 256, 64, 18, 3, 112, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1400x1050 at 59.95 Hz */
+ [41] = { NULL, 59,
+ 1400, 1050, 9900, 80, 48, 23, 3, 32, 4,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1400x1050 at 59.98 Hz */
+ [42] = { NULL, 59,
+ 1400, 1050, 8213, 232, 88, 32, 3, 144, 4,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1440x900 at 59.89 Hz */
+ [47] = { NULL, 59,
+ 1440, 900, 9389, 232, 80, 25, 3, 152, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1680x1050 at 59.88 Hz */
+ [57] = { NULL, 59,
+ 1680, 1050, 8403, 80, 48, 21, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1680x1050 at 59.95 Hz */
+ [58] = { NULL, 59,
+ 1680, 1050, 6837, 280, 104, 30, 3, 176, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, },
+ /* 1366x768 at 59.79 Hz */
+ [81] = { NULL, 59,
+ 1366, 768, 11695, 213, 70, 24, 3, 143, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1920x1080 at 60.22 Hz */
+ [82] = { NULL, 60,
+ 1920, 1080, 6734, 80, 148, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
+ /* 1280x720 at 60.00 Hz */
+ [84] = { NULL, 60,
+ 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, },
};
-static const int code_vesa[85] = {
- -1, -1, -1, -1, 15, -1, -1, -1, -1, 16,
- -1, -1, -1, -1, 17, -1, 23, -1, -1, -1,
- -1, -1, 29, 18, -1, -1, -1, 32, 19, -1,
- -1, -1, 21, -1, -1, 22, -1, -1, -1, 20,
- -1, 30, 24, -1, -1, -1, -1, 25, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 31, 26, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 27, 28, -1, 33};
-
static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0};
static int hdmi_runtime_get(void)
@@ -232,178 +348,116 @@ int hdmi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static void copy_hdmi_to_dss_timings(struct hdmi_video_timings hdmi_timings,
- struct omap_video_timings *timings)
+static int relaxed_fb_mode_is_equal(const struct fb_videomode *mode1,
+ const struct fb_videomode *mode2)
{
- timings->x_res = hdmi_timings.x_res;
- timings->y_res = hdmi_timings.y_res;
- timings->pixel_clock = hdmi_timings.pixel_clock;
- timings->hbp = hdmi_timings.hbp;
- timings->hfp = hdmi_timings.hfp;
- timings->hsw = hdmi_timings.hsw;
- timings->vbp = hdmi_timings.vbp;
- timings->vfp = hdmi_timings.vfp;
- timings->vsw = hdmi_timings.vsw;
+ return (mode1->xres == mode2->xres &&
+ mode1->yres == mode2->yres &&
+ mode1->pixclock <= mode2->pixclock + 1 &&
+ mode1->pixclock >= mode2->pixclock - 1 &&
+ mode1->hsync_len + mode1->left_margin + mode1->right_margin ==
+ mode2->hsync_len + mode2->left_margin + mode2->right_margin &&
+ mode1->vsync_len + mode1->upper_margin + mode1->lower_margin ==
+ mode2->vsync_len + mode2->upper_margin + mode2->lower_margin &&
+ (mode1->vmode & FB_VMODE_INTERLACED) ==
+ (mode2->vmode & FB_VMODE_INTERLACED));
}
-static int get_timings_index(void)
+static int hdmi_set_timings(const struct fb_videomode *vm, bool check_only)
{
- int code;
-
- if (hdmi.mode == 0)
- code = code_vesa[hdmi.code];
- else
- code = code_cea[hdmi.code];
-
- if (code == -1) {
- /* HDMI code 4 corresponds to 640 * 480 VGA */
- hdmi.code = 4;
- /* DVI mode 1 corresponds to HDMI 0 to DVI */
- hdmi.mode = HDMI_DVI;
+ int i = 0;
+ DSSDBG("hdmi_get_code\n");
- code = code_vesa[hdmi.code];
+ if (!vm->xres || !vm->yres || !vm->pixclock)
+ goto fail;
+
+ for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
+ if (relaxed_fb_mode_is_equal(cea_timings + i, vm)) {
+ if (check_only)
+ return 1;
+ hdmi.cfg.cm.code = i;
+ hdmi.cfg.cm.mode = HDMI_HDMI;
+ hdmi.cfg.timings = cea_timings[hdmi.cfg.cm.code];
+ goto done;
+ }
}
- return code;
-}
-static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
-{
- int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0;
- int timing_vsync = 0, timing_hsync = 0;
- struct hdmi_video_timings temp;
- struct hdmi_cm cm = {-1};
- DSSDBG("hdmi_get_code\n");
-
- for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) {
- temp = cea_vesa_timings[i].timings;
- if ((temp.pixel_clock == timing->pixel_clock) &&
- (temp.x_res == timing->x_res) &&
- (temp.y_res == timing->y_res)) {
-
- temp_hsync = temp.hfp + temp.hsw + temp.hbp;
- timing_hsync = timing->hfp + timing->hsw + timing->hbp;
- temp_vsync = temp.vfp + temp.vsw + temp.vbp;
- timing_vsync = timing->vfp + timing->vsw + timing->vbp;
-
- DSSDBG("temp_hsync = %d , temp_vsync = %d"
- "timing_hsync = %d, timing_vsync = %d\n",
- temp_hsync, temp_hsync,
- timing_hsync, timing_vsync);
-
- if ((temp_hsync == timing_hsync) &&
- (temp_vsync == timing_vsync)) {
- code = i;
- cm.code = code_index[i];
- if (code < 14)
- cm.mode = HDMI_HDMI;
- else
- cm.mode = HDMI_DVI;
- DSSDBG("Hdmi_code = %d mode = %d\n",
- cm.code, cm.mode);
- break;
- }
+ for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
+ if (relaxed_fb_mode_is_equal(vesa_timings + i, vm)) {
+ if (check_only)
+ return 1;
+ hdmi.cfg.cm.code = i;
+ hdmi.cfg.cm.mode = HDMI_DVI;
+ hdmi.cfg.timings = vesa_timings[hdmi.cfg.cm.code];
+ goto done;
+ }
+ }
+#if 0
+ for (i = 0; i < sizeof(cea_modes); i++) {
+ if (relaxed_fb_mode_is_equal(cea_modes + i, vm)) {
+ if (check_only)
+ return 1;
+ hdmi.cfg.cm.code = i;
+ hdmi.cfg.cm.mode = HDMI_HDMI;
+ hdmi.cfg.timings = cea_modes[hdmi.cfg.cm.code];
+ goto done;
}
}
- return cm;
+ for (i = 0; i < 34; i++) {
+ if (relaxed_fb_mode_is_equal(vesa_modes + i, vm)) {
+ if (check_only)
+ return 1;
+ hdmi.cfg.cm.code = i;
+ hdmi.cfg.cm.mode = HDMI_DVI;
+ hdmi.cfg.timings = vesa_modes[hdmi.cfg.cm.code];
+ goto done;
+ }
+ }
+#endif
+fail:
+ if (check_only)
+ return 0;
+ hdmi.cfg.cm.code = 1;
+ hdmi.cfg.cm.mode = HDMI_HDMI;
+ hdmi.cfg.timings = cea_timings[hdmi.cfg.cm.code];
+
+ i = -1;
+done:
+
+ DSSDBG("%s-%d\n", hdmi.cfg.cm.mode ? "CEA" : "VESA", hdmi.cfg.cm.code);
+ return i >= 0;
}
-static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid ,
- struct omap_video_timings *timings)
+void hdmi_get_monspecs(struct fb_monspecs *specs)
{
- /* X and Y resolution */
- timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) |
- edid[current_descriptor_addrs + 2]);
- timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) |
- edid[current_descriptor_addrs + 5]);
-
- timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) |
- edid[current_descriptor_addrs]);
-
- timings->pixel_clock = 10 * timings->pixel_clock;
-
- /* HORIZONTAL FRONT PORCH */
- timings->hfp = edid[current_descriptor_addrs + 8] |
- ((edid[current_descriptor_addrs + 11] & 0xc0) << 2);
- /* HORIZONTAL SYNC WIDTH */
- timings->hsw = edid[current_descriptor_addrs + 9] |
- ((edid[current_descriptor_addrs + 11] & 0x30) << 4);
- /* HORIZONTAL BACK PORCH */
- timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) |
- edid[current_descriptor_addrs + 3]) -
- (timings->hfp + timings->hsw);
- /* VERTICAL FRONT PORCH */
- timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) |
- ((edid[current_descriptor_addrs + 11] & 0x0f) << 2);
- /* VERTICAL SYNC WIDTH */
- timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) |
- ((edid[current_descriptor_addrs + 11] & 0x03) << 4);
- /* VERTICAL BACK PORCH */
- timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) |
- edid[current_descriptor_addrs + 6]) -
- (timings->vfp + timings->vsw);
+ int i, j;
+ char *edid = (char *) hdmi.edid;
-}
+ memset(specs, 0x0, sizeof(*specs));
+ if (!hdmi.edid_set)
+ 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;
- }
- }
+ fb_edid_to_monspecs(edid, specs);
+ if (specs->modedb == NULL)
+ return;
+
+ for (i = 1; i <= edid[0x7e] && i * 128 < HDMI_EDID_MAX_LENGTH; i++) {
+ if (edid[i * 128] == 0x2)
+ fb_edid_add_monspecs(edid + i * 128, specs);
}
- DSSINFO("no valid timing found , falling back to VGA\n");
- hdmi.code = 4; /* setting default value of 640 480 VGA */
- hdmi.mode = HDMI_DVI;
+ /* filter out resolutions we don't support */
+ for (i = j = 0; i < specs->modedb_len; i++) {
+ if (hdmi_set_timings(&specs->modedb[i], true))
+ specs->modedb[j++] = specs->modedb[i];
+ }
+ specs->modedb_len = j;
}
u8 *hdmi_read_edid(struct omap_video_timings *dp)
{
- int ret = 0, code, i;
+ int ret = 0, i;
memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
@@ -412,7 +466,7 @@ u8 *hdmi_read_edid(struct omap_video_timings *dp)
HDMI_EDID_MAX_LENGTH);
for (i = 0; i < 256; i += 16)
- pr_debug("edid[%03x] = %02x %02x %02x %02x %02x %02x %02x %02x "
+ pr_info("edid[%03x] = %02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
hdmi.edid[i], hdmi.edid[i + 1], hdmi.edid[i + 2],
hdmi.edid[i + 3], hdmi.edid[i + 4], hdmi.edid[i + 5],
@@ -421,44 +475,16 @@ u8 *hdmi_read_edid(struct omap_video_timings *dp)
hdmi.edid[i + 12], hdmi.edid[i + 13], hdmi.edid[i + 14],
hdmi.edid[i + 15]);
- 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 {
+ if (ret) {
DSSWARN("failed to read E-EDID\n");
- ret = -EINVAL;
- }
-
- if (!hdmi.edid_set) {
- DSSINFO("fallback to VGA\n");
- hdmi.code = 4; /* setting default value of 640 480 VGA */
- hdmi.mode = HDMI_DVI;
+ return NULL;
}
- code = get_timings_index();
+ if (memcmp(hdmi.edid, edid_header, sizeof(edid_header)))
+ return NULL;
- copy_hdmi_to_dss_timings(cea_vesa_timings[code].timings, dp);
-
- return ret ? NULL : hdmi.edid;
-}
-
-static void update_hdmi_timings(struct hdmi_config *cfg,
- struct omap_video_timings *timings, int code)
-{
- cfg->timings.timings.x_res = timings->x_res;
- cfg->timings.timings.y_res = timings->y_res;
- cfg->timings.timings.hbp = timings->hbp;
- cfg->timings.timings.hfp = timings->hfp;
- cfg->timings.timings.hsw = timings->hsw;
- cfg->timings.timings.vbp = timings->vbp;
- cfg->timings.timings.vfp = timings->vfp;
- cfg->timings.timings.vsw = timings->vsw;
- cfg->timings.timings.pixel_clock = timings->pixel_clock;
- cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol;
- cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
+ hdmi.edid_set = true;
+ return hdmi.edid;
}
static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
@@ -503,7 +529,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
- int r, code = 0;
+ int r;
struct hdmi_pll_info pll_data;
struct omap_video_timings *p;
unsigned long phy;
@@ -522,16 +548,10 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
- if (!hdmi.custom_set) {
- DSSDBG("Read EDID as no EDID is not set on poweron\n");
-
- hdmi_read_edid(p);
- }
- code = get_timings_index();
- copy_hdmi_to_dss_timings(cea_vesa_timings[code].timings,
- &dssdev->panel.timings);
+ if (!hdmi.custom_set)
+ hdmi_set_timings(&vesa_timings[4], false);
- update_hdmi_timings(&hdmi.cfg, p, code);
+ omapfb_fb2dss_timings(&hdmi.cfg.timings, &dssdev->panel.timings);
phy = p->pixel_clock;
@@ -643,30 +663,47 @@ static irqreturn_t hpd_irq_handler(int irq, void *ptr)
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- struct hdmi_cm cm;
+ struct fb_videomode t;
- cm = hdmi_get_code(timings);
- if (cm.code == -1) {
- DSSERR("Invalid timing entered\n");
- return -EINVAL;
- }
+ omapfb_dss2fb_timings(timings, &t);
+ /* also check interlaced timings */
+ if (!hdmi_set_timings(&t, true)) {
+ t.yres *= 2;
+ t.vmode |= FB_VMODE_INTERLACED;
+ }
+ if (!hdmi_set_timings(&t, true))
+ return -EINVAL;
return 0;
-
}
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+int omapdss_hdmi_display_set_mode(struct omap_dss_device *dssdev,
+ struct fb_videomode *vm)
{
- struct hdmi_cm cm;
-
+ int r1, r2;
hdmi.custom_set = 1;
- cm = hdmi_get_code(&dssdev->panel.timings);
/* turn the hdmi off and on to get new timings to use */
omapdss_hdmi_display_disable(dssdev);
- hdmi.code = cm.code;
- hdmi.mode = cm.mode;
- omapdss_hdmi_display_enable(dssdev);
+ r1 = hdmi_set_timings(vm, false) ? 0 : -EINVAL;
+ hdmi.code = hdmi.cfg.cm.code;
+ hdmi.mode = hdmi.cfg.cm.mode;
+ r2 = omapdss_hdmi_display_enable(dssdev);
hdmi.custom_set = 0;
+ return r1 ? : r2;
+}
+
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+{
+ struct fb_videomode t;
+
+ omapfb_dss2fb_timings(&dssdev->panel.timings, &t);
+ /* also check interlaced timings */
+ if (!hdmi_set_timings(&t, true)) {
+ t.yres *= 2;
+ t.vmode |= FB_VMODE_INTERLACED;
+ }
+
+ omapdss_hdmi_display_set_mode(dssdev, &t);
}
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index aafe636..d609c37 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -202,6 +202,11 @@ static void hdmi_hotplug_detect_worker(struct work_struct *work)
if (state == HPD_STATE_START) {
dssdev->driver->enable(dssdev);
} else if (hdmi_read_edid(&dssdev->panel.timings)) {
+ /* get monspecs from edid */
+ hdmi_get_monspecs(&dssdev->panel.monspecs);
+ pr_info("panel size %d by %d\n",
+ dssdev->panel.monspecs.max_x,
+ dssdev->panel.monspecs.max_y);
switch_set_state(&hdmi.hpd_switch, 1);
return;
} else if (state == HPD_STATE_EDID_TRYLAST){
@@ -265,6 +270,16 @@ err:
return r;
}
+static int hdmi_get_modedb(struct omap_dss_device *dssdev,
+ struct fb_videomode *modedb, int modedb_len)
+{
+ struct fb_monspecs *specs = &dssdev->panel.monspecs;
+ if (specs->modedb_len < modedb_len)
+ modedb_len = specs->modedb_len;
+ memcpy(modedb, specs->modedb, sizeof(*modedb) * modedb_len);
+ return modedb_len;
+}
+
static struct omap_dss_driver hdmi_driver = {
.probe = hdmi_panel_probe,
.remove = hdmi_panel_remove,
@@ -275,6 +290,8 @@ static struct omap_dss_driver hdmi_driver = {
.get_timings = hdmi_get_timings,
.set_timings = hdmi_set_timings,
.check_timings = hdmi_check_timings,
+ .get_modedb = hdmi_get_modedb,
+ .set_mode = omapdss_hdmi_display_set_mode,
.driver = {
.name = "hdmi_panel",
.owner = THIS_MODULE,
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index aa33386..d15486e 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -7,6 +7,7 @@ menuconfig FB_OMAP2
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
help
Frame buffer driver for OMAP2+ based boards.
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 5317d5e..2bd0c9a 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1020,6 +1020,41 @@ static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
return r;
}
+void omapfb_fb2dss_timings(struct fb_videomode *fb_timings,
+ struct omap_video_timings *dss_timings)
+{
+ dss_timings->x_res = fb_timings->xres;
+ dss_timings->y_res = fb_timings->yres;
+ if (fb_timings->vmode & FB_VMODE_INTERLACED)
+ dss_timings->y_res /= 2;
+ dss_timings->pixel_clock = fb_timings->pixclock ?
+ PICOS2KHZ(fb_timings->pixclock) : 0;
+ dss_timings->hfp = fb_timings->right_margin;
+ dss_timings->hbp = fb_timings->left_margin;
+ dss_timings->hsw = fb_timings->hsync_len;
+ dss_timings->vfp = fb_timings->lower_margin;
+ dss_timings->vbp = fb_timings->upper_margin;
+ dss_timings->vsw = fb_timings->vsync_len;
+}
+EXPORT_SYMBOL(omapfb_fb2dss_timings);
+
+void omapfb_dss2fb_timings(struct omap_video_timings *dss_timings,
+ struct fb_videomode *fb_timings)
+{
+ memset(fb_timings, 0, sizeof(*fb_timings));
+ fb_timings->xres = dss_timings->x_res;
+ fb_timings->yres = dss_timings->y_res;
+ fb_timings->pixclock = dss_timings->pixel_clock ?
+ KHZ2PICOS(dss_timings->pixel_clock) : 0;
+ fb_timings->right_margin = dss_timings->hfp;
+ fb_timings->left_margin = dss_timings->hbp;
+ fb_timings->hsync_len = dss_timings->hsw;
+ fb_timings->lower_margin = dss_timings->vfp;
+ fb_timings->upper_margin = dss_timings->vbp;
+ fb_timings->vsync_len = dss_timings->vsw;
+}
+EXPORT_SYMBOL(omapfb_dss2fb_timings);
+
/* set the video mode according to info->var */
static int omapfb_set_par(struct fb_info *fbi)
{
diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
index c744e93..f12501d 100644
--- a/include/linux/omapfb.h
+++ b/include/linux/omapfb.h
@@ -260,8 +260,13 @@ extern void omapfb_reserve_sdram_memblock(void);
/* helper methods that may be used by other modules */
enum omap_color_mode;
+struct omap_video_timings;
int omapfb_mode_to_dss_mode(struct fb_var_screeninfo *var,
enum omap_color_mode *mode);
+void omapfb_fb2dss_timings(struct fb_videomode *fb_timings,
+ struct omap_video_timings *dss_timings);
+void omapfb_dss2fb_timings(struct omap_video_timings *dss_timings,
+ struct fb_videomode *fb_timings);
#endif
diff --git a/include/video/hdmi_ti_4xxx_ip.h b/include/video/hdmi_ti_4xxx_ip.h
index cb7f5d8..68af674 100644
--- a/include/video/hdmi_ti_4xxx_ip.h
+++ b/include/video/hdmi_ti_4xxx_ip.h
@@ -73,8 +73,7 @@ struct hdmi_cm {
};
struct hdmi_config {
- struct hdmi_timings timings;
- u16 interlace;
+ struct fb_videomode timings;
struct hdmi_cm cm;
enum hdmi_deep_color_mode deep_color;
};
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 7b0dabe..daa0e73 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -21,6 +21,7 @@
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/device.h>
+#include <linux/fb.h>
#define DISPC_IRQ_FRAMEDONE (1 << 0)
#define DISPC_IRQ_VSYNC (1 << 1)
@@ -545,6 +546,7 @@ struct omap_dss_device {
int acb; /* ac-bias pin frequency */
enum omap_panel_config config;
+ struct fb_monspecs monspecs;
} panel;
struct {
@@ -632,6 +634,11 @@ struct omap_dss_driver {
int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
u32 (*get_wss)(struct omap_dss_device *dssdev);
+ int (*get_modedb)(struct omap_dss_device *dssdev,
+ struct fb_videomode *modedb,
+ int modedb_len);
+ int (*set_mode)(struct omap_dss_device *dssdev,
+ struct fb_videomode *mode);
/* for wrapping around state changes */
void (*disable_orig)(struct omap_dss_device *display);