diff options
Diffstat (limited to 'qemu/roms/openbios/drivers/vga_load_regs.c')
-rw-r--r-- | qemu/roms/openbios/drivers/vga_load_regs.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/qemu/roms/openbios/drivers/vga_load_regs.c b/qemu/roms/openbios/drivers/vga_load_regs.c new file mode 100644 index 000000000..dda6b798a --- /dev/null +++ b/qemu/roms/openbios/drivers/vga_load_regs.c @@ -0,0 +1,496 @@ +#include "asm/io.h" +#include "drivers/vga.h" +#include "vga.h" + +/* + * $Id$ + * $Source$ + * + * from the Linux kernel code base. + * orig by Ben Pfaff and Petr Vandrovec. + * + * modified by + * Steve M. Gehlbach <steve@kesa.com> + * + * NOTE: to change the horiz and vertical pixels, + * change the xres,yres,xres_virt,yres_virt setting + * in the screeninfo structure below. You may also need + * to change the border settings as well. + * + * Convert the screeninfo structure to data for + * writing to the vga registers + * + */ + +// prototypes +static int vga_decode_var(const struct screeninfo *var, struct vga_par *par); +static int vga_set_regs(const struct vga_par *par); + +u8 read_seq_b(u16 addr) { + outb(addr,SEQ_I); + return inb(SEQ_D); +} +u8 read_gra_b(u16 addr) { + outb(addr,GRA_I); + return inb(GRA_D); +} +u8 read_crtc_b(u16 addr) { + outb(addr,CRT_IC); + return inb(CRT_DC); +} +u8 read_att_b(u16 addr) { + inb(IS1_RC); + inb(0x80); + outb(addr,ATT_IW); + return inb(ATT_R); +} + + +/* +From: The Frame Buffer Device +by Geert Uytterhoeven <geert@linux-m68k.org> +in the linux kernel docs. + +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. + + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |upper_margin | | | + | | | | | | + +----------###############################################----------+-------+ + | # ^ # | | + | # | # | | + | # | # | | + | # | # | | + | left # | # right | hsync | + | margin # | xres # margin | len | + |<-------->#<---------------+--------------------------->#<-------->|<----->| + | # | # | | + | # | # | | + | # | # | | + | # |yres # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + +----------###############################################----------+-------+ + | | ^ | | | + | | |lower_margin | | | + | | | | | | + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | | | | | + +----------+---------------------------------------------+----------+-------+ + +All horizontal timings are in number of dotclocks +(in picoseconds, 1E-12 s), and vertical timings in number of scanlines. + +The vga uses the following fields: + + - pixclock: pixel clock in ps (pico seconds) + - xres,yres,xres_v,yres_v + - left_margin: time from sync to picture + - right_margin: time from picture to sync + - upper_margin: time from sync to picture + - lower_margin: time from picture to sync + - hsync_len: length of horizontal sync + - vsync_len: length of vertical sync + +*/ + +/* our display parameters per the above */ + +static const struct screeninfo vga_settings = { + 640,400,640,400,/* xres,yres,xres_virt,yres_virt */ + 0,0, /* xoffset,yoffset */ + 4, /* bits_per_pixel NOT USED*/ + 0, /* greyscale ? */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* transparency */ + 0, /* standard pixel format */ + 0, // activate now + -1,-1, // height and width in mm + 0, // accel flags + 39721, // pixclock: 79442 -> 12.587 Mhz (NOT USED) + // 70616 -> 14.161 + // 39721 -> 25.175 + // 35308 -> 28.322 + + 48, 16, 39, 8, // margins left,right,upper,lower + 96, // hsync length + 2, // vsync length + 0, // sync polarity + 0, // non interlaced, single mode + {0,0,0,0,0,0} // compatibility +}; + +// ALPHA-MODE +// Hard coded to BIOS VGA mode 3 (alpha color text) +// screen size settable in screeninfo structure + +static int vga_decode_var(const struct screeninfo *var, + struct vga_par *par) +{ + u8 VgaAttributeTable[16] = + { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x014, 0x007, 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x03F}; + + u32 xres, right, hslen, left, xtotal; + u32 yres, lower, vslen, upper, ytotal; + u32 vxres, xoffset, vyres, yoffset; + u32 pos; + u8 r7, rMode; + int i; + + xres = (var->xres + 7) & ~7; + vxres = (var->xres_virtual + 0xF) & ~0xF; + xoffset = (var->xoffset + 7) & ~7; + left = (var->left_margin + 7) & ~7; + right = (var->right_margin + 7) & ~7; + hslen = (var->hsync_len + 7) & ~7; + + if (vxres < xres) + vxres = xres; + if (xres + xoffset > vxres) + xoffset = vxres - xres; + + xres >>= 3; + right >>= 3; + hslen >>= 3; + left >>= 3; + vxres >>= 3; + xtotal = xres + right + hslen + left; + if (xtotal >= 256) + return VERROR; //xtotal too big + if (hslen > 32) + return VERROR; //hslen too big + if (right + hslen + left > 64) + return VERROR; //hblank too big + par->crtc[CRTC_H_TOTAL] = xtotal - 5; + par->crtc[CRTC_H_BLANK_START] = xres - 1; + par->crtc[CRTC_H_DISP] = xres - 1; + pos = xres + right; + par->crtc[CRTC_H_SYNC_START] = pos; + pos += hslen; + par->crtc[CRTC_H_SYNC_END] = (pos & 0x1F) | 0x20 ; //<--- stpc text mode p178 + pos += left - 2; /* blank_end + 2 <= total + 5 */ + par->crtc[CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80; + if (pos & 0x20) + par->crtc[CRTC_H_SYNC_END] |= 0x80; + + yres = var->yres; + lower = var->lower_margin; + vslen = var->vsync_len; + upper = var->upper_margin; + vyres = var->yres_virtual; + yoffset = var->yoffset; + + if (yres > vyres) + vyres = yres; + if (vxres * vyres > 65536) { + vyres = 65536 / vxres; + if (vyres < yres) + return VERROR; // out of memory + } + if (yoffset + yres > vyres) + yoffset = vyres - yres; + + if (var->vmode & VMODE_DOUBLE) { + yres <<= 1; + lower <<= 1; + vslen <<= 1; + upper <<= 1; + } + ytotal = yres + lower + vslen + upper; + if (ytotal > 1024) { + ytotal >>= 1; + yres >>= 1; + lower >>= 1; + vslen >>= 1; + upper >>= 1; + rMode = 0x04; + } else + rMode = 0x00; + if (ytotal > 1024) + return VERROR; //ytotal too big + if (vslen > 16) + return VERROR; //vslen too big + par->crtc[CRTC_V_TOTAL] = ytotal - 2; + r7 = 0x10; /* disable linecompare */ + if (ytotal & 0x100) r7 |= 0x01; + if (ytotal & 0x200) r7 |= 0x20; + par->crtc[CRTC_PRESET_ROW] = 0; + + +// GMODE <--> ALPHA-MODE +// default using alpha mode so we need to set char rows= CHAR_HEIGHT-1 + par->crtc[CRTC_MAX_SCAN] = 0x40 | (CHAR_HEIGHT-1); /* 16 scanlines, linecmp max*/ + + if (var->vmode & VMODE_DOUBLE) + par->crtc[CRTC_MAX_SCAN] |= 0x80; + par->crtc[CRTC_CURSOR_START] = 0x00; // curs enabled, start line = 0 + par->crtc[CRTC_CURSOR_END] = CHAR_HEIGHT-1; // end line = 12 + pos = yoffset * vxres + (xoffset >> 3); + par->crtc[CRTC_START_HI] = pos >> 8; + par->crtc[CRTC_START_LO] = pos & 0xFF; + par->crtc[CRTC_CURSOR_HI] = 0x00; + par->crtc[CRTC_CURSOR_LO] = 0x00; + pos = yres - 1; + par->crtc[CRTC_V_DISP_END] = pos & 0xFF; + par->crtc[CRTC_V_BLANK_START] = pos & 0xFF; + if (pos & 0x100) + r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */ + if (pos & 0x200) { + r7 |= 0x40; /* 0x40 -> DISP_END */ + par->crtc[CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */ + } + pos += lower; + par->crtc[CRTC_V_SYNC_START] = pos & 0xFF; + if (pos & 0x100) + r7 |= 0x04; + if (pos & 0x200) + r7 |= 0x80; + pos += vslen; + par->crtc[CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled reg write prot, IRQ */ + pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */ + par->crtc[CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA, + but some SVGA chips requires all 8 bits to set */ + if (vxres >= 512) + return VERROR; //vxres too long + par->crtc[CRTC_OFFSET] = vxres >> 1; + + // put the underline off of the character, necessary in alpha color mode + par->crtc[CRTC_UNDERLINE] = 0x1f; + + par->crtc[CRTC_MODE] = rMode | 0xA3; // word mode + par->crtc[CRTC_LINE_COMPARE] = 0xFF; + par->crtc[CRTC_OVERFLOW] = r7; + + + // not used ?? + par->vss = 0x00; /* 3DA */ + + for (i = 0x00; i < 0x10; i++) { + par->atc[i] = VgaAttributeTable[i]; + } + // GMODE <--> ALPHA-MODE + par->atc[ATC_MODE] = 0x0c; // text mode + + par->atc[ATC_OVERSCAN] = 0x00; // no border + par->atc[ATC_PLANE_ENABLE] = 0x0F; + par->atc[ATC_PEL] = xoffset & 7; + par->atc[ATC_COLOR_PAGE] = 0x00; + + par->misc = 0x67; /* enable CPU, ports 0x3Dx, positive sync*/ + if (var->sync & SYNC_HOR_HIGH_ACT) + par->misc &= ~0x40; + if (var->sync & SYNC_VERT_HIGH_ACT) + par->misc &= ~0x80; + + par->seq[SEQ_CLOCK_MODE] = 0x01; //8-bit char; 0x01=alpha mode + par->seq[SEQ_PLANE_WRITE] = 0x03; // just char/attr plane + par->seq[SEQ_CHARACTER_MAP] = 0x00; + par->seq[SEQ_MEMORY_MODE] = 0x02; // A/G bit not used in stpc; O/E on, C4 off + + par->gdc[GDC_SR_VALUE] = 0x00; + // bits set in the SR_EN regs will enable set/reset action + // based on the bit settings in the SR_VAL register + par->gdc[GDC_SR_ENABLE] = 0x00; + par->gdc[GDC_COMPARE_VALUE] = 0x00; + par->gdc[GDC_DATA_ROTATE] = 0x00; + par->gdc[GDC_PLANE_READ] = 0; + par->gdc[GDC_MODE] = 0x10; //Okay + + // GMODE <--> ALPHA-MMODE + par->gdc[GDC_MISC] = 0x0e; // b0=0 ->alpha mode; memory at 0xb8000 + + par->gdc[GDC_COMPARE_MASK] = 0x00; + par->gdc[GDC_BIT_MASK] = 0xFF; + + return 0; +} + +// +// originally from the stpc web site +// +static const unsigned char VgaLookupTable[3 * 0x3f + 3] = { + // Red Green Blue + 0x000, 0x000, 0x000, // 00h + 0x000, 0x000, 0x02A, // 01h + 0x000, 0x02A, 0x000, // 02h + 0x000, 0x02A, 0x02A, // 03h + 0x02A, 0x000, 0x000, // 04h + 0x02A, 0x000, 0x02A, // 05h + 0x02A, 0x02A, 0x000, // 06h + 0x02A, 0x02A, 0x02A, // 07h + 0x000, 0x000, 0x015, // 08h + 0x000, 0x000, 0x03F, // 09h + 0x000, 0x02A, 0x015, // 0Ah + 0x000, 0x02A, 0x03F, // 0Bh + 0x02A, 0x000, 0x015, // 0Ch + 0x02A, 0x000, 0x03F, // 0Dh + 0x02A, 0x02A, 0x015, // 0Eh + 0x02A, 0x02A, 0x03F, // 0Fh + 0x000, 0x015, 0x000, // 10h + 0x000, 0x015, 0x02A, // 11h + 0x000, 0x03F, 0x000, // 12h + 0x000, 0x03F, 0x02A, // 13h + 0x02A, 0x015, 0x000, // 14h + 0x02A, 0x015, 0x02A, // 15h + 0x02A, 0x03F, 0x000, // 16h + 0x02A, 0x03F, 0x02A, // 17h + 0x000, 0x015, 0x015, // 18h + 0x000, 0x015, 0x03F, // 19h + 0x000, 0x03F, 0x015, // 1Ah + 0x000, 0x03F, 0x03F, // 1Bh + 0x02A, 0x015, 0x015, // 1Ch + 0x02A, 0x015, 0x03F, // 1Dh + 0x02A, 0x03F, 0x015, // 1Eh + 0x02A, 0x03F, 0x03F, // 1Fh + 0x015, 0x000, 0x000, // 20h + 0x015, 0x000, 0x02A, // 21h + 0x015, 0x02A, 0x000, // 22h + 0x015, 0x02A, 0x02A, // 23h + 0x03F, 0x000, 0x000, // 24h + 0x03F, 0x000, 0x02A, // 25h + 0x03F, 0x02A, 0x000, // 26h + 0x03F, 0x02A, 0x02A, // 27h + 0x015, 0x000, 0x015, // 28h + 0x015, 0x000, 0x03F, // 29h + 0x015, 0x02A, 0x015, // 2Ah + 0x015, 0x02A, 0x03F, // 2Bh + 0x03F, 0x000, 0x015, // 2Ch + 0x03F, 0x000, 0x03F, // 2Dh + 0x03F, 0x02A, 0x015, // 2Eh + 0x03F, 0x02A, 0x03F, // 2Fh + 0x015, 0x015, 0x000, // 30h + 0x015, 0x015, 0x02A, // 31h + 0x015, 0x03F, 0x000, // 32h + 0x015, 0x03F, 0x02A, // 33h + 0x03F, 0x015, 0x000, // 34h + 0x03F, 0x015, 0x02A, // 35h + 0x03F, 0x03F, 0x000, // 36h + 0x03F, 0x03F, 0x02A, // 37h + 0x015, 0x015, 0x015, // 38h + 0x015, 0x015, 0x03F, // 39h + 0x015, 0x03F, 0x015, // 3Ah + 0x015, 0x03F, 0x03F, // 3Bh + 0x03F, 0x015, 0x015, // 3Ch + 0x03F, 0x015, 0x03F, // 3Dh + 0x03F, 0x03F, 0x015, // 3Eh + 0x03F, 0x03F, 0x03F, // 3Fh +}; + +/* + * From the Linux kernel. + * orig by Ben Pfaff and Petr Vandrovec. + * see the note in the vga.h for attribution. + * + * modified by + * Steve M. Gehlbach <steve@kesa.com> + * for the linuxbios project + * + * Write the data in the vga parameter structure + * to the vga registers, along with other default + * settings. + * + */ +static int vga_set_regs(const struct vga_par *par) +{ + int i; + + /* update misc output register */ + outb(par->misc, MIS_W); + + /* synchronous reset on */ + outb(0x00, SEQ_I); + outb(0x00, SEQ_D); + + /* write sequencer registers */ + outb(1, SEQ_I); + outb(par->seq[1] | 0x20, SEQ_D); // blank display + for (i = 2; i < SEQ_C; i++) { + outb(i, SEQ_I); + outb(par->seq[i], SEQ_D); + } + + /* synchronous reset off */ + outb(0x00, SEQ_I); + outb(0x03, SEQ_D); + + /* deprotect CRT registers 0-7 */ + outb(0x11, CRT_IC); + outb(par->crtc[0x11], CRT_DC); + + /* write CRT registers */ + for (i = 0; i < CRTC_C; i++) { + outb(i, CRT_IC); + outb(par->crtc[i], CRT_DC); + } + /* write graphics controller registers */ + for (i = 0; i < GRA_C; i++) { + outb(i, GRA_I); + outb(par->gdc[i], GRA_D); + } + + /* write attribute controller registers */ + for (i = 0; i < ATT_C; i++) { + inb(IS1_RC); /* reset flip-flop */ + inb(0x80); //delay + outb(i, ATT_IW); + inb(0x80); //delay + + outb(par->atc[i], ATT_IW); + inb(0x80); //delay + } + + // initialize the color table + outb(0, PEL_IW); + i = 0; + // length is a magic number right now + while ( i < (0x3f*3 + 3) ) { + outb(VgaLookupTable[i++], PEL_D); + outb(VgaLookupTable[i++], PEL_D); + outb(VgaLookupTable[i++], PEL_D); + } + + outb(0x0ff, PEL_MSK); // palette mask + + // very important + // turn on video, disable palette access + inb(IS1_RC); /* reset flip-flop */ + inb(0x80); //delay + outb(0x20, ATT_IW); + + /* Wait for screen to stabilize. */ + //for(i=0;i<1000;i++) { inb(0x80); } + + outb(0x01, SEQ_I); // unblank display + outb(par->seq[1], SEQ_D); + +// turn on display, disable access to attr palette + inb(IS1_RC); + outb(0x20, ATT_IW); + +return 0; +} + +void +vga_load_regs(void) +{ + struct vga_par par; + + if (vga_decode_var(&vga_settings, &par) == 0) { + vga_set_regs(&par); + } +} |