diff --git a/drivers/video/edid.h b/drivers/video/edid.h index bd89fb3be8c..29361c0e616 100644 --- a/drivers/video/edid.h +++ b/drivers/video/edid.h @@ -47,6 +47,7 @@ #define STD_TIMING_DESCRIPTIONS_START 0x26 #define DETAILED_TIMING_DESCRIPTIONS_START 0x36 +#define DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START 0x80 #define DETAILED_TIMING_DESCRIPTION_SIZE 18 #define NO_DETAILED_TIMING_DESCRIPTIONS 4 @@ -101,8 +102,8 @@ #define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO ) #define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO ) -#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) -#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) +#define H_SYNC_WIDTH COMBINE_HI_8LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) +#define H_SYNC_OFFSET COMBINE_HI_8LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) #define H_SIZE_LO (unsigned)block[ 12 ] #define V_SIZE_LO (unsigned)block[ 13 ] diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 9ae9cd32bd0..54d05f1ce4b 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -40,7 +40,8 @@ * EDID parser */ -#undef DEBUG /* define this for verbose EDID parsing output */ +//#undef DEBUG /* define this for verbose EDID parsing output */ +#define DEBUG 1 #ifdef DEBUG #define DPRINTK(fmt, args...) printk(fmt,## args) @@ -492,18 +493,25 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) return num; } -static int get_std_timing(unsigned char *block, struct fb_videomode *mode) +static int get_std_timing(u8 edid_ver, u8 edid_rev, unsigned char *block, struct fb_videomode *mode) { int xres, yres = 0, refresh, ratio, i; + if( edid_ver < 1 || (edid_ver == 1 && edid_rev < 3 ) ) xres = (block[0] + 31) * 8; + else + xres = (block[0] * 8) + 248; /* edid v1.3 */ + if (xres <= 256) return 0; ratio = (block[1] & 0xc0) >> 6; switch (ratio) { - case 0: + case 0: /* aspect ratio 16:10 in v1.3, ratio 1:1 prior to v1.3 */ + if( edid_ver < 1 || (edid_ver == 1 && edid_rev < 3 ) ) yres = xres; + else + yres = (xres *10)/16; break; case 1: yres = (xres * 3)/4; @@ -531,13 +539,13 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode) return 1; } -static int get_dst_timing(unsigned char *block, +static int get_dst_timing(u8 edid_ver, u8 edid_rev, unsigned char *block, struct fb_videomode *mode) { int j, num = 0; for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) - num += get_std_timing(block, &mode[num]); + num += get_std_timing(edid_ver, edid_rev, block, &mode[num]); return num; } @@ -573,13 +581,21 @@ static void get_detailed_timing(unsigned char *block, } mode->flag = FB_MODE_IS_DETAILED; - DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); - DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, - H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); - DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, - V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); - DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", - (VSYNC_POSITIVE) ? "+" : "-"); + DPRINTK(" \"%dx%d%s%d\" %d ", + mode->xres, mode->yres, INTERLACED ? "i@" : "@", mode->refresh, + PIXEL_CLOCK/1000000); + DPRINTK("%d %d %d %d ", + mode->xres, + mode->xres + mode->right_margin, + mode->xres + mode->right_margin + mode->hsync_len, + mode->xres + mode->right_margin + mode->hsync_len + mode->left_margin ); + DPRINTK("%d %d %d %d ", + mode->yres, + mode->yres + mode->lower_margin, + mode->yres + mode->lower_margin + mode->vsync_len, + mode->yres + mode->lower_margin + mode->vsync_len + mode->upper_margin ); + DPRINTK("%shsync %svsync\n", (HSYNC_POSITIVE) ? "+" : "-", + (VSYNC_POSITIVE) ? "+" : "-" ); } /** @@ -599,6 +615,9 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) unsigned char *block; int num = 0, i, first = 1; + int offset = 0; + u8 edid_ver = 0, edid_rev = 0; + mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); if (mode == NULL) return NULL; @@ -611,6 +630,9 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) *dbsize = 0; + edid_ver = edid[EDID_STRUCT_VERSION]; + edid_rev = edid[EDID_STRUCT_REVISION]; + DPRINTK(" Detailed Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { @@ -631,12 +653,43 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) DPRINTK(" Standard Timings\n"); block = edid + STD_TIMING_DESCRIPTIONS_START; for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) - num += get_std_timing(block, &mode[num]); + num += get_std_timing(edid_ver, edid_rev, block, &mode[num]); + DPRINTK(" Detail Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) - num += get_dst_timing(block + 5, &mode[num]); + num += get_dst_timing(edid_ver, edid_rev, block + 5, &mode[num]); + } + + /* how many additional extension blocks available */ + if (edid[126] > 0 ) { + if (edid[DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START] == 0x02) { + /* This block is CEA extension */ + DPRINTK("----------------------------------------\n"); + DPRINTK(" EIA/CEA-861 Information\n"); + DPRINTK(" Revision number: %d\n", + edid[DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START+1] ); + DPRINTK(" DTV underscan: %s\n", + (edid[DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START+3] & 0x80 ) ? + "Supported" : "Not supported"); + DPRINTK(" Basic audio: %s\n", + (edid[DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START+3] & 0x40 ) ? + "Supported" : "Not supported"); + + offset = edid[DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START + 2]; + if (offset > 0) { + block = edid + DETAILED_TIMING_DESCRIPTIONS_BLOCK1_START + offset; + + DPRINTK(" Detailed Timings\n"); + for (i = 0; i < 5; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + if (!(block[0] == 0x00 && block[1] == 0x00)) { + get_detailed_timing(block, &mode[num]); + num++; + } + } + } + } } /* Yikes, EDID data is totally useless */ diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 34e4e799516..070d2869f57 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -264,12 +264,24 @@ static const struct fb_videomode modedb[] = { /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0, FB_VMODE_NONINTERLACED - }, { - /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + }, + { /* 1280x720 @ 60 CEA-MODE 4 */ + "1280x720-16@60", 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + { /* 1280x720 @ 50 Hz CEA-MODE 19 */ + "1280x720-16@50", 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + { /* 1280x768, 60Hz, 68.26MHz */ + "1280x768-16@60", 60, 1280, 768, 14650, 80, 48, 12, 3, 32, 7, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + { /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0, FB_VMODE_INTERLACED - }, { - /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + }, + { /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0, FB_VMODE_INTERLACED }, @@ -402,19 +414,17 @@ const struct fb_videomode vesa_modes[] = { EXPORT_SYMBOL(vesa_modes); #endif /* CONFIG_FB_MODE_HELPERS */ -static int my_atoi(const char *name) +int fb_dump_mode( char *func_char, struct fb_videomode *mode) { - int val = 0; + printk( KERN_INFO "%s geometry %u %u %u\n", + func_char, mode->xres, mode->yres, mode->pixclock); + printk( KERN_INFO "%s timings %u %u %u %u %u %u %u\n", + func_char, mode->pixclock, mode->left_margin, mode->right_margin, + mode->upper_margin, mode->lower_margin, mode->hsync_len, mode->vsync_len ); + printk( KERN_INFO "%s flag %u sync %u vmode %u\n", + func_char, mode->flag, mode->sync, mode->vmode ); - for (;; name++) { - switch (*name) { - case '0' ... '9': - val = 10*val+(*name-'0'); - break; - default: - return val; - } - } + return 0; } /** @@ -525,6 +535,9 @@ int fb_find_mode(struct fb_var_screeninfo *var, /* Did the user specify a video mode? */ if (!mode_option) mode_option = fb_mode_option; + + printk(KERN_INFO "mode_option=%s\n", mode_option); + if (mode_option) { const char *name = mode_option; unsigned int namelen = strlen(name); @@ -539,7 +552,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, namelen = i; if (!refresh_specified && !bpp_specified && !yres_specified) { - refresh = my_atoi(&name[i+1]); + refresh = simple_strtol(&name[i+1], NULL, 10); refresh_specified = 1; if (cvt || rb) cvt = 0; @@ -549,7 +562,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, case '-': namelen = i; if (!bpp_specified && !yres_specified) { - bpp = my_atoi(&name[i+1]); + bpp = simple_strtol(&name[i+1], NULL, 10); bpp_specified = 1; if (cvt || rb) cvt = 0; @@ -558,7 +571,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, break; case 'x': if (!yres_specified) { - yres = my_atoi(&name[i+1]); + yres = simple_strtol(&name[i+1], NULL, 10); yres_specified = 1; } else goto done; @@ -585,11 +598,12 @@ int fb_find_mode(struct fb_var_screeninfo *var, goto done; } } + if (i < 0 && yres_specified) { - xres = my_atoi(name); + xres = simple_strtol(name, NULL, 10); res_specified = 1; } -done: + done: if (cvt) { struct fb_videomode cvt_mode; int ret; @@ -609,8 +623,8 @@ done: else cvt_mode.vmode &= ~FB_VMODE_INTERLACED; - ret = fb_find_mode_cvt(&cvt_mode, margins, rb); - + ret = fb_find_mode_cvt(&cvt_mode, margins, rb); + if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) { DPRINTK("modedb CVT: CVT mode ok\n"); return 1; diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig index 66a7f84c565..424c6b826ef 100644 --- a/drivers/video/mxc/Kconfig +++ b/drivers/video/mxc/Kconfig @@ -38,6 +38,10 @@ config FB_MXC_CLAA_WVGA_SYNC_PANEL depends on FB_MXC_SYNC_PANEL tristate "CLAA WVGA Panel" +config FB_MXC_SII9022 + depends on FB_MXC_SYNC_PANEL + tristate "SII9022A HDMI Interface Chip" + config FB_MXC_CH7026 depends on FB_MXC_SYNC_PANEL tristate "Chrontel CH7026 VGA Interface Chip" diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile index c428bb95a94..170afd836ab 100644 --- a/drivers/video/mxc/Makefile +++ b/drivers/video/mxc/Makefile @@ -20,5 +20,6 @@ obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o obj-$(CONFIG_FB_MXC_LDB) += ldb.o obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o #obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o +obj-$(CONFIG_FB_MXC_SII9022) += mxcfb_sii9022.o obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o obj-$(CONFIG_FB_MXC_ELCDIF_FB) += mxc_elcdif_fb.o diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index 1cdb55d899f..f8a349a17db 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -48,6 +48,24 @@ #include #include +#if defined(CONFIG_MACH_MX51_EFIKAMX) + +#include <../arch/arm/mach-mx5/mx51_efikamx.h> + +#ifndef dev_dbg +#define dev_dbg(dev, format, arg...) \ + dev_printk(KERN_INFO , dev , format , ## arg) +#endif + +extern int mxc_debug; +extern int clock_auto; +extern int extsync; +extern int pixclk_limit; +extern void mxcfb_adjust(struct fb_var_screeninfo *var ); +#endif + + + /* * Driver name */ @@ -147,6 +165,19 @@ static int mxcfb_set_fix(struct fb_info *info) fix->xpanstep = 1; fix->ypanstep = 1; +#if defined(CONFIG_MACH_MX51_EFIKAMX) + if( clock_auto && extsync ) { + if ( var->pixclock < pixclk_limit ) { + printk(KERN_INFO "exceed pixel clock limit %d, auto adjust to 720p\n", pixclk_limit ); + fb_find_mode( var, info, "1280x720-24@60", NULL, 0, NULL, 0 ); + } + var->sync |= FB_SYNC_EXT; /* x window need it otherwise refresh rate will become bigger than user specified */ + } + /* skip mxc_sdc_fb.2 (overlay) configure */ + if ( ((struct mxcfb_info *)info->par)->ipu_ch != MEM_FG_SYNC) + mxcfb_adjust( var ); +#endif + return 0; } @@ -1677,7 +1708,11 @@ static int mxcfb_probe(struct platform_device *pdev) mxcfb_check_var(&fbi->var, fbi); /* Default Y virtual size is 2x panel size */ +#if defined(CONFIG_MACH_MX51_EFIKAMX) + fbi->var.yres_virtual = fbi->var.yres * 2; +#else fbi->var.yres_virtual = fbi->var.yres * 3; +#endif mxcfb_set_fix(fbi);