linux/arch/e2k/boot/bios/video/init.c

593 lines
12 KiB
C

#include <x86emu.h>
#include "init.h"
#include "printk.h"
#include <linux/pci_ids.h>
#include "pci-iface.h"
#include "bios.h"
#define die(x) { rom_printk(x); }
#define warn(x) { rom_printk(x); }
#define DEBUG_VIDEO 0
#define DebugV(fmt, args...) \
({ if (DEBUG_VIDEO) \
rom_printk(fmt, ##args); })
void x86emu_dump_xregs(void);
int int15_handler(void);
int int16_handler(void);
int int1A_handler(void);
#ifndef _PC
int int42_handler(void);
#endif
int intE6_handler(void);
void setup_int_vect(void);
int run_bios_int(int num);
u32 getIntVect(int num);
void pushw(u16 val);
_ptr p;
ptr currentp = 0;
unsigned char biosmem[1024 * 1024];
int verbose = 1;
/* Interrupt multiplexer */
void do_int(int num)
{
int ret = 0;
// rom_printk("int%x vector at %x\n", num, getIntVect(num));
/* This is a pInt leftover */
currentp->num = num;
switch (num) {
#ifndef _PC
case 0x10:
case 0x42:
case 0x6D:
if (getIntVect(num) == 0xFF065) {
ret = int42_handler();
}
break;
#endif
case 0x15:
ret = int15_handler();
break;
case 0x16:
ret = int16_handler();
break;
case 0x1A:
ret = int1A_handler();
break;
case 0xe6:
ret = intE6_handler();
break;
default:
break;
}
if (!ret)
ret = run_bios_int(num);
if (!ret) {
rom_printk("\nint%x: not implemented\n", num);
//x86emu_dump_xregs();
}
}
static void x_outb(u16 port, u8 val)
{
bios_outb(val, port);
}
static void x_outw(u16 port, u16 val)
{
bios_outw(val, port);
}
static void x_outl(u16 port, u32 val)
{
bios_outl(val, port);
}
X86EMU_pioFuncs myfuncs = {
bios_inb, bios_inw, bios_inl,
x_outb, x_outw, x_outl
};
void X86EMU_setMemBase(void *base, unsigned int size);
void X86EMU_setabseg(void *abseg);
void x86emu_dump_xregs(void);
int X86EMU_set_debug(int debug);
X86EMU_intrFuncs intFuncs[256];
int pci_video_bios_init(struct bios_pci_dev *dev)
{
void *abseg = 0;
int i;
unsigned char *cp;
unsigned int size = 0;
int base = 0;
unsigned short initialip = 0, initialcs = 0, devfn = 0;
char *date = "01/01/99";
#ifdef DEBUG
int debugflag = 0;
int trace = 0;
#endif
// size = 64 * 1024;
size = dev->rom_size;
base = 0xc0000;
initialcs = 0xc000;
initialip = 0x0003;
// rom_printk("Point 1 int%x vector at %x\n", 0x42, getIntVect(0x42));
abseg = (void *) 0xa0000;
currentp = &p;
X86EMU_setMemBase(biosmem, sizeof(biosmem));
X86EMU_setabseg(abseg);
X86EMU_setupPioFuncs(&myfuncs);
/* Setting up interrupt environment.
* basically this means initializing PCI and
* intXX handlers.
*/
pciInit();
setup_int_vect();
for (i = 0; i < 256; i++)
intFuncs[i] = do_int;
X86EMU_setupIntrFuncs(intFuncs);
cp = (unsigned char *) dev->rom_address ;
devfn = (PCI_SLOT(dev->devfn) << 3) |
PCI_FUNC(dev->devfn);
currentp->ax = devfn ? devfn : 0xff;
currentp->dx = 0x80;
for (i = 0; i < size; i++) {
wrb(base + i, cp[i]);
}
/* Put a date into ROM */
for (i = 0; date[i]; i++)
wrb(0xffff5 + i, date[i]);
wrb(0xffff7, '/');
wrb(0xffffa, '/');
/* cpu setup */
X86_AX = devfn ? devfn : 0xff;
X86_DX = 0x80;
X86_EIP = initialip;
X86_CS = initialcs;
/* Initialize stack and data segment */
X86_SS = 0x0030;
X86_DS = 0x0040;
X86_SP = 0xfffe;
/* We need a sane way to return from bios
* execution. A hlt instruction and a pointer
* to it, both kept on the stack, will do.
*/
pushw(0xf4f4); /* hlt; hlt */
pushw(X86_SS);
pushw(X86_SP + 2);
X86_ES = 0x0000;
#ifdef DEBUG
if (trace) {
rom_printk("Switching to single step mode.\n");
X86EMU_trace_on();
}
#endif
#if 0
debugflag = DEBUG_MEM_TRACE_F |
DEBUG_DECODE_F | DEBUG_DISASSEMBLE_F |
DEBUG_TRACE_F |
DEBUG_SYSINT_F;
#endif
#ifdef DEBUG
// debugflag = 0x00ffffff;
if (debugflag) {
X86EMU_set_debug(debugflag);
}
#endif
X86EMU_exec();
/* Cleaning up */
pciExit();
return 0;
}
/* VGA index register ports */
#define GRA_I 0x3CE /* Graphics Controller Index */
#define SEQ_I 0x3C4 /* Sequencer Index */
/* VGA data register ports */
#define GRA_D 0x3CF /* Graphics Controller Data Register */
#define SEQ_D 0x3C5 /* Sequencer Data Register */
#define CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
#define CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
#define IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
#define ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
#define ATC_MODE 0x10
#define ATC_COLOR_PAGE 0x14
#define CRTC_H_TOTAL 0
#define CRTC_H_DISP 1
#define CRTC_H_BLANK_START 2
#define CRTC_H_BLANK_END 3
#define CRTC_H_SYNC_START 4
#define CRTC_H_SYNC_END 5
#define CRTC_V_TOTAL 6
#define CRTC_OVERFLOW 7
#define CRTC_PRESET_ROW 8
#define CRTC_MAX_SCAN 9
#define CRTC_CURSOR_START 0x0A
#define CRTC_CURSOR_END 0x0B
#define CRTC_START_HI 0x0C
#define CRTC_START_LO 0x0D
#define CRTC_CURSOR_HI 0x0E
#define CRTC_CURSOR_LO 0x0F
#define CRTC_V_SYNC_START 0x10
#define CRTC_V_SYNC_END 0x11
#define CRTC_V_DISP_END 0x12
#define CRTC_OFFSET 0x13
#define CRTC_UNDERLINE 0x14
#define CRTC_V_BLANK_START 0x15
#define CRTC_V_BLANK_END 0x16
#define CRTC_MODE 0x17
#define CRTC_LINE_COMPARE 0x18
// macros for writing to vga regs
#define write_seq(data, addr) \
({ \
bios_outb(addr, SEQ_I); \
bios_outb(data, SEQ_D); \
})
#define write_gra(data, addr) \
({ \
bios_outb(addr, GRA_I); \
bios_outb(data, GRA_D); \
})
#define write_crtc(data, addr) \
({ \
bios_outb(addr, CRT_IC); \
bios_outb(data, CRT_DC); \
})
#define write_att(data, addr) \
({ \
bios_inb(IS1_RC); \
bios_inb(0x80); \
bios_outb(addr, ATT_IW); \
bios_inb(0x80); \
bios_outb(data, ATT_IW); \
bios_inb(0x80); \
})
#define SEQ_CLOCK_MODE 0x01
#define SEQ_PLANE_WRITE 0x02
#define SEQ_CHARACTER_MAP 0x03
#define SEQ_MEMORY_MODE 0x04
#define GDC_PLANE_READ 0x04
#define GDC_MODE 0x05
#define GDC_MISC 0x06
#define GDC_BIT_MASK 0x08
#define VGA_FONT_BASE 0xa8000
#define CHAR_HEIGHT 16
unsigned char read_seq_b(unsigned short addr) {
bios_outb(addr, SEQ_I);
return bios_inb(SEQ_D);
}
unsigned char read_gra_b(unsigned short addr) {
bios_outb(addr, GRA_I);
return bios_inb(GRA_D);
}
unsigned char read_crtc_b(unsigned short addr) {
bios_outb(addr, CRT_IC);
return bios_inb(CRT_DC);
}
unsigned char read_att_b(unsigned short addr) {
bios_inb(IS1_RC);
bios_inb(0x80);
bios_outb(addr, ATT_IW);
return bios_inb(ATT_R);
}
#if 0
void vga_set_amode (void) {
unsigned char byte;
rom_printk("Switching into alpha mode...");
write_att(0x0c, ATC_MODE);
//reset palette to normal in the case it was changed
write_att(0x0, ATC_COLOR_PAGE);
//
// display is off at this point
write_seq(0x3, SEQ_PLANE_WRITE); /* planes 0 & 1 */
byte = read_seq_b(SEQ_MEMORY_MODE) & ~0x04;
write_seq(byte, SEQ_MEMORY_MODE);
byte = read_gra_b(GDC_MODE) & ~0x60;
write_gra(byte|0x10, GDC_MODE);
write_gra(0x0e, GDC_MISC);
write_crtc(0x00, CRTC_CURSOR_START);
write_crtc(CHAR_HEIGHT-1, CRTC_CURSOR_END);
byte = read_crtc_b(CRTC_MODE) & ~0xe0;
write_crtc(byte|0xa0, CRTC_MODE);
byte = read_crtc_b(CRTC_MAX_SCAN) & ~0x01f;
write_crtc(byte | (CHAR_HEIGHT-1), CRTC_MAX_SCAN);
// turn on display, disable access to attr palette
bios_inb(IS1_RC);
bios_outb(0x20, ATT_IW);
rom_printk("done.\n");
}
#endif
/*
* by Steve M. Gehlbach, Ph.D. <steve@kesa.com>
*
* vga_font_load loads a font into font memory. It
* assumes alpha mode has been set.
*
* The font load code follows technique used
* in the tiara project, which came from
* the Universal Talkware Boot Loader,
* http://www.talkware.net.
*/
void atyr128_font_enable(unsigned char *vidmem, int height, int num_chars) {
/* Note: the font table is 'height' long but the font storage area
* is 32 bytes long.
*/
int i;
unsigned char byte;
// rom_printk("Loading VGA font...");
// set sequencer map 2, odd/even off
byte = read_seq_b(SEQ_PLANE_WRITE) & ~0xf;
// rom_printk("SEQ_PLANE_WRITE %x\n", byte);
write_seq(byte|4,SEQ_PLANE_WRITE);
byte = read_seq_b(SEQ_MEMORY_MODE);
// rom_printk("SEQ_MEMORY_MODE %x\n", byte);
write_seq(byte|4,SEQ_MEMORY_MODE);
// select graphics map 2, odd/even off, map starts at 0xa0000
write_gra(2,GDC_PLANE_READ);
byte = read_gra_b(GDC_MODE) & ~0x10;
// rom_printk("GDC_MODE %x\n", byte);
write_gra(byte,GDC_MODE);
write_gra(0,GDC_MISC);
/* Clear 256K */
for (i = 0; i<(256 * 1024); i++) {
vidmem[i] = 0;
}
// set sequencer back to maps 0,1, odd/even on
byte = read_seq_b(SEQ_PLANE_WRITE) & ~0xf;
write_seq(byte|3,SEQ_PLANE_WRITE);
byte = read_seq_b(SEQ_MEMORY_MODE) & ~0x4;
write_seq(byte,SEQ_MEMORY_MODE);
byte = read_seq_b(SEQ_CHARACTER_MAP);
// rom_printk("SEQ_CHARACTER_MAP %x\n", byte);
write_seq(0x0a, SEQ_CHARACTER_MAP);
// select graphics back to map 0,1, odd/even on
write_gra(0,GDC_PLANE_READ);
byte = read_gra_b(GDC_MODE);
write_gra(byte|0x10,GDC_MODE);
write_gra(0xe,GDC_MISC);
// rom_printk("done\n");
}
void video_bios(void)
{
struct bios_pci_dev *dev;
int adpt_cnt;
unsigned char *code = 0;
int pcirom = 0;
int atyr128 = 0;
int cl5446 = 0;
int mga2 = 0;
adpt_cnt = 0;
DebugV("video_bios() started\n");
dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
adpt_cnt++;
if (dev) {
#if DEBUG_VIDEO
rom_printk("--------- VIDEO BIOS ------\n");
rom_printk("Class: %X\n", dev->class);
rom_printk("command: %x\n", dev->command);
rom_printk("base_address[0]: %04x\n", dev->base_address[0]);
rom_printk("size[0]: %04x\n", dev->size[0]);
rom_printk("base_address[1]: %04x\n", dev->base_address[1]);
rom_printk("size[1]: %04x\n", dev->size[1]);
rom_printk("base_address[2]: %04x\n", dev->base_address[2]);
rom_printk("size[2]: %04x\n", dev->size[2]);
rom_printk("base_address[3]: %04x\n", dev->base_address[3]);
rom_printk("size[0]: %04x\n", dev->size[3]);
rom_printk("base_address[4]: %04x\n", dev->base_address[4]);
rom_printk("size[4]: %04x\n", dev->size[4]);
rom_printk("base_address[5]: %04x\n", dev->base_address[5]);
rom_printk("size[5]: %04x\n", dev->size[5]);
rom_printk("rom_address: %04x\n", dev->rom_address);
rom_printk("rom_size %04x\n", dev->rom_size);
#endif
code = (unsigned char *) dev->rom_address;
if (code[0] == 0x55U &&
code[1] == 0xAAU ) {
rom_printk("VIDEO BIOS found at %X\n", code);
} else {
rom_printk("No ROM signature found."
" Skipping BIOS init...\n");
rom_printk("BYTES: %x %x\n", code[0],
code[1]);
}
switch (dev->vendor)
{
case PCI_VENDOR_ID_CIRRUS:
if (dev->device == PCI_DEVICE_ID_CIRRUS_5446) {
rom_printk("Cirrus Logic GD 5446 detected!\n");
cl5446 = 1;
};
break;
case PCI_VENDOR_ID_ATI:
switch(dev->device)
{
case PCI_DEVICE_ID_ATI_RAGE128_PP:
rom_printk("ATI Rage 128 PP detected!\n");
atyr128 = 1;
break;
case PCI_DEVICE_ID_ATI_RAGE128_TR:
rom_printk("ATI Rage 128 TR detected!\n");
atyr128 = 1;
break;
default:
rom_printk("Unknown ATI display adapter detected!\n");
break;
};
break;
case PCI_VENDOR_ID_MCST_TMP:
if (dev->device == PCI_DEVICE_ID_MCST_MGA2) {
rom_printk("Embeded Graphic MGA2/GC2500 "
"detected!\n");
mga2 = 1;
};
break;
default:
rom_printk("Unknown display adapter found!\n");
break;
}
} else {
rom_printk("No PCI display adaplers found!\n");
}
if (pcirom) {
pci_video_bios_init(dev);
} else if (mga2) {
#ifdef CONFIG_VGA_CONSOLE
vga_init();
#endif /* CONFIG_VGA_CONSOLE */
} else {
return;
}
if (atyr128) {
atyr128_font_enable( (unsigned char *) VGA_FONT_BASE,
CHAR_HEIGHT, 256);
#if 0
unsigned char *vidmem = (unsigned char *) dev->base_address[0];
int i;
for (i=0; i < (1 * 1024 * 1024); i++) {
vidmem[i] = 0;
};
#endif
}
// vga_set_amode();
hardware.video = 1;
if (atyr128)
{
long int i;
/* delay to relax ATI hardware */
for (i=0; i<77000000L; i++) {
do {
(void) (i);
} while (0) ;
}
}
#if 0
if (cl5446)
{
long int i;
// rom_printk("qwertyuiopasdfghjklzxcvbnm\n");
// rom_printk("qwertyuiopasdfghjklzxcvbnm\n");
// rom_printk("qwertyuiopasdfghjklzxcvbnm\n");
for (i=0; i<2000000L; i++) { do {i; } while (0) ; }
}
#endif
}