|
From: Antonino D. <ad...@po...> - 2002-03-08 06:54:36
|
Hi,
I was actually wondering how feasible it is to implement the GTF in the
framebuffer. The fb timings are in table format, and aside from that,
most drivers utilize timing tables which can really take a toll on
kernel resources. With GTF, you can have just have a small code that
given xres, yres, and one of the three: hsync, vrefresh, or pixelclock,
video timings can be generated. Another advantage is that it can also
generate non-discrete timings.
I've inserted code in modedb.c that really does not do anything but fill
an fb_videomode structure with all the values, given xres, yres, and
vrefresh, then prints the result. A lot of default values I've fixed as
#defines and they are based on US specs. They can probably be changed
through EDID/DDC, or as user-entered info.
The GTF with the default numbers seems to be acceptable for my display,
and also to some people who were willing to test the fb driver I'm
writing.
I'm not sure how universal/applicable/feasible this is, so I'd rather
ask this list for comments.
Thanks
Tony
I have these results for 640x480 @ 60Hz, and 800x600 @ 85Hz
#----------------------------------------------------------------------
Console: switching to colour frame buffer device 128x48
VESA GTF:
640x480 @ 60Hz
pixclock : 43103
left margin : 16
right margin: 80
upper margin: 1
lower margin: 13
hsync len : 64
vsync len : 3
VESA GTF:
800x600 @ 85Hz
pixclock : 17867
left margin : 40
right margin: 128
upper margin: 1
lower margin: 26
hsync len : 88
vsync len : 3
#---------------------------------------------------------------------------
Here's part of the output from the GTF spreadsheet (800x600 @ 85Hz) that
I've found in an FTP site. The numbers do corresponde but precision may be lost
especially for pixclock. Also, I haven't checked for all possible modes yet.
#----------------------------------------------------------------------------
THE VESA GENERALIZED TIMING FORMULA (GTF)
GTF SPREADSHEET BY ANDY MORRISH 1/5/97
HOR PIXELS 800PIXELS
VER PIXELS 600LINES
HOR FREQUENCY 53.550 kHz
VER FREQUENCY 85.000 Hz
PIXEL CLOCK 56.549 MHz 1 PIXELS
CHARACTER WIDTH 141.471 ns 8 PIXELS
SCAN TYPE NON-INT
PREDICTED H BLANK DUTY CYCLE 24.398 %
(from blanking formula)
HOR TOTAL TIME 18.674 us 132 CHARS
HOR ADDR TIME 14.147 us 100 CHARS
HOR BLANK TIME 4.527 us 32 CHARS
HOR BLANK+MARGIN TIME 4.527 us 32 CHARS
ACTUAL HOR BLANK DUTY CYCLE 24.242 %
ACT. HOR BLNK+MARGIN DUTY CYCLE 24.242 %
H LEFT MARGIN 0.000 us 0 CHARS
H FRONT PORCH 0.707 us 5 CHARS
HOR SYNC TIME 1.556 us 11 CHARS
H BACK PORCH 2.264 us 16 CHARS
H RIGHT MARGIN 0.000 us 0 CHARS
VER TOTAL TIME 11.765 ms 630.0 LINES
VER ADDR TIME 11.204 ms 600.0 LINES
VER BLANK TIME 0.560 ms 30.0 LINES
V TOP MARGIN 0.000 us 0.0 LINES
V FRONT PORCH 18.674 us 1.0 LINES
VER SYNC TIME 56.022 us 3.0 LINES
V BACK PORCH 485.528 us 26.0 LINES
V BOTTOM MARGIN 0.000 us 0.0 LINES
COMMENT: GTF Version1 Rev 1.0 Andy Morrish National Semiconductor 1/5/97
#--------------------------------------------------------------------------------------
Finally, here's part of modedb.c:
#define FLYBACK 550
#define FRONTPORCH 1
#define VSYNC_LEN 3
#define OFFSET 40
#define SCALEFACTOR 20
#define BLANKSCALE 128
#define GRADIENT 600
#include <asm/div64.h>
/**
* fb_get_gtf - gets video timings using VESA GTF
* @xres: horizontal resolution in pixels
* @yres: vertical resoltion in scanlines
* @refresh: refresh rate
* @gtf: pointer to fb_videomode structure
*
* Calculates required video timings using GTF
* given xres, yres and rr, then
* writes all timing values to @gtf
*/
static void fb_get_gtf(unsigned int xres, unsigned int yres,
unsigned int refresh, struct fb_videomode *gtf)
{
unsigned int long scratch;
unsigned int denom, hfreq, vblank, hblank, duty_cycle, m_val, htotal;
/* Estimate hsync using yres and refresh */
scratch = (unsigned long long) (yres + FRONTPORCH) *
(unsigned long long) (refresh) * 1000000;
denom = 1000000 - (refresh * FLYBACK);
do_div(scratch, denom);
hfreq = (u32) scratch;
/* Compute for vblank (vtotal - yres) given hsync*/
vblank = (hfreq * FLYBACK)/1000;
vblank = (vblank + 500)/1000 + FRONTPORCH;
/* Compute for hblank (htotal - xres) given hfreq and xres */
duty_cycle = (((OFFSET - SCALEFACTOR) * BLANKSCALE)/256 +
SCALEFACTOR) * 1000;
m_val = (BLANKSCALE * GRADIENT)/256;
m_val = (m_val * 1000000)/hfreq;
duty_cycle -= m_val;
hblank = (xres * duty_cycle)/(100000 - duty_cycle);
hblank = (hblank + 4) & ~7;
htotal = hblank + xres;
gtf->name = NULL;
gtf->refresh = refresh;
gtf->xres = xres;
gtf->yres = yres;
gtf->pixclock = 1000000000/((hfreq/1000) * htotal);
/* hsync_len: default to 8% of htotal */
gtf->hsync_len = (htotal * 8)/100;
gtf->hsync_len = (gtf->hsync_len + 4) & ~7;
gtf->left_margin = (hblank >> 1) - gtf->hsync_len;
gtf->left_margin = (gtf->left_margin + 4) & ~7;
gtf->right_margin = gtf->hsync_len + gtf->left_margin;
gtf->upper_margin = FRONTPORCH;
gtf->vsync_len = VSYNC_LEN;
gtf->lower_margin = vblank - (FRONTPORCH + VSYNC_LEN);
gtf->sync = FB_VMODE_NONINTERLACED;
/* What do we place here */
gtf->vmode = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT;
}
/**
* fb_find_mode - finds a valid video mode
* @var: frame buffer user defined part of display
* @info: frame buffer info structure
* @mode_option: string video mode to find
* @db: video mode database
* @dbsize: size of @db
* @default_mode: default video mode to fall back to
* @default_bpp: default color depth in bits per pixel
*
* Finds a suitable video mode, starting with the specified mode
* in @mode_option with fallback to @default_mode. If
* @default_mode fails, all modes in the video mode database will
* be tried.
*
* Valid mode specifiers for @mode_option:
*
* <xres>x<yres>[-<bpp>][@<refresh>] or
* <name>[-<bpp>][@<refresh>]
*
* with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
* <name> a string.
*
* NOTE: The passed struct @var is _not_ cleared! This allows you
* to supply values for e.g. the grayscale and accel_flags fields.
*
* Returns zero for failure, 1 if using specified @mode_option,
* 2 if using specified @mode_option with an ignored refresh rate,
* 3 if default mode is used, 4 if fall back to any valid mode.
*
*/
int __init fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info, const char *mode_option,
const struct fb_videomode *db, unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp)
{
int i, j;
/* Set up defaults */
if (!db) {
db = modedb;
dbsize = sizeof(modedb)/sizeof(*modedb);
}
if (!default_mode)
default_mode = &modedb[DEFAULT_MODEDB_INDEX];
if (!default_bpp)
default_bpp = 8;
/* Did the user specify a video mode? */
if (mode_option || (mode_option = global_mode_option)) {
const char *name = mode_option;
unsigned int namelen = strlen(name);
int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
int yres_specified = 0;
for (i = namelen-1; i >= 0; i--) {
switch (name[i]) {
case '@':
namelen = i;
if (!refresh_specified && !bpp_specified &&
!yres_specified) {
refresh = my_atoi(&name[i+1]);
refresh_specified = 1;
} else
goto done;
break;
case '-':
namelen = i;
if (!bpp_specified && !yres_specified) {
bpp = my_atoi(&name[i+1]);
bpp_specified = 1;
} else
goto done;
break;
case 'x':
if (!yres_specified) {
yres = my_atoi(&name[i+1]);
yres_specified = 1;
} else
goto done;
break;
case '0'...'9':
break;
default:
goto done;
}
}
if (i < 0 && yres_specified) {
xres = my_atoi(name);
res_specified = 1;
}
done:
/* Tony: VESA GTF */
DPRINTK("Trying VESA GTF\n");
struct fb_videomode gtf;
fb_get_gtf(xres, yres, refresh, >f);
printk("VESA GTF:\n"
"%dx%d @ %dHz\n"
"pixclock : %d\n"
"left margin : %d\n"
"right margin: %d\n"
"upper margin: %d\n"
"lower margin: %d\n"
"hsync len : %d\n"
"vsync len : %d\n",
gtf.xres, gtf.yres, gtf.refresh, gtf.pixclock,
gtf.left_margin, gtf.right_margin, gtf.upper_margin,
gtf.lower_margin, gtf.hsync_len, gtf.vsync_len);
for (i = refresh_specified; i >= 0; i--) {
DPRINTK("Trying specified video mode%s\n",
i ? "" : " (ignoring refresh rate)");
for (j = 0; j < dbsize; j++)
if ((name_matches(db[j], name, namelen) ||
(res_specified && res_matches(db[j], xres, yres))) &&
(!i || db[j].refresh == refresh) &&
__fb_try_mode(var, info, &db[j], bpp))
return 2-i;
}
}
DPRINTK("Trying default video mode\n");
if (__fb_try_mode(var, info, default_mode, default_bpp))
return 3;
DPRINTK("Trying all modes\n");
for (i = 0; i < dbsize; i++)
if (__fb_try_mode(var, info, &db[i], default_bpp))
return 4;
DPRINTK("No valid mode found\n");
return 0;
}
Tony
|