<!DOCTYPE linuxdoc PUBLIC "-//XFree86//DTD linuxdoc//EN">

<article>
<title>The Linux/m68k Frame Buffer Device
<author>Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
<date>7 November 1998
<toc>

<sect>Introduction
<p>
The frame buffer device provides an abstraction for the graphics hardware. It
represents the frame buffer of some video hardware and allows application
software to access the graphics hardware through a well-defined interface, so
the software doesn't need to know anything about the low-level (hardware
register) stuff.

The device is accessed through special device nodes, usually located in the
/dev directory, i.e. <tt>/dev/fb*</tt>.


<sect>User's View of <tt>/dev/fb*</tt>
<p>
From the user's point of view, the frame buffer device looks just like any
other device in <tt>/dev</tt>. It's a character device using major 29, the
minor specifies the frame buffer number.

By convention, the following device nodes are used (numbers indicate the device
minor numbers):

<descrip>
<tag>  0 = <tt>/dev/fb0</tt></tag>First frame buffer
<tag> 32 = <tt>/dev/fb1</tt></tag>Second frame buffer
<tag>...</tag><p>
<tag>224 = <tt>/dev/fb7</tt></tag>8th frame buffer
</descrip>

For backwards compatibility, you may want to create a symbolic link from
<tt>/dev/fb0current</tt> to <tt>fb0</tt>.

The frame buffer devices are also `normal' memory devices, this means, you can
read and write their contents. You can, for example, make a screen snapshot by

    <tscreen><verb>
    cp /dev/fb0 myfile
    </verb></tscreen>

There also can be more than one frame buffer at a time, e.g. if you have a
graphics card in addition to the built-in hardware. The corresponding frame
buffer devices (<tt>/dev/fb0</tt> and <tt>/dev/fb1</tt> etc.) work
independently.

Application software that uses the frame buffer device (e.g. the X server) will
use <tt>/dev/fb0</tt> by default (older software uses
<tt>/dev/fb0current</tt>). You can specify an alternative frame buffer device
by setting the environment variable <tt>&dollar;FRAMEBUFFER</tt> to the path
name of a frame buffer device, e.g. (for sh/bash users):

    <tscreen><verb>
    export FRAMEBUFFER=/dev/fb1
    </verb></tscreen>

or (for csh users):

    <tscreen><verb>
    setenv FRAMEBUFFER /dev/fb1
    </verb></tscreen>

After this the X server will use the second frame buffer.


<sect>Programmer's View of <tt>/dev/fb*</tt>
<p>
As you already know, a frame buffer device is a memory device like
<tt>/dev/mem</tt> and it has the same features. You can read it, write it, seek
to some location in it and <tt>mmap()</tt> it (the main usage). The difference
is just that the memory that appears in the special file is not the whole
memory, but the frame buffer of some video hardware.

<tt>/dev/fb*</tt> also allows several ioctls on it, by which lots of
information about the hardware can be queried and set. The color map handling
works via ioctls, too. Look into <tt>&lt;linux/fb.h&gt;</tt> for more
information on what ioctls exist and on which data structures they work. Here's
just a brief overview:

    <itemize>
    <item>You can request unchangeable information about the hardware, like
    name, organization of the screen memory (planes, packed pixels, ...) and
    address and length of the screen memory.

    <item>You can request and change variable information about the hardware,
    like visible and virtual geometry, depth, color map format, timing, and so
    on.  If you try to change that informations, the driver maybe will round up
    some values to meet the hardware's capabilities (or return <tt>EINVAL</tt>
    if that isn't possible).

    <item>You can get and set parts of the color map. Communication is done
    with 16 bit per color part (red, green, blue, transparency) to support all
    existing hardware. The driver does all the computations needed to bring it
    into the hardware (round it down to less bits, maybe throw away
    transparency).
    </itemize>

All this hardware abstraction makes the implementation of application programs
easier and more portable. E.g. the X server works completely on /dev/fb* and
thus doesn't need to know, for example, how the color registers of the concrete
hardware are organized. <em/XF68_FBDev/ is a general X server for bitmapped,
unaccelerated video hardware. The only thing that has to be built into
application programs is the screen organization (bitplanes or chunky pixels
etc.), because it works on the frame buffer image data directly.

For the future it is planned that frame buffer drivers for graphics cards and
the like can be implemented as kernel modules that are loaded at runtime. Such
a driver just has to call register_framebuffer() and supply some functions.
Writing and distributing such drivers independently from the kernel will save
much trouble...


<sect>Frame Buffer Resolution Maintenance
<p>
Frame buffer resolutions are maintained using the utility <em/fbset/. It can
change the video mode properties of a frame buffer device. Its main usage is
to change the current video mode, e.g. during boot up in one of your
<tt>/etc/rc.*</tt> or <tt>/etc/init.d/*</tt> files.

Fbset uses a video mode database stored in a configuration file, so you can
easily add your own modes and refer to them with a simple identifier.


<sect>The X Server
<p>
The X server (XF68_FBDev) is the most notable application program for the frame
buffer device. Starting with XFree86 release 3.2, the X server is part of
XFree86 and has 2 modes:

    <itemize>
    <item>If the <tt/Display/ subsection for the <tt/fbdev/ driver in the
    <tt>/etc/XF86Config</tt> file contains a

	<tscreen><verb>
        Modes "default"
	</verb></tscreen>

    line, the X server will use the scheme discussed above, i.e. it will start
    up in the resolution determined by <tt>/dev/fb0</tt> (or
    <tt>&dollar;FRAMEBUFFER</tt>, if set). You still have to specify the color
    depth (using the <tt>Depth</tt> keyword) and virtual resolution (using the
    <tt>Virtual</tt> keyword) though. This is the default for the configuration
    file supplied with XFree86. It's the most simple configuration, but it has
    some limitations.

    <item>Therefore it's also possible to specify resolutions in the
    <tt>/etc/XF86Config</tt> file. This allows for on-the-fly resolution
    switching while retaining the same virtual desktop size. The frame buffer
    device that's used is still <tt>/dev/fb0</tt> (or
    <tt>&dollar;FRAMEBUFFER</tt>), but the available resolutions are defined by
    <tt>/etc/XF86Config</tt> now. The disadvantage is that you have to specify
    the timings in a different format (but <tt>fbset -x</tt> may help).
    </itemize>

To tune a video mode, you can use fbset or xvidtune. Note that xvidtune doesn't
work 100% with XF68_FBDev: the reported clock values are always incorrect.


<sect>Video Mode Timings
<p>
A monitor draws an image on the screen by using an electron beam (3 electron
beams for color models, 1 electron beam for monochrome monitors). The front of
the screen is covered by a pattern of colored phosphors (pixels). If a phosphor
is hit by an electron, it emits a photon and thus becomes visible.

The electron beam draws horizontal lines (scanlines) from left to right, and
from the top to the bottom of the screen. By modifying the intensity of the
electron beam, pixels with various colors and intensities can be shown.

After each scanline the electron beam has to move back to the left side of the
screen and to the next line: this is called the horizontal retrace. After the
whole screen (frame) was painted, the beam moves back to the upper left corner:
this is called the vertical retrace. During both the horizontal and vertical
retrace, the electron beam is turned off (blanked).

The speed at which the electron beam paints the pixels is determined by the
dotclock in the graphics board. For a dotclock of e.g. 28.37516 MHz (millions
of cycles per second), each pixel is 35242 ps (picoseconds) long:

    <tscreen><verb>
    </verb></tscreen>
    1/(28.37516E6 Hz) = 35.242E-9 s

If the screen resolution is 640x480, it will take

    <tscreen><verb>
    640*35.242E-9 s = 22.555E-6 s
    </verb></tscreen>

to paint the 640 (xres) pixels on one scanline. But the horizontal retrace
also takes time (e.g. 272 `pixels'), so a full scanline takes

    <tscreen><verb>
    (640+272)*35.242E-9 s = 32.141E-6 s
    </verb></tscreen>

We'll say that the horizontal scanrate is about 31 kHz:

    <tscreen><verb>
    1/(32.141E-6 s) = 31.113E3 Hz
    </verb></tscreen>

A full screen counts 480 (yres) lines, but we have to consider the vertical
retrace too (e.g. 49 `pixels'). So a full screen will take

    <tscreen><verb>
    (480+49)*32.141E-6 s = 17.002E-3 s
    </verb></tscreen>

The vertical scanrate is about 59 Hz:

    <tscreen><verb>
    1/(17.002E-3 s) = 58.815 Hz
    </verb></tscreen>

This means the screen data is refreshed about 59 times per second. To have a
stable picture without visible flicker, VESA recommends a vertical scanrate of
at least 72 Hz. But the perceived flicker is very human dependent: some people
can use 50 Hz without any trouble, while I'll notice if it's less than 80 Hz.

Since the monitor doesn't know when a new scanline starts, the graphics board
will supply a synchronization pulse (horizontal sync or hsync) for each
scanline.  Similarly it supplies a synchronization pulse (vertical sync or
vsync) for each new frame. The position of the image on the screen is
influenced by the moments at which the synchronization pulses occur.

The following picture summarizes all timings. The horizontal retrace time is
the sum of the left margin, the right margin and the hsync length, while the
vertical retrace time is the sum of the upper margin, the lower margin and the
vsync length.

<tscreen><verb>
  +----------+---------------------------------------------+----------+-------+
  |          |                x                            |          |       |
  |          |                |upper_margin                |          |       |
  |          |                x                            |          |       |
  +----------###############################################----------+-------+
  |          #                x                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |   left   #                |                            #  right   | hsync |
  |  margin  #                |       xres                 #  margin  |  len  |
  |<-------->#<---------------+--------------------------->#<-------->|<----->|
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |yres                        #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                x                            #          |       |
  +----------###############################################----------+-------+
  |          |                x                            |          |       |
  |          |                |lower_margin                |          |       |
  |          |                x                            |          |       |
  +----------+---------------------------------------------+----------+-------+
  |          |                x                            |          |       |
  |          |                |vsync_len                   |          |       |
  |          |                x                            |          |       |
  +----------+---------------------------------------------+----------+-------+
</verb></tscreen>

The frame buffer device expects all horizontal timings in number of dotclocks
(in picoseconds, 1E-12 s), and vertical timings in number of scanlines.


<sect>Converting XFree86 timing values into frame buffer device timings
<p>
An XFree86 mode line consists of the following fields:

    <tscreen><verb>
    "800x600"     50      800  856  976 1040    600  637  643  666
    < name >     DCF       HR  SH1  SH2  HFL     VR  SV1  SV2  VFL
    </verb></tscreen>

The frame buffer device uses the following fields:

    <descrip>
    <tag>pixclock</tag> pixel clock in ps (pico seconds)
    <tag>left_margin</tag> time from sync to picture
    <tag>right_margin</tag> time from picture to sync
    <tag>upper_margin</tag> time from sync to picture
    <tag>lower_margin</tag> time from picture to sync
    <tag>hsync_len</tag> length of horizontal sync
    <tag>vsync_len</tag> length of vertical sync
    </descrip>

    <descrip>
    <tag>Pixelclock</tag>
	<itemize>
	<item>xfree: in MHz
	<item>fb: In Picoseconds (ps)
	<item>pixclock = 1000000 / DCF
	</itemize>

    <tag>Horizontal timings</tag>
	<itemize>
	<item>left_margin = HFL - SH2
	<item>right_margin = SH1 - HR
	<item>hsync_len = SH2 - SH1
	</itemize>

    <tag>Vertical timings</tag>
	<itemize>
	<item>upper_margin = VFL - SV2
	<item>lower_margin = SV1 - VR
	<item>vsync_len = SV2 - SV1
	</itemize>
    </descrip>

Good examples for VESA timings can be found in the XFree86 source tree,
under <tt>xc/programs/Xserver/hw/xfree86/doc/modeDB.txt</tt>.


<sect>References
<p>
For more specific information about the frame buffer device and its
applications, please refer to the following documentation:

    <itemize>
    <item>The manual pages for fbset: fbset(8), fb.modes(5)
    <item>The manual pages for XFree86: XF68_FBDev(1), XF86Config(4/5)
    <item>The mighty kernel sources:
	<itemize>
	<item>linux/drivers/video/
	<item>linux/include/linux/fb.h
	<item>linux/include/video/
	</itemize>
    </itemize>


<sect>Downloading
<p>
All necessary files can be found at

    <tscreen><verb>
    ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/
    </verb></tscreen>

and on its mirrors.

  
<sect>Credits                                                       
<p>                
This readme was written by Geert Uytterhoeven, partly based on the original
<tt>X-framebuffer.README</tt> by Roman Hodek and Martin Schaller. Section
`Converting XFree86 timing values into frame buffer device timings' was
provided by Frank Neumann.

The frame buffer device abstraction was designed by Martin Schaller.


<verb>
$XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/fbdev.sgml,v 1.2 1999/08/23 06:38:53 dawes Exp $

</verb>

</article>
