Re: FB and MTRR

Gerd Knorr (kraxel@goldbach.isdn.cs.tu-berlin.de)
Mon, 3 Aug 1998 21:07:31 +0200


In lists.linux.kernel you write:

>In lists.linux.kernel you write:

>>On Sat, 1 Aug 1998, Richard Gooch wrote:
>>> Hi, Geert. IIRC, you wrote a note about using the FB code on i386,
>>> and at the end you mentioned using /proc/mtrr to speed up

>Already done (but I want boot that kernel at least once before
>mailing patches).

ok, here we go. Some new vesafb bits. Changed:

* doc update, I hope less confusing now...
* does the mtrr thing mentioned above automatically at startup.
Killed the two doc lines, as they are not required any more :-)
* some startup-asm hacking, passes more information.
* started support for the VESA Protected Mode Interface. Does
NOT work for me and is therefore disabled by default. Once
this works we will hopefully get a nice speedup becauce we
can use YPAN for scrolling then.

Gerd

PS: Anyone has the full VESA 2.0 specs? I have just a magazine
article which is'nt very verbose wrt. Protected Mode Interface.

--------------------------------------------------------------
diff -urN kernel/2.1.113/Documentation/fb/vesafb.txt linux/Documentation/fb/vesafb.txt
--- kernel/2.1.113/Documentation/fb/vesafb.txt Thu Jul 30 23:04:01 1998
+++ linux/Documentation/fb/vesafb.txt Mon Aug 3 20:44:38 1998
@@ -30,11 +30,13 @@
==============

Switching modes is done using the vga=... boot parameter. Read
-Documentation/svga.txt for details. With vesafb both text and
-graphics modes work. Text modes are handled by vgafb, graphic modes
-by the new vesafb.c.
+Documentation/svga.txt for details.

-The graphic modes are not in the list which you get if you boot with
+You should compile in both vgacon (for text mode) and vesafb (for
+graphics mode). Which of them takes over the console depends on
+whenever the specified mode is text or graphics.
+
+The graphic modes are NOT in the list which you get if you boot with
vga=ask and hit return. Here are some mode numbers:

| 640x480 800x600 1024x768
@@ -44,17 +46,22 @@
64k | 0x111 0x114 0x117
16M | 0x112 0x115 0x118

-Note 1: this are the VESA mode numbers. The video mode select code
- expects 0x200 + VESA mode number.
-Note 2: lilo can't handle hex, for booting with "vga=??" you have to
- transform the numbers to decimal.
+This are the VESA mode numbers. The video mode select code expects
+0x200 + VESA mode number. Therefore you have to enter "305" at the
+"vga=ask" prompt to boot into 1024x768x8.
+
+If this does'nt work, this might be becauce your BIOS does not support
+linear framebuffers or becauce it does'nt support this mode at all.
+Even if your board does, it might be the BIOS does not. VESA BIOS
+Extentions v2.0 are required, 1.2 is NOT sufficient. You'll get a
+"bad mode number" message if something goes wrong.
+
+Note: LILO can't handle hex, for booting directly with "vga=mode-number"
+ you have to transform the numbers to decimal.


Speed it up!
============
-
-Check /usr/src/linux/Documentation/mtrr.txt, enabling write-combining
-for the framebuffer memory gives a performance boost.

There are two ways to do console scrolling: redraw the screen
completely, or by copying around the video memory. You can select one
diff -urN kernel/2.1.113/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- kernel/2.1.113/arch/i386/boot/video.S Thu Jul 30 23:03:41 1998
+++ linux/arch/i386/boot/video.S Mon Jul 27 23:09:06 1998
@@ -85,6 +85,9 @@
#define PARAM_LFB_SIZE 0x1c
#define PARAM_LFB_LINELENGTH 0x24
#define PARAM_LFB_COLORS 0x26
+#define PARAM_VESAPM_SEG 0x2e
+#define PARAM_VESAPM_OFF 0x30
+#define PARAM_LFB_PAGES 0x32

! Define DO_STORE according to CONFIG_VIDEO_RETAIN
#ifdef CONFIG_VIDEO_RETAIN
@@ -236,13 +239,14 @@
seg fs
mov [PARAM_LFB_DEPTH],ax

- mov eax,(di+40)
+ mov al,(di+29)
+ mov ah,#0
seg fs
- mov [PARAM_LFB_BASE],eax
+ mov [PARAM_LFB_PAGES],ax

- mov eax,(di+44)
+ mov eax,(di+40)
seg fs
- mov [PARAM_LFB_SIZE],eax
+ mov [PARAM_LFB_BASE],eax

mov eax,(di+31)
seg fs
@@ -251,7 +255,30 @@
mov eax,(di+35)
seg fs
mov [PARAM_LFB_COLORS+4],eax
-
+
+ ! get video mem size
+ lea di,modelist+1024
+ mov ax,#0x4f00
+ int 0x10
+
+ xor eax,eax
+ mov ax,(di+18)
+ seg fs
+ mov [PARAM_LFB_SIZE],eax
+
+ ! get protected mode interface informations
+ mov ax,#0x4f0a
+ xor bx,bx
+ xor di,di
+ int 0x10
+ cmp ax,#0x004f
+ jnz no_pm
+ seg fs
+ mov [PARAM_VESAPM_SEG],es
+ seg fs
+ mov [PARAM_VESAPM_OFF],di
+
+no_pm:
ret

!
diff -urN kernel/2.1.113/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- kernel/2.1.113/drivers/video/vesafb.c Mon Aug 3 00:33:31 1998
+++ linux/drivers/video/vesafb.c Mon Aug 3 20:37:58 1998
@@ -21,8 +21,10 @@
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/config.h>

#include <asm/io.h>
+#include <asm/mtrr.h>

#include "fbcon.h"
#include "fbcon-cfb8.h"
@@ -77,9 +79,14 @@
static struct fb_info fb_info;
static struct { u_char red, green, blue, pad; } palette[256];

-static int inverse = 0;
-
-static int currcon = 0;
+static int inverse = 0;
+static int currcon = 0;
+static int ypanstep = 0;
+
+static int pmi = 0; /* use VESA protected mode interface ? */
+static unsigned short *pmi_base = 0;
+static void (*pmi_start)(void);
+static void (*pmi_pal)(void);

/* --------------------------------------------------------------------- */
/* speed up scrolling */
@@ -111,8 +118,34 @@
return(0);
}

-static int fb_update_var(int con, struct fb_info *info)
+static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+#if 0
+ printk("vesafb: pan: yoffset=%d\n",var->yoffset);
+#endif
+ if (!pmi)
+ return -EINVAL;
+ if (var->xoffset || var->yoffset+var->yres > var->yres_virtual)
+ return -EINVAL;
+
+ __asm__ __volatile__(
+ "call *(%%edi)"
+ : /* no return value */
+ : "a" (0x4f07), /* EAX */
+ "b" (0), /* EBX */
+ "c" (0), /* ECX */
+ "d" (var->yoffset), /* EDX */
+ "D" (&pmi_start)); /* EDI */
+ return 0;
+}
+
+static int vesafb_update_var(int con, struct fb_info *info)
{
+ if (con == currcon && pmi) {
+ struct fb_var_screeninfo *var = &fb_display[currcon].var;
+ return vesafb_pan_display(var,con,info);
+ }
return 0;
}

@@ -127,7 +160,7 @@
fix->type = video_type;
fix->visual = video_visual;
fix->xpanstep=0;
- fix->ypanstep=0;
+ fix->ypanstep=ypanstep;
fix->ywrapstep=0;
fix->line_length=video_linelength;
return 0;
@@ -317,13 +350,6 @@
return 0;
}

-static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- /* no panning */
- return -EINVAL;
-}
-
static int vesafb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg, int con,
struct fb_info *info)
@@ -363,6 +389,8 @@
vesafb_scroll = USE_REDRAW;
else if (! strcmp(this_opt, "memmove"))
vesafb_scroll = USE_MEMMOVE;
+ else if (! strcmp(this_opt, "pmi"))
+ pmi = 1;
else if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt+5);
}
@@ -400,15 +428,42 @@
video_width = screen_info.lfb_width;
video_height = screen_info.lfb_height;
video_linelength = screen_info.lfb_linelength;
- video_size = video_linelength * video_height /* screen_info.lfb_size */;
+ video_size = screen_info.lfb_size * 65536;
video_visual = (video_bpp == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
video_vbase = ioremap((unsigned long)video_base, video_size);

- printk("vesafb: %dx%dx%d, linelength=%d\n",
- video_width, video_height, video_bpp, video_linelength);
- printk("vesafb: framebuffer at 0x%p, mapped to 0x%p, size %d\n",
- video_base, video_vbase, video_size);
+ printk("vesafb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n",
+ video_base, video_vbase, video_size/1024);
+ printk("vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+ video_width, video_height, video_bpp, video_linelength, screen_info.pages);
+
+ if (screen_info.vesapm_seg) {
+ if (screen_info.vesapm_seg < 0xc000)
+ pmi = 0; /* don't try to use some DOS TSR ... */
+ printk("vesafb: protected mode interface info at %04x:%04x, %s\n",
+ screen_info.vesapm_seg,screen_info.vesapm_off,
+ pmi ? "enabled" : "disabled");
+ } else
+ pmi = 0;
+
+ if (pmi) {
+ pmi_base = (unsigned short*)(__PAGE_OFFSET+((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+ pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
+ pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
+ printk("vesafb: pmi: set display start : %p\n",pmi_start);
+ printk("vesafb: pmi: set palette : %p\n",pmi_pal);
+ printk("vesafb: pmi: required ports : ");
+ for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
+ printk("%x ",pmi_base[i]);
+ printk("\nvesavb: pmi: required mem areas: ");
+ for (i++; pmi_base[i] != 0xffff; i+=3)
+ printk("%lx+%x ",
+ ((unsigned long)pmi_base[i]<<16)
+ + pmi_base[i+1], pmi_base[i+3]);
+ printk("\n");
+ }
+
if (vesafb_scroll == USE_REDRAW) printk("vesafb: scrolling=redraw\n");
if (vesafb_scroll == USE_MEMMOVE) printk("vesafb: scrolling=memmove\n");

@@ -418,6 +473,13 @@
vesafb_defined.yres_virtual=video_height;
vesafb_defined.bits_per_pixel=video_bpp;

+ if (pmi && screen_info.pages) {
+ /* set up ypan using VESA Protected Mode Interface */
+ vesafb_defined.yres_virtual = video_height * screen_info.pages;
+ ypanstep = 1;
+ printk("vesafb: using pmi for ypan\n");
+ }
+
if (video_bpp > 8) {
vesafb_defined.red.offset = screen_info.red_pos;
vesafb_defined.red.length = screen_info.red_size;
@@ -451,6 +513,9 @@
video_cmap_len = 256;
}
request_region(0x3c0, 32, "vga+");
+#ifdef CONFIG_MTRR
+ mtrr_add(video_base, video_size, MTRR_TYPE_WRCOMB, 0);
+#endif

strcpy(fb_info.modename, "VESA VGA");
fb_info.changevar = NULL;
@@ -458,7 +523,7 @@
fb_info.fbops = &vesafb_ops;
fb_info.disp=&disp;
fb_info.switch_con=&vesafb_switch;
- fb_info.updatevar=&fb_update_var;
+ fb_info.updatevar=&vesafb_update_var;
fb_info.blank=&vesafb_blank;
vesafb_set_disp(-1);

diff -urN kernel/2.1.113/include/linux/tty.h linux/include/linux/tty.h
--- kernel/2.1.113/include/linux/tty.h Thu Jul 30 23:03:55 1998
+++ linux/include/linux/tty.h Mon Aug 3 00:45:00 1998
@@ -69,7 +69,10 @@
unsigned char blue_pos; /* 0x2b */
unsigned char rsvd_size; /* 0x2c */
unsigned char rsvd_pos; /* 0x2d */
- /* 0x2e -- 0x3f reserved for future expansion */
+ unsigned short vesapm_seg; /* 0x2e */
+ unsigned short vesapm_off; /* 0x30 */
+ unsigned short pages; /* 0x32 */
+ /* 0x34 -- 0x3f reserved for future expansion */
};

extern struct screen_info screen_info;

-- 
Gerd Knorr <kraxel@cs.tu-berlin.de>

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html