Support for SII9022 transmitter

EDID updates for EDID 1.3, HDMI and CEA data
This commit is contained in:
Matt Sealey
2010-08-14 12:35:09 -05:00
parent 7fa0618862
commit 4a227175d3
6 changed files with 146 additions and 38 deletions

View File

@@ -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 ]

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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"

View File

@@ -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

View File

@@ -48,6 +48,24 @@
#include <asm/uaccess.h>
#include <mach/hardware.h>
#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);